@@ -, +, @@ --- .../prog/js/vue/components/Breadcrumbs.vue | 9 +- .../prog/js/vue/components/NavigationItem.vue | 3 +- .../intranet-tmpl/prog/js/vue/i18n/index.js | 9 + .../intranet-tmpl/prog/js/vue/modules/erm.ts | 9 +- .../intranet-tmpl/prog/js/vue/routes/erm.js | 107 ++++--- .../prog/js/vue/stores/navigation.js | 303 ++++++++++++------ 6 files changed, 276 insertions(+), 164 deletions(-) create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/i18n/index.js --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Breadcrumbs.vue +++ a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Breadcrumbs.vue @@ -8,7 +8,7 @@ > @@ -35,9 +35,10 @@ export default { --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/NavigationItem.vue +++ a/koha-tmpl/intranet-tmpl/prog/js/vue/components/NavigationItem.vue @@ -21,7 +21,8 @@ {{ $__(item.title) }} - + --- a/koha-tmpl/intranet-tmpl/prog/js/vue/i18n/index.js +++ a/koha-tmpl/intranet-tmpl/prog/js/vue/i18n/index.js @@ -0,0 +1,9 @@ +export const $__ = (key) => { + return window["__"](key); +}; + +export default { + install: (app, options) => { + app.config.globalProperties.$__ = $__ + }, +}; --- a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/erm.ts +++ a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/erm.ts @@ -23,17 +23,10 @@ import { useMainStore } from "../stores/main"; import { useVendorStore } from "../stores/vendors"; import { useAVStore } from "../stores/authorised-values"; import { useNavigationStore } from "../stores/navigation"; +import i18n from "../i18n"; const pinia = createPinia(); -const i18n = { - install: (app, options) => { - app.config.globalProperties.$__ = (key) => { - return window["__"](key); - }; - }, -}; - const mainStore = useMainStore(pinia); const AVStore = useAVStore(pinia); const navigationStore = useNavigationStore(pinia); --- a/koha-tmpl/intranet-tmpl/prog/js/vue/routes/erm.js +++ a/koha-tmpl/intranet-tmpl/prog/js/vue/routes/erm.js @@ -1,3 +1,5 @@ +import { markRaw } from "vue"; + import Home from "../components/ERM/Home.vue"; import AgreementsList from "../components/ERM/AgreementsList.vue"; import AgreementsShow from "../components/ERM/AgreementsShow.vue"; @@ -19,6 +21,8 @@ import LicensesList from "../components/ERM/LicensesList.vue"; import LicensesShow from "../components/ERM/LicensesShow.vue"; import LicensesFormAdd from "../components/ERM/LicensesFormAdd.vue"; +import { $__ } from "../i18n"; + export const routes = [ { path: "/cgi-bin/koha/admin/background_jobs/:id", @@ -31,143 +35,142 @@ export const routes = [ }, { path: "/cgi-bin/koha/erm/erm.pl", - component: {template: ''}, is_default: true, is_base: true, - title: 'E-resource management', + title: $__('E-resource management'), children: [ { path: "", - component: Home, + component: markRaw(Home), is_navigation_item: false, }, { path: "/cgi-bin/koha/erm/agreements", - title: 'Agreements', + title: $__('Agreements'), icon: 'fa-check-circle-o', is_end_node: true, children: [ { path: "", - component: AgreementsList, + component: markRaw(AgreementsList), }, { path: ":agreement_id", - component: AgreementsShow, - title: "Show agreement", + component: markRaw(AgreementsShow), + title: $__('Show agreement'), }, { path: "add", - component: AgreementsFormAdd, - title: "Add agreement", + component: markRaw(AgreementsFormAdd), + title: $__('Add agreement'), }, { path: "edit/:agreement_id", - component: AgreementsFormAdd, - title: "Edit agreement", + component: markRaw(AgreementsFormAdd), + title: $__('Edit agreement'), }, ], }, { path: "/cgi-bin/koha/erm/licenses", - title: "Licenses", + title: $__('Licenses'), icon: "fa-gavel", is_end_node: true, children: [ { path: "", - component: LicensesList, + component: markRaw(LicensesList), }, { path: ":license_id", - component: LicensesShow, - title: "Show license", + component: markRaw(LicensesShow), + title: $__('Show license'), }, { path: "add", - component: LicensesFormAdd, - title: "Add license", + component: markRaw(LicensesFormAdd), + title: $__('Add license'), }, { path: "edit/:license_id", - component: LicensesFormAdd, - title: "Edit license", + component: markRaw(LicensesFormAdd), + title: $__('Edit license'), }, ], }, { path: "/cgi-bin/koha/erm/eholdings", - title: "eHoldings", + title: $__('eHoldings'), icon: 'fa-crosshairs', disabled: true, children: [ { path: "local", - title: "Local", + title: $__('Local'), icon: "fa-map-marker", disabled: true, children: [ { path: "packages", - title: "Packages", + title: $__('Packages'), icon: "fa-archive", is_end_node: true, children: [ { path: "", - component: EHoldingsLocalPackagesList, + component: markRaw(EHoldingsLocalPackagesList), }, { path: ":package_id", - component: EHoldingsLocalPackagesShow, - title: "Show package", + component: markRaw(EHoldingsLocalPackagesShow), + title: $__('Show package'), }, { path: "add", - component: EHoldingsLocalPackagesFormAdd, - title: "Add package", + component: markRaw(EHoldingsLocalPackagesFormAdd), + title: $__('Add package'), }, { path: "edit/:package_id", - component: EHoldingsLocalPackagesFormAdd, - title: "Edit package", + component: markRaw(EHoldingsLocalPackagesFormAdd), + title: $__('Edit package'), }, ], }, { path: "titles", - title: "Titles", + title: $__('Titles'), icon: "fa-sort-alpha-asc", is_end_node: true, children: [ { path: "", - component: EHoldingsLocalTitlesList, + component: markRaw(EHoldingsLocalTitlesList), }, { path: ":title_id", - component: EHoldingsLocalTitlesShow, - title: "Show title", + component: markRaw(EHoldingsLocalTitlesShow), + title: $__('Show title'), }, { path: "add", - component: EHoldingsLocalTitlesFormAdd, - title: "Add title", + component: markRaw(EHoldingsLocalTitlesFormAdd), + title: $__('Add title'), }, { path: "edit/:title_id", - component: EHoldingsLocalTitlesFormAdd, - title: "Edit title", + component: markRaw(EHoldingsLocalTitlesFormAdd), + title: $__('Edit title'), }, { path: "import", - component: EHoldingsLocalTitlesFormImport, - title: "Import from a list", + component: markRaw(EHoldingsLocalTitlesFormImport), + title: $__('Import from a list'), }, { path: "/cgi-bin/koha/erm/eholdings/local/resources/:resource_id", - component: EHoldingsLocalResourcesShow, - title: "Resource", + component: markRaw(EHoldingsLocalResourcesShow), + title: $__('Resource'), }, ], }, @@ -175,46 +178,46 @@ export const routes = [ }, { path: "ebsco", - title: "EBSCO", + title: $__('EBSCO'), icon: 'fa-globe', disabled: true, children: [ { path: "packages", - title: "Packages", + title: $__('Packages'), icon: "fa-archive", is_end_node: true, children: [ { path: "", - component: EHoldingsEBSCOPackagesList, + component: markRaw(EHoldingsEBSCOPackagesList), }, { path: ":package_id", - component: EHoldingsEBSCOPackagesShow, - title: "Show package", + component: markRaw(EHoldingsEBSCOPackagesShow), + title: $__('Show package'), }, ], }, { path: "titles", - title: "Titles", + title: $__('Titles'), icon: "fa-sort-alpha-asc", is_end_node: true, children: [ { path: "", - component: EHoldingsEBSCOTitlesList, + component: markRaw(EHoldingsEBSCOTitlesList), }, { path: ":title_id", - component: EHoldingsEBSCOTitlesShow, - title: "Show title", + component: markRaw(EHoldingsEBSCOTitlesShow), + title: $__('Show title'), }, { path: "/cgi-bin/koha/erm/eholdings/ebsco/resources/:resource_id", - component: EHoldingsEBSCOResourcesShow, - title: "Resource", + component: markRaw(EHoldingsEBSCOResourcesShow), + title: $__('Resource'), is_navigation_item: false, }, ], --- a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/navigation.js +++ a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/navigation.js @@ -1,106 +1,211 @@ -import { defineStore } from "pinia"; +import { + defineStore +} from "pinia"; export const useNavigationStore = defineStore("navigation", { - state: () => ({ - routeState: { - alt: "Home", - href: "/cgi-bin/koha/mainpage.pl", - is_navigation_item: false, - is_base: true, - children: [] - }, - current: null, - }), - actions: { - setRoutes(routesDef) { - const _traverse_children = (parent) => { - if(parent.children && parent.children.length) { - parent.children.forEach(child => { - child.parent = parent; - if(child.path !== undefined) { - if(!child.meta) child.meta = {}; - child.meta.self = child; - } - if(parent.children.length === 1 && parent.is_base) { - child.is_base = child.is_base !== undefined ? child.is_base : true; - child.is_navigation_item = child.is_navigation_item !== undefined ? child.is_navigation_item : false; - } else if (parent.children.length > 1 || !parent.is_base) { - child.is_base = child.is_base !== undefined ? child.is_base : false; - child.is_navigation_item = child.is_navigation_item !== undefined ? child.is_navigation_item : true; - } - _traverse_children(child) - }) - } - } - if(!Array.isArray(routesDef)) { - routesDef = [routesDef] - } - this.routeState.children = routesDef - _traverse_children(this.routeState) - return this.navigationRoutes - } - }, - getters: { - breadcrumbs() { - const _traverse_parent = (child) => { - let breadcrumbs = [] - let builtPath = child.path - if(child.parent) { - breadcrumbs = _traverse_parent(child.parent) - if(builtPath !== undefined && !/^\//.test(builtPath)) { - const {path:parentPath} = breadcrumbs[breadcrumbs.length - 1] - if(parentPath !== undefined) { - builtPath = `${parentPath}${/\/$/.test(parentPath)?'':'/'}${builtPath}` - } - } - } - if (child.is_base || (child.path && child.path !== '')) breadcrumbs.push({...child, icon: null, path: builtPath, children: null}) - return breadcrumbs - } - if(this.current) - return _traverse_parent(this.current) - - const _get_base_elements = (parent) => { - if(!parent.is_base) return [] - let next = {} - if(parent.children && parent.children.length) { - next = parent.children.find(child => child.is_default) || parent.children[0] - } - return [{...parent, children: null}, ..._get_base_elements(next)] - } + state: () => ({ + routeState: { + alt: "Home", + href: "/cgi-bin/koha/mainpage.pl", + is_navigation_item: false, + is_base: true, + children: [] + }, + current: null, + }), + actions: { + setRoutes(routesDef) { + if (!Array.isArray(routesDef)) { + routesDef = [routesDef] + } + this.routeState.children = routesDef + _traverseChildren(this.routeState) - return _get_base_elements(this.routeState) - }, - leftNavigation() { - const _get_navigation_elements = (parent, builtPath = '') => { - if (parent.is_base && (!parent.children || !parent.children.length)) return []; - if (parent.is_base) return parent.children.filter(child => child.is_base || child.is_navigation_item).map(_get_navigation_elements).flat(Infinity) - let items = [] - if(builtPath) builtPath = `${builtPath}${/\/$/.test(builtPath)?'':'/'}` - if(parent.path !== undefined && /^\//.test(parent.path)) { - builtPath = parent.path - } else if (parent.path !== undefined) { - builtPath = `${builtPath}${parent.path}` - } else { - builtPath = '' - } - if (!parent.is_end_node && parent.children && parent.children.length) { - items = parent.children - .filter(child => child.is_navigation_item) - .map(child => _get_navigation_elements(child, builtPath)) + return this.navigationRoutes + + // Function declarations + + function _traverseChildren(parent) { + if (isParent(parent)) { + parent.children.forEach(child => { + _setChildDefaults(parent, child); + _traverseChildren(child) + }) + } + } + + function _setChildDefaults(parent, child) { + child.parent = parent; + if (isRoutable(child)) { + _setMetadata(child); + } + if (parent.children.length === 1 && parent.is_base) { + _setBaseAndNavigationDefaults(child, { + is_base: true, + is_navigation_item: false + }); + } else { + _setBaseAndNavigationDefaults(child, { + is_base: false, + is_navigation_item: true + }); + } + } + + function _setBaseAndNavigationDefaults(child, { + is_base, + is_navigation_item + }) { + child.is_base = child.is_base !== undefined ? child.is_base : is_base; + child.is_navigation_item = child.is_navigation_item !== undefined ? child.is_navigation_item : is_navigation_item; + } + + function _setMetadata(child) { + if (!child.meta) + child.meta = {}; + child.meta.self = child; + } } - return {...parent, path: builtPath ? builtPath : parent.path, children: items} - } - const leftNav = _get_navigation_elements(this.routeState) - return leftNav }, - navigationRoutes() { - const _to_route = (parent) => { - if(parent.path === undefined) return parent.children.map(child => _to_route(child)).flat(Infinity) - return parent - } - let routes = _to_route(this.routeState) - return Array.isArray(routes) ? routes : [routes] + getters: { + breadcrumbs() { + if (this.current) + return _traverseParent(this.current) + + return _getBaseElements(this.routeState) + + // Function declarations + + function _getBaseElements(parent) { + if (!parent.is_base) return [] + let next = {} + if (isParent(parent)) { + next = _defineNextElement(parent) + } + return [{ + ...parent, + children: null + }, ..._getBaseElements(next)] + } + + function _defineNextElement(parent) { + return parent.children.find(child => child.is_default) || parent.children[0]; + } + + function _traverseParent(child) { + let breadcrumbs = [] + let builtPath = child.path + if (child.parent) { + breadcrumbs = _traverseParent(child.parent) + builtPath = _buildPath(builtPath, breadcrumbs); + } + if (_isBaseOrNotStub(child)) breadcrumbs.push({ + ...child, + icon: null, + path: builtPath, + children: null + }) + return breadcrumbs + } + + function _isBaseOrNotStub(child) { + return child.is_base || (child.path && child.path !== ''); + } + + function _buildPath(builtPath, breadcrumbs) { + if (!isAbsolutePath(builtPath)) { + const { + path: parentPath + } = breadcrumbs[breadcrumbs.length - 1]; + if (parentPath !== undefined) { + builtPath = `${parentPath}${addSlashIfNotPresent(parentPath)}${builtPath}`; + } + } + return builtPath; + } + }, + leftNavigation() { + return _getNavigationElements(this.routeState) + + // Function declarations + + function _getNavigationElements(parent, prevPath = '') { + if (_isBaseAndNoChildren(parent)) return []; + if (parent.is_base) + return _buildChildNavigationElements(parent).flat(Infinity) + + const builtPath = _buildPath(prevPath, parent); + + let children = [] + if (!parent.is_end_node && isParent(parent)) { + children = _buildChildNavigationElements(parent, builtPath) + } + + return { + ...parent, + path: builtPath ? builtPath : parent.path, + children + } + } + + function _buildPath(prevPath, element) { + let builtPath; + + if (isRoutable(element) && isAbsolutePath(element.path)) { + builtPath = element.path; + } else { + if (prevPath) + builtPath = `${prevPath}${addSlashIfNotPresent(prevPath)}`; + if (isRoutable(element)) + builtPath = `${builtPath}${element.path}`; + } + + return builtPath; + } + + function _buildChildNavigationElements(parent, builtPath) { + return parent.children + .filter(child => child.is_base || child.is_navigation_item) + .map(child => _getNavigationElements(child, builtPath)); + } + + function _isBaseAndNoChildren(parent) { + return parent.is_base && (!parent.children || !parent.children.length); + } + }, + navigationRoutes() { + let routes = _toRoute(this.routeState) + return Array.isArray(routes) ? routes : [routes] + + // Function declarations + + function _toRoute(parent) { + if (!isRoutable(parent)) + return _getRoutableChildren(parent) + return parent + } + + function _getRoutableChildren(parent) { + return parent.children + .map(child => _toRoute(child)) + .flat(Infinity); + } + } } - } }) + +function addSlashIfNotPresent(path) { + return /\/$/.test(path) ? '' : '/'; +} + +function isRoutable(element) { + return element.path !== undefined; +} + +function isParent(parent) { + return parent.children && parent.children.length; +} + +function isAbsolutePath(path) { + return /^\//.test(path); +} --