Cleaned up code, added support for lists, classes, attributes, and more. Added more test code, everything appears to be working. More cleanup and testing is needed.

This commit is contained in:
2020-07-28 09:04:04 -07:00
parent 8f9ade2dbd
commit b591a42370
10 changed files with 619 additions and 12 deletions

226
src/ignite-template.js Normal file
View File

@ -0,0 +1,226 @@
import { IgniteProperty, IgniteAttribute } from './ignite-html.js';
class IgniteTemplate {
constructor(items) {
this.siblings = [];
this.children = [];
this.attributes = {};
this.classes = [];
this.tagName = null;
this.element = null;
this.properties = {};
if (items) {
for (var i = 0; i < items.length; i++) {
if (items[i] instanceof IgniteAttribute) {
this.attributes.push(items[i]);
} else if (items[i] instanceof IgniteProperty) {
this.children.push(new propertyObserver(items[i]));
} else {
this.children.push(items[i]);
}
}
}
}
class(...items) {
for (var i = 0; i < items.length; i++) {
if (items[i] instanceof IgniteProperty) {
items[i].onPropertyChange.push((oldValue, newValue) => this.onClassChanged(oldValue, newValue));
this.classes.push(items[i].value);
} else {
this.classes.push(items[i]);
}
}
return this;
}
attribute(name, value) {
if (value instanceof IgniteProperty) {
value.onPropertyChange.push((oldValue, newValue) => this.onAttributeChanged(oldValue, newValue, name));
this.attributes[name] = value.value;
} else {
this.attributes[name] = value;
}
return this;
}
property(name, value) {
if (value instanceof IgniteProperty) {
value.onPropertyChange.push((oldValue, newValue) => this.onPropertyChanged(oldValue, newValue, name));
this.properties[name] = value.value;
} else {
this.properties[name] = value;
}
return this;
}
child(...items) {
this.children = this.children.concat(items);
return this;
}
construct(parent) {
//Construct this element if we haven't already
if (!this.element) {
this.element = window.document.createElement(this.tagName);
parent.appendChild(this.element);
}
//Set the classes on this element
for (var i = 0; i < this.classes.length; i++) {
if (this.classes[i] !== null && this.classes[i] !== undefined) {
this.element.classList.add(this.classes[i]);
}
}
//Set the attributes on this element
var keys = Object.keys(this.attributes);
for (var i = 0; i < keys.length; i++) {
if (this.attributes[keys[i]] !== null && this.attributes[keys[i]] !== undefined) {
this.element.setAttribute(keys[i], this.attributes[keys[i]]);
}
}
//Set the properties on this element
var keys = Object.keys(this.properties);
for (var i = 0; i < keys.length; i++) {
this.element[keys[i]] = this.properties[keys[i]];
}
//Construct the children under this element
for (var i = 0; i < this.children.length; i++) {
if (this.children[i] instanceof String || typeof this.children[i] === 'string') {
this.element.appendChild(document.createTextNode(this.children[i]));
} else if (this.children[i] instanceof IgniteTemplate || this.children[i].prototype instanceof IgniteTemplate) {
this.children[i].construct(this.element);
}
}
}
onClassChanged(oldValue, newValue) {
console.log(`Class changed, oldValue: ${oldValue} newValue: ${newValue}`);
if (oldValue !== null && oldValue !== undefined && oldValue !== "" && oldValue !== " ") {
this.element.classList.remove(oldValue);
}
if (newValue !== null && newValue !== undefined && newValue !== "" && newValue !== " ") {
this.element.classList.add(newValue);
}
}
onAttributeChanged(oldValue, newValue, attributeName) {
console.log(`Attribute changed, oldValue: ${oldValue} newValue: ${newValue} attribute: ${attributeName}`);
if (newValue == null || newValue == undefined) {
this.element.removeAttribute(attributeName);
} else {
this.element.setAttribute(attributeName, newValue);
}
}
onPropertyChanged(oldValue, newValue, propertyName) {
console.log(`Property changed, oldValue: ${oldValue} newValue: ${newValue} property: ${propertyName}`);
this.properties[propertyName] = newValue;
this.element[propertyName] = newValue;
}
}
class div extends IgniteTemplate {
constructor(...items) {
super(items);
this.tagName = "div";
}
}
class a extends IgniteTemplate {
constructor(...items) {
super(items);
this.tagName = "a";
}
}
class html extends IgniteTemplate {
constructor(code) {
super([]);
this.code = code;
}
construct(parent) {
if (!parent) {
parent = window.document.body;
}
parent.insertAdjacentHTML('beforeend', this.code);
}
}
class list extends IgniteTemplate {
constructor(list, forEach) {
super([]);
if (list instanceof IgniteProperty) {
list.onPropertyChange.push((oldValue, newValue) => {
this.list = list.value;
this.construct(null); //If the list changed, reconstruct this template
});
this.list = list.value;
} else {
this.list = list;
}
this.forEach = forEach;
this.elements = [];
}
construct(parent) {
if (!this.element) {
this.element = window.document.createTextNode(""); //Use a textnode as our placeholder
parent.appendChild(this.element);
}
//If we already have elements we created, destroy them.
if (this.elements.length > 0) {
for (var i = 0; i < this.elements.length; i++) {
this.elements[i].remove();
}
this.elements = [];
}
//Create a temporary container
var container = window.document.createElement("div");
//Construct all the items in our list and use the container
if (this.list) {
for (var i = 0; i < this.list.length; i++) {
this.forEach(this.list[i]).construct(container);
}
}
//If we have any child nodes in the container, save the element, and add it after our placeholder
while (container.childNodes.length > 0) {
this.elements.push(container.childNodes[0]);
this.element.parentElement.insertBefore(container.childNodes[0], this.element);
}
//Make sure we cleanup the container to be safe.
container.remove();
container = null;
}
}
export {
IgniteTemplate,
div,
html,
list,
a
};