mirror of
https://github.com/esiur/iui.git
synced 2025-05-06 06:42:58 +00:00
1.1.2
This commit is contained in:
parent
fab9e186c9
commit
1e8ae99d39
94
css/iui.css
94
css/iui.css
@ -192,17 +192,17 @@
|
||||
background: var(--textbox-background);
|
||||
}
|
||||
|
||||
.textbox-with-label > 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);
|
||||
}
|
||||
.textbox-with-label > 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);
|
||||
}
|
||||
|
||||
html[dir="rtl"] .textbox-with-label > span {
|
||||
right: 0;
|
||||
@ -219,30 +219,75 @@ html[dir="ltr"] .textbox-with-label > span {
|
||||
background: var(--textbox-background-active);
|
||||
}
|
||||
|
||||
.textbox-with-label > input {
|
||||
.textbox-with-label > input,
|
||||
.textbox-with-label > i-input > input
|
||||
{
|
||||
padding: 5px;
|
||||
border: 0;
|
||||
background: var(--textbox-background);
|
||||
color: var(--textbox-color);
|
||||
}
|
||||
|
||||
.textbox-with-label > input:focus {
|
||||
outline: none;
|
||||
background: var(--textbox-background-active);
|
||||
}
|
||||
.textbox-with-label > input:focus,
|
||||
.textbox-with-label > i-input:focus
|
||||
{
|
||||
outline: none;
|
||||
background: var(--textbox-background-active);
|
||||
}
|
||||
|
||||
.textbox-with-label > input:focus + span,
|
||||
.textbox-with-label > input:not(:placeholder-shown) + span {
|
||||
opacity: 1;
|
||||
transform: scale(0.75) translateY(-40%) translateX(-20px);
|
||||
}
|
||||
.textbox-with-label > input:focus + span,
|
||||
.textbox-with-label > input:not(:placeholder-shown) + span
|
||||
{
|
||||
opacity: 1;
|
||||
transform: scale(0.75) translateY(-40%) translateX(-20px);
|
||||
}
|
||||
|
||||
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;
|
||||
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 {
|
||||
position: relative;
|
||||
}
|
||||
@ -1932,6 +1977,9 @@ _:-moz-tree-row(hover), html[dir='rtl'] .autocomplete-menu, html[dir='rtl'] .sel
|
||||
|
||||
.input-invalid > input {
|
||||
border-color: var(--textbox-border-color-invalid) !important;
|
||||
}
|
||||
|
||||
.input-invalid > input:focus {
|
||||
box-shadow: var(--textbox-box-shadow-invalid) !important;
|
||||
}
|
||||
|
||||
@ -2555,6 +2603,7 @@ html[dir='rtl'] .multiselect-list-remove {
|
||||
|
||||
.router, i-router
|
||||
{
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@ -2897,6 +2946,7 @@ html[dir='rtl'] .multiselect-list-remove {
|
||||
min-width: 100%;
|
||||
/* top: calc(100% - 1px);*/
|
||||
overflow: visible;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.sitebar-container > *
|
||||
|
31
package.json
Normal file
31
package.json
Normal 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"
|
||||
}
|
@ -274,11 +274,8 @@ export class Binding {
|
||||
{
|
||||
let d = await this._execute(this.target.ownerElement, data);
|
||||
|
||||
if (d === undefined)
|
||||
return false;
|
||||
|
||||
//if (d instanceof Promise)
|
||||
// d = await d;
|
||||
//if (d === undefined)
|
||||
// return false;
|
||||
|
||||
this.target.ownerElement.style.display = d ? "" : "none";
|
||||
}
|
||||
|
@ -7,10 +7,15 @@ export default class IUIElement extends HTMLElement {
|
||||
|
||||
this._events = [];
|
||||
this._data = null;
|
||||
this._defaults = defaults;
|
||||
|
||||
for (var i in defaults)
|
||||
if (this[i] == undefined)
|
||||
this[i] = defaults[i];
|
||||
try {
|
||||
this[i] = defaults[i];
|
||||
} catch {
|
||||
// mostly because modifying dom attributes are not allowed in custom elements creation
|
||||
}
|
||||
|
||||
this._register("data");
|
||||
}
|
||||
@ -106,12 +111,6 @@ export default class IUIElement extends HTMLElement {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//console.log("_renderElement " + element.getAttribute("ref"), element);
|
||||
|
||||
//if (element.hasAttribute("debug"))
|
||||
// debugger;
|
||||
|
||||
// render attributes & text nodes
|
||||
for (var i = 0; i < element.bindings.length; i++)
|
||||
await element.bindings[i].render(data);
|
||||
@ -153,11 +152,12 @@ export default class IUIElement extends HTMLElement {
|
||||
connectedCallback() {
|
||||
|
||||
if (this.hasAttribute("css-class"))
|
||||
{
|
||||
this.classList.add(this.getAttribute("css-class"));
|
||||
}
|
||||
else
|
||||
{
|
||||
let className = this.constructor.moduleName;
|
||||
|
||||
this.setAttribute("css-class", className);
|
||||
this.classList.add(className);
|
||||
}
|
||||
@ -204,19 +204,23 @@ export default class IUIElement extends HTMLElement {
|
||||
// async: Async Field
|
||||
// @ Event
|
||||
|
||||
|
||||
// tags to skip
|
||||
if (element instanceof HTMLScriptElement
|
||||
|| element instanceof HTMLTemplateElement)
|
||||
return;
|
||||
|
||||
let bindings = [];
|
||||
|
||||
|
||||
//if (element.hasAttribute("debug"))
|
||||
// debugger;
|
||||
|
||||
// compile attributes
|
||||
for (var i = 0; i < element.attributes.length; i++) {
|
||||
|
||||
let b = Binding.create(element.attributes[i]);
|
||||
|
||||
if (b != null) {
|
||||
if (b.type == BindingType.HTMLElementDataAttribute || b.type == BindingType.IUIElementDataAttribute)
|
||||
if (b.type == BindingType.HTMLElementDataAttribute
|
||||
|| b.type == BindingType.IUIElementDataAttribute)
|
||||
element.dataMap = b;
|
||||
else if (b.type == BindingType.RevertAttribute)
|
||||
element.revertMap = b;
|
||||
@ -249,7 +253,7 @@ export default class IUIElement extends HTMLElement {
|
||||
_emit(event, values) {
|
||||
//var args = Array.prototype.slice.call(arguments, 1);
|
||||
var e = new CustomEvent(event, values);
|
||||
for (var i in values) {
|
||||
for (let i in values) {
|
||||
if (e[i] === undefined)
|
||||
e[i] = values[i];
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import IUIElement from "../Core/IUIElement.js";
|
||||
import { IUI } from "../Core/IUI.js";
|
||||
import Modifiable from "./Modifiable.js";
|
||||
|
||||
export default IUI.module(class Form extends IUIElement {
|
||||
constructor() {
|
||||
super();
|
||||
//this.form = {};
|
||||
}
|
||||
|
||||
static _copy(val){
|
||||
@ -34,34 +34,23 @@ export default IUI.module(class Form extends IUIElement {
|
||||
this.original = value;
|
||||
//var copy = {};
|
||||
//Object.assign(copy, value);
|
||||
super.setData(Form._copy(this.original));
|
||||
super.setData(new Modifiable(this.original));// Form._copy(this.original));
|
||||
//super.setData({ ...this.original });
|
||||
}
|
||||
|
||||
|
||||
async reset() {
|
||||
//super.setData({ ...this.original });
|
||||
super.setData(Form._copy(this.original));
|
||||
super.setData(new Modifiable(this.original));//Form._copy(this.original));
|
||||
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() {
|
||||
|
||||
return this._data._diff;
|
||||
|
||||
if (this.original == null)
|
||||
return this._data;
|
||||
|
||||
|
@ -9,26 +9,35 @@ export default IUI.module(class Include extends IUIElement
|
||||
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)
|
||||
return;
|
||||
|
||||
if (this.getAttribute("src") == "views/studio/realestate.html")
|
||||
console.log("Create include");
|
||||
this._loading = true;
|
||||
|
||||
if (this.hasAttribute("src")) {
|
||||
let src = url.replace(/^\/+|\/+$/g, '');
|
||||
|
||||
let src = this.getAttribute("src").replace(/^\/+|\/+$/g, '');
|
||||
let x = await fetch(src);
|
||||
this.classList.add(this.cssClass + "-loading");
|
||||
|
||||
if (x.status !== 200)
|
||||
return;
|
||||
let x = await fetch(src);
|
||||
|
||||
if (x.status == 200)
|
||||
{
|
||||
let t = await x.text();
|
||||
|
||||
this.innerHTML = t;
|
||||
|
||||
let xeval = (code) => eval(code);
|
||||
//let xeval = (code) => eval(code);
|
||||
|
||||
// call create for the new elements
|
||||
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();
|
||||
}
|
||||
|
||||
this._loading = false;
|
||||
}
|
||||
|
||||
get src()
|
||||
async create()
|
||||
{
|
||||
return this._src;
|
||||
if (this.hasAttribute("src"))
|
||||
await this._load(this.getAttribute("src"));
|
||||
}
|
||||
|
||||
});
|
139
src/Data/Modifiable.js
Normal file
139
src/Data/Modifiable.js
Normal 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] = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -263,9 +263,10 @@ export default IUI.module(class Repeat extends IUIElement
|
||||
//super._uiBindings = null;
|
||||
//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;
|
||||
}
|
||||
|
@ -145,6 +145,8 @@ export default IUI.module(class Route extends IUIElement {
|
||||
|
||||
this.setAttribute("selected", "");
|
||||
this._emit("show");
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -116,7 +116,7 @@ export default IUI.module(class Router extends Target
|
||||
return JSON.parse(JSON.stringify(rt));
|
||||
}
|
||||
|
||||
async navigate(url, data, target, state)
|
||||
async navigate(url, data, target, state, dataToQuery = true)
|
||||
{
|
||||
let q = url.match(/^\/*(.*?)\?(.*)$|^\/*(.*)$/);
|
||||
|
||||
@ -132,8 +132,8 @@ export default IUI.module(class Router extends Target
|
||||
}
|
||||
// do we have data ?
|
||||
else if (data !== undefined) {
|
||||
path = q[3];
|
||||
url = path + "?" + this._toQuery(data);
|
||||
path = q[3];
|
||||
url = dataToQuery ? path + "?" + this._toQuery(data) : path;
|
||||
}
|
||||
else {
|
||||
path = q[3];
|
||||
@ -144,13 +144,19 @@ export default IUI.module(class Router extends Target
|
||||
let [stateRoute, viewRoute] = this.getRoute(path, data);
|
||||
|
||||
if (stateRoute == null)
|
||||
{
|
||||
console.warn("State not found ", path);
|
||||
return;
|
||||
}
|
||||
|
||||
let ok = this._emit("navigate", { url, stateRoute, viewRoute, base: path, data, cancelable: true });
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
console.warn("Route not allowed", path);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// destination view not found
|
||||
if (viewRoute == null) {
|
||||
console.log(`Destination route not found ${stateRoute.dst}`);
|
||||
@ -173,11 +179,9 @@ export default IUI.module(class Router extends Target
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
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 };
|
||||
|
@ -115,7 +115,7 @@ export default IUI.module(class DateTimePicker extends IUIElement {
|
||||
self._value.setMonth(self._month);
|
||||
self.render();
|
||||
self._emit("select", { value: self._value });
|
||||
self._emit("modified", { value, property: "value" });
|
||||
self._emit(":value", { value });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,15 @@ export default IUI.module(class Input extends IUIElement {
|
||||
return true;
|
||||
}
|
||||
|
||||
get caption(){
|
||||
return this.getAttribute("caption");// this._span.innerHTML;
|
||||
}
|
||||
|
||||
set caption(value){
|
||||
this.setAttribute("caption", value);
|
||||
this._span.innerHTML = value;
|
||||
}
|
||||
|
||||
create() {
|
||||
|
||||
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._span = document.createElement("span");
|
||||
this._span.innerHTML = this.getAttribute("caption");
|
||||
|
||||
this._input = document.createElement("input");
|
||||
this._input.placeholder = " ";
|
||||
|
||||
let self = this;
|
||||
|
||||
this._input.addEventListener("input", () => {
|
||||
@ -62,6 +76,7 @@ export default IUI.module(class Input extends IUIElement {
|
||||
this.accept = this.getAttribute("accept");
|
||||
|
||||
this.appendChild(this._input);
|
||||
this.appendChild(this._span);
|
||||
|
||||
if (this.type == "password")
|
||||
{
|
||||
|
@ -10,8 +10,8 @@ export default IUI.module(class Tab extends IUIElement {
|
||||
|
||||
}
|
||||
|
||||
get title() {
|
||||
return this.getAttribute("title");
|
||||
get caption() {
|
||||
return this.getAttribute("caption");
|
||||
}
|
||||
|
||||
get selected() {
|
||||
|
@ -855,6 +855,7 @@ export default IUI.module(class Table extends IUIElement {
|
||||
if (dynamicLoading)
|
||||
this._createTreeButton(newRow, true, item);
|
||||
|
||||
// @TODO: fix this since modified event is removed
|
||||
if (item.on)
|
||||
if (this.updateOnModification)
|
||||
item.on("modified", function(propertyName){
|
||||
|
@ -2,6 +2,7 @@
|
||||
import IUIElement from "../Core/IUIElement.js";
|
||||
import Tab from "./Tab.js";
|
||||
import { IUI } from "../Core/IUI.js";
|
||||
import Check from "./Check.js";
|
||||
|
||||
export default IUI.module(class Tabs extends IUIElement {
|
||||
|
||||
@ -117,8 +118,8 @@ export default IUI.module(class Tabs extends IUIElement {
|
||||
|
||||
add(item) {
|
||||
|
||||
var label = document.createElement("i-check");
|
||||
label.innerHTML = item.title;
|
||||
var label = new Check();// document.createElement("i-check");
|
||||
label.innerHTML = item.caption;
|
||||
|
||||
this._ext.insertAdjacentElement("beforebegin", label);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user