[ Index ]

PHP Cross Reference of moodle-2.8

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.str.lti.using_tool_configuration + 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.str.lti.domain_mismatch);
 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.str.lti.custom_config);
 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.str.lti.using_tool_configuration + 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.str.lti.tool_config_not_found);
 180                      }
 181                  }
 182              };
 183  
 184              // Cache urls which have already been checked to increase performance
 185              // Don't use URL cache if tool type manually selected
 186              if(selectedToolType && self.toolTypeCache[selectedToolType]){
 187                  return continuation(self.toolTypeCache[selectedToolType]);
 188              } else if(self.urlCache[url] && !selectedToolType){
 189                  return continuation(self.urlCache[url]);
 190              } else if(!selectedToolType && !url) {
 191                  // No tool type or url set
 192                  return continuation({}, field);
 193              } else {
 194                  self.findToolByUrl(url, selectedToolType, function(toolInfo){
 195                      if(toolInfo){
 196                          // Cache the result based on whether the URL or tool type was used to look up the tool
 197                          if(!selectedToolType){
 198                              self.urlCache[url] = toolInfo;
 199                          } else {
 200                              self.toolTypeCache[selectedToolType] = toolInfo;
 201                          }
 202  
 203                          Y.one('#id_urlmatchedtypeid').set('value', toolInfo.toolid);
 204  
 205                          continuation(toolInfo);
 206                      }
 207                  });
 208              }
 209          },
 210  
 211          /**
 212           * Updates display of privacy settings to show course / site tool configuration settings.
 213           */
 214          updatePrivacySettings: function(toolInfo){
 215              if(!toolInfo || !toolInfo.toolid){
 216                  toolInfo = {
 217                      sendname: M.mod_lti.LTI_SETTING_DELEGATE,
 218                      sendemailaddr: M.mod_lti.LTI_SETTING_DELEGATE,
 219                      acceptgrades: M.mod_lti.LTI_SETTING_DELEGATE
 220                  }
 221              }
 222  
 223              var setting, control;
 224  
 225              var privacyControls = {
 226                  sendname: Y.one('#id_instructorchoicesendname'),
 227                  sendemailaddr: Y.one('#id_instructorchoicesendemailaddr'),
 228                  acceptgrades: Y.one('#id_instructorchoiceacceptgrades')
 229              };
 230  
 231              // Store a copy of user entered privacy settings as we may overwrite them
 232              if(!this.userPrivacySettings){
 233                  this.userPrivacySettings = {};
 234              }
 235  
 236              for(setting in privacyControls){
 237                  if(privacyControls.hasOwnProperty(setting)){
 238                      control = privacyControls[setting];
 239  
 240                      // Only store the value if it hasn't been forced by the editor
 241                      if(!control.get('disabled')){
 242                          this.userPrivacySettings[setting] = control.get('checked');
 243                      }
 244                  }
 245              }
 246  
 247              // Update UI based on course / site tool configuration
 248              for(setting in privacyControls){
 249                  if(privacyControls.hasOwnProperty(setting)){
 250                      var settingValue = toolInfo[setting];
 251                      control = privacyControls[setting];
 252  
 253                      if(settingValue == M.mod_lti.LTI_SETTING_NEVER){
 254                          control.set('disabled', true);
 255                          control.set('checked', false);
 256                          control.set('title', M.str.lti.forced_help);
 257                      } else if(settingValue == M.mod_lti.LTI_SETTING_ALWAYS){
 258                          control.set('disabled', true);
 259                          control.set('checked', true);
 260                          control.set('title', M.str.lti.forced_help);
 261                      } else if(settingValue == M.mod_lti.LTI_SETTING_DELEGATE){
 262                          control.set('disabled', false);
 263  
 264                          // Get the value out of the stored copy
 265                          control.set('checked', this.userPrivacySettings[setting]);
 266                          control.set('title', '');
 267                      }
 268                  }
 269              }
 270  
 271              this.toggleGradeSection();
 272          },
 273  
 274          getSelectedToolTypeOption: function(){
 275              var typeSelector = Y.one('#id_typeid');
 276  
 277              return typeSelector.one('option[value="' + typeSelector.get('value') + '"]');
 278          },
 279  
 280          /**
 281           * Separate tool listing into option groups. Server-side select control
 282           * doesn't seem to support this.
 283           */
 284          addOptGroups: function(){
 285              var typeSelector = Y.one('#id_typeid');
 286  
 287              if(typeSelector.one('option[courseTool=1]')){
 288                  // One ore more course tools exist
 289  
 290                  var globalGroup = Y.Node.create('<optgroup />')
 291                                      .set('id', 'global_tool_group')
 292                                      .set('label', M.str.lti.global_tool_types);
 293  
 294                  var courseGroup = Y.Node.create('<optgroup />')
 295                                      .set('id', 'course_tool_group')
 296                                      .set('label', M.str.lti.course_tool_types);
 297  
 298                  var globalOptions = typeSelector.all('option[globalTool=1]').remove().each(function(node){
 299                      globalGroup.append(node);
 300                  });
 301  
 302                  var courseOptions = typeSelector.all('option[courseTool=1]').remove().each(function(node){
 303                      courseGroup.append(node);
 304                  });
 305  
 306                  if(globalOptions.size() > 0){
 307                      typeSelector.append(globalGroup);
 308                  }
 309  
 310                  if(courseOptions.size() > 0){
 311                      typeSelector.append(courseGroup);
 312                  }
 313              }
 314          },
 315  
 316          /**
 317           * Adds buttons for creating, editing, and deleting tool types.
 318           * Javascript is a requirement to edit course level tools at this point.
 319           */
 320          createTypeEditorButtons: function(){
 321              var self = this;
 322  
 323              var typeSelector = Y.one('#id_typeid');
 324  
 325              var createIcon = function(id, tooltip, iconUrl){
 326                  return Y.Node.create('<a />')
 327                          .set('id', id)
 328                          .set('title', tooltip)
 329                          .setStyle('margin-left', '.5em')
 330                          .set('href', 'javascript:void(0);')
 331                          .append(Y.Node.create('<img src="' + iconUrl + '" />'));
 332              }
 333  
 334              var addIcon = createIcon('lti_add_tool_type', M.str.lti.addtype, this.settings.add_icon_url);
 335              var editIcon = createIcon('lti_edit_tool_type', M.str.lti.edittype, this.settings.edit_icon_url);
 336              var deleteIcon  = createIcon('lti_delete_tool_type', M.str.lti.deletetype, this.settings.delete_icon_url);
 337  
 338              editIcon.on('click', function(e){
 339                  var toolTypeId = typeSelector.get('value');
 340  
 341                  if(self.getSelectedToolTypeOption().getAttribute('editable')){
 342                      window.open(self.settings.instructor_tool_type_edit_url + '&action=edit&typeid=' + toolTypeId, 'edit_tool');
 343                  } else {
 344                      alert(M.str.lti.cannot_edit);
 345                  }
 346              });
 347  
 348              addIcon.on('click', function(e){
 349                  window.open(self.settings.instructor_tool_type_edit_url + '&action=add', 'add_tool');
 350              });
 351  
 352              deleteIcon.on('click', function(e){
 353                  var toolTypeId = typeSelector.get('value');
 354  
 355                  if(self.getSelectedToolTypeOption().getAttribute('editable')){
 356                      if(confirm(M.str.lti.delete_confirmation)){
 357                          self.deleteTool(toolTypeId);
 358                      }
 359                  } else {
 360                      alert(M.str.lti.cannot_delete);
 361                  }
 362              });
 363  
 364              typeSelector.insert(addIcon, 'after');
 365              addIcon.insert(editIcon, 'after');
 366              editIcon.insert(deleteIcon, 'after');
 367          },
 368  
 369          toggleEditButtons: function(){
 370              var lti_edit_tool_type = Y.one('#lti_edit_tool_type');
 371              var lti_delete_tool_type = Y.one('#lti_delete_tool_type');
 372  
 373              // Make the edit / delete icons look enabled / disabled.
 374              // Does not work in older browsers, but alerts will catch those cases.
 375              if(this.getSelectedToolTypeOption().getAttribute('editable')){
 376                  lti_edit_tool_type.setStyle('opacity', '1');
 377                  lti_delete_tool_type.setStyle('opacity', '1');
 378              } else {
 379                  lti_edit_tool_type.setStyle('opacity', '.2');
 380                  lti_delete_tool_type.setStyle('opacity', '.2');
 381              }
 382          },
 383  
 384          addToolType: function(toolType){
 385              var typeSelector = Y.one('#id_typeid');
 386              var course_tool_group = Y.one('#course_tool_group');
 387  
 388              var option = Y.Node.create('<option />')
 389                              .set('text', toolType.name)
 390                              .set('value', toolType.id)
 391                              .set('selected', 'selected')
 392                              .setAttribute('editable', '1')
 393                              .setAttribute('courseTool', '1')
 394                              .setAttribute('domain', toolType.tooldomain);
 395  
 396              if(course_tool_group){
 397                  course_tool_group.append(option);
 398              } else {
 399                  typeSelector.append(option);
 400              }
 401  
 402              // Adding the new tool may affect which tool gets matched automatically
 403              this.clearToolCache();
 404              this.updateAutomaticToolMatch(Y.one('#id_toolurl'));
 405              this.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
 406          },
 407  
 408          updateToolType: function(toolType){
 409              var typeSelector = Y.one('#id_typeid');
 410  
 411              var option = typeSelector.one('option[value="' + toolType.id + '"]');
 412              option.set('text', toolType.name)
 413                    .set('domain', toolType.tooldomain);
 414  
 415              // Editing the tool may affect which tool gets matched automatically
 416              this.clearToolCache();
 417              this.updateAutomaticToolMatch(Y.one('#id_toolurl'));
 418              this.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
 419          },
 420  
 421          deleteTool: function(toolTypeId){
 422              var self = this;
 423  
 424              Y.io(self.settings.instructor_tool_type_edit_url + '&action=delete&typeid=' + toolTypeId, {
 425                  on: {
 426                      success: function(){
 427                          self.getSelectedToolTypeOption().remove();
 428  
 429                          // Editing the tool may affect which tool gets matched automatically
 430                          self.clearToolCache();
 431                          self.updateAutomaticToolMatch(Y.one('#id_toolurl'));
 432                          self.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
 433                      },
 434                      failure: function(){
 435  
 436                      }
 437                  }
 438              });
 439          },
 440  
 441          findToolByUrl: function(url, toolId, callback){
 442              var self = this;
 443  
 444              Y.io(self.settings.ajax_url, {
 445                  data: {action: 'find_tool_config',
 446                          course: self.settings.courseId,
 447                          toolurl: url,
 448                          toolid: toolId || 0
 449                  },
 450  
 451                  on: {
 452                      success: function(transactionid, xhr){
 453                          var response = xhr.response;
 454  
 455                          var toolInfo = Y.JSON.parse(response);
 456  
 457                          callback(toolInfo);
 458                      },
 459                      failure: function(){
 460  
 461                      }
 462                  }
 463              });
 464          }
 465  
 466      };
 467  })();


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1