/** * JQHTML Integration - Component Registration and Hydration Bootstrap * * This module bridges RSpade's manifest system with jqhtml's component runtime. * * == TWO-PHASE INITIALIZATION == * * Phase 1: _on_framework_modules_define() - Component Registration * - Runs early in framework boot, before DOM is processed * - Registers all ES6 classes extending Component with jqhtml runtime * - Tags static methods with cache IDs for jqhtml's caching system * - After this phase, jqhtml knows: "User_Card" → UserCardClass * * Phase 2: _on_framework_modules_init() - DOM Hydration * - Calls jqhtml.boot() to hydrate all ._Component_Init placeholders * - Triggers 'jqhtml_ready' when all components are initialized * * == KEY PARTICIPANTS == * * JqhtmlBladeCompiler.php - Transforms tags into ._Component_Init divs * jqhtml runtime - Maintains registry of component names → classes * jqhtml.boot() - Finds and hydrates all ._Component_Init placeholders * This module - Orchestrates registration and triggers hydration */ class Jqhtml_Integration { /** * Phase 1: Register Component Classes * * Compiled .jqhtml templates self-register their render methods with jqhtml. * But the framework must separately register ES6 component classes (the ones * extending Component with lifecycle methods like on_create, on_load, etc). * * This runs during framework_modules_define, before any DOM processing. */ static _on_framework_modules_define() { // ───────────────────────────────────────────────────────────────────── // Register Component Classes with jqhtml Runtime // // The Manifest knows all classes extending Component. We register each // with jqhtml so it can instantiate them by name during hydration. // ───────────────────────────────────────────────────────────────────── let jqhtml_components = Manifest.get_extending('Component'); console_debug('JQHTML_INIT', 'Registering ' + jqhtml_components.length + ' Components'); for (let component of jqhtml_components) { jqhtml.register_component(component.class_name, component.class_object); } // ───────────────────────────────────────────────────────────────────── // Tag Static Methods with Cache IDs // // jqhtml caches component output based on args. When a function is passed // as an arg (e.g., DataGrid's data_source), we need a stable string key. // // Without this: data_source: function() {...} → no cache (functions aren't serializable) // With this: function._jqhtml_cache_id = "My_DataGrid.fetch_data" → cacheable // ───────────────────────────────────────────────────────────────────── const all_classes = Manifest.get_all_classes(); let methods_tagged = 0; for (const class_info of all_classes) { const class_object = class_info.class_object; const class_name = class_info.class_name; const property_names = Object.getOwnPropertyNames(class_object); for (const property_name of property_names) { if (property_name === 'length' || property_name === 'name' || property_name === 'prototype') { continue; } const property_value = class_object[property_name]; if (typeof property_value === 'function') { property_value._jqhtml_cache_id = `${class_name}.${property_name}`; methods_tagged++; } } } console_debug('JQHTML_INIT', `Tagged ${methods_tagged} static methods with _jqhtml_cache_id`); // ───────────────────────────────────────────────────────────────────── // Configure jqhtml Caching // // scope_key() changes when: app code changes, user logs out, site changes. // This automatically invalidates cached component renders. // ───────────────────────────────────────────────────────────────────── jqhtml.set_cache_key(Rsx.scope_key()); window.jqhtml.debug.verbose = false; } /** * Phase 2: DOM Hydration * * Delegates to jqhtml.boot() which finds all ._Component_Init placeholders * and converts them into live components. * * jqhtml.boot() handles: * - Finding ._Component_Init elements * - Parsing data-component-init-name / data-component-args * - Calling $element.component(name, args) * - Recursive nested component handling * - Promise tracking for async components */ static _on_framework_modules_init() { jqhtml.boot().then(() => { Rsx.trigger('jqhtml_ready'); }); } // ═══════════════════════════════════════════════════════════════════════ // Utility Methods (pass-through to jqhtml runtime) // ═══════════════════════════════════════════════════════════════════════ /** Get all registered component names. Useful for debugging/introspection. */ static get_component_names() { return jqhtml.get_component_names(); } /** Check if a component is registered by name. */ static has_component(name) { return jqhtml.has_component(name); } } // Class is automatically made global by RSX manifest - no window assignment needed