web-mojo 2.1.294 → 2.1.295
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.es.js +10 -10
- 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-DLDSJEIk.js → ContextMenu-BhyvSOLE.js} +2 -2
- package/dist/chunks/{ContextMenu-DLDSJEIk.js.map → ContextMenu-BhyvSOLE.js.map} +1 -1
- package/dist/chunks/{ContextMenu-DR9qV_8Z.js → ContextMenu-DKKmjtgo.js} +2 -2
- package/dist/chunks/{ContextMenu-DR9qV_8Z.js.map → ContextMenu-DKKmjtgo.js.map} +1 -1
- package/dist/chunks/{DataView-CB3fkiWE.js → DataView-CX04UO6n.js} +2 -2
- package/dist/chunks/{DataView-CB3fkiWE.js.map → DataView-CX04UO6n.js.map} +1 -1
- package/dist/chunks/{DataView-DX2XDuNt.js → DataView-CjjREbqE.js} +2 -2
- package/dist/chunks/{DataView-DX2XDuNt.js.map → DataView-CjjREbqE.js.map} +1 -1
- package/dist/chunks/{Dialog-BUZEYiTL.js → Dialog-C7XcgLt8.js} +5 -5
- package/dist/chunks/{Dialog-BUZEYiTL.js.map → Dialog-C7XcgLt8.js.map} +1 -1
- package/dist/chunks/{Dialog-DCpfJ63g.js → Dialog-Dvb1SU1y.js} +2 -2
- package/dist/chunks/{Dialog-DCpfJ63g.js.map → Dialog-Dvb1SU1y.js.map} +1 -1
- package/dist/chunks/{FilePreviewView-A32KUENg.js → FilePreviewView-CB0yqQtV.js} +6 -6
- package/dist/chunks/{FilePreviewView-A32KUENg.js.map → FilePreviewView-CB0yqQtV.js.map} +1 -1
- package/dist/chunks/{FilePreviewView-DWLPUdX6.js → FilePreviewView-DgVmlBjn.js} +2 -2
- package/dist/chunks/{FilePreviewView-DWLPUdX6.js.map → FilePreviewView-DgVmlBjn.js.map} +1 -1
- package/dist/chunks/{FormView-CYJpCFJ2.js → FormView-CWFqrlKb.js} +2 -2
- package/dist/chunks/{FormView-CYJpCFJ2.js.map → FormView-CWFqrlKb.js.map} +1 -1
- package/dist/chunks/{FormView-GJqUOJqR.js → FormView-DJxUvj0p.js} +140 -3
- package/dist/chunks/{FormView-GJqUOJqR.js.map → FormView-DJxUvj0p.js.map} +1 -1
- package/dist/chunks/{MetricsChart-BMtSNVSC.js → MetricsChart-CpfACPrE.js} +3 -3
- package/dist/chunks/{MetricsChart-BMtSNVSC.js.map → MetricsChart-CpfACPrE.js.map} +1 -1
- package/dist/chunks/{MetricsChart-khF2NtDH.js → MetricsChart-DQUOkYQ9.js} +2 -2
- package/dist/chunks/{MetricsChart-khF2NtDH.js.map → MetricsChart-DQUOkYQ9.js.map} +1 -1
- package/dist/chunks/{PDFViewer-DG_JyAZU.js → PDFViewer-BUOnvSfV.js} +2 -2
- package/dist/chunks/{PDFViewer-DG_JyAZU.js.map → PDFViewer-BUOnvSfV.js.map} +1 -1
- package/dist/chunks/{PDFViewer-DoHxXjiP.js → PDFViewer-I1qlINnm.js} +3 -3
- package/dist/chunks/{PDFViewer-DoHxXjiP.js.map → PDFViewer-I1qlINnm.js.map} +1 -1
- package/dist/chunks/{Page-CkziZoUi.js → Page-ZtYiac8Q.js} +2 -2
- package/dist/chunks/{Page-CkziZoUi.js.map → Page-ZtYiac8Q.js.map} +1 -1
- package/dist/chunks/{Page-uLnlAlwn.js → Page-h5bbwzKf.js} +2 -2
- package/dist/chunks/{Page-uLnlAlwn.js.map → Page-h5bbwzKf.js.map} +1 -1
- package/dist/chunks/{TopNav-MEetwvBb.js → TopNav-DVX8V6fL.js} +2 -2
- package/dist/chunks/{TopNav-MEetwvBb.js.map → TopNav-DVX8V6fL.js.map} +1 -1
- package/dist/chunks/{TopNav-BuFxvfyc.js → TopNav-mtuzmduR.js} +2 -2
- package/dist/chunks/{TopNav-BuFxvfyc.js.map → TopNav-mtuzmduR.js.map} +1 -1
- package/dist/chunks/{WebApp-CKLwTH9q.js → WebApp-BgZwmmBY.js} +15 -12
- package/dist/chunks/WebApp-BgZwmmBY.js.map +1 -0
- package/dist/chunks/WebApp-C_DpNvNx.js +2 -0
- package/dist/chunks/WebApp-C_DpNvNx.js.map +1 -0
- 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/WebApp-CKLwTH9q.js.map +0 -1
- package/dist/chunks/WebApp-D0A6nJtm.js +0 -2
- package/dist/chunks/WebApp-D0A6nJtm.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TopNav-MEetwvBb.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-DVX8V6fL.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-C_DpNvNx.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-mtuzmduR.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TopNav-BuFxvfyc.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":"qDAOA,MAAMA,eAAeC,EAAAA,KACjB,WAAAC,CAAYC,EAAU,IAElB,MAAMC,EAAS,CACXC,MAAO,oDACPC,KAAM,kDACNC,MAAO,oDACPC,SAAU,uDAKd,IAAIC,EAAcL,EADAD,EAAQO,OAAS,UACIN,EAAOC,MAG1CF,EAAQQ,SACRF,GAAe,kBAAkBN,EAAQQ,UAG7CC,MAAM,CACFC,QAAS,MACTC,UAAWL,EACXM,MAAO,wCACJZ,IAIPa,KAAKC,YAAcd,EAAQc,aAAe,OAC1CD,KAAKE,cAAwC,IAAzBf,EAAQe,aAC5BF,KAAKG,oBAAsBhB,EAAQgB,sBAAuB,EAC1DH,KAAKI,gBAAkBjB,EAAQiB,kBAAmB,EAGlDJ,KAAKK,YAAc,KACnBL,KAAKM,aAAe,KAGpBN,KAAKO,OAAS,CACVC,MAAOrB,EAAQqB,OAAS,WACxBC,UAAWtB,EAAQsB,WAAa,oBAChCC,WAAYvB,EAAQuB,YAAc,IAClCC,SAAUxB,EAAQwB,UAAY,GAC9BC,WAAYzB,EAAQyB,YAAc,GAClCC,kBAAmB1B,EAAQ0B,oBAAqB,EAChDC,oBAAqB3B,EAAQ2B,qBAAuB,oBACjD3B,GAEPa,KAAKe,SAAW5B,EAAQ4B,UAAYf,KAAKgB,aAAa,QAClDhB,KAAKe,WAAUf,KAAKe,SAASE,GAAK,QACtCjB,KAAKkB,UAAY/B,EAAQ+B,WAAalB,KAAKgB,aAAa,SAExDhB,KAAKmB,oBACT,CAEA,YAAAH,CAAaC,GACT,IAAIG,EAAOpB,KAAKO,OAAOI,SAASU,KAAKD,GAAQA,EAAKH,KAAOA,GAIzD,OAHKG,IACDA,EAAOpB,KAAKO,OAAOK,WAAWS,KAAKD,GAAQA,EAAKH,KAAOA,IAEpDG,GAAQ,IACnB,CAEA,eAAAE,CAAgBL,EAAIM,GAEhB,MAAMC,EAAWxB,KAAKO,OAAOI,SAASc,UAAUL,GAAQA,EAAKH,KAAOA,GACpE,IAAiB,IAAbO,EAEA,OADAxB,KAAKO,OAAOI,SAASa,GAAYD,GAC1B,EAIX,MAAMG,EAAa1B,KAAKO,OAAOK,WAAWa,UAAUL,GAAQA,EAAKH,KAAOA,GACxE,OAAmB,IAAfS,IACA1B,KAAKO,OAAOK,WAAWc,GAAcH,GAC9B,EAIf,CAEA,QAAAI,CAASnB,EAAOoB,EAAK,MACjB5B,KAAKO,OAAOC,MAAQA,EACpBR,KAAKO,OAAOE,UAAYmB,GAAQ5B,KAAKO,OAAOE,UAC5CT,KAAK6B,QACT,CAEA,OAAAC,CAAQC,GACCA,GAGD/B,KAAKe,SAASiB,MAAQD,EAAKE,IAAI,gBAC/BjC,KAAKsB,gBAAgB,QAAStB,KAAKe,WAHnCf,KAAKsB,gBAAgB,OAAQtB,KAAKkB,WAKtClB,KAAKkC,SAASH,EAClB,CAEA,cAAAI,GACMnC,KAAKoC,QACPpC,KAAKe,SAASiB,MAAQhC,KAAKoC,MAAMH,IAAI,iBAEnCjC,KAAKqC,aACLrC,KAAK6B,QAEX,CAKA,iBAAMS,GACF,MAAO,4+IA2FX,CAKA,oBAAMC,SACI3C,MAAM2C,iBAEZ,MAAMC,EAAoC,SAArBxC,KAAKC,aAA+C,SAArBD,KAAKC,YACnDwC,EAAoC,SAArBzC,KAAKC,aAA+C,SAArBD,KAAKC,YAGnDU,EAAWX,KAAK0C,yBAAyB1C,KAAKO,OAAOI,UAAY,IAGjEC,EAAaZ,KAAK2C,kBAAkB3C,KAAKO,OAAOK,YAAc,IAEpEZ,KAAK4C,KAAO,CAERpC,MAAOR,KAAKO,OAAOC,MACnBC,UAAWT,KAAKO,OAAOE,UACvBC,WAAYV,KAAKO,OAAOG,WAGxBmC,SAAU,UAAU7C,KAAKiB,KAGzBN,WACA8B,eAGA7B,aACAkC,cAAelC,EAAWmC,OAAS,EAGnCP,eACAQ,gBAAiBhD,KAAKK,aAAa4C,OAASjD,KAAKK,aAAa6C,MAAQ,GACtEC,gBAAiBnD,KAAKK,aAAauB,MAAQ5B,KAAKK,aAAa+C,UAAY,GACzEC,uBAAwBrD,KAAKG,oBAAsBH,KAAKK,aAAaiD,YAAc,GAGnFzC,kBAAmBb,KAAKO,OAAOM,kBAC/BC,oBAAqBd,KAAKO,OAAOO,oBAGjCb,YAAaD,KAAKC,YAE1B,CAKA,iBAAA0C,CAAkB/B,GACd,OAAOZ,KAAK0C,yBAAyB9B,GAAY2C,IAAInC,IACjD,MAAMoC,EAAgB,IAAKpC,GA4B3B,OAzBIA,EAAKqC,QACLD,EAAcC,MAAQzD,KAAK0C,yBAAyBtB,EAAKqC,QAIzDD,EAAcC,OAASD,EAAcC,MAAMV,OAAS,GAEpDS,EAAcE,YAAa,EAC3BF,EAAcG,UAAW,GAClBvC,EAAKwC,aAEZJ,EAAcG,UAAW,EACzBH,EAAcE,YAAa,IAG3BF,EAAcG,UAAW,EACzBH,EAAcE,YAAa,GAI3BtC,EAAKyC,UACL7D,KAAK8D,kBAAoB9D,KAAK8D,kCAAqB,IAAIC,IACvD/D,KAAK8D,kBAAkBE,IAAI5C,EAAKH,GAAIG,EAAKyC,UAGtCL,GAEf,CAKA,kBAAArC,GAEInB,KAAKiE,SAASC,OAAOC,GAAG,CAAC,YAAa,YAAa,eAAiBvB,IAChE5C,KAAKoE,cAAcxB,IAE3B,CAMA,kBAAAyB,CAAmBzB,GAEU,SAArB5C,KAAKC,aAA0BD,KAAKC,WAG5C,CAMA,aAAAmE,CAAcxB,GACV5C,KAAKM,aAAeN,KAAKK,YACzBL,KAAKK,YAAcuC,EAAK0B,KAGC,SAArBtE,KAAKC,aAA+C,SAArBD,KAAKC,aACpCD,KAAKuE,oBAIgB,SAArBvE,KAAKC,aAA+C,SAArBD,KAAKC,aAChCD,KAAKK,aAAeL,KAAKK,YAAYmE,OACrCxE,KAAKyE,iBAAiBzE,KAAKK,YAAYmE,MAGnD,CAKA,iBAAAD,GACSvE,KAAKK,aAGNL,KAAK0E,SACL1E,KAAK6B,QAEb,CAEA,gBAAA4C,CAAiBE,GAEb,MAAMC,EAAkBJ,GACfA,EACEA,EAAMK,WAAW,KAAOL,EAAQ,IAAIA,IADxB,IAIjBM,EAAyBF,EAAeD,GAGxChE,EAAWX,KAAK4C,KAAKjC,SAAS4C,IAAInC,IACpC,MAAM2D,EAAsBH,EAAexD,EAAKoD,OAGhD,IAAIQ,GAAW,EAYf,MAV4B,MAAxBD,GAA0D,MAA3BD,EAE/BE,GAAW,EACoB,MAAxBD,GAA0D,MAA3BD,IAGtCE,EAAWF,EAAuBD,WAAWE,IACnCD,IAA2BC,GAGlC,IACA3D,EACH6D,OAAQD,KAIhBhF,KAAKkF,WAAW,CAAEvE,aAAY,EAClC,CAEA,uBAAAwE,GAEInF,KAAKiE,SAASC,OAAOkB,KAAK,gBAAiB,CAACC,OAAQ,WACxD,CAEA,gBAAAC,GAEItF,KAAKiE,SAASC,OAAOkB,KAAK,gBAAiB,CAACC,OAAQ,YACxD,CAEA,cAAAE,GAEIvF,KAAKiE,SAASC,OAAOkB,KAAK,cAAe,CAACC,OAAQ,UACtD,CAKA,kBAAMG,CAAaC,EAAYC,EAAOC,GAElC,MAAMC,EAASD,EAAQE,aAAa,WACpC,GAAID,GAAU5F,KAAK8D,mBAAqB9D,KAAK8D,kBAAkBgC,IAAIF,GAAS,CACxE,MAAM/B,EAAU7D,KAAK8D,kBAAkB7B,IAAI2D,GAC3C,GAAuB,mBAAZ/B,EACP,aAAaA,EAAQkC,KAAK/F,KAAMyF,EAAYC,EAAOC,EAE3D,CAGA,MAAMK,EAAa,WAAWP,EAAWQ,OAAO,GAAGC,cAAgBT,EAAWU,MAAM,GAAGC,QAAQ,YAAcC,GAAMA,EAAE,GAAGH,iBACxH,GAAgC,mBAArBlG,KAAKgG,GACZ,aAAahG,KAAKgG,GAAYN,EAAOC,GAIzC3F,KAAKoF,KAAK,SAAU,CAChBC,OAAQI,EACRC,QACAC,UACAW,OAAQtG,MAEhB,CAKA,qBAAMuG,CAAgBlB,EAAQK,EAAOc,GAEjC,GAAIxG,KAAKO,OAAOI,SACZ,IAAA,MAAWS,KAAQpB,KAAKO,OAAOI,SAC3B,GAAIS,EAAKiE,SAAWA,GAAUjE,EAAKyC,QAE/B,aADMzC,EAAKyC,QAAQkC,KAAK/F,KAAMqF,EAAQK,EAAOc,IACtC,EAMnB,GAAIxG,KAAKO,OAAOK,WACZ,IAAA,MAAWQ,KAAQpB,KAAKO,OAAOK,WAAY,CACvC,GAAIQ,EAAKiE,SAAWA,GAAUjE,EAAKyC,QAE/B,aADMzC,EAAKyC,QAAQkC,KAAK/F,KAAMqF,EAAQK,EAAOc,IACtC,EAGX,GAAIpF,EAAKqC,MACL,IAAA,MAAWgD,KAAWrF,EAAKqC,MACvB,GAAIgD,EAAQpB,SAAWA,GAAUoB,EAAQ5C,QAErC,aADM4C,EAAQ5C,QAAQkC,KAAK/F,KAAMqF,EAAQK,EAAOc,IACzC,CAIvB,CAKJ,OAFAxG,KAAKiE,SAASC,OAAOkB,KAAK,gBAAiB,CAAEC,SAAQK,QAAOc,QAErD,CACX,CAKA,wBAAA9D,CAAyBe,GACrB,IAAKA,EAAO,MAAO,GAEnB,MAAMiD,EAAM1G,KAAKiE,SACX0C,EAAaD,GAAKC,WAExB,OAAOlD,EAAMmD,OAAOxF,IAEZA,EAAKyF,cAAeF,GACbA,EAAWG,cAAc1F,EAAKyF,aAKjD"}
|
|
1
|
+
{"version":3,"file":"TopNav-mtuzmduR.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.295";
|
|
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 = 295;
|
|
5
|
+
const BUILD_TIME = "2025-09-27T16:53:54.885Z";
|
|
6
6
|
const VERSION_INFO = {
|
|
7
7
|
full: VERSION,
|
|
8
8
|
major: VERSION_MAJOR,
|
|
@@ -529,7 +529,10 @@ class DataFormatter {
|
|
|
529
529
|
this.register("compact", this.compact.bind(this));
|
|
530
530
|
this.register("uppercase", (v) => String(v).toUpperCase());
|
|
531
531
|
this.register("lowercase", (v) => String(v).toLowerCase());
|
|
532
|
+
this.register("upper", (v) => String(v).toUpperCase());
|
|
533
|
+
this.register("lower", (v) => String(v).toLowerCase());
|
|
532
534
|
this.register("capitalize", this.capitalize.bind(this));
|
|
535
|
+
this.register("caps", this.capitalize.bind(this));
|
|
533
536
|
this.register("truncate", this.truncate.bind(this));
|
|
534
537
|
this.register("truncate_middle", this.truncate_middle.bind(this));
|
|
535
538
|
this.register("slug", this.slug.bind(this));
|
|
@@ -4729,7 +4732,7 @@ class WebApp {
|
|
|
4729
4732
|
*/
|
|
4730
4733
|
async showError(message) {
|
|
4731
4734
|
try {
|
|
4732
|
-
const Dialog = (await import("./Dialog-
|
|
4735
|
+
const Dialog = (await import("./Dialog-C7XcgLt8.js")).default;
|
|
4733
4736
|
await Dialog.alert(message, "Error", { size: "md", class: "text-danger" });
|
|
4734
4737
|
} catch (e) {
|
|
4735
4738
|
this.events.emit("notification", { message, type: "error" });
|
|
@@ -4746,7 +4749,7 @@ class WebApp {
|
|
|
4746
4749
|
*/
|
|
4747
4750
|
async showSuccess(message) {
|
|
4748
4751
|
try {
|
|
4749
|
-
const Dialog = (await import("./Dialog-
|
|
4752
|
+
const Dialog = (await import("./Dialog-C7XcgLt8.js")).default;
|
|
4750
4753
|
await Dialog.alert(message, "Success", { size: "md", class: "text-success" });
|
|
4751
4754
|
} catch (e) {
|
|
4752
4755
|
this.events.emit("notification", { message, type: "success" });
|
|
@@ -4763,7 +4766,7 @@ class WebApp {
|
|
|
4763
4766
|
*/
|
|
4764
4767
|
async showInfo(message) {
|
|
4765
4768
|
try {
|
|
4766
|
-
const Dialog = (await import("./Dialog-
|
|
4769
|
+
const Dialog = (await import("./Dialog-C7XcgLt8.js")).default;
|
|
4767
4770
|
await Dialog.alert(message, "Information", { size: "md", class: "text-info" });
|
|
4768
4771
|
} catch (e) {
|
|
4769
4772
|
this.events.emit("notification", { message, type: "info" });
|
|
@@ -4780,7 +4783,7 @@ class WebApp {
|
|
|
4780
4783
|
*/
|
|
4781
4784
|
async showWarning(message) {
|
|
4782
4785
|
try {
|
|
4783
|
-
const Dialog = (await import("./Dialog-
|
|
4786
|
+
const Dialog = (await import("./Dialog-C7XcgLt8.js")).default;
|
|
4784
4787
|
await Dialog.alert(message, "Warning", { size: "md", class: "text-warning" });
|
|
4785
4788
|
} catch (e) {
|
|
4786
4789
|
this.events.emit("notification", { message, type: "warning" });
|
|
@@ -4806,7 +4809,7 @@ class WebApp {
|
|
|
4806
4809
|
opts = { message: opts };
|
|
4807
4810
|
}
|
|
4808
4811
|
try {
|
|
4809
|
-
const Dialog = (await import("./Dialog-
|
|
4812
|
+
const Dialog = (await import("./Dialog-C7XcgLt8.js")).default;
|
|
4810
4813
|
Dialog.showBusy(opts);
|
|
4811
4814
|
} catch (e) {
|
|
4812
4815
|
if (typeof window !== "undefined" && window?.console) {
|
|
@@ -4820,7 +4823,7 @@ class WebApp {
|
|
|
4820
4823
|
*/
|
|
4821
4824
|
async hideLoading() {
|
|
4822
4825
|
try {
|
|
4823
|
-
const Dialog = (await import("./Dialog-
|
|
4826
|
+
const Dialog = (await import("./Dialog-C7XcgLt8.js")).default;
|
|
4824
4827
|
Dialog.hideBusy();
|
|
4825
4828
|
} catch (e) {
|
|
4826
4829
|
if (typeof window !== "undefined" && window?.console) {
|
|
@@ -4830,7 +4833,7 @@ class WebApp {
|
|
|
4830
4833
|
}
|
|
4831
4834
|
async showModelForm(options = {}) {
|
|
4832
4835
|
try {
|
|
4833
|
-
const Dialog = (await import("./Dialog-
|
|
4836
|
+
const Dialog = (await import("./Dialog-C7XcgLt8.js")).default;
|
|
4834
4837
|
return await Dialog.showModelForm(options);
|
|
4835
4838
|
} catch (e) {
|
|
4836
4839
|
if (typeof window !== "undefined" && window?.console) {
|
|
@@ -4841,7 +4844,7 @@ class WebApp {
|
|
|
4841
4844
|
}
|
|
4842
4845
|
async showForm(options = {}) {
|
|
4843
4846
|
try {
|
|
4844
|
-
const Dialog = (await import("./Dialog-
|
|
4847
|
+
const Dialog = (await import("./Dialog-C7XcgLt8.js")).default;
|
|
4845
4848
|
return await Dialog.showForm(options);
|
|
4846
4849
|
} catch (e) {
|
|
4847
4850
|
if (typeof window !== "undefined" && window?.console) {
|
|
@@ -5104,4 +5107,4 @@ export {
|
|
|
5104
5107
|
EventEmitter as i,
|
|
5105
5108
|
rest as r
|
|
5106
5109
|
};
|
|
5107
|
-
//# sourceMappingURL=WebApp-
|
|
5110
|
+
//# sourceMappingURL=WebApp-BgZwmmBY.js.map
|