Improvements to transform + make source a textarea

This commit is contained in:
Misode
2020-05-28 01:28:19 +02:00
parent 9c20e9520a
commit 9189bbe229
10 changed files with 50 additions and 40 deletions

View File

@@ -15,7 +15,6 @@ modelSelector.innerHTML = `
<option value="predicate">Predicate</option>
<option value="sandbox">Sandbox</option>`
modelSelector.addEventListener('change', evt => {
console.log("hello?")
if (modelSelector.value === 'sandbox') {
model = sandboxModel
} else {

View File

@@ -1,4 +1,3 @@
import { RootNode } from "../nodes/RootNode"
import { Path } from "./Path"
import { INode } from "../nodes/AbstractNode"
@@ -25,6 +24,11 @@ export class DataModel {
this.listeners.forEach(listener => listener.invalidated(this))
}
reset(value: any) {
this.data = value
this.invalidate()
}
get(path: Path) {
let node = this.data;
for (let index of path) {

View File

@@ -14,6 +14,14 @@ export class ListNode extends AbstractNode<IObject[]> {
this.children = values
}
transform(path: Path, value: IObject[]) {
if (!(value instanceof Array)) return undefined
const res = value.map((obj, index) =>
this.children.transform(path.push(index), obj)
)
return this.transformMod(res)
}
updateModel(el: Element, path: Path, model: DataModel) {
model.set(path, el.querySelector('select')?.value)
}

View File

@@ -19,6 +19,15 @@ export class MapNode extends AbstractNode<IMap> {
this.values = values
}
transform(path: Path, value: IMap) {
if (value === undefined) return undefined
let res: any = {}
Object.keys(value).forEach(f =>
res[f] = this.values.transform(path.push(f), value[f])
)
return this.transformMod(res);
}
renderRaw(path: Path, value: IMap, view: TreeView) {
value = value ?? []
const button = view.registerClick(el => {

View File

@@ -36,14 +36,14 @@ export class ObjectNode extends AbstractNode<IObject> {
transform(path: Path, value: IObject) {
if (value === undefined) return undefined
value = value ?? {}
const activeCase = this.filter ? this.cases[value[this.filter]] : {};
const activeFields = {...this.fields, ...activeCase}
let res: any = {}
Object.keys(activeFields).forEach(f =>
res[f] = activeFields[f].transform(path.push(f), value[f])
)
return res;
Object.keys(activeFields).forEach(f => {
console.log(f)
return res[f] = activeFields[f].transform(path.push(f), value[f])
})
return this.transformMod(res);
}
renderRaw(path: Path, value: IObject, view: TreeView, options?: RenderOptions) {

View File

@@ -1,22 +0,0 @@
import { NodeChildren, NodeMods } from './AbstractNode'
import { ObjectNode, IObject } from './ObjectNode'
import { Path } from '../model/Path'
import { TreeView } from '../view/TreeView'
export class RootNode extends ObjectNode {
id: string
constructor(id: string, fields: NodeChildren, mods?: NodeMods<IObject>) {
super(fields, mods)
this.id = id
}
render(path: Path, value: IObject, view: TreeView) {
value = value ?? {}
return `<div>
${Object.keys(this.fields).map(f => {
return this.fields[f].render(path.push(f), value[f], view)
}).join('')}
</div>`
}
}

View File

@@ -17,7 +17,7 @@ export class ResourceNode extends EnumNode {
const options = mods?.options ?? [] // TODO: Support registry using `github.com/Arcensoth/mcdata`
super(options, {
transform: (v) => {
if (v === undefined) return undefined
if (v === undefined || v.length === 0) return undefined
return v.startsWith('minecraft:') ? v : 'minecraft:' + v
}, ...mods})
this.additional = mods?.additional ?? false

View File

@@ -1,9 +1,7 @@
import { ObjectNode } from '../nodes/ObjectNode';
import { EnumNode } from '../nodes/EnumNode';
import { ResourceNode } from '../nodes/custom/ResourceNode';
import { NumberNode } from '../nodes/NumberNode';
import { BooleanNode } from '../nodes/BooleanNode';
import { RootNode } from '../nodes/RootNode';
import { RangeNode } from '../nodes/custom/RangeNode';
import { MapNode } from '../nodes/MapNode';
import { StringNode } from '../nodes/StringNode';
@@ -11,10 +9,9 @@ import { ListNode } from '../nodes/ListNode';
const EntityCollection = ['sheep', 'pig']
export const SandboxSchema = new RootNode('predicate', {
export const SandboxSchema = new ObjectNode({
condition: new EnumNode(['foo', 'bar'], {
default: () => 'bar',
transform: (s: string) => (s === 'foo') ? {test: 'baz'} : s
default: () => 'bar'
}),
number: new NumberNode({integer: false, min: 0}),
range: new RangeNode({
@@ -22,14 +19,18 @@ export const SandboxSchema = new RootNode('predicate', {
}),
predicate: new ObjectNode({
type: new EnumNode(EntityCollection),
nbt: new ResourceNode({
nbt: new StringNode({
default: (v) => 'hahaha'
}),
test: new BooleanNode({force: () => true}),
recipes: new MapNode(
new StringNode(),
new RangeNode({
default: (v) => RangeNode.isExact(v) ? 2 : v
default: (v) => RangeNode.isExact(v) ? 2 : v,
transform: (v: any) => RangeNode.isRange(v) ? ({
min: v?.min ?? -2147483648,
max: v?.max ?? 2147483647
}) : v
})
)
}),
@@ -49,5 +50,6 @@ export const SandboxSchema = new RootNode('predicate', {
predicate: {
nbt: 'hi'
}
})
}),
transform: (v) => v?.condition === 'foo' ? ({...v, test: 'hello'}) : v
});

View File

@@ -13,7 +13,16 @@ export class SourceView implements ModelListener {
render() {
const transformed = this.model.schema.transform(new Path([], this.model), this.model.data)
this.target.textContent = JSON.stringify(transformed)
const textarea = document.createElement('textarea')
textarea.style.width = 'calc(100% - 6px)'
textarea.rows = 10
textarea.textContent = JSON.stringify(transformed)
textarea.addEventListener('change', evt => {
const parsed = JSON.parse(textarea.value)
this.model.reset(parsed)
})
this.target.innerHTML = ''
this.target.appendChild(textarea)
}
invalidated() {

View File

@@ -49,7 +49,8 @@ export class TreeView implements ModelListener {
}
render() {
this.target.innerHTML = this.model.schema.render(new Path(), this.model.data, this)
this.target.innerHTML = this.model.schema.render(
new Path(), this.model.data, this, {hideLabel: true})
for (const id in this.registry) {
const element = this.target.querySelector(`[data-id="${id}"]`)
if (element !== null) this.registry[id](element)