/** * @file * Dropbutton feature. */ (function ($, Drupal) { 'use strict'; /** * Process elements with the .dropbutton class on page load. * * @type {Drupal~behavior} * * @prop {Drupal~behaviorAttach} attach * Attaches dropButton behaviors. */ Drupal.behaviors.dropButton = { attach: function (context, settings) { var $dropbuttons = $(context).find('.dropbutton-wrapper').once('dropbutton'); if ($dropbuttons.length) { // Adds the delegated handler that will toggle dropdowns on click. var $body = $('body').once('dropbutton-click'); if ($body.length) { $body.on('click', '.dropbutton-toggle', dropbuttonClickHandler); } // Initialize all buttons. var il = $dropbuttons.length; for (var i = 0; i < il; i++) { DropButton.dropbuttons.push(new DropButton($dropbuttons[i], settings.dropbutton)); } } } }; /** * Delegated callback for opening and closing dropbutton secondary actions. * * @function Drupal.DropButton~dropbuttonClickHandler * * @param {jQuery.Event} e * The event triggered. */ function dropbuttonClickHandler(e) { e.preventDefault(); $(e.target).closest('.dropbutton-wrapper').toggleClass('open'); } /** * A DropButton presents an HTML list as a button with a primary action. * * All secondary actions beyond the first in the list are presented in a * dropdown list accessible through a toggle arrow associated with the button. * * @constructor Drupal.DropButton * * @param {HTMLElement} dropbutton * A DOM element. * @param {object} settings * A list of options including: * @param {string} settings.title * The text inside the toggle link element. This text is hidden * from visual UAs. */ function DropButton(dropbutton, settings) { // Merge defaults with settings. var options = $.extend({title: Drupal.t('List additional actions')}, settings); var $dropbutton = $(dropbutton); /** * @type {jQuery} */ this.$dropbutton = $dropbutton; /** * @type {jQuery} */ this.$list = $dropbutton.find('.dropbutton'); /** * Find actions and mark them. * * @type {jQuery} */ this.$actions = this.$list.find('li').addClass('dropbutton-action'); // Add the special dropdown only if there are hidden actions. if (this.$actions.length > 1) { // Identify the first element of the collection. var $primary = this.$actions.slice(0, 1); // Identify the secondary actions. var $secondary = this.$actions.slice(1); $secondary.addClass('secondary-action'); // Add toggle link. $primary.after(Drupal.theme('dropbuttonToggle', options)); // Bind mouse events. this.$dropbutton .addClass('dropbutton-multiple') .on({ /** * Adds a timeout to close the dropdown on mouseleave. * * @ignore */ 'mouseleave.dropbutton': $.proxy(this.hoverOut, this), /** * Clears timeout when mouseout of the dropdown. * * @ignore */ 'mouseenter.dropbutton': $.proxy(this.hoverIn, this), /** * Similar to mouseleave/mouseenter, but for keyboard navigation. * * @ignore */ 'focusout.dropbutton': $.proxy(this.focusOut, this), /** * @ignore */ 'focusin.dropbutton': $.proxy(this.focusIn, this) }); } else { this.$dropbutton.addClass('dropbutton-single'); } } /** * Extend the DropButton constructor. */ $.extend(DropButton, /** @lends Drupal.DropButton */{ /** * Store all processed DropButtons. * * @type {Array.} */ dropbuttons: [] }); /** * Extend the DropButton prototype. */ $.extend(DropButton.prototype, /** @lends Drupal.DropButton# */{ /** * Toggle the dropbutton open and closed. * * @param {bool} [show] * Force the dropbutton to open by passing true or to close by * passing false. */ toggle: function (show) { var isBool = typeof show === 'boolean'; show = isBool ? show : !this.$dropbutton.hasClass('open'); this.$dropbutton.toggleClass('open', show); }, /** * @method */ hoverIn: function () { // Clear any previous timer we were using. if (this.timerID) { window.clearTimeout(this.timerID); } }, /** * @method */ hoverOut: function () { // Wait half a second before closing. this.timerID = window.setTimeout($.proxy(this, 'close'), 500); }, /** * @method */ open: function () { this.toggle(true); }, /** * @method */ close: function () { this.toggle(false); }, /** * @param {jQuery.Event} e * The event triggered. */ focusOut: function (e) { this.hoverOut.call(this, e); }, /** * @param {jQuery.Event} e * The event triggered. */ focusIn: function (e) { this.hoverIn.call(this, e); } }); $.extend(Drupal.theme, /** @lends Drupal.theme */{ /** * A toggle is an interactive element often bound to a click handler. * * @param {object} options * Options object. * @param {string} [options.title] * The HTML anchor title attribute and text for the inner span element. * * @return {string} * A string representing a DOM fragment. */ dropbuttonToggle: function (options) { return '
  • '; } }); // Expose constructor in the public space. Drupal.DropButton = DropButton; })(jQuery, Drupal);