Update jqhtml packages
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
24
node_modules/.package-lock.json
generated
vendored
24
node_modules/.package-lock.json
generated
vendored
@@ -2211,9 +2211,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jqhtml/core": {
|
||||
"version": "2.3.20",
|
||||
"resolved": "http://privatenpm.hanson.xyz/@jqhtml/core/-/core-2.3.20.tgz",
|
||||
"integrity": "sha512-5C1+0cFzt6/p1EtxPGOW7aqMVQRE5XIuntQNAOaNbmELdHSRfxcGcg3jv3lKh0qq7cFBEs7Jm1EmsGZ83B3wPQ==",
|
||||
"version": "2.3.21",
|
||||
"resolved": "http://privatenpm.hanson.xyz/@jqhtml/core/-/core-2.3.21.tgz",
|
||||
"integrity": "sha512-M6ZTSPL4mAIaezP+VOmo1jFC09lnoUueu/ZknIGrlpwDA/OxiLp+j6btMOukhlB7OQmB+xr9I8HulT8e/4uw+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||
@@ -2237,9 +2237,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jqhtml/parser": {
|
||||
"version": "2.3.20",
|
||||
"resolved": "http://privatenpm.hanson.xyz/@jqhtml/parser/-/parser-2.3.20.tgz",
|
||||
"integrity": "sha512-lrzfeCuQ/n6eqepk6Gjlxj25qFzQJCkezMirXhO99WtaGLm4T7sAMfcpVhdGstq2rqdCuAoEka370myd4LBTeA==",
|
||||
"version": "2.3.21",
|
||||
"resolved": "http://privatenpm.hanson.xyz/@jqhtml/parser/-/parser-2.3.21.tgz",
|
||||
"integrity": "sha512-S5VUqo9SN4HEeeTsYNbvRXreTML9cLO3N9mFrz76Z5+iwi9SnSxZEKx4ImDrkhcmQCjZu+JHGyscVj2QrehzvA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/jest": "^29.5.11",
|
||||
@@ -2277,9 +2277,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jqhtml/vscode-extension": {
|
||||
"version": "2.3.20",
|
||||
"resolved": "http://privatenpm.hanson.xyz/@jqhtml/vscode-extension/-/vscode-extension-2.3.20.tgz",
|
||||
"integrity": "sha512-xmMHcWVekFx3DWDCNqz8e+Q/JIJzVIG/1ww+r+6jz6gvaoc1nkNGKAzxbkJeZuNQWOzkEsfECJbVGeZsCOK5+A==",
|
||||
"version": "2.3.21",
|
||||
"resolved": "http://privatenpm.hanson.xyz/@jqhtml/vscode-extension/-/vscode-extension-2.3.21.tgz",
|
||||
"integrity": "sha512-CXCjk+RcqXUbx1EnvAqZwYqLmcTEz5kiGQS8/JaiqvMHbil2PiiFrTCqfhWcPBXPuW6XH2fosQIzPlC+35MI7g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"vscode": "^1.74.0"
|
||||
@@ -3997,9 +3997,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.9.6",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.6.tgz",
|
||||
"integrity": "sha512-v9BVVpOTLB59C9E7aSnmIF8h7qRsFpx+A2nugVMTszEOMcfjlZMsXRm4LF23I3Z9AJxc8ANpIvzbzONoX9VJlg==",
|
||||
"version": "2.9.7",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.7.tgz",
|
||||
"integrity": "sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"baseline-browser-mapping": "dist/cli.js"
|
||||
|
||||
0
node_modules/@jqhtml/core/dist/boot.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/boot.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/boot.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/boot.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/component-registry.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/component-registry.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/component-registry.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/component-registry.d.ts.map
generated
vendored
Executable file → Normal file
36
node_modules/@jqhtml/core/dist/component.d.ts
generated
vendored
Executable file → Normal file
36
node_modules/@jqhtml/core/dist/component.d.ts
generated
vendored
Executable file → Normal file
@@ -54,6 +54,8 @@ export declare class Jqhtml_Component {
|
||||
private _skip_render_and_ready;
|
||||
private _skip_ready;
|
||||
private _has_rendered;
|
||||
private _load_queue;
|
||||
private __has_custom_on_load;
|
||||
constructor(element?: any, args?: Record<string, any>);
|
||||
/**
|
||||
* Protect lifecycle methods from manual invocation
|
||||
@@ -77,6 +79,7 @@ export declare class Jqhtml_Component {
|
||||
/**
|
||||
* Check if on_load() is overridden in a subclass
|
||||
* Used to skip the load phase entirely for components that don't fetch data
|
||||
* Returns cached value set in _boot() for O(1) performance
|
||||
* @private
|
||||
*/
|
||||
private _has_on_load;
|
||||
@@ -124,12 +127,43 @@ export declare class Jqhtml_Component {
|
||||
*/
|
||||
create(): void;
|
||||
/**
|
||||
* Load phase - Fetch data from APIs
|
||||
* Load phase - Fetch asynchronous data
|
||||
* Called bottom-up, fully parallel
|
||||
* NO DOM MODIFICATIONS ALLOWED IN THIS PHASE
|
||||
*
|
||||
* Key design: on_load() runs on a DETACHED proxy with a clone of this.data.
|
||||
* The real component's this.data is not touched during on_load execution.
|
||||
* After on_load completes, the result is applied via a sequential queue.
|
||||
*
|
||||
* @private - Internal lifecycle method, not for external use
|
||||
*/
|
||||
_load(): Promise<void>;
|
||||
/**
|
||||
* Execute on_load() on a fully detached proxy.
|
||||
*
|
||||
* The proxy has:
|
||||
* - A CLONE of this.data (from __initial_data_snapshot)
|
||||
* - Read-only access to this.args
|
||||
* - No access to anything else (this.$, this.sid, etc.)
|
||||
*
|
||||
* This ensures on_load runs completely isolated from the component instance.
|
||||
*
|
||||
* @param use_load_coordinator - If true, register with Load_Coordinator for deduplication
|
||||
* @returns The resulting data from the proxy after on_load completes
|
||||
* @private
|
||||
*/
|
||||
private _execute_on_load_detached;
|
||||
/**
|
||||
* Apply the result of on_load() to this.data via the sequential queue.
|
||||
*
|
||||
* Multiple _load calls can execute on_load in parallel, but this method
|
||||
* ensures that setting this.data happens in FIFO order.
|
||||
*
|
||||
* @param result_data - The data returned from _execute_on_load_detached
|
||||
* @param data_before_load - JSON string of this.data before on_load (for change detection), or null
|
||||
* @private
|
||||
*/
|
||||
private _apply_load_result;
|
||||
/**
|
||||
* Ready phase - Component fully initialized
|
||||
* Called bottom-up (children before parent)
|
||||
|
||||
2
node_modules/@jqhtml/core/dist/component.d.ts.map
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/core/dist/component.d.ts.map
generated
vendored
Executable file → Normal file
@@ -1 +1 @@
|
||||
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"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"}
|
||||
0
node_modules/@jqhtml/core/dist/debug-entry.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/debug-entry.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/debug-entry.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/debug-entry.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/debug.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/debug.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/debug.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/debug.d.ts.map
generated
vendored
Executable file → Normal file
475
node_modules/@jqhtml/core/dist/index.cjs
generated
vendored
Executable file → Normal file
475
node_modules/@jqhtml/core/dist/index.cjs
generated
vendored
Executable file → Normal file
@@ -2138,6 +2138,17 @@ class Jqhtml_Component {
|
||||
// rendered event - fires once after the synchronous render chain completes
|
||||
// (after on_load's re-render if applicable, or after first render if no on_load)
|
||||
this._has_rendered = false;
|
||||
// Sequential queue for setting this.data after on_load completes
|
||||
// Multiple _load calls can run on_load in parallel, but setting this.data is serialized
|
||||
this._load_queue = Promise.resolve();
|
||||
// Cached flag: true if this component has a custom on_load() override
|
||||
// Set in constructor (prototype chain is established before constructor runs)
|
||||
// Used to skip expensive cache/load operations for static components
|
||||
this.__has_custom_on_load = false;
|
||||
// Detect custom on_load() override immediately
|
||||
// Prototype chain is set up before constructor runs, so this.on_load
|
||||
// correctly resolves to child class override if one exists
|
||||
this.__has_custom_on_load = this.on_load !== Jqhtml_Component.prototype.on_load;
|
||||
this._cid = this._generate_cid();
|
||||
this._lifecycle_manager = LifecycleManager.get_instance();
|
||||
// Create or wrap element
|
||||
@@ -2318,14 +2329,11 @@ class Jqhtml_Component {
|
||||
/**
|
||||
* Check if on_load() is overridden in a subclass
|
||||
* Used to skip the load phase entirely for components that don't fetch data
|
||||
* Returns cached value set in _boot() for O(1) performance
|
||||
* @private
|
||||
*/
|
||||
_has_on_load() {
|
||||
// Get this instance's on_load implementation
|
||||
const impl = lifecycle_impls.get(this)?.['on_load'] || this.on_load;
|
||||
// Compare to base class implementation
|
||||
// If they're the same function reference, it wasn't overridden
|
||||
return impl !== Jqhtml_Component.prototype.on_load;
|
||||
return this.__has_custom_on_load;
|
||||
}
|
||||
/**
|
||||
* Boot - Start the full component lifecycle
|
||||
@@ -2341,6 +2349,7 @@ class Jqhtml_Component {
|
||||
return;
|
||||
this._booted = true;
|
||||
// Protect lifecycle methods from manual invocation (must happen after subclass constructor)
|
||||
// Note: __has_custom_on_load is already set in constructor
|
||||
this._protect_lifecycle_methods();
|
||||
await this._lifecycle_manager.boot_component(this);
|
||||
}
|
||||
@@ -2693,98 +2702,102 @@ class Jqhtml_Component {
|
||||
`on_create() must be synchronous code. Remove 'async' from the function declaration.`);
|
||||
// Don't await - on_create MUST be sync. The warning is enough.
|
||||
}
|
||||
// CACHE CHECK - Read from cache based on cache mode ('data' or 'html')
|
||||
// This happens after on_create() but before render, allowing instant first render
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
let uncacheable_property;
|
||||
if (typeof this.cache_id === 'function') {
|
||||
try {
|
||||
const custom_cache_id = this.cache_id();
|
||||
cache_key = `${this.component_name()}::${String(custom_cache_id)}`;
|
||||
}
|
||||
catch (error) {
|
||||
// cache_id() threw error - disable caching
|
||||
uncacheable_property = 'cache_id()';
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use standard args-based cache key generation
|
||||
const result = Load_Coordinator.generate_invocation_key(this.component_name(), this.args);
|
||||
cache_key = result.key;
|
||||
uncacheable_property = result.uncacheable_property;
|
||||
}
|
||||
// If cache_key is null, caching disabled
|
||||
if (cache_key === null) {
|
||||
// Set data-nocache attribute for debugging (shows which property prevented caching)
|
||||
if (uncacheable_property) {
|
||||
this.$.attr('data-nocache', uncacheable_property);
|
||||
}
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - caching disabled`, { uncacheable_property });
|
||||
}
|
||||
// Don't return - continue to snapshot this.data for on_load restoration
|
||||
}
|
||||
else {
|
||||
// Store cache key for later use
|
||||
this._cache_key = cache_key;
|
||||
// Get cache mode
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache ${cache_mode}] Component ${this._cid} (${this.component_name()}) checking cache in create()`, { cache_key, cache_mode, has_cache_key_set: Jqhtml_Local_Storage.has_cache_key() });
|
||||
}
|
||||
if (cache_mode === 'html') {
|
||||
// HTML cache mode - check for cached HTML to inject on first render
|
||||
const html_cache_key = `${cache_key}::html`;
|
||||
const cached_html = Jqhtml_Local_Storage.get(html_cache_key);
|
||||
if (cached_html !== null && typeof cached_html === 'string') {
|
||||
// Store cached HTML for injection in _render()
|
||||
this._cached_html = cached_html;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) found cached HTML`, { cache_key: html_cache_key, html_length: cached_html.length });
|
||||
}
|
||||
// OPTIMIZATION: Skip cache operations and snapshot if no custom on_load()
|
||||
// Components without on_load() don't fetch data, so nothing to cache or restore
|
||||
if (this.__has_custom_on_load) {
|
||||
// CACHE CHECK - Read from cache based on cache mode ('data' or 'html')
|
||||
// This happens after on_create() but before render, allowing instant first render
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
let uncacheable_property;
|
||||
if (typeof this.cache_id === 'function') {
|
||||
try {
|
||||
const custom_cache_id = this.cache_id();
|
||||
cache_key = `${this.component_name()}::${String(custom_cache_id)}`;
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key: html_cache_key });
|
||||
}
|
||||
}
|
||||
// Warn if use_cached_data is set in html cache mode - it has no effect
|
||||
if (this.args.use_cached_data === true) {
|
||||
console.warn(`[JQHTML] Component "${this.component_name()}" has use_cached_data=true but cache mode is 'html'.\n` +
|
||||
`use_cached_data only applies to 'data' cache mode. In 'html' mode, the entire rendered HTML is cached.\n` +
|
||||
`The use_cached_data flag will be ignored.`);
|
||||
catch (error) {
|
||||
// cache_id() threw error - disable caching
|
||||
uncacheable_property = 'cache_id()';
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Data cache mode (default) - check for cached data to hydrate this.data
|
||||
const cached_data = Jqhtml_Local_Storage.get(cache_key);
|
||||
if (cached_data !== null && typeof cached_data === 'object') {
|
||||
// Hydrate this.data with cached data
|
||||
this.data = cached_data;
|
||||
// If use_cached_data=true, skip on_load() entirely - use cached data as final data
|
||||
if (this.args.use_cached_data === true) {
|
||||
this._use_cached_data_hit = true;
|
||||
// Use standard args-based cache key generation
|
||||
const result = Load_Coordinator.generate_invocation_key(this.component_name(), this.args);
|
||||
cache_key = result.key;
|
||||
uncacheable_property = result.uncacheable_property;
|
||||
}
|
||||
// If cache_key is null, caching disabled
|
||||
if (cache_key === null) {
|
||||
// Set data-nocache attribute for debugging (shows which property prevented caching)
|
||||
if (uncacheable_property) {
|
||||
this.$.attr('data-nocache', uncacheable_property);
|
||||
}
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - caching disabled`, { uncacheable_property });
|
||||
}
|
||||
// Don't return - continue to snapshot this.data for on_load restoration
|
||||
}
|
||||
else {
|
||||
// Store cache key for later use
|
||||
this._cache_key = cache_key;
|
||||
// Get cache mode
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache ${cache_mode}] Component ${this._cid} (${this.component_name()}) checking cache in create()`, { cache_key, cache_mode, has_cache_key_set: Jqhtml_Local_Storage.has_cache_key() });
|
||||
}
|
||||
if (cache_mode === 'html') {
|
||||
// HTML cache mode - check for cached HTML to inject on first render
|
||||
const html_cache_key = `${cache_key}::html`;
|
||||
const cached_html = Jqhtml_Local_Storage.get(html_cache_key);
|
||||
if (cached_html !== null && typeof cached_html === 'string') {
|
||||
// Store cached HTML for injection in _render()
|
||||
this._cached_html = cached_html;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) using cached data (use_cached_data=true, skipping on_load)`, { cache_key, data: cached_data });
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) found cached HTML`, { cache_key: html_cache_key, html_length: cached_html.length });
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) hydrated from cache`, { cache_key, data: cached_data });
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key: html_cache_key });
|
||||
}
|
||||
}
|
||||
// Warn if use_cached_data is set in html cache mode - it has no effect
|
||||
if (this.args.use_cached_data === true) {
|
||||
console.warn(`[JQHTML] Component "${this.component_name()}" has use_cached_data=true but cache mode is 'html'.\n` +
|
||||
`use_cached_data only applies to 'data' cache mode. In 'html' mode, the entire rendered HTML is cached.\n` +
|
||||
`The use_cached_data flag will be ignored.`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key });
|
||||
// Data cache mode (default) - check for cached data to hydrate this.data
|
||||
const cached_data = Jqhtml_Local_Storage.get(cache_key);
|
||||
if (cached_data !== null && typeof cached_data === 'object') {
|
||||
// Hydrate this.data with cached data
|
||||
this.data = cached_data;
|
||||
// If use_cached_data=true, skip on_load() entirely - use cached data as final data
|
||||
if (this.args.use_cached_data === true) {
|
||||
this._use_cached_data_hit = true;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) using cached data (use_cached_data=true, skipping on_load)`, { cache_key, data: cached_data });
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) hydrated from cache`, { cache_key, data: cached_data });
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Snapshot this.data after on_create() completes
|
||||
// This will be restored before each on_load() execution to reset state
|
||||
this.__initial_data_snapshot = JSON.parse(JSON.stringify(this.data));
|
||||
}
|
||||
// Snapshot this.data after on_create() completes
|
||||
// This will be restored before each on_load() execution to reset state
|
||||
this.__initial_data_snapshot = JSON.parse(JSON.stringify(this.data));
|
||||
// Freeze this.data after on_create() - only on_load() can modify it now
|
||||
this.__data_frozen = true;
|
||||
this._ready_state = 1;
|
||||
@@ -2794,9 +2807,14 @@ class Jqhtml_Component {
|
||||
this.trigger('create');
|
||||
}
|
||||
/**
|
||||
* Load phase - Fetch data from APIs
|
||||
* Load phase - Fetch asynchronous data
|
||||
* Called bottom-up, fully parallel
|
||||
* NO DOM MODIFICATIONS ALLOWED IN THIS PHASE
|
||||
*
|
||||
* Key design: on_load() runs on a DETACHED proxy with a clone of this.data.
|
||||
* The real component's this.data is not touched during on_load execution.
|
||||
* After on_load completes, the result is applied via a sequential queue.
|
||||
*
|
||||
* @private - Internal lifecycle method, not for external use
|
||||
*/
|
||||
async _load() {
|
||||
@@ -2812,14 +2830,6 @@ class Jqhtml_Component {
|
||||
this.trigger('load');
|
||||
return;
|
||||
}
|
||||
// Restore this.data to initial state from snapshot (skip on first load)
|
||||
// This ensures on_load() always starts with clean state
|
||||
const is_first_load = this._ready_state < 2;
|
||||
if (!is_first_load && this.__initial_data_snapshot) {
|
||||
this.data = JSON.parse(JSON.stringify(this.__initial_data_snapshot));
|
||||
}
|
||||
// Unfreeze this.data so on_load() can modify it
|
||||
this.__data_frozen = false;
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
let uncacheable_property;
|
||||
@@ -2839,6 +2849,8 @@ class Jqhtml_Component {
|
||||
cache_key = result.key;
|
||||
uncacheable_property = result.uncacheable_property;
|
||||
}
|
||||
// Store cache key for later use
|
||||
this._cache_key = cache_key;
|
||||
// If cache_key is null, args are not serializable - skip load deduplication and caching
|
||||
if (cache_key === null) {
|
||||
// Set data-nocache attribute for debugging (shows which property prevented caching)
|
||||
@@ -2848,9 +2860,10 @@ class Jqhtml_Component {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - load deduplication and caching disabled`, { uncacheable_property });
|
||||
}
|
||||
// Execute on_load() with authorization, without deduplication or caching
|
||||
await this._call_lifecycle('on_load');
|
||||
this.__data_frozen = true;
|
||||
// Execute on_load on detached proxy without deduplication
|
||||
const result_data = await this._execute_on_load_detached();
|
||||
// Apply result via sequential queue
|
||||
await this._apply_load_result(result_data, null);
|
||||
return;
|
||||
}
|
||||
// Store "before" snapshot for comparison after on_load()
|
||||
@@ -2884,10 +2897,39 @@ class Jqhtml_Component {
|
||||
this.trigger('load');
|
||||
return;
|
||||
}
|
||||
// This component is a leader - execute on_load() normally
|
||||
// This component is a leader - execute on_load() on detached proxy
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Load Deduplication] Component ${this._cid} (${this.component_name()}) is the leader`, { args: this.args });
|
||||
}
|
||||
// Execute on_load on detached proxy with Load_Coordinator registration
|
||||
const result_data = await this._execute_on_load_detached(true);
|
||||
// Apply result via sequential queue
|
||||
await this._apply_load_result(result_data, data_before_load);
|
||||
}
|
||||
/**
|
||||
* Execute on_load() on a fully detached proxy.
|
||||
*
|
||||
* The proxy has:
|
||||
* - A CLONE of this.data (from __initial_data_snapshot)
|
||||
* - Read-only access to this.args
|
||||
* - No access to anything else (this.$, this.sid, etc.)
|
||||
*
|
||||
* This ensures on_load runs completely isolated from the component instance.
|
||||
*
|
||||
* @param use_load_coordinator - If true, register with Load_Coordinator for deduplication
|
||||
* @returns The resulting data from the proxy after on_load completes
|
||||
* @private
|
||||
*/
|
||||
async _execute_on_load_detached(use_load_coordinator = false) {
|
||||
// Clone this.data from the snapshot captured after on_create()
|
||||
const data_clone = this.__initial_data_snapshot
|
||||
? JSON.parse(JSON.stringify(this.__initial_data_snapshot))
|
||||
: {};
|
||||
// Create a detached context object that on_load will operate on
|
||||
const detached_context = {
|
||||
args: this.args, // Read-only reference to real args
|
||||
data: data_clone // Cloned data - modifications stay isolated
|
||||
};
|
||||
// Capture args state before on_load() for validation
|
||||
let argsBeforeLoad = null;
|
||||
try {
|
||||
@@ -2898,17 +2940,21 @@ class Jqhtml_Component {
|
||||
}
|
||||
// Set loading flag to prevent render() calls during on_load()
|
||||
this.__loading = true;
|
||||
// Create restricted proxy to prevent DOM access during on_load()
|
||||
const restricted_this = new Proxy(this, {
|
||||
// Create restricted proxy that operates on the detached context
|
||||
const component_name = this.component_name();
|
||||
const restricted_this = new Proxy(detached_context, {
|
||||
get(target, prop) {
|
||||
// Only allow access to this.args and this.data
|
||||
if (prop === 'args' || prop === 'data') {
|
||||
return target[prop];
|
||||
// Only allow access to args and data
|
||||
if (prop === 'args') {
|
||||
return target.args;
|
||||
}
|
||||
if (prop === 'data') {
|
||||
return target.data;
|
||||
}
|
||||
// Block everything else
|
||||
console.error(`[JQHTML] ERROR: Component "${target.component_name()}" attempted to access this.${String(prop)} during on_load().\n\n` +
|
||||
console.error(`[JQHTML] ERROR: Component "${component_name}" attempted to access this.${String(prop)} during on_load().\n\n` +
|
||||
`RESTRICTION: on_load() may ONLY access:\n` +
|
||||
` - this.args (read during on_load, modify before/after)\n` +
|
||||
` - this.args (read-only)\n` +
|
||||
` - this.data (read/write)\n\n` +
|
||||
`WHY: on_load() is for data fetching only. All other component functionality should happen in other lifecycle methods.\n\n` +
|
||||
`FIX:\n` +
|
||||
@@ -2919,14 +2965,14 @@ class Jqhtml_Component {
|
||||
`on_load() may only access this.args and this.data.`);
|
||||
},
|
||||
set(target, prop, value) {
|
||||
// Only allow setting this.data
|
||||
// Only allow setting data
|
||||
if (prop === 'data') {
|
||||
target[prop] = value;
|
||||
target.data = value;
|
||||
return true;
|
||||
}
|
||||
// Block setting this.args
|
||||
// Block setting args
|
||||
if (prop === 'args') {
|
||||
console.error(`[JQHTML] ERROR: Component "${target.component_name()}" attempted to modify this.args during on_load().\n\n` +
|
||||
console.error(`[JQHTML] ERROR: Component "${component_name}" attempted to modify this.args during on_load().\n\n` +
|
||||
`RESTRICTION: on_load() may ONLY modify:\n` +
|
||||
` - this.data (read/write)\n\n` +
|
||||
`WHY: this.args is component state that on_load() depends on. Modifying it inside on_load() creates circular dependencies.\n\n` +
|
||||
@@ -2937,7 +2983,7 @@ class Jqhtml_Component {
|
||||
`Modify this.args in other lifecycle methods, not inside on_load().`);
|
||||
}
|
||||
// Block setting any other properties
|
||||
console.error(`[JQHTML] ERROR: Component "${target.component_name()}" attempted to modify this.${String(prop)} during on_load().\n\n` +
|
||||
console.error(`[JQHTML] ERROR: Component "${component_name}" attempted to modify this.${String(prop)} during on_load().\n\n` +
|
||||
`RESTRICTION: on_load() may ONLY modify:\n` +
|
||||
` - this.data (read/write)\n\n` +
|
||||
`WHY: on_load() is for data fetching only. Setting properties on the component instance should happen in other lifecycle methods.\n\n` +
|
||||
@@ -2948,35 +2994,36 @@ class Jqhtml_Component {
|
||||
`Only this.data can be modified in on_load().`);
|
||||
}
|
||||
});
|
||||
// Create promise for this on_load() call with restricted this context
|
||||
// Create promise for this on_load() call
|
||||
const on_load_promise = (async () => {
|
||||
try {
|
||||
// TODO: Implement proper error handling for on_load() failures
|
||||
// - Should errors trigger re-render with error state?
|
||||
// - Should errors clear cached data?
|
||||
// - Should errors reset state machine flags (next_reload_force_refresh)?
|
||||
// - Should partial data be preserved or rolled back?
|
||||
// - Should followers be notified differently based on error type?
|
||||
await this._call_lifecycle('on_load', restricted_this);
|
||||
}
|
||||
catch (error) {
|
||||
// Handle error and notify coordinator
|
||||
Load_Coordinator.handle_leader_error(this, error);
|
||||
if (use_load_coordinator) {
|
||||
// Handle error and notify coordinator
|
||||
Load_Coordinator.handle_leader_error(this, error);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
})();
|
||||
// Register as leader and get cleanup function
|
||||
const complete_coordination = Load_Coordinator.register_leader(this, on_load_promise);
|
||||
// If using Load_Coordinator, register as leader
|
||||
let complete_coordination = null;
|
||||
if (use_load_coordinator) {
|
||||
complete_coordination = Load_Coordinator.register_leader(this, on_load_promise);
|
||||
}
|
||||
try {
|
||||
await on_load_promise;
|
||||
}
|
||||
finally {
|
||||
// Always clear loading flag and complete coordination
|
||||
// Always clear loading flag
|
||||
this.__loading = false;
|
||||
complete_coordination();
|
||||
// Note: this.data stays unfrozen until after normalization below
|
||||
// Complete coordination if we registered
|
||||
if (complete_coordination) {
|
||||
complete_coordination();
|
||||
}
|
||||
}
|
||||
// Validate that on_load() only modified this.data
|
||||
// Validate that on_load() didn't somehow modify this.args (shouldn't be possible with new proxy)
|
||||
let argsAfterLoad = null;
|
||||
try {
|
||||
argsAfterLoad = JSON.stringify(this.args);
|
||||
@@ -2984,44 +3031,59 @@ class Jqhtml_Component {
|
||||
catch (error) {
|
||||
// Args contain circular references - skip validation
|
||||
}
|
||||
// Check if args were modified (skip if args are non-serializable)
|
||||
if (argsBeforeLoad !== null && argsAfterLoad !== null && argsBeforeLoad !== argsAfterLoad) {
|
||||
console.error(`[JQHTML] WARNING: Component "${this.component_name()}" modified this.args in on_load().\n` +
|
||||
`on_load() should ONLY modify this.data.\n\n` +
|
||||
console.error(`[JQHTML] WARNING: Component "${this.component_name()}" somehow modified this.args during on_load().\n` +
|
||||
`This should not be possible with the detached proxy. Please report this bug.\n\n` +
|
||||
`Before: ${argsBeforeLoad}\n` +
|
||||
`After: ${argsAfterLoad}\n\n` +
|
||||
`Fix: Modify this.args in on_create() or other lifecycle methods, not in on_load().\n` +
|
||||
`this.args stores state that on_load() depends on. Modifying it inside on_load() creates circular dependencies.`);
|
||||
`After: ${argsAfterLoad}`);
|
||||
}
|
||||
// NOTE: We previously checked for new properties being added to the component instance
|
||||
// during on_load() and warned about them. However, this validation was removed because:
|
||||
// 1. The restricted proxy already throws errors if code tries to set properties during on_load()
|
||||
// 2. The validation was producing false positives for properties set during template render
|
||||
// (templates can legitimately set this.* properties in code blocks like <% this._tabs = [...] %>)
|
||||
// 3. Properties set via the restricted proxy throw immediately, making post-hoc validation redundant
|
||||
// DATA MODE: Normalize this.data through serialize/deserialize round-trip
|
||||
// This ensures "hot" data (fresh from on_load) behaves identically to "cold" data
|
||||
// (restored from cache). Unregistered class instances become plain objects immediately,
|
||||
// so developers catch missing class registrations during development rather than
|
||||
// only after a page reload when data comes from cache.
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (cache_mode === 'data') {
|
||||
const normalized = Jqhtml_Local_Storage.normalize_for_cache(this.data);
|
||||
this.data = normalized;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) normalized this.data after on_load()`, { data: this.data });
|
||||
// Return the data from the detached context
|
||||
return detached_context.data;
|
||||
}
|
||||
/**
|
||||
* Apply the result of on_load() to this.data via the sequential queue.
|
||||
*
|
||||
* Multiple _load calls can execute on_load in parallel, but this method
|
||||
* ensures that setting this.data happens in FIFO order.
|
||||
*
|
||||
* @param result_data - The data returned from _execute_on_load_detached
|
||||
* @param data_before_load - JSON string of this.data before on_load (for change detection), or null
|
||||
* @private
|
||||
*/
|
||||
async _apply_load_result(result_data, data_before_load) {
|
||||
// Queue this operation - wait for any earlier _load calls to finish setting data
|
||||
const my_turn = this._load_queue;
|
||||
let resolve_my_turn;
|
||||
this._load_queue = new Promise((resolve) => {
|
||||
resolve_my_turn = resolve;
|
||||
});
|
||||
// Wait for our turn
|
||||
await my_turn;
|
||||
try {
|
||||
// Now it's our turn to set this.data
|
||||
// Unfreeze, set data, freeze
|
||||
this.__data_frozen = false;
|
||||
this.data = result_data;
|
||||
// DATA MODE: Normalize this.data through serialize/deserialize round-trip
|
||||
// This ensures "hot" data (fresh from on_load) behaves identically to "cold" data
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (cache_mode === 'data') {
|
||||
const normalized = Jqhtml_Local_Storage.normalize_for_cache(this.data);
|
||||
this.data = normalized;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) normalized this.data after on_load()`, { data: this.data });
|
||||
}
|
||||
}
|
||||
}
|
||||
// Freeze this.data after normalization completes
|
||||
this.__data_frozen = true;
|
||||
// CACHE WRITE - If data changed during on_load(), write to cache based on mode
|
||||
const data_after_load = JSON.stringify(this.data);
|
||||
const data_changed = data_after_load !== data_before_load;
|
||||
// Track if component is "dynamic" (this.data changed during on_load)
|
||||
// Used by HTML cache mode for synchronization - static parents don't block children
|
||||
this._is_dynamic = data_changed && data_after_load !== '{}';
|
||||
if (this._is_dynamic) {
|
||||
if (this._cache_key) {
|
||||
// Freeze this.data
|
||||
this.__data_frozen = true;
|
||||
// Calculate if data changed
|
||||
const data_after_load = JSON.stringify(this.data);
|
||||
const data_changed = data_before_load !== null && data_after_load !== data_before_load;
|
||||
// Track if component is "dynamic" (this.data changed during on_load)
|
||||
// Used by HTML cache mode for synchronization - static parents don't block children
|
||||
this._is_dynamic = data_changed && data_after_load !== '{}';
|
||||
// CACHE WRITE - If data changed during on_load(), write to cache based on mode
|
||||
if (this._is_dynamic && this._cache_key) {
|
||||
if (cache_mode === 'html') {
|
||||
// HTML cache mode - flag to cache HTML after children ready in _ready()
|
||||
this._should_cache_html_after_ready = true;
|
||||
@@ -3037,12 +3099,16 @@ class Jqhtml_Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
this._ready_state = 2;
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete');
|
||||
// Emit lifecycle event
|
||||
this.trigger('load');
|
||||
}
|
||||
finally {
|
||||
// Signal next in queue
|
||||
resolve_my_turn();
|
||||
}
|
||||
this._ready_state = 2;
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete');
|
||||
// Emit lifecycle event
|
||||
this.trigger('load');
|
||||
}
|
||||
/**
|
||||
* Ready phase - Component fully initialized
|
||||
@@ -3305,6 +3371,18 @@ class Jqhtml_Component {
|
||||
if (this._stopped)
|
||||
return;
|
||||
this._log_lifecycle('reload', 'start');
|
||||
// OPTIMIZATION: If no custom on_load(), skip data fetching entirely
|
||||
// Just re-render with current data and call on_ready
|
||||
if (!this.__has_custom_on_load) {
|
||||
// Reset state machine
|
||||
this.next_reload_force_refresh = null;
|
||||
this._render();
|
||||
await this._wait_for_children_ready();
|
||||
await this._call_lifecycle('on_ready');
|
||||
this.trigger('ready');
|
||||
this._log_lifecycle('reload', 'complete (no on_load)');
|
||||
return;
|
||||
}
|
||||
// STEP 1: Cache check (if args changed)
|
||||
let rendered_from_cache = false;
|
||||
let data_before_load = null;
|
||||
@@ -3374,72 +3452,16 @@ class Jqhtml_Component {
|
||||
}
|
||||
// Capture data state before on_load for comparison
|
||||
data_before_load = JSON.stringify(this.data);
|
||||
// STEP 2: Call on_load() to fetch fresh data
|
||||
// Unfreeze this.data so we can restore snapshot and on_load() can modify it
|
||||
this.__data_frozen = false;
|
||||
// Restore this.data to initial state from snapshot (if not first load)
|
||||
if (this.__initial_data_snapshot) {
|
||||
this.data = JSON.parse(JSON.stringify(this.__initial_data_snapshot));
|
||||
}
|
||||
try {
|
||||
await this._call_lifecycle('on_load');
|
||||
}
|
||||
finally {
|
||||
// Freeze this.data after on_load() completes
|
||||
this.__data_frozen = true;
|
||||
}
|
||||
// DATA MODE: Normalize this.data through serialize/deserialize round-trip
|
||||
// (Same as in _load() - ensures hot/cold cache parity)
|
||||
const reload_cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (reload_cache_mode === 'data') {
|
||||
this.__data_frozen = false;
|
||||
const normalized = Jqhtml_Local_Storage.normalize_for_cache(this.data);
|
||||
this.data = normalized;
|
||||
this.__data_frozen = true;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) normalized this.data after on_load() in reload()`, { data: this.data });
|
||||
}
|
||||
}
|
||||
// Check if data changed during on_load() - if so, update cache (but not if empty)
|
||||
// STEP 2: Call on_load() on detached proxy
|
||||
// This uses the same detached execution as _load() - on_load runs isolated
|
||||
// and result is applied via sequential queue
|
||||
const result_data = await this._execute_on_load_detached(false); // false = don't use Load_Coordinator
|
||||
// Apply result via sequential queue
|
||||
// This handles normalization, caching, and setting _is_dynamic
|
||||
await this._apply_load_result(result_data, data_before_load);
|
||||
// Re-read data state after apply (for render decision below)
|
||||
const data_after_load = JSON.stringify(this.data);
|
||||
const data_changed = data_after_load !== data_before_load;
|
||||
if (data_changed && data_after_load !== '{}') {
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
if (typeof this.cache_id === 'function') {
|
||||
try {
|
||||
const custom_cache_id = this.cache_id();
|
||||
cache_key = `${this.component_name()}::${String(custom_cache_id)}`;
|
||||
}
|
||||
catch (error) {
|
||||
// cache_id() threw error - disable caching
|
||||
cache_key = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use standard args-based cache key generation
|
||||
const result = Load_Coordinator.generate_invocation_key(this.component_name(), this.args);
|
||||
cache_key = result.key;
|
||||
}
|
||||
// Write to cache based on mode
|
||||
if (cache_key !== null) {
|
||||
this._cache_key = cache_key;
|
||||
if (reload_cache_mode === 'html') {
|
||||
// HTML cache mode - flag to cache HTML after children ready in _ready()
|
||||
this._should_cache_html_after_ready = true;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) will cache HTML after ready in reload()`, { cache_key });
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Data cache mode (default) - write this.data to cache
|
||||
Jqhtml_Local_Storage.set(cache_key, this.data);
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) cached data after on_load() in reload()`, { cache_key, data: this.data });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// STEP 3: Conditionally re-render (with refresh() support)
|
||||
// Read force_refresh from state machine (default true)
|
||||
const force_refresh = this.next_reload_force_refresh !== null ? this.next_reload_force_refresh : true;
|
||||
@@ -3573,6 +3595,11 @@ class Jqhtml_Component {
|
||||
this._used_cached_html = false;
|
||||
return true;
|
||||
}
|
||||
// OPTIMIZATION: If no custom on_load(), data cannot change, skip serialization
|
||||
// Data is frozen after on_create() and only unfrozen during on_load()
|
||||
if (!this.__has_custom_on_load) {
|
||||
return false;
|
||||
}
|
||||
// Compare current data state with data state before initial render
|
||||
const currentDataState = JSON.stringify(this.data);
|
||||
const dataChanged = this._data_before_render !== currentDataState;
|
||||
@@ -4817,7 +4844,7 @@ function init(jQuery) {
|
||||
}
|
||||
}
|
||||
// Version - will be replaced during build with actual version from package.json
|
||||
const version = '2.3.20';
|
||||
const version = '2.3.21';
|
||||
// Default export with all functionality
|
||||
const jqhtml = {
|
||||
// Core
|
||||
|
||||
2
node_modules/@jqhtml/core/dist/index.cjs.map
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/core/dist/index.cjs.map
generated
vendored
Executable file → Normal file
File diff suppressed because one or more lines are too long
0
node_modules/@jqhtml/core/dist/index.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/index.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/index.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/index.d.ts.map
generated
vendored
Executable file → Normal file
475
node_modules/@jqhtml/core/dist/index.js
generated
vendored
Executable file → Normal file
475
node_modules/@jqhtml/core/dist/index.js
generated
vendored
Executable file → Normal file
@@ -2134,6 +2134,17 @@ class Jqhtml_Component {
|
||||
// rendered event - fires once after the synchronous render chain completes
|
||||
// (after on_load's re-render if applicable, or after first render if no on_load)
|
||||
this._has_rendered = false;
|
||||
// Sequential queue for setting this.data after on_load completes
|
||||
// Multiple _load calls can run on_load in parallel, but setting this.data is serialized
|
||||
this._load_queue = Promise.resolve();
|
||||
// Cached flag: true if this component has a custom on_load() override
|
||||
// Set in constructor (prototype chain is established before constructor runs)
|
||||
// Used to skip expensive cache/load operations for static components
|
||||
this.__has_custom_on_load = false;
|
||||
// Detect custom on_load() override immediately
|
||||
// Prototype chain is set up before constructor runs, so this.on_load
|
||||
// correctly resolves to child class override if one exists
|
||||
this.__has_custom_on_load = this.on_load !== Jqhtml_Component.prototype.on_load;
|
||||
this._cid = this._generate_cid();
|
||||
this._lifecycle_manager = LifecycleManager.get_instance();
|
||||
// Create or wrap element
|
||||
@@ -2314,14 +2325,11 @@ class Jqhtml_Component {
|
||||
/**
|
||||
* Check if on_load() is overridden in a subclass
|
||||
* Used to skip the load phase entirely for components that don't fetch data
|
||||
* Returns cached value set in _boot() for O(1) performance
|
||||
* @private
|
||||
*/
|
||||
_has_on_load() {
|
||||
// Get this instance's on_load implementation
|
||||
const impl = lifecycle_impls.get(this)?.['on_load'] || this.on_load;
|
||||
// Compare to base class implementation
|
||||
// If they're the same function reference, it wasn't overridden
|
||||
return impl !== Jqhtml_Component.prototype.on_load;
|
||||
return this.__has_custom_on_load;
|
||||
}
|
||||
/**
|
||||
* Boot - Start the full component lifecycle
|
||||
@@ -2337,6 +2345,7 @@ class Jqhtml_Component {
|
||||
return;
|
||||
this._booted = true;
|
||||
// Protect lifecycle methods from manual invocation (must happen after subclass constructor)
|
||||
// Note: __has_custom_on_load is already set in constructor
|
||||
this._protect_lifecycle_methods();
|
||||
await this._lifecycle_manager.boot_component(this);
|
||||
}
|
||||
@@ -2689,98 +2698,102 @@ class Jqhtml_Component {
|
||||
`on_create() must be synchronous code. Remove 'async' from the function declaration.`);
|
||||
// Don't await - on_create MUST be sync. The warning is enough.
|
||||
}
|
||||
// CACHE CHECK - Read from cache based on cache mode ('data' or 'html')
|
||||
// This happens after on_create() but before render, allowing instant first render
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
let uncacheable_property;
|
||||
if (typeof this.cache_id === 'function') {
|
||||
try {
|
||||
const custom_cache_id = this.cache_id();
|
||||
cache_key = `${this.component_name()}::${String(custom_cache_id)}`;
|
||||
}
|
||||
catch (error) {
|
||||
// cache_id() threw error - disable caching
|
||||
uncacheable_property = 'cache_id()';
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use standard args-based cache key generation
|
||||
const result = Load_Coordinator.generate_invocation_key(this.component_name(), this.args);
|
||||
cache_key = result.key;
|
||||
uncacheable_property = result.uncacheable_property;
|
||||
}
|
||||
// If cache_key is null, caching disabled
|
||||
if (cache_key === null) {
|
||||
// Set data-nocache attribute for debugging (shows which property prevented caching)
|
||||
if (uncacheable_property) {
|
||||
this.$.attr('data-nocache', uncacheable_property);
|
||||
}
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - caching disabled`, { uncacheable_property });
|
||||
}
|
||||
// Don't return - continue to snapshot this.data for on_load restoration
|
||||
}
|
||||
else {
|
||||
// Store cache key for later use
|
||||
this._cache_key = cache_key;
|
||||
// Get cache mode
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache ${cache_mode}] Component ${this._cid} (${this.component_name()}) checking cache in create()`, { cache_key, cache_mode, has_cache_key_set: Jqhtml_Local_Storage.has_cache_key() });
|
||||
}
|
||||
if (cache_mode === 'html') {
|
||||
// HTML cache mode - check for cached HTML to inject on first render
|
||||
const html_cache_key = `${cache_key}::html`;
|
||||
const cached_html = Jqhtml_Local_Storage.get(html_cache_key);
|
||||
if (cached_html !== null && typeof cached_html === 'string') {
|
||||
// Store cached HTML for injection in _render()
|
||||
this._cached_html = cached_html;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) found cached HTML`, { cache_key: html_cache_key, html_length: cached_html.length });
|
||||
}
|
||||
// OPTIMIZATION: Skip cache operations and snapshot if no custom on_load()
|
||||
// Components without on_load() don't fetch data, so nothing to cache or restore
|
||||
if (this.__has_custom_on_load) {
|
||||
// CACHE CHECK - Read from cache based on cache mode ('data' or 'html')
|
||||
// This happens after on_create() but before render, allowing instant first render
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
let uncacheable_property;
|
||||
if (typeof this.cache_id === 'function') {
|
||||
try {
|
||||
const custom_cache_id = this.cache_id();
|
||||
cache_key = `${this.component_name()}::${String(custom_cache_id)}`;
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key: html_cache_key });
|
||||
}
|
||||
}
|
||||
// Warn if use_cached_data is set in html cache mode - it has no effect
|
||||
if (this.args.use_cached_data === true) {
|
||||
console.warn(`[JQHTML] Component "${this.component_name()}" has use_cached_data=true but cache mode is 'html'.\n` +
|
||||
`use_cached_data only applies to 'data' cache mode. In 'html' mode, the entire rendered HTML is cached.\n` +
|
||||
`The use_cached_data flag will be ignored.`);
|
||||
catch (error) {
|
||||
// cache_id() threw error - disable caching
|
||||
uncacheable_property = 'cache_id()';
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Data cache mode (default) - check for cached data to hydrate this.data
|
||||
const cached_data = Jqhtml_Local_Storage.get(cache_key);
|
||||
if (cached_data !== null && typeof cached_data === 'object') {
|
||||
// Hydrate this.data with cached data
|
||||
this.data = cached_data;
|
||||
// If use_cached_data=true, skip on_load() entirely - use cached data as final data
|
||||
if (this.args.use_cached_data === true) {
|
||||
this._use_cached_data_hit = true;
|
||||
// Use standard args-based cache key generation
|
||||
const result = Load_Coordinator.generate_invocation_key(this.component_name(), this.args);
|
||||
cache_key = result.key;
|
||||
uncacheable_property = result.uncacheable_property;
|
||||
}
|
||||
// If cache_key is null, caching disabled
|
||||
if (cache_key === null) {
|
||||
// Set data-nocache attribute for debugging (shows which property prevented caching)
|
||||
if (uncacheable_property) {
|
||||
this.$.attr('data-nocache', uncacheable_property);
|
||||
}
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - caching disabled`, { uncacheable_property });
|
||||
}
|
||||
// Don't return - continue to snapshot this.data for on_load restoration
|
||||
}
|
||||
else {
|
||||
// Store cache key for later use
|
||||
this._cache_key = cache_key;
|
||||
// Get cache mode
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache ${cache_mode}] Component ${this._cid} (${this.component_name()}) checking cache in create()`, { cache_key, cache_mode, has_cache_key_set: Jqhtml_Local_Storage.has_cache_key() });
|
||||
}
|
||||
if (cache_mode === 'html') {
|
||||
// HTML cache mode - check for cached HTML to inject on first render
|
||||
const html_cache_key = `${cache_key}::html`;
|
||||
const cached_html = Jqhtml_Local_Storage.get(html_cache_key);
|
||||
if (cached_html !== null && typeof cached_html === 'string') {
|
||||
// Store cached HTML for injection in _render()
|
||||
this._cached_html = cached_html;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) using cached data (use_cached_data=true, skipping on_load)`, { cache_key, data: cached_data });
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) found cached HTML`, { cache_key: html_cache_key, html_length: cached_html.length });
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) hydrated from cache`, { cache_key, data: cached_data });
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key: html_cache_key });
|
||||
}
|
||||
}
|
||||
// Warn if use_cached_data is set in html cache mode - it has no effect
|
||||
if (this.args.use_cached_data === true) {
|
||||
console.warn(`[JQHTML] Component "${this.component_name()}" has use_cached_data=true but cache mode is 'html'.\n` +
|
||||
`use_cached_data only applies to 'data' cache mode. In 'html' mode, the entire rendered HTML is cached.\n` +
|
||||
`The use_cached_data flag will be ignored.`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key });
|
||||
// Data cache mode (default) - check for cached data to hydrate this.data
|
||||
const cached_data = Jqhtml_Local_Storage.get(cache_key);
|
||||
if (cached_data !== null && typeof cached_data === 'object') {
|
||||
// Hydrate this.data with cached data
|
||||
this.data = cached_data;
|
||||
// If use_cached_data=true, skip on_load() entirely - use cached data as final data
|
||||
if (this.args.use_cached_data === true) {
|
||||
this._use_cached_data_hit = true;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) using cached data (use_cached_data=true, skipping on_load)`, { cache_key, data: cached_data });
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) hydrated from cache`, { cache_key, data: cached_data });
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Snapshot this.data after on_create() completes
|
||||
// This will be restored before each on_load() execution to reset state
|
||||
this.__initial_data_snapshot = JSON.parse(JSON.stringify(this.data));
|
||||
}
|
||||
// Snapshot this.data after on_create() completes
|
||||
// This will be restored before each on_load() execution to reset state
|
||||
this.__initial_data_snapshot = JSON.parse(JSON.stringify(this.data));
|
||||
// Freeze this.data after on_create() - only on_load() can modify it now
|
||||
this.__data_frozen = true;
|
||||
this._ready_state = 1;
|
||||
@@ -2790,9 +2803,14 @@ class Jqhtml_Component {
|
||||
this.trigger('create');
|
||||
}
|
||||
/**
|
||||
* Load phase - Fetch data from APIs
|
||||
* Load phase - Fetch asynchronous data
|
||||
* Called bottom-up, fully parallel
|
||||
* NO DOM MODIFICATIONS ALLOWED IN THIS PHASE
|
||||
*
|
||||
* Key design: on_load() runs on a DETACHED proxy with a clone of this.data.
|
||||
* The real component's this.data is not touched during on_load execution.
|
||||
* After on_load completes, the result is applied via a sequential queue.
|
||||
*
|
||||
* @private - Internal lifecycle method, not for external use
|
||||
*/
|
||||
async _load() {
|
||||
@@ -2808,14 +2826,6 @@ class Jqhtml_Component {
|
||||
this.trigger('load');
|
||||
return;
|
||||
}
|
||||
// Restore this.data to initial state from snapshot (skip on first load)
|
||||
// This ensures on_load() always starts with clean state
|
||||
const is_first_load = this._ready_state < 2;
|
||||
if (!is_first_load && this.__initial_data_snapshot) {
|
||||
this.data = JSON.parse(JSON.stringify(this.__initial_data_snapshot));
|
||||
}
|
||||
// Unfreeze this.data so on_load() can modify it
|
||||
this.__data_frozen = false;
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
let uncacheable_property;
|
||||
@@ -2835,6 +2845,8 @@ class Jqhtml_Component {
|
||||
cache_key = result.key;
|
||||
uncacheable_property = result.uncacheable_property;
|
||||
}
|
||||
// Store cache key for later use
|
||||
this._cache_key = cache_key;
|
||||
// If cache_key is null, args are not serializable - skip load deduplication and caching
|
||||
if (cache_key === null) {
|
||||
// Set data-nocache attribute for debugging (shows which property prevented caching)
|
||||
@@ -2844,9 +2856,10 @@ class Jqhtml_Component {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - load deduplication and caching disabled`, { uncacheable_property });
|
||||
}
|
||||
// Execute on_load() with authorization, without deduplication or caching
|
||||
await this._call_lifecycle('on_load');
|
||||
this.__data_frozen = true;
|
||||
// Execute on_load on detached proxy without deduplication
|
||||
const result_data = await this._execute_on_load_detached();
|
||||
// Apply result via sequential queue
|
||||
await this._apply_load_result(result_data, null);
|
||||
return;
|
||||
}
|
||||
// Store "before" snapshot for comparison after on_load()
|
||||
@@ -2880,10 +2893,39 @@ class Jqhtml_Component {
|
||||
this.trigger('load');
|
||||
return;
|
||||
}
|
||||
// This component is a leader - execute on_load() normally
|
||||
// This component is a leader - execute on_load() on detached proxy
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Load Deduplication] Component ${this._cid} (${this.component_name()}) is the leader`, { args: this.args });
|
||||
}
|
||||
// Execute on_load on detached proxy with Load_Coordinator registration
|
||||
const result_data = await this._execute_on_load_detached(true);
|
||||
// Apply result via sequential queue
|
||||
await this._apply_load_result(result_data, data_before_load);
|
||||
}
|
||||
/**
|
||||
* Execute on_load() on a fully detached proxy.
|
||||
*
|
||||
* The proxy has:
|
||||
* - A CLONE of this.data (from __initial_data_snapshot)
|
||||
* - Read-only access to this.args
|
||||
* - No access to anything else (this.$, this.sid, etc.)
|
||||
*
|
||||
* This ensures on_load runs completely isolated from the component instance.
|
||||
*
|
||||
* @param use_load_coordinator - If true, register with Load_Coordinator for deduplication
|
||||
* @returns The resulting data from the proxy after on_load completes
|
||||
* @private
|
||||
*/
|
||||
async _execute_on_load_detached(use_load_coordinator = false) {
|
||||
// Clone this.data from the snapshot captured after on_create()
|
||||
const data_clone = this.__initial_data_snapshot
|
||||
? JSON.parse(JSON.stringify(this.__initial_data_snapshot))
|
||||
: {};
|
||||
// Create a detached context object that on_load will operate on
|
||||
const detached_context = {
|
||||
args: this.args, // Read-only reference to real args
|
||||
data: data_clone // Cloned data - modifications stay isolated
|
||||
};
|
||||
// Capture args state before on_load() for validation
|
||||
let argsBeforeLoad = null;
|
||||
try {
|
||||
@@ -2894,17 +2936,21 @@ class Jqhtml_Component {
|
||||
}
|
||||
// Set loading flag to prevent render() calls during on_load()
|
||||
this.__loading = true;
|
||||
// Create restricted proxy to prevent DOM access during on_load()
|
||||
const restricted_this = new Proxy(this, {
|
||||
// Create restricted proxy that operates on the detached context
|
||||
const component_name = this.component_name();
|
||||
const restricted_this = new Proxy(detached_context, {
|
||||
get(target, prop) {
|
||||
// Only allow access to this.args and this.data
|
||||
if (prop === 'args' || prop === 'data') {
|
||||
return target[prop];
|
||||
// Only allow access to args and data
|
||||
if (prop === 'args') {
|
||||
return target.args;
|
||||
}
|
||||
if (prop === 'data') {
|
||||
return target.data;
|
||||
}
|
||||
// Block everything else
|
||||
console.error(`[JQHTML] ERROR: Component "${target.component_name()}" attempted to access this.${String(prop)} during on_load().\n\n` +
|
||||
console.error(`[JQHTML] ERROR: Component "${component_name}" attempted to access this.${String(prop)} during on_load().\n\n` +
|
||||
`RESTRICTION: on_load() may ONLY access:\n` +
|
||||
` - this.args (read during on_load, modify before/after)\n` +
|
||||
` - this.args (read-only)\n` +
|
||||
` - this.data (read/write)\n\n` +
|
||||
`WHY: on_load() is for data fetching only. All other component functionality should happen in other lifecycle methods.\n\n` +
|
||||
`FIX:\n` +
|
||||
@@ -2915,14 +2961,14 @@ class Jqhtml_Component {
|
||||
`on_load() may only access this.args and this.data.`);
|
||||
},
|
||||
set(target, prop, value) {
|
||||
// Only allow setting this.data
|
||||
// Only allow setting data
|
||||
if (prop === 'data') {
|
||||
target[prop] = value;
|
||||
target.data = value;
|
||||
return true;
|
||||
}
|
||||
// Block setting this.args
|
||||
// Block setting args
|
||||
if (prop === 'args') {
|
||||
console.error(`[JQHTML] ERROR: Component "${target.component_name()}" attempted to modify this.args during on_load().\n\n` +
|
||||
console.error(`[JQHTML] ERROR: Component "${component_name}" attempted to modify this.args during on_load().\n\n` +
|
||||
`RESTRICTION: on_load() may ONLY modify:\n` +
|
||||
` - this.data (read/write)\n\n` +
|
||||
`WHY: this.args is component state that on_load() depends on. Modifying it inside on_load() creates circular dependencies.\n\n` +
|
||||
@@ -2933,7 +2979,7 @@ class Jqhtml_Component {
|
||||
`Modify this.args in other lifecycle methods, not inside on_load().`);
|
||||
}
|
||||
// Block setting any other properties
|
||||
console.error(`[JQHTML] ERROR: Component "${target.component_name()}" attempted to modify this.${String(prop)} during on_load().\n\n` +
|
||||
console.error(`[JQHTML] ERROR: Component "${component_name}" attempted to modify this.${String(prop)} during on_load().\n\n` +
|
||||
`RESTRICTION: on_load() may ONLY modify:\n` +
|
||||
` - this.data (read/write)\n\n` +
|
||||
`WHY: on_load() is for data fetching only. Setting properties on the component instance should happen in other lifecycle methods.\n\n` +
|
||||
@@ -2944,35 +2990,36 @@ class Jqhtml_Component {
|
||||
`Only this.data can be modified in on_load().`);
|
||||
}
|
||||
});
|
||||
// Create promise for this on_load() call with restricted this context
|
||||
// Create promise for this on_load() call
|
||||
const on_load_promise = (async () => {
|
||||
try {
|
||||
// TODO: Implement proper error handling for on_load() failures
|
||||
// - Should errors trigger re-render with error state?
|
||||
// - Should errors clear cached data?
|
||||
// - Should errors reset state machine flags (next_reload_force_refresh)?
|
||||
// - Should partial data be preserved or rolled back?
|
||||
// - Should followers be notified differently based on error type?
|
||||
await this._call_lifecycle('on_load', restricted_this);
|
||||
}
|
||||
catch (error) {
|
||||
// Handle error and notify coordinator
|
||||
Load_Coordinator.handle_leader_error(this, error);
|
||||
if (use_load_coordinator) {
|
||||
// Handle error and notify coordinator
|
||||
Load_Coordinator.handle_leader_error(this, error);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
})();
|
||||
// Register as leader and get cleanup function
|
||||
const complete_coordination = Load_Coordinator.register_leader(this, on_load_promise);
|
||||
// If using Load_Coordinator, register as leader
|
||||
let complete_coordination = null;
|
||||
if (use_load_coordinator) {
|
||||
complete_coordination = Load_Coordinator.register_leader(this, on_load_promise);
|
||||
}
|
||||
try {
|
||||
await on_load_promise;
|
||||
}
|
||||
finally {
|
||||
// Always clear loading flag and complete coordination
|
||||
// Always clear loading flag
|
||||
this.__loading = false;
|
||||
complete_coordination();
|
||||
// Note: this.data stays unfrozen until after normalization below
|
||||
// Complete coordination if we registered
|
||||
if (complete_coordination) {
|
||||
complete_coordination();
|
||||
}
|
||||
}
|
||||
// Validate that on_load() only modified this.data
|
||||
// Validate that on_load() didn't somehow modify this.args (shouldn't be possible with new proxy)
|
||||
let argsAfterLoad = null;
|
||||
try {
|
||||
argsAfterLoad = JSON.stringify(this.args);
|
||||
@@ -2980,44 +3027,59 @@ class Jqhtml_Component {
|
||||
catch (error) {
|
||||
// Args contain circular references - skip validation
|
||||
}
|
||||
// Check if args were modified (skip if args are non-serializable)
|
||||
if (argsBeforeLoad !== null && argsAfterLoad !== null && argsBeforeLoad !== argsAfterLoad) {
|
||||
console.error(`[JQHTML] WARNING: Component "${this.component_name()}" modified this.args in on_load().\n` +
|
||||
`on_load() should ONLY modify this.data.\n\n` +
|
||||
console.error(`[JQHTML] WARNING: Component "${this.component_name()}" somehow modified this.args during on_load().\n` +
|
||||
`This should not be possible with the detached proxy. Please report this bug.\n\n` +
|
||||
`Before: ${argsBeforeLoad}\n` +
|
||||
`After: ${argsAfterLoad}\n\n` +
|
||||
`Fix: Modify this.args in on_create() or other lifecycle methods, not in on_load().\n` +
|
||||
`this.args stores state that on_load() depends on. Modifying it inside on_load() creates circular dependencies.`);
|
||||
`After: ${argsAfterLoad}`);
|
||||
}
|
||||
// NOTE: We previously checked for new properties being added to the component instance
|
||||
// during on_load() and warned about them. However, this validation was removed because:
|
||||
// 1. The restricted proxy already throws errors if code tries to set properties during on_load()
|
||||
// 2. The validation was producing false positives for properties set during template render
|
||||
// (templates can legitimately set this.* properties in code blocks like <% this._tabs = [...] %>)
|
||||
// 3. Properties set via the restricted proxy throw immediately, making post-hoc validation redundant
|
||||
// DATA MODE: Normalize this.data through serialize/deserialize round-trip
|
||||
// This ensures "hot" data (fresh from on_load) behaves identically to "cold" data
|
||||
// (restored from cache). Unregistered class instances become plain objects immediately,
|
||||
// so developers catch missing class registrations during development rather than
|
||||
// only after a page reload when data comes from cache.
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (cache_mode === 'data') {
|
||||
const normalized = Jqhtml_Local_Storage.normalize_for_cache(this.data);
|
||||
this.data = normalized;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) normalized this.data after on_load()`, { data: this.data });
|
||||
// Return the data from the detached context
|
||||
return detached_context.data;
|
||||
}
|
||||
/**
|
||||
* Apply the result of on_load() to this.data via the sequential queue.
|
||||
*
|
||||
* Multiple _load calls can execute on_load in parallel, but this method
|
||||
* ensures that setting this.data happens in FIFO order.
|
||||
*
|
||||
* @param result_data - The data returned from _execute_on_load_detached
|
||||
* @param data_before_load - JSON string of this.data before on_load (for change detection), or null
|
||||
* @private
|
||||
*/
|
||||
async _apply_load_result(result_data, data_before_load) {
|
||||
// Queue this operation - wait for any earlier _load calls to finish setting data
|
||||
const my_turn = this._load_queue;
|
||||
let resolve_my_turn;
|
||||
this._load_queue = new Promise((resolve) => {
|
||||
resolve_my_turn = resolve;
|
||||
});
|
||||
// Wait for our turn
|
||||
await my_turn;
|
||||
try {
|
||||
// Now it's our turn to set this.data
|
||||
// Unfreeze, set data, freeze
|
||||
this.__data_frozen = false;
|
||||
this.data = result_data;
|
||||
// DATA MODE: Normalize this.data through serialize/deserialize round-trip
|
||||
// This ensures "hot" data (fresh from on_load) behaves identically to "cold" data
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (cache_mode === 'data') {
|
||||
const normalized = Jqhtml_Local_Storage.normalize_for_cache(this.data);
|
||||
this.data = normalized;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) normalized this.data after on_load()`, { data: this.data });
|
||||
}
|
||||
}
|
||||
}
|
||||
// Freeze this.data after normalization completes
|
||||
this.__data_frozen = true;
|
||||
// CACHE WRITE - If data changed during on_load(), write to cache based on mode
|
||||
const data_after_load = JSON.stringify(this.data);
|
||||
const data_changed = data_after_load !== data_before_load;
|
||||
// Track if component is "dynamic" (this.data changed during on_load)
|
||||
// Used by HTML cache mode for synchronization - static parents don't block children
|
||||
this._is_dynamic = data_changed && data_after_load !== '{}';
|
||||
if (this._is_dynamic) {
|
||||
if (this._cache_key) {
|
||||
// Freeze this.data
|
||||
this.__data_frozen = true;
|
||||
// Calculate if data changed
|
||||
const data_after_load = JSON.stringify(this.data);
|
||||
const data_changed = data_before_load !== null && data_after_load !== data_before_load;
|
||||
// Track if component is "dynamic" (this.data changed during on_load)
|
||||
// Used by HTML cache mode for synchronization - static parents don't block children
|
||||
this._is_dynamic = data_changed && data_after_load !== '{}';
|
||||
// CACHE WRITE - If data changed during on_load(), write to cache based on mode
|
||||
if (this._is_dynamic && this._cache_key) {
|
||||
if (cache_mode === 'html') {
|
||||
// HTML cache mode - flag to cache HTML after children ready in _ready()
|
||||
this._should_cache_html_after_ready = true;
|
||||
@@ -3033,12 +3095,16 @@ class Jqhtml_Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
this._ready_state = 2;
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete');
|
||||
// Emit lifecycle event
|
||||
this.trigger('load');
|
||||
}
|
||||
finally {
|
||||
// Signal next in queue
|
||||
resolve_my_turn();
|
||||
}
|
||||
this._ready_state = 2;
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete');
|
||||
// Emit lifecycle event
|
||||
this.trigger('load');
|
||||
}
|
||||
/**
|
||||
* Ready phase - Component fully initialized
|
||||
@@ -3301,6 +3367,18 @@ class Jqhtml_Component {
|
||||
if (this._stopped)
|
||||
return;
|
||||
this._log_lifecycle('reload', 'start');
|
||||
// OPTIMIZATION: If no custom on_load(), skip data fetching entirely
|
||||
// Just re-render with current data and call on_ready
|
||||
if (!this.__has_custom_on_load) {
|
||||
// Reset state machine
|
||||
this.next_reload_force_refresh = null;
|
||||
this._render();
|
||||
await this._wait_for_children_ready();
|
||||
await this._call_lifecycle('on_ready');
|
||||
this.trigger('ready');
|
||||
this._log_lifecycle('reload', 'complete (no on_load)');
|
||||
return;
|
||||
}
|
||||
// STEP 1: Cache check (if args changed)
|
||||
let rendered_from_cache = false;
|
||||
let data_before_load = null;
|
||||
@@ -3370,72 +3448,16 @@ class Jqhtml_Component {
|
||||
}
|
||||
// Capture data state before on_load for comparison
|
||||
data_before_load = JSON.stringify(this.data);
|
||||
// STEP 2: Call on_load() to fetch fresh data
|
||||
// Unfreeze this.data so we can restore snapshot and on_load() can modify it
|
||||
this.__data_frozen = false;
|
||||
// Restore this.data to initial state from snapshot (if not first load)
|
||||
if (this.__initial_data_snapshot) {
|
||||
this.data = JSON.parse(JSON.stringify(this.__initial_data_snapshot));
|
||||
}
|
||||
try {
|
||||
await this._call_lifecycle('on_load');
|
||||
}
|
||||
finally {
|
||||
// Freeze this.data after on_load() completes
|
||||
this.__data_frozen = true;
|
||||
}
|
||||
// DATA MODE: Normalize this.data through serialize/deserialize round-trip
|
||||
// (Same as in _load() - ensures hot/cold cache parity)
|
||||
const reload_cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (reload_cache_mode === 'data') {
|
||||
this.__data_frozen = false;
|
||||
const normalized = Jqhtml_Local_Storage.normalize_for_cache(this.data);
|
||||
this.data = normalized;
|
||||
this.__data_frozen = true;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) normalized this.data after on_load() in reload()`, { data: this.data });
|
||||
}
|
||||
}
|
||||
// Check if data changed during on_load() - if so, update cache (but not if empty)
|
||||
// STEP 2: Call on_load() on detached proxy
|
||||
// This uses the same detached execution as _load() - on_load runs isolated
|
||||
// and result is applied via sequential queue
|
||||
const result_data = await this._execute_on_load_detached(false); // false = don't use Load_Coordinator
|
||||
// Apply result via sequential queue
|
||||
// This handles normalization, caching, and setting _is_dynamic
|
||||
await this._apply_load_result(result_data, data_before_load);
|
||||
// Re-read data state after apply (for render decision below)
|
||||
const data_after_load = JSON.stringify(this.data);
|
||||
const data_changed = data_after_load !== data_before_load;
|
||||
if (data_changed && data_after_load !== '{}') {
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
if (typeof this.cache_id === 'function') {
|
||||
try {
|
||||
const custom_cache_id = this.cache_id();
|
||||
cache_key = `${this.component_name()}::${String(custom_cache_id)}`;
|
||||
}
|
||||
catch (error) {
|
||||
// cache_id() threw error - disable caching
|
||||
cache_key = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use standard args-based cache key generation
|
||||
const result = Load_Coordinator.generate_invocation_key(this.component_name(), this.args);
|
||||
cache_key = result.key;
|
||||
}
|
||||
// Write to cache based on mode
|
||||
if (cache_key !== null) {
|
||||
this._cache_key = cache_key;
|
||||
if (reload_cache_mode === 'html') {
|
||||
// HTML cache mode - flag to cache HTML after children ready in _ready()
|
||||
this._should_cache_html_after_ready = true;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) will cache HTML after ready in reload()`, { cache_key });
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Data cache mode (default) - write this.data to cache
|
||||
Jqhtml_Local_Storage.set(cache_key, this.data);
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) cached data after on_load() in reload()`, { cache_key, data: this.data });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// STEP 3: Conditionally re-render (with refresh() support)
|
||||
// Read force_refresh from state machine (default true)
|
||||
const force_refresh = this.next_reload_force_refresh !== null ? this.next_reload_force_refresh : true;
|
||||
@@ -3569,6 +3591,11 @@ class Jqhtml_Component {
|
||||
this._used_cached_html = false;
|
||||
return true;
|
||||
}
|
||||
// OPTIMIZATION: If no custom on_load(), data cannot change, skip serialization
|
||||
// Data is frozen after on_create() and only unfrozen during on_load()
|
||||
if (!this.__has_custom_on_load) {
|
||||
return false;
|
||||
}
|
||||
// Compare current data state with data state before initial render
|
||||
const currentDataState = JSON.stringify(this.data);
|
||||
const dataChanged = this._data_before_render !== currentDataState;
|
||||
@@ -4813,7 +4840,7 @@ function init(jQuery) {
|
||||
}
|
||||
}
|
||||
// Version - will be replaced during build with actual version from package.json
|
||||
const version = '2.3.20';
|
||||
const version = '2.3.21';
|
||||
// Default export with all functionality
|
||||
const jqhtml = {
|
||||
// Core
|
||||
|
||||
2
node_modules/@jqhtml/core/dist/index.js.map
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/core/dist/index.js.map
generated
vendored
Executable file → Normal file
File diff suppressed because one or more lines are too long
0
node_modules/@jqhtml/core/dist/instruction-processor.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/instruction-processor.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/instruction-processor.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/instruction-processor.d.ts.map
generated
vendored
Executable file → Normal file
477
node_modules/@jqhtml/core/dist/jqhtml-core.esm.js
generated
vendored
Executable file → Normal file
477
node_modules/@jqhtml/core/dist/jqhtml-core.esm.js
generated
vendored
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* JQHTML Core v2.3.20
|
||||
* JQHTML Core v2.3.21
|
||||
* (c) 2025 JQHTML Team
|
||||
* Released under the MIT License
|
||||
*/
|
||||
@@ -2139,6 +2139,17 @@ class Jqhtml_Component {
|
||||
// rendered event - fires once after the synchronous render chain completes
|
||||
// (after on_load's re-render if applicable, or after first render if no on_load)
|
||||
this._has_rendered = false;
|
||||
// Sequential queue for setting this.data after on_load completes
|
||||
// Multiple _load calls can run on_load in parallel, but setting this.data is serialized
|
||||
this._load_queue = Promise.resolve();
|
||||
// Cached flag: true if this component has a custom on_load() override
|
||||
// Set in constructor (prototype chain is established before constructor runs)
|
||||
// Used to skip expensive cache/load operations for static components
|
||||
this.__has_custom_on_load = false;
|
||||
// Detect custom on_load() override immediately
|
||||
// Prototype chain is set up before constructor runs, so this.on_load
|
||||
// correctly resolves to child class override if one exists
|
||||
this.__has_custom_on_load = this.on_load !== Jqhtml_Component.prototype.on_load;
|
||||
this._cid = this._generate_cid();
|
||||
this._lifecycle_manager = LifecycleManager.get_instance();
|
||||
// Create or wrap element
|
||||
@@ -2319,14 +2330,11 @@ class Jqhtml_Component {
|
||||
/**
|
||||
* Check if on_load() is overridden in a subclass
|
||||
* Used to skip the load phase entirely for components that don't fetch data
|
||||
* Returns cached value set in _boot() for O(1) performance
|
||||
* @private
|
||||
*/
|
||||
_has_on_load() {
|
||||
// Get this instance's on_load implementation
|
||||
const impl = lifecycle_impls.get(this)?.['on_load'] || this.on_load;
|
||||
// Compare to base class implementation
|
||||
// If they're the same function reference, it wasn't overridden
|
||||
return impl !== Jqhtml_Component.prototype.on_load;
|
||||
return this.__has_custom_on_load;
|
||||
}
|
||||
/**
|
||||
* Boot - Start the full component lifecycle
|
||||
@@ -2342,6 +2350,7 @@ class Jqhtml_Component {
|
||||
return;
|
||||
this._booted = true;
|
||||
// Protect lifecycle methods from manual invocation (must happen after subclass constructor)
|
||||
// Note: __has_custom_on_load is already set in constructor
|
||||
this._protect_lifecycle_methods();
|
||||
await this._lifecycle_manager.boot_component(this);
|
||||
}
|
||||
@@ -2694,98 +2703,102 @@ class Jqhtml_Component {
|
||||
`on_create() must be synchronous code. Remove 'async' from the function declaration.`);
|
||||
// Don't await - on_create MUST be sync. The warning is enough.
|
||||
}
|
||||
// CACHE CHECK - Read from cache based on cache mode ('data' or 'html')
|
||||
// This happens after on_create() but before render, allowing instant first render
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
let uncacheable_property;
|
||||
if (typeof this.cache_id === 'function') {
|
||||
try {
|
||||
const custom_cache_id = this.cache_id();
|
||||
cache_key = `${this.component_name()}::${String(custom_cache_id)}`;
|
||||
}
|
||||
catch (error) {
|
||||
// cache_id() threw error - disable caching
|
||||
uncacheable_property = 'cache_id()';
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use standard args-based cache key generation
|
||||
const result = Load_Coordinator.generate_invocation_key(this.component_name(), this.args);
|
||||
cache_key = result.key;
|
||||
uncacheable_property = result.uncacheable_property;
|
||||
}
|
||||
// If cache_key is null, caching disabled
|
||||
if (cache_key === null) {
|
||||
// Set data-nocache attribute for debugging (shows which property prevented caching)
|
||||
if (uncacheable_property) {
|
||||
this.$.attr('data-nocache', uncacheable_property);
|
||||
}
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - caching disabled`, { uncacheable_property });
|
||||
}
|
||||
// Don't return - continue to snapshot this.data for on_load restoration
|
||||
}
|
||||
else {
|
||||
// Store cache key for later use
|
||||
this._cache_key = cache_key;
|
||||
// Get cache mode
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache ${cache_mode}] Component ${this._cid} (${this.component_name()}) checking cache in create()`, { cache_key, cache_mode, has_cache_key_set: Jqhtml_Local_Storage.has_cache_key() });
|
||||
}
|
||||
if (cache_mode === 'html') {
|
||||
// HTML cache mode - check for cached HTML to inject on first render
|
||||
const html_cache_key = `${cache_key}::html`;
|
||||
const cached_html = Jqhtml_Local_Storage.get(html_cache_key);
|
||||
if (cached_html !== null && typeof cached_html === 'string') {
|
||||
// Store cached HTML for injection in _render()
|
||||
this._cached_html = cached_html;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) found cached HTML`, { cache_key: html_cache_key, html_length: cached_html.length });
|
||||
}
|
||||
// OPTIMIZATION: Skip cache operations and snapshot if no custom on_load()
|
||||
// Components without on_load() don't fetch data, so nothing to cache or restore
|
||||
if (this.__has_custom_on_load) {
|
||||
// CACHE CHECK - Read from cache based on cache mode ('data' or 'html')
|
||||
// This happens after on_create() but before render, allowing instant first render
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
let uncacheable_property;
|
||||
if (typeof this.cache_id === 'function') {
|
||||
try {
|
||||
const custom_cache_id = this.cache_id();
|
||||
cache_key = `${this.component_name()}::${String(custom_cache_id)}`;
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key: html_cache_key });
|
||||
}
|
||||
}
|
||||
// Warn if use_cached_data is set in html cache mode - it has no effect
|
||||
if (this.args.use_cached_data === true) {
|
||||
console.warn(`[JQHTML] Component "${this.component_name()}" has use_cached_data=true but cache mode is 'html'.\n` +
|
||||
`use_cached_data only applies to 'data' cache mode. In 'html' mode, the entire rendered HTML is cached.\n` +
|
||||
`The use_cached_data flag will be ignored.`);
|
||||
catch (error) {
|
||||
// cache_id() threw error - disable caching
|
||||
uncacheable_property = 'cache_id()';
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Data cache mode (default) - check for cached data to hydrate this.data
|
||||
const cached_data = Jqhtml_Local_Storage.get(cache_key);
|
||||
if (cached_data !== null && typeof cached_data === 'object') {
|
||||
// Hydrate this.data with cached data
|
||||
this.data = cached_data;
|
||||
// If use_cached_data=true, skip on_load() entirely - use cached data as final data
|
||||
if (this.args.use_cached_data === true) {
|
||||
this._use_cached_data_hit = true;
|
||||
// Use standard args-based cache key generation
|
||||
const result = Load_Coordinator.generate_invocation_key(this.component_name(), this.args);
|
||||
cache_key = result.key;
|
||||
uncacheable_property = result.uncacheable_property;
|
||||
}
|
||||
// If cache_key is null, caching disabled
|
||||
if (cache_key === null) {
|
||||
// Set data-nocache attribute for debugging (shows which property prevented caching)
|
||||
if (uncacheable_property) {
|
||||
this.$.attr('data-nocache', uncacheable_property);
|
||||
}
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - caching disabled`, { uncacheable_property });
|
||||
}
|
||||
// Don't return - continue to snapshot this.data for on_load restoration
|
||||
}
|
||||
else {
|
||||
// Store cache key for later use
|
||||
this._cache_key = cache_key;
|
||||
// Get cache mode
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache ${cache_mode}] Component ${this._cid} (${this.component_name()}) checking cache in create()`, { cache_key, cache_mode, has_cache_key_set: Jqhtml_Local_Storage.has_cache_key() });
|
||||
}
|
||||
if (cache_mode === 'html') {
|
||||
// HTML cache mode - check for cached HTML to inject on first render
|
||||
const html_cache_key = `${cache_key}::html`;
|
||||
const cached_html = Jqhtml_Local_Storage.get(html_cache_key);
|
||||
if (cached_html !== null && typeof cached_html === 'string') {
|
||||
// Store cached HTML for injection in _render()
|
||||
this._cached_html = cached_html;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) using cached data (use_cached_data=true, skipping on_load)`, { cache_key, data: cached_data });
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) found cached HTML`, { cache_key: html_cache_key, html_length: cached_html.length });
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) hydrated from cache`, { cache_key, data: cached_data });
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key: html_cache_key });
|
||||
}
|
||||
}
|
||||
// Warn if use_cached_data is set in html cache mode - it has no effect
|
||||
if (this.args.use_cached_data === true) {
|
||||
console.warn(`[JQHTML] Component "${this.component_name()}" has use_cached_data=true but cache mode is 'html'.\n` +
|
||||
`use_cached_data only applies to 'data' cache mode. In 'html' mode, the entire rendered HTML is cached.\n` +
|
||||
`The use_cached_data flag will be ignored.`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key });
|
||||
// Data cache mode (default) - check for cached data to hydrate this.data
|
||||
const cached_data = Jqhtml_Local_Storage.get(cache_key);
|
||||
if (cached_data !== null && typeof cached_data === 'object') {
|
||||
// Hydrate this.data with cached data
|
||||
this.data = cached_data;
|
||||
// If use_cached_data=true, skip on_load() entirely - use cached data as final data
|
||||
if (this.args.use_cached_data === true) {
|
||||
this._use_cached_data_hit = true;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) using cached data (use_cached_data=true, skipping on_load)`, { cache_key, data: cached_data });
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) hydrated from cache`, { cache_key, data: cached_data });
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) cache miss`, { cache_key });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Snapshot this.data after on_create() completes
|
||||
// This will be restored before each on_load() execution to reset state
|
||||
this.__initial_data_snapshot = JSON.parse(JSON.stringify(this.data));
|
||||
}
|
||||
// Snapshot this.data after on_create() completes
|
||||
// This will be restored before each on_load() execution to reset state
|
||||
this.__initial_data_snapshot = JSON.parse(JSON.stringify(this.data));
|
||||
// Freeze this.data after on_create() - only on_load() can modify it now
|
||||
this.__data_frozen = true;
|
||||
this._ready_state = 1;
|
||||
@@ -2795,9 +2808,14 @@ class Jqhtml_Component {
|
||||
this.trigger('create');
|
||||
}
|
||||
/**
|
||||
* Load phase - Fetch data from APIs
|
||||
* Load phase - Fetch asynchronous data
|
||||
* Called bottom-up, fully parallel
|
||||
* NO DOM MODIFICATIONS ALLOWED IN THIS PHASE
|
||||
*
|
||||
* Key design: on_load() runs on a DETACHED proxy with a clone of this.data.
|
||||
* The real component's this.data is not touched during on_load execution.
|
||||
* After on_load completes, the result is applied via a sequential queue.
|
||||
*
|
||||
* @private - Internal lifecycle method, not for external use
|
||||
*/
|
||||
async _load() {
|
||||
@@ -2813,14 +2831,6 @@ class Jqhtml_Component {
|
||||
this.trigger('load');
|
||||
return;
|
||||
}
|
||||
// Restore this.data to initial state from snapshot (skip on first load)
|
||||
// This ensures on_load() always starts with clean state
|
||||
const is_first_load = this._ready_state < 2;
|
||||
if (!is_first_load && this.__initial_data_snapshot) {
|
||||
this.data = JSON.parse(JSON.stringify(this.__initial_data_snapshot));
|
||||
}
|
||||
// Unfreeze this.data so on_load() can modify it
|
||||
this.__data_frozen = false;
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
let uncacheable_property;
|
||||
@@ -2840,6 +2850,8 @@ class Jqhtml_Component {
|
||||
cache_key = result.key;
|
||||
uncacheable_property = result.uncacheable_property;
|
||||
}
|
||||
// Store cache key for later use
|
||||
this._cache_key = cache_key;
|
||||
// If cache_key is null, args are not serializable - skip load deduplication and caching
|
||||
if (cache_key === null) {
|
||||
// Set data-nocache attribute for debugging (shows which property prevented caching)
|
||||
@@ -2849,9 +2861,10 @@ class Jqhtml_Component {
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - load deduplication and caching disabled`, { uncacheable_property });
|
||||
}
|
||||
// Execute on_load() with authorization, without deduplication or caching
|
||||
await this._call_lifecycle('on_load');
|
||||
this.__data_frozen = true;
|
||||
// Execute on_load on detached proxy without deduplication
|
||||
const result_data = await this._execute_on_load_detached();
|
||||
// Apply result via sequential queue
|
||||
await this._apply_load_result(result_data, null);
|
||||
return;
|
||||
}
|
||||
// Store "before" snapshot for comparison after on_load()
|
||||
@@ -2885,10 +2898,39 @@ class Jqhtml_Component {
|
||||
this.trigger('load');
|
||||
return;
|
||||
}
|
||||
// This component is a leader - execute on_load() normally
|
||||
// This component is a leader - execute on_load() on detached proxy
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Load Deduplication] Component ${this._cid} (${this.component_name()}) is the leader`, { args: this.args });
|
||||
}
|
||||
// Execute on_load on detached proxy with Load_Coordinator registration
|
||||
const result_data = await this._execute_on_load_detached(true);
|
||||
// Apply result via sequential queue
|
||||
await this._apply_load_result(result_data, data_before_load);
|
||||
}
|
||||
/**
|
||||
* Execute on_load() on a fully detached proxy.
|
||||
*
|
||||
* The proxy has:
|
||||
* - A CLONE of this.data (from __initial_data_snapshot)
|
||||
* - Read-only access to this.args
|
||||
* - No access to anything else (this.$, this.sid, etc.)
|
||||
*
|
||||
* This ensures on_load runs completely isolated from the component instance.
|
||||
*
|
||||
* @param use_load_coordinator - If true, register with Load_Coordinator for deduplication
|
||||
* @returns The resulting data from the proxy after on_load completes
|
||||
* @private
|
||||
*/
|
||||
async _execute_on_load_detached(use_load_coordinator = false) {
|
||||
// Clone this.data from the snapshot captured after on_create()
|
||||
const data_clone = this.__initial_data_snapshot
|
||||
? JSON.parse(JSON.stringify(this.__initial_data_snapshot))
|
||||
: {};
|
||||
// Create a detached context object that on_load will operate on
|
||||
const detached_context = {
|
||||
args: this.args, // Read-only reference to real args
|
||||
data: data_clone // Cloned data - modifications stay isolated
|
||||
};
|
||||
// Capture args state before on_load() for validation
|
||||
let argsBeforeLoad = null;
|
||||
try {
|
||||
@@ -2899,17 +2941,21 @@ class Jqhtml_Component {
|
||||
}
|
||||
// Set loading flag to prevent render() calls during on_load()
|
||||
this.__loading = true;
|
||||
// Create restricted proxy to prevent DOM access during on_load()
|
||||
const restricted_this = new Proxy(this, {
|
||||
// Create restricted proxy that operates on the detached context
|
||||
const component_name = this.component_name();
|
||||
const restricted_this = new Proxy(detached_context, {
|
||||
get(target, prop) {
|
||||
// Only allow access to this.args and this.data
|
||||
if (prop === 'args' || prop === 'data') {
|
||||
return target[prop];
|
||||
// Only allow access to args and data
|
||||
if (prop === 'args') {
|
||||
return target.args;
|
||||
}
|
||||
if (prop === 'data') {
|
||||
return target.data;
|
||||
}
|
||||
// Block everything else
|
||||
console.error(`[JQHTML] ERROR: Component "${target.component_name()}" attempted to access this.${String(prop)} during on_load().\n\n` +
|
||||
console.error(`[JQHTML] ERROR: Component "${component_name}" attempted to access this.${String(prop)} during on_load().\n\n` +
|
||||
`RESTRICTION: on_load() may ONLY access:\n` +
|
||||
` - this.args (read during on_load, modify before/after)\n` +
|
||||
` - this.args (read-only)\n` +
|
||||
` - this.data (read/write)\n\n` +
|
||||
`WHY: on_load() is for data fetching only. All other component functionality should happen in other lifecycle methods.\n\n` +
|
||||
`FIX:\n` +
|
||||
@@ -2920,14 +2966,14 @@ class Jqhtml_Component {
|
||||
`on_load() may only access this.args and this.data.`);
|
||||
},
|
||||
set(target, prop, value) {
|
||||
// Only allow setting this.data
|
||||
// Only allow setting data
|
||||
if (prop === 'data') {
|
||||
target[prop] = value;
|
||||
target.data = value;
|
||||
return true;
|
||||
}
|
||||
// Block setting this.args
|
||||
// Block setting args
|
||||
if (prop === 'args') {
|
||||
console.error(`[JQHTML] ERROR: Component "${target.component_name()}" attempted to modify this.args during on_load().\n\n` +
|
||||
console.error(`[JQHTML] ERROR: Component "${component_name}" attempted to modify this.args during on_load().\n\n` +
|
||||
`RESTRICTION: on_load() may ONLY modify:\n` +
|
||||
` - this.data (read/write)\n\n` +
|
||||
`WHY: this.args is component state that on_load() depends on. Modifying it inside on_load() creates circular dependencies.\n\n` +
|
||||
@@ -2938,7 +2984,7 @@ class Jqhtml_Component {
|
||||
`Modify this.args in other lifecycle methods, not inside on_load().`);
|
||||
}
|
||||
// Block setting any other properties
|
||||
console.error(`[JQHTML] ERROR: Component "${target.component_name()}" attempted to modify this.${String(prop)} during on_load().\n\n` +
|
||||
console.error(`[JQHTML] ERROR: Component "${component_name}" attempted to modify this.${String(prop)} during on_load().\n\n` +
|
||||
`RESTRICTION: on_load() may ONLY modify:\n` +
|
||||
` - this.data (read/write)\n\n` +
|
||||
`WHY: on_load() is for data fetching only. Setting properties on the component instance should happen in other lifecycle methods.\n\n` +
|
||||
@@ -2949,35 +2995,36 @@ class Jqhtml_Component {
|
||||
`Only this.data can be modified in on_load().`);
|
||||
}
|
||||
});
|
||||
// Create promise for this on_load() call with restricted this context
|
||||
// Create promise for this on_load() call
|
||||
const on_load_promise = (async () => {
|
||||
try {
|
||||
// TODO: Implement proper error handling for on_load() failures
|
||||
// - Should errors trigger re-render with error state?
|
||||
// - Should errors clear cached data?
|
||||
// - Should errors reset state machine flags (next_reload_force_refresh)?
|
||||
// - Should partial data be preserved or rolled back?
|
||||
// - Should followers be notified differently based on error type?
|
||||
await this._call_lifecycle('on_load', restricted_this);
|
||||
}
|
||||
catch (error) {
|
||||
// Handle error and notify coordinator
|
||||
Load_Coordinator.handle_leader_error(this, error);
|
||||
if (use_load_coordinator) {
|
||||
// Handle error and notify coordinator
|
||||
Load_Coordinator.handle_leader_error(this, error);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
})();
|
||||
// Register as leader and get cleanup function
|
||||
const complete_coordination = Load_Coordinator.register_leader(this, on_load_promise);
|
||||
// If using Load_Coordinator, register as leader
|
||||
let complete_coordination = null;
|
||||
if (use_load_coordinator) {
|
||||
complete_coordination = Load_Coordinator.register_leader(this, on_load_promise);
|
||||
}
|
||||
try {
|
||||
await on_load_promise;
|
||||
}
|
||||
finally {
|
||||
// Always clear loading flag and complete coordination
|
||||
// Always clear loading flag
|
||||
this.__loading = false;
|
||||
complete_coordination();
|
||||
// Note: this.data stays unfrozen until after normalization below
|
||||
// Complete coordination if we registered
|
||||
if (complete_coordination) {
|
||||
complete_coordination();
|
||||
}
|
||||
}
|
||||
// Validate that on_load() only modified this.data
|
||||
// Validate that on_load() didn't somehow modify this.args (shouldn't be possible with new proxy)
|
||||
let argsAfterLoad = null;
|
||||
try {
|
||||
argsAfterLoad = JSON.stringify(this.args);
|
||||
@@ -2985,44 +3032,59 @@ class Jqhtml_Component {
|
||||
catch (error) {
|
||||
// Args contain circular references - skip validation
|
||||
}
|
||||
// Check if args were modified (skip if args are non-serializable)
|
||||
if (argsBeforeLoad !== null && argsAfterLoad !== null && argsBeforeLoad !== argsAfterLoad) {
|
||||
console.error(`[JQHTML] WARNING: Component "${this.component_name()}" modified this.args in on_load().\n` +
|
||||
`on_load() should ONLY modify this.data.\n\n` +
|
||||
console.error(`[JQHTML] WARNING: Component "${this.component_name()}" somehow modified this.args during on_load().\n` +
|
||||
`This should not be possible with the detached proxy. Please report this bug.\n\n` +
|
||||
`Before: ${argsBeforeLoad}\n` +
|
||||
`After: ${argsAfterLoad}\n\n` +
|
||||
`Fix: Modify this.args in on_create() or other lifecycle methods, not in on_load().\n` +
|
||||
`this.args stores state that on_load() depends on. Modifying it inside on_load() creates circular dependencies.`);
|
||||
`After: ${argsAfterLoad}`);
|
||||
}
|
||||
// NOTE: We previously checked for new properties being added to the component instance
|
||||
// during on_load() and warned about them. However, this validation was removed because:
|
||||
// 1. The restricted proxy already throws errors if code tries to set properties during on_load()
|
||||
// 2. The validation was producing false positives for properties set during template render
|
||||
// (templates can legitimately set this.* properties in code blocks like <% this._tabs = [...] %>)
|
||||
// 3. Properties set via the restricted proxy throw immediately, making post-hoc validation redundant
|
||||
// DATA MODE: Normalize this.data through serialize/deserialize round-trip
|
||||
// This ensures "hot" data (fresh from on_load) behaves identically to "cold" data
|
||||
// (restored from cache). Unregistered class instances become plain objects immediately,
|
||||
// so developers catch missing class registrations during development rather than
|
||||
// only after a page reload when data comes from cache.
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (cache_mode === 'data') {
|
||||
const normalized = Jqhtml_Local_Storage.normalize_for_cache(this.data);
|
||||
this.data = normalized;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) normalized this.data after on_load()`, { data: this.data });
|
||||
// Return the data from the detached context
|
||||
return detached_context.data;
|
||||
}
|
||||
/**
|
||||
* Apply the result of on_load() to this.data via the sequential queue.
|
||||
*
|
||||
* Multiple _load calls can execute on_load in parallel, but this method
|
||||
* ensures that setting this.data happens in FIFO order.
|
||||
*
|
||||
* @param result_data - The data returned from _execute_on_load_detached
|
||||
* @param data_before_load - JSON string of this.data before on_load (for change detection), or null
|
||||
* @private
|
||||
*/
|
||||
async _apply_load_result(result_data, data_before_load) {
|
||||
// Queue this operation - wait for any earlier _load calls to finish setting data
|
||||
const my_turn = this._load_queue;
|
||||
let resolve_my_turn;
|
||||
this._load_queue = new Promise((resolve) => {
|
||||
resolve_my_turn = resolve;
|
||||
});
|
||||
// Wait for our turn
|
||||
await my_turn;
|
||||
try {
|
||||
// Now it's our turn to set this.data
|
||||
// Unfreeze, set data, freeze
|
||||
this.__data_frozen = false;
|
||||
this.data = result_data;
|
||||
// DATA MODE: Normalize this.data through serialize/deserialize round-trip
|
||||
// This ensures "hot" data (fresh from on_load) behaves identically to "cold" data
|
||||
const cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (cache_mode === 'data') {
|
||||
const normalized = Jqhtml_Local_Storage.normalize_for_cache(this.data);
|
||||
this.data = normalized;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) normalized this.data after on_load()`, { data: this.data });
|
||||
}
|
||||
}
|
||||
}
|
||||
// Freeze this.data after normalization completes
|
||||
this.__data_frozen = true;
|
||||
// CACHE WRITE - If data changed during on_load(), write to cache based on mode
|
||||
const data_after_load = JSON.stringify(this.data);
|
||||
const data_changed = data_after_load !== data_before_load;
|
||||
// Track if component is "dynamic" (this.data changed during on_load)
|
||||
// Used by HTML cache mode for synchronization - static parents don't block children
|
||||
this._is_dynamic = data_changed && data_after_load !== '{}';
|
||||
if (this._is_dynamic) {
|
||||
if (this._cache_key) {
|
||||
// Freeze this.data
|
||||
this.__data_frozen = true;
|
||||
// Calculate if data changed
|
||||
const data_after_load = JSON.stringify(this.data);
|
||||
const data_changed = data_before_load !== null && data_after_load !== data_before_load;
|
||||
// Track if component is "dynamic" (this.data changed during on_load)
|
||||
// Used by HTML cache mode for synchronization - static parents don't block children
|
||||
this._is_dynamic = data_changed && data_after_load !== '{}';
|
||||
// CACHE WRITE - If data changed during on_load(), write to cache based on mode
|
||||
if (this._is_dynamic && this._cache_key) {
|
||||
if (cache_mode === 'html') {
|
||||
// HTML cache mode - flag to cache HTML after children ready in _ready()
|
||||
this._should_cache_html_after_ready = true;
|
||||
@@ -3038,12 +3100,16 @@ class Jqhtml_Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
this._ready_state = 2;
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete');
|
||||
// Emit lifecycle event
|
||||
this.trigger('load');
|
||||
}
|
||||
finally {
|
||||
// Signal next in queue
|
||||
resolve_my_turn();
|
||||
}
|
||||
this._ready_state = 2;
|
||||
this._update_debug_attrs();
|
||||
this._log_lifecycle('load', 'complete');
|
||||
// Emit lifecycle event
|
||||
this.trigger('load');
|
||||
}
|
||||
/**
|
||||
* Ready phase - Component fully initialized
|
||||
@@ -3306,6 +3372,18 @@ class Jqhtml_Component {
|
||||
if (this._stopped)
|
||||
return;
|
||||
this._log_lifecycle('reload', 'start');
|
||||
// OPTIMIZATION: If no custom on_load(), skip data fetching entirely
|
||||
// Just re-render with current data and call on_ready
|
||||
if (!this.__has_custom_on_load) {
|
||||
// Reset state machine
|
||||
this.next_reload_force_refresh = null;
|
||||
this._render();
|
||||
await this._wait_for_children_ready();
|
||||
await this._call_lifecycle('on_ready');
|
||||
this.trigger('ready');
|
||||
this._log_lifecycle('reload', 'complete (no on_load)');
|
||||
return;
|
||||
}
|
||||
// STEP 1: Cache check (if args changed)
|
||||
let rendered_from_cache = false;
|
||||
let data_before_load = null;
|
||||
@@ -3375,72 +3453,16 @@ class Jqhtml_Component {
|
||||
}
|
||||
// Capture data state before on_load for comparison
|
||||
data_before_load = JSON.stringify(this.data);
|
||||
// STEP 2: Call on_load() to fetch fresh data
|
||||
// Unfreeze this.data so we can restore snapshot and on_load() can modify it
|
||||
this.__data_frozen = false;
|
||||
// Restore this.data to initial state from snapshot (if not first load)
|
||||
if (this.__initial_data_snapshot) {
|
||||
this.data = JSON.parse(JSON.stringify(this.__initial_data_snapshot));
|
||||
}
|
||||
try {
|
||||
await this._call_lifecycle('on_load');
|
||||
}
|
||||
finally {
|
||||
// Freeze this.data after on_load() completes
|
||||
this.__data_frozen = true;
|
||||
}
|
||||
// DATA MODE: Normalize this.data through serialize/deserialize round-trip
|
||||
// (Same as in _load() - ensures hot/cold cache parity)
|
||||
const reload_cache_mode = Jqhtml_Local_Storage.get_cache_mode();
|
||||
if (reload_cache_mode === 'data') {
|
||||
this.__data_frozen = false;
|
||||
const normalized = Jqhtml_Local_Storage.normalize_for_cache(this.data);
|
||||
this.data = normalized;
|
||||
this.__data_frozen = true;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) normalized this.data after on_load() in reload()`, { data: this.data });
|
||||
}
|
||||
}
|
||||
// Check if data changed during on_load() - if so, update cache (but not if empty)
|
||||
// STEP 2: Call on_load() on detached proxy
|
||||
// This uses the same detached execution as _load() - on_load runs isolated
|
||||
// and result is applied via sequential queue
|
||||
const result_data = await this._execute_on_load_detached(false); // false = don't use Load_Coordinator
|
||||
// Apply result via sequential queue
|
||||
// This handles normalization, caching, and setting _is_dynamic
|
||||
await this._apply_load_result(result_data, data_before_load);
|
||||
// Re-read data state after apply (for render decision below)
|
||||
const data_after_load = JSON.stringify(this.data);
|
||||
const data_changed = data_after_load !== data_before_load;
|
||||
if (data_changed && data_after_load !== '{}') {
|
||||
// Check if component implements cache_id() for custom cache key
|
||||
let cache_key = null;
|
||||
if (typeof this.cache_id === 'function') {
|
||||
try {
|
||||
const custom_cache_id = this.cache_id();
|
||||
cache_key = `${this.component_name()}::${String(custom_cache_id)}`;
|
||||
}
|
||||
catch (error) {
|
||||
// cache_id() threw error - disable caching
|
||||
cache_key = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use standard args-based cache key generation
|
||||
const result = Load_Coordinator.generate_invocation_key(this.component_name(), this.args);
|
||||
cache_key = result.key;
|
||||
}
|
||||
// Write to cache based on mode
|
||||
if (cache_key !== null) {
|
||||
this._cache_key = cache_key;
|
||||
if (reload_cache_mode === 'html') {
|
||||
// HTML cache mode - flag to cache HTML after children ready in _ready()
|
||||
this._should_cache_html_after_ready = true;
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache html] Component ${this._cid} (${this.component_name()}) will cache HTML after ready in reload()`, { cache_key });
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Data cache mode (default) - write this.data to cache
|
||||
Jqhtml_Local_Storage.set(cache_key, this.data);
|
||||
if (window.jqhtml?.debug?.verbose) {
|
||||
console.log(`[Cache data] Component ${this._cid} (${this.component_name()}) cached data after on_load() in reload()`, { cache_key, data: this.data });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// STEP 3: Conditionally re-render (with refresh() support)
|
||||
// Read force_refresh from state machine (default true)
|
||||
const force_refresh = this.next_reload_force_refresh !== null ? this.next_reload_force_refresh : true;
|
||||
@@ -3574,6 +3596,11 @@ class Jqhtml_Component {
|
||||
this._used_cached_html = false;
|
||||
return true;
|
||||
}
|
||||
// OPTIMIZATION: If no custom on_load(), data cannot change, skip serialization
|
||||
// Data is frozen after on_create() and only unfrozen during on_load()
|
||||
if (!this.__has_custom_on_load) {
|
||||
return false;
|
||||
}
|
||||
// Compare current data state with data state before initial render
|
||||
const currentDataState = JSON.stringify(this.data);
|
||||
const dataChanged = this._data_before_render !== currentDataState;
|
||||
@@ -4818,7 +4845,7 @@ function init(jQuery) {
|
||||
}
|
||||
}
|
||||
// Version - will be replaced during build with actual version from package.json
|
||||
const version = '2.3.20';
|
||||
const version = '2.3.21';
|
||||
// Default export with all functionality
|
||||
const jqhtml = {
|
||||
// Core
|
||||
|
||||
2
node_modules/@jqhtml/core/dist/jqhtml-core.esm.js.map
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/core/dist/jqhtml-core.esm.js.map
generated
vendored
Executable file → Normal file
File diff suppressed because one or more lines are too long
0
node_modules/@jqhtml/core/dist/jqhtml-debug.esm.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/jqhtml-debug.esm.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/jqhtml-debug.esm.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/jqhtml-debug.esm.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/jquery-plugin.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/jquery-plugin.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/jquery-plugin.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/jquery-plugin.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/lifecycle-manager.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/lifecycle-manager.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/lifecycle-manager.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/lifecycle-manager.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/load-coordinator.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/load-coordinator.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/load-coordinator.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/load-coordinator.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/local-storage.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/local-storage.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/local-storage.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/local-storage.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/template-renderer.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/template-renderer.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/template-renderer.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/core/dist/template-renderer.d.ts.map
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/core/package.json
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/core/package.json
generated
vendored
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@jqhtml/core",
|
||||
"version": "2.3.20",
|
||||
"version": "2.3.21",
|
||||
"description": "Core runtime library for JQHTML",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
0
node_modules/@jqhtml/parser/dist/ast.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/ast.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/ast.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/ast.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/ast.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/ast.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/ast.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/ast.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/codegen.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/codegen.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/codegen.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/codegen.d.ts.map
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/parser/dist/codegen.js
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/parser/dist/codegen.js
generated
vendored
Executable file → Normal file
@@ -1377,7 +1377,7 @@ export class CodeGenerator {
|
||||
for (const [name, component] of this.components) {
|
||||
code += `// Component: ${name}\n`;
|
||||
code += `jqhtml_components.set('${name}', {\n`;
|
||||
code += ` _jqhtml_version: '2.3.20',\n`; // Version will be replaced during build
|
||||
code += ` _jqhtml_version: '2.3.21',\n`; // Version will be replaced during build
|
||||
code += ` name: '${name}',\n`;
|
||||
code += ` tag: '${component.tagName}',\n`;
|
||||
code += ` defaultAttributes: ${this.serializeAttributeObject(component.defaultAttributes)},\n`;
|
||||
|
||||
0
node_modules/@jqhtml/parser/dist/codegen.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/codegen.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/compiler.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/compiler.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/compiler.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/compiler.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/compiler.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/compiler.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/compiler.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/compiler.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/errors.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/errors.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/errors.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/errors.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/errors.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/errors.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/errors.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/errors.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/index.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/index.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/index.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/index.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/index.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/index.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/index.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/index.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/integration.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/integration.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/integration.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/integration.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/integration.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/integration.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/integration.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/integration.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/lexer.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/lexer.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/lexer.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/lexer.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/lexer.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/lexer.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/lexer.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/lexer.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/parser.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/parser.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/parser.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/parser.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/parser.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/parser.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/parser.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/parser.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/runtime.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/runtime.d.ts
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/runtime.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/runtime.d.ts.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/runtime.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/runtime.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/runtime.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/parser/dist/runtime.js.map
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/parser/package.json
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/parser/package.json
generated
vendored
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@jqhtml/parser",
|
||||
"version": "2.3.20",
|
||||
"version": "2.3.21",
|
||||
"description": "JQHTML template parser - converts templates to JavaScript",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
||||
2
node_modules/@jqhtml/vscode-extension/.version
generated
vendored
2
node_modules/@jqhtml/vscode-extension/.version
generated
vendored
@@ -1 +1 @@
|
||||
2.3.20
|
||||
2.3.21
|
||||
|
||||
0
node_modules/@jqhtml/vscode-extension/blade-language-configuration.json
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/blade-language-configuration.json
generated
vendored
Executable file → Normal file
BIN
node_modules/@jqhtml/vscode-extension/jqhtml-vscode-extension-2.3.20.vsix → node_modules/@jqhtml/vscode-extension/jqhtml-vscode-extension-2.3.21.vsix
generated
vendored
Executable file → Normal file
BIN
node_modules/@jqhtml/vscode-extension/jqhtml-vscode-extension-2.3.20.vsix → node_modules/@jqhtml/vscode-extension/jqhtml-vscode-extension-2.3.21.vsix
generated
vendored
Executable file → Normal file
Binary file not shown.
0
node_modules/@jqhtml/vscode-extension/out/blade_component_provider.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_component_provider.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_component_provider.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_component_provider.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_language_config.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_language_config.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_language_config.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_language_config.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_spacer.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_spacer.js
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_spacer.js.map
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/out/blade_spacer.js.map
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/vscode-extension/package.json
generated
vendored
Executable file → Normal file
2
node_modules/@jqhtml/vscode-extension/package.json
generated
vendored
Executable file → Normal file
@@ -2,7 +2,7 @@
|
||||
"name": "@jqhtml/vscode-extension",
|
||||
"displayName": "JQHTML",
|
||||
"description": "Syntax highlighting and language support for JQHTML template files",
|
||||
"version": "2.3.20",
|
||||
"version": "2.3.21",
|
||||
"publisher": "jqhtml",
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
|
||||
0
node_modules/@jqhtml/vscode-extension/syntaxes/blade-jqhtml.tmLanguage.json
generated
vendored
Executable file → Normal file
0
node_modules/@jqhtml/vscode-extension/syntaxes/blade-jqhtml.tmLanguage.json
generated
vendored
Executable file → Normal file
2
node_modules/baseline-browser-mapping/dist/index.cjs
generated
vendored
2
node_modules/baseline-browser-mapping/dist/index.cjs
generated
vendored
File diff suppressed because one or more lines are too long
2
node_modules/baseline-browser-mapping/dist/index.js
generated
vendored
2
node_modules/baseline-browser-mapping/dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
4
node_modules/baseline-browser-mapping/package.json
generated
vendored
4
node_modules/baseline-browser-mapping/package.json
generated
vendored
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "baseline-browser-mapping",
|
||||
"main": "./dist/index.cjs",
|
||||
"version": "2.9.6",
|
||||
"version": "2.9.7",
|
||||
"description": "A library for obtaining browser versions with their maximum supported Baseline feature set and Widely Available status.",
|
||||
"exports": {
|
||||
".": {
|
||||
@@ -55,7 +55,7 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.7.2",
|
||||
"typescript-eslint": "^8.35.0",
|
||||
"web-features": "^3.11.0"
|
||||
"web-features": "^3.11.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user