diff --git a/src/core/01_base.jsx b/src/core/01_base.jsx index ddc7063..74248a0 100644 --- a/src/core/01_base.jsx +++ b/src/core/01_base.jsx @@ -58,6 +58,21 @@ class Lilium { return func; } + removeElement(a, e) { + if(this.isArray(a)) { + let index = a.indexOf(e); + if(index != -1) + return a.splice(index, 1); + } + return []; + } + + clone(a) { + if(this.isArray(a)) + return a.slice(0); + return null; + } + isArray(o) { return Object.prototype.toString.call(o) === '[object Array]'; } diff --git a/src/core/03_properties.jsx b/src/core/03_properties.jsx index 6d516b6..3214fe2 100644 --- a/src/core/03_properties.jsx +++ b/src/core/03_properties.jsx @@ -29,6 +29,139 @@ class PropertySource extends lilium.core.EventSource { } } -provides([PropertySource], 'core'); +class TreePropertySourceNode extends lilium.core.EventSource { + constructor(name, parent, value) { + super(); + this.parent = parent; + if(parent && parent instanceof TreePropertySourceNode) { + parent.appendChild(this); + } + this.name = name; + if(value) + this.value = value; + } + + removeChild(child) { + if(child && this.children) { + child.parent = null; + lilium.removeElement(this.children, child); + events.off(child, 'change'); // Remove all the change listeners + } + } + + appendChild(child) { + if(!this.children) + this.children = []; + this.children.push(child); + child.parent = this; + } + + path() { + let path = []; + let n = this; + while(n) { + path.unshift(n.name); + n = n.parent; + } + return path.join('.'); + } + + /** + * Generate the children tree + */ + childTree(names) { + if(lilium.isArray(names)) { + var cs = []; + var child = null; + while(names.length) { + child = this.child(lilium.clone(names)); + if(child) { + break; + } + + var n = names.pop(); + if(n) { + cs.unshift(n); + } + } + + var p = child? child: this; + for(let c of cs) { + child = new TreePropertySourceNode(c, p); + p = child; + } + return child; + } + else { + return this.childTree(names.split(".")); + } + } + + /** + * Get the child by its name + */ + child(names) { + if(lilium.isArray(names)) { + let node = this; + while(names.length) { + let n = names.shift(); + if(n) { + node = node.child(n); + if(!node) + break; + } + } + if(node != this) + return node; + } + else { + if(this.children) { + for(let child of this.children) { + if(child.name == names) + return child; + } + } + } + return null; + } +} + +class TreePropertySource extends TreePropertySourceNode { + get(name, default_value) { + let n = this.childTree(name); + return n? n.value: default_value; + } + + change(name, func) { + var n = this.childTree(name); + if(n) { + n.addEventListener('change', func); + } + return this; + } + + set(name, value) { + var n = this.childTree(name); + var event = { + 'target': n, + 'currentTarget': n, + 'propertyName': name, + 'value': value, + 'orig_value': n.value + }; + + var p = n; + // balloon event + while(p && !event.stop) { + event.currentTarget = p; + p.fire('change', event); + p = p.parent; + } + + n.value = value; + } +} + +provides([PropertySource, TreePropertySourceNode, TreePropertySource], 'core'); })(); diff --git a/tests/core/properties_spec.jsx b/tests/core/properties_spec.jsx index 90885af..87372d5 100644 --- a/tests/core/properties_spec.jsx +++ b/tests/core/properties_spec.jsx @@ -6,11 +6,64 @@ class Bean extends lilium.core.PropertySource { describe("core.properties.suite", function() { it("properties.source.test", function() { - var b = new Bean(); + let b = new Bean(); b.addEventListener('change', (e) => { expect(e.propertyName).toBe('a'); expect(e.value).toBe(1); }) b.set('a', 1); }); + + it("properties.tree.node.child.test", function() { + let root = new lilium.core.TreePropertySourceNode('root'); + let branch = new lilium.core.TreePropertySourceNode('branch', root); + let leaf = new lilium.core.TreePropertySourceNode('leaf', branch, 1); + expect(root.child(['branch', 'leaf']).value).toBe(1); + }); + + it("properties.tree.node.child.tree.test", function() { + let root = new lilium.core.TreePropertySourceNode('root'); + let leaf = root.childTree('branch.leaf'); + leaf.value = 1; + expect(root.child(['branch', 'leaf']).value).toBe(1); + expect(root.childTree('branch.leaf').value).toBe(1); + + let branch = root.child('branch'); + branch.value = 2; + + let leaf2 = root.childTree('branch.leaf2'); + expect(leaf2.parent.value).toBe(2); + }); + + it("properties.tree.node.child.path.test", function() { + let root = new lilium.core.TreePropertySourceNode('root'); + let leaf = root.childTree('branch.leaf'); + leaf.value = 1; + expect(leaf.path()).toBe('root.branch.leaf'); + }); + + it("properties.tree.property.source.base.test", function() { + let source = new lilium.core.TreePropertySource(); + var count = []; + source.addEventListener('change', (e) => { + count.unshift('ALL'); + }); + + source.change('a', (e) => { + count.unshift('a'); + }); + + source.change('a.b', (e) => { + count.unshift('a.b'); + }); + + source.change('a.b.c', (e) => { + count.unshift('a.b.c'); + }); + + source.set('a.b.c', 1); + let c = source.childTree("a.b.c"); + expect(c.value).toBe(1); + expect(count).toEqual(['ALL', 'a', 'a.b', 'a.b.c']); + }); });