Upgraded drupal core with security updates
[yaffs-website] / web / core / misc / dropbutton / dropbutton.js
1 /**
2  * @file
3  * Dropbutton feature.
4  */
5
6 (function ($, Drupal) {
7
8   'use strict';
9
10   /**
11    * Process elements with the .dropbutton class on page load.
12    *
13    * @type {Drupal~behavior}
14    *
15    * @prop {Drupal~behaviorAttach} attach
16    *   Attaches dropButton behaviors.
17    */
18   Drupal.behaviors.dropButton = {
19     attach: function (context, settings) {
20       var $dropbuttons = $(context).find('.dropbutton-wrapper').once('dropbutton');
21       if ($dropbuttons.length) {
22         // Adds the delegated handler that will toggle dropdowns on click.
23         var $body = $('body').once('dropbutton-click');
24         if ($body.length) {
25           $body.on('click', '.dropbutton-toggle', dropbuttonClickHandler);
26         }
27         // Initialize all buttons.
28         var il = $dropbuttons.length;
29         for (var i = 0; i < il; i++) {
30           DropButton.dropbuttons.push(new DropButton($dropbuttons[i], settings.dropbutton));
31         }
32       }
33     }
34   };
35
36   /**
37    * Delegated callback for opening and closing dropbutton secondary actions.
38    *
39    * @function Drupal.DropButton~dropbuttonClickHandler
40    *
41    * @param {jQuery.Event} e
42    *   The event triggered.
43    */
44   function dropbuttonClickHandler(e) {
45     e.preventDefault();
46     $(e.target).closest('.dropbutton-wrapper').toggleClass('open');
47   }
48
49   /**
50    * A DropButton presents an HTML list as a button with a primary action.
51    *
52    * All secondary actions beyond the first in the list are presented in a
53    * dropdown list accessible through a toggle arrow associated with the button.
54    *
55    * @constructor Drupal.DropButton
56    *
57    * @param {HTMLElement} dropbutton
58    *   A DOM element.
59    * @param {object} settings
60    *   A list of options including:
61    * @param {string} settings.title
62    *   The text inside the toggle link element. This text is hidden
63    *   from visual UAs.
64    */
65   function DropButton(dropbutton, settings) {
66     // Merge defaults with settings.
67     var options = $.extend({title: Drupal.t('List additional actions')}, settings);
68     var $dropbutton = $(dropbutton);
69
70     /**
71      * @type {jQuery}
72      */
73     this.$dropbutton = $dropbutton;
74
75     /**
76      * @type {jQuery}
77      */
78     this.$list = $dropbutton.find('.dropbutton');
79
80     /**
81      * Find actions and mark them.
82      *
83      * @type {jQuery}
84      */
85     this.$actions = this.$list.find('li').addClass('dropbutton-action');
86
87     // Add the special dropdown only if there are hidden actions.
88     if (this.$actions.length > 1) {
89       // Identify the first element of the collection.
90       var $primary = this.$actions.slice(0, 1);
91       // Identify the secondary actions.
92       var $secondary = this.$actions.slice(1);
93       $secondary.addClass('secondary-action');
94       // Add toggle link.
95       $primary.after(Drupal.theme('dropbuttonToggle', options));
96       // Bind mouse events.
97       this.$dropbutton
98         .addClass('dropbutton-multiple')
99         .on({
100
101           /**
102            * Adds a timeout to close the dropdown on mouseleave.
103            *
104            * @ignore
105            */
106           'mouseleave.dropbutton': $.proxy(this.hoverOut, this),
107
108           /**
109            * Clears timeout when mouseout of the dropdown.
110            *
111            * @ignore
112            */
113           'mouseenter.dropbutton': $.proxy(this.hoverIn, this),
114
115           /**
116            * Similar to mouseleave/mouseenter, but for keyboard navigation.
117            *
118            * @ignore
119            */
120           'focusout.dropbutton': $.proxy(this.focusOut, this),
121
122           /**
123            * @ignore
124            */
125           'focusin.dropbutton': $.proxy(this.focusIn, this)
126         });
127     }
128     else {
129       this.$dropbutton.addClass('dropbutton-single');
130     }
131   }
132
133   /**
134    * Extend the DropButton constructor.
135    */
136   $.extend(DropButton, /** @lends Drupal.DropButton */{
137     /**
138      * Store all processed DropButtons.
139      *
140      * @type {Array.<Drupal.DropButton>}
141      */
142     dropbuttons: []
143   });
144
145   /**
146    * Extend the DropButton prototype.
147    */
148   $.extend(DropButton.prototype, /** @lends Drupal.DropButton# */{
149
150     /**
151      * Toggle the dropbutton open and closed.
152      *
153      * @param {bool} [show]
154      *   Force the dropbutton to open by passing true or to close by
155      *   passing false.
156      */
157     toggle: function (show) {
158       var isBool = typeof show === 'boolean';
159       show = isBool ? show : !this.$dropbutton.hasClass('open');
160       this.$dropbutton.toggleClass('open', show);
161     },
162
163     /**
164      * @method
165      */
166     hoverIn: function () {
167       // Clear any previous timer we were using.
168       if (this.timerID) {
169         window.clearTimeout(this.timerID);
170       }
171     },
172
173     /**
174      * @method
175      */
176     hoverOut: function () {
177       // Wait half a second before closing.
178       this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
179     },
180
181     /**
182      * @method
183      */
184     open: function () {
185       this.toggle(true);
186     },
187
188     /**
189      * @method
190      */
191     close: function () {
192       this.toggle(false);
193     },
194
195     /**
196      * @param {jQuery.Event} e
197      *   The event triggered.
198      */
199     focusOut: function (e) {
200       this.hoverOut.call(this, e);
201     },
202
203     /**
204      * @param {jQuery.Event} e
205      *   The event triggered.
206      */
207     focusIn: function (e) {
208       this.hoverIn.call(this, e);
209     }
210   });
211
212   $.extend(Drupal.theme, /** @lends Drupal.theme */{
213
214     /**
215      * A toggle is an interactive element often bound to a click handler.
216      *
217      * @param {object} options
218      *   Options object.
219      * @param {string} [options.title]
220      *   The HTML anchor title attribute and text for the inner span element.
221      *
222      * @return {string}
223      *   A string representing a DOM fragment.
224      */
225     dropbuttonToggle: function (options) {
226       return '<li class="dropbutton-toggle"><button type="button"><span class="dropbutton-arrow"><span class="visually-hidden">' + options.title + '</span></span></button></li>';
227     }
228   });
229
230   // Expose constructor in the public space.
231   Drupal.DropButton = DropButton;
232
233 })(jQuery, Drupal);