PageSourceSearch

https://www.brotherssupply.com/wp-content/plugins/hozio-studio/components/img/img.js?ver=6add7c040a9a

js brotherssupply.com collected 2026-10-09 00:30:17 UTC 7,329 bytes, 140 lines download raw bytes

1/* ═════════════════════════════════════════════════════════════════════════
2   LQIP PROGRESSIVE IMAGE (W-023) — widget behavior · closes G51
3
4   A tiny, dependency-free decode-fade adapter. The aspect-ratio box, the LQIP,
5   and the full <img> are ALL server-rendered and fully functional without this
6   file (progressive enhancement). This script adds exactly one layer, gated so a
7   load failure degrades to the plain image in a reserved box:
8
9     BLUR-UP — before decode, hide the full image (via the CSS armed leg, which
10     applies ONLY under the `html.hzo-img-ready` flag this script sets) so the
11     LQIP shows; on img.decode() (fallback `load`) fade the full image in and drop
12     the LQIP. On `error` — or a decode watchdog that never resolves — RECONCILE
13     the optimistic placeholder to a real fallback (drop the frozen blur, show the
14     alt as visible text) so a broken source is never a silent blurred box.
15
16   FAIL-VISIBLE BY CONSTRUCTION: the ready flag is NOT set under reduced-motion or
17   forced-colors (nothing to arm — the full image is already visible), and any
18   throw before it leaves content visible. Emits/consumes NO hzo:* events — decode
19   and failure are native DOM, not cross-component signals (§8.2). Reveal is NOT
20   handled here — [hzo_img] composes UNDER [hzo_reveal] without listening for it.
21
22   Idempotent (guarded by data-hzo-img-ready). Public API on the shared namespace
23   (never a new top-level global):  hzo.img = { init, setup }.
24   ═════════════════════════════════════════════════════════════════════════ */
25(function () {
26    'use strict';
27
28    var mm       = window.matchMedia;
29    var WATCHDOG = 10000; // ms — a never-decoding placeholder resolves to the plain image (G23-analogue)
30
31    function reduceMotion() { return !!(mm && mm('(prefers-reduced-motion: reduce)').matches); }
32    function forcedColors() { return !!(mm && mm('(forced-colors: active)').matches); }
33
34    function __(s) {
35        return (window.wp && wp.i18n && wp.i18n.__) ? wp.i18n.__(s, 'hozio-studio') : s;
36    }
37
38    /* Decoded / loaded: reveal the full image, fade out the LQIP. Idempotent. */
39    function markLoaded(root) {
40        if (!root || root._hzoImgDone) { return; }
41        root._hzoImgDone = true;
42        if (root._hzoImgWatch) { clearTimeout(root._hzoImgWatch); root._hzoImgWatch = null; }
43        root.classList.remove('hzo-img--loading', 'hzo-img--error');
44        root.classList.add('hzo-img--loaded');
45    }
46
47    /* Failure branch: reconcile the placeholder to a real fallback on EVERY
48       failure (the G1-analogue — never leave the optimistic blur desynced from
49       truth). Drop the frozen blur (CSS), and surface the alt as visible text. */
50    function markError(root, full) {
51        if (!root || root._hzoImgDone) { return; }
52        root._hzoImgDone = true;
53        if (root._hzoImgWatch) { clearTimeout(root._hzoImgWatch); root._hzoImgWatch = null; }
54        root.classList.remove('hzo-img--loading', 'hzo-img--loaded');
55        root.classList.add('hzo-img--error');
56
57        if (!root.querySelector('.hzo-img__fallback')) {
58            var label = (full && full.getAttribute('alt')) ? full.getAttribute('alt') : __('Image unavailable');
59            var span  = document.createElement('span');
60            span.className = 'hzo-img__fallback';
61            span.textContent = label;
62            // Decorative images (alt="") get an aria-hidden frame — no nameless noise.
63            if (!(full && full.getAttribute('alt'))) { span.setAttribute('aria-hidden', 'true'); }
64            root.appendChild(span);
65        }
66    }
67
68    function setup(root) {
69        if (!root || !root.getAttribute) { return; }
70        if (root.getAttribute('data-hzo-img-ready') === 'true') { return; } // idempotent
71        root.setAttribute('data-hzo-img-ready', 'true');
72
73        var full = root.querySelector('[data-hzo-img-full]') || root.querySelector('.hzo-img__full');
74        if (!full) { return; } // nothing to enhance — server markup stands
75
76        // Show-instant environments: never arm; the full image is already visible.
77        // Still settle so the LQIP is dropped from behind it.
78        if (reduceMotion() || forcedColors()) { markLoaded(root); return; }
79
80        // Already in cache / decoded before this ran → reveal now (no flash: this
81        // runs synchronously inside boot(), before the browser next paints).
82        if (full.complete && full.naturalWidth > 0) { markLoaded(root); return; }
83        if (full.complete && full.naturalWidth === 0) { markError(root, full); return; } // already errored
84
85        var onLoad  = function () { markLoaded(root); };
86        var onError = function () { markError(root, full); };
87
88        // decode() gives a clean "ready to paint" signal; load/error are the
89        // fallback for browsers/paths where decode() rejects spuriously.
90        if (typeof full.decode === 'function') {
91            full.decode().then(onLoad, function () {
92                // decode rejected — defer to the load/error listeners rather than
93                // erroring outright (decode can reject even when the image loads).
94                if (full.complete && full.naturalWidth > 0) { markLoaded(root); }
95            });
96        }
97        full.addEventListener('load', onLoad);
98        full.addEventListener('error', onError);
99
100        // Watchdog: a decode/load that never resolves must not blur forever.
101        root._hzoImgWatch = setTimeout(function () { markLoaded(root); }, WATCHDOG);
102    }
103
104    function init(scope) {
105        var imgs = (scope || document).querySelectorAll('.hzo-img:not([data-hzo-img-ready])');
106        for (var i = 0; i < imgs.length; i++) { setup(imgs[i]); }
107    }
108
109    /* Print: force every still-loading instance to its full image (CSS covers the
110       static case; this flushes any instance mid-decode at print time). */
111    function flushForPrint() {
112        var imgs = document.querySelectorAll('.hzo-img--loading');
113        for (var i = 0; i < imgs.length; i++) { markLoaded(imgs[i]); }
114    }
115    window.addEventListener('beforeprint', flushForPrint);
116    if (mm) {
117        try { mm('print').addListener(function (m) { if (m.matches) { flushForPrint(); } }); }
118        catch (e) { /* addListener unsupported */ }
119    }
120
121    function boot() {
122        // Arm-gate: the CSS hidden leg applies ONLY under this flag, so any failure
123        // BEFORE this line leaves the full image visible. Not set under a
124        // show-instant environment (nothing to arm).
125        if (!(reduceMotion() || forcedColors())) {
126            document.documentElement.classList.add('hzo-img-ready');
127        }
128        try { init(); }
129        catch (e) { /* leave content visible */ }
130    }
131    if (document.readyState === 'loading') {
132        document.addEventListener('DOMContentLoaded', boot);
133    } else {
134        boot();
135    }
136
137    // Shared engine namespace (widget convention) — never a new top-level global.
138    window.hzo = window.hzo || {};
139    window.hzo.img = { init: init, setup: setup };
140})();

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.