diff --git a/webapp/src/main/webapp/vue-apps/common/js/NavigationUtils.js b/webapp/src/main/webapp/vue-apps/common/js/NavigationUtils.js new file mode 100644 index 00000000000..8b8dbe40cdf --- /dev/null +++ b/webapp/src/main/webapp/vue-apps/common/js/NavigationUtils.js @@ -0,0 +1,33 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +export function getNavigationNodeUri(baseSiteUri, navigation) { + const hasPage = !!navigation?.pageKey; + const pageUrl = hasPage && `${baseSiteUri}${navigation.uri}`; + const pageLink = navigation?.pageLink && Autolinker.parse(navigation?.pageLink, { + email: true, + })?.[0]?.getUrl?.() || navigation?.pageLink; + navigation.nodeUri = pageLink || pageUrl; + return navigation.nodeUri; +} + +export function getNavigationNodeTarget(navigation) { + navigation.nodeTarget = navigation?.target === 'SAME_TAB' && '_self' || '_blank'; + return navigation.nodeTarget; +} diff --git a/webapp/src/main/webapp/vue-apps/common/main.js b/webapp/src/main/webapp/vue-apps/common/main.js index 1a2817cea05..87424afab52 100644 --- a/webapp/src/main/webapp/vue-apps/common/main.js +++ b/webapp/src/main/webapp/vue-apps/common/main.js @@ -20,6 +20,7 @@ import * as navigationService from '../common/js/NavigationService.js'; import * as profileSettingsService from '../common/js/ProfileSettingsService.js'; import * as profileLabelService from '../common/js/ProfileLabelService.js'; import * as siteService from './js/SiteService.js'; +import * as navigationUtils from './js/NavigationUtils.js'; // get overrided components if exists if (extensionRegistry) { @@ -97,6 +98,9 @@ window.Object.defineProperty(Vue.prototype, '$profileLabelService', { window.Object.defineProperty(Vue.prototype, '$navigationService', { value: navigationService, }); +window.Object.defineProperty(Vue.prototype, '$navigationUtils', { + value: navigationUtils, +}); if (eXo.env.portal.userIdentityId) { window.Object.defineProperty(Vue.prototype, '$currentUserIdentity', { diff --git a/webapp/src/main/webapp/vue-apps/top-bar-menu/components/NavigationMenuItem.vue b/webapp/src/main/webapp/vue-apps/top-bar-menu/components/NavigationMenuItem.vue index 2d575164484..6748073f631 100644 --- a/webapp/src/main/webapp/vue-apps/top-bar-menu/components/NavigationMenuItem.vue +++ b/webapp/src/main/webapp/vue-apps/top-bar-menu/components/NavigationMenuItem.vue @@ -41,8 +41,7 @@ v-on="on" v-bind="attrs" role="tab" - @click.stop="checkLink(navigation, $event)" - @click="openUrl(navigationNodeUri, navigationNodeTarget)" + @click="checkLink" @change="updateNavigationState"> @@ -107,10 +106,10 @@ export default { return !!this.navigation?.pageKey; }, navigationNodeUri() { - return this.navigation?.pageLink || (this.hasPage && `${this.baseSiteUri}${this.navigation.uri}`); + return this.$navigationUtils.getNavigationNodeUri(this.baseSiteUri, this.navigation); }, navigationNodeTarget() { - return this.navigation?.target === 'SAME_TAB' && '_self' || '_blank'; + return this.$navigationUtils.getNavigationNodeTarget(this.navigation); }, childrenHasPage() { return this.checkChildrenHasPage(this.navigation); @@ -138,11 +137,18 @@ export default { updateNavigationState() { this.$emit('update-navigation-state', this.navigationNodeUri); }, - checkLink(navigation, e) { - if (!navigation.pageKey) { + checkLink(e) { + if (!this.navigationNodeUri) { + e.stopPropagation(); e.preventDefault(); } - if (navigation.children) { + if (this.navigationNodeUri?.includes?.('#')) { + if (this.navigationNodeTarget === '_blank') { + window.open(this.navigationNodeUri); + } else { + window.location.href = this.navigationNodeUri; + } + } else if (this.hasChildren && this.childrenHasPage) { this.openDropMenu(); } }, @@ -182,16 +188,6 @@ export default { }); return childrenHasPage; }, - openUrl(url, target) { - if (url) { - if (!url?.match?.(/^(https?:\/\/|javascript:|\/portal\/)/)) { - url = `//${url}`; - } else if (url?.match?.(/^(\/portal\/)/)) { - url = `${window.location.origin}${url}`; - } - window.open(url, target); - } - }, } }; \ No newline at end of file diff --git a/webapp/src/main/webapp/vue-apps/top-bar-menu/components/NavigationMenuSubItem.vue b/webapp/src/main/webapp/vue-apps/top-bar-menu/components/NavigationMenuSubItem.vue index 598c91eda69..1086a2ab1d8 100644 --- a/webapp/src/main/webapp/vue-apps/top-bar-menu/components/NavigationMenuSubItem.vue +++ b/webapp/src/main/webapp/vue-apps/top-bar-menu/components/NavigationMenuSubItem.vue @@ -29,7 +29,7 @@ :target="navigationNodeTarget" :link="!!hasPage" class="pt-0 pb-0" - @click.stop="checkLink(navigation, $event)"> + @click="checkLink"> @@ -69,11 +70,6 @@ \ No newline at end of file diff --git a/webapp/src/main/webapp/vue-apps/top-bar-menu/components/mobile/NavigationMobileMenuSubItem.vue b/webapp/src/main/webapp/vue-apps/top-bar-menu/components/mobile/NavigationMobileMenuSubItem.vue index c771f859298..d4ddcf1b710 100644 --- a/webapp/src/main/webapp/vue-apps/top-bar-menu/components/mobile/NavigationMobileMenuSubItem.vue +++ b/webapp/src/main/webapp/vue-apps/top-bar-menu/components/mobile/NavigationMobileMenuSubItem.vue @@ -43,29 +43,30 @@ class="mt-n3" dense> - - - - - - - - {{ $vuetify.rtl && 'fa-angle-left' || 'fa-angle-right' }} - - - - + @@ -74,12 +75,6 @@