[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/mod/lti/ -> mod_form.js (source)

   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   * Javascript extensions for the External Tool activity editor.
  18   *
  19   * @package    mod
  20   * @subpackage lti
  21   * @copyright  Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  (function(){
  25      var Y;
  26  
  27      M.mod_lti = M.mod_lti || {};
  28  
  29      M.mod_lti.LTI_SETTING_NEVER = 0;
  30      M.mod_lti.LTI_SETTING_ALWAYS = 1;
  31      M.mod_lti.LTI_SETTING_DELEGATE = 2;
  32  
  33      M.mod_lti.editor = {
  34          init: function(yui3, settings){
  35              if(yui3){
  36                  Y = yui3;
  37              }
  38  
  39              var self = this;
  40              this.settings = Y.JSON.parse(settings);
  41  
  42              this.urlCache = {};
  43              this.toolTypeCache = {};
  44  
  45              this.addOptGroups();
  46  
  47              var updateToolMatches = function(){
  48                  self.updateAutomaticToolMatch(Y.one('#id_toolurl'));
  49                  self.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
  50              };
  51  
  52              var typeSelector = Y.one('#id_typeid');
  53              typeSelector.on('change', function(e){
  54                  updateToolMatches();
  55  
  56                  self.toggleEditButtons();
  57  
  58                  if (self.getSelectedToolTypeOption().getAttribute('toolproxy')){
  59                      var allowname = Y.one('#id_instructorchoicesendname');
  60                      allowname.set('checked', !self.getSelectedToolTypeOption().getAttribute('noname'));
  61  
  62                      var allowemail = Y.one('#id_instructorchoicesendemailaddr');
  63                      allowemail.set('checked', !self.getSelectedToolTypeOption().getAttribute('noemail'));
  64  
  65                      var allowgrades = Y.one('#id_instructorchoiceacceptgrades');
  66                      allowgrades.set('checked', !self.getSelectedToolTypeOption().getAttribute('nogrades'));
  67                      self.toggleGradeSection();
  68                  }
  69  
  70              });
  71  
  72              this.createTypeEditorButtons();
  73  
  74              this.toggleEditButtons();
  75  
  76              var textAreas = new Y.NodeList([
  77                  Y.one('#id_toolurl'),
  78                  Y.one('#id_securetoolurl'),
  79                  Y.one('#id_resourcekey'),
  80                  Y.one('#id_password')
  81              ]);
  82  
  83              var debounce;
  84              textAreas.on('keyup', function(e){
  85                  clearTimeout(debounce);
  86  
  87                  // If no more changes within 2 seconds, look up the matching tool URL
  88                  debounce = setTimeout(function(){
  89                      updateToolMatches();
  90                  }, 2000);
  91              });
  92  
  93              var allowgrades = Y.one('#id_instructorchoiceacceptgrades');
  94              allowgrades.on('change', this.toggleGradeSection, this);
  95  
  96              updateToolMatches();
  97          },
  98  
  99          toggleGradeSection: function(e) {
 100              if (e) {
 101                  e.preventDefault();
 102              }
 103              var allowgrades = Y.one('#id_instructorchoiceacceptgrades');
 104              var gradefieldset = Y.one('#id_modstandardgrade');
 105              if (!allowgrades.get('checked')) {
 106                  gradefieldset.hide();
 107              } else {
 108                  gradefieldset.show();
 109              }
 110          },
 111  
 112          clearToolCache: function(){
 113              this.urlCache = {};
 114              this.toolTypeCache = {};
 115          },
 116  
 117          updateAutomaticToolMatch: function(field){
 118              var self = this;
 119  
 120              var toolurl = field;
 121              var typeSelector = Y.one('#id_typeid');
 122  
 123              var id = field.get('id') + '_lti_automatch_tool';
 124              var automatchToolDisplay = Y.one('#' + id);
 125  
 126              if(!automatchToolDisplay){
 127                  automatchToolDisplay = Y.Node.create('<span />')
 128                                          .set('id', id)
 129                                          .setStyle('padding-left', '1em');
 130  
 131                  toolurl.insert(automatchToolDisplay, 'after');
 132              }
 133  
 134              var url = toolurl.get('value');
 135  
 136              // Hide the display if the url box is empty
 137              if(!url){
 138                  automatchToolDisplay.setStyle('display', 'none');
 139              } else {
 140                  automatchToolDisplay.set('innerHTML', '');
 141                  automatchToolDisplay.setStyle('display', '');
 142              }
 143  
 144              var selectedToolType = parseInt(typeSelector.get('value'));
 145              var selectedOption = typeSelector.one('option[value="' + selectedToolType + '"]');
 146  
 147              // A specific tool type is selected (not "auto")
 148              // We still need to check with the server to get privacy settings
 149              if(selectedToolType > 0){
 150                  // If the entered domain matches the domain of the tool configuration...
 151                  var domainRegex = /(?:https?:\/\/)?(?:www\.)?([^\/]+)(?:\/|$)/i;
 152                  var match = domainRegex.exec(url);
 153                  if(match && match[1] && match[1].toLowerCase() === selectedOption.getAttribute('domain').toLowerCase()){
 154                      automatchToolDisplay.set('innerHTML',  '<img style="vertical-align:text-bottom" src="' + self.settings.green_check_icon_url + '" />' + M.util.get_string('using_tool_configuration', 'lti') + selectedOption.get('text'));
 155                  } else {
 156                      // The entered URL does not match the domain of the tool configuration
 157                      automatchToolDisplay.set('innerHTML', '<img style="vertical-align:text-bottom" src="' + self.settings.warning_icon_url + '" />' + M.util.get_string('domain_mismatch', 'lti'));
 158                  }
 159              }
 160  
 161              var key = Y.one('#id_resourcekey');
 162              var secret = Y.one('#id_password');
 163  
 164              // Indicate the tool is manually configured
 165              // We still check the Launch URL with the server as course/site tools may override privacy settings
 166              if(key.get('value') !== '' && secret.get('value') !== ''){
 167                  automatchToolDisplay.set('innerHTML',  '<img style="vertical-align:text-bottom" src="' + self.settings.green_check_icon_url + '" />' + M.util.get_string('custom_config', 'lti'));
 168              }
 169  
 170              var continuation = function(toolInfo, inputfield){
 171                  if (inputfield === undefined || (inputfield.get('id') != 'id_securetoolurl' || inputfield.get('value'))) {
 172                      self.updatePrivacySettings(toolInfo);
 173                  }
 174                  if(toolInfo.toolname){
 175                      automatchToolDisplay.set('innerHTML',  '<img style="vertical-align:text-bottom" src="' + self.settings.green_check_icon_url + '" />' + M.util.get_string('using_tool_configuration', 'lti') + toolInfo.toolname);
 176                  } else if(!selectedToolType) {
 177                      // Inform them custom configuration is in use
 178                      if(key.get('value') === '' || secret.get('value') === ''){
 179                          automatchToolDisplay.set('innerHTML', '<img style="vertical-align:text-bottom" src="' + self.settings.warning_icon_url + '" />' + M.util.get_string('tool_config_not_found', 'lti'));
 180                      }
 181                  }
 182                  if (toolInfo.cartridge) {
 183                      automatchToolDisplay.set('innerHTML', '<img style="vertical-align:text-bottom" src="' + self.settings.green_check_icon_url +
 184                                               '" />' + M.util.get_string('using_tool_cartridge', 'lti'));
 185                  }
 186              };
 187  
 188              // Cache urls which have already been checked to increase performance
 189              // Don't use URL cache if tool type manually selected
 190              if(selectedToolType && self.toolTypeCache[selectedToolType]){
 191                  return continuation(self.toolTypeCache[selectedToolType]);
 192              } else if(self.urlCache[url] && !selectedToolType){
 193                  return continuation(self.urlCache[url]);
 194              } else if(!selectedToolType && !url) {
 195                  // No tool type or url set
 196                  return continuation({}, field);
 197              } else {
 198                  self.findToolByUrl(url, selectedToolType, function(toolInfo){
 199                      if(toolInfo){
 200                          // Cache the result based on whether the URL or tool type was used to look up the tool
 201                          if(!selectedToolType){
 202                              self.urlCache[url] = toolInfo;
 203                          } else {
 204                              self.toolTypeCache[selectedToolType] = toolInfo;
 205                          }
 206  
 207                          Y.one('#id_urlmatchedtypeid').set('value', toolInfo.toolid);
 208  
 209                          continuation(toolInfo);
 210                      }
 211                  });
 212              }
 213          },
 214  
 215          /**
 216           * Updates display of privacy settings to show course / site tool configuration settings.
 217           */
 218          updatePrivacySettings: function(toolInfo){
 219              if(!toolInfo || !toolInfo.toolid){
 220                  toolInfo = {
 221                      sendname: M.mod_lti.LTI_SETTING_DELEGATE,
 222                      sendemailaddr: M.mod_lti.LTI_SETTING_DELEGATE,
 223                      acceptgrades: M.mod_lti.LTI_SETTING_DELEGATE
 224                  }
 225              }
 226  
 227              var setting, control;
 228  
 229              var privacyControls = {
 230                  sendname: Y.one('#id_instructorchoicesendname'),
 231                  sendemailaddr: Y.one('#id_instructorchoicesendemailaddr'),
 232                  acceptgrades: Y.one('#id_instructorchoiceacceptgrades')
 233              };
 234  
 235              // Store a copy of user entered privacy settings as we may overwrite them
 236              if(!this.userPrivacySettings){
 237                  this.userPrivacySettings = {};
 238              }
 239  
 240              for(setting in privacyControls){
 241                  if(privacyControls.hasOwnProperty(setting)){
 242                      control = privacyControls[setting];
 243  
 244                      // Only store the value if it hasn't been forced by the editor
 245                      if(!control.get('disabled')){
 246                          this.userPrivacySettings[setting] = control.get('checked');
 247                      }
 248                  }
 249              }
 250  
 251              // Update UI based on course / site tool configuration
 252              for(setting in privacyControls){
 253                  if(privacyControls.hasOwnProperty(setting)){
 254                      var settingValue = toolInfo[setting];
 255                      control = privacyControls[setting];
 256  
 257                      if(settingValue == M.mod_lti.LTI_SETTING_NEVER){
 258                          control.set('disabled', true);
 259                          control.set('checked', false);
 260                          control.set('title', M.util.get_string('forced_help', 'lti'));
 261                      } else if(settingValue == M.mod_lti.LTI_SETTING_ALWAYS){
 262                          control.set('disabled', true);
 263                          control.set('checked', true);
 264                          control.set('title', M.util.get_string('forced_help', 'lti'));
 265                      } else if(settingValue == M.mod_lti.LTI_SETTING_DELEGATE){
 266                          control.set('disabled', false);
 267  
 268                          // Get the value out of the stored copy
 269                          control.set('checked', this.userPrivacySettings[setting]);
 270                          control.set('title', '');
 271                      }
 272                  }
 273              }
 274  
 275              this.toggleGradeSection();
 276          },
 277  
 278          getSelectedToolTypeOption: function(){
 279              var typeSelector = Y.one('#id_typeid');
 280  
 281              return typeSelector.one('option[value="' + typeSelector.get('value') + '"]');
 282          },
 283  
 284          /**
 285           * Separate tool listing into option groups. Server-side select control
 286           * doesn't seem to support this.
 287           */
 288          addOptGroups: function(){
 289              var typeSelector = Y.one('#id_typeid');
 290  
 291              if(typeSelector.one('option[courseTool=1]')){
 292                  // One ore more course tools exist
 293  
 294                  var globalGroup = Y.Node.create('<optgroup />')
 295                                      .set('id', 'global_tool_group')
 296                                      .set('label', M.util.get_string('global_tool_types', 'lti'));
 297  
 298                  var courseGroup = Y.Node.create('<optgroup />')
 299                                      .set('id', 'course_tool_group')
 300                                      .set('label', M.util.get_string('course_tool_types', 'lti'));
 301  
 302                  var globalOptions = typeSelector.all('option[globalTool=1]').remove().each(function(node){
 303                      globalGroup.append(node);
 304                  });
 305  
 306                  var courseOptions = typeSelector.all('option[courseTool=1]').remove().each(function(node){
 307                      courseGroup.append(node);
 308                  });
 309  
 310                  if(globalOptions.size() > 0){
 311                      typeSelector.append(globalGroup);
 312                  }
 313  
 314                  if(courseOptions.size() > 0){
 315                      typeSelector.append(courseGroup);
 316                  }
 317              }
 318          },
 319  
 320          /**
 321           * Adds buttons for creating, editing, and deleting tool types.
 322           * Javascript is a requirement to edit course level tools at this point.
 323           */
 324          createTypeEditorButtons: function(){
 325              var self = this;
 326  
 327              var typeSelector = Y.one('#id_typeid');
 328  
 329              var createIcon = function(id, tooltip, iconUrl){
 330                  return Y.Node.create('<a />')
 331                          .set('id', id)
 332                          .set('title', tooltip)
 333                          .setStyle('margin-left', '.5em')
 334                          .set('href', 'javascript:void(0);')
 335                          .append(Y.Node.create('<img src="' + iconUrl + '" />'));
 336              }
 337  
 338              var addIcon = createIcon('lti_add_tool_type', M.util.get_string('addtype', 'lti'), this.settings.add_icon_url);
 339              var editIcon = createIcon('lti_edit_tool_type', M.util.get_string('edittype', 'lti'), this.settings.edit_icon_url);
 340              var deleteIcon  = createIcon('lti_delete_tool_type', M.util.get_string('deletetype', 'lti'), this.settings.delete_icon_url);
 341  
 342              editIcon.on('click', function(e){
 343                  var toolTypeId = typeSelector.get('value');
 344  
 345                  if(self.getSelectedToolTypeOption().getAttribute('editable')){
 346                      window.open(self.settings.instructor_tool_type_edit_url + '&action=edit&typeid=' + toolTypeId, 'edit_tool');
 347                  } else {
 348                      alert(M.util.get_string('cannot_edit', 'lti'));
 349                  }
 350              });
 351  
 352              addIcon.on('click', function(e){
 353                  window.open(self.settings.instructor_tool_type_edit_url + '&action=add', 'add_tool');
 354              });
 355  
 356              deleteIcon.on('click', function(e){
 357                  var toolTypeId = typeSelector.get('value');
 358  
 359                  if(self.getSelectedToolTypeOption().getAttribute('editable')){
 360                      if(confirm(M.util.get_string('delete_confirmation', 'lti'))){
 361                          self.deleteTool(toolTypeId);
 362                      }
 363                  } else {
 364                      alert(M.util.get_string('cannot_delete', 'lti'));
 365                  }
 366              });
 367  
 368              typeSelector.insert(addIcon, 'after');
 369              addIcon.insert(editIcon, 'after');
 370              editIcon.insert(deleteIcon, 'after');
 371          },
 372  
 373          toggleEditButtons: function(){
 374              var lti_edit_tool_type = Y.one('#lti_edit_tool_type');
 375              var lti_delete_tool_type = Y.one('#lti_delete_tool_type');
 376  
 377              // Make the edit / delete icons look enabled / disabled.
 378              // Does not work in older browsers, but alerts will catch those cases.
 379              if(this.getSelectedToolTypeOption().getAttribute('editable')){
 380                  lti_edit_tool_type.setStyle('opacity', '1');
 381                  lti_delete_tool_type.setStyle('opacity', '1');
 382              } else {
 383                  lti_edit_tool_type.setStyle('opacity', '.2');
 384                  lti_delete_tool_type.setStyle('opacity', '.2');
 385              }
 386          },
 387  
 388          addToolType: function(toolType){
 389              var typeSelector = Y.one('#id_typeid');
 390              var course_tool_group = Y.one('#course_tool_group');
 391  
 392              var option = Y.Node.create('<option />')
 393                              .set('text', toolType.name)
 394                              .set('value', toolType.id)
 395                              .set('selected', 'selected')
 396                              .setAttribute('editable', '1')
 397                              .setAttribute('courseTool', '1')
 398                              .setAttribute('domain', toolType.tooldomain);
 399  
 400              if(course_tool_group){
 401                  course_tool_group.append(option);
 402              } else {
 403                  typeSelector.append(option);
 404              }
 405  
 406              // Adding the new tool may affect which tool gets matched automatically
 407              this.clearToolCache();
 408              this.updateAutomaticToolMatch(Y.one('#id_toolurl'));
 409              this.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
 410              this.toggleEditButtons();
 411  
 412              require(["core/notification"], function (notification) {
 413                  notification.addNotification({
 414                      message: M.util.get_string('tooltypeadded', 'lti'),
 415                      type: "success"
 416                  });
 417              });
 418          },
 419  
 420          updateToolType: function(toolType){
 421              var typeSelector = Y.one('#id_typeid');
 422  
 423              var option = typeSelector.one('option[value="' + toolType.id + '"]');
 424              option.set('text', toolType.name)
 425                    .set('domain', toolType.tooldomain);
 426  
 427              // Editing the tool may affect which tool gets matched automatically
 428              this.clearToolCache();
 429              this.updateAutomaticToolMatch(Y.one('#id_toolurl'));
 430              this.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
 431  
 432              require(["core/notification"], function (notification) {
 433                  notification.addNotification({
 434                      message: M.util.get_string('tooltypeupdated', 'lti'),
 435                      type: "success"
 436                  });
 437              });
 438          },
 439  
 440          deleteTool: function(toolTypeId){
 441              var self = this;
 442  
 443              Y.io(self.settings.instructor_tool_type_edit_url + '&action=delete&typeid=' + toolTypeId, {
 444                  on: {
 445                      success: function(){
 446                          self.getSelectedToolTypeOption().remove();
 447  
 448                          // Editing the tool may affect which tool gets matched automatically
 449                          self.clearToolCache();
 450                          self.updateAutomaticToolMatch(Y.one('#id_toolurl'));
 451                          self.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
 452  
 453                          require(["core/notification"], function (notification) {
 454                              notification.addNotification({
 455                                  message: M.util.get_string('tooltypedeleted', 'lti'),
 456                                  type: "success"
 457                              });
 458                          });
 459                      },
 460                      failure: function(){
 461                          require(["core/notification"], function (notification) {
 462                              notification.addNotification({
 463                                  message: M.util.get_string('tooltypenotdeleted', 'lti'),
 464                                  type: "problem"
 465                              });
 466                          });
 467                      }
 468                  }
 469              });
 470          },
 471  
 472          findToolByUrl: function(url, toolId, callback){
 473              var self = this;
 474  
 475              Y.io(self.settings.ajax_url, {
 476                  data: {action: 'find_tool_config',
 477                          course: self.settings.courseId,
 478                          toolurl: url,
 479                          toolid: toolId || 0
 480                  },
 481  
 482                  on: {
 483                      success: function(transactionid, xhr){
 484                          var response = xhr.response;
 485  
 486                          var toolInfo = Y.JSON.parse(response);
 487  
 488                          callback(toolInfo);
 489                      },
 490                      failure: function(){
 491  
 492                      }
 493                  }
 494              });
 495          }
 496  
 497      };
 498  })();


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1