Skip to content

Commit e3aa4a3

Browse files
committed
chore(uip-editor): code refactoring
1 parent d4f6f11 commit e3aa4a3

File tree

10 files changed

+59
-74
lines changed

10 files changed

+59
-74
lines changed

src/core/base/model.change.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import {overrideEvent} from '@exadel/esl/modules/esl-utils/dom';
33
import type {UIPPlugin} from './plugin';
44
import type {UIPRoot} from './root';
55
import type {UIPStateModel} from './model';
6+
import type {UIPSource} from './source';
67

78
export type UIPChangeInfo = {
89
modifier: UIPPlugin | UIPRoot;
9-
type: 'html' | 'js' | 'note';
10+
type: UIPSource;
1011
force?: boolean;
1112
};
1213

src/core/base/model.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type {UIPRoot} from './root';
1414
import type {UIPPlugin} from './plugin';
1515
import type {UIPSnippetTemplate} from './snippet';
1616
import type {UIPChangeInfo} from './model.change';
17+
import type {UIPEditableSource} from './source';
1718

1819
/** Type for function to change attribute's current value */
1920
export type TransformSignature = (
@@ -125,7 +126,7 @@ export class UIPStateModel extends SyntheticEventTarget {
125126
return this.normalizeJS(this.activeSnippet.js) !== this.js;
126127
}
127128

128-
public resetSnippet(source: 'js' | 'html', modifier: UIPPlugin | UIPRoot): void {
129+
public reset(source: UIPEditableSource, modifier: UIPPlugin | UIPRoot): void {
129130
if (source === 'html') this.resetHTML(modifier);
130131
if (source === 'js') this.resetJS(modifier);
131132
}

src/core/base/root.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99

1010
import {UIPStateModel} from './model';
1111
import {UIPChangeEvent} from './model.change';
12-
import {UIPStateStorage} from './model.storage';
12+
import {UIPStateStorage} from './state.storage';
1313

1414
import type {UIPChangeInfo} from './model.change';
1515
import type {UIPSnippetTemplate} from './snippet';
@@ -41,7 +41,7 @@ export class UIPRoot extends ESLBaseElement {
4141
/** Key to store UIP state in the local storage */
4242
@attr({defaultValue: ''}) public storeKey: string;
4343
/** State storage based on `storeKey` */
44-
protected storage: UIPStateStorage;
44+
public storage: UIPStateStorage | undefined;
4545

4646
/** Indicates ready state of the uip-root */
4747
@boolAttr({readonly: true}) public ready: boolean;
@@ -65,7 +65,7 @@ export class UIPRoot extends ESLBaseElement {
6565

6666
protected override connectedCallback(): void {
6767
super.connectedCallback();
68-
this.storage = new UIPStateStorage(this.storeKey, this.model);
68+
if (this.storeKey) this.storage = new UIPStateStorage(this.storeKey, this);
6969

7070
this.model.snippets = this.$snippets;
7171
this.model.applyCurrentSnippet(this);
@@ -96,21 +96,8 @@ export class UIPRoot extends ESLBaseElement {
9696
}
9797
}
9898

99-
public resetSnippet(source: 'js' | 'html'): void {
100-
this.storage.resetState(source, this);
101-
}
102-
103-
public applySnippet(): void {
104-
this.storage.loadState(this);
105-
}
106-
107-
public saveSnippet(): void {
108-
this.storage.saveState();
109-
}
110-
11199
@listen({event: 'uip:model:change', target: ($this: UIPRoot) => $this.model})
112100
protected onModelChange({detail}: CustomEvent<UIPChangeInfo[]>): void {
113-
this.saveSnippet();
114101
this.dispatchEvent(new UIPChangeEvent(this.CHANGE_EVENT, this, detail));
115102
}
116103

@@ -119,7 +106,6 @@ export class UIPRoot extends ESLBaseElement {
119106
target: ($this: UIPRoot) => $this.model
120107
})
121108
protected onSnippetChange({detail}: CustomEvent): void {
122-
this.applySnippet();
123109
this.$$fire(this.SNIPPET_CHANGE_EVENT, {detail, bubbles: false});
124110
}
125111
}

src/core/base/source.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type UIPEditableSource = 'js' | 'html';
2+
3+
export type UIPSource = UIPEditableSource | 'note';
Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type {UIPStateModel} from './model';
2-
import type {UIPPlugin} from './plugin';
32
import type {UIPRoot} from './root';
3+
import type {UIPEditableSource} from './source';
44

55
interface UIPStateStorageEntry {
66
ts: string;
@@ -18,30 +18,40 @@ export class UIPStateStorage {
1818

1919
protected static readonly EXPIRATION_TIME = 3600000 * 12; // 12 hours
2020

21-
public constructor(protected storeKey: string, protected model: UIPStateModel) {}
21+
protected model: UIPStateModel;
22+
23+
public constructor(protected storeKey: string, protected root: UIPRoot) {
24+
this.model = root.model;
25+
this.addEventListeners();
26+
}
27+
28+
protected addEventListeners(): void {
29+
this.model.addEventListener('uip:model:change', () => this.saveState());
30+
this.model.addEventListener('uip:model:snippet:change', () => this.loadState());
31+
}
2232

2333
protected loadEntry(key: string): string | null {
24-
const entry = (this.lsGet()[key] || {}) as UIPStateStorageEntry;
34+
const entry = (this.lsState[key] || {}) as UIPStateStorageEntry;
2535
if (parseInt(entry?.ts, 10) + UIPStateStorage.EXPIRATION_TIME > Date.now()) return entry.snippets || null;
2636
this.removeEntry(key);
2737
return null;
2838
}
2939

3040
protected saveEntry(key: string, value: string): void {
31-
this.lsSet(Object.assign(this.lsGet(), {[key]: {ts: Date.now(), snippets: value}}));
41+
this.lsState = Object.assign(this.lsState, {[key]: {ts: Date.now(), snippets: value}});
3242
}
3343

3444
protected removeEntry(key: string): void {
35-
const data = this.lsGet();
36-
delete data[key];
37-
this.lsSet(data);
45+
const data = this.lsState;
46+
delete this.lsState[key];
47+
this.lsState = data;
3848
}
3949

40-
protected lsGet(): Record<string, any> {
50+
protected get lsState(): Record<string, any> {
4151
return JSON.parse(localStorage.getItem(UIPStateStorage.STORAGE_KEY) || '{}');
4252
}
43-
44-
protected lsSet(value: Record<string, any>): void {
53+
54+
protected set lsState(value: Record<string, any>) {
4555
localStorage.setItem(UIPStateStorage.STORAGE_KEY, JSON.stringify(value));
4656
}
4757

@@ -51,15 +61,15 @@ export class UIPStateStorage {
5161
return JSON.stringify({key: this.storeKey, snippet: activeSnippet.html});
5262
}
5363

54-
public loadState(initiator: UIPPlugin | UIPRoot): void {
64+
public loadState(): void {
5565
const stateKey = this.getStateKey();
5666
const state = stateKey && this.loadEntry(stateKey);
5767
if (!state) return;
5868

59-
const stateobj = JSON.parse(state);
60-
this.model.setHtml(stateobj.html, initiator, true);
61-
this.model.setJS(stateobj.js, initiator);
62-
this.model.setNote(stateobj.note, initiator);
69+
const stateobj = JSON.parse(state) as UIPStateModelSnippets;
70+
this.model.setHtml(stateobj.html, this.root, true);
71+
this.model.setJS(stateobj.js, this.root);
72+
this.model.setNote(stateobj.note, this.root);
6373
}
6474

6575
public saveState(): void {
@@ -68,10 +78,10 @@ export class UIPStateStorage {
6878
stateKey && this.saveEntry(stateKey, JSON.stringify({js, html, note}));
6979
}
7080

71-
public resetState(source: 'js' | 'html', modifier: UIPPlugin | UIPRoot): void {
81+
public resetState(source: UIPEditableSource): void {
7282
const stateKey = this.getStateKey();
7383
stateKey && this.removeEntry(stateKey);
7484

75-
this.model.resetSnippet(source, modifier);
85+
this.model.reset(source, this.root);
7686
}
7787
}

src/plugins/copy/copy-button.shape.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import type {ESLBaseElementShape} from '@exadel/esl/modules/esl-base-element/core';
22
import type {UIPCopy} from './copy-button';
3+
import type {UIPEditableSource} from '../../core/base/source';
34

45
export interface UIPCopyShape extends ESLBaseElementShape<UIPCopy> {
5-
source?: 'javascript' | 'js' | 'html';
6+
source?: UIPEditableSource;
67
children?: any;
78
}
89

src/plugins/copy/copy-button.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import {attr} from '@exadel/esl/modules/esl-utils/decorators';
44
import {UIPPluginButton} from '../../core/button/plugin-button';
55

66
import type {ESLAlertActionParams} from '@exadel/esl/modules/esl-alert/core';
7+
import type {UIPEditableSource} from '../../core/base/source';
78

89
/** Button-plugin to copy snippet to clipboard */
910
export class UIPCopy extends UIPPluginButton {
1011
public static override is = 'uip-copy';
1112
public static override defaultTitle = 'Copy to clipboard';
1213

1314
/** Source type to copy (html | js) */
14-
@attr({defaultValue: 'html'}) public source: string;
15+
@attr({defaultValue: 'html'}) public source: UIPEditableSource;
1516

1617
public static msgConfig: ESLAlertActionParams = {
1718
text: 'Playground content copied to clipboard',
@@ -20,14 +21,7 @@ export class UIPCopy extends UIPPluginButton {
2021

2122
/** Content to copy */
2223
protected get content(): string | undefined {
23-
switch (this.source) {
24-
case 'js':
25-
case 'javascript':
26-
return this.model?.js;
27-
case 'html':
28-
default:
29-
return this.model?.html;
30-
}
24+
if (this.source === 'js' || this.source === 'html') return this.model?.[this.source];
3125
}
3226

3327
protected override connectedCallback(): void {

src/plugins/editor/editor.tsx

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {EditorIcon} from './editor.icon';
1717

1818
import type {UIPSnippetsList} from '../snippets-list/snippets-list';
1919
import type {UIPChangeEvent} from '../../core/base/model.change';
20+
import type {UIPEditableSource} from '../../core/base/source';
2021

2122
/**
2223
* Editor {@link UIPPlugin} custom element definition
@@ -30,7 +31,7 @@ export class UIPEditor extends UIPPluginPanel {
3031
public static highlight = (editor: HTMLElement): void => Prism.highlightElement(editor, false);
3132

3233
/** Source for Editor plugin (default: 'html') */
33-
@attr({defaultValue: 'html'}) public source: 'js' | 'javascript' | 'html';
34+
@attr({defaultValue: 'html'}) public source: UIPEditableSource;
3435

3536
/** Marker to display copy widget */
3637
@boolAttr({name: 'copy'}) public showCopy: boolean;
@@ -143,30 +144,19 @@ export class UIPEditor extends UIPPluginPanel {
143144
@decorate(debounce, 2000)
144145
protected _onChange(): void {
145146
if (!this.editable) return;
146-
switch (this.source) {
147-
case 'js':
148-
case 'javascript':
149-
this.model!.setJS(this.value, this);
150-
break;
151-
case 'html':
152-
this.model!.setHtml(this.value, this);
153-
}
147+
if (this.source === 'js') this.model!.setJS(this.value, this);
148+
if (this.source === 'html') this.model!.setHtml(this.value, this);
154149
}
155150

156151
/** Change editor's markup from markup state changes */
157152
@listen({event: 'uip:change', target: ($this: UIPEditor) => $this.$root})
158153
protected _onRootStateChange(e?: UIPChangeEvent): void {
159154
if (e && e.isOnlyModifier(this)) return;
160-
switch (this.source) {
161-
case 'js':
162-
case 'javascript':
163-
if (e && !e.jsChanges.length) return;
164-
this.value = this.model!.js;
165-
break;
166-
case 'html':
167-
if (e && !e.htmlChanges.length) return;
168-
this.value = this.model!.html;
169-
}
155+
156+
if (
157+
(this.source === 'js' && (!e || e.jsChanges.length)) ||
158+
(this.source === 'html' && (!e || e.htmlChanges.length))
159+
) this.value = this.model![this.source];
170160
}
171161

172162
/** Handles snippet change to set readonly value */

src/plugins/reset/reset-button.shape.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import type {ESLBaseElementShape} from '@exadel/esl/modules/esl-base-element/core';
22
import type {UIPReset} from './reset-button';
3+
import type {UIPEditableSource} from '../../core/base/source';
34

45
export interface UIPResetShape extends ESLBaseElementShape<UIPReset> {
5-
source?: 'javascript' | 'js' | 'html';
6+
source?: UIPEditableSource;
67
children?: any;
78
}
89

src/plugins/reset/reset-button.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,25 @@ import {listen, attr, boolAttr} from '@exadel/esl/modules/esl-utils/decorators';
55
import {UIPPluginButton} from '../../core/button/plugin-button';
66
import {UIPRoot} from '../../core/base/root';
77

8+
import type {UIPEditableSource} from '../../core/base/source';
9+
810
/** Button-plugin to reset snippet to default settings */
911
export class UIPReset extends UIPPluginButton {
1012
public static override is = 'uip-reset';
1113

1214
@boolAttr() public disabled: boolean;
1315

1416
/** Source type to copy (html | js) */
15-
@attr({defaultValue: 'html'}) public source: 'js' | 'javascript' | 'html';
16-
17-
protected get actualSrc(): 'js' | 'html' {
18-
return this.source === 'javascript' ? 'js' : this.source;
19-
}
17+
@attr({defaultValue: 'html'}) public source: UIPEditableSource;
2018

2119
public override onAction(): void {
22-
this.$root?.resetSnippet(this.actualSrc);
20+
this.$root?.storage!.resetState(this.source);
2321
}
2422

2523
@listen({event: 'uip:model:change', target: ($this: UIPRoot) => $this.model})
2624
protected onModelChange(): void {
2725
if (!this.model || !this.model.activeSnippet) return;
28-
if (this.actualSrc === 'js') this.disabled = !this.model.isJSChanged();
29-
if (this.actualSrc === 'html') this.disabled = !this.model.isHTMLChanged();
26+
if (this.source === 'js') this.disabled = !this.model.isJSChanged();
27+
if (this.source === 'html') this.disabled = !this.model.isHTMLChanged();
3028
}
3129
}

0 commit comments

Comments
 (0)