MDL-30268 Web service : resolved version number conflict
[moodle.git] / mod / lti / mod_form.js
CommitLineData
61eb12d4
CS
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/**
8f45215d 17 * Javascript extensions for the External Tool activity editor.
61eb12d4
CS
18 *
19 * @package mod
20 * @subpackage lti
8f45215d 21 * @copyright Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
61eb12d4
CS
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
6831c7cd
CS
24(function(){
25 var Y;
e27cb316 26
6831c7cd
CS
27 M.mod_lti = M.mod_lti || {};
28
29 M.mod_lti.editor = {
30 init: function(yui3, settings){
31 if(yui3){
32 Y = yui3;
996b0fd9 33 }
e27cb316 34
16e8f130 35 var self = this;
6831c7cd
CS
36 this.settings = Y.JSON.parse(settings);
37
38 this.urlCache = {};
39
40 this.addOptGroups();
41
d8d04121
CS
42 var updateToolMatches = function(){
43 self.updateAutomaticToolMatch(Y.one('#id_toolurl'));
44 self.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
45 };
46
6831c7cd
CS
47 var typeSelector = Y.one('#id_typeid');
48 typeSelector.on('change', function(e){
d8d04121 49 updateToolMatches();
e27cb316 50
6831c7cd
CS
51 self.toggleEditButtons();
52 });
53
54 this.createTypeEditorButtons();
55
56 this.toggleEditButtons();
e27cb316 57
6831c7cd
CS
58 var textAreas = new Y.NodeList([
59 Y.one('#id_toolurl'),
d8d04121 60 Y.one('#id_securetoolurl'),
6831c7cd
CS
61 Y.one('#id_resourcekey'),
62 Y.one('#id_password')
63 ]);
e27cb316 64
6831c7cd
CS
65 var debounce;
66 textAreas.on('keyup', function(e){
67 clearTimeout(debounce);
68
69 //If no more changes within 2 seconds, look up the matching tool URL
70 debounce = setTimeout(function(){
d8d04121 71 updateToolMatches();
6831c7cd
CS
72 }, 2000);
73 });
e27cb316 74
d8d04121 75 updateToolMatches();
6831c7cd
CS
76 },
77
16e8f130
CS
78 clearToolCache: function(){
79 this.urlCache = {};
80 },
81
d8d04121 82 updateAutomaticToolMatch: function(field){
16e8f130 83 var self = this;
e27cb316 84
d8d04121 85 var toolurl = field;
606ab1a1 86 var typeSelector = Y.one('#id_typeid');
e27cb316 87
d8d04121
CS
88 var id = field.get('id') + '_lti_automatch_tool';
89 var automatchToolDisplay = Y.one('#' + id);
6831c7cd
CS
90
91 if(!automatchToolDisplay){
92 automatchToolDisplay = Y.Node.create('<span />')
d8d04121 93 .set('id', id)
6831c7cd 94 .setStyle('padding-left', '1em');
e27cb316 95
6831c7cd
CS
96 toolurl.insert(automatchToolDisplay, 'after');
97 }
98
99 var url = toolurl.get('value');
996b0fd9 100
16e8f130
CS
101 //Hide the display if the url box is empty
102 if(!url){
6831c7cd 103 automatchToolDisplay.setStyle('display', 'none');
16e8f130
CS
104 } else {
105 automatchToolDisplay.set('innerHTML', '');
106 automatchToolDisplay.setStyle('display', '');
107 }
108
109 var selectedToolType = typeSelector.get('value');
89b7bbe9 110 var selectedOption = typeSelector.one('option[value="' + selectedToolType + '"]');
16e8f130 111
89b7bbe9 112 //A specific tool type is selected (not "auto")
16e8f130
CS
113 if(selectedToolType > 0){
114 //If the entered domain matches the domain of the tool configuration...
115 var domainRegex = /(?:https?:\/\/)?(?:www\.)?([^\/]+)(?:\/|$)/i;
116 var match = domainRegex.exec(url);
117 if(match && match[1] && match[1].toLowerCase() === selectedOption.getAttribute('domain').toLowerCase()){
118 automatchToolDisplay.set('innerHTML', '<img style="vertical-align:text-bottom" src="' + self.settings.green_check_icon_url + '" />' + M.str.lti.using_tool_configuration + selectedOption.get('text'));
119 } else {
120 //The entered URL does not match the domain of the tool configuration
121 automatchToolDisplay.set('innerHTML', '<img style="vertical-align:text-bottom" src="' + self.settings.warning_icon_url + '" />' + M.str.lti.domain_mismatch);
122 }
e27cb316 123
6831c7cd
CS
124 return;
125 }
126
127 var key = Y.one('#id_resourcekey');
128 var secret = Y.one('#id_password');
129
130 //We don't care what tool type this tool is associated with if it's manually configured'
131 if(key.get('value') !== '' && secret.get('value') !== ''){
16e8f130 132 automatchToolDisplay.set('innerHTML', '<img style="vertical-align:text-bottom" src="' + self.settings.green_check_icon_url + '" />' + M.str.lti.custom_config);
6831c7cd
CS
133 } else {
134 var continuation = function(toolInfo){
6831c7cd 135 if(toolInfo.toolname){
16e8f130 136 automatchToolDisplay.set('innerHTML', '<img style="vertical-align:text-bottom" src="' + self.settings.green_check_icon_url + '" />' + M.str.lti.using_tool_configuration + toolInfo.toolname);
6831c7cd
CS
137 } else {
138 //Inform them custom configuration is in use
139 if(key.get('value') === '' || secret.get('value') === ''){
16e8f130 140 automatchToolDisplay.set('innerHTML', '<img style="vertical-align:text-bottom" src="' + self.settings.warning_icon_url + '" />' + M.str.lti.tool_config_not_found);
996b0fd9
CS
141 }
142 }
6831c7cd 143 };
e27cb316 144
6831c7cd
CS
145 //Cache urls which have already been checked to increaes performance
146 if(self.urlCache[url]){
147 continuation(self.urlCache[url]);
148 } else {
149 self.findToolByUrl(url, function(toolInfo){
150 self.urlCache[url] = toolInfo;
151
152 continuation(toolInfo);
153 });
154 }
155 }
156 },
157
158 getSelectedToolTypeOption: function(){
159 var typeSelector = Y.one('#id_typeid');
160
89b7bbe9 161 return typeSelector.one('option[value="' + typeSelector.get('value') + '"]');
6831c7cd
CS
162 },
163
164 /**
165 * Separate tool listing into option groups. Server-side select control
166 * doesn't seem to support this.
167 */
168 addOptGroups: function(){
169 var typeSelector = Y.one('#id_typeid');
170
171 if(typeSelector.one('option[courseTool=1]')){
172 //One ore more course tools exist
173
174 var globalGroup = Y.Node.create('<optgroup />')
175 .set('id', 'global_tool_group')
176 .set('label', M.str.lti.global_tool_types);
177
178 var courseGroup = Y.Node.create('<optgroup />')
179 .set('id', 'course_tool_group')
180 .set('label', M.str.lti.course_tool_types);
181
606ab1a1 182 var globalOptions = typeSelector.all('option[globalTool=1]').remove().each(function(node){
6831c7cd
CS
183 globalGroup.append(node);
184 });
185
606ab1a1 186 var courseOptions = typeSelector.all('option[courseTool=1]').remove().each(function(node){
6831c7cd 187 courseGroup.append(node);
996b0fd9 188 });
6831c7cd 189
606ab1a1
CS
190 if(globalOptions.size() > 0){
191 typeSelector.append(globalGroup);
192 }
e27cb316 193
606ab1a1
CS
194 if(courseOptions.size() > 0){
195 typeSelector.append(courseGroup);
196 }
996b0fd9 197 }
6831c7cd
CS
198 },
199
200 /**
201 * Adds buttons for creating, editing, and deleting tool types.
202 * Javascript is a requirement to edit course level tools at this point.
203 */
204 createTypeEditorButtons: function(){
16e8f130 205 var self = this;
e27cb316 206
6831c7cd
CS
207 var typeSelector = Y.one('#id_typeid');
208
209 var createIcon = function(id, tooltip, iconUrl){
e27cb316 210 return Y.Node.create('<a />')
6831c7cd
CS
211 .set('id', id)
212 .set('title', tooltip)
213 .setStyle('margin-left', '.5em')
214 .set('href', 'javascript:void(0);')
215 .append(Y.Node.create('<img src="' + iconUrl + '" />'));
216 }
217
218 var addIcon = createIcon('lti_add_tool_type', M.str.lti.addtype, this.settings.add_icon_url);
219 var editIcon = createIcon('lti_edit_tool_type', M.str.lti.edittype, this.settings.edit_icon_url);
220 var deleteIcon = createIcon('lti_delete_tool_type', M.str.lti.deletetype, this.settings.delete_icon_url);
221
222 editIcon.on('click', function(e){
223 var toolTypeId = typeSelector.get('value');
224
225 if(self.getSelectedToolTypeOption().getAttribute('editable')){
226 window.open(self.settings.instructor_tool_type_edit_url + '&action=edit&typeid=' + toolTypeId, 'edit_tool');
227 } else {
228 alert(M.str.lti.cannot_edit);
229 }
230 });
231
232 addIcon.on('click', function(e){
233 window.open(self.settings.instructor_tool_type_edit_url + '&action=add', 'add_tool');
234 });
235
236 deleteIcon.on('click', function(e){
237 var toolTypeId = typeSelector.get('value');
238
239 if(self.getSelectedToolTypeOption().getAttribute('editable')){
240 if(confirm(M.str.lti.delete_confirmation)){
16e8f130 241 self.deleteTool(toolTypeId);
6831c7cd
CS
242 }
243 } else {
244 alert(M.str.lti.cannot_delete);
245 }
246 });
247
248 typeSelector.insert(addIcon, 'after');
249 addIcon.insert(editIcon, 'after');
250 editIcon.insert(deleteIcon, 'after');
251 },
252
253 toggleEditButtons: function(){
254 var lti_edit_tool_type = Y.one('#lti_edit_tool_type');
255 var lti_delete_tool_type = Y.one('#lti_delete_tool_type');
256
257 //Make the edit / delete icons look enabled / disabled.
258 //Does not work in older browsers, but alerts will catch those cases.
259 if(this.getSelectedToolTypeOption().getAttribute('editable')){
260 lti_edit_tool_type.setStyle('opacity', '1');
261 lti_delete_tool_type.setStyle('opacity', '1');
262 } else {
263 lti_edit_tool_type.setStyle('opacity', '.2');
264 lti_delete_tool_type.setStyle('opacity', '.2');
265 }
266 },
267
16e8f130 268 addToolType: function(toolType){
6831c7cd
CS
269 var typeSelector = Y.one('#id_typeid');
270 var course_tool_group = Y.one('#course_tool_group');
271
272 var option = Y.Node.create('<option />')
16e8f130
CS
273 .set('text', toolType.name)
274 .set('value', toolType.id)
6831c7cd
CS
275 .set('selected', 'selected')
276 .setAttribute('editable', '1')
16e8f130
CS
277 .setAttribute('courseTool', '1')
278 .setAttribute('domain', toolType.tooldomain);
6831c7cd
CS
279
280 if(course_tool_group){
281 course_tool_group.append(option);
282 } else {
283 typeSelector.append(option);
284 }
e27cb316 285
16e8f130
CS
286 //Adding the new tool may affect which tool gets matched automatically
287 this.clearToolCache();
89b7bbe9
CS
288 this.updateAutomaticToolMatch(Y.one('#id_toolurl'));
289 this.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
6831c7cd
CS
290 },
291
16e8f130 292 updateToolType: function(toolType){
6831c7cd
CS
293 var typeSelector = Y.one('#id_typeid');
294
89b7bbe9 295 var option = typeSelector.one('option[value="' + toolType.id + '"]');
16e8f130
CS
296 option.set('text', toolType.name)
297 .set('domain', toolType.tooldomain);
e27cb316 298
16e8f130
CS
299 //Editing the tool may affect which tool gets matched automatically
300 this.clearToolCache();
89b7bbe9
CS
301 this.updateAutomaticToolMatch(Y.one('#id_toolurl'));
302 this.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
16e8f130
CS
303 },
304
305 deleteTool: function(toolTypeId){
306 var self = this;
e27cb316 307
16e8f130
CS
308 Y.io(self.settings.instructor_tool_type_edit_url + '&action=delete&typeid=' + toolTypeId, {
309 on: {
310 success: function(){
311 self.getSelectedToolTypeOption().remove();
e27cb316 312
16e8f130
CS
313 //Editing the tool may affect which tool gets matched automatically
314 self.clearToolCache();
89b7bbe9
CS
315 self.updateAutomaticToolMatch(Y.one('#id_toolurl'));
316 self.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
16e8f130
CS
317 },
318 failure: function(){
319
320 }
321 }
322 });
6831c7cd
CS
323 },
324
325 findToolByUrl: function(url, callback){
16e8f130 326 var self = this;
e27cb316
CS
327
328 Y.io(self.settings.ajax_url, {
16e8f130 329 data: {action: 'find_tool_config',
6831c7cd
CS
330 course: self.settings.courseId,
331 toolurl: url
332 },
996b0fd9 333
6831c7cd
CS
334 on: {
335 success: function(transactionid, xhr){
336 var response = xhr.response;
e27cb316 337
6831c7cd 338 var toolInfo = Y.JSON.parse(response);
e27cb316 339
6831c7cd
CS
340 callback(toolInfo);
341 },
342 failure: function(){
996b0fd9 343
6831c7cd
CS
344 }
345 }
346 });
347 }
996b0fd9 348
6831c7cd 349 };
61eb12d4 350})();