PageSourceSearch

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

js brotherssupply.com collected 2026-10-09 00:30:05 UTC 7,402 bytes, 139 lines download raw bytes

1/* ═════════════════════════════════════════════════════════════════════════
2   BUTTONS — widget behavior (Phase-2 widget system; moved out of main.js)
3
4   Self-contained, no hard dependencies. As a shortcode widget the buttons
5   component ALWAYS loads: buttons.php un-gates it via the
6   hzostudio_component_markers filter (a no-op today — buttons never had a
7   gate entry — kept for convention uniformity). The add-to-cart IIFE was
8   moved here from main.js; attribute-free markup behaves exactly as before.
9
10   ADD-TO-CART STATE MACHINE (UI surface — no real cart POST). Drives the
11   default → loading → added flow by class + aria, exposed for an integration
12   layer (assets/js/commerce.js on WC-active sites) to wire to a real cart.
13   A button with `data-hzo-add-to-cart` enters `.is-loading` (aria-busy) on
14   click and dispatches a bubbling `hzo:addtocart` CustomEvent
15   (detail { button }); the integration does the real POST, then calls
16   hzo.cart.added(btn) / hzo.cart.reset(btn). With
17   `data-hzo-add-to-cart-demo` it self-resolves so the gallery shows the full
18   flow. aria-disabled buttons (out-of-stock) and in-flight buttons never
19   (re)fire. Markup contract: component-patterns.md §8.10.
20
21   OPTION CONTRACT — settings are data-attributes on the button element, so
22   the block-pattern surface (author writes attributes) and the [hzo_button]
23   shortcode (buttons.php emits the markup) drive the SAME behavior. Every
24   option defaults OFF/legacy:
25
26     data-hzo-buttons-message    custom "added" toast text
27                                 (default "Added to cart")
28     data-hzo-buttons-rest       "in-cart" → the added state is sticky instead
29                                 of reverting (set the label yourself, e.g.
30                                 "In cart") — the declarative twin of
31                                 hzo.cart.added(btn, { rest: 'in-cart' })
32     data-hzo-buttons-added-ms   ms the ✓ confirmation shows before the button
33                                 settles back to default (int; default 1600)
34
35   Explicit opts passed to hzo.cart.added(btn, opts) always win — the
36   attributes only fill opts an integration left unset — so every existing
37   caller is unaffected.
38
39   A11y (WAI-ARIA APG Button pattern): the component uses native <button> /
40   <a> elements, so roles and the Enter/Space keyboard map come for free
41   (click fires natively). In-flight state is announced via aria-busy;
42   out-of-stock is aria-disabled plus a text label (never colour alone).
43   Reduced motion: the loading/added visuals are pure class-driven state
44   swaps — buttons.css slows the spinner and freezes the icon-slide arrow
45   under prefers-reduced-motion; this file animates nothing.
46
47   Behavior is fully event-delegated (ONE document-level click listener bound
48   once at module scope), so dynamically injected buttons (AJAX loops,
49   product-grid swaps) work with no re-init. init/setup exist for the widget
50   convention and stamp the idempotency marker (data-hzo-buttons-ready) on
51   add-to-cart buttons; they wire nothing per-instance today.
52
53   Shared primitives (hzo.toast — components/toast/toast.js) are guarded at
54   event time, never assumed at parse time: script load order across
55   component bundles and the conditionally-enqueued main.js is NOT guaranteed.
56
57   Public API (back-compat — commerce.js and integrations call these):
58     hzo.cart = { loading, added, reset }          (historical names, verbatim)
59     hzo.buttons = { init, setup, loading, added, reset }
60   ═════════════════════════════════════════════════════════════════════════ */
61(function () {
62    'use strict';
63
64    var ADDED_MS = 1600;
65
66    function loading(btn) {
67        btn.classList.remove('is-added');
68        btn.classList.add('is-loading');
69        btn.setAttribute('aria-busy', 'true');
70    }
71
72    function added(btn, opts) {
73        opts = opts || {};
74        btn.classList.remove('is-loading');
75        btn.setAttribute('aria-busy', 'false');
76        btn.classList.add('is-added');
77        if (window.hzo && window.hzo.toast) {
78            window.hzo.toast(opts.message || btn.getAttribute('data-hzo-buttons-message') || 'Added to cart', { type: 'success' });
79        }
80        // Brief confirmation, then settle back to default — the toast persists
81        // the outcome. Pass { rest: 'in-cart' } (or author
82        // data-hzo-buttons-rest="in-cart") to keep a sticky state (label is the
83        // integration's call, e.g. "In cart").
84        var rest = opts.rest || btn.getAttribute('data-hzo-buttons-rest') || '';
85        if (rest === 'in-cart') { return; }
86        var ms = opts.ms || parseInt(btn.getAttribute('data-hzo-buttons-added-ms') || '', 10) || ADDED_MS;
87        window.setTimeout(function () { btn.classList.remove('is-added'); }, ms);
88    }
89
90    function reset(btn) {
91        btn.classList.remove('is-loading', 'is-added');
92        btn.setAttribute('aria-busy', 'false');
93    }
94
95    /* No per-instance wiring is needed (behavior is delegated below) — setup
96       just stamps the widget-convention ready marker, idempotently. */
97    function setup(btn) {
98        if (!btn || btn.getAttribute('data-hzo-buttons-ready') === 'true') { return; }
99        btn.setAttribute('data-hzo-buttons-ready', 'true');
100    }
101
102    function init(scope) {
103        var btns = (scope || document).querySelectorAll('[data-hzo-add-to-cart]');
104        for (var i = 0; i < btns.length; i++) { setup(btns[i]); }
105    }
106
107    // Delegated at the document level, bound ONCE at module scope —
108    // dynamically-inserted buttons work with no re-init.
109    document.addEventListener('click', function (e) {
110        var btn = e.target.closest ? e.target.closest('[data-hzo-add-to-cart]') : null;
111        if (!btn) { return; }
112        e.preventDefault();
113        // Out-of-stock (aria-disabled) or an in-flight add never (re)fires.
114        if (btn.getAttribute('aria-disabled') === 'true' || btn.classList.contains('is-loading')) { return; }
115        setup(btn);   // covers buttons injected after init (AJAX content)
116        loading(btn);
117        btn.dispatchEvent(new CustomEvent('hzo:addtocart', { bubbles: true, detail: { button: btn } }));
118        // Self-contained demo (no integration listening): resolve to "added".
119        if (btn.hasAttribute('data-hzo-add-to-cart-demo')) {
120            window.setTimeout(function () { added(btn); }, 700);
121        }
122    });
123
124    if (document.readyState === 'loading') {
125        document.addEventListener('DOMContentLoaded', function () { init(); });
126    } else {
127        init();
128    }
129
130    // Shared engine namespace. hzo.cart keeps its historical shape verbatim
131    // (commerce.js resolves add-to-cart through it at event time); hzo.buttons
132    // is the widget-convention surface for dynamically-injected instances.
133    window.hzo = window.hzo || {};
134    window.hzo.cart = window.hzo.cart || {};
135    window.hzo.cart.loading = loading;
136    window.hzo.cart.added = added;
137    window.hzo.cart.reset = reset;
138    window.hzo.buttons = { init: init, setup: setup, loading: loading, added: added, reset: reset };
139})();

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.