Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// This file is part of Moodle - http://moodle.org/
2
//
3
// Moodle is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// Moodle is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
 
16
/**
17
 * Edit items in feedback module
18
 *
19
 * @module     mod_feedback/edit
20
 * @copyright  2016 Marina Glancy
1441 ariadna 21
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1 efrain 22
 */
23
 
1441 ariadna 24
"use strict";
1 efrain 25
 
1441 ariadna 26
import {addIconToContainerRemoveOnCompletion} from 'core/loadingicon';
27
import Notification from 'core/notification';
28
import Pending from 'core/pending';
29
import {prefetchStrings} from 'core/prefetch';
30
import SortableList from 'core/sortable_list';
31
import {getString, getStrings} from 'core/str';
32
import {add as addToast} from 'core/toast';
33
import {reorderQuestions} from 'mod_feedback/local/repository';
34
import Templates from 'core/templates';
1 efrain 35
 
1441 ariadna 36
const Selectors = {
37
    deleteQuestionButton: '[data-action="delete"]',
38
    sortableListRegion: '[data-region="questions-sortable-list"]',
39
    sortableElement: '[data-region="questions-sortable-list"] .feedback_itemlist[id]',
40
    sortableElementTitle: '[data-region="item-title"] span',
41
    questionLabel: '[data-region="questions-sortable-list"] .col-form-label',
42
    actionsMenuData: '[data-item-actions-menu]',
43
};
44
 
45
/**
46
 * Returns the Feedback question item id from the DOM id of an item.
47
 *
48
 * @param {String} id The dom id, f.g.: feedback_item_22
49
 * @return int
50
 */
51
const getItemId = (id) => {
52
    return Number(id.replace(/^.*feedback_item_/i, ''));
53
};
54
 
55
/**
56
 * Returns the order of the items in the sortable list.
57
 *
58
 * @param {Element} element The element to get the order from.
59
 * @return string
60
 */
61
const getItemOrder = (element) => {
62
    const sortableList = element.closest(Selectors.sortableListRegion);
63
    let itemOrder = [];
64
    sortableList.querySelectorAll(Selectors.sortableElement).forEach((item) => {
65
        itemOrder.push(getItemId(item.id));
66
    });
67
    return itemOrder.toString();
68
};
69
 
70
let initialized = false;
71
let moduleId = null;
72
 
73
/**
74
 * Initialise editor and all it's modules
75
 *
76
 * @param {Integer} cmId
77
 */
78
export const init = async(cmId) => {
79
 
80
    moduleId = cmId;
81
 
82
    // Ensure we only add our listeners once (can be called multiple times).
83
    if (initialized) {
84
        return;
85
    }
86
 
87
    prefetchStrings('core', [
88
        'yes',
89
        'no',
90
    ]);
91
    prefetchStrings('admin', [
92
        'confirmation',
93
    ]);
94
    prefetchStrings('mod_feedback', [
95
        'confirmdeleteitem',
96
        'questionmoved',
97
        'move_item',
98
    ]);
99
 
100
    await enhanceEditForm();
101
 
102
    // Add event listeners.
103
    document.addEventListener('click', async event => {
104
 
105
        // Delete question.
106
        const deleteButton = event.target.closest(Selectors.deleteQuestionButton);
107
        if (deleteButton) {
108
            event.preventDefault();
109
            const confirmationStrings = await getStrings([
110
                {key: 'confirmation', component: 'admin'},
111
                {key: 'confirmdeleteitem', component: 'mod_feedback'},
112
                {key: 'yes', component: 'core'},
113
                {key: 'no', component: 'core'},
114
            ]);
115
            Notification.confirm(...confirmationStrings, () => {
116
                window.location = deleteButton.getAttribute('href');
117
            });
118
            return;
1 efrain 119
        }
1441 ariadna 120
    });
1 efrain 121
 
1441 ariadna 122
    // Initialize sortable list to handle active conditions moving.
123
    const sortableList = new SortableList(document.querySelector(Selectors.sortableListRegion));
124
    sortableList.getElementName = element => Promise.resolve(element[0].querySelector(Selectors.sortableElementTitle)?.textContent);
125
 
126
    document.addEventListener(SortableList.EVENTS.elementDrop, event => {
127
        if (!event.detail.positionChanged) {
128
            return;
129
        }
130
        const pendingPromise = new Pending('mod_feedback/questions:reorder');
131
        const itemOrder = getItemOrder(event.detail.element[0]);
132
        addIconToContainerRemoveOnCompletion(event.detail.element[0], pendingPromise);
133
        reorderQuestions(moduleId, itemOrder)
134
            .then(() => getString('questionmoved', 'mod_feedback'))
135
            .then(addToast)
136
            .then(() => pendingPromise.resolve())
137
            .catch(Notification.exception);
138
    });
139
 
140
    initialized = true;
141
};
142
 
143
/**
144
 * Enhance the edit form by adding a move item button and an action menu to each question.
145
 *
146
 * @returns {Promise<void>}
147
 */
148
const enhanceEditForm = async() => {
149
    const questionLabels = document.querySelectorAll(Selectors.questionLabel);
150
    const movetitle = await getString('move_item', 'mod_feedback');
151
 
152
    const updates = Array.from(questionLabels).map(async(container) => {
153
        const label = container.querySelector(Selectors.actionsMenuData);
154
        if (!label) {
155
            return;
156
        }
157
 
158
        try {
159
            const contextData = {
160
                movetitle,
161
                label: label.parentElement.outerHTML,
162
                actionsmenu: JSON.parse(label.dataset.itemActionsMenu || '{}'),
163
            };
164
            container.innerHTML = await Templates.render('mod_feedback/item_edit_enhanced_title', contextData);
165
        } catch (error) {
166
            await Notification.exception(error);
167
        }
168
    });
169
    await Promise.all(updates);
170
};