Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / themes / contrib / bootstrap / js / modal.jquery.ui.bridge.js
diff --git a/web/themes/contrib/bootstrap/js/modal.jquery.ui.bridge.js b/web/themes/contrib/bootstrap/js/modal.jquery.ui.bridge.js
new file mode 100644 (file)
index 0000000..88d5ce4
--- /dev/null
@@ -0,0 +1,489 @@
+/**
+ * @file
+ * Bootstrap Modals.
+ */
+(function ($, Drupal, Bootstrap, Attributes, drupalSettings) {
+  'use strict';
+
+  /**
+   * Only process this once.
+   */
+  Bootstrap.once('modal.jquery.ui.bridge', function (settings) {
+    // RTL support.
+    var rtl = document.documentElement.getAttribute('dir').toLowerCase() === 'rtl';
+
+    // Override drupal.dialog button classes. This must be done on DOM ready
+    // since core/drupal.dialog technically depends on this file and has not
+    // yet set their default settings.
+    $(function () {
+      drupalSettings.dialog.buttonClass = 'btn';
+      drupalSettings.dialog.buttonPrimaryClass = 'btn-primary';
+    });
+
+    var relayEvent = function ($element, name, stopPropagation) {
+      return function (e) {
+        if (stopPropagation === void 0 || stopPropagation) {
+          e.stopPropagation();
+        }
+        var parts = name.split('.').filter(Boolean);
+        var type = parts.shift();
+        e.target = $element[0];
+        e.currentTarget = $element[0];
+        e.namespace = parts.join('.');
+        e.type = type;
+        $element.trigger(e);
+      };
+    };
+
+    /**
+     * Proxy $.fn.dialog to $.fn.modal.
+     */
+    Bootstrap.createPlugin('dialog', function (options) {
+      // When only options are passed, jQuery UI dialog treats this like a
+      // initialization method. Destroy any existing Bootstrap modal and
+      // recreate it using the contents of the dialog HTML.
+      if (arguments.length === 1 && typeof options === 'object') {
+        this.each(function () {
+          // This part gets a little tricky. Core can potentially already
+          // semi-process this "dialog" if was created using an Ajax command
+          // (i.e. prepareDialogButtons in drupal.ajax.js). Because of this,
+          // we cannot simply dump the existing dialog content into a newly
+          // created modal because that would destroy any existing event
+          // bindings. Instead, we have to create this in steps and "move"
+          // (append) the existing content as needed.
+          var $this = $(this);
+
+          // Create a new modal to get a complete template.
+          var $modal = $(Drupal.theme('bootstrapModal', {attributes: Attributes.create(this).remove('style')}));
+
+          // Store a reference to the content inside the existing dialog.
+          // This references the actual DOM node elements which will allow
+          // jQuery to "move" then when appending below. Using $.fn.children()
+          // does not return any text nodes present and $.fn.html() only returns
+          // a string representation of the content, which effectively destroys
+          // any prior event bindings or processing.
+          var $existing = $this.contents();
+
+          // Destroy any existing Bootstrap Modal data that may have been saved.
+          $this.removeData('bs.modal');
+
+          // Set the attributes of the dialog to that of the newly created modal.
+          $this.attr(Attributes.create($modal).toPlainObject());
+
+          // Append the newly created modal markup.
+          $this.append($modal.html());
+
+          // Move the existing HTML into the modal markup that was just appended.
+          $this.find('.modal-body').append($existing);
+        });
+
+        // Indicate that the modal is a jQuery UI dialog bridge.
+        options.jQueryUiBridge = true;
+
+        // Proxy just the options to the Bootstrap Modal plugin.
+        return $.fn.modal.apply(this, [options]);
+      }
+
+      // Otherwise, proxy all arguments to the Bootstrap Modal plugin.
+      return $.fn.modal.apply(this, arguments);
+    });
+
+    /**
+     * Extend the Bootstrap Modal plugin constructor class.
+     */
+    Bootstrap.extendPlugin('modal', function () {
+      var Modal = this;
+
+      return {
+        DEFAULTS: {
+          // By default, this option is disabled. It's only flagged when a modal
+          // was created using $.fn.dialog above.
+          jQueryUiBridge: false
+        },
+        prototype: {
+
+          /**
+           * Handler for $.fn.dialog('close').
+           */
+          close: function () {
+            var _this = this;
+
+            this.hide.apply(this, arguments);
+
+            // For some reason (likely due to the transition event not being
+            // registered properly), the backdrop doesn't always get removed
+            // after the above "hide" method is invoked . Instead, ensure the
+            // backdrop is removed after the transition duration by manually
+            // invoking the internal "hideModal" method shortly thereafter.
+            setTimeout(function () {
+              if (!_this.isShown && _this.$backdrop) {
+                _this.hideModal();
+              }
+            }, (Modal.TRANSITION_DURATION !== void 0 ? Modal.TRANSITION_DURATION : 300) + 10);
+          },
+
+          /**
+           * Creates any necessary buttons from dialog options.
+           */
+          createButtons: function () {
+            this.$footer.find('.modal-buttons').remove();
+            var buttons = this.options.dialogOptions && this.options.dialogOptions.buttons || [];
+            if (buttons.length) {
+              var $buttons = $('<div class="modal-buttons"/>').appendTo(this.$footer);
+              for (var i = 0, l = buttons.length; i < l; i++) {
+                var button = buttons[i];
+                var $button = $(Drupal.theme('bootstrapModalDialogButton', button));
+                if (typeof button.click === 'function') {
+                  $button.on('click', button.click);
+                }
+                $buttons.append($button);
+              }
+            }
+          },
+
+          /**
+           * Initializes the Bootstrap Modal.
+           */
+          init: function () {
+            // Relay necessary events.
+            if (this.options.jQueryUiBridge) {
+              this.$element.on('hide.bs.modal',   relayEvent(this.$element, 'dialogbeforeclose', false));
+              this.$element.on('hidden.bs.modal', relayEvent(this.$element, 'dialogclose', false));
+              this.$element.on('show.bs.modal',   relayEvent(this.$element, 'dialogcreate', false));
+              this.$element.on('shown.bs.modal',  relayEvent(this.$element, 'dialogopen', false));
+            }
+
+            // Create a footer if one doesn't exist.
+            // This is necessary in case dialog.ajax.js decides to add buttons.
+            if (!this.$footer[0]) {
+              this.$footer = $(Drupal.theme('bootstrapModalFooter', {}, true)).insertAfter(this.$dialogBody);
+            }
+
+            // Create buttons.
+            this.createButtons();
+
+            // Hide the footer if there are no children.
+            if (!this.$footer.children()[0]) {
+              this.$footer.hide();
+            }
+
+            // Now call the parent init method.
+            this.super();
+
+            // Handle autoResize option (this is a drupal.dialog option).
+            if (this.options.dialogOptions && this.options.dialogOptions.autoResize && this.options.dialogOptions.position) {
+              this.position(this.options.dialogOptions.position);
+            }
+
+            // If show is enabled and currently not shown, show it.
+            if (this.options.show && !this.isShown) {
+              this.show();
+            }
+          },
+
+          /**
+           * Handler for $.fn.dialog('instance').
+           */
+          instance: function () {
+            Bootstrap.unsupported('method', 'instance', arguments);
+          },
+
+          /**
+           * Handler for $.fn.dialog('isOpen').
+           */
+          isOpen: function () {
+            return !!this.isShown;
+          },
+
+          /**
+           * Maps dialog options to the modal.
+           *
+           * @param {Object} options
+           *   The options to map.
+           */
+          mapDialogOptions: function (options) {
+            var dialogOptions = {};
+            var mappedOptions = {};
+
+            // Handle CSS properties.
+            var cssUnitRegExp = /^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)?$/;
+            var parseCssUnit = function (value, defaultUnit) {
+              var parts = ('' + value).match(cssUnitRegExp);
+              return parts && parts[1] !== void 0 ? parts[1] + (parts[2] || defaultUnit || 'px') : null;
+            };
+            var styles = {};
+            var cssProperties = ['height', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'width'];
+            for (var i = 0, l = cssProperties.length; i < l; i++) {
+              var prop = cssProperties[i];
+              if (options[prop] !== void 0) {
+                var value = parseCssUnit(options[prop]);
+                if (value) {
+                  dialogOptions[prop] = value;
+                  styles[prop] = value;
+                }
+              }
+            }
+
+            // Apply mapped CSS styles to the modal-content container.
+            this.$content.css(styles);
+
+            // Handle deprecated "dialogClass" option by merging it with "classes".
+            var classesMap = {
+              'ui-dialog': 'modal-content',
+              'ui-dialog-titlebar': 'modal-header',
+              'ui-dialog-title': 'modal-title',
+              'ui-dialog-titlebar-close': 'close',
+              'ui-dialog-content': 'modal-body',
+              'ui-dialog-buttonpane': 'modal-footer'
+            };
+            if (options.dialogClass) {
+              if (options.classes === void 0) {
+                options.classes = {};
+              }
+              if (options.classes['ui-dialog'] === void 0) {
+                options.classes['ui-dialog'] = '';
+              }
+              var dialogClass = options.classes['ui-dialog'].split(' ');
+              dialogClass.push(options.dialogClass);
+              options.classes['ui-dialog'] = dialogClass.join(' ');
+              delete options.dialogClass;
+            }
+
+
+            // Bind events.
+            var events = [
+              'beforeClose', 'close',
+              'create',
+              'drag', 'dragStart', 'dragStop',
+              'focus',
+              'open',
+              'resize', 'resizeStart', 'resizeStop'
+            ];
+            for (i = 0, l = events.length; i < l; i++) {
+              var event = events[i].toLowerCase();
+              if (options[event] === void 0 || typeof options[event] !== 'function') continue;
+              this.$element.on('dialog' + event, options[event]);
+            }
+
+            // Handle the reset of the options.
+            for (var name in options) {
+              if (!options.hasOwnProperty(name) || options[name] === void 0) continue;
+
+              switch (name) {
+                case 'appendTo':
+                  Bootstrap.unsupported('option', name, options.appendTo);
+                  break;
+
+                case 'autoOpen':
+                  mappedOptions.show = !!options.autoOpen;
+                  break;
+
+                // This is really a drupal.dialog option, not jQuery UI.
+                case 'autoResize':
+                  dialogOptions.autoResize = !!options.autoResize;
+                  break;
+
+                case 'buttons':
+                  dialogOptions.buttons = options.buttons;
+                  break;
+
+                case 'classes':
+                  dialogOptions.classes = options.classes;
+                  for (var key in options.classes) {
+                    if (options.classes.hasOwnProperty(key) && classesMap[key] !== void 0) {
+                      // Run through Attributes to sanitize classes.
+                      var attributes = Attributes.create().addClass(options.classes[key]).toPlainObject();
+                      var selector = '.' + classesMap[key];
+                      this.$element.find(selector).addClass(attributes['class']);
+                    }
+                  }
+                  break;
+
+                case 'closeOnEscape':
+                  dialogOptions.closeOnEscape = options.closeOnEscape;
+                  mappedOptions.keyboard = !!options.closeOnEscape;
+                  this.$close[options.closeOnEscape ? 'show' : 'hide']();
+                  if (!options.closeOnEscape && options.modal) {
+                    mappedOptions.backdrop = options.modal = 'static';
+                  }
+                  break;
+
+                case 'closeText':
+                  Bootstrap.unsupported('option', name, options.closeText);
+                  break;
+
+                case 'draggable':
+                  dialogOptions.draggable = options.draggable;
+                  this.$content
+                    .draggable({
+                      handle: '.modal-header',
+                      drag: relayEvent(this.$element, 'dialogdrag'),
+                      start: relayEvent(this.$element, 'dialogdragstart'),
+                      end: relayEvent(this.$element, 'dialogdragend')
+                    })
+                    .draggable(options.draggable ? 'enable' : 'disable');
+                  break;
+
+                case 'hide':
+                  if (options.hide === false || options.hide === true) {
+                    this.$element[options.hide ? 'addClass' : 'removeClass']('fade');
+                    mappedOptions.animation = options.hide;
+                  }
+                  else {
+                    Bootstrap.unsupported('option', name + ' (complex animation)', options.hide);
+                  }
+                  break;
+
+                case 'modal':
+                  mappedOptions.backdrop = options.modal;
+                  dialogOptions.modal = !!options.modal;
+
+                  // If not a modal and no initial position, center it.
+                  if (!options.modal && !options.position) {
+                    this.position({ my: 'center', of: window });
+                  }
+                  break;
+
+                case 'position':
+                  dialogOptions.position = options.position;
+                  this.position(options.position);
+                  break;
+
+                // Resizable support (must initialize first).
+                case 'resizable':
+                  dialogOptions.resizeable = options.resizable;
+                  this.$content
+                    .resizable({
+                      resize: relayEvent(this.$element, 'dialogresize'),
+                      start: relayEvent(this.$element, 'dialogresizestart'),
+                      end: relayEvent(this.$element, 'dialogresizeend')
+                    })
+                    .resizable(options.resizable ? 'enable' : 'disable');
+                  break;
+
+                case 'show':
+                  if (options.show === false || options.show === true) {
+                    this.$element[options.show ? 'addClass' : 'removeClass']('fade');
+                    mappedOptions.animation = options.show;
+                  }
+                  else {
+                    Bootstrap.unsupported('option', name + ' (complex animation)', options.show);
+                  }
+                  break;
+
+                case 'title':
+                  dialogOptions.title = options.title;
+                  this.$dialog.find('.modal-title').text(options.title);
+                  break;
+
+              }
+            }
+
+            // Add the supported dialog options to the mapped options.
+            mappedOptions.dialogOptions = dialogOptions;
+
+            return mappedOptions;
+          },
+
+          /**
+           * Handler for $.fn.dialog('moveToTop').
+           */
+          moveToTop: function () {
+            Bootstrap.unsupported('method', 'moveToTop', arguments);
+          },
+
+          /**
+           * Handler for $.fn.dialog('option').
+           */
+          option: function () {
+            var clone = {options: $.extend({}, this.options)};
+
+            // Apply the parent option method to the clone of current options.
+            this.super.apply(clone, arguments);
+
+            // Merge in the cloned mapped options.
+            $.extend(true, this.options, this.mapDialogOptions(clone.options));
+          },
+
+          position: function(position) {
+            // Reset modal styling.
+            this.$element.css({
+              bottom: 'initial',
+              overflow: 'visible',
+              right: 'initial'
+            });
+
+            // Position the modal.
+            this.$element.position(position);
+          },
+
+          /**
+           * Handler for $.fn.dialog('open').
+           */
+          open: function () {
+            this.show.apply(this, arguments);
+          },
+
+          /**
+           * Handler for $.fn.dialog('widget').
+           */
+          widget: function () {
+            return this.$element;
+          }
+        }
+      };
+    });
+
+    /**
+     * Extend Drupal theming functions.
+     */
+    $.extend(Drupal.theme, /** @lend Drupal.theme */ {
+
+      /**
+       * Renders a jQuery UI Dialog compatible button element.
+       *
+       * @param {Object} button
+       *   The button object passed in the dialog options.
+       *
+       * @return {String}
+       *   The modal dialog button markup.
+       *
+       * @see http://api.jqueryui.com/dialog/#option-buttons
+       * @see http://api.jqueryui.com/button/
+       */
+      bootstrapModalDialogButton: function (button) {
+        var attributes = Attributes.create();
+
+        var icon = '';
+        var iconPosition = button.iconPosition || 'beginning';
+        iconPosition = (iconPosition === 'end' && !rtl) || (iconPosition === 'beginning' && rtl) ? 'after' : 'before';
+        if (button.icon) {
+          var iconAttributes = Attributes.create()
+            .addClass(['ui-icon', button.icon])
+            .set('aria-hidden', 'true');
+          icon = '<span' + iconAttributes + '></span>';
+        }
+
+        // Value.
+        var value = button.text;
+        attributes.set('value', iconPosition === 'before' ? icon + value : value + icon);
+
+        // Handle disabled.
+        attributes[button.disabled ? 'set' :'remove']('disabled', 'disabled');
+
+        if (button.classes) {
+          attributes.addClass(Object.keys(button.classes).map(function(key) { return button.classes[key]; }));
+        }
+        if (button['class']) {
+          attributes.addClass(button['class']);
+        }
+
+        return Drupal.theme('button', attributes);
+      }
+
+    });
+
+  });
+
+
+})(window.jQuery, window.Drupal, window.Drupal.bootstrap, window.Attributes, window.drupalSettings);