[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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

   1  /* global TOOLBOX, BODY, SELECTOR, INDENTLIMITS */
   2  
   3  /**
   4   * Resource and activity toolbox class.
   5   *
   6   * This class is responsible for managing AJAX interactions with activities and resources
   7   * when viewing a course in editing mode.
   8   *
   9   * @module moodle-course-toolboxes
  10   * @namespace M.course.toolboxes
  11   */
  12  
  13  /**
  14   * Resource and activity toolbox class.
  15   *
  16   * This is a class extending TOOLBOX containing code specific to resources
  17   *
  18   * This class is responsible for managing AJAX interactions with activities and resources
  19   * when viewing a course in editing mode.
  20   *
  21   * @class resources
  22   * @constructor
  23   * @extends M.course.toolboxes.toolbox
  24   */
  25  var RESOURCETOOLBOX = function() {
  26      RESOURCETOOLBOX.superclass.constructor.apply(this, arguments);
  27  };
  28  
  29  Y.extend(RESOURCETOOLBOX, TOOLBOX, {
  30      /**
  31       * No groups are being used.
  32       *
  33       * @property GROUPS_NONE
  34       * @protected
  35       * @type Number
  36       */
  37      GROUPS_NONE: 0,
  38  
  39      /**
  40       * Separate groups are being used.
  41       *
  42       * @property GROUPS_SEPARATE
  43       * @protected
  44       * @type Number
  45       */
  46      GROUPS_SEPARATE: 1,
  47  
  48      /**
  49       * Visible groups are being used.
  50       *
  51       * @property GROUPS_VISIBLE
  52       * @protected
  53       * @type Number
  54       */
  55      GROUPS_VISIBLE: 2,
  56  
  57      /**
  58       * Initialize the resource toolbox
  59       *
  60       * For each activity the commands are updated and a reference to the activity is attached.
  61       * This way it doesn't matter where the commands are going to called from they have a reference to the
  62       * activity that they relate to.
  63       * This is essential as some of the actions are displayed in an actionmenu which removes them from the
  64       * page flow.
  65       *
  66       * This function also creates a single event delegate to manage all AJAX actions for all activities on
  67       * the page.
  68       *
  69       * @method initializer
  70       * @protected
  71       */
  72      initializer: function() {
  73          M.course.coursebase.register_module(this);
  74          BODY.delegate('key', this.handle_data_action, 'down:enter', SELECTOR.ACTIVITYACTION, this);
  75          Y.delegate('click', this.handle_data_action, BODY, SELECTOR.ACTIVITYACTION, this);
  76      },
  77  
  78      /**
  79       * Handles the delegation event. When this is fired someone has triggered an action.
  80       *
  81       * Note not all actions will result in an AJAX enhancement.
  82       *
  83       * @protected
  84       * @method handle_data_action
  85       * @param {EventFacade} ev The event that was triggered.
  86       * @return {boolean}
  87       */
  88      handle_data_action: function(ev) {
  89          // We need to get the anchor element that triggered this event.
  90          var node = ev.target;
  91          if (!node.test('a')) {
  92              node = node.ancestor(SELECTOR.ACTIVITYACTION);
  93          }
  94  
  95          // From the anchor we can get both the activity (added during initialisation) and the action being
  96          // performed (added by the UI as a data attribute).
  97          var action = node.getData('action'),
  98              activity = node.ancestor(SELECTOR.ACTIVITYLI);
  99  
 100          if (!node.test('a') || !action || !activity) {
 101              // It wasn't a valid action node.
 102              return;
 103          }
 104  
 105          // Switch based upon the action and do the desired thing.
 106          switch (action) {
 107              case 'moveleft':
 108              case 'moveright':
 109                  // The user changing the indent of the activity.
 110                  this.change_indent(ev, node, activity, action);
 111                  break;
 112              case 'delete':
 113                  // The user is deleting the activity.
 114                  this.delete_with_confirmation(ev, node, activity, action);
 115                  break;
 116              case 'duplicate':
 117                  // The user is duplicating the activity.
 118                  this.duplicate(ev, node, activity, action);
 119                  break;
 120              case 'hide':
 121              case 'show':
 122                  // The user is changing the visibility of the activity.
 123                  this.change_visibility(ev, node, activity, action);
 124                  break;
 125              case 'groupsseparate':
 126              case 'groupsvisible':
 127              case 'groupsnone':
 128                  // The user is changing the group mode.
 129                  this.change_groupmode(ev, node, activity, action);
 130                  break;
 131              case 'move':
 132              case 'update':
 133              case 'assignroles':
 134                  break;
 135              default:
 136                  // Nothing to do here!
 137                  break;
 138          }
 139      },
 140  
 141      /**
 142       * Add a loading icon to the specified activity.
 143       *
 144       * The icon is added within the action area.
 145       *
 146       * @method add_spinner
 147       * @param {Node} activity The activity to add a loading icon to
 148       * @return {Node|null} The newly created icon, or null if the action area was not found.
 149       */
 150      add_spinner: function(activity) {
 151          var actionarea = activity.one(SELECTOR.ACTIONAREA);
 152          if (actionarea) {
 153              return M.util.add_spinner(Y, actionarea);
 154          }
 155          return null;
 156      },
 157  
 158      /**
 159       * Change the indent of the activity or resource.
 160       *
 161       * @method change_indent
 162       * @protected
 163       * @param {EventFacade} ev The event that was fired.
 164       * @param {Node} button The button that triggered this action.
 165       * @param {Node} activity The activity node that this action will be performed on.
 166       * @param {String} action The action that has been requested. Will be 'moveleft' or 'moveright'.
 167       */
 168      change_indent: function(ev, button, activity, action) {
 169          // Prevent the default button action
 170          ev.preventDefault();
 171  
 172          var direction = (action === 'moveleft') ? -1 : 1;
 173  
 174          // And we need to determine the current and new indent level
 175          var indentdiv = activity.one(SELECTOR.MODINDENTDIV),
 176              indent = indentdiv.getAttribute('class').match(/mod-indent-(\d{1,})/),
 177              oldindent = 0,
 178              newindent;
 179  
 180          if (indent) {
 181              oldindent = parseInt(indent[1], 10);
 182          }
 183          newindent = oldindent + parseInt(direction, 10);
 184  
 185          if (newindent < INDENTLIMITS.MIN || newindent > INDENTLIMITS.MAX) {
 186              return;
 187          }
 188  
 189          if (indent) {
 190              indentdiv.removeClass(indent[0]);
 191          }
 192  
 193          // Perform the move
 194          indentdiv.addClass(CSS.MODINDENTCOUNT + newindent);
 195          var data = {
 196              'class': 'resource',
 197              'field': 'indent',
 198              'value': newindent,
 199              'id': Y.Moodle.core_course.util.cm.getId(activity)
 200          };
 201          var spinner = this.add_spinner(activity);
 202          this.send_request(data, spinner);
 203  
 204          var remainingmove;
 205  
 206          // Handle removal/addition of the moveleft button.
 207          if (newindent === INDENTLIMITS.MIN) {
 208              button.addClass('hidden');
 209              remainingmove = activity.one('.editing_moveright');
 210          } else if (newindent > INDENTLIMITS.MIN && oldindent === INDENTLIMITS.MIN) {
 211              button.ancestor('.menu').one('[data-action=moveleft]').removeClass('hidden');
 212          }
 213  
 214          if (newindent === INDENTLIMITS.MAX) {
 215              button.addClass('hidden');
 216              remainingmove = activity.one('.editing_moveleft');
 217          } else if (newindent < INDENTLIMITS.MAX && oldindent === INDENTLIMITS.MAX) {
 218              button.ancestor('.menu').one('[data-action=moveright]').removeClass('hidden');
 219          }
 220  
 221          // Handle massive indentation to match non-ajax display
 222          var hashugeclass = indentdiv.hasClass(CSS.MODINDENTHUGE);
 223          if (newindent > 15 && !hashugeclass) {
 224              indentdiv.addClass(CSS.MODINDENTHUGE);
 225          } else if (newindent <= 15 && hashugeclass) {
 226              indentdiv.removeClass(CSS.MODINDENTHUGE);
 227          }
 228  
 229          if (ev.type && ev.type === "key" && remainingmove) {
 230              remainingmove.focus();
 231          }
 232      },
 233  
 234      /**
 235       * Deletes the given activity or resource after confirmation.
 236       *
 237       * @protected
 238       * @method delete_with_confirmation
 239       * @param {EventFacade} ev The event that was fired.
 240       * @param {Node} button The button that triggered this action.
 241       * @param {Node} activity The activity node that this action will be performed on.
 242       * @chainable
 243       */
 244      delete_with_confirmation: function(ev, button, activity) {
 245          // Prevent the default button action
 246          ev.preventDefault();
 247  
 248          // Get the element we're working on
 249          var element = activity,
 250              // Create confirm string (different if element has or does not have name)
 251              confirmstring = '',
 252              plugindata = {
 253                  type: M.util.get_string('pluginname', element.getAttribute('class').match(/modtype_([^\s]*)/)[1])
 254              };
 255          if (Y.Moodle.core_course.util.cm.getName(element) !== null) {
 256              plugindata.name = Y.Moodle.core_course.util.cm.getName(element);
 257              confirmstring = M.util.get_string('deletechecktypename', 'moodle', plugindata);
 258          } else {
 259              confirmstring = M.util.get_string('deletechecktype', 'moodle', plugindata);
 260          }
 261  
 262          // Create the confirmation dialogue.
 263          var confirm = new M.core.confirm({
 264              question: confirmstring,
 265              modal: true,
 266              visible: false
 267          });
 268          confirm.show();
 269  
 270          // If it is confirmed.
 271          confirm.on('complete-yes', function() {
 272  
 273              // Actually remove the element.
 274              element.remove();
 275              var data = {
 276                  'class': 'resource',
 277                  'action': 'DELETE',
 278                  'id': Y.Moodle.core_course.util.cm.getId(element)
 279              };
 280              this.send_request(data);
 281              if (M.core.actionmenu && M.core.actionmenu.instance) {
 282                  M.core.actionmenu.instance.hideMenu(ev);
 283              }
 284  
 285          }, this);
 286  
 287          return this;
 288      },
 289  
 290      /**
 291       * Duplicates the activity.
 292       *
 293       * @method duplicate
 294       * @protected
 295       * @param {EventFacade} ev The event that was fired.
 296       * @param {Node} button The button that triggered this action.
 297       * @param {Node} activity The activity node that this action will be performed on.
 298       * @chainable
 299       */
 300      duplicate: function(ev, button, activity) {
 301          // Prevent the default button action
 302          ev.preventDefault();
 303  
 304          // Get the element we're working on
 305          var element = activity;
 306  
 307          // Add the lightbox.
 308          var section = activity.ancestor(M.course.format.get_section_selector(Y)),
 309              lightbox = M.util.add_lightbox(Y, section).show();
 310  
 311          // Build and send the request.
 312          var data = {
 313              'class': 'resource',
 314              'field': 'duplicate',
 315              'id': Y.Moodle.core_course.util.cm.getId(element),
 316              'sr': button.getData('sr')
 317          };
 318          this.send_request(data, lightbox, function(response) {
 319              var newcm = Y.Node.create(response.fullcontent);
 320  
 321              // Append to the section?
 322              activity.insert(newcm, 'after');
 323              Y.use('moodle-course-coursebase', function() {
 324                  M.course.coursebase.invoke_function('setup_for_resource', newcm);
 325              });
 326              if (M.core.actionmenu && M.core.actionmenu.newDOMNode) {
 327                  M.core.actionmenu.newDOMNode(newcm);
 328              }
 329          });
 330          return this;
 331      },
 332  
 333      /**
 334       * Changes the visibility of this activity or resource.
 335       *
 336       * @method change_visibility
 337       * @protected
 338       * @param {EventFacade} ev The event that was fired.
 339       * @param {Node} button The button that triggered this action.
 340       * @param {Node} activity The activity node that this action will be performed on.
 341       * @param {String} action The action that has been requested.
 342       * @chainable
 343       */
 344      change_visibility: function(ev, button, activity, action) {
 345          // Prevent the default button action
 346          ev.preventDefault();
 347  
 348          // Get the element we're working on
 349          var element = activity;
 350          var value = this.handle_resource_dim(button, activity, action);
 351  
 352          // Send the request
 353          var data = {
 354              'class': 'resource',
 355              'field': 'visible',
 356              'value': value,
 357              'id': Y.Moodle.core_course.util.cm.getId(element)
 358          };
 359          var spinner = this.add_spinner(element);
 360          this.send_request(data, spinner);
 361  
 362          return this;
 363      },
 364  
 365      /**
 366       * Handles the UI aspect of dimming the activity or resource.
 367       *
 368       * @method handle_resource_dim
 369       * @protected
 370       * @param {Node} button The button that triggered the action.
 371       * @param {Node} activity The activity node that this action will be performed on.
 372       * @param {String} action 'show' or 'hide'.
 373       * @return {Number} 1 if we changed to visible, 0 if we were hiding.
 374       */
 375      handle_resource_dim: function(button, activity, action) {
 376          var toggleclass = CSS.DIMCLASS,
 377              dimarea = activity.one([
 378                      SELECTOR.ACTIVITYLINK,
 379                      SELECTOR.CONTENTWITHOUTLINK
 380                  ].join(', ')),
 381              availabilityinfo = activity.one(CSS.AVAILABILITYINFODIV),
 382              nextaction = (action === 'hide') ? 'show' : 'hide',
 383              buttontext = button.one('span'),
 384              newstring = M.util.get_string(nextaction, 'moodle'),
 385              buttonimg = button.one('img');
 386  
 387          // Update button info.
 388          buttonimg.setAttrs({
 389              'src': M.util.image_url('t/' + nextaction)
 390          });
 391  
 392          if (Y.Lang.trim(button.getAttribute('title'))) {
 393              button.setAttribute('title', newstring);
 394          }
 395  
 396          if (Y.Lang.trim(buttonimg.getAttribute('alt'))) {
 397              buttonimg.setAttribute('alt', newstring);
 398          }
 399  
 400          button.replaceClass('editing_' + action, 'editing_' + nextaction);
 401          button.setData('action', nextaction);
 402          if (buttontext) {
 403              buttontext.set('text', newstring);
 404          }
 405  
 406          if (activity.one(SELECTOR.CONTENTWITHOUTLINK)) {
 407              dimarea = activity.one(SELECTOR.CONTENTWITHOUTLINK);
 408              toggleclass = CSS.DIMMEDTEXT;
 409          }
 410  
 411          // If activity is conditionally hidden, then don't toggle.
 412          if (!dimarea.hasClass(CSS.CONDITIONALHIDDEN)) {
 413              if (action === 'hide') {
 414                  // Change the UI.
 415                  dimarea.addClass(toggleclass);
 416                  // We need to toggle dimming on the description too.
 417                  activity.all(SELECTOR.CONTENTAFTERLINK).addClass(CSS.DIMMEDTEXT);
 418                  activity.all(SELECTOR.GROUPINGLABEL).addClass(CSS.DIMMEDTEXT);
 419              } else {
 420                  // Change the UI.
 421                  dimarea.removeClass(toggleclass);
 422                  // We need to toggle dimming on the description too.
 423                  activity.all(SELECTOR.CONTENTAFTERLINK).removeClass(CSS.DIMMEDTEXT);
 424                  activity.all(SELECTOR.GROUPINGLABEL).removeClass(CSS.DIMMEDTEXT);
 425              }
 426          }
 427          // Toggle availablity info for conditional activities.
 428          if (availabilityinfo) {
 429              availabilityinfo.toggleClass(CSS.HIDE);
 430          }
 431          return (action === 'hide') ? 0 : 1;
 432      },
 433  
 434      /**
 435       * Changes the groupmode of the activity to the next groupmode in the sequence.
 436       *
 437       * @method change_groupmode
 438       * @protected
 439       * @param {EventFacade} ev The event that was fired.
 440       * @param {Node} button The button that triggered this action.
 441       * @param {Node} activity The activity node that this action will be performed on.
 442       * @chainable
 443       */
 444      change_groupmode: function(ev, button, activity) {
 445          // Prevent the default button action.
 446          ev.preventDefault();
 447  
 448          // Current Mode
 449          var groupmode = parseInt(button.getData('nextgroupmode'), 10),
 450              newtitle = '',
 451              iconsrc = '',
 452              newtitlestr,
 453              data,
 454              spinner,
 455              nextgroupmode = groupmode + 1,
 456              buttonimg = button.one('img');
 457  
 458          if (nextgroupmode > 2) {
 459              nextgroupmode = 0;
 460          }
 461  
 462          if (groupmode === this.GROUPS_NONE) {
 463              newtitle = 'groupsnone';
 464              iconsrc = M.util.image_url('i/groupn', 'moodle');
 465          } else if (groupmode === this.GROUPS_SEPARATE) {
 466              newtitle = 'groupsseparate';
 467              iconsrc = M.util.image_url('i/groups', 'moodle');
 468          } else if (groupmode === this.GROUPS_VISIBLE) {
 469              newtitle = 'groupsvisible';
 470              iconsrc = M.util.image_url('i/groupv', 'moodle');
 471          }
 472          newtitlestr = M.util.get_string('clicktochangeinbrackets', 'moodle', M.util.get_string(newtitle, 'moodle'));
 473  
 474          // Change the UI
 475          var oldAction = button.getData('action');
 476          button.replaceClass('editing_' + oldAction, 'editing_' + newtitle);
 477          buttonimg.setAttrs({
 478              'src': iconsrc
 479          });
 480          if (Y.Lang.trim(button.getAttribute('title'))) {
 481              button.setAttribute('title', newtitlestr).setData('action', newtitle).setData('nextgroupmode', nextgroupmode);
 482          }
 483  
 484          if (Y.Lang.trim(buttonimg.getAttribute('alt'))) {
 485              buttonimg.setAttribute('alt', newtitlestr);
 486          }
 487  
 488          // And send the request
 489          data = {
 490              'class': 'resource',
 491              'field': 'groupmode',
 492              'value': groupmode,
 493              'id': Y.Moodle.core_course.util.cm.getId(activity)
 494          };
 495  
 496          spinner = this.add_spinner(activity);
 497          this.send_request(data, spinner);
 498          return this;
 499      },
 500  
 501      /**
 502       * Set the visibility of the specified resource to match the visible parameter.
 503       *
 504       * Note: This is not a toggle function and only changes the visibility
 505       * in the browser (no ajax update is performed).
 506       *
 507       * @method set_visibility_resource_ui
 508       * @param {object} args An object containing the required information to trigger a change.
 509       * @param {Node} args.element The resource to toggle
 510       * @param {Boolean} args.visible The target visibility
 511       */
 512      set_visibility_resource_ui: function(args) {
 513          var element = args.element,
 514              buttonnode = element.one(SELECTOR.HIDE),
 515              // By default we assume that the item is visible and we're going to hide it.
 516              currentVisibility = true,
 517              targetVisibility = false;
 518  
 519          if (!buttonnode) {
 520              // If the buttonnode was not found, try to find the HIDE button
 521              // and change the target visibility setting to false.
 522              buttonnode = element.one(SELECTOR.SHOW);
 523              currentVisibility = false;
 524              targetVisibility = true;
 525          }
 526  
 527          if (typeof args.visible !== 'undefined') {
 528              // If we were provided with a visibility argument, use that instead.
 529              targetVisibility = args.visible;
 530          }
 531  
 532          // Only trigger a change if necessary.
 533          if (currentVisibility !== targetVisibility) {
 534              var action = 'hide';
 535              if (targetVisibility) {
 536                  action = 'show';
 537              }
 538  
 539              this.handle_resource_dim(buttonnode, element, action);
 540          }
 541      }
 542  }, {
 543      NAME: 'course-resource-toolbox',
 544      ATTRS: {
 545      }
 546  });
 547  
 548  M.course.resource_toolbox = null;
 549  M.course.init_resource_toolbox = function(config) {
 550      M.course.resource_toolbox = new RESOURCETOOLBOX(config);
 551      return M.course.resource_toolbox;
 552  };


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