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