diff --git a/client/client-app.js b/client/client-app.js index cdf27a804..048d3e82d 100644 --- a/client/client-app.js +++ b/client/client-app.js @@ -177,6 +177,68 @@ Vue.component('Welcome', () => import(/* webpackChunkName: "welcome" */ './compo Vue.component('NavFooter', () => import(/* webpackChunkName: "theme" */ './themes/' + siteConfig.theme + '/components/nav-footer.vue')) Vue.component('Page', () => import(/* webpackChunkName: "theme" */ './themes/' + siteConfig.theme + '/components/page.vue')) +const normalizedBaseUrl = (siteConfig.baseUrl || '').replace(/\/+$/, '') + +const prefixUrlPath = (url) => { + if (!normalizedBaseUrl || typeof url !== 'string') { + return url + } + if (!url.startsWith('/') || url.startsWith('//')) { + return url + } + if (url === normalizedBaseUrl || url.startsWith(`${normalizedBaseUrl}/`)) { + return url + } + return `${normalizedBaseUrl}${url}` +} + +const applyBaseUrlToRenderedUrls = () => { + if (!normalizedBaseUrl) { + return + } + const attrs = ['href', 'src', 'action'] + const patchElement = (el) => { + if (!el || el.nodeType !== Node.ELEMENT_NODE) { + return + } + attrs.forEach((attr) => { + const value = el.getAttribute(attr) + if (!value) { + return + } + const patchedValue = prefixUrlPath(value) + if (patchedValue !== value) { + el.setAttribute(attr, patchedValue) + } + }) + } + const patchTree = (root) => { + patchElement(root) + if (root.querySelectorAll) { + root.querySelectorAll('[href],[src],[action]').forEach(patchElement) + } + } + + patchTree(document.documentElement) + + const observer = new MutationObserver((records) => { + records.forEach((record) => { + if (record.type === 'attributes') { + patchElement(record.target) + return + } + record.addedNodes.forEach(patchTree) + }) + }) + + observer.observe(document.documentElement, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: attrs + }) +} + let bootstrap = () => { // ==================================== // Notifications @@ -215,6 +277,7 @@ let bootstrap = () => { } }), mounted () { + applyBaseUrlToRenderedUrls() this.$moment.locale(siteConfig.lang) if ((store.get('user/dateFormat') || '').length > 0) { this.$moment.updateLocale(this.$moment.locale(), { diff --git a/client/components/login.vue b/client/components/login.vue index 0bbaa2a5e..e753ef87f 100644 --- a/client/components/login.vue +++ b/client/components/login.vue @@ -94,7 +94,7 @@ color='indigo darken-2' text rounded - href='/register' + :href='withBaseUrl(`/register`)' ): .caption {{ $t('auth:switchToRegister.link') }} //------------------------------------------------- //- FORGOT PASSWORD FORM @@ -185,7 +185,7 @@ v-dialog(v-model='isTFAShown', max-width='500', persistent) v-card .login-tfa.text-center.pa-5.grey--text.text--darken-3 - img(src='_assets/svg/icon-pin-pad.svg') + img(src= (baseUrl + '/_assets/svg/icon-pin-pad.svg')) .subtitle-2 {{$t('auth:tfaFormTitle')}} v-text-field.login-tfa-field.mt-2( solo @@ -260,6 +260,10 @@ import { sync } from 'vuex-pathify' export default { i18nOptions: { namespaces: 'auth' }, props: { + baseUrl: { + type: String, + default: '' + }, bgUrl: { type: String, default: '' @@ -333,7 +337,7 @@ export default { this.screen = 'login' if (!this.selectedStrategy.strategy.useForm) { this.isLoading = true - window.location.assign('/login/' + newValue) + window.location.assign(this.withBaseUrl('/login/' + newValue)) } else { this.$nextTick(() => { this.$refs.iptEmail.focus() @@ -349,6 +353,12 @@ export default { } }, methods: { + withBaseUrl (path) { + if (!this.baseUrl) { + return path + } + return `${this.baseUrl}${path}` + }, /** * LOGIN */ diff --git a/client/components/not-found.vue b/client/components/not-found.vue index 5a23892a2..e989cae96 100644 --- a/client/components/not-found.vue +++ b/client/components/not-found.vue @@ -2,10 +2,10 @@ v-app .notfound .notfound-content - img.animated.fadeIn(src='/_assets/svg/icon-delete-file.svg', alt='Not Found') + img.animated.fadeIn(:src='withBaseUrl(`/_assets/svg/icon-delete-file.svg`)', alt='Not Found') .headline {{$t('notfound.title')}} .subheading.mt-3 {{$t('notfound.subtitle')}} - v-btn.mt-5(color='red lighten-4', href='/', large, outlined) + v-btn.mt-5(color='red lighten-4', :href='withBaseUrl(`/`)', large, outlined) v-icon(left) mdi-home span {{$t('notfound.gohome')}} @@ -13,6 +13,20 @@