PageSourceSearch

https://www.freelo.io/js/utils.js?v=tltff4

js freelo.io collected 2026-09-24 10:12:05 UTC 9,888 bytes, 314 lines download raw bytes

1/**
2 * Utility Functions - Bootstrap Removal Phase 9
3 *
4 * Helper functions to replace common jQuery patterns with vanilla JavaScript.
5 * These utilities provide a cleaner API for common DOM operations.
6 */
7
8(function(window) {
9    'use strict';
10
11    /**
12     * Select single element (querySelector shorthand)
13     * @param {string} selector - CSS selector
14     * @param {Element|Document} context - Context element (defaults to document)
15     * @returns {Element|null}
16     */
17    function $(selector, context) {
18        return (context || document).querySelector(selector);
19    }
20
21    /**
22     * Select multiple elements (querySelectorAll shorthand, returns array)
23     * @param {string} selector - CSS selector
24     * @param {Element|Document} context - Context element (defaults to document)
25     * @returns {Element[]}
26     */
27    function $$(selector, context) {
28        return Array.from((context || document).querySelectorAll(selector));
29    }
30
31    /**
32     * Execute function when DOM is ready
33     * @param {Function} fn - Function to execute
34     */
35    function ready(fn) {
36        if (document.readyState !== 'loading') {
37            fn();
38        } else {
39            document.addEventListener('DOMContentLoaded', fn);
40        }
41    }
42
43    /**
44     * Delegate event handler
45     * @param {Element} parent - Parent element to attach listener to
46     * @param {string} eventType - Event type (e.g., 'click')
47     * @param {string} selector - CSS selector for matching children
48     * @param {Function} handler - Event handler function
49     */
50    function delegate(parent, eventType, selector, handler) {
51        parent.addEventListener(eventType, function(e) {
52            var target = e.target.closest(selector);
53            if (target && parent.contains(target)) {
54                handler.call(target, e);
55            }
56        });
57    }
58
59    /**
60     * Serialize form data to URL-encoded string
61     * @param {HTMLFormElement} form - Form element
62     * @returns {string}
63     */
64    function serialize(form) {
65        return new URLSearchParams(new FormData(form)).toString();
66    }
67
68    /**
69     * Fade in element using Web Animations API
70     * @param {Element} el - Element to fade in
71     * @param {number} duration - Duration in milliseconds (default: 300)
72     * @param {Function} callback - Optional callback when animation completes
73     */
74    function fadeIn(el, duration, callback) {
75        duration = duration || 300;
76        el.style.display = '';
77        el.style.opacity = '0';
78
79        var animation = el.animate(
80            [{ opacity: 0 }, { opacity: 1 }],
81            { duration: duration, fill: 'forwards' }
82        );
83
84        if (callback) {
85            animation.onfinish = callback;
86        }
87    }
88
89    /**
90     * Fade out element using Web Animations API
91     * @param {Element} el - Element to fade out
92     * @param {number} duration - Duration in milliseconds (default: 300)
93     * @param {Function} callback - Optional callback when animation completes
94     */
95    function fadeOut(el, duration, callback) {
96        duration = duration || 300;
97
98        var animation = el.animate(
99            [{ opacity: 1 }, { opacity: 0 }],
100            { duration: duration, fill: 'forwards' }
101        );
102
103        animation.onfinish = function() {
104            el.style.display = 'none';
105            if (callback) callback();
106        };
107    }
108
109    /**
110     * Slide down element (expand)
111     * @param {Element} el - Element to expand
112     * @param {number} duration - Duration in milliseconds (default: 300)
113     * @param {Function} callback - Optional callback when animation completes
114     */
115    function slideDown(el, duration, callback) {
116        duration = duration || 300;
117
118        /* Reset to get natural height */
119        el.style.display = '';
120        el.style.overflow = 'hidden';
121        var height = el.scrollHeight;
122
123        el.style.height = '0';
124
125        var animation = el.animate(
126            [{ height: '0px' }, { height: height + 'px' }],
127            { duration: duration, easing: 'ease-out' }
128        );
129
130        animation.onfinish = function() {
131            el.style.height = '';
132            el.style.overflow = '';
133            if (callback) callback();
134        };
135    }
136
137    /**
138     * Slide up element (collapse)
139     * @param {Element} el - Element to collapse
140     * @param {number} duration - Duration in milliseconds (default: 300)
141     * @param {Function} callback - Optional callback when animation completes
142     */
143    function slideUp(el, duration, callback) {
144        duration = duration || 300;
145
146        el.style.overflow = 'hidden';
147        var height = el.scrollHeight;
148
149        var animation = el.animate(
150            [{ height: height + 'px' }, { height: '0px' }],
151            { duration: duration, easing: 'ease-out' }
152        );
153
154        animation.onfinish = function() {
155            el.style.display = 'none';
156            el.style.height = '';
157            el.style.overflow = '';
158            if (callback) callback();
159        };
160    }
161
162    /**
163     * Toggle element visibility with slide animation
164     * @param {Element} el - Element to toggle
165     * @param {number} duration - Duration in milliseconds (default: 300)
166     * @param {Function} callback - Optional callback when animation completes
167     */
168    function slideToggle(el, duration, callback) {
169        if (el.offsetHeight === 0 || getComputedStyle(el).display === 'none') {
170            slideDown(el, duration, callback);
171        } else {
172            slideUp(el, duration, callback);
173        }
174    }
175
176    /**
177     * Add class to element(s)
178     * @param {Element|Element[]} elements - Element or array of elements
179     * @param {string} className - Class name to add
180     */
181    function addClass(elements, className) {
182        var els = Array.isArray(elements) ? elements : [elements];
183        els.forEach(function(el) {
184            if (el) el.classList.add(className);
185        });
186    }
187
188    /**
189     * Remove class from element(s)
190     * @param {Element|Element[]} elements - Element or array of elements
191     * @param {string} className - Class name to remove
192     */
193    function removeClass(elements, className) {
194        var els = Array.isArray(elements) ? elements : [elements];
195        els.forEach(function(el) {
196            if (el) el.classList.remove(className);
197        });
198    }
199
200    /**
201     * Toggle class on element(s)
202     * @param {Element|Element[]} elements - Element or array of elements
203     * @param {string} className - Class name to toggle
204     */
205    function toggleClass(elements, className) {
206        var els = Array.isArray(elements) ? elements : [elements];
207        els.forEach(function(el) {
208            if (el) el.classList.toggle(className);
209        });
210    }
211
212    /**
213     * Check if element has class
214     * @param {Element} element - Element to check
215     * @param {string} className - Class name to check
216     * @returns {boolean}
217     */
218    function hasClass(element, className) {
219        return element ? element.classList.contains(className) : false;
220    }
221
222    /**
223     * Simple AJAX GET request
224     * @param {string} url - URL to fetch
225     * @param {Object} options - Optional fetch options
226     * @returns {Promise}
227     */
228    function ajax(url, options) {
229        options = options || {};
230        options.headers = options.headers || {};
231
232        /* Add XMLHttpRequest header for Nette compatibility */
233        if (!options.headers['X-Requested-With']) {
234            options.headers['X-Requested-With'] = 'XMLHttpRequest';
235        }
236
237        return fetch(url, options).then(function(response) {
238            if (!response.ok) {
239                throw new Error('Network response was not ok');
240            }
241            var contentType = response.headers.get('content-type');
242            if (contentType && contentType.includes('application/json')) {
243                return response.json();
244            }
245            return response.text();
246        });
247    }
248
249    /**
250     * POST request with form data
251     * @param {string} url - URL to post to
252     * @param {FormData|Object|string} data - Data to send
253     * @returns {Promise}
254     */
255    function post(url, data) {
256        var body;
257        var headers = {
258            'X-Requested-With': 'XMLHttpRequest'
259        };
260
261        if (data instanceof FormData) {
262            body = data;
263        } else if (typeof data === 'object') {
264            body = JSON.stringify(data);
265            headers['Content-Type'] = 'application/json';
266        } else {
267            body = data;
268            headers['Content-Type'] = 'application/x-www-form-urlencoded';
269        }
270
271        return fetch(url, {
272            method: 'POST',
273            headers: headers,
274            body: body
275        }).then(function(response) {
276            if (!response.ok) {
277                throw new Error('Network response was not ok');
278            }
279            var contentType = response.headers.get('content-type');
280            if (contentType && contentType.includes('application/json')) {
281                return response.json();
282            }
283            return response.text();
284        });
285    }
286
287    /* Export utilities to window.FreeloUtils namespace */
288    window.FreeloUtils = {
289        $: $,
290        $$: $$,
291        ready: ready,
292        delegate: delegate,
293        serialize: serialize,
294        fadeIn: fadeIn,
295        fadeOut: fadeOut,
296        slideDown: slideDown,
297        slideUp: slideUp,
298        slideToggle: slideToggle,
299        addClass: addClass,
300        removeClass: removeClass,
301        toggleClass: toggleClass,
302        hasClass: hasClass,
303        ajax: ajax,
304        post: post
305    };
306
307    /* Also expose commonly used functions globally for convenience */
308    /* Note: These won't override jQuery's $ if it's loaded */
309    if (typeof window.FreeloSelect === 'undefined') {
310        window.FreeloSelect = $;
311        window.FreeloSelectAll = $$;
312    }
313
314})(window);

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.