misskey/packages/frontend/src/scripts/get-embed-code.ts

88 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { defineAsyncComponent } from 'vue';
import { v4 as uuid } from 'uuid';
import type { EmbedParams, EmbeddableEntity } from '@@/js/embed-page.js';
import { url } from '@@/js/config.js';
import * as os from '@/os.js';
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { defaultEmbedParams, embedRouteWithScrollbar } from '@@/js/embed-page.js';
const MOBILE_THRESHOLD = 500;
/**
* パラメータを正規化する(埋め込みコード作成用)
* @param params パラメータ
* @returns 正規化されたパラメータ
*/
export function normalizeEmbedParams(params: EmbedParams): Record<string, string> {
// paramsのvalueをすべてstringに変換。undefinedやnullはプロパティごと消す
const normalizedParams: Record<string, string> = {};
for (const key in params) {
// デフォルトの値と同じならparamsに含めない
if (params[key] == null || params[key] === defaultEmbedParams[key]) {
continue;
}
switch (typeof params[key]) {
case 'number':
normalizedParams[key] = params[key].toString();
break;
case 'boolean':
normalizedParams[key] = params[key] ? 'true' : 'false';
break;
default:
normalizedParams[key] = params[key];
break;
}
}
return normalizedParams;
}
/**
* 埋め込みコードを生成iframe IDの発番もやる
*/
export function getEmbedCode(path: string, params?: EmbedParams): string {
const iframeId = 'v1_' + uuid(); // 将来embed.jsのバージョンが上がったとき用にv1_を付けておく
let paramString = '';
if (params) {
const searchParams = new URLSearchParams(normalizeEmbedParams(params));
paramString = searchParams.toString() === '' ? '' : '?' + searchParams.toString();
}
const iframeCode = [
`<iframe src="${url + path + paramString}" data-misskey-embed-id="${iframeId}" loading="lazy" referrerpolicy="strict-origin-when-cross-origin" style="border: none; width: 100%; max-width: 500px; height: 300px; color-scheme: light dark;"></iframe>`,
`<script defer src="${url}/embed.js"></script>`,
];
return iframeCode.join('\n');
}
/**
* 埋め込みコードを生成してコピーする(カスタマイズ機能つき)
*
* カスタマイズ機能がいらない場合(事前にパラメータを指定する場合)は getEmbedCode を直接使ってください
*/
export function genEmbedCode(entity: EmbeddableEntity, id: string, params?: EmbedParams) {
const _params = { ...params };
if (embedRouteWithScrollbar.includes(entity) && _params.maxHeight == null) {
_params.maxHeight = 700;
}
// PCじゃない場合はコードカスタマイズ画面を出さずにそのままコピー
if (window.innerWidth < MOBILE_THRESHOLD) {
copyToClipboard(getEmbedCode(`/embed/${entity}/${id}`, _params));
os.success();
} else {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkEmbedCodeGenDialog.vue')), {
entity,
id,
params: _params,
}, {
closed: () => dispose(),
});
}
}