fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled
Some checks failed
Deploy Application / deploy (push) Has been cancelled
This commit is contained in:
529
resources/js/modules/livecomponent/UIEventHandler.js
Normal file
529
resources/js/modules/livecomponent/UIEventHandler.js
Normal file
@@ -0,0 +1,529 @@
|
||||
/**
|
||||
* UI Event Handler for LiveComponents
|
||||
*
|
||||
* Listens to UI-related events from LiveComponents and automatically
|
||||
* displays Toasts, Modals, and other UI components.
|
||||
*
|
||||
* Supported Events:
|
||||
* - toast:show - Show toast notification
|
||||
* - toast:hide - Hide toast notification
|
||||
* - modal:show - Show modal dialog
|
||||
* - modal:close - Close modal dialog
|
||||
* - modal:confirm - Show confirmation dialog
|
||||
* - modal:alert - Show alert dialog
|
||||
*/
|
||||
|
||||
import { LiveComponentUIHelper } from './LiveComponentUIHelper.js';
|
||||
|
||||
export class UIEventHandler {
|
||||
constructor(liveComponentManager) {
|
||||
this.manager = liveComponentManager;
|
||||
this.uiHelper = liveComponentManager.uiHelper || new LiveComponentUIHelper(liveComponentManager);
|
||||
this.eventListeners = new Map();
|
||||
this.isInitialized = false;
|
||||
this.drawerManager = null; // Lazy-loaded when needed
|
||||
this.popoverManager = null; // Lazy-loaded when needed
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize event listeners
|
||||
*/
|
||||
init() {
|
||||
if (this.isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Toast events
|
||||
this.addEventListener('toast:show', (e) => this.handleToastShow(e));
|
||||
this.addEventListener('toast:hide', (e) => this.handleToastHide(e));
|
||||
|
||||
// Modal events
|
||||
this.addEventListener('modal:show', (e) => this.handleModalShow(e));
|
||||
this.addEventListener('modal:close', (e) => this.handleModalClose(e));
|
||||
this.addEventListener('modal:confirm', (e) => this.handleModalConfirm(e));
|
||||
this.addEventListener('modal:alert', (e) => this.handleModalAlert(e));
|
||||
|
||||
// Also listen to livecomponent: prefixed events for compatibility
|
||||
this.addEventListener('livecomponent:toast:show', (e) => this.handleToastShow(e));
|
||||
this.addEventListener('livecomponent:toast:hide', (e) => this.handleToastHide(e));
|
||||
this.addEventListener('livecomponent:modal:show', (e) => this.handleModalShow(e));
|
||||
this.addEventListener('livecomponent:modal:close', (e) => this.handleModalClose(e));
|
||||
this.addEventListener('livecomponent:modal:confirm', (e) => this.handleModalConfirm(e));
|
||||
this.addEventListener('livecomponent:modal:alert', (e) => this.handleModalAlert(e));
|
||||
|
||||
// Drawer events
|
||||
this.addEventListener('drawer:open', (e) => this.handleDrawerOpen(e));
|
||||
this.addEventListener('drawer:close', (e) => this.handleDrawerClose(e));
|
||||
this.addEventListener('drawer:toggle', (e) => this.handleDrawerToggle(e));
|
||||
this.addEventListener('livecomponent:drawer:open', (e) => this.handleDrawerOpen(e));
|
||||
this.addEventListener('livecomponent:drawer:close', (e) => this.handleDrawerClose(e));
|
||||
this.addEventListener('livecomponent:drawer:toggle', (e) => this.handleDrawerToggle(e));
|
||||
|
||||
// Popover events
|
||||
this.addEventListener('popover:show', (e) => this.handlePopoverShow(e));
|
||||
this.addEventListener('popover:hide', (e) => this.handlePopoverHide(e));
|
||||
this.addEventListener('popover:toggle', (e) => this.handlePopoverToggle(e));
|
||||
this.addEventListener('livecomponent:popover:show', (e) => this.handlePopoverShow(e));
|
||||
this.addEventListener('livecomponent:popover:hide', (e) => this.handlePopoverHide(e));
|
||||
this.addEventListener('livecomponent:popover:toggle', (e) => this.handlePopoverToggle(e));
|
||||
|
||||
this.isInitialized = true;
|
||||
console.log('[UIEventHandler] Initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add event listener
|
||||
* @param {string} eventName - Event name
|
||||
* @param {Function} handler - Event handler
|
||||
*/
|
||||
addEventListener(eventName, handler) {
|
||||
const wrappedHandler = (e) => {
|
||||
try {
|
||||
handler(e);
|
||||
} catch (error) {
|
||||
console.error(`[UIEventHandler] Error handling event ${eventName}:`, error);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener(eventName, wrappedHandler);
|
||||
this.eventListeners.set(eventName, wrappedHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove event listener
|
||||
* @param {string} eventName - Event name
|
||||
*/
|
||||
removeEventListener(eventName) {
|
||||
const handler = this.eventListeners.get(eventName);
|
||||
if (handler) {
|
||||
document.removeEventListener(eventName, handler);
|
||||
this.eventListeners.delete(eventName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle toast:show event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
handleToastShow(e) {
|
||||
const payload = e.detail || {};
|
||||
const {
|
||||
message = '',
|
||||
type = 'info',
|
||||
duration = 5000,
|
||||
position = 'top-right',
|
||||
componentId = 'global'
|
||||
} = payload;
|
||||
|
||||
if (!message) {
|
||||
console.warn('[UIEventHandler] toast:show event missing message');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIEventHandler] Showing toast: ${message} (${type})`);
|
||||
|
||||
this.uiHelper.showNotification(componentId, {
|
||||
message: message,
|
||||
type: type,
|
||||
duration: duration,
|
||||
position: position
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle toast:hide event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
handleToastHide(e) {
|
||||
const payload = e.detail || {};
|
||||
const { componentId = 'global' } = payload;
|
||||
|
||||
console.log(`[UIEventHandler] Hiding toast for component: ${componentId}`);
|
||||
|
||||
this.uiHelper.hideNotification(componentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle modal:show event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
handleModalShow(e) {
|
||||
const payload = e.detail || {};
|
||||
const {
|
||||
componentId,
|
||||
title = '',
|
||||
content = '',
|
||||
size = 'medium',
|
||||
buttons = [],
|
||||
closeOnBackdrop = true,
|
||||
closeOnEscape = true,
|
||||
onClose = null,
|
||||
onConfirm = null
|
||||
} = payload;
|
||||
|
||||
if (!componentId) {
|
||||
console.warn('[UIEventHandler] modal:show event missing componentId');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIEventHandler] Showing modal for component: ${componentId}`);
|
||||
|
||||
this.uiHelper.showDialog(componentId, {
|
||||
title: title,
|
||||
content: content,
|
||||
size: size,
|
||||
buttons: buttons,
|
||||
closeOnBackdrop: closeOnBackdrop,
|
||||
closeOnEscape: closeOnEscape,
|
||||
onClose: onClose,
|
||||
onConfirm: onConfirm
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle modal:close event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
handleModalClose(e) {
|
||||
const payload = e.detail || {};
|
||||
const { componentId } = payload;
|
||||
|
||||
if (!componentId) {
|
||||
console.warn('[UIEventHandler] modal:close event missing componentId');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIEventHandler] Closing modal for component: ${componentId}`);
|
||||
|
||||
this.uiHelper.closeDialog(componentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle modal:confirm event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
async handleModalConfirm(e) {
|
||||
const payload = e.detail || {};
|
||||
const {
|
||||
componentId,
|
||||
title = 'Confirm',
|
||||
message = 'Are you sure?',
|
||||
confirmText = 'Confirm',
|
||||
cancelText = 'Cancel',
|
||||
confirmClass = 'btn-primary',
|
||||
cancelClass = 'btn-secondary',
|
||||
confirmAction = null,
|
||||
confirmParams = null,
|
||||
onConfirm = null,
|
||||
onCancel = null
|
||||
} = payload;
|
||||
|
||||
if (!componentId) {
|
||||
console.warn('[UIEventHandler] modal:confirm event missing componentId');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIEventHandler] Showing confirmation dialog for component: ${componentId}`);
|
||||
|
||||
try {
|
||||
const confirmed = await this.uiHelper.showConfirm(componentId, {
|
||||
title: title,
|
||||
message: message,
|
||||
confirmText: confirmText,
|
||||
cancelText: cancelText,
|
||||
confirmClass: confirmClass,
|
||||
cancelClass: cancelClass
|
||||
});
|
||||
|
||||
// If user confirmed and confirmAction is provided, call the LiveComponent action
|
||||
if (confirmed && confirmAction) {
|
||||
console.log(`[UIEventHandler] User confirmed, calling action: ${confirmAction}`, confirmParams);
|
||||
|
||||
// Call LiveComponent action via manager
|
||||
if (this.manager && typeof this.manager.callAction === 'function') {
|
||||
await this.manager.callAction(componentId, confirmAction, confirmParams || {});
|
||||
} else if (this.manager && typeof this.manager.executeAction === 'function') {
|
||||
// Fallback to executeAction for backward compatibility
|
||||
await this.manager.executeAction(componentId, confirmAction, confirmParams || {});
|
||||
} else {
|
||||
console.warn('[UIEventHandler] Cannot execute confirmAction: manager.callAction/executeAction not available');
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy callback support
|
||||
if (confirmed && onConfirm) {
|
||||
onConfirm();
|
||||
} else if (!confirmed && onCancel) {
|
||||
onCancel();
|
||||
}
|
||||
|
||||
// Dispatch result event
|
||||
document.dispatchEvent(new CustomEvent('modal:confirm:result', {
|
||||
detail: {
|
||||
componentId: componentId,
|
||||
confirmed: confirmed
|
||||
}
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('[UIEventHandler] Error showing confirmation dialog:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle modal:alert event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
handleModalAlert(e) {
|
||||
const payload = e.detail || {};
|
||||
const {
|
||||
componentId,
|
||||
title = 'Alert',
|
||||
message = '',
|
||||
buttonText = 'OK',
|
||||
type = 'info',
|
||||
onClose = null
|
||||
} = payload;
|
||||
|
||||
if (!componentId) {
|
||||
console.warn('[UIEventHandler] modal:alert event missing componentId');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIEventHandler] Showing alert dialog for component: ${componentId}`);
|
||||
|
||||
this.uiHelper.showAlert(componentId, {
|
||||
title: title,
|
||||
message: message,
|
||||
buttonText: buttonText,
|
||||
type: type
|
||||
});
|
||||
|
||||
if (onClose) {
|
||||
// Note: showAlert doesn't return a promise, so we'll call onClose after a delay
|
||||
// This is a limitation - ideally showAlert would return a promise
|
||||
setTimeout(() => {
|
||||
onClose();
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle drawer:open event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
async handleDrawerOpen(e) {
|
||||
const payload = e.detail || {};
|
||||
const {
|
||||
componentId,
|
||||
title = '',
|
||||
content = '',
|
||||
position = 'left',
|
||||
width = '400px',
|
||||
showOverlay = true,
|
||||
closeOnOverlay = true,
|
||||
closeOnEscape = true,
|
||||
animation = 'slide'
|
||||
} = payload;
|
||||
|
||||
if (!componentId) {
|
||||
console.warn('[UIEventHandler] drawer:open event missing componentId');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIEventHandler] Opening drawer for component: ${componentId}`);
|
||||
|
||||
// Initialize DrawerManager if not already done
|
||||
if (!this.drawerManager) {
|
||||
const { DrawerManager } = await import('./DrawerManager.js');
|
||||
this.drawerManager = new DrawerManager();
|
||||
}
|
||||
|
||||
this.drawerManager.open(componentId, {
|
||||
title: title,
|
||||
content: content,
|
||||
position: position,
|
||||
width: width,
|
||||
showOverlay: showOverlay,
|
||||
closeOnOverlay: closeOnOverlay,
|
||||
closeOnEscape: closeOnEscape,
|
||||
animation: animation
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle drawer:close event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
handleDrawerClose(e) {
|
||||
const payload = e.detail || {};
|
||||
const { componentId } = payload;
|
||||
|
||||
if (!componentId) {
|
||||
console.warn('[UIEventHandler] drawer:close event missing componentId');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIEventHandler] Closing drawer for component: ${componentId}`);
|
||||
|
||||
if (this.drawerManager) {
|
||||
this.drawerManager.close(componentId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle drawer:toggle event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
handleDrawerToggle(e) {
|
||||
const payload = e.detail || {};
|
||||
const { componentId } = payload;
|
||||
|
||||
if (!componentId) {
|
||||
console.warn('[UIEventHandler] drawer:toggle event missing componentId');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIEventHandler] Toggling drawer for component: ${componentId}`);
|
||||
|
||||
if (this.drawerManager) {
|
||||
const isOpen = this.drawerManager.isOpen(componentId);
|
||||
if (isOpen) {
|
||||
this.drawerManager.close(componentId);
|
||||
} else {
|
||||
// For toggle, we need the full options - this is a limitation
|
||||
// In practice, components should use open/close explicitly
|
||||
console.warn('[UIEventHandler] drawer:toggle requires full options - use drawer:open/close instead');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle popover:show event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
async handlePopoverShow(e) {
|
||||
const payload = e.detail || {};
|
||||
const {
|
||||
componentId,
|
||||
anchorId,
|
||||
content = '',
|
||||
title = '',
|
||||
position = 'top',
|
||||
showArrow = true,
|
||||
offset = 8,
|
||||
closeOnOutsideClick = true
|
||||
} = payload;
|
||||
|
||||
if (!componentId || !anchorId) {
|
||||
console.warn('[UIEventHandler] popover:show event missing componentId or anchorId');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIEventHandler] Showing popover for component: ${componentId}`);
|
||||
|
||||
// Initialize PopoverManager if not already done
|
||||
if (!this.popoverManager) {
|
||||
const { PopoverManager } = await import('./PopoverManager.js');
|
||||
this.popoverManager = new PopoverManager();
|
||||
}
|
||||
|
||||
this.popoverManager.show(componentId, {
|
||||
anchorId: anchorId,
|
||||
content: content,
|
||||
title: title,
|
||||
position: position,
|
||||
showArrow: showArrow,
|
||||
offset: offset,
|
||||
closeOnOutsideClick: closeOnOutsideClick
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle popover:hide event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
handlePopoverHide(e) {
|
||||
const payload = e.detail || {};
|
||||
const { componentId } = payload;
|
||||
|
||||
if (!componentId) {
|
||||
console.warn('[UIEventHandler] popover:hide event missing componentId');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[UIEventHandler] Hiding popover for component: ${componentId}`);
|
||||
|
||||
if (this.popoverManager) {
|
||||
this.popoverManager.hide(componentId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle popover:toggle event
|
||||
* @param {CustomEvent} e - Event object
|
||||
*/
|
||||
async handlePopoverToggle(e) {
|
||||
const payload = e.detail || {};
|
||||
const {
|
||||
componentId,
|
||||
anchorId,
|
||||
content = '',
|
||||
title = '',
|
||||
position = 'top',
|
||||
showArrow = true,
|
||||
offset = 8,
|
||||
closeOnOutsideClick = true
|
||||
} = payload;
|
||||
|
||||
if (!componentId || !anchorId) {
|
||||
console.warn('[UIEventHandler] popover:toggle event missing componentId or anchorId');
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize PopoverManager if not already done
|
||||
if (!this.popoverManager) {
|
||||
const { PopoverManager } = await import('./PopoverManager.js');
|
||||
this.popoverManager = new PopoverManager();
|
||||
}
|
||||
|
||||
// Check if popover is visible
|
||||
const isVisible = this.popoverManager.popovers.has(componentId);
|
||||
|
||||
if (isVisible) {
|
||||
this.popoverManager.hide(componentId);
|
||||
} else {
|
||||
this.popoverManager.show(componentId, {
|
||||
anchorId: anchorId,
|
||||
content: content,
|
||||
title: title,
|
||||
position: position,
|
||||
showArrow: showArrow,
|
||||
offset: offset,
|
||||
closeOnOutsideClick: closeOnOutsideClick
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup all event listeners
|
||||
*/
|
||||
destroy() {
|
||||
for (const [eventName, handler] of this.eventListeners.entries()) {
|
||||
document.removeEventListener(eventName, handler);
|
||||
}
|
||||
this.eventListeners.clear();
|
||||
|
||||
// Cleanup managers
|
||||
if (this.drawerManager) {
|
||||
this.drawerManager.destroy();
|
||||
}
|
||||
|
||||
if (this.popoverManager) {
|
||||
this.popoverManager.destroy();
|
||||
}
|
||||
|
||||
this.isInitialized = false;
|
||||
console.log('[UIEventHandler] Destroyed');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user