From d6142ea25099752f9151852ea67b908d3afcbb37 Mon Sep 17 00:00:00 2001 From: MattMo Date: Tue, 25 May 2021 22:27:23 -0700 Subject: [PATCH] Added IgniteObject to support full end to end properties. --- ignite-element.js | 67 +++++++++++++++------------------------------- ignite-html.js | 65 ++++++++++++++++++++++++++++++++++++++++++-- ignite-template.js | 32 +++++++++++++--------- 3 files changed, 104 insertions(+), 60 deletions(-) diff --git a/ignite-element.js b/ignite-element.js index 26588a9..1ec726d 100644 --- a/ignite-element.js +++ b/ignite-element.js @@ -1,4 +1,4 @@ -import { IgniteProperty, IgniteCallback } from './ignite-html.js'; +import { IgniteProperty, IgniteCallback, IgniteRenderingContext } from './ignite-html.js'; import { IgniteTemplate } from './ignite-template.js'; /** @@ -139,12 +139,8 @@ class IgniteElement extends HTMLElement { */ createVariables() { var vars = this.variables; - if (vars != null) { - var keys = Object.keys(vars); - for (var i = 0; i < keys.length; i++) { - this[keys[i]] = vars[keys[i]]; - } + Object.keys(vars).forEach(name => this[name] = vars[name]); } } @@ -154,15 +150,23 @@ class IgniteElement extends HTMLElement { */ resetVariables() { var vars = this.variables; - if (vars != null) { - var keys = Object.keys(vars); - for (var i = 0; i < keys.length; i++) { - this[keys[i]] = vars[keys[i]]; - } + Object.keys(vars).forEach(name => this[name] = vars[name]); } } + /** + * Gets all the property values from this element and returns it. + */ + getProperties() { + var ret = {}; + var props = this.properties; + IgniteRenderingContext.push(); + Object.keys(props).forEach(name => ret[name] = this[name]); + IgniteRenderingContext.pop(); + return ret; + } + /** * Creates the getters/setters for properties in this * ignite element and initializes everything. @@ -170,37 +174,14 @@ class IgniteElement extends HTMLElement { */ createProperties() { var props = this.properties; - if (props != null) { - var keys = Object.keys(props); - for (var i = 0; i < keys.length; i++) { - let propValue = props[keys[i]]; - let propName = keys[i]; - - //Create a new property, if the propValue is a property, use that instead. - var prop = null; - if (propValue instanceof IgniteProperty) { - prop = propValue; - } else { - prop = new IgniteProperty(propValue); - } - - this[`_${propName}`] = prop; - - Object.defineProperty(this, propName, { - get: () => { - if (IgniteRenderingContext.rendering == false) { - return this[`_${propName}`].value; - } else { - return this[`_${propName}`]; - } - }, - - set: (value) => { - this[`_${propName}`].value = value; - } + Object.keys(props).forEach(name => { + var prop = (props[name] instanceof IgniteProperty ? props[name] : new IgniteProperty(props[name])); + Object.defineProperty(this, name, { + get: () => { return (IgniteRenderingContext.rendering ? prop : prop.value); }, + set: (value) => { prop.value = value; } }); - } + }); } } @@ -210,12 +191,8 @@ class IgniteElement extends HTMLElement { */ resetProperties() { var props = this.properties; - if (props != null) { - var keys = Object.keys(props); - for (var i = 0; i < keys.length; i++) { - this[keys[i]] = props[keys[i]]; - } + Object.keys(props).forEach(name => this[name] = props[name]); } } diff --git a/ignite-html.js b/ignite-html.js index 5761a50..fcef1b6 100644 --- a/ignite-html.js +++ b/ignite-html.js @@ -11,11 +11,11 @@ class IgniteProperty { this.onShiftCallbacks = []; this.onUnshiftCallbacks = []; this.onSpliceCallbacks = []; - this.arrayCallbacks = []; this.reflected = []; this._value = val; this.ignoreValueChange = false; + this.name = null; //If we were passed options, add any callbacks needed. if (options) { @@ -43,7 +43,7 @@ class IgniteProperty { this.attachOnSplice(options.onSplice); } } - + //Attempt to patch the value if it's a list. this.patchArray(); } @@ -361,6 +361,65 @@ Array.prototype.getOldPropertyValues = function (property, oldValue) { return ret; } +/** + * The outline of an IgniteObject which contains IgniteProperties. + */ +class IgniteObject { + /** + * Creates a new IgniteObject from an object and returns it. + * @param {Any} obj The object to create an IgniteObject out of. + * @returns {IgniteObject} The ignite object created. + */ + constructor(obj) { + //Only do this if the object is not an ignite object already. + if (!(obj instanceof IgniteObject)) { + Object.keys(obj).forEach(name => { + var prop = new IgniteProperty(obj[name]); + Object.defineProperty(this, name, { + get: () => { return (IgniteRenderingContext.rendering ? prop : prop.value); }, + set: (value) => { prop.value = value; } + }); + }); + } else { + return obj; + } + } + + /** + * Checks this IgniteObject for any properties not converted and automatically + * converts them. + */ + update() { + Object.keys(this).forEach(name => { + if (!(this[name] instanceof IgniteProperty)) { + var prop = new IgniteProperty(this[name]); + delete this[name]; + Object.defineProperty(this, name, { + get: () => { return (IgniteRenderingContext.rendering ? prop : prop.value); }, + set: (value) => { prop.value = value; } + }); + } + }); + } + + /** + * Creates an IgniteObject or Array of IgniteObjects and returns it. + * @param {Object|Array} obj The object to create an IgniteObject from. + * @returns {IgniteObject} The created IgniteObject. + */ + static create(obj) { + if (obj instanceof Array) { + var converted = []; + obj.forEach(item => converted.push(new IgniteObject(item))); + return converted; + } else if (!(obj instanceof IgniteObject)) { + return new IgniteObject(obj); + } else { + return obj; + } + } +} + /** * The outline of a ignite callback that can be invoked and disconnected * to help maintain and cleanup callbacks. @@ -457,9 +516,11 @@ class IgniteRenderingContext { } window.IgniteRenderingContext = IgniteRenderingContext; +window.IgniteObject = IgniteObject; export { IgniteProperty, + IgniteObject, IgniteRenderingContext, IgniteCallback }; \ No newline at end of file diff --git a/ignite-template.js b/ignite-template.js index 06123e0..33f98bf 100644 --- a/ignite-template.js +++ b/ignite-template.js @@ -1,4 +1,4 @@ -import { IgniteProperty } from './ignite-html.js'; +import { IgniteObject, IgniteProperty, IgniteRenderingContext } from './ignite-html.js'; import { IgniteElement } from './ignite-element.js'; /** @@ -318,28 +318,27 @@ class IgniteTemplate { /** * Adds a set of properties from an object to be added to this template once it's constructed. - * @param {Object} props The object value that property names/values will be pulled from. + * @param {Object|IgniteObject} props The object value that property names/values will be pulled from. * @returns This ignite template so function calls can be chained. */ properties(props) { - IgniteRenderingContext.push(); - //Make sure we have a valid props. if (props == null || props == undefined) { return; } - - if (!(typeof props === 'object')) { + else if (!(typeof props === 'object')) { throw `Cannot set properties with a non object set of properties: ${props}`; } - var propNames = Object.keys(props); + if (props instanceof IgniteObject) { + props.update(); - propNames.forEach(name => { - this.property(name, props[name], false, null); - }); + Object.getOwnPropertyNames(props).forEach(name => this.property(name, props[name], true)); + } + else { + Object.keys(props).forEach(name => this.property(name, props[name], false, null)); + } - IgniteRenderingContext.pop(); return this; } @@ -907,7 +906,8 @@ class IgniteTemplate { for (var i = 0; i < keys.length; i++) { this.element[keys[i]] = this._properties[keys[i]].value; - if (this._properties[keys[i]].reflect != null) { + //Reflect the property if it can be on the element. + if (this._properties[keys[i]].reflect != null && this.element[keys[i]] instanceof IgniteProperty) { this.element[keys[i]].reflected.push(this._properties[keys[i]].reflect); } } @@ -1136,7 +1136,13 @@ class IgniteTemplate { if (this.element) { //Use the set value function and don't reflect the change because it came from above which //would be the reflected property, this reduces some functions being called twice that don't need to be. - this.element[`_${propertyName}`].setValue(newValue, false); + IgniteRenderingContext.enter(); + if (this.element[propertyName] instanceof IgniteProperty) { + this.element[propertyName].setValue(newValue, false); + } else { + this.element[propertyName] = newValue; + } + IgniteRenderingContext.leave(); } this._properties[propertyName].value = newValue;