Update model and add invalidated cycle

This commit is contained in:
Misode
2020-05-25 14:45:10 +02:00
parent 79a5742dad
commit 56f3766a13
9 changed files with 73 additions and 20 deletions

View File

@@ -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()

View File

@@ -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()
}
}

View File

@@ -1,7 +1,7 @@
type PathElement = (string | number)
export class Path {
export class Path implements Iterable<PathElement> {
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
}
}
}

View File

@@ -33,7 +33,6 @@ export abstract class AbstractNode<T> implements INode<T> {
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 `<div data-id="${id}">${renderResult}</div>`

View File

@@ -12,12 +12,14 @@ export class EnumNode extends AbstractNode<string> {
}
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, `<span>${path.last()}</span>
<select value="${value}">
${this.options.map(o => `<option>${o}</option>`)}
<select data-id=${id}>
${this.options.map(o => `<option value="${o}">${o}</option>`).join('')}
</select>`)
}
}

View File

@@ -9,6 +9,7 @@ export class StringNode extends AbstractNode<string> {
}
updateModel(el: Element, path: Path, model: DataModel) {
model.set(path, el.querySelector('input')?.value)
}
render(path: Path, value: string, view: TreeView) {

View File

@@ -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()
}
}

View File

@@ -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()
}
}

View File

@@ -4,6 +4,7 @@
"module": "esnext",
"strict": true,
"esModuleInterop": true,
"downlevelIteration": true,
"forceConsistentCasingInFileNames": true
},
"include": [