mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-09-14 15:51:55 +08:00
feat(editor): 完善storageService功能
新增namespace,setItem/getItem时自动key自动加上namespace;setItem可以指定协议;getItem时根据协议自动解析 fix #224
This commit is contained in:
parent
6e199897ac
commit
574e03f685
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
import { reactive, toRaw } from 'vue';
|
import { reactive, toRaw } from 'vue';
|
||||||
import { cloneDeep, mergeWith, uniq } from 'lodash-es';
|
import { cloneDeep, mergeWith, uniq } from 'lodash-es';
|
||||||
import serialize from 'serialize-javascript';
|
|
||||||
|
|
||||||
import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
|
import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
|
||||||
import { NodeType } from '@tmagic/schema';
|
import { NodeType } from '@tmagic/schema';
|
||||||
@ -26,7 +25,7 @@ import StageCore from '@tmagic/stage';
|
|||||||
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
||||||
|
|
||||||
import historyService, { StepValue } from '@editor/services/history';
|
import historyService, { StepValue } from '@editor/services/history';
|
||||||
import storageService from '@editor/services/storage';
|
import storageService, { Protocol } from '@editor/services/storage';
|
||||||
import type { AddMNode, EditorNodeInfo, PastePosition, StoreState } from '@editor/type';
|
import type { AddMNode, EditorNodeInfo, PastePosition, StoreState } from '@editor/type';
|
||||||
import { LayerOffset, Layout } from '@editor/type';
|
import { LayerOffset, Layout } from '@editor/type';
|
||||||
import {
|
import {
|
||||||
@ -483,7 +482,9 @@ class Editor extends BaseService {
|
|||||||
* @returns 组件节点配置
|
* @returns 组件节点配置
|
||||||
*/
|
*/
|
||||||
public async copy(config: MNode | MNode[]): Promise<void> {
|
public async copy(config: MNode | MNode[]): Promise<void> {
|
||||||
await storageService.setItem(COPY_STORAGE_KEY, serialize(Array.isArray(config) ? config : [config]));
|
await storageService.setItem(COPY_STORAGE_KEY, Array.isArray(config) ? config : [config], {
|
||||||
|
protocol: Protocol.OBJECT,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -492,19 +493,10 @@ class Editor extends BaseService {
|
|||||||
* @returns 添加后的组件节点配置
|
* @returns 添加后的组件节点配置
|
||||||
*/
|
*/
|
||||||
public async paste(position: PastePosition = {}): Promise<MNode[] | void> {
|
public async paste(position: PastePosition = {}): Promise<MNode[] | void> {
|
||||||
const configStr = await storageService.getItem(COPY_STORAGE_KEY);
|
const config = await storageService.getItem(COPY_STORAGE_KEY);
|
||||||
// eslint-disable-next-line prefer-const
|
|
||||||
let config: any = {};
|
if (!config) return;
|
||||||
if (!configStr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// eslint-disable-next-line no-eval
|
|
||||||
eval(`config = ${configStr}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const pasteConfigs = await beforePaste(position, config);
|
const pasteConfigs = await beforePaste(position, config);
|
||||||
|
|
||||||
return await this.multiAdd(pasteConfigs);
|
return await this.multiAdd(pasteConfigs);
|
||||||
|
@ -1,39 +1,80 @@
|
|||||||
|
import serialize from 'serialize-javascript';
|
||||||
|
|
||||||
import BaseService from './BaseService';
|
import BaseService from './BaseService';
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
namespace?: string;
|
||||||
|
protocol?: Protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Protocol {
|
||||||
|
OBJECT = 'object',
|
||||||
|
JSON = 'json',
|
||||||
|
STRING = 'string',
|
||||||
|
NUMBER = 'number',
|
||||||
|
BOOLEAN = 'boolean',
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据存储服务
|
* 数据存储服务
|
||||||
*/
|
*/
|
||||||
export class WebStorage extends BaseService {
|
export class WebStorage extends BaseService {
|
||||||
|
private storage: Storage = globalThis.localStorage;
|
||||||
|
private namespace = 'tmagic';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(['getStorage', 'clear', 'getItem', 'removeItem', 'setItem']);
|
super(['getStorage', 'getNamespace', 'clear', 'getItem', 'removeItem', 'setItem']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取数据存储对象,可以通过
|
* 获取数据存储对象,可以通过
|
||||||
* const storageService = new StorageService();
|
* const storageService = new StorageService();
|
||||||
* storageService.use({
|
* storageService.usePlugin({
|
||||||
* // 替换存储对象为 sessionStorage
|
* // 替换存储对象为 sessionStorage
|
||||||
* async getStorage(): Promise<Storage> {
|
* async afterGetStorage(): Promise<Storage> {
|
||||||
* return window.sessionStorage;
|
* return window.sessionStorage;
|
||||||
* },
|
* },
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
public async getStorage(): Promise<Storage> {
|
public async getStorage(): Promise<Storage> {
|
||||||
return globalThis.localStorage;
|
return this.storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getNamespace(): Promise<string> {
|
||||||
|
return this.namespace;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清理,支持storageService.use
|
* 清理,支持storageService.usePlugin
|
||||||
*/
|
*/
|
||||||
public async clear(): Promise<void> {
|
public async clear(): Promise<void> {
|
||||||
const storage = await this.getStorage();
|
const storage = await this.getStorage();
|
||||||
storage.clear();
|
storage.clear();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 获取存储项,支持storageService.use
|
* 获取存储项,支持storageService.usePlugin
|
||||||
*/
|
*/
|
||||||
public async getItem(key: string): Promise<string | null> {
|
public async getItem(key: string, options: Options = {}): Promise<any> {
|
||||||
const storage = await this.getStorage();
|
const [storage, namespace] = await Promise.all([this.getStorage(), this.getNamespace()]);
|
||||||
return storage.getItem(key);
|
const { protocol = options.protocol, item } = this.getValueAndProtocol(
|
||||||
|
storage.getItem(`${options.namespace || namespace}:${key}`),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (item === null) return null;
|
||||||
|
|
||||||
|
switch (protocol) {
|
||||||
|
case Protocol.OBJECT:
|
||||||
|
// eslint-disable-next-line no-eval
|
||||||
|
return eval(`(${item})`);
|
||||||
|
case Protocol.JSON:
|
||||||
|
return JSON.parse(item);
|
||||||
|
case Protocol.NUMBER:
|
||||||
|
return Number(item);
|
||||||
|
case Protocol.BOOLEAN:
|
||||||
|
return Boolean(item);
|
||||||
|
default:
|
||||||
|
return item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 获取指定索引位置的key
|
* 获取指定索引位置的key
|
||||||
@ -42,20 +83,51 @@ export class WebStorage extends BaseService {
|
|||||||
const storage = await this.getStorage();
|
const storage = await this.getStorage();
|
||||||
return storage.key(index);
|
return storage.key(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除存储项,支持storageService.use
|
* 移除存储项,支持storageService.usePlugin
|
||||||
*/
|
*/
|
||||||
public async removeItem(key: string): Promise<void> {
|
public async removeItem(key: string, options: Options = {}): Promise<void> {
|
||||||
const storage = await this.getStorage();
|
const [storage, namespace] = await Promise.all([this.getStorage(), this.getNamespace()]);
|
||||||
storage.removeItem(key);
|
storage.removeItem(`${options.namespace || namespace}:${key}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置存储项,支持storageService.use
|
* 设置存储项,支持storageService.usePlugin
|
||||||
*/
|
*/
|
||||||
public async setItem(key: string, value: string): Promise<void> {
|
public async setItem(key: string, value: any, options: Options = {}): Promise<void> {
|
||||||
const storage = await this.getStorage();
|
const [storage, namespace] = await Promise.all([this.getStorage(), this.getNamespace()]);
|
||||||
storage.setItem(key, value);
|
let item = value;
|
||||||
|
const protocol = options.protocol ? `${options.protocol}:` : '';
|
||||||
|
if (typeof value === Protocol.STRING || typeof value === Protocol.NUMBER) {
|
||||||
|
item = `${protocol}${value}`;
|
||||||
|
} else {
|
||||||
|
item = `${protocol}${serialize(value)}`;
|
||||||
|
}
|
||||||
|
storage.setItem(`${options.namespace || namespace}:${key}`, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getValueAndProtocol(value: string | null) {
|
||||||
|
let protocol = '';
|
||||||
|
|
||||||
|
if (value === null) {
|
||||||
|
return {
|
||||||
|
item: value,
|
||||||
|
protocol,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = value.replace(new RegExp(`^(${Object.values(Protocol).join('|')})(:)(.+)`), (_$0, $1, _$2, $3) => {
|
||||||
|
protocol = $1;
|
||||||
|
return $3;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
protocol,
|
||||||
|
item,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StorageService = WebStorage;
|
export type StorageService = WebStorage;
|
||||||
export default new WebStorage();
|
export default new WebStorage();
|
||||||
|
@ -354,7 +354,7 @@ describe('copy', () => {
|
|||||||
const node = editorService.getNodeById(NodeId.NODE_ID2);
|
const node = editorService.getNodeById(NodeId.NODE_ID2);
|
||||||
await editorService.copy(node!);
|
await editorService.copy(node!);
|
||||||
const str = await storageService.getItem(COPY_STORAGE_KEY);
|
const str = await storageService.getItem(COPY_STORAGE_KEY);
|
||||||
expect(str).toBe(JSON.stringify([node]));
|
expect(str).toHaveLength(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -372,7 +372,7 @@ describe('paste', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('空', async () => {
|
test('空', async () => {
|
||||||
globalThis.localStorage.clear();
|
await storageService.clear();
|
||||||
const newNode = await editorService.paste({ left: 0, top: 0 });
|
const newNode = await editorService.paste({ left: 0, top: 0 });
|
||||||
expect(newNode).toBeUndefined();
|
expect(newNode).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user