Observed Object reactivity with array

This commit is contained in:
metacryst
2024-03-27 14:30:28 -05:00
parent 7231a5bdac
commit ec2ae3229a
3 changed files with 126 additions and 34 deletions

View File

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

View File

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

View File

@@ -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,12 +211,20 @@ class ObservedObject {
const backingFieldName = `_${key}`;
Object.defineProperty(instance, key, {
set: function(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) {
if(property === "children") {
Registry.rerender(observer)
} else {
observer[property] = newValue;
}
}
}
},
get: function() {
Registry.lastState.push(key)
@@ -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, "")
}