embedのURLパラメータの初期化を共通化

This commit is contained in:
kakkokari-gtyih 2024-06-29 17:47:38 +09:00
parent 237605d6b8
commit 1ed6ed6ef0
8 changed files with 113 additions and 78 deletions

View file

@ -81,8 +81,9 @@ import * as os from '@/os.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { url } from '@/config.js'; import { url } from '@/config.js';
import copy from '@/scripts/copy-to-clipboard.js'; import copy from '@/scripts/copy-to-clipboard.js';
import { normalizeEmbedParams, embedRouteWithScrollbar, getEmbedCode } from '@/scripts/get-embed-code.js'; import { normalizeEmbedParams, getEmbedCode } from '@/scripts/get-embed-code.js';
import type { EmbeddableEntity, EmbedParams } from '@/scripts/get-embed-code.js'; import { embedRouteWithScrollbar } from '@/scripts/embed-page.js';
import type { EmbeddableEntity, EmbedParams } from '@/scripts/embed-page.js';
const emit = defineEmits<{ const emit = defineEmits<{
(ev: 'ok', url: string, code: string): void; (ev: 'ok', url: string, code: string): void;

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div> <div>
<MkLoading v-if="loading"/> <MkLoading v-if="loading"/>
<XEmbedTimelineUI v-else-if="clip" :showHeader="normalizedShowHeader"> <XEmbedTimelineUI v-else-if="clip" :showHeader="embedParams.header">
<template #header> <template #header>
<div :class="$style.clipHeader"> <div :class="$style.clipHeader">
<div :class="$style.headerClipIconRoot"> <div :class="$style.headerClipIconRoot">
@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNotes <MkNotes
ref="notesEl" ref="notesEl"
:pagination="pagination" :pagination="pagination"
:disableAutoLoad="!normalizedEnableAutoLoad" :disableAutoLoad="embedParams.autoload"
:noGap="true" :noGap="true"
:ad="false" :ad="false"
/> />
@ -52,11 +52,11 @@ import { url, instanceName } from '@/config.js';
import { scrollToTop } from '@/scripts/scroll.js'; import { scrollToTop } from '@/scripts/scroll.js';
import { isLink } from '@/scripts/is-link.js'; import { isLink } from '@/scripts/is-link.js';
import { useRouter } from '@/router/supplier.js'; import { useRouter } from '@/router/supplier.js';
import { defaultEmbedParams } from '@/scripts/embed-page.js';
import type { ParsedEmbedParams } from '@/scripts/embed-page.js';
const props = defineProps<{ const props = defineProps<{
clipId: string; clipId: string;
showHeader?: string;
enableAutoLoad?: string;
}>(); }>();
function redirectIfNotEmbedPage() { function redirectIfNotEmbedPage() {
@ -72,11 +72,7 @@ redirectIfNotEmbedPage();
onActivated(redirectIfNotEmbedPage); onActivated(redirectIfNotEmbedPage);
// : true const embedParams = inject<ParsedEmbedParams>('embedParams', defaultEmbedParams);
const normalizedShowHeader = computed(() => props.showHeader !== 'false');
// : false
const normalizedEnableAutoLoad = computed(() => props.enableAutoLoad === 'true');
const clip = ref<Misskey.entities.Clip | null>(null); const clip = ref<Misskey.entities.Clip | null>(null);
const pagination = computed(() => ({ const pagination = computed(() => ({

View file

@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div> <div>
<XEmbedTimelineUI v-if="tag" :showHeader="normalizedShowHeader"> <XEmbedTimelineUI v-if="tag" :showHeader="embedParams.header">
<template #header> <template #header>
<div :class="$style.clipHeader"> <div :class="$style.clipHeader">
<div :class="$style.headerClipIconRoot"> <div :class="$style.headerClipIconRoot">
@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNotes <MkNotes
ref="notesEl" ref="notesEl"
:pagination="pagination" :pagination="pagination"
:disableAutoLoad="!normalizedEnableAutoLoad" :disableAutoLoad="embedParams.autoload"
:noGap="true" :noGap="true"
:ad="false" :ad="false"
/> />
@ -49,6 +49,8 @@ import { url, instanceName } from '@/config.js';
import { scrollToTop } from '@/scripts/scroll.js'; import { scrollToTop } from '@/scripts/scroll.js';
import { isLink } from '@/scripts/is-link.js'; import { isLink } from '@/scripts/is-link.js';
import { useRouter } from '@/router/supplier.js'; import { useRouter } from '@/router/supplier.js';
import { defaultEmbedParams } from '@/scripts/embed-page.js';
import type { ParsedEmbedParams } from '@/scripts/embed-page.js';
const props = defineProps<{ const props = defineProps<{
tag: string; tag: string;
@ -69,11 +71,7 @@ redirectIfNotEmbedPage();
onActivated(redirectIfNotEmbedPage); onActivated(redirectIfNotEmbedPage);
// : true const embedParams = inject<ParsedEmbedParams>('embedParams', defaultEmbedParams);
const normalizedShowHeader = computed(() => props.showHeader !== 'false');
// : false
const normalizedEnableAutoLoad = computed(() => props.enableAutoLoad === 'true');
const pagination = computed(() => ({ const pagination = computed(() => ({
endpoint: 'notes/search-by-tag', endpoint: 'notes/search-by-tag',

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div> <div>
<MkLoading v-if="loading"/> <MkLoading v-if="loading"/>
<XEmbedTimelineUI v-else-if="user" :showHeader="normalizedShowHeader"> <XEmbedTimelineUI v-else-if="user" :showHeader="embedParams.header">
<template #header> <template #header>
<div :class="$style.userHeader"> <div :class="$style.userHeader">
<a :href="`/@${user.username}`" target="_blank" rel="noopener noreferrer" :class="$style.avatarLink"> <a :href="`/@${user.username}`" target="_blank" rel="noopener noreferrer" :class="$style.avatarLink">
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNotes <MkNotes
ref="notesEl" ref="notesEl"
:pagination="pagination" :pagination="pagination"
:disableAutoLoad="!normalizedEnableAutoLoad" :disableAutoLoad="embedParams.autoload"
:noGap="true" :noGap="true"
:ad="false" :ad="false"
/> />
@ -58,6 +58,8 @@ import { url, instanceName } from '@/config.js';
import { scrollToTop } from '@/scripts/scroll.js'; import { scrollToTop } from '@/scripts/scroll.js';
import { isLink } from '@/scripts/is-link.js'; import { isLink } from '@/scripts/is-link.js';
import { useRouter } from '@/router/supplier.js'; import { useRouter } from '@/router/supplier.js';
import { defaultEmbedParams } from '@/scripts/embed-page.js';
import type { ParsedEmbedParams } from '@/scripts/embed-page.js';
const props = defineProps<{ const props = defineProps<{
username: string; username: string;
@ -78,11 +80,7 @@ redirectIfNotEmbedPage();
onActivated(redirectIfNotEmbedPage); onActivated(redirectIfNotEmbedPage);
// : true const embedParams = inject<ParsedEmbedParams>('embedParams', defaultEmbedParams);
const normalizedShowHeader = computed(() => props.showHeader !== 'false');
// : false
const normalizedEnableAutoLoad = computed(() => props.enableAutoLoad === 'true');
const user = ref<Misskey.entities.UserLite | null>(null); const user = ref<Misskey.entities.UserLite | null>(null);
const pagination = computed(() => ({ const pagination = computed(() => ({

View file

@ -569,24 +569,12 @@ const routes: RouteDef[] = [{
}, { }, {
path: '/embed/user-timeline/@:username', path: '/embed/user-timeline/@:username',
component: page(() => import('@/pages/embed/user-timeline.vue')), component: page(() => import('@/pages/embed/user-timeline.vue')),
query: {
header: 'showHeader',
autoload: 'enableAutoLoad',
}
}, { }, {
path: '/embed/clips/:clipId', path: '/embed/clips/:clipId',
component: page(() => import('@/pages/embed/clip.vue')), component: page(() => import('@/pages/embed/clip.vue')),
query: {
header: 'showHeader',
autoload: 'enableAutoLoad',
}
}, { }, {
path: '/embed/tags/:tag', path: '/embed/tags/:tag',
component: page(() => import('@/pages/embed/tag.vue')), component: page(() => import('@/pages/embed/tag.vue')),
query: {
header: 'showHeader',
autoload: 'enableAutoLoad',
},
}, { }, {
path: '/timeline', path: '/timeline',
component: page(() => import('@/pages/timeline.vue')), component: page(() => import('@/pages/timeline.vue')),

View file

@ -6,6 +6,85 @@ import { miLocalStorage } from "@/local-storage.js";
import type { Keys } from "@/local-storage.js"; import type { Keys } from "@/local-storage.js";
import { embedPage } from "@/config.js"; import { embedPage } from "@/config.js";
//#region Embed関連の定義
/** 埋め込みの対象となるエンティティ(/embed/xxx の xxx の部分と対応させる) */
const embeddableEntities = [
'notes',
'user-timeline',
'clips',
'tags',
] as const;
/** 埋め込みの対象となるエンティティ */
export type EmbeddableEntity = typeof embeddableEntities[number];
/** 内部でスクロールがあるページ */
export const embedRouteWithScrollbar: EmbeddableEntity[] = [
'clips',
'tags',
'user-timeline'
];
/** 埋め込みコードのパラメータ */
export type EmbedParams = {
maxHeight?: number;
colorMode?: 'light' | 'dark';
rounded?: boolean;
border?: boolean;
autoload?: boolean;
header?: boolean;
};
export type ParsedEmbedParams = Required<Omit<EmbedParams, 'maxHeight' | 'colorMode'>> & Pick<EmbedParams, 'maxHeight' | 'colorMode'>;
/** パラメータのデフォルトの値 */
export const defaultEmbedParams = {
maxHeight: undefined,
colorMode: undefined,
rounded: true,
border: true,
autoload: false,
header: true,
} as const;
/**
*
* @param searchParams URLSearchParamsもしくはクエリ文字列
* @returns
*/
export function parseEmbedParams(searchParams: URLSearchParams | string): ParsedEmbedParams {
let _searchParams: URLSearchParams;
if (typeof searchParams === 'string') {
_searchParams = new URLSearchParams(searchParams);
} else {
_searchParams = searchParams;
}
const params: EmbedParams = {};
for (const key in defaultEmbedParams) {
const value = _searchParams.get(key);
if (value != null) {
if (value === 'true') {
params[key] = true;
} else if (value === 'false') {
params[key] = false;
} else if (!isNaN(Number(value))) {
params[key] = Number(value);
} else if (key === 'colorMode' && ['light', 'dark'].includes(value)) {
params[key] = value as 'light' | 'dark';
} else {
params[key] = value;
}
}
}
return {
...defaultEmbedParams,
...params,
};
}
/** /**
* EmbedページではlocalStorageを使用できないようにしているが * EmbedページではlocalStorageを使用できないようにしているが
* safeSessionStoragemiLocalStorage内のやつ * safeSessionStoragemiLocalStorage内のやつ

View file

@ -7,44 +7,15 @@ import { url } from '@/config.js';
import { MOBILE_THRESHOLD } from '@/const.js'; import { MOBILE_THRESHOLD } from '@/const.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import copy from '@/scripts/copy-to-clipboard.js'; import copy from '@/scripts/copy-to-clipboard.js';
import type { EmbedParams, EmbeddableEntity } from '@/scripts/embed-page.js';
import { defaultEmbedParams, embedRouteWithScrollbar } from '@/scripts/embed-page.js';
import MkEmbedCodeGenDialog from '@/components/MkEmbedCodeGenDialog.vue'; import MkEmbedCodeGenDialog from '@/components/MkEmbedCodeGenDialog.vue';
// 埋め込みの対象となるエンティティ(/embed/xxx の xxx の部分と対応させる) /**
const embeddableEntities = [ *
'notes', * @param params
'user-timeline', * @returns
'clips', */
'tags',
] as const;
export type EmbeddableEntity = typeof embeddableEntities[number];
// 内部でスクロールがあるページ
export const embedRouteWithScrollbar: EmbeddableEntity[] = [
'clips',
'tags',
'user-timeline'
];
export type EmbedParams = {
maxHeight?: number;
colorMode?: 'light' | 'dark';
rounded?: boolean;
border?: boolean;
autoload?: boolean;
header?: boolean;
};
// パラメータのデフォルトの値
export const defaultEmbedParams: EmbedParams = {
maxHeight: undefined,
colorMode: undefined,
rounded: true,
border: true,
autoload: false,
header: true,
};
export function normalizeEmbedParams(params: EmbedParams): Record<string, string> { export function normalizeEmbedParams(params: EmbedParams): Record<string, string> {
// paramsのvalueをすべてstringに変換。undefinedやnullはプロパティごと消す // paramsのvalueをすべてstringに変換。undefinedやnullはプロパティごと消す
const normalizedParams: Record<string, string> = {}; const normalizedParams: Record<string, string> = {};

View file

@ -31,7 +31,8 @@ import XCommon from './_common_/common.vue';
import { PageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js'; import { PageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
import { instanceName } from '@/config.js'; import { instanceName } from '@/config.js';
import { mainRouter } from '@/router/main.js'; import { mainRouter } from '@/router/main.js';
import { postMessageToParentWindow } from '@/scripts/post-message'; import { postMessageToParentWindow } from '@/scripts/post-message.js';
import { parseEmbedParams } from '@/scripts/embed-page.js';
const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index'); const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index');
@ -61,13 +62,16 @@ mainRouter.navHook = (path, flag): boolean => {
//#region Embed Provide //#region Embed Provide
provide('EMBED_PAGE', true); provide('EMBED_PAGE', true);
const params = new URLSearchParams(location.search);
const embedParams = parseEmbedParams(params);
provide('embedParams', embedParams);
//#endregion //#endregion
//#region Embed Style //#region Embed Style
const params = new URLSearchParams(location.search); const embedRounded = ref(embedParams.rounded);
const embedRounded = ref(params.get('rounded') !== 'false'); const embedNoBorder = ref(!embedParams.border);
const embedNoBorder = ref(params.get('border') === 'false'); const maxHeight = ref(embedParams.maxHeight ?? 0);
const maxHeight = ref(params.get('maxHeight') ? parseInt(params.get('maxHeight')!) : 0);
//#endregion //#endregion
//#region Embed Resizer //#region Embed Resizer