mirror of
https://github.com/esiur/iui.git
synced 2025-05-06 06:42:58 +00:00
Refs
This commit is contained in:
parent
589c4f3227
commit
e52b89fb4d
@ -1,6 +1,7 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
@ -15,7 +16,7 @@
|
||||
<meta name="msapplication-TileColor" content="#ffc40d">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/default.min.css">
|
||||
@ -95,6 +96,14 @@
|
||||
<i-route name="if-content" caption="Conditions and Filling" :content="load(this)">
|
||||
</i-route>
|
||||
|
||||
<i-route name="scripts" caption="Scripts" :content="load(this)">
|
||||
|
||||
</i-route>
|
||||
|
||||
<i-route name="referencing" caption="Referencing" :content="load(this)">
|
||||
|
||||
</i-route>
|
||||
|
||||
</i-route>
|
||||
|
||||
|
||||
|
5
docs/md/components/input.md
Normal file
5
docs/md/components/input.md
Normal file
@ -0,0 +1,5 @@
|
||||
# I-Input
|
||||
|
||||
<i-codepreview>
|
||||
|
||||
</i-codepreview>
|
@ -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 `<i-app>` in the document when its loaded.
|
||||
|
||||
|
||||
# Extension to the Scope
|
||||
|
||||
IUI components might extend the scope with
|
@ -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.
|
||||
|
||||
<i-codepreview>
|
||||
<div :data="{name: 'Ahmed Zamil', job: 'Developer'} ">
|
||||
|
@ -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.
|
||||
|
||||
<i-codepreview>
|
||||
<button @click="refs.modification.innerHTML = new Date()">Click me</button>
|
||||
<div>Last modification : </div><div ref="modification"></div>
|
||||
</i-codepreview>
|
||||
|
||||
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*
|
||||
|
||||
<i-codepreview>
|
||||
<button @click="refs.name[0].innerHTML = 'Zak'; refs.name[1].innerHTML = 'Bilal'">
|
||||
Click me
|
||||
</button>
|
||||
<div>First Name : </div><div ref="name"></div>
|
||||
<div>Last Name : </div><div ref="name"></div>
|
||||
</i-codepreview>
|
||||
|
@ -11,3 +11,14 @@ These variables propagate from an element to its children and could be altered o
|
||||
<div>Time: ${now.toTimeString()}</div>
|
||||
</div>
|
||||
</i-codepreview>
|
||||
|
||||
# Events
|
||||
|
||||
Events can access scope variables when declared with *@eventName*
|
||||
|
||||
<i-codepreview>
|
||||
<div :scope="{now: new Date()}">
|
||||
<button @click="this.innerHTML = now">Click me</button>
|
||||
</div>
|
||||
</i-codepreview>
|
||||
|
||||
|
38
docs/md/getting-started/scripts.md
Normal file
38
docs/md/getting-started/scripts.md
Normal file
@ -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
|
||||
|
||||
<i-codepreview>
|
||||
<button>
|
||||
<script>
|
||||
this.onclick = () => { alert("Hello World !")};
|
||||
this.innerHTML = "Click me";
|
||||
</script>
|
||||
</button>
|
||||
</i-codepreview>
|
||||
|
||||
When the function returns an object it will be projected to the parent element.
|
||||
|
||||
<i-codepreview>
|
||||
<button>
|
||||
<script>
|
||||
this.onclick = () => { alert("Hello World !")};
|
||||
return {innerHTML: "Click Me"}
|
||||
</script>
|
||||
</button>
|
||||
</i-codepreview>
|
||||
|
||||
Scope variables example
|
||||
|
||||
<i-codepreview>
|
||||
<button>
|
||||
<script>
|
||||
this.onclick = () => {
|
||||
refs.msg.innerHTML = new Date().toTimeString();
|
||||
};
|
||||
return {innerHTML: "Click Me"}
|
||||
</script>
|
||||
</button>
|
||||
<div ref="msg"></div>
|
||||
</i-codepreview>
|
@ -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;
|
||||
|
@ -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(){
|
||||
|
@ -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,10 +201,29 @@ export class IUI {
|
||||
}
|
||||
else
|
||||
{
|
||||
element.__i_bindings?.destroy();
|
||||
|
||||
// compile attributes
|
||||
for (var i = 0; i < element.attributes.length; i++) {
|
||||
|
||||
// skip scope
|
||||
if (element.attributes[i].name == ":scope")
|
||||
continue;
|
||||
|
||||
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);
|
||||
|
||||
@ -199,6 +237,7 @@ export class IUI {
|
||||
bindings.push(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add reference
|
||||
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -6,11 +6,12 @@ export default class RefsCollection
|
||||
this._rootElement = rootElement;
|
||||
}
|
||||
|
||||
_build(element) {
|
||||
_build(element, append) {
|
||||
|
||||
if (element == undefined)
|
||||
element = this._rootElement;
|
||||
|
||||
if (!append)
|
||||
for(var i in this)
|
||||
if (i != "_rootElement" && i != "_build")
|
||||
delete this[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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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,12 +62,18 @@ 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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user