@livenetworks/ashlar 1.5.1 → 1.6.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/README.md +189 -177
- package/js/COMPONENTS.md +55 -49
- package/js/index.js +22 -5
- package/js/ln-accordion/README.md +186 -137
- package/js/ln-accordion/ln-accordion.js +1 -1
- package/js/ln-ajax/README.md +73 -4
- package/js/ln-ajax/ln-ajax.js +1 -1
- package/js/ln-ajax/src/ln-ajax.js +13 -13
- package/js/ln-api-connector/README.md +261 -150
- package/js/ln-api-connector/ln-api-connector.js +1 -1
- package/js/ln-api-connector/src/ln-api-connector.js +368 -265
- package/js/ln-api-queue/README.md +219 -0
- package/js/ln-api-queue/ln-api-queue.js +1 -0
- package/js/ln-api-queue/src/ln-api-queue.js +320 -0
- package/js/ln-api-queue/src/queue-storage.js +455 -0
- package/js/ln-autoresize/README.md +47 -0
- package/js/ln-autoresize/ln-autoresize.js +1 -1
- package/js/ln-autosave/README.md +33 -1
- package/js/ln-autosave/ln-autosave.js +1 -1
- package/js/ln-autosave/src/ln-autosave.js +4 -4
- package/js/ln-circular-progress/README.md +27 -13
- package/js/ln-circular-progress/ln-circular-progress.js +1 -1
- package/js/ln-circular-progress/src/ln-circular-progress.js +18 -5
- package/js/ln-confirm/README.md +162 -86
- package/js/ln-confirm/_ln-confirm.scss +11 -0
- package/js/ln-confirm/ln-confirm.js +1 -1
- package/js/ln-confirm/src/ln-confirm.js +77 -41
- package/js/ln-core/README.md +896 -0
- package/js/ln-core/hash.js +92 -0
- package/js/ln-core/helpers.js +337 -8
- package/js/ln-core/index.js +4 -2
- package/js/ln-core/persist.js +29 -3
- package/js/ln-core/positioning.js +1 -35
- package/js/ln-core/window-cache.js +213 -0
- package/js/ln-couchdb-connector/README.md +177 -156
- package/js/ln-couchdb-connector/ln-couchdb-connector.js +1 -1
- package/js/ln-couchdb-connector/src/ln-couchdb-connector.js +398 -348
- package/js/ln-data-coordinator/README.md +536 -165
- package/js/ln-data-coordinator/ln-data-coordinator.js +1 -1
- package/js/ln-data-coordinator/src/data-read-policy.js +18 -0
- package/js/ln-data-coordinator/src/ln-data-coordinator.js +1042 -249
- package/js/ln-data-coordinator/src/mutation-receipts.js +46 -0
- package/js/ln-data-store/README.md +241 -94
- package/js/ln-data-store/ln-data-store.js +1 -1
- package/js/ln-data-store/src/ln-data-store.js +694 -699
- package/js/ln-date/README.md +39 -1
- package/js/ln-date/ln-date-dev.scss +14 -0
- package/js/ln-date/ln-date.js +1 -1
- package/js/ln-date/src/ln-date.js +236 -178
- package/js/ln-debug/README.md +58 -0
- package/js/ln-debug/ln-debug.js +1 -0
- package/js/ln-debug/src/ln-debug.js +19 -0
- package/js/ln-dropdown/README.md +31 -8
- package/js/ln-dropdown/ln-dropdown.js +1 -1
- package/js/ln-dropdown/src/ln-dropdown.js +30 -13
- package/js/ln-editor/README.md +274 -0
- package/js/ln-editor/ln-editor.js +1 -0
- package/js/ln-editor/ln-editor.scss +43 -0
- package/js/ln-editor/src/ln-editor.js +619 -0
- package/js/ln-external-links/README.md +44 -5
- package/js/ln-external-links/ln-external-links.js +1 -1
- package/js/ln-fill/README.md +199 -0
- package/js/ln-fill/ln-fill.js +1 -0
- package/js/ln-fill/src/ln-fill.js +87 -0
- package/js/ln-filter/README.md +92 -2
- package/js/ln-filter/ln-filter-dev.scss +8 -0
- package/js/ln-filter/ln-filter.js +1 -1
- package/js/ln-filter/src/ln-filter.js +22 -7
- package/js/ln-form/README.md +212 -49
- package/js/ln-form/ln-form.js +1 -1
- package/js/ln-form/src/ln-form.js +99 -199
- package/js/ln-http/README.md +125 -89
- package/js/ln-http/ln-http.js +1 -1
- package/js/ln-http/src/ln-http.js +32 -13
- package/js/ln-icon/README.md +130 -0
- package/js/ln-icon/ln-icon.js +1 -0
- package/js/{ln-icons/src/ln-icons.js → ln-icon/src/ln-icon.js} +20 -15
- package/js/ln-link/README.md +47 -9
- package/js/ln-link/ln-link.js +1 -1
- package/js/ln-link/src/ln-link.js +22 -6
- package/js/ln-list/README.md +129 -0
- package/js/ln-list/ln-list.js +1 -0
- package/js/ln-list/ln-list.scss +28 -0
- package/js/ln-list/src/ln-list.js +1216 -0
- package/js/ln-modal/README.md +185 -154
- package/js/ln-modal/ln-modal-dev.scss +13 -0
- package/js/ln-modal/ln-modal.js +1 -1
- package/js/ln-modal/ln-modal.scss +28 -4
- package/js/ln-modal/src/ln-modal.js +137 -201
- package/js/ln-modal-coordinator/README.md +99 -0
- package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +8 -0
- package/js/ln-modal-coordinator/ln-modal-coordinator.js +1 -0
- package/js/ln-modal-coordinator/src/ln-modal-coordinator.js +345 -0
- package/js/ln-nav/README.md +46 -3
- package/js/ln-nav/ln-nav.js +1 -1
- package/js/ln-nav/src/ln-nav.js +92 -127
- package/js/ln-number/README.md +28 -1
- package/js/ln-number/ln-number-dev.scss +13 -0
- package/js/ln-number/ln-number.js +1 -1
- package/js/ln-number/src/ln-number.js +443 -350
- package/js/ln-options/README.md +66 -0
- package/js/ln-options/ln-options.js +1 -0
- package/js/ln-options/src/ln-options.js +74 -0
- package/js/ln-popover/README.md +40 -5
- package/js/ln-popover/ln-popover.js +1 -1
- package/js/ln-popover/src/ln-popover.js +38 -11
- package/js/ln-progress/README.md +413 -442
- package/js/ln-progress/ln-progress.js +1 -1
- package/js/ln-progress/src/ln-progress.js +98 -150
- package/js/ln-router/README.md +432 -0
- package/js/ln-router/ln-router.js +1 -0
- package/js/ln-router/src/ln-router.js +539 -0
- package/js/ln-search/README.md +158 -83
- package/js/ln-search/ln-search-dev.scss +8 -0
- package/js/ln-search/ln-search.js +1 -1
- package/js/ln-search/src/ln-search.js +12 -9
- package/js/ln-slug/README.md +110 -0
- package/js/ln-slug/ln-slug.js +1 -0
- package/js/ln-slug/src/ln-slug.js +74 -0
- package/js/ln-sort/README.md +170 -0
- package/js/ln-sort/ln-sort-dev.scss +8 -0
- package/js/ln-sort/ln-sort.js +1 -0
- package/js/ln-sort/src/ln-sort.js +178 -0
- package/js/ln-sortable/README.md +133 -95
- package/js/ln-sortable/ln-sortable.js +1 -1
- package/js/ln-stat/README.md +55 -0
- package/js/ln-stat/ln-stat.js +1 -0
- package/js/ln-stat/src/ln-stat.js +55 -0
- package/js/ln-table/README.md +285 -101
- package/js/ln-table/ln-table-dev.scss +17 -0
- package/js/ln-table/ln-table.js +1 -1
- package/js/ln-table/ln-table.scss +1 -1
- package/js/ln-table/src/ln-table.js +1493 -473
- package/js/ln-table-coordinator/README.md +73 -0
- package/js/ln-table-coordinator/ln-table-coordinator.js +1 -0
- package/js/ln-table-coordinator/src/ln-table-coordinator.js +160 -0
- package/js/ln-tabs/README.md +221 -137
- package/js/ln-tabs/ln-tabs-dev.scss +18 -0
- package/js/ln-tabs/ln-tabs.js +1 -1
- package/js/ln-tabs/src/ln-tabs.js +41 -24
- package/js/ln-time/README.md +14 -0
- package/js/ln-time/ln-time.js +1 -1
- package/js/ln-time/src/ln-time.js +223 -192
- package/js/ln-toast/README.md +178 -122
- package/js/ln-toast/ln-toast.js +1 -15
- package/js/ln-toast/src/ln-toast.js +232 -210
- package/js/ln-toast/template.html +16 -12
- package/js/ln-toggle/README.md +61 -2
- package/js/ln-toggle/ln-toggle-dev.scss +13 -0
- package/js/ln-toggle/ln-toggle.js +1 -1
- package/js/ln-toggle/src/ln-toggle.js +56 -43
- package/js/ln-tooltip/README.md +95 -58
- package/js/ln-tooltip/ln-tooltip-dev.scss +9 -0
- package/js/ln-tooltip/ln-tooltip.js +1 -1
- package/js/ln-tooltip/src/ln-tooltip.js +45 -6
- package/js/ln-translations/README.md +118 -96
- package/js/ln-translations/ln-translations.js +1 -1
- package/js/ln-translations/src/ln-translations.js +10 -5
- package/js/ln-upload/README.md +85 -10
- package/js/ln-upload/ln-upload.js +1 -1
- package/js/ln-upload/src/ln-upload.js +26 -10
- package/js/ln-validate/README.md +72 -0
- package/js/ln-validate/ln-validate-dev.scss +15 -0
- package/js/ln-validate/ln-validate.js +1 -1
- package/js/ln-validate/src/ln-validate.js +64 -0
- package/package.json +61 -56
- package/scss/base/_global.scss +2 -2
- package/scss/base/_typography.scss +1 -2
- package/scss/components/_date.scss +1 -0
- package/scss/components/_dropdown.scss +0 -5
- package/scss/components/_editor.scss +5 -0
- package/scss/components/_filter.scss +26 -25
- package/scss/components/_form.scss +7 -0
- package/scss/components/_ln-table.scss +13 -3
- package/scss/components/_sort.scss +10 -0
- package/scss/components/_table.scss +36 -23
- package/scss/components/_toast.scss +68 -41
- package/scss/components/_toggle.scss +16 -0
- package/scss/config/_density.scss +205 -117
- package/scss/config/_icons.scss +10 -9
- package/scss/config/_tokens.scss +69 -47
- package/scss/config/mixins/_accordion.scss +2 -7
- package/scss/config/mixins/_alert.scss +4 -4
- package/scss/config/mixins/_breadcrumbs.scss +2 -2
- package/scss/config/mixins/_btn.scss +1 -1
- package/scss/config/mixins/_card.scss +89 -14
- package/scss/config/mixins/_collapsible.scss +3 -0
- package/scss/config/mixins/_colors.scss +1 -1
- package/scss/config/mixins/_diagnostics.scss +11 -0
- package/scss/config/mixins/_display.scss +1 -0
- package/scss/config/mixins/_dropdown.scss +3 -5
- package/scss/config/mixins/_editor.scss +124 -0
- package/scss/config/mixins/_empty-state.scss +7 -0
- package/scss/config/mixins/_filter.scss +3 -5
- package/scss/config/mixins/_footer.scss +1 -2
- package/scss/config/mixins/_form.scss +207 -21
- package/scss/config/mixins/_index.scss +2 -0
- package/scss/config/mixins/_ln-table.scss +41 -2
- package/scss/config/mixins/_modal.scss +149 -66
- package/scss/config/mixins/_nav.scss +3 -4
- package/scss/config/mixins/_popover.scss +39 -0
- package/scss/config/mixins/_sidebar.scss +1 -1
- package/scss/config/mixins/_sort.scss +42 -0
- package/scss/config/mixins/_table.scss +85 -60
- package/scss/config/mixins/_toast.scss +179 -152
- package/scss/config/mixins/_tooltip.scss +17 -7
- package/scss/config/mixins/_typography.scss +4 -2
- package/scss/ln-ashlar-dev.scss +27 -9
- package/scss/ln-ashlar.scss +7 -1
- package/js/ln-data-table/README.md +0 -110
- package/js/ln-data-table/ln-data-table.js +0 -1
- package/js/ln-data-table/ln-data-table.scss +0 -10
- package/js/ln-data-table/src/ln-data-table.js +0 -1087
- package/js/ln-icons/README.md +0 -88
- package/js/ln-icons/ln-icons.js +0 -1
- package/js/ln-table/ln-table-sort.js +0 -1
- package/js/ln-table/src/ln-table-sort.js +0 -156
package/js/ln-nav/src/ln-nav.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { registerComponent, dispatch, dispatchCancelable } from '../../ln-core';
|
|
2
2
|
|
|
3
3
|
(function () {
|
|
4
4
|
const DOM_SELECTOR = 'data-ln-nav';
|
|
@@ -6,8 +6,6 @@ import { guardBody } from '../../ln-core';
|
|
|
6
6
|
|
|
7
7
|
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
8
8
|
|
|
9
|
-
const navInstances = new WeakMap();
|
|
10
|
-
|
|
11
9
|
// ─── pushState singleton patch ──────────────────────────────
|
|
12
10
|
const _pushStateCallbacks = [];
|
|
13
11
|
|
|
@@ -20,158 +18,125 @@ import { guardBody } from '../../ln-core';
|
|
|
20
18
|
history._lnNavPatched = true;
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
// ───
|
|
24
|
-
|
|
25
|
-
function constructor(navElement) {
|
|
26
|
-
if (!navElement.hasAttribute(DOM_SELECTOR)) return;
|
|
27
|
-
if (navInstances.has(navElement)) return;
|
|
21
|
+
// ─── Component ─────────────────────────────────────────────
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
function _component(dom) {
|
|
24
|
+
this.dom = dom;
|
|
25
|
+
this.activeClass = dom.getAttribute(DOM_SELECTOR) || 'active';
|
|
26
|
+
this.exact = dom.hasAttribute('data-ln-nav-exact');
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
navInstances.set(navElement, instance);
|
|
34
|
-
navElement[DOM_ATTRIBUTE] = instance;
|
|
35
|
-
}
|
|
28
|
+
this.updateHandler = () => this.update();
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
// Listen to navigation events
|
|
31
|
+
window.addEventListener('popstate', this.updateHandler);
|
|
32
|
+
_pushStateCallbacks.push(this.updateHandler);
|
|
39
33
|
|
|
40
|
-
|
|
34
|
+
// Observe DOM changes inside this nav element
|
|
35
|
+
this.observer = new MutationObserver(() => this.update());
|
|
36
|
+
this.observer.observe(dom, { childList: true, subtree: true });
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
_updateActiveState(links, activeClass, window.location.pathname);
|
|
45
|
-
};
|
|
38
|
+
// Perform initial highlight
|
|
39
|
+
this.update();
|
|
46
40
|
|
|
47
|
-
|
|
48
|
-
_pushStateCallbacks.push(updateHandler);
|
|
49
|
-
|
|
50
|
-
const observer = new MutationObserver(function (mutations) {
|
|
51
|
-
for (const mutation of mutations) {
|
|
52
|
-
if (mutation.type === 'childList') {
|
|
53
|
-
for (const node of mutation.addedNodes) {
|
|
54
|
-
if (node.nodeType === 1) {
|
|
55
|
-
if (node.tagName === 'A') {
|
|
56
|
-
links.push(node);
|
|
57
|
-
_updateActiveState([node], activeClass, window.location.pathname);
|
|
58
|
-
} else if (node.querySelectorAll) {
|
|
59
|
-
const newLinks = Array.from(node.querySelectorAll('a'));
|
|
60
|
-
links = links.concat(newLinks);
|
|
61
|
-
_updateActiveState(newLinks, activeClass, window.location.pathname);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
for (const node of mutation.removedNodes) {
|
|
67
|
-
if (node.nodeType === 1) {
|
|
68
|
-
if (node.tagName === 'A') {
|
|
69
|
-
links = links.filter(function (link) { return link !== node; });
|
|
70
|
-
} else if (node.querySelectorAll) {
|
|
71
|
-
const removedLinks = Array.from(node.querySelectorAll('a'));
|
|
72
|
-
links = links.filter(function (link) {
|
|
73
|
-
return !removedLinks.includes(link);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
observer.observe(navElement, { childList: true, subtree: true });
|
|
83
|
-
|
|
84
|
-
return {
|
|
85
|
-
navElement: navElement,
|
|
86
|
-
activeClass: activeClass,
|
|
87
|
-
observer: observer,
|
|
88
|
-
updateHandler: updateHandler,
|
|
89
|
-
destroy: function () {
|
|
90
|
-
observer.disconnect();
|
|
91
|
-
window.removeEventListener('popstate', updateHandler);
|
|
92
|
-
const idx = _pushStateCallbacks.indexOf(updateHandler);
|
|
93
|
-
if (idx !== -1) _pushStateCallbacks.splice(idx, 1);
|
|
94
|
-
navInstances.delete(navElement);
|
|
95
|
-
delete navElement[DOM_ATTRIBUTE];
|
|
96
|
-
}
|
|
97
|
-
};
|
|
41
|
+
return this;
|
|
98
42
|
}
|
|
99
43
|
|
|
100
|
-
function
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
} catch (e) {
|
|
105
|
-
return url.replace(/\/$/, '') || '/';
|
|
106
|
-
}
|
|
107
|
-
}
|
|
44
|
+
_component.prototype.update = function () {
|
|
45
|
+
if (!this.activeClass) return;
|
|
46
|
+
const before = dispatchCancelable(this.dom, 'ln-nav:before-update', { target: this.dom });
|
|
47
|
+
if (before.defaultPrevented) return;
|
|
108
48
|
|
|
109
|
-
|
|
49
|
+
const links = Array.from(this.dom.querySelectorAll('a'));
|
|
50
|
+
const currentPath = window.location.pathname;
|
|
110
51
|
const normalizedCurrent = _normalizeUrl(currentPath);
|
|
111
52
|
|
|
112
53
|
for (const link of links) {
|
|
113
54
|
const href = link.getAttribute('href');
|
|
114
|
-
if (!href)
|
|
115
|
-
|
|
116
|
-
|
|
55
|
+
if (!href || href === '#' || href.startsWith('#') || href.startsWith('javascript:') || href.startsWith('mailto:') || href.startsWith('tel:')) {
|
|
56
|
+
link.classList.remove(this.activeClass);
|
|
57
|
+
link.removeAttribute('aria-current');
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
117
60
|
|
|
118
|
-
|
|
61
|
+
// Exclude external links
|
|
62
|
+
if (link.hostname && link.hostname !== window.location.hostname) {
|
|
63
|
+
link.classList.remove(this.activeClass);
|
|
64
|
+
link.removeAttribute('aria-current');
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
119
67
|
|
|
68
|
+
const normalizedHref = _normalizeUrl(href);
|
|
120
69
|
const isExact = normalizedHref === normalizedCurrent;
|
|
121
|
-
const isParent = normalizedHref !== '/' && normalizedCurrent.startsWith(normalizedHref + '/');
|
|
70
|
+
const isParent = !this.exact && normalizedHref !== '/' && normalizedCurrent.startsWith(normalizedHref + '/');
|
|
122
71
|
|
|
123
72
|
if (isExact || isParent) {
|
|
124
|
-
link.classList.add(activeClass);
|
|
73
|
+
link.classList.add(this.activeClass);
|
|
74
|
+
link.setAttribute('aria-current', 'page');
|
|
75
|
+
} else {
|
|
76
|
+
link.classList.remove(this.activeClass);
|
|
77
|
+
link.removeAttribute('aria-current');
|
|
125
78
|
}
|
|
126
79
|
}
|
|
127
|
-
}
|
|
128
80
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
} else if (mutation.type === 'attributes') {
|
|
149
|
-
if (mutation.target.hasAttribute && mutation.target.hasAttribute(DOM_SELECTOR)) {
|
|
150
|
-
constructor(mutation.target);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
});
|
|
81
|
+
dispatch(this.dom, 'ln-nav:update', { target: this.dom });
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
_component.prototype.destroy = function () {
|
|
85
|
+
if (!this.dom[DOM_ATTRIBUTE]) return;
|
|
86
|
+
if (this.observer) {
|
|
87
|
+
this.observer.disconnect();
|
|
88
|
+
}
|
|
89
|
+
window.removeEventListener('popstate', this.updateHandler);
|
|
90
|
+
const idx = _pushStateCallbacks.indexOf(this.updateHandler);
|
|
91
|
+
if (idx !== -1) {
|
|
92
|
+
_pushStateCallbacks.splice(idx, 1);
|
|
93
|
+
}
|
|
94
|
+
dispatch(this.dom, 'ln-nav:destroyed', { target: this.dom });
|
|
95
|
+
delete this.dom[DOM_ATTRIBUTE];
|
|
96
|
+
};
|
|
155
97
|
|
|
156
|
-
|
|
157
|
-
|
|
98
|
+
// ─── Helper Functions ──────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
function _normalizeUrl(url) {
|
|
101
|
+
try {
|
|
102
|
+
const urlObj = new URL(url, window.location.href);
|
|
103
|
+
return urlObj.pathname.replace(/\/$/, '') || '/';
|
|
104
|
+
} catch (e) {
|
|
105
|
+
return url.replace(/\/$/, '') || '/';
|
|
106
|
+
}
|
|
158
107
|
}
|
|
159
108
|
|
|
160
|
-
// ───
|
|
109
|
+
// ─── Attribute Sync ────────────────────────────────────────
|
|
161
110
|
|
|
162
|
-
|
|
111
|
+
function _syncAttribute(el, attrName) {
|
|
112
|
+
const instance = el[DOM_ATTRIBUTE];
|
|
113
|
+
if (!instance) return;
|
|
163
114
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
115
|
+
if (attrName === DOM_SELECTOR) {
|
|
116
|
+
if (!el.hasAttribute(DOM_SELECTOR)) {
|
|
117
|
+
instance.destroy();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const oldClass = instance.activeClass;
|
|
121
|
+
const newClass = el.getAttribute(DOM_SELECTOR) || 'active';
|
|
122
|
+
if (oldClass !== newClass) {
|
|
123
|
+
const links = el.querySelectorAll('a');
|
|
124
|
+
for (const link of links) {
|
|
125
|
+
if (oldClass) link.classList.remove(oldClass);
|
|
126
|
+
}
|
|
127
|
+
instance.activeClass = newClass;
|
|
128
|
+
}
|
|
129
|
+
} else if (attrName === 'data-ln-nav-exact') {
|
|
130
|
+
instance.exact = el.hasAttribute('data-ln-nav-exact');
|
|
167
131
|
}
|
|
132
|
+
|
|
133
|
+
instance.update();
|
|
168
134
|
}
|
|
169
135
|
|
|
170
|
-
|
|
136
|
+
// ─── Init ──────────────────────────────────────────────────
|
|
171
137
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
138
|
+
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-nav', {
|
|
139
|
+
extraAttributes: ['data-ln-nav-exact'],
|
|
140
|
+
onAttributeChange: _syncAttribute
|
|
141
|
+
});
|
|
177
142
|
})();
|
package/js/ln-number/README.md
CHANGED
|
@@ -8,7 +8,12 @@ Real-time locale-aware number formatting for input fields.
|
|
|
8
8
|
<input type="number" name="amount" data-ln-number>
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The component creates a hidden input that holds the raw numeric value for form submission and formats the visible input with locale-aware thousand separators.
|
|
11
|
+
The component creates a hidden input that holds the raw numeric value for form submission and formats the visible input with locale-aware thousand separators. After initialization:
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<input type="text" inputmode="decimal" data-ln-number>
|
|
15
|
+
<input type="hidden" name="amount" value="1234567">
|
|
16
|
+
```
|
|
12
17
|
|
|
13
18
|
## Loading & Source Files
|
|
14
19
|
|
|
@@ -120,3 +125,25 @@ on the visible input and works as expected:
|
|
|
120
125
|
Works automatically. `serializeForm()` reads the hidden input (which has the
|
|
121
126
|
`name`). `populateForm()` sets the hidden input's value, which triggers the
|
|
122
127
|
display update.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## 🔧 Internals
|
|
132
|
+
|
|
133
|
+
Source: `js/ln-number/ln-number.js`. Each `[data-ln-number]` gets a `_component` instance at `element.lnNumber`, holding `dom` (visible input), `_hidden` (hidden input), and bound `_onInput`/`_onPaste` handlers.
|
|
134
|
+
|
|
135
|
+
### Formatter cache
|
|
136
|
+
|
|
137
|
+
One `Intl.NumberFormat` instance per unique locale, cached at module level (`_formatters[locale]`), storing the formatter plus `groupSep`/`decimalSep` extracted once via `formatToParts()`. Separate cache keys (`locale + '|d' + max`, `locale + '|u' + n`) exist for decimal-fixed and user-decimal-preserving formatters. Reused across all instances sharing a locale — `Intl.NumberFormat` construction is the expensive part, not the format call.
|
|
138
|
+
|
|
139
|
+
### Input flow
|
|
140
|
+
|
|
141
|
+
On every `input` event: empty value clears the hidden input and dispatches; a bare `-` (user starting a negative number) is left alone. Otherwise: cursor position is saved as a digit-count left of `selectionStart` (not a raw index — formatting inserts/removes separators, so digit-count is the only stable anchor). The typed string is parsed (strip `groupSep`, swap `decimalSep` for `.`); a trailing decimal point or trailing zeros after the decimal point short-circuit to a hidden-only update (so `"12."` doesn't get reformatted mid-type and eat the point the user just typed). Otherwise the decimal limit is enforced (truncated, not rounded), the value is formatted via `Intl.NumberFormat`, `dom.value` is set, the cursor is restored by walking the formatted string until the saved digit-count is reached, and `hidden.value` is set to the raw numeric string. `ln-number:input` dispatches last.
|
|
142
|
+
|
|
143
|
+
### Hidden input value interceptor
|
|
144
|
+
|
|
145
|
+
`hidden.value` is wrapped via `Object.defineProperty` so programmatic sets (e.g. `populateForm()` writing `hidden.value = "1234"`) route through the same parse → format → display path as user input. Internal code writes through `_setHiddenRaw()`, which calls the prototype's original setter directly — bypassing the custom setter avoids the interceptor re-triggering itself (infinite loop).
|
|
146
|
+
|
|
147
|
+
### Auto-init
|
|
148
|
+
|
|
149
|
+
A single `document.body` `MutationObserver` watches `childList` (subtree — new `[data-ln-number]` elements auto-initialize via `findElements`) and `attributes` on `data-ln-number` (attribute added to an existing element initializes it in place).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@use '../../scss/config/mixins' as *;
|
|
2
|
+
|
|
3
|
+
[data-ln-debug] {
|
|
4
|
+
// 1. Number element misuse: data-ln-number belongs on <input>, <span>, <time>, or <td>
|
|
5
|
+
[data-ln-number]:not(input, span, time, td, p, div, b, strong, data) {
|
|
6
|
+
@include dev-inline-error("data-ln-number belongs on <input>, <span>, <time>, or <td>");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// 2. Number input missing ID: input[data-ln-number] must have an id for proper labeling/association
|
|
10
|
+
input[data-ln-number]:not([id]) {
|
|
11
|
+
@include dev-inline-error("data-ln-number is missing required 'id' attribute");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(){"use strict";function v(s,i,u){s.dispatchEvent(new CustomEvent(i,{bubbles:!0,detail:u||{}}))}function S(s,i){if(!document.body){document.addEventListener("DOMContentLoaded",function(){S(s,i)}),console.warn("["+i+'] Script loaded before <body> — add "defer" to your <script> tag');return}s()}function x(s,i,u,p){if(s.nodeType!==1)return;const y=i.indexOf("[")!==-1||i.indexOf(".")!==-1||i.indexOf("#")!==-1?i:"["+i+"]",m=Array.from(s.querySelectorAll(y));s.matches&&s.matches(y)&&m.push(s);for(const h of m)h[u]||(h[u]=new p(h))}function E(s){const i=s.closest("[lang]");return(i?i.lang:null)||navigator.language}function O(s,i,{get:u,set:p}){Object.defineProperty(s,"value",{get:function(){return u?u.call(this):i.get.call(this)},set:function(g){p?p.call(this,g,y=>i.set.call(this,y)):i.set.call(this,g)},configurable:!0})}function I(s,i,u,p,g={}){const y=g.extraAttributes||[],m=g.onAttributeChange||null,h=g.onInit||null;function t(a){const e=a||document.body;x(e,s,i,u),h&&h(e)}return S(function(){const a=new MutationObserver(function(c){for(let r=0;r<c.length;r++){const n=c[r];if(n.type==="childList"){for(let o=0;o<n.addedNodes.length;o++){const l=n.addedNodes[o];l.nodeType===1&&(x(l,s,i,u),h&&h(l))}for(let o=0;o<n.removedNodes.length;o++){const l=n.removedNodes[o];if(l.nodeType===1){const _=s.indexOf("[")!==-1||s.indexOf(".")!==-1||s.indexOf("#")!==-1?s:"["+s+"]",F=Array.from(l.querySelectorAll(_));l.matches&&l.matches(_)&&F.push(l);for(let b=0;b<F.length;b++){const D=F[b];if(!document.contains(D)){const N=D[i];N&&typeof N.destroy=="function"&&N.destroy()}}}}}else n.type==="attributes"&&(m&&n.target[i]?m(n.target,n.attributeName):(x(n.target,s,i,u),h&&h(n.target)))}});let e=[];if(s.indexOf("[")!==-1){const c=/\[([\w-]+)/g;let r;for(;(r=c.exec(s))!==null;)e.push(r[1])}else e.push(s);a.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:e.concat(y)})},p),window[i]=t,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){t(document.body)}):t(document.body),t}const A={};function C(s,i){A[s]=i}function L(s){return A[s]||{ingress:i=>i,egress:i=>i}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=C,window.lnCore.getDataMapper=L),(function(){const s="data-ln-number",i="lnNumber";if(window[i]!==void 0)return;const u={},p=Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,"value");function g(t){if(!u[t]){const a=new Intl.NumberFormat(t,{useGrouping:!0}),e=a.formatToParts(1234.5);let c="",r=".";for(let n=0;n<e.length;n++)e[n].type==="group"&&(c=e[n].value),e[n].type==="decimal"&&(r=e[n].value);u[t]={fmt:a,groupSep:c,decimalSep:r}}return u[t]}function y(t,a,e){if(e!==null){const c=parseInt(e,10),r=t+"|d"+c;return u[r]||(u[r]=new Intl.NumberFormat(t,{useGrouping:!0,minimumFractionDigits:0,maximumFractionDigits:c})),u[r].format(a)}return g(t).fmt.format(a)}function m(t){if(t.tagName!=="INPUT")return console.warn("[ln-number] Can only be applied to <input>, got:",t.tagName),this;if(t[i])return t[i];t[i]=this,this.dom=t;const a=document.createElement("input");a.type="hidden",a.name=t.name,t.removeAttribute("name"),t.type="text",t.setAttribute("inputmode","decimal"),t.insertAdjacentElement("afterend",a),this._hidden=a;const e=this;Object.defineProperty(a,"value",{get:function(){return p.get.call(a)},set:function(r){if(p.set.call(a,r),r!==""&&!isNaN(parseFloat(r))){const n=parseFloat(r);e._displayFormatted(n),v(e.dom,"ln-number:input",{value:n,formatted:e.dom.value}),e.dom.dispatchEvent(new Event("input",{bubbles:!0}))}else r===""&&(e.dom.value="",v(e.dom,"ln-number:input",{value:NaN,formatted:""}),e.dom.dispatchEvent(new Event("input",{bubbles:!0})))}}),O(t,p,{get:function(){return p.get.call(t)},set:function(r,n){if(e._isFormatting){n(r);return}if(r===""){n(""),e._setHiddenRaw(""),v(t,"ln-number:input",{value:NaN,formatted:""}),t.dispatchEvent(new Event("input",{bubbles:!0}));return}let o=typeof r=="number"?r:parseFloat(String(r).replace(/[^\d.-]/g,""));if(isNaN(o))n(String(r)),e._setHiddenRaw(""),v(t,"ln-number:input",{value:NaN,formatted:String(r)}),t.dispatchEvent(new Event("input",{bubbles:!0}));else{e._setHiddenRaw(o);const l=y(E(t),o,t.getAttribute("data-ln-number-decimals"));n(l),v(t,"ln-number:input",{value:o,formatted:l}),t.dispatchEvent(new Event("input",{bubbles:!0}))}}}),this._onInput=function(){e._handleInput()},t.addEventListener("input",this._onInput),this._onPaste=function(r){r.preventDefault();const n=(r.clipboardData||window.clipboardData).getData("text"),o=g(E(t)),l=o.decimalSep.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");let f=n.replace(new RegExp("[^0-9\\-"+l+".]","g"),"");o.groupSep&&(f=f.split(o.groupSep).join("")),o.decimalSep!=="."&&(f=f.replace(o.decimalSep,"."));const _=parseFloat(f);isNaN(_)?(t.value="",e._hidden.value=""):e.value=_},t.addEventListener("paste",this._onPaste);const c=t.value;if(c!==""){const r=parseFloat(c);isNaN(r)||(this._displayFormatted(r),p.set.call(a,String(r)),v(t,"ln-number:input",{value:r,formatted:t.value}),t.dispatchEvent(new Event("input",{bubbles:!0})))}return this}m.prototype._handleInput=function(){const t=this.dom,a=g(E(t)),e=t.value;if(e===""){this._hidden.value="",v(t,"ln-number:input",{value:NaN,formatted:""});return}if(e==="-"){this._hidden.value="";return}const c=t.selectionStart;let r=0;for(let d=0;d<c;d++)/[0-9]/.test(e[d])&&r++;let n=e;if(a.groupSep&&(n=n.split(a.groupSep).join("")),n=n.replace(a.decimalSep,"."),e.endsWith(a.decimalSep)||e.endsWith(".")){const d=n.replace(/\.$/,""),w=parseFloat(d);isNaN(w)||this._setHiddenRaw(w);return}const o=n.indexOf(".");if(o!==-1&&n.slice(o+1).endsWith("0")){const w=parseFloat(n);isNaN(w)||this._setHiddenRaw(w);return}const l=t.getAttribute("data-ln-number-decimals");if(l!==null&&o!==-1){const d=parseInt(l,10);n.slice(o+1).length>d&&(n=n.slice(0,o+1+d))}const f=parseFloat(n);if(isNaN(f))return;const _=t.getAttribute("data-ln-number-min"),F=t.getAttribute("data-ln-number-max");if(_!==null&&f<parseFloat(_)||F!==null&&f>parseFloat(F))return;let b;if(l!==null)b=y(E(t),f,l);else{const d=o!==-1?n.slice(o+1).length:0;if(d>0){const w=E(t)+"|u"+d;u[w]||(u[w]=new Intl.NumberFormat(E(t),{useGrouping:!0,minimumFractionDigits:d,maximumFractionDigits:d})),b=u[w].format(f)}else b=a.fmt.format(f)}t.value=b;let D=r,N=0;for(let d=0;d<b.length&&D>0;d++)N=d+1,/[0-9]/.test(b[d])&&D--;D>0&&(N=b.length),t.setSelectionRange(N,N),this._setHiddenRaw(f),v(t,"ln-number:input",{value:f,formatted:b})},m.prototype._setHiddenRaw=function(t){p.set.call(this._hidden,String(t))},m.prototype._displayFormatted=function(t){this._isFormatting=!0,this.dom.value=y(E(this.dom),t,this.dom.getAttribute("data-ln-number-decimals")),this._isFormatting=!1},Object.defineProperty(m.prototype,"value",{get:function(){const t=this._hidden.value;return t===""?NaN:parseFloat(t)},set:function(t){if(typeof t!="number"||isNaN(t)){this.dom.value="",this._setHiddenRaw(""),this.dom.dispatchEvent(new Event("input",{bubbles:!0}));return}this._displayFormatted(t),this._setHiddenRaw(t),v(this.dom,"ln-number:input",{value:t,formatted:this.dom.value}),this.dom.dispatchEvent(new Event("input",{bubbles:!0}))}}),Object.defineProperty(m.prototype,"formatted",{get:function(){return this.dom.value}}),m.prototype.destroy=function(){this.dom[i]&&(this.dom.removeEventListener("input",this._onInput),this.dom.removeEventListener("paste",this._onPaste),this.dom.name=this._hidden.name,this.dom.type="number",this.dom.removeAttribute("inputmode"),this._hidden.remove(),v(this.dom,"ln-number:destroyed",{target:this.dom}),delete this.dom[i])};function h(){new MutationObserver(function(){const t=document.querySelectorAll("["+s+"]");for(let a=0;a<t.length;a++){const e=t[a][i];e&&!isNaN(e.value)&&e._displayFormatted(e.value)}}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"]})}I(s,i,m,"ln-number"),h()})()})();
|
|
1
|
+
(function(){"use strict";if(typeof window<"u"){const e=console.warn;console.warn=function(...n){typeof n[0]=="string"&&(n[0].startsWith("[ln-")||n[0].startsWith("[lnCore"))&&!(document.documentElement.hasAttribute("data-ln-debug")||document.body&&document.body.hasAttribute("data-ln-debug"))||e.apply(console,n)}}const v={};function H(e,n){v[e]||(v[e]=document.querySelector('[data-ln-template="'+e+'"]'));const s=v[e];return s?s.content.cloneNode(!0):(console.warn("["+(n||"ln-core")+'] Template "'+e+'" not found'),null)}function S(e,n,s){e.dispatchEvent(new CustomEvent(n,{bubbles:!0,detail:s||{}}))}function R(e,n){if(!e||!n)return e;const s=e.querySelectorAll("[data-ln-field]");for(let l=0;l<s.length;l++){const a=s[l],d=a.getAttribute("data-ln-field");n[d]!=null&&(a.textContent=n[d])}const u=e.querySelectorAll("[data-ln-attr]");for(let l=0;l<u.length;l++){const a=u[l],d=a.getAttribute("data-ln-attr").split(",");for(let t=0;t<d.length;t++){const i=d[t].trim().split(":");if(i.length!==2)continue;const r=i[0].trim(),m=i[1].trim();n[m]!=null&&a.setAttribute(r,n[m])}}const p=e.querySelectorAll("[data-ln-show]");for(let l=0;l<p.length;l++){const a=p[l],d=a.getAttribute("data-ln-show");d in n&&a.classList.toggle("hidden",!n[d])}const c=e.querySelectorAll("[data-ln-class]");for(let l=0;l<c.length;l++){const a=c[l],d=a.getAttribute("data-ln-class").split(",");for(let t=0;t<d.length;t++){const i=d[t].trim().split(":");if(i.length!==2)continue;const r=i[0].trim(),m=i[1].trim();m in n&&a.classList.toggle(r,!!n[m])}}return e}function P(e,n){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&e.dispatchEvent(new CustomEvent("ln-fill",{detail:n??null,bubbles:!0}));const s=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let u=0;u<s.length;u++)s[u].dispatchEvent(new CustomEvent("ln-fill",{detail:n??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)R(e.target,e.detail);else{const n=e.target.querySelectorAll("[data-ln-field]");for(let s=0;s<n.length;s++)n[s].textContent=""}})));function L(e,n){if(!e||!n)return e;const s=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;s.nextNode();){const c=s.currentNode;c.textContent.indexOf("{{")!==-1&&(c.textContent=c.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(l,a){return n[a]!==void 0?n[a]:""}))}const u=function(c,l){return n[l]!==void 0?n[l]:""},p=Array.from(e.querySelectorAll("*"));e.nodeType===1&&p.push(e);for(let c=0;c<p.length;c++){const l=p[c],a=l.attributes;for(let d=0;d<a.length;d++){const t=a[d];t.value.indexOf("{{")!==-1&&l.setAttribute(t.name,t.value.replace(/\{\{\s*(\w+)\s*\}\}/g,u))}}return e}function M(e,n,s,u,p,c){const l={};for(let d=0;d<e.children.length;d++){const t=e.children[d],i=t.getAttribute("data-ln-key");i&&(l[i]=t)}const a=document.createDocumentFragment();for(let d=0;d<n.length;d++){const t=n[d],i=String(u(t));let r=l[i];if(r)p(r,t,d);else{const m=H(s,c);if(!m||(L(m,t),r=m.firstElementChild,!r))continue;r.setAttribute("data-ln-key",i),p(r,t,d)}a.appendChild(r)}e.textContent="",e.appendChild(a)}function O(e,n){if(!document.body){document.addEventListener("DOMContentLoaded",function(){O(e,n)}),console.warn("["+n+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}function D(e,n,s,u){if(e.nodeType!==1)return;const c=n.indexOf("[")!==-1||n.indexOf(".")!==-1||n.indexOf("#")!==-1?n:"["+n+"]",l=Array.from(e.querySelectorAll(c));e.matches&&e.matches(c)&&l.push(e);for(const a of l)a[s]||(a[s]=new u(a))}const F={mk:"mk-MK",de:"de-DE",fr:"fr-FR",es:"es-ES",it:"it-IT",nl:"nl-NL",pt:"pt-PT",ru:"ru-RU",bg:"bg-BG",hr:"hr-HR",sr:"sr-RS",sq:"sq-AL",el:"el-GR",en:"en-US"};function w(e){const n=e?e.closest("[lang]"):null,s=(n?n.getAttribute("lang")||n.lang:null)||(document.documentElement?document.documentElement.getAttribute("lang")||document.documentElement.lang:null)||navigator.language;if(!s)return"en-US";const u=s.trim().toLowerCase();return u.indexOf("-")===-1&&F[u]?F[u]:s}function V(e,n,{get:s,set:u}){Object.defineProperty(e,"value",{get:function(){return s?s.call(this):n.get.call(this)},set:function(p){u?u.call(this,p,c=>n.set.call(this,c)):n.set.call(this,p)},configurable:!0})}function W(e,n,s,u,p={}){const c=p.extraAttributes||[],l=p.onAttributeChange||null,a=p.onInit||null;function d(t){const i=t||document.body;D(i,e,n,s),a&&a(i)}return O(function(){const t=new MutationObserver(function(r){for(let m=0;m<r.length;m++){const o=r[m];if(o.type==="childList"){for(let f=0;f<o.addedNodes.length;f++){const h=o.addedNodes[f];h.nodeType===1&&(D(h,e,n,s),a&&a(h))}for(let f=0;f<o.removedNodes.length;f++){const h=o.removedNodes[f];if(h.nodeType===1){const b=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]",x=Array.from(h.querySelectorAll(b));h.matches&&h.matches(b)&&x.push(h);for(let E=0;E<x.length;E++){const y=x[E];if(!document.contains(y)){const A=y[n];A&&typeof A.destroy=="function"&&A.destroy()}}}}}else o.type==="attributes"&&(l&&o.target[n]?l(o.target,o.attributeName):(D(o.target,e,n,s),a&&a(o.target)))}});let i=[];if(e.indexOf("[")!==-1){const r=/\[([\w-]+)/g;let m;for(;(m=r.exec(e))!==null;)i.push(m[1])}else i.push(e);t.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:i.concat(c)})},u),window[n]=d,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){d(document.body)}):d(document.body),d}const k={};function B(e,n){k[e]=n}function G(e){return k[e]||{ingress:n=>n,egress:n=>n}}const I={};function j(e,n){if(!e||typeof n!="object")return;const s=e.toLowerCase().split("-")[0];I[s]=n}function U(e){if(!e)return null;const n=e.toLowerCase().split("-")[0];return I[n]||null}j("mk",{monthsLong:["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември"],monthsShort:["јан","фев","мар","апр","мај","јун","јул","авг","септ","окт","ноем","дек"],daysLong:["недела","понеделник","вторник","среда","четврток","петок","сабота"],daysShort:["нед","пон","вт","ср","чет","пет","саб"]}),typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=B,window.lnCore.getDataMapper=G,window.lnCore.registerLocaleFallback=j,window.lnCore.getLocaleFallback=U,window.lnCore.fillTemplate=L,window.lnCore.fill=R,window.lnCore.lnFill=P,window.lnCore.renderList=M);function q(e){return(e||"").replace(/^#/,"")}function T(e){const n=e===void 0?location.hash:e,s={},u=q(n);if(!u)return s;const p=u.split("&");for(let c=0;c<p.length;c++){const l=p[c];if(!l)continue;const a=l.indexOf(":"),d=a>-1?l.slice(0,a):l,t=a>-1?l.slice(a+1):"";if(d)try{s[d]=decodeURIComponent(t)}catch{s[d]=t}}return s}function K(e){if(!e)return null;const n=T();return e in n?n[e]:null}function $(e,n){if(!e)return;const s=T();n==null?delete s[e]:s[e]=String(n);const p=Object.keys(s).map(function(c){const l=s[c];return l===""?c:c+":"+encodeURIComponent(l)}).join("&");q(location.hash)!==p&&(location.hash=p)}function X(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=T,window.lnCore.hashGet=K,window.lnCore.hashSet=$,window.lnCore.hashLinkClick=X),(function(){const e="data-ln-number",n="lnNumber";if(window[n]!==void 0)return;const s={},u=Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,"value");function p(t){if(!s[t]){const i=new Intl.NumberFormat(t,{useGrouping:!0}),r=i.formatToParts(1234.5);let m="",o=".";for(let f=0;f<r.length;f++)r[f].type==="group"&&(m=r[f].value),r[f].type==="decimal"&&(o=r[f].value);s[t]={fmt:i,groupSep:m,decimalSep:o}}return s[t]}function c(t,i,r){if(r!==null){const m=parseInt(r,10),o=t+"|d"+m;return s[o]||(s[o]=new Intl.NumberFormat(t,{useGrouping:!0,minimumFractionDigits:0,maximumFractionDigits:m})),s[o].format(i)}return p(t).fmt.format(i)}function l(t){if(t[n])return t[n];if(t[n]=this,this.dom=t,t.tagName!=="INPUT")return this.isTextElement=!0,this._initTextElement(),this;const i=document.createElement("input");i.type="hidden",i.name=t.name,t.removeAttribute("name"),t.hasAttribute("data-ln-fill-as")&&i.setAttribute("data-ln-fill-as",t.getAttribute("data-ln-fill-as")),t.type="text",t.setAttribute("inputmode","decimal"),t.insertAdjacentElement("afterend",i),this._hidden=i;const r=this;Object.defineProperty(i,"value",{get:function(){return u.get.call(i)},set:function(o){u.set.call(i,o),o!==""&&!isNaN(parseFloat(o))?r._setDisplayRaw(c(w(r.dom),parseFloat(o),r.dom.getAttribute("data-ln-number-decimals"))):r._setDisplayRaw(""),r.dom.dispatchEvent(new Event("input",{bubbles:!0}))}}),V(t,u,{get:function(){return u.get.call(t)},set:function(o){if(o===""){r._setDisplayRaw(""),r._setHiddenRaw(""),t.dispatchEvent(new Event("input",{bubbles:!0}));return}const f=typeof o=="number"?o:parseFloat(String(o).replace(/[^\d.-]/g,""));isNaN(f)?(r._setDisplayRaw(String(o)),r._setHiddenRaw("")):(r._setHiddenRaw(f),r._setDisplayRaw(c(w(t),f,t.getAttribute("data-ln-number-decimals")))),t.dispatchEvent(new Event("input",{bubbles:!0}))}}),this._onInput=function(){r._handleInput()},t.addEventListener("input",this._onInput),this._onPaste=function(o){o.preventDefault();const f=(o.clipboardData||window.clipboardData).getData("text"),h=p(w(t)),C=h.decimalSep.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");let b=f.replace(new RegExp("[^0-9\\-"+C+".]","g"),"");h.groupSep&&(b=b.split(h.groupSep).join("")),h.decimalSep!=="."&&(b=b.replace(h.decimalSep,"."));const x=parseFloat(b);r.value=isNaN(x)?NaN:x},t.addEventListener("paste",this._onPaste);const m=t.value;if(m!==""){const o=parseFloat(m);isNaN(o)||(this._setHiddenRaw(o),this._setDisplayRaw(c(w(t),o,t.getAttribute("data-ln-number-decimals"))),t.dispatchEvent(new Event("input",{bubbles:!0})))}return this}function a(t){if(typeof t=="number")return isNaN(t)?null:t;if(!t||typeof t!="string")return null;let i=t.trim();if(i==="")return null;i=i.replace(/[\s\u00A0$€£]/g,""),i.indexOf(",")!==-1&&i.indexOf(".")!==-1?i.indexOf(".")<i.indexOf(",")?i=i.replace(/\./g,"").replace(",","."):i=i.replace(/,/g,""):i.indexOf(",")!==-1&&(i=i.replace(",",".")),i=i.replace(/[^\d.-]/g,"");const r=parseFloat(i);return isNaN(r)?null:r}l.prototype._initTextElement=function(){const t=this.dom;let i=t.getAttribute("data-ln-value"),r=t.getAttribute("data-ln-number"),m=null;i!==null&&i!==""?m=i:r!==null&&r!==""&&r!=="true"?m=r:m=t.textContent.trim();const o=a(m);o!==null?(this._rawValue=o,t.hasAttribute("data-ln-value")||t.setAttribute("data-ln-value",String(o)),this._formatTextContent()):this._rawValue=null},l.prototype._formatTextContent=function(){if(this._rawValue!==null&&!isNaN(this._rawValue)){const t=this.dom.getAttribute("data-ln-number-decimals");this.dom.textContent=c(w(this.dom),this._rawValue,t)}},l.prototype._handleInput=function(){const t=this.dom,i=p(w(t)),r=u.get.call(t);if(r===""){this._setHiddenRaw(""),S(t,"ln-number:input",{value:NaN,formatted:""});return}if(r==="-"){this._setHiddenRaw("");return}const m=t.selectionStart;let o=0;for(let g=0;g<m;g++)/[0-9]/.test(r[g])&&o++;let f=r;if(i.groupSep&&(f=f.split(i.groupSep).join("")),f=f.replace(i.decimalSep,"."),r.endsWith(i.decimalSep)||r.endsWith(".")){const g=f.replace(/\.$/,""),_=parseFloat(g);isNaN(_)||this._setHiddenRaw(_);return}const h=f.indexOf(".");if(h!==-1&&f.slice(h+1).endsWith("0")){const _=parseFloat(f);isNaN(_)||this._setHiddenRaw(_);return}const C=t.getAttribute("data-ln-number-decimals");if(C!==null&&h!==-1){const g=parseInt(C,10);f.slice(h+1).length>g&&(f=f.slice(0,h+1+g))}const b=parseFloat(f);if(isNaN(b))return;const x=t.getAttribute("data-ln-number-min"),E=t.getAttribute("data-ln-number-max");if(x!==null&&b<parseFloat(x)||E!==null&&b>parseFloat(E))return;let y;if(C!==null)y=c(w(t),b,C);else{const g=h!==-1?f.slice(h+1).length:0;if(g>0){const _=w(t)+"|u"+g;s[_]||(s[_]=new Intl.NumberFormat(w(t),{useGrouping:!0,minimumFractionDigits:g,maximumFractionDigits:g})),y=s[_].format(b)}else y=i.fmt.format(b)}this._setDisplayRaw(y);let A=o,N=0;for(let g=0;g<y.length&&A>0;g++)N=g+1,/[0-9]/.test(y[g])&&A--;A>0&&(N=y.length),t.setSelectionRange(N,N),this._setHiddenRaw(b),S(t,"ln-number:input",{value:b,formatted:y})},l.prototype._setHiddenRaw=function(t){this._hidden&&u.set.call(this._hidden,String(t))},l.prototype._setDisplayRaw=function(t){this.isTextElement?this.dom.textContent=String(t):u.set.call(this.dom,String(t))},l.prototype._displayFormatted=function(t){this.isTextElement?this._formatTextContent():this._setDisplayRaw(c(w(this.dom),t,this.dom.getAttribute("data-ln-number-decimals")))},Object.defineProperty(l.prototype,"value",{get:function(){if(this.isTextElement)return this._rawValue;const t=u.get.call(this._hidden);return t===""?NaN:parseFloat(t)},set:function(t){if(this.isTextElement){typeof t!="number"||isNaN(t)?(this._rawValue=null,this.dom.textContent=""):(this._rawValue=t,this.dom.setAttribute("data-ln-value",String(t)),this._formatTextContent());return}if(typeof t!="number"||isNaN(t)){this._setDisplayRaw(""),this._setHiddenRaw(""),this.dom.dispatchEvent(new Event("input",{bubbles:!0}));return}this._setHiddenRaw(t),this._setDisplayRaw(c(w(this.dom),t,this.dom.getAttribute("data-ln-number-decimals"))),this.dom.dispatchEvent(new Event("input",{bubbles:!0}))}}),Object.defineProperty(l.prototype,"formatted",{get:function(){return this.isTextElement?this.dom.textContent:u.get.call(this.dom)}}),l.prototype.destroy=function(){this.dom[n]&&(this.isTextElement||(this.dom.removeEventListener("input",this._onInput),this.dom.removeEventListener("paste",this._onPaste),this._hidden&&(this.dom.name=this._hidden.name,this._hidden.remove()),this.dom.type="number",this.dom.removeAttribute("inputmode")),S(this.dom,"ln-number:destroyed",{target:this.dom}),delete this.dom[n])};function d(){new MutationObserver(function(){const t=document.querySelectorAll("["+e+"]");for(let i=0;i<t.length;i++){const r=t[i][n];r&&(r.isTextElement?r._formatTextContent():isNaN(r.value)||r._displayFormatted(r.value))}}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})}W(e,n,l,"ln-number",{extraAttributes:["data-ln-value","data-ln-number-decimals","data-ln-number-min","data-ln-number-max","lang"],onAttributeChange:function(t){const i=t[n];i&&(i.isTextElement?i._initTextElement():isNaN(i.value)||i._displayFormatted(i.value))}}),d()})()})();
|