@jqhtml/core 2.3.68 → 2.3.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/component.d.ts +12 -0
- package/dist/component.d.ts.map +1 -1
- package/dist/debug-overlay/index.d.ts +6 -0
- package/dist/debug-overlay/index.d.ts.map +1 -1
- package/dist/index.cjs +256 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +256 -22
- package/dist/index.js.map +1 -1
- package/dist/jqhtml-core.esm.js +257 -23
- package/dist/jqhtml-core.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/component.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export declare class Jqhtml_Component {
|
|
|
40
40
|
_cid: string;
|
|
41
41
|
_component_name: string;
|
|
42
42
|
_ready_state: number;
|
|
43
|
+
_debug_no_data: boolean;
|
|
43
44
|
private _lifecycle_manager;
|
|
44
45
|
private _instantiator;
|
|
45
46
|
private _dom_parent;
|
|
@@ -336,6 +337,17 @@ export declare class Jqhtml_Component {
|
|
|
336
337
|
* while refresh() is queued, reload() takes precedence and will always render.
|
|
337
338
|
*/
|
|
338
339
|
refresh(): Promise<void>;
|
|
340
|
+
/**
|
|
341
|
+
* Re-render this component from its on_create() state with its cache dropped and
|
|
342
|
+
* WITHOUT running on_load()/on_loaded()/on_ready().
|
|
343
|
+
*
|
|
344
|
+
* @internal debug tool. Used by the debug overlay's lifecycle footer to see what a
|
|
345
|
+
* component looks like with no loaded data at all. Not public API, not documented,
|
|
346
|
+
* and no downstream code should call it: reload() or refresh() afterwards returns
|
|
347
|
+
* the component to normal (the snapshot is intact and the cache is gone, so the
|
|
348
|
+
* next load is a genuine fresh fetch).
|
|
349
|
+
*/
|
|
350
|
+
_reload_without_data(): Promise<void>;
|
|
339
351
|
/**
|
|
340
352
|
* Internal reload implementation - re-fetch data and re-render
|
|
341
353
|
*
|
package/dist/component.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAcH,OAAO,EAA6C,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACxG,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE7D;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;CAK5B,CAAC;AAiEF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,YAAY,CAAC,EAAE;YACb,GAAG,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;YACjF,UAAU,EAAE,MAAM,IAAI,CAAC;SACxB,CAAC;KACH;CACF;AAED,qBAAa,gBAAgB;IAE3B,MAAM,CAAC,kBAAkB,UAAQ;IACjC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC;IAGtB,MAAM,CAAC,QAAQ,CAAC,sBAAsB,SAA0B;IAGhE,CAAC,EAAE,GAAG,CAAC;IACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAK;
|
|
1
|
+
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
* data, state, ancestry, instantiator) instead of firing the click. Alt+click
|
|
9
9
|
* passes through. `disable()` puts everything back.
|
|
10
10
|
*
|
|
11
|
+
* The labels are part of the interaction, not just decoration: the pointer can
|
|
12
|
+
* move from a component onto one of its tabs without the hover set collapsing,
|
|
13
|
+
* and clicking a tab inspects that tab's component. The modal keeps an amber
|
|
14
|
+
* outline on whatever it is showing, and its title bar carries Parent / Back so
|
|
15
|
+
* the DOM chain can be walked without going back to the page.
|
|
16
|
+
*
|
|
11
17
|
* Non-invasiveness, the design goal (details in ./CLAUDE.md):
|
|
12
18
|
* - The overlay's own UI lives in a shadow root on a host element appended to
|
|
13
19
|
* <body>, styled by shadow.scss. Page CSS cannot select into it and :host
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/debug-overlay/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/debug-overlay/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAwDH,eAAO,MAAM,aAAa;IACxB,sEAAsE;cAC5D,OAAO;IAgBjB,qEAAqE;eAC1D,IAAI;kBAeD,OAAO;IAIrB;;;OAGG;oBACa,GAAG,GAAG,OAAO;CAS9B,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -1913,7 +1913,7 @@ Load_Coordinator._registry = new Map();
|
|
|
1913
1913
|
const class_registry = Object.create(null);
|
|
1914
1914
|
// Markers for serialized class instances (unique to avoid collisions with user data)
|
|
1915
1915
|
// Replaced at build time by rollup (see rollup.config.js).
|
|
1916
|
-
const CORE_VERSION = '2.3.
|
|
1916
|
+
const CORE_VERSION = '2.3.70';
|
|
1917
1917
|
const CLASS_MARKER = '__jqhtml_class__';
|
|
1918
1918
|
const PROPS_MARKER = '__jqhtml_props__';
|
|
1919
1919
|
/**
|
|
@@ -3942,6 +3942,7 @@ function resolve_parent_template(template_def, ctor) {
|
|
|
3942
3942
|
class Jqhtml_Component {
|
|
3943
3943
|
constructor(element, args = {}) {
|
|
3944
3944
|
this._ready_state = 0; // 0=created, 1=init, 2=loaded, 3=rendered, 4=ready
|
|
3945
|
+
this._debug_no_data = false; // Set by _reload_without_data(); cleared by any real load
|
|
3945
3946
|
this._instantiator = null; // Component that instantiated this one
|
|
3946
3947
|
this._dom_parent = null; // Closest component in DOM tree (for lifecycle)
|
|
3947
3948
|
this._dom_children = new Set(); // Components in DOM subtree (for lifecycle)
|
|
@@ -4554,6 +4555,8 @@ class Jqhtml_Component {
|
|
|
4554
4555
|
// The queued executor can start long after load() was called - re-check.
|
|
4555
4556
|
if (this._stopped)
|
|
4556
4557
|
return false;
|
|
4558
|
+
// Any real load returns the component to normal, whatever the debug tool did.
|
|
4559
|
+
this._debug_no_data = false;
|
|
4557
4560
|
// Snapshot current data for change detection
|
|
4558
4561
|
const data_before = JSON.stringify(this.data);
|
|
4559
4562
|
// Execute on_load() on detached proxy (restores data to on_create snapshot)
|
|
@@ -4743,6 +4746,8 @@ class Jqhtml_Component {
|
|
|
4743
4746
|
async _load() {
|
|
4744
4747
|
if (this._stopped || this._ready_state >= 2)
|
|
4745
4748
|
return;
|
|
4749
|
+
// Any real load returns the component to normal, whatever the debug tool did.
|
|
4750
|
+
this._debug_no_data = false;
|
|
4746
4751
|
this._log_lifecycle('load', 'start');
|
|
4747
4752
|
// use_cached_data feature: If cache hit occurred and use_cached_data=true, skip on_load() entirely
|
|
4748
4753
|
// The cached data is already in this.data from create() phase
|
|
@@ -5175,6 +5180,51 @@ class Jqhtml_Component {
|
|
|
5175
5180
|
async refresh() {
|
|
5176
5181
|
return this.reload(false);
|
|
5177
5182
|
}
|
|
5183
|
+
/**
|
|
5184
|
+
* Re-render this component from its on_create() state with its cache dropped and
|
|
5185
|
+
* WITHOUT running on_load()/on_loaded()/on_ready().
|
|
5186
|
+
*
|
|
5187
|
+
* @internal debug tool. Used by the debug overlay's lifecycle footer to see what a
|
|
5188
|
+
* component looks like with no loaded data at all. Not public API, not documented,
|
|
5189
|
+
* and no downstream code should call it: reload() or refresh() afterwards returns
|
|
5190
|
+
* the component to normal (the snapshot is intact and the cache is gone, so the
|
|
5191
|
+
* next load is a genuine fresh fetch).
|
|
5192
|
+
*/
|
|
5193
|
+
_reload_without_data() {
|
|
5194
|
+
if (this._stopped)
|
|
5195
|
+
return Promise.resolve();
|
|
5196
|
+
// Same marker invalidation reload()/render() do: later ready() waiters must wait
|
|
5197
|
+
// for THIS cycle rather than resolve off the previous one.
|
|
5198
|
+
this.invalidate('ready');
|
|
5199
|
+
// Serialised with reload()/refresh() so it can never interleave with a real load.
|
|
5200
|
+
return this._queue.enqueue('reload', async () => {
|
|
5201
|
+
if (this._stopped)
|
|
5202
|
+
return;
|
|
5203
|
+
// Drop this component's own cache entries (data and html snapshot), so a later
|
|
5204
|
+
// reload() genuinely re-fetches instead of hydrating from what is on screen now.
|
|
5205
|
+
const { cache_key } = generate_cache_key(this);
|
|
5206
|
+
if (cache_key !== null) {
|
|
5207
|
+
Jqhtml_Local_Storage.remove(cache_key);
|
|
5208
|
+
Jqhtml_Local_Storage.remove(`${cache_key}::html`);
|
|
5209
|
+
}
|
|
5210
|
+
// Back to the on_create() state. Components with no custom on_load() take no
|
|
5211
|
+
// snapshot (nothing can have changed this.data), so they simply re-render.
|
|
5212
|
+
if (this.__initial_data_snapshot !== null) {
|
|
5213
|
+
this.__data_frozen = false;
|
|
5214
|
+
this.data = JSON.parse(JSON.stringify(this.__initial_data_snapshot));
|
|
5215
|
+
this.__data_frozen = true;
|
|
5216
|
+
}
|
|
5217
|
+
// Read by the debug overlay's lifecycle row; cleared by _reload()/load()/_load().
|
|
5218
|
+
this._debug_no_data = true;
|
|
5219
|
+
this._render();
|
|
5220
|
+
await this._wait_for_children_ready();
|
|
5221
|
+
if (this._stopped)
|
|
5222
|
+
return;
|
|
5223
|
+
this._ready_state = 4;
|
|
5224
|
+
this._update_debug_attrs();
|
|
5225
|
+
this.trigger('ready');
|
|
5226
|
+
});
|
|
5227
|
+
}
|
|
5178
5228
|
/**
|
|
5179
5229
|
* Internal reload implementation - re-fetch data and re-render
|
|
5180
5230
|
*
|
|
@@ -5212,6 +5262,8 @@ class Jqhtml_Component {
|
|
|
5212
5262
|
async _reload() {
|
|
5213
5263
|
if (this._stopped)
|
|
5214
5264
|
return;
|
|
5265
|
+
// Any real load returns the component to normal, whatever the debug tool did.
|
|
5266
|
+
this._debug_no_data = false;
|
|
5215
5267
|
// Invalidate ready event so new handlers wait for this reload to complete
|
|
5216
5268
|
// This prevents .on('ready') handlers from firing immediately based on previous lifecycle
|
|
5217
5269
|
this.invalidate('ready');
|
|
@@ -5950,9 +6002,9 @@ Jqhtml_Component.__jqhtml_component = true; // Marker for unified register() det
|
|
|
5950
6002
|
// A bare component name, as accepted by closest() in place of a class selector
|
|
5951
6003
|
Jqhtml_Component.COMPONENT_NAME_PATTERN = COMPONENT_NAME_PATTERN;
|
|
5952
6004
|
|
|
5953
|
-
var light_css = "html[data-jqhtml-debug] .jqhtml-debug-hit {\n outline: 2px solid #e5322d;\n outline-offset: -2px;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-0 {\n outline-color: #e5322d;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-1 {\n outline-color: #2f6fe4;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-2 {\n outline-color: #1f9d55;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-3 {\n outline-color: #d97706;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-4 {\n outline-color: #7c3aed;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-5 {\n outline-color: #0e7490;\n}";
|
|
6005
|
+
var light_css = "html[data-jqhtml-debug] .jqhtml-debug-selected {\n outline: 2px solid #b45309;\n outline-offset: -2px;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit {\n outline: 2px solid #e5322d;\n outline-offset: -2px;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-0 {\n outline-color: #e5322d;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-1 {\n outline-color: #2f6fe4;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-2 {\n outline-color: #1f9d55;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-3 {\n outline-color: #d97706;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-4 {\n outline-color: #7c3aed;\n}\n\nhtml[data-jqhtml-debug] .jqhtml-debug-hit.jqhtml-debug-depth-5 {\n outline-color: #0e7490;\n}";
|
|
5954
6006
|
|
|
5955
|
-
var shadow_css = ":host {\n all: initial;\n display: block;\n position: fixed;\n box-sizing: border-box;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n z-index: 2147483647;\n pointer-events: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 12px;\n font-weight: normal;\n font-style: normal;\n font-variant: normal;\n line-height: 1.4;\n color: #1c1c1c;\n text-align: left;\n text-transform: none;\n text-indent: 0;\n text-shadow: none;\n letter-spacing: normal;\n word-spacing: normal;\n white-space: normal;\n word-break: normal;\n overflow-wrap: anywhere;\n hyphens: none;\n tab-size: 4;\n direction: ltr;\n visibility: visible;\n cursor: default;\n list-style: none;\n quotes: none;\n}\n\n.jqhtml-debug-layer {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n overflow: hidden;\n pointer-events: none;\n}\n\n.jqhtml-debug-label {\n position: absolute;\n box-sizing: border-box;\n display: block;\n padding: 1px 5px;\n min-height: 18px;\n color: #ffffff;\n background: #e5322d;\n border-radius: 0 0 3px 0;\n font-size: 11px;\n line-height: 16px;\n white-space: normal;\n overflow-wrap: anywhere;\n overflow: hidden;\n pointer-events:
|
|
6007
|
+
var shadow_css = ":host {\n all: initial;\n display: block;\n position: fixed;\n box-sizing: border-box;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n z-index: 2147483647;\n pointer-events: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 12px;\n font-weight: normal;\n font-style: normal;\n font-variant: normal;\n line-height: 1.4;\n color: #1c1c1c;\n text-align: left;\n text-transform: none;\n text-indent: 0;\n text-shadow: none;\n letter-spacing: normal;\n word-spacing: normal;\n white-space: normal;\n word-break: normal;\n overflow-wrap: anywhere;\n hyphens: none;\n tab-size: 4;\n direction: ltr;\n visibility: visible;\n cursor: default;\n list-style: none;\n quotes: none;\n}\n\n.jqhtml-debug-layer {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n overflow: hidden;\n pointer-events: none;\n}\n\n.jqhtml-debug-label {\n position: absolute;\n box-sizing: border-box;\n display: block;\n padding: 1px 5px;\n min-height: 18px;\n color: #ffffff;\n background: #e5322d;\n border-radius: 0 0 3px 0;\n font-size: 11px;\n line-height: 16px;\n white-space: normal;\n overflow-wrap: anywhere;\n overflow: hidden;\n pointer-events: auto;\n cursor: pointer;\n}\n\n.jqhtml-debug-label.jqhtml-debug-depth-0 {\n background: #e5322d;\n}\n\n.jqhtml-debug-label.jqhtml-debug-depth-1 {\n background: #2f6fe4;\n}\n\n.jqhtml-debug-label.jqhtml-debug-depth-2 {\n background: #1f9d55;\n}\n\n.jqhtml-debug-label.jqhtml-debug-depth-3 {\n background: #d97706;\n}\n\n.jqhtml-debug-label.jqhtml-debug-depth-4 {\n background: #7c3aed;\n}\n\n.jqhtml-debug-label.jqhtml-debug-depth-5 {\n background: #0e7490;\n}\n\n.jqhtml-debug-label-name {\n font-weight: bold;\n}\n\n.jqhtml-debug-label-args {\n opacity: 0.9;\n margin-left: 6px;\n}\n\n.jqhtml-debug-modal {\n display: none;\n position: absolute;\n box-sizing: border-box;\n top: 24px;\n right: 24px;\n width: 520px;\n max-width: calc(100% - 48px);\n overflow: hidden;\n padding: 0;\n background: #ffffff;\n color: #1c1c1c;\n border: 1px solid #d0d0d0;\n border-radius: 6px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);\n pointer-events: auto;\n}\n\n.jqhtml-debug-modal.jqhtml-debug-modal-open {\n display: block;\n}\n\n.jqhtml-debug-modal.jqhtml-debug-modal-left {\n left: 24px;\n right: auto;\n}\n\n.jqhtml-debug-title {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: #1c1c1c;\n color: #ffffff;\n font-weight: bold;\n}\n\n.jqhtml-debug-body {\n display: block;\n box-sizing: border-box;\n overflow-y: scroll;\n min-height: 300px;\n max-height: min(600px, 100vh - 200px);\n padding: 0 0 12px 0;\n}\n\n.jqhtml-debug-footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: #ffffff;\n border-top: 1px solid #d0d0d0;\n}\n\n.jqhtml-debug-footer-label {\n color: #666666;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.jqhtml-debug-title-name {\n flex: 1 1 auto;\n font-size: 13px;\n}\n\n.jqhtml-debug-button {\n all: unset;\n display: inline-block;\n box-sizing: border-box;\n padding: 2px 8px;\n border: 1px solid rgba(255, 255, 255, 0.6);\n border-radius: 3px;\n color: #ffffff;\n font-size: 11px;\n line-height: 16px;\n cursor: pointer;\n user-select: none;\n}\n\n.jqhtml-debug-button:hover {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.jqhtml-debug-button.jqhtml-debug-footer-button {\n color: #1c1c1c;\n border-color: #d0d0d0;\n}\n\n.jqhtml-debug-button.jqhtml-debug-footer-button:hover {\n background: #eef3ff;\n}\n\n.jqhtml-debug-section {\n padding: 8px 12px 0 12px;\n}\n\n.jqhtml-debug-h {\n margin: 4px 0;\n color: #666666;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.jqhtml-debug-table {\n display: grid;\n grid-template-columns: max-content max-content 1fr;\n column-gap: 12px;\n row-gap: 2px;\n align-items: baseline;\n}\n\n.jqhtml-debug-key {\n color: #005cc5;\n white-space: nowrap;\n}\n\n.jqhtml-debug-type {\n color: #666666;\n font-size: 11px;\n white-space: nowrap;\n}\n\n.jqhtml-debug-value {\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.jqhtml-debug-empty {\n color: #666666;\n font-style: italic;\n}\n\n.jqhtml-debug-list {\n display: block;\n margin: 0;\n padding: 0;\n}\n\n.jqhtml-debug-link {\n display: block;\n padding: 2px 4px;\n margin: 0 -4px;\n border-radius: 3px;\n cursor: pointer;\n}\n\n.jqhtml-debug-link:hover {\n background: #eef3ff;\n}\n\n.jqhtml-debug-link-cid {\n color: #666666;\n margin-left: 6px;\n}\n\n.jqhtml-debug-note {\n margin-top: 4px;\n color: #92400e;\n font-size: 11px;\n}";
|
|
5956
6008
|
|
|
5957
6009
|
/**
|
|
5958
6010
|
* Component debug overlay.
|
|
@@ -5964,6 +6016,12 @@ var shadow_css = ":host {\n all: initial;\n display: block;\n position: fixed
|
|
|
5964
6016
|
* data, state, ancestry, instantiator) instead of firing the click. Alt+click
|
|
5965
6017
|
* passes through. `disable()` puts everything back.
|
|
5966
6018
|
*
|
|
6019
|
+
* The labels are part of the interaction, not just decoration: the pointer can
|
|
6020
|
+
* move from a component onto one of its tabs without the hover set collapsing,
|
|
6021
|
+
* and clicking a tab inspects that tab's component. The modal keeps an amber
|
|
6022
|
+
* outline on whatever it is showing, and its title bar carries Parent / Back so
|
|
6023
|
+
* the DOM chain can be walked without going back to the page.
|
|
6024
|
+
*
|
|
5967
6025
|
* Non-invasiveness, the design goal (details in ./CLAUDE.md):
|
|
5968
6026
|
* - The overlay's own UI lives in a shadow root on a host element appended to
|
|
5969
6027
|
* <body>, styled by shadow.scss. Page CSS cannot select into it and :host
|
|
@@ -5982,8 +6040,11 @@ const HOST_ATTR = 'data-jqhtml-debug-root'; // the shadow host
|
|
|
5982
6040
|
const LIGHT_STYLE_ID = 'jqhtml-debug-light-styles';
|
|
5983
6041
|
const HIT_CLASS = `${PREFIX}hit`;
|
|
5984
6042
|
const DEPTH_CLASS = `${PREFIX}depth-`;
|
|
6043
|
+
const SELECTED_CLASS = `${PREFIX}selected`; // on the element the modal is showing
|
|
5985
6044
|
const DEPTH_COLORS = 6; // keep in step with $depth-colors in _tokens.scss
|
|
5986
6045
|
const LABEL_HEIGHT = 18;
|
|
6046
|
+
const LABEL_MIN_WIDTH = 400; // a narrow component still gets a readable tab
|
|
6047
|
+
const VIEWPORT_MARGIN = 5; // gap kept between a label's right edge and the viewport
|
|
5987
6048
|
const READY_STATES = ['created', 'init', 'loaded', 'rendered', 'ready'];
|
|
5988
6049
|
const state = {
|
|
5989
6050
|
enabled: false,
|
|
@@ -5993,7 +6054,10 @@ const state = {
|
|
|
5993
6054
|
modal: null,
|
|
5994
6055
|
chain: [],
|
|
5995
6056
|
hit_elements: [],
|
|
6057
|
+
label_hovered: false,
|
|
5996
6058
|
modal_component: null,
|
|
6059
|
+
nav_stack: [],
|
|
6060
|
+
selected_element: null,
|
|
5997
6061
|
};
|
|
5998
6062
|
// ---------------------------------------------------------------------------
|
|
5999
6063
|
// Public API
|
|
@@ -6050,7 +6114,7 @@ const debug_overlay = {
|
|
|
6050
6114
|
: chain_for(target && target.jquery ? target[0] : target)[0];
|
|
6051
6115
|
if (!component)
|
|
6052
6116
|
return false;
|
|
6053
|
-
|
|
6117
|
+
select(component);
|
|
6054
6118
|
return true;
|
|
6055
6119
|
},
|
|
6056
6120
|
};
|
|
@@ -6105,9 +6169,18 @@ function is_ours(event) {
|
|
|
6105
6169
|
// ---------------------------------------------------------------------------
|
|
6106
6170
|
// Hover
|
|
6107
6171
|
// ---------------------------------------------------------------------------
|
|
6172
|
+
/**
|
|
6173
|
+
* A hover on the page replaces the hover set - except while the pointer is on
|
|
6174
|
+
* our own UI. An event from inside the shadow host (a label, the modal) never
|
|
6175
|
+
* clears or changes the hover, and neither does a page hover raised while the
|
|
6176
|
+
* pointer is parked on a label: that is what lets a label be reached and clicked
|
|
6177
|
+
* without the outlines it belongs to vanishing on the way.
|
|
6178
|
+
*/
|
|
6108
6179
|
function on_mouseover(event) {
|
|
6109
6180
|
if (is_ours(event))
|
|
6110
6181
|
return;
|
|
6182
|
+
if (state.label_hovered)
|
|
6183
|
+
return;
|
|
6111
6184
|
const chain = chain_for(event.target);
|
|
6112
6185
|
if (chain[0] === state.chain[0])
|
|
6113
6186
|
return;
|
|
@@ -6117,6 +6190,32 @@ function on_mouseout(event) {
|
|
|
6117
6190
|
if (!event.relatedTarget)
|
|
6118
6191
|
clear_hover(); // pointer left the document
|
|
6119
6192
|
}
|
|
6193
|
+
/**
|
|
6194
|
+
* The pointer left a label. If it landed back inside the component the label
|
|
6195
|
+
* belongs to (the usual case - the label sits on the component's own corner),
|
|
6196
|
+
* the hover set stays; anywhere else it goes. `elementFromPoint` reports our
|
|
6197
|
+
* shadow host for a point covered by another label, so the host is skipped and
|
|
6198
|
+
* the page element underneath is used.
|
|
6199
|
+
*/
|
|
6200
|
+
function on_label_leave(event) {
|
|
6201
|
+
state.label_hovered = false;
|
|
6202
|
+
const innermost = state.chain[0];
|
|
6203
|
+
if (!innermost)
|
|
6204
|
+
return;
|
|
6205
|
+
const under = element_under(event.clientX, event.clientY);
|
|
6206
|
+
if (!under || !innermost.$[0].contains(under))
|
|
6207
|
+
clear_hover();
|
|
6208
|
+
}
|
|
6209
|
+
function element_under(x, y) {
|
|
6210
|
+
const all = document.elementsFromPoint;
|
|
6211
|
+
const candidates = all
|
|
6212
|
+
? all.call(document, x, y)
|
|
6213
|
+
: [document.elementFromPoint(x, y)].filter(Boolean);
|
|
6214
|
+
for (const node of candidates)
|
|
6215
|
+
if (node !== state.host)
|
|
6216
|
+
return node;
|
|
6217
|
+
return null;
|
|
6218
|
+
}
|
|
6120
6219
|
function on_reposition() {
|
|
6121
6220
|
if (state.chain.length)
|
|
6122
6221
|
render_labels();
|
|
@@ -6139,18 +6238,23 @@ function clear_hover() {
|
|
|
6139
6238
|
}
|
|
6140
6239
|
state.hit_elements = [];
|
|
6141
6240
|
state.chain = [];
|
|
6241
|
+
state.label_hovered = false;
|
|
6142
6242
|
if (state.layer)
|
|
6143
6243
|
state.layer.textContent = '';
|
|
6144
6244
|
}
|
|
6145
6245
|
/**
|
|
6146
6246
|
* One tab per component in the chain, pinned to the component's top-left
|
|
6147
|
-
* corner
|
|
6148
|
-
*
|
|
6149
|
-
*
|
|
6247
|
+
* corner. Width: the component's, but a narrow component still gets up to
|
|
6248
|
+
* LABEL_MIN_WIDTH so its name and args stay legible; a label that would then
|
|
6249
|
+
* run off the right edge is slid back so its right edge sits at the margin.
|
|
6250
|
+
* Outermost first so the innermost paints on top; tabs that share a corner (a
|
|
6251
|
+
* child filling its parent, the usual case) stack downward instead of hiding
|
|
6252
|
+
* each other.
|
|
6150
6253
|
*/
|
|
6151
6254
|
function render_labels() {
|
|
6152
6255
|
const layer = state.layer;
|
|
6153
6256
|
layer.textContent = '';
|
|
6257
|
+
state.label_hovered = false; // the element the pointer was on is gone
|
|
6154
6258
|
const taken = new Map();
|
|
6155
6259
|
for (let depth = state.chain.length - 1; depth >= 0; depth--) {
|
|
6156
6260
|
const component = state.chain[depth];
|
|
@@ -6163,14 +6267,33 @@ function render_labels() {
|
|
|
6163
6267
|
const stacked = taken.get(key) || 0;
|
|
6164
6268
|
taken.set(key, stacked + 1);
|
|
6165
6269
|
const label = el('div', `label ${PREFIX}depth-${depth % DEPTH_COLORS}`);
|
|
6166
|
-
|
|
6270
|
+
// Laid out at the left edge FIRST, then moved. An absolutely positioned box
|
|
6271
|
+
// shrink-to-fits into the room its own `left` leaves, so measuring it at its
|
|
6272
|
+
// final position would report the squeezed width, and moving it would let it
|
|
6273
|
+
// re-expand - the two chase each other. At left 0 it has the whole viewport,
|
|
6274
|
+
// so the measurement below is the width it will actually keep.
|
|
6275
|
+
label.style.left = '0px';
|
|
6167
6276
|
label.style.top = `${top + stacked * LABEL_HEIGHT}px`;
|
|
6168
|
-
label.style.maxWidth = `${
|
|
6277
|
+
label.style.maxWidth = `${rect.width < LABEL_MIN_WIDTH ? LABEL_MIN_WIDTH : Math.round(rect.width)}px`;
|
|
6169
6278
|
label.appendChild(el('span', 'label-name', component.component_name()));
|
|
6170
6279
|
const args = simple_args(component);
|
|
6171
6280
|
if (args)
|
|
6172
6281
|
label.appendChild(el('span', 'label-args', args));
|
|
6282
|
+
// Each label knows its own component: it is a hover target that holds the set
|
|
6283
|
+
// in place, and a click target that inspects THAT component, not the innermost.
|
|
6284
|
+
label.addEventListener('mouseenter', () => { state.label_hovered = true; });
|
|
6285
|
+
label.addEventListener('mouseleave', on_label_leave);
|
|
6286
|
+
label.addEventListener('click', (event) => {
|
|
6287
|
+
event.stopPropagation(); // the document handler already skips is_ours events
|
|
6288
|
+
select(component);
|
|
6289
|
+
});
|
|
6173
6290
|
layer.appendChild(label);
|
|
6291
|
+
// A label on a narrow component may be wider than the component, so a component
|
|
6292
|
+
// near the right edge can push its label off-screen. Slide it back until its
|
|
6293
|
+
// right edge sits on the margin, never past the left edge.
|
|
6294
|
+
const width = label.getBoundingClientRect().width || label.offsetWidth;
|
|
6295
|
+
const limit = window.innerWidth - VIEWPORT_MARGIN;
|
|
6296
|
+
label.style.left = `${left + width > limit ? Math.max(0, Math.round(limit - width)) : left}px`;
|
|
6174
6297
|
}
|
|
6175
6298
|
}
|
|
6176
6299
|
/** `$id=7 $title="Users"` - only strings, numbers and booleans, never internals. */
|
|
@@ -6200,7 +6323,7 @@ function on_click(event) {
|
|
|
6200
6323
|
close_modal();
|
|
6201
6324
|
return;
|
|
6202
6325
|
}
|
|
6203
|
-
|
|
6326
|
+
select(chain[0]);
|
|
6204
6327
|
}
|
|
6205
6328
|
function on_keydown(event) {
|
|
6206
6329
|
if (event.key === 'Escape' && state.modal_component) {
|
|
@@ -6214,17 +6337,82 @@ function close_modal() {
|
|
|
6214
6337
|
state.modal.classList.remove(`${PREFIX}modal-open`);
|
|
6215
6338
|
state.modal.textContent = '';
|
|
6216
6339
|
state.modal_component = null;
|
|
6340
|
+
state.nav_stack = [];
|
|
6341
|
+
set_selected(null);
|
|
6342
|
+
}
|
|
6343
|
+
// ---------------------------------------------------------------------------
|
|
6344
|
+
// Selection and navigation
|
|
6345
|
+
//
|
|
6346
|
+
// Three ways in, and they differ only in what they do to the navigation stack:
|
|
6347
|
+
// select() - a FRESH selection (page click, label click, inspect()): the stack
|
|
6348
|
+
// is dropped, so Back disappears.
|
|
6349
|
+
// navigate() - a step along the chain (Parent, an Ancestry entry, the
|
|
6350
|
+
// Instantiator link): the component being left is pushed.
|
|
6351
|
+
// show() - render only, stack untouched; what Back and the lifecycle
|
|
6352
|
+
// buttons re-open with.
|
|
6353
|
+
// ---------------------------------------------------------------------------
|
|
6354
|
+
function select(component) {
|
|
6355
|
+
state.nav_stack = [];
|
|
6356
|
+
show(component);
|
|
6357
|
+
}
|
|
6358
|
+
function navigate(component) {
|
|
6359
|
+
if (state.modal_component && state.modal_component !== component) {
|
|
6360
|
+
state.nav_stack.push(state.modal_component);
|
|
6361
|
+
}
|
|
6362
|
+
show(component);
|
|
6217
6363
|
}
|
|
6218
|
-
|
|
6364
|
+
/** Pop to the last component still alive; a stopped one is skipped, not shown. */
|
|
6365
|
+
function go_back() {
|
|
6366
|
+
while (state.nav_stack.length) {
|
|
6367
|
+
const previous = state.nav_stack.pop();
|
|
6368
|
+
if (previous.$.hasClass('_Component_Stopped'))
|
|
6369
|
+
continue;
|
|
6370
|
+
show(previous);
|
|
6371
|
+
return;
|
|
6372
|
+
}
|
|
6373
|
+
if (state.modal_component)
|
|
6374
|
+
show(state.modal_component); // nothing left: drop Back
|
|
6375
|
+
}
|
|
6376
|
+
/** Move SELECTED_CLASS to `element`, or take it off the page entirely for null. */
|
|
6377
|
+
function set_selected(element) {
|
|
6378
|
+
if (state.selected_element && state.selected_element !== element) {
|
|
6379
|
+
state.selected_element.classList.remove(SELECTED_CLASS);
|
|
6380
|
+
}
|
|
6381
|
+
state.selected_element = element;
|
|
6382
|
+
if (element)
|
|
6383
|
+
element.classList.add(SELECTED_CLASS);
|
|
6384
|
+
}
|
|
6385
|
+
/**
|
|
6386
|
+
* The inspector. Three children: a fixed title bar, a scrolling body holding every
|
|
6387
|
+
* section, and a fixed footer of lifecycle buttons. The modal sits top-right, but
|
|
6388
|
+
* moves to the left when the inspected component is itself in the right half of the
|
|
6389
|
+
* viewport - otherwise the panel covers the thing being inspected.
|
|
6390
|
+
*/
|
|
6391
|
+
function show(component) {
|
|
6219
6392
|
const modal = state.modal;
|
|
6220
6393
|
modal.textContent = '';
|
|
6221
6394
|
state.modal_component = component;
|
|
6222
6395
|
const chain = chain_for(component.$[0]);
|
|
6223
6396
|
const ancestors = chain.slice(1);
|
|
6224
6397
|
const element = component.$[0];
|
|
6225
|
-
|
|
6398
|
+
set_selected(element);
|
|
6399
|
+
modal.classList.toggle(`${PREFIX}modal-left`, element.getBoundingClientRect().left > window.innerWidth / 2);
|
|
6400
|
+
// Title bar: the name, then [Back] [Parent] [Log to console] [Close]. Back is
|
|
6401
|
+
// there only while something was navigated away from, Parent only while the
|
|
6402
|
+
// component has a DOM parent component - the first Ancestry entry.
|
|
6226
6403
|
const title = el('div', 'title');
|
|
6227
6404
|
title.appendChild(el('span', 'title-name', `<${component.component_name()}>`));
|
|
6405
|
+
if (state.nav_stack.length) {
|
|
6406
|
+
const back = el('button', 'button', 'Back');
|
|
6407
|
+
back.addEventListener('click', go_back);
|
|
6408
|
+
title.appendChild(back);
|
|
6409
|
+
}
|
|
6410
|
+
const parent = ancestors[0];
|
|
6411
|
+
if (parent) {
|
|
6412
|
+
const up = el('button', 'button', 'Parent');
|
|
6413
|
+
up.addEventListener('click', () => navigate(parent));
|
|
6414
|
+
title.appendChild(up);
|
|
6415
|
+
}
|
|
6228
6416
|
const log = el('button', 'button', 'Log to console');
|
|
6229
6417
|
log.addEventListener('click', () => {
|
|
6230
6418
|
console.log(`[JQHTML debug] <${component.component_name()}>`, component, element);
|
|
@@ -6234,6 +6422,9 @@ function open_modal(component) {
|
|
|
6234
6422
|
close.addEventListener('click', close_modal);
|
|
6235
6423
|
title.appendChild(close);
|
|
6236
6424
|
modal.appendChild(title);
|
|
6425
|
+
// The only scrolling element: the title bar and the footer stay put.
|
|
6426
|
+
const body = el('div', 'body');
|
|
6427
|
+
modal.appendChild(body);
|
|
6237
6428
|
// Identity
|
|
6238
6429
|
const ctor = component.constructor;
|
|
6239
6430
|
const hierarchy = ctor.get_class_hierarchy ? ctor.get_class_hierarchy() : [ctor.name];
|
|
@@ -6242,15 +6433,18 @@ function open_modal(component) {
|
|
|
6242
6433
|
row(identity, 'class', '', hierarchy.join(' → '));
|
|
6243
6434
|
row(identity, 'element', '', describe_element(element));
|
|
6244
6435
|
row(identity, '_cid', '', String(component._cid));
|
|
6245
|
-
|
|
6436
|
+
const lifecycle = READY_STATES[component._ready_state] || String(component._ready_state);
|
|
6437
|
+
row(identity, 'lifecycle', '', component._debug_no_data
|
|
6438
|
+
? `${lifecycle} (no data - reload w/o data)`
|
|
6439
|
+
: lifecycle);
|
|
6246
6440
|
const nocache = element.getAttribute('data-nocache');
|
|
6247
6441
|
if (nocache)
|
|
6248
6442
|
row(identity, 'cache', '', `declined: ${nocache}`);
|
|
6249
|
-
|
|
6443
|
+
body.appendChild(section('Identity', identity));
|
|
6250
6444
|
// Args / data / state
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6445
|
+
body.appendChild(section('Args', object_table(component.args)));
|
|
6446
|
+
body.appendChild(section('Data', object_table(component.data)));
|
|
6447
|
+
body.appendChild(section('State', object_table(component.state)));
|
|
6254
6448
|
// Ancestry
|
|
6255
6449
|
const list = el('div', 'list');
|
|
6256
6450
|
if (!ancestors.length)
|
|
@@ -6259,10 +6453,10 @@ function open_modal(component) {
|
|
|
6259
6453
|
const link = el('div', 'link');
|
|
6260
6454
|
link.appendChild(el('span', 'link-name', `<${ancestor.component_name()}>`));
|
|
6261
6455
|
link.appendChild(el('span', 'link-cid', String(ancestor._cid)));
|
|
6262
|
-
link.addEventListener('click', () =>
|
|
6456
|
+
link.addEventListener('click', () => navigate(ancestor));
|
|
6263
6457
|
list.appendChild(link);
|
|
6264
6458
|
}
|
|
6265
|
-
|
|
6459
|
+
body.appendChild(section('Ancestry (DOM, nearest first)', list));
|
|
6266
6460
|
// Instantiator - the component whose template wrote this tag. Differs from
|
|
6267
6461
|
// the DOM parent for markup written in a slot body or default content.
|
|
6268
6462
|
const instantiator = component.instantiator ? component.instantiator() : null;
|
|
@@ -6271,7 +6465,7 @@ function open_modal(component) {
|
|
|
6271
6465
|
const link = el('div', 'link');
|
|
6272
6466
|
link.appendChild(el('span', 'link-name', `<${instantiator.component_name()}>`));
|
|
6273
6467
|
link.appendChild(el('span', 'link-cid', String(instantiator._cid)));
|
|
6274
|
-
link.addEventListener('click', () =>
|
|
6468
|
+
link.addEventListener('click', () => navigate(instantiator));
|
|
6275
6469
|
inst.appendChild(link);
|
|
6276
6470
|
if (ancestors[0] && instantiator !== ancestors[0]) {
|
|
6277
6471
|
inst.appendChild(el('div', 'note', 'Written in this component\'s template but rendered inside a different parent (slot or default content): handlers and $sid bind here.'));
|
|
@@ -6280,9 +6474,49 @@ function open_modal(component) {
|
|
|
6280
6474
|
else {
|
|
6281
6475
|
inst.appendChild(el('div', 'empty', 'none - created directly'));
|
|
6282
6476
|
}
|
|
6283
|
-
|
|
6477
|
+
body.appendChild(section('Instantiator', inst));
|
|
6478
|
+
// Footer: lifecycle controls. Clicks land inside the shadow host, so the
|
|
6479
|
+
// overlay's own click hijack lets them through (is_ours).
|
|
6480
|
+
const footer = el('div', 'footer');
|
|
6481
|
+
footer.appendChild(el('span', 'footer-label', 'Lifecycle:'));
|
|
6482
|
+
footer.appendChild(lifecycle_button(component, 'Reload', (c) => c.reload()));
|
|
6483
|
+
footer.appendChild(lifecycle_button(component, 'Refresh', (c) => c.refresh()));
|
|
6484
|
+
footer.appendChild(lifecycle_button(component, 'Rerender', (c) => c.render()));
|
|
6485
|
+
footer.appendChild(lifecycle_button(component, 'Reload w/o data', (c) => c._reload_without_data()));
|
|
6486
|
+
modal.appendChild(footer);
|
|
6284
6487
|
modal.classList.add(`${PREFIX}modal-open`);
|
|
6285
6488
|
}
|
|
6489
|
+
/**
|
|
6490
|
+
* One footer button. Runs its lifecycle call on a live component, logs whatever it
|
|
6491
|
+
* throws or rejects with, and re-opens the modal once the call settles so the panel
|
|
6492
|
+
* (lifecycle row above all) describes the state the button just produced.
|
|
6493
|
+
*/
|
|
6494
|
+
function lifecycle_button(component, label, run) {
|
|
6495
|
+
const button = el('button', 'button footer-button', label);
|
|
6496
|
+
button.addEventListener('click', () => {
|
|
6497
|
+
if (component.$.hasClass('_Component_Stopped'))
|
|
6498
|
+
return; // dead component: nothing to do
|
|
6499
|
+
let result;
|
|
6500
|
+
try {
|
|
6501
|
+
result = run(component);
|
|
6502
|
+
}
|
|
6503
|
+
catch (error) {
|
|
6504
|
+
console.error(`[JQHTML debug] ${label} threw on <${component.component_name()}>`, error);
|
|
6505
|
+
return;
|
|
6506
|
+
}
|
|
6507
|
+
Promise.resolve(result)
|
|
6508
|
+
.catch((error) => {
|
|
6509
|
+
console.error(`[JQHTML debug] ${label} rejected on <${component.component_name()}>`, error);
|
|
6510
|
+
})
|
|
6511
|
+
.then(() => {
|
|
6512
|
+
// `show`, not `select`: the lifecycle buttons re-render the panel in place
|
|
6513
|
+
// and must not throw away the navigation stack behind it.
|
|
6514
|
+
if (state.enabled && state.modal_component === component)
|
|
6515
|
+
show(component);
|
|
6516
|
+
});
|
|
6517
|
+
});
|
|
6518
|
+
return button;
|
|
6519
|
+
}
|
|
6286
6520
|
// ---------------------------------------------------------------------------
|
|
6287
6521
|
// DOM helpers (shadow side)
|
|
6288
6522
|
// ---------------------------------------------------------------------------
|
|
@@ -7013,7 +7247,7 @@ function init(jQuery, config) {
|
|
|
7013
7247
|
}
|
|
7014
7248
|
}
|
|
7015
7249
|
// Version - will be replaced during build with actual version from package.json
|
|
7016
|
-
const version = '2.3.
|
|
7250
|
+
const version = '2.3.70';
|
|
7017
7251
|
// Default export with all functionality
|
|
7018
7252
|
const jqhtml = {
|
|
7019
7253
|
// Core
|