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,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
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);
if (d === undefined)
return false;
//if (d instanceof Promise)
// d = await d;
//if (d === undefined)
// return false;
this.target.ownerElement.style.display = d ? "" : "none";
}

View File

@ -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];
}

View File

@ -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;

View File

@ -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
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.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;
}

View File

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

View File

@ -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(/^\/*(.*?)\?(.*)$|^\/*(.*)$/);
@ -133,7 +133,7 @@ export default IUI.module(class Router extends Target
// do we have data ?
else if (data !== undefined) {
path = q[3];
url = path + "?" + this._toQuery(data);
url = dataToQuery ? path + "?" + this._toQuery(data) : path;
}
else {
path = q[3];
@ -144,12 +144,18 @@ 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) {
@ -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 };

View File

@ -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 });
});
}
}

View File

@ -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")
{

View File

@ -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() {

View File

@ -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){

View File

@ -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);