embedのstoreでの変更が外部タブに影響しないように・されないように

This commit is contained in:
kakkokari-gtyih 2024-06-07 19:43:09 +09:00
parent e5415812e6
commit 6a7ed7e0d1
3 changed files with 74 additions and 47 deletions

View File

@ -32,6 +32,8 @@
renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.') renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.')
} }
const isEmbedPage = document.documentElement.classList.contains('embed');
//#region Detect language & fetch translations //#region Detect language & fetch translations
if (!localStorage.hasOwnProperty('locale')) { if (!localStorage.hasOwnProperty('locale')) {
const supportedLangs = LANGS; const supportedLangs = LANGS;
@ -104,6 +106,7 @@
} }
//#endregion //#endregion
if (!isEmbedPage) {
//#region Theme //#region Theme
const theme = localStorage.getItem('theme'); const theme = localStorage.getItem('theme');
if (theme) { if (theme) {
@ -148,6 +151,7 @@
style.innerHTML = customCss; style.innerHTML = customCss;
document.head.appendChild(style); document.head.appendChild(style);
} }
}
async function addStyle(styleText) { async function addStyle(styleText) {
let css = document.createElement('style'); let css = document.createElement('style');

View File

@ -11,6 +11,7 @@ import '@/style.embed.scss';
import type { CommonBootOptions } from '@/boot/common.js'; import type { CommonBootOptions } from '@/boot/common.js';
import { subBoot } from '@/boot/sub-boot.js'; import { subBoot } from '@/boot/sub-boot.js';
import { setIframeId, postMessageToParentWindow } from '@/scripts/post-message.js'; import { setIframeId, postMessageToParentWindow } from '@/scripts/post-message.js';
import { defaultStore } from '@/store.js';
const bootOptions: Partial<CommonBootOptions> = {}; const bootOptions: Partial<CommonBootOptions> = {};
@ -21,6 +22,11 @@ if (color && ['light', 'dark'].includes(color)) {
bootOptions.forceColorMode = color as 'light' | 'dark'; bootOptions.forceColorMode = color as 'light' | 'dark';
} }
// 外部タブでのstoreの変更の影響を受けないように
defaultStore.setConfig({
disableMessageChannel: true,
});
// iframeIdの設定 // iframeIdの設定
window.addEventListener('message', event => { window.addEventListener('message', event => {
if (event.data?.type === 'misskey:embedParent:registerIframeId' && event.data.payload?.iframeId != null) { if (event.data?.type === 'misskey:embedParent:registerIframeId' && event.data.payload?.iframeId != null) {

View File

@ -32,6 +32,10 @@ type PizzaxChannelMessage<T extends StateDef> = {
userId?: string; userId?: string;
}; };
export type PizzaxConfig = {
disableMessageChannel: boolean;
};
export class Storage<T extends StateDef> { export class Storage<T extends StateDef> {
public readonly ready: Promise<void>; public readonly ready: Promise<void>;
public readonly loaded: Promise<void>; public readonly loaded: Promise<void>;
@ -47,6 +51,10 @@ export class Storage<T extends StateDef> {
public readonly state: State<T>; public readonly state: State<T>;
public readonly reactiveState: ReactiveState<T>; public readonly reactiveState: ReactiveState<T>;
private options: PizzaxConfig = {
disableMessageChannel: false,
};
private pizzaxChannel: BroadcastChannel<PizzaxChannelMessage<T>>; private pizzaxChannel: BroadcastChannel<PizzaxChannelMessage<T>>;
// 簡易的にキューイングして占有ロックとする // 簡易的にキューイングして占有ロックとする
@ -60,12 +68,13 @@ export class Storage<T extends StateDef> {
return promise; return promise;
} }
constructor(key: string, def: T) { constructor(key: string, def: T, options?: Partial<PizzaxConfig>) {
this.key = key; this.key = key;
this.deviceStateKeyName = `pizzax::${key}`; this.deviceStateKeyName = `pizzax::${key}`;
this.deviceAccountStateKeyName = $i ? `pizzax::${key}::${$i.id}` : ''; this.deviceAccountStateKeyName = $i ? `pizzax::${key}::${$i.id}` : '';
this.registryCacheKeyName = $i ? `pizzax::${key}::cache::${$i.id}` : ''; this.registryCacheKeyName = $i ? `pizzax::${key}::cache::${$i.id}` : '';
this.def = def; this.def = def;
this.options = Object.assign(this.options, options);
this.pizzaxChannel = new BroadcastChannel(`pizzax::${key}`); this.pizzaxChannel = new BroadcastChannel(`pizzax::${key}`);
@ -119,7 +128,7 @@ export class Storage<T extends StateDef> {
this.pizzaxChannel.addEventListener('message', ({ where, key, value, userId }) => { this.pizzaxChannel.addEventListener('message', ({ where, key, value, userId }) => {
// アカウント変更すればunisonReloadが効くため、このreturnが発火することは // アカウント変更すればunisonReloadが効くため、このreturnが発火することは
// まずないと思うけど一応弾いておく // まずないと思うけど一応弾いておく
if (where === 'deviceAccount' && !($i && userId !== $i.id)) return; if ((where === 'deviceAccount' && !($i && userId !== $i.id) || this.options.disableMessageChannel)) return;
this.reactiveState[key].value = this.state[key] = value; this.reactiveState[key].value = this.state[key] = value;
}); });
@ -174,6 +183,10 @@ export class Storage<T extends StateDef> {
}); });
} }
public setConfig(config: Partial<PizzaxConfig>) {
this.options = Object.assign(this.options, config);
}
public set<K extends keyof T>(key: K, value: T[K]['default']): Promise<void> { public set<K extends keyof T>(key: K, value: T[K]['default']): Promise<void> {
// IndexedDBやBroadcastChannelで扱うために単純なオブジェクトにする // IndexedDBやBroadcastChannelで扱うために単純なオブジェクトにする
// (JSON.parse(JSON.stringify(value))の代わり) // (JSON.parse(JSON.stringify(value))の代わり)
@ -187,11 +200,13 @@ export class Storage<T extends StateDef> {
if (_DEV_) console.log(`set ${String(key)} start`); if (_DEV_) console.log(`set ${String(key)} start`);
switch (this.def[key].where) { switch (this.def[key].where) {
case 'device': { case 'device': {
if (!this.options.disableMessageChannel) {
this.pizzaxChannel.postMessage({ this.pizzaxChannel.postMessage({
where: 'device', where: 'device',
key, key,
value: rawValue, value: rawValue,
}); });
}
const deviceState = await get(this.deviceStateKeyName) || {}; const deviceState = await get(this.deviceStateKeyName) || {};
deviceState[key] = rawValue; deviceState[key] = rawValue;
await set(this.deviceStateKeyName, deviceState); await set(this.deviceStateKeyName, deviceState);
@ -199,12 +214,14 @@ export class Storage<T extends StateDef> {
} }
case 'deviceAccount': { case 'deviceAccount': {
if ($i == null) break; if ($i == null) break;
if (!this.options.disableMessageChannel) {
this.pizzaxChannel.postMessage({ this.pizzaxChannel.postMessage({
where: 'deviceAccount', where: 'deviceAccount',
key, key,
value: rawValue, value: rawValue,
userId: $i.id, userId: $i.id,
}); });
}
const deviceAccountState = await get(this.deviceAccountStateKeyName) || {}; const deviceAccountState = await get(this.deviceAccountStateKeyName) || {};
deviceAccountState[key] = rawValue; deviceAccountState[key] = rawValue;
await set(this.deviceAccountStateKeyName, deviceAccountState); await set(this.deviceAccountStateKeyName, deviceAccountState);