+
@@ -15,7 +16,7 @@
-
+
@@ -95,6 +96,14 @@
+
+
+
+
+
+
+
+
diff --git a/docs/md/components/input.md b/docs/md/components/input.md
new file mode 100644
index 0000000..9864468
--- /dev/null
+++ b/docs/md/components/input.md
@@ -0,0 +1,5 @@
+# I-Input
+
+
+
+
\ No newline at end of file
diff --git a/docs/md/components/iui-element.md b/docs/md/components/iui-element.md
index 6ee0c68..2492946 100644
--- a/docs/md/components/iui-element.md
+++ b/docs/md/components/iui-element.md
@@ -22,3 +22,8 @@ When the document is loaded or new HTML is inserted in the document, IUI process
Render invokes the data binding functions and sets the element text nodes and attributes to the value returned by the binding functions. The process is recursive to all children in the element tree (**IUIElement** and **HTMLElement**)
The rootElement is the first `` in the document when its loaded.
+
+
+# Extension to the Scope
+
+IUI components might extend the scope with
\ No newline at end of file
diff --git a/docs/md/getting-started/data-flow.md b/docs/md/getting-started/data-flow.md
index 96b2cf9..6f5ba56 100644
--- a/docs/md/getting-started/data-flow.md
+++ b/docs/md/getting-started/data-flow.md
@@ -1,7 +1,9 @@
# Data flow
+
When the :data attribute is set to an element any other attribute and child will be able to access this field directly using the variable *data* or the shortended *d*.
+It is a scope variable responsible for the rerendering process of the view when the value provided implements **Modifiable** interface, such as the Esiur distributed objects.
diff --git a/docs/md/getting-started/referencing.md b/docs/md/getting-started/referencing.md
index 6a477d9..75b9ada 100644
--- a/docs/md/getting-started/referencing.md
+++ b/docs/md/getting-started/referencing.md
@@ -1,2 +1,20 @@
# Referencing
+To avoid duplication, IUI relies on referencing instead of element id.
+
+Refs is a scope variable contains a collection of every element in the tree, unless overwritten by another component.
+
+
+
+
Last modification :
+
+
+When a duplicated referecing happens, the key in the refs collection will represent an array of the duplicated elements. *note: this always happends in I-Repeat components*
+
+
+
+
First Name :
+
Last Name :
+
diff --git a/docs/md/getting-started/scope.md b/docs/md/getting-started/scope.md
index c5c1243..33fffb6 100644
--- a/docs/md/getting-started/scope.md
+++ b/docs/md/getting-started/scope.md
@@ -10,4 +10,15 @@ These variables propagate from an element to its children and could be altered o
Date: ${now.toDateString()}
Time: ${now.toTimeString()}
-
\ No newline at end of file
+
+
+# Events
+
+Events can access scope variables when declared with *@eventName*
+
+
+
+
+
+
+
diff --git a/docs/md/getting-started/scripts.md b/docs/md/getting-started/scripts.md
new file mode 100644
index 0000000..b8f00d5
--- /dev/null
+++ b/docs/md/getting-started/scripts.md
@@ -0,0 +1,38 @@
+
+#Scripts
+
+Scripts within tags are executed as functions with the scope varaiables and *this* argument is set to the parent element
+
+
+
+
+
+When the function returns an object it will be projected to the parent element.
+
+
+
+
+
+Scope variables example
+
+
+
+
+
diff --git a/src/Core/Binding.js b/src/Core/Binding.js
index 3902dd0..64c4dc7 100644
--- a/src/Core/Binding.js
+++ b/src/Core/Binding.js
@@ -59,11 +59,19 @@ export class Binding {
isAsync = true;
attrType = AttributeBindingDestination.Field;
attrKey = nodeOrAttributeOrIUIElement.name.substr(6);
+
+ // skip scope
+ // if (attrKey == "scope")
+ // return null;
}
else if (nodeOrAttributeOrIUIElement.name.startsWith(":")) {
isAsync = false;
attrType = AttributeBindingDestination.Field;
attrKey = nodeOrAttributeOrIUIElement.name.substr(1);
+
+ // skip scope
+ // if (attrKey == "scope")
+ // return null;
}
else {
return null;
@@ -151,7 +159,7 @@ export class Binding {
try {
let d = this.func.apply(thisArg, [proxy, proxy, {}, true
- , ...this.scopeKeys]);
+ , ...this.scopeValues]);
this.map = map;
return d;
diff --git a/src/Core/BindingList.js b/src/Core/BindingList.js
index 472220d..6075ddf 100644
--- a/src/Core/BindingList.js
+++ b/src/Core/BindingList.js
@@ -5,6 +5,22 @@ export default class BindingList extends Array {
super();
this.target = target;
this.scope = scope;
+ this.events = [];
+ }
+
+ destroy(){
+ for(var i = 0; i < this.length; i++)
+ this[i].unbind();
+ this.scope = {};
+ this.target = null;
+ for(var i = 0; i < this.events.length; i++)
+ this.target.removeEventListener(this.events[i].name, this.events[i].handle);
+ }
+
+ addEvent(name, handle)
+ {
+ this.target.addEventListener(name, handle);
+ this.events.push({name, handle})
}
getArgumentsNames(){
diff --git a/src/Core/IUI.js b/src/Core/IUI.js
index 75c55aa..78e7ea3 100644
--- a/src/Core/IUI.js
+++ b/src/Core/IUI.js
@@ -161,7 +161,7 @@ export class IUI {
if (scope == null)
- scope = {};
+ scope = {};
// get refs before they get overwritten
//let refs = scope?.refs;
@@ -169,6 +169,25 @@ export class IUI {
// some element extended or overwritten the binding arguments
if (element.scope != null)
IUI.extend(scope, element.scope, true);
+ else if (element.hasAttribute(":scope"))
+ {
+ let script = element.getAttribute(":scope");
+ let code = `try {\r\n context.value = ${script}; \r\n}\r\n catch(ex) { context.error = ex; }`
+ let func = new Function("context", code);
+ let context = {};
+
+ func.call(element, context);
+
+ if (context.error != undefined)
+ console.log("Scope binding failed", context.error.name + ": " + context.error.message, this.script, this.target);
+ else if (context.value != undefined
+ && context.value instanceof Object)
+ IUI.extend(scope, context.value, true);
+ }
+
+ let scopeArgs = Object.keys(scope);
+ let scopeValues = Object.values(scope);
+
bindings = new BindingList(element, scope);
@@ -182,22 +201,42 @@ export class IUI {
}
else
{
+ element.__i_bindings?.destroy();
// compile attributes
for (var i = 0; i < element.attributes.length; i++) {
- let b = Binding.create(element.attributes[i],
- bindings.scope);
+ // skip scope
+ if (element.attributes[i].name == ":scope")
+ continue;
- 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);
- }
+ if (element.attributes[i].name.startsWith("@")){
+
+ // make events
+ let code = element.attributes[i].value;
+ //let code = `try {\r\n context.value = ${script}; \r\n}\r\n catch(ex) { context.error = ex; }`
+ let func = new Function("event", ...scopeArgs, code);
+ let handler = (event) => {
+ func.call(element, event, ...scopeValues);
+ }
+
+ bindings.addEvent(element.attributes[i].name.substr(1), handler);
+ }
+ else
+ {
+ let b = Binding.create(element.attributes[i],
+ bindings.scope);
+
+ 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);
+ }
+ }
}
@@ -218,8 +257,6 @@ export class IUI {
// }
}
-
-
// get new refs (scope might been overwritten)
//refs = scope?.refs;
@@ -230,6 +267,31 @@ export class IUI {
// @TODO: check if the IUI element handles the binding
IUI.bind(el, false, sourcePath, scope);
}
+ else if (el instanceof HTMLScriptElement)
+ {
+
+ try
+ {
+ // this because HTML parser don't evaluate script tag
+ /// let func = new Function("//# sourceURL=iui://" + sourcePath + "-" + Math.round(Math.random() * 10000) + "\r\n return " + el.text.trim());
+ let func = new Function(...scopeArgs,
+ "//# sourceURL=iui://" + sourcePath + "-"
+ + Math.round(Math.random() * 10000)
+ + "\r\n" + el.text.trim());
+
+ let rt = func.apply(el.parentElement, scopeValues);
+
+ console.log("rt", rt);
+
+ if (typeof (rt) === "object") {
+ for (var k in rt)
+ el.parentElement[k] = rt[k];
+ }
+ }
+ catch (ex) {
+ console.log(ex);
+ }
+ }
else if (el instanceof HTMLElement) {
IUI.bind(el, false, sourcePath, scope);
}
@@ -238,19 +300,6 @@ export class IUI {
if (b != null)
bindings.push(b);
}
- else if (el instanceof HTMLScriptElement)
- {
- // this because HTML parser don't evaluate script tag
- /// let func = new Function("//# sourceURL=iui://" + sourcePath + "-" + Math.round(Math.random() * 10000) + "\r\n return " + el.text.trim());
- let func = new Function("//# sourceURL=iui://" + sourcePath + "-" + Math.round(Math.random() * 10000) + "\r\n" + el.text.trim());
-
- let rt = func.call(el.parentElement);
-
- if (typeof (rt) === "object") {
- for (var k in rt)
- el.parentElement[k] = rt[k];
- }
- }
}
element.__i_bindings = bindings;
diff --git a/src/Core/IUIElement.js b/src/Core/IUIElement.js
index 01531ec..cffb07b 100644
--- a/src/Core/IUIElement.js
+++ b/src/Core/IUIElement.js
@@ -172,6 +172,7 @@ export default class IUIElement extends HTMLElement {
_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) {
@@ -196,6 +197,7 @@ export default class IUIElement extends HTMLElement {
}
}
}
+ */
}
off(event, func) {
diff --git a/src/Core/RefsCollection.js b/src/Core/RefsCollection.js
index 1b0eaf2..6fd5d65 100644
--- a/src/Core/RefsCollection.js
+++ b/src/Core/RefsCollection.js
@@ -6,14 +6,15 @@ export default class RefsCollection
this._rootElement = rootElement;
}
- _build(element) {
+ _build(element, append) {
if (element == undefined)
element = this._rootElement;
- for(var i in this)
- if (i != "_rootElement" && i != "_build")
- delete this[i];
+ if (!append)
+ for(var i in this)
+ if (i != "_rootElement" && i != "_build")
+ delete this[i];
for(var i = 0; i < element.children.length; i++)
{
@@ -33,14 +34,13 @@ export default class RefsCollection
var firstRef = this[ref];
this[ref] =[firstRef, child];
}
-
}
if (child.refs != undefined)
// opt out if the element handles referencing
break;
else
- this._build(child);
+ this._build(child, true);
}
}
}
\ No newline at end of file
diff --git a/src/UI/CodePreview.js b/src/UI/CodePreview.js
index 426ec34..dea36ac 100644
--- a/src/UI/CodePreview.js
+++ b/src/UI/CodePreview.js
@@ -6,6 +6,9 @@ export default IUI.module(class CodePreview extends IUIElement {
constructor() {
super();
this.refs = new RefsCollection(this);
+ this._code = this.innerHTML.trim();
+ this.textContent = '';
+
}
async create() {
@@ -13,8 +16,8 @@ export default IUI.module(class CodePreview extends IUIElement {
if (this.hasAttribute("debug"))
debugger;
- this._code = this.innerHTML.trim();
- this.textContent = '';
+ //this._code = this.innerHTML.trim();
+ //this.textContent = '';
// create elements
this.bar = document.createElement("div");
@@ -31,7 +34,7 @@ export default IUI.module(class CodePreview extends IUIElement {
let self = this;
this.editor.addEventListener("input", function() {
- self._code = self.editor.innerText.trim();
+ self._code = self.editor.textContent.trim();
self.updatePreview();
}, false);
@@ -59,13 +62,19 @@ export default IUI.module(class CodePreview extends IUIElement {
async updatePreview() {
+
if (this._updating)
return;
this._updating = true;
- this.preview.innerHTML = this._code;
-
+ this.preview.innerHTML = this._code;
+ //this.editor.innerHTML = hljs.highlightAuto(this._code).value;
+
+// this.editor.innerHTML = hljs.highlight(this._code, {language: 'html'}).value
+
+ // this.editor.innerHTML = hljs.highlightElement(this.editor, {language: 'html'}).value;
+
if (window.app?.loaded)
{
await IUI.create(this.preview);