@livenetworks/ashlar 2.0.4 → 2.0.6
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/components/ln-debug/ln-debug.js +1 -1
- package/components/ln-debug/src/generated-attributes.js +0 -1
- package/components/ln-fill/README.md +14 -11
- package/components/ln-fill/ln-fill.js +1 -1
- package/components/ln-fill/src/ln-fill.js +0 -6
- package/components/ln-modal/README.md +33 -12
- package/components/ln-modal/ln-modal.js +1 -1
- package/components/ln-modal/ln-modal.schema.json +17 -6
- package/components/ln-modal/src/ln-modal.js +57 -2
- package/components/ln-ui-coordinator/README.md +62 -101
- package/components/ln-ui-coordinator/ln-ui-coordinator.js +1 -1
- package/components/ln-ui-coordinator/ln-ui-coordinator.schema.json +1 -33
- package/components/ln-ui-coordinator/src/ln-ui-coordinator.js +140 -403
- package/ln-ashlar.html-data.json +10 -6
- package/package.json +1 -1
- package/web-types.json +8 -11
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { registerComponent, dispatch, dispatchCancelable, isVisible } from '../../ln-core';
|
|
1
|
+
import { registerComponent, dispatch, dispatchCancelable, isVisible, shouldIgnoreClick, isTargetDisabled } from '../../ln-core';
|
|
2
2
|
|
|
3
3
|
(function () {
|
|
4
4
|
const DOM_SELECTOR = 'data-ln-modal';
|
|
5
5
|
const DOM_ATTRIBUTE = 'lnModal';
|
|
6
|
+
const TRIGGER_ATTRIBUTE = 'data-ln-modal-for';
|
|
7
|
+
const CLOSE_TRIGGER_ATTRIBUTE = 'data-ln-modal-close';
|
|
6
8
|
|
|
7
9
|
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
8
10
|
|
|
@@ -15,12 +17,56 @@ import { registerComponent, dispatch, dispatchCancelable, isVisible } from '../.
|
|
|
15
17
|
effect: _syncAttribute,
|
|
16
18
|
description: 'Control state of the modal dialog'
|
|
17
19
|
},
|
|
20
|
+
'data-ln-modal-for': {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'Target modal ID to open on trigger click'
|
|
23
|
+
},
|
|
24
|
+
'data-ln-modal-mode': {
|
|
25
|
+
type: 'enum',
|
|
26
|
+
values: ['new', 'edit'],
|
|
27
|
+
fallback: 'new',
|
|
28
|
+
description: 'Operational mode of the modal (new vs edit)'
|
|
29
|
+
},
|
|
18
30
|
'data-ln-modal-close': {
|
|
19
31
|
type: 'trigger',
|
|
20
32
|
description: 'Click dismiss trigger inside the modal'
|
|
21
33
|
}
|
|
22
34
|
};
|
|
23
35
|
|
|
36
|
+
const instances = new Set();
|
|
37
|
+
let clickListener = null;
|
|
38
|
+
|
|
39
|
+
function _ensureClickListener() {
|
|
40
|
+
if (clickListener) return;
|
|
41
|
+
clickListener = function (e) {
|
|
42
|
+
if (shouldIgnoreClick(e)) return;
|
|
43
|
+
|
|
44
|
+
const trigger = e.target.closest('[' + TRIGGER_ATTRIBUTE + ']');
|
|
45
|
+
if (!trigger || isTargetDisabled(trigger)) return;
|
|
46
|
+
|
|
47
|
+
const targetId = trigger.getAttribute(TRIGGER_ATTRIBUTE);
|
|
48
|
+
if (!targetId) return;
|
|
49
|
+
|
|
50
|
+
const target = document.getElementById(targetId) || document.querySelector('[' + DOM_SELECTOR + '="' + targetId + '"]');
|
|
51
|
+
if (!target || !target[DOM_ATTRIBUTE]) return;
|
|
52
|
+
|
|
53
|
+
e.preventDefault();
|
|
54
|
+
if (trigger.hasAttribute('data-ln-modal-mode')) {
|
|
55
|
+
target.setAttribute('data-ln-modal-mode', trigger.getAttribute('data-ln-modal-mode'));
|
|
56
|
+
} else if (target.hasAttribute('data-ln-modal-mode')) {
|
|
57
|
+
target.setAttribute('data-ln-modal-mode', 'new');
|
|
58
|
+
}
|
|
59
|
+
target.setAttribute(DOM_SELECTOR, 'open');
|
|
60
|
+
};
|
|
61
|
+
document.addEventListener('click', clickListener);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function _maybeRemoveClickListener() {
|
|
65
|
+
if (instances.size > 0 || !clickListener) return;
|
|
66
|
+
document.removeEventListener('click', clickListener);
|
|
67
|
+
clickListener = null;
|
|
68
|
+
}
|
|
69
|
+
|
|
24
70
|
// ─── Component Constructor ─────────────────────────────
|
|
25
71
|
|
|
26
72
|
function _component(dom) {
|
|
@@ -46,7 +92,7 @@ import { registerComponent, dispatch, dispatchCancelable, isVisible } from '../.
|
|
|
46
92
|
|
|
47
93
|
// Dismiss trigger buttons inside modal [data-ln-modal-close]
|
|
48
94
|
this._onClickClose = function (e) {
|
|
49
|
-
const closeBtn = e.target.closest('[
|
|
95
|
+
const closeBtn = e.target.closest('[' + CLOSE_TRIGGER_ATTRIBUTE + ']');
|
|
50
96
|
if (closeBtn && self.dom.contains(closeBtn)) {
|
|
51
97
|
e.preventDefault();
|
|
52
98
|
self.dom.setAttribute(DOM_SELECTOR, 'close');
|
|
@@ -58,6 +104,9 @@ import { registerComponent, dispatch, dispatchCancelable, isVisible } from '../.
|
|
|
58
104
|
this.dom.addEventListener('cancel', this._onCancel);
|
|
59
105
|
this.dom.addEventListener('click', this._onClickClose);
|
|
60
106
|
|
|
107
|
+
instances.add(this);
|
|
108
|
+
_ensureClickListener();
|
|
109
|
+
|
|
61
110
|
// Apply initial state if rendered with open attribute
|
|
62
111
|
if (this.isOpen) {
|
|
63
112
|
if (typeof this.dom.showModal === 'function') this.dom.showModal();
|
|
@@ -89,6 +138,9 @@ import { registerComponent, dispatch, dispatchCancelable, isVisible } from '../.
|
|
|
89
138
|
this.dom.removeEventListener('cancel', this._onCancel);
|
|
90
139
|
this.dom.removeEventListener('click', this._onClickClose);
|
|
91
140
|
|
|
141
|
+
instances.delete(this);
|
|
142
|
+
_maybeRemoveClickListener();
|
|
143
|
+
|
|
92
144
|
if (this.isOpen) {
|
|
93
145
|
const dom = this.dom;
|
|
94
146
|
const otherOpen = Array.prototype.some.call(
|
|
@@ -147,6 +199,9 @@ import { registerComponent, dispatch, dispatchCancelable, isVisible } from '../.
|
|
|
147
199
|
return;
|
|
148
200
|
}
|
|
149
201
|
instance.isOpen = false;
|
|
202
|
+
if (el.hasAttribute('data-ln-modal-mode')) {
|
|
203
|
+
el.setAttribute('data-ln-modal-mode', 'new');
|
|
204
|
+
}
|
|
150
205
|
dispatch(el, 'ln-modal:close', { modalId: el.id, target: el });
|
|
151
206
|
|
|
152
207
|
if (typeof el.close === 'function') el.close();
|
|
@@ -1,101 +1,62 @@
|
|
|
1
|
-
# ln-ui-coordinator
|
|
2
|
-
|
|
3
|
-
> Applied to a container element (`<main data-ln-ui-coordinator>`). It listens for clicks on `
|
|
4
|
-
|
|
5
|
-
A
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 1. Responsibilities
|
|
10
|
-
|
|
11
|
-
1. **
|
|
12
|
-
2. **
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
|
63
|
-
|:---|:---|:---|
|
|
64
|
-
| `data-ln-ui-coordinator` | Container / Dialog | Activates UI orchestration on the element and its subtree, acting as dictionary host. |
|
|
65
|
-
| `data-ln-ui-coordinator-dict` | `<li>` element | Translatable fallback toast messages (see Dictionary Keys below). |
|
|
66
|
-
| `data-ln-modal-for="id"` | Trigger `<button>` | Opens the target `ln-modal` by id. |
|
|
67
|
-
| `data-ln-modal-mode="new\|edit"` | Trigger / `<dialog>` | Forces explicit modal creation or edit mode. |
|
|
68
|
-
| `data-ln-fill-*` | Trigger `<a>` | Passes record values to form controls inside the opened modal. |
|
|
69
|
-
|
|
70
|
-
### Dictionary Keys
|
|
71
|
-
|
|
72
|
-
| Key | Used For | Fallback |
|
|
73
|
-
|:---|:---|:---|
|
|
74
|
-
| `network-error` | Network disconnection error message | `Network error` |
|
|
75
|
-
| `network-error-title` | Network error toast title | `""` |
|
|
76
|
-
| `server-error` | HTTP server error message | `Server error` |
|
|
77
|
-
| `server-error-title` | HTTP server error toast title | `""` |
|
|
78
|
-
| `upload-invalid-title` | Invalid file toast title | `Invalid File` |
|
|
79
|
-
| `upload-invalid-type` | Invalid file extension / MIME message | `This file type is not allowed` |
|
|
80
|
-
| `upload-max-size` | Exceeded max size message | `File is too large` |
|
|
81
|
-
| `upload-max-files` | Exceeded max file count message | `Maximum file count exceeded` |
|
|
82
|
-
| `upload-error-title` | Upload failure toast title | `Upload Error` |
|
|
83
|
-
| `upload-failed` | Upload failure message | `Failed to upload file` |
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## 4. DOM Events
|
|
88
|
-
|
|
89
|
-
| Event | Direction | Target | Description |
|
|
90
|
-
|:---|:---|:---|:---|
|
|
91
|
-
| `ln-modal:request-open` | Emits | `<dialog>` | Requests panel opening on target `ln-modal`. |
|
|
92
|
-
| `ln-modal:request-close` | Emits | `<dialog>` | Requests panel closing on target `ln-modal`. |
|
|
93
|
-
| `ln-fill:request` | Emits | `<dialog>` | Requests form data population for the opened modal. |
|
|
94
|
-
| `ln-toast:enqueue` | Emits | `window` | Dispatched with `{ type, title, message }` on AJAX responses or error fallbacks. |
|
|
95
|
-
| `click` | Listens | `document` | Intercepts modal triggers and hash links. |
|
|
96
|
-
| `submit` | Listens | `document` | Tracks native submissions in modals for clean hash/reload lifecycle. |
|
|
97
|
-
| `hashchange` | Listens | `window` | Synchronizes URL hash and active modals. |
|
|
98
|
-
| `ln-ajax:success` | Listens | `document` | Enqueues success toast, closes modal, and resets forms. |
|
|
99
|
-
| `ln-ajax:error` | Listens | `document` | Enqueues error toast while keeping modals open. |
|
|
100
|
-
| `ln-upload:invalid` | Listens | `document` | Enqueues error toast on file validation failure. |
|
|
101
|
-
| `ln-upload:error` | Listens | `document` | Enqueues error toast on upload failure. |
|
|
1
|
+
# ln-ui-coordinator
|
|
2
|
+
|
|
3
|
+
> Applied to a container element (`<main data-ln-ui-coordinator>`). It listens for clicks on `a[href^="#"]` hash anchors and window `hashchange` events to synchronize `[data-ln-modal]` dialogs with the URL hash, intercepts bubbling `ln-ajax:success`/`ln-ajax:error` and `ln-upload:error` events to dispatch `ln-toast:enqueue` notifications from server response envelopes, and clears the modal URL hash and closes active modals upon successful AJAX submit. Button triggers (`data-ln-modal-for`) are handled autonomously by `ln-modal`.
|
|
4
|
+
|
|
5
|
+
A minimal **Layer 2 Coordinator** that mediates URL hash navigation, modal lifecycle, and server toast notifications.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Responsibilities
|
|
10
|
+
|
|
11
|
+
1. **Hash Navigation & URL Synchronization:** Listens for clicks on `a[href^="#"]` hash anchors and window `hashchange` events, dispatching `ln-modal:request-open` to matching dialogs. Listens to `ln-modal:close` to clean up the URL hash segment.
|
|
12
|
+
2. **AJAX Submit Mediation:** Catches `ln-ajax:success` events:
|
|
13
|
+
- Dispatches `ln-toast:enqueue` notifications when the server returns `{ message: ... }`.
|
|
14
|
+
- Closes the active modal (if submit originated inside a modal) and cleans URL hash (`hashSet(modal.id, null)`).
|
|
15
|
+
3. **Server Error Feedback:** Catches `ln-ajax:error` and `ln-upload:error`:
|
|
16
|
+
- Dispatches error toasts when the server returns an error message.
|
|
17
|
+
- Keeps modals open on error so form validation messages remain visible.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 2. HTML Markup
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<main data-ln-ui-coordinator>
|
|
25
|
+
<!-- Triggers (button opens autonomously; hash anchor deep-links) -->
|
|
26
|
+
<button type="button" data-ln-modal-for="user-modal">New User</button>
|
|
27
|
+
<a href="#user-modal">Open User Modal</a>
|
|
28
|
+
|
|
29
|
+
<!-- Modal Dialog -->
|
|
30
|
+
<dialog class="ln-modal" data-ln-modal id="user-modal">
|
|
31
|
+
<form action="/api/users" method="POST" data-ln-ajax id="user-form">
|
|
32
|
+
<input type="text" name="name" required />
|
|
33
|
+
<button type="submit">Save</button>
|
|
34
|
+
<button type="button" data-ln-modal-close>Cancel</button>
|
|
35
|
+
</form>
|
|
36
|
+
</dialog>
|
|
37
|
+
</main>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 3. Declarative Attributes
|
|
43
|
+
|
|
44
|
+
| Attribute | Element | Description |
|
|
45
|
+
|:---|:---|:---|
|
|
46
|
+
| `data-ln-ui-coordinator` | Container | Activates UI coordination for hash-routing, modal closing on AJAX success, and server toast dispatching. |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 4. DOM Events
|
|
51
|
+
|
|
52
|
+
| Event | Direction | Target | Description |
|
|
53
|
+
|:---|:---|:---|:---|
|
|
54
|
+
| `ln-modal:request-open` | Emits | `<dialog>` | Requests panel opening on target `ln-modal` from URL hash routes. |
|
|
55
|
+
| `ln-modal:request-close` | Emits | `<dialog>` | Requests panel closing on target `ln-modal` upon AJAX success. |
|
|
56
|
+
| `ln-toast:enqueue` | Emits | `window` | Dispatched with server `{ type, title, message }` from response envelopes. |
|
|
57
|
+
| `click` | Listens | `document` | Intercepts `a[href^="#"]` hash navigation links. |
|
|
58
|
+
| `hashchange` | Listens | `window` | Synchronizes URL hash and active modals. |
|
|
59
|
+
| `ln-modal:close` | Listens | `document` | Cleans up modal hash segment when modal closes. |
|
|
60
|
+
| `ln-ajax:success` | Listens | `document` | Relays server message to toast, cleans modal URL hash, and closes parent modal. |
|
|
61
|
+
| `ln-ajax:error` | Listens | `document` | Relays server error message to toast while keeping modal open. |
|
|
62
|
+
| `ln-upload:error` | Listens | `document` | Relays server error message to toast. |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(){"use strict";function j(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function L(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let o=null;for(let r=1;r<t.length;r++)if(t[r]&&t[r].nodeType===1){o=t[r];break}if(!L(o))return}e.apply(console,t)}}function m(e,t,n){const o=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:o}))}function x(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){x(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}const B={};function J(e,t){B[e]=t}function P(e){return B[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=J,window.lnCore.getDataMapper=P);function X(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,x(function(){new MutationObserver(function(){m(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const W={};function Y(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];W[n]=t}function Z(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return W[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=Y,window.lnCore.getLocaleFallback=Z,window.lnCore.ensureLocaleObserver=X);const D={};function ee(e,t){D[e]||(D[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=D[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function N(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let l=0;l<n.length;l++){const u=n[l],d=u.getAttribute("data-ln-field");t[d]!=null&&(u.textContent=t[d])}const o=e.querySelectorAll("[data-ln-attr]");for(let l=0;l<o.length;l++){const u=o[l],d=u.getAttribute("data-ln-attr").split(",");for(let h=0;h<d.length;h++){const g=d[h].trim().split(":");if(g.length!==2)continue;const b=g[0].trim(),C=g[1].trim();t[C]!=null&&u.setAttribute(b,t[C])}}const r=e.querySelectorAll("[data-ln-show]");for(let l=0;l<r.length;l++){const u=r[l],d=u.getAttribute("data-ln-show");d in t&&u.classList.toggle("hidden",!t[d])}const i=e.querySelectorAll("[data-ln-class]");for(let l=0;l<i.length;l++){const u=i[l],d=u.getAttribute("data-ln-class").split(",");for(let h=0;h<d.length;h++){const g=d[h].trim().split(":");if(g.length!==2)continue;const b=g[0].trim(),C=g[1].trim();C in t&&u.classList.toggle(b,!!t[C])}}return e}function te(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const n=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let o=0;o<n.length;o++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[o],t??null),n[o].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)N(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let n=0;n<t.length;n++)t[n].textContent=""}})));function U(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const i=n.currentNode;i.textContent.indexOf("{{")!==-1&&(i.textContent=i.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(l,u){return t[u]!==void 0?t[u]:""}))}const o=function(i,l){return t[l]!==void 0?t[l]:""},r=Array.from(e.querySelectorAll("*"));e.nodeType===1&&r.push(e);for(let i=0;i<r.length;i++){const l=r[i],u=l.attributes;for(let d=0;d<u.length;d++){const h=u[d];h.value.indexOf("{{")!==-1&&l.setAttribute(h.name,h.value.replace(/\{\{\s*(\w+)\s*\}\}/g,o))}}return e}function ne(e,t,n,o,r,i){const l={};for(let d=0;d<e.children.length;d++){const h=e.children[d],g=h.getAttribute("data-ln-render-key");g&&(l[g]=h)}const u=document.createDocumentFragment();for(let d=0;d<t.length;d++){const h=t[d],g=String(o(h));let b=l[g];if(b)r(b,h,d);else{const C=ee(n,i);if(!C||(U(C,h),b=C.firstElementChild,!b))continue;b.setAttribute("data-ln-render-key",g),r(b,h,d)}u.appendChild(b)}e.textContent="",e.appendChild(u)}function oe(e,t){const n={},o=e.querySelectorAll("["+t+"]");for(let r=0;r<o.length;r++)n[o[r].getAttribute(t)]=o[r].textContent,o[r].remove();return n}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=U,window.lnCore.fill=N,window.lnCore.lnFill=te,window.lnCore.renderList=ne);function V(e,t,n,o,r){if(!e||t===null)return!0;const i=o||"ln-component",l=e.type;if(l==="trigger"||l==="marker"||l==="string"||l==="list"||!l||t===""&&e.fallback!==void 0)return!0;const u=d=>{r?console.warn(d,r):console.warn(d)};if(l==="boolean"){const d=t.trim().toLowerCase();return d!==""&&d!=="true"&&d!=="false"&&d!=="1"&&d!=="0"?(u(`[${i}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(l==="enum"){const d=e.values||[];return d.includes(t)?!0:(u(`[${i}] Invalid value "${t}" for attribute "${n}". Allowed: ${d.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(l==="integer"){if(!/^-?\d+$/.test(t))return u(`[${i}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const d=parseInt(t,10);return e.min!==void 0&&d<e.min?(u(`[${i}] Value ${d} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&d>e.max?(u(`[${i}] Value ${d} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(l==="float")return isNaN(Number(t))?(u(`[${i}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(l==="json")try{return JSON.parse(t),!0}catch(d){return u(`[${i}] Invalid JSON for attribute "${n}": ${d.message}. Fallback: ${e.fallback}.`),!1}return!0}function re(e){const t={};for(const n in e){const o=e[n];o&&o.effect&&(t[n]=o.effect)}return Object.keys(t).length?t:null}function ie(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const n in e.effects)t.add(n);if(e.onAttrChange&&e.declared)for(const n of e.declared)t.add(n);return t}function T(e,t,n,o){if(e.nodeType!==1)return;const i=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",l=Array.from(e.querySelectorAll(i));e.matches&&e.matches(i)&&l.push(e);for(const u of l)if(!u[n]){window.lnCore._persistSink&&u.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(u,t);try{u[n]=new o(u)}catch(d){console.error("["+n+"] init failed",u,d)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function le(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function $(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function H(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function se(e){const t=H(),n=e.observed||[];for(let o=0;o<n.length;o++){const r=n[o];t.byAttr.has(r)||t.byAttr.set(r,[]),t.byAttr.get(r).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const o in e.attributes){t.byDeclaredAttr.has(o)||t.byDeclaredAttr.set(o,[]);const r=t.byDeclaredAttr.get(o);r.some(i=>i.componentTag===e.componentTag)||r.push({spec:e.attributes[o],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const o=ie(e);if(o===null)t.reactiveWildcard.push(e);else for(const r of o)t.byReactive.has(r)||t.byReactive.set(r,[]),t.byReactive.get(r).push(e)}e.persist&&t.persist.push(e)}function K(e,t,n,o){for(let r=0;r<e.length;r++){const i=e[r];if(!t[i.attribute])continue;const l=i.effects&&i.effects[n];l?l(t,n,o):i.onAttrChange&&(!i.declared||i.declared.has(n))&&i.onAttrChange(t,n,o)}}function de(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const o=H(),r=o.byAttr.get(n);if(j()&&o.byDeclaredAttr&&o.byDeclaredAttr.has(n)&&L(t)){const i=o.byDeclaredAttr.get(n),l=t.getAttribute(n);for(let u=0;u<i.length;u++)V(i[u].spec,l,n,i[u].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||r)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const i=o.byReactive.get(n);i&&K(i,t,n,e.oldValue),o.reactiveWildcard.length&&K(o.reactiveWildcard,t,n,e.oldValue)}if(r)for(let i=0;i<r.length;i++){const l=r[i];if(l.handler){l.handler(t,n,e.oldValue);continue}l.onAttributeChange&&t[l.attribute]?l.onAttributeChange(t,n):(T(t,l.selector,l.attribute,l.ComponentFn),l.onInit&&l.onInit(t))}}function ae(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,x(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{de(t[n])}catch(o){console.error("[ln-core] mutation handler failed",t[n].target,o)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function Q(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function ce(e){const t=Q();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const o=t[n];if(o.onSubtreeChange){const r=o.query,i=e.target.nodeType===1?e.target.matches(r)?e.target:e.target.closest(r):e.target.parentElement?e.target.parentElement.closest(r):null;i&&o.onSubtreeChange(i,e)}}for(let n=0;n<e.addedNodes.length;n++){const o=e.addedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const i=t[r];T(o,i.selector,i.attribute,i.ComponentFn),i.onInit&&i.onInit(o)}}for(let n=0;n<e.removedNodes.length;n++){const o=e.removedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const i=t[r],l=i.query,u=Array.from(o.querySelectorAll(l));o.matches&&o.matches(l)&&u.push(o);for(let d=0;d<u.length;d++){const h=u[d];if(!document.contains(h)){const g=h[i.attribute];if(g&&typeof g.destroy=="function")try{g.destroy()}catch(b){console.error("["+i.attribute+"] destroy failed",h,b)}delete h[i.attribute]}}}}}}function ue(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,x(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const o=t[n];if(o.type==="childList")try{ce(o)}catch(r){console.error("[ln-core] lifecycle handler failed",o.target,r)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function fe(e,t,n,o,r={}){const i=r.extraAttributes||[],l=r.onAttributeChange||null,u=r.onSubtreeChange||null,d=r.onInit||null,h=r.onAttrChange||null,g=r.effects||null,b=r.attributes||null,C=b?re(b):g,F=b?new Set(Object.keys(b)):null,I=r.persist||null;function v(w){const c=w||document.body;if(T(c,e,t,n),b&&j())for(const p in b){const y=b[p],A=Array.from(c.querySelectorAll("["+p+"]"));c.matches&&c.matches("["+p+"]")&&A.push(c);for(let S=0;S<A.length;S++){const E=A[S];L(E)&&V(y,E.getAttribute(p),p,o,E)}}d&&d(c)}const M=[];if(e.indexOf("[")!==-1){const w=/\[([\w-]+)/g;let c;for(;(c=w.exec(e))!==null;)M.push(c[1])}else M.push(e);se({selector:e,attribute:t,componentTag:o,attributes:b,ComponentFn:n,onInit:d,observed:M.concat(i),onAttributeChange:l,onAttrChange:h,effects:C,declared:F,persist:I}),ae();const s=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";Q().push({selector:e,attribute:t,ComponentFn:n,onInit:d,onSubtreeChange:u,query:s}),ue(),window[t]=v;function a(){le()>0?$(function(){v(document.body)}):v(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",a):a(),v}function z(e){return(e||"").replace(/^#/,"")}function O(e){const t=e===void 0?location.hash:e,n={},o=z(t);if(!o)return n;const r=o.split("&");for(let i=0;i<r.length;i++){const l=r[i];if(!l)continue;const u=l.indexOf(":"),d=u>-1?l.slice(0,u):l,h=u>-1?l.slice(u+1):"";if(d)try{n[d]=decodeURIComponent(h)}catch{n[d]=h}}return n}function k(e){if(!e)return null;const t=O();return e in t?t[e]:null}function _(e,t){if(!e)return;const n=O();t==null?delete n[e]:n[e]=String(t);const r=Object.keys(n).map(function(i){const l=n[i];return l===""?i:i+":"+encodeURIComponent(l)}).join("&");z(location.hash)!==r&&(location.hash=r)}function G(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function we(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const n=e.getAttribute("data-ln-hash");if(n&&n.trim()!=="")return n.trim();const o=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return o?t?o+"-"+t:o:t||null}function he(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function be(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function ge(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function pe(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),o=e.slice(t+1),r=o?o.split(",").map(function(i){try{return decodeURIComponent(i)}catch{return i}}).filter(Boolean):[];return{key:n,values:r}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=O,window.lnCore.hashGet=k,window.lnCore.hashSet=_,window.lnCore.hashLinkClick=G,window.lnCore.resolveHashNamespace=we,window.lnCore.hashSortEncode=he,window.lnCore.hashSortDecode=be,window.lnCore.hashFilterEncode=ge,window.lnCore.hashFilterDecode=pe),(function(){const e="data-ln-ui-coordinator",t="lnUiCoordinator",n="data-ln-ui-coordinator-dict";if(window[t]!==void 0)return;const o={"data-ln-ui-coordinator":{type:"marker",description:"Mounts UI coordinator mediating global hash-routing, modals, and toasts"},"data-ln-ui-coordinator-dict":{type:"string",description:"Dictionary key prefix mapping for translatable UI coordinator messages"}};function r(f){const s={};let a=f;const w=[];for(;a;){const c=a.closest("["+e+"]");if(!c)break;c[t]&&c[t].dict&&w.unshift(c[t].dict),a=c.parentElement}for(const c of w)Object.assign(s,c);return s}function i(f,s){if(s){if(f){const w=f.closest("["+e+"]");if(w){if(w.id===s&&w.hasAttribute("data-ln-modal"))return w;const c=w.querySelector("#"+CSS.escape(s)+'[data-ln-modal], [data-ln-modal="'+s+'"]');if(c)return c}}const a=document.getElementById(s)||document.querySelector('[data-ln-modal="'+s+'"]');if(a)return a}if(f){const a=f.closest("["+e+"]");if(a){if(a.hasAttribute("data-ln-modal"))return a;const c=a.querySelector("[data-ln-modal]");if(c)return c}const w=f.closest("[data-ln-modal]");if(w)return w}return document.querySelector("[data-ln-modal]")}function l(f,s){if(f!=="edit")return"";if(s){const a=s.getAttribute("data-ln-fill-id");if(a)return a}return"edit"}function u(f){if(!f)return;const s=f.querySelectorAll("[data-ln-field]");for(let w=0;w<s.length;w++)s[w].textContent="";const a=f.querySelectorAll("form");for(let w=0;w<a.length;w++)window.lnCore&&typeof window.lnCore.lnFill=="function"?window.lnCore.lnFill(a[w],null):a[w].reset()}document.addEventListener("click",function(f){if(f.ctrlKey||f.metaKey||f.button===1)return;const s=f.target.closest("[data-ln-modal-for]");if(s){const w=s.getAttribute("data-ln-modal-for"),c=i(s,w);if(c&&c.lnModal){f.preventDefault();const p={lnModalFor:!0,lnModalClose:!0,lnModalMode:!0},y={},A=s.dataset;for(const q in A){if(!q.startsWith("lnModal")||p[q])continue;const R=q.slice(7);R&&(y[R.charAt(0).toLowerCase()+R.slice(1)]=A[q])}const S=Object.keys(y).length>0;s.hasAttribute("data-ln-modal-mode")?c.dataset.lnModalMode=s.getAttribute("data-ln-modal-mode"):c.dataset.lnModalMode=S?"edit":"new",S&&window.lnCore&&typeof window.lnCore.lnFill=="function"?window.lnCore.lnFill(c,y):c.dataset.lnModalMode==="new"&&u(c),c.getAttribute("data-ln-modal")==="open"?m(c,"ln-modal:request-close",{}):(c.id&&_(c.id,l(c.dataset.lnModalMode,s)),m(c,"ln-modal:request-open",{}))}return}const a=f.target.closest('a[href^="#"]');if(a){const w=O(a.getAttribute("href"));for(const c in w){const p=document.getElementById(c);if(p&&p.lnModal){if(!G(f))return;_(c,w[c]);return}}}}),document.addEventListener("ln-modal:before-open",function(f){const s=f.target;if(!s||!s.lnModal)return;(s.dataset.lnModalMode||"new")==="new"&&u(s)}),document.addEventListener("ln-modal:open",function(f){const s=f.target;if(!s||!s.lnModal||!s.id)return;let a=k(s.id);a===null&&(a=l(s.dataset.lnModalMode,null),_(s.id,a)),a?(s.dataset.lnModalMode="edit",m(s,"ln-fill:request",{id:a})):(s.dataset.lnModalMode="new",u(s))});let d=!1;function h(){if(!d){d=!0;try{const f=document.querySelectorAll("[data-ln-modal][id]");for(let s=0;s<f.length;s++){const a=f[s];if(!a.lnModal)continue;const w=a.id,c=k(w),p=c!==null,y=a.lnModal.isOpen;if(p){const A=c?"edit":"new";a.dataset.lnModalMode=A,y?c?m(a,"ln-fill:request",{id:c}):u(a):m(a,"ln-modal:request-open",{})}else y&&m(a,"ln-modal:request-close",{})}}finally{d=!1}}}function g(){const f=document.querySelectorAll('[data-ln-modal="open"][id]');for(let s=0;s<f.length;s++){const a=f[s];a.lnModal&&k(a.id)===null&&_(a.id,l(a.dataset.lnModalMode,null))}}window.addEventListener("hashchange",h);function b(){g(),h()}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){$(b)}):$(b);function C(f){const a=(f.detail||{}).data;if(a&&a.message){const c=a.message;m(window,"ln-toast:enqueue",{type:c.type||"success",title:c.title||"",message:c.body||""})}const w=f.target.closest("[data-ln-modal]");w&&w.lnModal&&(w.id&&_(w.id,null),m(w,"ln-modal:request-close",{}),u(w))}function F(f){const s=f.detail||{},a=s.data,w=s.status||0,c=r(f.target);if(a&&a.message){const p=a.message;m(window,"ln-toast:enqueue",{type:p.type||"error",title:p.title||"",message:p.body||""})}else w===0?m(window,"ln-toast:enqueue",{type:"error",title:c["network-error-title"]||"",message:c["network-error"]||"Network error"}):m(window,"ln-toast:enqueue",{type:"error",title:c["server-error-title"]||"",message:c["server-error"]||"Server error"})}document.addEventListener("ln-ajax:success",C),document.addEventListener("ln-ajax:error",F);function I(f){const s=f.detail||{},a=r(f.target),w=s.message||(s.reason==="max-size"?a["upload-max-size"]||"File is too large":s.reason==="max-files"?a["upload-max-files"]||"Maximum file count exceeded":a["upload-invalid-type"]||"This file type is not allowed"),c=a["upload-invalid-title"]||"Invalid File";m(window,"ln-toast:enqueue",{type:"error",title:c,message:w})}function v(f){const s=f.detail||{},a=r(f.target),w=s.message||a["upload-failed"]||"Failed to upload file",c=a["upload-error-title"]||"Upload Error";m(window,"ln-toast:enqueue",{type:"error",title:c,message:w})}document.addEventListener("ln-upload:invalid",I),document.addEventListener("ln-upload:error",v),document.addEventListener("ln-modal:close",function(f){const s=f.target;!s||!s.lnModal||(s.id&&k(s.id)!==null&&_(s.id,null),s.dataset.lnModalMode==="new"&&u(s))});function M(f){return this.dom=f,this.dict=oe(f,n),this}M.prototype.destroy=function(){this.dom[t]&&(this.dict={},delete this.dom[t])},fe(e,t,M,"ln-ui-coordinator",{attributes:o})})()})();
|
|
1
|
+
(function(){"use strict";function L(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function y(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let r=null;for(let s=1;s<t.length;s++)if(t[s]&&t[s].nodeType===1){r=t[s];break}if(!y(r))return}e.apply(console,t)}}function h(e,t,n){const r=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,r),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:r}))}function p(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){p(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}const $={};function N(e,t){$[e]=t}function H(e){return $[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=N,window.lnCore.getDataMapper=H);function V(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,p(function(){new MutationObserver(function(){h(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const D={};function U(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];D[n]=t}function K(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return D[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=U,window.lnCore.getLocaleFallback=K,window.lnCore.ensureLocaleObserver=V);const A={};function Q(e,t){A[e]||(A[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=A[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function q(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let i=0;i<n.length;i++){const d=n[i],l=d.getAttribute("data-ln-field");t[l]!=null&&(d.textContent=t[l])}const r=e.querySelectorAll("[data-ln-attr]");for(let i=0;i<r.length;i++){const d=r[i],l=d.getAttribute("data-ln-attr").split(",");for(let c=0;c<l.length;c++){const a=l[c].trim().split(":");if(a.length!==2)continue;const u=a[0].trim(),f=a[1].trim();t[f]!=null&&d.setAttribute(u,t[f])}}const s=e.querySelectorAll("[data-ln-show]");for(let i=0;i<s.length;i++){const d=s[i],l=d.getAttribute("data-ln-show");l in t&&d.classList.toggle("hidden",!t[l])}const o=e.querySelectorAll("[data-ln-class]");for(let i=0;i<o.length;i++){const d=o[i],l=d.getAttribute("data-ln-class").split(",");for(let c=0;c<l.length;c++){const a=l[c].trim().split(":");if(a.length!==2)continue;const u=a[0].trim(),f=a[1].trim();f in t&&d.classList.toggle(u,!!t[f])}}return e}function G(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const n=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let r=0;r<n.length;r++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[r],t??null),n[r].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)q(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let n=0;n<t.length;n++)t[n].textContent=""}})));function I(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const o=n.currentNode;o.textContent.indexOf("{{")!==-1&&(o.textContent=o.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(i,d){return t[d]!==void 0?t[d]:""}))}const r=function(o,i){return t[i]!==void 0?t[i]:""},s=Array.from(e.querySelectorAll("*"));e.nodeType===1&&s.push(e);for(let o=0;o<s.length;o++){const i=s[o],d=i.attributes;for(let l=0;l<d.length;l++){const c=d[l];c.value.indexOf("{{")!==-1&&i.setAttribute(c.name,c.value.replace(/\{\{\s*(\w+)\s*\}\}/g,r))}}return e}function J(e,t,n,r,s,o){const i={};for(let l=0;l<e.children.length;l++){const c=e.children[l],a=c.getAttribute("data-ln-render-key");a&&(i[a]=c)}const d=document.createDocumentFragment();for(let l=0;l<t.length;l++){const c=t[l],a=String(r(c));let u=i[a];if(u)s(u,c,l);else{const f=Q(n,o);if(!f||(I(f,c),u=f.firstElementChild,!u))continue;u.setAttribute("data-ln-render-key",a),s(u,c,l)}d.appendChild(u)}e.textContent="",e.appendChild(d)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=I,window.lnCore.fill=q,window.lnCore.lnFill=G,window.lnCore.renderList=J);function M(e,t,n,r,s){if(!e||t===null)return!0;const o=r||"ln-component",i=e.type;if(i==="trigger"||i==="marker"||i==="string"||i==="list"||!i||t===""&&e.fallback!==void 0)return!0;const d=l=>{s?console.warn(l,s):console.warn(l)};if(i==="boolean"){const l=t.trim().toLowerCase();return l!==""&&l!=="true"&&l!=="false"&&l!=="1"&&l!=="0"?(d(`[${o}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(i==="enum"){const l=e.values||[];return l.includes(t)?!0:(d(`[${o}] Invalid value "${t}" for attribute "${n}". Allowed: ${l.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(i==="integer"){if(!/^-?\d+$/.test(t))return d(`[${o}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const l=parseInt(t,10);return e.min!==void 0&&l<e.min?(d(`[${o}] Value ${l} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&l>e.max?(d(`[${o}] Value ${l} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(i==="float")return isNaN(Number(t))?(d(`[${o}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(i==="json")try{return JSON.parse(t),!0}catch(l){return d(`[${o}] Invalid JSON for attribute "${n}": ${l.message}. Fallback: ${e.fallback}.`),!1}return!0}function P(e){const t={};for(const n in e){const r=e[n];r&&r.effect&&(t[n]=r.effect)}return Object.keys(t).length?t:null}function X(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const n in e.effects)t.add(n);if(e.onAttrChange&&e.declared)for(const n of e.declared)t.add(n);return t}function _(e,t,n,r){if(e.nodeType!==1)return;const o=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",i=Array.from(e.querySelectorAll(o));e.matches&&e.matches(o)&&i.push(e);for(const d of i)if(!d[n]){window.lnCore._persistSink&&d.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(d,t);try{d[n]=new r(d)}catch(l){console.error("["+n+"] init failed",d,l)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function z(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function Y(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function T(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function Z(e){const t=T(),n=e.observed||[];for(let r=0;r<n.length;r++){const s=n[r];t.byAttr.has(s)||t.byAttr.set(s,[]),t.byAttr.get(s).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const r in e.attributes){t.byDeclaredAttr.has(r)||t.byDeclaredAttr.set(r,[]);const s=t.byDeclaredAttr.get(r);s.some(o=>o.componentTag===e.componentTag)||s.push({spec:e.attributes[r],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const r=X(e);if(r===null)t.reactiveWildcard.push(e);else for(const s of r)t.byReactive.has(s)||t.byReactive.set(s,[]),t.byReactive.get(s).push(e)}e.persist&&t.persist.push(e)}function R(e,t,n,r){for(let s=0;s<e.length;s++){const o=e[s];if(!t[o.attribute])continue;const i=o.effects&&o.effects[n];i?i(t,n,r):o.onAttrChange&&(!o.declared||o.declared.has(n))&&o.onAttrChange(t,n,r)}}function ee(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const r=T(),s=r.byAttr.get(n);if(L()&&r.byDeclaredAttr&&r.byDeclaredAttr.has(n)&&y(t)){const o=r.byDeclaredAttr.get(n),i=t.getAttribute(n);for(let d=0;d<o.length;d++)M(o[d].spec,i,n,o[d].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||s)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const o=r.byReactive.get(n);o&&R(o,t,n,e.oldValue),r.reactiveWildcard.length&&R(r.reactiveWildcard,t,n,e.oldValue)}if(s)for(let o=0;o<s.length;o++){const i=s[o];if(i.handler){i.handler(t,n,e.oldValue);continue}i.onAttributeChange&&t[i.attribute]?i.onAttributeChange(t,n):(_(t,i.selector,i.attribute,i.ComponentFn),i.onInit&&i.onInit(t))}}function te(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,p(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{ee(t[n])}catch(r){console.error("[ln-core] mutation handler failed",t[n].target,r)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function B(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function ne(e){const t=B();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const r=t[n];if(r.onSubtreeChange){const s=r.query,o=e.target.nodeType===1?e.target.matches(s)?e.target:e.target.closest(s):e.target.parentElement?e.target.parentElement.closest(s):null;o&&r.onSubtreeChange(o,e)}}for(let n=0;n<e.addedNodes.length;n++){const r=e.addedNodes[n];if(r.nodeType===1)for(let s=0;s<t.length;s++){const o=t[s];_(r,o.selector,o.attribute,o.ComponentFn),o.onInit&&o.onInit(r)}}for(let n=0;n<e.removedNodes.length;n++){const r=e.removedNodes[n];if(r.nodeType===1)for(let s=0;s<t.length;s++){const o=t[s],i=o.query,d=Array.from(r.querySelectorAll(i));r.matches&&r.matches(i)&&d.push(r);for(let l=0;l<d.length;l++){const c=d[l];if(!document.contains(c)){const a=c[o.attribute];if(a&&typeof a.destroy=="function")try{a.destroy()}catch(u){console.error("["+o.attribute+"] destroy failed",c,u)}delete c[o.attribute]}}}}}}function oe(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,p(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const r=t[n];if(r.type==="childList")try{ne(r)}catch(s){console.error("[ln-core] lifecycle handler failed",r.target,s)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function re(e,t,n,r,s={}){const o=s.extraAttributes||[],i=s.onAttributeChange||null,d=s.onSubtreeChange||null,l=s.onInit||null,c=s.onAttrChange||null,a=s.effects||null,u=s.attributes||null,f=u?P(u):a,ae=u?new Set(Object.keys(u)):null,ue=s.persist||null;function m(k){const w=k||document.body;if(_(w,e,t,n),u&&L())for(const g in u){const we=u[g],O=Array.from(w.querySelectorAll("["+g+"]"));w.matches&&w.matches("["+g+"]")&&O.push(w);for(let E=0;E<O.length;E++){const x=O[E];y(x)&&M(we,x.getAttribute(g),g,r,x)}}l&&l(w)}const S=[];if(e.indexOf("[")!==-1){const k=/\[([\w-]+)/g;let w;for(;(w=k.exec(e))!==null;)S.push(w[1])}else S.push(e);Z({selector:e,attribute:t,componentTag:r,attributes:u,ComponentFn:n,onInit:l,observed:S.concat(o),onAttributeChange:i,onAttrChange:c,effects:f,declared:ae,persist:ue}),te();const fe=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";B().push({selector:e,attribute:t,ComponentFn:n,onInit:l,onSubtreeChange:d,query:fe}),oe(),window[t]=m;function W(){z()>0?Y(function(){m(document.body)}):m(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",W):W(),m}function F(e){return(e||"").replace(/^#/,"")}function b(e){const t=e===void 0?location.hash:e,n={},r=F(t);if(!r)return n;const s=r.split("&");for(let o=0;o<s.length;o++){const i=s[o];if(!i)continue;const d=i.indexOf(":"),l=d>-1?i.slice(0,d):i,c=d>-1?i.slice(d+1):"";if(l)try{n[l]=decodeURIComponent(c)}catch{n[l]=c}}return n}function v(e){if(!e)return null;const t=b();return e in t?t[e]:null}function C(e,t){if(!e)return;const n=b();t==null?delete n[e]:n[e]=String(t);const s=Object.keys(n).map(function(o){const i=n[o];return i===""?o:o+":"+encodeURIComponent(i)}).join("&");F(location.hash)!==s&&(location.hash=s)}function j(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function ie(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const n=e.getAttribute("data-ln-hash");if(n&&n.trim()!=="")return n.trim();const r=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return r?t?r+"-"+t:r:t||null}function le(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function se(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function de(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function ce(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),r=e.slice(t+1),s=r?r.split(",").map(function(o){try{return decodeURIComponent(o)}catch{return o}}).filter(Boolean):[];return{key:n,values:s}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=b,window.lnCore.hashGet=v,window.lnCore.hashSet=C,window.lnCore.hashLinkClick=j,window.lnCore.resolveHashNamespace=ie,window.lnCore.hashSortEncode=le,window.lnCore.hashSortDecode=se,window.lnCore.hashFilterEncode=de,window.lnCore.hashFilterDecode=ce),(function(){const e="data-ln-ui-coordinator",t="lnUiCoordinator";if(window[t]!==void 0)return;const n={"data-ln-ui-coordinator":{type:"marker",description:"Mounts UI coordinator mediating global hash-routing, modals, and toasts"}};document.addEventListener("click",function(o){if(o.ctrlKey||o.metaKey||o.button===1)return;const i=o.target.closest('a[href^="#"]');if(!i)return;const d=i.getAttribute("href"),l=b(d);for(const c in l){const a=document.getElementById(c);if(a&&a.lnModal){if(!j(o))return;C(c,l[c]),a.lnModal.isOpen||h(a,"ln-modal:request-open",{});return}}});function r(){const o=location.hash;if(!o)return;const i=b(o);for(const d in i){const l=document.getElementById(d);l&&l.lnModal&&!l.lnModal.isOpen&&h(l,"ln-modal:request-open",{})}}window.addEventListener("hashchange",r),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",r):r(),document.addEventListener("ln-modal:close",function(o){const i=o.target;i&&i.id&&v(i.id)!==null&&C(i.id,null)}),document.addEventListener("ln-ajax:success",function(o){const d=(o.detail||{}).data;if(d&&d.message){const c=d.message;h(window,"ln-toast:enqueue",{type:c.type||"success",title:c.title||"",message:typeof c=="string"?c:c.body||""})}const l=o.target.closest("[data-ln-modal]");l&&l.lnModal&&(l.id&&v(l.id)!==null&&C(l.id,null),h(l,"ln-modal:request-close",{}))}),document.addEventListener("ln-ajax:error",function(o){const d=(o.detail||{}).data;if(d&&d.message){const l=d.message;h(window,"ln-toast:enqueue",{type:l.type||"error",title:l.title||"",message:typeof l=="string"?l:l.body||""})}}),document.addEventListener("ln-upload:error",function(o){const i=o.detail||{};i.message&&h(window,"ln-toast:enqueue",{type:"error",title:"",message:i.message})});function s(o){return this.dom=o,this}s.prototype.destroy=function(){delete this.dom[t]},re(e,t,s,"ln-ui-coordinator",{attributes:n})})()})();
|
|
@@ -9,52 +9,20 @@
|
|
|
9
9
|
"ln-ui-coordinator-dev.scss"
|
|
10
10
|
]
|
|
11
11
|
},
|
|
12
|
-
"data-ln-field": {
|
|
13
|
-
"direction": "author",
|
|
14
|
-
"sources": [
|
|
15
|
-
"src/ln-ui-coordinator.js"
|
|
16
|
-
]
|
|
17
|
-
},
|
|
18
|
-
"data-ln-fill-id": {
|
|
19
|
-
"direction": "author",
|
|
20
|
-
"sources": [
|
|
21
|
-
"src/ln-ui-coordinator.js"
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
12
|
"data-ln-modal": {
|
|
25
13
|
"direction": "author",
|
|
26
14
|
"sources": [
|
|
27
15
|
"src/ln-ui-coordinator.js"
|
|
28
16
|
]
|
|
29
17
|
},
|
|
30
|
-
"data-ln-modal-for": {
|
|
31
|
-
"direction": "author",
|
|
32
|
-
"sources": [
|
|
33
|
-
"src/ln-ui-coordinator.js"
|
|
34
|
-
]
|
|
35
|
-
},
|
|
36
|
-
"data-ln-modal-mode": {
|
|
37
|
-
"direction": "both",
|
|
38
|
-
"sources": [
|
|
39
|
-
"src/ln-ui-coordinator.js"
|
|
40
|
-
]
|
|
41
|
-
},
|
|
42
18
|
"data-ln-ui-coordinator": {
|
|
43
|
-
"direction":
|
|
19
|
+
"direction": null,
|
|
44
20
|
"sources": [
|
|
45
21
|
"ln-ui-coordinator-dev.scss",
|
|
46
22
|
"src/ln-ui-coordinator.js"
|
|
47
23
|
],
|
|
48
24
|
"type": "marker",
|
|
49
25
|
"description": "Mounts UI coordinator mediating global hash-routing, modals, and toasts"
|
|
50
|
-
},
|
|
51
|
-
"data-ln-ui-coordinator-dict": {
|
|
52
|
-
"direction": null,
|
|
53
|
-
"sources": [
|
|
54
|
-
"src/ln-ui-coordinator.js"
|
|
55
|
-
],
|
|
56
|
-
"type": "string",
|
|
57
|
-
"description": "Dictionary key prefix mapping for translatable UI coordinator messages"
|
|
58
26
|
}
|
|
59
27
|
}
|
|
60
28
|
}
|