diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue index fae4246335..4fbdc51d22 100644 --- a/packages/frontend/src/components/MkPageWindow.vue +++ b/packages/frontend/src/components/MkPageWindow.vue @@ -59,7 +59,7 @@ const windowRouter = createRouter(props.initialPath); const pageMetadata = ref(null); const windowEl = shallowRef>(); const history = ref<{ path: string; }[]>([{ - path: windowRouter.getCurrentPath(), + path: windowRouter.getCurrentFullPath(), }]); const buttonsLeft = computed(() => { const buttons: Record[] = []; @@ -97,20 +97,20 @@ function getSearchMarker(path: string) { const searchMarkerId = ref(getSearchMarker(props.initialPath)); windowRouter.addListener('push', ctx => { - history.value.push({ path: ctx.path }); + history.value.push({ path: ctx.fullPath }); }); windowRouter.addListener('replace', ctx => { history.value.pop(); - history.value.push({ path: ctx.path }); + history.value.push({ path: ctx.fullPath }); }); windowRouter.addListener('change', ctx => { - if (_DEV_) console.log('windowRouter: change', ctx.path); - searchMarkerId.value = getSearchMarker(ctx.path); + if (_DEV_) console.log('windowRouter: change', ctx.fullPath); + searchMarkerId.value = getSearchMarker(ctx.fullPath); analytics.page({ - path: ctx.path, - title: ctx.path, + path: ctx.fullPath, + title: ctx.fullPath, }); }); @@ -139,14 +139,14 @@ const contextmenu = computed(() => ([{ icon: 'ti ti-external-link', text: i18n.ts.openInNewTab, action: () => { - window.open(url + windowRouter.getCurrentPath(), '_blank', 'noopener'); + window.open(url + windowRouter.getCurrentFullPath(), '_blank', 'noopener'); windowEl.value?.close(); }, }, { icon: 'ti ti-link', text: i18n.ts.copyLink, action: () => { - copyToClipboard(url + windowRouter.getCurrentPath()); + copyToClipboard(url + windowRouter.getCurrentFullPath()); }, }])); @@ -164,12 +164,12 @@ function close() { } function expand() { - mainRouter.push(windowRouter.getCurrentPath(), 'forcePage'); + mainRouter.push(windowRouter.getCurrentFullPath(), 'forcePage'); windowEl.value?.close(); } function popout() { - _popout(windowRouter.getCurrentPath(), windowEl.value?.$el); + _popout(windowRouter.getCurrentFullPath(), windowEl.value?.$el); windowEl.value?.close(); } diff --git a/packages/frontend/src/components/global/NestedRouterView.vue b/packages/frontend/src/components/global/NestedRouterView.vue index 5b22d0b7a8..af00347db8 100644 --- a/packages/frontend/src/components/global/NestedRouterView.vue +++ b/packages/frontend/src/components/global/NestedRouterView.vue @@ -14,8 +14,9 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/global/RouterView.vue b/packages/frontend/src/components/global/RouterView.vue index 720034a942..fbdb7d261e 100644 --- a/packages/frontend/src/components/global/RouterView.vue +++ b/packages/frontend/src/components/global/RouterView.vue @@ -5,10 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/global/StackingRouterView.vue b/packages/frontend/src/components/global/StackingRouterView.vue index b94e020072..c95c74aef3 100644 --- a/packages/frontend/src/components/global/StackingRouterView.vue +++ b/packages/frontend/src/components/global/StackingRouterView.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only :duration="200" tag="div" :class="$style.tabs" > -
+
@@ -41,10 +41,9 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/events.ts b/packages/frontend/src/events.ts index a74018223c..dfd3d4120c 100644 --- a/packages/frontend/src/events.ts +++ b/packages/frontend/src/events.ts @@ -10,5 +10,4 @@ export const globalEvents = new EventEmitter<{ themeChanging: () => void; themeChanged: () => void; clientNotification: (notification: Misskey.entities.Notification) => void; - requestClearPageCache: () => void; }>(); diff --git a/packages/frontend/src/lib/nirax.ts b/packages/frontend/src/lib/nirax.ts index cc20d497e6..8783874bc2 100644 --- a/packages/frontend/src/lib/nirax.ts +++ b/packages/frontend/src/lib/nirax.ts @@ -5,7 +5,7 @@ // NIRAX --- A lightweight router -import { onMounted, shallowRef } from 'vue'; +import { onBeforeUnmount, onMounted, shallowRef } from 'vue'; import { EventEmitter } from 'eventemitter3'; import type { Component, ShallowRef } from 'vue'; @@ -45,28 +45,28 @@ type ParsedPath = (string | { optional?: boolean; })[]; -export type RouterEvent = { +export type RouterEvents = { change: (ctx: { - beforePath: string; - path: string; - resolved: Resolved; + beforeFullPath: string; + fullPath: string; + resolved: PathResolvedResult; }) => void; replace: (ctx: { - path: string; + fullPath: string; }) => void; push: (ctx: { - beforePath: string; - path: string; + beforeFullPath: string; + fullPath: string; route: RouteDef | null; props: Map | null; }) => void; same: () => void; }; -export type Resolved = { +export type PathResolvedResult = { route: RouteDef; props: Map; - child?: Resolved; + child?: PathResolvedResult; redirected?: boolean; /** @internal */ @@ -102,39 +102,39 @@ function parsePath(path: string): ParsedPath { return res; } -export class Nirax extends EventEmitter { +export class Nirax extends EventEmitter { private routes: DEF; - public current: Resolved; - public currentRef: ShallowRef; + public current: PathResolvedResult; + public currentRef: ShallowRef; public currentRoute: ShallowRef; - private currentPath: string; + private currentFullPath: string; // /foo/bar?baz=qux#hash private isLoggedIn: boolean; private notFoundPageComponent: Component; private redirectCount = 0; - public navHook: ((path: string, flag?: RouterFlag) => boolean) | null = null; + public navHook: ((fullPath: string, flag?: RouterFlag) => boolean) | null = null; - constructor(routes: DEF, currentPath: Nirax['currentPath'], isLoggedIn: boolean, notFoundPageComponent: Component) { + constructor(routes: DEF, currentFullPath: Nirax['currentFullPath'], isLoggedIn: boolean, notFoundPageComponent: Component) { super(); this.routes = routes; - this.current = this.resolve(currentPath)!; + this.current = this.resolve(currentFullPath)!; this.currentRef = shallowRef(this.current); this.currentRoute = shallowRef(this.current.route); - this.currentPath = currentPath; + this.currentFullPath = currentFullPath; this.isLoggedIn = isLoggedIn; this.notFoundPageComponent = notFoundPageComponent; } public init() { - const res = this.navigate(this.currentPath, false); + const res = this.navigate(this.currentFullPath, false); this.emit('replace', { - path: res._parsedRoute.fullPath, + fullPath: res._parsedRoute.fullPath, }); } - public resolve(path: string): Resolved | null { - const fullPath = path; + public resolve(fullPath: string): PathResolvedResult | null { + let path = fullPath; let queryString: string | null = null; let hash: string | null = null; if (path[0] === '/') path = path.substring(1); @@ -153,7 +153,7 @@ export class Nirax extends EventEmitter { hash, }; - function check(routes: RouteDef[], _parts: string[]): Resolved | null { + function check(routes: RouteDef[], _parts: string[]): PathResolvedResult | null { forEachRouteLoop: for (const route of routes) { let parts = [..._parts]; @@ -256,14 +256,14 @@ export class Nirax extends EventEmitter { return check(this.routes, _parts); } - private navigate(path: string, emitChange = true, _redirected = false): Resolved { - const beforePath = this.currentPath; - this.currentPath = path; + private navigate(fullPath: string, emitChange = true, _redirected = false): PathResolvedResult { + const beforeFullPath = this.currentFullPath; + this.currentFullPath = fullPath; - const res = this.resolve(this.currentPath); + const res = this.resolve(this.currentFullPath); if (res == null) { - throw new Error('no route found for: ' + path); + throw new Error('no route found for: ' + fullPath); } if ('redirect' in res.route) { @@ -291,8 +291,8 @@ export class Nirax extends EventEmitter { if (emitChange && res.route.path !== '/:(*)') { this.emit('change', { - beforePath, - path, + beforeFullPath, + fullPath, resolved: res, }); } @@ -304,37 +304,45 @@ export class Nirax extends EventEmitter { }; } - public getCurrentPath() { - return this.currentPath; + public getCurrentFullPath() { + return this.currentFullPath; } - public push(path: string, flag?: RouterFlag) { - const beforePath = this.currentPath; - if (path === beforePath) { + public push(fullPath: string, flag?: RouterFlag) { + const beforeFullPath = this.currentFullPath; + if (fullPath === beforeFullPath) { this.emit('same'); return; } if (this.navHook) { - const cancel = this.navHook(path, flag); + const cancel = this.navHook(fullPath, flag); if (cancel) return; } - const res = this.navigate(path); + const res = this.navigate(fullPath); if (res.route.path === '/:(*)') { - location.href = path; + location.href = fullPath; } else { this.emit('push', { - beforePath, - path: res._parsedRoute.fullPath, + beforeFullPath, + fullPath: res._parsedRoute.fullPath, route: res.route, props: res.props, }); } } - public replace(path: string) { - const res = this.navigate(path); + public replace(fullPath: string) { + const res = this.navigate(fullPath); this.emit('replace', { - path: res._parsedRoute.fullPath, + fullPath: res._parsedRoute.fullPath, + }); + } + + public useListener(event: E, listener: L) { + this.addListener(event, listener); + + onBeforeUnmount(() => { + this.removeListener(event, listener); }); } } diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index e9b1ee8101..30b7cf9a86 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -169,7 +169,6 @@ import { langmap } from '@/utility/langmap.js'; import { definePage } from '@/page.js'; import { claimAchievement } from '@/utility/achievements.js'; import { store } from '@/store.js'; -import { globalEvents } from '@/events.js'; import MkInfo from '@/components/MkInfo.vue'; import MkTextarea from '@/components/MkTextarea.vue'; @@ -223,7 +222,6 @@ function saveFields() { os.apiWithDialog('i/update', { fields: fields.value.filter(field => field.name !== '' && field.value !== '').map(field => ({ name: field.name, value: field.value })), }); - globalEvents.emit('requestClearPageCache'); } function save() { @@ -249,7 +247,6 @@ function save() { text: i18n.ts.yourNameContainsProhibitedWordsDescription, }, }); - globalEvents.emit('requestClearPageCache'); claimAchievement('profileFilled'); if (profile.name === 'syuilo' || profile.name === 'しゅいろ') { claimAchievement('setNameToSyuilo'); @@ -281,7 +278,6 @@ function changeAvatar(ev) { }); $i.avatarId = i.avatarId; $i.avatarUrl = i.avatarUrl; - globalEvents.emit('requestClearPageCache'); claimAchievement('profileFilled'); }); } @@ -308,7 +304,6 @@ function changeBanner(ev) { }); $i.bannerId = i.bannerId; $i.bannerUrl = i.bannerUrl; - globalEvents.emit('requestClearPageCache'); }); } diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index b5f59b30c1..dd70571d64 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -13,8 +13,8 @@ import { DI } from '@/di.js'; export type Router = Nirax; -export function createRouter(path: string): Router { - return new Nirax(ROUTE_DEF, path, !!$i, page(() => import('@/pages/not-found.vue'))); +export function createRouter(fullPath: string): Router { + return new Nirax(ROUTE_DEF, fullPath, !!$i, page(() => import('@/pages/not-found.vue'))); } export const mainRouter = createRouter(location.pathname + location.search + location.hash); @@ -24,23 +24,23 @@ window.addEventListener('popstate', (event) => { }); mainRouter.addListener('push', ctx => { - window.history.pushState({ }, '', ctx.path); + window.history.pushState({ }, '', ctx.fullPath); }); mainRouter.addListener('replace', ctx => { - window.history.replaceState({ }, '', ctx.path); + window.history.replaceState({ }, '', ctx.fullPath); }); mainRouter.addListener('change', ctx => { - console.log('mainRouter: change', ctx.path); + console.log('mainRouter: change', ctx.fullPath); analytics.page({ - path: ctx.path, - title: ctx.path, + path: ctx.fullPath, + title: ctx.fullPath, }); }); mainRouter.init(); export function useRouter(): Router { - return inject(DI.router, null) ?? mainRouter; + return inject(DI.router) ?? mainRouter; } diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue index fa63586ef7..2ef06726f9 100644 --- a/packages/frontend/src/ui/classic.vue +++ b/packages/frontend/src/ui/classic.vue @@ -112,7 +112,7 @@ function onContextmenu(ev: MouseEvent) { if (isLink(ev.target)) return; if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(ev.target.tagName) || ev.target.attributes['contenteditable']) return; if (window.getSelection().toString() !== '') return; - const path = mainRouter.getCurrentPath(); + const path = mainRouter.getCurrentFullPath(); os.contextMenu([{ type: 'label', text: path, diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index a6695de39d..133360972b 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -186,7 +186,7 @@ const onContextmenu = (ev) => { if (isLink(ev.target)) return; if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(ev.target.tagName) || ev.target.attributes['contenteditable']) return; if (window.getSelection()?.toString() !== '') return; - const path = mainRouter.getCurrentPath(); + const path = mainRouter.getCurrentFullPath(); os.contextMenu([{ type: 'label', text: path,