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
 * Launches the modal dialogue that contains the iframe that sends the Content-Item selection request to an
18
 * LTI tool provider that supports Content-Item type message.
19
 *
20
 * See template: mod_lti/contentitem
21
 *
22
 * @module     mod_lti/contentitem
23
 * @copyright  2016 Jun Pataleta <jun@moodle.com>
24
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25
 * @since      3.2
26
 */
27
define(
28
    [
29
        'jquery',
30
        'core/notification',
31
        'core/str',
32
        'core/templates',
33
        'mod_lti/form-field',
34
        'core/modal',
35
        'core/modal_events'
36
    ],
37
    function($, notification, str, templates, FormField, Modal, ModalEvents) {
38
        var dialogue;
39
        var doneCallback;
40
        var contentItem = {
41
            /**
42
             * Init function.
43
             *
44
             * @param {string} url The URL for the content item selection.
45
             * @param {object} postData The data to be sent for the content item selection request.
46
             * @param {Function} cb The callback to run once the content item has been processed.
47
             */
48
            init: function(url, postData, cb) {
49
                doneCallback = cb;
50
                var context = {
51
                    url: url,
52
                    postData: postData
53
                };
54
                var bodyPromise = templates.render('mod_lti/contentitem', context);
55
 
56
                if (dialogue) {
57
                    // Set dialogue body.
58
                    dialogue.setBody(bodyPromise);
59
                    // Display the dialogue.
60
                    dialogue.show();
61
                    return;
62
                }
63
 
64
                str.get_string('selectcontent', 'lti').then(function(title) {
65
                    return Modal.create({
66
                        title: title,
67
                        body: bodyPromise,
68
                        large: true,
69
                        show: true,
70
                    });
71
                }).then(function(modal) {
72
                    dialogue = modal;
73
                    // On hide handler.
74
                    modal.getRoot().on(ModalEvents.hidden, function() {
75
                        // Empty modal contents when it's hidden.
76
                        modal.setBody('');
77
 
78
                        // Fetch notifications.
79
                        notification.fetchNotifications();
80
                    });
81
                    return;
82
                }).catch(notification.exception);
83
            }
84
        };
85
 
86
        /**
87
         * Array of form fields for LTI tool configuration.
88
         */
89
        var ltiFormFields = [
90
            new FormField('name', FormField.TYPES.TEXT, false, ''),
91
            new FormField('introeditor', FormField.TYPES.EDITOR, false, ''),
92
            new FormField('toolurl', FormField.TYPES.TEXT, true, ''),
93
            new FormField('securetoolurl', FormField.TYPES.TEXT, true, ''),
94
            new FormField('instructorchoiceacceptgrades', FormField.TYPES.CHECKBOX, true, true),
95
            new FormField('instructorchoicesendname', FormField.TYPES.CHECKBOX, true, true),
96
            new FormField('instructorchoicesendemailaddr', FormField.TYPES.CHECKBOX, true, true),
97
            new FormField('instructorcustomparameters', FormField.TYPES.TEXT, true, ''),
98
            new FormField('icon', FormField.TYPES.TEXT, true, ''),
99
            new FormField('secureicon', FormField.TYPES.TEXT, true, ''),
100
            new FormField('launchcontainer', FormField.TYPES.SELECT, true, 0),
101
            new FormField('grade_modgrade_point', FormField.TYPES.TEXT, false, ''),
102
            new FormField('lineitemresourceid', FormField.TYPES.TEXT, true, ''),
103
            new FormField('lineitemtag', FormField.TYPES.TEXT, true, ''),
104
            new FormField('lineitemsubreviewurl', FormField.TYPES.TEXT, true, ''),
105
            new FormField('lineitemsubreviewparams', FormField.TYPES.TEXT, true, '')
106
        ];
107
 
108
        /**
109
         * Hide the element, including aria and tab index.
110
         * @param {HTMLElement} e the element to be hidden.
111
         */
112
        const hideElement = (e) => {
113
            e.setAttribute('hidden', 'true');
114
            e.setAttribute('aria-hidden', 'true');
115
            e.setAttribute('tab-index', '-1');
116
        };
117
 
118
        /**
119
         * Show the element, including aria and tab index (set to 1).
120
         * @param {HTMLElement} e the element to be shown.
121
         */
122
        const showElement = (e) => {
123
            e.removeAttribute('hidden');
124
            e.setAttribute('aria-hidden', 'false');
125
            e.setAttribute('tab-index', '1');
126
        };
127
 
128
        /**
129
         * When more than one item needs to be added, the UI is simplified
130
         * to just list the items to be added. Form is hidden and the only
131
         * options is (save and return to course) or cancel.
132
         * This function injects the summary to the form page, and hides
133
         * the unneeded elements.
134
         * @param {Object[]} items items to be added to the course.
135
         */
136
        const showMultipleSummaryAndHideForm = async function(items) {
137
            const form = document.querySelector('#region-main-box form');
138
            const toolArea = form.querySelector('[data-attribute="dynamic-import"]');
139
            const buttonGroup = form.querySelector('#fgroup_id_buttonar');
140
            const submitAndLaunch = form.querySelector('#id_submitbutton');
141
            Array.from(form.children).forEach(hideElement);
142
            hideElement(submitAndLaunch);
143
            const {html, js} = await templates.renderForPromise('mod_lti/tool_deeplinking_results',
144
                {items: items});
145
 
146
            await templates.replaceNodeContents(toolArea, html, js);
147
            showElement(toolArea);
148
            showElement(buttonGroup);
149
        };
150
 
151
        /**
152
         * Transforms config values aimed at populating the lti mod form to JSON variant
153
         * which are used to insert more than one activity modules in one submit
154
         * by applying variation to the submitted form.
155
         * See /course/modedit.php.
156
         * @private
157
         * @param {Object} config transforms a config to an actual form data to be posted.
158
         * @return {Object} variant that will be used to modify form values on submit.
159
         */
160
        var configToVariant = (config) => {
161
            const variant = {};
162
            ['name', 'toolurl', 'securetoolurl', 'instructorcustomparameters', 'icon', 'secureicon',
163
                'launchcontainer', 'lineitemresourceid', 'lineitemtag', 'lineitemsubreviewurl',
11 efrain 164
                'lineitemsubreviewparams'].forEach(
1 efrain 165
                function(name) {
166
                    variant[name] = config[name] || '';
167
                }
168
            );
169
            variant['introeditor[text]'] = config.introeditor ? config.introeditor.text : '';
170
            variant['introeditor[format]'] = config.introeditor ? config.introeditor.format : '';
171
            if (config.instructorchoiceacceptgrades === 1) {
172
                variant.instructorchoiceacceptgrades = '1';
173
                variant['grade[modgrade_point]'] = config.grade_modgrade_point || '100';
174
            } else {
175
                variant.instructorchoiceacceptgrades = '0';
176
            }
177
            return variant;
178
        };
179
 
180
        /**
181
         * Window function that can be called from mod_lti/contentitem_return to close the dialogue and process the return data.
182
         * If the return data contains more than one item, the form will not be populated with item data
183
         * but rather hidden, and the item data will be added to a single input field used to create multiple
184
         * instances in one request.
185
         *
186
         * @param {object} returnData The fetched configuration data from the Content-Item selection dialogue.
187
         */
188
        window.processContentItemReturnData = function(returnData) {
189
            if (dialogue) {
190
                dialogue.hide();
191
            }
192
            var index;
193
            if (returnData.multiple) {
194
                for (index in ltiFormFields) {
195
                    // Name is required, so putting a placeholder as it will not be used
196
                    // in multi-items add.
197
                    ltiFormFields[index].setFieldValue(ltiFormFields[index].name === 'name' ? 'item' : null);
198
                }
199
                var variants = [];
200
                returnData.multiple.forEach(function(v) {
201
                    variants.push(configToVariant(v));
202
                });
203
                showMultipleSummaryAndHideForm(returnData.multiple);
204
                const submitAndCourse = document.querySelector('#id_submitbutton2');
205
                submitAndCourse.onclick = (e) => {
206
                    e.preventDefault();
207
                    submitAndCourse.disabled = true;
208
                    const fd = new FormData(document.querySelector('#region-main-box form'));
209
                    const postVariant = (promise, variant) => {
210
                        Object.entries(variant).forEach((entry) => fd.set(entry[0], entry[1]));
211
                        const body = new URLSearchParams(fd);
212
                        const doPost = () => fetch(document.location.pathname, {method: 'post', body});
213
                        return promise.then(doPost).catch(doPost);
214
                    };
215
                    const backToCourse = () => {
216
                        document.querySelector("#id_cancel").click();
217
                    };
218
                    variants.reduce(postVariant, Promise.resolve()).then(backToCourse).catch(backToCourse);
219
                };
220
            } else {
221
                // Populate LTI configuration fields from return data.
222
                for (index in ltiFormFields) {
223
                    var field = ltiFormFields[index];
224
                    var value = null;
225
                    if (typeof returnData[field.name] !== 'undefined') {
226
                        value = returnData[field.name];
227
                    }
228
                    field.setFieldValue(value);
229
                }
230
                field.setFieldValue(value);
231
 
232
                // Update the UI element which signifies content has been selected.
233
                document.querySelector("#id_selectcontentindicator").innerHTML = returnData.selectcontentindicator;
234
            }
235
 
236
            if (doneCallback) {
237
                doneCallback(returnData);
238
            }
239
        };
240
 
241
        return contentItem;
242
    }
243
);