@jqhtml/core 2.3.4 → 2.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -879,7 +879,7 @@ function devWarn(message) {
879
879
  console.warn(`[JQHTML Dev Warning] ${message}`);
880
880
  }
881
881
  // Get global jqhtml object
882
- function getJqhtml$1() {
882
+ function getJqhtml() {
883
883
  if (typeof window !== 'undefined' && window.jqhtml) {
884
884
  return window.jqhtml;
885
885
  }
@@ -892,7 +892,7 @@ function getJqhtml$1() {
892
892
  }
893
893
  // Visual flash effect
894
894
  function flashComponent(component, eventType) {
895
- const jqhtml = getJqhtml$1();
895
+ const jqhtml = getJqhtml();
896
896
  if (!jqhtml?.debug?.flashComponents)
897
897
  return;
898
898
  const duration = jqhtml.debug.flashDuration || 500;
@@ -914,7 +914,7 @@ function flashComponent(component, eventType) {
914
914
  }
915
915
  // Log lifecycle event
916
916
  function logLifecycle(component, phase, status) {
917
- const jqhtml = getJqhtml$1();
917
+ const jqhtml = getJqhtml();
918
918
  if (!jqhtml?.debug)
919
919
  return;
920
920
  const shouldLog = jqhtml.debug.logFullLifecycle ||
@@ -960,7 +960,7 @@ function logLifecycle(component, phase, status) {
960
960
  }
961
961
  // Apply delays based on lifecycle phase
962
962
  function applyDebugDelay(phase) {
963
- const jqhtml = getJqhtml$1();
963
+ const jqhtml = getJqhtml();
964
964
  if (!jqhtml?.debug)
965
965
  return;
966
966
  let delayMs = 0;
@@ -981,14 +981,14 @@ function applyDebugDelay(phase) {
981
981
  }
982
982
  // Log instruction processing
983
983
  function logInstruction(type, data) {
984
- const jqhtml = getJqhtml$1();
984
+ const jqhtml = getJqhtml();
985
985
  if (!jqhtml?.debug?.logInstructionProcessing)
986
986
  return;
987
987
  console.log(`[JQHTML Instruction] ${type}:`, data);
988
988
  }
989
989
  // Log data changes
990
990
  function logDataChange(component, property, oldValue, newValue) {
991
- const jqhtml = getJqhtml$1();
991
+ const jqhtml = getJqhtml();
992
992
  if (!jqhtml?.debug?.traceDataFlow)
993
993
  return;
994
994
  console.log(`[JQHTML Data] ${component.constructor.name}#${component._cid}.data.${property}:`, { old: oldValue, new: newValue });
@@ -1001,7 +1001,7 @@ function updateComponentTree() {
1001
1001
  }
1002
1002
  // Router dispatch logging
1003
1003
  function logDispatch(url, route, params, verbose = false) {
1004
- const jqhtml = getJqhtml$1();
1004
+ const jqhtml = getJqhtml();
1005
1005
  if (!jqhtml?.debug)
1006
1006
  return;
1007
1007
  const shouldLog = jqhtml.debug.logDispatch || jqhtml.debug.logDispatchVerbose;
@@ -1023,12 +1023,12 @@ function logDispatch(url, route, params, verbose = false) {
1023
1023
  }
1024
1024
  // Check if sequential processing is enabled
1025
1025
  function isSequentialProcessing() {
1026
- const jqhtml = getJqhtml$1();
1026
+ const jqhtml = getJqhtml();
1027
1027
  return jqhtml?.debug?.sequentialProcessing || false;
1028
1028
  }
1029
1029
  // Error handling with break on error
1030
1030
  function handleComponentError(component, phase, error) {
1031
- const jqhtml = getJqhtml$1();
1031
+ const jqhtml = getJqhtml();
1032
1032
  console.error(`[JQHTML Error] ${component.constructor.name}#${component._cid} failed in ${phase}:`, error);
1033
1033
  if (jqhtml?.debug?.breakOnError) {
1034
1034
  debugger; // This will pause execution in dev tools
@@ -1056,6 +1056,9 @@ function handleComponentError(component, phase, error) {
1056
1056
  * - Scoped IDs using _cid pattern
1057
1057
  * - Event emission and CSS class hierarchy
1058
1058
  */
1059
+ // WeakMap storage for protected lifecycle method implementations (Option 2)
1060
+ // See docs/internal/lifecycle-method-protection.md for design details
1061
+ const lifecycle_impls = new WeakMap();
1059
1062
  class Jqhtml_Component {
1060
1063
  constructor(element, args = {}) {
1061
1064
  this._ready_state = 0; // 0=created, 1=init, 2=loaded, 3=rendered, 4=ready
@@ -1076,6 +1079,7 @@ class Jqhtml_Component {
1076
1079
  this.__initial_data_snapshot = null; // Snapshot of this.data after on_create() for restoration before on_load()
1077
1080
  this.__data_frozen = false; // Track if this.data is currently frozen
1078
1081
  this.next_reload_force_refresh = null; // State machine for reload()/refresh() debounce precedence
1082
+ this.__lifecycle_authorized = false; // Flag for lifecycle method protection
1079
1083
  this._cid = this._generate_cid();
1080
1084
  this._lifecycle_manager = LifecycleManager.get_instance();
1081
1085
  // Create or wrap element
@@ -1189,6 +1193,63 @@ class Jqhtml_Component {
1189
1193
  this.state = {};
1190
1194
  this._log_lifecycle('construct', 'complete');
1191
1195
  }
1196
+ /**
1197
+ * Protect lifecycle methods from manual invocation
1198
+ * Stores original implementations in WeakMap, replaces with guarded wrappers
1199
+ * @private
1200
+ */
1201
+ _protect_lifecycle_methods() {
1202
+ const methods = {
1203
+ on_create: 'Called automatically during creation.',
1204
+ on_render: 'Use render() to trigger a re-render.',
1205
+ on_load: 'Use reload() to refresh data.',
1206
+ on_ready: 'Called automatically when ready.',
1207
+ on_stop: 'Use stop() to stop the component.'
1208
+ };
1209
+ const impls = {};
1210
+ const self = this;
1211
+ for (const [name, help] of Object.entries(methods)) {
1212
+ const original = this[name];
1213
+ // Skip if using base class default (empty method)
1214
+ if (original === Jqhtml_Component.prototype[name])
1215
+ continue;
1216
+ impls[name] = original;
1217
+ // Create wrapper with same function name (for stack traces)
1218
+ this[name] = {
1219
+ [name](...args) {
1220
+ if (!self.__lifecycle_authorized) {
1221
+ throw new Error(`[JQHTML] ${name}() cannot be called manually. ${help}\n` +
1222
+ `Component: ${self.component_name()} (_cid: ${self._cid})`);
1223
+ }
1224
+ return lifecycle_impls.get(self)[name].apply(self, args);
1225
+ }
1226
+ }[name];
1227
+ }
1228
+ lifecycle_impls.set(this, impls);
1229
+ }
1230
+ /**
1231
+ * Call a lifecycle method with authorization (async)
1232
+ * Framework calls this to invoke lifecycle methods, bypassing the protection wrapper.
1233
+ * The flag is set momentarily for the wrapper check, then reset BEFORE user code runs.
1234
+ * This ensures any nested lifecycle calls from user code will fail the flag check.
1235
+ * @private
1236
+ */
1237
+ async _call_lifecycle(name, context) {
1238
+ // Get the original implementation (bypasses wrapper entirely)
1239
+ const impl = lifecycle_impls.get(this)?.[name] || this[name];
1240
+ // Call original directly - no flag needed since we bypass the wrapper
1241
+ return await impl.call(context || this);
1242
+ }
1243
+ /**
1244
+ * Call a lifecycle method with authorization (sync version for sync methods like on_stop)
1245
+ * @private
1246
+ */
1247
+ _call_lifecycle_sync(name) {
1248
+ // Get the original implementation (bypasses wrapper entirely)
1249
+ const impl = lifecycle_impls.get(this)?.[name] || this[name];
1250
+ // Call original directly - no flag needed since we bypass the wrapper
1251
+ return impl.call(this);
1252
+ }
1192
1253
  /**
1193
1254
  * Boot - Start the full component lifecycle
1194
1255
  * Called immediately after construction by instruction processor
@@ -1202,6 +1263,8 @@ class Jqhtml_Component {
1202
1263
  if (this._booted)
1203
1264
  return;
1204
1265
  this._booted = true;
1266
+ // Protect lifecycle methods from manual invocation (must happen after subclass constructor)
1267
+ this._protect_lifecycle_methods();
1205
1268
  await this._lifecycle_manager.boot_component(this);
1206
1269
  }
1207
1270
  // -------------------------------------------------------------------------
@@ -1412,9 +1475,9 @@ class Jqhtml_Component {
1412
1475
  // Don't update ready state here - let phases complete in order
1413
1476
  this._update_debug_attrs();
1414
1477
  this._log_lifecycle('render', 'complete');
1415
- // Call on_render() immediately after render completes
1478
+ // Call on_render() with authorization (sync) immediately after render completes
1416
1479
  // This ensures event handlers are always re-attached after DOM updates
1417
- const renderResult = this.on_render();
1480
+ const renderResult = this._call_lifecycle_sync('on_render');
1418
1481
  if (renderResult && typeof renderResult.then === 'function') {
1419
1482
  console.warn(`[JQHTML] Component "${this.component_name()}" returned a Promise from on_render(). ` +
1420
1483
  `on_render() must be synchronous code. Remove 'async' from the function declaration.`);
@@ -1479,8 +1542,8 @@ class Jqhtml_Component {
1479
1542
  if (this._render_count !== render_id) {
1480
1543
  return; // Stale render, don't call on_ready
1481
1544
  }
1482
- // Call on_ready hook
1483
- await this.on_ready();
1545
+ // Call on_ready hook with authorization
1546
+ await this._call_lifecycle('on_ready');
1484
1547
  // Trigger ready event
1485
1548
  await this.trigger('ready');
1486
1549
  })();
@@ -1500,8 +1563,8 @@ class Jqhtml_Component {
1500
1563
  if (this._stopped || this._ready_state >= 1)
1501
1564
  return;
1502
1565
  this._log_lifecycle('create', 'start');
1503
- // Call on_create() and validate it's synchronous
1504
- const result = this.on_create();
1566
+ // Call on_create() with authorization and validate it's synchronous
1567
+ const result = await this._call_lifecycle('on_create');
1505
1568
  if (result && typeof result.then === 'function') {
1506
1569
  console.warn(`[JQHTML] Component "${this.component_name()}" returned a Promise from on_create(). ` +
1507
1570
  `on_create() must be synchronous code. Remove 'async' from the function declaration.`);
@@ -1616,8 +1679,8 @@ class Jqhtml_Component {
1616
1679
  if (window.jqhtml?.debug?.verbose) {
1617
1680
  console.log(`[Cache] Component ${this._cid} (${this.component_name()}) has non-serializable args - load deduplication and caching disabled`, { uncacheable_property });
1618
1681
  }
1619
- // Execute on_load() without deduplication or caching
1620
- await this.on_load();
1682
+ // Execute on_load() with authorization, without deduplication or caching
1683
+ await this._call_lifecycle('on_load');
1621
1684
  this.__data_frozen = true;
1622
1685
  return;
1623
1686
  }
@@ -1726,7 +1789,7 @@ class Jqhtml_Component {
1726
1789
  // - Should errors reset state machine flags (next_reload_force_refresh)?
1727
1790
  // - Should partial data be preserved or rolled back?
1728
1791
  // - Should followers be notified differently based on error type?
1729
- await this.on_load.call(restricted_this);
1792
+ await this._call_lifecycle('on_load', restricted_this);
1730
1793
  }
1731
1794
  catch (error) {
1732
1795
  // Handle error and notify coordinator
@@ -1798,7 +1861,7 @@ class Jqhtml_Component {
1798
1861
  this._log_lifecycle('ready', 'start');
1799
1862
  // Wait for all children to reach ready state (bottom-up execution)
1800
1863
  await this._wait_for_children_ready();
1801
- await this.on_ready();
1864
+ await this._call_lifecycle('on_ready');
1802
1865
  this._ready_state = 4;
1803
1866
  this._update_debug_attrs();
1804
1867
  this._log_lifecycle('ready', 'complete');
@@ -2014,7 +2077,7 @@ class Jqhtml_Component {
2014
2077
  this.data = JSON.parse(JSON.stringify(this.__initial_data_snapshot));
2015
2078
  }
2016
2079
  try {
2017
- await this.on_load();
2080
+ await this._call_lifecycle('on_load');
2018
2081
  }
2019
2082
  finally {
2020
2083
  // Freeze this.data after on_load() completes
@@ -2090,7 +2153,7 @@ class Jqhtml_Component {
2090
2153
  // STEP 3.5 & 4: Wait for children and call on_ready (only if we rendered)
2091
2154
  if (rendered_from_cache || should_render) {
2092
2155
  await this._wait_for_children_ready();
2093
- await this.on_ready();
2156
+ await this._call_lifecycle('on_ready');
2094
2157
  }
2095
2158
  this._log_lifecycle('reload', 'complete');
2096
2159
  }
@@ -2124,16 +2187,14 @@ class Jqhtml_Component {
2124
2187
  this.$.addClass('_Component_Stopped');
2125
2188
  // Unregister from lifecycle manager
2126
2189
  this._lifecycle_manager.unregister_component(this);
2127
- // Call user's on_stop() hook
2128
- const stopResult = this.on_stop();
2190
+ // Call user's on_stop() hook with authorization (sync)
2191
+ const stopResult = this._call_lifecycle_sync('on_stop');
2129
2192
  if (stopResult && typeof stopResult.then === 'function') {
2130
2193
  console.warn(`[JQHTML] Component "${this.component_name()}" returned a Promise from on_stop(). ` +
2131
2194
  `on_stop() must be synchronous code. Remove 'async' from the function declaration.`);
2132
2195
  }
2133
- // Fire registered destroy callbacks
2134
- this.trigger('destroy');
2135
- // Trigger jQuery destroy event
2136
- this.$.trigger('destroy');
2196
+ // Fire registered stop callbacks
2197
+ this.trigger('stop');
2137
2198
  // Remove from DOM parent's children
2138
2199
  if (this._dom_parent) {
2139
2200
  this._dom_parent._dom_children.delete(this);
@@ -3091,388 +3152,6 @@ function hydrateElement($element, jQ) {
3091
3152
  }
3092
3153
  }
3093
3154
 
3094
- /**
3095
- * JQHTML Debug Overlay
3096
- *
3097
- * Independent debug controls using pure jQuery DOM manipulation.
3098
- * Does NOT use JQHTML components so it works even when components are broken.
3099
- */
3100
- // Get global jQuery
3101
- function getJQuery() {
3102
- if (typeof window !== 'undefined' && window.$) {
3103
- return window.$;
3104
- }
3105
- if (typeof window !== 'undefined' && window.jQuery) {
3106
- return window.jQuery;
3107
- }
3108
- throw new Error('FATAL: jQuery is not defined. jQuery must be loaded before using JQHTML. ' +
3109
- 'Add <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> before loading JQHTML.');
3110
- }
3111
- // Get global jqhtml object
3112
- function getJqhtml() {
3113
- if (typeof window !== 'undefined' && window.jqhtml) {
3114
- return window.jqhtml;
3115
- }
3116
- if (typeof globalThis !== 'undefined' && globalThis.jqhtml) {
3117
- return globalThis.jqhtml;
3118
- }
3119
- throw new Error('FATAL: window.jqhtml is not defined. The JQHTML runtime must be loaded before using JQHTML components. ' +
3120
- 'Ensure @jqhtml/core is imported and initialized before attempting to use debug features.');
3121
- }
3122
- class DebugOverlay {
3123
- constructor(options = {}) {
3124
- this.$container = null;
3125
- this.$statusIndicator = null;
3126
- this.$ = getJQuery();
3127
- if (!this.$) {
3128
- throw new Error('jQuery is required for DebugOverlay');
3129
- }
3130
- this.options = {
3131
- position: 'bottom',
3132
- theme: 'dark',
3133
- compact: false,
3134
- showStatus: true,
3135
- autoHide: false,
3136
- ...options
3137
- };
3138
- }
3139
- /**
3140
- * Static method to show debug overlay (singleton pattern)
3141
- */
3142
- static show(options) {
3143
- if (!DebugOverlay.instance) {
3144
- DebugOverlay.instance = new DebugOverlay(options);
3145
- }
3146
- DebugOverlay.instance.display();
3147
- return DebugOverlay.instance;
3148
- }
3149
- /**
3150
- * Static method to hide debug overlay
3151
- */
3152
- static hide() {
3153
- if (DebugOverlay.instance) {
3154
- DebugOverlay.instance.hide();
3155
- }
3156
- }
3157
- /**
3158
- * Static method to toggle debug overlay visibility
3159
- */
3160
- static toggle() {
3161
- if (DebugOverlay.instance && DebugOverlay.instance.$container) {
3162
- if (DebugOverlay.instance.$container.is(':visible')) {
3163
- DebugOverlay.hide();
3164
- }
3165
- else {
3166
- DebugOverlay.instance.display();
3167
- }
3168
- }
3169
- else {
3170
- DebugOverlay.show();
3171
- }
3172
- }
3173
- /**
3174
- * Static method to destroy debug overlay
3175
- */
3176
- static destroy() {
3177
- if (DebugOverlay.instance) {
3178
- DebugOverlay.instance.destroy();
3179
- DebugOverlay.instance = null;
3180
- }
3181
- }
3182
- /**
3183
- * Display the debug overlay
3184
- */
3185
- display() {
3186
- if (this.$container) {
3187
- this.$container.show();
3188
- return;
3189
- }
3190
- this.createOverlay();
3191
- if (this.options.showStatus) {
3192
- this.createStatusIndicator();
3193
- }
3194
- }
3195
- /**
3196
- * Hide the debug overlay
3197
- */
3198
- hide() {
3199
- if (this.$container) {
3200
- this.$container.hide();
3201
- }
3202
- if (this.$statusIndicator) {
3203
- this.$statusIndicator.hide();
3204
- }
3205
- }
3206
- /**
3207
- * Remove the debug overlay completely
3208
- */
3209
- destroy() {
3210
- if (this.$container) {
3211
- this.$container.remove();
3212
- this.$container = null;
3213
- }
3214
- if (this.$statusIndicator) {
3215
- this.$statusIndicator.remove();
3216
- this.$statusIndicator = null;
3217
- }
3218
- }
3219
- /**
3220
- * Update the status indicator
3221
- */
3222
- updateStatus(mode) {
3223
- if (!this.$statusIndicator)
3224
- return;
3225
- this.$statusIndicator.text('Debug: ' + mode);
3226
- this.$statusIndicator.attr('class', 'jqhtml-debug-status' + (mode !== 'Off' ? ' active' : ''));
3227
- }
3228
- createOverlay() {
3229
- // Add styles first
3230
- this.addStyles();
3231
- // Create container using jQuery
3232
- this.$container = this.$('<div>')
3233
- .addClass(`jqhtml-debug-overlay ${this.options.theme} ${this.options.position}`);
3234
- // Create content structure
3235
- const $content = this.$('<div>').addClass('jqhtml-debug-content');
3236
- const $controls = this.$('<div>').addClass('jqhtml-debug-controls');
3237
- // Add title
3238
- const $title = this.$('<span>')
3239
- .addClass('jqhtml-debug-title')
3240
- .html('<strong>🐛 JQHTML Debug:</strong>');
3241
- $controls.append($title);
3242
- // Create buttons
3243
- const buttons = [
3244
- { text: 'Slow Motion + Flash', action: 'enableSlowMotionDebug', class: 'success' },
3245
- { text: 'Basic Debug', action: 'enableBasicDebug', class: '' },
3246
- { text: 'Full Debug', action: 'enableFullDebug', class: '' },
3247
- { text: 'Sequential', action: 'enableSequentialMode', class: '' },
3248
- { text: 'Clear Debug', action: 'clearAllDebug', class: 'danger' },
3249
- { text: 'Settings', action: 'showDebugInfo', class: '' }
3250
- ];
3251
- buttons.forEach(btn => {
3252
- const $button = this.$('<button>')
3253
- .text(btn.text)
3254
- .addClass('jqhtml-debug-btn' + (btn.class ? ` ${btn.class}` : ''))
3255
- .on('click', () => this.executeAction(btn.action));
3256
- $controls.append($button);
3257
- });
3258
- // Add minimize/close button
3259
- const $toggleBtn = this.$('<button>')
3260
- .text(this.options.compact ? '▼' : '▲')
3261
- .addClass('jqhtml-debug-toggle')
3262
- .on('click', () => this.toggle());
3263
- $controls.append($toggleBtn);
3264
- // Assemble and add to page
3265
- $content.append($controls);
3266
- this.$container.append($content);
3267
- this.$('body').append(this.$container);
3268
- }
3269
- createStatusIndicator() {
3270
- this.$statusIndicator = this.$('<div>')
3271
- .addClass('jqhtml-debug-status')
3272
- .text('Debug: Off')
3273
- .css({
3274
- position: 'fixed',
3275
- top: '10px',
3276
- right: '10px',
3277
- background: '#2c3e50',
3278
- color: 'white',
3279
- padding: '5px 10px',
3280
- borderRadius: '4px',
3281
- fontSize: '0.75rem',
3282
- zIndex: '10001',
3283
- opacity: '0.8',
3284
- fontFamily: 'monospace'
3285
- });
3286
- this.$('body').append(this.$statusIndicator);
3287
- }
3288
- addStyles() {
3289
- // Check if styles already exist
3290
- if (this.$('#jqhtml-debug-styles').length > 0)
3291
- return;
3292
- // Create and inject CSS using jQuery - concatenated strings for better minification
3293
- const $style = this.$('<style>')
3294
- .attr('id', 'jqhtml-debug-styles')
3295
- .text('.jqhtml-debug-overlay {' +
3296
- 'position: fixed;' +
3297
- 'left: 0;' +
3298
- 'right: 0;' +
3299
- 'z-index: 10000;' +
3300
- 'font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace;' +
3301
- 'font-size: 0.8rem;' +
3302
- 'box-shadow: 0 2px 10px rgba(0,0,0,0.2);' +
3303
- '}' +
3304
- '.jqhtml-debug-overlay.top {' +
3305
- 'top: 0;' +
3306
- '}' +
3307
- '.jqhtml-debug-overlay.bottom {' +
3308
- 'bottom: 0;' +
3309
- '}' +
3310
- '.jqhtml-debug-overlay.dark {' +
3311
- 'background: #34495e;' +
3312
- 'color: #ecf0f1;' +
3313
- '}' +
3314
- '.jqhtml-debug-overlay.light {' +
3315
- 'background: #f8f9fa;' +
3316
- 'color: #333;' +
3317
- 'border-bottom: 1px solid #dee2e6;' +
3318
- '}' +
3319
- '.jqhtml-debug-content {' +
3320
- 'padding: 0.5rem 1rem;' +
3321
- '}' +
3322
- '.jqhtml-debug-controls {' +
3323
- 'display: flex;' +
3324
- 'flex-wrap: wrap;' +
3325
- 'gap: 8px;' +
3326
- 'align-items: center;' +
3327
- '}' +
3328
- '.jqhtml-debug-title {' +
3329
- 'margin-right: 10px;' +
3330
- 'font-weight: bold;' +
3331
- '}' +
3332
- '.jqhtml-debug-btn {' +
3333
- 'padding: 4px 8px;' +
3334
- 'border: none;' +
3335
- 'border-radius: 3px;' +
3336
- 'background: #3498db;' +
3337
- 'color: white;' +
3338
- 'cursor: pointer;' +
3339
- 'font-size: 0.75rem;' +
3340
- 'transition: background 0.2s;' +
3341
- '}' +
3342
- '.jqhtml-debug-btn:hover {' +
3343
- 'background: #2980b9;' +
3344
- '}' +
3345
- '.jqhtml-debug-btn.success {' +
3346
- 'background: #27ae60;' +
3347
- '}' +
3348
- '.jqhtml-debug-btn.success:hover {' +
3349
- 'background: #229954;' +
3350
- '}' +
3351
- '.jqhtml-debug-btn.danger {' +
3352
- 'background: #e74c3c;' +
3353
- '}' +
3354
- '.jqhtml-debug-btn.danger:hover {' +
3355
- 'background: #c0392b;' +
3356
- '}' +
3357
- '.jqhtml-debug-toggle {' +
3358
- 'padding: 4px 8px;' +
3359
- 'border: none;' +
3360
- 'border-radius: 3px;' +
3361
- 'background: #7f8c8d;' +
3362
- 'color: white;' +
3363
- 'cursor: pointer;' +
3364
- 'font-size: 0.75rem;' +
3365
- 'margin-left: auto;' +
3366
- '}' +
3367
- '.jqhtml-debug-toggle:hover {' +
3368
- 'background: #6c7b7d;' +
3369
- '}' +
3370
- '.jqhtml-debug-status.active {' +
3371
- 'background: #27ae60 !important;' +
3372
- '}' +
3373
- '@media (max-width: 768px) {' +
3374
- '.jqhtml-debug-controls {' +
3375
- 'flex-direction: column;' +
3376
- 'align-items: flex-start;' +
3377
- '}' +
3378
- '.jqhtml-debug-title {' +
3379
- 'margin-bottom: 5px;' +
3380
- '}' +
3381
- '}');
3382
- this.$('head').append($style);
3383
- }
3384
- toggle() {
3385
- // Toggle between compact and full view
3386
- this.options.compact = !this.options.compact;
3387
- const $toggleBtn = this.$container.find('.jqhtml-debug-toggle');
3388
- $toggleBtn.text(this.options.compact ? '▼' : '▲');
3389
- const $buttons = this.$container.find('.jqhtml-debug-btn');
3390
- if (this.options.compact) {
3391
- $buttons.hide();
3392
- }
3393
- else {
3394
- $buttons.show();
3395
- }
3396
- }
3397
- executeAction(action) {
3398
- const jqhtml = getJqhtml();
3399
- if (!jqhtml) {
3400
- console.warn('JQHTML not available - make sure it\'s loaded and exposed globally');
3401
- return;
3402
- }
3403
- switch (action) {
3404
- case 'enableSlowMotionDebug':
3405
- jqhtml.setDebugSettings({
3406
- logFullLifecycle: true,
3407
- sequentialProcessing: true,
3408
- delayAfterComponent: 150,
3409
- delayAfterRender: 200,
3410
- delayAfterRerender: 250,
3411
- flashComponents: true,
3412
- flashDuration: 800,
3413
- flashColors: {
3414
- create: '#3498db',
3415
- render: '#27ae60',
3416
- ready: '#9b59b6'
3417
- },
3418
- profilePerformance: true,
3419
- highlightSlowRenders: 30,
3420
- logDispatch: true
3421
- });
3422
- this.updateStatus('Slow Motion');
3423
- console.log('🐛 Slow Motion Debug Mode Enabled');
3424
- break;
3425
- case 'enableBasicDebug':
3426
- jqhtml.enableDebugMode('basic');
3427
- this.updateStatus('Basic');
3428
- console.log('🐛 Basic Debug Mode Enabled');
3429
- break;
3430
- case 'enableFullDebug':
3431
- jqhtml.enableDebugMode('full');
3432
- this.updateStatus('Full');
3433
- console.log('🐛 Full Debug Mode Enabled');
3434
- break;
3435
- case 'enableSequentialMode':
3436
- jqhtml.setDebugSettings({
3437
- logCreationReady: true,
3438
- sequentialProcessing: true,
3439
- flashComponents: true,
3440
- profilePerformance: true
3441
- });
3442
- this.updateStatus('Sequential');
3443
- console.log('🐛 Sequential Processing Mode Enabled');
3444
- break;
3445
- case 'clearAllDebug':
3446
- jqhtml.clearDebugSettings();
3447
- this.updateStatus('Off');
3448
- console.log('🐛 All Debug Modes Disabled');
3449
- break;
3450
- case 'showDebugInfo':
3451
- const settings = JSON.stringify(jqhtml.debug, null, 2);
3452
- console.log('🐛 Current Debug Settings:', settings);
3453
- alert('Debug settings logged to console:\n\n' + (Object.keys(jqhtml.debug).length > 0 ? settings : 'No debug settings active'));
3454
- break;
3455
- }
3456
- }
3457
- }
3458
- DebugOverlay.instance = null;
3459
- // Simplified global convenience functions that use static methods
3460
- function showDebugOverlay(options) {
3461
- return DebugOverlay.show(options);
3462
- }
3463
- function hideDebugOverlay() {
3464
- DebugOverlay.hide();
3465
- }
3466
- // Auto-initialize if debug query parameter is present
3467
- if (typeof window !== 'undefined') {
3468
- const urlParams = new URLSearchParams(window.location.search);
3469
- if (urlParams.get('debug') === 'true' || urlParams.get('jqhtml-debug') === 'true') {
3470
- document.addEventListener('DOMContentLoaded', () => {
3471
- DebugOverlay.show();
3472
- });
3473
- }
3474
- }
3475
-
3476
3155
  /**
3477
3156
  * JQHTML v2 jQuery Plugin
3478
3157
  *
@@ -4371,7 +4050,7 @@ function init(jQuery) {
4371
4050
  }
4372
4051
  }
4373
4052
  // Version - will be replaced during build with actual version from package.json
4374
- const version = '2.3.4';
4053
+ const version = '2.3.6';
4375
4054
  // Default export with all functionality
4376
4055
  const jqhtml = {
4377
4056
  // Core
@@ -4395,6 +4074,8 @@ const jqhtml = {
4395
4074
  escape_html,
4396
4075
  // Version property - internal
4397
4076
  __version: version,
4077
+ // state facts
4078
+ tombstone: 'pepperoni and cheese',
4398
4079
  // Debug settings
4399
4080
  debug: {
4400
4081
  enabled: false,
@@ -4421,15 +4102,6 @@ const jqhtml = {
4421
4102
  clearDebugSettings() {
4422
4103
  this.debug = {};
4423
4104
  },
4424
- // Debug overlay methods
4425
- showDebugOverlay(options) {
4426
- return DebugOverlay.show(options);
4427
- },
4428
- hideDebugOverlay() {
4429
- return DebugOverlay.hide();
4430
- },
4431
- // Export DebugOverlay class for direct access
4432
- DebugOverlay,
4433
4105
  // Install globals function
4434
4106
  installGlobals() {
4435
4107
  if (typeof window !== 'undefined') {
@@ -4483,5 +4155,5 @@ if (typeof window !== 'undefined' && !window.jqhtml) {
4483
4155
  }
4484
4156
  }
4485
4157
 
4486
- export { DebugOverlay, Jqhtml_Component, LifecycleManager as Jqhtml_LifecycleManager, Jqhtml_Local_Storage, LifecycleManager, Load_Coordinator, applyDebugDelay, boot, create_component, jqhtml as default, devWarn, escape_html, extract_slots, get_component_class, get_component_names, get_registered_templates, get_template, get_template_by_class, handleComponentError, has_component, hideDebugOverlay, init, init_jquery_plugin, isSequentialProcessing, list_components, logDataChange, logDispatch, logInstruction, logLifecycle, process_instructions, register_component, register_template, render_template, showDebugOverlay, version };
4158
+ export { Jqhtml_Component, LifecycleManager as Jqhtml_LifecycleManager, Jqhtml_Local_Storage, LifecycleManager, Load_Coordinator, applyDebugDelay, boot, create_component, jqhtml as default, devWarn, escape_html, extract_slots, get_component_class, get_component_names, get_registered_templates, get_template, get_template_by_class, handleComponentError, has_component, init, init_jquery_plugin, isSequentialProcessing, list_components, logDataChange, logDispatch, logInstruction, logLifecycle, process_instructions, register_component, register_template, render_template, version };
4487
4159
  //# sourceMappingURL=index.js.map