PageSourceSearch

https://www.brotherssupply.com/wp-content/plugins/hozio-studio/components/drawer/drawer.js?ver=c296874084b8

js brotherssupply.com collected 2026-10-09 00:30:12 UTC 6,551 bytes, 128 lines download raw bytes

1/* ═════════════════════════════════════════════════════════════════════════
2   DRAWER / OFF-CANVAS — widget behavior (Phase-2; moved out of main.js)
3
4   Edge-anchored side panel sharing the modal's overlay mechanics — focus trap
5   + shared background inert/scroll lock stay in main.js (hzo.trapFocus /
6   hzo.lockOverlayBackground; cross-overlay primitives). As a shortcode widget
7   the drawer ALWAYS loads (drawer.php un-gates it). The drawer IIFE was
8   removed from main.js so behavior lives here. commerce.js opens the
9   mini-cart through hzo.openDrawer — that public name is preserved.
10
11   OPTION CONTRACT — data-attributes on `.hzo-drawer`; block pattern and
12   [hzo_drawer] shortcode drive the same behavior. All options default
13   OFF/legacy — attribute-free markup behaves exactly as before:
14
15     data-hzo-drawer-static      "true" → backdrop click does NOT close
16     data-hzo-drawer-esc         "false" → Esc does NOT close
17     data-hzo-drawer-auto-open   ms after init to auto-open (int; 0/absent =
18                                 off). Once per page load; skipped if another
19                                 overlay is already open at fire time.
20
21   Side/width are CSS concerns (.hzo-drawer--left, .hzo-drawer__panel--wide);
22   the shortcode maps its side/wide settings to those classes.
23
24   A11y (WAI-ARIA APG Dialog): panel carries role="dialog" + aria-modal; focus
25   trapped while open; background inert + scroll-locked; Esc closes (unless
26   opted out); focus returns to the trigger. Nested overlays stack via the
27   trap stack (a confirm modal over an open drawer works).
28
29   Public API (back-compat): hzo.openDrawer(idOrEl, trigger?) /
30   hzo.closeDrawer(idOrEl) · hzo.drawer = { init, setup, open, close }.
31   ═════════════════════════════════════════════════════════════════════════ */
32(function () {
33    'use strict';
34
35    function boolAttr(el, name, def) {
36        var v = el.getAttribute('data-hzo-drawer-' + name);
37        if (v === null || v === '') { return def; }
38        return v !== 'false' && v !== '0';
39    }
40
41    function openDrawer(drawer, trigger) {
42        if (!drawer || drawer.classList.contains('is-open')) { return; }
43        if (!window.hzo || typeof window.hzo.trapFocus !== 'function') { return; } // primitives (main.js) missing — never half-open
44        drawer.classList.add('is-open');
45        window.hzo.lockOverlayBackground();
46        var panel = drawer.querySelector('.hzo-drawer__panel') || drawer;
47        var initial = drawer.querySelector('[data-hzo-autofocus]') ||
48                      drawer.querySelector('.hzo-drawer__close') ||
49                      panel;
50        drawer._hzoTrap = window.hzo.trapFocus(panel, {
51            onEscape: function () { if (boolAttr(drawer, 'esc', true)) { closeDrawer(drawer); } },
52            initialFocus: initial,
53            returnFocus: trigger || document.activeElement
54        });
55    }
56
57    function closeDrawer(drawer) {
58        if (!drawer || !drawer.classList.contains('is-open')) { return; }
59        drawer.classList.remove('is-open');
60        if (window.hzo && window.hzo.unlockOverlayBackground) { window.hzo.unlockOverlayBackground(); }
61        if (drawer._hzoTrap) { drawer._hzoTrap(); drawer._hzoTrap = null; } // release() returns focus to the trigger
62    }
63
64    /* Portal to <body> + wire close affordances. Idempotent via ready guard. */
65    function setup(drawer) {
66        if (!drawer || drawer.getAttribute('data-hzo-drawer-ready') === 'true') { return; }
67        drawer.setAttribute('data-hzo-drawer-ready', 'true');
68
69        if (drawer.parentNode !== document.body) { document.body.appendChild(drawer); }
70
71        // G31: close only when the press ALSO began on the backdrop (a select/drag
72        // starting inside the panel and released on the backdrop must not close).
73        var pressTarget = null;
74        drawer.addEventListener('mousedown', function (e) { pressTarget = e.target; });
75        drawer.addEventListener('click', function (e) {
76            if (e.target === drawer) {                                  // backdrop click
77                if (pressTarget === drawer && !boolAttr(drawer, 'static', false)) { closeDrawer(drawer); }
78                pressTarget = null;
79                return;
80            }
81            if (e.target.closest('[data-hzo-drawer-close]')) { closeDrawer(drawer); }
82        });
83
84        var delay = parseInt(drawer.getAttribute('data-hzo-drawer-auto-open') || '', 10);
85        if (delay > 0) {
86            setTimeout(function () {
87                if (document.body.classList.contains('hzo-overlay-open')) { return; }
88                openDrawer(drawer, null);
89            }, delay);
90        }
91    }
92
93    function init(scope) {
94        var drawers = (scope || document).querySelectorAll('.hzo-drawer');
95        for (var d = 0; d < drawers.length; d++) { setup(drawers[d]); }
96    }
97
98    // Delegated triggers — dynamically-inserted triggers work too.
99    document.addEventListener('click', function (e) {
100        var trigger = e.target.closest('[data-hzo-drawer-open]');
101        if (!trigger) { return; }
102        var drawer = document.getElementById(trigger.getAttribute('data-hzo-drawer-open'));
103        if (!drawer) { return; }
104        e.preventDefault();
105        setup(drawer);   // covers drawers injected after init (AJAX content)
106        openDrawer(drawer, trigger);
107    });
108
109    if (document.readyState === 'loading') {
110        document.addEventListener('DOMContentLoaded', function () { init(); });
111    } else {
112        init();
113    }
114
115    // Shared engine namespace. openDrawer/closeDrawer keep their historical
116    // names (commerce.js mini-cart depends on them); hzo.drawer is the
117    // widget-convention surface for dynamically-injected instances.
118    window.hzo = window.hzo || {};
119    window.hzo.openDrawer = function (idOrEl, trigger) {
120        var el = typeof idOrEl === 'string' ? document.getElementById(idOrEl) : idOrEl;
121        if (el) { setup(el); }
122        openDrawer(el, trigger);
123    };
124    window.hzo.closeDrawer = function (idOrEl) {
125        closeDrawer(typeof idOrEl === 'string' ? document.getElementById(idOrEl) : idOrEl);
126    };
127    window.hzo.drawer = { init: init, setup: setup, open: window.hzo.openDrawer, close: window.hzo.closeDrawer };
128})();

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.