Skip to content

Commit

Permalink
feat(uip-model): add ability to identify last state modifier; add mod…
Browse files Browse the repository at this point in the history
…el shorthand to uip-plugin
  • Loading branch information
nattallius committed Jun 22, 2021
1 parent 6d38c0c commit bdd846a
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 41 deletions.
14 changes: 10 additions & 4 deletions src/core/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import {attr, ESLBaseElement} from '@exadel/esl/modules/esl-base-element/core';
import {UIPRoot} from './root';
import {StateModelFiredObj} from './state-model';
import {UIPStateModel} from './state-model';

/**
* Base class for UI Playground plugins.
*
* Implements basic relation and styles
*/
export abstract class UIPPlugin extends ESLBaseElement {
static get observedAttributes() { return ['label']; }
static get observedAttributes() {
return ['label'];
}

private _root: UIPRoot | null;

Expand All @@ -25,11 +27,15 @@ export abstract class UIPPlugin extends ESLBaseElement {
this._root?.addStateListener(this._onRootStateChange);
}

protected get model(): UIPStateModel | null {
return this.root ? this.root.model : null
}

protected connectedCallback() {
super.connectedCallback();
this.classList.add('uip-plugin');
this.root = this.closest(`${UIPRoot.is}`) as UIPRoot;
this.root && this._onRootStateChange({markup: this.root.model.html});
this.root && this._onRootStateChange();
}
protected disconnectedCallback() {
this._root?.removeStateListener(this._onRootStateChange);
Expand All @@ -42,5 +48,5 @@ export abstract class UIPPlugin extends ESLBaseElement {
}

/** Handles root state change*/
protected _onRootStateChange(e: StateModelFiredObj): void {};
protected _onRootStateChange(): void {};
}
46 changes: 22 additions & 24 deletions src/core/state-model.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,53 @@
import {Observable} from '@exadel/esl';

export interface StateModelFiredObj {
markup: string,
}
import {UIPPlugin} from './plugin';

export class UIPStateModel extends Observable {
protected root: Element;

constructor() {
super();
this.root = new DOMParser().parseFromString('', 'text/html').body;
}
private _html = new DOMParser().parseFromString('', 'text/html').body;
private _lastModifier: UIPPlugin;

public set html(markup: string) {
public setHtml(markup: string, modifier: UIPPlugin) {
const root = new DOMParser().parseFromString(markup, 'text/html').body;
if (root.innerHTML !== this.root.innerHTML) {
this.root = root;
this.fire({markup: markup});
if (root.innerHTML !== this._html.innerHTML) {
this._html = root;
this._lastModifier = modifier;
this.fire();
}
}

public get html(): string {
return this.root ? this.root.innerHTML : '';
return this._html ? this._html.innerHTML : '';
}

public get lastModifier() {
return this._lastModifier;
}

public getAttribute(target: string, name: string): (string | null)[] {
return Array.from(this.root.querySelectorAll(target)).map(el => el.getAttribute(name));
return Array.from(this._html.querySelectorAll(target)).map(el => el.getAttribute(name));
}

public setAttribute(target: string, name: string, value: string | boolean): void {
const elements = Array.from(this.root.querySelectorAll(target));
public setAttribute(target: string, name: string, value: string | boolean, modifier: UIPPlugin): void {
const elements = Array.from(this._html.querySelectorAll(target));
if (!elements.length) return;

if (typeof value === 'string') {
elements.forEach(el => el.setAttribute(name, value));
} else {
elements.forEach(el => value ? el.setAttribute(name, '') : el.removeAttribute(name));
}

this.fire({markup: this.html});
this._lastModifier = modifier;
this.fire();
}

public transformAttribute(target: string, name: string, transform: (current: string | null) => string | null) {
const elements = Array.from(this.root.querySelectorAll(target));
public transformAttribute(target: string, name: string, transform: (current: string | null) => string | null, modifier: UIPPlugin) {
const elements = Array.from(this._html.querySelectorAll(target));
if (!elements.length) return;

elements.forEach(el => {
const transformed = transform(el.getAttribute(name));
transformed === null ? el.removeAttribute(name) : el.setAttribute(name, transformed);
});

this.fire({markup: this.html});
this._lastModifier = modifier;
this.fire();
}
}
9 changes: 4 additions & 5 deletions src/editor/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {debounce} from '@exadel/esl/modules/esl-utils/async/debounce';
import {jsonAttr} from '@exadel/esl/modules/esl-base-element/core';

import {UIPPlugin} from '../core/plugin';
import {StateModelFiredObj} from '../core/state-model';

interface EditorConfig {
theme: string;
Expand Down Expand Up @@ -41,14 +40,14 @@ export class UIPEditor extends UIPPlugin {
}

protected onChange = debounce(() => {
this.root!.model.html = this.editor.getValue();
this.model!.setHtml(this.editor.getValue(), this);
}, 1000);

@bind
protected _onRootStateChange(e: StateModelFiredObj): void {
const {markup} = e;
if (this.editor && markup === this.editor.getValue()) return; // check for self triggered changes
protected _onRootStateChange(): void {
if (this.model!.lastModifier === this) return;

const markup = this.model!.html;
const $inner = document.createElement('div');
$inner.classList.add('uip-editor-inner');

Expand Down
2 changes: 1 addition & 1 deletion src/preview/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class UIPPreview extends UIPPlugin {

@bind
protected _onRootStateChange(): void {
this.$inner.innerHTML = this.root!.model.html;
this.$inner.innerHTML = this.model!.html;
this.innerHTML = '';
this.appendChild(this.$inner);
}
Expand Down
2 changes: 1 addition & 1 deletion src/settings/setting/select-setting/select-setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export class UIPSelectSetting extends UIPSetting {
val && attrTokens.push(val);

return TokenListUtils.join(attrTokens);
});
}, this.settings);
}

updateFrom(model: UIPStateModel) {
Expand Down
6 changes: 5 additions & 1 deletion src/settings/setting/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export abstract class UIPSetting extends ESLBaseElement {
return this.closest(UIPSettings.is);
}

public get settings() {
return this.settingContainer as UIPSettings;
}

protected connectedCallback() {
super.connectedCallback();
this.classList.add(UIPSetting.is);
Expand Down Expand Up @@ -47,7 +51,7 @@ export abstract class UIPSetting extends ESLBaseElement {
}

public applyTo(model: UIPStateModel): void {
this.isValid() ? model.setAttribute(this.target, this.attribute, this.getDisplayedValue()) :
this.isValid() ? model.setAttribute(this.target, this.attribute, this.getDisplayedValue(), this.settings) :
this.setInconsistency(WARN.invalid);
}

Expand Down
6 changes: 3 additions & 3 deletions src/settings/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export class UIPSettings extends UIPPlugin {

protected _onSettingChanged(e: any) {
e.stopPropagation();
if (!this.root) return;
(e.target as UIPSetting).applyTo(this.root.model);
if (!this.model) return;
(e.target as UIPSetting).applyTo(this.model);
}

protected get settings(): UIPSetting[] {
Expand All @@ -43,7 +43,7 @@ export class UIPSettings extends UIPPlugin {

@bind
protected _onRootStateChange(): void {
this.settings.forEach(setting => setting.updateFrom(this.root!.model));
this.settings.forEach(setting => setting.updateFrom(this.model!));
}
}

4 changes: 2 additions & 2 deletions src/snippets/snippets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ export class UIPSnippets extends UIPPlugin {

protected applyActive(): void {
const tmpl = this.$active?.querySelector('template[uip-snippet]');
if (!tmpl || !this.root) return;
this.root.model.html = tmpl.innerHTML;
if (!tmpl || !this.model) return;
this.model.setHtml(tmpl.innerHTML, this);
}

@bind
Expand Down

0 comments on commit bdd846a

Please sign in to comment.