PageSourceSearch

https://www.red.es/core/misc/dropbutton/dropbutton.js?v=11.3.12

js red.es collected 2026-09-24 08:27:00 UTC 5,981 bytes, 236 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.