@jinntec/fore 3.1.2 → 3.2.1
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/dist/fore-dev.js +261 -13
- package/dist/fore.js +31 -13
- package/index.js +1 -0
- package/package.json +1 -1
- package/src/fore.js +1 -0
- package/src/fx-fore.js +21 -10
- package/src/ui/fx-case.js +7 -0
- package/src/ui/fx-include.js +296 -0
package/dist/fore-dev.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Version: 3.1
|
|
1
|
+
/* Version: 3.2.1 - June 12, 2026 14:10:39 */
|
|
2
2
|
function t$2(t, s, r, i) {
|
|
3
3
|
const n = {
|
|
4
4
|
op: s,
|
|
@@ -20124,7 +20124,7 @@ class Fore {
|
|
|
20124
20124
|
return Fore.ACTION_ELEMENTS.includes(elementName);
|
|
20125
20125
|
}
|
|
20126
20126
|
static get UI_ELEMENTS() {
|
|
20127
|
-
return new Set(['FX-ALERT', 'FX-CONTROL', 'FX-DIALOG', 'FX-FILENAME', 'FX-MEDIATYPE', 'FX-GROUP', 'FX-HINT', 'FX-ITEMS', 'FX-OUTPUT', 'FX-RANGE', 'FX-REPEAT', 'FX-REPEATITEM', 'FX-REPEAT-ATTRIBUTES', 'FX-SWITCH', 'FX-SECRET', 'FX-SELECT', 'FX-SUBMIT', 'FX-TEXTAREA', 'FX-TRIGGER', 'FX-UPLOAD', 'FX-VAR']);
|
|
20127
|
+
return new Set(['FX-ALERT', 'FX-CONTROL', 'FX-DIALOG', 'FX-FILENAME', 'FX-MEDIATYPE', 'FX-GROUP', 'FX-HINT', 'FX-ITEMS', 'FX-INCLUDE', 'FX-OUTPUT', 'FX-RANGE', 'FX-REPEAT', 'FX-REPEATITEM', 'FX-REPEAT-ATTRIBUTES', 'FX-SWITCH', 'FX-SECRET', 'FX-SELECT', 'FX-SUBMIT', 'FX-TEXTAREA', 'FX-TRIGGER', 'FX-UPLOAD', 'FX-VAR']);
|
|
20128
20128
|
}
|
|
20129
20129
|
|
|
20130
20130
|
/**
|
|
@@ -25479,7 +25479,7 @@ class FxFore extends HTMLElement {
|
|
|
25479
25479
|
this._createRepeatsFromAttributes();
|
|
25480
25480
|
this.inited = true;
|
|
25481
25481
|
};
|
|
25482
|
-
this.version = 'Version: 3.1
|
|
25482
|
+
this.version = 'Version: 3.2.1 - built on June 12, 2026 14:10:39';
|
|
25483
25483
|
|
|
25484
25484
|
/**
|
|
25485
25485
|
* @type {import('./fx-model.js').FxModel}
|
|
@@ -25708,10 +25708,21 @@ class FxFore extends HTMLElement {
|
|
|
25708
25708
|
}
|
|
25709
25709
|
return null;
|
|
25710
25710
|
}
|
|
25711
|
-
_isReadyTarget(el) {
|
|
25711
|
+
static _isReadyTarget(el) {
|
|
25712
25712
|
return !!(el && (el.ready === true || el.classList && el.classList.contains('fx-ready') || typeof el.hasAttribute === 'function' && el.hasAttribute('ready')));
|
|
25713
25713
|
}
|
|
25714
25714
|
|
|
25715
|
+
/**
|
|
25716
|
+
* Resolves once `fore` has dispatched its initial `ready` event (or
|
|
25717
|
+
* immediately, if it's already ready).
|
|
25718
|
+
*/
|
|
25719
|
+
static waitUntilReady(fore) {
|
|
25720
|
+
if (FxFore._isReadyTarget(fore)) {
|
|
25721
|
+
return Promise.resolve();
|
|
25722
|
+
}
|
|
25723
|
+
return FxFore._waitForEvent(fore, 'ready', FxFore._isReadyTarget);
|
|
25724
|
+
}
|
|
25725
|
+
|
|
25715
25726
|
/**
|
|
25716
25727
|
* Collect all init gates derived from attributes.
|
|
25717
25728
|
*
|
|
@@ -25748,7 +25759,7 @@ class FxFore extends HTMLElement {
|
|
|
25748
25759
|
}
|
|
25749
25760
|
return gates;
|
|
25750
25761
|
}
|
|
25751
|
-
_waitForEvent(target, eventName, isSatisfiedFn = null) {
|
|
25762
|
+
static _waitForEvent(target, eventName, isSatisfiedFn = null) {
|
|
25752
25763
|
// If a caller provides an explicit satisfaction check, honor it first.
|
|
25753
25764
|
if (typeof isSatisfiedFn === 'function' && isSatisfiedFn(target)) {
|
|
25754
25765
|
FxFore._markInitEventSeen(target, eventName);
|
|
@@ -25812,19 +25823,19 @@ class FxFore extends HTMLElement {
|
|
|
25812
25823
|
}) {
|
|
25813
25824
|
// Direct targets
|
|
25814
25825
|
if (targetSpec === 'self') {
|
|
25815
|
-
const satisfied = event === 'ready' ? t =>
|
|
25816
|
-
return
|
|
25826
|
+
const satisfied = event === 'ready' ? t => FxFore._isReadyTarget(t) : null;
|
|
25827
|
+
return FxFore._waitForEvent(this, event, satisfied);
|
|
25817
25828
|
}
|
|
25818
25829
|
if (targetSpec === 'document') {
|
|
25819
|
-
return
|
|
25830
|
+
return FxFore._waitForEvent(document, event);
|
|
25820
25831
|
}
|
|
25821
25832
|
if (targetSpec === 'window') {
|
|
25822
|
-
return
|
|
25833
|
+
return FxFore._waitForEvent(window, event);
|
|
25823
25834
|
}
|
|
25824
25835
|
|
|
25825
25836
|
// Special: closest fx-fore
|
|
25826
25837
|
if (targetSpec === 'closest') {
|
|
25827
|
-
const recheckFn = event === 'ready' ? () =>
|
|
25838
|
+
const recheckFn = event === 'ready' ? () => FxFore._isReadyTarget(this.closest('fx-fore')) : null;
|
|
25828
25839
|
const matchesFn = ev => {
|
|
25829
25840
|
const t = ev.target;
|
|
25830
25841
|
return t?.tagName === 'FX-FORE' && t.contains(this);
|
|
@@ -25834,7 +25845,7 @@ class FxFore extends HTMLElement {
|
|
|
25834
25845
|
|
|
25835
25846
|
// Selector targets
|
|
25836
25847
|
const selector = targetSpec;
|
|
25837
|
-
const recheckFn = event === 'ready' ? () =>
|
|
25848
|
+
const recheckFn = event === 'ready' ? () => FxFore._isReadyTarget(this._findBySelector(selector)) : null;
|
|
25838
25849
|
if (typeof recheckFn === 'function' && recheckFn()) {
|
|
25839
25850
|
return Promise.resolve();
|
|
25840
25851
|
}
|
|
@@ -26929,7 +26940,7 @@ class FxFore extends HTMLElement {
|
|
|
26929
26940
|
bound.evalInContext();
|
|
26930
26941
|
if (bound.nodeName !== 'FX-REPEAT') {
|
|
26931
26942
|
// Do not try to get a bind for a nodeSET of a repeat. there are multiple.
|
|
26932
|
-
bound.getModelItem()
|
|
26943
|
+
bound.getModelItem()?.bind?.evalInContext();
|
|
26933
26944
|
}
|
|
26934
26945
|
continue;
|
|
26935
26946
|
}
|
|
@@ -26978,7 +26989,7 @@ class FxFore extends HTMLElement {
|
|
|
26978
26989
|
}
|
|
26979
26990
|
}
|
|
26980
26991
|
bound.evalInContext();
|
|
26981
|
-
bound.getModelItem()
|
|
26992
|
+
bound.getModelItem()?.bind?.evalInContext();
|
|
26982
26993
|
if (!isResolvedBound(bound)) {
|
|
26983
26994
|
console.warn('create-nodes: could not resolve bound after node creation, skipping', bound);
|
|
26984
26995
|
continue;
|
|
@@ -29635,6 +29646,236 @@ if (!customElements.get('fx-hint')) {
|
|
|
29635
29646
|
customElements.define('fx-hint', FxHint);
|
|
29636
29647
|
}
|
|
29637
29648
|
|
|
29649
|
+
/**
|
|
29650
|
+
* <fx-include>
|
|
29651
|
+
*
|
|
29652
|
+
* Lazy light-DOM include component.
|
|
29653
|
+
*
|
|
29654
|
+
* Loads markup either from:
|
|
29655
|
+
* - a direct child <template>
|
|
29656
|
+
* - an external HTML document via @src
|
|
29657
|
+
*
|
|
29658
|
+
* Default behavior:
|
|
29659
|
+
* - listens for an event
|
|
29660
|
+
* - includes content once
|
|
29661
|
+
* - removes the event listener afterwards
|
|
29662
|
+
*
|
|
29663
|
+
* With @reload:
|
|
29664
|
+
* - listens repeatedly
|
|
29665
|
+
* - clears previously included content
|
|
29666
|
+
* - includes fresh content again
|
|
29667
|
+
*
|
|
29668
|
+
* Attributes:
|
|
29669
|
+
* event Event name to listen for. Defaults to "click".
|
|
29670
|
+
* target CSS selector for the event target. Defaults to "self".
|
|
29671
|
+
* Special values: self, document, window.
|
|
29672
|
+
* src Optional external HTML source.
|
|
29673
|
+
* selector Optional selector inside external HTML.
|
|
29674
|
+
* replace Replace <fx-include> with the included content.
|
|
29675
|
+
* immediate Include immediately when connected.
|
|
29676
|
+
* reload Re-include on every matching event.
|
|
29677
|
+
*/
|
|
29678
|
+
class FxInclude extends HTMLElement {
|
|
29679
|
+
constructor() {
|
|
29680
|
+
super();
|
|
29681
|
+
this._listener = this._handleEvent.bind(this);
|
|
29682
|
+
this._eventTarget = null;
|
|
29683
|
+
this._loaded = false;
|
|
29684
|
+
this._replaced = false;
|
|
29685
|
+
}
|
|
29686
|
+
connectedCallback() {
|
|
29687
|
+
this.eventName = this.getAttribute('event') || 'click';
|
|
29688
|
+
this.targetSelector = this.getAttribute('target') || 'self';
|
|
29689
|
+
this.src = this.getAttribute('src');
|
|
29690
|
+
this.selector = this.getAttribute('selector');
|
|
29691
|
+
this.replace = this.hasAttribute('replace');
|
|
29692
|
+
this.immediate = this.hasAttribute('immediate');
|
|
29693
|
+
this.reload = this.hasAttribute('reload');
|
|
29694
|
+
if (this.immediate) {
|
|
29695
|
+
this._includeWhenReady();
|
|
29696
|
+
return;
|
|
29697
|
+
}
|
|
29698
|
+
this._bindListener();
|
|
29699
|
+
}
|
|
29700
|
+
|
|
29701
|
+
/**
|
|
29702
|
+
* Includes content immediately, but waits until the closest `fx-fore` has
|
|
29703
|
+
* finished its initial Rebuild/Recalculate/Revalidate/Refresh cycle (i.e. is
|
|
29704
|
+
* "ready"), so the included content can resolve binding context against an
|
|
29705
|
+
* already-initialized ancestor chain.
|
|
29706
|
+
*/
|
|
29707
|
+
_includeWhenReady() {
|
|
29708
|
+
const fore = this.closest('fx-fore');
|
|
29709
|
+
if (!fore) {
|
|
29710
|
+
queueMicrotask(() => this.include());
|
|
29711
|
+
return;
|
|
29712
|
+
}
|
|
29713
|
+
FxFore.waitUntilReady(fore).then(() => this.include());
|
|
29714
|
+
}
|
|
29715
|
+
disconnectedCallback() {
|
|
29716
|
+
this._unbindListener();
|
|
29717
|
+
}
|
|
29718
|
+
_bindListener() {
|
|
29719
|
+
const target = this._resolveEventTarget();
|
|
29720
|
+
if (!target) {
|
|
29721
|
+
this._dispatchError(`fx-include: event target not found: '${this.targetSelector}'`);
|
|
29722
|
+
return;
|
|
29723
|
+
}
|
|
29724
|
+
target.addEventListener(this.eventName, this._listener);
|
|
29725
|
+
this._eventTarget = target;
|
|
29726
|
+
}
|
|
29727
|
+
_unbindListener() {
|
|
29728
|
+
if (this._eventTarget && this._listener) {
|
|
29729
|
+
this._eventTarget.removeEventListener(this.eventName, this._listener);
|
|
29730
|
+
}
|
|
29731
|
+
this._eventTarget = null;
|
|
29732
|
+
}
|
|
29733
|
+
_resolveEventTarget() {
|
|
29734
|
+
if (!this.targetSelector || this.targetSelector === 'self') {
|
|
29735
|
+
return this;
|
|
29736
|
+
}
|
|
29737
|
+
if (this.targetSelector === 'document') {
|
|
29738
|
+
return document;
|
|
29739
|
+
}
|
|
29740
|
+
if (this.targetSelector === 'window') {
|
|
29741
|
+
return window;
|
|
29742
|
+
}
|
|
29743
|
+
const fore = this.closest('fx-fore');
|
|
29744
|
+
return fore?.querySelector(this.targetSelector) || document.querySelector(this.targetSelector);
|
|
29745
|
+
}
|
|
29746
|
+
async _handleEvent(event) {
|
|
29747
|
+
await this.include(event);
|
|
29748
|
+
}
|
|
29749
|
+
async include(triggerEvent = null) {
|
|
29750
|
+
if (this._replaced) {
|
|
29751
|
+
return;
|
|
29752
|
+
}
|
|
29753
|
+
if (this._loaded && !this.reload) {
|
|
29754
|
+
return;
|
|
29755
|
+
}
|
|
29756
|
+
const fragment = this.src ? await this._loadExternalFragment() : this._loadTemplateFragment();
|
|
29757
|
+
if (!fragment) {
|
|
29758
|
+
return;
|
|
29759
|
+
}
|
|
29760
|
+
if (this.replace) {
|
|
29761
|
+
await this._replaceSelf(fragment, triggerEvent);
|
|
29762
|
+
return;
|
|
29763
|
+
}
|
|
29764
|
+
this._clearIncludedContent();
|
|
29765
|
+
const wrapper = document.createElement('span');
|
|
29766
|
+
wrapper.setAttribute('data-fx-include-content', '');
|
|
29767
|
+
wrapper.style.display = 'contents';
|
|
29768
|
+
wrapper.appendChild(fragment);
|
|
29769
|
+
this.appendChild(wrapper);
|
|
29770
|
+
this._loaded = true;
|
|
29771
|
+
await this._initializeInsertedContent(wrapper);
|
|
29772
|
+
await Fore.dispatch(this, 'include-done', {
|
|
29773
|
+
src: this.src || null,
|
|
29774
|
+
included: wrapper,
|
|
29775
|
+
replaced: false,
|
|
29776
|
+
triggerEvent
|
|
29777
|
+
});
|
|
29778
|
+
if (!this.reload) {
|
|
29779
|
+
this._unbindListener();
|
|
29780
|
+
}
|
|
29781
|
+
}
|
|
29782
|
+
_loadTemplateFragment() {
|
|
29783
|
+
const template = this.querySelector(':scope > template');
|
|
29784
|
+
if (!template) {
|
|
29785
|
+
this._dispatchError('fx-include: no src and no direct template child found');
|
|
29786
|
+
return null;
|
|
29787
|
+
}
|
|
29788
|
+
return template.content.cloneNode(true);
|
|
29789
|
+
}
|
|
29790
|
+
async _loadExternalFragment() {
|
|
29791
|
+
const html = await Fore.loadHtml(this.src);
|
|
29792
|
+
if (!html) {
|
|
29793
|
+
this._dispatchError(`fx-include: failed to load '${this.src}'`);
|
|
29794
|
+
return null;
|
|
29795
|
+
}
|
|
29796
|
+
const parsed = new DOMParser().parseFromString(html, 'text/html');
|
|
29797
|
+
if (this.selector) {
|
|
29798
|
+
const selected = parsed.querySelector(this.selector);
|
|
29799
|
+
if (!selected) {
|
|
29800
|
+
this._dispatchError(`fx-include: selector '${this.selector}' not found in '${this.src}'`);
|
|
29801
|
+
return null;
|
|
29802
|
+
}
|
|
29803
|
+
const fragment = document.createDocumentFragment();
|
|
29804
|
+
fragment.appendChild(document.importNode(selected, true));
|
|
29805
|
+
return fragment;
|
|
29806
|
+
}
|
|
29807
|
+
const template = parsed.body.querySelector(':scope > template');
|
|
29808
|
+
if (template) {
|
|
29809
|
+
return document.importNode(template.content, true);
|
|
29810
|
+
}
|
|
29811
|
+
const rootElements = Array.from(parsed.body.children);
|
|
29812
|
+
if (rootElements.length === 1) {
|
|
29813
|
+
const fragment = document.createDocumentFragment();
|
|
29814
|
+
fragment.appendChild(document.importNode(rootElements[0], true));
|
|
29815
|
+
return fragment;
|
|
29816
|
+
}
|
|
29817
|
+
const fragment = document.createDocumentFragment();
|
|
29818
|
+
Array.from(parsed.body.childNodes).forEach(node => {
|
|
29819
|
+
fragment.appendChild(document.importNode(node, true));
|
|
29820
|
+
});
|
|
29821
|
+
return fragment;
|
|
29822
|
+
}
|
|
29823
|
+
async _replaceSelf(fragment, triggerEvent) {
|
|
29824
|
+
const parent = this.parentNode;
|
|
29825
|
+
if (!parent) {
|
|
29826
|
+
return;
|
|
29827
|
+
}
|
|
29828
|
+
const wrapper = document.createElement('span');
|
|
29829
|
+
wrapper.setAttribute('data-fx-include-replacement', '');
|
|
29830
|
+
wrapper.style.display = 'contents';
|
|
29831
|
+
wrapper.appendChild(fragment);
|
|
29832
|
+
this._unbindListener();
|
|
29833
|
+
this.replaceWith(wrapper);
|
|
29834
|
+
this._replaced = true;
|
|
29835
|
+
this._loaded = true;
|
|
29836
|
+
await this._initializeInsertedContent(wrapper);
|
|
29837
|
+
await Fore.dispatch(wrapper, 'include-done', {
|
|
29838
|
+
src: this.src || null,
|
|
29839
|
+
included: wrapper,
|
|
29840
|
+
replaced: true,
|
|
29841
|
+
triggerEvent
|
|
29842
|
+
});
|
|
29843
|
+
}
|
|
29844
|
+
_clearIncludedContent() {
|
|
29845
|
+
this.querySelectorAll(':scope > [data-fx-include-content]').forEach(node => {
|
|
29846
|
+
node.remove();
|
|
29847
|
+
});
|
|
29848
|
+
}
|
|
29849
|
+
async _initializeInsertedContent(startElement) {
|
|
29850
|
+
this._initForeUiDescendants(startElement);
|
|
29851
|
+
const fore = startElement.closest('fx-fore');
|
|
29852
|
+
if (fore?.createNodes && typeof fore.initData === 'function') {
|
|
29853
|
+
fore.initData(startElement);
|
|
29854
|
+
}
|
|
29855
|
+
await Fore.refreshChildren(startElement, true);
|
|
29856
|
+
}
|
|
29857
|
+
_initForeUiDescendants(startElement) {
|
|
29858
|
+
Array.from(startElement.children || []).forEach(element => {
|
|
29859
|
+
if (element.nodeName.toUpperCase() === 'FX-FORE') {
|
|
29860
|
+
return;
|
|
29861
|
+
}
|
|
29862
|
+
if (Fore.isUiElement(element.nodeName) && typeof element.init === 'function') {
|
|
29863
|
+
element.init();
|
|
29864
|
+
}
|
|
29865
|
+
this._initForeUiDescendants(element);
|
|
29866
|
+
});
|
|
29867
|
+
}
|
|
29868
|
+
_dispatchError(message) {
|
|
29869
|
+
Fore.dispatch(this, 'error', {
|
|
29870
|
+
level: 'Error',
|
|
29871
|
+
message
|
|
29872
|
+
});
|
|
29873
|
+
}
|
|
29874
|
+
}
|
|
29875
|
+
if (!customElements.get('fx-include')) {
|
|
29876
|
+
customElements.define('fx-include', FxInclude);
|
|
29877
|
+
}
|
|
29878
|
+
|
|
29638
29879
|
/**
|
|
29639
29880
|
* todo: review placing of value. should probably work with value attribute and not allow slotted content.
|
|
29640
29881
|
*/
|
|
@@ -31153,6 +31394,13 @@ class FxCase extends FxContainer {
|
|
|
31153
31394
|
}
|
|
31154
31395
|
await parentNode.replaceCase(this, replacement);
|
|
31155
31396
|
target = replacement;
|
|
31397
|
+
// Re-dispatch 'select' on the loaded replacement so its fx-action handlers fire.
|
|
31398
|
+
// The replacement's handlers are registered after async loading; they miss the
|
|
31399
|
+
// initial 'select' that triggered the load.
|
|
31400
|
+
if (parentNode.selectedCase === replacement) {
|
|
31401
|
+
await Fore.dispatch(replacement, 'select', {});
|
|
31402
|
+
return;
|
|
31403
|
+
}
|
|
31156
31404
|
}
|
|
31157
31405
|
ownerForm.getModel();
|
|
31158
31406
|
ownerForm.addToBatchedNotifications(target);
|
package/dist/fore.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Version: 3.1
|
|
1
|
+
/* Version: 3.2.1 - June 12, 2026 14:10:38 */
|
|
2
2
|
function t$2(t, s, r, i) {
|
|
3
3
|
const n = {
|
|
4
4
|
op: s,
|
|
@@ -20121,7 +20121,7 @@ class Fore {
|
|
|
20121
20121
|
return Fore.ACTION_ELEMENTS.includes(elementName);
|
|
20122
20122
|
}
|
|
20123
20123
|
static get UI_ELEMENTS() {
|
|
20124
|
-
return new Set(['FX-ALERT', 'FX-CONTROL', 'FX-DIALOG', 'FX-FILENAME', 'FX-MEDIATYPE', 'FX-GROUP', 'FX-HINT', 'FX-ITEMS', 'FX-OUTPUT', 'FX-RANGE', 'FX-REPEAT', 'FX-REPEATITEM', 'FX-REPEAT-ATTRIBUTES', 'FX-SWITCH', 'FX-SECRET', 'FX-SELECT', 'FX-SUBMIT', 'FX-TEXTAREA', 'FX-TRIGGER', 'FX-UPLOAD', 'FX-VAR']);
|
|
20124
|
+
return new Set(['FX-ALERT', 'FX-CONTROL', 'FX-DIALOG', 'FX-FILENAME', 'FX-MEDIATYPE', 'FX-GROUP', 'FX-HINT', 'FX-ITEMS', 'FX-INCLUDE', 'FX-OUTPUT', 'FX-RANGE', 'FX-REPEAT', 'FX-REPEATITEM', 'FX-REPEAT-ATTRIBUTES', 'FX-SWITCH', 'FX-SECRET', 'FX-SELECT', 'FX-SUBMIT', 'FX-TEXTAREA', 'FX-TRIGGER', 'FX-UPLOAD', 'FX-VAR']);
|
|
20125
20125
|
}
|
|
20126
20126
|
|
|
20127
20127
|
/**
|
|
@@ -25425,7 +25425,7 @@ class FxFore extends HTMLElement {
|
|
|
25425
25425
|
this._createRepeatsFromAttributes();
|
|
25426
25426
|
this.inited = true;
|
|
25427
25427
|
};
|
|
25428
|
-
this.version = 'Version: 3.1
|
|
25428
|
+
this.version = 'Version: 3.2.1 - built on June 12, 2026 14:10:38';
|
|
25429
25429
|
|
|
25430
25430
|
/**
|
|
25431
25431
|
* @type {import('./fx-model.js').FxModel}
|
|
@@ -25653,10 +25653,21 @@ class FxFore extends HTMLElement {
|
|
|
25653
25653
|
}
|
|
25654
25654
|
return null;
|
|
25655
25655
|
}
|
|
25656
|
-
_isReadyTarget(el) {
|
|
25656
|
+
static _isReadyTarget(el) {
|
|
25657
25657
|
return !!(el && (el.ready === true || el.classList && el.classList.contains('fx-ready') || typeof el.hasAttribute === 'function' && el.hasAttribute('ready')));
|
|
25658
25658
|
}
|
|
25659
25659
|
|
|
25660
|
+
/**
|
|
25661
|
+
* Resolves once `fore` has dispatched its initial `ready` event (or
|
|
25662
|
+
* immediately, if it's already ready).
|
|
25663
|
+
*/
|
|
25664
|
+
static waitUntilReady(fore) {
|
|
25665
|
+
if (FxFore._isReadyTarget(fore)) {
|
|
25666
|
+
return Promise.resolve();
|
|
25667
|
+
}
|
|
25668
|
+
return FxFore._waitForEvent(fore, 'ready', FxFore._isReadyTarget);
|
|
25669
|
+
}
|
|
25670
|
+
|
|
25660
25671
|
/**
|
|
25661
25672
|
* Collect all init gates derived from attributes.
|
|
25662
25673
|
*
|
|
@@ -25692,7 +25703,7 @@ class FxFore extends HTMLElement {
|
|
|
25692
25703
|
}
|
|
25693
25704
|
return gates;
|
|
25694
25705
|
}
|
|
25695
|
-
_waitForEvent(target, eventName, isSatisfiedFn = null) {
|
|
25706
|
+
static _waitForEvent(target, eventName, isSatisfiedFn = null) {
|
|
25696
25707
|
// If a caller provides an explicit satisfaction check, honor it first.
|
|
25697
25708
|
if (typeof isSatisfiedFn === 'function' && isSatisfiedFn(target)) {
|
|
25698
25709
|
FxFore._markInitEventSeen(target, eventName);
|
|
@@ -25756,19 +25767,19 @@ class FxFore extends HTMLElement {
|
|
|
25756
25767
|
}) {
|
|
25757
25768
|
// Direct targets
|
|
25758
25769
|
if (targetSpec === 'self') {
|
|
25759
|
-
const satisfied = event === 'ready' ? t =>
|
|
25760
|
-
return
|
|
25770
|
+
const satisfied = event === 'ready' ? t => FxFore._isReadyTarget(t) : null;
|
|
25771
|
+
return FxFore._waitForEvent(this, event, satisfied);
|
|
25761
25772
|
}
|
|
25762
25773
|
if (targetSpec === 'document') {
|
|
25763
|
-
return
|
|
25774
|
+
return FxFore._waitForEvent(document, event);
|
|
25764
25775
|
}
|
|
25765
25776
|
if (targetSpec === 'window') {
|
|
25766
|
-
return
|
|
25777
|
+
return FxFore._waitForEvent(window, event);
|
|
25767
25778
|
}
|
|
25768
25779
|
|
|
25769
25780
|
// Special: closest fx-fore
|
|
25770
25781
|
if (targetSpec === 'closest') {
|
|
25771
|
-
const recheckFn = event === 'ready' ? () =>
|
|
25782
|
+
const recheckFn = event === 'ready' ? () => FxFore._isReadyTarget(this.closest('fx-fore')) : null;
|
|
25772
25783
|
const matchesFn = ev => {
|
|
25773
25784
|
const t = ev.target;
|
|
25774
25785
|
return t?.tagName === 'FX-FORE' && t.contains(this);
|
|
@@ -25778,7 +25789,7 @@ class FxFore extends HTMLElement {
|
|
|
25778
25789
|
|
|
25779
25790
|
// Selector targets
|
|
25780
25791
|
const selector = targetSpec;
|
|
25781
|
-
const recheckFn = event === 'ready' ? () =>
|
|
25792
|
+
const recheckFn = event === 'ready' ? () => FxFore._isReadyTarget(this._findBySelector(selector)) : null;
|
|
25782
25793
|
if (typeof recheckFn === 'function' && recheckFn()) {
|
|
25783
25794
|
return Promise.resolve();
|
|
25784
25795
|
}
|
|
@@ -26859,7 +26870,7 @@ class FxFore extends HTMLElement {
|
|
|
26859
26870
|
bound.evalInContext();
|
|
26860
26871
|
if (bound.nodeName !== 'FX-REPEAT') {
|
|
26861
26872
|
// Do not try to get a bind for a nodeSET of a repeat. there are multiple.
|
|
26862
|
-
bound.getModelItem()
|
|
26873
|
+
bound.getModelItem()?.bind?.evalInContext();
|
|
26863
26874
|
}
|
|
26864
26875
|
continue;
|
|
26865
26876
|
}
|
|
@@ -26908,7 +26919,7 @@ class FxFore extends HTMLElement {
|
|
|
26908
26919
|
}
|
|
26909
26920
|
}
|
|
26910
26921
|
bound.evalInContext();
|
|
26911
|
-
bound.getModelItem()
|
|
26922
|
+
bound.getModelItem()?.bind?.evalInContext();
|
|
26912
26923
|
if (!isResolvedBound(bound)) {
|
|
26913
26924
|
continue;
|
|
26914
26925
|
}
|
|
@@ -31053,6 +31064,13 @@ class FxCase extends FxContainer {
|
|
|
31053
31064
|
}
|
|
31054
31065
|
await parentNode.replaceCase(this, replacement);
|
|
31055
31066
|
target = replacement;
|
|
31067
|
+
// Re-dispatch 'select' on the loaded replacement so its fx-action handlers fire.
|
|
31068
|
+
// The replacement's handlers are registered after async loading; they miss the
|
|
31069
|
+
// initial 'select' that triggered the load.
|
|
31070
|
+
if (parentNode.selectedCase === replacement) {
|
|
31071
|
+
await Fore.dispatch(replacement, 'select', {});
|
|
31072
|
+
return;
|
|
31073
|
+
}
|
|
31056
31074
|
}
|
|
31057
31075
|
ownerForm.getModel();
|
|
31058
31076
|
ownerForm.addToBatchedNotifications(target);
|
package/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import './src/ui/fx-control.js';
|
|
|
14
14
|
import './src/ui/fx-container.js';
|
|
15
15
|
import './src/ui/fx-group.js';
|
|
16
16
|
import './src/ui/fx-hint.js';
|
|
17
|
+
import './src/ui/fx-include.js';
|
|
17
18
|
import './src/ui/fx-output.js';
|
|
18
19
|
import './src/ui/fx-repeat.js';
|
|
19
20
|
import './src/ui/fx-repeat-attributes.js';
|
package/package.json
CHANGED
package/src/fore.js
CHANGED
package/src/fx-fore.js
CHANGED
|
@@ -387,7 +387,7 @@ export class FxFore extends HTMLElement {
|
|
|
387
387
|
return null;
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
-
_isReadyTarget(el) {
|
|
390
|
+
static _isReadyTarget(el) {
|
|
391
391
|
return !!(
|
|
392
392
|
el &&
|
|
393
393
|
(el.ready === true ||
|
|
@@ -396,6 +396,17 @@ export class FxFore extends HTMLElement {
|
|
|
396
396
|
);
|
|
397
397
|
}
|
|
398
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Resolves once `fore` has dispatched its initial `ready` event (or
|
|
401
|
+
* immediately, if it's already ready).
|
|
402
|
+
*/
|
|
403
|
+
static waitUntilReady(fore) {
|
|
404
|
+
if (FxFore._isReadyTarget(fore)) {
|
|
405
|
+
return Promise.resolve();
|
|
406
|
+
}
|
|
407
|
+
return FxFore._waitForEvent(fore, 'ready', FxFore._isReadyTarget);
|
|
408
|
+
}
|
|
409
|
+
|
|
399
410
|
/**
|
|
400
411
|
* Collect all init gates derived from attributes.
|
|
401
412
|
*
|
|
@@ -433,7 +444,7 @@ export class FxFore extends HTMLElement {
|
|
|
433
444
|
return gates;
|
|
434
445
|
}
|
|
435
446
|
|
|
436
|
-
_waitForEvent(target, eventName, isSatisfiedFn = null) {
|
|
447
|
+
static _waitForEvent(target, eventName, isSatisfiedFn = null) {
|
|
437
448
|
// If a caller provides an explicit satisfaction check, honor it first.
|
|
438
449
|
if (typeof isSatisfiedFn === 'function' && isSatisfiedFn(target)) {
|
|
439
450
|
FxFore._markInitEventSeen(target, eventName);
|
|
@@ -495,20 +506,20 @@ export class FxFore extends HTMLElement {
|
|
|
495
506
|
_waitForInitGate({ event, targetSpec }) {
|
|
496
507
|
// Direct targets
|
|
497
508
|
if (targetSpec === 'self') {
|
|
498
|
-
const satisfied = event === 'ready' ? t =>
|
|
499
|
-
return
|
|
509
|
+
const satisfied = event === 'ready' ? t => FxFore._isReadyTarget(t) : null;
|
|
510
|
+
return FxFore._waitForEvent(this, event, satisfied);
|
|
500
511
|
}
|
|
501
512
|
if (targetSpec === 'document') {
|
|
502
|
-
return
|
|
513
|
+
return FxFore._waitForEvent(document, event);
|
|
503
514
|
}
|
|
504
515
|
if (targetSpec === 'window') {
|
|
505
|
-
return
|
|
516
|
+
return FxFore._waitForEvent(window, event);
|
|
506
517
|
}
|
|
507
518
|
|
|
508
519
|
// Special: closest fx-fore
|
|
509
520
|
if (targetSpec === 'closest') {
|
|
510
521
|
const recheckFn =
|
|
511
|
-
event === 'ready' ? () =>
|
|
522
|
+
event === 'ready' ? () => FxFore._isReadyTarget(this.closest('fx-fore')) : null;
|
|
512
523
|
|
|
513
524
|
const matchesFn = ev => {
|
|
514
525
|
const t = ev.target;
|
|
@@ -522,7 +533,7 @@ export class FxFore extends HTMLElement {
|
|
|
522
533
|
const selector = targetSpec;
|
|
523
534
|
|
|
524
535
|
const recheckFn =
|
|
525
|
-
event === 'ready' ? () =>
|
|
536
|
+
event === 'ready' ? () => FxFore._isReadyTarget(this._findBySelector(selector)) : null;
|
|
526
537
|
|
|
527
538
|
if (typeof recheckFn === 'function' && recheckFn()) {
|
|
528
539
|
return Promise.resolve();
|
|
@@ -1819,7 +1830,7 @@ export class FxFore extends HTMLElement {
|
|
|
1819
1830
|
bound.evalInContext();
|
|
1820
1831
|
if (bound.nodeName !== 'FX-REPEAT') {
|
|
1821
1832
|
// Do not try to get a bind for a nodeSET of a repeat. there are multiple.
|
|
1822
|
-
bound.getModelItem()
|
|
1833
|
+
bound.getModelItem()?.bind?.evalInContext();
|
|
1823
1834
|
}
|
|
1824
1835
|
continue;
|
|
1825
1836
|
}
|
|
@@ -1878,7 +1889,7 @@ export class FxFore extends HTMLElement {
|
|
|
1878
1889
|
}
|
|
1879
1890
|
|
|
1880
1891
|
bound.evalInContext();
|
|
1881
|
-
bound.getModelItem()
|
|
1892
|
+
bound.getModelItem()?.bind?.evalInContext();
|
|
1882
1893
|
|
|
1883
1894
|
if (!isResolvedBound(bound)) {
|
|
1884
1895
|
console.warn('create-nodes: could not resolve bound after node creation, skipping', bound);
|
package/src/ui/fx-case.js
CHANGED
|
@@ -81,6 +81,13 @@ export class FxCase extends FxContainer {
|
|
|
81
81
|
}
|
|
82
82
|
await parentNode.replaceCase(this, replacement);
|
|
83
83
|
target = replacement;
|
|
84
|
+
// Re-dispatch 'select' on the loaded replacement so its fx-action handlers fire.
|
|
85
|
+
// The replacement's handlers are registered after async loading; they miss the
|
|
86
|
+
// initial 'select' that triggered the load.
|
|
87
|
+
if (parentNode.selectedCase === replacement) {
|
|
88
|
+
await Fore.dispatch(replacement, 'select', {});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
84
91
|
}
|
|
85
92
|
const model = ownerForm.getModel();
|
|
86
93
|
ownerForm.addToBatchedNotifications(target);
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { Fore } from '../fore.js';
|
|
2
|
+
import { FxFore } from '../fx-fore.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* <fx-include>
|
|
6
|
+
*
|
|
7
|
+
* Lazy light-DOM include component.
|
|
8
|
+
*
|
|
9
|
+
* Loads markup either from:
|
|
10
|
+
* - a direct child <template>
|
|
11
|
+
* - an external HTML document via @src
|
|
12
|
+
*
|
|
13
|
+
* Default behavior:
|
|
14
|
+
* - listens for an event
|
|
15
|
+
* - includes content once
|
|
16
|
+
* - removes the event listener afterwards
|
|
17
|
+
*
|
|
18
|
+
* With @reload:
|
|
19
|
+
* - listens repeatedly
|
|
20
|
+
* - clears previously included content
|
|
21
|
+
* - includes fresh content again
|
|
22
|
+
*
|
|
23
|
+
* Attributes:
|
|
24
|
+
* event Event name to listen for. Defaults to "click".
|
|
25
|
+
* target CSS selector for the event target. Defaults to "self".
|
|
26
|
+
* Special values: self, document, window.
|
|
27
|
+
* src Optional external HTML source.
|
|
28
|
+
* selector Optional selector inside external HTML.
|
|
29
|
+
* replace Replace <fx-include> with the included content.
|
|
30
|
+
* immediate Include immediately when connected.
|
|
31
|
+
* reload Re-include on every matching event.
|
|
32
|
+
*/
|
|
33
|
+
export class FxInclude extends HTMLElement {
|
|
34
|
+
constructor() {
|
|
35
|
+
super();
|
|
36
|
+
|
|
37
|
+
this._listener = this._handleEvent.bind(this);
|
|
38
|
+
this._eventTarget = null;
|
|
39
|
+
this._loaded = false;
|
|
40
|
+
this._replaced = false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
connectedCallback() {
|
|
44
|
+
this.eventName = this.getAttribute('event') || 'click';
|
|
45
|
+
this.targetSelector = this.getAttribute('target') || 'self';
|
|
46
|
+
this.src = this.getAttribute('src');
|
|
47
|
+
this.selector = this.getAttribute('selector');
|
|
48
|
+
|
|
49
|
+
this.replace = this.hasAttribute('replace');
|
|
50
|
+
this.immediate = this.hasAttribute('immediate');
|
|
51
|
+
this.reload = this.hasAttribute('reload');
|
|
52
|
+
|
|
53
|
+
if (this.immediate) {
|
|
54
|
+
this._includeWhenReady();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this._bindListener();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Includes content immediately, but waits until the closest `fx-fore` has
|
|
63
|
+
* finished its initial Rebuild/Recalculate/Revalidate/Refresh cycle (i.e. is
|
|
64
|
+
* "ready"), so the included content can resolve binding context against an
|
|
65
|
+
* already-initialized ancestor chain.
|
|
66
|
+
*/
|
|
67
|
+
_includeWhenReady() {
|
|
68
|
+
const fore = this.closest('fx-fore');
|
|
69
|
+
|
|
70
|
+
if (!fore) {
|
|
71
|
+
queueMicrotask(() => this.include());
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
FxFore.waitUntilReady(fore).then(() => this.include());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
disconnectedCallback() {
|
|
79
|
+
this._unbindListener();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_bindListener() {
|
|
83
|
+
const target = this._resolveEventTarget();
|
|
84
|
+
|
|
85
|
+
if (!target) {
|
|
86
|
+
this._dispatchError(`fx-include: event target not found: '${this.targetSelector}'`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
target.addEventListener(this.eventName, this._listener);
|
|
91
|
+
this._eventTarget = target;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
_unbindListener() {
|
|
95
|
+
if (this._eventTarget && this._listener) {
|
|
96
|
+
this._eventTarget.removeEventListener(this.eventName, this._listener);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this._eventTarget = null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
_resolveEventTarget() {
|
|
103
|
+
if (!this.targetSelector || this.targetSelector === 'self') {
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (this.targetSelector === 'document') {
|
|
108
|
+
return document;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (this.targetSelector === 'window') {
|
|
112
|
+
return window;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const fore = this.closest('fx-fore');
|
|
116
|
+
|
|
117
|
+
return fore?.querySelector(this.targetSelector) || document.querySelector(this.targetSelector);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async _handleEvent(event) {
|
|
121
|
+
await this.include(event);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async include(triggerEvent = null) {
|
|
125
|
+
if (this._replaced) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (this._loaded && !this.reload) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const fragment = this.src ? await this._loadExternalFragment() : this._loadTemplateFragment();
|
|
134
|
+
|
|
135
|
+
if (!fragment) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (this.replace) {
|
|
140
|
+
await this._replaceSelf(fragment, triggerEvent);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
this._clearIncludedContent();
|
|
145
|
+
|
|
146
|
+
const wrapper = document.createElement('span');
|
|
147
|
+
wrapper.setAttribute('data-fx-include-content', '');
|
|
148
|
+
wrapper.style.display = 'contents';
|
|
149
|
+
wrapper.appendChild(fragment);
|
|
150
|
+
|
|
151
|
+
this.appendChild(wrapper);
|
|
152
|
+
|
|
153
|
+
this._loaded = true;
|
|
154
|
+
|
|
155
|
+
await this._initializeInsertedContent(wrapper);
|
|
156
|
+
|
|
157
|
+
await Fore.dispatch(this, 'include-done', {
|
|
158
|
+
src: this.src || null,
|
|
159
|
+
included: wrapper,
|
|
160
|
+
replaced: false,
|
|
161
|
+
triggerEvent,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (!this.reload) {
|
|
165
|
+
this._unbindListener();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
_loadTemplateFragment() {
|
|
170
|
+
const template = this.querySelector(':scope > template');
|
|
171
|
+
|
|
172
|
+
if (!template) {
|
|
173
|
+
this._dispatchError('fx-include: no src and no direct template child found');
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return template.content.cloneNode(true);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async _loadExternalFragment() {
|
|
181
|
+
const html = await Fore.loadHtml(this.src);
|
|
182
|
+
|
|
183
|
+
if (!html) {
|
|
184
|
+
this._dispatchError(`fx-include: failed to load '${this.src}'`);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const parsed = new DOMParser().parseFromString(html, 'text/html');
|
|
189
|
+
|
|
190
|
+
if (this.selector) {
|
|
191
|
+
const selected = parsed.querySelector(this.selector);
|
|
192
|
+
|
|
193
|
+
if (!selected) {
|
|
194
|
+
this._dispatchError(`fx-include: selector '${this.selector}' not found in '${this.src}'`);
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const fragment = document.createDocumentFragment();
|
|
199
|
+
fragment.appendChild(document.importNode(selected, true));
|
|
200
|
+
return fragment;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const template = parsed.body.querySelector(':scope > template');
|
|
204
|
+
|
|
205
|
+
if (template) {
|
|
206
|
+
return document.importNode(template.content, true);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const rootElements = Array.from(parsed.body.children);
|
|
210
|
+
|
|
211
|
+
if (rootElements.length === 1) {
|
|
212
|
+
const fragment = document.createDocumentFragment();
|
|
213
|
+
fragment.appendChild(document.importNode(rootElements[0], true));
|
|
214
|
+
return fragment;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const fragment = document.createDocumentFragment();
|
|
218
|
+
|
|
219
|
+
Array.from(parsed.body.childNodes).forEach(node => {
|
|
220
|
+
fragment.appendChild(document.importNode(node, true));
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return fragment;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async _replaceSelf(fragment, triggerEvent) {
|
|
227
|
+
const parent = this.parentNode;
|
|
228
|
+
|
|
229
|
+
if (!parent) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const wrapper = document.createElement('span');
|
|
234
|
+
wrapper.setAttribute('data-fx-include-replacement', '');
|
|
235
|
+
wrapper.style.display = 'contents';
|
|
236
|
+
wrapper.appendChild(fragment);
|
|
237
|
+
|
|
238
|
+
this._unbindListener();
|
|
239
|
+
|
|
240
|
+
this.replaceWith(wrapper);
|
|
241
|
+
|
|
242
|
+
this._replaced = true;
|
|
243
|
+
this._loaded = true;
|
|
244
|
+
|
|
245
|
+
await this._initializeInsertedContent(wrapper);
|
|
246
|
+
|
|
247
|
+
await Fore.dispatch(wrapper, 'include-done', {
|
|
248
|
+
src: this.src || null,
|
|
249
|
+
included: wrapper,
|
|
250
|
+
replaced: true,
|
|
251
|
+
triggerEvent,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
_clearIncludedContent() {
|
|
256
|
+
this.querySelectorAll(':scope > [data-fx-include-content]').forEach(node => {
|
|
257
|
+
node.remove();
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async _initializeInsertedContent(startElement) {
|
|
262
|
+
this._initForeUiDescendants(startElement);
|
|
263
|
+
|
|
264
|
+
const fore = startElement.closest('fx-fore');
|
|
265
|
+
if (fore?.createNodes && typeof fore.initData === 'function') {
|
|
266
|
+
fore.initData(startElement);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
await Fore.refreshChildren(startElement, true);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
_initForeUiDescendants(startElement) {
|
|
273
|
+
Array.from(startElement.children || []).forEach(element => {
|
|
274
|
+
if (element.nodeName.toUpperCase() === 'FX-FORE') {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (Fore.isUiElement(element.nodeName) && typeof element.init === 'function') {
|
|
279
|
+
element.init();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
this._initForeUiDescendants(element);
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
_dispatchError(message) {
|
|
287
|
+
Fore.dispatch(this, 'error', {
|
|
288
|
+
level: 'Error',
|
|
289
|
+
message,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (!customElements.get('fx-include')) {
|
|
295
|
+
customElements.define('fx-include', FxInclude);
|
|
296
|
+
}
|