2022-08-02 09:58:03 +00:00
|
|
|
import { getCurrentInstance, inject } from 'vue'
|
2022-08-24 16:04:56 +00:00
|
|
|
import type { Router, RouteLocationNormalizedLoaded, NavigationGuard, RouteLocationNormalized, RouteLocationRaw, NavigationFailure, RouteLocationPathRaw } from 'vue-router'
|
2022-03-16 21:39:47 +00:00
|
|
|
import { sendRedirect } from 'h3'
|
2022-08-24 16:04:56 +00:00
|
|
|
import { hasProtocol, joinURL, parseURL } from 'ufo'
|
2022-08-31 08:02:48 +00:00
|
|
|
import { useNuxtApp, useRuntimeConfig, useState } from '#app'
|
2022-02-21 13:03:42 +00:00
|
|
|
|
|
|
|
export const useRouter = () => {
|
|
|
|
return useNuxtApp()?.$router as Router
|
|
|
|
}
|
|
|
|
|
2022-08-07 04:57:11 +00:00
|
|
|
export const useRoute = (): RouteLocationNormalizedLoaded => {
|
2022-08-02 09:58:03 +00:00
|
|
|
if (getCurrentInstance()) {
|
2022-08-07 04:57:11 +00:00
|
|
|
return inject('_route', useNuxtApp()._route)
|
2022-08-02 09:58:03 +00:00
|
|
|
}
|
|
|
|
return useNuxtApp()._route
|
2022-02-21 13:03:42 +00:00
|
|
|
}
|
|
|
|
|
2022-08-02 09:58:03 +00:00
|
|
|
/** @deprecated Use `useRoute` instead. */
|
2022-08-07 04:57:11 +00:00
|
|
|
export const useActiveRoute = (): RouteLocationNormalizedLoaded => {
|
|
|
|
return useNuxtApp()._route
|
2022-04-06 12:45:18 +00:00
|
|
|
}
|
|
|
|
|
2022-02-21 13:03:42 +00:00
|
|
|
export interface RouteMiddleware {
|
|
|
|
(to: RouteLocationNormalized, from: RouteLocationNormalized): ReturnType<NavigationGuard>
|
|
|
|
}
|
|
|
|
|
|
|
|
export const defineNuxtRouteMiddleware = (middleware: RouteMiddleware) => middleware
|
|
|
|
|
|
|
|
export interface AddRouteMiddlewareOptions {
|
|
|
|
global?: boolean
|
|
|
|
}
|
|
|
|
|
|
|
|
interface AddRouteMiddleware {
|
|
|
|
(name: string, middleware: RouteMiddleware, options?: AddRouteMiddlewareOptions): void
|
|
|
|
(middleware: RouteMiddleware): void
|
|
|
|
}
|
|
|
|
|
|
|
|
export const addRouteMiddleware: AddRouteMiddleware = (name: string | RouteMiddleware, middleware?: RouteMiddleware, options: AddRouteMiddlewareOptions = {}) => {
|
|
|
|
const nuxtApp = useNuxtApp()
|
|
|
|
if (options.global || typeof name === 'function') {
|
|
|
|
nuxtApp._middleware.global.push(typeof name === 'function' ? name : middleware)
|
|
|
|
} else {
|
|
|
|
nuxtApp._middleware.named[name] = middleware
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const isProcessingMiddleware = () => {
|
|
|
|
try {
|
|
|
|
if (useNuxtApp()._processingMiddleware) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
} catch {
|
|
|
|
// Within an async middleware
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-03-16 21:39:47 +00:00
|
|
|
export interface NavigateToOptions {
|
|
|
|
replace?: boolean
|
2022-08-24 16:04:56 +00:00
|
|
|
redirectCode?: number,
|
|
|
|
external?: boolean
|
2022-03-16 21:39:47 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 12:30:03 +00:00
|
|
|
export const navigateTo = (to: RouteLocationRaw | undefined | null, options?: NavigateToOptions): Promise<void | NavigationFailure> | RouteLocationRaw => {
|
2022-05-05 20:46:54 +00:00
|
|
|
if (!to) {
|
|
|
|
to = '/'
|
|
|
|
}
|
2022-08-24 16:04:56 +00:00
|
|
|
|
|
|
|
const toPath = typeof to === 'string' ? to : ((to as RouteLocationPathRaw).path || '/')
|
|
|
|
const isExternal = hasProtocol(toPath, true)
|
2022-09-03 12:30:03 +00:00
|
|
|
if (isExternal && !options?.external) {
|
2022-08-24 16:04:56 +00:00
|
|
|
throw new Error('Navigating to external URL is not allowed by default. Use `nagivateTo (url, { external: true })`.')
|
|
|
|
}
|
|
|
|
if (isExternal && parseURL(toPath).protocol === 'script:') {
|
|
|
|
throw new Error('Cannot navigate to an URL with script protocol.')
|
|
|
|
}
|
|
|
|
|
|
|
|
// Early redirect on client-side
|
|
|
|
if (!isExternal && isProcessingMiddleware()) {
|
2022-02-21 13:03:42 +00:00
|
|
|
return to
|
|
|
|
}
|
2022-08-24 16:04:56 +00:00
|
|
|
|
2022-03-16 21:39:47 +00:00
|
|
|
const router = useRouter()
|
2022-08-24 16:04:56 +00:00
|
|
|
|
2022-04-19 19:13:11 +00:00
|
|
|
if (process.server) {
|
|
|
|
const nuxtApp = useNuxtApp()
|
|
|
|
if (nuxtApp.ssrContext && nuxtApp.ssrContext.event) {
|
2022-08-24 16:04:56 +00:00
|
|
|
const redirectLocation = isExternal ? toPath : joinURL(useRuntimeConfig().app.baseURL, router.resolve(to).fullPath || '/')
|
2022-09-03 12:30:03 +00:00
|
|
|
return nuxtApp.callHook('app:redirected').then(() => sendRedirect(nuxtApp.ssrContext!.event, redirectLocation, options?.redirectCode || 302))
|
2022-04-07 11:28:04 +00:00
|
|
|
}
|
2022-03-16 21:39:47 +00:00
|
|
|
}
|
2022-08-24 16:04:56 +00:00
|
|
|
|
2022-03-16 21:39:47 +00:00
|
|
|
// Client-side redirection using vue-router
|
2022-08-24 16:04:56 +00:00
|
|
|
if (isExternal) {
|
2022-09-03 12:30:03 +00:00
|
|
|
if (options?.replace) {
|
2022-08-24 16:04:56 +00:00
|
|
|
location.replace(toPath)
|
|
|
|
} else {
|
|
|
|
location.href = toPath
|
|
|
|
}
|
|
|
|
return Promise.resolve()
|
|
|
|
}
|
|
|
|
|
2022-09-03 12:30:03 +00:00
|
|
|
return options?.replace ? router.replace(to) : router.push(to)
|
2022-02-21 13:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** This will abort navigation within a Nuxt route middleware handler. */
|
|
|
|
export const abortNavigation = (err?: Error | string) => {
|
|
|
|
if (process.dev && !isProcessingMiddleware()) {
|
|
|
|
throw new Error('abortNavigation() is only usable inside a route middleware handler.')
|
|
|
|
}
|
|
|
|
if (err) {
|
|
|
|
throw err instanceof Error ? err : new Error(err)
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2022-08-31 08:02:48 +00:00
|
|
|
|
|
|
|
export const setPageLayout = (layout: string) => {
|
|
|
|
if (process.server) {
|
|
|
|
useState('_layout').value = layout
|
|
|
|
}
|
|
|
|
const nuxtApp = useNuxtApp()
|
|
|
|
const inMiddleware = isProcessingMiddleware()
|
|
|
|
if (inMiddleware || process.server || nuxtApp.isHydrating) {
|
|
|
|
const unsubscribe = useRouter().beforeResolve((to) => {
|
|
|
|
to.meta.layout = layout
|
|
|
|
unsubscribe()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if (!inMiddleware) {
|
|
|
|
useRoute().meta.layout = layout
|
|
|
|
}
|
|
|
|
}
|