Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(uip-editor): store editor state #780

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7c8dc7e
feat(uip-editor): store editor state
fshovchko Jun 27, 2024
06b246c
chore(uip-editor): code refactoring
fshovchko Jul 3, 2024
ab1ae15
chore(uip-editor): code refactoring
fshovchko Jul 3, 2024
ce6f1c7
Merge branch 'main' into feat/store-state
ala-n Nov 8, 2024
77cd6d1
chore(uip-editor): add reset button
fshovchko Nov 12, 2024
55a5d7e
chore(uip-editor): hide reset button if snippet is unmodified
fshovchko Nov 19, 2024
8b444ee
Merge branch 'main' into feat/store-state
ala-n Nov 27, 2024
7ff2cd8
chore(uip-editor): remove duplicate code
fshovchko Dec 3, 2024
63f85ed
Merge branch 'feat/store-state' of github.com:exadel-inc/ui-playgroun…
fshovchko Dec 3, 2024
c83116c
Merge branch 'main' into feat/store-state
ala-n Dec 3, 2024
81df5e6
chore(uip-editor): move logic to uip-model
fshovchko Dec 5, 2024
3467d7d
Merge branch 'feat/store-state' of github.com:exadel-inc/ui-playgroun…
fshovchko Dec 5, 2024
2f6bd92
chore(uip-editor): get rid of cyclic dependency
fshovchko Dec 10, 2024
d4f6f11
chore(uip-editor): code refactoring
fshovchko Dec 10, 2024
e3aa4a3
chore(uip-editor): code refactoring
fshovchko Dec 11, 2024
7d922fb
chore(uip-editor): code refactoring
fshovchko Dec 11, 2024
559f537
chore(uip-editor): code refactoring
fshovchko Dec 13, 2024
03cf84c
chore(uip-editor): code refactoring
fshovchko Dec 13, 2024
0ec11cb
Merge branch 'main' into feat/store-state
ala-n Dec 16, 2024
13920ba
chore(uip-editor): code refactoring
fshovchko Dec 18, 2024
d33cd14
Merge branch 'feat/store-state' of github.com:exadel-inc/ui-playgroun…
fshovchko Dec 18, 2024
d02fc15
chore(uip-editor): code refactoring
fshovchko Dec 18, 2024
af67d3e
chore(uip-editor): code refactoring
fshovchko Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}
Loading