[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/mod/quiz/yui/src/util/js/ -> slot.js (source)

   1  /**
   2   * A collection of utility classes for use with slots.
   3   *
   4   * @module moodle-mod_quiz-util
   5   * @submodule moodle-mod_quiz-util-slot
   6   */
   7  
   8  Y.namespace('Moodle.mod_quiz.util.slot');
   9  
  10  /**
  11   * A collection of utility classes for use with slots.
  12   *
  13   * @class Moodle.mod_quiz.util.slot
  14   * @static
  15   */
  16  Y.Moodle.mod_quiz.util.slot = {
  17      CSS: {
  18          SLOT: 'slot',
  19          QUESTIONTYPEDESCRIPTION: 'qtype_description',
  20          CANNOT_DEPEND: 'question_dependency_cannot_depend'
  21      },
  22      CONSTANTS: {
  23          SLOTIDPREFIX: 'slot-',
  24          QUESTION: M.util.get_string('question', 'moodle')
  25      },
  26      SELECTORS: {
  27          SLOT: 'li.slot',
  28          INSTANCENAME: '.instancename',
  29          NUMBER: 'span.slotnumber',
  30          PAGECONTENT: 'div#page-content',
  31          PAGEBREAK: 'span.page_split_join_wrapper',
  32          ICON: 'img.smallicon',
  33          QUESTIONTYPEDESCRIPTION: '.qtype_description',
  34          SECTIONUL: 'ul.section',
  35          DEPENDENCY_WRAPPER: '.question_dependency_wrapper',
  36          DEPENDENCY_LINK: '.question_dependency_wrapper .cm-edit-action',
  37          DEPENDENCY_ICON: '.question_dependency_wrapper img'
  38      },
  39  
  40      /**
  41       * Retrieve the slot item from one of it's child Nodes.
  42       *
  43       * @method getSlotFromComponent
  44       * @param slotcomponent {Node} The component Node.
  45       * @return {Node|null} The Slot Node.
  46       */
  47      getSlotFromComponent: function(slotcomponent) {
  48          return Y.one(slotcomponent).ancestor(this.SELECTORS.SLOT, true);
  49      },
  50  
  51      /**
  52       * Determines the slot ID for the provided slot.
  53       *
  54       * @method getId
  55       * @param slot {Node} The slot to find an ID for.
  56       * @return {Number|false} The ID of the slot in question or false if no ID was found.
  57       */
  58      getId: function(slot) {
  59          // We perform a simple substitution operation to get the ID.
  60          var id = slot.get('id').replace(
  61                  this.CONSTANTS.SLOTIDPREFIX, '');
  62  
  63          // Attempt to validate the ID.
  64          id = parseInt(id, 10);
  65          if (typeof id === 'number' && isFinite(id)) {
  66              return id;
  67          }
  68          return false;
  69      },
  70  
  71      /**
  72       * Determines the slot name for the provided slot.
  73       *
  74       * @method getName
  75       * @param slot {Node} The slot to find a name for.
  76       * @return {string|false} The name of the slot in question or false if no ID was found.
  77       */
  78      getName: function(slot) {
  79          var instance = slot.one(this.SELECTORS.INSTANCENAME);
  80          if (instance) {
  81              return instance.get('firstChild').get('data');
  82          }
  83          return null;
  84      },
  85  
  86      /**
  87       * Determines the slot number for the provided slot.
  88       *
  89       * @method getNumber
  90       * @param slot {Node} The slot to find the number for.
  91       * @return {Number|false} The number of the slot in question or false if no number was found.
  92       */
  93      getNumber: function(slot) {
  94          if (!slot) {
  95              return false;
  96          }
  97          // We perform a simple substitution operation to get the number.
  98          var number = slot.one(this.SELECTORS.NUMBER).get('text').replace(
  99                          this.CONSTANTS.QUESTION, '');
 100          // Attempt to validate the ID.
 101          number = parseInt(number, 10);
 102          if (typeof number === 'number' && isFinite(number)) {
 103              return number;
 104          }
 105          return false;
 106      },
 107  
 108      /**
 109       * Updates the slot number for the provided slot.
 110       *
 111       * @method setNumber
 112       * @param slot {Node} The slot to update the number for.
 113       * @return void
 114       */
 115      setNumber: function(slot, number) {
 116          var numbernode = slot.one(this.SELECTORS.NUMBER);
 117          numbernode.setHTML('<span class="accesshide">' + this.CONSTANTS.QUESTION + '</span> ' + number);
 118      },
 119  
 120      /**
 121       * Returns a list of all slot elements on the page.
 122       *
 123       * @method getSlots
 124       * @return {node[]} An array containing slot nodes.
 125       */
 126      getSlots: function() {
 127          return Y.all(this.SELECTORS.PAGECONTENT + ' ' + this.SELECTORS.SECTIONUL + ' ' + this.SELECTORS.SLOT);
 128      },
 129  
 130      /**
 131       * Returns a list of all slot elements on the page that have numbers. Excudes description questions.
 132       *
 133       * @method getSlots
 134       * @return {node[]} An array containing slot nodes.
 135       */
 136      getNumberedSlots: function() {
 137          var selector = this.SELECTORS.PAGECONTENT + ' ' + this.SELECTORS.SECTIONUL;
 138              selector += ' ' + this.SELECTORS.SLOT + ':not(' + this.SELECTORS.QUESTIONTYPEDESCRIPTION + ')';
 139          return Y.all(selector);
 140      },
 141  
 142      /**
 143       * Returns the previous slot to the given slot.
 144       *
 145       * @method getPrevious
 146       * @param slot Slot node
 147       * @return {node|false} The previous slot node or false.
 148       */
 149      getPrevious: function(slot) {
 150          return slot.previous(this.SELECTORS.SLOT);
 151      },
 152  
 153      /**
 154       * Returns the previous numbered slot to the given slot.
 155       *
 156       * Ignores slots containing description question types.
 157       *
 158       * @method getPrevious
 159       * @param slot Slot node
 160       * @return {node|false} The previous slot node or false.
 161       */
 162      getPreviousNumbered: function(slot) {
 163          var previous = slot.previous(this.SELECTORS.SLOT + ':not(' + this.SELECTORS.QUESTIONTYPEDESCRIPTION + ')');
 164          if (previous) {
 165              return previous;
 166          }
 167  
 168          var section = slot.ancestor('li.section').previous('li.section');
 169          while (section) {
 170              var questions = section.all(this.SELECTORS.SLOT + ':not(' + this.SELECTORS.QUESTIONTYPEDESCRIPTION + ')');
 171              if (questions.size() > 0) {
 172                  return questions.item(questions.size() - 1);
 173              }
 174              section = section.previous('li.section');
 175          }
 176          return false;
 177      },
 178  
 179      /**
 180       * Reset the order of the numbers given to each slot.
 181       *
 182       * @method reorderSlots
 183       * @return void
 184       */
 185      reorderSlots: function() {
 186          // Get list of slot nodes.
 187          var slots = this.getSlots();
 188          // Loop through slots incrementing the number each time.
 189          slots.each(function(slot) {
 190  
 191              if (!Y.Moodle.mod_quiz.util.page.getPageFromSlot(slot)) {
 192                  // Move the next page to the front.
 193                  var nextpage = slot.next(Y.Moodle.mod_quiz.util.page.SELECTORS.PAGE);
 194                  slot.swap(nextpage);
 195              }
 196  
 197              var previousSlot = this.getPreviousNumbered(slot),
 198                  previousslotnumber = 0;
 199              if (slot.hasClass(this.CSS.QUESTIONTYPEDESCRIPTION)) {
 200                  return;
 201              }
 202  
 203              if (previousSlot) {
 204                  previousslotnumber = this.getNumber(previousSlot);
 205              }
 206  
 207              // Set slot number.
 208              this.setNumber(slot, previousslotnumber + 1);
 209          }, this);
 210      },
 211  
 212      /**
 213       * Add class only-has-one-slot to those sections that need it.
 214       *
 215       * @method updateOneSlotSections
 216       * @return void
 217       */
 218      updateOneSlotSections: function() {
 219          Y.all('.mod-quiz-edit-content ul.slots li.section').each(function(section) {
 220              if (section.all(this.SELECTORS.SLOT).size() > 1) {
 221                  section.removeClass('only-has-one-slot');
 222              } else {
 223                  section.addClass('only-has-one-slot');
 224              }
 225          }, this);
 226      },
 227  
 228      /**
 229       * Remove a slot and related elements from the list of slots.
 230       *
 231       * @method remove
 232       * @param slot Slot node
 233       * @return void
 234       */
 235      remove: function(slot) {
 236          var page = Y.Moodle.mod_quiz.util.page.getPageFromSlot(slot);
 237          slot.remove();
 238          // Is the page empty.
 239          if (!Y.Moodle.mod_quiz.util.page.isEmpty(page)) {
 240              return;
 241          }
 242          // If so remove it. Including add menu and page break.
 243          Y.Moodle.mod_quiz.util.page.remove(page);
 244      },
 245  
 246      /**
 247       * Returns a list of all page break elements on the page.
 248       *
 249       * @method getPageBreaks
 250       * @return {node[]} An array containing page break nodes.
 251       */
 252      getPageBreaks: function() {
 253          var selector = this.SELECTORS.PAGECONTENT + ' ' + this.SELECTORS.SECTIONUL;
 254              selector += ' ' + this.SELECTORS.SLOT + this.SELECTORS.PAGEBREAK;
 255          return Y.all(selector);
 256      },
 257  
 258      /**
 259       * Retrieve the page break element item from the given slot.
 260       *
 261       * @method getPageBreak
 262       * @param slot Slot node
 263       * @return {Node|null} The Page Break Node.
 264       */
 265      getPageBreak: function(slot) {
 266          return Y.one(slot).one(this.SELECTORS.PAGEBREAK);
 267      },
 268  
 269      /**
 270       * Add a page break and related elements to the list of slots.
 271       *
 272       * @method addPageBreak
 273       * @param beforenode Int | Node | HTMLElement | String to add
 274       * @return pagebreak PageBreak node
 275       */
 276      addPageBreak: function(slot) {
 277          var nodetext = M.mod_quiz.resource_toolbox.get('config').addpageiconhtml;
 278          nodetext = nodetext.replace('%%SLOT%%', this.getNumber(slot));
 279          var pagebreak = Y.Node.create(nodetext);
 280          slot.one('div').insert(pagebreak, 'after');
 281          return pagebreak;
 282      },
 283  
 284      /**
 285       * Remove a pagebreak from the given slot.
 286       *
 287       * @method removePageBreak
 288       * @param slot Slot node
 289       * @return boolean
 290       */
 291      removePageBreak: function(slot) {
 292          var pagebreak = this.getPageBreak(slot);
 293          if (!pagebreak) {
 294              return false;
 295          }
 296          pagebreak.remove();
 297          return true;
 298      },
 299  
 300      /**
 301       * Reorder each pagebreak by iterating through each related slot.
 302       *
 303       * @method reorderPageBreaks
 304       * @return void
 305       */
 306      reorderPageBreaks: function() {
 307          // Get list of slot nodes.
 308          var slots = this.getSlots();
 309          var slotnumber = 0;
 310          // Loop through slots incrementing the number each time.
 311          slots.each(function(slot, key) {
 312              slotnumber++;
 313              var pagebreak = this.getPageBreak(slot);
 314              var nextitem = slot.next('li.activity');
 315              if (!nextitem) {
 316                  // Last slot in a section. Should not have an icon.
 317                  return;
 318              }
 319  
 320              // No pagebreak and not last slot. Add one.
 321              if (!pagebreak) {
 322                  pagebreak = this.addPageBreak(slot);
 323              }
 324  
 325              // Remove last page break if there is one.
 326              if (pagebreak && key === slots.size() - 1) {
 327                  this.removePageBreak(slot);
 328              }
 329  
 330              // Get page break anchor element.
 331              var pagebreaklink = pagebreak.get('childNodes').item(0);
 332  
 333              // Get the correct title.
 334              var action = '';
 335              var iconname = '';
 336              if (Y.Moodle.mod_quiz.util.page.isPage(nextitem)) {
 337                  action = 'removepagebreak';
 338                  iconname = 'e/remove_page_break';
 339              } else {
 340                  action = 'addpagebreak';
 341                  iconname = 'e/insert_page_break';
 342              }
 343  
 344              // Update the link and image titles
 345              pagebreaklink.set('title', M.util.get_string(action, 'quiz'));
 346              pagebreaklink.setData('action', action);
 347              // Update the image title.
 348              var icon = pagebreaklink.one(this.SELECTORS.ICON);
 349              icon.set('title', M.util.get_string(action, 'quiz'));
 350              icon.set('alt', M.util.get_string(action, 'quiz'));
 351  
 352              // Update the image src.
 353              icon.set('src', M.util.image_url(iconname));
 354  
 355              // Get anchor url parameters as an associative array.
 356              var params = Y.QueryString.parse(pagebreaklink.get('href'));
 357              // Update slot number.
 358              params.slot = slotnumber;
 359              // Create the new url.
 360              var newurl = '';
 361              for (var index in params) {
 362                  if (newurl.length) {
 363                      newurl += "&";
 364                  }
 365                  newurl += index + "=" + params[index];
 366              }
 367              // Update the anchor.
 368              pagebreaklink.set('href', newurl);
 369          }, this);
 370      },
 371  
 372      /**
 373       * Update the dependency icons.
 374       *
 375       * @method updateAllDependencyIcons
 376       * @return void
 377       */
 378      updateAllDependencyIcons: function() {
 379          // Get list of slot nodes.
 380          var slots = this.getSlots(),
 381              slotnumber = 0,
 382              previousslot = null;
 383          // Loop through slots incrementing the number each time.
 384          slots.each(function(slot) {
 385              slotnumber++;
 386  
 387              if (slotnumber == 1 || previousslot.getData('canfinish') === '0') {
 388                  slot.one(this.SELECTORS.DEPENDENCY_WRAPPER).addClass(this.CSS.CANNOT_DEPEND);
 389              } else {
 390                  slot.one(this.SELECTORS.DEPENDENCY_WRAPPER).removeClass(this.CSS.CANNOT_DEPEND);
 391              }
 392              this.updateDependencyIcon(slot, null);
 393  
 394              previousslot = slot;
 395          }, this);
 396      },
 397  
 398      /**
 399       * Update the slot icon to indicate the new requiresprevious state.
 400       *
 401       * @method slot Slot node
 402       * @method requiresprevious Whether this node now requires the previous one.
 403       * @return void
 404       */
 405      updateDependencyIcon: function(slot, requiresprevious) {
 406          var link = slot.one(this.SELECTORS.DEPENDENCY_LINK);
 407          var icon = slot.one(this.SELECTORS.DEPENDENCY_ICON);
 408          var previousSlot = this.getPrevious(slot);
 409          var a = {thisq: this.getNumber(slot)};
 410          if (previousSlot) {
 411              a.previousq = this.getNumber(previousSlot);
 412          }
 413  
 414          if (requiresprevious === null) {
 415              requiresprevious = link.getData('action') === 'removedependency';
 416          }
 417  
 418          if (requiresprevious) {
 419              link.set('title', M.util.get_string('questiondependencyremove', 'quiz', a));
 420              link.setData('action', 'removedependency');
 421              icon.set('alt', M.util.get_string('questiondependsonprevious', 'quiz'));
 422              icon.set('src', M.util.image_url('t/locked', 'moodle'));
 423          } else {
 424              link.set('title', M.util.get_string('questiondependencyadd', 'quiz', a));
 425              link.setData('action', 'adddependency');
 426              icon.set('alt', M.util.get_string('questiondependencyfree', 'quiz'));
 427              icon.set('src', M.util.image_url('t/unlocked', 'moodle'));
 428          }
 429      }
 430  };


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