Skip to content

Commit

Permalink
feat(uip-editor): store editor state
Browse files Browse the repository at this point in the history
  • Loading branch information
fshovchko committed Jun 27, 2024
1 parent 9faef4e commit 7c8dc7e
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 4 deletions.
11 changes: 7 additions & 4 deletions src/core/base/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import {
memoize,
boolAttr,
listen,
prop
prop,
attr
} from '@exadel/esl/modules/esl-utils/decorators';

import {sequentialUID} from '@exadel/esl/modules/esl-utils/misc';
import {UIPStateModel} from './model';

import type {UIPSnippetTemplate} from './snippet';
Expand Down Expand Up @@ -33,6 +34,8 @@ export class UIPRoot extends ESLBaseElement {
/** CSS query for snippets */
public static SNIPPET_SEL = '[uip-snippet]';

@attr() public uipId: string = sequentialUID(UIPRoot.is);

/** Indicates that the UIP components' theme is dark */
@boolAttr() public darkTheme: boolean;

Expand All @@ -50,7 +53,7 @@ export class UIPRoot extends ESLBaseElement {
return Array.from(this.querySelectorAll(UIPRoot.SNIPPET_SEL));
}

protected delyedScrollIntoView(): void {
protected delayedScrollIntoView(): void {
setTimeout(() => {
this.scrollIntoView({behavior: 'smooth', block: 'start'});
}, 100);
Expand All @@ -64,7 +67,7 @@ export class UIPRoot extends ESLBaseElement {
this.$$fire(this.READY_EVENT, {bubbles: false});

if (this.model.anchorSnippet) {
this.delyedScrollIntoView();
this.delayedScrollIntoView();
}
}

Expand Down
39 changes: 39 additions & 0 deletions src/plugins/editor/editor-storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
interface EditorStorageEntry {
ts: string;
data: string;
}

export class EditorStorage {
public static readonly STORAGE_KEY = 'uip-editor-storage';

protected static get(): Record<string, any> {
return JSON.parse(localStorage.getItem(EditorStorage.STORAGE_KEY) || '{}');
}

protected static set(value: Record<string, any>): void {
localStorage.setItem(EditorStorage.STORAGE_KEY, JSON.stringify(value));
}

protected static serializeWithPathname(key: string): string {
return JSON.stringify({path: location.pathname, key});
}

public static save(key: string, value: string): void {
const state = {[EditorStorage.serializeWithPathname(key)]: {ts: Date.now(), value}};
EditorStorage.set(Object.assign(EditorStorage.get(), state));
}

public static load(key: string): string | null {
const entry = EditorStorage.get()[EditorStorage.serializeWithPathname(key)] || {} as EditorStorageEntry;
const expirationTime = 3600000 * 12;
if (entry?.ts + expirationTime > Date.now()) return entry.value || null;
EditorStorage.remove(key);
return null;
}

public static remove(key: string): void {
const data = EditorStorage.get();
delete data[key];
EditorStorage.set(data);
}
}
20 changes: 20 additions & 0 deletions src/plugins/editor/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {attr, boolAttr, decorate, listen, memoize} from '@exadel/esl/modules/esl
import {UIPPluginPanel} from '../../core/panel/plugin-panel';
import {CopyIcon} from '../copy/copy-button.icon';

import {EditorStorage} from './editor-storage';
import {EditorIcon} from './editor.icon';

import type {UIPSnippetsList} from '../snippets-list/snippets-list';
Expand Down Expand Up @@ -165,12 +166,31 @@ export class UIPEditor extends UIPPluginPanel {
case 'html':
if (e && !e.htmlChanges.length) return;
this.value = this.model!.html;
if (e && !e.force) this.saveState();
}
}

protected saveState(): void {
const key = this.getStateKey();
if (key && this.value) EditorStorage.save(key, this.value);
}

protected getStateKey(): string | null {
if (!this.model?.activeSnippet || !this.$root) return null;
return JSON.stringify({html: this.model.activeSnippet.html, id: this.$root.uipId});
}

/** Handles snippet change to set readonly value */
@listen({event: 'uip:snippet:change', target: ($this: UIPSnippetsList) => $this.$root})
protected _onSnippetChange(): void {
this.editable = this.isSnippetEditable;
this.loadState();
}

protected loadState(): void {
if (!this.model?.activeSnippet) return;
const key = this.getStateKey();
const state = key && EditorStorage.load(key);
if (state) this.model.setHtml(state, this);
}
}

0 comments on commit 7c8dc7e

Please # to comment.