@jqhtml/core 2.3.2 → 2.3.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/dist/boot.d.ts +20 -0
- package/dist/boot.d.ts.map +1 -0
- package/dist/component.d.ts +20 -0
- package/dist/component.d.ts.map +1 -1
- package/dist/debug-entry.d.ts +3 -31
- package/dist/debug-entry.d.ts.map +1 -1
- package/dist/index.cjs +216 -406
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +216 -404
- package/dist/index.js.map +1 -1
- package/dist/jqhtml-core.esm.js +217 -405
- package/dist/jqhtml-core.esm.js.map +1 -1
- package/dist/jqhtml-debug.esm.js +1 -383
- package/dist/jqhtml-debug.esm.js.map +1 -1
- package/package.json +1 -1
- package/dist/debug-overlay.d.ts +0 -61
- package/dist/debug-overlay.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -883,7 +883,7 @@ function devWarn(message) {
|
|
|
883
883
|
console.warn(`[JQHTML Dev Warning] ${message}`);
|
|
884
884
|
}
|
|
885
885
|
// Get global jqhtml object
|
|
886
|
-
function getJqhtml
|
|
886
|
+
function getJqhtml() {
|
|
887
887
|
if (typeof window !== 'undefined' && window.jqhtml) {
|
|
888
888
|
return window.jqhtml;
|
|
889
889
|
}
|
|
@@ -896,7 +896,7 @@ function getJqhtml$1() {
|
|
|
896
896
|
}
|
|
897
897
|
// Visual flash effect
|
|
898
898
|
function flashComponent(component, eventType) {
|
|
899
|
-
const jqhtml = getJqhtml
|
|
899
|
+
const jqhtml = getJqhtml();
|
|
900
900
|
if (!jqhtml?.debug?.flashComponents)
|
|
901
901
|
return;
|
|
902
902
|
const duration = jqhtml.debug.flashDuration || 500;
|
|
@@ -918,7 +918,7 @@ function flashComponent(component, eventType) {
|
|
|
918
918
|
}
|
|
919
919
|
// Log lifecycle event
|
|
920
920
|
function logLifecycle(component, phase, status) {
|
|
921
|
-
const jqhtml = getJqhtml
|
|
921
|
+
const jqhtml = getJqhtml();
|
|
922
922
|
if (!jqhtml?.debug)
|
|
923
923
|
return;
|
|
924
924
|
const shouldLog = jqhtml.debug.logFullLifecycle ||
|
|
@@ -964,7 +964,7 @@ function logLifecycle(component, phase, status) {
|
|
|
964
964
|
}
|
|
965
965
|
// Apply delays based on lifecycle phase
|
|
966
966
|
function applyDebugDelay(phase) {
|
|
967
|
-
const jqhtml = getJqhtml
|
|
967
|
+
const jqhtml = getJqhtml();
|
|
968
968
|
if (!jqhtml?.debug)
|
|
969
969
|
return;
|
|
970
970
|
let delayMs = 0;
|
|
@@ -985,14 +985,14 @@ function applyDebugDelay(phase) {
|
|
|
985
985
|
}
|
|
986
986
|
// Log instruction processing
|
|
987
987
|
function logInstruction(type, data) {
|
|
988
|
-
const jqhtml = getJqhtml
|
|
988
|
+
const jqhtml = getJqhtml();
|
|
989
989
|
if (!jqhtml?.debug?.logInstructionProcessing)
|
|
990
990
|
return;
|
|
991
991
|
console.log(`[JQHTML Instruction] ${type}:`, data);
|
|
992
992
|
}
|
|
993
993
|
// Log data changes
|
|
994
994
|
function logDataChange(component, property, oldValue, newValue) {
|
|
995
|
-
const jqhtml = getJqhtml
|
|
995
|
+
const jqhtml = getJqhtml();
|
|
996
996
|
if (!jqhtml?.debug?.traceDataFlow)
|
|
997
997
|
return;
|
|
998
998
|
console.log(`[JQHTML Data] ${component.constructor.name}#${component._cid}.data.${property}:`, { old: oldValue, new: newValue });
|
|
@@ -1005,7 +1005,7 @@ function updateComponentTree() {
|
|
|
1005
1005
|
}
|
|
1006
1006
|
// Router dispatch logging
|
|
1007
1007
|
function logDispatch(url, route, params, verbose = false) {
|
|
1008
|
-
const jqhtml = getJqhtml
|
|
1008
|
+
const jqhtml = getJqhtml();
|
|
1009
1009
|
if (!jqhtml?.debug)
|
|
1010
1010
|
return;
|
|
1011
1011
|
const shouldLog = jqhtml.debug.logDispatch || jqhtml.debug.logDispatchVerbose;
|
|
@@ -1027,12 +1027,12 @@ function logDispatch(url, route, params, verbose = false) {
|
|
|
1027
1027
|
}
|
|
1028
1028
|
// Check if sequential processing is enabled
|
|
1029
1029
|
function isSequentialProcessing() {
|
|
1030
|
-
const jqhtml = getJqhtml
|
|
1030
|
+
const jqhtml = getJqhtml();
|
|
1031
1031
|
return jqhtml?.debug?.sequentialProcessing || false;
|
|
1032
1032
|
}
|
|
1033
1033
|
// Error handling with break on error
|
|
1034
1034
|
function handleComponentError(component, phase, error) {
|
|
1035
|
-
const jqhtml = getJqhtml
|
|
1035
|
+
const jqhtml = getJqhtml();
|
|
1036
1036
|
console.error(`[JQHTML Error] ${component.constructor.name}#${component._cid} failed in ${phase}:`, error);
|
|
1037
1037
|
if (jqhtml?.debug?.breakOnError) {
|
|
1038
1038
|
debugger; // This will pause execution in dev tools
|
|
@@ -1060,6 +1060,9 @@ function handleComponentError(component, phase, error) {
|
|
|
1060
1060
|
* - Scoped IDs using _cid pattern
|
|
1061
1061
|
* - Event emission and CSS class hierarchy
|
|
1062
1062
|
*/
|
|
1063
|
+
// WeakMap storage for protected lifecycle method implementations (Option 2)
|
|
1064
|
+
// See docs/internal/lifecycle-method-protection.md for design details
|
|
1065
|
+
const lifecycle_impls = new WeakMap();
|
|
1063
1066
|
class Jqhtml_Component {
|
|
1064
1067
|
constructor(element, args = {}) {
|
|
1065
1068
|
this._ready_state = 0; // 0=created, 1=init, 2=loaded, 3=rendered, 4=ready
|
|
@@ -1080,6 +1083,7 @@ class Jqhtml_Component {
|
|
|
1080
1083
|
this.__initial_data_snapshot = null; // Snapshot of this.data after on_create() for restoration before on_load()
|
|
1081
1084
|
this.__data_frozen = false; // Track if this.data is currently frozen
|
|
1082
1085
|
this.next_reload_force_refresh = null; // State machine for reload()/refresh() debounce precedence
|
|
1086
|
+
this.__lifecycle_authorized = false; // Flag for lifecycle method protection
|
|
1083
1087
|
this._cid = this._generate_cid();
|
|
1084
1088
|
this._lifecycle_manager = LifecycleManager.get_instance();
|
|
1085
1089
|
// Create or wrap element
|
|
@@ -1193,6 +1197,63 @@ class Jqhtml_Component {
|
|
|
1193
1197
|
this.state = {};
|
|
1194
1198
|
this._log_lifecycle('construct', 'complete');
|
|
1195
1199
|
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Protect lifecycle methods from manual invocation
|
|
1202
|
+
* Stores original implementations in WeakMap, replaces with guarded wrappers
|
|
1203
|
+
* @private
|
|
1204
|
+
*/
|
|
1205
|
+
_protect_lifecycle_methods() {
|
|
1206
|
+
const methods = {
|
|
1207
|
+
on_create: 'Called automatically during creation.',
|
|
1208
|
+
on_render: 'Use render() to trigger a re-render.',
|
|
1209
|
+
on_load: 'Use reload() to refresh data.',
|
|
1210
|
+
on_ready: 'Called automatically when ready.',
|
|
1211
|
+
on_stop: 'Use stop() to stop the component.'
|
|
1212
|
+
};
|
|
1213
|
+
const impls = {};
|
|
1214
|
+
const self = this;
|
|
1215
|
+
for (const [name, help] of Object.entries(methods)) {
|
|
1216
|
+
const original = this[name];
|
|
1217
|
+
// Skip if using base class default (empty method)
|
|
1218
|
+
if (original === Jqhtml_Component.prototype[name])
|
|
1219
|
+
continue;
|
|
1220
|
+
impls[name] = original;
|
|
1221
|
+
// Create wrapper with same function name (for stack traces)
|
|
1222
|
+
this[name] = {
|
|
1223
|
+
[name](...args) {
|
|
1224
|
+
if (!self.__lifecycle_authorized) {
|
|
1225
|
+
throw new Error(`[JQHTML] ${name}() cannot be called manually. ${help}\n` +
|
|
1226
|
+
`Component: ${self.component_name()} (_cid: ${self._cid})`);
|
|
1227
|
+
}
|
|
1228
|
+
return lifecycle_impls.get(self)[name].apply(self, args);
|
|
1229
|
+
}
|
|
1230
|
+
}[name];
|
|
1231
|
+
}
|
|
1232
|
+
lifecycle_impls.set(this, impls);
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Call a lifecycle method with authorization (async)
|
|
1236
|
+
* Framework calls this to invoke lifecycle methods, bypassing the protection wrapper.
|
|
1237
|
+
* The flag is set momentarily for the wrapper check, then reset BEFORE user code runs.
|
|
1238
|
+
* This ensures any nested lifecycle calls from user code will fail the flag check.
|
|
1239
|
+
* @private
|
|
1240
|
+
*/
|
|
1241
|
+
async _call_lifecycle(name, context) {
|
|
1242
|
+
// Get the original implementation (bypasses wrapper entirely)
|
|
1243
|
+
const impl = lifecycle_impls.get(this)?.[name] || this[name];
|
|
1244
|
+
// Call original directly - no flag needed since we bypass the wrapper
|
|
1245
|
+
return await impl.call(context || this);
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* Call a lifecycle method with authorization (sync version for sync methods like on_stop)
|
|
1249
|
+
* @private
|
|
1250
|
+
*/
|
|
1251
|
+
_call_lifecycle_sync(name) {
|
|
1252
|
+
// Get the original implementation (bypasses wrapper entirely)
|
|
1253
|
+
const impl = lifecycle_impls.get(this)?.[name] || this[name];
|
|
1254
|
+
// Call original directly - no flag needed since we bypass the wrapper
|
|
1255
|
+
return impl.call(this);
|
|
1256
|
+
}
|
|
1196
1257
|
/**
|
|
1197
1258
|
* Boot - Start the full component lifecycle
|
|
1198
1259
|
* Called immediately after construction by instruction processor
|
|
@@ -1206,6 +1267,8 @@ class Jqhtml_Component {
|
|
|
1206
1267
|
if (this._booted)
|
|
1207
1268
|
return;
|
|
1208
1269
|
this._booted = true;
|
|
1270
|
+
// Protect lifecycle methods from manual invocation (must happen after subclass constructor)
|
|
1271
|
+
this._protect_lifecycle_methods();
|
|
1209
1272
|
await this._lifecycle_manager.boot_component(this);
|
|
1210
1273
|
}
|
|
1211
1274
|
// -------------------------------------------------------------------------
|
|
@@ -1416,9 +1479,9 @@ class Jqhtml_Component {
|
|
|
1416
1479
|
// Don't update ready state here - let phases complete in order
|
|
1417
1480
|
this._update_debug_attrs();
|
|
1418
1481
|
this._log_lifecycle('render', 'complete');
|
|
1419
|
-
// Call on_render() immediately after render completes
|
|
1482
|
+
// Call on_render() with authorization (sync) immediately after render completes
|
|
1420
1483
|
// This ensures event handlers are always re-attached after DOM updates
|
|
1421
|
-
const renderResult = this.on_render
|
|
1484
|
+
const renderResult = this._call_lifecycle_sync('on_render');
|
|
1422
1485
|
if (renderResult && typeof renderResult.then === 'function') {
|
|
1423
1486
|
console.warn(`[JQHTML] Component "${this.component_name()}" returned a Promise from on_render(). ` +
|
|
1424
1487
|
`on_render() must be synchronous code. Remove 'async' from the function declaration.`);
|
|
@@ -1483,8 +1546,8 @@ class Jqhtml_Component {
|
|
|
1483
1546
|
if (this._render_count !== render_id) {
|
|
1484
1547
|
return; // Stale render, don't call on_ready
|
|
1485
1548
|
}
|
|
1486
|
-
// Call on_ready hook
|
|
1487
|
-
await this.on_ready
|
|
1549
|
+
// Call on_ready hook with authorization
|
|
1550
|
+
await this._call_lifecycle('on_ready');
|
|
1488
1551
|
// Trigger ready event
|
|
1489
1552
|
await this.trigger('ready');
|
|
1490
1553
|
})();
|
|
@@ -1504,8 +1567,8 @@ class Jqhtml_Component {
|
|
|
1504
1567
|
if (this._stopped || this._ready_state >= 1)
|
|
1505
1568
|
return;
|
|
1506
1569
|
this._log_lifecycle('create', 'start');
|
|
1507
|
-
// Call on_create() and validate it's synchronous
|
|
1508
|
-
const result = this.on_create
|
|
1570
|
+
// Call on_create() with authorization and validate it's synchronous
|
|
1571
|
+
const result = await this._call_lifecycle('on_create');
|
|
1509
1572
|
if (result && typeof result.then === 'function') {
|
|
1510
1573
|
console.warn(`[JQHTML] Component "${this.component_name()}" returned a Promise from on_create(). ` +
|
|
1511
1574
|
`on_create() must be synchronous code. Remove 'async' from the function declaration.`);
|
|
@@ -1620,8 +1683,8 @@ class Jqhtml_Component {
|
|
|
1620
1683
|
if (window.jqhtml?.debug?.verbose) {
|
|
1621
1684
|
console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - load deduplication and caching disabled`, { uncacheable_property });
|
|
1622
1685
|
}
|
|
1623
|
-
// Execute on_load() without deduplication or caching
|
|
1624
|
-
await this.on_load
|
|
1686
|
+
// Execute on_load() with authorization, without deduplication or caching
|
|
1687
|
+
await this._call_lifecycle('on_load');
|
|
1625
1688
|
this.__data_frozen = true;
|
|
1626
1689
|
return;
|
|
1627
1690
|
}
|
|
@@ -1730,7 +1793,7 @@ class Jqhtml_Component {
|
|
|
1730
1793
|
// - Should errors reset state machine flags (next_reload_force_refresh)?
|
|
1731
1794
|
// - Should partial data be preserved or rolled back?
|
|
1732
1795
|
// - Should followers be notified differently based on error type?
|
|
1733
|
-
await this.on_load
|
|
1796
|
+
await this._call_lifecycle('on_load', restricted_this);
|
|
1734
1797
|
}
|
|
1735
1798
|
catch (error) {
|
|
1736
1799
|
// Handle error and notify coordinator
|
|
@@ -1802,7 +1865,7 @@ class Jqhtml_Component {
|
|
|
1802
1865
|
this._log_lifecycle('ready', 'start');
|
|
1803
1866
|
// Wait for all children to reach ready state (bottom-up execution)
|
|
1804
1867
|
await this._wait_for_children_ready();
|
|
1805
|
-
await this.on_ready
|
|
1868
|
+
await this._call_lifecycle('on_ready');
|
|
1806
1869
|
this._ready_state = 4;
|
|
1807
1870
|
this._update_debug_attrs();
|
|
1808
1871
|
this._log_lifecycle('ready', 'complete');
|
|
@@ -1852,6 +1915,14 @@ class Jqhtml_Component {
|
|
|
1852
1915
|
* @private
|
|
1853
1916
|
*/
|
|
1854
1917
|
async _wait_for_children_ready() {
|
|
1918
|
+
// Server-rendered components (created via jqhtml.boot()) may have children
|
|
1919
|
+
// that were hydrated asynchronously during the 'render' event callback.
|
|
1920
|
+
// Those children couldn't register via _find_dom_parent() because they were
|
|
1921
|
+
// created after the parent's lifecycle started. Force DOM traversal fallback
|
|
1922
|
+
// to reliably discover all children, including boot-hydrated ones.
|
|
1923
|
+
if (this.args._inner_html !== undefined) {
|
|
1924
|
+
this._use_dom_fallback = true;
|
|
1925
|
+
}
|
|
1855
1926
|
const children = this._get_dom_children();
|
|
1856
1927
|
if (children.length === 0) {
|
|
1857
1928
|
return; // No children, nothing to wait for
|
|
@@ -2010,7 +2081,7 @@ class Jqhtml_Component {
|
|
|
2010
2081
|
this.data = JSON.parse(JSON.stringify(this.__initial_data_snapshot));
|
|
2011
2082
|
}
|
|
2012
2083
|
try {
|
|
2013
|
-
await this.on_load
|
|
2084
|
+
await this._call_lifecycle('on_load');
|
|
2014
2085
|
}
|
|
2015
2086
|
finally {
|
|
2016
2087
|
// Freeze this.data after on_load() completes
|
|
@@ -2086,7 +2157,7 @@ class Jqhtml_Component {
|
|
|
2086
2157
|
// STEP 3.5 & 4: Wait for children and call on_ready (only if we rendered)
|
|
2087
2158
|
if (rendered_from_cache || should_render) {
|
|
2088
2159
|
await this._wait_for_children_ready();
|
|
2089
|
-
await this.on_ready
|
|
2160
|
+
await this._call_lifecycle('on_ready');
|
|
2090
2161
|
}
|
|
2091
2162
|
this._log_lifecycle('reload', 'complete');
|
|
2092
2163
|
}
|
|
@@ -2120,16 +2191,14 @@ class Jqhtml_Component {
|
|
|
2120
2191
|
this.$.addClass('_Component_Stopped');
|
|
2121
2192
|
// Unregister from lifecycle manager
|
|
2122
2193
|
this._lifecycle_manager.unregister_component(this);
|
|
2123
|
-
// Call user's on_stop() hook
|
|
2124
|
-
const stopResult = this.on_stop
|
|
2194
|
+
// Call user's on_stop() hook with authorization (sync)
|
|
2195
|
+
const stopResult = this._call_lifecycle_sync('on_stop');
|
|
2125
2196
|
if (stopResult && typeof stopResult.then === 'function') {
|
|
2126
2197
|
console.warn(`[JQHTML] Component "${this.component_name()}" returned a Promise from on_stop(). ` +
|
|
2127
2198
|
`on_stop() must be synchronous code. Remove 'async' from the function declaration.`);
|
|
2128
2199
|
}
|
|
2129
|
-
// Fire registered
|
|
2130
|
-
this.trigger('
|
|
2131
|
-
// Trigger jQuery destroy event
|
|
2132
|
-
this.$.trigger('destroy');
|
|
2200
|
+
// Fire registered stop callbacks
|
|
2201
|
+
this.trigger('stop');
|
|
2133
2202
|
// Remove from DOM parent's children
|
|
2134
2203
|
if (this._dom_parent) {
|
|
2135
2204
|
this._dom_parent._dom_children.delete(this);
|
|
@@ -2958,384 +3027,132 @@ function escape_html(str) {
|
|
|
2958
3027
|
}
|
|
2959
3028
|
|
|
2960
3029
|
/**
|
|
2961
|
-
* JQHTML
|
|
3030
|
+
* JQHTML Boot - Component Hydration System
|
|
3031
|
+
*
|
|
3032
|
+
* Bridges server-rendered HTML and client-side jqhtml components.
|
|
2962
3033
|
*
|
|
2963
|
-
*
|
|
2964
|
-
*
|
|
3034
|
+
* Server output: <div class="_Component_Init" data-component-init-name="User_Card" data-component-args='{"id":1}'></div>
|
|
3035
|
+
* After boot(): <div class="User_Card Component">...rendered template...</div>
|
|
3036
|
+
*
|
|
3037
|
+
* Usage:
|
|
3038
|
+
* await jqhtml.boot(); // Hydrate all placeholders, wait for ready
|
|
3039
|
+
* jqhtml.boot($('#container')); // Hydrate within scope
|
|
2965
3040
|
*/
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
}
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
'Ensure @jqhtml/core is imported and initialized before attempting to use debug features.');
|
|
2987
|
-
}
|
|
2988
|
-
class DebugOverlay {
|
|
2989
|
-
constructor(options = {}) {
|
|
2990
|
-
this.$container = null;
|
|
2991
|
-
this.$statusIndicator = null;
|
|
2992
|
-
this.$ = getJQuery();
|
|
2993
|
-
if (!this.$) {
|
|
2994
|
-
throw new Error('jQuery is required for DebugOverlay');
|
|
2995
|
-
}
|
|
2996
|
-
this.options = {
|
|
2997
|
-
position: 'bottom',
|
|
2998
|
-
theme: 'dark',
|
|
2999
|
-
compact: false,
|
|
3000
|
-
showStatus: true,
|
|
3001
|
-
autoHide: false,
|
|
3002
|
-
...options
|
|
3003
|
-
};
|
|
3004
|
-
}
|
|
3005
|
-
/**
|
|
3006
|
-
* Static method to show debug overlay (singleton pattern)
|
|
3007
|
-
*/
|
|
3008
|
-
static show(options) {
|
|
3009
|
-
if (!DebugOverlay.instance) {
|
|
3010
|
-
DebugOverlay.instance = new DebugOverlay(options);
|
|
3011
|
-
}
|
|
3012
|
-
DebugOverlay.instance.display();
|
|
3013
|
-
return DebugOverlay.instance;
|
|
3014
|
-
}
|
|
3015
|
-
/**
|
|
3016
|
-
* Static method to hide debug overlay
|
|
3017
|
-
*/
|
|
3018
|
-
static hide() {
|
|
3019
|
-
if (DebugOverlay.instance) {
|
|
3020
|
-
DebugOverlay.instance.hide();
|
|
3021
|
-
}
|
|
3022
|
-
}
|
|
3023
|
-
/**
|
|
3024
|
-
* Static method to toggle debug overlay visibility
|
|
3025
|
-
*/
|
|
3026
|
-
static toggle() {
|
|
3027
|
-
if (DebugOverlay.instance && DebugOverlay.instance.$container) {
|
|
3028
|
-
if (DebugOverlay.instance.$container.is(':visible')) {
|
|
3029
|
-
DebugOverlay.hide();
|
|
3030
|
-
}
|
|
3031
|
-
else {
|
|
3032
|
-
DebugOverlay.instance.display();
|
|
3033
|
-
}
|
|
3034
|
-
}
|
|
3035
|
-
else {
|
|
3036
|
-
DebugOverlay.show();
|
|
3037
|
-
}
|
|
3038
|
-
}
|
|
3039
|
-
/**
|
|
3040
|
-
* Static method to destroy debug overlay
|
|
3041
|
-
*/
|
|
3042
|
-
static destroy() {
|
|
3043
|
-
if (DebugOverlay.instance) {
|
|
3044
|
-
DebugOverlay.instance.destroy();
|
|
3045
|
-
DebugOverlay.instance = null;
|
|
3046
|
-
}
|
|
3047
|
-
}
|
|
3048
|
-
/**
|
|
3049
|
-
* Display the debug overlay
|
|
3050
|
-
*/
|
|
3051
|
-
display() {
|
|
3052
|
-
if (this.$container) {
|
|
3053
|
-
this.$container.show();
|
|
3041
|
+
/**
|
|
3042
|
+
* Hydrate all _Component_Init placeholders within a scope.
|
|
3043
|
+
*
|
|
3044
|
+
* @param scope - jQuery object, HTMLElement, or undefined (defaults to body)
|
|
3045
|
+
* @returns Promise that resolves when all components (including nested) are ready
|
|
3046
|
+
*/
|
|
3047
|
+
function boot(scope) {
|
|
3048
|
+
const jQ = typeof jQuery !== 'undefined' ? jQuery : $;
|
|
3049
|
+
if (!scope) {
|
|
3050
|
+
scope = jQ('body');
|
|
3051
|
+
}
|
|
3052
|
+
else if (!(scope instanceof jQ)) {
|
|
3053
|
+
scope = jQ(scope);
|
|
3054
|
+
}
|
|
3055
|
+
const readyPromises = [];
|
|
3056
|
+
// Find top-level placeholders only (skip those nested inside other placeholders)
|
|
3057
|
+
scope.find('._Component_Init').each(function () {
|
|
3058
|
+
const $element = jQ(this);
|
|
3059
|
+
// Skip if removed from DOM
|
|
3060
|
+
if (!document.contains($element[0])) {
|
|
3054
3061
|
return;
|
|
3055
3062
|
}
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
*/
|
|
3064
|
-
hide() {
|
|
3065
|
-
if (this.$container) {
|
|
3066
|
-
this.$container.hide();
|
|
3067
|
-
}
|
|
3068
|
-
if (this.$statusIndicator) {
|
|
3069
|
-
this.$statusIndicator.hide();
|
|
3070
|
-
}
|
|
3071
|
-
}
|
|
3072
|
-
/**
|
|
3073
|
-
* Remove the debug overlay completely
|
|
3074
|
-
*/
|
|
3075
|
-
destroy() {
|
|
3076
|
-
if (this.$container) {
|
|
3077
|
-
this.$container.remove();
|
|
3078
|
-
this.$container = null;
|
|
3079
|
-
}
|
|
3080
|
-
if (this.$statusIndicator) {
|
|
3081
|
-
this.$statusIndicator.remove();
|
|
3082
|
-
this.$statusIndicator = null;
|
|
3063
|
+
// Skip nested placeholders - they'll be hydrated by parent's render callback
|
|
3064
|
+
let parent = $element[0].parentElement;
|
|
3065
|
+
while (parent) {
|
|
3066
|
+
if (parent.classList.contains('_Component_Init')) {
|
|
3067
|
+
return;
|
|
3068
|
+
}
|
|
3069
|
+
parent = parent.parentElement;
|
|
3083
3070
|
}
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
*/
|
|
3088
|
-
updateStatus(mode) {
|
|
3089
|
-
if (!this.$statusIndicator)
|
|
3071
|
+
// Hydrate this placeholder
|
|
3072
|
+
const component = hydrateElement($element);
|
|
3073
|
+
if (!component)
|
|
3090
3074
|
return;
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
createOverlay() {
|
|
3095
|
-
// Add styles first
|
|
3096
|
-
this.addStyles();
|
|
3097
|
-
// Create container using jQuery
|
|
3098
|
-
this.$container = this.$('<div>')
|
|
3099
|
-
.addClass(`jqhtml-debug-overlay ${this.options.theme} ${this.options.position}`);
|
|
3100
|
-
// Create content structure
|
|
3101
|
-
const $content = this.$('<div>').addClass('jqhtml-debug-content');
|
|
3102
|
-
const $controls = this.$('<div>').addClass('jqhtml-debug-controls');
|
|
3103
|
-
// Add title
|
|
3104
|
-
const $title = this.$('<span>')
|
|
3105
|
-
.addClass('jqhtml-debug-title')
|
|
3106
|
-
.html('<strong>🐛 JQHTML Debug:</strong>');
|
|
3107
|
-
$controls.append($title);
|
|
3108
|
-
// Create buttons
|
|
3109
|
-
const buttons = [
|
|
3110
|
-
{ text: 'Slow Motion + Flash', action: 'enableSlowMotionDebug', class: 'success' },
|
|
3111
|
-
{ text: 'Basic Debug', action: 'enableBasicDebug', class: '' },
|
|
3112
|
-
{ text: 'Full Debug', action: 'enableFullDebug', class: '' },
|
|
3113
|
-
{ text: 'Sequential', action: 'enableSequentialMode', class: '' },
|
|
3114
|
-
{ text: 'Clear Debug', action: 'clearAllDebug', class: 'danger' },
|
|
3115
|
-
{ text: 'Settings', action: 'showDebugInfo', class: '' }
|
|
3116
|
-
];
|
|
3117
|
-
buttons.forEach(btn => {
|
|
3118
|
-
const $button = this.$('<button>')
|
|
3119
|
-
.text(btn.text)
|
|
3120
|
-
.addClass('jqhtml-debug-btn' + (btn.class ? ` ${btn.class}` : ''))
|
|
3121
|
-
.on('click', () => this.executeAction(btn.action));
|
|
3122
|
-
$controls.append($button);
|
|
3075
|
+
// On render, recursively hydrate any nested placeholders
|
|
3076
|
+
component.on('render', function () {
|
|
3077
|
+
hydrateNested(component.$, jQ);
|
|
3123
3078
|
});
|
|
3124
|
-
//
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
right: '10px',
|
|
3143
|
-
background: '#2c3e50',
|
|
3144
|
-
color: 'white',
|
|
3145
|
-
padding: '5px 10px',
|
|
3146
|
-
borderRadius: '4px',
|
|
3147
|
-
fontSize: '0.75rem',
|
|
3148
|
-
zIndex: '10001',
|
|
3149
|
-
opacity: '0.8',
|
|
3150
|
-
fontFamily: 'monospace'
|
|
3151
|
-
});
|
|
3152
|
-
this.$('body').append(this.$statusIndicator);
|
|
3153
|
-
}
|
|
3154
|
-
addStyles() {
|
|
3155
|
-
// Check if styles already exist
|
|
3156
|
-
if (this.$('#jqhtml-debug-styles').length > 0)
|
|
3079
|
+
// Collect ready promise - parent.ready() waits for all children via _wait_for_children_ready()
|
|
3080
|
+
readyPromises.push(component.ready());
|
|
3081
|
+
});
|
|
3082
|
+
// Fire jqhtml:ready event when all top-level components are ready
|
|
3083
|
+
const result = Promise.all(readyPromises);
|
|
3084
|
+
result.then(() => {
|
|
3085
|
+
document.dispatchEvent(new CustomEvent('jqhtml:ready'));
|
|
3086
|
+
});
|
|
3087
|
+
return result;
|
|
3088
|
+
}
|
|
3089
|
+
/**
|
|
3090
|
+
* Hydrate nested _Component_Init placeholders within a component's DOM.
|
|
3091
|
+
* Called from parent's 'render' event.
|
|
3092
|
+
*/
|
|
3093
|
+
function hydrateNested($scope, jQ) {
|
|
3094
|
+
$scope.find('._Component_Init').each(function () {
|
|
3095
|
+
const $element = jQ(this);
|
|
3096
|
+
if (!document.contains($element[0])) {
|
|
3157
3097
|
return;
|
|
3158
|
-
// Create and inject CSS using jQuery - concatenated strings for better minification
|
|
3159
|
-
const $style = this.$('<style>')
|
|
3160
|
-
.attr('id', 'jqhtml-debug-styles')
|
|
3161
|
-
.text('.jqhtml-debug-overlay {' +
|
|
3162
|
-
'position: fixed;' +
|
|
3163
|
-
'left: 0;' +
|
|
3164
|
-
'right: 0;' +
|
|
3165
|
-
'z-index: 10000;' +
|
|
3166
|
-
'font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace;' +
|
|
3167
|
-
'font-size: 0.8rem;' +
|
|
3168
|
-
'box-shadow: 0 2px 10px rgba(0,0,0,0.2);' +
|
|
3169
|
-
'}' +
|
|
3170
|
-
'.jqhtml-debug-overlay.top {' +
|
|
3171
|
-
'top: 0;' +
|
|
3172
|
-
'}' +
|
|
3173
|
-
'.jqhtml-debug-overlay.bottom {' +
|
|
3174
|
-
'bottom: 0;' +
|
|
3175
|
-
'}' +
|
|
3176
|
-
'.jqhtml-debug-overlay.dark {' +
|
|
3177
|
-
'background: #34495e;' +
|
|
3178
|
-
'color: #ecf0f1;' +
|
|
3179
|
-
'}' +
|
|
3180
|
-
'.jqhtml-debug-overlay.light {' +
|
|
3181
|
-
'background: #f8f9fa;' +
|
|
3182
|
-
'color: #333;' +
|
|
3183
|
-
'border-bottom: 1px solid #dee2e6;' +
|
|
3184
|
-
'}' +
|
|
3185
|
-
'.jqhtml-debug-content {' +
|
|
3186
|
-
'padding: 0.5rem 1rem;' +
|
|
3187
|
-
'}' +
|
|
3188
|
-
'.jqhtml-debug-controls {' +
|
|
3189
|
-
'display: flex;' +
|
|
3190
|
-
'flex-wrap: wrap;' +
|
|
3191
|
-
'gap: 8px;' +
|
|
3192
|
-
'align-items: center;' +
|
|
3193
|
-
'}' +
|
|
3194
|
-
'.jqhtml-debug-title {' +
|
|
3195
|
-
'margin-right: 10px;' +
|
|
3196
|
-
'font-weight: bold;' +
|
|
3197
|
-
'}' +
|
|
3198
|
-
'.jqhtml-debug-btn {' +
|
|
3199
|
-
'padding: 4px 8px;' +
|
|
3200
|
-
'border: none;' +
|
|
3201
|
-
'border-radius: 3px;' +
|
|
3202
|
-
'background: #3498db;' +
|
|
3203
|
-
'color: white;' +
|
|
3204
|
-
'cursor: pointer;' +
|
|
3205
|
-
'font-size: 0.75rem;' +
|
|
3206
|
-
'transition: background 0.2s;' +
|
|
3207
|
-
'}' +
|
|
3208
|
-
'.jqhtml-debug-btn:hover {' +
|
|
3209
|
-
'background: #2980b9;' +
|
|
3210
|
-
'}' +
|
|
3211
|
-
'.jqhtml-debug-btn.success {' +
|
|
3212
|
-
'background: #27ae60;' +
|
|
3213
|
-
'}' +
|
|
3214
|
-
'.jqhtml-debug-btn.success:hover {' +
|
|
3215
|
-
'background: #229954;' +
|
|
3216
|
-
'}' +
|
|
3217
|
-
'.jqhtml-debug-btn.danger {' +
|
|
3218
|
-
'background: #e74c3c;' +
|
|
3219
|
-
'}' +
|
|
3220
|
-
'.jqhtml-debug-btn.danger:hover {' +
|
|
3221
|
-
'background: #c0392b;' +
|
|
3222
|
-
'}' +
|
|
3223
|
-
'.jqhtml-debug-toggle {' +
|
|
3224
|
-
'padding: 4px 8px;' +
|
|
3225
|
-
'border: none;' +
|
|
3226
|
-
'border-radius: 3px;' +
|
|
3227
|
-
'background: #7f8c8d;' +
|
|
3228
|
-
'color: white;' +
|
|
3229
|
-
'cursor: pointer;' +
|
|
3230
|
-
'font-size: 0.75rem;' +
|
|
3231
|
-
'margin-left: auto;' +
|
|
3232
|
-
'}' +
|
|
3233
|
-
'.jqhtml-debug-toggle:hover {' +
|
|
3234
|
-
'background: #6c7b7d;' +
|
|
3235
|
-
'}' +
|
|
3236
|
-
'.jqhtml-debug-status.active {' +
|
|
3237
|
-
'background: #27ae60 !important;' +
|
|
3238
|
-
'}' +
|
|
3239
|
-
'@media (max-width: 768px) {' +
|
|
3240
|
-
'.jqhtml-debug-controls {' +
|
|
3241
|
-
'flex-direction: column;' +
|
|
3242
|
-
'align-items: flex-start;' +
|
|
3243
|
-
'}' +
|
|
3244
|
-
'.jqhtml-debug-title {' +
|
|
3245
|
-
'margin-bottom: 5px;' +
|
|
3246
|
-
'}' +
|
|
3247
|
-
'}');
|
|
3248
|
-
this.$('head').append($style);
|
|
3249
|
-
}
|
|
3250
|
-
toggle() {
|
|
3251
|
-
// Toggle between compact and full view
|
|
3252
|
-
this.options.compact = !this.options.compact;
|
|
3253
|
-
const $toggleBtn = this.$container.find('.jqhtml-debug-toggle');
|
|
3254
|
-
$toggleBtn.text(this.options.compact ? '▼' : '▲');
|
|
3255
|
-
const $buttons = this.$container.find('.jqhtml-debug-btn');
|
|
3256
|
-
if (this.options.compact) {
|
|
3257
|
-
$buttons.hide();
|
|
3258
3098
|
}
|
|
3259
|
-
|
|
3260
|
-
|
|
3099
|
+
// Skip if nested inside another placeholder
|
|
3100
|
+
let parent = $element[0].parentElement;
|
|
3101
|
+
while (parent && parent !== $scope[0]) {
|
|
3102
|
+
if (parent.classList.contains('_Component_Init')) {
|
|
3103
|
+
return;
|
|
3104
|
+
}
|
|
3105
|
+
parent = parent.parentElement;
|
|
3261
3106
|
}
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
const jqhtml = getJqhtml();
|
|
3265
|
-
if (!jqhtml) {
|
|
3266
|
-
console.warn('JQHTML not available - make sure it\'s loaded and exposed globally');
|
|
3107
|
+
const component = hydrateElement($element);
|
|
3108
|
+
if (!component)
|
|
3267
3109
|
return;
|
|
3110
|
+
// Recursively handle deeper nesting
|
|
3111
|
+
component.on('render', function () {
|
|
3112
|
+
hydrateNested(component.$, jQ);
|
|
3113
|
+
});
|
|
3114
|
+
});
|
|
3115
|
+
}
|
|
3116
|
+
/**
|
|
3117
|
+
* Hydrate a single _Component_Init element into a live component.
|
|
3118
|
+
*/
|
|
3119
|
+
function hydrateElement($element, jQ) {
|
|
3120
|
+
const componentName = $element.attr('data-component-init-name');
|
|
3121
|
+
if (!componentName)
|
|
3122
|
+
return null;
|
|
3123
|
+
// Parse args
|
|
3124
|
+
const argsString = $element.attr('data-component-args');
|
|
3125
|
+
let args = {};
|
|
3126
|
+
if (argsString) {
|
|
3127
|
+
try {
|
|
3128
|
+
args = JSON.parse(argsString);
|
|
3268
3129
|
}
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
case 'enableBasicDebug':
|
|
3292
|
-
jqhtml.enableDebugMode('basic');
|
|
3293
|
-
this.updateStatus('Basic');
|
|
3294
|
-
console.log('🐛 Basic Debug Mode Enabled');
|
|
3295
|
-
break;
|
|
3296
|
-
case 'enableFullDebug':
|
|
3297
|
-
jqhtml.enableDebugMode('full');
|
|
3298
|
-
this.updateStatus('Full');
|
|
3299
|
-
console.log('🐛 Full Debug Mode Enabled');
|
|
3300
|
-
break;
|
|
3301
|
-
case 'enableSequentialMode':
|
|
3302
|
-
jqhtml.setDebugSettings({
|
|
3303
|
-
logCreationReady: true,
|
|
3304
|
-
sequentialProcessing: true,
|
|
3305
|
-
flashComponents: true,
|
|
3306
|
-
profilePerformance: true
|
|
3307
|
-
});
|
|
3308
|
-
this.updateStatus('Sequential');
|
|
3309
|
-
console.log('🐛 Sequential Processing Mode Enabled');
|
|
3310
|
-
break;
|
|
3311
|
-
case 'clearAllDebug':
|
|
3312
|
-
jqhtml.clearDebugSettings();
|
|
3313
|
-
this.updateStatus('Off');
|
|
3314
|
-
console.log('🐛 All Debug Modes Disabled');
|
|
3315
|
-
break;
|
|
3316
|
-
case 'showDebugInfo':
|
|
3317
|
-
const settings = JSON.stringify(jqhtml.debug, null, 2);
|
|
3318
|
-
console.log('🐛 Current Debug Settings:', settings);
|
|
3319
|
-
alert('Debug settings logged to console:\n\n' + (Object.keys(jqhtml.debug).length > 0 ? settings : 'No debug settings active'));
|
|
3320
|
-
break;
|
|
3321
|
-
}
|
|
3130
|
+
catch (e) {
|
|
3131
|
+
console.error(`[jqhtml.boot] Failed to parse args for ${componentName}:`, e);
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
// Strip data- prefix from args if present
|
|
3135
|
+
const filteredArgs = {};
|
|
3136
|
+
for (const [key, value] of Object.entries(args)) {
|
|
3137
|
+
filteredArgs[key.startsWith('data-') ? key.substring(5) : key] = value;
|
|
3138
|
+
}
|
|
3139
|
+
// Capture innerHTML for content() and mark as boot-created
|
|
3140
|
+
filteredArgs._inner_html = $element.html();
|
|
3141
|
+
filteredArgs._component_name = componentName;
|
|
3142
|
+
// Cleanup placeholder
|
|
3143
|
+
$element.removeAttr('data-component-init-name');
|
|
3144
|
+
$element.removeAttr('data-component-args');
|
|
3145
|
+
$element.removeData('component-init-name');
|
|
3146
|
+
$element.removeData('component-args');
|
|
3147
|
+
$element.removeClass('_Component_Init');
|
|
3148
|
+
$element.empty();
|
|
3149
|
+
// Create component
|
|
3150
|
+
try {
|
|
3151
|
+
return $element.component(componentName, filteredArgs).component();
|
|
3322
3152
|
}
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
function showDebugOverlay(options) {
|
|
3327
|
-
return DebugOverlay.show(options);
|
|
3328
|
-
}
|
|
3329
|
-
function hideDebugOverlay() {
|
|
3330
|
-
DebugOverlay.hide();
|
|
3331
|
-
}
|
|
3332
|
-
// Auto-initialize if debug query parameter is present
|
|
3333
|
-
if (typeof window !== 'undefined') {
|
|
3334
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
3335
|
-
if (urlParams.get('debug') === 'true' || urlParams.get('jqhtml-debug') === 'true') {
|
|
3336
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
3337
|
-
DebugOverlay.show();
|
|
3338
|
-
});
|
|
3153
|
+
catch (error) {
|
|
3154
|
+
console.error(`[jqhtml.boot] Failed to create ${componentName}:`, error);
|
|
3155
|
+
return null;
|
|
3339
3156
|
}
|
|
3340
3157
|
}
|
|
3341
3158
|
|
|
@@ -4237,7 +4054,7 @@ function init(jQuery) {
|
|
|
4237
4054
|
}
|
|
4238
4055
|
}
|
|
4239
4056
|
// Version - will be replaced during build with actual version from package.json
|
|
4240
|
-
const version = '2.
|
|
4057
|
+
const version = '2.3.6';
|
|
4241
4058
|
// Default export with all functionality
|
|
4242
4059
|
const jqhtml = {
|
|
4243
4060
|
// Core
|
|
@@ -4261,6 +4078,8 @@ const jqhtml = {
|
|
|
4261
4078
|
escape_html,
|
|
4262
4079
|
// Version property - internal
|
|
4263
4080
|
__version: version,
|
|
4081
|
+
// state facts
|
|
4082
|
+
tombstone: 'pepperoni and cheese',
|
|
4264
4083
|
// Debug settings
|
|
4265
4084
|
debug: {
|
|
4266
4085
|
enabled: false,
|
|
@@ -4287,15 +4106,6 @@ const jqhtml = {
|
|
|
4287
4106
|
clearDebugSettings() {
|
|
4288
4107
|
this.debug = {};
|
|
4289
4108
|
},
|
|
4290
|
-
// Debug overlay methods
|
|
4291
|
-
showDebugOverlay(options) {
|
|
4292
|
-
return DebugOverlay.show(options);
|
|
4293
|
-
},
|
|
4294
|
-
hideDebugOverlay() {
|
|
4295
|
-
return DebugOverlay.hide();
|
|
4296
|
-
},
|
|
4297
|
-
// Export DebugOverlay class for direct access
|
|
4298
|
-
DebugOverlay,
|
|
4299
4109
|
// Install globals function
|
|
4300
4110
|
installGlobals() {
|
|
4301
4111
|
if (typeof window !== 'undefined') {
|
|
@@ -4329,7 +4139,9 @@ const jqhtml = {
|
|
|
4329
4139
|
// Cache key setter - enables component caching via local storage
|
|
4330
4140
|
set_cache_key(cache_key) {
|
|
4331
4141
|
Jqhtml_Local_Storage.set_cache_key(cache_key);
|
|
4332
|
-
}
|
|
4142
|
+
},
|
|
4143
|
+
// Boot - hydrate server-rendered component placeholders
|
|
4144
|
+
boot
|
|
4333
4145
|
};
|
|
4334
4146
|
// Auto-register on window for browser environments
|
|
4335
4147
|
// This is REQUIRED for compiled templates which use window.jqhtml.register_template()
|
|
@@ -4347,13 +4159,13 @@ if (typeof window !== 'undefined' && !window.jqhtml) {
|
|
|
4347
4159
|
}
|
|
4348
4160
|
}
|
|
4349
4161
|
|
|
4350
|
-
exports.DebugOverlay = DebugOverlay;
|
|
4351
4162
|
exports.Jqhtml_Component = Jqhtml_Component;
|
|
4352
4163
|
exports.Jqhtml_LifecycleManager = LifecycleManager;
|
|
4353
4164
|
exports.Jqhtml_Local_Storage = Jqhtml_Local_Storage;
|
|
4354
4165
|
exports.LifecycleManager = LifecycleManager;
|
|
4355
4166
|
exports.Load_Coordinator = Load_Coordinator;
|
|
4356
4167
|
exports.applyDebugDelay = applyDebugDelay;
|
|
4168
|
+
exports.boot = boot;
|
|
4357
4169
|
exports.create_component = create_component;
|
|
4358
4170
|
exports.default = jqhtml;
|
|
4359
4171
|
exports.devWarn = devWarn;
|
|
@@ -4366,7 +4178,6 @@ exports.get_template = get_template;
|
|
|
4366
4178
|
exports.get_template_by_class = get_template_by_class;
|
|
4367
4179
|
exports.handleComponentError = handleComponentError;
|
|
4368
4180
|
exports.has_component = has_component;
|
|
4369
|
-
exports.hideDebugOverlay = hideDebugOverlay;
|
|
4370
4181
|
exports.init = init;
|
|
4371
4182
|
exports.init_jquery_plugin = init_jquery_plugin;
|
|
4372
4183
|
exports.isSequentialProcessing = isSequentialProcessing;
|
|
@@ -4379,6 +4190,5 @@ exports.process_instructions = process_instructions;
|
|
|
4379
4190
|
exports.register_component = register_component;
|
|
4380
4191
|
exports.register_template = register_template;
|
|
4381
4192
|
exports.render_template = render_template;
|
|
4382
|
-
exports.showDebugOverlay = showDebugOverlay;
|
|
4383
4193
|
exports.version = version;
|
|
4384
4194
|
//# sourceMappingURL=index.cjs.map
|