admin-lte 4.0.2 → 4.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ACCESSIBILITY-COMPLIANCE.md +60 -339
- package/CHANGELOG.md +43 -0
- package/README.md +15 -2
- package/dist/css/adminlte.css +24 -786
- package/dist/css/adminlte.css.map +1 -1
- package/dist/css/adminlte.min.css +2 -2
- package/dist/css/adminlte.min.css.map +1 -1
- package/dist/css/adminlte.rtl.css +24 -786
- package/dist/css/adminlte.rtl.css.map +1 -1
- package/dist/css/adminlte.rtl.min.css +2 -2
- package/dist/css/adminlte.rtl.min.css.map +1 -1
- package/dist/js/adminlte.js +233 -128
- package/dist/js/adminlte.js.map +1 -1
- package/dist/js/adminlte.min.js +2 -2
- package/dist/js/adminlte.min.js.map +1 -1
- package/package.json +30 -17
- package/src/scss/_callouts.scss +13 -3
- package/src/scss/_dropdown.scss +3 -1
- package/src/scss/adminlte.scss +1 -1
- package/src/scss/parts/_core.scss +0 -1
- package/src/ts/accessibility.ts +129 -69
- package/src/ts/adminlte.ts +1 -1
- package/src/ts/card-widget.ts +33 -8
- package/src/ts/fullscreen.ts +48 -42
- package/src/ts/layout.ts +2 -1
- package/src/ts/push-menu.ts +24 -8
- package/src/ts/treeview.ts +27 -1
- package/src/ts/util/index.ts +114 -29
- package/.browserslistrc +0 -17
- package/.prettierrc +0 -6
- package/CODE_OF_CONDUCT.md +0 -43
- package/SECURITY.md +0 -99
- package/dist/UI/general.html +0 -2317
- package/dist/UI/icons.html +0 -1126
- package/dist/UI/timeline.html +0 -1212
- package/dist/docs/browser-support.html +0 -826
- package/dist/docs/color-mode.html +0 -1142
- package/dist/docs/components/main-header.html +0 -1209
- package/dist/docs/components/main-sidebar.html +0 -924
- package/dist/docs/customization.html +0 -1080
- package/dist/docs/deployment.html +0 -1145
- package/dist/docs/faq.html +0 -1392
- package/dist/docs/getting-started.html +0 -991
- package/dist/docs/how-to-contribute.html +0 -890
- package/dist/docs/index.html +0 -16
- package/dist/docs/integrations.html +0 -1231
- package/dist/docs/introduction.html +0 -1008
- package/dist/docs/javascript/accessibility.html +0 -949
- package/dist/docs/javascript/card-widget.html +0 -1019
- package/dist/docs/javascript/direct-chat.html +0 -896
- package/dist/docs/javascript/fullscreen.html +0 -905
- package/dist/docs/javascript/layout.html +0 -908
- package/dist/docs/javascript/plugins-overview.html +0 -1144
- package/dist/docs/javascript/pushmenu.html +0 -1045
- package/dist/docs/javascript/treeview.html +0 -1024
- package/dist/docs/layout-blueprint.html +0 -1087
- package/dist/docs/layout.html +0 -842
- package/dist/docs/license.html +0 -807
- package/dist/docs/migration.html +0 -1149
- package/dist/docs/recipes.html +0 -1185
- package/dist/docs/rtl.html +0 -957
- package/dist/examples/lockscreen.html +0 -249
- package/dist/examples/login-v2.html +0 -282
- package/dist/examples/login.html +0 -272
- package/dist/examples/register-v2.html +0 -291
- package/dist/examples/register.html +0 -277
- package/dist/forms/elements.html +0 -1405
- package/dist/forms/layout.html +0 -1267
- package/dist/forms/validation.html +0 -1275
- package/dist/forms/wizard.html +0 -1410
- package/dist/generate/theme.html +0 -1082
- package/dist/index.html +0 -1745
- package/dist/index2.html +0 -2277
- package/dist/index3.html +0 -1532
- package/dist/layout/collapsed-sidebar-without-hover.html +0 -1144
- package/dist/layout/collapsed-sidebar.html +0 -1137
- package/dist/layout/fixed-complete.html +0 -1138
- package/dist/layout/fixed-footer.html +0 -1136
- package/dist/layout/fixed-header.html +0 -1136
- package/dist/layout/fixed-sidebar.html +0 -1138
- package/dist/layout/layout-custom-area.html +0 -1177
- package/dist/layout/layout-rtl.html +0 -1137
- package/dist/layout/logo-switch.html +0 -683
- package/dist/layout/sidebar-mini.html +0 -1137
- package/dist/layout/unfixed-sidebar.html +0 -1136
- package/dist/mailbox/compose.html +0 -1151
- package/dist/mailbox/inbox.html +0 -1509
- package/dist/mailbox/read.html +0 -1202
- package/dist/pages/404.html +0 -239
- package/dist/pages/500.html +0 -227
- package/dist/pages/calendar.html +0 -1266
- package/dist/pages/chat.html +0 -1427
- package/dist/pages/faq.html +0 -1383
- package/dist/pages/file-manager.html +0 -1835
- package/dist/pages/invoice.html +0 -1199
- package/dist/pages/kanban.html +0 -1439
- package/dist/pages/maintenance.html +0 -230
- package/dist/pages/pricing.html +0 -1279
- package/dist/pages/profile.html +0 -1382
- package/dist/pages/projects.html +0 -1644
- package/dist/pages/settings.html +0 -1387
- package/dist/tables/data.html +0 -1319
- package/dist/tables/simple.html +0 -1435
- package/dist/widgets/cards.html +0 -1356
- package/dist/widgets/info-box.html +0 -1429
- package/dist/widgets/small-box.html +0 -1225
- package/eslint.config.js +0 -82
- package/github-issue-response.md +0 -40
- package/index.html +0 -12
- package/netlify.toml +0 -16
package/dist/js/adminlte.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* AdminLTE v4.0.
|
|
2
|
+
* AdminLTE v4.0.4 (https://adminlte.io)
|
|
3
3
|
* Copyright 2014-2026 Colorlib <https://colorlib.com>
|
|
4
4
|
* Licensed under MIT (https://github.com/ColorlibHQ/AdminLTE/blob/master/LICENSE)
|
|
5
5
|
*/
|
|
@@ -9,25 +9,57 @@
|
|
|
9
9
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.adminlte = {}));
|
|
10
10
|
})(this, (function (exports) { 'use strict';
|
|
11
11
|
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
domContentLoadedCallbacks.push(callback);
|
|
12
|
+
const lifecycleCallbacks = [];
|
|
13
|
+
const lifecycleState = {
|
|
14
|
+
controller: new AbortController(),
|
|
15
|
+
hasInitialized: false
|
|
16
|
+
};
|
|
17
|
+
const getLifecycleSignal = () => lifecycleState.controller.signal;
|
|
18
|
+
const runLifecycleCallbacks = () => {
|
|
19
|
+
if (lifecycleState.hasInitialized) {
|
|
20
|
+
return;
|
|
23
21
|
}
|
|
24
|
-
|
|
22
|
+
lifecycleState.hasInitialized = true;
|
|
23
|
+
for (const callback of lifecycleCallbacks) {
|
|
25
24
|
callback();
|
|
26
25
|
}
|
|
27
26
|
};
|
|
27
|
+
const onDOMContentLoaded = (callback) => {
|
|
28
|
+
lifecycleCallbacks.push(callback);
|
|
29
|
+
if (lifecycleState.hasInitialized) {
|
|
30
|
+
callback();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
if (document.readyState === 'loading') {
|
|
34
|
+
document.addEventListener('DOMContentLoaded', runLifecycleCallbacks, { once: true });
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
runLifecycleCallbacks();
|
|
38
|
+
}
|
|
39
|
+
document.addEventListener('turbo:before-render', () => {
|
|
40
|
+
lifecycleState.controller.abort();
|
|
41
|
+
lifecycleState.controller = new AbortController();
|
|
42
|
+
lifecycleState.hasInitialized = false;
|
|
43
|
+
});
|
|
44
|
+
document.addEventListener('turbo:load', runLifecycleCallbacks);
|
|
45
|
+
const slideTimers = new WeakMap();
|
|
46
|
+
const cancelSlide = (target) => {
|
|
47
|
+
const timers = slideTimers.get(target) ?? [];
|
|
48
|
+
for (const timer of timers) {
|
|
49
|
+
globalThis.clearTimeout(timer);
|
|
50
|
+
}
|
|
51
|
+
slideTimers.delete(target);
|
|
52
|
+
};
|
|
53
|
+
const clearSlideStyles = (target) => {
|
|
54
|
+
for (const property of ['height', 'padding-top', 'padding-bottom', 'margin-top', 'margin-bottom', 'overflow', 'transition-duration', 'transition-property']) {
|
|
55
|
+
target.style.removeProperty(property);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
28
58
|
const slideUp = (target, duration = 500) => {
|
|
59
|
+
cancelSlide(target);
|
|
29
60
|
if (duration <= 1) {
|
|
30
61
|
target.style.display = 'none';
|
|
62
|
+
clearSlideStyles(target);
|
|
31
63
|
return;
|
|
32
64
|
}
|
|
33
65
|
target.style.transitionProperty = 'height, margin, padding';
|
|
@@ -35,26 +67,23 @@
|
|
|
35
67
|
target.style.boxSizing = 'border-box';
|
|
36
68
|
target.style.height = `${target.offsetHeight}px`;
|
|
37
69
|
target.style.overflow = 'hidden';
|
|
38
|
-
globalThis.setTimeout(() => {
|
|
70
|
+
const stepTimer = globalThis.setTimeout(() => {
|
|
39
71
|
target.style.height = '0';
|
|
40
72
|
target.style.paddingTop = '0';
|
|
41
73
|
target.style.paddingBottom = '0';
|
|
42
74
|
target.style.marginTop = '0';
|
|
43
75
|
target.style.marginBottom = '0';
|
|
44
76
|
}, 1);
|
|
45
|
-
globalThis.setTimeout(() => {
|
|
77
|
+
const cleanupTimer = globalThis.setTimeout(() => {
|
|
46
78
|
target.style.display = 'none';
|
|
47
|
-
target
|
|
48
|
-
|
|
49
|
-
target.style.removeProperty('padding-bottom');
|
|
50
|
-
target.style.removeProperty('margin-top');
|
|
51
|
-
target.style.removeProperty('margin-bottom');
|
|
52
|
-
target.style.removeProperty('overflow');
|
|
53
|
-
target.style.removeProperty('transition-duration');
|
|
54
|
-
target.style.removeProperty('transition-property');
|
|
79
|
+
clearSlideStyles(target);
|
|
80
|
+
slideTimers.delete(target);
|
|
55
81
|
}, duration);
|
|
82
|
+
slideTimers.set(target, [stepTimer, cleanupTimer]);
|
|
56
83
|
};
|
|
57
84
|
const slideDown = (target, duration = 500) => {
|
|
85
|
+
cancelSlide(target);
|
|
86
|
+
clearSlideStyles(target);
|
|
58
87
|
target.style.removeProperty('display');
|
|
59
88
|
let { display } = globalThis.getComputedStyle(target);
|
|
60
89
|
if (display === 'none') {
|
|
@@ -71,7 +100,7 @@
|
|
|
71
100
|
target.style.paddingBottom = '0';
|
|
72
101
|
target.style.marginTop = '0';
|
|
73
102
|
target.style.marginBottom = '0';
|
|
74
|
-
globalThis.setTimeout(() => {
|
|
103
|
+
const stepTimer = globalThis.setTimeout(() => {
|
|
75
104
|
target.style.boxSizing = 'border-box';
|
|
76
105
|
target.style.transitionProperty = 'height, margin, padding';
|
|
77
106
|
target.style.transitionDuration = `${duration}ms`;
|
|
@@ -81,12 +110,11 @@
|
|
|
81
110
|
target.style.removeProperty('margin-top');
|
|
82
111
|
target.style.removeProperty('margin-bottom');
|
|
83
112
|
}, 1);
|
|
84
|
-
globalThis.setTimeout(() => {
|
|
85
|
-
target
|
|
86
|
-
|
|
87
|
-
target.style.removeProperty('transition-duration');
|
|
88
|
-
target.style.removeProperty('transition-property');
|
|
113
|
+
const cleanupTimer = globalThis.setTimeout(() => {
|
|
114
|
+
clearSlideStyles(target);
|
|
115
|
+
slideTimers.delete(target);
|
|
89
116
|
}, duration);
|
|
117
|
+
slideTimers.set(target, [stepTimer, cleanupTimer]);
|
|
90
118
|
};
|
|
91
119
|
|
|
92
120
|
const CLASS_NAME_HOLD_TRANSITIONS = 'hold-transition';
|
|
@@ -110,7 +138,7 @@
|
|
|
110
138
|
}
|
|
111
139
|
onDOMContentLoaded(() => {
|
|
112
140
|
const layout = new Layout(document.body);
|
|
113
|
-
window.addEventListener('resize', () => layout.holdTransition(200));
|
|
141
|
+
window.addEventListener('resize', () => layout.holdTransition(200), { signal: getLifecycleSignal() });
|
|
114
142
|
setTimeout(() => {
|
|
115
143
|
document.body.classList.add(CLASS_NAME_APP_LOADED);
|
|
116
144
|
}, 400);
|
|
@@ -158,6 +186,7 @@
|
|
|
158
186
|
const event = new Event(EVENT_COLLAPSED$2);
|
|
159
187
|
if (this._parent) {
|
|
160
188
|
this._parent.classList.add(CLASS_NAME_COLLAPSING);
|
|
189
|
+
this._parent.classList.remove(CLASS_NAME_EXPANDING);
|
|
161
190
|
const elm = this._parent?.querySelectorAll(`:scope > ${SELECTOR_CARD_BODY}, :scope > ${SELECTOR_CARD_FOOTER}`);
|
|
162
191
|
elm.forEach(el => {
|
|
163
192
|
if (el instanceof HTMLElement) {
|
|
@@ -165,7 +194,7 @@
|
|
|
165
194
|
}
|
|
166
195
|
});
|
|
167
196
|
setTimeout(() => {
|
|
168
|
-
if (this._parent) {
|
|
197
|
+
if (this._parent?.classList.contains(CLASS_NAME_COLLAPSING)) {
|
|
169
198
|
this._parent.classList.add(CLASS_NAME_COLLAPSED);
|
|
170
199
|
this._parent.classList.remove(CLASS_NAME_COLLAPSING);
|
|
171
200
|
}
|
|
@@ -177,6 +206,7 @@
|
|
|
177
206
|
const event = new Event(EVENT_EXPANDED$2);
|
|
178
207
|
if (this._parent) {
|
|
179
208
|
this._parent.classList.add(CLASS_NAME_EXPANDING);
|
|
209
|
+
this._parent.classList.remove(CLASS_NAME_COLLAPSING, CLASS_NAME_COLLAPSED);
|
|
180
210
|
const elm = this._parent?.querySelectorAll(`:scope > ${SELECTOR_CARD_BODY}, :scope > ${SELECTOR_CARD_FOOTER}`);
|
|
181
211
|
elm.forEach(el => {
|
|
182
212
|
if (el instanceof HTMLElement) {
|
|
@@ -184,8 +214,8 @@
|
|
|
184
214
|
}
|
|
185
215
|
});
|
|
186
216
|
setTimeout(() => {
|
|
187
|
-
if (this._parent) {
|
|
188
|
-
this._parent.classList.remove(
|
|
217
|
+
if (this._parent?.classList.contains(CLASS_NAME_EXPANDING)) {
|
|
218
|
+
this._parent.classList.remove(CLASS_NAME_EXPANDING);
|
|
189
219
|
}
|
|
190
220
|
}, this._config.animationSpeed);
|
|
191
221
|
}
|
|
@@ -194,12 +224,16 @@
|
|
|
194
224
|
remove() {
|
|
195
225
|
const event = new Event(EVENT_REMOVE);
|
|
196
226
|
if (this._parent) {
|
|
197
|
-
|
|
227
|
+
const parent = this._parent;
|
|
228
|
+
slideUp(parent, this._config.animationSpeed);
|
|
229
|
+
setTimeout(() => {
|
|
230
|
+
parent.remove();
|
|
231
|
+
}, this._config.animationSpeed);
|
|
198
232
|
}
|
|
199
233
|
this._element?.dispatchEvent(event);
|
|
200
234
|
}
|
|
201
235
|
toggle() {
|
|
202
|
-
if (this._parent?.classList.contains(CLASS_NAME_COLLAPSED)) {
|
|
236
|
+
if (this._parent?.classList.contains(CLASS_NAME_COLLAPSED) || this._parent?.classList.contains(CLASS_NAME_COLLAPSING)) {
|
|
203
237
|
this.expand();
|
|
204
238
|
return;
|
|
205
239
|
}
|
|
@@ -242,6 +276,11 @@
|
|
|
242
276
|
if (this._parent?.classList.contains(CLASS_NAME_WAS_COLLAPSED)) {
|
|
243
277
|
this._parent.classList.remove(CLASS_NAME_WAS_COLLAPSED);
|
|
244
278
|
}
|
|
279
|
+
setTimeout(() => {
|
|
280
|
+
this._parent?.style.removeProperty('height');
|
|
281
|
+
this._parent?.style.removeProperty('width');
|
|
282
|
+
this._parent?.style.removeProperty('transition');
|
|
283
|
+
}, 150);
|
|
245
284
|
}
|
|
246
285
|
}, 10);
|
|
247
286
|
}
|
|
@@ -260,7 +299,7 @@
|
|
|
260
299
|
collapseBtn.forEach(btn => {
|
|
261
300
|
btn.addEventListener('click', event => {
|
|
262
301
|
event.preventDefault();
|
|
263
|
-
const target = event.
|
|
302
|
+
const target = event.currentTarget;
|
|
264
303
|
const data = new CardWidget(target, Default$1);
|
|
265
304
|
data.toggle();
|
|
266
305
|
});
|
|
@@ -269,7 +308,7 @@
|
|
|
269
308
|
removeBtn.forEach(btn => {
|
|
270
309
|
btn.addEventListener('click', event => {
|
|
271
310
|
event.preventDefault();
|
|
272
|
-
const target = event.
|
|
311
|
+
const target = event.currentTarget;
|
|
273
312
|
const data = new CardWidget(target, Default$1);
|
|
274
313
|
data.remove();
|
|
275
314
|
});
|
|
@@ -278,7 +317,7 @@
|
|
|
278
317
|
maxBtn.forEach(btn => {
|
|
279
318
|
btn.addEventListener('click', event => {
|
|
280
319
|
event.preventDefault();
|
|
281
|
-
const target = event.
|
|
320
|
+
const target = event.currentTarget;
|
|
282
321
|
const data = new CardWidget(target, Default$1);
|
|
283
322
|
data.toggleMaximize();
|
|
284
323
|
});
|
|
@@ -299,6 +338,10 @@
|
|
|
299
338
|
animationSpeed: 300,
|
|
300
339
|
accordion: true
|
|
301
340
|
};
|
|
341
|
+
const setAriaExpanded = (navItem, expanded) => {
|
|
342
|
+
const link = navItem.querySelector(`:scope > ${SELECTOR_NAV_LINK}`);
|
|
343
|
+
link?.setAttribute('aria-expanded', String(expanded));
|
|
344
|
+
};
|
|
302
345
|
class Treeview {
|
|
303
346
|
_element;
|
|
304
347
|
_config;
|
|
@@ -311,8 +354,9 @@
|
|
|
311
354
|
if (this._config.accordion) {
|
|
312
355
|
const openMenuList = this._element.parentElement?.querySelectorAll(`${SELECTOR_NAV_ITEM}.${CLASS_NAME_MENU_OPEN}`);
|
|
313
356
|
openMenuList?.forEach(openMenu => {
|
|
314
|
-
if (
|
|
357
|
+
if (!this._element.contains(openMenu)) {
|
|
315
358
|
openMenu.classList.remove(CLASS_NAME_MENU_OPEN);
|
|
359
|
+
setAriaExpanded(openMenu, false);
|
|
316
360
|
const childElement = openMenu?.querySelector(SELECTOR_TREEVIEW_MENU);
|
|
317
361
|
if (childElement) {
|
|
318
362
|
slideUp(childElement, this._config.animationSpeed);
|
|
@@ -321,6 +365,7 @@
|
|
|
321
365
|
});
|
|
322
366
|
}
|
|
323
367
|
this._element.classList.add(CLASS_NAME_MENU_OPEN);
|
|
368
|
+
setAriaExpanded(this._element, true);
|
|
324
369
|
const childElement = this._element?.querySelector(SELECTOR_TREEVIEW_MENU);
|
|
325
370
|
if (childElement) {
|
|
326
371
|
slideDown(childElement, this._config.animationSpeed);
|
|
@@ -330,6 +375,7 @@
|
|
|
330
375
|
close() {
|
|
331
376
|
const event = new Event(EVENT_COLLAPSED$1);
|
|
332
377
|
this._element.classList.remove(CLASS_NAME_MENU_OPEN);
|
|
378
|
+
setAriaExpanded(this._element, false);
|
|
333
379
|
const childElement = this._element?.querySelector(SELECTOR_TREEVIEW_MENU);
|
|
334
380
|
if (childElement) {
|
|
335
381
|
slideUp(childElement, this._config.animationSpeed);
|
|
@@ -355,6 +401,13 @@
|
|
|
355
401
|
menuItem.dispatchEvent(event);
|
|
356
402
|
}
|
|
357
403
|
});
|
|
404
|
+
document.querySelectorAll(SELECTOR_DATA_TOGGLE$1).forEach(root => {
|
|
405
|
+
root.querySelectorAll(SELECTOR_NAV_ITEM).forEach(item => {
|
|
406
|
+
if (item.querySelector(`:scope > ${SELECTOR_TREEVIEW_MENU}`)) {
|
|
407
|
+
setAriaExpanded(item, item.classList.contains(CLASS_NAME_MENU_OPEN));
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
});
|
|
358
411
|
const button = document.querySelectorAll(SELECTOR_DATA_TOGGLE$1);
|
|
359
412
|
button.forEach(btn => {
|
|
360
413
|
btn.addEventListener('click', event => {
|
|
@@ -430,6 +483,17 @@
|
|
|
430
483
|
const SELECTOR_FULLSCREEN_TOGGLE = '[data-lte-toggle="fullscreen"]';
|
|
431
484
|
const SELECTOR_MAXIMIZE_ICON = '[data-lte-icon="maximize"]';
|
|
432
485
|
const SELECTOR_MINIMIZE_ICON = '[data-lte-icon="minimize"]';
|
|
486
|
+
function syncFullScreenState() {
|
|
487
|
+
const iconMaximize = document.querySelector(SELECTOR_MAXIMIZE_ICON);
|
|
488
|
+
const iconMinimize = document.querySelector(SELECTOR_MINIMIZE_ICON);
|
|
489
|
+
const isFullScreen = Boolean(document.fullscreenElement);
|
|
490
|
+
iconMaximize?.classList.toggle('d-none', isFullScreen);
|
|
491
|
+
iconMinimize?.classList.toggle('d-none', !isFullScreen);
|
|
492
|
+
const eventName = isFullScreen ? EVENT_MAXIMIZED : EVENT_MINIMIZED;
|
|
493
|
+
document.querySelectorAll(SELECTOR_FULLSCREEN_TOGGLE).forEach(button => {
|
|
494
|
+
button.dispatchEvent(new Event(eventName));
|
|
495
|
+
});
|
|
496
|
+
}
|
|
433
497
|
class FullScreen {
|
|
434
498
|
_element;
|
|
435
499
|
_config;
|
|
@@ -438,43 +502,27 @@
|
|
|
438
502
|
this._config = config;
|
|
439
503
|
}
|
|
440
504
|
inFullScreen() {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
const iconMinimize = document.querySelector(SELECTOR_MINIMIZE_ICON);
|
|
444
|
-
void document.documentElement.requestFullscreen();
|
|
445
|
-
if (iconMaximize) {
|
|
446
|
-
iconMaximize.classList.add('d-none');
|
|
447
|
-
}
|
|
448
|
-
if (iconMinimize) {
|
|
449
|
-
iconMinimize.classList.remove('d-none');
|
|
450
|
-
}
|
|
451
|
-
this._element.dispatchEvent(event);
|
|
505
|
+
void document.documentElement.requestFullscreen().catch(() => {
|
|
506
|
+
});
|
|
452
507
|
}
|
|
453
508
|
outFullscreen() {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
const iconMinimize = document.querySelector(SELECTOR_MINIMIZE_ICON);
|
|
457
|
-
void document.exitFullscreen();
|
|
458
|
-
if (iconMaximize) {
|
|
459
|
-
iconMaximize.classList.remove('d-none');
|
|
460
|
-
}
|
|
461
|
-
if (iconMinimize) {
|
|
462
|
-
iconMinimize.classList.add('d-none');
|
|
463
|
-
}
|
|
464
|
-
this._element.dispatchEvent(event);
|
|
509
|
+
void document.exitFullscreen().catch(() => {
|
|
510
|
+
});
|
|
465
511
|
}
|
|
466
512
|
toggleFullScreen() {
|
|
467
|
-
if (document.fullscreenEnabled) {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
513
|
+
if (!document.fullscreenEnabled) {
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (document.fullscreenElement) {
|
|
517
|
+
this.outFullscreen();
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
this.inFullScreen();
|
|
474
521
|
}
|
|
475
522
|
}
|
|
476
523
|
}
|
|
477
524
|
onDOMContentLoaded(() => {
|
|
525
|
+
document.addEventListener('fullscreenchange', syncFullScreenState, { signal: getLifecycleSignal() });
|
|
478
526
|
const buttons = document.querySelectorAll(SELECTOR_FULLSCREEN_TOGGLE);
|
|
479
527
|
buttons.forEach(btn => {
|
|
480
528
|
btn.addEventListener('click', event => {
|
|
@@ -504,7 +552,7 @@
|
|
|
504
552
|
const SELECTOR_SIDEBAR_TOGGLE = '[data-lte-toggle="sidebar"]';
|
|
505
553
|
const STORAGE_KEY_SIDEBAR_STATE = 'lte.sidebar.state';
|
|
506
554
|
const Defaults = {
|
|
507
|
-
sidebarBreakpoint:
|
|
555
|
+
sidebarBreakpoint: 991.98,
|
|
508
556
|
enablePersistence: false
|
|
509
557
|
};
|
|
510
558
|
class PushMenu {
|
|
@@ -648,13 +696,17 @@
|
|
|
648
696
|
};
|
|
649
697
|
const pushMenu = new PushMenu(sidebar, config);
|
|
650
698
|
pushMenu.init();
|
|
651
|
-
|
|
652
|
-
|
|
699
|
+
const breakpointQuery = globalThis.matchMedia(`(max-width: ${pushMenu._config.sidebarBreakpoint}px)`);
|
|
700
|
+
breakpointQuery.addEventListener('change', () => {
|
|
653
701
|
pushMenu.updateStateByResponsiveLogic();
|
|
654
|
-
});
|
|
655
|
-
const
|
|
656
|
-
sidebarOverlay
|
|
657
|
-
|
|
702
|
+
}, { signal: getLifecycleSignal() });
|
|
703
|
+
const appWrapper = document.querySelector(SELECTOR_APP_WRAPPER);
|
|
704
|
+
let sidebarOverlay = appWrapper?.querySelector(`:scope > .${CLASS_NAME_SIDEBAR_OVERLAY}`);
|
|
705
|
+
if (!sidebarOverlay) {
|
|
706
|
+
sidebarOverlay = document.createElement('div');
|
|
707
|
+
sidebarOverlay.className = CLASS_NAME_SIDEBAR_OVERLAY;
|
|
708
|
+
appWrapper?.append(sidebarOverlay);
|
|
709
|
+
}
|
|
658
710
|
let overlayTouchMoved = false;
|
|
659
711
|
sidebarOverlay.addEventListener('touchstart', () => {
|
|
660
712
|
overlayTouchMoved = false;
|
|
@@ -693,6 +745,7 @@
|
|
|
693
745
|
config;
|
|
694
746
|
liveRegion = null;
|
|
695
747
|
focusHistory = [];
|
|
748
|
+
signal = getLifecycleSignal();
|
|
696
749
|
constructor(config = {}) {
|
|
697
750
|
this.config = {
|
|
698
751
|
announcements: true,
|
|
@@ -727,6 +780,11 @@
|
|
|
727
780
|
createLiveRegion() {
|
|
728
781
|
if (this.liveRegion)
|
|
729
782
|
return;
|
|
783
|
+
const existingRegion = document.getElementById('live-region');
|
|
784
|
+
if (existingRegion) {
|
|
785
|
+
this.liveRegion = existingRegion;
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
730
788
|
this.liveRegion = document.createElement('div');
|
|
731
789
|
this.liveRegion.id = 'live-region';
|
|
732
790
|
this.liveRegion.className = 'live-region';
|
|
@@ -736,6 +794,10 @@
|
|
|
736
794
|
document.body.append(this.liveRegion);
|
|
737
795
|
}
|
|
738
796
|
addSkipLinks() {
|
|
797
|
+
if (document.querySelector('.skip-links')) {
|
|
798
|
+
this.ensureSkipTargets();
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
739
801
|
const skipLinksContainer = document.createElement('div');
|
|
740
802
|
skipLinksContainer.className = 'skip-links';
|
|
741
803
|
const skipToMain = document.createElement('a');
|
|
@@ -769,42 +831,13 @@
|
|
|
769
831
|
}
|
|
770
832
|
initFocusManagement() {
|
|
771
833
|
document.addEventListener('keydown', (event) => {
|
|
772
|
-
if (event.key === 'Tab') {
|
|
773
|
-
this.handleTabNavigation(event);
|
|
774
|
-
}
|
|
775
834
|
if (event.key === 'Escape') {
|
|
776
835
|
this.handleEscapeKey(event);
|
|
777
836
|
}
|
|
778
|
-
});
|
|
837
|
+
}, { signal: this.signal });
|
|
779
838
|
this.initModalFocusManagement();
|
|
780
839
|
this.initDropdownFocusManagement();
|
|
781
840
|
}
|
|
782
|
-
handleTabNavigation(event) {
|
|
783
|
-
const focusableElements = this.getFocusableElements();
|
|
784
|
-
const currentIndex = focusableElements.indexOf(document.activeElement);
|
|
785
|
-
if (event.shiftKey) {
|
|
786
|
-
if (currentIndex <= 0) {
|
|
787
|
-
event.preventDefault();
|
|
788
|
-
focusableElements.at(-1)?.focus();
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
else if (currentIndex >= focusableElements.length - 1) {
|
|
792
|
-
event.preventDefault();
|
|
793
|
-
focusableElements[0]?.focus();
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
getFocusableElements() {
|
|
797
|
-
const selector = [
|
|
798
|
-
'a[href]',
|
|
799
|
-
'button:not([disabled])',
|
|
800
|
-
'input:not([disabled])',
|
|
801
|
-
'select:not([disabled])',
|
|
802
|
-
'textarea:not([disabled])',
|
|
803
|
-
'[tabindex]:not([tabindex="-1"])',
|
|
804
|
-
'[contenteditable="true"]'
|
|
805
|
-
].join(', ');
|
|
806
|
-
return Array.from(document.querySelectorAll(selector));
|
|
807
|
-
}
|
|
808
841
|
handleEscapeKey(event) {
|
|
809
842
|
const activeModal = document.querySelector('.modal.show');
|
|
810
843
|
if (activeModal) {
|
|
@@ -820,6 +853,9 @@
|
|
|
820
853
|
initKeyboardNavigation() {
|
|
821
854
|
document.addEventListener('keydown', (event) => {
|
|
822
855
|
const target = event.target;
|
|
856
|
+
if (target.matches('input, textarea, select, [contenteditable], [contenteditable] *')) {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
823
859
|
if (target.closest('.nav, .navbar-nav, .dropdown-menu')) {
|
|
824
860
|
this.handleMenuNavigation(event);
|
|
825
861
|
}
|
|
@@ -827,15 +863,19 @@
|
|
|
827
863
|
event.preventDefault();
|
|
828
864
|
target.click();
|
|
829
865
|
}
|
|
830
|
-
});
|
|
866
|
+
}, { signal: this.signal });
|
|
831
867
|
}
|
|
832
868
|
handleMenuNavigation(event) {
|
|
833
869
|
if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) {
|
|
834
870
|
return;
|
|
835
871
|
}
|
|
836
872
|
const currentElement = event.target;
|
|
837
|
-
const menuItems = Array.from(currentElement.closest('.nav, .navbar-nav, .dropdown-menu')?.querySelectorAll('a, button') || [])
|
|
873
|
+
const menuItems = Array.from(currentElement.closest('.nav, .navbar-nav, .dropdown-menu')?.querySelectorAll('a, button') || [])
|
|
874
|
+
.filter(item => item.offsetParent !== null);
|
|
838
875
|
const currentIndex = menuItems.indexOf(currentElement);
|
|
876
|
+
if (currentIndex === -1) {
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
839
879
|
let nextIndex;
|
|
840
880
|
switch (event.key) {
|
|
841
881
|
case 'ArrowDown':
|
|
@@ -868,15 +908,18 @@
|
|
|
868
908
|
if (prefersReducedMotion) {
|
|
869
909
|
document.body.classList.add('reduce-motion');
|
|
870
910
|
document.documentElement.style.scrollBehavior = 'auto';
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
911
|
+
if (!document.getElementById('adminlte-reduce-motion')) {
|
|
912
|
+
const style = document.createElement('style');
|
|
913
|
+
style.id = 'adminlte-reduce-motion';
|
|
914
|
+
style.textContent = `
|
|
915
|
+
*, *::before, *::after {
|
|
916
|
+
animation-duration: 0.01ms !important;
|
|
917
|
+
animation-iteration-count: 1 !important;
|
|
918
|
+
transition-duration: 0.01ms !important;
|
|
919
|
+
}
|
|
920
|
+
`;
|
|
921
|
+
document.head.append(style);
|
|
922
|
+
}
|
|
880
923
|
}
|
|
881
924
|
}
|
|
882
925
|
initErrorAnnouncements() {
|
|
@@ -899,6 +942,9 @@
|
|
|
899
942
|
childList: true,
|
|
900
943
|
subtree: true
|
|
901
944
|
});
|
|
945
|
+
this.signal.addEventListener('abort', () => {
|
|
946
|
+
observer.disconnect();
|
|
947
|
+
}, { once: true });
|
|
902
948
|
}
|
|
903
949
|
initTableAccessibility() {
|
|
904
950
|
document.querySelectorAll('table').forEach((table) => {
|
|
@@ -950,6 +996,9 @@
|
|
|
950
996
|
});
|
|
951
997
|
}
|
|
952
998
|
handleFormError(input) {
|
|
999
|
+
if (!input.id && !input.name) {
|
|
1000
|
+
input.id = accessibilityUtils.generateId('field');
|
|
1001
|
+
}
|
|
953
1002
|
const errorId = `${input.id || input.name}-error`;
|
|
954
1003
|
let errorElement = document.getElementById(errorId);
|
|
955
1004
|
if (!errorElement) {
|
|
@@ -960,25 +1009,31 @@
|
|
|
960
1009
|
input.parentNode?.append(errorElement);
|
|
961
1010
|
}
|
|
962
1011
|
errorElement.textContent = input.validationMessage;
|
|
963
|
-
input.
|
|
1012
|
+
const describedBy = (input.getAttribute('aria-describedby') || '').split(/\s+/).filter(Boolean);
|
|
1013
|
+
if (!describedBy.includes(errorId)) {
|
|
1014
|
+
describedBy.push(errorId);
|
|
1015
|
+
}
|
|
1016
|
+
input.setAttribute('aria-describedby', describedBy.join(' '));
|
|
964
1017
|
input.classList.add('is-invalid');
|
|
965
1018
|
this.announce(`Error in ${input.labels?.[0]?.textContent || input.name}: ${input.validationMessage}`, 'assertive');
|
|
966
1019
|
}
|
|
967
1020
|
initModalFocusManagement() {
|
|
1021
|
+
document.addEventListener('show.bs.modal', () => {
|
|
1022
|
+
this.focusHistory.push(document.activeElement);
|
|
1023
|
+
}, { signal: this.signal });
|
|
968
1024
|
document.addEventListener('shown.bs.modal', (event) => {
|
|
969
1025
|
const modal = event.target;
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
});
|
|
1026
|
+
const autofocusElement = modal.querySelector('[autofocus]');
|
|
1027
|
+
const firstFocusable = autofocusElement ||
|
|
1028
|
+
modal.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
|
1029
|
+
firstFocusable?.focus();
|
|
1030
|
+
}, { signal: this.signal });
|
|
976
1031
|
document.addEventListener('hidden.bs.modal', () => {
|
|
977
1032
|
const previousElement = this.focusHistory.pop();
|
|
978
|
-
if (previousElement) {
|
|
1033
|
+
if (previousElement?.isConnected) {
|
|
979
1034
|
previousElement.focus();
|
|
980
1035
|
}
|
|
981
|
-
});
|
|
1036
|
+
}, { signal: this.signal });
|
|
982
1037
|
}
|
|
983
1038
|
initDropdownFocusManagement() {
|
|
984
1039
|
document.addEventListener('shown.bs.dropdown', (event) => {
|
|
@@ -988,7 +1043,7 @@
|
|
|
988
1043
|
if (firstItem) {
|
|
989
1044
|
firstItem.focus();
|
|
990
1045
|
}
|
|
991
|
-
});
|
|
1046
|
+
}, { signal: this.signal });
|
|
992
1047
|
}
|
|
993
1048
|
announce(message, priority = 'polite') {
|
|
994
1049
|
if (!this.liveRegion) {
|
|
@@ -1029,7 +1084,7 @@
|
|
|
1029
1084
|
event.preventDefault();
|
|
1030
1085
|
}
|
|
1031
1086
|
}
|
|
1032
|
-
});
|
|
1087
|
+
}, { signal: this.signal });
|
|
1033
1088
|
}
|
|
1034
1089
|
addLandmarks() {
|
|
1035
1090
|
const main = document.querySelector('main');
|
|
@@ -1037,7 +1092,9 @@
|
|
|
1037
1092
|
const appMain = document.querySelector('.app-main');
|
|
1038
1093
|
if (appMain) {
|
|
1039
1094
|
appMain.setAttribute('role', 'main');
|
|
1040
|
-
appMain.id
|
|
1095
|
+
if (!appMain.id) {
|
|
1096
|
+
appMain.id = 'main';
|
|
1097
|
+
}
|
|
1041
1098
|
}
|
|
1042
1099
|
}
|
|
1043
1100
|
document.querySelectorAll('.navbar-nav, .nav').forEach((nav, index) => {
|
|
@@ -1060,6 +1117,54 @@
|
|
|
1060
1117
|
const initAccessibility = (config) => {
|
|
1061
1118
|
return new AccessibilityManager(config);
|
|
1062
1119
|
};
|
|
1120
|
+
const parseColorChannels = (color) => {
|
|
1121
|
+
const hexMatch = /^#([\da-f]{3}|[\da-f]{6})$/i.exec(color.trim());
|
|
1122
|
+
if (hexMatch) {
|
|
1123
|
+
let hex = hexMatch[1];
|
|
1124
|
+
if (hex.length === 3) {
|
|
1125
|
+
hex = [...hex].map(character => character + character).join('');
|
|
1126
|
+
}
|
|
1127
|
+
return [
|
|
1128
|
+
Number.parseInt(hex.slice(0, 2), 16),
|
|
1129
|
+
Number.parseInt(hex.slice(2, 4), 16),
|
|
1130
|
+
Number.parseInt(hex.slice(4, 6), 16)
|
|
1131
|
+
];
|
|
1132
|
+
}
|
|
1133
|
+
return color.match(/\d+/g)?.map(Number) || [0, 0, 0];
|
|
1134
|
+
};
|
|
1135
|
+
const getLuminance = (color) => {
|
|
1136
|
+
const [r, g, b] = parseColorChannels(color).map(c => {
|
|
1137
|
+
c = c / 255;
|
|
1138
|
+
return c <= 0.039_28 ? c / 12.92 : (c + 0.055) ** 2.4 / (1.055 ** 2.4);
|
|
1139
|
+
});
|
|
1140
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
1141
|
+
};
|
|
1142
|
+
const accessibilityUtils = {
|
|
1143
|
+
checkColorContrast: (foreground, background) => {
|
|
1144
|
+
const l1 = getLuminance(foreground);
|
|
1145
|
+
const l2 = getLuminance(background);
|
|
1146
|
+
const ratio = (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
|
|
1147
|
+
return {
|
|
1148
|
+
ratio: Math.round(ratio * 100) / 100,
|
|
1149
|
+
passes: ratio >= 4.5
|
|
1150
|
+
};
|
|
1151
|
+
},
|
|
1152
|
+
generateId: (prefix = 'a11y') => {
|
|
1153
|
+
return `${prefix}-${Math.random().toString(36).slice(2, 11)}`;
|
|
1154
|
+
},
|
|
1155
|
+
isFocusable: (element) => {
|
|
1156
|
+
const focusableSelectors = [
|
|
1157
|
+
'a[href]',
|
|
1158
|
+
'button:not([disabled])',
|
|
1159
|
+
'input:not([disabled])',
|
|
1160
|
+
'select:not([disabled])',
|
|
1161
|
+
'textarea:not([disabled])',
|
|
1162
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
1163
|
+
'[contenteditable="true"]'
|
|
1164
|
+
];
|
|
1165
|
+
return focusableSelectors.some(selector => element.matches(selector));
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1063
1168
|
|
|
1064
1169
|
onDOMContentLoaded(() => {
|
|
1065
1170
|
const accessibilityManager = initAccessibility({
|