mirror of
https://github.com/esiur/iui.git
synced 2025-06-27 09:23:12 +00:00
initial commit
This commit is contained in:
24
src/Core/App.js
Normal file
24
src/Core/App.js
Normal file
@ -0,0 +1,24 @@
|
||||
import IUIElement from "../Core/IUIElement.js";
|
||||
import { IUI } from "../Core/IUI.js";
|
||||
|
||||
export default IUI.module(class App extends IUIElement {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
create() {
|
||||
this._register("load");
|
||||
window.app = this;
|
||||
}
|
||||
|
||||
created() {
|
||||
this.updateBindings();
|
||||
this.render();
|
||||
this._emit("load", { app: this });
|
||||
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
351
src/Core/Binding.js
Normal file
351
src/Core/Binding.js
Normal file
@ -0,0 +1,351 @@
|
||||
import IUIElement from "./IUIElement.js";
|
||||
|
||||
export const BindingType = {
|
||||
IUIElement: 0, // this will never happen !
|
||||
TextNode: 1,
|
||||
ContentAttribute: 2,
|
||||
Attribute: 3,
|
||||
HTMLElementDataAttribute: 4,
|
||||
IUIElementDataAttribute: 5,
|
||||
IfAttribute: 6,
|
||||
RevertAttribute: 7
|
||||
};
|
||||
|
||||
export const AttributeBindingDestination = {
|
||||
Field: 0,
|
||||
Attribute: 1
|
||||
};
|
||||
|
||||
const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;
|
||||
|
||||
export class Binding {
|
||||
static create(nodeOrAttributeOrIUIElement) {
|
||||
var code, isAsync, type, attrType, attrKey, func, script;
|
||||
|
||||
//if (nodeOrAttributeOrIUIElement.created)
|
||||
// debugger;
|
||||
|
||||
if (nodeOrAttributeOrIUIElement instanceof IUIElement) {
|
||||
isAsync = nodeOrAttributeOrIUIElement.hasAttribute("async");
|
||||
type = BindingType.IUIElement;
|
||||
} else if (nodeOrAttributeOrIUIElement instanceof Text) {// nodeOrAttribute.nodeType == 3) {
|
||||
if (!nodeOrAttributeOrIUIElement.wholeText.match(/\${.*}/))
|
||||
return null;
|
||||
type = BindingType.TextNode;
|
||||
isAsync = nodeOrAttributeOrIUIElement.parentElement.hasAttribute("async");
|
||||
//code = "return `" + nodeOrAttributeOrIUIElement.wholeText + "`;";
|
||||
|
||||
script = nodeOrAttributeOrIUIElement.wholeText;
|
||||
|
||||
code = `try {\r\n context.value = \`${script}\`\r\n}\r\n catch(ex) { context.error = ex; }`
|
||||
|
||||
|
||||
nodeOrAttributeOrIUIElement.data = "";
|
||||
nodeOrAttributeOrIUIElement.created = true;
|
||||
} else if (nodeOrAttributeOrIUIElement instanceof Attr) {
|
||||
|
||||
if (nodeOrAttributeOrIUIElement.name.startsWith("async::")) {
|
||||
isAsync = true;
|
||||
attrType = AttributeBindingDestination.Attribute;
|
||||
attrKey = nodeOrAttributeOrIUIElement.name.substr(7);
|
||||
}
|
||||
else if (nodeOrAttributeOrIUIElement.name.startsWith("::")) {
|
||||
isAsync = false;
|
||||
attrType = AttributeBindingDestination.Attribute;
|
||||
attrKey = nodeOrAttributeOrIUIElement.name.substr(2);
|
||||
}
|
||||
else if (nodeOrAttributeOrIUIElement.name.startsWith("async:")) {
|
||||
isAsync = true;
|
||||
attrType = AttributeBindingDestination.Field;
|
||||
attrKey = nodeOrAttributeOrIUIElement.name.substr(6);
|
||||
}
|
||||
else if (nodeOrAttributeOrIUIElement.name.startsWith(":")) {
|
||||
isAsync = false;
|
||||
attrType = AttributeBindingDestination.Field;
|
||||
attrKey = nodeOrAttributeOrIUIElement.name.substr(1);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
// isAsync = nodeOrAttributeOrIUIElement.value.search("await");
|
||||
|
||||
// code = "return " + nodeOrAttributeOrIUIElement.value + ";";
|
||||
|
||||
script = nodeOrAttributeOrIUIElement.value
|
||||
code = `try {\r\n context.value = ${script}; \r\n}\r\n catch(ex) { context.error = ex; }`
|
||||
|
||||
let sentence = attrKey.split("-");
|
||||
for (var i = 1; i < sentence.length; i++)
|
||||
sentence[i] = sentence[i].charAt(0).toUpperCase() + sentence[i].slice(1);
|
||||
attrKey = sentence.join("");
|
||||
|
||||
if (attrKey == "content")
|
||||
type = BindingType.ContentAttribute;
|
||||
else if (attrKey == "if") {
|
||||
type = BindingType.IfAttribute;
|
||||
//displayMode =
|
||||
}
|
||||
else if (attrKey == "revert")
|
||||
type = BindingType.RevertAttribute;
|
||||
else if (attrKey != "data")
|
||||
type = BindingType.Attribute;
|
||||
else if (nodeOrAttributeOrIUIElement.ownerElement instanceof IUIElement)
|
||||
type = BindingType.IUIElementDataAttribute;
|
||||
else
|
||||
type = BindingType.HTMLElementDataAttribute;
|
||||
}
|
||||
|
||||
|
||||
// test the function
|
||||
|
||||
try {
|
||||
if (isAsync)
|
||||
func = new AsyncFunction("data", "d", "context", "_test", code);
|
||||
else
|
||||
func = new Function("data", "d", "context", "_test", code);
|
||||
}
|
||||
catch (ex) {
|
||||
console.log("Test failed: " + ex, code);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
let rt = new Binding();
|
||||
Object.assign(rt, { isAsync, type, attrType, attrKey, func, target: nodeOrAttributeOrIUIElement, checked: false, script });
|
||||
return rt;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.watchList = [];
|
||||
let self = this;
|
||||
this.listener = function (name, value) {
|
||||
self.render(self.data);
|
||||
};
|
||||
}
|
||||
|
||||
_findMap(thisArg) {
|
||||
|
||||
// @TODO: Map thisArg too
|
||||
let map = {};
|
||||
|
||||
let detector = {
|
||||
get: function (obj, prop) {
|
||||
if (typeof prop == "string") {
|
||||
obj[prop] = {};
|
||||
return new Proxy(obj[prop], detector);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.checked = true;
|
||||
|
||||
let proxy = new Proxy(map, detector);
|
||||
|
||||
try {
|
||||
let d = this.func.apply(thisArg, [proxy, proxy, {}, true]);
|
||||
this.map = map;
|
||||
return d;
|
||||
}
|
||||
catch (ex) {
|
||||
//console.log("Proxy failed", ex);
|
||||
this.map = map;
|
||||
}
|
||||
}
|
||||
|
||||
async _execute(thisArg, data) {
|
||||
if (!this.checked)
|
||||
this._findMap(thisArg);
|
||||
|
||||
|
||||
let context = {};
|
||||
var rt = this.func.apply(thisArg, [data, data, context, false]);
|
||||
|
||||
//console.log(rt);
|
||||
if (rt instanceof Promise)
|
||||
await rt;
|
||||
|
||||
if (context.error != undefined)
|
||||
{
|
||||
console.log("Execution failed", context.error.name + ": " + context.error.message, this.script, this.target);
|
||||
return;
|
||||
}
|
||||
else if (context.value == undefined)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (context.value instanceof Promise)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await context.value;
|
||||
} catch(ex) {
|
||||
console.log("Execution failed", ex.name + ": " + ex.message, this.script, this.target);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.value;
|
||||
}
|
||||
}
|
||||
|
||||
unbind() {
|
||||
this.data = null;
|
||||
for (var i = 0; i < this.watchList.length; i++)
|
||||
this.watchList[i].data.off(this.watchList[i].event, this.listener);
|
||||
this.watchList = [];
|
||||
}
|
||||
|
||||
bind(data, map) {
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
if (data?.on) {
|
||||
|
||||
for (var p in map) {
|
||||
let event = ":" + p;
|
||||
data.on(":" + p, this.listener);
|
||||
this.watchList.push({ data, event});
|
||||
|
||||
this.bind(data[p], map[p]);
|
||||
}
|
||||
|
||||
//if (this.watchList.includes(data))
|
||||
// this.watchList.push({ data, event : });
|
||||
}
|
||||
else {
|
||||
for (var p in map) {
|
||||
this.bind(data[p], map[p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
async render(data) {
|
||||
|
||||
// @TODO: Checking properties bindings moved here
|
||||
if (data != this.data)
|
||||
this.unbind();
|
||||
|
||||
try {
|
||||
if (this.type === BindingType.IUIElement) {
|
||||
let d = this.func.apply(this.target, [data, data]);
|
||||
if (d instanceof Promise)
|
||||
d = await d;
|
||||
await this.target.setData(d);
|
||||
}
|
||||
else if (this.type === BindingType.TextNode) {
|
||||
|
||||
try {
|
||||
|
||||
let d = await this._execute(this.target.parentElement, data);
|
||||
|
||||
if (d === undefined)
|
||||
return false;
|
||||
//if (d instanceof Promise)
|
||||
// d = await d;
|
||||
|
||||
this.target.data = d;// (d === undefined) ? "" : d;
|
||||
|
||||
if (data != this.data) {
|
||||
this.data = data;
|
||||
this.bind(data, this.map);
|
||||
}
|
||||
|
||||
}
|
||||
catch (ex) {
|
||||
this.target.data = "";
|
||||
}
|
||||
}
|
||||
// Content Attribute
|
||||
else if (this.type == BindingType.ContentAttribute) {
|
||||
let d = await this._execute(this.target.ownerElement, data);
|
||||
|
||||
if (d === undefined)
|
||||
return false;
|
||||
|
||||
//if (d instanceof Promise)
|
||||
// d = await d;
|
||||
|
||||
this.target.ownerElement.innerHTML = d;
|
||||
}
|
||||
else if (this.type == BindingType.IfAttribute)
|
||||
{
|
||||
let d = await this._execute(this.target.ownerElement, data);
|
||||
|
||||
if (d === undefined)
|
||||
return false;
|
||||
|
||||
//if (d instanceof Promise)
|
||||
// d = await d;
|
||||
|
||||
this.target.ownerElement.style.display = d ? "" : "none";
|
||||
}
|
||||
else if (this.type == BindingType.RevertAttribute)
|
||||
{
|
||||
let d = await this._execute(this.target.ownerElement, data);
|
||||
if (d === undefined)
|
||||
return false;
|
||||
//if (d instanceof Promise)
|
||||
// d = await d;
|
||||
|
||||
}
|
||||
// Attribute
|
||||
else if (this.type === BindingType.Attribute) {
|
||||
|
||||
//if (this.target.ownerElement.hasAttribute("debug"))
|
||||
// debugger;
|
||||
|
||||
let d = await this._execute(this.target.ownerElement, data);
|
||||
|
||||
if (d === undefined)
|
||||
return false;
|
||||
|
||||
//if (d instanceof Promise)
|
||||
// d = await d;
|
||||
|
||||
if (this.attrType == AttributeBindingDestination.Field)
|
||||
this.target.ownerElement[this.attrKey] = d;
|
||||
else
|
||||
this.target.ownerElement.setAttribute(this.attrKey, d);
|
||||
|
||||
if (data != this.data) {
|
||||
this.data = data;
|
||||
this.bind(data, this.map);
|
||||
}
|
||||
}
|
||||
|
||||
// Data Attribute of IUI Element
|
||||
else if (this.type === BindingType.IUIElementDataAttribute) {
|
||||
|
||||
|
||||
|
||||
let d = await this._execute(this.target.ownerElement, data);
|
||||
//if (d === undefined)
|
||||
// return false;
|
||||
|
||||
//if (d instanceof Promise)
|
||||
// d = await d;
|
||||
await this.target.ownerElement.setData(d);
|
||||
}
|
||||
// Data Attribute of HTML Element
|
||||
else if (this.type == BindingType.HTMLElementDataAttribute) {
|
||||
|
||||
let d = await this._execute(this.target.ownerElement, data);
|
||||
if (d === undefined)
|
||||
return false;
|
||||
//if (d instanceof Promise)
|
||||
// d = await d;
|
||||
this.target.ownerElement.data = d;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (ex) {
|
||||
// console.log(ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
310
src/Core/IUI.js
Normal file
310
src/Core/IUI.js
Normal file
@ -0,0 +1,310 @@
|
||||
import IUIElement from "./IUIElement.js";
|
||||
|
||||
export const IUI = {
|
||||
format: function (input) {
|
||||
if (typeof input == "string" || input instanceof String) {
|
||||
let template = document.createElement("template");
|
||||
template.innerHTML = input;
|
||||
let nodes = template.content.cloneNode(true).childNodes;
|
||||
return nodes;
|
||||
}
|
||||
else if (input instanceof HTMLCollection)
|
||||
return input;
|
||||
else if (input instanceof HTMLElement)
|
||||
return [input];
|
||||
else
|
||||
return [];
|
||||
},
|
||||
_menus: [],
|
||||
views: [],
|
||||
modules: {},
|
||||
registry : [],
|
||||
observer: new IntersectionObserver(function(entries) {
|
||||
// isIntersecting is true when element and viewport are overlapping
|
||||
// isIntersecting is false when element and viewport don't overlap
|
||||
for(var i = 0; i < entries.length; i++)
|
||||
{
|
||||
if (entries[i].isIntersecting)
|
||||
{
|
||||
if (entries[i]._require_update)
|
||||
entries[i].update();
|
||||
}
|
||||
}
|
||||
|
||||
}, { threshold: [0] }),
|
||||
created: async function (element) {
|
||||
|
||||
for (var i = 0; i < element.children.length; i++) {
|
||||
let e = element.children[i];
|
||||
if (e instanceof IUIElement)
|
||||
await e.created();
|
||||
await IUI.created(e);
|
||||
}
|
||||
},
|
||||
create: async function(element)
|
||||
{
|
||||
|
||||
for (let i = 0; i < element.children.length; i++) {
|
||||
let e = element.children[i];
|
||||
if (e instanceof IUIElement) {
|
||||
await e.create();
|
||||
// e.updateBindings();
|
||||
}
|
||||
|
||||
await IUI.create(e);
|
||||
}
|
||||
/*
|
||||
let router = document.getElementsByTagName("i-router")[0];
|
||||
|
||||
await router.create();
|
||||
|
||||
let elements = document.querySelectorAll("*");
|
||||
for (var i = 0; i < elements.length; i++)
|
||||
if (elements[i] instanceof IUIElement && elements[i].tagName != "I-ROUTER") {
|
||||
console.log(elements[i]);
|
||||
await elements[i].create();
|
||||
}
|
||||
*/
|
||||
|
||||
//for(var i = 0; i < IUI.registry.length; i++)
|
||||
//{
|
||||
// IUI.extend(IUI.registry[i], IUI.registry[i].properties);
|
||||
// await IUI.registry[i].create();
|
||||
// //await IUI.registry[i].updateAttributes();
|
||||
//}
|
||||
//return;
|
||||
},
|
||||
get : function(o)
|
||||
{
|
||||
return document.getElementById(o);
|
||||
|
||||
//for(var i = 0; i < IUI.registry.length; i++)
|
||||
// if (IUI.registry[i].id == o)
|
||||
// return IUI.registry[i];
|
||||
//return null;
|
||||
},
|
||||
put: function(o)
|
||||
{
|
||||
IUI.registry.push(o);
|
||||
},
|
||||
remove: function(id)
|
||||
{
|
||||
for(var i = 0; i < IUI.registry.length; i++)
|
||||
if (IUI.registry[i].el.id == id)
|
||||
{
|
||||
IUI.registry.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
},
|
||||
module: function(objectClass)
|
||||
{
|
||||
let moduleName = objectClass.moduleName;
|
||||
|
||||
if (IUI.modules[moduleName] === undefined) {
|
||||
customElements.define("i-" + moduleName, objectClass);
|
||||
IUI.modules[moduleName] = {
|
||||
cls: objectClass, init: function (properties) {
|
||||
return new objectClass(properties);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return objectClass;
|
||||
},
|
||||
extend: function(properties, defaults, force)
|
||||
{
|
||||
if (properties == null)
|
||||
properties = defaults;
|
||||
else
|
||||
for(var i in defaults)
|
||||
if (force)
|
||||
properties[i] = defaults[i];
|
||||
else if (properties[i] === undefined)
|
||||
properties[i] = defaults[i];
|
||||
return properties;
|
||||
}
|
||||
};
|
||||
|
||||
export function iui(selector)
|
||||
{
|
||||
return IUI.get(selector);
|
||||
|
||||
/*
|
||||
if ((typeof selector === 'string' || selector instanceof String) && selector.length > 0)
|
||||
{
|
||||
var els = document.querySelectorAll(selector);
|
||||
}
|
||||
else
|
||||
{
|
||||
var els = IUI.get(selector);
|
||||
if (els != null)
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
if (typeof(this) == "undefined" || this == window)
|
||||
{
|
||||
var o = IUI.get(selector);
|
||||
if (o)
|
||||
return o;
|
||||
else
|
||||
{
|
||||
var el;
|
||||
|
||||
if (typeof Node === "object" ? o instanceof Node : (
|
||||
selector && typeof selector === "object" && typeof selector.nodeType === "number" && typeof selector.nodeName==="string") || selector === window)
|
||||
{
|
||||
el = selector;
|
||||
}
|
||||
else if (typeof selector === 'string' || selector instanceof String)
|
||||
{
|
||||
if (selector[0] == ".")
|
||||
el = document.getElementsByClassName(selector.substr(1));
|
||||
else
|
||||
el = document.getElementById(selector);
|
||||
}
|
||||
|
||||
if (el)
|
||||
{
|
||||
var rt = {};
|
||||
var makeFunc = function(module){
|
||||
return function(){
|
||||
if (el instanceof HTMLCollection)
|
||||
{
|
||||
let rt = [];
|
||||
for(var i = 0; i < el.length; i++)
|
||||
{
|
||||
var args = [el[i]];
|
||||
for(var j = 0; j < arguments.length; j++)
|
||||
args.push(arguments[j]);
|
||||
rt.push(IUI.modules[module].init.apply(this, args));
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
else
|
||||
{
|
||||
var args = [el];
|
||||
for(var i = 0; i < arguments.length; i++)
|
||||
args.push(arguments[i]);
|
||||
return IUI.modules[module].init.apply(this, args);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for(var m in IUI.modules)
|
||||
rt[m] = makeFunc(m);
|
||||
|
||||
return rt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
IUI.registry.push(this);
|
||||
|
||||
|
||||
if (selector)
|
||||
{
|
||||
if( Object.prototype.toString.call( selector ) === '[object Array]' )
|
||||
{
|
||||
this.el = [];
|
||||
selector.forEach(function(i){
|
||||
this.el.push(query(i));
|
||||
});
|
||||
}
|
||||
else
|
||||
this.el = query(selector);
|
||||
|
||||
this.events = {};
|
||||
this.id = this.el.id;
|
||||
}
|
||||
*/
|
||||
}
|
||||
/*
|
||||
Array.prototype.each = function(func)
|
||||
{
|
||||
if (this instanceof Array)
|
||||
{
|
||||
for(var i = 0; i < this.length; i++)
|
||||
if (func(this[i], i))
|
||||
break;
|
||||
}
|
||||
else
|
||||
for(var i in this)
|
||||
if(func(this[i], i))
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Array.prototype.distinct = function(field)
|
||||
{
|
||||
var rt = [];
|
||||
|
||||
this.forEach(function(item)
|
||||
{
|
||||
if (rt.indexOf(item[field]) == -1)
|
||||
rt.push(item[field]);
|
||||
});
|
||||
|
||||
return rt;
|
||||
}
|
||||
/*
|
||||
iui.prototype.ec = function(className, parent)
|
||||
{
|
||||
if (parent)
|
||||
return parent.getElementsByClassName(className);
|
||||
else
|
||||
return document.getElementsByClassName(className);
|
||||
}
|
||||
|
||||
iui.prototype.ne = function(tag)
|
||||
{
|
||||
return document.createElement(tag);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
iui.prototype.destroy = function()
|
||||
{
|
||||
IUI.registry.splice(IUI.registry.indexOf(this.el), 1);
|
||||
};
|
||||
|
||||
iui.prototype.register = function(event)
|
||||
{
|
||||
this.events[event] = [];
|
||||
return this;
|
||||
};
|
||||
|
||||
iui.prototype.emit = function(event)
|
||||
{
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
if (this.events && this.events[event])
|
||||
for(var i = 0; i < this.events[event].length; i++)
|
||||
this.events[event][i].apply(this, args);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
iui.prototype.on = function(event, fn)
|
||||
{
|
||||
if (this.events && this.events[event])
|
||||
this.events[event].push(fn);
|
||||
else if (document.attachEvent)
|
||||
this.el.attachEvent('on' + event, fn)
|
||||
else // if (document.addEventListener)
|
||||
this.el.addEventListener(event, fn, !0);
|
||||
|
||||
return this;
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
window.addEventListener("load", function(){
|
||||
for(var m in IUI.modules)
|
||||
{
|
||||
var elements = document.getElementsByTagName(m);
|
||||
|
||||
}
|
||||
});
|
||||
*/
|
313
src/Core/IUIElement.js
Normal file
313
src/Core/IUIElement.js
Normal file
@ -0,0 +1,313 @@
|
||||
import { IUI } from "./IUI.js";
|
||||
import { Binding, BindingType, AttributeBindingDestination } from "./Binding.js";
|
||||
|
||||
export default class IUIElement extends HTMLElement {
|
||||
constructor(defaults) {
|
||||
super();
|
||||
|
||||
this._events = [];
|
||||
this._data = null;
|
||||
|
||||
for (var i in defaults)
|
||||
if (this[i] == undefined)
|
||||
this[i] = defaults[i];
|
||||
|
||||
this._register("data");
|
||||
}
|
||||
|
||||
static get moduleName(){
|
||||
return this.name.toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
get cssClass(){
|
||||
if (this.hasAttribute("css-class"))
|
||||
return this.getAttribute("css-class");
|
||||
//else
|
||||
// return this.constructor.moduleName;
|
||||
}
|
||||
|
||||
set cssClass(value)
|
||||
{
|
||||
this.classList.remove(this.cssClass);
|
||||
this.setAttribute("css-class", value);
|
||||
this.classList.add(value);
|
||||
}
|
||||
|
||||
async render() {
|
||||
await this._renderElement(this, this._data);
|
||||
}
|
||||
|
||||
_getParentData() {
|
||||
var p = this.parentElement;
|
||||
do {
|
||||
if (p.data !== undefined)
|
||||
return p.data;
|
||||
} while (p = p.parentElement);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async setData(value) {
|
||||
//if (this.bindings === undefined)
|
||||
// this.updateBindings();
|
||||
|
||||
|
||||
this._data = value;
|
||||
this._emit("data", {data: value});
|
||||
await this._renderElement(this, value);
|
||||
|
||||
//console.log("IUI: SetData", value, this.tagName);
|
||||
}
|
||||
|
||||
get data() {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
async revert(){
|
||||
//if (this.revertMap != null)
|
||||
//{
|
||||
//if (data == undefined)
|
||||
// await this.revertMap.render(this._getParentData());
|
||||
//else
|
||||
// await this.revertMap.render(data);
|
||||
// revert parents
|
||||
|
||||
let e = this;
|
||||
|
||||
do {
|
||||
var p = e.parentElement;
|
||||
|
||||
if (e.revertMap != null)
|
||||
await e.revertMap.render(p?.data);
|
||||
} while (e = p);
|
||||
//}
|
||||
}
|
||||
|
||||
async update(data) {
|
||||
if (data == undefined) {
|
||||
// get parent data
|
||||
if (this.dataMap != null) {
|
||||
await this.dataMap.render(this._getParentData());
|
||||
} else
|
||||
await this.setData(this.data);
|
||||
}
|
||||
else {
|
||||
// apply specified data
|
||||
if (this.dataMap != null) {
|
||||
await this.dataMap.render(data);
|
||||
} else
|
||||
await this.setData(data);
|
||||
}
|
||||
}
|
||||
|
||||
async _renderElement(element, data) {
|
||||
if (!element.bindings) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//console.log("_renderElement " + element.getAttribute("ref"), element);
|
||||
|
||||
//if (element.hasAttribute("debug"))
|
||||
// debugger;
|
||||
|
||||
// render attributes & text nodes
|
||||
for (var i = 0; i < element.bindings.length; i++)
|
||||
await element.bindings[i].render(data);
|
||||
|
||||
// render children
|
||||
for (var i = 0; i < element.children.length; i++) {
|
||||
let e = element.children[i];
|
||||
if (e instanceof IUIElement)
|
||||
// @TODO should check if the element depends on parent or not
|
||||
if (e.dataMap != null) {
|
||||
// if map function failed to call setData, we will render without it
|
||||
if (!(await e.dataMap.render(data)))
|
||||
await e.render();
|
||||
}
|
||||
else
|
||||
await e.setData(data);
|
||||
else {
|
||||
if (e.dataMap != null)
|
||||
await e.dataMap.render(data);
|
||||
else
|
||||
e.data = data;
|
||||
|
||||
//let data = e.mapData(data);
|
||||
await this._renderElement(e, e.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// this meant to be inherited
|
||||
modified() {
|
||||
|
||||
}
|
||||
|
||||
get data() {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
|
||||
if (this.hasAttribute("css-class"))
|
||||
this.classList.add(this.getAttribute("css-class"));
|
||||
else
|
||||
{
|
||||
let className = this.constructor.moduleName;
|
||||
|
||||
this.setAttribute("css-class", className);
|
||||
this.classList.add(className);
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
// console.log("removed", this);
|
||||
}
|
||||
|
||||
adoptedCallback() {
|
||||
|
||||
//console.log("adopted", this);
|
||||
|
||||
}
|
||||
|
||||
//appendChild(node) {
|
||||
// // do some bindings
|
||||
// super.appendChild(node);
|
||||
//}
|
||||
|
||||
created() {
|
||||
|
||||
}
|
||||
|
||||
create() {
|
||||
//this.updateBindings();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
console.log("Destroy", this);
|
||||
IUI.registry.splice(IUI.registry.indexOf(this), 1);
|
||||
if (this.parentNode)
|
||||
this.parentNode.removeChild(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
_make_bindings(element) {
|
||||
|
||||
// ::Attribute
|
||||
// : Field
|
||||
// async:: Async Attribute
|
||||
// async: Async Field
|
||||
// @ Event
|
||||
|
||||
let bindings = [];
|
||||
|
||||
|
||||
//if (element.hasAttribute("debug"))
|
||||
// debugger;
|
||||
|
||||
// compile attributes
|
||||
for (var i = 0; i < element.attributes.length; i++) {
|
||||
|
||||
let b = Binding.create(element.attributes[i]);
|
||||
|
||||
if (b != null) {
|
||||
if (b.type == BindingType.HTMLElementDataAttribute || b.type == BindingType.IUIElementDataAttribute)
|
||||
element.dataMap = b;
|
||||
else if (b.type == BindingType.RevertAttribute)
|
||||
element.revertMap = b;
|
||||
else
|
||||
bindings.push(b);
|
||||
}
|
||||
}
|
||||
|
||||
// compile nodes
|
||||
for (var i = 0; i < element.childNodes.length; i++) {
|
||||
let e = element.childNodes[i];
|
||||
if (e instanceof IUIElement) {
|
||||
// @TODO: check if the IUI element handles the binding
|
||||
this._make_bindings(e);
|
||||
}
|
||||
else if (e instanceof HTMLElement) {
|
||||
this._make_bindings(e);
|
||||
}
|
||||
else if (e instanceof Text) {
|
||||
let b = Binding.create(e);
|
||||
if (b != null)
|
||||
bindings.push(b);
|
||||
}
|
||||
}
|
||||
|
||||
element.bindings = bindings;
|
||||
}
|
||||
|
||||
|
||||
_emit(event, values) {
|
||||
//var args = Array.prototype.slice.call(arguments, 1);
|
||||
var e = new CustomEvent(event, values);
|
||||
for (var i in values) {
|
||||
if (e[i] === undefined)
|
||||
e[i] = values[i];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return this.dispatchEvent(e);
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
console.log(ex);
|
||||
}
|
||||
}
|
||||
|
||||
updateBindings() {
|
||||
this._make_bindings(this);
|
||||
}
|
||||
|
||||
_encapsulateEvent(code){
|
||||
return `try {\r\n ${code} \r\n}\r\n catch(ex) { console.log(ex.name + ":" + ex.message, this); }`;
|
||||
}
|
||||
|
||||
_register(event) {
|
||||
this._events.push(event);
|
||||
|
||||
if (this.hasAttribute("@" + event)) {
|
||||
let handler = this.getAttribute("@" + event);
|
||||
if (handler.match(/^[A-Za-z\$_]+(?:[\$_][A-Za-z0-9]+)*$/g) === null) {
|
||||
try
|
||||
{
|
||||
let func = new Function("event", this._encapsulateEvent(this.getAttribute("@" + event)));
|
||||
this.addEventListener(event, func);
|
||||
} catch (ex)
|
||||
{
|
||||
console.log(ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
let func = this[handler];
|
||||
if (func instanceof Function) {
|
||||
this.addEventListener(event, func, false);
|
||||
}
|
||||
else {
|
||||
// might be added in the future
|
||||
let func = new Function("event", `this["${handler}"](event)`);
|
||||
this.addEventListener(event, func, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
off(event, fn) {
|
||||
this.removeEventListener(event, fn);
|
||||
return this;
|
||||
}
|
||||
|
||||
on(event, fn) {
|
||||
this.addEventListener(event, fn, false);
|
||||
return this;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user