PageSourceSearch

https://services.unitedbaristas.com/wp-content/plugins/jreviews/resources/js/alpine-helpers.js?ver=5.12.0

js unitedbaristas.com collected 2026-10-04 02:40:28 UTC 10,629 bytes, 280 lines download raw bytes

1document.addEventListener('alpine:init', () => {
2
3    Alpine.magic('clipboard', () => subject => {
4        const text = String(subject)
5
6        // Secure contexts (HTTPS / localhost) expose the async Clipboard API.
7        if (navigator.clipboard && window.isSecureContext) {
8            navigator.clipboard.writeText(text).catch(() => fallbackClipboardCopy(text))
9            return
10        }
11
12        // Insecure contexts (plain HTTP) — navigator.clipboard is undefined, so
13        // fall back to the legacy textarea + execCommand('copy') approach. This
14        // keeps copy working on HTTP admin/dev origins, not just HTTPS.
15        fallbackClipboardCopy(text)
16    })
17
18    function fallbackClipboardCopy(text) {
19        const ta = document.createElement('textarea')
20        ta.value = text
21        ta.setAttribute('readonly', '')
22        ta.style.position = 'fixed'
23        ta.style.top = '-9999px'
24        document.body.appendChild(ta)
25        ta.select()
26        try { document.execCommand('copy') } catch (e) { /* no-op */ }
27        document.body.removeChild(ta)
28    }
29
30    Alpine.directive('script', (el, { expression }, { evaluateLater }) => {
31        let [url, handler, method] = expression.split(",").map(item => item.trim());
32    
33        let scripts = Array.from(document.head.getElementsByTagName('script'));
34        let scriptTagExists = scripts.some(script => script.dataset.name === handler);
35        let callback = el.getAttribute('x-script-callback');
36
37        const scriptReady = () => window[handler] && (! method || typeof window[handler][method] === 'function');
38
39        if (! scriptTagExists && ! scriptReady()) {
40            let script = document.createElement('script');
41            script.dataset.name = handler;
42            script.src = url;
43            document.head.appendChild(script);
44
45            script.onload = () => {
46                let checkExist = setInterval(function() {
47                    if (scriptReady()) {
48                        clearInterval(checkExist);
49                        if(callback) {
50                            evaluateLater(callback)();
51                        }
52                    }
53                }, 50);
54            };
55        } else if (scriptReady()) {
56            evaluateLater(callback)();
57        }
58    });
59
60    Alpine.directive('slug', (el, { modifiers, expression }, { evaluateLater, effect }) => {
61        const setValue = evaluateLater(expression)
62
63        const isInput = el.tagName === 'INPUT'
64  
65        const spaceless = modifiers.includes('spaceless');
66
67        let replacementChar = modifiers.includes('replacement')
68            ? modifiers[modifiers.indexOf('replacement') + 1]
69            : '-' 
70        
71        replacementChar = spaceless ? '' : replacementChar;
72
73        function slugify(string) {
74            return string
75                .normalize('NFKD') // split accented characters into their base characters and diacritical marks
76                .replace(/[\u0300-\u036f]/g, '') // remove all the accents, which happen to be all in the \u03xx UNICODE block.
77                .trim() // trim leading or trailing whitespace
78                .toLowerCase() // convert to lowercase
79                .replace(/æ/gi, 'ae')
80                .replace(/ß/gi, 'ss')
81                .replace(/œ/gi, 'oe')
82                .replace(/[^a-z0-9 _-]/g, '') // remove non-alphanumeric characters
83                .replace(/\s+/g, replacementChar) // replace spaces
84                .replace(/_+/g, replacementChar) // replace underscores
85                .replace(/-+/g, replacementChar); // remove consecutive
86        }
87
88        function unicodeSlugify(string) {
89            return string
90                .trim() // trim leading or trailing whitespace
91                .toLowerCase() // convert to lowercase
92                .replace(/\s+/g, replacementChar) // replace spaces
93                .replace(/_+/g, replacementChar) // replace underscores
94                .replace(/-+/g, replacementChar); // remove consecutive
95        }
96
97        effect(() => {
98            setValue(passedString => {
99                if (! passedString) {
100                    return;
101                }
102
103                const stringSlug = modifiers.includes('unicode') ? unicodeSlugify(passedString) : slugify(passedString);
104
105                isInput ? (el.value = stringSlug) : (el.innerText = stringSlug);
106            })
107        })
108    })
109
110    Alpine.directive('htmx-preserve-scroll', (el, { expression, modifiers }, { cleanup }) => {
111        let selector = expression ? expression.replace(/['"]/g, '') 
111: null;
112        let elementId = selector ? null : el.id;
113        let observer;
114        let savedScroll = null;
115        let isRestoring = false;
116        let isRelevantRequest = false;
117
118        function getTargetEl() {
119            if (modifiers.includes('window')) {
120                return window;
121            }
122            if (selector) {
123                return document.querySelector(selector);
124            }
125            return document.getElementById(elementId);
126        }
127
128        function saveScrollPosition(element) {
129            if (!element) return null;
130            const pos = element === window ? {
131                top: window.scrollY,
132                left: window.scrollX
133            } : {
134                top: element.scrollTop,
135                left: element.scrollLeft
136            };
137            // console.log('Saving scroll position:', pos);
138            return pos;
139        }
140
141        function restoreScrollPosition(element, position) {
142            if (!element || !position) return;
143            // console.log('Restoring scroll position:', position);
144            isRestoring = true;
145            
146            if (element === window) {
147                window.scrollTo({
148                    left: position.left,
149                    top: position.top,
150                    behavior: 'instant'
151                });
152            } else {
153                element.scrollTo({
154                    left: position.left,
155                    top: position.top,
156                    behavior: 'instant'
157                });
158            }
159            
160            setTimeout(() => {
161                isRestoring = false;
162            }, 350);
163        }
164
165        function isEventRelevant(event, targetEl) {
166            if (targetEl === window) {
167                const triggerElement = event.detail.elt;
168                if (!triggerElement) return false;
169                return el === triggerElement || el.contains(triggerElement);
170            }
171            // For non-window elements, keep using the existing ID check
172            return event.detail.target.id === elementId;
173        }
174
175        // HTMX event handlers
176        function handleBeforeRequest(event) {
177            const targetEl = getTargetEl();
178            if (!targetEl) return;
179            
180            // Store the relevancy check result
181            isRelevantRequest = isEventRelevant(event, targetEl);
182            if (!isRelevantRequest) return;
183            
184            savedScroll = saveScrollPosition(targetEl);
185        }
186    
187        function handleBeforeSwap(event) {
188            const targetEl = getTargetEl();
189            if (!targetEl || !isRelevantRequest) return;
190    
191            if (!savedScroll) {
192                savedScroll = saveScrollPosition(targetEl);
193            }
194        }
195    
196        function handleAfterSwap(event) {
197            const targetEl = getTargetEl();
198            if (!targetEl || !isRelevantRequest) return;
199            
200            if (targetEl !== window) {
201                targetEl.classList.add('fwd-opacity-0');
202            }
203            
204            requestAnimationFrame(() => {
205                restoreScrollPosition(targetEl, savedScroll);
206                if (targetEl !== window) {
207                    targetEl.classList.remove('fwd-opacity-0'); 
208                }
209                // Reset the flag after restore is complete
210                isRelevantRequest = false;
211            });
212        }
213        
214        // Set up mutation observer for non-HTMX updates
215        function setupScrollLock() {
216            const targetEl = getTargetEl();
217            if (!targetEl || targetEl === window) return; // Skip MutationObserver for window
218
219            if (observer) {
220                observer.disconnect();
221            }
222
223            let lastScrollPos = saveScrollPosition(targetEl);
224            
225            observer = new MutationObserver((mutations) => {
226                if (document.documentElement.hasAttribute('data-htmx-swapping') || isRestoring) {
227                    return;
228                }
229
230                const affectsScroll = mutations.some(mutation => {
231                    return mutation.target === targetEl || targetEl.contains(mutation.target);
232                });
233
234                if (!affectsScroll) return;
235
236                const currentPos = saveScrollPosition(targetEl);
237                // console.log('Mutation detected - current:', currentPos, 'last:', lastScrollPos);
238                
239                if (lastScrollPos && (currentPos.top !== lastScrollPos.top || currentPos.left !== lastScrollPos.left)) {
240                    requestAnimationFrame(() => {
241                        restoreScrollPosition(targetEl, lastScrollPos);
242                    });
243                }
244            });
245
246            observer.observe(targetEl, {
247                childList: true,
248                subtree: true,
249                characterData: true,
250                attributes: true,
251                attributeFilter: ['class', 'style', 'data-*']
252            });
253
254            // Update last scroll position when user scrolls
255            const scrollTarget = targetEl === window ? document : targetEl;
256            scrollTarget.addEventListener('scroll', () => {
257                if (!isRestoring) {
258                    lastScrollPos = saveScrollPosition(targetEl);
259                    // console.log('User scrolled - updating last position:', lastScrollPos);
260                }
261            });
262        }
263
264        // Set up all event listeners
265        window.addEventListener('htmx:beforeRequest', handleBeforeRequest);
266        window.addEventListener('htmx:beforeSwap', handleBeforeSwap);
267        window.addEventListener('htmx:afterSwap', handleAfterSwap);
268        setupScrollLock();
269
270        // Handle cleanup
271        cleanup(() => {
272            window.removeEventListener('htmx:beforeRequest', handleBeforeRequest);
273            window.removeEventListener('htmx:beforeSwap', handleBeforeSwap);
274            window.removeEventListener('htmx:afterSwap', handleAfterSwap);
275            if (observer) {
276                observer.disconnect();
277            }
278        });
279    });
280});

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.