refactor(frontend): router refactoring
This commit is contained in:
parent
7d4045e8b4
commit
409cd4fbd3
|
@ -273,7 +273,6 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド
|
||||||
query?: Record<string, string>;
|
query?: Record<string, string>;
|
||||||
loginRequired?: boolean;
|
loginRequired?: boolean;
|
||||||
hash?: string;
|
hash?: string;
|
||||||
globalCacheKey?: string;
|
|
||||||
children?: RouteDef[];
|
children?: RouteDef[];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -26,8 +26,6 @@ import { deckStore } from '@/ui/deck/deck-store.js';
|
||||||
import { analytics, initAnalytics } from '@/analytics.js';
|
import { analytics, initAnalytics } from '@/analytics.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
||||||
import { setupRouter } from '@/router/main.js';
|
|
||||||
import { createMainRouter } from '@/router/definition.js';
|
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
|
|
||||||
|
@ -267,8 +265,6 @@ export async function common(createVue: () => App<Element>) {
|
||||||
|
|
||||||
const app = createVue();
|
const app = createVue();
|
||||||
|
|
||||||
setupRouter(app, createMainRouter);
|
|
||||||
|
|
||||||
if (_DEV_) {
|
if (_DEV_) {
|
||||||
app.config.performance = true;
|
app.config.performance = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { claimAchievement, claimedAchievements } from '@/utility/achievements.js';
|
import { claimAchievement, claimedAchievements } from '@/utility/achievements.js';
|
||||||
import { initializeSw } from '@/utility/initialize-sw.js';
|
import { initializeSw } from '@/utility/initialize-sw.js';
|
||||||
import { emojiPicker } from '@/utility/emoji-picker.js';
|
import { emojiPicker } from '@/utility/emoji-picker.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { makeHotkey } from '@/utility/hotkey.js';
|
import { makeHotkey } from '@/utility/hotkey.js';
|
||||||
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
|
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
|
@ -88,9 +88,9 @@ import { i18n } from '@/i18n.js';
|
||||||
import { dateString } from '@/filters/date.js';
|
import { dateString } from '@/filters/date.js';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import RouterView from '@/components/global/RouterView.vue';
|
import RouterView from '@/components/global/RouterView.vue';
|
||||||
import { useRouterFactory } from '@/router/supplier';
|
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||||
|
import { createRouter } from '@/router.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
report: Misskey.entities.AdminAbuseUserReportsResponse[number];
|
report: Misskey.entities.AdminAbuseUserReportsResponse[number];
|
||||||
|
@ -100,10 +100,9 @@ const emit = defineEmits<{
|
||||||
(ev: 'resolved', reportId: string): void;
|
(ev: 'resolved', reportId: string): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const routerFactory = useRouterFactory();
|
const targetRouter = createRouter(`/admin/user/${props.report.targetUserId}`);
|
||||||
const targetRouter = routerFactory(`/admin/user/${props.report.targetUserId}`);
|
|
||||||
targetRouter.init();
|
targetRouter.init();
|
||||||
const reporterRouter = routerFactory(`/admin/user/${props.report.reporterId}`);
|
const reporterRouter = createRouter(`/admin/user/${props.report.reporterId}`);
|
||||||
reporterRouter.init();
|
reporterRouter.init();
|
||||||
|
|
||||||
const moderationNote = ref(props.report.moderationNote ?? '');
|
const moderationNote = ref(props.report.moderationNote ?? '');
|
||||||
|
|
|
@ -47,7 +47,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { getDriveFileMenu } from '@/utility/get-drive-file-menu.js';
|
import { getDriveFileMenu } from '@/utility/get-drive-file-menu.js';
|
||||||
import { deviceKind } from '@/utility/device-kind.js';
|
import { deviceKind } from '@/utility/device-kind.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||||
import { openingWindowsCount } from '@/os.js';
|
import { openingWindowsCount } from '@/os.js';
|
||||||
import { claimAchievement } from '@/utility/achievements.js';
|
import { claimAchievement } from '@/utility/achievements.js';
|
||||||
import { useRouterFactory } from '@/router/supplier.js';
|
import { createRouter, mainRouter } from '@/router.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
|
||||||
import { analytics } from '@/analytics.js';
|
import { analytics } from '@/analytics.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
@ -55,8 +54,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const routerFactory = useRouterFactory();
|
const windowRouter = createRouter(props.initialPath);
|
||||||
const windowRouter = routerFactory(props.initialPath);
|
|
||||||
|
|
||||||
const pageMetadata = ref<null | PageMetadata>(null);
|
const pageMetadata = ref<null | PageMetadata>(null);
|
||||||
const windowEl = shallowRef<InstanceType<typeof MkWindow>>();
|
const windowEl = shallowRef<InstanceType<typeof MkWindow>>();
|
||||||
|
|
|
@ -98,7 +98,7 @@ import type { SearchIndexItem } from '@/utility/autogen/settings-search-index.js
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { getScrollContainer } from '@@/js/scroll.js';
|
import { getScrollContainer } from '@@/js/scroll.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
import { initIntlString, compareStringIncludes } from '@/utility/intl-string.js';
|
import { initIntlString, compareStringIncludes } from '@/utility/intl-string.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { url } from '@@/js/config.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
to: string;
|
to: string;
|
||||||
|
|
|
@ -0,0 +1,340 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
// NIRAX --- A lightweight router
|
||||||
|
|
||||||
|
import { onMounted, shallowRef } from 'vue';
|
||||||
|
import { EventEmitter } from 'eventemitter3';
|
||||||
|
import type { Component, ShallowRef } from 'vue';
|
||||||
|
|
||||||
|
function safeURIDecode(str: string): string {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(str);
|
||||||
|
} catch {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RouteDefBase {
|
||||||
|
path: string;
|
||||||
|
query?: Record<string, string>;
|
||||||
|
loginRequired?: boolean;
|
||||||
|
name?: string;
|
||||||
|
hash?: string;
|
||||||
|
children?: RouteDef[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RouteDefWithComponent extends RouteDefBase {
|
||||||
|
component: Component,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RouteDefWithRedirect extends RouteDefBase {
|
||||||
|
redirect: string | ((props: Map<string, string | boolean>) => string);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RouteDef = RouteDefWithComponent | RouteDefWithRedirect;
|
||||||
|
|
||||||
|
export type RouterFlag = 'forcePage';
|
||||||
|
|
||||||
|
type ParsedPath = (string | {
|
||||||
|
name: string;
|
||||||
|
startsWith?: string;
|
||||||
|
wildcard?: boolean;
|
||||||
|
optional?: boolean;
|
||||||
|
})[];
|
||||||
|
|
||||||
|
export type RouterEvent = {
|
||||||
|
change: (ctx: {
|
||||||
|
beforePath: string;
|
||||||
|
path: string;
|
||||||
|
resolved: Resolved;
|
||||||
|
}) => void;
|
||||||
|
replace: (ctx: {
|
||||||
|
path: string;
|
||||||
|
}) => void;
|
||||||
|
push: (ctx: {
|
||||||
|
beforePath: string;
|
||||||
|
path: string;
|
||||||
|
route: RouteDef | null;
|
||||||
|
props: Map<string, string> | null;
|
||||||
|
}) => void;
|
||||||
|
same: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Resolved = {
|
||||||
|
route: RouteDef;
|
||||||
|
props: Map<string, string | boolean>;
|
||||||
|
child?: Resolved;
|
||||||
|
redirected?: boolean;
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
_parsedRoute: {
|
||||||
|
fullPath: string;
|
||||||
|
queryString: string | null;
|
||||||
|
hash: string | null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function parsePath(path: string): ParsedPath {
|
||||||
|
const res = [] as ParsedPath;
|
||||||
|
|
||||||
|
path = path.substring(1);
|
||||||
|
|
||||||
|
for (const part of path.split('/')) {
|
||||||
|
if (part.includes(':')) {
|
||||||
|
const prefix = part.substring(0, part.indexOf(':'));
|
||||||
|
const placeholder = part.substring(part.indexOf(':') + 1);
|
||||||
|
const wildcard = placeholder.includes('(*)');
|
||||||
|
const optional = placeholder.endsWith('?');
|
||||||
|
res.push({
|
||||||
|
name: placeholder.replace('(*)', '').replace('?', ''),
|
||||||
|
startsWith: prefix !== '' ? prefix : undefined,
|
||||||
|
wildcard,
|
||||||
|
optional,
|
||||||
|
});
|
||||||
|
} else if (part.length !== 0) {
|
||||||
|
res.push(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Nirax<DEF extends RouteDef[]> extends EventEmitter<RouterEvent> {
|
||||||
|
private routes: DEF;
|
||||||
|
public current: Resolved;
|
||||||
|
public currentRef: ShallowRef<Resolved>;
|
||||||
|
public currentRoute: ShallowRef<RouteDef>;
|
||||||
|
private currentPath: string;
|
||||||
|
private isLoggedIn: boolean;
|
||||||
|
private notFoundPageComponent: Component;
|
||||||
|
private redirectCount = 0;
|
||||||
|
|
||||||
|
public navHook: ((path: string, flag?: RouterFlag) => boolean) | null = null;
|
||||||
|
|
||||||
|
constructor(routes: DEF, currentPath: Nirax<DEF>['currentPath'], isLoggedIn: boolean, notFoundPageComponent: Component) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.routes = routes;
|
||||||
|
this.current = this.resolve(currentPath)!;
|
||||||
|
this.currentRef = shallowRef(this.current);
|
||||||
|
this.currentRoute = shallowRef(this.current.route);
|
||||||
|
this.currentPath = currentPath;
|
||||||
|
this.isLoggedIn = isLoggedIn;
|
||||||
|
this.notFoundPageComponent = notFoundPageComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
const res = this.navigate(this.currentPath, false);
|
||||||
|
this.emit('replace', {
|
||||||
|
path: res._parsedRoute.fullPath,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public resolve(path: string): Resolved | null {
|
||||||
|
const fullPath = path;
|
||||||
|
let queryString: string | null = null;
|
||||||
|
let hash: string | null = null;
|
||||||
|
if (path[0] === '/') path = path.substring(1);
|
||||||
|
if (path.includes('#')) {
|
||||||
|
hash = path.substring(path.indexOf('#') + 1);
|
||||||
|
path = path.substring(0, path.indexOf('#'));
|
||||||
|
}
|
||||||
|
if (path.includes('?')) {
|
||||||
|
queryString = path.substring(path.indexOf('?') + 1);
|
||||||
|
path = path.substring(0, path.indexOf('?'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const _parsedRoute = {
|
||||||
|
fullPath,
|
||||||
|
queryString,
|
||||||
|
hash,
|
||||||
|
};
|
||||||
|
|
||||||
|
function check(routes: RouteDef[], _parts: string[]): Resolved | null {
|
||||||
|
forEachRouteLoop:
|
||||||
|
for (const route of routes) {
|
||||||
|
let parts = [..._parts];
|
||||||
|
const props = new Map<string, string>();
|
||||||
|
|
||||||
|
pathMatchLoop:
|
||||||
|
for (const p of parsePath(route.path)) {
|
||||||
|
if (typeof p === 'string') {
|
||||||
|
if (p === parts[0]) {
|
||||||
|
parts.shift();
|
||||||
|
} else {
|
||||||
|
continue forEachRouteLoop;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (parts[0] == null && !p.optional) {
|
||||||
|
continue forEachRouteLoop;
|
||||||
|
}
|
||||||
|
if (p.wildcard) {
|
||||||
|
if (parts.length !== 0) {
|
||||||
|
props.set(p.name, safeURIDecode(parts.join('/')));
|
||||||
|
parts = [];
|
||||||
|
}
|
||||||
|
break pathMatchLoop;
|
||||||
|
} else {
|
||||||
|
if (p.startsWith) {
|
||||||
|
if (parts[0] == null || !parts[0].startsWith(p.startsWith)) continue forEachRouteLoop;
|
||||||
|
|
||||||
|
props.set(p.name, safeURIDecode(parts[0].substring(p.startsWith.length)));
|
||||||
|
parts.shift();
|
||||||
|
} else {
|
||||||
|
if (parts[0]) {
|
||||||
|
props.set(p.name, safeURIDecode(parts[0]));
|
||||||
|
}
|
||||||
|
parts.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.length === 0) {
|
||||||
|
if (route.children) {
|
||||||
|
const child = check(route.children, []);
|
||||||
|
if (child) {
|
||||||
|
return {
|
||||||
|
route,
|
||||||
|
props,
|
||||||
|
child,
|
||||||
|
_parsedRoute,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
continue forEachRouteLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route.hash != null && hash != null) {
|
||||||
|
props.set(route.hash, safeURIDecode(hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route.query != null && queryString != null) {
|
||||||
|
const queryObject = [...new URLSearchParams(queryString).entries()]
|
||||||
|
.reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1] }), {});
|
||||||
|
|
||||||
|
for (const q in route.query) {
|
||||||
|
const as = route.query[q];
|
||||||
|
if (queryObject[q]) {
|
||||||
|
props.set(as, safeURIDecode(queryObject[q]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
route,
|
||||||
|
props,
|
||||||
|
_parsedRoute,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
if (route.children) {
|
||||||
|
const child = check(route.children, parts);
|
||||||
|
if (child) {
|
||||||
|
return {
|
||||||
|
route,
|
||||||
|
props,
|
||||||
|
child,
|
||||||
|
_parsedRoute,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
continue forEachRouteLoop;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue forEachRouteLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _parts = path.split('/').filter(part => part.length !== 0);
|
||||||
|
|
||||||
|
return check(this.routes, _parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private navigate(path: string, emitChange = true, _redirected = false): Resolved {
|
||||||
|
const beforePath = this.currentPath;
|
||||||
|
this.currentPath = path;
|
||||||
|
|
||||||
|
const res = this.resolve(this.currentPath);
|
||||||
|
|
||||||
|
if (res == null) {
|
||||||
|
throw new Error('no route found for: ' + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('redirect' in res.route) {
|
||||||
|
let redirectPath: string;
|
||||||
|
if (typeof res.route.redirect === 'function') {
|
||||||
|
redirectPath = res.route.redirect(res.props);
|
||||||
|
} else {
|
||||||
|
redirectPath = res.route.redirect + (res._parsedRoute.queryString ? '?' + res._parsedRoute.queryString : '') + (res._parsedRoute.hash ? '#' + res._parsedRoute.hash : '');
|
||||||
|
}
|
||||||
|
if (_DEV_) console.log('Redirecting to: ', redirectPath);
|
||||||
|
if (_redirected && this.redirectCount++ > 10) {
|
||||||
|
throw new Error('redirect loop detected');
|
||||||
|
}
|
||||||
|
return this.navigate(redirectPath, emitChange, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.route.loginRequired && !this.isLoggedIn) {
|
||||||
|
res.route.component = this.notFoundPageComponent;
|
||||||
|
res.props.set('showLoginPopup', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.current = res;
|
||||||
|
this.currentRef.value = res;
|
||||||
|
this.currentRoute.value = res.route;
|
||||||
|
|
||||||
|
if (emitChange && res.route.path !== '/:(*)') {
|
||||||
|
this.emit('change', {
|
||||||
|
beforePath,
|
||||||
|
path,
|
||||||
|
resolved: res,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.redirectCount = 0;
|
||||||
|
return {
|
||||||
|
...res,
|
||||||
|
redirected: _redirected,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCurrentPath() {
|
||||||
|
return this.currentPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public push(path: string, flag?: RouterFlag) {
|
||||||
|
const beforePath = this.currentPath;
|
||||||
|
if (path === beforePath) {
|
||||||
|
this.emit('same');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.navHook) {
|
||||||
|
const cancel = this.navHook(path, flag);
|
||||||
|
if (cancel) return;
|
||||||
|
}
|
||||||
|
const res = this.navigate(path);
|
||||||
|
if (res.route.path === '/:(*)') {
|
||||||
|
location.href = path;
|
||||||
|
} else {
|
||||||
|
this.emit('push', {
|
||||||
|
beforePath,
|
||||||
|
path: res._parsedRoute.fullPath,
|
||||||
|
route: res.route,
|
||||||
|
props: res.props,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public replace(path: string) {
|
||||||
|
const res = this.navigate(path);
|
||||||
|
this.emit('replace', {
|
||||||
|
path: res._parsedRoute.fullPath,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { lookupUser, lookupUserByEmail, lookupFile } from '@/utility/admin-lookup.js';
|
import { lookupUser, lookupUserByEmail, lookupFile } from '@/utility/admin-lookup.js';
|
||||||
import { definePage, provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
import { definePage, provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const isEmpty = (x: string | null) => x == null || x === '';
|
const isEmpty = (x: string | null) => x == null || x === '';
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { rolesCache } from '@/cache.js';
|
import { rolesCache } from '@/cache.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { infoImageUrl } from '@/instance.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -295,7 +295,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { instance, fetchInstance } from '@/instance.js';
|
import { instance, fetchInstance } from '@/instance.js';
|
||||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const baseRoleQ = ref('');
|
const baseRoleQ = ref('');
|
||||||
|
|
|
@ -32,7 +32,7 @@ import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ import { isSupportShare } from '@/utility/navigator.js';
|
||||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||||
import { notesSearchAvailable } from '@/utility/check-permissions.js';
|
import { notesSearchAvailable } from '@/utility/check-permissions.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ import { infoImageUrl } from '@/instance.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import MkCodeEditor from '@/components/MkCodeEditor.vue';
|
import MkCodeEditor from '@/components/MkCodeEditor.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const PRESET_DEFAULT = `/// @ ${AISCRIPT_VERSION}
|
const PRESET_DEFAULT = `/// @ ${AISCRIPT_VERSION}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ import MkGalleryPostPreview from '@/components/MkGalleryPostPreview.vue';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ import { prefer } from '@/preferences.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { isSupportShare } from '@/utility/navigator.js';
|
import { isSupportShare } from '@/utility/navigator.js';
|
||||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
|
||||||
const state = ref<'fetching' | 'done'>('fetching');
|
const state = ref<'fetching' | 'done'>('fetching');
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { computed } from 'vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { antennasCache } from '@/cache.js';
|
import { antennasCache } from '@/cache.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
import MkAntennaEditor from '@/components/MkAntennaEditor.vue';
|
import MkAntennaEditor from '@/components/MkAntennaEditor.vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { antennasCache } from '@/cache.js';
|
import { antennasCache } from '@/cache.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ import MkInput from '@/components/MkInput.vue';
|
||||||
import { userListsCache } from '@/cache.js';
|
import { userListsCache } from '@/cache.js';
|
||||||
import { ensureSignin } from '@/i.js';
|
import { ensureSignin } from '@/i.js';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = ensureSignin();
|
||||||
|
|
|
@ -76,7 +76,7 @@ import { selectFile } from '@/utility/select-file.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { getPageBlockList } from '@/pages/page-editor/common.js';
|
import { getPageBlockList } from '@/pages/page-editor/common.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
|
@ -120,7 +120,7 @@ import { isSupportShare } from '@/utility/navigator.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { getStaticImageUrl } from '@/utility/media-proxy.js';
|
import { getStaticImageUrl } from '@/utility/media-proxy.js';
|
||||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { getPluginHandlers } from '@/plugin.js';
|
import { getPluginHandlers } from '@/plugin.js';
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
token?: string;
|
token?: string;
|
||||||
|
|
|
@ -122,7 +122,7 @@ import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = ensureSignin();
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import { ensureSignin } from '@/i.js';
|
import { ensureSignin } from '@/i.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { url } from '@@/js/config.js';
|
import { url } from '@@/js/config.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
|
@ -115,7 +115,7 @@ import MkFolder from '@/components/MkFolder.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { useInterval } from '@@/js/use-interval.js';
|
import { useInterval } from '@@/js/use-interval.js';
|
||||||
import { pleaseLogin } from '@/utility/please-login.js';
|
import { pleaseLogin } from '@/utility/please-login.js';
|
||||||
|
|
|
@ -121,7 +121,7 @@ import { instance } from '@/instance.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { apLookup } from '@/utility/lookup.js';
|
import { apLookup } from '@/utility/lookup.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
|
|
@ -37,7 +37,7 @@ import { instance } from '@/instance.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
query?: string,
|
query?: string,
|
||||||
|
|
|
@ -42,7 +42,7 @@ import { clearCache } from '@/utility/clear-cache.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { definePage, provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
import { definePage, provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
import { searchIndexes } from '@/utility/autogen/settings-search-index.js';
|
import { searchIndexes } from '@/utility/autogen/settings-search-index.js';
|
||||||
import { enableAutoBackup, getPreferencesProfileMenu } from '@/preferences/utility.js';
|
import { enableAutoBackup, getPreferencesProfileMenu } from '@/preferences/utility.js';
|
||||||
import { store } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
|
|
|
@ -26,7 +26,7 @@ import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { installPlugin } from '@/plugin.js';
|
import { installPlugin } from '@/plugin.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const code = ref<string | null>(null);
|
const code = ref<string | null>(null);
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { parseThemeCode, previewTheme, installTheme } from '@/theme.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const installThemeCode = ref<string | null>(null);
|
const installThemeCode = ref<string | null>(null);
|
||||||
|
|
|
@ -79,7 +79,7 @@ import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ import { scroll } from '@@/js/scroll.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,7 @@ import { dateString } from '@/filters/date.js';
|
||||||
import { confetti } from '@/utility/confetti.js';
|
import { confetti } from '@/utility/confetti.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/utility/isFfVisibleForMe.js';
|
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/utility/isFfVisibleForMe.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
import { getStaticImageUrl } from '@/utility/media-proxy.js';
|
import { getStaticImageUrl } from '@/utility/media-proxy.js';
|
||||||
import MkSparkle from '@/components/MkSparkle.vue';
|
import MkSparkle from '@/components/MkSparkle.vue';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
|
|
||||||
import { defineAsyncComponent } from 'vue';
|
import { defineAsyncComponent } from 'vue';
|
||||||
import type { AsyncComponentLoader } from 'vue';
|
import type { AsyncComponentLoader } from 'vue';
|
||||||
import type { RouteDef } from '@/router.js';
|
import type { RouteDef } from '@/lib/nirax.js';
|
||||||
import { Router } from '@/router.js';
|
|
||||||
import { $i, iAmModerator } from '@/i.js';
|
import { $i, iAmModerator } from '@/i.js';
|
||||||
import MkLoading from '@/pages/_loading_.vue';
|
import MkLoading from '@/pages/_loading_.vue';
|
||||||
import MkError from '@/pages/_error_.vue';
|
import MkError from '@/pages/_error_.vue';
|
||||||
|
@ -17,7 +16,7 @@ export const page = (loader: AsyncComponentLoader) => defineAsyncComponent({
|
||||||
errorComponent: MkError,
|
errorComponent: MkError,
|
||||||
});
|
});
|
||||||
|
|
||||||
const routes: RouteDef[] = [{
|
export const ROUTE_DEF = [{
|
||||||
path: '/@:username/pages/:pageName(*)',
|
path: '/@:username/pages/:pageName(*)',
|
||||||
component: page(() => import('@/pages/page.vue')),
|
component: page(() => import('@/pages/page.vue')),
|
||||||
}, {
|
}, {
|
||||||
|
@ -567,7 +566,6 @@ const routes: RouteDef[] = [{
|
||||||
name: 'index',
|
name: 'index',
|
||||||
path: '/',
|
path: '/',
|
||||||
component: $i ? page(() => import('@/pages/timeline.vue')) : page(() => import('@/pages/welcome.vue')),
|
component: $i ? page(() => import('@/pages/timeline.vue')) : page(() => import('@/pages/welcome.vue')),
|
||||||
globalCacheKey: 'index',
|
|
||||||
}, {
|
}, {
|
||||||
// テスト用リダイレクト設定。ログイン中ユーザのプロフィールにリダイレクトする
|
// テスト用リダイレクト設定。ログイン中ユーザのプロフィールにリダイレクトする
|
||||||
path: '/redirect-test',
|
path: '/redirect-test',
|
||||||
|
@ -576,8 +574,4 @@ const routes: RouteDef[] = [{
|
||||||
}, {
|
}, {
|
||||||
path: '/:(*)',
|
path: '/:(*)',
|
||||||
component: page(() => import('@/pages/not-found.vue')),
|
component: page(() => import('@/pages/not-found.vue')),
|
||||||
}];
|
}] satisfies RouteDef[];
|
||||||
|
|
||||||
export function createMainRouter(path: string): Router {
|
|
||||||
return new Router(routes, path, !!$i, page(() => import('@/pages/not-found.vue')));
|
|
||||||
}
|
|
|
@ -3,339 +3,44 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NIRAX --- A lightweight router
|
import { inject } from 'vue';
|
||||||
|
import { page } from '@/router.definition.js';
|
||||||
|
import { $i } from '@/i.js';
|
||||||
|
import { Nirax } from '@/lib/nirax.js';
|
||||||
|
import { ROUTE_DEF } from '@/router.definition.js';
|
||||||
|
import { analytics } from '@/analytics.js';
|
||||||
|
import { DI } from '@/di.js';
|
||||||
|
|
||||||
import { onMounted, shallowRef } from 'vue';
|
export type Router = Nirax<typeof ROUTE_DEF>;
|
||||||
import { EventEmitter } from 'eventemitter3';
|
|
||||||
import type { Component, ShallowRef } from 'vue';
|
|
||||||
|
|
||||||
function safeURIDecode(str: string): string {
|
export function createRouter(path: string): Router {
|
||||||
try {
|
return new Nirax(ROUTE_DEF, path, !!$i, page(() => import('@/pages/not-found.vue')));
|
||||||
return decodeURIComponent(str);
|
|
||||||
} catch {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RouteDefBase {
|
export const mainRouter = createRouter(location.pathname + location.search + location.hash);
|
||||||
path: string;
|
|
||||||
query?: Record<string, string>;
|
|
||||||
loginRequired?: boolean;
|
|
||||||
name?: string;
|
|
||||||
hash?: string;
|
|
||||||
globalCacheKey?: string;
|
|
||||||
children?: RouteDef[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RouteDefWithComponent extends RouteDefBase {
|
window.addEventListener('popstate', (event) => {
|
||||||
component: Component,
|
mainRouter.replace(location.pathname + location.search + location.hash);
|
||||||
}
|
});
|
||||||
|
|
||||||
interface RouteDefWithRedirect extends RouteDefBase {
|
mainRouter.addListener('push', ctx => {
|
||||||
redirect: string | ((props: Map<string, string | boolean>) => string);
|
window.history.pushState({ }, '', ctx.path);
|
||||||
}
|
});
|
||||||
|
|
||||||
export type RouteDef = RouteDefWithComponent | RouteDefWithRedirect;
|
mainRouter.addListener('replace', ctx => {
|
||||||
|
window.history.replaceState({ }, '', ctx.path);
|
||||||
|
});
|
||||||
|
|
||||||
export type RouterFlag = 'forcePage';
|
mainRouter.addListener('change', ctx => {
|
||||||
|
console.log('mainRouter: change', ctx.path);
|
||||||
type ParsedPath = (string | {
|
analytics.page({
|
||||||
name: string;
|
path: ctx.path,
|
||||||
startsWith?: string;
|
title: ctx.path,
|
||||||
wildcard?: boolean;
|
|
||||||
optional?: boolean;
|
|
||||||
})[];
|
|
||||||
|
|
||||||
export type RouterEvent = {
|
|
||||||
change: (ctx: {
|
|
||||||
beforePath: string;
|
|
||||||
path: string;
|
|
||||||
resolved: Resolved;
|
|
||||||
}) => void;
|
|
||||||
replace: (ctx: {
|
|
||||||
path: string;
|
|
||||||
}) => void;
|
|
||||||
push: (ctx: {
|
|
||||||
beforePath: string;
|
|
||||||
path: string;
|
|
||||||
route: RouteDef | null;
|
|
||||||
props: Map<string, string> | null;
|
|
||||||
}) => void;
|
|
||||||
same: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Resolved = {
|
|
||||||
route: RouteDef;
|
|
||||||
props: Map<string, string | boolean>;
|
|
||||||
child?: Resolved;
|
|
||||||
redirected?: boolean;
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
_parsedRoute: {
|
|
||||||
fullPath: string;
|
|
||||||
queryString: string | null;
|
|
||||||
hash: string | null;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function parsePath(path: string): ParsedPath {
|
|
||||||
const res = [] as ParsedPath;
|
|
||||||
|
|
||||||
path = path.substring(1);
|
|
||||||
|
|
||||||
for (const part of path.split('/')) {
|
|
||||||
if (part.includes(':')) {
|
|
||||||
const prefix = part.substring(0, part.indexOf(':'));
|
|
||||||
const placeholder = part.substring(part.indexOf(':') + 1);
|
|
||||||
const wildcard = placeholder.includes('(*)');
|
|
||||||
const optional = placeholder.endsWith('?');
|
|
||||||
res.push({
|
|
||||||
name: placeholder.replace('(*)', '').replace('?', ''),
|
|
||||||
startsWith: prefix !== '' ? prefix : undefined,
|
|
||||||
wildcard,
|
|
||||||
optional,
|
|
||||||
});
|
});
|
||||||
} else if (part.length !== 0) {
|
});
|
||||||
res.push(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
mainRouter.init();
|
||||||
}
|
|
||||||
|
export function useRouter(): Router {
|
||||||
export class Router extends EventEmitter<RouterEvent> {
|
return inject(DI.router, null) ?? mainRouter;
|
||||||
private routes: RouteDef[];
|
|
||||||
public current: Resolved;
|
|
||||||
public currentRef: ShallowRef<Resolved>;
|
|
||||||
public currentRoute: ShallowRef<RouteDef>;
|
|
||||||
private currentPath: string;
|
|
||||||
private isLoggedIn: boolean;
|
|
||||||
private notFoundPageComponent: Component;
|
|
||||||
private redirectCount = 0;
|
|
||||||
|
|
||||||
public navHook: ((path: string, flag?: RouterFlag) => boolean) | null = null;
|
|
||||||
|
|
||||||
constructor(routes: Router['routes'], currentPath: Router['currentPath'], isLoggedIn: boolean, notFoundPageComponent: Component) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.routes = routes;
|
|
||||||
this.current = this.resolve(currentPath)!;
|
|
||||||
this.currentRef = shallowRef(this.current);
|
|
||||||
this.currentRoute = shallowRef(this.current.route);
|
|
||||||
this.currentPath = currentPath;
|
|
||||||
this.isLoggedIn = isLoggedIn;
|
|
||||||
this.notFoundPageComponent = notFoundPageComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public init() {
|
|
||||||
const res = this.navigate(this.currentPath, false);
|
|
||||||
this.emit('replace', {
|
|
||||||
path: res._parsedRoute.fullPath,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public resolve(path: string): Resolved | null {
|
|
||||||
const fullPath = path;
|
|
||||||
let queryString: string | null = null;
|
|
||||||
let hash: string | null = null;
|
|
||||||
if (path[0] === '/') path = path.substring(1);
|
|
||||||
if (path.includes('#')) {
|
|
||||||
hash = path.substring(path.indexOf('#') + 1);
|
|
||||||
path = path.substring(0, path.indexOf('#'));
|
|
||||||
}
|
|
||||||
if (path.includes('?')) {
|
|
||||||
queryString = path.substring(path.indexOf('?') + 1);
|
|
||||||
path = path.substring(0, path.indexOf('?'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const _parsedRoute = {
|
|
||||||
fullPath,
|
|
||||||
queryString,
|
|
||||||
hash,
|
|
||||||
};
|
|
||||||
|
|
||||||
function check(routes: RouteDef[], _parts: string[]): Resolved | null {
|
|
||||||
forEachRouteLoop:
|
|
||||||
for (const route of routes) {
|
|
||||||
let parts = [..._parts];
|
|
||||||
const props = new Map<string, string>();
|
|
||||||
|
|
||||||
pathMatchLoop:
|
|
||||||
for (const p of parsePath(route.path)) {
|
|
||||||
if (typeof p === 'string') {
|
|
||||||
if (p === parts[0]) {
|
|
||||||
parts.shift();
|
|
||||||
} else {
|
|
||||||
continue forEachRouteLoop;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (parts[0] == null && !p.optional) {
|
|
||||||
continue forEachRouteLoop;
|
|
||||||
}
|
|
||||||
if (p.wildcard) {
|
|
||||||
if (parts.length !== 0) {
|
|
||||||
props.set(p.name, safeURIDecode(parts.join('/')));
|
|
||||||
parts = [];
|
|
||||||
}
|
|
||||||
break pathMatchLoop;
|
|
||||||
} else {
|
|
||||||
if (p.startsWith) {
|
|
||||||
if (parts[0] == null || !parts[0].startsWith(p.startsWith)) continue forEachRouteLoop;
|
|
||||||
|
|
||||||
props.set(p.name, safeURIDecode(parts[0].substring(p.startsWith.length)));
|
|
||||||
parts.shift();
|
|
||||||
} else {
|
|
||||||
if (parts[0]) {
|
|
||||||
props.set(p.name, safeURIDecode(parts[0]));
|
|
||||||
}
|
|
||||||
parts.shift();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parts.length === 0) {
|
|
||||||
if (route.children) {
|
|
||||||
const child = check(route.children, []);
|
|
||||||
if (child) {
|
|
||||||
return {
|
|
||||||
route,
|
|
||||||
props,
|
|
||||||
child,
|
|
||||||
_parsedRoute,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
continue forEachRouteLoop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route.hash != null && hash != null) {
|
|
||||||
props.set(route.hash, safeURIDecode(hash));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route.query != null && queryString != null) {
|
|
||||||
const queryObject = [...new URLSearchParams(queryString).entries()]
|
|
||||||
.reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1] }), {});
|
|
||||||
|
|
||||||
for (const q in route.query) {
|
|
||||||
const as = route.query[q];
|
|
||||||
if (queryObject[q]) {
|
|
||||||
props.set(as, safeURIDecode(queryObject[q]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
route,
|
|
||||||
props,
|
|
||||||
_parsedRoute,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
if (route.children) {
|
|
||||||
const child = check(route.children, parts);
|
|
||||||
if (child) {
|
|
||||||
return {
|
|
||||||
route,
|
|
||||||
props,
|
|
||||||
child,
|
|
||||||
_parsedRoute,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
continue forEachRouteLoop;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
continue forEachRouteLoop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const _parts = path.split('/').filter(part => part.length !== 0);
|
|
||||||
|
|
||||||
return check(this.routes, _parts);
|
|
||||||
}
|
|
||||||
|
|
||||||
private navigate(path: string, emitChange = true, _redirected = false): Resolved {
|
|
||||||
const beforePath = this.currentPath;
|
|
||||||
this.currentPath = path;
|
|
||||||
|
|
||||||
const res = this.resolve(this.currentPath);
|
|
||||||
|
|
||||||
if (res == null) {
|
|
||||||
throw new Error('no route found for: ' + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('redirect' in res.route) {
|
|
||||||
let redirectPath: string;
|
|
||||||
if (typeof res.route.redirect === 'function') {
|
|
||||||
redirectPath = res.route.redirect(res.props);
|
|
||||||
} else {
|
|
||||||
redirectPath = res.route.redirect + (res._parsedRoute.queryString ? '?' + res._parsedRoute.queryString : '') + (res._parsedRoute.hash ? '#' + res._parsedRoute.hash : '');
|
|
||||||
}
|
|
||||||
if (_DEV_) console.log('Redirecting to: ', redirectPath);
|
|
||||||
if (_redirected && this.redirectCount++ > 10) {
|
|
||||||
throw new Error('redirect loop detected');
|
|
||||||
}
|
|
||||||
return this.navigate(redirectPath, emitChange, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.route.loginRequired && !this.isLoggedIn) {
|
|
||||||
res.route.component = this.notFoundPageComponent;
|
|
||||||
res.props.set('showLoginPopup', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.current = res;
|
|
||||||
this.currentRef.value = res;
|
|
||||||
this.currentRoute.value = res.route;
|
|
||||||
|
|
||||||
if (emitChange && res.route.path !== '/:(*)') {
|
|
||||||
this.emit('change', {
|
|
||||||
beforePath,
|
|
||||||
path,
|
|
||||||
resolved: res,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.redirectCount = 0;
|
|
||||||
return {
|
|
||||||
...res,
|
|
||||||
redirected: _redirected,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCurrentPath() {
|
|
||||||
return this.currentPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public push(path: string, flag?: RouterFlag) {
|
|
||||||
const beforePath = this.currentPath;
|
|
||||||
if (path === beforePath) {
|
|
||||||
this.emit('same');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.navHook) {
|
|
||||||
const cancel = this.navHook(path, flag);
|
|
||||||
if (cancel) return;
|
|
||||||
}
|
|
||||||
const res = this.navigate(path);
|
|
||||||
if (res.route.path === '/:(*)') {
|
|
||||||
location.href = path;
|
|
||||||
} else {
|
|
||||||
this.emit('push', {
|
|
||||||
beforePath,
|
|
||||||
path: res._parsedRoute.fullPath,
|
|
||||||
route: res.route,
|
|
||||||
props: res.props,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public replace(path: string) {
|
|
||||||
const res = this.navigate(path);
|
|
||||||
this.emit('replace', {
|
|
||||||
path: res._parsedRoute.fullPath,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,199 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { EventEmitter } from 'eventemitter3';
|
|
||||||
import type { Router, Resolved, RouteDef, RouterEvent, RouterFlag } from '@/router.js';
|
|
||||||
|
|
||||||
import type { App, ShallowRef } from 'vue';
|
|
||||||
import { analytics } from '@/analytics.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link Router}による画面遷移を可能とするために{@link mainRouter}をセットアップする。
|
|
||||||
* また、{@link Router}のインスタンスを作成するためのファクトリも{@link provide}経由で公開する(`routerFactory`というキーで取得可能)
|
|
||||||
*/
|
|
||||||
export function setupRouter(app: App, routerFactory: ((path: string) => Router)): void {
|
|
||||||
app.provide('routerFactory', routerFactory);
|
|
||||||
|
|
||||||
const mainRouter = routerFactory(location.pathname + location.search + location.hash);
|
|
||||||
|
|
||||||
window.addEventListener('popstate', (event) => {
|
|
||||||
mainRouter.replace(location.pathname + location.search + location.hash);
|
|
||||||
});
|
|
||||||
|
|
||||||
mainRouter.addListener('push', ctx => {
|
|
||||||
window.history.pushState({ }, '', ctx.path);
|
|
||||||
});
|
|
||||||
|
|
||||||
mainRouter.addListener('replace', ctx => {
|
|
||||||
window.history.replaceState({ }, '', ctx.path);
|
|
||||||
});
|
|
||||||
|
|
||||||
mainRouter.addListener('change', ctx => {
|
|
||||||
console.log('mainRouter: change', ctx.path);
|
|
||||||
analytics.page({
|
|
||||||
path: ctx.path,
|
|
||||||
title: ctx.path,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
mainRouter.init();
|
|
||||||
|
|
||||||
setMainRouter(mainRouter);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMainRouter(): Router {
|
|
||||||
const router = mainRouterHolder;
|
|
||||||
if (!router) {
|
|
||||||
throw new Error('mainRouter is not found.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* メインルータを設定する。一度設定すると、それ以降は変更できない。
|
|
||||||
* {@link setupRouter}から呼び出されることのみを想定している。
|
|
||||||
*/
|
|
||||||
export function setMainRouter(router: Router) {
|
|
||||||
if (mainRouterHolder) {
|
|
||||||
throw new Error('mainRouter is already exists.');
|
|
||||||
}
|
|
||||||
|
|
||||||
mainRouterHolder = router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link mainRouter}用のプロキシ実装。
|
|
||||||
* {@link mainRouter}は起動シーケンスの一部にて初期化されるため、僅かにundefinedになる期間がある。
|
|
||||||
* その僅かな期間のためだけに型をundefined込みにしたくないのでこのクラスを緩衝材として使用する。
|
|
||||||
*/
|
|
||||||
class MainRouterProxy implements Router {
|
|
||||||
private supplier: () => Router;
|
|
||||||
|
|
||||||
constructor(supplier: () => Router) {
|
|
||||||
this.supplier = supplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
get current(): Resolved {
|
|
||||||
return this.supplier().current;
|
|
||||||
}
|
|
||||||
|
|
||||||
get currentRef(): ShallowRef<Resolved> {
|
|
||||||
return this.supplier().currentRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
get currentRoute(): ShallowRef<RouteDef> {
|
|
||||||
return this.supplier().currentRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
get navHook(): ((path: string, flag?: RouterFlag) => boolean) | null {
|
|
||||||
return this.supplier().navHook;
|
|
||||||
}
|
|
||||||
|
|
||||||
set navHook(value) {
|
|
||||||
this.supplier().navHook = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentPath(): string {
|
|
||||||
return this.supplier().getCurrentPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
push(path: string, flag?: RouterFlag): void {
|
|
||||||
this.supplier().push(path, flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
replace(path: string, key?: string | null): void {
|
|
||||||
this.supplier().replace(path, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(path: string): Resolved | null {
|
|
||||||
return this.supplier().resolve(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
init(): void {
|
|
||||||
this.supplier().init();
|
|
||||||
}
|
|
||||||
|
|
||||||
eventNames(): Array<EventEmitter.EventNames<RouterEvent>> {
|
|
||||||
return this.supplier().eventNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
listeners<T extends EventEmitter.EventNames<RouterEvent>>(
|
|
||||||
event: T,
|
|
||||||
): Array<EventEmitter.EventListener<RouterEvent, T>> {
|
|
||||||
return this.supplier().listeners(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
listenerCount(
|
|
||||||
event: EventEmitter.EventNames<RouterEvent>,
|
|
||||||
): number {
|
|
||||||
return this.supplier().listenerCount(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit<T extends EventEmitter.EventNames<RouterEvent>>(
|
|
||||||
event: T,
|
|
||||||
...args: EventEmitter.EventArgs<RouterEvent, T>
|
|
||||||
): boolean {
|
|
||||||
return this.supplier().emit(event, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
on<T extends EventEmitter.EventNames<RouterEvent>>(
|
|
||||||
event: T,
|
|
||||||
fn: EventEmitter.EventListener<RouterEvent, T>,
|
|
||||||
context?: any,
|
|
||||||
): this {
|
|
||||||
this.supplier().on(event, fn, context);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
addListener<T extends EventEmitter.EventNames<RouterEvent>>(
|
|
||||||
event: T,
|
|
||||||
fn: EventEmitter.EventListener<RouterEvent, T>,
|
|
||||||
context?: any,
|
|
||||||
): this {
|
|
||||||
this.supplier().addListener(event, fn, context);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
once<T extends EventEmitter.EventNames<RouterEvent>>(
|
|
||||||
event: T,
|
|
||||||
fn: EventEmitter.EventListener<RouterEvent, T>,
|
|
||||||
context?: any,
|
|
||||||
): this {
|
|
||||||
this.supplier().once(event, fn, context);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeListener<T extends EventEmitter.EventNames<RouterEvent>>(
|
|
||||||
event: T,
|
|
||||||
fn?: EventEmitter.EventListener<RouterEvent, T>,
|
|
||||||
context?: any,
|
|
||||||
once?: boolean,
|
|
||||||
): this {
|
|
||||||
this.supplier().removeListener(event, fn, context, once);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
off<T extends EventEmitter.EventNames<RouterEvent>>(
|
|
||||||
event: T,
|
|
||||||
fn?: EventEmitter.EventListener<RouterEvent, T>,
|
|
||||||
context?: any,
|
|
||||||
once?: boolean,
|
|
||||||
): this {
|
|
||||||
this.supplier().off(event, fn, context, once);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeAllListeners(
|
|
||||||
event?: EventEmitter.EventNames<RouterEvent>,
|
|
||||||
): this {
|
|
||||||
this.supplier().removeAllListeners(event);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mainRouterHolder: Router | null = null;
|
|
||||||
|
|
||||||
export const mainRouter: Router = new MainRouterProxy(getMainRouter);
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { inject } from 'vue';
|
|
||||||
import type { Router } from '@/router.js';
|
|
||||||
import { mainRouter } from '@/router/main.js';
|
|
||||||
import { DI } from '@/di.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* メインの{@link Router}を取得する。
|
|
||||||
* あらかじめ{@link setupRouter}を実行しておく必要がある({@link provide}により{@link Router}のインスタンスを注入可能であるならばこの限りではない)
|
|
||||||
*/
|
|
||||||
export function useRouter(): Router {
|
|
||||||
return inject(DI.router, null) ?? mainRouter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 任意の{@link Router}を取得するためのファクトリを取得する。
|
|
||||||
* あらかじめ{@link setupRouter}を実行しておく必要がある。
|
|
||||||
*/
|
|
||||||
export function useRouterFactory(): (path: string) => Router {
|
|
||||||
const factory = inject<(path: string) => Router>('routerFactory');
|
|
||||||
if (!factory) {
|
|
||||||
console.error('routerFactory is not defined.');
|
|
||||||
throw new Error('routerFactory is not defined.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return factory;
|
|
||||||
}
|
|
|
@ -97,7 +97,7 @@ import { store } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { getHTMLElementOrNull } from '@/utility/get-dom-node-or-null.js';
|
import { getHTMLElementOrNull } from '@/utility/get-dom-node-or-null.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { openAccountMenu as openAccountMenu_ } from '@/accounts.js';
|
import { openAccountMenu as openAccountMenu_ } from '@/accounts.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { getAccountFromId } from '@/utility/get-account-from-id.js';
|
import { getAccountFromId } from '@/utility/get-account-from-id.js';
|
||||||
import { deepClone } from '@/utility/clone.js';
|
import { deepClone } from '@/utility/clone.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { login } from '@/accounts.js';
|
import { login } from '@/accounts.js';
|
||||||
|
|
||||||
export function swInject() {
|
export function swInject() {
|
||||||
|
|
|
@ -58,7 +58,7 @@ import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||||
import { store } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ import XWidgetsColumn from '@/ui/deck/widgets-column.vue';
|
||||||
import XMentionsColumn from '@/ui/deck/mentions-column.vue';
|
import XMentionsColumn from '@/ui/deck/mentions-column.vue';
|
||||||
import XDirectColumn from '@/ui/deck/direct-column.vue';
|
import XDirectColumn from '@/ui/deck/direct-column.vue';
|
||||||
import XRoleTimelineColumn from '@/ui/deck/role-timeline-column.vue';
|
import XRoleTimelineColumn from '@/ui/deck/role-timeline-column.vue';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { columns, layout, columnTypes, switchProfileMenu, addColumn as addColumnToStore, deleteProfile as deleteProfile_ } from '@/deck.js';
|
import { columns, layout, columnTypes, switchProfileMenu, addColumn as addColumnToStore, deleteProfile as deleteProfile_ } from '@/deck.js';
|
||||||
const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue'));
|
const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue'));
|
||||||
const XAnnouncements = defineAsyncComponent(() => import('@/ui/_common_/announcements.vue'));
|
const XAnnouncements = defineAsyncComponent(() => import('@/ui/_common_/announcements.vue'));
|
||||||
|
|
|
@ -28,7 +28,7 @@ import type { PageMetadata } from '@/page.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { instanceName } from '@@/js/config.js';
|
||||||
import XCommon from './_common_/common.vue';
|
import XCommon from './_common_/common.vue';
|
||||||
import type { PageMetadata } from '@/page.js';
|
import type { PageMetadata } from '@/page.js';
|
||||||
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
|
|
||||||
const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index');
|
const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index');
|
||||||
|
|
|
@ -110,7 +110,7 @@ import { $i } from '@/i.js';
|
||||||
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||||
import { deviceKind } from '@/utility/device-kind.js';
|
import { deviceKind } from '@/utility/device-kind.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { shouldSuggestRestoreBackup } from '@/preferences/utility.js';
|
import { shouldSuggestRestoreBackup } from '@/preferences/utility.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
|
|
|
@ -36,7 +36,7 @@ import { instance } from '@/instance.js';
|
||||||
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue';
|
import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
|
|
||||||
const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index');
|
const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index');
|
||||||
|
|
|
@ -30,7 +30,7 @@ import XCommon from './_common_/common.vue';
|
||||||
import type { PageMetadata } from '@/page.js';
|
import type { PageMetadata } from '@/page.js';
|
||||||
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
|
|
||||||
const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index');
|
const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index');
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { $i, iAmModerator } from '@/i.js';
|
import { $i, iAmModerator } from '@/i.js';
|
||||||
import { notesSearchAvailable, canSearchNonLocalNotes } from '@/utility/check-permissions.js';
|
import { notesSearchAvailable, canSearchNonLocalNotes } from '@/utility/check-permissions.js';
|
||||||
import { antennasCache, rolesCache, userListsCache } from '@/cache.js';
|
import { antennasCache, rolesCache, userListsCache } from '@/cache.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { genEmbedCode } from '@/utility/get-embed-code.js';
|
import { genEmbedCode } from '@/utility/get-embed-code.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { getPluginHandlers } from '@/plugin.js';
|
import { getPluginHandlers } from '@/plugin.js';
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { Router } from '@/router.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { Router } from '@/router.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
|
||||||
|
|
||||||
export async function lookup(router?: Router) {
|
export async function lookup(router?: Router) {
|
||||||
const _router = router ?? mainRouter;
|
const _router = router ?? mainRouter;
|
||||||
|
|
Loading…
Reference in New Issue