Standardize settings file naming and relocate documentation files Fix code quality violations from rsx:check Reorganize user_management directory into logical subdirectories Move Quill Bundle to core and align with Tom Select pattern Simplify Site Settings page to focus on core site information Complete Phase 5: Multi-tenant authentication with login flow and site selection Add route query parameter rule and synchronize filename validation logic Fix critical bug in UpdateNpmCommand causing missing JavaScript stubs Implement filename convention rule and resolve VS Code auto-rename conflict Implement js-sanitizer RPC server to eliminate 900+ Node.js process spawns Implement RPC server architecture for JavaScript parsing WIP: Add RPC server infrastructure for JS parsing (partial implementation) Update jqhtml terminology from destroy to stop, fix datagrid DOM preservation Add JQHTML-CLASS-01 rule and fix redundant class names Improve code quality rules and resolve violations Remove legacy fatal error format in favor of unified 'fatal' error type Filter internal keys from window.rsxapp output Update button styling and comprehensive form/modal documentation Add conditional fly-in animation for modals Fix non-deterministic bundle compilation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
122 lines
11 KiB
JavaScript
Executable File
122 lines
11 KiB
JavaScript
Executable File
"use strict";
|
|
|
|
/**
|
|
* Modal_Abstract - Base class for modal orchestration classes
|
|
*
|
|
* **Philosophy**:
|
|
* Modal classes are orchestration layers that manage the lifecycle of showing
|
|
* a modal, collecting user input, and returning results. They do NOT contain
|
|
* form validation or business logic - that belongs in jqhtml components and
|
|
* controller endpoints.
|
|
*
|
|
* **Purpose**:
|
|
* - Provides a common base class for type identification
|
|
* - Enforces file naming conventions (modal classes end with _Modal)
|
|
* - Documents the modal class pattern
|
|
* - Enables framework-level features (future: discovery, validation)
|
|
*
|
|
* **Responsibilities of Modal Classes**:
|
|
* - Invoke Modal.form() / Modal.show() / Modal.confirm() with appropriate configuration
|
|
* - Handle modal lifecycle (show, submit, cancel, errors)
|
|
* - Return Promise that resolves with data or false
|
|
* - Encapsulate modal-specific UI logic
|
|
*
|
|
* **Contract**:
|
|
* All modal classes extending Modal_Abstract must implement:
|
|
* - `static async show(params)`: Primary entry point, returns Promise
|
|
*
|
|
* **Return Values**:
|
|
* - Success: Resolve with data object (e.g., created user record)
|
|
* - Cancel/Close: Resolve with false
|
|
* - Error: Show error in modal, keep open, don't resolve until user acts
|
|
*
|
|
* **Integration**:
|
|
* Modal classes use Modal.js static API (Modal.form(), Modal.show(), etc.)
|
|
* as building blocks. Form validation handled by Rsx_Form and Form_Utils.
|
|
* Page JS orchestrates modal flow but doesn't contain modal UI logic.
|
|
*
|
|
* **Pattern Examples**:
|
|
*
|
|
* Simple form modal:
|
|
* ```
|
|
* class Add_User_Modal extends Modal_Abstract {
|
|
* static async show() {
|
|
* const result = await Modal.form({
|
|
* title: 'Add User',
|
|
* component: 'Add_User_Modal_Form',
|
|
* on_submit: async (form) => {
|
|
* try {
|
|
* const values = form.vals();
|
|
* const result = await Controller.add_user(values);
|
|
* return result; // Close modal, return data
|
|
* } catch (error) {
|
|
* await form.render_error(error);
|
|
* return false; // Keep modal open
|
|
* }
|
|
* },
|
|
* });
|
|
* return result || false;
|
|
* }
|
|
* }
|
|
* ```
|
|
*
|
|
* Custom content modal:
|
|
* ```
|
|
* class Confirm_Delete_Modal extends Modal_Abstract {
|
|
* static async show({item_name}) {
|
|
* return await Modal.confirm(
|
|
* 'Confirm Delete',
|
|
* `Are you sure you want to delete ${item_name}?`
|
|
* );
|
|
* }
|
|
* }
|
|
* ```
|
|
*
|
|
* Modal with backend call:
|
|
* ```
|
|
* class Send_Invite_Modal extends Modal_Abstract {
|
|
* static async show(user_id) {
|
|
* const result = await Controller.send_invite({user_id});
|
|
* if (result.invite_url) {
|
|
* await Modal.alert('Invite Sent', result.invite_url);
|
|
* }
|
|
* return result;
|
|
* }
|
|
* }
|
|
* ```
|
|
*
|
|
* **Usage Pattern**:
|
|
* ```
|
|
* // Page JS orchestrates flow, modals handle UI
|
|
* const user = await Add_User_Modal.show();
|
|
* if (user) {
|
|
* $('.Users_DataGrid').component().reload();
|
|
* await Send_User_Invite_Modal.show(user.id);
|
|
* }
|
|
* ```
|
|
*
|
|
* **Best Practices**:
|
|
* - Keep modal classes focused: one modal = one class
|
|
* - Page JS orchestrates sequence, modal classes handle individual modals
|
|
* - Modal classes don't call each other directly
|
|
* - Modal classes don't update UI (grids, lists) - page JS does that
|
|
* - Use descriptive names ending in _Modal (Add_User_Modal, Send_Invite_Modal)
|
|
* - Place feature-specific modals in feature directory
|
|
* - Place reusable modals in theme/components/modal/
|
|
*
|
|
* **When to Use Modal Classes**:
|
|
* - Multi-step forms
|
|
* - Forms with complex validation
|
|
* - Modals called from multiple places
|
|
* - Modals with backend interactions
|
|
*
|
|
* **When NOT to Use Modal Classes**:
|
|
* - Simple alerts: `await Modal.alert('Saved!')`
|
|
* - Simple confirmations: `if (await Modal.confirm('Delete?')) {...}`
|
|
* - One-off prompts: `const name = await Modal.prompt('Enter name:')`
|
|
*/
|
|
class Modal_Abstract {
|
|
// This class provides structure and documentation for modal patterns.
|
|
// Concrete modal classes extend this and implement static show() method.
|
|
}
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb2RhbF9BYnN0cmFjdCJdLCJzb3VyY2VzIjpbInJzeC90aGVtZS9jb21wb25lbnRzL21vZGFsL21vZGFsX2Fic3RyYWN0LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTW9kYWxfQWJzdHJhY3QgLSBCYXNlIGNsYXNzIGZvciBtb2RhbCBvcmNoZXN0cmF0aW9uIGNsYXNzZXNcbiAqXG4gKiAqKlBoaWxvc29waHkqKjpcbiAqIE1vZGFsIGNsYXNzZXMgYXJlIG9yY2hlc3RyYXRpb24gbGF5ZXJzIHRoYXQgbWFuYWdlIHRoZSBsaWZlY3ljbGUgb2Ygc2hvd2luZ1xuICogYSBtb2RhbCwgY29sbGVjdGluZyB1c2VyIGlucHV0LCBhbmQgcmV0dXJuaW5nIHJlc3VsdHMuIFRoZXkgZG8gTk9UIGNvbnRhaW5cbiAqIGZvcm0gdmFsaWRhdGlvbiBvciBidXNpbmVzcyBsb2dpYyAtIHRoYXQgYmVsb25ncyBpbiBqcWh0bWwgY29tcG9uZW50cyBhbmRcbiAqIGNvbnRyb2xsZXIgZW5kcG9pbnRzLlxuICpcbiAqICoqUHVycG9zZSoqOlxuICogLSBQcm92aWRlcyBhIGNvbW1vbiBiYXNlIGNsYXNzIGZvciB0eXBlIGlkZW50aWZpY2F0aW9uXG4gKiAtIEVuZm9yY2VzIGZpbGUgbmFtaW5nIGNvbnZlbnRpb25zIChtb2RhbCBjbGFzc2VzIGVuZCB3aXRoIF9Nb2RhbClcbiAqIC0gRG9jdW1lbnRzIHRoZSBtb2RhbCBjbGFzcyBwYXR0ZXJuXG4gKiAtIEVuYWJsZXMgZnJhbWV3b3JrLWxldmVsIGZlYXR1cmVzIChmdXR1cmU6IGRpc2NvdmVyeSwgdmFsaWRhdGlvbilcbiAqXG4gKiAqKlJlc3BvbnNpYmlsaXRpZXMgb2YgTW9kYWwgQ2xhc3NlcyoqOlxuICogLSBJbnZva2UgTW9kYWwuZm9ybSgpIC8gTW9kYWwuc2hvdygpIC8gTW9kYWwuY29uZmlybSgpIHdpdGggYXBwcm9wcmlhdGUgY29uZmlndXJhdGlvblxuICogLSBIYW5kbGUgbW9kYWwgbGlmZWN5Y2xlIChzaG93LCBzdWJtaXQsIGNhbmNlbCwgZXJyb3JzKVxuICogLSBSZXR1cm4gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggZGF0YSBvciBmYWxzZVxuICogLSBFbmNhcHN1bGF0ZSBtb2RhbC1zcGVjaWZpYyBVSSBsb2dpY1xuICpcbiAqICoqQ29udHJhY3QqKjpcbiAqIEFsbCBtb2RhbCBjbGFzc2VzIGV4dGVuZGluZyBNb2RhbF9BYnN0cmFjdCBtdXN0IGltcGxlbWVudDpcbiAqIC0gYHN0YXRpYyBhc3luYyBzaG93KHBhcmFtcylgOiBQcmltYXJ5IGVudHJ5IHBvaW50LCByZXR1cm5zIFByb21pc2VcbiAqXG4gKiAqKlJldHVybiBWYWx1ZXMqKjpcbiAqIC0gU3VjY2VzczogUmVzb2x2ZSB3aXRoIGRhdGEgb2JqZWN0IChlLmcuLCBjcmVhdGVkIHVzZXIgcmVjb3JkKVxuICogLSBDYW5jZWwvQ2xvc2U6IFJlc29sdmUgd2l0aCBmYWxzZVxuICogLSBFcnJvcjogU2hvdyBlcnJvciBpbiBtb2RhbCwga2VlcCBvcGVuLCBkb24ndCByZXNvbHZlIHVudGlsIHVzZXIgYWN0c1xuICpcbiAqICoqSW50ZWdyYXRpb24qKjpcbiAqIE1vZGFsIGNsYXNzZXMgdXNlIE1vZGFsLmpzIHN0YXRpYyBBUEkgKE1vZGFsLmZvcm0oKSwgTW9kYWwuc2hvdygpLCBldGMuKVxuICogYXMgYnVpbGRpbmcgYmxvY2tzLiBGb3JtIHZhbGlkYXRpb24gaGFuZGxlZCBieSBSc3hfRm9ybSBhbmQgRm9ybV9VdGlscy5cbiAqIFBhZ2UgSlMgb3JjaGVzdHJhdGVzIG1vZGFsIGZsb3cgYnV0IGRvZXNuJ3QgY29udGFpbiBtb2RhbCBVSSBsb2dpYy5cbiAqXG4gKiAqKlBhdHRlcm4gRXhhbXBsZXMqKjpcbiAqXG4gKiBTaW1wbGUgZm9ybSBtb2RhbDpcbiAqIGBgYFxuICogY2xhc3MgQWRkX1VzZXJfTW9kYWwgZXh0ZW5kcyBNb2RhbF9BYnN0cmFjdCB7XG4gKiAgICAgc3RhdGljIGFzeW5jIHNob3coKSB7XG4gKiAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IE1vZGFsLmZvcm0oe1xuICogICAgICAgICAgICAgdGl0bGU6ICdBZGQgVXNlcicsXG4gKiAgICAgICAgICAgICBjb21wb25lbnQ6ICdBZGRfVXNlcl9Nb2RhbF9Gb3JtJyxcbiAqICAgICAgICAgICAgIG9uX3N1Ym1pdDogYXN5bmMgKGZvcm0pID0+IHtcbiAqICAgICAgICAgICAgICAgICB0cnkge1xuICogICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZXMgPSBmb3JtLnZhbHMoKTtcbiAqICAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgQ29udHJvbGxlci5hZGRfdXNlcih2YWx1ZXMpO1xuICogICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0OyAvLyBDbG9zZSBtb2RhbCwgcmV0dXJuIGRhdGFcbiAqICAgICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICogICAgICAgICAgICAgICAgICAgICBhd2FpdCBmb3JtLnJlbmRlcl9lcnJvcihlcnJvcik7XG4gKiAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsgLy8gS2VlcCBtb2RhbCBvcGVuXG4gKiAgICAgICAgICAgICAgICAgfVxuICogICAgICAgICAgICAgfSxcbiAqICAgICAgICAgfSk7XG4gKiAgICAgICAgIHJldHVybiByZXN1bHQgfHwgZmFsc2U7XG4gKiAgICAgfVxuICogfVxuICogYGBgXG4gKlxuICogQ3VzdG9tIGNvbnRlbnQgbW9kYWw6XG4gKiBgYGBcbiAqIGNsYXNzIENvbmZpcm1fRGVsZXRlX01vZGFsIGV4dGVuZHMgTW9kYWxfQWJzdHJhY3Qge1xuICogICAgIHN0YXRpYyBhc3luYyBzaG93KHtpdGVtX25hbWV9KSB7XG4gKiAgICAgICAgIHJldHVybiBhd2FpdCBNb2RhbC5jb25maXJtKFxuICogICAgICAgICAgICAgJ0NvbmZpcm0gRGVsZXRlJyxcbiAqICAgICAgICAgICAgIGBBcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gZGVsZXRlICR7aXRlbV9uYW1lfT9gXG4gKiAgICAgICAgICk7XG4gKiAgICAgfVxuICogfVxuICogYGBgXG4gKlxuICogTW9kYWwgd2l0aCBiYWNrZW5kIGNhbGw6XG4gKiBgYGBcbiAqIGNsYXNzIFNlbmRfSW52aXRlX01vZGFsIGV4dGVuZHMgTW9kYWxfQWJzdHJhY3Qge1xuICogICAgIHN0YXRpYyBhc3luYyBzaG93KHVzZXJfaWQpIHtcbiAqICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgQ29udHJvbGxlci5zZW5kX2ludml0ZSh7dXNlcl9pZH0pO1xuICogICAgICAgICBpZiAocmVzdWx0Lmludml0ZV91cmwpIHtcbiAqICAgICAgICAgICAgIGF3YWl0IE1vZGFsLmFsZXJ0KCdJbnZpdGUgU2VudCcsIHJlc3VsdC5pbnZpdGVfdXJsKTtcbiAqICAgICAgICAgfVxuICogICAgICAgICByZXR1cm4gcmVzdWx0O1xuICogICAgIH1cbiAqIH1cbiAqIGBgYFxuICpcbiAqICoqVXNhZ2UgUGF0dGVybioqOlxuICogYGBgXG4gKiAvLyBQYWdlIEpTIG9yY2hlc3RyYXRlcyBmbG93LCBtb2RhbHMgaGFuZGxlIFVJXG4gKiBjb25zdCB1c2VyID0gYXdhaXQgQWRkX1VzZXJfTW9kYWwuc2hvdygpO1xuICogaWYgKHVzZXIpIHtcbiAqICAgICAkKCcuVXNlcnNfRGF0YUdyaWQnKS5jb21wb25lbnQoKS5yZWxvYWQoKTtcbiAqICAgICBhd2FpdCBTZW5kX1VzZXJfSW52aXRlX01vZGFsLnNob3codXNlci5pZCk7XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiAqKkJlc3QgUHJhY3RpY2VzKio6XG4gKiAtIEtlZXAgbW9kYWwgY2xhc3NlcyBmb2N1c2VkOiBvbmUgbW9kYWwgPSBvbmUgY2xhc3NcbiAqIC0gUGFnZSBKUyBvcmNoZXN0cmF0ZXMgc2VxdWVuY2UsIG1vZGFsIGNsYXNzZXMgaGFuZGxlIGluZGl2aWR1YWwgbW9kYWxzXG4gKiAtIE1vZGFsIGNsYXNzZXMgZG9uJ3QgY2FsbCBlYWNoIG90aGVyIGRpcmVjdGx5XG4gKiAtIE1vZGFsIGNsYXNzZXMgZG9uJ3QgdXBkYXRlIFVJIChncmlkcywgbGlzdHMpIC0gcGFnZSBKUyBkb2VzIHRoYXRcbiAqIC0gVXNlIGRlc2NyaXB0aXZlIG5hbWVzIGVuZGluZyBpbiBfTW9kYWwgKEFkZF9Vc2VyX01vZGFsLCBTZW5kX0ludml0ZV9Nb2RhbClcbiAqIC0gUGxhY2UgZmVhdHVyZS1zcGVjaWZpYyBtb2RhbHMgaW4gZmVhdHVyZSBkaXJlY3RvcnlcbiAqIC0gUGxhY2UgcmV1c2FibGUgbW9kYWxzIGluIHRoZW1lL2NvbXBvbmVudHMvbW9kYWwvXG4gKlxuICogKipXaGVuIHRvIFVzZSBNb2RhbCBDbGFzc2VzKio6XG4gKiAtIE11bHRpLXN0ZXAgZm9ybXNcbiAqIC0gRm9ybXMgd2l0aCBjb21wbGV4IHZhbGlkYXRpb25cbiAqIC0gTW9kYWxzIGNhbGxlZCBmcm9tIG11bHRpcGxlIHBsYWNlc1xuICogLSBNb2RhbHMgd2l0aCBiYWNrZW5kIGludGVyYWN0aW9uc1xuICpcbiAqICoqV2hlbiBOT1QgdG8gVXNlIE1vZGFsIENsYXNzZXMqKjpcbiAqIC0gU2ltcGxlIGFsZXJ0czogYGF3YWl0IE1vZGFsLmFsZXJ0KCdTYXZlZCEnKWBcbiAqIC0gU2ltcGxlIGNvbmZpcm1hdGlvbnM6IGBpZiAoYXdhaXQgTW9kYWwuY29uZmlybSgnRGVsZXRlPycpKSB7Li4ufWBcbiAqIC0gT25lLW9mZiBwcm9tcHRzOiBgY29uc3QgbmFtZSA9IGF3YWl0IE1vZGFsLnByb21wdCgnRW50ZXIgbmFtZTonKWBcbiAqL1xuY2xhc3MgTW9kYWxfQWJzdHJhY3Qge1xuICAgIC8vIFRoaXMgY2xhc3MgcHJvdmlkZXMgc3RydWN0dXJlIGFuZCBkb2N1bWVudGF0aW9uIGZvciBtb2RhbCBwYXR0ZXJucy5cbiAgICAvLyBDb25jcmV0ZSBtb2RhbCBjbGFzc2VzIGV4dGVuZCB0aGlzIGFuZCBpbXBsZW1lbnQgc3RhdGljIHNob3coKSBtZXRob2QuXG59XG4iXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNQSxjQUFjLENBQUM7RUFDakI7RUFDQTtBQUFBIiwiaWdub3JlTGlzdCI6W119
|