diff --git a/src/Router/Route.js b/src/Router/Route.js index cf9a76b..14d27dd 100644 --- a/src/Router/Route.js +++ b/src/Router/Route.js @@ -3,86 +3,84 @@ import { IUI } from "../Core/IUI.js"; import Router from "./Router.js"; import RefsCollection from "../Core/RefsCollection.js"; -export default IUI.module(class Route extends IUIElement { - +export default IUI.module( + class Route extends IUIElement { constructor() { - super(); + super(); - this.routes = []; - this.refs = new RefsCollection(this); + this.routes = []; + this.refs = new RefsCollection(this); - this._register("show"); - this._register("hide"); + this._register("show"); + this._register("hide"); } async setData(value) { - if (this.hasAttribute("debug")) - debugger; + if (this.hasAttribute("debug")) debugger; - return await super.setData(value); + return await super.setData(value); } - get scope(){ - return {route: this, view: this}; + get scope() { + return { route: this, view: this }; } _updateLinks() { - for (var i = 0; i < this.children.length; i++) { - if (this.children[i] instanceof Route) { - this.routes.push(this.children[i]); - window.router.add(this.children[i], this); - i--; - } + for (var i = 0; i < this.children.length; i++) { + if (this.children[i] instanceof Route) { + this.routes.push(this.children[i]); + window.router.add(this.children[i], this); + i--; } + } } get link() { - var link = this.name; - var parent = this.parent; - while (parent != null) { - link = parent.name + "/" + link; - parent = parent.parent; - } + var link = this.name; + var parent = this.parent; + while (parent != null) { + link = parent.name + "/" + link; + parent = parent.parent; + } - return link; + return (window.router.base ? window.router.base + "/" : "") + link; } get name() { - return this.getAttribute("name"); + return this.getAttribute("name"); } get src() { - return this.getAttribute("src"); + return this.getAttribute("src"); } get dst() { - return this._dst || this.getAttribute("dst"); + return this._dst || this.getAttribute("dst"); } - set dst(value){ - this._dst = value; + set dst(value) { + this._dst = value; } - + get caption() { - return this.getAttribute("caption"); + return this.getAttribute("caption"); } get private() { - return this.hasAttribute("private"); + return this.hasAttribute("private"); } get icon() { - return this.getAttribute("icon"); + return this.getAttribute("icon"); } _getParent() { - let e = null;//this.parentElement; - while (e = this.parentElement) { - if (e instanceof Route || e instanceof Router) - return e; - } + let e = null; //this.parentElement; + while ((e = this.parentElement)) { + if (e instanceof Route || e instanceof Router) return e; + } - return null; + return null; } // get route() { @@ -92,93 +90,85 @@ export default IUI.module(class Route extends IUIElement { // get view() { // return this; // } - + async create() { + //window.router.add(this); + this._updateLinks(); - //window.router.add(this); - this._updateLinks(); + if (this.hasAttribute("src")) { + let src = this.getAttribute("src").replace(/^\/+|\/+$/g, ""); + let x = await fetch(src); + if (x.status != 200) return; - if (this.hasAttribute("src")) { + let t = await x.text(); - let src = this.getAttribute("src").replace(/^\/+|\/+$/g, ''); - let x = await fetch(src); - if (x.status != 200) - return; - - let t = await x.text(); + this.innerHTML = t; - this.innerHTML = t; - - //let xeval = (code) => eval(code); - } + //let xeval = (code) => eval(code); + } - - if (window?.app?.loaded) - { - await IUI.create(this); - IUI.bind(this, true, "route:" + src, this.scope); - this.refs._build(); - await IUI.created(this); - await IUI.render(this, this._data, true); - } - - // // call create for the new elements - // var newElements = this.querySelectorAll("*"); - // for (var i = 0; i < newElements.length; i++) { - // // set route for all elements - // var el = newElements[i]; - // // newElements[i].route = this; - // el.view = this; - // el.route = this; - - // if (el.hasAttribute("ref")) { - // this.refs[el.getAttribute("ref")] = el; - // } - - // if (el instanceof HTMLScriptElement) { - // // this because HTML parsers don't evaluate script tag - // // xeval.call(el.parentElement, "//# sourceURL=iui://" + src + "\r\n" + el.text); - - // //let func = new Function("//# sourceURL=iui://" + - // // src + "-" + Math.round(Math.random() * 10000) + "\r\n return " + el.text.trim()); - - // let func = new Function("//# sourceURL=iui://" + this.link - // + "\r\n return " + el.text.trim()); - - // let rt = func.call(el.parentElement); - - // if (typeof (rt) === "object") { - // for (var k in rt) - // el.parentElement[k] = rt[k]; - // } - // } - // } - } - - created() - { + if (window?.app?.loaded) { + await IUI.create(this); + IUI.bind(this, true, "route:" + src, this.scope); this.refs._build(); + await IUI.created(this); + await IUI.render(this, this._data, true); + } + + // // call create for the new elements + // var newElements = this.querySelectorAll("*"); + // for (var i = 0; i < newElements.length; i++) { + // // set route for all elements + // var el = newElements[i]; + // // newElements[i].route = this; + // el.view = this; + // el.route = this; + + // if (el.hasAttribute("ref")) { + // this.refs[el.getAttribute("ref")] = el; + // } + + // if (el instanceof HTMLScriptElement) { + // // this because HTML parsers don't evaluate script tag + // // xeval.call(el.parentElement, "//# sourceURL=iui://" + src + "\r\n" + el.text); + + // //let func = new Function("//# sourceURL=iui://" + + // // src + "-" + Math.round(Math.random() * 10000) + "\r\n return " + el.text.trim()); + + // let func = new Function("//# sourceURL=iui://" + this.link + // + "\r\n return " + el.text.trim()); + + // let rt = func.call(el.parentElement); + + // if (typeof (rt) === "object") { + // for (var k in rt) + // el.parentElement[k] = rt[k]; + // } + // } + // } } - + + created() { + this.refs._build(); + } + set(value) { - if (value == this.visible) - return; + if (value == this.visible) return; - if (value) { - - this.setAttribute("selected", ""); - this._emit("show"); - - - } - else - { - this.removeAttribute("selected"); - this._emit("hide"); - } + if (value) { + this.setAttribute("selected", ""); + this._emit("show"); + } else { + this.removeAttribute("selected"); + this._emit("hide"); + } } - get visible() { return this.hasAttribute("selected"); } - set visible(value) { this.set(value); } - -}); + get visible() { + return this.hasAttribute("selected"); + } + set visible(value) { + this.set(value); + } + } +); diff --git a/src/Router/Router.js b/src/Router/Router.js index 42920f2..98e48da 100644 --- a/src/Router/Router.js +++ b/src/Router/Router.js @@ -1,338 +1,322 @@ import IUIElement from "../Core/IUIElement.js"; -import Route from "./Route.js" +import Route from "./Route.js"; import Target from "./Target.js"; import { IUI } from "../Core/IUI.js"; +export default IUI.module( + class Router extends Target { + constructor() { + super({ + routes: [], + _states: new Map(), + active: null, + cssClass: "router", + }); -export default IUI.module(class Router extends Target -{ - - constructor() - { - super({routes: [], _states: new Map(), active: null, cssClass: "router"}); + this._history = []; - this._history = []; - - - //IUI._router = this; - - //Object.defineProperty(window, "router", { - // get() { - // if (!IUI._router.isConnected) - // IUI._router = document.getElementsByTagName("i-router")[0]; - // return IUI._router; - // } - //}); + //IUI._router = this; + //Object.defineProperty(window, "router", { + // get() { + // if (!IUI._router.isConnected) + // IUI._router = document.getElementsByTagName("i-router")[0]; + // return IUI._router; + // } + //}); } _getRouteParent(route) { - let e = null; + let e = null; - while (e = route.parentElement) { - if (e instanceof Route || e instanceof Router) - return e; - } + while ((e = route.parentElement)) { + if (e instanceof Route || e instanceof Router) return e; + } - return null; + return null; } add(route, parent = null) { - if (parent == null) { - this.routes.push(route); - } - else { - route.parent = parent; - this.appendChild(route); - //parent.routes.push(route); - } + if (parent == null) { + this.routes.push(route); + } else { + route.parent = parent; + this.appendChild(route); + //parent.routes.push(route); + } } - _routeInPath(name, routes) - { - for (var i = 0; i < routes.length; i++) - if (routes[i].name == name) - return routes[i]; - return null; + _routeInPath(name, routes) { + for (var i = 0; i < routes.length; i++) + if (routes[i].name == name) return routes[i]; + return null; } getRoute(url, data) { - let p = url.split("/"); + /** + * @type {String[]} + */ + let p = url.split("/"); - let searchRoutes = this.routes; + let searchRoutes = this.routes; - for (var i = 0; i < p.length; i++) { - var route = this._routeInPath(p[i], searchRoutes); + if (p[0] == this.base) { + p.shift(); + } - if (route == null) - return [null, null]; + for (var i = 0; i < p.length; i++) { + var route = this._routeInPath(p[i], searchRoutes); - if (i == p.length - 1) { - // return [destination state route (link, icon,..etc) , actual route to view] - if (route.dst == null) - return [route, route]; - else { + if (route == null) return [null, null]; - let dst = route.dst instanceof Function ? route.dst(data) : route.dst; - let url = dst.replace(/^[/]*(.*?)[/]*$/g, '$1').trim(); - return [route, this.getRoute(url)[1]]; - } - } - - searchRoutes = route.routes; + if (i == p.length - 1) { + // return [destination state route (link, icon,..etc) , actual route to view] + if (route.dst == null) return [route, route]; + else { + let dst = + route.dst instanceof Function ? route.dst(data) : route.dst; + let url = dst.replace(/^[/]*(.*?)[/]*$/g, "$1").trim(); + return [route, this.getRoute(url)[1]]; + } } + searchRoutes = route.routes; + } } back() { - //if (this._history.length > 1) { - // let last = this._history[this._history.length - 2]; - // this.navigate(last.url, last.data, last.target); - //} + //if (this._history.length > 1) { + // let last = this._history[this._history.length - 2]; + // this.navigate(last.url, last.data, last.target); + //} - window.history.back(); - } + window.history.back(); + } _toQuery(o) { - let rt = []; - for (let i in o) - if (o[i] == undefined) - rt.push(i); - else - rt.push(i + "=" + encodeURI(o[i].toString().replace("&", "&&")));///encodeURIComponent(o[i])); - return rt.join("&"); + let rt = []; + for (let i in o) + if (o[i] == undefined) rt.push(i); + else rt.push(i + "=" + encodeURI(o[i].toString().replace("&", "&&"))); ///encodeURIComponent(o[i])); + return rt.join("&"); } _fromQuery(q) { - let kv = q.replace("&&", "\0").split('&'); - let rt = {}; - for (let i = 0; i < kv.length; i++) { - let d = kv[i].replace("\0", "&").split('=', 2); - let v = decodeURI(d[1] || ''); //decodeURIComponent(d[1] || ''); - if (v != null && v.trim() != '' && !isNaN(v)) - v = new Number(v); - rt[d[0]] = v; - } - return JSON.parse(JSON.stringify(rt)); + let kv = q.replace("&&", "\0").split("&"); + let rt = {}; + for (let i = 0; i < kv.length; i++) { + let d = kv[i].replace("\0", "&").split("=", 2); + let v = decodeURI(d[1] || ""); //decodeURIComponent(d[1] || ''); + if (v != null && v.trim() != "" && !isNaN(v)) v = new Number(v); + rt[d[0]] = v; + } + return JSON.parse(JSON.stringify(rt)); } - async navigate(url, data, target, state, dataToQuery = true) - { - let q = url.match(/^\/*(.*?)\?(.*)$|^\/*(.*)$/); + async navigate(url, data, target, state, dataToQuery = true) { + let q = url.match(/^\/*(.*?)\?(.*)$|^\/*(.*)$/); - //debugger; + //debugger; - var path; + var path; - // do we have a query string ? - if (q[2] !== undefined) { - path = q[1]; - data = this._fromQuery(q[2]); - url = path + "?" + q[2]; - } - // do we have data ? - else if (data !== undefined) { - path = q[3]; - url = dataToQuery ? path + "?" + this._toQuery(data) : path; - } - else { - path = q[3]; - url = path; - } - + // do we have a query string ? + if (q[2] !== undefined) { + path = q[1]; + data = this._fromQuery(q[2]); + url = path + "?" + q[2]; + } + // do we have data ? + else if (data !== undefined) { + path = q[3]; + url = dataToQuery ? path + "?" + this._toQuery(data) : path; + } else { + path = q[3]; + url = path; + } - let [stateRoute, viewRoute] = this.getRoute(path, data); + let [stateRoute, viewRoute] = this.getRoute(path, data); - if (stateRoute == null) - { - console.warn("State not found ", path); - return; - } + if (stateRoute == null) { + console.warn("State not found ", path); + return; + } - let ok = this._emit("navigate", { url, stateRoute, viewRoute, base: path, data, cancelable: true }); + let ok = this._emit("navigate", { + url, + stateRoute, + viewRoute, + base: path, + data, + cancelable: true, + }); - if (!ok) - { - console.warn("Route not allowed", path); - return; - } + if (!ok) { + console.warn("Route not allowed", path); + return; + } - // destination view not found - if (viewRoute == null) { - console.log(`Destination route not found ${stateRoute.dst}`); - viewRoute = stateRoute; - } - + // destination view not found + if (viewRoute == null) { + console.log(`Destination route not found ${stateRoute.dst}`); + viewRoute = stateRoute; + } - //let state = null; + //let state = null; - //if (data !== undefined) { - // for (let [k, v] of this._states) - // if (v == data) { - // state = k; - // break; - // } + //if (data !== undefined) { + // for (let [k, v] of this._states) + // if (v == data) { + // state = k; + // break; + // } - // if (state == null) { - // state = Math.random().toString(36).substr(2, 10); - // this._states.set(state, data); - // } - //} + // if (state == null) { + // state = Math.random().toString(36).substr(2, 10); + // this._states.set(state, data); + // } + //} - if (!(target instanceof Target)) - target = this; + if (!(target instanceof Target)) target = this; - if (state == null) { - let id = Math.random().toString(36).substr(2, 10); - state = { id, url, data, target, stateRoute, viewRoute }; - this._states.set(id, state); - history.pushState(id, stateRoute.caption, this._hash ? "#" + url : "/" + url); - } + if (state == null) { + let id = Math.random().toString(36).substr(2, 10); + state = { id, url, data, target, stateRoute, viewRoute }; + this._states.set(id, state); + history.pushState( + id, + stateRoute.caption, + this._hash ? "#" + url : "/" + url + ); + } - this._history.push(state.id);// { url, data, target, stateRoute, viewRoute }); + this._history.push(state.id); // { url, data, target, stateRoute, viewRoute }); - target.show(viewRoute, this.active); - viewRoute.set(true); + target.show(viewRoute, this.active); + viewRoute.set(true); + this.active = viewRoute; - this.active = viewRoute; + //{ url: "/", data: null, target: null }; + this._emit("route", { route: stateRoute }); + viewRoute.query = data || {}; + stateRoute.query = viewRoute.query; - //{ url: "/", data: null, target: null }; - this._emit("route", { route: stateRoute }); + target.setLoading(true); - viewRoute.query = data || {}; - stateRoute.query = viewRoute.query; + 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); - 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(); - - if (viewRoute != stateRoute) - await viewRoute.setData(stateRoute.data); - } - else //if (data !== undefined) - await viewRoute.setData(data); - - target.setLoading(false); - + target.setLoading(false); } hide() { - // do nothing, we're not here to hide. + // do nothing, we're not here to hide. } refresh() { + let state = this.current; + this.navigate(state.url, state.data, state.target, state); - let state = this.current; - this.navigate(state.url, state.data, state.target, state); - - //this.current.render(); - //this.current.data = this.current.data; - //if (updateAttributes) - // this.current.updateAttributes(true); + //this.current.render(); + //this.current.data = this.current.data; + //if (updateAttributes) + // this.current.updateAttributes(true); } show(route, active) { - super.show(route, active); - - + super.show(route, active); } get current() { - return this._states.get(history.state);//.viewRoute; - //return this._history[this._history.length - 1].viewRoute; + return this._states.get(history.state); //.viewRoute; + //return this._history[this._history.length - 1].viewRoute; } get previous() { - - if (this._history.length > 2) - return this._states.get(this._history[this._history.length - 2]);//.viewRoute; - else - return null; + if (this._history.length > 2) + return this._states.get(this._history[this._history.length - 2]); + //.viewRoute; + else return null; } create() { - - // save origin - this.origin = window.location.pathname + window.location.search; + // save origin + this.origin = window.location.pathname + window.location.search; + this.base = this.getAttribute("base") || ""; } destroy() { - console.log("Destroyed", this); + console.log("Destroyed", this); } - created() - { + created() { + if ( + this.hasAttribute("type") && + this.getAttribute("type").toLowerCase() == "hash" + ) + this._hash = true; - if (this.hasAttribute("type") && this.getAttribute("type").toLowerCase() == "hash") - this._hash = true; - - - /// find all children - for (var i = 0; i < this.children.length; i++) { - let e = this.children[i]; - if (e instanceof Route) { - this.add(e); - if (e.visible) - this.navigate(e.name); - } + /// find all children + for (var i = 0; i < this.children.length; i++) { + let e = this.children[i]; + if (e instanceof Route) { + this.add(e); + if (e.visible) this.navigate(e.name); } + } - this._emit("created"); - - //console.log("Router created", this); + this._emit("created"); + this.navigate(this.origin); + //console.log("Router created", this); } connectedCallback() { - //console.log("New router", this); + //console.log("New router", this); - window.router = this; + window.router = this; - let self = this; + let self = this; - window.addEventListener("popstate", function (event) { + window.addEventListener("popstate", function (event) { + //console.log(event); + let stateId = event.state; + let path; - //console.log(event); - let stateId = event.state; - let path; + if (self._hash) { + path = window.location.hash; - if (self._hash) { - path = window.location.hash; + if (path.length > 0) path = path.substr(1); + } else { + path = window.location.pathname; + } - if (path.length > 0) - path = path.substr(1); - } - else { - path = window.location.pathname; - } + if (stateId != null) { + if (stateId != self._history[self._history.length - 1]) { + //this._lastStateId = stateId; + let state = self._states.get(stateId); + self.navigate(path, state.data, state.target, state); + } else { + console.log("SAME"); + } + } else { + this._lastState = null; + self.navigate(path, undefined, undefined, {}); + } + //alert("location: " + document.location + ", state: " + JSON.stringify(event.state)); + console.log(document.location.hash, event.state); + }); - if (stateId != null) { - - if (stateId != self._history[self._history.length -1]) { - //this._lastStateId = stateId; - let state = self._states.get(stateId); - self.navigate(path, state.data, state.target, state); - } - else { - console.log("SAME"); - } - } - else { - this._lastState = null; - self.navigate(path, undefined, undefined, {}); - } - //alert("location: " + document.location + ", state: " + JSON.stringify(event.state)); - console.log(document.location.hash, event.state); - }); - - this._register("navigate"); - this._register("route"); - this._register("created"); + this._register("navigate"); + this._register("route"); + this._register("created"); } - -}); \ No newline at end of file + } +); diff --git a/src/iui.js b/src/iui.js index 36a94d2..6c00440 100644 --- a/src/iui.js +++ b/src/iui.js @@ -1,58 +1,58 @@ -import {IUI, iui} from "./Core/IUI.js"; +import { IUI, iui } from "./Core/IUI.js"; import "./Core/IUIElement.js"; -import './Core/App.js'; +import "./Core/App.js"; -import './Router/Router.js'; -import './Router/Route.js'; -import './Router/Link.js'; -import './Router/Target.js'; +import "./Router/Router.js"; +import "./Router/Route.js"; +import "./Router/Link.js"; +import "./Router/Target.js"; -import './Data/Repeat.js'; -import './Data/Include.js'; -import './Data/Form.js'; -import './UI/Login.js'; -import './UI/Window.js'; -import './UI/Dialog.js'; -import './UI/Input.js'; -import './UI/Tab.js'; -import './UI/Tabs.js'; +import "./Data/Repeat.js"; +import "./Data/Include.js"; +import "./Data/Form.js"; +import "./UI/Login.js"; +import "./UI/Window.js"; +import "./UI/Dialog.js"; +import "./UI/Input.js"; +import "./UI/Tab.js"; +import "./UI/Tabs.js"; -import './UI/Table.js'; +import "./UI/Table.js"; -import './UI/Check.js'; -import './UI/Button.js'; -import './UI/Navbar.js'; +import "./UI/Check.js"; +import "./UI/Button.js"; +import "./UI/Navbar.js"; -import './UI/DateTimePicker.js'; +import "./UI/DateTimePicker.js"; -import './Data/Layout.js'; -import './Data/Field.js'; +import "./Data/Layout.js"; +import "./Data/Field.js"; -import './UI/Background.js'; -import './UI/Menu.js'; -import './Data/TableRow.js'; +import "./UI/Background.js"; +import "./UI/Menu.js"; +import "./Data/TableRow.js"; -import './UI/Select.js'; +import "./UI/Select.js"; -import './UI/DropDown.js'; -import './UI/Grid.js'; +import "./UI/DropDown.js"; +import "./UI/Grid.js"; import './UI/Location.js'; import './UI/CodePreview.js'; import Modifiable from "./Data/Modifiable.js"; -window.addEventListener("beforeprint", (e)=>{ - let viewRoute = router.current.viewRoute; - viewRoute.style.height = "auto"; - router.style.height = viewRoute.clientHeight + "px"; +window.addEventListener("beforeprint", e => { + let viewRoute = router.current.viewRoute; + viewRoute.style.height = "auto"; + router.style.height = viewRoute.clientHeight + "px"; }); -window.addEventListener("afterprint", (e)=>{ - let viewRoute = router.current.viewRoute; - viewRoute.style.height = ""; - router.style.height = ""; +window.addEventListener("afterprint", e => { + let viewRoute = router.current.viewRoute; + viewRoute.style.height = ""; + router.style.height = ""; }); window.addEventListener("load", async function () { @@ -63,4 +63,4 @@ window.addEventListener("load", async function () { window.iui = iui; -window.Modifiable = Modifiable; \ No newline at end of file +window.Modifiable = Modifiable;