diff --git a/Test/observedobject.test.js b/Test/observedobject.test.js index cc97fc5..43f9c5e 100644 --- a/Test/observedobject.test.js +++ b/Test/observedobject.test.js @@ -26,6 +26,19 @@ window.testSuites.push( class testObservedObject { } } + // MustInitAllFields() { + // class Form extends ObservedObject { + // id + // path + // $canvasPosition + // } + + // let obj = Form.decode({id: "123", path: "/", canvasPosition: "25|25"}) + // if(!(obj && obj["id"] === "123" && obj["path"] === "/" && obj["canvasPosition"] === "25|25")) { + // return "Not all fields initialized!" + // } + // } + // ChangingObjChangesInstance() { // class Form extends ObservedObject { // id diff --git a/Test/render.test.js b/Test/render.test.js index f3762c0..1bfbe9c 100644 --- a/Test/render.test.js +++ b/Test/render.test.js @@ -98,11 +98,10 @@ window.testSuites.push( class testRender { let Form = class Form extends ObservedObject { id $path - $children $canvasPosition } - let object = Form.decode({id: "123", path: "/", children: [], canvasPosition: "25|25"}); + let object = Form.decode({id: "123", path: "/", canvasPosition: "25|25"}); register(class File extends Shadow { $$form @@ -127,39 +126,34 @@ window.testSuites.push( class testRender { } } - // ObservedObjectWithArray() { - // let Form = class Form extends ObservedObject { - // id - // $path - // $children - // $canvasPosition - // } + ObservedObjectWithArray() { + let Form = class Form extends ObservedObject { + id + $children + } - // let object = Form.decode({id: "123", path: "/", children: [], canvasPosition: "25|25"}); + let object = Form.decode({id: "123", children: [{path: "berry"}, {path: "blue"}]}); - // register(class File extends Shadow { - // $$form + register(class File extends Shadow { + $$form - // render = () => { - // p(this.form.path) - // } - // }, randomName("file")) + render = () => { + ForEach(this.form.children, (child) => { + p(child.path) + }) + } + }, randomName("file")) - // let file = File(object) + let file = File(object) - // if(file.firstChild?.innerText !== "/") { - // return "Path is not inside of paragraph tag" - // } + if(file.firstChild?.innerText !== "berry" || file.children[1].innerText !== "blue") { + return "Paths did not render correctly in children" + } - // file.form.children.push("hello") - - // object.path = "/asd" - // if(file.form.path !== "/asd") { - // return "Path did not change when changing original object" - // } - // if(file.firstChild?.innerText !== "/asd") { - // return "Observed Object did not cause a reactive change" - // } - // } + file.form.children.push({path: "hello"}) + if(file.children.length !== 3) { + return "No reactivity for adding children" + } + } }) \ No newline at end of file diff --git a/index.js b/index.js index a1016d7..838a3c1 100644 --- a/index.js +++ b/index.js @@ -144,6 +144,58 @@ function getSafariVersion() { } /* REGISTER */ +class ObservedArray extends Array { + parent; + name; + + constructor(arr = [], parent, name) { + super(); + this.parent = parent + this.name = name + this.push(...arr); + } + + triggerParent() { + this.parent[this.name] = this + } + + push(...args) { + const result = super.push(...args); + this.triggerParent() + return result; + } + + pop() { + const result = super.pop(); + this.triggerParent() + return result; + } + + shift() { + const result = super.shift(); + this.triggerParent() + return result; + } + + unshift(...args) { + const result = super.unshift(...args); + this.triggerParent() + return result; + } + + splice(start, deleteCount, ...items) { + const removedItems = super.splice(start, deleteCount, ...items); + if (items.length > 0) { + console.log(`Inserted ${items.length} items:`, items); + } + if (removedItems.length > 0) { + console.log(`Removed ${removedItems.length} items:`, removedItems); + } + this.triggerParent() + return removedItems; + } +} + class ObservedObject { constructor() { this._observers = {} @@ -159,10 +211,18 @@ class ObservedObject { const backingFieldName = `_${key}`; Object.defineProperty(instance, key, { set: function(newValue) { - instance[backingFieldName] = newValue; + if(Array.isArray(newValue) && newValue.parent === undefined) { + instance[backingFieldName] = new ObservedArray(newValue, this, key) + } else { + instance[backingFieldName] = newValue; + } for (let [observer, properties] of instance._observers[key]) { for (let property of properties) { - observer[property] = newValue; + if(property === "children") { + Registry.rerender(observer) + } else { + observer[property] = newValue; + } } } }, @@ -206,7 +266,7 @@ window.Shadow = class Shadow extends HTMLElement { window.Registry = class Registry { static initReactivity(elem, name, value) { - let parent = window.rendering[window.rendering.length-1] + let parent = window.rendering.last() if(Registry.lastState.length === 3) { let [objName, objField, fieldValue] = Registry.lastState @@ -217,7 +277,10 @@ window.Registry = class Registry { if(!parent[objName]._observers[objField].get(elem)) { parent[objName]._observers[objField].set(elem, []) } - parent[objName]._observers[objField].get(elem).push(name) + let properties = parent[objName]._observers[objField].get(elem) + if(!properties.includes(name)) { + properties.push(name) + } } } else { let [stateUsed, stateValue] = Registry.lastState @@ -243,6 +306,17 @@ window.Registry = class Registry { window.rendering.pop(el) } + static rerender = (el) => { + if(el.parentElement) { + window.rendering.push(el.parentElement) + } + window.rendering.push(el) + el.innerHTML = "" + el.render() + window.rendering.pop() + window.rendering.pop() + } + static testInitialized(el) { let fields = Object.keys(el).filter(key => typeof el[key] !== 'function' && key !== "_observers" @@ -485,6 +559,13 @@ window.Registry = class Registry { /* DEFAULT WRAPPERS */ +window.ForEach = function (arr, cb) { + Registry.initReactivity(window.rendering.last(), "children", arr) + arr.forEach((el, i) => { + cb(el, i) + }) +} + window.a = function a({ href, name=href } = {}) { let link = document.createElement("a") link.setAttribute('href', href); @@ -525,6 +606,10 @@ window.span = function (innerText) { } /* PROTOTYPE FUNCTIONS */ + +Array.prototype.last = function() { + return this[this.length-1] +} HTMLElement.prototype.addAttribute = function(name) { this.setAttribute(name, "") }