[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yui/build/moodle-core-chooserdialogue/ -> moodle-core-chooserdialogue.js (source)

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


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