|
29 | 29 | */ |
30 | 30 | csk.ui = { |
31 | 31 | scrollToTopVisible: false, |
| 32 | + alertClasses: ["info", "success", "warning", "danger"], |
| 33 | + |
32 | 34 | /** |
33 | 35 | * Confirmation alert using either bootbox or default alert. |
34 | 36 | * @since 1.20 |
|
75 | 77 | falseCallback(true); |
76 | 78 | } |
77 | 79 | }, |
78 | | - /** Alert (Notification). */ |
79 | | - alert: function(message, type) { |
80 | | - if (!message.length) { |
81 | | - return false; |
82 | | - } |
83 | | - type = type || 'info'; |
84 | | - if (type === "error" || type === "critical") { |
85 | | - type = "danger"; |
86 | | - } |
87 | 80 |
|
| 81 | + /** |
| 82 | + * Alert (notification) |
| 83 | + * @since 1.20 |
| 84 | + * @param {string} message Message to display. |
| 85 | + * @param {string} type Alert type('danger', 'warning', 'info', or 'success') |
| 86 | + * @return {void} |
| 87 | + */ |
| 88 | + alert: function(message, type = "info") { |
| 89 | + // Make sure a valid string message is passed. |
| 90 | + if (typeof message !== "string" || !message.length) return; |
| 91 | + |
| 92 | + // Normalize and validate alert type |
| 93 | + type = type?.toLowerCase() || 'info'; |
| 94 | + type = (type === "error" || type === "critical") ? "danger" : (csk.ui.alertClasses.includes(type) ? type : "info"); |
| 95 | + |
| 96 | + // Case 1: Toastr is available? |
88 | 97 | if (typeof toastr !== "undefined") { |
89 | | - switch (type) { |
90 | | - case "success": |
91 | | - toastr.success(message); |
92 | | - break; |
93 | | - case "error": |
94 | | - case "danger": |
95 | | - toastr.error(message); |
96 | | - break; |
97 | | - case "warning": |
98 | | - toastr.warning(message); |
99 | | - break; |
100 | | - case "info": |
101 | | - default: |
102 | | - toastr.info(message); |
103 | | - break; |
104 | | - } |
| 98 | + (toastr[type] || toastr.info).call(toastr, message.trim()); |
105 | 99 | return; |
106 | 100 | } |
107 | 101 |
|
108 | | - /** |
109 | | - * If Handlebars is loaded, we already have an alert template |
110 | | - * stored within the dashboard default layout. So we use it. |
111 | | - */ |
112 | | - if (typeof Handlebars === "object") { |
113 | | - /** We store any old alert so we can remove it later. */ |
114 | | - var oldAlert = $("#csk-alert"), |
115 | | - alertSource = document.getElementById("csk-alert-template").innerHTML, |
116 | | - alertTemplate = Handlebars.compile(alertSource); |
117 | | - |
118 | | - /** Compile the alert. */ |
119 | | - var alertCompiled = alertTemplate({ |
120 | | - message: message, |
121 | | - type: type |
122 | | - }); |
| 102 | + // Case 2: Use provided alter template. |
| 103 | + const clone = document.getElementById("csk-alert-template")?.content?.querySelector('div')?.cloneNode(true); |
| 104 | + if (clone) { |
| 105 | + // Add alert Bootstrap alert classes then add message. |
| 106 | + clone.classList.add("alert", "alert-" + type, "alert-dismissible"); |
| 107 | + clone.prepend(message.trim()); // Add message |
123 | 108 |
|
124 | | - /** If we have an old alert, remove it first. */ |
125 | | - if (oldAlert.length) { |
126 | | - oldAlert.fadeOut(function() { |
127 | | - $(this).remove(); |
128 | | - $(alertCompiled).prependTo("#wrapper > .container"); |
129 | | - }); |
130 | | - } else { |
131 | | - $(alertCompiled).prependTo("#wrapper > .container"); |
132 | | - } |
| 109 | + // Prepend cloned alert to first '.container' inside '#wrapper'. |
| 110 | + (document.querySelector("#wrapper>.container") || document.body).prepend(clone); |
| 111 | + csk.ui.autoHideAlert($(clone)); |
| 112 | + return; |
| 113 | + } |
133 | 114 |
|
| 115 | + // Case 3: Strip any HTML from message use default 'alert()'. |
| 116 | + window.alert(message.replace(/(<([^>]+)>)/ig, "").trim()); |
| 117 | + }, |
| 118 | + |
| 119 | + /** |
| 120 | + * Auto-hides alerts if needed. |
| 121 | + * @since 3.11.0 |
| 122 | + * @param {HTMLElement} $alert |
| 123 | + * @return {void} |
| 124 | + */ |
| 125 | + autoHideAlert: function($alert) { |
| 126 | + // Skip keep/danger/warning |
| 127 | + if ($alert.hasClass("alert-keep") || $alert.hasClass("alert-danger") || $alert.hasClass("alert-warning")) { |
134 | 128 | return; |
135 | 129 | } |
136 | 130 |
|
137 | | - /** |
138 | | - * Otherwise, we make sure to strip any HTML tags from the message |
139 | | - * and simply use browser's default alert. |
140 | | - */ |
141 | | - alert(message.replace(/(<([^>]+)>)/ig, "")); |
| 131 | + let len = $alert.text().trim().length; |
| 132 | + let after = Math.min(10000, 4000 + (len * 50)); |
| 133 | + |
| 134 | + $alert.delay(after).slideUp(500, function () { |
| 135 | + $alert.alert("close").remove(); |
| 136 | + }); |
142 | 137 | }, |
143 | | - /** Reload main page parts. */ |
| 138 | + |
| 139 | + /** |
| 140 | + * Reloads given element. |
| 141 | + * @since 1.20 |
| 142 | + * @param {string} el Query selector. |
| 143 | + * @param {boolean} navbar Whether to reload navbar. |
| 144 | + * @param {Function} callback Callback to execute after reload. |
| 145 | + * @return {void} |
| 146 | + */ |
144 | 147 | reload: function(el, navbar, callback) { |
145 | 148 | /** If no element is provided, we use "#wrapper". */ |
146 | 149 | el = el || "#wrapper"; |
|
152 | 155 | } |
153 | 156 | $(el).load(csk.config.currentURL + " " + el + " > *", callback); |
154 | 157 | }, |
| 158 | + |
155 | 159 | /** |
156 | 160 | * Check if an element is in viewport. |
157 | 161 | * @since 2.0 |
|
160 | 164 | var $that = el.getBoundingClientRect(); |
161 | 165 | return $that.bottom >= 0 && $that.right >= 0 && $that.top <= (window.innerHeight || document.documentElement.clientHeight) && $that.left <= (window.innerWidth || document.documentElement.clientWidth); |
162 | 166 | }, |
| 167 | + |
163 | 168 | /** |
164 | 169 | * Function to add an event listener. |
165 | 170 | * @since 2.0 |
|
171 | 176 | window.attachEvent("on" + event, callback); |
172 | 177 | } |
173 | 178 | }, |
| 179 | + |
174 | 180 | /** |
175 | 181 | * Adds a delegated event listener to the document. |
176 | 182 | * |
|
195 | 201 | } |
196 | 202 | }); |
197 | 203 | }, |
| 204 | + |
198 | 205 | /** |
199 | 206 | * Lazy load images. |
200 | 207 | * @since 2.0 |
|
216 | 223 | } |
217 | 224 | } |
218 | 225 | }, |
| 226 | + |
219 | 227 | /** |
220 | 228 | * Scroll to top. |
221 | 229 | * @since 3.9.6 |
|
234 | 242 | } |
235 | 243 | } |
236 | 244 | }, |
| 245 | + |
237 | 246 | /** |
238 | 247 | * Element fade out. |
239 | 248 | * @since 3.9.6 |
|
248 | 257 | } |
249 | 258 | })(); |
250 | 259 | }, |
| 260 | + |
251 | 261 | /** |
252 | 262 | * Element fade in. |
253 | 263 | * @since 3.9.6 |
|
263 | 273 | } |
264 | 274 | })(); |
265 | 275 | }, |
| 276 | + |
266 | 277 | /** |
267 | 278 | * Splits given string into an array. |
268 | 279 | * @since 2.16 |
|
277 | 288 | } |
278 | 289 | return fields; |
279 | 290 | }, |
| 291 | + |
280 | 292 | /** |
281 | 293 | * Returns an array of GET parameters. |
282 | 294 | * @since 2.16 |
|
292 | 304 | } |
293 | 305 | return params; |
294 | 306 | }, |
| 307 | + |
295 | 308 | /** |
296 | 309 | * Returns a GET parameter. |
297 | 310 | * @since 2.16 |
|
309 | 322 | } |
310 | 323 | return false; |
311 | 324 | }, |
| 325 | + |
312 | 326 | /** |
313 | 327 | * Copy to clipboard. |
314 | 328 | * @since 2.18 |
|
321 | 335 | navigator.clipboard.writeText(copyText); |
322 | 336 | csk.ui.alert(csk.i18n.media.copied, "success"); |
323 | 337 | }, |
| 338 | + |
324 | 339 | /** |
325 | 340 | * Disable selection. |
326 | 341 | * @since 2.166 |
|
331 | 346 | document.body.style.userSelect = "none"; |
332 | 347 | } |
333 | 348 | }, |
| 349 | + |
334 | 350 | /** |
335 | 351 | * Enable selection. |
336 | 352 | * @since 2.166 |
337 | 353 | */ |
338 | 354 | selectOn: function(e) { |
339 | 355 | document.body.style.userSelect = ""; |
340 | 356 | }, |
| 357 | + |
341 | 358 | /** |
342 | 359 | * DataTable. |
343 | 360 | * @since 3.9.8 |
|
363 | 380 | }; |
364 | 381 | return $(selector).DataTable($.extend(true, {}, defaults, options)); |
365 | 382 | }, |
| 383 | + |
366 | 384 | /** |
367 | 385 | * Highlights and element referenced by the URL hash (element ID). |
368 | 386 | * Smooth scroll included. Silently bails if no match. |
|
385 | 403 | // Remove the class after blink sequence |
386 | 404 | setTimeout(() => target.classList.remove('highlight-focus'), 4000); |
387 | 405 | }, |
| 406 | + |
388 | 407 | /** |
389 | 408 | * Enables or disable one or more elements. |
390 | 409 | * @since 3.10.1 |
|
760 | 779 | * @since 2.16 |
761 | 780 | */ |
762 | 781 | $(".alert-dismissible").each(function() { |
763 | | - let $alert = $(this); |
764 | | - |
765 | | - // Skip 'alert-keep', 'alert-danger' and 'alert-warning' |
766 | | - if ($alert.hasClass("alert-keep") || $alert.hasClass("alert-danger") || $alert.hasClass("alert-warning")) { |
767 | | - return; |
768 | | - } |
769 | | - |
770 | | - // Calculate display time based on content length |
771 | | - let len = $alert.text().trim().length; |
772 | | - let after = Math.min(10000, 4000 + (len * 50)); // Max 10 sec. |
773 | | - |
774 | | - // Auto-close after calculated delay |
775 | | - $alert.delay(after).slideUp(500, function() { |
776 | | - $alert.alert("close").remove(); |
777 | | - }); |
| 782 | + csk.ui.autoHideAlert($(this)); |
778 | 783 | }); |
779 | 784 |
|
780 | 785 | /** |
|
0 commit comments