[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/mod/quiz/yui/src/toolboxes/js/ -> resource.js (source)

   1  /**
   2   * Resource and activity toolbox class.
   3   *
   4   * This class is responsible for managing AJAX interactions with activities and resources
   5   * when viewing a quiz in editing mode.
   6   *
   7   * @module mod_quiz-resource-toolbox
   8   * @namespace M.mod_quiz.resource_toolbox
   9   */
  10  
  11  /**
  12   * Resource and activity toolbox class.
  13   *
  14   * This is a class extending TOOLBOX containing code specific to resources
  15   *
  16   * This class is responsible for managing AJAX interactions with activities and resources
  17   * when viewing a quiz in editing mode.
  18   *
  19   * @class resources
  20   * @constructor
  21   * @extends M.course.toolboxes.toolbox
  22   */
  23  var RESOURCETOOLBOX = function() {
  24      RESOURCETOOLBOX.superclass.constructor.apply(this, arguments);
  25  };
  26  
  27  Y.extend(RESOURCETOOLBOX, TOOLBOX, {
  28      /**
  29       * An Array of events added when editing a max mark field.
  30       * These should all be detached when editing is complete.
  31       *
  32       * @property editmaxmarkevents
  33       * @protected
  34       * @type Array
  35       * @protected
  36       */
  37      editmaxmarkevents: [],
  38  
  39      /**
  40       *
  41       */
  42      NODE_PAGE: 1,
  43      NODE_SLOT: 2,
  44      NODE_JOIN: 3,
  45  
  46      /**
  47       * Initialize the resource toolbox
  48       *
  49       * For each activity the commands are updated and a reference to the activity is attached.
  50       * This way it doesn't matter where the commands are going to called from they have a reference to the
  51       * activity that they relate to.
  52       * This is essential as some of the actions are displayed in an actionmenu which removes them from the
  53       * page flow.
  54       *
  55       * This function also creates a single event delegate to manage all AJAX actions for all activities on
  56       * the page.
  57       *
  58       * @method initializer
  59       * @protected
  60       */
  61      initializer: function() {
  62          M.mod_quiz.quizbase.register_module(this);
  63          BODY.delegate('key', this.handle_data_action, 'down:enter', SELECTOR.ACTIVITYACTION, this);
  64          Y.delegate('click', this.handle_data_action, BODY, SELECTOR.ACTIVITYACTION, this);
  65      },
  66  
  67      /**
  68       * Handles the delegation event. When this is fired someone has triggered an action.
  69       *
  70       * Note not all actions will result in an AJAX enhancement.
  71       *
  72       * @protected
  73       * @method handle_data_action
  74       * @param {EventFacade} ev The event that was triggered.
  75       * @returns {boolean}
  76       */
  77      handle_data_action: function(ev) {
  78          // We need to get the anchor element that triggered this event.
  79          var node = ev.target;
  80          if (!node.test('a')) {
  81              node = node.ancestor(SELECTOR.ACTIVITYACTION);
  82          }
  83  
  84          // From the anchor we can get both the activity (added during initialisation) and the action being
  85          // performed (added by the UI as a data attribute).
  86          var action = node.getData('action'),
  87              activity = node.ancestor(SELECTOR.ACTIVITYLI);
  88  
  89          if (!node.test('a') || !action || !activity) {
  90              // It wasn't a valid action node.
  91              return;
  92          }
  93  
  94          // Switch based upon the action and do the desired thing.
  95          switch (action) {
  96              case 'editmaxmark':
  97                  // The user wishes to edit the maxmark of the resource.
  98                  this.edit_maxmark(ev, node, activity, action);
  99                  break;
 100              case 'delete':
 101                  // The user is deleting the activity.
 102                  this.delete_with_confirmation(ev, node, activity, action);
 103                  break;
 104              case 'addpagebreak':
 105              case 'removepagebreak':
 106                  // The user is adding or removing a page break.
 107                  this.update_page_break(ev, node, activity, action);
 108                  break;
 109              default:
 110                  // Nothing to do here!
 111                  break;
 112          }
 113      },
 114  
 115      /**
 116       * Add a loading icon to the specified activity.
 117       *
 118       * The icon is added within the action area.
 119       *
 120       * @method add_spinner
 121       * @param {Node} activity The activity to add a loading icon to
 122       * @return {Node|null} The newly created icon, or null if the action area was not found.
 123       */
 124      add_spinner: function(activity) {
 125          var actionarea = activity.one(SELECTOR.ACTIONAREA);
 126          if (actionarea) {
 127              return M.util.add_spinner(Y, actionarea);
 128          }
 129          return null;
 130      },
 131  
 132      /**
 133       * Deletes the given activity or resource after confirmation.
 134       *
 135       * @protected
 136       * @method delete_with_confirmation
 137       * @param {EventFacade} ev The event that was fired.
 138       * @param {Node} button The button that triggered this action.
 139       * @param {Node} activity The activity node that this action will be performed on.
 140       * @chainable
 141       */
 142      delete_with_confirmation: function(ev, button, activity) {
 143          // Prevent the default button action.
 144          ev.preventDefault();
 145  
 146          // Get the element we're working on.
 147          var element   = activity,
 148              // Create confirm string (different if element has or does not have name)
 149              confirmstring = '',
 150              qtypename = M.util.get_string('pluginname',
 151                          'qtype_' + element.getAttribute('class').match(/qtype_([^\s]*)/)[1]);
 152          confirmstring = M.util.get_string('confirmremovequestion', 'quiz', qtypename);
 153  
 154          // Create the confirmation dialogue.
 155          var confirm = new M.core.confirm({
 156              question: confirmstring,
 157              modal: true
 158          });
 159  
 160          // If it is confirmed.
 161          confirm.on('complete-yes', function() {
 162  
 163              var spinner = this.add_spinner(element);
 164              var data = {
 165                  'class': 'resource',
 166                  'action': 'DELETE',
 167                  'id': Y.Moodle.mod_quiz.util.slot.getId(element)
 168              };
 169              this.send_request(data, spinner, function(response) {
 170                  if (response.deleted) {
 171                      // Actually remove the element.
 172                      Y.Moodle.mod_quiz.util.slot.remove(element);
 173                      this.reorganise_edit_page();
 174                      if (M.core.actionmenu && M.core.actionmenu.instance) {
 175                          M.core.actionmenu.instance.hideMenu();
 176                      }
 177                  } else {
 178                      window.location.reload(true);
 179                  }
 180              });
 181  
 182          }, this);
 183  
 184          return this;
 185      },
 186  
 187  
 188      /**
 189       * Edit the maxmark for the resource
 190       *
 191       * @protected
 192       * @method edit_maxmark
 193       * @param {EventFacade} ev The event that was fired.
 194       * @param {Node} button The button that triggered this action.
 195       * @param {Node} activity The activity node that this action will be performed on.
 196       * @param {String} action The action that has been requested.
 197       * @return Boolean
 198       */
 199      edit_maxmark : function(ev, button, activity) {
 200          // Get the element we're working on
 201          var activityid = Y.Moodle.mod_quiz.util.slot.getId(activity),
 202              instancemaxmark  = activity.one(SELECTOR.INSTANCEMAXMARK),
 203              instance = activity.one(SELECTOR.ACTIVITYINSTANCE),
 204              currentmaxmark = instancemaxmark.get('firstChild'),
 205              oldmaxmark = currentmaxmark.get('data'),
 206              maxmarktext = oldmaxmark,
 207              thisevent,
 208              anchor = instancemaxmark,// Grab the anchor so that we can swap it with the edit form.
 209              data = {
 210                  'class'   : 'resource',
 211                  'field'   : 'getmaxmark',
 212                  'id'      : activityid
 213              };
 214  
 215          // Prevent the default actions.
 216          ev.preventDefault();
 217  
 218          this.send_request(data, null, function(response) {
 219              if (M.core.actionmenu && M.core.actionmenu.instance) {
 220                  M.core.actionmenu.instance.hideMenu();
 221              }
 222  
 223              // Try to retrieve the existing string from the server.
 224              if (response.instancemaxmark) {
 225                  maxmarktext = response.instancemaxmark;
 226              }
 227  
 228              // Create the editor and submit button.
 229              var editform = Y.Node.create('<form action="#" />');
 230              var editinstructions = Y.Node.create('<span class="' + CSS.EDITINSTRUCTIONS + '" id="id_editinstructions" />')
 231                  .set('innerHTML', M.util.get_string('edittitleinstructions', 'moodle'));
 232              var editor = Y.Node.create('<input name="maxmark" type="text" class="' + CSS.TITLEEDITOR + '" />').setAttrs({
 233                  'value' : maxmarktext,
 234                  'autocomplete' : 'off',
 235                  'aria-describedby' : 'id_editinstructions',
 236                  'maxLength' : '12',
 237                  'size' : parseInt(this.get('config').questiondecimalpoints, 10) + 2
 238              });
 239  
 240              // Clear the existing content and put the editor in.
 241              editform.appendChild(editor);
 242              editform.setData('anchor', anchor);
 243              instance.insert(editinstructions, 'before');
 244              anchor.replace(editform);
 245  
 246              // Force the editing instruction to match the mod-indent position.
 247              var padside = 'left';
 248              if (right_to_left()) {
 249                  padside = 'right';
 250              }
 251  
 252              // We hide various components whilst editing:
 253              activity.addClass(CSS.EDITINGMAXMARK);
 254  
 255              // Focus and select the editor text.
 256              editor.focus().select();
 257  
 258              // Cancel the edit if we lose focus or the escape key is pressed.
 259              thisevent = editor.on('blur', this.edit_maxmark_cancel, this, activity, false);
 260              this.editmaxmarkevents.push(thisevent);
 261              thisevent = editor.on('key', this.edit_maxmark_cancel, 'esc', this, activity, true);
 262              this.editmaxmarkevents.push(thisevent);
 263  
 264              // Handle form submission.
 265              thisevent = editform.on('submit', this.edit_maxmark_submit, this, activity, oldmaxmark);
 266              this.editmaxmarkevents.push(thisevent);
 267          });
 268      },
 269  
 270      /**
 271       * Handles the submit event when editing the activity or resources maxmark.
 272       *
 273       * @protected
 274       * @method edit_maxmark_submit
 275       * @param {EventFacade} ev The event that triggered this.
 276       * @param {Node} activity The activity whose maxmark we are altering.
 277       * @param {String} originalmaxmark The original maxmark the activity or resource had.
 278       */
 279      edit_maxmark_submit : function(ev, activity, originalmaxmark) {
 280          // We don't actually want to submit anything.
 281          ev.preventDefault();
 282          var newmaxmark = Y.Lang.trim(activity.one(SELECTOR.ACTIVITYFORM + ' ' + SELECTOR.ACTIVITYMAXMARK).get('value'));
 283          var spinner = this.add_spinner(activity);
 284          this.edit_maxmark_clear(activity);
 285          activity.one(SELECTOR.INSTANCEMAXMARK).setContent(newmaxmark);
 286          if (newmaxmark !== null && newmaxmark !== "" && newmaxmark !== originalmaxmark) {
 287              var data = {
 288                  'class'   : 'resource',
 289                  'field'   : 'updatemaxmark',
 290                  'maxmark'   : newmaxmark,
 291                  'id'      : Y.Moodle.mod_quiz.util.slot.getId(activity)
 292              };
 293              this.send_request(data, spinner, function(response) {
 294                  if (response.instancemaxmark) {
 295                      activity.one(SELECTOR.INSTANCEMAXMARK).setContent(response.instancemaxmark);
 296                  }
 297              });
 298          }
 299      },
 300  
 301      /**
 302       * Handles the cancel event when editing the activity or resources maxmark.
 303       *
 304       * @protected
 305       * @method edit_maxmark_cancel
 306       * @param {EventFacade} ev The event that triggered this.
 307       * @param {Node} activity The activity whose maxmark we are altering.
 308       * @param {Boolean} preventdefault If true we should prevent the default action from occuring.
 309       */
 310      edit_maxmark_cancel : function(ev, activity, preventdefault) {
 311          if (preventdefault) {
 312              ev.preventDefault();
 313          }
 314          this.edit_maxmark_clear(activity);
 315      },
 316  
 317      /**
 318       * Handles clearing the editing UI and returning things to the original state they were in.
 319       *
 320       * @protected
 321       * @method edit_maxmark_clear
 322       * @param {Node} activity  The activity whose maxmark we were altering.
 323       */
 324      edit_maxmark_clear : function(activity) {
 325          // Detach all listen events to prevent duplicate triggers
 326          new Y.EventHandle(this.editmaxmarkevents).detach();
 327  
 328          var editform = activity.one(SELECTOR.ACTIVITYFORM),
 329              instructions = activity.one('#id_editinstructions');
 330          if (editform) {
 331              editform.replace(editform.getData('anchor'));
 332          }
 333          if (instructions) {
 334              instructions.remove();
 335          }
 336  
 337          // Remove the editing class again to revert the display.
 338          activity.removeClass(CSS.EDITINGMAXMARK);
 339  
 340          // Refocus the link which was clicked originally so the user can continue using keyboard nav.
 341          Y.later(100, this, function() {
 342              activity.one(SELECTOR.EDITMAXMARK).focus();
 343          });
 344  
 345          // This hack is to keep Behat happy until they release a version of
 346          // MinkSelenium2Driver that fixes
 347          // https://github.com/Behat/MinkSelenium2Driver/issues/80.
 348          if (!Y.one('input[name=maxmark')) {
 349              Y.one('body').append('<input type="text" name="maxmark" style="display: none">');
 350          }
 351      },
 352  
 353      /**
 354       * Joins or separates the given slot with the page of the previous slot. Reorders the pages of
 355       * the other slots
 356       *
 357       * @protected
 358       * @method update_page_break
 359       * @param {EventFacade} ev The event that was fired.
 360       * @param {Node} button The button that triggered this action.
 361       * @param {Node} activity The activity node that this action will be performed on.
 362       * @chainable
 363       */
 364      update_page_break: function(ev, button, activity, action) {
 365          // Prevent the default button action
 366          ev.preventDefault();
 367  
 368          nextactivity = activity.next('li.activity.slot');
 369          var spinner = this.add_spinner(nextactivity),
 370              slotid = 0;
 371          var value = action === 'removepagebreak' ? 1 : 2;
 372  
 373          var data = {
 374              'class': 'resource',
 375              'field': 'updatepagebreak',
 376              'id':    slotid,
 377              'value': value
 378          };
 379  
 380          slotid = Y.Moodle.mod_quiz.util.slot.getId(nextactivity);
 381          if (slotid) {
 382              data.id = Number(slotid);
 383          }
 384          this.send_request(data, spinner, function(response) {
 385              if (response.slots) {
 386                  if (action === 'addpagebreak') {
 387                      Y.Moodle.mod_quiz.util.page.add(activity);
 388                  } else {
 389                      var page = activity.next(Y.Moodle.mod_quiz.util.page.SELECTORS.PAGE);
 390                      Y.Moodle.mod_quiz.util.page.remove(page, true);
 391                  }
 392                  this.reorganise_edit_page();
 393              } else {
 394                  window.location.reload(true);
 395              }
 396          });
 397  
 398          return this;
 399      },
 400  
 401      /**
 402       * Reorganise the UI after every edit action.
 403       *
 404       * @protected
 405       * @method reorganise_edit_page
 406       */
 407      reorganise_edit_page: function() {
 408          Y.Moodle.mod_quiz.util.slot.reorderSlots();
 409          Y.Moodle.mod_quiz.util.slot.reorderPageBreaks();
 410          Y.Moodle.mod_quiz.util.page.reorderPages();
 411      },
 412  
 413      NAME : 'mod_quiz-resource-toolbox',
 414      ATTRS : {
 415          courseid : {
 416              'value' : 0
 417          },
 418          quizid : {
 419              'value' : 0
 420          }
 421      }
 422  });
 423  
 424  M.mod_quiz.resource_toolbox = null;
 425  M.mod_quiz.init_resource_toolbox = function(config) {
 426      M.mod_quiz.resource_toolbox = new RESOURCETOOLBOX(config);
 427      return M.mod_quiz.resource_toolbox;
 428  };


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