Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 18... Línea 18...
18
 *
18
 *
19
 * @module     theme_universe/drawers
19
 * @module     theme_universe/drawers
20
 * @copyright  2021 Bas Brands
20
 * @copyright  2021 Bas Brands
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
22
 */
-
 
23
import ModalBackdrop from 'core/modal_backdrop';
-
 
24
import Templates from 'core/templates';
-
 
25
import * as Aria from 'core/aria';
-
 
26
import {dispatchEvent} from 'core/event_dispatcher';
-
 
27
import {debounce} from 'core/utils';
-
 
28
import {isSmall, isLarge} from 'core/pagehelpers';
-
 
29
import Pending from 'core/pending';
-
 
30
import {setUserPreference} from 'core_user/repository';
-
 
31
import Tooltip from './bootstrap/tooltip';
Línea 23... Línea 32...
23
 
32
 
24
define(function (require) {
-
 
Línea 25... Línea -...
25
  "use strict";
-
 
26
 
-
 
27
  const ModalBackdrop = require("core/modal_backdrop");
-
 
28
  const Templates = require("core/templates");
-
 
29
  const Aria = require("core/aria");
-
 
30
  const { dispatchEvent } = require("core/event_dispatcher");
-
 
31
  const { debounce } = require("core/utils");
-
 
32
  const { isSmall, isLarge } = require("core/pagehelpers");
-
 
33
  const Pending = require("core/pending");
-
 
34
  const UserRepository = require("core_user/repository");
33
let backdropPromise = null;
Línea 35... Línea -...
35
  // The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-71979 is integrated.
-
 
36
  const jQuery = require("jquery");
-
 
37
 
-
 
38
  let backdropPromise = null;
-
 
39
 
34
 
40
  const drawerMap = new Map();
35
const drawerMap = new Map();
41
 
36
 
42
  const SELECTORS = {
37
const SELECTORS = {
43
    BUTTONS: '[data-toggler="drawers"]',
38
    BUTTONS: '[data-toggler="drawers"]',
44
    CLOSEBTN: '[data-toggler="drawers"][data-action="closedrawer"]',
39
    CLOSEBTN: '[data-toggler="drawers"][data-action="closedrawer"]',
45
    OPENBTN: '[data-toggler="drawers"][data-action="opendrawer"]',
40
    OPENBTN: '[data-toggler="drawers"][data-action="opendrawer"]',
46
    TOGGLEBTN: '[data-toggler="drawers"][data-action="toggle"]',
41
    TOGGLEBTN: '[data-toggler="drawers"][data-action="toggle"]',
47
    DRAWERS: '[data-region="fixed-drawer"]',
42
    DRAWERS: '[data-region="fixed-drawer"]',
48
    DRAWERCONTENT: ".drawercontent",
43
    DRAWERCONTENT: '.drawercontent',
49
    PAGECONTENT: "#page-content",
44
    PAGECONTENT: '#page-content',
50
    HEADERCONTENT: ".drawerheadercontent",
45
    HEADERCONTENT: '.drawerheadercontent',
51
  };
46
};
52
 
47
 
53
  const CLASSES = {
48
const CLASSES = {
54
    SCROLLED: "scrolled",
49
    SCROLLED: 'scrolled',
55
    SHOW: "show",
50
    SHOW: 'show',
56
    NOTINITIALISED: "not-initialized",
51
    NOTINITIALISED: 'not-initialized',
57
  };
52
};
58
 
53
 
59
  /**
54
/**
60
   * Pixel thresshold to auto-hide drawers.
55
 * Pixel thresshold to auto-hide drawers.
61
   *
56
 *
62
   * @type {Number}
57
 * @type {Number}
63
   */
58
 */
64
  const THRESHOLD = 20;
59
const THRESHOLD = 20;
65
 
60
 
66
  /**
61
/**
67
   * Try to get the drawer z-index from the page content.
62
 * Try to get the drawer z-index from the page content.
68
   *
63
 *
69
   * @returns {Number|null} the z-index of the drawer.
64
 * @returns {Number|null} the z-index of the drawer.
70
   * @private
65
 * @private
71
   */
66
 */
72
  const getDrawerZIndex = () => {
67
const getDrawerZIndex = () => {
73
    const drawer = document.querySelector(SELECTORS.DRAWERS);
68
    const drawer = document.querySelector(SELECTORS.DRAWERS);
74
    if (!drawer) {
69
    if (!drawer) {
75
      return null;
70
        return null;
Línea 76... Línea 71...
76
    }
71
    }
77
    return parseInt(window.getComputedStyle(drawer).zIndex, 10);
72
    return parseInt(window.getComputedStyle(drawer).zIndex, 10);
78
  };
73
};
79
 
74
 
80
  /**
75
/**
81
   * Add a backdrop to the page.
76
 * Add a backdrop to the page.
82
   *
77
 *
83
   * @returns {Promise} rendering of modal backdrop.
78
 * @returns {Promise} rendering of modal backdrop.
84
   * @private
79
 * @private
85
   */
80
 */
86
  const getBackdrop = () => {
81
const getBackdrop = () => {
87
    if (!backdropPromise) {
82
    if (!backdropPromise) {
88
      backdropPromise = Templates.render("core/modal_backdrop", {})
83
        backdropPromise = Templates.render('core/modal_backdrop', {})
89
        .then((html) => new ModalBackdrop(html))
84
        .then(html => new ModalBackdrop(html))
90
        .then((modalBackdrop) => {
85
        .then(modalBackdrop => {
91
          const drawerZindex = getDrawerZIndex();
-
 
92
          if (drawerZindex) {
-
 
93
            modalBackdrop.setZIndex(getDrawerZIndex() - 1);
-
 
94
          }
86
            const drawerZindex = getDrawerZIndex();
95
          modalBackdrop
87
            if (drawerZindex) {
96
            .getAttachmentPoint()
88
                modalBackdrop.setZIndex(getDrawerZIndex() - 1);
97
            .get(0)
89
            }
98
            .addEventListener("click", (e) => {
90
            modalBackdrop.getAttachmentPoint().get(0).addEventListener('click', e => {
99
              e.preventDefault();
91
                e.preventDefault();
100
              Drawers.closeAllDrawers();
92
                Drawers.closeAllDrawers();
101
            });
93
            });
102
          return modalBackdrop;
94
            return modalBackdrop;
103
        })
95
        })
Línea 104... Línea 96...
104
        .catch();
96
        .catch();
105
    }
97
    }
106
    return backdropPromise;
98
    return backdropPromise;
107
  };
99
};
108
 
100
 
109
  /**
101
/**
110
   * Get the button element to open a specific drawer.
102
 * Get the button element to open a specific drawer.
111
   *
103
 *
112
   * @param {String} drawerId the drawer element Id
-
 
113
   * @return {HTMLElement|undefined} the open button element
104
 * @param {String} drawerId the drawer element Id
114
   * @private
-
 
115
   */
105
 * @return {HTMLElement|undefined} the open button element
116
  const getDrawerOpenButton = (drawerId) => {
-
 
117
    let openButton = document.querySelector(
106
 * @private
118
      `${SELECTORS.OPENBTN}[data-target="${drawerId}"]`
-
 
119
    );
107
 */
120
    if (!openButton) {
108
const getDrawerOpenButton = (drawerId) => {
121
      openButton = document.querySelector(
109
    let openButton = document.querySelector(`${SELECTORS.OPENBTN}[data-target="${drawerId}"]`);
Línea 122... Línea 110...
122
        `${SELECTORS.TOGGLEBTN}[data-target="${drawerId}"]`
110
    if (!openButton) {
123
      );
111
        openButton = document.querySelector(`${SELECTORS.TOGGLEBTN}[data-target="${drawerId}"]`);
124
    }
112
    }
125
    return openButton;
113
    return openButton;
126
  };
114
};
127
 
115
 
128
  /**
116
/**
129
   * Disable drawer tooltips.
117
 * Disable drawer tooltips.
130
   *
118
 *
131
   * @param {HTMLElement} drawerNode the drawer main node
119
 * @param {HTMLElement} drawerNode the drawer main node
132
   * @private
120
 * @private
133
   */
121
 */
134
  const disableDrawerTooltips = (drawerNode) => {
122
const disableDrawerTooltips = (drawerNode) => {
135
    const buttons = [
123
    const buttons = [
136
      drawerNode.querySelector(SELECTORS.CLOSEBTN),
124
        drawerNode.querySelector(SELECTORS.CLOSEBTN),
137
      getDrawerOpenButton(drawerNode.id),
125
        getDrawerOpenButton(drawerNode.id),
138
    ];
126
    ];
139
    buttons.forEach((button) => {
127
    buttons.forEach(button => {
Línea 140... Línea 128...
140
      if (!button) {
128
        if (!button) {
141
        return;
129
            return;
142
      }
130
        }
143
      disableButtonTooltip(button);
131
        disableButtonTooltip(button);
144
    });
132
    });
145
  };
133
};
146
 
134
 
147
  /**
135
/**
148
   * Disable the button tooltips.
136
 * Disable the button tooltips.
149
   *
-
 
150
   * @param {HTMLElement} button the button element
137
 *
151
   * @param {boolean} enableOnBlur if the tooltip must be re-enabled on blur.
138
 * @param {HTMLElement} button the button element
152
   * @private
139
 * @param {boolean} enableOnBlur if the tooltip must be re-enabled on blur.
153
   */
140
 * @private
154
  const disableButtonTooltip = (button, enableOnBlur) => {
141
 */
155
    if (button.hasAttribute("data-original-title")) {
142
const disableButtonTooltip = (button, enableOnBlur) => {
156
      // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.
143
    if (button.hasAttribute('data-original-title')) {
157
      jQuery(button).tooltip("disable");
144
        Tooltip.getInstance(button).disable();
158
      button.setAttribute("title", button.dataset.originalTitle);
145
        button.setAttribute('title', button.dataset.originalTitle);
159
    } else {
146
    } else {
Línea 160... Línea 147...
160
      button.dataset.disabledToggle = button.dataset.toggle;
147
        button.dataset.disabledToggle = button.dataset.toggle;
161
      button.removeAttribute("data-toggle");
148
        button.removeAttribute('data-bs-toggle');
162
    }
149
    }
163
    if (enableOnBlur) {
150
    if (enableOnBlur) {
164
      button.dataset.restoreTooltipOnBlur = true;
151
        button.dataset.restoreTooltipOnBlur = true;
165
    }
152
    }
166
  };
153
};
167
 
154
 
168
  /**
155
/**
169
   * Enable drawer tooltips.
156
 * Enable drawer tooltips.
170
   *
157
 *
171
   * @param {HTMLElement} drawerNode the drawer main node
158
 * @param {HTMLElement} drawerNode the drawer main node
172
   * @private
159
 * @private
173
   */
160
 */
174
  const enableDrawerTooltips = (drawerNode) => {
161
const enableDrawerTooltips = (drawerNode) => {
175
    const buttons = [
162
    const buttons = [
176
      drawerNode.querySelector(SELECTORS.CLOSEBTN),
163
        drawerNode.querySelector(SELECTORS.CLOSEBTN),
177
      getDrawerOpenButton(drawerNode.id),
164
        getDrawerOpenButton(drawerNode.id),
Línea 178... Línea 165...
178
    ];
165
    ];
179
    buttons.forEach((button) => {
166
    buttons.forEach(button => {
180
      if (!button) {
167
        if (!button) {
181
        return;
168
            return;
182
      }
169
        }
183
      enableButtonTooltip(button);
170
        enableButtonTooltip(button);
184
    });
171
    });
185
  };
-
 
186
 
172
};
187
  /**
173
 
188
   * Enable the button tooltips.
174
/**
189
   *
175
 * Enable the button tooltips.
190
   * @param {HTMLElement} button the button element
176
 *
191
   * @private
177
 * @param {HTMLElement} button the button element
192
   */
178
 * @private
193
  const enableButtonTooltip = (button) => {
179
 */
194
    // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.
180
const enableButtonTooltip = (button) => {
Línea 195... Línea 181...
195
    if (button.hasAttribute("data-original-title")) {
181
    if (button.hasAttribute('data-bs-original-title')) {
196
      jQuery(button).tooltip("enable");
182
        Tooltip.getInstance(button).enable();
197
      button.removeAttribute("title");
183
        button.removeAttribute('title');
198
    } else if (button.dataset.disabledToggle) {
184
    } else if (button.dataset.disabledToggle) {
199
      button.dataset.toggle = button.dataset.disabledToggle;
185
        button.dataset.toggle = button.dataset.disabledToggle;
200
      jQuery(button).tooltip();
186
        new Tooltip(button);
201
    }
187
    }
202
    delete button.dataset.restoreTooltipOnBlur;
188
    delete button.dataset.restoreTooltipOnBlur;
203
  };
189
};
204
 
190
 
205
  /**
191
/**
206
   * Add scroll listeners to a drawer element.
192
 * Add scroll listeners to a drawer element.
207
   *
193
 *
-
 
194
 * @param {HTMLElement} drawerNode the drawer main node
-
 
195
 * @private
-
 
196
 */
208
   * @param {HTMLElement} drawerNode the drawer main node
197
const addInnerScrollListener = (drawerNode) => {
209
   * @private
198
    const content = drawerNode.querySelector(SELECTORS.DRAWERCONTENT);
Línea 210... Línea 199...
210
   */
199
    if (!content) {
211
  const addInnerScrollListener = (drawerNode) => {
200
        return;
212
    const content = drawerNode.querySelector(SELECTORS.DRAWERCONTENT);
201
    }
213
    if (!content) {
202
    content.addEventListener("scroll", () => {
214
      return;
203
        drawerNode.classList.toggle(
215
    }
204
            CLASSES.SCROLLED,
216
    content.addEventListener("scroll", () => {
205
            content.scrollTop != 0
217
      drawerNode.classList.toggle(CLASSES.SCROLLED, content.scrollTop != 0);
206
        );
218
    });
207
    });
219
  };
208
};
220
 
209
 
221
  /**
210
/**
222
   * The Drawers class is used to control on-screen drawer elements.
211
 * The Drawers class is used to control on-screen drawer elements.
223
   *
212
 *
224
   * It handles opening, and closing of drawer elements, as well as more detailed behaviours such as closing a drawer when
213
 * It handles opening, and closing of drawer elements, as well as more detailed behaviours such as closing a drawer when
225
   * another drawer is opened, and supports closing a drawer when the screen is resized.
214
 * another drawer is opened, and supports closing a drawer when the screen is resized.
226
   *
215
 *
227
   * Drawers are instantiated on page load, and can also be toggled lazily when toggling any drawer toggle, open button,
216
 * Drawers are instantiated on page load, and can also be toggled lazily when toggling any drawer toggle, open button,
228
   * or close button.
217
 * or close button.
229
   *
218
 *
230
   * A range of show and hide events are also dispatched as detailed in the class
219
 * A range of show and hide events are also dispatched as detailed in the class
231
   * {@link module:theme_universe/drawers#eventTypes eventTypes} object.
220
 * {@link module:theme_universe/drawers#eventTypes eventTypes} object.
232
   *
221
 *
233
   * @example <caption>Standard usage</caption>
222
 * @example <caption>Standard usage</caption>
234
   *
223
 *
235
   * // The module just needs to be included to add drawer support.
224
 * // The module just needs to be included to add drawer support.
236
   * import 'theme_universe/drawers';
225
 * import 'theme_universe/drawers';
237
   *
226
 *
238
   * @example <caption>Manually open or close any drawer</caption>
227
 * @example <caption>Manually open or close any drawer</caption>
239
   *
228
 *
240
   * import Drawers from 'theme_universe/drawers';
229
 * import Drawers from 'theme_universe/drawers';
241
   *
230
 *
242
   * const myDrawer = Drawers.getDrawerInstanceForNode(document.querySelector('.myDrawerNode');
231
 * const myDrawer = Drawers.getDrawerInstanceForNode(document.querySelector('.myDrawerNode');
243
   * myDrawer.closeDrawer();
232
 * myDrawer.closeDrawer();
244
   *
233
 *
245
   * @example <caption>Listen to the before show event and cancel it</caption>
234
 * @example <caption>Listen to the before show event and cancel it</caption>
246
   *
235
 *
247
   * import Drawers from 'theme_universe/drawers';
236
 * import Drawers from 'theme_universe/drawers';
248
   *
237
 *
249
   * document.addEventListener(Drawers.eventTypes.drawerShow, e => {
238
 * document.addEventListener(Drawers.eventTypes.drawerShow, e => {
250
   *     // The drawer which will be shown.
239
 *     // The drawer which will be shown.
251
   *     window.console.log(e.target);
240
 *     window.console.log(e.target);
252
   *
241
 *
253
   *     // The instance of the Drawers class for this drawer.
242
 *     // The instance of the Drawers class for this drawer.
254
   *     window.console.log(e.detail.drawerInstance);
243
 *     window.console.log(e.detail.drawerInstance);
255
   *
244
 *
256
   *     // Prevent this drawer from being shown.
245
 *     // Prevent this drawer from being shown.
257
   *     e.preventDefault();
246
 *     e.preventDefault();
258
   * });
247
 * });
259
   *
248
 *
260
   * @example <caption>Listen to the shown event</caption>
249
 * @example <caption>Listen to the shown event</caption>
261
   *
250
 *
262
   * document.addEventListener(Drawers.eventTypes.drawerShown, e => {
251
 * document.addEventListener(Drawers.eventTypes.drawerShown, e => {
263
   *     // The drawer which was shown.
252
 *     // The drawer which was shown.
Línea 278... Línea 267...
278
     * @var {DOMRect} boundingRect
267
     * @var {DOMRect} boundingRect
279
     */
268
     */
280
    boundingRect = null;
269
    boundingRect = null;
Línea 281... Línea 270...
281
 
270
 
282
    constructor(drawerNode) {
271
    constructor(drawerNode) {
283
      // Some behat tests may use fake drawer divs to test components in drawers.
272
        // Some behat tests may use fake drawer divs to test components in drawers.
284
      if (drawerNode.dataset.behatFakeDrawer !== undefined) {
273
        if (drawerNode.dataset.behatFakeDrawer !== undefined) {
285
        return;
274
            return;
Línea 286... Línea 275...
286
      }
275
        }
Línea 287... Línea 276...
287
 
276
 
288
      this.drawerNode = drawerNode;
-
 
289
 
277
        this.drawerNode = drawerNode;
290
      if (isSmall()) {
-
 
291
        this.closeDrawer({
278
 
292
          focusOnOpenButton: false,
-
 
Línea 293... Línea 279...
293
          updatePreferences: false,
279
        if (isSmall()) {
294
        });
280
            this.closeDrawer({focusOnOpenButton: false, updatePreferences: false});
295
      }
281
        }
296
 
282
 
297
      if (this.drawerNode.classList.contains(CLASSES.SHOW)) {
283
        if (this.drawerNode.classList.contains(CLASSES.SHOW)) {
-
 
284
            this.openDrawer({focusOnCloseButton: false, setUserPref: false});
-
 
285
        } else if (this.drawerNode.dataset.forceopen == 1) {
-
 
286
            if (!isSmall()) {
298
        this.openDrawer({ focusOnCloseButton: false });
287
                this.openDrawer({focusOnCloseButton: false, setUserPref: false});
299
      } else if (this.drawerNode.dataset.forceopen == 1) {
-
 
300
        if (!isSmall()) {
-
 
301
          this.openDrawer({ focusOnCloseButton: false });
-
 
Línea 302... Línea 288...
302
        }
288
            }
303
      } else {
289
        } else {
304
        Aria.hide(this.drawerNode);
290
            Aria.hide(this.drawerNode);
305
      }
291
        }
Línea 306... Línea 292...
306
 
292
 
Línea 307... Línea 293...
307
      // Disable tooltips in small screens.
293
        // Disable tooltips in small screens.
Línea 308... Línea 294...
308
      if (isSmall()) {
294
        if (isSmall()) {
309
        disableDrawerTooltips(this.drawerNode);
295
            disableDrawerTooltips(this.drawerNode);
Línea 310... Línea 296...
310
      }
296
        }
311
 
297
 
312
      addInnerScrollListener(this.drawerNode);
298
        addInnerScrollListener(this.drawerNode);
313
 
299
 
314
      drawerMap.set(drawerNode, this);
300
        drawerMap.set(drawerNode, this);
315
 
301
 
316
      drawerNode.classList.remove(CLASSES.NOTINITIALISED);
302
        drawerNode.classList.remove(CLASSES.NOTINITIALISED);
317
    }
303
    }
Línea 318... Línea 304...
318
 
304
 
319
    /**
305
    /**
320
     * Whether the drawer is open.
306
     * Whether the drawer is open.
321
     *
307
     *
322
     * @returns {boolean}
308
     * @returns {boolean}
323
     */
309
     */
324
    get isOpen() {
310
    get isOpen() {
325
      return this.drawerNode.classList.contains(CLASSES.SHOW);
311
        return this.drawerNode.classList.contains(CLASSES.SHOW);
Línea 326... Línea 312...
326
    }
312
    }
327
 
313
 
328
    /**
314
    /**
Línea 342... Línea 328...
342
     * @property {String} drawerShown See {@link event:theme_universe/drawers:shown}
328
     * @property {String} drawerShown See {@link event:theme_universe/drawers:shown}
343
     * @property {String} drawerHide See {@link event:theme_universe/drawers:hide}
329
     * @property {String} drawerHide See {@link event:theme_universe/drawers:hide}
344
     * @property {String} drawerHidden See {@link event:theme_universe/drawers:hidden}
330
     * @property {String} drawerHidden See {@link event:theme_universe/drawers:hidden}
345
     */
331
     */
346
    static eventTypes = {
332
    static eventTypes = {
347
      /**
333
        /**
348
       * An event triggered before a drawer is shown.
334
         * An event triggered before a drawer is shown.
349
       *
335
         *
350
       * @event theme_universe/drawers:show
336
         * @event theme_universe/drawers:show
351
       * @type {CustomEvent}
337
         * @type {CustomEvent}
352
       * @property {HTMLElement} target The drawer that will be opened.
338
         * @property {HTMLElement} target The drawer that will be opened.
353
       */
339
         */
354
      drawerShow: "theme_universe/drawers:show",
340
        drawerShow: 'theme_universe/drawers:show',
355
 
341
 
356
      /**
342
        /**
357
       * An event triggered after a drawer is shown.
343
         * An event triggered after a drawer is shown.
358
       *
344
         *
359
       * @event theme_universe/drawers:shown
345
         * @event theme_universe/drawers:shown
360
       * @type {CustomEvent}
346
         * @type {CustomEvent}
361
       * @property {HTMLElement} target The drawer that was be opened.
347
         * @property {HTMLElement} target The drawer that was be opened.
362
       */
348
         */
363
      drawerShown: "theme_universe/drawers:shown",
349
        drawerShown: 'theme_universe/drawers:shown',
364
 
350
 
365
      /**
351
        /**
366
       * An event triggered before a drawer is hidden.
352
         * An event triggered before a drawer is hidden.
367
       *
353
         *
368
       * @event theme_universe/drawers:hide
354
         * @event theme_universe/drawers:hide
369
       * @type {CustomEvent}
355
         * @type {CustomEvent}
370
       * @property {HTMLElement} target The drawer that will be hidden.
356
         * @property {HTMLElement} target The drawer that will be hidden.
371
       */
357
         */
372
      drawerHide: "theme_universe/drawers:hide",
358
        drawerHide: 'theme_universe/drawers:hide',
373
 
359
 
374
      /**
360
        /**
375
       * An event triggered after a drawer is hidden.
361
         * An event triggered after a drawer is hidden.
376
       *
362
         *
377
       * @event theme_universe/drawers:hidden
363
         * @event theme_universe/drawers:hidden
378
       * @type {CustomEvent}
364
         * @type {CustomEvent}
379
       * @property {HTMLElement} target The drawer that was be hidden.
365
         * @property {HTMLElement} target The drawer that was be hidden.
380
       */
366
         */
381
      drawerHidden: "theme_universe/drawers:hidden",
367
        drawerHidden: 'theme_universe/drawers:hidden',
382
    };
368
    };
Línea -... Línea 369...
-
 
369
 
383
 
370
 
384
    /**
371
    /**
385
     * Get the drawer instance for the specified node
372
     * Get the drawer instance for the specified node
386
     *
373
     *
387
     * @param {HTMLElement} drawerNode
374
     * @param {HTMLElement} drawerNode
388
     * @returns {module:theme_universe/drawers}
375
     * @returns {module:theme_universe/drawers}
389
     */
376
     */
390
    static getDrawerInstanceForNode(drawerNode) {
377
    static getDrawerInstanceForNode(drawerNode) {
391
      if (!drawerMap.has(drawerNode)) {
378
        if (!drawerMap.has(drawerNode)) {
392
        new Drawers(drawerNode);
379
            new Drawers(drawerNode);
Línea 393... Línea 380...
393
      }
380
        }
394
 
381
 
Línea 395... Línea 382...
395
      return drawerMap.get(drawerNode);
382
        return drawerMap.get(drawerNode);
396
    }
383
    }
397
 
384
 
398
    /**
385
    /**
399
     * Dispatch a drawer event.
386
     * Dispatch a drawer event.
400
     *
387
     *
401
     * @param {string} eventname the event name
388
     * @param {string} eventname the event name
402
     * @param {boolean} cancelable if the event is cancelable
389
     * @param {boolean} cancelable if the event is cancelable
403
     * @returns {CustomEvent} the resulting custom event
390
     * @returns {CustomEvent} the resulting custom event
404
     */
391
     */
405
    dispatchEvent(eventname, cancelable = false) {
392
    dispatchEvent(eventname, cancelable = false) {
406
      return dispatchEvent(
393
        return dispatchEvent(
407
        eventname,
394
            eventname,
408
        {
395
            {
409
          drawerInstance: this,
396
                drawerInstance: this,
410
        },
397
            },
411
        this.drawerNode,
398
            this.drawerNode,
412
        {
399
            {
413
          cancelable,
400
                cancelable,
Línea 414... Línea 401...
414
        }
401
            }
415
      );
402
        );
416
    }
403
    }
Línea 422... Línea 409...
422
     * load, this represents an accessibility problem as the initial focus changes without any user interaction. The
409
     * load, this represents an accessibility problem as the initial focus changes without any user interaction. The
423
     * focusOnCloseButton parameter can be set to false to prevent this behaviour.
410
     * focusOnCloseButton parameter can be set to false to prevent this behaviour.
424
     *
411
     *
425
     * @param {object} args
412
     * @param {object} args
426
     * @param {boolean} [args.focusOnCloseButton=true] Whether to alter page focus when opening the drawer
413
     * @param {boolean} [args.focusOnCloseButton=true] Whether to alter page focus when opening the drawer
-
 
414
     * @param {boolean} [args.setUserPref=true] Whether to store the opened drawer state as a user preference
427
     */
415
     */
428
    openDrawer({ focusOnCloseButton = true } = {}) {
416
    openDrawer({focusOnCloseButton = true, setUserPref = true} = {}) {
-
 
417
 
429
      const pendingPromise = new Pending("theme_universe/drawers:open");
418
        const pendingPromise = new Pending('theme_universe/drawers:open');
430
      const showEvent = this.dispatchEvent(Drawers.eventTypes.drawerShow, true);
419
        const showEvent = this.dispatchEvent(Drawers.eventTypes.drawerShow, true);
431
      if (showEvent.defaultPrevented) {
420
        if (showEvent.defaultPrevented) {
432
        return;
421
            return;
433
      }
422
        }
Línea 434... Línea 423...
434
 
423
 
435
      // Hide close button and header content while the drawer is showing to prevent glitchy effects.
-
 
436
      this.drawerNode
424
        // Hide close button and header content while the drawer is showing to prevent glitchy effects.
437
        .querySelector(SELECTORS.CLOSEBTN)
-
 
438
        ?.classList.toggle("hidden", true);
-
 
439
      this.drawerNode
425
        this.drawerNode.querySelector(SELECTORS.CLOSEBTN)?.classList.toggle('hidden', true);
440
        .querySelector(SELECTORS.HEADERCONTENT)
-
 
441
        ?.classList.toggle("hidden", true);
-
 
442
 
-
 
443
      // Remove open tooltip if still visible.
-
 
444
      let openButton = getDrawerOpenButton(this.drawerNode.id);
-
 
445
      if (openButton && openButton.hasAttribute("data-original-title")) {
-
 
446
        // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.
-
 
447
        jQuery(openButton)?.tooltip("hide");
-
 
448
      }
-
 
449
 
-
 
450
      Aria.unhide(this.drawerNode);
-
 
451
      this.drawerNode.classList.add(CLASSES.SHOW);
-
 
452
 
-
 
453
      const preference = this.drawerNode.dataset.preference;
-
 
454
      if (preference && !isSmall() && this.drawerNode.dataset.forceopen != 1) {
-
 
455
        UserRepository.setUserPreference(preference, true);
-
 
456
      }
-
 
457
 
-
 
458
      const state = this.drawerNode.dataset.state;
-
 
459
      if (state) {
-
 
460
        const page = document.getElementById("page");
-
 
461
        page.classList.add(state);
-
 
462
      }
-
 
463
 
-
 
464
      this.boundingRect = this.drawerNode.getBoundingClientRect();
-
 
465
 
-
 
466
      if (isSmall()) {
-
 
467
        getBackdrop()
-
 
468
          .then((backdrop) => {
-
 
Línea 469... Línea -...
469
            backdrop.show();
-
 
470
 
-
 
471
            const pageWrapper = document.getElementById("page");
-
 
472
            pageWrapper.style.overflow = "hidden";
-
 
473
            return backdrop;
-
 
474
          })
-
 
475
          .catch();
426
        this.drawerNode.querySelector(SELECTORS.HEADERCONTENT)?.classList.toggle('hidden', true);
476
      }
-
 
477
 
-
 
478
      // Show close button and header content once the drawer is fully opened.
-
 
479
      const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);
-
 
480
      const headerContent = this.drawerNode.querySelector(
-
 
481
        SELECTORS.HEADERCONTENT
427
 
482
      );
428
 
483
      if (focusOnCloseButton && closeButton) {
-
 
484
        disableButtonTooltip(closeButton, true);
-
 
485
      }
429
        // Remove open tooltip if still visible.
486
      setTimeout(() => {
-
 
487
        closeButton.classList.toggle("hidden", false);
430
        let openButton = getDrawerOpenButton(this.drawerNode.id);
488
        headerContent.classList.toggle("hidden", false);
-
 
489
        if (focusOnCloseButton) {
431
        if (openButton && openButton.hasAttribute('data-original-title')) {
490
          closeButton.focus();
-
 
491
        }
-
 
Línea -... Línea 432...
-
 
432
            Tooltip.getInstance(openButton)?.hide();
-
 
433
        }
-
 
434
 
-
 
435
        Aria.unhide(this.drawerNode);
-
 
436
        this.drawerNode.classList.add(CLASSES.SHOW);
-
 
437
 
-
 
438
        const preference = this.drawerNode.dataset.preference;
-
 
439
        if (preference && !isSmall() && (this.drawerNode.dataset.forceopen != 1) && setUserPref) {
-
 
440
            setUserPreference(preference, true);
-
 
441
        }
-
 
442
 
-
 
443
        const state = this.drawerNode.dataset.state;
-
 
444
        if (state) {
-
 
445
            const page = document.getElementById('page');
-
 
446
            page.classList.add(state);
-
 
447
        }
-
 
448
 
-
 
449
        this.boundingRect = this.drawerNode.getBoundingClientRect();
-
 
450
 
-
 
451
        if (isSmall()) {
-
 
452
            getBackdrop().then(backdrop => {
-
 
453
                backdrop.show();
-
 
454
 
-
 
455
                const pageWrapper = document.getElementById('page');
-
 
456
                pageWrapper.style.overflow = 'hidden';
-
 
457
                return backdrop;
-
 
458
            })
-
 
459
            .catch();
-
 
460
        }
-
 
461
 
-
 
462
        // Show close button and header content once the drawer is fully opened.
-
 
463
        const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);
-
 
464
        const headerContent = this.drawerNode.querySelector(SELECTORS.HEADERCONTENT);
-
 
465
        if (focusOnCloseButton && closeButton) {
-
 
466
            disableButtonTooltip(closeButton, true);
-
 
467
        }
-
 
468
        setTimeout(() => {
-
 
469
            closeButton.classList.toggle('hidden', false);
-
 
470
            headerContent.classList.toggle('hidden', false);
-
 
471
            if (focusOnCloseButton) {
-
 
472
                closeButton.focus();
-
 
473
            }
492
        pendingPromise.resolve();
474
            pendingPromise.resolve();
493
      }, 300);
475
        }, 300);
Línea 494... Línea 476...
494
 
476
 
495
      this.dispatchEvent(Drawers.eventTypes.drawerShown);
477
        this.dispatchEvent(Drawers.eventTypes.drawerShown);
496
    }
478
    }
497
 
479
 
498
    /**
480
    /**
499
     * Close the drawer.
481
     * Close the drawer.
500
     *
482
     *
501
     * @param {object} args
483
     * @param {object} args
502
     * @param {boolean} [args.focusOnOpenButton=true] Whether to alter page focus when opening the drawer
-
 
Línea -... Línea 484...
-
 
484
     * @param {boolean} [args.focusOnOpenButton=true] Whether to alter page focus when opening the drawer
-
 
485
     * @param {boolean} [args.updatePreferences=true] Whether to update the user prewference
503
     * @param {boolean} [args.updatePreferences=true] Whether to update the user prewference
486
     */
504
     */
487
    closeDrawer({focusOnOpenButton = true, updatePreferences = true} = {}) {
505
    closeDrawer({ focusOnOpenButton = true, updatePreferences = true } = {}) {
488
 
-
 
489
        const pendingPromise = new Pending('theme_universe/drawers:close');
-
 
490
 
-
 
491
        const hideEvent = this.dispatchEvent(Drawers.eventTypes.drawerHide, true);
-
 
492
        if (hideEvent.defaultPrevented) {
-
 
493
            return;
-
 
494
        }
-
 
495
 
-
 
496
        // Hide close button and header content while the drawer is hiding to prevent glitchy effects.
-
 
497
        const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);
-
 
498
        closeButton?.classList.toggle('hidden', true);
506
      const pendingPromise = new Pending("theme_universe/drawers:close");
499
        const headerContent = this.drawerNode.querySelector(SELECTORS.HEADERCONTENT);
Línea 507... Línea -...
507
 
-
 
508
      const hideEvent = this.dispatchEvent(Drawers.eventTypes.drawerHide, true);
-
 
509
      if (hideEvent.defaultPrevented) {
-
 
510
        return;
-
 
511
      }
-
 
512
 
-
 
513
      // Hide close button and header content while the drawer is hiding to prevent glitchy effects.
-
 
514
      const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);
-
 
515
      closeButton?.classList.toggle("hidden", true);
-
 
516
      const headerContent = this.drawerNode.querySelector(
-
 
517
        SELECTORS.HEADERCONTENT
-
 
518
      );
-
 
519
      headerContent?.classList.toggle("hidden", true);
-
 
520
      // Remove the close button tooltip if visible.
500
        headerContent?.classList.toggle('hidden', true);
521
      if (closeButton.hasAttribute("data-original-title")) {
501
        // Remove the close button tooltip if visible.
522
        // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.
502
        if (closeButton.hasAttribute('data-original-title')) {
523
        jQuery(closeButton)?.tooltip("hide");
503
            Tooltip.getInstance(closeButton)?.hide();
524
      }
504
        }
525
 
505
 
526
      const preference = this.drawerNode.dataset.preference;
506
        const preference = this.drawerNode.dataset.preference;
527
      if (preference && updatePreferences && !isSmall()) {
507
        if (preference && updatePreferences && !isSmall()) {
528
        UserRepository.setUserPreference(preference, false);
508
            setUserPreference(preference, false);
529
      }
509
        }
530
 
510
 
531
      const state = this.drawerNode.dataset.state;
511
        const state = this.drawerNode.dataset.state;
532
      if (state) {
512
        if (state) {
533
        const page = document.getElementById("page");
513
            const page = document.getElementById('page');
534
        page.classList.remove(state);
-
 
535
      }
514
            page.classList.remove(state);
536
 
515
        }
537
      Aria.hide(this.drawerNode);
516
 
538
      this.drawerNode.classList.remove(CLASSES.SHOW);
517
        Aria.hide(this.drawerNode);
539
 
518
        this.drawerNode.classList.remove(CLASSES.SHOW);
540
      getBackdrop()
519
 
541
        .then((backdrop) => {
520
        getBackdrop().then(backdrop => {
542
          backdrop.hide();
521
            backdrop.hide();
543
 
522
 
544
          if (isSmall()) {
523
            if (isSmall()) {
Línea 545... Línea 524...
545
            const pageWrapper = document.getElementById("page");
524
                const pageWrapper = document.getElementById('page');
546
            pageWrapper.style.overflow = "visible";
525
                pageWrapper.style.overflow = 'visible';
547
          }
526
            }
548
          return backdrop;
527
            return backdrop;
549
        })
-
 
550
        .catch();
-
 
551
 
-
 
552
      // Move focus to the open drawer (or toggler) button once the drawer is hidden.
-
 
553
      let openButton = getDrawerOpenButton(this.drawerNode.id);
528
        })
-
 
529
        .catch();
-
 
530
 
-
 
531
        // Move focus to the open drawer (or toggler) button once the drawer is hidden.
-
 
532
        let openButton = getDrawerOpenButton(this.drawerNode.id);
554
      if (openButton) {
533
        if (openButton) {
555
        disableButtonTooltip(openButton, true);
534
            disableButtonTooltip(openButton, true);
Línea 556... Línea 535...
556
      }
535
        }
557
      setTimeout(() => {
536
        setTimeout(() => {
Línea 558... Línea 537...
558
        if (openButton && focusOnOpenButton) {
537
            if (openButton && focusOnOpenButton) {
559
          openButton.focus();
538
                openButton.focus();
560
        }
539
            }
561
        pendingPromise.resolve();
540
            pendingPromise.resolve();
562
      }, 300);
541
        }, 300);
563
 
542
 
564
      this.dispatchEvent(Drawers.eventTypes.drawerHidden);
543
        this.dispatchEvent(Drawers.eventTypes.drawerHidden);
565
    }
544
    }
566
 
545
 
567
    /**
546
    /**
Línea 568... Línea 547...
568
     * Toggle visibility of the drawer.
547
     * Toggle visibility of the drawer.
569
     */
548
     */
570
    toggleVisibility() {
549
    toggleVisibility() {
571
      if (this.drawerNode.classList.contains(CLASSES.SHOW)) {
550
        if (this.drawerNode.classList.contains(CLASSES.SHOW)) {
572
        this.closeDrawer();
551
            this.closeDrawer();
573
      } else {
552
        } else {
574
        this.openDrawer();
553
            this.openDrawer();
575
      }
554
        }
576
    }
555
    }
577
 
556
 
-
 
557
    /**
-
 
558
     * Displaces the drawer outsite the page.
-
 
559
     *
-
 
560
     * @param {Number} scrollPosition the page current scroll position
-
 
561
     */
-
 
562
    displace(scrollPosition) {
-
 
563
        let displace = scrollPosition;
-
 
564
        let openButton = getDrawerOpenButton(this.drawerNode.id);
-
 
565
        if (scrollPosition === 0) {
-
 
566
            this.drawerNode.style.transform = '';
-
 
567
            if (openButton) {
-
 
568
                openButton.style.transform = '';
-
 
569
            }
-
 
570
            return;
-
 
571
        }
-
 
572
        const state = this.drawerNode.dataset?.state;
-
 
573
        const drawrWidth = this.drawerNode.offsetWidth;
-
 
574
        let scrollThreshold = drawrWidth;
-
 
575
        let direction = -1;
578
    /**
576
        if (state === 'show-drawer-right') {
579
     * Displaces the drawer outsite the page.
577
            direction = 1;
580
     *
578
            scrollThreshold = THRESHOLD;
581
     * @param {Number} scrollPosition the page current scroll position
-
 
582
     */
-
 
583
    displace(scrollPosition) {
-
 
584
      let displace = scrollPosition;
-
 
585
      let openButton = getDrawerOpenButton(this.drawerNode.id);
-
 
586
      if (scrollPosition === 0) {
-
 
587
        this.drawerNode.style.transform = "";
-
 
588
        if (openButton) {
-
 
589
          openButton.style.transform = "";
-
 
590
        }
-
 
591
        return;
-
 
592
      }
-
 
593
      const state = this.drawerNode.dataset?.state;
-
 
594
      const drawrWidth = this.drawerNode.offsetWidth;
-
 
595
      let scrollThreshold = drawrWidth;
-
 
596
      let direction = -1;
-
 
597
      if (state === "show-drawer-right") {
-
 
598
        direction = 1;
-
 
599
        scrollThreshold = THRESHOLD;
-
 
600
      }
579
        }
601
      // LTR scroll is positive while RTL scroll is negative.
580
        // LTR scroll is positive while RTL scroll is negative.
Línea 602... Línea 581...
602
      if (Math.abs(scrollPosition) > scrollThreshold) {
581
        if (Math.abs(scrollPosition) > scrollThreshold) {
603
        displace = Math.sign(scrollPosition) * (drawrWidth + THRESHOLD);
582
            displace = Math.sign(scrollPosition) * (drawrWidth + THRESHOLD);
604
      }
583
        }
605
      displace *= direction;
584
        displace *= direction;
606
      const transform = `translateX(${displace}px)`;
585
        const transform = `translateX(${displace}px)`;
607
      if (openButton) {
586
        if (openButton) {
608
        openButton.style.transform = transform;
587
            openButton.style.transform = transform;
609
      }
-
 
610
      this.drawerNode.style.transform = transform;
-
 
611
    }
588
        }
612
 
-
 
613
    /**
589
        this.drawerNode.style.transform = transform;
614
     * Prevent drawer from overlapping an element.
590
    }
615
     *
591
 
616
     * @param {HTMLElement} currentFocus
592
    /**
617
     */
593
     * Prevent drawer from overlapping an element.
618
    preventOverlap(currentFocus) {
594
     *
619
      // Start position drawer (aka. left drawer) will never overlap with the page content.
595
     * @param {HTMLElement} currentFocus
620
      if (
596
     */
621
        !this.isOpen ||
597
    preventOverlap(currentFocus) {
622
        this.drawerNode.dataset?.state === "show-drawer-left"
598
        // Start position drawer (aka. left drawer) will never overlap with the page content.
623
      ) {
599
        if (!this.isOpen || this.drawerNode.dataset?.state === 'show-drawer-left') {
624
        return;
600
            return;
625
      }
601
        }
626
      const drawrWidth = this.drawerNode.offsetWidth;
602
        const drawrWidth = this.drawerNode.offsetWidth;
-
 
603
        const element = currentFocus.getBoundingClientRect();
627
      const element = currentFocus.getBoundingClientRect();
604
 
628
 
605
        // The this.boundingRect is calculated only once and it is reliable
629
      // The this.boundingRect is calculated only once and it is reliable
606
        // for horizontal overlapping (which is the most common). However,
630
      // for horizontal overlapping (which is the most common). However,
607
        // it is not reliable for vertical overlapping because the drawer
631
      // it is not reliable for vertical overlapping because the drawer
608
        // height can be changed by other elements like sticky footer.
-
 
609
        // To prevent recalculating the boundingRect on every
632
      // height can be changed by other elements like sticky footer.
610
        // focusin event, we use horizontal overlapping as first fast check.
633
      // To prevent recalculating the boundingRect on every
611
        let overlapping = (
634
      // focusin event, we use horizontal overlapping as first fast check.
612
            (element.right + THRESHOLD) > this.boundingRect.left &&
635
      let overlapping =
613
            (element.left - THRESHOLD) < this.boundingRect.right
636
        element.right + THRESHOLD > this.boundingRect.left &&
614
        );
637
        element.left - THRESHOLD < this.boundingRect.right;
615
        if (overlapping) {
638
      if (overlapping) {
616
            const currentBoundingRect = this.drawerNode.getBoundingClientRect();
639
        const currentBoundingRect = this.drawerNode.getBoundingClientRect();
617
            overlapping = (
640
        overlapping =
618
                (element.bottom) > currentBoundingRect.top &&
641
          element.bottom > currentBoundingRect.top &&
619
                (element.top) < currentBoundingRect.bottom
642
          element.top < currentBoundingRect.bottom;
620
            );
643
      }
621
        }
644
 
622
 
645
      if (overlapping) {
623
        if (overlapping) {
Línea 646... Línea 624...
646
        // Force drawer to displace out of the page.
624
            // Force drawer to displace out of the page.
647
        let displaceOut = drawrWidth + 1;
625
            let displaceOut = drawrWidth + 1;
648
        if (window.right_to_left()) {
626
            if (window.right_to_left()) {
649
          displaceOut *= -1;
627
                displaceOut *= -1;
650
        }
628
            }
651
        this.displace(displaceOut);
629
            this.displace(displaceOut);
652
      } else {
630
        } else {
653
        // Reset drawer displacement.
631
            // Reset drawer displacement.
Línea 654... Línea 632...
654
        this.displace(window.scrollX);
632
            this.displace(window.scrollX);
655
      }
633
        }
656
    }
634
    }
657
 
635
 
658
    /**
636
    /**
659
     * Close all drawers.
637
     * Close all drawers.
660
     */
638
     */
661
    static closeAllDrawers() {
639
    static closeAllDrawers() {
662
      drawerMap.forEach((drawerInstance) => {
640
        drawerMap.forEach(drawerInstance => {
663
        drawerInstance.closeDrawer();
641
            drawerInstance.closeDrawer();
Línea 664... Línea 642...
664
      });
642
        });
665
    }
643
    }
666
 
644
 
Línea 667... Línea 645...
667
    /**
645
    /**
668
     * Close all drawers except for the specified drawer.
646
     * Close all drawers except for the specified drawer.
669
     *
647
     *
670
     * @param {module:theme_universe/drawers} comparisonInstance
648
     * @param {module:theme_universe/drawers} comparisonInstance
671
     */
649
     */
672
    static closeOtherDrawers(comparisonInstance) {
650
    static closeOtherDrawers(comparisonInstance) {
673
      drawerMap.forEach((drawerInstance) => {
651
        drawerMap.forEach(drawerInstance => {
674
        if (drawerInstance === comparisonInstance) {
652
            if (drawerInstance === comparisonInstance) {
675
          return;
653
                return;
676
        }
654
            }
677
 
655
 
678
        drawerInstance.closeDrawer();
656
            drawerInstance.closeDrawer();
679
      });
657
        });
680
    }
658
    }
681
 
659
 
Línea 682... Línea 660...
682
    /**
660
    /**
683
     * Prevent drawers from covering the focused element.
661
     * Prevent drawers from covering the focused element.
684
     */
662
     */
685
    static preventCoveringFocusedElement() {
663
    static preventCoveringFocusedElement() {
686
      const currentFocus = document.activeElement;
664
        const currentFocus = document.activeElement;
687
      // Focus on page layout elements should be ignored.
665
        // Focus on page layout elements should be ignored.
688
      const pagecontent = document.querySelector(SELECTORS.PAGECONTENT);
666
        const pagecontent = document.querySelector(SELECTORS.PAGECONTENT);
689
      if (!currentFocus || !pagecontent?.contains(currentFocus)) {
667
        if (!currentFocus || !pagecontent?.contains(currentFocus)) {
690
        Drawers.displaceDrawers(window.scrollX);
668
            Drawers.displaceDrawers(window.scrollX);
691
        return;
669
            return;
692
      }
670
        }
693
      drawerMap.forEach((drawerInstance) => {
671
        drawerMap.forEach(drawerInstance => {
694
        drawerInstance.preventOverlap(currentFocus);
672
            drawerInstance.preventOverlap(currentFocus);
695
      });
673
        });
696
    }
674
    }
697
 
675
 
698
    /**
676
    /**
699
     * Prevent drawer from covering the content when the page content covers the full page.
677
     * Prevent drawer from covering the content when the page content covers the full page.
700
     *
678
     *
701
     * @param {Number} displace
-
 
702
     */
-
 
703
    static displaceDrawers(displace) {
679
     * @param {Number} displace
704
      drawerMap.forEach((drawerInstance) => {
-
 
705
        drawerInstance.displace(displace);
680
     */
706
      });
681
    static displaceDrawers(displace) {
707
    }
682
        drawerMap.forEach(drawerInstance => {
708
  }
683
            drawerInstance.displace(displace);
709
 
684
        });
710
  /**
685
    }
Línea 711... Línea 686...
711
   * Set the last used attribute for the last used toggle button for a drawer.
686
}
712
   *
687
 
713
   * @param {object} toggleButton The clicked button.
688
/**
714
   */
689
 * Set the last used attribute for the last used toggle button for a drawer.
715
  const setLastUsedToggle = (toggleButton) => {
690
 *
716
    if (toggleButton.dataset.target) {
-
 
717
      document
691
 * @param {object} toggleButton The clicked button.
718
        .querySelectorAll(
-
 
719
          `${SELECTORS.BUTTONS}[data-target="${toggleButton.dataset.target}"]`
692
 */
720
        )
693
const setLastUsedToggle = (toggleButton) => {
721
        .forEach((btn) => {
694
    if (toggleButton.dataset.target) {
722
          btn.dataset.lastused = false;
695
        document.querySelectorAll(`${SELECTORS.BUTTONS}[data-target="${toggleButton.dataset.target}"]`)
Línea 723... Línea 696...
723
        });
696
        .forEach(btn => {
724
      toggleButton.dataset.lastused = true;
697
            btn.dataset.lastused = false;
725
    }
698
        });
726
  };
699
        toggleButton.dataset.lastused = true;
727
 
700
    }
728
  /**
701
};
729
   * Set the focus to the last used button to open this drawer.
702
 
730
   * @param {string} target The drawer target.
703
/**
731
   */
704
 * Set the focus to the last used button to open this drawer.
732
  const focusLastUsedToggle = (target) => {
705
 * @param {string} target The drawer target.
733
    const lastUsedButton = document.querySelector(
706
 */
734
      `${SELECTORS.BUTTONS}[data-target="${target}"][data-lastused="true"`
707
const focusLastUsedToggle = (target) => {
735
    );
-
 
736
    if (lastUsedButton) {
-
 
737
      lastUsedButton.focus();
708
    const lastUsedButton = document.querySelector(`${SELECTORS.BUTTONS}[data-target="${target}"][data-lastused="true"`);
738
    }
709
    if (lastUsedButton) {
Línea 739... Línea 710...
739
  };
710
        lastUsedButton.focus();
740
 
711
    }
Línea 741... Línea 712...
741
  /**
712
};
742
   * Register the event listeners for the drawer.
713
 
743
   *
714
/**
744
   * @private
715
 * Register the event listeners for the drawer.
745
   */
-
 
746
  const registerListeners = () => {
-
 
747
    // Listen for show/hide events.
716
 *
748
    document.addEventListener("click", (e) => {
717
 * @private
Línea 749... Línea 718...
749
      const toggleButton = e.target.closest(SELECTORS.TOGGLEBTN);
718
 */
750
      if (toggleButton && toggleButton.dataset.target) {
719
const registerListeners = () => {
Línea 751... Línea 720...
751
        e.preventDefault();
720
    // Listen for show/hide events.
752
        const targetDrawer = document.getElementById(
721
    document.addEventListener('click', e => {
753
          toggleButton.dataset.target
722
        const toggleButton = e.target.closest(SELECTORS.TOGGLEBTN);
754
        );
723
        if (toggleButton && toggleButton.dataset.target) {
755
        const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);
-
 
756
        setLastUsedToggle(toggleButton);
-
 
757
 
724
            e.preventDefault();
Línea 758... Línea 725...
758
        drawerInstance.toggleVisibility();
725
            const targetDrawer = document.getElementById(toggleButton.dataset.target);
759
      }
726
            const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);
760
 
727
            setLastUsedToggle(toggleButton);
761
      const openDrawerButton = e.target.closest(SELECTORS.OPENBTN);
728
 
Línea 762... Línea 729...
762
      if (openDrawerButton && openDrawerButton.dataset.target) {
729
            drawerInstance.toggleVisibility();
763
        e.preventDefault();
730
        }
764
        const targetDrawer = document.getElementById(
731
 
765
          openDrawerButton.dataset.target
732
        const openDrawerButton = e.target.closest(SELECTORS.OPENBTN);
766
        );
733
        if (openDrawerButton && openDrawerButton.dataset.target) {
767
        const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);
734
            e.preventDefault();
768
        setLastUsedToggle(toggleButton);
735
            const targetDrawer = document.getElementById(openDrawerButton.dataset.target);
Línea 769... Línea 736...
769
 
736
            const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);
770
        drawerInstance.openDrawer();
737
            setLastUsedToggle(toggleButton);
771
      }
738
 
772
 
739
            drawerInstance.openDrawer();
773
      const closeDrawerButton = e.target.closest(SELECTORS.CLOSEBTN);
740
        }
774
      if (closeDrawerButton && closeDrawerButton.dataset.target) {
741
 
775
        e.preventDefault();
742
        const closeDrawerButton = e.target.closest(SELECTORS.CLOSEBTN);
776
        const targetDrawer = document.getElementById(
743
        if (closeDrawerButton && closeDrawerButton.dataset.target) {
Línea 777... Línea 744...
777
          closeDrawerButton.dataset.target
744
            e.preventDefault();
778
        );
745
            const targetDrawer = document.getElementById(closeDrawerButton.dataset.target);
779
        const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);
746
            const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);
780
 
747
 
781
        drawerInstance.closeDrawer();
748
            drawerInstance.closeDrawer();
782
        focusLastUsedToggle(closeDrawerButton.dataset.target);
749
            focusLastUsedToggle(closeDrawerButton.dataset.target);
-
 
750
        }
-
 
751
    });
-
 
752
 
783
      }
753
    // Close drawer when another drawer opens.
784
    });
754
    document.addEventListener(Drawers.eventTypes.drawerShow, e => {
785
 
755
        if (isLarge()) {
786
    // Close drawer when another drawer opens.
756
            return;
787
    document.addEventListener(Drawers.eventTypes.drawerShow, (e) => {
757
        }
788
      if (isLarge()) {
758
        Drawers.closeOtherDrawers(e.detail.drawerInstance);
789
        return;
759
    });
Línea 790... Línea 760...
790
      }
760
 
-
 
761
    // Tooglers and openers blur listeners.
-
 
762
    const btnSelector = `${SELECTORS.TOGGLEBTN}, ${SELECTORS.OPENBTN}, ${SELECTORS.CLOSEBTN}`;
791
      Drawers.closeOtherDrawers(e.detail.drawerInstance);
763
    document.addEventListener('focusout', (e) => {
-
 
764
        const button = e.target.closest(btnSelector);
792
    });
765
        if (button?.dataset.restoreTooltipOnBlur !== undefined) {
793
 
766
            enableButtonTooltip(button);
-
 
767
        }
794
    // Tooglers and openers blur listeners.
768
    });
795
    const btnSelector = `${SELECTORS.TOGGLEBTN}, ${SELECTORS.OPENBTN}, ${SELECTORS.CLOSEBTN}`;
-
 
796
    document.addEventListener("focusout", (e) => {
-
 
797
      const button = e.target.closest(btnSelector);
-
 
798
      if (button?.dataset.restoreTooltipOnBlur !== undefined) {
-
 
799
        enableButtonTooltip(button);
-
 
800
      }
-
 
801
    });
-
 
802
 
-
 
803
    const closeOnResizeListener = () => {
769
 
Línea 804... Línea 770...
804
      if (isSmall()) {
770
    const closeOnResizeListener = () => {
-
 
771
        if (isSmall()) {
-
 
772
            let anyOpen = false;
-
 
773
            drawerMap.forEach(drawerInstance => {
-
 
774
                disableDrawerTooltips(drawerInstance.drawerNode);
-
 
775
                if (drawerInstance.isOpen) {
-
 
776
                    const currentFocus = document.activeElement;
805
        let anyOpen = false;
777
                    const drawerContent = drawerInstance.drawerNode.querySelector(SELECTORS.DRAWERCONTENT);
806
        drawerMap.forEach((drawerInstance) => {
778
                    const shouldClose = drawerInstance.closeOnResize && (!drawerContent || !drawerContent.contains(currentFocus));
807
          disableDrawerTooltips(drawerInstance.drawerNode);
779
                    if (shouldClose) {
808
          if (drawerInstance.isOpen) {
780
                        drawerInstance.closeDrawer();
809
            if (drawerInstance.closeOnResize) {
781
                    } else {
810
              drawerInstance.closeDrawer();
782
                        anyOpen = true;
811
            } else {
783
                    }
812
              anyOpen = true;
784
                }
813
            }
785
            });
814
          }
786
 
Línea 815... Línea 787...
815
        });
787
            if (anyOpen) {
816
 
788
                getBackdrop().then(backdrop => backdrop.show()).catch();
817
        if (anyOpen) {
789
            }
818
          getBackdrop()
-
 
819
            .then((backdrop) => backdrop.show())
-
 
820
            .catch();
-
 
Línea 821... Línea 790...
821
        }
790
        } else {
-
 
791
            drawerMap.forEach(drawerInstance => {
Línea 822... Línea 792...
822
      } else {
792
                enableDrawerTooltips(drawerInstance.drawerNode);
823
        drawerMap.forEach((drawerInstance) => {
-
 
Línea 824... Línea 793...
824
          enableDrawerTooltips(drawerInstance.drawerNode);
793
            });
825
        });
-
 
-
 
794
            getBackdrop().then(backdrop => backdrop.hide()).catch();