web-mojo 2.1.380 → 2.1.443
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/admin.cjs.js +1 -1
- package/dist/admin.cjs.js.map +1 -1
- package/dist/admin.es.js +32 -43
- package/dist/admin.es.js.map +1 -1
- package/dist/auth.cjs.js +1 -1
- package/dist/auth.cjs.js.map +1 -1
- package/dist/auth.es.js +3 -3
- package/dist/auth.es.js.map +1 -1
- package/dist/charts.cjs.js +1 -1
- package/dist/charts.es.js +2 -2
- package/dist/chunks/{ContextMenu-BPJJR6l6.js → ContextMenu-Cao6A-Lu.js} +4 -2
- package/dist/chunks/{ContextMenu-BPJJR6l6.js.map → ContextMenu-Cao6A-Lu.js.map} +1 -1
- package/dist/chunks/ContextMenu-TK4-wzDb.js +3 -0
- package/dist/chunks/ContextMenu-TK4-wzDb.js.map +1 -0
- package/dist/chunks/DataView-CHoPxbYT.js +2 -0
- package/dist/chunks/DataView-CHoPxbYT.js.map +1 -0
- package/dist/chunks/{DataView-ED8X_cvp.js → DataView-Qnk-TnHd.js} +17 -3
- package/dist/chunks/DataView-Qnk-TnHd.js.map +1 -0
- package/dist/chunks/{Dialog-hiboYc1m.js → Dialog-B_ZJYlVS.js} +2 -2
- package/dist/chunks/{Dialog-hiboYc1m.js.map → Dialog-B_ZJYlVS.js.map} +1 -1
- package/dist/chunks/{Dialog-DmEPwI5D.js → Dialog-DbZ2jB_m.js} +5 -5
- package/dist/chunks/{Dialog-DmEPwI5D.js.map → Dialog-DbZ2jB_m.js.map} +1 -1
- package/dist/chunks/FilePreviewView-DeGgRRbW.js +2 -0
- package/dist/chunks/FilePreviewView-DeGgRRbW.js.map +1 -0
- package/dist/chunks/{FilePreviewView-D39a1bWs.js → FilePreviewView-nuZku1yG.js} +68 -19
- package/dist/chunks/FilePreviewView-nuZku1yG.js.map +1 -0
- package/dist/chunks/{FormView-CCrutTVr.js → FormView-BDKrUX1-.js} +41 -23
- package/dist/chunks/FormView-BDKrUX1-.js.map +1 -0
- package/dist/chunks/FormView-BZInlDfZ.js +2 -0
- package/dist/chunks/FormView-BZInlDfZ.js.map +1 -0
- package/dist/chunks/{MetricsChart-D9j0JkfY.js → MetricsChart-Aqum5Znr.js} +3 -3
- package/dist/chunks/{MetricsChart-D9j0JkfY.js.map → MetricsChart-Aqum5Znr.js.map} +1 -1
- package/dist/chunks/{MetricsChart-B7yBoTzr.js → MetricsChart-BbaBczOZ.js} +2 -2
- package/dist/chunks/{MetricsChart-B7yBoTzr.js.map → MetricsChart-BbaBczOZ.js.map} +1 -1
- package/dist/chunks/{PDFViewer--7dBYfiB.js → PDFViewer-Bq-NM6JH.js} +2 -2
- package/dist/chunks/{PDFViewer--7dBYfiB.js.map → PDFViewer-Bq-NM6JH.js.map} +1 -1
- package/dist/chunks/{PDFViewer-BPFrZSlU.js → PDFViewer-CGj7cZut.js} +3 -3
- package/dist/chunks/{PDFViewer-BPFrZSlU.js.map → PDFViewer-CGj7cZut.js.map} +1 -1
- package/dist/chunks/{Page-DY5i-6Wq.js → Page-BkkXMFuP.js} +2 -2
- package/dist/chunks/{Page-DY5i-6Wq.js.map → Page-BkkXMFuP.js.map} +1 -1
- package/dist/chunks/{Page-D2Yq8RbO.js → Page-QhPYRY-q.js} +2 -2
- package/dist/chunks/{Page-D2Yq8RbO.js.map → Page-QhPYRY-q.js.map} +1 -1
- package/dist/chunks/{TopNav-BN3TAAxN.js → TopNav-D6c7gsox.js} +2 -2
- package/dist/chunks/{TopNav-BN3TAAxN.js.map → TopNav-D6c7gsox.js.map} +1 -1
- package/dist/chunks/{TopNav-BzKZzgE6.js → TopNav-DUwNnOuM.js} +2 -2
- package/dist/chunks/{TopNav-BzKZzgE6.js.map → TopNav-DUwNnOuM.js.map} +1 -1
- package/dist/chunks/{WebApp-p0nOftj0.js → WebApp-BPWJVv80.js} +19 -13
- package/dist/chunks/{WebApp-p0nOftj0.js.map → WebApp-BPWJVv80.js.map} +1 -1
- package/dist/chunks/WebApp-CYqazUo5.js +2 -0
- package/dist/chunks/{WebApp-Czng9Krl.js.map → WebApp-CYqazUo5.js.map} +1 -1
- package/dist/core.css +10 -0
- package/dist/css/web-mojo.css +1 -1
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.es.js +5 -5
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +11 -11
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.es.js +4 -4
- package/package.json +1 -1
- package/dist/chunks/ContextMenu-YwW7txyQ.js +0 -3
- package/dist/chunks/ContextMenu-YwW7txyQ.js.map +0 -1
- package/dist/chunks/DataView-ED8X_cvp.js.map +0 -1
- package/dist/chunks/DataView-ryKnMcUa.js +0 -2
- package/dist/chunks/DataView-ryKnMcUa.js.map +0 -1
- package/dist/chunks/FilePreviewView-C3beZ-UX.js +0 -2
- package/dist/chunks/FilePreviewView-C3beZ-UX.js.map +0 -1
- package/dist/chunks/FilePreviewView-D39a1bWs.js.map +0 -1
- package/dist/chunks/FormView-CCrutTVr.js.map +0 -1
- package/dist/chunks/FormView-wKzv7Fey.js +0 -2
- package/dist/chunks/FormView-wKzv7Fey.js.map +0 -1
- package/dist/chunks/WebApp-Czng9Krl.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TopNav-BN3TAAxN.js","sources":["../../src/core/views/navigation/TopNav.js"],"sourcesContent":["/**\n * TopNav - Bootstrap navbar component for MOJO framework\n * Provides clean, responsive top navigation\n */\n\nimport View from '@core/View.js';\n\nclass TopNav extends View {\n constructor(options = {}) {\n // Define theme-to-class mappings\n const themes = {\n light: 'navbar navbar-expand-lg navbar-light topnav-light',\n dark: 'navbar navbar-expand-lg navbar-dark topnav-dark',\n clean: 'navbar navbar-expand-lg navbar-light topnav-clean',\n gradient: 'navbar navbar-expand-lg navbar-dark topnav-gradient',\n };\n\n // Set a default theme and determine the final class string\n const themeName = options.theme || 'light';\n let navbarClass = themes[themeName] || themes.light;\n\n // Add shadow class if specified\n if (options.shadow) {\n navbarClass += ` topnav-shadow-${options.shadow}`;\n }\n\n super({\n tagName: 'nav',\n className: navbarClass,\n style: 'position: relative; z-index: 1030;',\n ...options\n });\n\n // Display mode configuration\n this.displayMode = options.displayMode || 'both'; // 'menu' | 'page' | 'both'\n this.showPageIcon = options.showPageIcon !== false;\n this.showPageDescription = options.showPageDescription || false;\n this.showBreadcrumbs = options.showBreadcrumbs || false;\n\n // Current page tracking\n this.currentPage = null;\n this.previousPage = null;\n\n // Store raw config for processing in onBeforeRender\n this.config = {\n brand: options.brand || 'MOJO App',\n brandIcon: options.brandIcon || 'bi bi-play-circle',\n brandRoute: options.brandRoute || '/',\n navItems: options.navItems || [],\n rightItems: options.rightItems || [],\n showSidebarToggle: options.showSidebarToggle || false,\n sidebarToggleAction: options.sidebarToggleAction || 'toggle-sidebar',\n ...options\n };\n this.userMenu = options.userMenu || this.findMenuItem('user');\n if (this.userMenu) this.userMenu.id = \"user\";\n this.loginMenu = options.loginMenu || this.findMenuItem('login');\n // Setup page event listeners\n this.setupPageListeners();\n }\n\n findMenuItem(id) {\n let item = this.config.navItems.find(item => item.id === id);\n if (!item) {\n item = this.config.rightItems.find(item => item.id === id);\n }\n return item || null;\n }\n\n replaceMenuItem(id, new_menu) {\n // Find and replace in navItems\n const navIndex = this.config.navItems.findIndex(item => item.id === id);\n if (navIndex !== -1) {\n this.config.navItems[navIndex] = new_menu;\n return true;\n }\n\n // Find and replace in rightItems\n const rightIndex = this.config.rightItems.findIndex(item => item.id === id);\n if (rightIndex !== -1) {\n this.config.rightItems[rightIndex] = new_menu;\n return true;\n }\n\n return false;\n }\n\n setBrand(brand, icon=null) {\n this.config.brand = brand;\n this.config.brandIcon = icon || this.config.brandIcon;\n this.render();\n }\n\n setUser(user) {\n if (!user) {\n this.replaceMenuItem('user', this.loginMenu);\n } else {\n this.userMenu.label = user.get(\"display_name\");\n this.replaceMenuItem('login', this.userMenu);\n }\n this.setModel(user);\n }\n\n _onModelChange() {\n if (this.model) {\n this.userMenu.label = this.model.get(\"display_name\");\n }\n if (this.isMounted()) {\n this.render();\n }\n }\n\n /**\n * Get template based on display mode\n */\n async getTemplate() {\n return `\n <div class=\"container-fluid\">\n {{#data.showSidebarToggle}}\n <button class=\"topnav-sidebar-toggle me-2\" data-action=\"{{data.sidebarToggleAction}}\" aria-label=\"Toggle Sidebar\">\n <i class=\"bi bi-chevron-right toggle-chevron\"></i>\n </button>\n {{/data.showSidebarToggle}}\n\n {{#data.showPageInfo}}\n <div class=\"navbar-brand d-flex align-items-center\">\n {{#data.currentPageIcon}}<i class=\"{{data.currentPageIcon}} me-2\"></i>{{/data.currentPageIcon}}\n <div>\n <span>{{data.currentPageName}}</span>\n {{#data.currentPageDescription}}\n <small class=\"d-block\" style=\"font-size: 0.75rem; line-height: 1;\">{{data.currentPageDescription}}</small>\n {{/data.currentPageDescription}}\n </div>\n </div>\n {{/data.showPageInfo}}\n\n {{^data.showPageInfo}}\n <a class=\"navbar-brand\" href=\"{{data.brandRoute}}\">\n {{#data.brandIcon}}<i class=\"{{data.brandIcon}} me-2\"></i>{{/data.brandIcon}}\n {{data.brand}}\n </a>\n {{/data.showPageInfo}}\n\n <button class=\"navbar-toggler\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#{{data.navbarId}}\">\n <span class=\"navbar-toggler-icon\"></span>\n </button>\n\n <div class=\"collapse navbar-collapse\" id=\"{{data.navbarId}}\">\n {{#data.showNavItems}}\n <ul class=\"navbar-nav me-auto mb-2 mb-lg-0\">\n {{#data.navItems}}\n <li class=\"nav-item\">\n <a class=\"nav-link {{#active}}active{{/active}}\" href=\"{{route}}\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{text}}\n </a>\n </li>\n {{/data.navItems}}\n </ul>\n {{/data.showNavItems}}\n\n {{#data.hasRightItems}}\n <div class=\"navbar-nav ms-auto\">\n {{#data.rightItems}}\n {{#isDropdown}}\n <div class=\"nav-item dropdown\">\n <a class=\"nav-link dropdown-toggle\" role=\"button\" data-bs-toggle=\"dropdown\" aria-expanded=\"false\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n <ul class=\"dropdown-menu dropdown-menu-end\">\n {{#items}}\n {{#divider}}\n <li><hr class=\"dropdown-divider\"></li>\n {{/divider}}\n {{^divider}}\n <li>\n <a class=\"dropdown-item\" role=\"button\" {{#action}}data-action=\"{{action}}\"{{/action}}>\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n </li>\n {{/divider}}\n {{/items}}\n </ul>\n </div>\n {{/isDropdown}}\n {{^isDropdown}}\n {{#isButton}}\n <button class=\"{{buttonClass}}\" data-action=\"{{action}}\" data-id=\"{{id}}\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </button>\n {{/isButton}}\n {{^isButton}}\n <a class=\"nav-link\" href=\"{{href}}\" {{#action}}data-action=\"{{action}}\"{{/action}}>\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n {{/isButton}}\n {{/isDropdown}}\n {{/data.rightItems}}\n </div>\n {{/data.hasRightItems}}\n </div>\n </div>\n `;\n }\n\n /**\n * Process and normalize data before rendering (like Sidebar)\n */\n async onBeforeRender() {\n await super.onBeforeRender();\n\n const showPageInfo = this.displayMode === 'page' || this.displayMode === 'both';\n const showNavItems = this.displayMode === 'menu' || this.displayMode === 'both';\n\n // Filter navItems based on permissions\n const navItems = this.filterItemsByPermissions(this.config.navItems || []);\n\n // Process right items\n const rightItems = this.processRightItems(this.config.rightItems || []);\n\n this.data = {\n // Brand information\n brand: this.config.brand,\n brandIcon: this.config.brandIcon,\n brandRoute: this.config.brandRoute,\n\n // Navbar configuration\n navbarId: `navbar-${this.id}`,\n\n // Navigation items\n navItems: navItems,\n showNavItems: showNavItems,\n\n // Right items\n rightItems: rightItems,\n hasRightItems: rightItems.length > 0,\n\n // Page display\n showPageInfo: showPageInfo,\n currentPageName: this.currentPage?.title || this.currentPage?.name || '',\n currentPageIcon: this.currentPage?.icon || this.currentPage?.pageIcon || '',\n currentPageDescription: this.showPageDescription ? this.currentPage?.description : '',\n\n // Sidebar toggle\n showSidebarToggle: this.config.showSidebarToggle,\n sidebarToggleAction: this.config.sidebarToggleAction,\n\n // Display mode\n displayMode: this.displayMode\n };\n }\n\n /**\n * Process right items configuration\n */\n processRightItems(rightItems) {\n return this.filterItemsByPermissions(rightItems).map(item => {\n const processedItem = { ...item };\n\n // Filter dropdown items by permissions if they exist\n if (item.items) {\n processedItem.items = this.filterItemsByPermissions(item.items);\n }\n\n // Determine item type\n if (processedItem.items && processedItem.items.length > 0) {\n // Dropdown menu\n processedItem.isDropdown = true;\n processedItem.isButton = false;\n } else if (item.buttonClass) {\n // Button\n processedItem.isButton = true;\n processedItem.isDropdown = false;\n } else {\n // Link\n processedItem.isButton = false;\n processedItem.isDropdown = false;\n }\n\n // Store handler if provided\n if (item.handler) {\n this.rightItemHandlers = this.rightItemHandlers || new Map();\n this.rightItemHandlers.set(item.id, item.handler);\n }\n\n return processedItem;\n });\n }\n\n /**\n * Setup listeners for page change events\n */\n setupPageListeners() {\n // Use global MOJO event bus if available\n this.getApp().events.on([\"page:show\", \"page:hide\", \"page:denied\"], (data) => {\n this.onPageChanged(data);\n });\n }\n\n /**\n * Handle page before change event\n * @param {object} data - Event data\n */\n onPageBeforeChange(data) {\n // Can be used to show loading state\n if (this.displayMode === 'page' || this.displayMode === 'both') {\n // Optionally show loading indicator\n }\n }\n\n /**\n * Handle page changed event\n * @param {object} data - Event data with previousPage and currentPage\n */\n onPageChanged(data) {\n this.previousPage = this.currentPage;\n this.currentPage = data.page;\n\n // Update display based on mode\n if (this.displayMode === 'page' || this.displayMode === 'both') {\n this.updatePageDisplay();\n }\n\n // Update active menu items\n if (this.displayMode === 'menu' || this.displayMode === 'both') {\n if (this.currentPage && this.currentPage.route) {\n this.updateActiveItem(this.currentPage.route);\n }\n }\n }\n\n /**\n * Update the display to show current page info\n */\n updatePageDisplay() {\n if (!this.currentPage) return;\n\n // Just trigger re-render, onBeforeRender will handle the data processing\n if (this.mounted) {\n this.render();\n }\n }\n\n updateActiveItem(currentRoute) {\n // Normalize routes for comparison\n const normalizeRoute = (route) => {\n if (!route) return '/';\n return route.startsWith('/') ? route : `/${route}`;\n };\n\n const normalizedCurrentRoute = normalizeRoute(currentRoute);\n\n // Update active states with improved matching\n const navItems = this.data.navItems.map(item => {\n const normalizedItemRoute = normalizeRoute(item.route);\n\n // Check for active state\n let isActive = false;\n\n if (normalizedItemRoute === '/' && normalizedCurrentRoute === '/') {\n // Exact match for home route\n isActive = true;\n } else if (normalizedItemRoute !== '/' && normalizedCurrentRoute !== '/') {\n // For non-home routes, check if current route starts with nav item route\n // This allows /users to be active when on /users/123\n isActive = normalizedCurrentRoute.startsWith(normalizedItemRoute) ||\n normalizedCurrentRoute === normalizedItemRoute;\n }\n\n return {\n ...item,\n active: isActive\n };\n });\n\n this.updateData({ navItems }, true);\n }\n\n onPassThruActionProfile() {\n // Implement profile functionality here\n this.getApp().events.emit(\"portal:action\", {action: \"profile\"});\n }\n\n onActionSettings() {\n // Implement settings functionality here\n this.getApp().events.emit(\"portal:action\", {action: \"settings\"});\n }\n\n onActionLogout() {\n // Implement logout functionality here\n this.getApp().events.emit(\"auth:logout\", {action: \"logout\"});\n }\n\n /**\n * Handle dynamic action dispatch for right items\n */\n async handleAction(actionName, event, element) {\n // Check for custom handler first\n const itemId = element.getAttribute('data-id');\n if (itemId && this.rightItemHandlers && this.rightItemHandlers.has(itemId)) {\n const handler = this.rightItemHandlers.get(itemId);\n if (typeof handler === 'function') {\n return await handler.call(this, actionName, event, element);\n }\n }\n\n // Fallback to default action methods\n const methodName = `onAction${actionName.charAt(0).toUpperCase() + actionName.slice(1).replace(/-([a-z])/g, (g) => g[1].toUpperCase())}`;\n if (typeof this[methodName] === 'function') {\n return await this[methodName](event, element);\n }\n\n // Emit action event if no handler found\n this.emit('action', {\n action: actionName,\n event: event,\n element: element,\n topnav: this\n });\n }\n\n /**\n * Handle default actions by searching through rightItems and navItems\n */\n async onActionDefault(action, event, el) {\n // Check navItems first\n if (this.config.navItems) {\n for (const item of this.config.navItems) {\n if (item.action === action && item.handler) {\n await item.handler.call(this, action, event, el);\n return true;\n }\n }\n }\n\n // Check rightItems\n if (this.config.rightItems) {\n for (const item of this.config.rightItems) {\n if (item.action === action && item.handler) {\n await item.handler.call(this, action, event, el);\n return true;\n }\n // Also check dropdown items\n if (item.items) {\n for (const subItem of item.items) {\n if (subItem.action === action && subItem.handler) {\n await subItem.handler.call(this, action, event, el);\n return true;\n }\n }\n }\n }\n }\n\n this.getApp().events.emit(\"portal:action\", { action, event, el });\n\n return false;\n }\n\n /**\n * Filter items by user permissions\n */\n filterItemsByPermissions(items) {\n if (!items) return [];\n\n const app = this.getApp();\n const activeUser = app?.activeUser;\n\n return items.filter(item => {\n // If item has permissions and user exists, check permissions\n if (item.permissions && activeUser) {\n return activeUser.hasPermission(item.permissions);\n }\n // If no permissions required or no user, show the item\n return true;\n });\n }\n\n}\n\nexport default TopNav;\n"],"names":["item"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TopNav-D6c7gsox.js","sources":["../../src/core/views/navigation/TopNav.js"],"sourcesContent":["/**\n * TopNav - Bootstrap navbar component for MOJO framework\n * Provides clean, responsive top navigation\n */\n\nimport View from '@core/View.js';\n\nclass TopNav extends View {\n constructor(options = {}) {\n // Define theme-to-class mappings\n const themes = {\n light: 'navbar navbar-expand-lg navbar-light topnav-light',\n dark: 'navbar navbar-expand-lg navbar-dark topnav-dark',\n clean: 'navbar navbar-expand-lg navbar-light topnav-clean',\n gradient: 'navbar navbar-expand-lg navbar-dark topnav-gradient',\n };\n\n // Set a default theme and determine the final class string\n const themeName = options.theme || 'light';\n let navbarClass = themes[themeName] || themes.light;\n\n // Add shadow class if specified\n if (options.shadow) {\n navbarClass += ` topnav-shadow-${options.shadow}`;\n }\n\n super({\n tagName: 'nav',\n className: navbarClass,\n style: 'position: relative; z-index: 1030;',\n ...options\n });\n\n // Display mode configuration\n this.displayMode = options.displayMode || 'both'; // 'menu' | 'page' | 'both'\n this.showPageIcon = options.showPageIcon !== false;\n this.showPageDescription = options.showPageDescription || false;\n this.showBreadcrumbs = options.showBreadcrumbs || false;\n\n // Current page tracking\n this.currentPage = null;\n this.previousPage = null;\n\n // Store raw config for processing in onBeforeRender\n this.config = {\n brand: options.brand || 'MOJO App',\n brandIcon: options.brandIcon || 'bi bi-play-circle',\n brandRoute: options.brandRoute || '/',\n navItems: options.navItems || [],\n rightItems: options.rightItems || [],\n showSidebarToggle: options.showSidebarToggle || false,\n sidebarToggleAction: options.sidebarToggleAction || 'toggle-sidebar',\n ...options\n };\n this.userMenu = options.userMenu || this.findMenuItem('user');\n if (this.userMenu) this.userMenu.id = \"user\";\n this.loginMenu = options.loginMenu || this.findMenuItem('login');\n // Setup page event listeners\n this.setupPageListeners();\n }\n\n findMenuItem(id) {\n let item = this.config.navItems.find(item => item.id === id);\n if (!item) {\n item = this.config.rightItems.find(item => item.id === id);\n }\n return item || null;\n }\n\n replaceMenuItem(id, new_menu) {\n // Find and replace in navItems\n const navIndex = this.config.navItems.findIndex(item => item.id === id);\n if (navIndex !== -1) {\n this.config.navItems[navIndex] = new_menu;\n return true;\n }\n\n // Find and replace in rightItems\n const rightIndex = this.config.rightItems.findIndex(item => item.id === id);\n if (rightIndex !== -1) {\n this.config.rightItems[rightIndex] = new_menu;\n return true;\n }\n\n return false;\n }\n\n setBrand(brand, icon=null) {\n this.config.brand = brand;\n this.config.brandIcon = icon || this.config.brandIcon;\n this.render();\n }\n\n setUser(user) {\n if (!user) {\n this.replaceMenuItem('user', this.loginMenu);\n } else {\n this.userMenu.label = user.get(\"display_name\");\n this.replaceMenuItem('login', this.userMenu);\n }\n this.setModel(user);\n }\n\n _onModelChange() {\n if (this.model) {\n this.userMenu.label = this.model.get(\"display_name\");\n }\n if (this.isMounted()) {\n this.render();\n }\n }\n\n /**\n * Get template based on display mode\n */\n async getTemplate() {\n return `\n <div class=\"container-fluid\">\n {{#data.showSidebarToggle}}\n <button class=\"topnav-sidebar-toggle me-2\" data-action=\"{{data.sidebarToggleAction}}\" aria-label=\"Toggle Sidebar\">\n <i class=\"bi bi-chevron-right toggle-chevron\"></i>\n </button>\n {{/data.showSidebarToggle}}\n\n {{#data.showPageInfo}}\n <div class=\"navbar-brand d-flex align-items-center\">\n {{#data.currentPageIcon}}<i class=\"{{data.currentPageIcon}} me-2\"></i>{{/data.currentPageIcon}}\n <div>\n <span>{{data.currentPageName}}</span>\n {{#data.currentPageDescription}}\n <small class=\"d-block\" style=\"font-size: 0.75rem; line-height: 1;\">{{data.currentPageDescription}}</small>\n {{/data.currentPageDescription}}\n </div>\n </div>\n {{/data.showPageInfo}}\n\n {{^data.showPageInfo}}\n <a class=\"navbar-brand\" href=\"{{data.brandRoute}}\">\n {{#data.brandIcon}}<i class=\"{{data.brandIcon}} me-2\"></i>{{/data.brandIcon}}\n {{data.brand}}\n </a>\n {{/data.showPageInfo}}\n\n <button class=\"navbar-toggler\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#{{data.navbarId}}\">\n <span class=\"navbar-toggler-icon\"></span>\n </button>\n\n <div class=\"collapse navbar-collapse\" id=\"{{data.navbarId}}\">\n {{#data.showNavItems}}\n <ul class=\"navbar-nav me-auto mb-2 mb-lg-0\">\n {{#data.navItems}}\n <li class=\"nav-item\">\n <a class=\"nav-link {{#active}}active{{/active}}\" href=\"{{route}}\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{text}}\n </a>\n </li>\n {{/data.navItems}}\n </ul>\n {{/data.showNavItems}}\n\n {{#data.hasRightItems}}\n <div class=\"navbar-nav ms-auto\">\n {{#data.rightItems}}\n {{#isDropdown}}\n <div class=\"nav-item dropdown\">\n <a class=\"nav-link dropdown-toggle\" role=\"button\" data-bs-toggle=\"dropdown\" aria-expanded=\"false\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n <ul class=\"dropdown-menu dropdown-menu-end\">\n {{#items}}\n {{#divider}}\n <li><hr class=\"dropdown-divider\"></li>\n {{/divider}}\n {{^divider}}\n <li>\n <a class=\"dropdown-item\" role=\"button\" {{#action}}data-action=\"{{action}}\"{{/action}}>\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n </li>\n {{/divider}}\n {{/items}}\n </ul>\n </div>\n {{/isDropdown}}\n {{^isDropdown}}\n {{#isButton}}\n <button class=\"{{buttonClass}}\" data-action=\"{{action}}\" data-id=\"{{id}}\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </button>\n {{/isButton}}\n {{^isButton}}\n <a class=\"nav-link\" href=\"{{href}}\" {{#action}}data-action=\"{{action}}\"{{/action}}>\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n {{/isButton}}\n {{/isDropdown}}\n {{/data.rightItems}}\n </div>\n {{/data.hasRightItems}}\n </div>\n </div>\n `;\n }\n\n /**\n * Process and normalize data before rendering (like Sidebar)\n */\n async onBeforeRender() {\n await super.onBeforeRender();\n\n const showPageInfo = this.displayMode === 'page' || this.displayMode === 'both';\n const showNavItems = this.displayMode === 'menu' || this.displayMode === 'both';\n\n // Filter navItems based on permissions\n const navItems = this.filterItemsByPermissions(this.config.navItems || []);\n\n // Process right items\n const rightItems = this.processRightItems(this.config.rightItems || []);\n\n this.data = {\n // Brand information\n brand: this.config.brand,\n brandIcon: this.config.brandIcon,\n brandRoute: this.config.brandRoute,\n\n // Navbar configuration\n navbarId: `navbar-${this.id}`,\n\n // Navigation items\n navItems: navItems,\n showNavItems: showNavItems,\n\n // Right items\n rightItems: rightItems,\n hasRightItems: rightItems.length > 0,\n\n // Page display\n showPageInfo: showPageInfo,\n currentPageName: this.currentPage?.title || this.currentPage?.name || '',\n currentPageIcon: this.currentPage?.icon || this.currentPage?.pageIcon || '',\n currentPageDescription: this.showPageDescription ? this.currentPage?.description : '',\n\n // Sidebar toggle\n showSidebarToggle: this.config.showSidebarToggle,\n sidebarToggleAction: this.config.sidebarToggleAction,\n\n // Display mode\n displayMode: this.displayMode\n };\n }\n\n /**\n * Process right items configuration\n */\n processRightItems(rightItems) {\n return this.filterItemsByPermissions(rightItems).map(item => {\n const processedItem = { ...item };\n\n // Filter dropdown items by permissions if they exist\n if (item.items) {\n processedItem.items = this.filterItemsByPermissions(item.items);\n }\n\n // Determine item type\n if (processedItem.items && processedItem.items.length > 0) {\n // Dropdown menu\n processedItem.isDropdown = true;\n processedItem.isButton = false;\n } else if (item.buttonClass) {\n // Button\n processedItem.isButton = true;\n processedItem.isDropdown = false;\n } else {\n // Link\n processedItem.isButton = false;\n processedItem.isDropdown = false;\n }\n\n // Store handler if provided\n if (item.handler) {\n this.rightItemHandlers = this.rightItemHandlers || new Map();\n this.rightItemHandlers.set(item.id, item.handler);\n }\n\n return processedItem;\n });\n }\n\n /**\n * Setup listeners for page change events\n */\n setupPageListeners() {\n // Use global MOJO event bus if available\n this.getApp().events.on([\"page:show\", \"page:hide\", \"page:denied\"], (data) => {\n this.onPageChanged(data);\n });\n }\n\n /**\n * Handle page before change event\n * @param {object} data - Event data\n */\n onPageBeforeChange(data) {\n // Can be used to show loading state\n if (this.displayMode === 'page' || this.displayMode === 'both') {\n // Optionally show loading indicator\n }\n }\n\n /**\n * Handle page changed event\n * @param {object} data - Event data with previousPage and currentPage\n */\n onPageChanged(data) {\n this.previousPage = this.currentPage;\n this.currentPage = data.page;\n\n // Update display based on mode\n if (this.displayMode === 'page' || this.displayMode === 'both') {\n this.updatePageDisplay();\n }\n\n // Update active menu items\n if (this.displayMode === 'menu' || this.displayMode === 'both') {\n if (this.currentPage && this.currentPage.route) {\n this.updateActiveItem(this.currentPage.route);\n }\n }\n }\n\n /**\n * Update the display to show current page info\n */\n updatePageDisplay() {\n if (!this.currentPage) return;\n\n // Just trigger re-render, onBeforeRender will handle the data processing\n if (this.mounted) {\n this.render();\n }\n }\n\n updateActiveItem(currentRoute) {\n // Normalize routes for comparison\n const normalizeRoute = (route) => {\n if (!route) return '/';\n return route.startsWith('/') ? route : `/${route}`;\n };\n\n const normalizedCurrentRoute = normalizeRoute(currentRoute);\n\n // Update active states with improved matching\n const navItems = this.data.navItems.map(item => {\n const normalizedItemRoute = normalizeRoute(item.route);\n\n // Check for active state\n let isActive = false;\n\n if (normalizedItemRoute === '/' && normalizedCurrentRoute === '/') {\n // Exact match for home route\n isActive = true;\n } else if (normalizedItemRoute !== '/' && normalizedCurrentRoute !== '/') {\n // For non-home routes, check if current route starts with nav item route\n // This allows /users to be active when on /users/123\n isActive = normalizedCurrentRoute.startsWith(normalizedItemRoute) ||\n normalizedCurrentRoute === normalizedItemRoute;\n }\n\n return {\n ...item,\n active: isActive\n };\n });\n\n this.updateData({ navItems }, true);\n }\n\n onPassThruActionProfile() {\n // Implement profile functionality here\n this.getApp().events.emit(\"portal:action\", {action: \"profile\"});\n }\n\n onActionSettings() {\n // Implement settings functionality here\n this.getApp().events.emit(\"portal:action\", {action: \"settings\"});\n }\n\n onActionLogout() {\n // Implement logout functionality here\n this.getApp().events.emit(\"auth:logout\", {action: \"logout\"});\n }\n\n /**\n * Handle dynamic action dispatch for right items\n */\n async handleAction(actionName, event, element) {\n // Check for custom handler first\n const itemId = element.getAttribute('data-id');\n if (itemId && this.rightItemHandlers && this.rightItemHandlers.has(itemId)) {\n const handler = this.rightItemHandlers.get(itemId);\n if (typeof handler === 'function') {\n return await handler.call(this, actionName, event, element);\n }\n }\n\n // Fallback to default action methods\n const methodName = `onAction${actionName.charAt(0).toUpperCase() + actionName.slice(1).replace(/-([a-z])/g, (g) => g[1].toUpperCase())}`;\n if (typeof this[methodName] === 'function') {\n return await this[methodName](event, element);\n }\n\n // Emit action event if no handler found\n this.emit('action', {\n action: actionName,\n event: event,\n element: element,\n topnav: this\n });\n }\n\n /**\n * Handle default actions by searching through rightItems and navItems\n */\n async onActionDefault(action, event, el) {\n // Check navItems first\n if (this.config.navItems) {\n for (const item of this.config.navItems) {\n if (item.action === action && item.handler) {\n await item.handler.call(this, action, event, el);\n return true;\n }\n }\n }\n\n // Check rightItems\n if (this.config.rightItems) {\n for (const item of this.config.rightItems) {\n if (item.action === action && item.handler) {\n await item.handler.call(this, action, event, el);\n return true;\n }\n // Also check dropdown items\n if (item.items) {\n for (const subItem of item.items) {\n if (subItem.action === action && subItem.handler) {\n await subItem.handler.call(this, action, event, el);\n return true;\n }\n }\n }\n }\n }\n\n this.getApp().events.emit(\"portal:action\", { action, event, el });\n\n return false;\n }\n\n /**\n * Filter items by user permissions\n */\n filterItemsByPermissions(items) {\n if (!items) return [];\n\n const app = this.getApp();\n const activeUser = app?.activeUser;\n\n return items.filter(item => {\n // If item has permissions and user exists, check permissions\n if (item.permissions && activeUser) {\n return activeUser.hasPermission(item.permissions);\n }\n // If no permissions required or no user, show the item\n return true;\n });\n }\n\n}\n\nexport default TopNav;\n"],"names":["item"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const t=require("./WebApp-
|
|
2
|
-
//# sourceMappingURL=TopNav-
|
|
1
|
+
"use strict";const t=require("./WebApp-CYqazUo5.js");class TopNav extends t.View{constructor(t={}){const n={light:"navbar navbar-expand-lg navbar-light topnav-light",dark:"navbar navbar-expand-lg navbar-dark topnav-dark",clean:"navbar navbar-expand-lg navbar-light topnav-clean",gradient:"navbar navbar-expand-lg navbar-dark topnav-gradient"};let e=n[t.theme||"light"]||n.light;t.shadow&&(e+=` topnav-shadow-${t.shadow}`),super({tagName:"nav",className:e,style:"position: relative; z-index: 1030;",...t}),this.displayMode=t.displayMode||"both",this.showPageIcon=!1!==t.showPageIcon,this.showPageDescription=t.showPageDescription||!1,this.showBreadcrumbs=t.showBreadcrumbs||!1,this.currentPage=null,this.previousPage=null,this.config={brand:t.brand||"MOJO App",brandIcon:t.brandIcon||"bi bi-play-circle",brandRoute:t.brandRoute||"/",navItems:t.navItems||[],rightItems:t.rightItems||[],showSidebarToggle:t.showSidebarToggle||!1,sidebarToggleAction:t.sidebarToggleAction||"toggle-sidebar",...t},this.userMenu=t.userMenu||this.findMenuItem("user"),this.userMenu&&(this.userMenu.id="user"),this.loginMenu=t.loginMenu||this.findMenuItem("login"),this.setupPageListeners()}findMenuItem(t){let n=this.config.navItems.find(n=>n.id===t);return n||(n=this.config.rightItems.find(n=>n.id===t)),n||null}replaceMenuItem(t,n){const e=this.config.navItems.findIndex(n=>n.id===t);if(-1!==e)return this.config.navItems[e]=n,!0;const a=this.config.rightItems.findIndex(n=>n.id===t);return-1!==a&&(this.config.rightItems[a]=n,!0)}setBrand(t,n=null){this.config.brand=t,this.config.brandIcon=n||this.config.brandIcon,this.render()}setUser(t){t?(this.userMenu.label=t.get("display_name"),this.replaceMenuItem("login",this.userMenu)):this.replaceMenuItem("user",this.loginMenu),this.setModel(t)}_onModelChange(){this.model&&(this.userMenu.label=this.model.get("display_name")),this.isMounted()&&this.render()}async getTemplate(){return'\n <div class="container-fluid">\n {{#data.showSidebarToggle}}\n <button class="topnav-sidebar-toggle me-2" data-action="{{data.sidebarToggleAction}}" aria-label="Toggle Sidebar">\n <i class="bi bi-chevron-right toggle-chevron"></i>\n </button>\n {{/data.showSidebarToggle}}\n\n {{#data.showPageInfo}}\n <div class="navbar-brand d-flex align-items-center">\n {{#data.currentPageIcon}}<i class="{{data.currentPageIcon}} me-2"></i>{{/data.currentPageIcon}}\n <div>\n <span>{{data.currentPageName}}</span>\n {{#data.currentPageDescription}}\n <small class="d-block" style="font-size: 0.75rem; line-height: 1;">{{data.currentPageDescription}}</small>\n {{/data.currentPageDescription}}\n </div>\n </div>\n {{/data.showPageInfo}}\n\n {{^data.showPageInfo}}\n <a class="navbar-brand" href="{{data.brandRoute}}">\n {{#data.brandIcon}}<i class="{{data.brandIcon}} me-2"></i>{{/data.brandIcon}}\n {{data.brand}}\n </a>\n {{/data.showPageInfo}}\n\n <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#{{data.navbarId}}">\n <span class="navbar-toggler-icon"></span>\n </button>\n\n <div class="collapse navbar-collapse" id="{{data.navbarId}}">\n {{#data.showNavItems}}\n <ul class="navbar-nav me-auto mb-2 mb-lg-0">\n {{#data.navItems}}\n <li class="nav-item">\n <a class="nav-link {{#active}}active{{/active}}" href="{{route}}">\n {{#icon}}<i class="{{icon}} me-1"></i>{{/icon}}\n {{text}}\n </a>\n </li>\n {{/data.navItems}}\n </ul>\n {{/data.showNavItems}}\n\n {{#data.hasRightItems}}\n <div class="navbar-nav ms-auto">\n {{#data.rightItems}}\n {{#isDropdown}}\n <div class="nav-item dropdown">\n <a class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">\n {{#icon}}<i class="{{icon}} me-1"></i>{{/icon}}\n {{label}}\n </a>\n <ul class="dropdown-menu dropdown-menu-end">\n {{#items}}\n {{#divider}}\n <li><hr class="dropdown-divider"></li>\n {{/divider}}\n {{^divider}}\n <li>\n <a class="dropdown-item" role="button" {{#action}}data-action="{{action}}"{{/action}}>\n {{#icon}}<i class="{{icon}} me-1"></i>{{/icon}}\n {{label}}\n </a>\n </li>\n {{/divider}}\n {{/items}}\n </ul>\n </div>\n {{/isDropdown}}\n {{^isDropdown}}\n {{#isButton}}\n <button class="{{buttonClass}}" data-action="{{action}}" data-id="{{id}}">\n {{#icon}}<i class="{{icon}} me-1"></i>{{/icon}}\n {{label}}\n </button>\n {{/isButton}}\n {{^isButton}}\n <a class="nav-link" href="{{href}}" {{#action}}data-action="{{action}}"{{/action}}>\n {{#icon}}<i class="{{icon}} me-1"></i>{{/icon}}\n {{label}}\n </a>\n {{/isButton}}\n {{/isDropdown}}\n {{/data.rightItems}}\n </div>\n {{/data.hasRightItems}}\n </div>\n </div>\n '}async onBeforeRender(){await super.onBeforeRender();const t="page"===this.displayMode||"both"===this.displayMode,n="menu"===this.displayMode||"both"===this.displayMode,e=this.filterItemsByPermissions(this.config.navItems||[]),a=this.processRightItems(this.config.rightItems||[]);this.data={brand:this.config.brand,brandIcon:this.config.brandIcon,brandRoute:this.config.brandRoute,navbarId:`navbar-${this.id}`,navItems:e,showNavItems:n,rightItems:a,hasRightItems:a.length>0,showPageInfo:t,currentPageName:this.currentPage?.title||this.currentPage?.name||"",currentPageIcon:this.currentPage?.icon||this.currentPage?.pageIcon||"",currentPageDescription:this.showPageDescription?this.currentPage?.description:"",showSidebarToggle:this.config.showSidebarToggle,sidebarToggleAction:this.config.sidebarToggleAction,displayMode:this.displayMode}}processRightItems(t){return this.filterItemsByPermissions(t).map(t=>{const n={...t};return t.items&&(n.items=this.filterItemsByPermissions(t.items)),n.items&&n.items.length>0?(n.isDropdown=!0,n.isButton=!1):t.buttonClass?(n.isButton=!0,n.isDropdown=!1):(n.isButton=!1,n.isDropdown=!1),t.handler&&(this.rightItemHandlers=this.rightItemHandlers||/* @__PURE__ */new Map,this.rightItemHandlers.set(t.id,t.handler)),n})}setupPageListeners(){this.getApp().events.on(["page:show","page:hide","page:denied"],t=>{this.onPageChanged(t)})}onPageBeforeChange(t){"page"===this.displayMode||this.displayMode}onPageChanged(t){this.previousPage=this.currentPage,this.currentPage=t.page,"page"!==this.displayMode&&"both"!==this.displayMode||this.updatePageDisplay(),"menu"!==this.displayMode&&"both"!==this.displayMode||this.currentPage&&this.currentPage.route&&this.updateActiveItem(this.currentPage.route)}updatePageDisplay(){this.currentPage&&this.mounted&&this.render()}updateActiveItem(t){const n=t=>t?t.startsWith("/")?t:`/${t}`:"/",e=n(t),a=this.data.navItems.map(t=>{const a=n(t.route);let i=!1;return"/"===a&&"/"===e?i=!0:"/"!==a&&"/"!==e&&(i=e.startsWith(a)||e===a),{...t,active:i}});this.updateData({navItems:a},!0)}onPassThruActionProfile(){this.getApp().events.emit("portal:action",{action:"profile"})}onActionSettings(){this.getApp().events.emit("portal:action",{action:"settings"})}onActionLogout(){this.getApp().events.emit("auth:logout",{action:"logout"})}async handleAction(t,n,e){const a=e.getAttribute("data-id");if(a&&this.rightItemHandlers&&this.rightItemHandlers.has(a)){const i=this.rightItemHandlers.get(a);if("function"==typeof i)return await i.call(this,t,n,e)}const i=`onAction${t.charAt(0).toUpperCase()+t.slice(1).replace(/-([a-z])/g,t=>t[1].toUpperCase())}`;if("function"==typeof this[i])return await this[i](n,e);this.emit("action",{action:t,event:n,element:e,topnav:this})}async onActionDefault(t,n,e){if(this.config.navItems)for(const a of this.config.navItems)if(a.action===t&&a.handler)return await a.handler.call(this,t,n,e),!0;if(this.config.rightItems)for(const a of this.config.rightItems){if(a.action===t&&a.handler)return await a.handler.call(this,t,n,e),!0;if(a.items)for(const i of a.items)if(i.action===t&&i.handler)return await i.handler.call(this,t,n,e),!0}return this.getApp().events.emit("portal:action",{action:t,event:n,el:e}),!1}filterItemsByPermissions(t){if(!t)return[];const n=this.getApp(),e=n?.activeUser;return t.filter(t=>!t.permissions||!e||e.hasPermission(t.permissions))}}exports.TopNav=TopNav;
|
|
2
|
+
//# sourceMappingURL=TopNav-DUwNnOuM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TopNav-BzKZzgE6.js","sources":["../../src/core/views/navigation/TopNav.js"],"sourcesContent":["/**\n * TopNav - Bootstrap navbar component for MOJO framework\n * Provides clean, responsive top navigation\n */\n\nimport View from '@core/View.js';\n\nclass TopNav extends View {\n constructor(options = {}) {\n // Define theme-to-class mappings\n const themes = {\n light: 'navbar navbar-expand-lg navbar-light topnav-light',\n dark: 'navbar navbar-expand-lg navbar-dark topnav-dark',\n clean: 'navbar navbar-expand-lg navbar-light topnav-clean',\n gradient: 'navbar navbar-expand-lg navbar-dark topnav-gradient',\n };\n\n // Set a default theme and determine the final class string\n const themeName = options.theme || 'light';\n let navbarClass = themes[themeName] || themes.light;\n\n // Add shadow class if specified\n if (options.shadow) {\n navbarClass += ` topnav-shadow-${options.shadow}`;\n }\n\n super({\n tagName: 'nav',\n className: navbarClass,\n style: 'position: relative; z-index: 1030;',\n ...options\n });\n\n // Display mode configuration\n this.displayMode = options.displayMode || 'both'; // 'menu' | 'page' | 'both'\n this.showPageIcon = options.showPageIcon !== false;\n this.showPageDescription = options.showPageDescription || false;\n this.showBreadcrumbs = options.showBreadcrumbs || false;\n\n // Current page tracking\n this.currentPage = null;\n this.previousPage = null;\n\n // Store raw config for processing in onBeforeRender\n this.config = {\n brand: options.brand || 'MOJO App',\n brandIcon: options.brandIcon || 'bi bi-play-circle',\n brandRoute: options.brandRoute || '/',\n navItems: options.navItems || [],\n rightItems: options.rightItems || [],\n showSidebarToggle: options.showSidebarToggle || false,\n sidebarToggleAction: options.sidebarToggleAction || 'toggle-sidebar',\n ...options\n };\n this.userMenu = options.userMenu || this.findMenuItem('user');\n if (this.userMenu) this.userMenu.id = \"user\";\n this.loginMenu = options.loginMenu || this.findMenuItem('login');\n // Setup page event listeners\n this.setupPageListeners();\n }\n\n findMenuItem(id) {\n let item = this.config.navItems.find(item => item.id === id);\n if (!item) {\n item = this.config.rightItems.find(item => item.id === id);\n }\n return item || null;\n }\n\n replaceMenuItem(id, new_menu) {\n // Find and replace in navItems\n const navIndex = this.config.navItems.findIndex(item => item.id === id);\n if (navIndex !== -1) {\n this.config.navItems[navIndex] = new_menu;\n return true;\n }\n\n // Find and replace in rightItems\n const rightIndex = this.config.rightItems.findIndex(item => item.id === id);\n if (rightIndex !== -1) {\n this.config.rightItems[rightIndex] = new_menu;\n return true;\n }\n\n return false;\n }\n\n setBrand(brand, icon=null) {\n this.config.brand = brand;\n this.config.brandIcon = icon || this.config.brandIcon;\n this.render();\n }\n\n setUser(user) {\n if (!user) {\n this.replaceMenuItem('user', this.loginMenu);\n } else {\n this.userMenu.label = user.get(\"display_name\");\n this.replaceMenuItem('login', this.userMenu);\n }\n this.setModel(user);\n }\n\n _onModelChange() {\n if (this.model) {\n this.userMenu.label = this.model.get(\"display_name\");\n }\n if (this.isMounted()) {\n this.render();\n }\n }\n\n /**\n * Get template based on display mode\n */\n async getTemplate() {\n return `\n <div class=\"container-fluid\">\n {{#data.showSidebarToggle}}\n <button class=\"topnav-sidebar-toggle me-2\" data-action=\"{{data.sidebarToggleAction}}\" aria-label=\"Toggle Sidebar\">\n <i class=\"bi bi-chevron-right toggle-chevron\"></i>\n </button>\n {{/data.showSidebarToggle}}\n\n {{#data.showPageInfo}}\n <div class=\"navbar-brand d-flex align-items-center\">\n {{#data.currentPageIcon}}<i class=\"{{data.currentPageIcon}} me-2\"></i>{{/data.currentPageIcon}}\n <div>\n <span>{{data.currentPageName}}</span>\n {{#data.currentPageDescription}}\n <small class=\"d-block\" style=\"font-size: 0.75rem; line-height: 1;\">{{data.currentPageDescription}}</small>\n {{/data.currentPageDescription}}\n </div>\n </div>\n {{/data.showPageInfo}}\n\n {{^data.showPageInfo}}\n <a class=\"navbar-brand\" href=\"{{data.brandRoute}}\">\n {{#data.brandIcon}}<i class=\"{{data.brandIcon}} me-2\"></i>{{/data.brandIcon}}\n {{data.brand}}\n </a>\n {{/data.showPageInfo}}\n\n <button class=\"navbar-toggler\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#{{data.navbarId}}\">\n <span class=\"navbar-toggler-icon\"></span>\n </button>\n\n <div class=\"collapse navbar-collapse\" id=\"{{data.navbarId}}\">\n {{#data.showNavItems}}\n <ul class=\"navbar-nav me-auto mb-2 mb-lg-0\">\n {{#data.navItems}}\n <li class=\"nav-item\">\n <a class=\"nav-link {{#active}}active{{/active}}\" href=\"{{route}}\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{text}}\n </a>\n </li>\n {{/data.navItems}}\n </ul>\n {{/data.showNavItems}}\n\n {{#data.hasRightItems}}\n <div class=\"navbar-nav ms-auto\">\n {{#data.rightItems}}\n {{#isDropdown}}\n <div class=\"nav-item dropdown\">\n <a class=\"nav-link dropdown-toggle\" role=\"button\" data-bs-toggle=\"dropdown\" aria-expanded=\"false\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n <ul class=\"dropdown-menu dropdown-menu-end\">\n {{#items}}\n {{#divider}}\n <li><hr class=\"dropdown-divider\"></li>\n {{/divider}}\n {{^divider}}\n <li>\n <a class=\"dropdown-item\" role=\"button\" {{#action}}data-action=\"{{action}}\"{{/action}}>\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n </li>\n {{/divider}}\n {{/items}}\n </ul>\n </div>\n {{/isDropdown}}\n {{^isDropdown}}\n {{#isButton}}\n <button class=\"{{buttonClass}}\" data-action=\"{{action}}\" data-id=\"{{id}}\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </button>\n {{/isButton}}\n {{^isButton}}\n <a class=\"nav-link\" href=\"{{href}}\" {{#action}}data-action=\"{{action}}\"{{/action}}>\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n {{/isButton}}\n {{/isDropdown}}\n {{/data.rightItems}}\n </div>\n {{/data.hasRightItems}}\n </div>\n </div>\n `;\n }\n\n /**\n * Process and normalize data before rendering (like Sidebar)\n */\n async onBeforeRender() {\n await super.onBeforeRender();\n\n const showPageInfo = this.displayMode === 'page' || this.displayMode === 'both';\n const showNavItems = this.displayMode === 'menu' || this.displayMode === 'both';\n\n // Filter navItems based on permissions\n const navItems = this.filterItemsByPermissions(this.config.navItems || []);\n\n // Process right items\n const rightItems = this.processRightItems(this.config.rightItems || []);\n\n this.data = {\n // Brand information\n brand: this.config.brand,\n brandIcon: this.config.brandIcon,\n brandRoute: this.config.brandRoute,\n\n // Navbar configuration\n navbarId: `navbar-${this.id}`,\n\n // Navigation items\n navItems: navItems,\n showNavItems: showNavItems,\n\n // Right items\n rightItems: rightItems,\n hasRightItems: rightItems.length > 0,\n\n // Page display\n showPageInfo: showPageInfo,\n currentPageName: this.currentPage?.title || this.currentPage?.name || '',\n currentPageIcon: this.currentPage?.icon || this.currentPage?.pageIcon || '',\n currentPageDescription: this.showPageDescription ? this.currentPage?.description : '',\n\n // Sidebar toggle\n showSidebarToggle: this.config.showSidebarToggle,\n sidebarToggleAction: this.config.sidebarToggleAction,\n\n // Display mode\n displayMode: this.displayMode\n };\n }\n\n /**\n * Process right items configuration\n */\n processRightItems(rightItems) {\n return this.filterItemsByPermissions(rightItems).map(item => {\n const processedItem = { ...item };\n\n // Filter dropdown items by permissions if they exist\n if (item.items) {\n processedItem.items = this.filterItemsByPermissions(item.items);\n }\n\n // Determine item type\n if (processedItem.items && processedItem.items.length > 0) {\n // Dropdown menu\n processedItem.isDropdown = true;\n processedItem.isButton = false;\n } else if (item.buttonClass) {\n // Button\n processedItem.isButton = true;\n processedItem.isDropdown = false;\n } else {\n // Link\n processedItem.isButton = false;\n processedItem.isDropdown = false;\n }\n\n // Store handler if provided\n if (item.handler) {\n this.rightItemHandlers = this.rightItemHandlers || new Map();\n this.rightItemHandlers.set(item.id, item.handler);\n }\n\n return processedItem;\n });\n }\n\n /**\n * Setup listeners for page change events\n */\n setupPageListeners() {\n // Use global MOJO event bus if available\n this.getApp().events.on([\"page:show\", \"page:hide\", \"page:denied\"], (data) => {\n this.onPageChanged(data);\n });\n }\n\n /**\n * Handle page before change event\n * @param {object} data - Event data\n */\n onPageBeforeChange(data) {\n // Can be used to show loading state\n if (this.displayMode === 'page' || this.displayMode === 'both') {\n // Optionally show loading indicator\n }\n }\n\n /**\n * Handle page changed event\n * @param {object} data - Event data with previousPage and currentPage\n */\n onPageChanged(data) {\n this.previousPage = this.currentPage;\n this.currentPage = data.page;\n\n // Update display based on mode\n if (this.displayMode === 'page' || this.displayMode === 'both') {\n this.updatePageDisplay();\n }\n\n // Update active menu items\n if (this.displayMode === 'menu' || this.displayMode === 'both') {\n if (this.currentPage && this.currentPage.route) {\n this.updateActiveItem(this.currentPage.route);\n }\n }\n }\n\n /**\n * Update the display to show current page info\n */\n updatePageDisplay() {\n if (!this.currentPage) return;\n\n // Just trigger re-render, onBeforeRender will handle the data processing\n if (this.mounted) {\n this.render();\n }\n }\n\n updateActiveItem(currentRoute) {\n // Normalize routes for comparison\n const normalizeRoute = (route) => {\n if (!route) return '/';\n return route.startsWith('/') ? route : `/${route}`;\n };\n\n const normalizedCurrentRoute = normalizeRoute(currentRoute);\n\n // Update active states with improved matching\n const navItems = this.data.navItems.map(item => {\n const normalizedItemRoute = normalizeRoute(item.route);\n\n // Check for active state\n let isActive = false;\n\n if (normalizedItemRoute === '/' && normalizedCurrentRoute === '/') {\n // Exact match for home route\n isActive = true;\n } else if (normalizedItemRoute !== '/' && normalizedCurrentRoute !== '/') {\n // For non-home routes, check if current route starts with nav item route\n // This allows /users to be active when on /users/123\n isActive = normalizedCurrentRoute.startsWith(normalizedItemRoute) ||\n normalizedCurrentRoute === normalizedItemRoute;\n }\n\n return {\n ...item,\n active: isActive\n };\n });\n\n this.updateData({ navItems }, true);\n }\n\n onPassThruActionProfile() {\n // Implement profile functionality here\n this.getApp().events.emit(\"portal:action\", {action: \"profile\"});\n }\n\n onActionSettings() {\n // Implement settings functionality here\n this.getApp().events.emit(\"portal:action\", {action: \"settings\"});\n }\n\n onActionLogout() {\n // Implement logout functionality here\n this.getApp().events.emit(\"auth:logout\", {action: \"logout\"});\n }\n\n /**\n * Handle dynamic action dispatch for right items\n */\n async handleAction(actionName, event, element) {\n // Check for custom handler first\n const itemId = element.getAttribute('data-id');\n if (itemId && this.rightItemHandlers && this.rightItemHandlers.has(itemId)) {\n const handler = this.rightItemHandlers.get(itemId);\n if (typeof handler === 'function') {\n return await handler.call(this, actionName, event, element);\n }\n }\n\n // Fallback to default action methods\n const methodName = `onAction${actionName.charAt(0).toUpperCase() + actionName.slice(1).replace(/-([a-z])/g, (g) => g[1].toUpperCase())}`;\n if (typeof this[methodName] === 'function') {\n return await this[methodName](event, element);\n }\n\n // Emit action event if no handler found\n this.emit('action', {\n action: actionName,\n event: event,\n element: element,\n topnav: this\n });\n }\n\n /**\n * Handle default actions by searching through rightItems and navItems\n */\n async onActionDefault(action, event, el) {\n // Check navItems first\n if (this.config.navItems) {\n for (const item of this.config.navItems) {\n if (item.action === action && item.handler) {\n await item.handler.call(this, action, event, el);\n return true;\n }\n }\n }\n\n // Check rightItems\n if (this.config.rightItems) {\n for (const item of this.config.rightItems) {\n if (item.action === action && item.handler) {\n await item.handler.call(this, action, event, el);\n return true;\n }\n // Also check dropdown items\n if (item.items) {\n for (const subItem of item.items) {\n if (subItem.action === action && subItem.handler) {\n await subItem.handler.call(this, action, event, el);\n return true;\n }\n }\n }\n }\n }\n\n this.getApp().events.emit(\"portal:action\", { action, event, el });\n\n return false;\n }\n\n /**\n * Filter items by user permissions\n */\n filterItemsByPermissions(items) {\n if (!items) return [];\n\n const app = this.getApp();\n const activeUser = app?.activeUser;\n\n return items.filter(item => {\n // If item has permissions and user exists, check permissions\n if (item.permissions && activeUser) {\n return activeUser.hasPermission(item.permissions);\n }\n // If no permissions required or no user, show the item\n return true;\n });\n }\n\n}\n\nexport default TopNav;\n"],"names":["TopNav","View","constructor","options","themes","light","dark","clean","gradient","navbarClass","theme","shadow","super","tagName","className","style","this","displayMode","showPageIcon","showPageDescription","showBreadcrumbs","currentPage","previousPage","config","brand","brandIcon","brandRoute","navItems","rightItems","showSidebarToggle","sidebarToggleAction","userMenu","findMenuItem","id","loginMenu","setupPageListeners","item","find","replaceMenuItem","new_menu","navIndex","findIndex","rightIndex","setBrand","icon","render","setUser","user","label","get","setModel","_onModelChange","model","isMounted","getTemplate","onBeforeRender","showPageInfo","showNavItems","filterItemsByPermissions","processRightItems","data","navbarId","hasRightItems","length","currentPageName","title","name","currentPageIcon","pageIcon","currentPageDescription","description","map","processedItem","items","isDropdown","isButton","buttonClass","handler","rightItemHandlers","Map","set","getApp","events","on","onPageChanged","onPageBeforeChange","page","updatePageDisplay","route","updateActiveItem","mounted","currentRoute","normalizeRoute","startsWith","normalizedCurrentRoute","normalizedItemRoute","isActive","active","updateData","onPassThruActionProfile","emit","action","onActionSettings","onActionLogout","handleAction","actionName","event","element","itemId","getAttribute","has","call","methodName","charAt","toUpperCase","slice","replace","g","topnav","onActionDefault","el","subItem","app","activeUser","filter","permissions","hasPermission"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TopNav-DUwNnOuM.js","sources":["../../src/core/views/navigation/TopNav.js"],"sourcesContent":["/**\n * TopNav - Bootstrap navbar component for MOJO framework\n * Provides clean, responsive top navigation\n */\n\nimport View from '@core/View.js';\n\nclass TopNav extends View {\n constructor(options = {}) {\n // Define theme-to-class mappings\n const themes = {\n light: 'navbar navbar-expand-lg navbar-light topnav-light',\n dark: 'navbar navbar-expand-lg navbar-dark topnav-dark',\n clean: 'navbar navbar-expand-lg navbar-light topnav-clean',\n gradient: 'navbar navbar-expand-lg navbar-dark topnav-gradient',\n };\n\n // Set a default theme and determine the final class string\n const themeName = options.theme || 'light';\n let navbarClass = themes[themeName] || themes.light;\n\n // Add shadow class if specified\n if (options.shadow) {\n navbarClass += ` topnav-shadow-${options.shadow}`;\n }\n\n super({\n tagName: 'nav',\n className: navbarClass,\n style: 'position: relative; z-index: 1030;',\n ...options\n });\n\n // Display mode configuration\n this.displayMode = options.displayMode || 'both'; // 'menu' | 'page' | 'both'\n this.showPageIcon = options.showPageIcon !== false;\n this.showPageDescription = options.showPageDescription || false;\n this.showBreadcrumbs = options.showBreadcrumbs || false;\n\n // Current page tracking\n this.currentPage = null;\n this.previousPage = null;\n\n // Store raw config for processing in onBeforeRender\n this.config = {\n brand: options.brand || 'MOJO App',\n brandIcon: options.brandIcon || 'bi bi-play-circle',\n brandRoute: options.brandRoute || '/',\n navItems: options.navItems || [],\n rightItems: options.rightItems || [],\n showSidebarToggle: options.showSidebarToggle || false,\n sidebarToggleAction: options.sidebarToggleAction || 'toggle-sidebar',\n ...options\n };\n this.userMenu = options.userMenu || this.findMenuItem('user');\n if (this.userMenu) this.userMenu.id = \"user\";\n this.loginMenu = options.loginMenu || this.findMenuItem('login');\n // Setup page event listeners\n this.setupPageListeners();\n }\n\n findMenuItem(id) {\n let item = this.config.navItems.find(item => item.id === id);\n if (!item) {\n item = this.config.rightItems.find(item => item.id === id);\n }\n return item || null;\n }\n\n replaceMenuItem(id, new_menu) {\n // Find and replace in navItems\n const navIndex = this.config.navItems.findIndex(item => item.id === id);\n if (navIndex !== -1) {\n this.config.navItems[navIndex] = new_menu;\n return true;\n }\n\n // Find and replace in rightItems\n const rightIndex = this.config.rightItems.findIndex(item => item.id === id);\n if (rightIndex !== -1) {\n this.config.rightItems[rightIndex] = new_menu;\n return true;\n }\n\n return false;\n }\n\n setBrand(brand, icon=null) {\n this.config.brand = brand;\n this.config.brandIcon = icon || this.config.brandIcon;\n this.render();\n }\n\n setUser(user) {\n if (!user) {\n this.replaceMenuItem('user', this.loginMenu);\n } else {\n this.userMenu.label = user.get(\"display_name\");\n this.replaceMenuItem('login', this.userMenu);\n }\n this.setModel(user);\n }\n\n _onModelChange() {\n if (this.model) {\n this.userMenu.label = this.model.get(\"display_name\");\n }\n if (this.isMounted()) {\n this.render();\n }\n }\n\n /**\n * Get template based on display mode\n */\n async getTemplate() {\n return `\n <div class=\"container-fluid\">\n {{#data.showSidebarToggle}}\n <button class=\"topnav-sidebar-toggle me-2\" data-action=\"{{data.sidebarToggleAction}}\" aria-label=\"Toggle Sidebar\">\n <i class=\"bi bi-chevron-right toggle-chevron\"></i>\n </button>\n {{/data.showSidebarToggle}}\n\n {{#data.showPageInfo}}\n <div class=\"navbar-brand d-flex align-items-center\">\n {{#data.currentPageIcon}}<i class=\"{{data.currentPageIcon}} me-2\"></i>{{/data.currentPageIcon}}\n <div>\n <span>{{data.currentPageName}}</span>\n {{#data.currentPageDescription}}\n <small class=\"d-block\" style=\"font-size: 0.75rem; line-height: 1;\">{{data.currentPageDescription}}</small>\n {{/data.currentPageDescription}}\n </div>\n </div>\n {{/data.showPageInfo}}\n\n {{^data.showPageInfo}}\n <a class=\"navbar-brand\" href=\"{{data.brandRoute}}\">\n {{#data.brandIcon}}<i class=\"{{data.brandIcon}} me-2\"></i>{{/data.brandIcon}}\n {{data.brand}}\n </a>\n {{/data.showPageInfo}}\n\n <button class=\"navbar-toggler\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#{{data.navbarId}}\">\n <span class=\"navbar-toggler-icon\"></span>\n </button>\n\n <div class=\"collapse navbar-collapse\" id=\"{{data.navbarId}}\">\n {{#data.showNavItems}}\n <ul class=\"navbar-nav me-auto mb-2 mb-lg-0\">\n {{#data.navItems}}\n <li class=\"nav-item\">\n <a class=\"nav-link {{#active}}active{{/active}}\" href=\"{{route}}\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{text}}\n </a>\n </li>\n {{/data.navItems}}\n </ul>\n {{/data.showNavItems}}\n\n {{#data.hasRightItems}}\n <div class=\"navbar-nav ms-auto\">\n {{#data.rightItems}}\n {{#isDropdown}}\n <div class=\"nav-item dropdown\">\n <a class=\"nav-link dropdown-toggle\" role=\"button\" data-bs-toggle=\"dropdown\" aria-expanded=\"false\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n <ul class=\"dropdown-menu dropdown-menu-end\">\n {{#items}}\n {{#divider}}\n <li><hr class=\"dropdown-divider\"></li>\n {{/divider}}\n {{^divider}}\n <li>\n <a class=\"dropdown-item\" role=\"button\" {{#action}}data-action=\"{{action}}\"{{/action}}>\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n </li>\n {{/divider}}\n {{/items}}\n </ul>\n </div>\n {{/isDropdown}}\n {{^isDropdown}}\n {{#isButton}}\n <button class=\"{{buttonClass}}\" data-action=\"{{action}}\" data-id=\"{{id}}\">\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </button>\n {{/isButton}}\n {{^isButton}}\n <a class=\"nav-link\" href=\"{{href}}\" {{#action}}data-action=\"{{action}}\"{{/action}}>\n {{#icon}}<i class=\"{{icon}} me-1\"></i>{{/icon}}\n {{label}}\n </a>\n {{/isButton}}\n {{/isDropdown}}\n {{/data.rightItems}}\n </div>\n {{/data.hasRightItems}}\n </div>\n </div>\n `;\n }\n\n /**\n * Process and normalize data before rendering (like Sidebar)\n */\n async onBeforeRender() {\n await super.onBeforeRender();\n\n const showPageInfo = this.displayMode === 'page' || this.displayMode === 'both';\n const showNavItems = this.displayMode === 'menu' || this.displayMode === 'both';\n\n // Filter navItems based on permissions\n const navItems = this.filterItemsByPermissions(this.config.navItems || []);\n\n // Process right items\n const rightItems = this.processRightItems(this.config.rightItems || []);\n\n this.data = {\n // Brand information\n brand: this.config.brand,\n brandIcon: this.config.brandIcon,\n brandRoute: this.config.brandRoute,\n\n // Navbar configuration\n navbarId: `navbar-${this.id}`,\n\n // Navigation items\n navItems: navItems,\n showNavItems: showNavItems,\n\n // Right items\n rightItems: rightItems,\n hasRightItems: rightItems.length > 0,\n\n // Page display\n showPageInfo: showPageInfo,\n currentPageName: this.currentPage?.title || this.currentPage?.name || '',\n currentPageIcon: this.currentPage?.icon || this.currentPage?.pageIcon || '',\n currentPageDescription: this.showPageDescription ? this.currentPage?.description : '',\n\n // Sidebar toggle\n showSidebarToggle: this.config.showSidebarToggle,\n sidebarToggleAction: this.config.sidebarToggleAction,\n\n // Display mode\n displayMode: this.displayMode\n };\n }\n\n /**\n * Process right items configuration\n */\n processRightItems(rightItems) {\n return this.filterItemsByPermissions(rightItems).map(item => {\n const processedItem = { ...item };\n\n // Filter dropdown items by permissions if they exist\n if (item.items) {\n processedItem.items = this.filterItemsByPermissions(item.items);\n }\n\n // Determine item type\n if (processedItem.items && processedItem.items.length > 0) {\n // Dropdown menu\n processedItem.isDropdown = true;\n processedItem.isButton = false;\n } else if (item.buttonClass) {\n // Button\n processedItem.isButton = true;\n processedItem.isDropdown = false;\n } else {\n // Link\n processedItem.isButton = false;\n processedItem.isDropdown = false;\n }\n\n // Store handler if provided\n if (item.handler) {\n this.rightItemHandlers = this.rightItemHandlers || new Map();\n this.rightItemHandlers.set(item.id, item.handler);\n }\n\n return processedItem;\n });\n }\n\n /**\n * Setup listeners for page change events\n */\n setupPageListeners() {\n // Use global MOJO event bus if available\n this.getApp().events.on([\"page:show\", \"page:hide\", \"page:denied\"], (data) => {\n this.onPageChanged(data);\n });\n }\n\n /**\n * Handle page before change event\n * @param {object} data - Event data\n */\n onPageBeforeChange(data) {\n // Can be used to show loading state\n if (this.displayMode === 'page' || this.displayMode === 'both') {\n // Optionally show loading indicator\n }\n }\n\n /**\n * Handle page changed event\n * @param {object} data - Event data with previousPage and currentPage\n */\n onPageChanged(data) {\n this.previousPage = this.currentPage;\n this.currentPage = data.page;\n\n // Update display based on mode\n if (this.displayMode === 'page' || this.displayMode === 'both') {\n this.updatePageDisplay();\n }\n\n // Update active menu items\n if (this.displayMode === 'menu' || this.displayMode === 'both') {\n if (this.currentPage && this.currentPage.route) {\n this.updateActiveItem(this.currentPage.route);\n }\n }\n }\n\n /**\n * Update the display to show current page info\n */\n updatePageDisplay() {\n if (!this.currentPage) return;\n\n // Just trigger re-render, onBeforeRender will handle the data processing\n if (this.mounted) {\n this.render();\n }\n }\n\n updateActiveItem(currentRoute) {\n // Normalize routes for comparison\n const normalizeRoute = (route) => {\n if (!route) return '/';\n return route.startsWith('/') ? route : `/${route}`;\n };\n\n const normalizedCurrentRoute = normalizeRoute(currentRoute);\n\n // Update active states with improved matching\n const navItems = this.data.navItems.map(item => {\n const normalizedItemRoute = normalizeRoute(item.route);\n\n // Check for active state\n let isActive = false;\n\n if (normalizedItemRoute === '/' && normalizedCurrentRoute === '/') {\n // Exact match for home route\n isActive = true;\n } else if (normalizedItemRoute !== '/' && normalizedCurrentRoute !== '/') {\n // For non-home routes, check if current route starts with nav item route\n // This allows /users to be active when on /users/123\n isActive = normalizedCurrentRoute.startsWith(normalizedItemRoute) ||\n normalizedCurrentRoute === normalizedItemRoute;\n }\n\n return {\n ...item,\n active: isActive\n };\n });\n\n this.updateData({ navItems }, true);\n }\n\n onPassThruActionProfile() {\n // Implement profile functionality here\n this.getApp().events.emit(\"portal:action\", {action: \"profile\"});\n }\n\n onActionSettings() {\n // Implement settings functionality here\n this.getApp().events.emit(\"portal:action\", {action: \"settings\"});\n }\n\n onActionLogout() {\n // Implement logout functionality here\n this.getApp().events.emit(\"auth:logout\", {action: \"logout\"});\n }\n\n /**\n * Handle dynamic action dispatch for right items\n */\n async handleAction(actionName, event, element) {\n // Check for custom handler first\n const itemId = element.getAttribute('data-id');\n if (itemId && this.rightItemHandlers && this.rightItemHandlers.has(itemId)) {\n const handler = this.rightItemHandlers.get(itemId);\n if (typeof handler === 'function') {\n return await handler.call(this, actionName, event, element);\n }\n }\n\n // Fallback to default action methods\n const methodName = `onAction${actionName.charAt(0).toUpperCase() + actionName.slice(1).replace(/-([a-z])/g, (g) => g[1].toUpperCase())}`;\n if (typeof this[methodName] === 'function') {\n return await this[methodName](event, element);\n }\n\n // Emit action event if no handler found\n this.emit('action', {\n action: actionName,\n event: event,\n element: element,\n topnav: this\n });\n }\n\n /**\n * Handle default actions by searching through rightItems and navItems\n */\n async onActionDefault(action, event, el) {\n // Check navItems first\n if (this.config.navItems) {\n for (const item of this.config.navItems) {\n if (item.action === action && item.handler) {\n await item.handler.call(this, action, event, el);\n return true;\n }\n }\n }\n\n // Check rightItems\n if (this.config.rightItems) {\n for (const item of this.config.rightItems) {\n if (item.action === action && item.handler) {\n await item.handler.call(this, action, event, el);\n return true;\n }\n // Also check dropdown items\n if (item.items) {\n for (const subItem of item.items) {\n if (subItem.action === action && subItem.handler) {\n await subItem.handler.call(this, action, event, el);\n return true;\n }\n }\n }\n }\n }\n\n this.getApp().events.emit(\"portal:action\", { action, event, el });\n\n return false;\n }\n\n /**\n * Filter items by user permissions\n */\n filterItemsByPermissions(items) {\n if (!items) return [];\n\n const app = this.getApp();\n const activeUser = app?.activeUser;\n\n return items.filter(item => {\n // If item has permissions and user exists, check permissions\n if (item.permissions && activeUser) {\n return activeUser.hasPermission(item.permissions);\n }\n // If no permissions required or no user, show the item\n return true;\n });\n }\n\n}\n\nexport default TopNav;\n"],"names":["TopNav","View","constructor","options","themes","light","dark","clean","gradient","navbarClass","theme","shadow","super","tagName","className","style","this","displayMode","showPageIcon","showPageDescription","showBreadcrumbs","currentPage","previousPage","config","brand","brandIcon","brandRoute","navItems","rightItems","showSidebarToggle","sidebarToggleAction","userMenu","findMenuItem","id","loginMenu","setupPageListeners","item","find","replaceMenuItem","new_menu","navIndex","findIndex","rightIndex","setBrand","icon","render","setUser","user","label","get","setModel","_onModelChange","model","isMounted","getTemplate","onBeforeRender","showPageInfo","showNavItems","filterItemsByPermissions","processRightItems","data","navbarId","hasRightItems","length","currentPageName","title","name","currentPageIcon","pageIcon","currentPageDescription","description","map","processedItem","items","isDropdown","isButton","buttonClass","handler","rightItemHandlers","Map","set","getApp","events","on","onPageChanged","onPageBeforeChange","page","updatePageDisplay","route","updateActiveItem","mounted","currentRoute","normalizeRoute","startsWith","normalizedCurrentRoute","normalizedItemRoute","isActive","active","updateData","onPassThruActionProfile","emit","action","onActionSettings","onActionLogout","handleAction","actionName","event","element","itemId","getAttribute","has","call","methodName","charAt","toUpperCase","slice","replace","g","topnav","onActionDefault","el","subItem","app","activeUser","filter","permissions","hasPermission"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const VERSION = "2.1.
|
|
1
|
+
const VERSION = "2.1.443";
|
|
2
2
|
const VERSION_MAJOR = 2;
|
|
3
3
|
const VERSION_MINOR = 1;
|
|
4
|
-
const VERSION_REVISION =
|
|
5
|
-
const BUILD_TIME = "2025-09-
|
|
4
|
+
const VERSION_REVISION = 443;
|
|
5
|
+
const BUILD_TIME = "2025-09-29T17:37:18.020Z";
|
|
6
6
|
const VERSION_INFO = {
|
|
7
7
|
full: VERSION,
|
|
8
8
|
major: VERSION_MAJOR,
|
|
@@ -2630,6 +2630,7 @@ class View {
|
|
|
2630
2630
|
return this;
|
|
2631
2631
|
}
|
|
2632
2632
|
canRender() {
|
|
2633
|
+
if (this.isRendering) return false;
|
|
2633
2634
|
if (this.options.renderCooldown > 0 && now - this.lastRenderTime < this.options.renderCooldown) {
|
|
2634
2635
|
View._warn(`View ${this.id}: Render called too quickly, cooldown active`);
|
|
2635
2636
|
return false;
|
|
@@ -2742,7 +2743,8 @@ class View {
|
|
|
2742
2743
|
container.replaceChildren(this.element);
|
|
2743
2744
|
} else if (!this.containerId && this.parent) {
|
|
2744
2745
|
this.parent.element.appendChild(this.element);
|
|
2745
|
-
} else if (!this.containerId && !this.parent) {
|
|
2746
|
+
} else if (!this.containerId && !this.parent && this.options.allowAppendToBody) {
|
|
2747
|
+
console.log("APPENDING TO BODY!!!!");
|
|
2746
2748
|
document.body.appendChild(this.element);
|
|
2747
2749
|
} else {
|
|
2748
2750
|
console.error(`Container not found for ${this.containerId}`);
|
|
@@ -4732,7 +4734,7 @@ class WebApp {
|
|
|
4732
4734
|
*/
|
|
4733
4735
|
async showError(message) {
|
|
4734
4736
|
try {
|
|
4735
|
-
const Dialog = (await import("./Dialog-
|
|
4737
|
+
const Dialog = (await import("./Dialog-DbZ2jB_m.js")).default;
|
|
4736
4738
|
await Dialog.alert(message, "Error", { size: "md", class: "text-danger" });
|
|
4737
4739
|
} catch (e) {
|
|
4738
4740
|
this.events.emit("notification", { message, type: "error" });
|
|
@@ -4749,7 +4751,7 @@ class WebApp {
|
|
|
4749
4751
|
*/
|
|
4750
4752
|
async showSuccess(message) {
|
|
4751
4753
|
try {
|
|
4752
|
-
const Dialog = (await import("./Dialog-
|
|
4754
|
+
const Dialog = (await import("./Dialog-DbZ2jB_m.js")).default;
|
|
4753
4755
|
await Dialog.alert(message, "Success", { size: "md", class: "text-success" });
|
|
4754
4756
|
} catch (e) {
|
|
4755
4757
|
this.events.emit("notification", { message, type: "success" });
|
|
@@ -4766,7 +4768,7 @@ class WebApp {
|
|
|
4766
4768
|
*/
|
|
4767
4769
|
async showInfo(message) {
|
|
4768
4770
|
try {
|
|
4769
|
-
const Dialog = (await import("./Dialog-
|
|
4771
|
+
const Dialog = (await import("./Dialog-DbZ2jB_m.js")).default;
|
|
4770
4772
|
await Dialog.alert(message, "Information", { size: "md", class: "text-info" });
|
|
4771
4773
|
} catch (e) {
|
|
4772
4774
|
this.events.emit("notification", { message, type: "info" });
|
|
@@ -4783,7 +4785,7 @@ class WebApp {
|
|
|
4783
4785
|
*/
|
|
4784
4786
|
async showWarning(message) {
|
|
4785
4787
|
try {
|
|
4786
|
-
const Dialog = (await import("./Dialog-
|
|
4788
|
+
const Dialog = (await import("./Dialog-DbZ2jB_m.js")).default;
|
|
4787
4789
|
await Dialog.alert(message, "Warning", { size: "md", class: "text-warning" });
|
|
4788
4790
|
} catch (e) {
|
|
4789
4791
|
this.events.emit("notification", { message, type: "warning" });
|
|
@@ -4809,7 +4811,7 @@ class WebApp {
|
|
|
4809
4811
|
opts = { message: opts };
|
|
4810
4812
|
}
|
|
4811
4813
|
try {
|
|
4812
|
-
const Dialog = (await import("./Dialog-
|
|
4814
|
+
const Dialog = (await import("./Dialog-DbZ2jB_m.js")).default;
|
|
4813
4815
|
Dialog.showBusy(opts);
|
|
4814
4816
|
} catch (e) {
|
|
4815
4817
|
if (typeof window !== "undefined" && window?.console) {
|
|
@@ -4823,7 +4825,7 @@ class WebApp {
|
|
|
4823
4825
|
*/
|
|
4824
4826
|
async hideLoading() {
|
|
4825
4827
|
try {
|
|
4826
|
-
const Dialog = (await import("./Dialog-
|
|
4828
|
+
const Dialog = (await import("./Dialog-DbZ2jB_m.js")).default;
|
|
4827
4829
|
Dialog.hideBusy();
|
|
4828
4830
|
} catch (e) {
|
|
4829
4831
|
if (typeof window !== "undefined" && window?.console) {
|
|
@@ -4833,7 +4835,7 @@ class WebApp {
|
|
|
4833
4835
|
}
|
|
4834
4836
|
async showModelForm(options = {}) {
|
|
4835
4837
|
try {
|
|
4836
|
-
const Dialog = (await import("./Dialog-
|
|
4838
|
+
const Dialog = (await import("./Dialog-DbZ2jB_m.js")).default;
|
|
4837
4839
|
return await Dialog.showModelForm(options);
|
|
4838
4840
|
} catch (e) {
|
|
4839
4841
|
if (typeof window !== "undefined" && window?.console) {
|
|
@@ -4844,7 +4846,7 @@ class WebApp {
|
|
|
4844
4846
|
}
|
|
4845
4847
|
async showForm(options = {}) {
|
|
4846
4848
|
try {
|
|
4847
|
-
const Dialog = (await import("./Dialog-
|
|
4849
|
+
const Dialog = (await import("./Dialog-DbZ2jB_m.js")).default;
|
|
4848
4850
|
return await Dialog.showForm(options);
|
|
4849
4851
|
} catch (e) {
|
|
4850
4852
|
if (typeof window !== "undefined" && window?.console) {
|
|
@@ -4853,6 +4855,10 @@ class WebApp {
|
|
|
4853
4855
|
throw e;
|
|
4854
4856
|
}
|
|
4855
4857
|
}
|
|
4858
|
+
async confirm(message, title = "Confirm", options = {}) {
|
|
4859
|
+
const Dialog = (await import("./Dialog-DbZ2jB_m.js")).default;
|
|
4860
|
+
return await Dialog.confirm(message, title, options);
|
|
4861
|
+
}
|
|
4856
4862
|
/**
|
|
4857
4863
|
* Setup browser focus/blur tracking
|
|
4858
4864
|
*/
|
|
@@ -5107,4 +5113,4 @@ export {
|
|
|
5107
5113
|
EventEmitter as i,
|
|
5108
5114
|
rest as r
|
|
5109
5115
|
};
|
|
5110
|
-
//# sourceMappingURL=WebApp-
|
|
5116
|
+
//# sourceMappingURL=WebApp-BPWJVv80.js.map
|