From 56f3766a13d83478df7e8d12373d6f7d650b9bd7 Mon Sep 17 00:00:00 2001 From: Misode Date: Mon, 25 May 2020 14:45:10 +0200 Subject: [PATCH] Update model and add invalidated cycle --- src/app/app.ts | 8 ++++---- src/model/DataModel.ts | 27 +++++++++++++++++++++++++++ src/model/Path.ts | 12 +++++++++++- src/nodes/AbstractNode.ts | 1 - src/nodes/EnumNode.ts | 6 ++++-- src/nodes/StringNode.ts | 1 + src/view/SourceView.ts | 18 ++++++++++++------ src/view/TreeView.ts | 19 +++++++++++++------ tsconfig.json | 1 + 9 files changed, 73 insertions(+), 20 deletions(-) diff --git a/src/app/app.ts b/src/app/app.ts index aa2e1893..9e37b8dc 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -21,8 +21,8 @@ const predicateTree = new RootNode('predicate', { }); const model = new DataModel(predicateTree) -const treeView = new TreeView(model) -const sourceView = new SourceView(model) -treeView.render(document!.getElementById('view')!) -sourceView.render(document!.getElementById('source')!) +new TreeView(model, document!.getElementById('view')!) +new SourceView(model, document!.getElementById('source')!) + +model.invalidate() diff --git a/src/model/DataModel.ts b/src/model/DataModel.ts index ff7e4e69..0f9112f1 100644 --- a/src/model/DataModel.ts +++ b/src/model/DataModel.ts @@ -1,12 +1,39 @@ import { RootNode } from "../nodes/RootNode" import { Path } from "./Path" +export interface ModelListener { + invalidated(model: DataModel): void +} + export class DataModel { data: any schema: RootNode + listeners: ModelListener[] constructor(schema: RootNode) { this.schema = schema this.data = schema.default + this.listeners = [] + } + + addListener(listener: ModelListener) { + this.listeners.push(listener) + } + + invalidate() { + this.listeners.forEach(listener => listener.invalidated(this)) + } + + set(path: Path, value: any) { + let node = this.data; + for (let index of path.pop()) { + if (node[index] === undefined) { + node[index] = {} + } + node = node[index] + } + node[path.last()] = value + + this.invalidate() } } diff --git a/src/model/Path.ts b/src/model/Path.ts index 14ece07a..b55017a1 100644 --- a/src/model/Path.ts +++ b/src/model/Path.ts @@ -1,7 +1,7 @@ type PathElement = (string | number) -export class Path { +export class Path implements Iterable { private arr: PathElement[] constructor(arr?: PathElement[]) { @@ -23,4 +23,14 @@ export class Path { copy(): Path { return new Path([...this.arr]) } + + toString(): string { + return `[${this.arr.map(e => e.toString()).join(', ')}]` + } + + *[Symbol.iterator]() { + for (const e of this.arr) { + yield e + } + } } diff --git a/src/nodes/AbstractNode.ts b/src/nodes/AbstractNode.ts index 1404774d..17d8fc38 100644 --- a/src/nodes/AbstractNode.ts +++ b/src/nodes/AbstractNode.ts @@ -33,7 +33,6 @@ export abstract class AbstractNode implements INode { wrap(path: Path, view: TreeView, renderResult: string): string { const id = view.register(el => { - console.log(`Callback ${id} -> ${path.last()}`) this.mounted(el, path, view) }) return `
${renderResult}
` diff --git a/src/nodes/EnumNode.ts b/src/nodes/EnumNode.ts index 81c75dba..d9b021c3 100644 --- a/src/nodes/EnumNode.ts +++ b/src/nodes/EnumNode.ts @@ -12,12 +12,14 @@ export class EnumNode extends AbstractNode { } updateModel(el: Element, path: Path, model: DataModel) { + model.set(path, el.querySelector('select')?.value) } render(path: Path, value: string, view: TreeView) { + const id = view.register(el => (el as HTMLInputElement).value = value) return this.wrap(path, view, `${path.last()} - + ${this.options.map(o => ``).join('')} `) } } diff --git a/src/nodes/StringNode.ts b/src/nodes/StringNode.ts index 4adaf591..0cd1aff8 100644 --- a/src/nodes/StringNode.ts +++ b/src/nodes/StringNode.ts @@ -9,6 +9,7 @@ export class StringNode extends AbstractNode { } updateModel(el: Element, path: Path, model: DataModel) { + model.set(path, el.querySelector('input')?.value) } render(path: Path, value: string, view: TreeView) { diff --git a/src/view/SourceView.ts b/src/view/SourceView.ts index f364d8d2..54b3bb92 100644 --- a/src/view/SourceView.ts +++ b/src/view/SourceView.ts @@ -1,14 +1,20 @@ -import { DataModel } from "../model/DataModel" -import { Path } from "../model/Path" +import { DataModel, ModelListener } from "../model/DataModel" -export class SourceView { +export class SourceView implements ModelListener { model: DataModel + target: HTMLElement - constructor(model: DataModel) { + constructor(model: DataModel, target: HTMLElement) { this.model = model + this.target = target + model.addListener(this) } - render(target: HTMLElement) { - target.textContent = this.model.schema.transform(this.model.data) + render() { + this.target.textContent = this.model.schema.transform(this.model.data) + } + + invalidated() { + this.render() } } diff --git a/src/view/TreeView.ts b/src/view/TreeView.ts index a14f335c..f4434d5d 100644 --- a/src/view/TreeView.ts +++ b/src/view/TreeView.ts @@ -1,4 +1,4 @@ -import { DataModel } from "../model/DataModel" +import { DataModel, ModelListener } from "../model/DataModel" import { Path } from "../model/Path" type Registry = { @@ -14,12 +14,15 @@ export function getId() { return Array.from(arr, dec2hex).join('') } -export class TreeView { +export class TreeView implements ModelListener { model: DataModel + target: HTMLElement registry: Registry = {} - constructor(model: DataModel) { + constructor(model: DataModel, target: HTMLElement) { this.model = model + this.target = target + model.addListener(this) } register(callback: (el: Element) => void): string { @@ -28,11 +31,15 @@ export class TreeView { return id } - render(target: HTMLElement) { - target.innerHTML = this.model.schema.render(new Path(), this.model.data, this) + render() { + this.target.innerHTML = this.model.schema.render(new Path(), this.model.data, this) for (const id in this.registry) { - const element = target.querySelector(`[data-id="${id}"]`) + const element = this.target.querySelector(`[data-id="${id}"]`) if (element !== null) this.registry[id](element) } } + + invalidated(model: DataModel) { + this.render() + } } diff --git a/tsconfig.json b/tsconfig.json index ea849705..32e592d6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "module": "esnext", "strict": true, "esModuleInterop": true, + "downlevelIteration": true, "forceConsistentCasingInFileNames": true }, "include": [