[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yui/src/chooserdialogue/js/ -> chooserdialogue.js (source)

   1  /**
   2   * A type of dialogue used as for choosing options.
   3   *
   4   * @module moodle-core-chooserdialogue
   5   */
   6  
   7  /**
   8   * A type of dialogue used as for choosing options.
   9   *
  10   * @constructor
  11   * @class M.core.chooserdialogue
  12   */
  13  var CHOOSERDIALOGUE = function() {
  14      CHOOSERDIALOGUE.superclass.constructor.apply(this, arguments);
  15  };
  16  
  17  Y.extend(CHOOSERDIALOGUE, Y.Base, {
  18      // The panel widget
  19      panel: null,
  20  
  21      // The submit button - we disable this until an element is set
  22      submitbutton: null,
  23  
  24      // The chooserdialogue container
  25      container: null,
  26  
  27      // Any event listeners we may need to cancel later
  28      listenevents: [],
  29  
  30      bodycontent: null,
  31      headercontent: null,
  32      instanceconfig: null,
  33  
  34      // The hidden field storing the disabled element values for submission.
  35      hiddenRadioValue: null,
  36  
  37      setup_chooser_dialogue: function(bodycontent, headercontent, config) {
  38          this.bodycontent = bodycontent;
  39          this.headercontent = headercontent;
  40          this.instanceconfig = config;
  41      },
  42  
  43      prepare_chooser: function() {
  44          if (this.panel) {
  45              return;
  46          }
  47  
  48          // Ensure that we're showing the JS version of the chooser.
  49          Y.one(Y.config.doc.body).addClass('jschooser');
  50  
  51          // Set Default options
  52          var paramkey,
  53              params = {
  54                  bodyContent: this.bodycontent.get('innerHTML'),
  55                  headerContent: this.headercontent.get('innerHTML'),
  56                  width: '540px',
  57                  draggable: true,
  58                  visible: false, // Hide by default
  59                  zindex: 100, // Display in front of other items
  60                  modal: true, // This dialogue should be modal.
  61                  shim: true,
  62                  closeButtonTitle: this.get('closeButtonTitle'),
  63                  focusOnPreviousTargetAfterHide: true,
  64                  render: false,
  65                  extraClasses: this._getClassNames()
  66              };
  67  
  68          // Override with additional options
  69          for (paramkey in this.instanceconfig) {
  70            params[paramkey] = this.instanceconfig[paramkey];
  71          }
  72  
  73          // Create the panel
  74          this.panel = new M.core.dialogue(params);
  75  
  76          // Remove the template for the chooser
  77          this.bodycontent.remove();
  78          this.headercontent.remove();
  79  
  80          // Hide and then render the panel
  81          this.panel.hide();
  82          this.panel.render();
  83  
  84          // Set useful links.
  85          this.container = this.panel.get('boundingBox').one('.choosercontainer');
  86          this.options = this.container.all('.option input[type=radio]');
  87  
  88          // The hidden form element we use when submitting.
  89          this.hiddenRadioValue = Y.Node.create('<input type="hidden" value="" />');
  90          this.container.one('form').appendChild(this.hiddenRadioValue);
  91  
  92  
  93          // Add the chooserdialogue class to the container for styling
  94          this.panel.get('boundingBox').addClass('chooserdialogue');
  95      },
  96  
  97      /**
  98        * Display the module chooser
  99        *
 100        * @method display_chooser
 101        * @param {EventFacade} e Triggering Event
 102        */
 103      display_chooser: function(e) {
 104          var bb, dialogue, thisevent;
 105          this.prepare_chooser();
 106  
 107          // Stop the default event actions before we proceed
 108          e.preventDefault();
 109  
 110          bb = this.panel.get('boundingBox');
 111          dialogue = this.container.one('.alloptions');
 112  
 113          // This will detect a change in orientation and retrigger centering
 114          thisevent = Y.one('document').on('orientationchange', function() {
 115              this.center_dialogue(dialogue);
 116          }, this);
 117          this.listenevents.push(thisevent);
 118  
 119          // Detect window resizes (most browsers)
 120          thisevent = Y.one('window').on('resize', function() {
 121              this.center_dialogue(dialogue);
 122          }, this);
 123          this.listenevents.push(thisevent);
 124  
 125          // These will trigger a check_options call to display the correct help
 126          thisevent = this.container.on('click', this.check_options, this);
 127          this.listenevents.push(thisevent);
 128          thisevent = this.container.on('key_up', this.check_options, this);
 129          this.listenevents.push(thisevent);
 130          thisevent = this.container.on('dblclick', function(e) {
 131              if (e.target.ancestor('div.option')) {
 132                  this.check_options();
 133  
 134                  // Prevent duplicate submissions
 135                  this.submitbutton.setAttribute('disabled', 'disabled');
 136                  this.options.setAttribute('disabled', 'disabled');
 137                  this.cancel_listenevents();
 138  
 139                  this.container.one('form').submit();
 140              }
 141          }, this);
 142          this.listenevents.push(thisevent);
 143  
 144          this.container.one('form').on('submit', function() {
 145              // Prevent duplicate submissions on submit
 146              this.submitbutton.setAttribute('disabled', 'disabled');
 147              this.options.setAttribute('disabled', 'disabled');
 148              this.cancel_listenevents();
 149          }, this);
 150  
 151          // Hook onto the cancel button to hide the form
 152          thisevent = this.container.one('.addcancel').on('click', this.cancel_popup, this);
 153          this.listenevents.push(thisevent);
 154  
 155          // Hide will be managed by cancel_popup after restoring the body overflow
 156          thisevent = bb.one('button.closebutton').on('click', this.cancel_popup, this);
 157          this.listenevents.push(thisevent);
 158  
 159          // Grab global keyup events and handle them
 160          thisevent = Y.one('document').on('keydown', this.handle_key_press, this);
 161          this.listenevents.push(thisevent);
 162  
 163          // Add references to various elements we adjust
 164          this.submitbutton = this.container.one('.submitbutton');
 165  
 166          // Disable the submit element until the user makes a selection
 167          this.submitbutton.set('disabled', 'true');
 168  
 169          // Ensure that the options are shown
 170          this.options.removeAttribute('disabled');
 171  
 172          // Display the panel
 173          this.panel.show(e);
 174  
 175          // Re-centre the dialogue after we've shown it.
 176          this.center_dialogue(dialogue);
 177  
 178          // Finally, focus the first radio element - this enables form selection via the keyboard
 179          this.container.one('.option input[type=radio]').focus();
 180  
 181          // Trigger check_options to set the initial jumpurl
 182          this.check_options();
 183      },
 184  
 185      /**
 186       * Cancel any listen events in the listenevents queue
 187       *
 188       * Several locations add event handlers which should only be called before the form is submitted. This provides
 189       * a way of cancelling those events.
 190       *
 191       * @method cancel_listenevents
 192       */
 193      cancel_listenevents: function() {
 194          // Detach all listen events to prevent duplicate triggers
 195          var thisevent;
 196          while (this.listenevents.length) {
 197              thisevent = this.listenevents.shift();
 198              thisevent.detach();
 199          }
 200      },
 201  
 202      /**
 203        * Calculate the optimum height of the chooser dialogue
 204        *
 205        * This tries to set a sensible maximum and minimum to ensure that some options are always shown, and preferably
 206        * all, whilst fitting the box within the current viewport.
 207        *
 208        * @method center_dialogue
 209        * @param Node {dialogue} Y.Node The dialogue
 210        */
 211      center_dialogue: function(dialogue) {
 212          var bb = this.panel.get('boundingBox'),
 213              winheight = bb.get('winHeight'),
 214              newheight, totalheight;
 215  
 216          if (this.panel.shouldResizeFullscreen()) {
 217              // No custom sizing required for a fullscreen dialog.
 218              return;
 219          }
 220  
 221          // Try and set a sensible max-height -- this must be done before setting the top
 222          // Set a default height of 640px
 223          newheight = this.get('maxheight');
 224          if (winheight <= newheight) {
 225              // Deal with smaller window sizes
 226              if (winheight <= this.get('minheight')) {
 227                  newheight = this.get('minheight');
 228              } else {
 229                  newheight = winheight;
 230              }
 231          }
 232  
 233          // If the dialogue is larger than a reasonable minimum height, we
 234          // disable the page scrollbars.
 235          if (newheight > this.get('minheight')) {
 236              // Disable the page scrollbars.
 237              if (this.panel.lockScroll && !this.panel.lockScroll.isActive()) {
 238                  this.panel.lockScroll.enableScrollLock(true);
 239              }
 240          } else {
 241              // Re-enable the page scrollbars.
 242              if (this.panel.lockScroll && this.panel.lockScroll.isActive()) {
 243                  this.panel.lockScroll.disableScrollLock();
 244              }
 245          }
 246  
 247          // Take off 15px top and bottom for borders, plus 40px each for the title and button area before setting the
 248          // new max-height
 249          totalheight = newheight;
 250          newheight = newheight - (15 + 15 + 40 + 40);
 251          dialogue.setStyle('maxHeight', newheight + 'px');
 252  
 253          var dialogueheight = bb.getStyle('height');
 254          if (dialogueheight.match(/.*px$/)) {
 255              dialogueheight = dialogueheight.replace(/px$/, '');
 256          } else {
 257              dialogueheight = totalheight;
 258          }
 259  
 260          if (dialogueheight < this.get('baseheight')) {
 261              dialogueheight = this.get('baseheight');
 262              dialogue.setStyle('height', dialogueheight + 'px');
 263          }
 264  
 265          this.panel.centerDialogue();
 266      },
 267  
 268      handle_key_press: function(e) {
 269          if (e.keyCode === 27) {
 270              this.cancel_popup(e);
 271          }
 272      },
 273  
 274      cancel_popup: function(e) {
 275          // Prevent normal form submission before hiding
 276          e.preventDefault();
 277          this.hide();
 278      },
 279  
 280      hide: function() {
 281          // Cancel all listen events
 282          this.cancel_listenevents();
 283  
 284          this.container.detachAll();
 285          this.panel.hide();
 286      },
 287  
 288      check_options: function() {
 289          // Check which options are set, and change the parent class
 290          // to show/hide help as required
 291          this.options.each(function(thisoption) {
 292              var optiondiv = thisoption.get('parentNode').get('parentNode');
 293              if (thisoption.get('checked')) {
 294                  optiondiv.addClass('selected');
 295  
 296                  // Trigger any events for this option
 297                  this.option_selected(thisoption);
 298  
 299                  // Ensure that the form may be submitted
 300                  this.submitbutton.removeAttribute('disabled');
 301  
 302                  // Ensure that the radio remains focus so that keyboard navigation is still possible
 303                  thisoption.focus();
 304              } else {
 305                  optiondiv.removeClass('selected');
 306              }
 307          }, this);
 308      },
 309  
 310      option_selected: function(e) {
 311          // Set a hidden input field with the value and name of the radio button.  When we submit the form, we
 312          // disable the radios to prevent duplicate submission. This has the result however that the value is never
 313          // submitted so we set this value to a hidden field instead
 314          this.hiddenRadioValue.setAttrs({
 315              value: e.get('value'),
 316              name: e.get('name')
 317          });
 318      },
 319  
 320      /**
 321       * Return an array of class names prefixed with 'chooserdialogue-' and
 322       * the name of the type of dialogue.
 323       *
 324       * Note: Class name are converted to lower-case.
 325       *
 326       * If an array of arguments is supplied, each of these is prefixed and
 327       * lower-cased also.
 328       *
 329       * If no arguments are supplied, then the prefix is returned on it's
 330       * own.
 331       *
 332       * @method _getClassNames
 333       * @param {Array} [args] Any additional names to prefix and lower-case.
 334       * @return {Array}
 335       * @private
 336       */
 337      _getClassNames: function(args) {
 338          var prefix = 'chooserdialogue-' + this.name,
 339              results = [];
 340  
 341          results.push(prefix.toLowerCase());
 342          if (args) {
 343              var arg;
 344              for (arg in args) {
 345                  results.push((prefix + '-' + arg).toLowerCase());
 346              }
 347          }
 348  
 349          return results;
 350      }
 351  },
 352  {
 353      NAME: 'moodle-core-chooserdialogue',
 354      ATTRS: {
 355          /**
 356           * The minimum height (in pixels) before resizing is prevented and scroll
 357           * locking disabled.
 358           *
 359           * @attribute minheight
 360           * @type Number
 361           * @default 300
 362           */
 363          minheight: {
 364              value: 300
 365          },
 366  
 367          /**
 368           * The base height??
 369           *
 370           * @attribute baseheight
 371           * @type Number
 372           * @default 400
 373           */
 374          baseheight: {
 375              value: 400
 376          },
 377  
 378          /**
 379           * The maximum height (in pixels) at which we stop resizing.
 380           *
 381           * @attribute maxheight
 382           * @type Number
 383           * @default 300
 384           */
 385          maxheight: {
 386              value: 660
 387          },
 388  
 389          /**
 390           * The title of the close button.
 391           *
 392           * @attribute closeButtonTitle
 393           * @type String
 394           * @default 'Close'
 395           */
 396          closeButtonTitle: {
 397              validator: Y.Lang.isString,
 398              value: 'Close'
 399          }
 400      }
 401  });
 402  M.core = M.core || {};
 403  M.core.chooserdialogue = CHOOSERDIALOGUE;


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