admin-lte 4.0.4 → 4.2.0
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/CHANGELOG.md +41 -1
- package/README.md +6 -6
- package/dist/css/adminlte-docs.css +878 -0
- package/dist/css/adminlte-docs.css.map +1 -0
- package/dist/css/adminlte-docs.min.css +7 -0
- package/dist/css/adminlte-docs.min.css.map +1 -0
- package/dist/css/adminlte-docs.rtl.css +877 -0
- package/dist/css/adminlte-docs.rtl.css.map +1 -0
- package/dist/css/adminlte-docs.rtl.min.css +7 -0
- package/dist/css/adminlte-docs.rtl.min.css.map +1 -0
- package/dist/css/adminlte.css +132 -912
- 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 +132 -912
- 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.esm.js +1406 -0
- package/dist/js/adminlte.esm.js.map +1 -0
- package/dist/js/adminlte.esm.min.js +7 -0
- package/dist/js/adminlte.esm.min.js.map +1 -0
- package/dist/js/adminlte.js +449 -215
- 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/dist/js/types/accessibility.d.ts +46 -0
- package/dist/js/types/adminlte.d.ts +10 -0
- package/dist/js/types/base-component.d.ts +60 -0
- package/dist/js/types/card-widget.d.ts +30 -0
- package/dist/js/types/color-mode.d.ts +74 -0
- package/dist/js/types/direct-chat.d.ts +19 -0
- package/dist/js/types/fullscreen.d.ts +21 -0
- package/dist/js/types/layout.d.ts +19 -0
- package/dist/js/types/push-menu.d.ts +123 -0
- package/dist/js/types/treeview.d.ts +27 -0
- package/dist/js/types/util/index.d.ts +79 -0
- package/package.json +52 -25
- package/src/scss/_app-header.scss +3 -1
- package/src/scss/_app-main.scss +4 -0
- package/src/scss/_app-sidebar.scss +3 -1
- package/src/scss/_bootstrap-overrides.scss +60 -0
- package/src/scss/_info-box.scss +3 -1
- package/src/scss/_progress-bars.scss +3 -1
- package/src/scss/_table.scss +4 -2
- package/src/scss/adminlte-docs.scss +25 -0
- package/src/scss/adminlte.scss +5 -4
- package/src/scss/pages/_login_and_register.scss +3 -1
- package/src/ts/accessibility.ts +6 -2
- package/src/ts/adminlte.ts +7 -3
- package/src/ts/base-component.ts +111 -0
- package/src/ts/card-widget.ts +124 -100
- package/src/ts/color-mode.ts +254 -0
- package/src/ts/direct-chat.ts +38 -32
- package/src/ts/fullscreen.ts +32 -23
- package/src/ts/push-menu.ts +106 -43
- package/src/ts/treeview.ts +84 -50
- package/src/ts/util/index.ts +80 -16
- package/src/scss/_bootstrap-variables.scss +0 -1766
package/src/scss/_table.scss
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@use "sass:map";
|
|
2
|
+
|
|
1
3
|
//
|
|
2
4
|
// Component: Table
|
|
3
5
|
//
|
|
@@ -56,11 +58,11 @@
|
|
|
56
58
|
tbody > tr > th,
|
|
57
59
|
tbody > tr > td {
|
|
58
60
|
&:first-of-type {
|
|
59
|
-
padding-left: map
|
|
61
|
+
padding-left: map.get($spacers, 4);
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
&:last-of-type {
|
|
63
|
-
padding-right: map
|
|
65
|
+
padding-right: map.get($spacers, 4);
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* AdminLTE v4.2.0 — documentation styles
|
|
3
|
+
* Styles for the documentation and FAQ pages only (body.docs-page /
|
|
4
|
+
* body.faq-page). Applications never need this file; it is loaded by the
|
|
5
|
+
* docs pages in addition to adminlte.css.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Bootstrap Configuration
|
|
9
|
+
// ---------------------------------------------------
|
|
10
|
+
@import "bootstrap/scss/functions";
|
|
11
|
+
@import "bootstrap-overrides";
|
|
12
|
+
@import "bootstrap/scss/variables";
|
|
13
|
+
@import "bootstrap/scss/variables-dark";
|
|
14
|
+
@import "bootstrap/scss/maps";
|
|
15
|
+
@import "bootstrap/scss/mixins";
|
|
16
|
+
|
|
17
|
+
// AdminLTE Configuration
|
|
18
|
+
// ---------------------------------------------------
|
|
19
|
+
@import "variables";
|
|
20
|
+
@import "variables-dark";
|
|
21
|
+
@import "mixins";
|
|
22
|
+
|
|
23
|
+
// Documentation styles
|
|
24
|
+
// ---------------------------------------------------
|
|
25
|
+
@import "docs";
|
package/src/scss/adminlte.scss
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* AdminLTE v4.0
|
|
2
|
+
* AdminLTE v4.2.0
|
|
3
3
|
* Author: Colorlib
|
|
4
4
|
* Website: AdminLTE.io <https://adminlte.io>
|
|
5
5
|
* License: Open source - MIT <https://opensource.org/licenses/MIT>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
// AdminLTE Configuration
|
|
13
13
|
// ---------------------------------------------------
|
|
14
|
-
@import "bootstrap-
|
|
14
|
+
@import "bootstrap-overrides"; // AdminLTE's ~10 changes to Bootstrap defaults
|
|
15
15
|
|
|
16
16
|
// Bootstrap Configuration
|
|
17
17
|
// ---------------------------------------------------
|
|
@@ -77,5 +77,6 @@
|
|
|
77
77
|
// AdminLTE Accessibility Styles - WCAG 2.1 AA Compliance
|
|
78
78
|
@import "accessibility";
|
|
79
79
|
|
|
80
|
-
//
|
|
81
|
-
|
|
80
|
+
// Documentation styles live in their own bundle (adminlte-docs.scss) so
|
|
81
|
+
// applications don't ship them — the docs pages load it in addition to
|
|
82
|
+
// this file.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@use "sass:map";
|
|
2
|
+
|
|
1
3
|
//
|
|
2
4
|
// Pages: Login & Register
|
|
3
5
|
//
|
|
@@ -28,7 +30,7 @@
|
|
|
28
30
|
.register-box {
|
|
29
31
|
width: 400px;
|
|
30
32
|
|
|
31
|
-
@media (max-width: map
|
|
33
|
+
@media (max-width: map.get($grid-breakpoints, sm)) {
|
|
32
34
|
width: 90%;
|
|
33
35
|
margin-top: .5rem;
|
|
34
36
|
}
|
package/src/ts/accessibility.ts
CHANGED
|
@@ -357,11 +357,15 @@ export class AccessibilityManager {
|
|
|
357
357
|
}
|
|
358
358
|
|
|
359
359
|
// Handle invalid state unless the element explicitly opts out via the
|
|
360
|
-
// 'disable-adminlte-validations' class.
|
|
360
|
+
// 'disable-adminlte-validations' class. Registered with the lifecycle
|
|
361
|
+
// signal: this runs once per cycle, and under a framework that
|
|
362
|
+
// re-initialises against a persistent <body> (initialize()) the inputs
|
|
363
|
+
// survive the cycle — an unsignalled listener would stack one handler
|
|
364
|
+
// per re-init on every field.
|
|
361
365
|
if (!htmlInput.classList.contains('disable-adminlte-validations')) {
|
|
362
366
|
htmlInput.addEventListener('invalid', () => {
|
|
363
367
|
this.handleFormError(htmlInput)
|
|
364
|
-
})
|
|
368
|
+
}, { signal: this.signal })
|
|
365
369
|
}
|
|
366
370
|
})
|
|
367
371
|
}
|
package/src/ts/adminlte.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { onDOMContentLoaded } from './util/index.js'
|
|
1
|
+
import { initialize, teardown, onDOMContentLoaded } from './util/index.js'
|
|
2
2
|
import Layout from './layout.js'
|
|
3
3
|
import CardWidget from './card-widget.js'
|
|
4
4
|
import Treeview from './treeview.js'
|
|
5
5
|
import DirectChat from './direct-chat.js'
|
|
6
6
|
import FullScreen from './fullscreen.js'
|
|
7
7
|
import PushMenu from './push-menu.js'
|
|
8
|
+
import ColorMode from './color-mode.js'
|
|
8
9
|
import { initAccessibility } from './accessibility.js'
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* AdminLTE v4.0
|
|
12
|
+
* AdminLTE v4.2.0
|
|
12
13
|
* Author: Colorlib
|
|
13
14
|
* Website: AdminLTE.io <https://adminlte.io>
|
|
14
15
|
* License: Open source - MIT <https://opensource.org/licenses/MIT>
|
|
@@ -38,5 +39,8 @@ export {
|
|
|
38
39
|
DirectChat,
|
|
39
40
|
FullScreen,
|
|
40
41
|
PushMenu,
|
|
41
|
-
|
|
42
|
+
ColorMode,
|
|
43
|
+
initAccessibility,
|
|
44
|
+
initialize,
|
|
45
|
+
teardown
|
|
42
46
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* --------------------------------------------
|
|
3
|
+
* @file AdminLTE base-component.ts
|
|
4
|
+
* @description Shared component lifecycle for AdminLTE plugins: a per-element
|
|
5
|
+
* instance registry (getInstance / getOrCreateInstance / dispose) and a
|
|
6
|
+
* consistent custom-event contract, mirroring Bootstrap's component API.
|
|
7
|
+
* @license MIT
|
|
8
|
+
* --------------------------------------------
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Component registry: element -> (data key -> component instance). A single
|
|
13
|
+
* element can host several components at once, each stored under its own
|
|
14
|
+
* DATA_KEY. WeakMap keys don't prevent garbage collection, so instances die
|
|
15
|
+
* with their elements — important under Hotwired Turbo, which swaps the whole
|
|
16
|
+
* <body> on navigation.
|
|
17
|
+
*/
|
|
18
|
+
const componentRegistry = new WeakMap<Element, Map<string, BaseComponent>>()
|
|
19
|
+
|
|
20
|
+
class BaseComponent {
|
|
21
|
+
/**
|
|
22
|
+
* Subclasses must override this getter to declare their own name.
|
|
23
|
+
*/
|
|
24
|
+
static get NAME(): string {
|
|
25
|
+
throw new Error('Component subclasses must override the static NAME getter.')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Key this component is registered under: `lte.<name>`.
|
|
30
|
+
*/
|
|
31
|
+
static get DATA_KEY(): string {
|
|
32
|
+
return `lte.${this.NAME}`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Untyped registry lookup. Every component exposes a typed wrapper
|
|
37
|
+
* (e.g. CardWidget.getInstance()) built on top of this.
|
|
38
|
+
*
|
|
39
|
+
* @param element The element to look up.
|
|
40
|
+
* @returns The instance for this component, or null if there is none.
|
|
41
|
+
*/
|
|
42
|
+
protected static _getInstance(element: Element | null | undefined): BaseComponent | null {
|
|
43
|
+
if (!element) {
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return componentRegistry.get(element)?.get(this.DATA_KEY) ?? null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The element this instance is attached to.
|
|
52
|
+
*/
|
|
53
|
+
_element: HTMLElement
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Attach a new instance to the given element and register it under the
|
|
57
|
+
* subclass's DATA_KEY.
|
|
58
|
+
*
|
|
59
|
+
* @param element The element to attach this instance to.
|
|
60
|
+
*/
|
|
61
|
+
constructor(element: HTMLElement) {
|
|
62
|
+
this._element = element
|
|
63
|
+
|
|
64
|
+
const instances = componentRegistry.get(element) ?? new Map<string, BaseComponent>()
|
|
65
|
+
componentRegistry.set(element, instances)
|
|
66
|
+
instances.set((this.constructor as typeof BaseComponent).DATA_KEY, this)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Remove this instance from the registry so getInstance() no longer
|
|
71
|
+
* returns it. Subclasses release their own resources, then call
|
|
72
|
+
* super.dispose().
|
|
73
|
+
*/
|
|
74
|
+
dispose(): void {
|
|
75
|
+
const instances = componentRegistry.get(this._element)
|
|
76
|
+
instances?.delete((this.constructor as typeof BaseComponent).DATA_KEY)
|
|
77
|
+
|
|
78
|
+
// Drop the element's entry once it holds no components at all.
|
|
79
|
+
if (instances?.size === 0) {
|
|
80
|
+
componentRegistry.delete(this._element)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Dispatch a namespaced custom event that bubbles — so applications can
|
|
87
|
+
* listen once on `document` — and can optionally carry a payload or be
|
|
88
|
+
* canceled. Returns the event so callers can check `defaultPrevented`.
|
|
89
|
+
*
|
|
90
|
+
* @param element The element to dispatch the event on.
|
|
91
|
+
* @param name The namespaced event name, e.g. `collapse.lte.push-menu`.
|
|
92
|
+
* @param options `cancelable` opts the event into preventDefault(); `detail`
|
|
93
|
+
* is the payload handed to listeners.
|
|
94
|
+
* @returns The dispatched event, after listeners have run.
|
|
95
|
+
*/
|
|
96
|
+
const dispatchCustomEvent = <T = undefined>(
|
|
97
|
+
element: Element,
|
|
98
|
+
name: string,
|
|
99
|
+
options: { cancelable?: boolean; detail?: T } = {}
|
|
100
|
+
): CustomEvent<T | undefined> => {
|
|
101
|
+
const event = new CustomEvent<T | undefined>(name, {
|
|
102
|
+
bubbles: true,
|
|
103
|
+
cancelable: options.cancelable ?? false,
|
|
104
|
+
detail: options.detail
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
element.dispatchEvent(event)
|
|
108
|
+
return event
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { BaseComponent, dispatchCustomEvent }
|
package/src/ts/card-widget.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* --------------------------------------------
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { BaseComponent, dispatchCustomEvent } from './base-component'
|
|
9
10
|
import {
|
|
10
|
-
onDOMContentLoaded,
|
|
11
11
|
slideUp,
|
|
12
12
|
slideDown
|
|
13
13
|
} from './util/index'
|
|
@@ -17,11 +17,18 @@ import {
|
|
|
17
17
|
* ====================================================
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
const
|
|
21
|
-
const EVENT_KEY =
|
|
20
|
+
const NAME = 'card-widget'
|
|
21
|
+
const EVENT_KEY = `.lte.${NAME}`
|
|
22
|
+
|
|
23
|
+
// Cancelable "before" events, dispatched on the card when an action starts.
|
|
24
|
+
const EVENT_COLLAPSE = `collapse${EVENT_KEY}`
|
|
25
|
+
const EVENT_EXPAND = `expand${EVENT_KEY}`
|
|
26
|
+
const EVENT_REMOVE = `remove${EVENT_KEY}`
|
|
27
|
+
|
|
28
|
+
// "After" events, dispatched on the card when the action has completed.
|
|
22
29
|
const EVENT_COLLAPSED = `collapsed${EVENT_KEY}`
|
|
23
30
|
const EVENT_EXPANDED = `expanded${EVENT_KEY}`
|
|
24
|
-
const
|
|
31
|
+
const EVENT_REMOVED = `removed${EVENT_KEY}`
|
|
25
32
|
const EVENT_MAXIMIZED = `maximized${EVENT_KEY}`
|
|
26
33
|
const EVENT_MINIMIZED = `minimized${EVENT_KEY}`
|
|
27
34
|
|
|
@@ -53,14 +60,24 @@ const Default: Config = {
|
|
|
53
60
|
maximizeTrigger: SELECTOR_DATA_MAXIMIZE
|
|
54
61
|
}
|
|
55
62
|
|
|
56
|
-
class CardWidget {
|
|
57
|
-
|
|
63
|
+
class CardWidget extends BaseComponent {
|
|
64
|
+
static get NAME(): string {
|
|
65
|
+
return NAME
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static getInstance(element: Element | null | undefined): CardWidget | null {
|
|
69
|
+
return this._getInstance(element) as CardWidget | null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static getOrCreateInstance(element: HTMLElement, config: Partial<Config> = {}): CardWidget {
|
|
73
|
+
return this.getInstance(element) ?? new this(element, config)
|
|
74
|
+
}
|
|
75
|
+
|
|
58
76
|
_parent: HTMLElement | undefined
|
|
59
|
-
_clone: HTMLElement | undefined
|
|
60
77
|
_config: Config
|
|
61
78
|
|
|
62
|
-
constructor(element: HTMLElement, config: Config) {
|
|
63
|
-
|
|
79
|
+
constructor(element: HTMLElement, config: Partial<Config> = {}) {
|
|
80
|
+
super(element)
|
|
64
81
|
this._parent = element.closest(SELECTOR_CARD) as HTMLElement | undefined
|
|
65
82
|
|
|
66
83
|
if (element.classList.contains(CLASS_NAME_CARD)) {
|
|
@@ -71,76 +88,87 @@ class CardWidget {
|
|
|
71
88
|
}
|
|
72
89
|
|
|
73
90
|
collapse() {
|
|
74
|
-
|
|
91
|
+
if (!this._parent) {
|
|
92
|
+
return
|
|
93
|
+
}
|
|
75
94
|
|
|
76
|
-
if (this._parent) {
|
|
77
|
-
|
|
78
|
-
|
|
95
|
+
if (dispatchCustomEvent(this._parent, EVENT_COLLAPSE, { cancelable: true }).defaultPrevented) {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
79
98
|
|
|
80
|
-
|
|
81
|
-
|
|
99
|
+
this._parent.classList.add(CLASS_NAME_COLLAPSING)
|
|
100
|
+
this._parent.classList.remove(CLASS_NAME_EXPANDING)
|
|
82
101
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
slideUp(el, this._config.animationSpeed)
|
|
86
|
-
}
|
|
87
|
-
})
|
|
102
|
+
// Only target direct children to avoid affecting nested cards
|
|
103
|
+
const elm = this._parent.querySelectorAll(`:scope > ${SELECTOR_CARD_BODY}, :scope > ${SELECTOR_CARD_FOOTER}`)
|
|
88
104
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
this._parent.classList.remove(CLASS_NAME_COLLAPSING)
|
|
95
|
-
}
|
|
96
|
-
}, this._config.animationSpeed)
|
|
97
|
-
}
|
|
105
|
+
elm.forEach(el => {
|
|
106
|
+
if (el instanceof HTMLElement) {
|
|
107
|
+
slideUp(el, this._config.animationSpeed)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
98
110
|
|
|
99
|
-
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
// Guard against a stale timer: if expand() ran while this collapse
|
|
113
|
+
// was still animating, the card must not end up marked collapsed.
|
|
114
|
+
if (this._parent?.classList.contains(CLASS_NAME_COLLAPSING)) {
|
|
115
|
+
this._parent.classList.add(CLASS_NAME_COLLAPSED)
|
|
116
|
+
this._parent.classList.remove(CLASS_NAME_COLLAPSING)
|
|
117
|
+
dispatchCustomEvent(this._parent, EVENT_COLLAPSED)
|
|
118
|
+
}
|
|
119
|
+
}, this._config.animationSpeed)
|
|
100
120
|
}
|
|
101
121
|
|
|
102
122
|
expand() {
|
|
103
|
-
|
|
123
|
+
if (!this._parent) {
|
|
124
|
+
return
|
|
125
|
+
}
|
|
104
126
|
|
|
105
|
-
if (this._parent) {
|
|
106
|
-
|
|
107
|
-
|
|
127
|
+
if (dispatchCustomEvent(this._parent, EVENT_EXPAND, { cancelable: true }).defaultPrevented) {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
108
130
|
|
|
109
|
-
|
|
110
|
-
|
|
131
|
+
this._parent.classList.add(CLASS_NAME_EXPANDING)
|
|
132
|
+
this._parent.classList.remove(CLASS_NAME_COLLAPSING, CLASS_NAME_COLLAPSED)
|
|
111
133
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
slideDown(el, this._config.animationSpeed)
|
|
115
|
-
}
|
|
116
|
-
})
|
|
134
|
+
// Only target direct children to avoid affecting nested cards
|
|
135
|
+
const elm = this._parent.querySelectorAll(`:scope > ${SELECTOR_CARD_BODY}, :scope > ${SELECTOR_CARD_FOOTER}`)
|
|
117
136
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}, this._config.animationSpeed)
|
|
124
|
-
}
|
|
137
|
+
elm.forEach(el => {
|
|
138
|
+
if (el instanceof HTMLElement) {
|
|
139
|
+
slideDown(el, this._config.animationSpeed)
|
|
140
|
+
}
|
|
141
|
+
})
|
|
125
142
|
|
|
126
|
-
|
|
143
|
+
setTimeout(() => {
|
|
144
|
+
// Same stale-timer guard as collapse(), in the other direction.
|
|
145
|
+
if (this._parent?.classList.contains(CLASS_NAME_EXPANDING)) {
|
|
146
|
+
this._parent.classList.remove(CLASS_NAME_EXPANDING)
|
|
147
|
+
dispatchCustomEvent(this._parent, EVENT_EXPANDED)
|
|
148
|
+
}
|
|
149
|
+
}, this._config.animationSpeed)
|
|
127
150
|
}
|
|
128
151
|
|
|
129
152
|
remove() {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const parent = this._parent
|
|
134
|
-
slideUp(parent, this._config.animationSpeed)
|
|
153
|
+
if (!this._parent) {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
135
156
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
setTimeout(() => {
|
|
139
|
-
parent.remove()
|
|
140
|
-
}, this._config.animationSpeed)
|
|
157
|
+
if (dispatchCustomEvent(this._parent, EVENT_REMOVE, { cancelable: true }).defaultPrevented) {
|
|
158
|
+
return
|
|
141
159
|
}
|
|
142
160
|
|
|
143
|
-
this.
|
|
161
|
+
const parent = this._parent
|
|
162
|
+
slideUp(parent, this._config.animationSpeed)
|
|
163
|
+
|
|
164
|
+
// Actually remove the card once the animation finishes — hiding it
|
|
165
|
+
// would keep its form fields submitting and its ids in the document.
|
|
166
|
+
// `removed` is dispatched just before detachment so it can still bubble.
|
|
167
|
+
setTimeout(() => {
|
|
168
|
+
dispatchCustomEvent(parent, EVENT_REMOVED)
|
|
169
|
+
parent.remove()
|
|
170
|
+
this.dispose()
|
|
171
|
+
}, this._config.animationSpeed)
|
|
144
172
|
}
|
|
145
173
|
|
|
146
174
|
toggle() {
|
|
@@ -155,8 +183,6 @@ class CardWidget {
|
|
|
155
183
|
}
|
|
156
184
|
|
|
157
185
|
maximize() {
|
|
158
|
-
const event = new Event(EVENT_MAXIMIZED)
|
|
159
|
-
|
|
160
186
|
if (this._parent) {
|
|
161
187
|
this._parent.style.height = `${this._parent.offsetHeight}px`
|
|
162
188
|
this._parent.style.width = `${this._parent.offsetWidth}px`
|
|
@@ -175,16 +201,14 @@ class CardWidget {
|
|
|
175
201
|
if (this._parent.classList.contains(CLASS_NAME_COLLAPSED)) {
|
|
176
202
|
this._parent.classList.add(CLASS_NAME_WAS_COLLAPSED)
|
|
177
203
|
}
|
|
204
|
+
|
|
205
|
+
dispatchCustomEvent(this._parent, EVENT_MAXIMIZED)
|
|
178
206
|
}
|
|
179
207
|
}, 150)
|
|
180
208
|
}
|
|
181
|
-
|
|
182
|
-
this._element?.dispatchEvent(event)
|
|
183
209
|
}
|
|
184
210
|
|
|
185
211
|
minimize() {
|
|
186
|
-
const event = new Event(EVENT_MINIMIZED)
|
|
187
|
-
|
|
188
212
|
if (this._parent) {
|
|
189
213
|
this._parent.style.height = 'auto'
|
|
190
214
|
this._parent.style.width = 'auto'
|
|
@@ -204,6 +228,8 @@ class CardWidget {
|
|
|
204
228
|
this._parent.classList.remove(CLASS_NAME_WAS_COLLAPSED)
|
|
205
229
|
}
|
|
206
230
|
|
|
231
|
+
dispatchCustomEvent(this._parent, EVENT_MINIMIZED)
|
|
232
|
+
|
|
207
233
|
// Drop the inline sizing/transition once the restore transition has
|
|
208
234
|
// finished so the card doesn't carry stale styles forever.
|
|
209
235
|
setTimeout(() => {
|
|
@@ -214,8 +240,6 @@ class CardWidget {
|
|
|
214
240
|
}
|
|
215
241
|
}, 10)
|
|
216
242
|
}
|
|
217
|
-
|
|
218
|
-
this._element?.dispatchEvent(event)
|
|
219
243
|
}
|
|
220
244
|
|
|
221
245
|
toggleMaximize() {
|
|
@@ -232,44 +256,44 @@ class CardWidget {
|
|
|
232
256
|
*
|
|
233
257
|
* Data Api implementation
|
|
234
258
|
* ====================================================
|
|
259
|
+
* A single delegated listener on `document` handles all card toggles — so
|
|
260
|
+
* cards inserted later (AJAX, Turbo Frames) work without re-initialisation,
|
|
261
|
+
* and the listener itself survives Turbo's <body> swaps.
|
|
235
262
|
*/
|
|
236
263
|
|
|
237
|
-
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
// Use currentTarget (the [data-lte-toggle] button itself), not target:
|
|
241
|
-
// clicking the <i> icon inside the button would otherwise make the widget's
|
|
242
|
-
// events fire on the icon instead of the button.
|
|
243
|
-
collapseBtn.forEach(btn => {
|
|
244
|
-
btn.addEventListener('click', event => {
|
|
245
|
-
event.preventDefault()
|
|
246
|
-
const target = event.currentTarget as HTMLElement
|
|
247
|
-
const data = new CardWidget(target, Default)
|
|
248
|
-
data.toggle()
|
|
249
|
-
})
|
|
250
|
-
})
|
|
264
|
+
document.addEventListener('click', event => {
|
|
265
|
+
const target = event.target
|
|
251
266
|
|
|
252
|
-
|
|
267
|
+
if (!(target instanceof Element)) {
|
|
268
|
+
return
|
|
269
|
+
}
|
|
253
270
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const data = new CardWidget(target, Default)
|
|
259
|
-
data.remove()
|
|
260
|
-
})
|
|
261
|
-
})
|
|
271
|
+
const collapseTrigger = target.closest(SELECTOR_DATA_COLLAPSE)
|
|
272
|
+
const removeTrigger = target.closest(SELECTOR_DATA_REMOVE)
|
|
273
|
+
const maximizeTrigger = target.closest(SELECTOR_DATA_MAXIMIZE)
|
|
274
|
+
const trigger = collapseTrigger ?? removeTrigger ?? maximizeTrigger
|
|
262
275
|
|
|
263
|
-
|
|
276
|
+
if (!trigger) {
|
|
277
|
+
return
|
|
278
|
+
}
|
|
264
279
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
280
|
+
event.preventDefault()
|
|
281
|
+
|
|
282
|
+
const card = trigger.closest(SELECTOR_CARD) as HTMLElement | null
|
|
283
|
+
|
|
284
|
+
if (!card) {
|
|
285
|
+
return
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const widget = CardWidget.getOrCreateInstance(card)
|
|
289
|
+
|
|
290
|
+
if (collapseTrigger) {
|
|
291
|
+
widget.toggle()
|
|
292
|
+
} else if (removeTrigger) {
|
|
293
|
+
widget.remove()
|
|
294
|
+
} else {
|
|
295
|
+
widget.toggleMaximize()
|
|
296
|
+
}
|
|
273
297
|
})
|
|
274
298
|
|
|
275
299
|
export default CardWidget
|