2
0
mirror of https://github.com/esiur/iui.git synced 2025-05-06 06:42:58 +00:00
This commit is contained in:
Ahmed Zamil 2021-10-21 14:15:22 +03:00
parent fab9e186c9
commit 1e8ae99d39
15 changed files with 339 additions and 84 deletions

View File

@ -192,7 +192,7 @@
background: var(--textbox-background); background: var(--textbox-background);
} }
.textbox-with-label > span { .textbox-with-label > span {
padding: 10px; padding: 10px;
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;
@ -202,7 +202,7 @@
transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1); transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
opacity: 0.5; opacity: 0.5;
color: var(--default-link-color); color: var(--default-link-color);
} }
html[dir="rtl"] .textbox-with-label > span { html[dir="rtl"] .textbox-with-label > span {
right: 0; right: 0;
@ -219,30 +219,75 @@ html[dir="ltr"] .textbox-with-label > span {
background: var(--textbox-background-active); background: var(--textbox-background-active);
} }
.textbox-with-label > input { .textbox-with-label > input,
.textbox-with-label > i-input > input
{
padding: 5px; padding: 5px;
border: 0; border: 0;
background: var(--textbox-background); background: var(--textbox-background);
color: var(--textbox-color); color: var(--textbox-color);
} }
.textbox-with-label > input:focus { .textbox-with-label > input:focus,
.textbox-with-label > i-input:focus
{
outline: none; outline: none;
background: var(--textbox-background-active); background: var(--textbox-background-active);
} }
.textbox-with-label > input:focus + span, .textbox-with-label > input:focus + span,
.textbox-with-label > input:not(:placeholder-shown) + span { .textbox-with-label > input:not(:placeholder-shown) + span
{
opacity: 1; opacity: 1;
transform: scale(0.75) translateY(-40%) translateX(-20px); transform: scale(0.75) translateY(-40%) translateX(-20px);
} }
html[dir="rtl"] .textbox-with-label > input:focus + span, html[dir="rtl"] .textbox-with-label > input:focus + span,
html[dir="rtl"] .textbox-with-label > input:not(:placeholder-shown) + span { html[dir="rtl"] .textbox-with-label > input:not(:placeholder-shown) + span
{
opacity: 1; opacity: 1;
transform: scale(0.75) translateY(-40%) translateX(20%); transform: scale(0.75) translateY(-40%) translateX(20%);
} }
.input > input:focus + span,
.input > input:not(:placeholder-shown) + span
{
opacity: 1;
transform: scale(0.75) translateY(-40%) translateX(-20px);
}
html[dir="rtl"] .input > input:focus + span,
html[dir="rtl"] .input > input:not(:placeholder-shown) + span
{
opacity: 1;
transform: scale(0.75) translateY(-40%) translateX(20%);
}
.input > span {
padding: 10px;
pointer-events: none;
position: absolute;
top: 0;
transition: 0.4s;
transition-timing-function: ease;
transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
opacity: 0.5;
color: var(--default-link-color);
}
.input[caption] > input {
padding: 16px 10px 5px 10;
}
html[dir="rtl"] .input > span {
right: 0;
}
html[dir="ltr"] .input > span {
left: 0;
}
.range2 { .range2 {
position: relative; position: relative;
} }
@ -1932,6 +1977,9 @@ _:-moz-tree-row(hover), html[dir='rtl'] .autocomplete-menu, html[dir='rtl'] .sel
.input-invalid > input { .input-invalid > input {
border-color: var(--textbox-border-color-invalid) !important; border-color: var(--textbox-border-color-invalid) !important;
}
.input-invalid > input:focus {
box-shadow: var(--textbox-box-shadow-invalid) !important; box-shadow: var(--textbox-box-shadow-invalid) !important;
} }
@ -2555,6 +2603,7 @@ html[dir='rtl'] .multiselect-list-remove {
.router, i-router .router, i-router
{ {
display: block;
position: relative; position: relative;
} }
@ -2897,6 +2946,7 @@ html[dir='rtl'] .multiselect-list-remove {
min-width: 100%; min-width: 100%;
/* top: calc(100% - 1px);*/ /* top: calc(100% - 1px);*/
overflow: visible; overflow: visible;
z-index: 10;
} }
.sitebar-container > * .sitebar-container > *

31
package.json Normal file
View File

@ -0,0 +1,31 @@
{
"name": "@esiur/iui",
"version": "1.1.2",
"description": "Interactive User Interface",
"main": "iui.js",
"type": "module",
"directories": {
"test": "test"
},
"dependencies": {},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/esiur/iui.git"
},
"keywords": [
"Web",
"Interface",
"User",
"Esiur"
],
"author": "Ahmed Kh. Zamil",
"license": "MIT",
"bugs": {
"url": "https://github.com/esiur/iui/issues"
},
"homepage": "https://github.com/esiur/iui#readme"
}

View File

@ -274,11 +274,8 @@ export class Binding {
{ {
let d = await this._execute(this.target.ownerElement, data); let d = await this._execute(this.target.ownerElement, data);
if (d === undefined) //if (d === undefined)
return false; // return false;
//if (d instanceof Promise)
// d = await d;
this.target.ownerElement.style.display = d ? "" : "none"; this.target.ownerElement.style.display = d ? "" : "none";
} }

View File

@ -7,10 +7,15 @@ export default class IUIElement extends HTMLElement {
this._events = []; this._events = [];
this._data = null; this._data = null;
this._defaults = defaults;
for (var i in defaults) for (var i in defaults)
if (this[i] == undefined) if (this[i] == undefined)
try {
this[i] = defaults[i]; this[i] = defaults[i];
} catch {
// mostly because modifying dom attributes are not allowed in custom elements creation
}
this._register("data"); this._register("data");
} }
@ -106,12 +111,6 @@ export default class IUIElement extends HTMLElement {
return; return;
} }
//console.log("_renderElement " + element.getAttribute("ref"), element);
//if (element.hasAttribute("debug"))
// debugger;
// render attributes & text nodes // render attributes & text nodes
for (var i = 0; i < element.bindings.length; i++) for (var i = 0; i < element.bindings.length; i++)
await element.bindings[i].render(data); await element.bindings[i].render(data);
@ -153,11 +152,12 @@ export default class IUIElement extends HTMLElement {
connectedCallback() { connectedCallback() {
if (this.hasAttribute("css-class")) if (this.hasAttribute("css-class"))
{
this.classList.add(this.getAttribute("css-class")); this.classList.add(this.getAttribute("css-class"));
}
else else
{ {
let className = this.constructor.moduleName; let className = this.constructor.moduleName;
this.setAttribute("css-class", className); this.setAttribute("css-class", className);
this.classList.add(className); this.classList.add(className);
} }
@ -204,19 +204,23 @@ export default class IUIElement extends HTMLElement {
// async: Async Field // async: Async Field
// @ Event // @ Event
// tags to skip
if (element instanceof HTMLScriptElement
|| element instanceof HTMLTemplateElement)
return;
let bindings = []; let bindings = [];
//if (element.hasAttribute("debug"))
// debugger;
// compile attributes // compile attributes
for (var i = 0; i < element.attributes.length; i++) { for (var i = 0; i < element.attributes.length; i++) {
let b = Binding.create(element.attributes[i]); let b = Binding.create(element.attributes[i]);
if (b != null) { if (b != null) {
if (b.type == BindingType.HTMLElementDataAttribute || b.type == BindingType.IUIElementDataAttribute) if (b.type == BindingType.HTMLElementDataAttribute
|| b.type == BindingType.IUIElementDataAttribute)
element.dataMap = b; element.dataMap = b;
else if (b.type == BindingType.RevertAttribute) else if (b.type == BindingType.RevertAttribute)
element.revertMap = b; element.revertMap = b;
@ -249,7 +253,7 @@ export default class IUIElement extends HTMLElement {
_emit(event, values) { _emit(event, values) {
//var args = Array.prototype.slice.call(arguments, 1); //var args = Array.prototype.slice.call(arguments, 1);
var e = new CustomEvent(event, values); var e = new CustomEvent(event, values);
for (var i in values) { for (let i in values) {
if (e[i] === undefined) if (e[i] === undefined)
e[i] = values[i]; e[i] = values[i];
} }

View File

@ -1,10 +1,10 @@
import IUIElement from "../Core/IUIElement.js"; import IUIElement from "../Core/IUIElement.js";
import { IUI } from "../Core/IUI.js"; import { IUI } from "../Core/IUI.js";
import Modifiable from "./Modifiable.js";
export default IUI.module(class Form extends IUIElement { export default IUI.module(class Form extends IUIElement {
constructor() { constructor() {
super(); super();
//this.form = {};
} }
static _copy(val){ static _copy(val){
@ -34,34 +34,23 @@ export default IUI.module(class Form extends IUIElement {
this.original = value; this.original = value;
//var copy = {}; //var copy = {};
//Object.assign(copy, value); //Object.assign(copy, value);
super.setData(Form._copy(this.original)); super.setData(new Modifiable(this.original));// Form._copy(this.original));
//super.setData({ ...this.original }); //super.setData({ ...this.original });
} }
async reset() { async reset() {
//super.setData({ ...this.original }); //super.setData({ ...this.original });
super.setData(Form._copy(this.original)); super.setData(new Modifiable(this.original));//Form._copy(this.original));
return this; return this;
} }
// @TODO: Remove this when esiur adds suport to partially modified arrays with modified flag
static _areEqual(ar1, ar2)
{
if (!(ar1 instanceof Array) || !( ar2 instanceof Array))
return false;
if (ar1.length != ar2.length)
return false;
for(var i = 0; i < ar1.length; i++)
if (ar1[i] != ar2[i])
return false;
return true;
}
get diff() { get diff() {
return this._data._diff;
if (this.original == null) if (this.original == null)
return this._data; return this._data;

View File

@ -9,26 +9,35 @@ export default IUI.module(class Include extends IUIElement
this.refs = {}; this.refs = {};
} }
async create() get src(){
return this.getAttribute("src");
}
set src(value){
this.setAttribute("src", value);
this._load(value);
}
async _load(url)
{ {
//console.log("Create ...", this.getAttribute("src")); if (this._loading)
if (this.getAttribute("src") == "views/studio/realestate.html")
console.log("Create include");
if (this.hasAttribute("src")) {
let src = this.getAttribute("src").replace(/^\/+|\/+$/g, '');
let x = await fetch(src);
if (x.status !== 200)
return; return;
this._loading = true;
let src = url.replace(/^\/+|\/+$/g, '');
this.classList.add(this.cssClass + "-loading");
let x = await fetch(src);
if (x.status == 200)
{
let t = await x.text(); let t = await x.text();
this.innerHTML = t; this.innerHTML = t;
let xeval = (code) => eval(code); //let xeval = (code) => eval(code);
// call create for the new elements // call create for the new elements
var newElements = this.querySelectorAll("*"); var newElements = this.querySelectorAll("*");
@ -58,11 +67,23 @@ export default IUI.module(class Include extends IUIElement
} }
} }
//this.updateBindings(); this.classList.remove(this.cssClass + "-loading");
if (window?.app?.loaded)
{
await IUI.create(this);
await IUI.created(this);
this.updateBindings();
await this.render();
} }
get src() this._loading = false;
{
return this._src;
} }
async create()
{
if (this.hasAttribute("src"))
await this._load(this.getAttribute("src"));
}
}); });

139
src/Data/Modifiable.js Normal file
View File

@ -0,0 +1,139 @@
export default class Modifiable
{
static _copy(val){
if (typeof val === 'object' && val !== null)
{
let rt = {};
for(var i in val)
if (val[i] instanceof Array)
// copy array
rt[i] = [...val[i]];
else
rt[i] = val[i];
return rt;
}
else
return val;
}
// @TODO: Remove this when esiur adds suport to partially modified arrays with modified flag
static _areEqual(ar1, ar2)
{
if (!(ar1 instanceof Array) || !( ar2 instanceof Array))
return false;
if (ar1.length != ar2.length)
return false;
for(var i = 0; i < ar1.length; i++)
if (ar1[i] != ar2[i])
return false;
return true;
}
constructor(original){
this._events = {};
this._data = Modifiable._copy(original);
this._original = original;
for(let p in this._data)
{
if (p.startsWith("_"))
continue;
this._register(":" + p);
Object.defineProperty(this, p, {
get() {
return this._data[p];
},
set(value) {
this._data[p] = value;
this._emit(":" + p, value);
}
});
}
}
get _diff() {
if (this._original == null)
return this._data;
var rt = {};
for (var i in this._data)
if (this._data[i] != this._original[i])
{
if (this._data[i] instanceof Array && Modifiable._areEqual(this._data[i], this._original[i]))
continue;
else
rt[i] = this._data[i];
}
return rt;
}
_register(event)
{
this._events[event] = [];
}
_emit(event)
{
event = event.toLowerCase();
var args = Array.prototype.slice.call(arguments, 1);
if (this._events[event])
for(var i = 0; i < this._events[event].length; i++)
if (this._events[event][i].f.apply(this._events[event][i].i, args))
return true;
return false;
}
_emitArgs(event, args)
{
event = event.toLowerCase();
if (this._events[event])
for(var i = 0; i < this._events[event].length; i++)
if (this._events[event][i].f.apply(this._events[event][i].i, args))
return true;
return this;
}
on(event, fn, issuer)
{
if (!(fn instanceof Function))
return this;
event = event.toLowerCase();
// add
if (!this._events[event])
this._events[event] = [];
this._events[event].push({f: fn, i: issuer == null ? this: issuer});
return this;
}
off(event, fn)
{
event = event.toLowerCase();
if (this._events[event])
{
if (fn)
{
for(var i = 0; i < this._events[event].length; i++)
if (this._events[event][i].f == fn)
this._events[event].splice(i--, 1);
}
else
{
this._events[event] = [];
}
}
}
}

View File

@ -263,9 +263,10 @@ export default IUI.module(class Repeat extends IUIElement
//super._uiBindings = null; //super._uiBindings = null;
//super.updateBindings(); //super.updateBindings();
this._emit("modified", { data: value, property: "data" }); // @TODO: check if this works for event names starting with ":"
this._emit(":data", { data: value });
// this._emit("modified", { data: value, property: "data" });
// console.log("SetDataEnd " + this.getAttribute("ref") + " " + id);
this._busy = false; this._busy = false;
} }

View File

@ -145,6 +145,8 @@ export default IUI.module(class Route extends IUIElement {
this.setAttribute("selected", ""); this.setAttribute("selected", "");
this._emit("show"); this._emit("show");
} }
else else
{ {

View File

@ -116,7 +116,7 @@ export default IUI.module(class Router extends Target
return JSON.parse(JSON.stringify(rt)); return JSON.parse(JSON.stringify(rt));
} }
async navigate(url, data, target, state) async navigate(url, data, target, state, dataToQuery = true)
{ {
let q = url.match(/^\/*(.*?)\?(.*)$|^\/*(.*)$/); let q = url.match(/^\/*(.*?)\?(.*)$|^\/*(.*)$/);
@ -133,7 +133,7 @@ export default IUI.module(class Router extends Target
// do we have data ? // do we have data ?
else if (data !== undefined) { else if (data !== undefined) {
path = q[3]; path = q[3];
url = path + "?" + this._toQuery(data); url = dataToQuery ? path + "?" + this._toQuery(data) : path;
} }
else { else {
path = q[3]; path = q[3];
@ -144,12 +144,18 @@ export default IUI.module(class Router extends Target
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);
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);
return; return;
}
// destination view not found // destination view not found
if (viewRoute == null) { if (viewRoute == null) {
@ -173,11 +179,9 @@ export default IUI.module(class Router extends Target
// } // }
//} //}
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 };

View File

@ -115,7 +115,7 @@ export default IUI.module(class DateTimePicker extends IUIElement {
self._value.setMonth(self._month); self._value.setMonth(self._month);
self.render(); self.render();
self._emit("select", { value: self._value }); self._emit("select", { value: self._value });
self._emit("modified", { value, property: "value" }); self._emit(":value", { value });
}); });
} }
} }

View File

@ -32,6 +32,15 @@ export default IUI.module(class Input extends IUIElement {
return true; return true;
} }
get caption(){
return this.getAttribute("caption");// this._span.innerHTML;
}
set caption(value){
this.setAttribute("caption", value);
this._span.innerHTML = value;
}
create() { create() {
this.isAuto = this.hasAttribute("auto"); this.isAuto = this.hasAttribute("auto");
@ -44,7 +53,12 @@ export default IUI.module(class Input extends IUIElement {
this.setAttribute("async:revert", `d['${this.field}'] = await this.getData()`); this.setAttribute("async:revert", `d['${this.field}'] = await this.getData()`);
} }
this._span = document.createElement("span");
this._span.innerHTML = this.getAttribute("caption");
this._input = document.createElement("input"); this._input = document.createElement("input");
this._input.placeholder = " ";
let self = this; let self = this;
this._input.addEventListener("input", () => { this._input.addEventListener("input", () => {
@ -62,6 +76,7 @@ export default IUI.module(class Input extends IUIElement {
this.accept = this.getAttribute("accept"); this.accept = this.getAttribute("accept");
this.appendChild(this._input); this.appendChild(this._input);
this.appendChild(this._span);
if (this.type == "password") if (this.type == "password")
{ {

View File

@ -10,8 +10,8 @@ export default IUI.module(class Tab extends IUIElement {
} }
get title() { get caption() {
return this.getAttribute("title"); return this.getAttribute("caption");
} }
get selected() { get selected() {

View File

@ -855,6 +855,7 @@ export default IUI.module(class Table extends IUIElement {
if (dynamicLoading) if (dynamicLoading)
this._createTreeButton(newRow, true, item); this._createTreeButton(newRow, true, item);
// @TODO: fix this since modified event is removed
if (item.on) if (item.on)
if (this.updateOnModification) if (this.updateOnModification)
item.on("modified", function(propertyName){ item.on("modified", function(propertyName){

View File

@ -2,6 +2,7 @@
import IUIElement from "../Core/IUIElement.js"; import IUIElement from "../Core/IUIElement.js";
import Tab from "./Tab.js"; import Tab from "./Tab.js";
import { IUI } from "../Core/IUI.js"; import { IUI } from "../Core/IUI.js";
import Check from "./Check.js";
export default IUI.module(class Tabs extends IUIElement { export default IUI.module(class Tabs extends IUIElement {
@ -117,8 +118,8 @@ export default IUI.module(class Tabs extends IUIElement {
add(item) { add(item) {
var label = document.createElement("i-check"); var label = new Check();// document.createElement("i-check");
label.innerHTML = item.title; label.innerHTML = item.caption;
this._ext.insertAdjacentElement("beforebegin", label); this._ext.insertAdjacentElement("beforebegin", label);