2
0
mirror of https://github.com/esiur/iui.git synced 2025-05-06 06:42:58 +00:00

Merge pull request #3 from msal4/main

Add router base option and navigate to origin after on init
This commit is contained in:
Esiur Project 2022-02-14 14:22:08 +03:00 committed by GitHub
commit 0b29064845
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 376 additions and 402 deletions

View File

@ -3,86 +3,84 @@ import { IUI } from "../Core/IUI.js";
import Router from "./Router.js"; import Router from "./Router.js";
import RefsCollection from "../Core/RefsCollection.js"; import RefsCollection from "../Core/RefsCollection.js";
export default IUI.module(class Route extends IUIElement { export default IUI.module(
class Route extends IUIElement {
constructor() { constructor() {
super(); super();
this.routes = []; this.routes = [];
this.refs = new RefsCollection(this); this.refs = new RefsCollection(this);
this._register("show"); this._register("show");
this._register("hide"); this._register("hide");
} }
async setData(value) { async setData(value) {
if (this.hasAttribute("debug")) if (this.hasAttribute("debug")) debugger;
debugger;
return await super.setData(value); return await super.setData(value);
} }
get scope(){ get scope() {
return {route: this, view: this}; return { route: this, view: this };
} }
_updateLinks() { _updateLinks() {
for (var i = 0; i < this.children.length; i++) { for (var i = 0; i < this.children.length; i++) {
if (this.children[i] instanceof Route) { if (this.children[i] instanceof Route) {
this.routes.push(this.children[i]); this.routes.push(this.children[i]);
window.router.add(this.children[i], this); window.router.add(this.children[i], this);
i--; i--;
}
} }
}
} }
get link() { get link() {
var link = this.name; var link = this.name;
var parent = this.parent; var parent = this.parent;
while (parent != null) { while (parent != null) {
link = parent.name + "/" + link; link = parent.name + "/" + link;
parent = parent.parent; parent = parent.parent;
} }
return link; return (window.router.base ? window.router.base + "/" : "") + link;
} }
get name() { get name() {
return this.getAttribute("name"); return this.getAttribute("name");
} }
get src() { get src() {
return this.getAttribute("src"); return this.getAttribute("src");
} }
get dst() { get dst() {
return this._dst || this.getAttribute("dst"); return this._dst || this.getAttribute("dst");
} }
set dst(value){ set dst(value) {
this._dst = value; this._dst = value;
} }
get caption() { get caption() {
return this.getAttribute("caption"); return this.getAttribute("caption");
} }
get private() { get private() {
return this.hasAttribute("private"); return this.hasAttribute("private");
} }
get icon() { get icon() {
return this.getAttribute("icon"); return this.getAttribute("icon");
} }
_getParent() { _getParent() {
let e = null;//this.parentElement; let e = null; //this.parentElement;
while (e = this.parentElement) { while ((e = this.parentElement)) {
if (e instanceof Route || e instanceof Router) if (e instanceof Route || e instanceof Router) return e;
return e; }
}
return null; return null;
} }
// get route() { // get route() {
@ -92,93 +90,85 @@ export default IUI.module(class Route extends IUIElement {
// get view() { // get view() {
// return this; // return this;
// } // }
async create() { async create() {
//window.router.add(this);
this._updateLinks();
//window.router.add(this); if (this.hasAttribute("src")) {
this._updateLinks(); 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, ''); this.innerHTML = t;
let x = await fetch(src);
if (x.status != 200)
return;
let t = await x.text();
this.innerHTML = t; //let xeval = (code) => eval(code);
}
//let xeval = (code) => eval(code);
}
if (window?.app?.loaded) {
if (window?.app?.loaded) await IUI.create(this);
{ IUI.bind(this, true, "route:" + src, this.scope);
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(); 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) { set(value) {
if (value == this.visible) if (value == this.visible) return;
return;
if (value) { if (value) {
this.setAttribute("selected", "");
this.setAttribute("selected", ""); this._emit("show");
this._emit("show"); } else {
this.removeAttribute("selected");
this._emit("hide");
} }
else
{
this.removeAttribute("selected");
this._emit("hide");
}
} }
get visible() { return this.hasAttribute("selected"); } get visible() {
set visible(value) { this.set(value); } return this.hasAttribute("selected");
}
}); set visible(value) {
this.set(value);
}
}
);

View File

@ -1,338 +1,322 @@
import IUIElement from "../Core/IUIElement.js"; import IUIElement from "../Core/IUIElement.js";
import Route from "./Route.js" import Route from "./Route.js";
import Target from "./Target.js"; import Target from "./Target.js";
import { IUI } from "../Core/IUI.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 this._history = [];
{
constructor()
{
super({routes: [], _states: new Map(), active: null, cssClass: "router"});
this._history = []; //IUI._router = this;
//IUI._router = this;
//Object.defineProperty(window, "router", {
// get() {
// if (!IUI._router.isConnected)
// IUI._router = document.getElementsByTagName("i-router")[0];
// return IUI._router;
// }
//});
//Object.defineProperty(window, "router", {
// get() {
// if (!IUI._router.isConnected)
// IUI._router = document.getElementsByTagName("i-router")[0];
// return IUI._router;
// }
//});
} }
_getRouteParent(route) { _getRouteParent(route) {
let e = null; let e = null;
while (e = route.parentElement) { while ((e = route.parentElement)) {
if (e instanceof Route || e instanceof Router) if (e instanceof Route || e instanceof Router) return e;
return e; }
}
return null; return null;
} }
add(route, parent = null) { add(route, parent = null) {
if (parent == null) { if (parent == null) {
this.routes.push(route); this.routes.push(route);
} } else {
else { route.parent = parent;
route.parent = parent; this.appendChild(route);
this.appendChild(route); //parent.routes.push(route);
//parent.routes.push(route); }
}
} }
_routeInPath(name, routes) _routeInPath(name, routes) {
{ for (var i = 0; i < routes.length; i++)
for (var i = 0; i < routes.length; i++) if (routes[i].name == name) return routes[i];
if (routes[i].name == name) return null;
return routes[i];
return null;
} }
getRoute(url, data) { 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++) { if (p[0] == this.base) {
var route = this._routeInPath(p[i], searchRoutes); p.shift();
}
if (route == null) for (var i = 0; i < p.length; i++) {
return [null, null]; var route = this._routeInPath(p[i], searchRoutes);
if (i == p.length - 1) { if (route == null) return [null, null];
// 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; if (i == p.length - 1) {
let url = dst.replace(/^[/]*(.*?)[/]*$/g, '$1').trim(); // return [destination state route (link, icon,..etc) , actual route to view]
return [route, this.getRoute(url)[1]]; if (route.dst == null) return [route, route];
} else {
} let dst =
route.dst instanceof Function ? route.dst(data) : route.dst;
searchRoutes = route.routes; let url = dst.replace(/^[/]*(.*?)[/]*$/g, "$1").trim();
return [route, this.getRoute(url)[1]];
}
} }
searchRoutes = route.routes;
}
} }
back() { back() {
//if (this._history.length > 1) { //if (this._history.length > 1) {
// let last = this._history[this._history.length - 2]; // let last = this._history[this._history.length - 2];
// this.navigate(last.url, last.data, last.target); // this.navigate(last.url, last.data, last.target);
//} //}
window.history.back(); window.history.back();
} }
_toQuery(o) { _toQuery(o) {
let rt = []; let rt = [];
for (let i in o) for (let i in o)
if (o[i] == undefined) if (o[i] == undefined) rt.push(i);
rt.push(i); else rt.push(i + "=" + encodeURI(o[i].toString().replace("&", "&&"))); ///encodeURIComponent(o[i]));
else return rt.join("&");
rt.push(i + "=" + encodeURI(o[i].toString().replace("&", "&&")));///encodeURIComponent(o[i]));
return rt.join("&");
} }
_fromQuery(q) { _fromQuery(q) {
let kv = q.replace("&&", "\0").split('&'); let kv = q.replace("&&", "\0").split("&");
let rt = {}; let rt = {};
for (let i = 0; i < kv.length; i++) { for (let i = 0; i < kv.length; i++) {
let d = kv[i].replace("\0", "&").split('=', 2); let d = kv[i].replace("\0", "&").split("=", 2);
let v = decodeURI(d[1] || ''); //decodeURIComponent(d[1] || ''); let v = decodeURI(d[1] || ""); //decodeURIComponent(d[1] || '');
if (v != null && v.trim() != '' && !isNaN(v)) if (v != null && v.trim() != "" && !isNaN(v)) v = new Number(v);
v = new Number(v); rt[d[0]] = v;
rt[d[0]] = v; }
} return JSON.parse(JSON.stringify(rt));
return JSON.parse(JSON.stringify(rt));
} }
async navigate(url, data, target, state, dataToQuery = true) async navigate(url, data, target, state, dataToQuery = true) {
{ let q = url.match(/^\/*(.*?)\?(.*)$|^\/*(.*)$/);
let q = url.match(/^\/*(.*?)\?(.*)$|^\/*(.*)$/);
//debugger; //debugger;
var path; var path;
// do we have a query string ? // do we have a query string ?
if (q[2] !== undefined) { if (q[2] !== undefined) {
path = q[1]; path = q[1];
data = this._fromQuery(q[2]); data = this._fromQuery(q[2]);
url = path + "?" + q[2]; url = path + "?" + q[2];
} }
// do we have data ? // do we have data ?
else if (data !== undefined) { else if (data !== undefined) {
path = q[3]; path = q[3];
url = dataToQuery ? path + "?" + this._toQuery(data) : path; url = dataToQuery ? path + "?" + this._toQuery(data) : path;
} } else {
else { path = q[3];
path = q[3]; url = path;
url = path; }
}
let [stateRoute, viewRoute] = this.getRoute(path, data); let [stateRoute, viewRoute] = this.getRoute(path, data);
if (stateRoute == null) if (stateRoute == null) {
{ console.warn("State not found ", path);
console.warn("State not found ", path); return;
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) if (!ok) {
{ console.warn("Route not allowed", path);
console.warn("Route not allowed", path); return;
return; }
}
// destination view not found // destination view not found
if (viewRoute == null) { if (viewRoute == null) {
console.log(`Destination route not found ${stateRoute.dst}`); console.log(`Destination route not found ${stateRoute.dst}`);
viewRoute = stateRoute; viewRoute = stateRoute;
} }
//let state = null; //let state = null;
//if (data !== undefined) { //if (data !== undefined) {
// for (let [k, v] of this._states) // for (let [k, v] of this._states)
// if (v == data) { // if (v == data) {
// state = k; // state = k;
// break; // break;
// } // }
// if (state == null) { // if (state == null) {
// state = Math.random().toString(36).substr(2, 10); // state = Math.random().toString(36).substr(2, 10);
// this._states.set(state, data); // this._states.set(state, data);
// } // }
//} //}
if (!(target instanceof Target)) if (!(target instanceof Target)) target = this;
target = this;
if (state == null) { if (state == null) {
let id = Math.random().toString(36).substr(2, 10); let id = Math.random().toString(36).substr(2, 10);
state = { id, url, data, target, stateRoute, viewRoute }; state = { id, url, data, target, stateRoute, viewRoute };
this._states.set(id, state); this._states.set(id, state);
history.pushState(id, stateRoute.caption, this._hash ? "#" + url : "/" + url); 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); target.show(viewRoute, this.active);
viewRoute.set(true); 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 }; target.setLoading(true);
this._emit("route", { route: stateRoute });
viewRoute.query = data || {}; if (stateRoute.dataMap != null) {
stateRoute.query = viewRoute.query; // 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); target.setLoading(false);
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);
} }
hide() { hide() {
// do nothing, we're not here to hide. // do nothing, we're not here to hide.
} }
refresh() { refresh() {
let state = this.current;
this.navigate(state.url, state.data, state.target, state);
let state = this.current; //this.current.render();
this.navigate(state.url, state.data, state.target, state); //this.current.data = this.current.data;
//if (updateAttributes)
//this.current.render(); // this.current.updateAttributes(true);
//this.current.data = this.current.data;
//if (updateAttributes)
// this.current.updateAttributes(true);
} }
show(route, active) { show(route, active) {
super.show(route, active); super.show(route, active);
} }
get current() { get current() {
return this._states.get(history.state);//.viewRoute; return this._states.get(history.state); //.viewRoute;
//return this._history[this._history.length - 1].viewRoute; //return this._history[this._history.length - 1].viewRoute;
} }
get previous() { get previous() {
if (this._history.length > 2)
if (this._history.length > 2) return this._states.get(this._history[this._history.length - 2]);
return this._states.get(this._history[this._history.length - 2]);//.viewRoute; //.viewRoute;
else else return null;
return null;
} }
create() { create() {
// save origin
// save origin this.origin = window.location.pathname + window.location.search;
this.origin = window.location.pathname + window.location.search; this.base = this.getAttribute("base") || "";
} }
destroy() { 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") /// find all children
this._hash = true; for (var i = 0; i < this.children.length; i++) {
let e = this.children[i];
if (e instanceof Route) {
/// find all children this.add(e);
for (var i = 0; i < this.children.length; i++) { if (e.visible) this.navigate(e.name);
let e = this.children[i];
if (e instanceof Route) {
this.add(e);
if (e.visible)
this.navigate(e.name);
}
} }
}
this._emit("created"); this._emit("created");
this.navigate(this.origin);
//console.log("Router created", this); //console.log("Router created", this);
} }
connectedCallback() { 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); if (self._hash) {
let stateId = event.state; path = window.location.hash;
let path;
if (self._hash) { if (path.length > 0) path = path.substr(1);
path = window.location.hash; } else {
path = window.location.pathname;
}
if (path.length > 0) if (stateId != null) {
path = path.substr(1); if (stateId != self._history[self._history.length - 1]) {
} //this._lastStateId = stateId;
else { let state = self._states.get(stateId);
path = window.location.pathname; 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) { this._register("navigate");
this._register("route");
if (stateId != self._history[self._history.length -1]) { this._register("created");
//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");
} }
}
}); );

View File

@ -1,64 +1,64 @@
import {IUI, iui} from "./Core/IUI.js"; import { IUI, iui } from "./Core/IUI.js";
import "./Core/IUIElement.js"; import "./Core/IUIElement.js";
import './Core/App.js'; import "./Core/App.js";
import './Router/Router.js'; import "./Router/Router.js";
import './Router/Route.js'; import "./Router/Route.js";
import './Router/Link.js'; import "./Router/Link.js";
import './Router/Target.js'; import "./Router/Target.js";
import './Data/Repeat.js'; import "./Data/Repeat.js";
import './Data/Include.js'; import "./Data/Include.js";
import './Data/Form.js'; import "./Data/Form.js";
import './UI/Login.js'; import "./UI/Login.js";
import './UI/Window.js'; import "./UI/Window.js";
import './UI/Dialog.js'; import "./UI/Dialog.js";
import './UI/Input.js'; import "./UI/Input.js";
import './UI/Tab.js'; import "./UI/Tab.js";
import './UI/Tabs.js'; import "./UI/Tabs.js";
import './UI/Table.js'; import "./UI/Table.js";
import './UI/Check.js'; import "./UI/Check.js";
import './UI/Button.js'; import "./UI/Button.js";
import './UI/Navbar.js'; import "./UI/Navbar.js";
import './UI/DateTimePicker.js'; import "./UI/DateTimePicker.js";
import './Data/Layout.js'; import "./Data/Layout.js";
import './Data/Field.js'; import "./Data/Field.js";
import './UI/Background.js'; import "./UI/Background.js";
import './UI/Menu.js'; import "./UI/Menu.js";
import './Data/TableRow.js'; import "./Data/TableRow.js";
import './UI/Select.js'; import "./UI/Select.js";
import './UI/DropDown.js'; import "./UI/DropDown.js";
import './UI/Grid.js'; import "./UI/Grid.js";
import './UI/Location.js'; import "./UI/Location.js";
import './UI/CodePreview.js'; import "./UI/CodePreview.js";
window.addEventListener("beforeprint", (e)=>{ window.addEventListener("beforeprint", e => {
let viewRoute = router.current.viewRoute; let viewRoute = router.current.viewRoute;
viewRoute.style.height = "auto"; viewRoute.style.height = "auto";
router.style.height = viewRoute.clientHeight + "px"; router.style.height = viewRoute.clientHeight + "px";
}); });
window.addEventListener("afterprint", (e)=>{ window.addEventListener("afterprint", e => {
let viewRoute = router.current.viewRoute; let viewRoute = router.current.viewRoute;
viewRoute.style.height = ""; viewRoute.style.height = "";
router.style.height = ""; router.style.height = "";
}); });
window.addEventListener("load", async function () { window.addEventListener("load", async function () {
await IUI.create(document.body); await IUI.create(document.body);
await IUI.created(document.body); await IUI.created(document.body);
//if (window.app != null) { //if (window.app != null) {
// window.app._emit("load", { app: window.app }); // window.app._emit("load", { app: window.app });
// } // }
}); });
window.iui = iui; window.iui = iui;