From 79a5742dad3f3cca5a80273a85f34e2de29fe444 Mon Sep 17 00:00:00 2001 From: Misode Date: Mon, 25 May 2020 13:22:36 +0200 Subject: [PATCH] Add view classes --- src/app/app.ts | 12 +++++++----- src/model/DataModel.ts | 30 ++---------------------------- src/nodes/AbstractNode.ts | 18 +++++++++--------- src/nodes/EnumNode.ts | 5 +++-- src/nodes/ObjectNode.ts | 8 ++++---- src/nodes/RootNode.ts | 6 +++--- src/nodes/StringNode.ts | 5 +++-- src/view/SourceView.ts | 14 ++++++++++++++ src/view/TreeView.ts | 38 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 83 insertions(+), 53 deletions(-) create mode 100644 src/view/SourceView.ts create mode 100644 src/view/TreeView.ts diff --git a/src/app/app.ts b/src/app/app.ts index f323c857..aa2e1893 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -3,7 +3,8 @@ import { EnumNode } from '../nodes/EnumNode' import { ObjectNode } from '../nodes/ObjectNode' import { StringNode } from '../nodes/StringNode' import { DataModel } from '../model/DataModel' - +import { TreeView } from '../view/TreeView' +import { SourceView } from '../view/SourceView' const EntityCollection = ['sheep', 'pig'] @@ -12,7 +13,7 @@ const predicateTree = new RootNode('predicate', { transform: (s: string) => (s === 'foo') ? {test: 'baz'} : s }), predicate: new ObjectNode({ - type: new EnumNode(EntityCollection, {}), + type: new EnumNode(EntityCollection), nbt: new StringNode() }) }, { @@ -20,7 +21,8 @@ const predicateTree = new RootNode('predicate', { }); const model = new DataModel(predicateTree) +const treeView = new TreeView(model) +const sourceView = new SourceView(model) -model.render(document!.getElementById('view')!) - -// document!.getElementById('source')!.textContent = predicateTree.transform(dummyData) +treeView.render(document!.getElementById('view')!) +sourceView.render(document!.getElementById('source')!) diff --git a/src/model/DataModel.ts b/src/model/DataModel.ts index 0f0ed496..ff7e4e69 100644 --- a/src/model/DataModel.ts +++ b/src/model/DataModel.ts @@ -1,38 +1,12 @@ import { RootNode } from "../nodes/RootNode" import { Path } from "./Path" -type Registry = { - [id: string]: (el: Element) => void -} - -const registryIdLength = 12 -const dec2hex = (dec: number) => ('0' + dec.toString(16)).substr(-2) - -export function getId() { - var arr = new Uint8Array((registryIdLength || 40) / 2) - window.crypto.getRandomValues(arr) - return Array.from(arr, dec2hex).join('') -} - export class DataModel { - private data: any - private schema: RootNode - private registry: Registry = {} + data: any + schema: RootNode constructor(schema: RootNode) { this.schema = schema this.data = schema.default } - - register(id: string, callback: (el: Element) => void) { - this.registry[id] = callback - } - - render(target: HTMLElement) { - target.innerHTML = this.schema.render(new Path(), this.data, this) - for (const id in this.registry) { - const element = target.querySelector(`[data-id="${id}"]`) - if (element !== null) this.registry[id](element) - } - } } diff --git a/src/nodes/AbstractNode.ts b/src/nodes/AbstractNode.ts index c2b20b88..1404774d 100644 --- a/src/nodes/AbstractNode.ts +++ b/src/nodes/AbstractNode.ts @@ -1,10 +1,11 @@ -import { DataModel, getId } from "../model/DataModel" +import { DataModel } from "../model/DataModel" import { Path } from "../model/Path" +import { TreeView } from "../view/TreeView" export interface INode { setParent: (parent: INode) => void transform: (value: T) => any - render: (path: Path, value: T, model: DataModel) => string + render: (path: Path, value: T, view: TreeView) => string } export type NodeChildren = { @@ -30,17 +31,16 @@ export abstract class AbstractNode implements INode { this.parent = parent } - wrap(path: Path, model: DataModel, renderResult: string): string { - const id = getId() - model.register(id, el => { + wrap(path: Path, view: TreeView, renderResult: string): string { + const id = view.register(el => { console.log(`Callback ${id} -> ${path.last()}`) - this.mounted(el, path, model) + this.mounted(el, path, view) }) return `
${renderResult}
` } - mounted(el: Element, path: Path, model: DataModel) { - el.addEventListener('change', evt => this.updateModel(el, path, model)) + mounted(el: Element, path: Path, view: TreeView) { + el.addEventListener('change', evt => this.updateModel(el, path, view.model)) } updateModel(el: Element, path: Path, model: DataModel) {} @@ -49,5 +49,5 @@ export abstract class AbstractNode implements INode { return this.transformMod(value) } - abstract render(path: Path, value: T, model: DataModel): string + abstract render(path: Path, value: T, view: TreeView): string } diff --git a/src/nodes/EnumNode.ts b/src/nodes/EnumNode.ts index 452f971c..81c75dba 100644 --- a/src/nodes/EnumNode.ts +++ b/src/nodes/EnumNode.ts @@ -1,5 +1,6 @@ import { AbstractNode, NodeMods } from './AbstractNode' import { DataModel } from '../model/DataModel' +import { TreeView } from '../view/TreeView' import { Path } from '../model/Path' export class EnumNode extends AbstractNode { @@ -13,8 +14,8 @@ export class EnumNode extends AbstractNode { updateModel(el: Element, path: Path, model: DataModel) { } - render(path: Path, value: string, model: DataModel) { - return this.wrap(path, model, `${path.last()} + render(path: Path, value: string, view: TreeView) { + return this.wrap(path, view, `${path.last()} `) diff --git a/src/nodes/ObjectNode.ts b/src/nodes/ObjectNode.ts index c47c2446..66d441e9 100644 --- a/src/nodes/ObjectNode.ts +++ b/src/nodes/ObjectNode.ts @@ -1,5 +1,5 @@ import { AbstractNode, NodeChildren, NodeMods } from './AbstractNode' -import { DataModel } from '../model/DataModel' +import { TreeView } from '../view/TreeView' import { Path } from '../model/Path' export interface IObject { @@ -27,11 +27,11 @@ export class ObjectNode extends AbstractNode { return res; } - render(path: Path, value: IObject, model: DataModel) { + render(path: Path, value: IObject, view: TreeView) { if (value === undefined) return `` - return this.wrap(path, model, `${path.last()}:
+ return this.wrap(path, view, `${path.last()}:
${Object.keys(this.fields).map(f => { - return this.fields[f].render(path.push(f), value[f], model) + return this.fields[f].render(path.push(f), value[f], view) }).join('')}
`) } diff --git a/src/nodes/RootNode.ts b/src/nodes/RootNode.ts index c84df6ca..19099d38 100644 --- a/src/nodes/RootNode.ts +++ b/src/nodes/RootNode.ts @@ -1,7 +1,7 @@ import { NodeChildren, NodeMods } from './AbstractNode' import { ObjectNode, IObject } from './ObjectNode' import { Path } from '../model/Path' -import { DataModel } from '../model/DataModel' +import { TreeView } from '../view/TreeView' export class RootNode extends ObjectNode { id: string @@ -15,11 +15,11 @@ export class RootNode extends ObjectNode { return JSON.stringify(super.transform(value)) } - render(path: Path, value: IObject, model: DataModel) { + render(path: Path, value: IObject, view: TreeView) { value = value || {} return `
${Object.keys(this.fields).map(f => { - return this.fields[f].render(path.push(f), value[f], model) + return this.fields[f].render(path.push(f), value[f], view) }).join('')}
` } diff --git a/src/nodes/StringNode.ts b/src/nodes/StringNode.ts index 7ebb8f21..4adaf591 100644 --- a/src/nodes/StringNode.ts +++ b/src/nodes/StringNode.ts @@ -1,6 +1,7 @@ import { AbstractNode, NodeMods } from './AbstractNode' import { Path } from '../model/Path' import { DataModel } from '../model/DataModel' +import { TreeView } from '../view/TreeView' export class StringNode extends AbstractNode { constructor(mods?: NodeMods) { @@ -10,8 +11,8 @@ export class StringNode extends AbstractNode { updateModel(el: Element, path: Path, model: DataModel) { } - render(path: Path, value: string, model: DataModel) { - return this.wrap(path, model, + render(path: Path, value: string, view: TreeView) { + return this.wrap(path, view, `${path.last()} `) } } diff --git a/src/view/SourceView.ts b/src/view/SourceView.ts new file mode 100644 index 00000000..f364d8d2 --- /dev/null +++ b/src/view/SourceView.ts @@ -0,0 +1,14 @@ +import { DataModel } from "../model/DataModel" +import { Path } from "../model/Path" + +export class SourceView { + model: DataModel + + constructor(model: DataModel) { + this.model = model + } + + render(target: HTMLElement) { + target.textContent = this.model.schema.transform(this.model.data) + } +} diff --git a/src/view/TreeView.ts b/src/view/TreeView.ts new file mode 100644 index 00000000..a14f335c --- /dev/null +++ b/src/view/TreeView.ts @@ -0,0 +1,38 @@ +import { DataModel } from "../model/DataModel" +import { Path } from "../model/Path" + +type Registry = { + [id: string]: (el: Element) => void +} + +const registryIdLength = 12 +const dec2hex = (dec: number) => ('0' + dec.toString(16)).substr(-2) + +export function getId() { + var arr = new Uint8Array((registryIdLength || 40) / 2) + window.crypto.getRandomValues(arr) + return Array.from(arr, dec2hex).join('') +} + +export class TreeView { + model: DataModel + registry: Registry = {} + + constructor(model: DataModel) { + this.model = model + } + + register(callback: (el: Element) => void): string { + const id = getId() + this.registry[id] = callback + return id + } + + render(target: HTMLElement) { + 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}"]`) + if (element !== null) this.registry[id](element) + } + } +}