PageSourceSearch

https://billing.faveohelpdesk.com/common/js/helper.js

js faveohelpdesk.com collected 2026-09-24 17:35:04 UTC 4,832 bytes, 148 lines download raw bytes

1window.helper = (() => {
2    const alertTimeouts = {};
3
4    function showAlert({
5                           message,
6                           type = 'info',
7                           autoDismiss = 5000,
8                           containerSelector = 'body',
9                           dismissible = true,
10                           additionalClasses = '',
11                           id = 'custom-alert',
12                           refresh = false,
13                       }) {
14        if (!message){
15            return;
16        }
17
18        const container = document.querySelector(containerSelector);
19        if (!container){
20            return;
21        }
22
23        const isSuccess = type === 'success';
24        const iconClass = isSuccess ? 'fa-check-circle' : 'fa-ban';
25        const alertClass = isSuccess ? 'alert-success' : 'alert-danger';
26
27        // Remove existing alert if present
28        const existingAlert = document.getElementById(id);
29        if (existingAlert) {
30            clearTimeout(alertTimeouts[id]);
31            existingAlert.remove();
32        }
33
34        const alertDiv = document.createElement('div');
35        alertDiv.id = id;
36        alertDiv.className = `alert ${alertClass} ${dismissible ? 'alert-dismissible' : ''} ${additionalClasses}`;
37        alertDiv.setAttribute('role', 'alert');
38
39        // Create icon element
40        const iconElement = document.createElement('i');
41        iconElement.className = `fa ${iconClass} mr-1`;
42
43        // Create message text node to prevent HTML injection
44        const messageText = document.createTextNode(` ${message}`);
45
46        // Append icon and message safely
47        alertDiv.appendChild(iconElement);
48        alertDiv.appendChild(messageText);
49
50        // Dismiss button
51        if (dismissible) {
52            const btn = document.createElement('button');
53            btn.type = 'button';
54            btn.className = 'close';
55            btn.setAttribute('data-dismiss', 'alert');
56            btn.setAttribute('aria-hidden', 'true');
57            btn.innerHTML = '×';
58            btn.onclick = () => {
59                alertDiv.remove();
60                if (refresh) {
61                    window.location.reload(true);
62                }
63            };
64            alertDiv.appendChild(btn);
65        }
66
67        container.prepend(alertDiv);
68
69        // Auto-dismiss after timeout
70        if (autoDismiss !== null && !isNaN(autoDismiss) && autoDismiss > 0) {
71            alertTimeouts[id] = setTimeout(() => {
72                alertDiv.classList.remove('show');
73                alertDiv.classList.add('hide');
74                setTimeout(() => {
75                    alertDiv.remove();
76                    if (refresh) {
77                        window.location.reload(true);
78                    }
79                }, 200);
80            }, autoDismiss);
81        }
82    }
83
84    const globalLoader = {
85        show: function () {
86            const loader = document.getElementById('global-loader');
87            if (loader) {
88                loader.style.display = 'flex';
89            }
90        },
91
92        hide: function () {
93            const loader = document.getElementById('global-loader');
94            if (loader) {
95                loader.style.display = 'none';
96            }
97        }
98    };
99
100    /**
101     * Input restrictions
102     */
103    const restrictions = {
104        "only-numbers": "0-9",
105        "only-letters": "a-zA-Z",
106        "only-alphanum": "a-zA-Z0-9",
107        "only-decimal": "0-9\\.",       // numbers + dot
108        "only-hex": "0-9a-fA-F",        // hexadecimal
109        "only-username": "a-zA-Z0-9_-", // username chars
110    };
111
112    function applyRestriction(el, pattern) {
113        if (!pattern) return;
114        el.value = el.value.replace(new RegExp(`[^${pattern}]`, 'g'), '');
115    }
116
117    function getPattern(el) {
118        // Priority: class restriction → data-allow attribute
119        for (let cls in restrictions) {
120            if (el.classList.contains(cls)) return restrictions[cls];
121        }
122        return el.getAttribute("data-allow");
123    }
124
125    function initRestrictions() {
126        ["input", "paste"].forEach(evt => {
127            document.addEventListener(evt, (e) => {
128                const el = e.target;
129                if (!(el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement)) return;
130
131                const pattern = getPattern(el);
132                if (pattern) {
133                    // Use setTimeout for paste to allow value update
134                    evt === "paste" ? setTimeout(() => applyRestriction(el, pattern), 0) : applyRestriction(el, pattern);
135                }
136            });
137        });
138    }
139
140    // Run immediately
141    initRestrictions();
142
143    return {
144        showAlert,
145        globalLoader,
146        addRestriction: (className, regex) => { restrictions[className] = regex; },
147    };
148})();

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.