diff --git a/css/iui.css b/css/iui.css index cc9fc2e..0b99752 100644 --- a/css/iui.css +++ b/css/iui.css @@ -3098,4 +3098,20 @@ html[dir='rtl'] .navbar-item[level='1'] { .codepreview-bar { +} + +.iui-error { + background: #7171714d; + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + pointer-events: none; +} + +.iui-error > span { + background: red; + color: white; + padding: 4px; } \ No newline at end of file diff --git a/package.json b/package.json index dfc6ea6..cffed88 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@esiur/iui", - "version": "1.1.8", + "version": "1.1.9", "description": "Interactive User Interface", "main": "iui.js", "type": "module", diff --git a/src/Core/Binding.js b/src/Core/Binding.js index fa7fb21..36ab8f0 100644 --- a/src/Core/Binding.js +++ b/src/Core/Binding.js @@ -179,6 +179,10 @@ export class Binding { if (context.error != undefined) { + if (thisArg instanceof IUIElement){ + thisArg.setError(context.error); + } + console.log("Execution failed", context.error.name + ": " + context.error.message, this.script, this.target); return; } @@ -192,6 +196,11 @@ export class Binding { { return await context.value; } catch(ex) { + + if (thisArg instanceof IUIElement){ + thisArg.setError(ex); + } + console.log("Execution failed", ex.name + ": " + ex.message, this.script, this.target); } } diff --git a/src/Core/IUI.js b/src/Core/IUI.js index 4fa9571..5904d09 100644 --- a/src/Core/IUI.js +++ b/src/Core/IUI.js @@ -3,9 +3,12 @@ import { Binding, BindingType } from "./Binding.js"; //import Route from '../Router/Route.js'; import BindingList from "./BindingList.js"; +const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor; export class IUI { + static debugMode = true; + static _menus = []; static views = []; static modules = {}; @@ -198,7 +201,7 @@ export class IUI { { // copy attributes bindings if (element.__i_bindings != null) - for(var i = 0; i < element.__i_bindings.length; i++) + for(let i = 0; i < element.__i_bindings.length; i++) if (element.__i_bindings[i].type != BindingType.TextNode) bindings.push(element.__i_bindings[i]); } @@ -207,28 +210,52 @@ export class IUI { element.__i_bindings?.destroy(); // compile attributes - for (var i = 0; i < element.attributes.length; i++) { + for (let i = 0; i < element.attributes.length; i++) { + let attr = element.attributes[i]; // skip scope - if (element.attributes[i].name == ":scope") + if (attr.name == ":scope") continue; - if (element.attributes[i].name.startsWith("@")){ + if (attr.name.startsWith("@")){ // make events - let code = element.attributes[i].value; + let code = attr.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); + bindings.addEvent(attr.name.substr(1), handler); + } + else if (attr.name.startsWith("event:")) + { + // make events + let code = attr.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(attr.name.substr(6), handler); + + } + else if (attr.name.startsWith("async-event:")) { + // make events + let code = attr.value; + //let code = `try {\r\n context.value = ${script}; \r\n}\r\n catch(ex) { context.error = ex; }` + let func = new AsyncFunction("event", ...scopeArgs, code); + let handler = (event) => { + func.call(element, event, ...scopeValues); + } + + bindings.addEvent(attr.name.substr(12), handler); } else { - let b = Binding.create(element.attributes[i], - bindings.scope); + let b = Binding.create(attr, bindings.scope); if (b != null) { if (b.type == BindingType.HTMLElementDataAttribute diff --git a/src/Core/IUIElement.js b/src/Core/IUIElement.js index c0f1d3a..ea7c002 100644 --- a/src/Core/IUIElement.js +++ b/src/Core/IUIElement.js @@ -63,6 +63,22 @@ export default class IUIElement extends HTMLElement { await this.updated(); } + + setError(exception) { + if (!IUI.debugMode) + return; + + if (this._errorElement == null) { + this._errorElement = document.createElement("div"); + this._errorElement.className = "iui-error"; + this.append(this._errorElement); + } + + var label = document.createElement("span"); + label.innerHTML = exception; + this._errorElement.append(label); + } + async updated() { // to be implemented by the user. diff --git a/src/Data/Repeat.js b/src/Data/Repeat.js index 3054ec7..723aaa9 100644 --- a/src/Data/Repeat.js +++ b/src/Data/Repeat.js @@ -23,7 +23,7 @@ export default IUI.module(class Repeat extends IUIElement /// Create /// ////////////// - console.log(this, this.innerHTML); + //console.log(this, this.innerHTML); if (this._created) debugger; @@ -144,12 +144,17 @@ export default IUI.module(class Repeat extends IUIElement this.list.push(el); - await IUI.create(el); + try { + await IUI.create(el); + + IUI.bind(el, false, "repeat", + IUI.extend(this.__i_bindings?.scope, + {index: i, repeat: this}, true)); + + } catch (ex) { + console.log(ex); + } - IUI.bind(el, false, "repeat", - IUI.extend(this.__i_bindings?.scope, - {index: i, repeat: this}, true)); - this._container.insertBefore(el, this._beforeNode); // update referencing diff --git a/src/Router/Router.js b/src/Router/Router.js index f0ef623..f74012f 100644 --- a/src/Router/Router.js +++ b/src/Router/Router.js @@ -114,6 +114,10 @@ export default IUI.module( } async navigate(url, data, target, state, dataToQuery = true) { + + if (url == null) + throw new Error("URL not specified."); + let q = url.match(/^\/*(.*?)\?(.*)$|^\/*(.*)$/); var path; @@ -203,14 +207,18 @@ export default IUI.module( target.setLoading(true); - if (stateRoute.dataMap != null) { - // if map function failed to call setData, we will render without it - if (!(await stateRoute.dataMap.render(data || {}))) - await stateRoute.render(); + try { + if (stateRoute.dataMap != null) { + // if map function failed to call setData, we will render without it + if (!(await stateRoute.dataMap.render(data || {}))) + await stateRoute.render(); - if (viewRoute != stateRoute) await viewRoute.setData(stateRoute.data); - } //if (data !== undefined) - else await viewRoute.setData(data); + if (viewRoute != stateRoute) await viewRoute.setData(stateRoute.data); + } //if (data !== undefined) + else await viewRoute.setData(data); + } catch (ex){ + console.log("EXXXXXXXXXX", ex); + } target.setLoading(false); } diff --git a/src/iui.js b/src/iui.js index ebf1a57..a764b1d 100644 --- a/src/iui.js +++ b/src/iui.js @@ -57,8 +57,7 @@ window.addEventListener("afterprint", e => { window.addEventListener("load", async function () { await IUI.create(document.body); await IUI.created(document.body); - - console.log("IUI.create()"); + }); window.iui = iui;