[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/course/yui/build/moodle-course-dragdrop/ -> moodle-course-dragdrop.js (source)

   1  YUI.add('moodle-course-dragdrop', function (Y, NAME) {
   2  
   3  /* eslint-disable no-unused-vars */
   4  /**
   5   * Drag and Drop for course sections and course modules.
   6   *
   7   * @module moodle-course-dragdrop
   8   */
   9  
  10  var CSS = {
  11      ACTIONAREA: '.actions',
  12      ACTIVITY: 'activity',
  13      ACTIVITYINSTANCE: 'activityinstance',
  14      CONTENT: 'content',
  15      COURSECONTENT: 'course-content',
  16      EDITINGMOVE: 'editing_move',
  17      ICONCLASS: 'iconsmall',
  18      JUMPMENU: 'jumpmenu',
  19      LEFT: 'left',
  20      LIGHTBOX: 'lightbox',
  21      MOVEDOWN: 'movedown',
  22      MOVEUP: 'moveup',
  23      PAGECONTENT: 'page-content',
  24      RIGHT: 'right',
  25      SECTION: 'section',
  26      SECTIONADDMENUS: 'section_add_menus',
  27      SECTIONHANDLE: 'section-handle',
  28      SUMMARY: 'summary',
  29      SECTIONDRAGGABLE: 'sectiondraggable'
  30  };
  31  
  32  M.course = M.course || {};
  33  /**
  34   * Section drag and drop.
  35   *
  36   * @class M.course.dragdrop.section
  37   * @constructor
  38   * @extends M.core.dragdrop
  39   */
  40  var DRAGSECTION = function() {
  41      DRAGSECTION.superclass.constructor.apply(this, arguments);
  42  };
  43  Y.extend(DRAGSECTION, M.core.dragdrop, {
  44      sectionlistselector: null,
  45  
  46      initializer: function() {
  47          // Set group for parent class
  48          this.groups = [CSS.SECTIONDRAGGABLE];
  49          this.samenodeclass = M.course.format.get_sectionwrapperclass();
  50          this.parentnodeclass = M.course.format.get_containerclass();
  51  
  52          // Check if we are in single section mode
  53          if (Y.Node.one('.' + CSS.JUMPMENU)) {
  54              return false;
  55          }
  56          // Initialise sections dragging
  57          this.sectionlistselector = M.course.format.get_section_wrapper(Y);
  58          if (this.sectionlistselector) {
  59              this.sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + this.sectionlistselector;
  60  
  61              this.setup_for_section(this.sectionlistselector);
  62  
  63              // Make each li element in the lists of sections draggable
  64              var del = new Y.DD.Delegate({
  65                  container: '.' + CSS.COURSECONTENT,
  66                  nodes: '.' + CSS.SECTIONDRAGGABLE,
  67                  target: true,
  68                  handles: ['.' + CSS.LEFT],
  69                  dragConfig: {groups: this.groups}
  70              });
  71              del.dd.plug(Y.Plugin.DDProxy, {
  72                  // Don't move the node at the end of the drag
  73                  moveOnEnd: false
  74              });
  75              del.dd.plug(Y.Plugin.DDConstrained, {
  76                  // Keep it inside the .course-content
  77                  constrain: '#' + CSS.PAGECONTENT,
  78                  stickY: true
  79              });
  80              del.dd.plug(Y.Plugin.DDWinScroll);
  81          }
  82      },
  83  
  84       /**
  85       * Apply dragdrop features to the specified selector or node that refers to section(s)
  86       *
  87       * @method setup_for_section
  88       * @param {String} baseselector The CSS selector or node to limit scope to
  89       */
  90      setup_for_section: function(baseselector) {
  91          Y.Node.all(baseselector).each(function(sectionnode) {
  92              // Determine the section ID
  93              var sectionid = Y.Moodle.core_course.util.section.getId(sectionnode);
  94  
  95              // We skip the top section as it is not draggable
  96              if (sectionid > 0) {
  97                  // Remove move icons
  98                  var movedown = sectionnode.one('.' + CSS.RIGHT + ' a.' + CSS.MOVEDOWN);
  99                  var moveup = sectionnode.one('.' + CSS.RIGHT + ' a.' + CSS.MOVEUP);
 100  
 101                  // Add dragger icon
 102                  var title = M.util.get_string('movesection', 'moodle', sectionid);
 103                  var cssleft = sectionnode.one('.' + CSS.LEFT);
 104  
 105                  if ((movedown || moveup) && cssleft) {
 106                      cssleft.setStyle('cursor', 'move');
 107                      cssleft.appendChild(this.get_drag_handle(title, CSS.SECTIONHANDLE, 'icon', true));
 108  
 109                      if (moveup) {
 110                          if (moveup.previous('br')) {
 111                              moveup.previous('br').remove();
 112                          } else if (moveup.next('br')) {
 113                              moveup.next('br').remove();
 114                          }
 115  
 116                          if (moveup.ancestor('.section_action_menu')) {
 117                              moveup.ancestor('li').remove();
 118                          } else {
 119                              moveup.remove();
 120                          }
 121                      }
 122                      if (movedown) {
 123                          if (movedown.previous('br')) {
 124                              movedown.previous('br').remove();
 125                          } else if (movedown.next('br')) {
 126                              movedown.next('br').remove();
 127                          }
 128  
 129                          if (movedown.ancestor('.section_action_menu')) {
 130                              movedown.ancestor('li').remove();
 131                          } else {
 132                              movedown.remove();
 133                          }
 134                      }
 135  
 136                      // This section can be moved - add the class to indicate this to Y.DD.
 137                      sectionnode.addClass(CSS.SECTIONDRAGGABLE);
 138                  }
 139              }
 140          }, this);
 141      },
 142  
 143      /*
 144       * Drag-dropping related functions
 145       */
 146      drag_start: function(e) {
 147          // Get our drag object
 148          var drag = e.target;
 149          // Creat a dummy structure of the outer elemnents for clean styles application
 150          var containernode = Y.Node.create('<' + M.course.format.get_containernode() +
 151                  '></' + M.course.format.get_containernode() + '>');
 152          containernode.addClass(M.course.format.get_containerclass());
 153          var sectionnode = Y.Node.create('<' + M.course.format.get_sectionwrappernode() +
 154                  '></' + M.course.format.get_sectionwrappernode() + '>');
 155          sectionnode.addClass(M.course.format.get_sectionwrapperclass());
 156          sectionnode.setStyle('margin', 0);
 157          sectionnode.setContent(drag.get('node').get('innerHTML'));
 158          containernode.appendChild(sectionnode);
 159          drag.get('dragNode').setContent(containernode);
 160          drag.get('dragNode').addClass(CSS.COURSECONTENT);
 161      },
 162  
 163      drag_dropmiss: function(e) {
 164          // Missed the target, but we assume the user intended to drop it
 165          // on the last last ghost node location, e.drag and e.drop should be
 166          // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
 167          this.drop_hit(e);
 168      },
 169  
 170      get_section_index: function(node) {
 171          var sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + M.course.format.get_section_selector(Y),
 172              sectionList = Y.all(sectionlistselector),
 173              nodeIndex = sectionList.indexOf(node),
 174              zeroIndex = sectionList.indexOf(Y.one('#section-0'));
 175  
 176          return (nodeIndex - zeroIndex);
 177      },
 178  
 179      drop_hit: function(e) {
 180          var drag = e.drag;
 181  
 182          // Get references to our nodes and their IDs.
 183          var dragnode = drag.get('node'),
 184              dragnodeid = Y.Moodle.core_course.util.section.getId(dragnode),
 185              loopstart = dragnodeid,
 186  
 187              dropnodeindex = this.get_section_index(dragnode),
 188              loopend = dropnodeindex;
 189  
 190          if (dragnodeid === dropnodeindex) {
 191              return;
 192          }
 193  
 194  
 195          if (loopstart > loopend) {
 196              // If we're going up, we need to swap the loop order
 197              // because loops can't go backwards.
 198              loopstart = dropnodeindex;
 199              loopend = dragnodeid;
 200          }
 201  
 202          // Get the list of nodes.
 203          drag.get('dragNode').removeClass(CSS.COURSECONTENT);
 204          var sectionlist = Y.Node.all(this.sectionlistselector);
 205  
 206          // Add a lightbox if it's not there.
 207          var lightbox = M.util.add_lightbox(Y, dragnode);
 208  
 209          // Handle any variables which we must pass via AJAX.
 210          var params = {},
 211              pageparams = this.get('config').pageparams,
 212              varname;
 213  
 214          for (varname in pageparams) {
 215              if (!pageparams.hasOwnProperty(varname)) {
 216                  continue;
 217              }
 218              params[varname] = pageparams[varname];
 219          }
 220  
 221          // Prepare request parameters
 222          params.sesskey = M.cfg.sesskey;
 223          params.courseId = this.get('courseid');
 224          params['class'] = 'section';
 225          params.field = 'move';
 226          params.id = dragnodeid;
 227          params.value = dropnodeindex;
 228  
 229          // Perform the AJAX request.
 230          var uri = M.cfg.wwwroot + this.get('ajaxurl');
 231          Y.io(uri, {
 232              method: 'POST',
 233              data: params,
 234              on: {
 235                  start: function() {
 236                      lightbox.show();
 237                  },
 238                  success: function(tid, response) {
 239                      // Update section titles, we can't simply swap them as
 240                      // they might have custom title
 241                      try {
 242                          var responsetext = Y.JSON.parse(response.responseText);
 243                          if (responsetext.error) {
 244                              new M.core.ajaxException(responsetext);
 245                          }
 246                          M.course.format.process_sections(Y, sectionlist, responsetext, loopstart, loopend);
 247                      } catch (e) {
 248                          // Ignore.
 249                      }
 250  
 251                      // Update all of the section IDs - first unset them, then set them
 252                      // to avoid duplicates in the DOM.
 253                      var index;
 254  
 255                      // Classic bubble sort algorithm is applied to the section
 256                      // nodes between original drag node location and the new one.
 257                      var swapped = false;
 258                      do {
 259                          swapped = false;
 260                          for (index = loopstart; index <= loopend; index++) {
 261                              if (Y.Moodle.core_course.util.section.getId(sectionlist.item(index - 1)) >
 262                                          Y.Moodle.core_course.util.section.getId(sectionlist.item(index))) {
 263                                  // Swap section id.
 264                                  var sectionid = sectionlist.item(index - 1).get('id');
 265                                  sectionlist.item(index - 1).set('id', sectionlist.item(index).get('id'));
 266                                  sectionlist.item(index).set('id', sectionid);
 267  
 268                                  // See what format needs to swap.
 269                                  M.course.format.swap_sections(Y, index - 1, index);
 270  
 271                                  // Update flag.
 272                                  swapped = true;
 273                              }
 274                          }
 275                          loopend = loopend - 1;
 276                      } while (swapped);
 277  
 278                      window.setTimeout(function() {
 279                          lightbox.hide();
 280                      }, 250);
 281                  },
 282  
 283                  failure: function(tid, response) {
 284                      this.ajax_failure(response);
 285                      lightbox.hide();
 286                  }
 287              },
 288              context: this
 289          });
 290      }
 291  
 292  }, {
 293      NAME: 'course-dragdrop-section',
 294      ATTRS: {
 295          courseid: {
 296              value: null
 297          },
 298          ajaxurl: {
 299              value: 0
 300          },
 301          config: {
 302              value: 0
 303          }
 304      }
 305  });
 306  
 307  M.course = M.course || {};
 308  M.course.init_section_dragdrop = function(params) {
 309      new DRAGSECTION(params);
 310  };
 311  /**
 312   * Resource drag and drop.
 313   *
 314   * @class M.course.dragdrop.resource
 315   * @constructor
 316   * @extends M.core.dragdrop
 317   */
 318  var DRAGRESOURCE = function() {
 319      DRAGRESOURCE.superclass.constructor.apply(this, arguments);
 320  };
 321  Y.extend(DRAGRESOURCE, M.core.dragdrop, {
 322      initializer: function() {
 323          // Set group for parent class
 324          this.groups = ['resource'];
 325          this.samenodeclass = CSS.ACTIVITY;
 326          this.parentnodeclass = CSS.SECTION;
 327          this.resourcedraghandle = this.get_drag_handle(M.util.get_string('movecoursemodule', 'moodle'),
 328                  CSS.EDITINGMOVE, CSS.ICONCLASS, true);
 329  
 330          this.samenodelabel = {
 331              identifier: 'afterresource',
 332              component: 'moodle'
 333          };
 334          this.parentnodelabel = {
 335              identifier: 'totopofsection',
 336              component: 'moodle'
 337          };
 338  
 339          // Go through all sections
 340          var sectionlistselector = M.course.format.get_section_selector(Y);
 341          if (sectionlistselector) {
 342              sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + sectionlistselector;
 343              this.setup_for_section(sectionlistselector);
 344  
 345              // Initialise drag & drop for all resources/activities
 346              var nodeselector = sectionlistselector.slice(CSS.COURSECONTENT.length + 2) + ' li.' + CSS.ACTIVITY;
 347              var del = new Y.DD.Delegate({
 348                  container: '.' + CSS.COURSECONTENT,
 349                  nodes: nodeselector,
 350                  target: true,
 351                  handles: ['.' + CSS.EDITINGMOVE],
 352                  dragConfig: {groups: this.groups}
 353              });
 354              del.dd.plug(Y.Plugin.DDProxy, {
 355                  // Don't move the node at the end of the drag
 356                  moveOnEnd: false,
 357                  cloneNode: true
 358              });
 359              del.dd.plug(Y.Plugin.DDConstrained, {
 360                  // Keep it inside the .course-content
 361                  constrain: '#' + CSS.PAGECONTENT
 362              });
 363              del.dd.plug(Y.Plugin.DDWinScroll);
 364  
 365              M.course.coursebase.register_module(this);
 366              M.course.dragres = this;
 367          }
 368      },
 369  
 370      /**
 371       * Apply dragdrop features to the specified selector or node that refers to section(s)
 372       *
 373       * @method setup_for_section
 374       * @param {String} baseselector The CSS selector or node to limit scope to
 375       */
 376      setup_for_section: function(baseselector) {
 377          Y.Node.all(baseselector).each(function(sectionnode) {
 378              var resources = sectionnode.one('.' + CSS.CONTENT + ' ul.' + CSS.SECTION);
 379              // See if resources ul exists, if not create one
 380              if (!resources) {
 381                  resources = Y.Node.create('<ul></ul>');
 382                  resources.addClass(CSS.SECTION);
 383                  sectionnode.one('.' + CSS.CONTENT + ' div.' + CSS.SUMMARY).insert(resources, 'after');
 384              }
 385              resources.setAttribute('data-draggroups', this.groups.join(' '));
 386              // Define empty ul as droptarget, so that item could be moved to empty list
 387              new Y.DD.Drop({
 388                  node: resources,
 389                  groups: this.groups,
 390                  padding: '20 0 20 0'
 391              });
 392  
 393              // Initialise each resource/activity in this section
 394              this.setup_for_resource('#' + sectionnode.get('id') + ' li.' + CSS.ACTIVITY);
 395          }, this);
 396      },
 397  
 398      /**
 399       * Apply dragdrop features to the specified selector or node that refers to resource(s)
 400       *
 401       * @method setup_for_resource
 402       * @param {String} baseselector The CSS selector or node to limit scope to
 403       */
 404      setup_for_resource: function(baseselector) {
 405          Y.Node.all(baseselector).each(function(resourcesnode) {
 406              var draggroups = resourcesnode.getData('draggroups');
 407              if (!draggroups) {
 408                  // This Drop Node has not been set up. Configure it now.
 409                  resourcesnode.setAttribute('data-draggroups', this.groups.join(' '));
 410                  // Define empty ul as droptarget, so that item could be moved to empty list
 411                  new Y.DD.Drop({
 412                      node: resourcesnode,
 413                      groups: this.groups,
 414                      padding: '20 0 20 0'
 415                  });
 416              }
 417  
 418              // Replace move icons
 419              var move = resourcesnode.one('a.' + CSS.EDITINGMOVE);
 420              if (move) {
 421                  move.replace(this.resourcedraghandle.cloneNode(true));
 422              }
 423          }, this);
 424      },
 425  
 426      drag_start: function(e) {
 427          // Get our drag object
 428          var drag = e.target;
 429          drag.get('dragNode').setContent(drag.get('node').get('innerHTML'));
 430          drag.get('dragNode').all('img.iconsmall').setStyle('vertical-align', 'baseline');
 431      },
 432  
 433      drag_dropmiss: function(e) {
 434          // Missed the target, but we assume the user intended to drop it
 435          // on the last last ghost node location, e.drag and e.drop should be
 436          // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
 437          this.drop_hit(e);
 438      },
 439  
 440      drop_hit: function(e) {
 441          var drag = e.drag;
 442          // Get a reference to our drag node
 443          var dragnode = drag.get('node');
 444          var dropnode = e.drop.get('node');
 445  
 446          // Add spinner if it not there
 447          var actionarea = dragnode.one(CSS.ACTIONAREA);
 448          var spinner = M.util.add_spinner(Y, actionarea);
 449  
 450          var params = {};
 451  
 452          // Handle any variables which we must pass back through to
 453          var pageparams = this.get('config').pageparams;
 454          var varname;
 455          for (varname in pageparams) {
 456              params[varname] = pageparams[varname];
 457          }
 458  
 459          // Prepare request parameters
 460          params.sesskey = M.cfg.sesskey;
 461          params.courseId = this.get('courseid');
 462          params['class'] = 'resource';
 463          params.field = 'move';
 464          params.id = Number(Y.Moodle.core_course.util.cm.getId(dragnode));
 465          params.sectionId = Y.Moodle.core_course.util.section.getId(dropnode.ancestor(M.course.format.get_section_wrapper(Y), true));
 466  
 467          if (dragnode.next()) {
 468              params.beforeId = Number(Y.Moodle.core_course.util.cm.getId(dragnode.next()));
 469          }
 470  
 471          // Do AJAX request
 472          var uri = M.cfg.wwwroot + this.get('ajaxurl');
 473  
 474          Y.io(uri, {
 475              method: 'POST',
 476              data: params,
 477              on: {
 478                  start: function() {
 479                      this.lock_drag_handle(drag, CSS.EDITINGMOVE);
 480                      spinner.show();
 481                  },
 482                  success: function(tid, response) {
 483                      var responsetext = Y.JSON.parse(response.responseText);
 484                      var params = {element: dragnode, visible: responsetext.visible};
 485                      M.course.coursebase.invoke_function('set_visibility_resource_ui', params);
 486                      this.unlock_drag_handle(drag, CSS.EDITINGMOVE);
 487                      window.setTimeout(function() {
 488                          spinner.hide();
 489                      }, 250);
 490                  },
 491                  failure: function(tid, response) {
 492                      this.ajax_failure(response);
 493                      this.unlock_drag_handle(drag, CSS.SECTIONHANDLE);
 494                      spinner.hide();
 495                      // TODO: revert nodes location
 496                  }
 497              },
 498              context: this
 499          });
 500      }
 501  }, {
 502      NAME: 'course-dragdrop-resource',
 503      ATTRS: {
 504          courseid: {
 505              value: null
 506          },
 507          ajaxurl: {
 508              value: 0
 509          },
 510          config: {
 511              value: 0
 512          }
 513      }
 514  });
 515  
 516  M.course = M.course || {};
 517  M.course.init_resource_dragdrop = function(params) {
 518      new DRAGRESOURCE(params);
 519  };
 520  
 521  
 522  }, '@VERSION@', {
 523      "requires": [
 524          "base",
 525          "node",
 526          "io",
 527          "dom",
 528          "dd",
 529          "dd-scroll",
 530          "moodle-core-dragdrop",
 531          "moodle-core-notification",
 532          "moodle-course-coursebase",
 533          "moodle-course-util"
 534      ]
 535  });


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