update news & events
This commit is contained in:
0
TWASys-App/wwwroot/js/libs/CacheManager.js
Normal file
0
TWASys-App/wwwroot/js/libs/CacheManager.js
Normal file
103
TWASys-App/wwwroot/js/libs/js-AAnimation.js
Normal file
103
TWASys-App/wwwroot/js/libs/js-AAnimation.js
Normal file
@ -0,0 +1,103 @@
|
||||
export default class AAnimation extends window.AObject {
|
||||
constructor(ele = null) {
|
||||
super();
|
||||
this.element = ele;
|
||||
this.onBefore = null;
|
||||
this.onAnimation = null;
|
||||
this.onAfter = null;
|
||||
this.status = 0;
|
||||
}
|
||||
setType(type, args = { "parent": null }) {
|
||||
args.parent.classList.add("animation" + type);
|
||||
this.params = args;
|
||||
switch (type) {
|
||||
case "Fade":
|
||||
this.onBefore = (function () {
|
||||
this.trigger("beforeAnimation", this.element);
|
||||
if (this.element.classList.contains("show")) {
|
||||
this.status = 0;
|
||||
this.element.style.opacity = 0;
|
||||
} else {
|
||||
this.status = 1;
|
||||
this.element.classList.add("show");
|
||||
}
|
||||
}).bind(this);
|
||||
this.onAnimation = (function () {
|
||||
if (this.status == 0) {
|
||||
window.requestTimeout((() => {
|
||||
this.element.classList.remove("show");
|
||||
this.trigger("endAnimation", this.element);
|
||||
}).bind(this), 100, window.registerCancel);
|
||||
} else {
|
||||
window.requestTimeout((() => {
|
||||
var f = function (ev) {
|
||||
if (ev.propertyName == "opacity") {
|
||||
this.trigger("endAnimation", this.element);
|
||||
ev.target.removeEventListener("transitionend", f, false);
|
||||
}
|
||||
}
|
||||
this.element.addEventListener('transitionend', f.bind(this), false);
|
||||
this.element.style.opacity = 1;
|
||||
|
||||
}).bind(this), 50, window.registerCancel);
|
||||
}
|
||||
}).bind(this);
|
||||
break;
|
||||
case "Slide":
|
||||
var slideC = document.createElement("div");
|
||||
slideC.classList.add("slideContent");
|
||||
while (this.params.parent.childNodes.length > 0) {
|
||||
slideC.appendChild(this.params.parent.childNodes[0]);
|
||||
}
|
||||
this.params.parent.appendChild(slideC);
|
||||
|
||||
slideC.querySelectorAll(".tabcontent").forEach((el) => {
|
||||
let style = this.params.parent.currentStyle || window.getComputedStyle(this.params.parent);
|
||||
let m = parseFloat(style.marginLeft) + parseFloat(style.marginRight);
|
||||
let w = this.params.parent.offsetWidth;
|
||||
if (m < 0) {
|
||||
// w += Math.abs(m);
|
||||
}
|
||||
el.style.width = w + "px";
|
||||
})
|
||||
this.slideC = slideC;
|
||||
this.onBefore = (function () {
|
||||
this.trigger("beforeAnimation", this.element);
|
||||
if (this.element.classList.contains("show")) {
|
||||
this.status = 0;
|
||||
} else {
|
||||
this.status = 1;
|
||||
this.element.classList.add("show");
|
||||
}
|
||||
}).bind(this);
|
||||
this.onAnimation = (function () {
|
||||
|
||||
if (this.status == 0) {
|
||||
this.element.classList.remove("show");
|
||||
this.trigger("endAnimation", this.element);
|
||||
} else {
|
||||
|
||||
var f = function (ev) {
|
||||
if (ev.propertyName == "transform") {
|
||||
this.trigger("endAnimation", this.element);
|
||||
ev.target.removeEventListener("transitionend", f, false);
|
||||
}
|
||||
}
|
||||
this.slideC.addEventListener('transitionend', f.bind(this), false);
|
||||
this.slideC.style.transform = "translateX(-" + this.element.offsetLeft + "px)";
|
||||
|
||||
}
|
||||
}).bind(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
animation() {
|
||||
if (this.onBefore != null) {
|
||||
this.onBefore();
|
||||
}
|
||||
this.onAnimation();
|
||||
}
|
||||
dispose() {
|
||||
|
||||
}
|
||||
}
|
||||
107
TWASys-App/wwwroot/js/libs/js-AAutoFill.js
Normal file
107
TWASys-App/wwwroot/js/libs/js-AAutoFill.js
Normal file
@ -0,0 +1,107 @@
|
||||
export default class AAutoFill extends window.AObject{
|
||||
constructor(root = document) {
|
||||
super();
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
fill(data) {
|
||||
const sel = '[data-id],[data-control],[data-controll]';
|
||||
this.root.querySelectorAll(sel).forEach(el => {
|
||||
const path = el.dataset.id ?? el.dataset.control ?? el.dataset.controll;
|
||||
const val = AAutoFill.get(data, path);
|
||||
if (val === undefined) return; // không có dữ liệu -> bỏ qua
|
||||
AAutoFill.apply(el, val, this.root);
|
||||
});
|
||||
}
|
||||
|
||||
// --- helpers ---
|
||||
static get(obj, path) {
|
||||
if (!obj || !path) return undefined;
|
||||
// dot + bracket: user.items[0].name
|
||||
const parts = path.split('.').flatMap(p => {
|
||||
const m = [...p.matchAll(/([^\[\]]+)|\[(\d+)\]/g)];
|
||||
return m.map(g => g[1] ?? Number(g[2]));
|
||||
});
|
||||
return parts.reduce((acc, k) => (acc == null ? undefined : acc[k]), obj);
|
||||
}
|
||||
|
||||
static apply(el, value, root) {
|
||||
const tag = el.tagName.toLowerCase();
|
||||
const type = (el.type || '').toLowerCase();
|
||||
|
||||
if (tag === 'input') {
|
||||
if (type === 'checkbox') {
|
||||
if (Array.isArray(value)) { el.checked = value.map(String).includes(el.value); }
|
||||
else { el.checked = AAutoFill.truthy(value, el.value); }
|
||||
AAutoFill.emit(el, 'change'); return;
|
||||
}
|
||||
if (type === 'radio') {
|
||||
const key = el.name || el.dataset.id || el.dataset.control || el.dataset.controll;
|
||||
const q = `input[type=radio][name="${CSS.escape(key)}"],input[type=radio][data-id="${CSS.escape(key)}"],input[type=radio][data-control="${CSS.escape(key)}"],input[type=radio][data-controll="${CSS.escape(key)}"]`;
|
||||
root.querySelectorAll(q).forEach(r => r.checked = String(r.value) === String(value));
|
||||
AAutoFill.emit(el, 'change'); return;
|
||||
}
|
||||
if (type === 'date' || type === 'time' || type === 'datetime-local') {
|
||||
el.value = AAutoFill.formatForInput(type, value);
|
||||
AAutoFill.emit(el); AAutoFill.emit(el, 'change'); return;
|
||||
}
|
||||
el.value = value ?? '';
|
||||
AAutoFill.emit(el); AAutoFill.emit(el, 'change'); return;
|
||||
}
|
||||
|
||||
if (tag === 'select') {
|
||||
if (el.multiple) {
|
||||
const arr = Array.isArray(value) ? value.map(String) : [String(value)];
|
||||
[...el.options].forEach(o => o.selected = arr.includes(o.value) || arr.includes(o.text));
|
||||
} else {
|
||||
el.value = String(value);
|
||||
if (el.value !== String(value)) {
|
||||
const opt = [...el.options].find(o => o.text === String(value));
|
||||
if (opt) opt.selected = true;
|
||||
}
|
||||
}
|
||||
AAutoFill.emit(el, 'change'); return;
|
||||
}
|
||||
|
||||
if (tag === 'textarea') {
|
||||
el.value = value ?? '';
|
||||
AAutoFill.emit(el); return;
|
||||
}
|
||||
|
||||
if (el.isContentEditable) {
|
||||
(el.dataset.html === 'true') ? el.innerHTML = String(value ?? '') : el.textContent = String(value ?? '');
|
||||
return;
|
||||
}
|
||||
|
||||
// fallback: textContent
|
||||
el.textContent = String(value ?? '');
|
||||
}
|
||||
|
||||
static truthy(v, compareVal) {
|
||||
if (typeof v === 'boolean') return v;
|
||||
const s = String(v).toLowerCase();
|
||||
return ['1', 'true', 'yes', 'on', String(compareVal).toLowerCase()].includes(s);
|
||||
}
|
||||
|
||||
static formatForInput(type, v) {
|
||||
const asDate = (x) => {
|
||||
if (x instanceof Date) return x;
|
||||
const n = Number(x);
|
||||
if (!Number.isNaN(n) && n > 0) { // epoch (ms or sec)
|
||||
const d = new Date(n > 1e12 ? n : n * 1000);
|
||||
if (!isNaN(d)) return d;
|
||||
}
|
||||
const d = new Date(x); return isNaN(d) ? null : d;
|
||||
};
|
||||
const pad = (n) => String(n).padStart(2, '0');
|
||||
const d = asDate(v);
|
||||
if (!d) return String(v ?? '');
|
||||
|
||||
if (type === 'date') return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
||||
if (type === 'time') return `${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||||
if (type === 'datetime-local') return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||||
return String(v ?? '');
|
||||
}
|
||||
|
||||
static emit(el, name = 'input') { el.dispatchEvent(new Event(name, { bubbles: true })); }
|
||||
}
|
||||
47
TWASys-App/wwwroot/js/libs/js-AButton.js
Normal file
47
TWASys-App/wwwroot/js/libs/js-AButton.js
Normal file
@ -0,0 +1,47 @@
|
||||
export default class AButton extends window.AObject {
|
||||
constructor(btn = null) {
|
||||
super();
|
||||
if (btn != null) {
|
||||
if (btn instanceof NodeList) {
|
||||
Array.from(btn).forEach(e => {
|
||||
this.AddEventBtn(el);
|
||||
})
|
||||
} else {
|
||||
this.AddEventBtn(btn);
|
||||
}
|
||||
}
|
||||
}
|
||||
AddEventBtn(e) {
|
||||
var f = function (ev) {
|
||||
if (ev.currentTarget.classList.contains("disabled")) {
|
||||
return;
|
||||
} else {
|
||||
this.AddLoading(ev.currentTarget);
|
||||
if (ev.currentTarget.hasAttribute("group-name")) {
|
||||
this.trigger("click_" + ev.currentTarget.getAttribute("group-name"), ev.currentTarget);
|
||||
} else if (ev.currentTarget.hasAttribute("id")) {
|
||||
this.trigger("click_" + ev.currentTarget.getAttribute("id"), ev.currentTarget);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}.bind(this);
|
||||
this.addSystemEvent("click", e, f);
|
||||
}
|
||||
AddLoading(e) {
|
||||
e.classList.add("disabled", "d-f", "a-i-center");
|
||||
var a = document.createElement("div");
|
||||
a.classList.add("loader");
|
||||
var b = document.createElement("span");
|
||||
b.textContent = e.textContent;
|
||||
e.innerHTML = "";
|
||||
e.appendChild(a);
|
||||
e.appendChild(b);
|
||||
|
||||
}
|
||||
RemoveLoading(e) {
|
||||
e.classList.remove("disabled", "d-f", "a-i-center");
|
||||
var c = e.querySelector("span");
|
||||
e.textContent = c.textContent;
|
||||
}
|
||||
}
|
||||
123
TWASys-App/wwwroot/js/libs/js-ADropdown.js
Normal file
123
TWASys-App/wwwroot/js/libs/js-ADropdown.js
Normal file
@ -0,0 +1,123 @@
|
||||
import ATransitionEffect from '/js/libs/js-ATransitionEffect.js'
|
||||
|
||||
|
||||
export default class Dropdown extends window.AObject {
|
||||
constructor() {
|
||||
super();
|
||||
this.transition = new ATransitionEffect();
|
||||
this.isLock = false;
|
||||
if (window.dropdown == null) {
|
||||
this.initGlobalVar();
|
||||
}
|
||||
}
|
||||
initGlobalVar() {
|
||||
var f = function (ev) {
|
||||
if (window.isValidPointerClick(ev)) return;
|
||||
this.document_onClick.call(this, ev);
|
||||
}.bind(this);
|
||||
this.addSystemEvent(this.eventName, document.body, f)
|
||||
window.dropdown = {
|
||||
"numObj": 1,
|
||||
"callback": f,
|
||||
"currentE": null
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
bindDropDowns(a, p = null) {
|
||||
if (a instanceof NodeList) {
|
||||
Array.from(a).forEach(e => {
|
||||
this.bindDropDown(e, p);
|
||||
});
|
||||
} else {
|
||||
this.bindDropDown(a, p);
|
||||
}
|
||||
|
||||
}
|
||||
unBindDropDowns(p) {
|
||||
|
||||
}
|
||||
bindDropDown(e, p = null) {
|
||||
var f = function (ev) {
|
||||
if (window.isValidPointerClick(ev)) return;
|
||||
this.onClick.call(this, ev);
|
||||
}.bind(this);
|
||||
this.addSystemEvent(this.eventName, e, f, p, true);
|
||||
}
|
||||
document_onClick(e) {
|
||||
this.checkRelease(e);
|
||||
}
|
||||
onClick(e) {
|
||||
if (this.isLock) {
|
||||
return;
|
||||
}
|
||||
console.log("Asdasd");
|
||||
var t1 = e.currentTarget;
|
||||
var p = t1.closest('[data-dropdown]');
|
||||
var p1 = e.target.closest(".noopen");
|
||||
if (window.dropdown.currentE != null && (e.target.closest(".item") != null || p1 == null)) {
|
||||
var tmp = window.dropdown.currentE.con;
|
||||
if (window.dropdown.currentE.item.hasAttribute("stopCollapsed")) {
|
||||
window.dropdown.currentE.item.removeAttribute("stopCollapsed")
|
||||
window.dropdown.currentE = null;
|
||||
} else if (e.target.closest(".nonhide") != null) {
|
||||
return;
|
||||
} else {
|
||||
|
||||
this.closeDropdown();
|
||||
}
|
||||
if (tmp.isEqualNode(p)) return;
|
||||
}
|
||||
if (p1 != null) {
|
||||
return;
|
||||
}
|
||||
p.classList.add("active");
|
||||
this.trigger("open", t1);
|
||||
var maxHeight = null;
|
||||
var t = p.getElementsByClassName("sub-item")[0];
|
||||
if (t1.hasAttribute("data-width")) {
|
||||
if (t1.getAttribute("data-width") == "auto") {
|
||||
t.style.width = t1.clientWidth + "px";
|
||||
} else {
|
||||
t.style.width = t1.getAttribute("data-width");
|
||||
}
|
||||
}
|
||||
if (t1.hasAttribute("data-zIndex")) {
|
||||
t.style.zIndex = t1.getAttribute("data-zIndex");
|
||||
}
|
||||
if (t1.hasAttribute("data-max-height")) {
|
||||
maxHeight = t1.getAttribute("data-max-height");
|
||||
t.style.maxHeight = maxHeight + "px";
|
||||
}
|
||||
window.dropdown.currentE = { "con": p, "sub": t, "item": e.currentTarget, "pClass": this, "maxHeight": maxHeight };
|
||||
this.transition.expandEffect(t, function () {
|
||||
this.trigger("opened", t1);
|
||||
}.bind(this), maxHeight);
|
||||
}
|
||||
|
||||
checkRelease(e) {
|
||||
if (e.target.closest(".nonhide") != null) {
|
||||
return;
|
||||
} else if (e.target.closest(".scrollbar-track") != null) {
|
||||
return;
|
||||
} else if ((e.target.getAttribute("data-dropdown") == null && e.target.closest("[data-dropdown]") == null) || e.target.closest(".sub-item.show") != null) {
|
||||
this.checkCloseDropdown();
|
||||
}
|
||||
}
|
||||
closeDropdown() {
|
||||
var tm = window.dropdown.currentE;
|
||||
tm.con.classList.remove("active");
|
||||
tm.pClass.trigger("close", tm);
|
||||
this.transition.collapsedEffect(tm.sub, function () {
|
||||
tm.pClass.trigger("closed", tm);
|
||||
}, tm.maxHeight);
|
||||
window.dropdown.currentE = null;
|
||||
}
|
||||
checkCloseDropdown() {
|
||||
if (window.dropdown.currentE != null) {
|
||||
if (!window.dropdown.currentE.item.hasAttribute("stopCollapsed")) {
|
||||
this.closeDropdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
601
TWASys-App/wwwroot/js/libs/js-AGrid.js
Normal file
601
TWASys-App/wwwroot/js/libs/js-AGrid.js
Normal file
@ -0,0 +1,601 @@
|
||||
export default class AGrid extends window.AObject {
|
||||
constructor(options) {
|
||||
super();
|
||||
const defaultO = { element: ".AGrid", gridType: "row", hasRatio: false, desiredHeight: 200, gutter: 20 };
|
||||
this._o = { ...defaultO, ...options };
|
||||
|
||||
|
||||
this.ele = (typeof this._o.element === "string") ? document.querySelector(this._o.element) : this._o.element;
|
||||
if (!this.ele) throw new Error("AGrid: element not found");
|
||||
|
||||
|
||||
this.timeout = false;
|
||||
this.ticking = false;
|
||||
this.isRender = false;
|
||||
this.loaded = false;
|
||||
this.cancelFunc = null;
|
||||
this.cancelResize = null;
|
||||
|
||||
this.addSystemEvent("resize", window, this.reLayout.bind(this));
|
||||
window.app?.on?.("App_Scrolling", ((_) => {
|
||||
if (window.app.checkVisible(this.ele) && !this.isRender) this.renderAnimation();
|
||||
}).bind(this));
|
||||
|
||||
this.reElement();
|
||||
}
|
||||
|
||||
observerInit(options) {
|
||||
this._scrollEnd = {
|
||||
...
|
||||
{
|
||||
enabled: true, // tắt/mở tính năng
|
||||
root: null, // null = viewport; có thể truyền 1 element scroll container
|
||||
rootMargin: "0px 0px 200px 0px", // nới 200px ở đáy để bắt sớm
|
||||
threshold: 0.01, // chỉ cần chạm nhẹ là báo
|
||||
onceUntilAppend: true // chỉ bắn 1 lần cho mỗi lần append; reset khi append thêm
|
||||
}, ...options
|
||||
};
|
||||
this._io = null; // IntersectionObserver instance
|
||||
this._ioTriggered = false;
|
||||
}
|
||||
_setupScrollEndIO() {
|
||||
if (!this._scrollEnd.enabled) return;
|
||||
if (this._io) return;
|
||||
this._io = new IntersectionObserver(this._onScrollEndIntersect.bind(this), {
|
||||
root: this._scrollEnd.root || null,
|
||||
rootMargin: this._scrollEnd.rootMargin,
|
||||
threshold: this._scrollEnd.threshold
|
||||
});
|
||||
}
|
||||
_getLastGridItemEl() {
|
||||
// Ưu tiên DOM order (an toàn cho append)
|
||||
let el = this.ele.querySelector(".grid-item:last-of-type");
|
||||
if (el) return el;
|
||||
// Fallback theo Map (key lớn nhất)
|
||||
if (this.listGrid && this.listGrid.size) {
|
||||
let last = null, lastKey = -Infinity;
|
||||
for (const [k, rec] of this.listGrid) { if (k > lastKey) { lastKey = k; last = rec; } }
|
||||
if (last) return last.gridEl;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Bắt đầu quan sát item cuối
|
||||
_observeLastItem() {
|
||||
if (!this._scrollEnd?.enabled) return;
|
||||
this._setupScrollEndIO();
|
||||
if (!this._io) return;
|
||||
|
||||
const lastEl = this._getLastGridItemEl();
|
||||
this._io.disconnect(); // luôn quan sát lại đúng item cuối
|
||||
if (lastEl) this._io.observe(lastEl);
|
||||
|
||||
// Nếu dùng chế độ bắn 1 lần đến khi append thêm:
|
||||
if (this._scrollEnd.onceUntilAppend) this._ioTriggered = false;
|
||||
}
|
||||
|
||||
// Xử lý khi giao cắt
|
||||
_onScrollEndIntersect(entries) {
|
||||
|
||||
for (const entry of entries) {
|
||||
if (!entry.isIntersecting) continue;
|
||||
if (this._ioTriggered && this._scrollEnd.onceUntilAppend) return;
|
||||
|
||||
this._ioTriggered = true;
|
||||
//console.log(this);
|
||||
this.trigger("scrollEnd", { instance: this });
|
||||
|
||||
// Nếu không dùng onceUntilAppend thì vẫn muốn chống spam khi còn trong khung:
|
||||
if (!this._scrollEnd.onceUntilAppend) {
|
||||
setTimeout(() => { this._ioTriggered = false; }, 800);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Public: cho phép tay reset cờ (nếu cần)
|
||||
resetScrollEndTrigger() { this._ioTriggered = false; }
|
||||
|
||||
// Public: tắt/bật nhanh
|
||||
enableScrollEnd(v = true) {
|
||||
this._scrollEnd.enabled = !!v;
|
||||
if (!v && this._io) { this._io.disconnect(); }
|
||||
if (v) { this._setupScrollEndIO(); this._observeLastItem(); }
|
||||
}
|
||||
|
||||
// ===== Khởi tạo lại list từ DOM hiện có =====
|
||||
reElement() {
|
||||
this.gridWidth = this.ele.clientWidth;
|
||||
if (this._o.gridType === "waterfall") {
|
||||
this.initCols();
|
||||
}
|
||||
this.listGrid = new Map();
|
||||
this.keyI = 1;
|
||||
|
||||
const imageLoadPromises = [];
|
||||
this.ele.querySelectorAll(".grid-item").forEach((el) => {
|
||||
const img = el.querySelector("img.mImg");
|
||||
const key = this.keyI;
|
||||
|
||||
this.listGrid.set(key, {
|
||||
gridEl: el,
|
||||
imgEl: img || null,
|
||||
aRatio: el.hasAttribute("aRatio") ? parseFloat(el.getAttribute("aRatio")) || 0 : 0,
|
||||
status: 0,
|
||||
bounding: el.getBoundingClientRect()
|
||||
});
|
||||
|
||||
const p = new Promise((resolve) => {
|
||||
if (!img) {
|
||||
const rec = this.listGrid.get(key);
|
||||
rec.status = 1;
|
||||
if (!rec.aRatio || !isFinite(rec.aRatio)) { rec.aRatio = 1; rec.gridEl.setAttribute("aRatio", rec.aRatio); }
|
||||
resolve(); return;
|
||||
}
|
||||
|
||||
const done = () => {
|
||||
const rec = this.listGrid.get(key);
|
||||
rec.status = 1;
|
||||
if (img.naturalWidth > 0 && img.naturalHeight > 0) {
|
||||
rec.aRatio = img.naturalWidth / img.naturalHeight;
|
||||
} else if (!rec.aRatio || !isFinite(rec.aRatio)) {
|
||||
rec.aRatio = 1;
|
||||
}
|
||||
rec.gridEl.setAttribute("aRatio", rec.aRatio);
|
||||
rec.bounding = img.getBoundingClientRect();
|
||||
this.removeSystemEvent?.("load", img, onLoad);
|
||||
this.removeSystemEvent?.("error", img, onError);
|
||||
resolve();
|
||||
};
|
||||
const onLoad = () => done();
|
||||
const onError = () => { const r = this.listGrid.get(key); r.status = -1; done(); };
|
||||
|
||||
if (typeof img.decode === "function") {
|
||||
img.decode().then(done).catch(() => {
|
||||
if (img.complete) done();
|
||||
else { this.addSystemEvent?.("load", img, onLoad); this.addSystemEvent?.("error", img, onError); }
|
||||
});
|
||||
} else if (img.complete) done();
|
||||
else { this.addSystemEvent?.("load", img, onLoad); this.addSystemEvent?.("error", img, onError); }
|
||||
});
|
||||
|
||||
imageLoadPromises.push(p);
|
||||
this.keyI++;
|
||||
});
|
||||
|
||||
Promise.allSettled(imageLoadPromises).then(() => {
|
||||
this.renderAnimation();
|
||||
window.requestTimeout?.(this.layoutInit.bind(this), 100);
|
||||
});
|
||||
}
|
||||
appendElement(input) {
|
||||
const items = this._normalizeToElements(input);
|
||||
if (!items.length) return;
|
||||
|
||||
if (!this.listGrid) this.listGrid = new Map();
|
||||
if (typeof this.keyI !== "number" || this.keyI < 1) this.keyI = this.listGrid.size + 1;
|
||||
|
||||
const newKeys = [];
|
||||
|
||||
for (const el of items) {
|
||||
if (!el.classList.contains("grid-item")) el.classList.add("grid-item");
|
||||
this.ele.appendChild(el);
|
||||
|
||||
const { key, rec } = this._registerItemSync(el); // đăng ký ngay (đồng bộ)
|
||||
newKeys.push(key);
|
||||
|
||||
// ĐẶT VỊ TRÍ NGAY (không chờ ảnh) — giữ tối ưu single append
|
||||
if (this._o.gridType === "waterfall") {
|
||||
this._appendOptimizedSingleWaterfall(key, rec);
|
||||
this._observeLastItem();
|
||||
} else {
|
||||
if (!this.listRows?.length) { this.isRender = false; this.layoutInit(); this.renderAnimation?.(); }
|
||||
else this._appendOptimizedSingleRow(key, rec);
|
||||
}
|
||||
|
||||
// BẮT ĐẦU load ảnh BẤT ĐỒNG BỘ (nếu có)
|
||||
if (rec.imgEl) this._watchImageAsync(key, rec.imgEl);
|
||||
}
|
||||
|
||||
if (newKeys.length > 1) {
|
||||
this.isRender = false;
|
||||
this.layoutInit();
|
||||
if (window.app?.checkVisible?.(this.ele)) this.renderAnimation();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Đăng ký item ngay lập tức + aRatio tạm nếu cần
|
||||
_registerItemSync(el) {
|
||||
el.style.width = this.colW + "px";
|
||||
const img = el.querySelector("img.mImg");
|
||||
const key = this.keyI++;
|
||||
const rec = {
|
||||
gridEl: el,
|
||||
imgEl: img || null,
|
||||
aRatio: el.hasAttribute("aRatio") ? parseFloat(el.getAttribute("aRatio")) : 0,
|
||||
status: 0,
|
||||
bounding: el.getBoundingClientRect()
|
||||
};
|
||||
|
||||
if (img && img.complete && img.naturalWidth > 0 && img.naturalHeight > 0) {
|
||||
// ảnh đã sẵn trong cache → dùng luôn tỉ lệ thật
|
||||
rec.aRatio = img.naturalWidth / img.naturalHeight;
|
||||
rec.status = 1;
|
||||
el.setAttribute("aRatio", rec.aRatio);
|
||||
rec.bounding = img.getBoundingClientRect();
|
||||
} else {
|
||||
// dùng tạm tỉ lệ 1 nếu thiếu
|
||||
if (!rec.aRatio || !isFinite(rec.aRatio)) {
|
||||
rec.aRatio = 1;
|
||||
el.setAttribute("aRatio", rec.aRatio);
|
||||
}
|
||||
rec.status = img ? 0 : 1; // 0: đang chờ ảnh, 1: không có ảnh
|
||||
}
|
||||
|
||||
this.listGrid.set(key, rec);
|
||||
return { key, rec };
|
||||
}
|
||||
|
||||
// Theo dõi load ảnh (BẤT ĐỒNG BỘ) → cập nhật tỉ lệ & re-layout (debounce)
|
||||
_watchImageAsync(key, img) {
|
||||
let done = false;
|
||||
const finalize = (ok) => {
|
||||
if (done) return; done = true;
|
||||
const rec = this.listGrid.get(key);
|
||||
if (!rec) return;
|
||||
if (ok && img.naturalWidth > 0 && img.naturalHeight > 0) {
|
||||
rec.aRatio = img.naturalWidth / img.naturalHeight;
|
||||
rec.gridEl.setAttribute("aRatio", rec.aRatio);
|
||||
rec.bounding = img.getBoundingClientRect();
|
||||
rec.status = 1;
|
||||
} else {
|
||||
// lỗi ảnh → giữ aRatio hiện tại (đã có), mark lỗi
|
||||
if (!rec.aRatio || !isFinite(rec.aRatio)) {
|
||||
rec.aRatio = 1;
|
||||
rec.gridEl.setAttribute("aRatio", rec.aRatio);
|
||||
}
|
||||
rec.status = -1;
|
||||
}
|
||||
|
||||
this.layoutInit(); // reflow lại sau khi ảnh sẵn sàng
|
||||
};
|
||||
|
||||
const onLoad = () => { cleanup(); finalize(true); };
|
||||
const onError = () => { cleanup(); finalize(false); };
|
||||
const cleanup = () => {
|
||||
img.removeEventListener("load", onLoad);
|
||||
img.removeEventListener("error", onError);
|
||||
if (timer) clearTimeout(timer);
|
||||
};
|
||||
|
||||
// Ưu tiên decode (async), fallback event load/error
|
||||
if (typeof img.decode === "function") {
|
||||
img.decode().then(() => finalize(true)).catch(() => {
|
||||
if (img.complete) finalize(true);
|
||||
else {
|
||||
img.addEventListener("load", onLoad, { once: true });
|
||||
img.addEventListener("error", onError, { once: true });
|
||||
}
|
||||
});
|
||||
} else if (img.complete) {
|
||||
finalize(true);
|
||||
} else {
|
||||
img.addEventListener("load", onLoad, { once: true });
|
||||
img.addEventListener("error", onError, { once: true });
|
||||
}
|
||||
|
||||
// Fallback timeout nếu load/error không bắn
|
||||
/// const timer = setTimeout(() => finalize(false), 8000);
|
||||
}
|
||||
|
||||
_normalizeToElements(input) {
|
||||
if (typeof input === "string") {
|
||||
const tpl = document.createElement("template");
|
||||
tpl.innerHTML = input.trim();
|
||||
return Array.from(tpl.content.children);
|
||||
}
|
||||
if (input instanceof HTMLElement) return [input];
|
||||
if (input instanceof DocumentFragment) return Array.from(input.children);
|
||||
if (input && (input instanceof NodeList || input instanceof HTMLCollection || Array.isArray(input))) {
|
||||
return Array.from(input).filter(n => n instanceof HTMLElement);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// ===== Layout chung =====
|
||||
layoutInit() {
|
||||
this.gridWidth = this.ele.clientWidth;
|
||||
this.isRender = false;
|
||||
if (this._o.gridType === "row") {
|
||||
this.initRows();
|
||||
this.layoutRows();
|
||||
} else {
|
||||
this.initCols();
|
||||
this.restructCol();
|
||||
this.layoutCols();
|
||||
}
|
||||
this._observeLastItem();
|
||||
}
|
||||
restructCol() {
|
||||
this.ele.style.height = 'auto';
|
||||
|
||||
this.listGrid.forEach((v, k) => {
|
||||
v.gridEl.style.top = '';
|
||||
v.gridEl.style.left = '';
|
||||
v.gridEl.style.width = this.colW;
|
||||
v.gridEl.style.height = '';
|
||||
v.gridEl.style.position = "relative";
|
||||
v.bounding = v.gridEl.getBoundingClientRect();
|
||||
});
|
||||
}
|
||||
reLayout() {
|
||||
if (this.cancelResize) this.cancelResize();
|
||||
if (!this.ticking) {
|
||||
if (this.cancelFunc) this.cancelFunc();
|
||||
const animationId = window.requestAnimationFrame(() => {
|
||||
this.isRender = false;
|
||||
this.sTime = new Date();
|
||||
this.timeout = false;
|
||||
this.ticking = true;
|
||||
this.layoutInit();
|
||||
this.ticking = false;
|
||||
});
|
||||
this.cancelFunc = (() => { cancelAnimationFrame(animationId); });
|
||||
window.requestTimeout(() => { if (this.cancelFunc) this.cancelFunc(); this.layoutInit(); }, 500, (t) => { this.cancelResize = t; });
|
||||
}
|
||||
}
|
||||
|
||||
// ===== ROW (Justified) =====
|
||||
initRows() {
|
||||
this.listRows = [];
|
||||
this.listRows.push(this.structureRow(this._o.desiredHeight));
|
||||
}
|
||||
|
||||
layoutRows() {
|
||||
let nRow = 0;
|
||||
this.listGrid.forEach((_, k) => { nRow = this.pushEleToRow(nRow, k); });
|
||||
this.ele.style.height = this.calcPosTop(0, this.listRows.length) + "px";
|
||||
if (window.app?.checkVisible?.(this.ele)) this.renderAnimation();
|
||||
}
|
||||
|
||||
pushEleToRow(nRow, k) {
|
||||
const grid = this.listGrid.get(k);
|
||||
const cRow = this.listRows[nRow];
|
||||
const t1 = this._o.desiredHeight * (grid.aRatio * 1);
|
||||
const denom = this.gridWidth - ((cRow.listElement.length - 1) * (1 * this._o.gutter));
|
||||
const errorH = (cRow.rowW + t1) / (denom <= 0 ? 1 : denom);
|
||||
|
||||
if (errorH > 1.2 && cRow.listElement.length !== 0) {
|
||||
cRow.rowH = this.reCalcWidth(cRow);
|
||||
this.listRows.push(this.structureRow(this._o.desiredHeight));
|
||||
return this.pushEleToRow(nRow + 1, k);
|
||||
}
|
||||
|
||||
const g = (cRow.listElement.length > 0) ? this._o.gutter * 1 : 0;
|
||||
cRow.listElement.push({ key: k, top: this.calcPosTop(0, nRow), left: (cRow.rowW + g), render: false });
|
||||
cRow.rowW += t1;
|
||||
cRow.numM = k;
|
||||
|
||||
if (errorH <= 1.2 && errorH >= 0.8) cRow.rowH = this.reCalcWidth(cRow);
|
||||
return nRow;
|
||||
}
|
||||
|
||||
calcPosTop(begin, end) {
|
||||
if (begin === 0 && end === 0) return 0;
|
||||
let rowH = 0;
|
||||
for (let i = begin; i <= end - 1; i++) rowH += this.listRows[i].rowH + 1 * this._o.gutter;
|
||||
return rowH;
|
||||
}
|
||||
|
||||
reCalcWidth(cRow) {
|
||||
const rowW = this.gridWidth - (cRow.listElement.length - 1) * this._o.gutter * 1;
|
||||
let tRate = 0;
|
||||
for (let i = 0; i < cRow.listElement.length; i++) tRate += this.listGrid.get(cRow.listElement[i].key).aRatio * 1;
|
||||
const rrowH = rowW / (tRate === 0 ? 1 : tRate);
|
||||
|
||||
cRow.rowW = 0;
|
||||
for (let i = 0; i < cRow.listElement.length; i++) {
|
||||
if (i === 0) cRow.listElement[i].left = 0;
|
||||
else {
|
||||
const prev = cRow.listElement[i - 1];
|
||||
const wPrev = (this.listGrid.get(prev.key).aRatio * 1) * rrowH;
|
||||
cRow.rowW += wPrev;
|
||||
cRow.listElement[i].left = prev.left + wPrev + this._o.gutter * 1;
|
||||
}
|
||||
}
|
||||
return rrowH;
|
||||
}
|
||||
|
||||
_appendOptimizedSingleRow(key, rec) {
|
||||
let lastIdx = this.listRows.length - 1;
|
||||
if (lastIdx < 0) { this.initRows(); lastIdx = 0; }
|
||||
const cRow = this.listRows[lastIdx];
|
||||
|
||||
const t1 = this._o.desiredHeight * (rec.aRatio || 1);
|
||||
const denom = this.gridWidth - (cRow.listElement.length - 1) * this._o.gutter;
|
||||
const errorH = (cRow.rowW + t1) / (denom <= 0 ? 1 : denom);
|
||||
const topBase = this.calcPosTop(0, lastIdx);
|
||||
|
||||
if (errorH > 1.2 && cRow.listElement.length !== 0) {
|
||||
cRow.rowH = this.reCalcWidth(cRow);
|
||||
// render lại row cũ
|
||||
for (let i = 0; i < cRow.listElement.length; i++) {
|
||||
const it = cRow.listElement[i];
|
||||
const g = this.listGrid.get(it.key);
|
||||
const w = cRow.rowH * (g.aRatio || 1);
|
||||
this._applyGridStyle(g.gridEl, it.top, it.left, w, cRow.rowH);
|
||||
if (g.imgEl) { g.imgEl.style.width = `${w.toFixed(2)}px`; g.imgEl.style.height = `${(+cRow.rowH).toFixed(2)}px`; }
|
||||
}
|
||||
|
||||
const newRow = this.structureRow(this._o.desiredHeight);
|
||||
this.listRows.push(newRow);
|
||||
const topNew = this.calcPosTop(0, this.listRows.length - 1);
|
||||
const leftNew = 0;
|
||||
newRow.listElement.push({ key, top: topNew, left: leftNew, render: false });
|
||||
newRow.rowW += t1;
|
||||
|
||||
const wNew = this._o.desiredHeight * (rec.aRatio || 1);
|
||||
this._applyGridStyle(rec.gridEl, topNew, leftNew, wNew, this._o.desiredHeight);
|
||||
} else {
|
||||
const gspace = cRow.listElement.length > 0 ? this._o.gutter : 0;
|
||||
const left = cRow.rowW + gspace;
|
||||
cRow.listElement.push({ key, top: topBase, left, render: false });
|
||||
cRow.rowW += t1;
|
||||
|
||||
if (errorH <= 1.2 && errorH >= 0.8) cRow.rowH = this.reCalcWidth(cRow);
|
||||
|
||||
for (let i = 0; i < cRow.listElement.length; i++) {
|
||||
const it = cRow.listElement[i];
|
||||
const g = this.listGrid.get(it.key);
|
||||
const w = cRow.rowH * (g.aRatio || 1);
|
||||
this._applyGridStyle(g.gridEl, it.top, it.left, w, cRow.rowH);
|
||||
if (g.imgEl) { g.imgEl.style.width = `${w.toFixed(2)}px`; g.imgEl.style.height = `${(+cRow.rowH).toFixed(2)}px`; }
|
||||
}
|
||||
}
|
||||
|
||||
this.ele.style.height = this.calcPosTop(0, this.listRows.length) + "px";
|
||||
this.isRender = true;
|
||||
}
|
||||
|
||||
// ===== WATERFALL (Masonry) =====
|
||||
initCols() {
|
||||
this.wWidth = window.innerWidth || document.body.clientWidth;
|
||||
const colNum = this._resolveColNum(this.wWidth);
|
||||
this._buildCols(colNum, this.gridWidth);
|
||||
}
|
||||
|
||||
layoutCols() {
|
||||
// phân bổ tuần tự sang cột (theo code gốc)
|
||||
let i = 0, col = 0, l = 0;
|
||||
this.listCols.forEach(c => { c.listElement = []; c.colH = 0; });
|
||||
|
||||
this.listGrid.forEach((v, k) => {
|
||||
let t = 0, cVal;
|
||||
const pC = v.gridEl.querySelector(".grid-content");
|
||||
let hC = pC ? pC.clientHeight : 0;
|
||||
if (i % this.listCols.length === 0) { col = 0; cVal = this.listCols[col]; l = 0; }
|
||||
else { col++; cVal = this.listCols[col]; l += this.colW + 1 * this._o.gutter; }
|
||||
|
||||
t = cVal.colH;
|
||||
hC = hC + this.colW / (1 * v.aRatio);
|
||||
// this._applyGridStyle(v.gridEl, t, l, this.colW, hC);
|
||||
cVal.listElement.push({ key: k, top: t, left: l, height: hC, render: false });
|
||||
cVal.colH = t + hC + 1 * this._o.gutter;
|
||||
i++;
|
||||
});
|
||||
|
||||
this.ele.style.height = this.getColMaxHeight() + "px";
|
||||
if (window.app?.checkVisible?.(this.ele)) this.renderAnimation();
|
||||
}
|
||||
_resolveColNum(width) {
|
||||
const bp = this._o.breakpoints;
|
||||
|
||||
|
||||
if (bp && typeof bp === "object") {
|
||||
const keys = Object.keys(bp)
|
||||
.map(k => +k)
|
||||
.filter(Number.isFinite)
|
||||
.sort((a, b) => b - a);
|
||||
|
||||
for (const k of keys) {
|
||||
if (width >= k) {
|
||||
const c = +bp[k]?.col;
|
||||
if (c > 0) return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
_buildCols(colNum, width) {
|
||||
const gutter = Number(this._o.gutter) || 0;
|
||||
this.colW = (width - (colNum - 1) * gutter) / colNum;
|
||||
this.listCols = [];
|
||||
let l = 0;
|
||||
for (let i = 0; i < colNum; i++) {
|
||||
this.listCols.push({ listElement: [], colH: 0, left: l, colW: this.colW });
|
||||
l += this.colW + 1 * this._o.gutter;
|
||||
}
|
||||
}
|
||||
_appendOptimizedSingleWaterfall(key, rec) {
|
||||
// Chọn cột thấp nhấtlistCols
|
||||
let minIdx = 0;
|
||||
for (let i = 1; i < this.listCols.length; i++) {
|
||||
if (this.listCols[i].colH < this.listCols[minIdx].colH) minIdx = i;
|
||||
}
|
||||
const col = this.listCols[minIdx];
|
||||
const pC = rec.gridEl.querySelector(".grid-content");
|
||||
const hC = pC ? pC.getBoundingClientRect().height : 0;
|
||||
|
||||
const height = (rec.aRatio == 0) ? rec.gridEl.clientHeight : hC + (this.colW / (1 * rec.aRatio));
|
||||
|
||||
const top = col.colH;
|
||||
const left = col.left;
|
||||
|
||||
col.listElement.push({ key, top, left, height, render: true });
|
||||
col.colH = top + height + 1 * (this._o.gutter || 0);
|
||||
this._applyGridStyle(rec.gridEl, top, left, this.colW, height);
|
||||
this.ele.style.height = this.getColMaxHeight() + "px";
|
||||
this.isRender = true;
|
||||
}
|
||||
getColMaxHeight() {
|
||||
let m = 0;
|
||||
for (let i = 0; i < this.listCols.length; i++) if (m <= this.listCols[i].colH) m = this.listCols[i].colH;
|
||||
return m;
|
||||
}
|
||||
|
||||
// ===== Render chung =====
|
||||
renderAnimation() {
|
||||
this.isRender = true;
|
||||
if (this._o.gridType === "row") {
|
||||
if (this.listRows == null) return;
|
||||
this.listRows.forEach((row) => {
|
||||
for (let i = 0; i < row.listElement.length; i++) {
|
||||
const it = row.listElement[i];
|
||||
const grid = this.listGrid.get(it.key);
|
||||
const w = row.rowH * (grid.aRatio || 1);
|
||||
this._applyGridStyle(grid.gridEl, it.top, it.left, w, row.rowH);
|
||||
if (grid.imgEl) {
|
||||
grid.imgEl.style.width = `${w.toFixed(2)}px`;
|
||||
grid.imgEl.style.height = `${(+row.rowH).toFixed(2)}px`;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (this.listCols == null) return;
|
||||
this.listCols.forEach((col) => {
|
||||
for (let i = 0; i < col.listElement.length; i++) {
|
||||
const it = col.listElement[i];
|
||||
const grid = this.listGrid.get(it.key);
|
||||
this._applyGridStyle(grid.gridEl, it.top, it.left, this.colW, it.height);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_applyGridStyle(el, top, left, width, height) {
|
||||
const s = el.style;
|
||||
if (s.position !== "absolute") s.position = "absolute";
|
||||
s.top = `${(+top).toFixed(2)}px`;
|
||||
s.left = `${(+left).toFixed(2)}px`;
|
||||
s.width = `${(+width).toFixed(2)}px`;
|
||||
s.height = `${(+height).toFixed(2)}px`;
|
||||
}
|
||||
structureCol(colN) { return { listElement: [], colNum: colN, colH: 0, colW: 0 }; }
|
||||
structureRow(rowH = 0) { return { listElement: [], rowH, status: 0, numM: 0, rowW: 0 }; }
|
||||
|
||||
// ===== Utility =====
|
||||
empty() {
|
||||
this.ele.innerHTML = '';
|
||||
this.listGrid?.clear();
|
||||
this.listRows = [];
|
||||
this.listCols = [];
|
||||
this.keyI = 1;
|
||||
this.isRender = false;
|
||||
this.gridWidth = 0;
|
||||
this.ele.style.height = '0px';
|
||||
this.gridWidth = this.ele.clientWidth;
|
||||
this.initCols();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
8
TWASys-App/wwwroot/js/libs/js-ALayout.js
Normal file
8
TWASys-App/wwwroot/js/libs/js-ALayout.js
Normal file
@ -0,0 +1,8 @@
|
||||
export default class ALayout extends window.AObject {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
renderMenu(){
|
||||
|
||||
}
|
||||
}
|
||||
57
TWASys-App/wwwroot/js/libs/js-AListBox.js
Normal file
57
TWASys-App/wwwroot/js/libs/js-AListBox.js
Normal file
@ -0,0 +1,57 @@
|
||||
import AbsTable from '/js/libs/js-AbsTable.js'
|
||||
|
||||
export default class AListBox extends AbsTable {
|
||||
constructor(e) {
|
||||
super(e);
|
||||
this.absContainer.setAttribute("data-style", "AListBox");
|
||||
this.multiSelect = false;
|
||||
this.selectedID = -1;
|
||||
this.selectedIDs = [];
|
||||
this.selectedItem = null;
|
||||
this.selectedItems = [];
|
||||
this.absRows.addEventListener("click", this.RowClick.bind(this), false);
|
||||
}
|
||||
RemoveItem(id) {
|
||||
|
||||
}
|
||||
CheckSelected(row) {
|
||||
var id = row.getAttribute("data-id");
|
||||
if (this.multiSelect) {
|
||||
|
||||
} else {
|
||||
if (this.selectedID != id) {
|
||||
(this.selectedItem != null)?this.selectedItem.classList.remove("active"):null;
|
||||
this.selectedItem = row;
|
||||
this.selectedID = id;
|
||||
this.selectedItem.classList.add("active");
|
||||
}
|
||||
}
|
||||
}
|
||||
checkMultiSeleted(id, ele, f) {
|
||||
if (this.multiSelect) {
|
||||
if (f) {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
} else {
|
||||
if (f) {
|
||||
this.selectedID = id;
|
||||
this.selectedItem = ele;
|
||||
} else {
|
||||
this.selectedID = null;
|
||||
this.selectedItem = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
RowClick(e) {
|
||||
var target = e.target;
|
||||
var row = target.closest("tr");
|
||||
if (row != null) {
|
||||
this.CheckSelected(row);
|
||||
}
|
||||
}
|
||||
LoadDataAuto() {
|
||||
|
||||
}
|
||||
}
|
||||
157
TWASys-App/wwwroot/js/libs/js-AMenu.js
Normal file
157
TWASys-App/wwwroot/js/libs/js-AMenu.js
Normal file
@ -0,0 +1,157 @@
|
||||
import ADropdown from '/js/libs/js-ADropdown.js'
|
||||
import ATransitionEffect from '/js/libs/js-ATransitionEffect.js'
|
||||
import AOverlay from '/js/libs/js-AOverlay.js';
|
||||
|
||||
export default class AMenu extends window.AObject {
|
||||
constructor(nav, navM, btnMs, isMDiffD = false) {
|
||||
super();
|
||||
this.listIco = [];
|
||||
this.navM = (navM != null) ? document.querySelector(navM) : null;
|
||||
this.navD = document.querySelector(nav);
|
||||
this.transition = new ATransitionEffect();
|
||||
this.overlay = new AOverlay(document.body);
|
||||
|
||||
this.isMDiffD = isMDiffD;
|
||||
this.changeActive();
|
||||
|
||||
if (btnMs != null) {
|
||||
if (!(Array.isArray(btnMs) || btnMs instanceof NodeList || btnMs instanceof HTMLCollection)) {
|
||||
const tmp = [];
|
||||
tmp.push(btnMs);
|
||||
btnMs = tmp;
|
||||
}
|
||||
btnMs.forEach((el => {
|
||||
|
||||
var f = function (e) {
|
||||
this.mobileMenu.call(this, e, el);
|
||||
}.bind(this);
|
||||
el.addEventListener(this.eventName, f, false);
|
||||
this.addSystemEvent(this.eventName, el, f, "icomenu");
|
||||
this.listIco.push(el);
|
||||
|
||||
}).bind(this));
|
||||
this.overlay.createOverlay();
|
||||
this.overlay.setIndex(2000);
|
||||
var e1 = this.navM.querySelector(".hd-close");
|
||||
var f1 = function (e) {
|
||||
this.overlay.removeOverlay();
|
||||
this.listIco.forEach(el => {
|
||||
el.classList.remove("active");
|
||||
})
|
||||
}.bind(this);
|
||||
e1.addEventListener(this.eventName, f1, false);
|
||||
this.addSystemEvent(this.eventName, e1, f1, "aOverlay");
|
||||
this.overlay.on("before_close", (function () {
|
||||
this.listIco.forEach(el => {
|
||||
el.classList.remove("active");
|
||||
})
|
||||
this.navM.classList.remove("show");
|
||||
}).bind(this));
|
||||
}
|
||||
this.initDropDown();
|
||||
this.initNav(this.navD);
|
||||
if (this.isMDiffD) {
|
||||
this.initNav(this.navM, "M");
|
||||
}
|
||||
}
|
||||
|
||||
initNav(ele, type = "D") {
|
||||
let arr = ele.querySelectorAll(".nav-i.has-sub .nav-link, .navmain > .nav-i:not(.has-sub) a");
|
||||
Array.from(arr).forEach(el => {
|
||||
var f = function (evt) {
|
||||
evt.preventDefault();
|
||||
if (window.isValidPointerClick(evt)) return;
|
||||
this.addEventClick.call(this, evt, type);
|
||||
}.bind(this);
|
||||
el.addEventListener("click", f, true);
|
||||
});
|
||||
}
|
||||
initDropDown() {
|
||||
var d2 = new ADropdown();
|
||||
d2.bindDropDowns(this.navD.querySelectorAll(".nav-i.has-sub"));
|
||||
if (this.isMDiffD) {
|
||||
d2.bindDropDowns(this.navM.querySelectorAll(".nav-i.has-sub"));
|
||||
}
|
||||
this.dropdown = d2;
|
||||
}
|
||||
dispose() {
|
||||
this.overlay.dispose();
|
||||
this.dropdown.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
updateIdPage() {
|
||||
this.idPage = document.head.querySelector("meta[name=idPage]").content;
|
||||
|
||||
this.navActiveD = this.navD.querySelector("a[nav-id='" + this.idPage + "']");
|
||||
if (this.isMDiffD) {
|
||||
this.navActiveM = this.navM.querySelector("a[nav-id='" + this.idPage + "']");
|
||||
}
|
||||
window.removeStopCollapsed();
|
||||
}
|
||||
changeActive() {
|
||||
this.checkItemActive(false);
|
||||
this.updateIdPage();
|
||||
this.checkItemActive(true);
|
||||
}
|
||||
checkItemActive(f) {
|
||||
this.toggleItemActive(this.navActiveD, f, "Desktop");
|
||||
if (this.isMDiffD) {
|
||||
this.toggleItemActive(this.navActiveM, f);
|
||||
}
|
||||
}
|
||||
toggleItemActive(e, f, t = "Mobile") {
|
||||
if (e != null) {
|
||||
var hasSubE = e.closest(".has-sub");
|
||||
if (t == "Mobile") {
|
||||
if (f) {
|
||||
(hasSubE != null) ? hasSubE.classList.add("activeM") : "";
|
||||
e.classList.add("active");
|
||||
} else {
|
||||
(hasSubE != null) ? hasSubE.classList.remove("activeM") : "";
|
||||
e.classList.remove("active");
|
||||
}
|
||||
} else {
|
||||
if (f) {
|
||||
if (hasSubE != null) {
|
||||
hasSubE.classList.add("activeM")
|
||||
}
|
||||
e.classList.add("active");
|
||||
} else {
|
||||
if (hasSubE != null) {
|
||||
hasSubE.classList.remove("activeM");
|
||||
}
|
||||
e.classList.remove("active");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addEventClick(e, t) {
|
||||
window.app.initNavApp(e.currentTarget.getAttribute("href"), e.currentTarget.hasAttribute("isflexpage"));
|
||||
window.requestTimeout((() => {
|
||||
requestAnimationFrame((() => {
|
||||
if (t == "M") {
|
||||
this.overlay.removeOverlay();
|
||||
this.listIco.forEach(el => {
|
||||
el.classList.remove("active");
|
||||
})
|
||||
} else {
|
||||
this.dropdown.closeDropdown();
|
||||
}
|
||||
}).bind(this));
|
||||
}).bind(this), 100);
|
||||
|
||||
}
|
||||
closeExpandMenu() {
|
||||
Array.from(this.navM.querySelectorAll(".nav-i.has-sub")).forEach(el => {
|
||||
el.classList.remove("active");
|
||||
});
|
||||
}
|
||||
mobileMenu(e, btn) {
|
||||
this.overlay.showOverlay();
|
||||
this.navM.classList.add("show");
|
||||
this.listIco.forEach(el => {
|
||||
el.classList.add("active");
|
||||
})
|
||||
}
|
||||
}
|
||||
94
TWASys-App/wwwroot/js/libs/js-AModal.js
Normal file
94
TWASys-App/wwwroot/js/libs/js-AModal.js
Normal file
@ -0,0 +1,94 @@
|
||||
import AOverlay from '/js/libs/js-AOverlay.js';
|
||||
|
||||
export default class AModal extends window.AObject {
|
||||
constructor(temp) {
|
||||
super();
|
||||
this.overlay = new AOverlay(document.body);
|
||||
this.overlay.isCloseOverlay(false);
|
||||
this.overlay.createOverlay();
|
||||
this.overlay.setIndex(2200);
|
||||
this.customForm = temp;
|
||||
}
|
||||
createModal(typeModal, t1 = 'default') {
|
||||
var temp = `
|
||||
<div class="modal-scroll">
|
||||
<div class="modal-con d-f j-c-center ${ (t1 instanceof Array) ? t1.join(" ") : t1 }">
|
||||
<div class="modal-dialog">
|
||||
<div class="btClose pointer">
|
||||
<span class="atg atg-x"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
this.overlay.overlay.insertAdjacentHTML("afterbegin", temp);
|
||||
const b = this.overlay.overlay.querySelector(".modal-dialog");
|
||||
const bc1 = this.overlay.overlay.querySelector(".btClose");
|
||||
bc1.addEventListener("click", ((e) => {
|
||||
this.trigger("Close");
|
||||
this.overlay.removeOverlay();
|
||||
}).bind(this));
|
||||
switch (typeModal) {
|
||||
case "CustomForm":
|
||||
b.insertAdjacentHTML("beforeend", this.customForm);
|
||||
this.CustomContainer = b;
|
||||
break;
|
||||
case "OK":
|
||||
this.AModalOK = new AModalOK(b);
|
||||
this.AModalOK.createElement();
|
||||
this.AModalOK.bindEvent(".btn-ok", "click", ((ev, mO) => {
|
||||
this.trigger("OK");
|
||||
this.overlay.removeOverlay();
|
||||
}).bind(this));
|
||||
this.AModalOK.bindEvent(".btn-close", "click", ((ev, mO) => {
|
||||
this.trigger("Close");
|
||||
this.overlay.removeOverlay();
|
||||
}).bind(this));
|
||||
break;
|
||||
case "YesNo":
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
showModal() {
|
||||
this.overlay.showOverlay();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class AModalOK {
|
||||
constructor(p) {
|
||||
this.parent = p;
|
||||
}
|
||||
message(str, classes = "") {
|
||||
this.mess.innerHTML = str;
|
||||
if (classes.length > 0) {
|
||||
Array.from(classes.split(" ")).forEach(el => {
|
||||
this.mess.classList.add(el);
|
||||
})
|
||||
}
|
||||
}
|
||||
title(str, classes = "") {
|
||||
this.tit.innerHTML = str;
|
||||
if (classes.length > 0) {
|
||||
Array.from(classes.split(" ")).forEach(el => {
|
||||
this.tit.classList.add(el);
|
||||
})
|
||||
}
|
||||
}
|
||||
createElement() {
|
||||
const temp = `<div class="d-f f-c modalok">
|
||||
<h5>Information</h5>
|
||||
<span class="mess-info"></span>
|
||||
<div class="ml-auto mt-2">
|
||||
<button class="btn btn-primary btn-effect waves-effect waves-float btn-ok">Ok</button>
|
||||
<button class="btn btn-secondary btn-effect waves-effect waves-float btn-close">Cancel</button>
|
||||
</div>
|
||||
</div>`;
|
||||
this.parent.insertAdjacentHTML("beforeend", temp);
|
||||
this.tit = this.parent.querySelector("h5");
|
||||
this.mess = this.parent.querySelector(".mess-info");
|
||||
}
|
||||
bindEvent(ele, n, f) {
|
||||
this.parent.querySelector(ele).addEventListener(n, f.bind(null, this));
|
||||
}
|
||||
}
|
||||
47
TWASys-App/wwwroot/js/libs/js-AMultiTag.js
Normal file
47
TWASys-App/wwwroot/js/libs/js-AMultiTag.js
Normal file
@ -0,0 +1,47 @@
|
||||
export default class AMultiTag extends window.AObject {
|
||||
constructor(ele) {
|
||||
super();
|
||||
this.parent = ele;
|
||||
this.cItems = ele.querySelector(".input-content");
|
||||
this.itemEles = [];
|
||||
this.itemDatas = [];
|
||||
this.btnAdd = ele.querySelector(".btn-Add");
|
||||
this.btnAdd.addEventListener("click", ((e) => {
|
||||
this.parent.classList.add("active");
|
||||
this.trigger("btnAdd_Click", e);
|
||||
}).bind(this));
|
||||
if (window.AMultiTag == null) {
|
||||
this.initGlobalVar();
|
||||
}
|
||||
}
|
||||
initGlobalVar() {
|
||||
var f = function (ev) {
|
||||
if (ev.target.closest(".amultitag") || ev.target.closest(".c-aoverlay")) {
|
||||
return;
|
||||
} else {
|
||||
this.parent.classList.remove("active");
|
||||
}
|
||||
}.bind(this);
|
||||
document.body.addEventListener("mousedown", f, false);
|
||||
window.AMultiTag = true;
|
||||
}
|
||||
addItem(id, name, obj, action = null) {
|
||||
var ele = this.addItem(id, name, action);
|
||||
this.itemEles.push(ele);
|
||||
this.itemDatas.push(obj);
|
||||
this.cItems.appendChild(ele);
|
||||
}
|
||||
createItem(id, name, action) {
|
||||
var p = document.createElement("div");
|
||||
p.setAttribute("data-id", id);
|
||||
p.classList.add("item");
|
||||
var label = document.createElement("span");
|
||||
label.innerHTML = name;
|
||||
label.classList.add("name");
|
||||
if (action != null) {
|
||||
p.appendChild(action);
|
||||
}
|
||||
p.appendChild(label);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
51
TWASys-App/wwwroot/js/libs/js-AOverlay.js
Normal file
51
TWASys-App/wwwroot/js/libs/js-AOverlay.js
Normal file
@ -0,0 +1,51 @@
|
||||
export default class AOverlay extends window.AObject {
|
||||
constructor(p) {
|
||||
super();
|
||||
this.parent = p;
|
||||
this.IsActive = false;
|
||||
this.isClose = true;
|
||||
}
|
||||
createOverlay() {
|
||||
var c = document.createElement("div");
|
||||
c.classList.add("c-aoverlay");
|
||||
this.parent.appendChild(c);
|
||||
this.overlay = c;
|
||||
var f = function (e) {
|
||||
this.onOverlay_click.call(this, e);
|
||||
}.bind(this);
|
||||
c.addEventListener("click", f, false);
|
||||
|
||||
}
|
||||
setIndex(i) {
|
||||
this.overlay.style.zIndex = i;
|
||||
}
|
||||
showOverlay() {
|
||||
this.overlay.classList.add("show");
|
||||
this.IsActive = true;
|
||||
}
|
||||
isCloseOverlay(flag) {
|
||||
this.isClose = flag;
|
||||
}
|
||||
addChildNode(childNode) {
|
||||
this.overlay.appendChild(childNode);
|
||||
}
|
||||
|
||||
removeOverlay() {
|
||||
this.trigger("before_close");
|
||||
var f = function (e) {
|
||||
this.IsActive = false;
|
||||
this.trigger("after_close");
|
||||
this.overlay.removeEventListener("transitionend", f, false);
|
||||
}.bind(this);
|
||||
this.overlay.addEventListener("transitionend", f, false);
|
||||
this.overlay.classList.remove("show");
|
||||
|
||||
}
|
||||
onOverlay_click(e) {
|
||||
if ((e.target.classList.contains("modal-con") || e.target.classList.contains("c-aoverlay") )&& this.isClose) {
|
||||
this.removeOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
145
TWASys-App/wwwroot/js/libs/js-APaging.js
Normal file
145
TWASys-App/wwwroot/js/libs/js-APaging.js
Normal file
@ -0,0 +1,145 @@
|
||||
export default class APaging extends window.AObject {
|
||||
constructor(pEle) {
|
||||
super();
|
||||
this.con = pEle;
|
||||
this.activePage = 1;
|
||||
this.bucket = 3;
|
||||
this.listActive = [];
|
||||
this.InitStructure();
|
||||
}
|
||||
SetPaging(maxR) {
|
||||
this.maxRow = maxR;
|
||||
this.numPage = Math.ceil(maxR / this.pageSize);
|
||||
this.lbNum.innerHTML = this.numPage;
|
||||
this.RefreshPaging(this.activePage);
|
||||
}
|
||||
RefreshPaging(page) {
|
||||
this.inpN.value = page;
|
||||
this.activePage = page;
|
||||
this.conPageLinks.innerHTML = "";
|
||||
if (page <= this.bucket - 1) {
|
||||
var length = (this.bucket < this.numPage) ? this.bucket : this.numPage;
|
||||
this.CreatePaging(1, length);
|
||||
} else if (this.numPage - this.activePage <= this.bucket - 2) {
|
||||
this.CreatePaging(this.numPage - this.bucket + 1, this.numPage);
|
||||
} else {
|
||||
this.CreatePaging(this.activePage - 1, this.activePage + this.bucket - 2);
|
||||
}
|
||||
}
|
||||
CreatePaging(start, end) {
|
||||
for (var i = start; i <= end; i++) {
|
||||
var m = this.CreatePageNum(i, "page-link");
|
||||
this.listActive.push(m);
|
||||
this.conPageLinks.appendChild(m);
|
||||
this.CheckActivePage(i, m);
|
||||
}
|
||||
}
|
||||
CheckActivePage(i, m) {
|
||||
if (i == this.activePage) {
|
||||
this.elActice = m;
|
||||
this.elActice.classList.add("active");
|
||||
}
|
||||
}
|
||||
InitStructure() {
|
||||
var d = document.createElement("div");
|
||||
d.classList.add("d-f", "f-wrap", "con-paging");
|
||||
var d1 = document.createElement("div");
|
||||
d1.classList.add("d-f", "a-i-center");
|
||||
var d2 = document.createElement("span");
|
||||
d2.innerHTML = "Page ";
|
||||
d1.appendChild(d2);
|
||||
var inpNum = document.createElement("input");
|
||||
inpNum.setAttribute("type", "input");
|
||||
inpNum.classList.add("ml-1", "inpNum");
|
||||
d1.appendChild(inpNum);
|
||||
this.inpN = inpNum;
|
||||
var sp = document.createElement("span");
|
||||
sp.innerHTML = " / ";
|
||||
var sp1 = document.createElement("span");
|
||||
sp1.innerHTML = "5";
|
||||
d1.appendChild(sp);
|
||||
d1.appendChild(sp1);
|
||||
this.lbNum = sp1;
|
||||
d.appendChild(d1);
|
||||
d1 = document.createElement("div");
|
||||
d1.classList.add("paging", "d-f", "ml-auto");
|
||||
d1.appendChild(this.CreatePageNum("", "item-less", "atg-less"));
|
||||
d2 = document.createElement("div");
|
||||
d2.classList.add("d-f", "c-page-link");
|
||||
this.conPageLinks = d2;
|
||||
d1.appendChild(d2);
|
||||
d1.appendChild(this.CreatePageNum("", "item-more", "atg-more"));
|
||||
d.appendChild(d1);
|
||||
this.conPaging = d1;
|
||||
this.con.appendChild(d);
|
||||
|
||||
var f = function (evt) {
|
||||
this.ItemClick.call(this, evt);
|
||||
}.bind(this);
|
||||
this.conPaging.addEventListener("click", f, false);
|
||||
f = function (evt) {
|
||||
/*if (this.aOverlay.IsActive) return;*/
|
||||
var selection = window.getSelection().toString();
|
||||
if (selection !== '') {
|
||||
return;
|
||||
}
|
||||
var arr = [38, 40, 37, 39];
|
||||
if (arr.includes(evt.keyCode)) {
|
||||
return;
|
||||
}
|
||||
var input = evt.currentTarget.value;
|
||||
input = input.replace(/[^0-9\.]+/g, "");
|
||||
if (input != "") {
|
||||
input = parseInt(input);
|
||||
if (input >= 1 && input <= this.numPage && input != this.activePage) {
|
||||
this.activePage = input;
|
||||
this.trigger("PagingChange", { "numPage": this.numPage, "pageSize": this.pageSize, "activePage": this.activePage });
|
||||
this.RefreshPaging(this.activePage);
|
||||
} else {
|
||||
input = this.activePage;
|
||||
}
|
||||
}
|
||||
evt.currentTarget.value = input;
|
||||
|
||||
}.bind(this);
|
||||
this.inpN.addEventListener("keyup", f, false);
|
||||
f = function (evt) {
|
||||
if (evt.currentTarget.value == "") evt.currentTarget.value = this.activePage;
|
||||
}.bind(this);
|
||||
this.inpN.addEventListener("blur", f, false);
|
||||
}
|
||||
ItemClick(e) {
|
||||
if (e.target.classList.contains("page-link") && e.target.classList.contains("active")) {
|
||||
return;
|
||||
}
|
||||
var clst = e.target.closest(".item-less");
|
||||
if (clst) {
|
||||
if (this.elActice.previousSibling != null) {
|
||||
this.elActice.previousSibling.click();
|
||||
}
|
||||
}
|
||||
var clst1 = e.target.closest(".item-more");
|
||||
if (clst1) {
|
||||
if (this.elActice.nextSibling != null) {
|
||||
this.elActice.nextSibling.click();
|
||||
}
|
||||
}
|
||||
if (e.target.classList.contains("page-link")) {
|
||||
this.RefreshPaging(parseInt(e.target.innerHTML));
|
||||
this.trigger("PagingChange", { "numPage": this.numPage, "pageSize": this.pageSize, "activePage": this.activePage });
|
||||
}
|
||||
}
|
||||
CreatePageNum(i, c = null, icon = null) {
|
||||
var d = document.createElement("a");
|
||||
d.setAttribute("href", "javascript:void(0)");
|
||||
d.classList.add("item", "d-f", "j-c-center", "a-i-center", c);
|
||||
d.innerHTML = i;
|
||||
if (icon != null) {
|
||||
var ic = document.createElement("span");
|
||||
ic.classList.add("atg", icon);
|
||||
d.appendChild(ic);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
||||
545
TWASys-App/wwwroot/js/libs/js-ASelect.js
Normal file
545
TWASys-App/wwwroot/js/libs/js-ASelect.js
Normal file
@ -0,0 +1,545 @@
|
||||
import ADropdown from '/js/libs/js-ADropdown.js'
|
||||
|
||||
class ASelectEle extends window.AObject {
|
||||
constructor(e, id, p) {
|
||||
super();
|
||||
this.dropdown = new ADropdown();
|
||||
this.parent = p;
|
||||
this.id = id;
|
||||
this.isFocus = false;
|
||||
this.isTextSearch = false;
|
||||
this.isSearch = false;
|
||||
this.isMultiSelect = false;
|
||||
this.multiSelectedItem = [];
|
||||
this.element = e;
|
||||
this.selectedByIndex = -1;
|
||||
this.selectedEleItem = null;
|
||||
this.cSubH = null;
|
||||
this.changeSearch = false;
|
||||
this.changeIndex = false;
|
||||
this.isOpen = false;
|
||||
this.o = {
|
||||
damping: 0.25,
|
||||
thumbMinSize: 5,
|
||||
renderByPixel: true,
|
||||
alwaysShowTracks: true,
|
||||
continuousScrolling: true
|
||||
};
|
||||
this.createElement(e);
|
||||
this.updateItem(true);
|
||||
}
|
||||
isLockElement() {
|
||||
return this.dropdown.isLock;
|
||||
}
|
||||
lockElement(str = "Loading....") {
|
||||
this.dropdown.isLock = true;
|
||||
if (this.isMultiSelect) {
|
||||
var t = this.cSelectedItem.querySelectorAll(".item:not(input.item)");
|
||||
if (t && t.length > 0) t.removeAll();
|
||||
} else {
|
||||
var t = this.cSelectedItem.querySelectorAll("span");
|
||||
if (t && t.length > 0) t.removeAll();
|
||||
}
|
||||
this.createSelectedText(str);
|
||||
this.aSelect.classList.add("lock");
|
||||
}
|
||||
unlockElement() {
|
||||
this.dropdown.isLock = false;
|
||||
var t = this.cSelectedItem.querySelector("span.text");
|
||||
if (t) t.remove();
|
||||
this.aSelect.classList.remove("lock");
|
||||
}
|
||||
updateItem(f = false) {
|
||||
if (this.isMultiSelect) {
|
||||
this.isMultiSelect = [];
|
||||
}
|
||||
this.listGroups = [];
|
||||
this.listItems = [];
|
||||
if (!f) this.resetItem();
|
||||
var listOptions = this.element.querySelectorAll("option");
|
||||
if (listOptions != null) {
|
||||
listOptions.forEach(u => {
|
||||
this.addItem(u.getAttribute("value"), u.innerHTML);
|
||||
});
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
addGroup(id, text) {
|
||||
var t = this.groupUI(text);
|
||||
this.listGroups.push({ "id": id, "text": text, "subItems": [], "element": t });
|
||||
this.updateHeight();
|
||||
}
|
||||
addItem(id, val) {
|
||||
var it = document.createElement("span");
|
||||
it.classList.add("ellipsis");
|
||||
it.innerHTML = val;
|
||||
this.addCustomItem(id, it, val);
|
||||
}
|
||||
addCustomItem(id, o, vSearch = "", g = null) {
|
||||
if (g != null) {
|
||||
for (var i = 0; i < this.listGroups.length; i++) {
|
||||
if (this.listGroups[i].id = g.id) {
|
||||
var lastE = this.listOptions[i].subitems.element;
|
||||
var t = this.itemSubUI(id, o, lastE);
|
||||
t.setAttribute("index", this.listItems.length);
|
||||
this.listItems.push({ "id": id, "o": o, "vSearch": vSearch, "gParent": this.listGroups[i], "element": t });
|
||||
this.listGroups[i].subItems.push(this.listItems[this.listItems.length - 1]);
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var t = this.itemUI(id, o);
|
||||
t.setAttribute("index", this.listItems.length);
|
||||
this.listItems.push({ "id": id, "o": o, "vSearch": vSearch, "gParent": null, "element": t });
|
||||
}
|
||||
}
|
||||
update() {
|
||||
if (!this.isMultiSelect) {
|
||||
if (this.listItems.length == 0 && !this.dropdown.isLock) {
|
||||
this.createSelectedText("Please choose one of the below options");
|
||||
} else {
|
||||
this.updateIndex(0);
|
||||
}
|
||||
}
|
||||
this.updateHeight();
|
||||
}
|
||||
setElement(el, str = "active") {
|
||||
if (this.selectedEleItem != null && !this.isMultiSelect) {
|
||||
this.selectedEleItem.classList.remove(str);
|
||||
}
|
||||
el.classList.add(str);
|
||||
this.selectedEleItem = el;
|
||||
}
|
||||
setSelectedItem(value, f = true) {
|
||||
if (f) {
|
||||
for (var i = 0; i < this.listItems.length; i++) {
|
||||
if (this.listItems[i].id == value) {
|
||||
this.updateIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.updateIndex(value);
|
||||
}
|
||||
}
|
||||
getSelectedItem() {
|
||||
return this.selectedItem;
|
||||
}
|
||||
updateHeight() {
|
||||
var tmp = (this.cSearch ? this.cSearch.clientHeight : 0);
|
||||
var tmp1 = this.maxHeight - tmp;
|
||||
if (this.scrollSub.clientHeight >= tmp1 && this.cSubH == null) {
|
||||
this.cSubH = (this.maxHeight - tmp - 8);
|
||||
this.cSub.style.minHeight = this.cSubH + "px";
|
||||
if (this.isOpen) {
|
||||
this.cSub.parentNode.style.height = this.maxHeight + "px";
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.scrollSub.clientHeight < tmp1) {
|
||||
this.cSubH = null;
|
||||
this.cSub.style.minHeight = this.scrollSub.clientHeight + "px";
|
||||
if (this.isOpen) {
|
||||
this.cSub.parentNode.style.height = (this.scrollSub.clientHeight + tmp) + "px";
|
||||
}
|
||||
}
|
||||
}
|
||||
isItemEqual(it1, it2) {
|
||||
return it1.getAttribute("data-value") === it2.getAttribute("data-value");
|
||||
}
|
||||
updateIndex(idx, f = false) {
|
||||
if (this.isOpen) {
|
||||
this.changeIndex = true;
|
||||
}
|
||||
if (this.isMultiSelect) {
|
||||
if (this.selectedEleItem != null) this.selectedEleItem.classList.remove("hover");
|
||||
|
||||
this.selectedEleItem = this.listItems[idx].element;
|
||||
this.selectedItem = this.listItems[idx];
|
||||
if (f) {
|
||||
if (!this.multiSelectedItem.hasItem(this.selectedEleItem, this.isItemEqual)) {
|
||||
const item = document.createElement("div");
|
||||
item.classList.add("item", "d-f", "a-i-center");
|
||||
item.setAttribute("data-id", idx);
|
||||
this.cSelectedItem.insertBefore(item, this.cSelectedItem.children[0]);
|
||||
this.cloneNodes(this.selectedEleItem, item);
|
||||
item.insertAdjacentHTML("beforeend", `<button class="ml-1 noopen action d-f a-i-center j-c-center"><span class="atg atg-x"></span></button>`);
|
||||
var bt = item.querySelector("button");
|
||||
bt.addEventListener("click", (e => {
|
||||
this.removeItem(e.currentTarget.parentNode);
|
||||
}).bind(this));
|
||||
this.setElement(this.selectedEleItem);
|
||||
this.multiSelectedItem.push(this.selectedEleItem);
|
||||
}
|
||||
this.eleSearch.value = "";
|
||||
this.eleSearch.focus();
|
||||
}
|
||||
this.setElement(this.selectedEleItem, "hover");
|
||||
} else {
|
||||
this.selectedByIndex = idx;
|
||||
if (this.selectedEleItem != null) this.selectedEleItem.classList.remove("active");
|
||||
this.selectedEleItem = this.listItems[idx].element;
|
||||
this.selectedItem = this.listItems[idx];
|
||||
this.removeAllChildNodes(this.cSelectedItem);
|
||||
this.cloneNodes(this.selectedEleItem, this.cSelectedItem);
|
||||
this.setElement(this.selectedEleItem);
|
||||
this.scroll.update();
|
||||
this.scroll.scrollIntoView(this.selectedEleItem, {
|
||||
offsetTop: this.selectedEleItem.clientHeight
|
||||
});
|
||||
}
|
||||
}
|
||||
itemSubUI(id, o, lastE) {
|
||||
var t = this.itemBaseUI(id, o);
|
||||
lastE.parentNode.insertBefore(t, lastE.nextSibling);
|
||||
return t;
|
||||
}
|
||||
itemUI(id, o) {
|
||||
var t = this.itemBaseUI(id, o);
|
||||
this.scrollSub.appendChild(t);
|
||||
return t;
|
||||
}
|
||||
itemBaseUI(id, o) {
|
||||
var d = document.createElement("div");
|
||||
d.classList.add("a-option", "nonhide");
|
||||
d.setAttribute("data-value", id);
|
||||
d.appendChild(o);
|
||||
return d;
|
||||
}
|
||||
groupUI(text) {
|
||||
var d = document.createElement("div");
|
||||
d.classList.add("a-option-group", "nonhide");
|
||||
d.innerHTML = text;
|
||||
return d;
|
||||
}
|
||||
createSelectedUI() {
|
||||
var s = document.createElement("div");
|
||||
s.classList.add("d-f", "a-i-center");
|
||||
if (this.isMultiSelect) {
|
||||
s.classList.add("f-wrap");
|
||||
s.setAttribute("item-multiple", "");
|
||||
};
|
||||
this.cSelectedItem = s;
|
||||
return s;
|
||||
}
|
||||
createSelectedText(text) {
|
||||
var te = document.createElement("span");
|
||||
te.classList.add("ellipsis", "text");
|
||||
te.innerHTML = text;
|
||||
this.cSelectedItem.insertBefore(te, this.cSelectedItem.children[0]);
|
||||
}
|
||||
createSubItemUI() {
|
||||
var s = document.createElement("div");
|
||||
s.classList.add("sub-item", "a-s-sub", "d-f", "f-c");
|
||||
var cs = null, inp = null, sH = 0;
|
||||
|
||||
|
||||
if (this.isSearch || this.isMultiSelect) {
|
||||
|
||||
if (this.isMultiSelect) {
|
||||
const t = `<input class="item nonhide" type="input"/>`;
|
||||
this.cSelectedItem.insertAdjacentHTML("beforeend", t)
|
||||
inp = this.cSelectedItem.querySelector("input.item");
|
||||
} else {
|
||||
cs = document.createElement("div");
|
||||
cs.classList.add("a-search", "nonhide");
|
||||
s.appendChild(cs);
|
||||
inp = document.createElement("input");
|
||||
cs.appendChild(inp);
|
||||
s.appendChild(cs);
|
||||
this.cSearch = cs;
|
||||
}
|
||||
this.eleSearch = inp;
|
||||
var fv = function (e) {
|
||||
if (this.dropdown.isLock) {
|
||||
return;
|
||||
}
|
||||
if (!this.isFocus) {
|
||||
window.fireEvent(this.aSelect, "click");
|
||||
this.isFocus = true;
|
||||
}
|
||||
this.inputSearchEvent.call(this, e);
|
||||
|
||||
}.bind(this);
|
||||
inp.addEventListener("keyup", fv, false);
|
||||
var fv1 = function (e) {
|
||||
this.keyDown.call(this, e);
|
||||
}.bind(this);
|
||||
inp.addEventListener("keydown", fv1, false);
|
||||
|
||||
}
|
||||
var sub = document.createElement("div");
|
||||
sub.classList.add("w-100");
|
||||
sub.setAttribute("style", "height:auto");
|
||||
this.cSub = sub;
|
||||
var s1 = document.createElement("div");
|
||||
s1.classList.add("d-f", "f-c", "sub-items");
|
||||
sub.appendChild(s1);
|
||||
this.scrollSub = s1;
|
||||
s.appendChild(sub);
|
||||
return s;
|
||||
}
|
||||
createElement(e) {
|
||||
var d = document.createElement("div");
|
||||
d.classList.add("con-aselect");
|
||||
if (e.getAttribute("data-container-width") != null) {
|
||||
d.style.width = e.getAttribute("data-container-width");
|
||||
}
|
||||
d.setAttribute("data-dropdown", "");
|
||||
var cselect = document.createElement("div");
|
||||
cselect.classList.add("hide");
|
||||
d.appendChild(cselect);
|
||||
var f = document.createElement("div");
|
||||
for (var i = 0; i < e.classList.length; i++) {
|
||||
f.classList.add(e.classList[i]);
|
||||
}
|
||||
var atts = e.attributes;
|
||||
for (var i = 0; i < atts.length; i++) {
|
||||
if (atts[i].nodeName == "id" || atts[i].nodeName == "name") {
|
||||
continue;
|
||||
}
|
||||
if (atts[i].nodeName == "data-max-height") {
|
||||
this.maxHeight = atts[i].nodeValue;
|
||||
}
|
||||
f.setAttribute(atts[i].nodeName, atts[i].nodeValue);
|
||||
e.removeAttribute(atts[i].nodeName);
|
||||
i--;
|
||||
}
|
||||
d.appendChild(f);
|
||||
this.aSelect = f;
|
||||
this.isMultiSelect = f.hasAttribute("isMultiple");
|
||||
this.selectedUI = this.createSelectedUI();
|
||||
f.appendChild(this.selectedUI);
|
||||
var ic = document.createElement("div");
|
||||
ic.classList.add("icon", "atg", "a-down-thick");
|
||||
f.appendChild(ic);
|
||||
this.isSearch = f.hasAttribute("isSearch") && !this.isMultiSelect;
|
||||
d.appendChild(this.createSubItemUI());
|
||||
this.conSelect = d;
|
||||
e.parentNode.insertBefore(d, e);
|
||||
this.conSelect = d;
|
||||
cselect.appendChild(e);
|
||||
this.dropdown.bindDropDowns(f);
|
||||
this.scroll = Scrollbar.init(this.cSub, this.o);
|
||||
f.setAttribute("data-select-id", this.id);
|
||||
this.dropdown.on("opened", function (ev) {
|
||||
this.isFocus = true;
|
||||
this.isOpen = true;
|
||||
if (this.isMultiSelect) {
|
||||
this.eleSearch.focus();
|
||||
this.listItems.forEach(e => { e.element.classList.remove("hover") });
|
||||
this.selectedEleItem = this.listItems[0].element;
|
||||
this.listItems[0].element.classList.add("hover");
|
||||
}
|
||||
}.bind(this));
|
||||
this.dropdown.on("closed", function (ev) {
|
||||
this.isFocus = false;
|
||||
this.isOpen = false;
|
||||
if ((this.isSearch && this.isTextSearch) || this.isMultiSelect) {
|
||||
this.isTextSearch = false;
|
||||
this.eleSearch.value = "";
|
||||
this.resetItem(false);
|
||||
this.updateHeight();
|
||||
}
|
||||
if (this.changeIndex) {
|
||||
this.trigger("change", this);
|
||||
this.changeIndex = false;
|
||||
} else {
|
||||
this.scroll.scrollIntoView(this.selectedEleItem, {
|
||||
offsetTop: 0,
|
||||
onlyScrollIfNeeded: true
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
if (isTouchAvailable && getOS() === "iOS") {
|
||||
e.classList.add("ios");
|
||||
}
|
||||
var fv1 = function (ev) {
|
||||
this.keyDown.call(this, ev);
|
||||
}.bind(this);
|
||||
e.addEventListener("keydown", fv1, false);
|
||||
var fc = function (e) {
|
||||
this.subItemClick.call(this, e);
|
||||
}.bind(this);
|
||||
var f3 = function (ev) {
|
||||
ev.preventDefault();
|
||||
if (!this.isFocus) {
|
||||
window.fireEvent(f, "click");
|
||||
this.isFocus = true;
|
||||
}
|
||||
}.bind(this);
|
||||
e.addEventListener("focus", f3, false);
|
||||
var f4 = function (ev) {
|
||||
ev.preventDefault();
|
||||
if (!this.isFocus) {
|
||||
this.dropdown.checkCloseDropdown();
|
||||
}
|
||||
}.bind(this);
|
||||
e.addEventListener("blur", f4, false);
|
||||
this.scrollSub.addEventListener("click", fc, false);
|
||||
}
|
||||
subItemClick(e) {
|
||||
var p = e.target.closest(".a-option");
|
||||
if (p != null && !p.hasAttribute("data-empty")) {
|
||||
this.updateIndex(p.getAttribute("index"), true);
|
||||
this.dropdown.checkCloseDropdown();
|
||||
}
|
||||
}
|
||||
keyDown(ev) {
|
||||
var q = this.selectedEleItem;
|
||||
if (ev.keyCode == 40) {
|
||||
ev.preventDefault();
|
||||
this.changeSearch = true;
|
||||
var tmp = q.nextSibling;
|
||||
while (tmp != null && tmp.classList.contains("a-option-group")) {
|
||||
tmp = tmp.nextSibling;
|
||||
}
|
||||
if (tmp != null && tmp.classList.contains("a-option")) {
|
||||
this.updateIndex(tmp.getAttribute("index"));
|
||||
console.log(tmp.offsetTop);
|
||||
this.scroll.scrollIntoView(tmp, {
|
||||
alignToTop: false,
|
||||
offsetBottom: 0,
|
||||
onlyScrollIfNeeded: false
|
||||
});
|
||||
}
|
||||
}
|
||||
if (ev.keyCode == 38) {
|
||||
ev.preventDefault();
|
||||
this.changeSearch = true;
|
||||
var tmp = q.previousSibling;
|
||||
while (tmp != null && tmp.classList.contains("a-option-group")) {
|
||||
tmp = tmp.previousSibling;
|
||||
}
|
||||
if (tmp != null && tmp.classList.contains("a-option")) {
|
||||
this.updateIndex(tmp.getAttribute("index"));
|
||||
this.scroll.scrollIntoView(tmp, {
|
||||
offsetTop: 0,
|
||||
onlyScrollIfNeeded: false
|
||||
});
|
||||
}
|
||||
}
|
||||
if (ev.keyCode == 13 || ev.keyCode == 9) {
|
||||
if (ev.keyCode == 13) ev.preventDefault();
|
||||
this.changeSearch = true;
|
||||
if (this.eleSearch !== ev.currentTarget && this.isFocus) {
|
||||
return;
|
||||
}
|
||||
if (q.classList.contains("a-option")) {
|
||||
this.eleSearch.value = "";
|
||||
this.dropdown.checkCloseDropdown();
|
||||
this.updateIndex(this.selectedEleItem.getAttribute("index"), true);
|
||||
}
|
||||
}
|
||||
if (ev.keyCode == 8 && this.isMultiSelect) {
|
||||
if (this.eleSearch.value.length == 0) {
|
||||
if (this.multiSelectedItem.length > 0) {
|
||||
var t = this.cSelectedItem.querySelectorAll(".item:not(input)");
|
||||
this.removeItem(t[t.length - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
removeItem(ele) {
|
||||
var l = this.listItems[ele.getAttribute("data-id")].element;
|
||||
l.classList.remove("active");
|
||||
this.multiSelectedItem.removeItem(l, this.isItemEqual);
|
||||
ele.remove();
|
||||
}
|
||||
resetItem(f = true) {
|
||||
if (this.scrollSub.children.length == 0) return;
|
||||
this.scrollSub.removeAll();
|
||||
if (this.listGroups.length == 0) {
|
||||
for (var i = 0; i < this.listItems.length; i++) {
|
||||
this.scrollSub.appendChild(this.listItems[i].element);
|
||||
}
|
||||
}
|
||||
this.scroll.update(true);
|
||||
if (this.isMultiSelect && f) {
|
||||
var t = this.cSelectedItem.querySelectorAll(".item:not(input)");
|
||||
if (t.length > 0) {
|
||||
t.removeAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
inputSearchEvent(ev) {
|
||||
if (this.changeSearch) {
|
||||
this.changeSearch = false;
|
||||
return;
|
||||
}
|
||||
this.isTextSearch = true;
|
||||
this.scrollSub.removeAll();
|
||||
var first = null;
|
||||
if (this.listGroups.length == 0) {
|
||||
for (var i = 0; i < this.listItems.length; i++) {
|
||||
if (this.listItems[i].vSearch.toLowerCase().indexOf(ev.currentTarget.value.toLowerCase()) !== -1) {
|
||||
this.scrollSub.appendChild(this.listItems[i].element);
|
||||
first = (first == null) ? i : first;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*arr.sub.querySelectorAll(".a-option-group").forEach(e => e.parentNode.removeChild(e));
|
||||
for (var i = 0; i < arr.listEG.length; i++) {
|
||||
var d = document.createElement("div");
|
||||
d.classList.add("a-option-group");
|
||||
d.innerHTML = arr.listEG[i].label;
|
||||
arr.sub.appendChild(d);
|
||||
var c = true;
|
||||
for (var j = 0; j < arr.listEG[i].subitems.length; j++) {
|
||||
if (arr.listEG[i].subitems[j].name.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1) {
|
||||
c = false;
|
||||
var tmp = this.addItem(arr.listEG[i].subitems[j]);
|
||||
arr.sub.appendChild(tmp);
|
||||
first = (first == null) ? tmp : first;
|
||||
}
|
||||
}
|
||||
if (c) d.remove();
|
||||
}*/
|
||||
}
|
||||
if (first != null) {
|
||||
this.updateIndex(first);
|
||||
}
|
||||
else {
|
||||
var it = document.createElement("span");
|
||||
it.classList.add("ellipsis", "text-center");
|
||||
it.innerHTML = "No Result";
|
||||
var item = this.itemBaseUI(null, it);
|
||||
item.classList.add("d-f", "j-c-center");
|
||||
this.scrollSub.appendChild(item);
|
||||
item.setAttribute("data-empty", "");
|
||||
};
|
||||
|
||||
this.updateHeight();
|
||||
}
|
||||
}
|
||||
|
||||
export default class ASelect extends window.AObject {
|
||||
constructor(e) {
|
||||
super();
|
||||
this.listE = Array.from([]);
|
||||
this.listA = [];
|
||||
this.el = e;
|
||||
this.el.forEach((e) => {
|
||||
if (e.nodeName != "SELECT") {
|
||||
return;
|
||||
}
|
||||
this.listA.push(new ASelectEle(e, this.listA.length, this));
|
||||
});
|
||||
}
|
||||
get(id = 0) {
|
||||
if (id >= 0 && id < this.listA.length) {
|
||||
return this.listA[id];
|
||||
} else {
|
||||
console.log("error get Aselect");
|
||||
}
|
||||
}
|
||||
getByID(id) {
|
||||
for (var i = 0; i < this.listA.length; i++) {
|
||||
if (this.listA[i].element.getAttribute("id") == id) {
|
||||
return this.listA[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
TWASys-App/wwwroot/js/libs/js-ASidebar.js
Normal file
9
TWASys-App/wwwroot/js/libs/js-ASidebar.js
Normal file
@ -0,0 +1,9 @@
|
||||
export default class ASidebar extends window.AObject {
|
||||
constructor(o, areaRender) {
|
||||
super();
|
||||
this.sideBar = document.querySelector(nav);
|
||||
this.areaRender = document.querySelector(areaRender);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
9
TWASys-App/wwwroot/js/libs/js-ASlideBar.js
Normal file
9
TWASys-App/wwwroot/js/libs/js-ASlideBar.js
Normal file
@ -0,0 +1,9 @@
|
||||
import AOverlay from '/js/libs/js-AOverlay.js';
|
||||
export default class ASliderBar extends window.AObject {
|
||||
constructor(o) {
|
||||
super();
|
||||
this.overlay = new AOverlay(document.body);
|
||||
this.overlay.isCloseOverlay(false);
|
||||
this.overlay.createOverlay();
|
||||
}
|
||||
}
|
||||
87
TWASys-App/wwwroot/js/libs/js-ASpinButton.js
Normal file
87
TWASys-App/wwwroot/js/libs/js-ASpinButton.js
Normal file
@ -0,0 +1,87 @@
|
||||
export default class ASpinButton extends window.AObject {
|
||||
constructor(ev) {
|
||||
super();
|
||||
this.el = ev;
|
||||
if (ev instanceof NodeList) {
|
||||
this.el.forEach((e) => {
|
||||
this.init(e);
|
||||
});
|
||||
} else {
|
||||
this.init(ev);
|
||||
}
|
||||
|
||||
}
|
||||
init(e) {
|
||||
var pa = e.closest(".input-custom");
|
||||
var m = pa.querySelector(".minus");
|
||||
var p = pa.querySelector(".plus");
|
||||
var f = function (evt) {
|
||||
this.MinusEvent.call(this, evt, e);
|
||||
}.bind(this);
|
||||
m.addEventListener("click", f, false);
|
||||
var f1 = function (evt) {
|
||||
this.PlusEvent.call(this, evt, e);
|
||||
}.bind(this);
|
||||
p.addEventListener("click", f1, false);
|
||||
var f2 = function (evt) {
|
||||
this.InputChange.call(this, evt);
|
||||
}.bind(this);
|
||||
e.addEventListener("keyup", f2, false);
|
||||
e.value = e.getAttribute("default-value");
|
||||
}
|
||||
MinusEvent(e, inp) {
|
||||
inp.focus();
|
||||
if (inp.value == "") {
|
||||
inp.value = inp.getAttribute("default-value").toLocaleString("us-US");
|
||||
return;
|
||||
}
|
||||
var v = parseFloat(inp.value.replace(/[,]/g, ''));
|
||||
var step = parseFloat(inp.getAttribute("step-value"));
|
||||
var min = parseFloat(inp.getAttribute("min-value"));
|
||||
if ((v - step) < min) {
|
||||
return;
|
||||
} else {
|
||||
inp.value = (v - step).toLocaleString("us-US");
|
||||
}
|
||||
}
|
||||
PlusEvent(e, inp) {
|
||||
inp.focus();
|
||||
if (inp.value == "") {
|
||||
inp.value = inp.getAttribute("default-value").toLocaleString("us-US");
|
||||
return;
|
||||
}
|
||||
var v = parseFloat(inp.value.replace(/[,]/g, ''));
|
||||
var step = parseFloat(inp.getAttribute("step-value"));
|
||||
var max = parseFloat(inp.getAttribute("max-value"));
|
||||
if ((v + step) > max) {
|
||||
return;
|
||||
} else {
|
||||
inp.value = (v + step).toLocaleString("us-US");
|
||||
}
|
||||
}
|
||||
InputChange(e) {
|
||||
var selection = window.getSelection().toString();
|
||||
if (selection !== '') {
|
||||
return;
|
||||
}
|
||||
var arr = [38, 40, 37, 39];
|
||||
if (e.currentTarget.hasAttribute("floating-point")) arr.push(190);
|
||||
if (arr.includes(e.keyCode)) {
|
||||
return;
|
||||
}
|
||||
var step = parseFloat(e.currentTarget.getAttribute("step-value"));
|
||||
var max = parseFloat(e.currentTarget.getAttribute("max-value"));
|
||||
var min = parseFloat(e.currentTarget.getAttribute("min-value"));
|
||||
var input = e.currentTarget.value;
|
||||
var input = input.replace(/[^\d\.\-]+/g, "");
|
||||
input = parseFloat(input);
|
||||
if (input > max) {
|
||||
input = max;
|
||||
}
|
||||
if (input < min) {
|
||||
input = min
|
||||
}
|
||||
e.currentTarget.value = (e.currentTarget.value == "") ? "" : input.toLocaleString("us-US");
|
||||
|
||||
}
|
||||
}
|
||||
68
TWASys-App/wwwroot/js/libs/js-ATab.js
Normal file
68
TWASys-App/wwwroot/js/libs/js-ATab.js
Normal file
@ -0,0 +1,68 @@
|
||||
import AAnimation from '/js/libs/js-AAnimation.js'
|
||||
export default class ATab extends window.AObject {
|
||||
constructor(tabs, content, type = true) {
|
||||
super();
|
||||
this.selTab = null;
|
||||
this.lockTabs = Array.from([]);
|
||||
this.tabContents = content;
|
||||
this.setAnimation("Slide");
|
||||
this.ctabs = Array.from(this.tabContents.children);
|
||||
this.aAnimation = new AAnimation();
|
||||
this.aAnimation.setType(this.typeAnimation, { "parent": this.tabContents });
|
||||
this.type = type;
|
||||
if (type) {
|
||||
this.tabs = tabs.querySelectorAll(".item");
|
||||
this.tabs.forEach((e, i) => {
|
||||
if (e.classList.contains("active")) {
|
||||
// this.ctabs[i].classList.add("show");
|
||||
this.selectedTab(i);
|
||||
}
|
||||
|
||||
this.ctabs[i].classList.add("fade");
|
||||
e.addEventListener("click", this.eventTabClick.bind(this, e, i));
|
||||
});
|
||||
|
||||
} else {
|
||||
this.selectedTab(0);
|
||||
this.ctabs.forEach((el) => { el.classList.add("fade"); });
|
||||
}
|
||||
}
|
||||
setAnimation(type) {
|
||||
this.typeAnimation = type;
|
||||
}
|
||||
eventTabClick(e, num) {
|
||||
if (e.hasAttribute("disabled") || e.classList.contains("active")) {
|
||||
return;
|
||||
}
|
||||
this.selectedTab(num);
|
||||
}
|
||||
selectedTab(id) {
|
||||
if (this.selTab != null) {
|
||||
if (this.lockTabs.length > 0) {
|
||||
if (this.lockTabs.includes(this.selTab)){
|
||||
this.disableTab(this.selTab);
|
||||
}
|
||||
}
|
||||
if (this.type) this.tabs[this.selTab].classList.remove("active");
|
||||
this.aAnimation.element = this.ctabs[this.selTab];
|
||||
|
||||
this.aAnimation.once("endAnimation", (( ev) => { this.setTab(id); }).bind(this));
|
||||
this.aAnimation.animation();
|
||||
} else {
|
||||
this.setTab(id);
|
||||
}
|
||||
}
|
||||
setTab(id) {
|
||||
this.aAnimation.element = this.ctabs[id];
|
||||
this.aAnimation.animation();
|
||||
this.aAnimation.once("endAnimation", ((ev) => { this.trigger("changed", { "tabIndex": id }) }).bind(this));
|
||||
if (this.type) this.tabs[id].classList.add("active");
|
||||
this.selTab = id;
|
||||
}
|
||||
enableTab(id) {
|
||||
this.tabs[id].removeAttribute("disabled");
|
||||
}
|
||||
disableTab(id) {
|
||||
this.tabs[id].setAttribute("disabled", "");
|
||||
}
|
||||
}
|
||||
55
TWASys-App/wwwroot/js/libs/js-ATable.js
Normal file
55
TWASys-App/wwwroot/js/libs/js-ATable.js
Normal file
@ -0,0 +1,55 @@
|
||||
import AbsTable from '/js/libs/js-AbsTable.js'
|
||||
import APaging from '/js/libs/js-APaging.js'
|
||||
import AOverlay from '/js/libs/js-AOverlay.js'
|
||||
|
||||
export default class ATable extends AbsTable {
|
||||
constructor(e, pageSize = 5) {
|
||||
super(e);
|
||||
this.hForm = new FormData();
|
||||
this.absPaging = new APaging(e);
|
||||
this.aOverlay = new AOverlay(e);
|
||||
this.aOverlay.createOverlay();
|
||||
this.absPaging.pageSize = pageSize;
|
||||
this.absPaging.activePage = 1;
|
||||
this.absPaging.maxRow = -1;
|
||||
this.absPaging.on("PagingChange", ((e) => {
|
||||
this.SendData(false);
|
||||
}).bind(this));
|
||||
|
||||
}
|
||||
LoadDataUrl(url, first = true) {
|
||||
this.url = url;
|
||||
this.aOverlay.showOverlay();
|
||||
this.SendData(first);
|
||||
}
|
||||
SendData(first) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", this.url);
|
||||
var f = function (evt) {
|
||||
if (evt.currentTarget.readyState == 4 && evt.currentTarget.status == 200) {
|
||||
if (evt.currentTarget.responseText) {
|
||||
var o = JSON.parse(evt.currentTarget.responseText);
|
||||
if (o.mrows != null) {
|
||||
this.absPaging.SetPaging(o.mrows);
|
||||
}
|
||||
this.LoadData(o.data);
|
||||
this.aOverlay.removeOverlay();
|
||||
}
|
||||
}
|
||||
}.bind(this);
|
||||
xhr.addEventListener("readystatechange", f, false);
|
||||
var frm = new FormData();
|
||||
AddFormData(frm, "isFirstQuery", first);
|
||||
AddFormData(frm, "pageSize", this.absPaging.pageSize);
|
||||
AddFormData(frm, "pageNumber", this.absPaging.activePage);
|
||||
AddFormData(frm, "maxRow", this.absPaging.maxRow);
|
||||
xhr.send(frm);
|
||||
}
|
||||
RefreshPage(page, firstQ = false) {
|
||||
this.absPaging.activePage = page;
|
||||
this.SendData(firstQ);
|
||||
}
|
||||
RefreshCurrentPage(firstQ = false) {
|
||||
this.SendData(firstQ);
|
||||
}
|
||||
}
|
||||
41
TWASys-App/wwwroot/js/libs/js-ATransitionEffect.js
Normal file
41
TWASys-App/wwwroot/js/libs/js-ATransitionEffect.js
Normal file
@ -0,0 +1,41 @@
|
||||
export default class ATransitionEffect {
|
||||
constructor() { }
|
||||
collapsedEffect(e, c = null, maxHeight = null) {
|
||||
var height = (maxHeight == null || e.scrollHeight <= maxHeight) ? e.scrollHeight : maxHeight;
|
||||
var transition = e.style.transition;
|
||||
e.style.transition = '';
|
||||
requestAnimationFrame(function () {
|
||||
e.style.height = height + 'px';
|
||||
e.style.opacity = 1;
|
||||
e.style.transition = transition;
|
||||
requestAnimationFrame(function () {
|
||||
e.style.height = 0 + 'px';
|
||||
e.style.opacity = .3
|
||||
});
|
||||
});
|
||||
var f = function (ev) {
|
||||
if (ev.propertyName == "height") {
|
||||
ev.target.classList.remove('show');
|
||||
if (c != null) c.call();
|
||||
}
|
||||
ev.target.removeEventListener("transitionend", f, false);
|
||||
};
|
||||
e.addEventListener('transitionend', f, false);
|
||||
}
|
||||
expandEffect(e, c = null, maxHeight = null) {
|
||||
e.style.opacity = 1;
|
||||
e.style.height = ((maxHeight == null || e.scrollHeight <= maxHeight) ? e.scrollHeight : maxHeight) + 'px';
|
||||
var f = function (ev) {
|
||||
if (ev.propertyName == "height") {
|
||||
ev.target.classList.add("show");
|
||||
ev.target.style.height = null;
|
||||
if (c != null) c.call();
|
||||
ev.target.removeEventListener("transitionend", f, false);
|
||||
}
|
||||
}
|
||||
e.addEventListener('transitionend', f, false);
|
||||
}
|
||||
fadeEffect(e, c) {
|
||||
|
||||
}
|
||||
}
|
||||
120
TWASys-App/wwwroot/js/libs/js-AWizard.js
Normal file
120
TWASys-App/wwwroot/js/libs/js-AWizard.js
Normal file
@ -0,0 +1,120 @@
|
||||
import ATab from '/js/libs/js-ATab.js'
|
||||
|
||||
export default class AWizard extends ATab {
|
||||
constructor(content) {
|
||||
super(null, content, false);
|
||||
this.cPage = 0;
|
||||
this.isRender = false;
|
||||
this.isStopNextPage = false;
|
||||
this.layBtn = `<div class="form-group mb-4">
|
||||
<button type="button" class="btn btn-effect btn-primary mt-2 waves-effect waves-float d-f a-i-center btnNext">
|
||||
Next
|
||||
</button>
|
||||
</div>`;
|
||||
this.layBtn1 = `<div class="form-group d-f mb-4">
|
||||
<button type="button" class="btn btn-effect btn-primary mt-2 waves-effect waves-float d-f a-i-center btnNext">
|
||||
Next
|
||||
</button>
|
||||
<button type="button" class="btn btn-effect btn-primary mt-2 ml-2 waves-effect waves-float d-f a-i-center btnBack">
|
||||
Back
|
||||
</button>
|
||||
<button type="button" class="btn btn-effect btn-primary mt-2 ml-2 waves-effect waves-float d-f a-i-center btnCancel">
|
||||
Cancel
|
||||
</button>
|
||||
</div>`;
|
||||
this.layBtn2 = `<div class="form-group d-f mb-4">
|
||||
<button type="button" class="btn btn-effect btn-primary mt-2 waves-effect waves-float d-f a-i-center btnFinish">
|
||||
Finish
|
||||
</button>
|
||||
<button type="button" class="btn btn-effect btn-primary mt-2 ml-2 waves-effect waves-float d-f a-i-center btnBack">
|
||||
Back
|
||||
</button>
|
||||
<button type="button" class="btn btn-effect btn-primary mt-2 ml-2 waves-effect waves-float d-f a-i-center btnCancel">
|
||||
Cancel
|
||||
</button>
|
||||
</div>`;
|
||||
|
||||
}
|
||||
showPage(i) {
|
||||
this.cPage = i;
|
||||
this.ctabs[i].removeAttribute("hide");
|
||||
}
|
||||
hidePage(i) {
|
||||
this.ctabs[i].setAttribute("hide", "");
|
||||
this.cPage = -1;
|
||||
}
|
||||
nextPage(i) {
|
||||
if (this.isStopNextPage) return;
|
||||
this.selectedTab(i);
|
||||
}
|
||||
renderTab() {
|
||||
if (this.isRender) return;
|
||||
let l = this.ctabs.length;
|
||||
if (l > 1) {
|
||||
this.setLayout(0, this.layBtn);
|
||||
}
|
||||
if (l > 2) {
|
||||
for (var i = 1; i < l - 1; i++) {
|
||||
this.setLayout(i, this.layBtn1);
|
||||
}
|
||||
}
|
||||
this.setLayout(l - 1, this.layBtn2);
|
||||
|
||||
this.tabContents.querySelectorAll(".btnNext").forEach((el, idx) => {
|
||||
el.addEventListener("click", ((e) => { this.btnNext_Click(e, idx); }).bind(this));
|
||||
});
|
||||
this.tabContents.querySelectorAll(".btnBack").forEach((el, idx) => {
|
||||
el.addEventListener("click", ((e) => { this.btnBack_Click(e, idx); }).bind(this));
|
||||
});
|
||||
this.tabContents.querySelectorAll(".btnFinish").forEach((el) => {
|
||||
|
||||
});
|
||||
this.tabContents.querySelectorAll(".btnCancel").forEach((el) => {
|
||||
el.addEventListener("click", ((e) => { this.btnCancel_Click(e); }).bind(this));
|
||||
});
|
||||
this.isRender = true;
|
||||
}
|
||||
checkSelectedNext(idx) {
|
||||
while (idx + 1 < this.ctabs.length) {
|
||||
if (this.ctabs[idx + 1].hasAttribute("hide")) {
|
||||
idx += 1;
|
||||
} else {
|
||||
return idx + 1;
|
||||
}
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
checkSelectedBack(idx) {
|
||||
while (idx >= 0) {
|
||||
if (this.ctabs[idx].hasAttribute("hide")) {
|
||||
idx -= 1;
|
||||
} else {
|
||||
return idx;
|
||||
}
|
||||
};
|
||||
return idx;
|
||||
}
|
||||
setLayout(idx, layout) {
|
||||
this.ctabs[idx].insertAdjacentHTML('beforeend', layout);
|
||||
}
|
||||
setNameButton(id, name) {
|
||||
|
||||
}
|
||||
btnCancel_Click(e) {
|
||||
this.selectedTab(0);
|
||||
}
|
||||
btnNext_Click(e, idx) {
|
||||
this.trigger("onBeforeNext", { "currentPage": this.ctabs[idx], "indexPage": idx, "currentButton": e.currentTarget });
|
||||
if (this.isStopNextPage) return;
|
||||
console.log(idx);
|
||||
this.selectedTab(this.checkSelectedNext(idx));
|
||||
|
||||
this.trigger("onAfterNext");
|
||||
}
|
||||
btnBack_Click(e, idx) {
|
||||
this.selectedTab(this.checkSelectedBack(idx));
|
||||
}
|
||||
btnFinish_Click(e) {
|
||||
|
||||
}
|
||||
}
|
||||
199
TWASys-App/wwwroot/js/libs/js-AbsTable.js
Normal file
199
TWASys-App/wwwroot/js/libs/js-AbsTable.js
Normal file
@ -0,0 +1,199 @@
|
||||
export default class AbsTable extends window.AObject {
|
||||
constructor(e) {
|
||||
super();
|
||||
this.data = [];
|
||||
this.idCheckBox = 1;
|
||||
this.pElement = e;
|
||||
this.Headers = [];
|
||||
this.lSysRows = [];
|
||||
this.InitStructure();
|
||||
this.InitCss();
|
||||
this.SetIdCheckBox();
|
||||
}
|
||||
SetIdCheckBox() {
|
||||
if (window.nAbsTable == null) {
|
||||
window.nAbsTable = 1;
|
||||
} else {
|
||||
window.nAbsTable += 1;
|
||||
}
|
||||
}
|
||||
SetScrollBarY(height) {
|
||||
this.absContainerRows.style.height = height + "px";
|
||||
}
|
||||
AddHeader(name, width, minWidth, id = "", rowTemp = null) {
|
||||
var d = document.createElement("th");
|
||||
d.innerHTML = name;
|
||||
d.style.width = width;
|
||||
if (id != "") {
|
||||
d.setAttribute("header-id", id);
|
||||
}
|
||||
this.Headers.push({ "id": id, "nameCol": name, "element": d, "rowTemp": rowTemp });
|
||||
this.absHeaders.appendChild(d);
|
||||
if (width == "") {
|
||||
this.UpdateWidth(minWidth);
|
||||
} else {
|
||||
this.UpdateWidth(width);
|
||||
}
|
||||
|
||||
}
|
||||
UpdateWidth(width) {
|
||||
this.absTableH.style.minWidth = (parseInt(width) + parseInt(this.absTableH.style.minWidth == "" ? 0 : this.absTableH.style.minWidth)) + "px";
|
||||
this.absTable.style.minWidth = this.absTableH.style.minWidth;
|
||||
this.absContainerRows.style.minWidth = this.absTableH.style.minWidth;
|
||||
}
|
||||
AddRow(temp) {
|
||||
if (this.lSysRows.length > 0) {
|
||||
this.absRows.insertBefore(temp, this.lSysRows[0]);
|
||||
} else {
|
||||
this.absRows.appendChild(temp);
|
||||
}
|
||||
temp.querySelectorAll("td").forEach((o, i) => {
|
||||
o.style.width = this.Headers[i].element.style.width;
|
||||
});
|
||||
}
|
||||
AddSysRow(temp, id) {
|
||||
this.absRows.insertBefore(temp, this.absRows.nextSibling);
|
||||
this.lSysRows.push({ "id": id, "element": temp });
|
||||
}
|
||||
InitCss() {
|
||||
this.pElement.classList.add("abs-pContainer");
|
||||
this.absContainer.setAttribute("data-style", "default");
|
||||
this.absContainer.classList.add("abs-container");
|
||||
this.absScrollbar.classList.add("abs-scrollbar");
|
||||
this.absTable.classList.add("abs-table", "virtual");
|
||||
this.absTableH.classList.add("abs-table");
|
||||
}
|
||||
IsCheckBox(f) {
|
||||
this.isCheckBox = f;
|
||||
if (f) {
|
||||
var t = this.InitCheckBox("checkItemAll" + window.nAbsTable);
|
||||
this.UpdateWidth(65);
|
||||
this.absHeaders.insertBefore(t, this.absHeaders.children[0]);
|
||||
this.Headers.unshift({
|
||||
"id": "", "nameCol": "", "element": t, "rowTemp": (function (id, data) {
|
||||
this.idCheckBox += 1;
|
||||
return this.InitCheckBox(("checkEle" + window.nAbsTable) + (this.idCheckBox - 1), false).children[0];
|
||||
}).bind(this)
|
||||
});
|
||||
var cBox = this.absHeaders.querySelector("#checkItemAll" + window.nAbsTable);
|
||||
var evF = function (evt) {
|
||||
this.CheckAll_EvtHandler.call(this, evt);
|
||||
}.bind(this);
|
||||
|
||||
this.addSystemEvent("change", cBox, evF);
|
||||
var lTD = this.absRows.querySelectorAll("tr");
|
||||
lTD.forEach(u => {
|
||||
u.insertBefore(this.InitCheckBox(("checkEle" + window.nAbsTable) + idCheckBox, false), u.children[0]);
|
||||
this.idCheckBox += 1;
|
||||
});
|
||||
} else {
|
||||
var t = this.absHeaders.querySelector("#checkItemAll" + window.nAbsTable);
|
||||
if (t != null) {
|
||||
this.UpdateWidth(-65);
|
||||
this.removeEvent(t);
|
||||
var tm = this.Headers.shift();
|
||||
tm.element.remove();
|
||||
var lTD = this.absRows.querySelectorAll("tr");
|
||||
lTD.forEach(u => {
|
||||
u.children[0].remove();
|
||||
});
|
||||
this.idCheckBox = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
InitCheckBox(name, isHeader = true) {
|
||||
var td = document.createElement((isHeader) ? "th" : "td");
|
||||
var con = document.createElement("div");
|
||||
con.classList.add("custom-checkbox", "mr-0", "mt-auto", "mb-auto");
|
||||
var cb = document.createElement("input");
|
||||
cb.setAttribute("id", name);
|
||||
cb.setAttribute("type", "checkbox");
|
||||
var lb = document.createElement("label");
|
||||
lb.classList.add("a-checkbox-label");
|
||||
lb.setAttribute("for", name);
|
||||
if (isHeader) {
|
||||
td.style.width = "65px";
|
||||
} else {
|
||||
cb.setAttribute("rowCheck", "");
|
||||
}
|
||||
con.appendChild(cb);
|
||||
con.appendChild(lb);
|
||||
td.appendChild(con);
|
||||
return td
|
||||
}
|
||||
InitStructure() {
|
||||
this.absContainer = document.createElement("div");
|
||||
this.absScrollbar = document.createElement("div");
|
||||
this.absContainer.appendChild(this.absScrollbar);
|
||||
this.pElement.appendChild(this.absContainer);
|
||||
var options = {
|
||||
damping: 0.25,
|
||||
thumbMinSize: 5,
|
||||
renderByPixel: true,
|
||||
alwaysShowTracks: true,
|
||||
continuousScrolling: true,
|
||||
plugins: {
|
||||
overscroll: {
|
||||
effect: 'bounce',
|
||||
damping: 0.15,
|
||||
maxOverscroll: 80
|
||||
}
|
||||
}
|
||||
};
|
||||
window.Scrollbar.init(this.absScrollbar, options);
|
||||
this.absScrollbarCon = this.absScrollbar.querySelector(".scroll-content");
|
||||
this.absTableH = document.createElement("table");
|
||||
this.absTable = document.createElement("table");
|
||||
var d1 = document.createElement("thead");
|
||||
var d2 = document.createElement("tr");
|
||||
this.absTableH.appendChild(d1);
|
||||
this.absHeaders = d2;
|
||||
d1.appendChild(d2);
|
||||
|
||||
d1 = document.createElement("tbody");
|
||||
this.absTable.appendChild(d1);
|
||||
this.absRows = d1;
|
||||
this.absScrollbarCon.appendChild(this.absTableH);
|
||||
|
||||
|
||||
|
||||
var c = document.createElement("div");
|
||||
c.classList.add("atable-scroll");
|
||||
c.setAttribute("data-scrollbar", "");
|
||||
c.appendChild(this.absTable);
|
||||
this.absContainerRows = c;
|
||||
this.absScrollbarCon.appendChild(c);
|
||||
Scrollbar.init(this.absContainerRows, options);
|
||||
|
||||
}
|
||||
CheckAll_EvtHandler(e) {
|
||||
var listC = this.absRows.querySelectorAll("input[type=checkbox][rowCheck]");
|
||||
listC.forEach(el => {
|
||||
if (e.currentTarget.checked) {
|
||||
el.checked = true;
|
||||
} else {
|
||||
el.checked = false;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
LoadData(data) {
|
||||
this.absRows.innerHTML = "";
|
||||
this.data = JSON.parse(data);
|
||||
|
||||
this.data.forEach((e, i) => {
|
||||
var r = document.createElement("tr");
|
||||
r.setAttribute("data-id", i);
|
||||
this.Headers.forEach((o) => {
|
||||
var td = document.createElement("td");
|
||||
if (o.rowTemp != null) {
|
||||
td.appendChild(o.rowTemp(i, e));
|
||||
} else {
|
||||
td.innerHTML = e[o.id];
|
||||
}
|
||||
r.appendChild(td);
|
||||
});
|
||||
this.AddRow(r);
|
||||
});
|
||||
}
|
||||
}
|
||||
1299
TWASys-App/wwwroot/js/libs/js-core.js
Normal file
1299
TWASys-App/wwwroot/js/libs/js-core.js
Normal file
File diff suppressed because it is too large
Load Diff
75
TWASys-App/wwwroot/js/libs/js-upload-worker.js
Normal file
75
TWASys-App/wwwroot/js/libs/js-upload-worker.js
Normal file
@ -0,0 +1,75 @@
|
||||
var requestInterval = function (fn, delay) {
|
||||
if (!self.requestAnimationFrame &&
|
||||
!self.webkitRequestAnimationFrame &&
|
||||
!(self.mozRequestAnimationFrame && self.mozCancelRequestAnimationFrame) && // Firefox 5 ships without cancel support
|
||||
!self.oRequestAnimationFrame &&
|
||||
!self.msRequestAnimationFrame)
|
||||
return self.setInterval(fn, delay);
|
||||
|
||||
var start = new Date().getTime(),
|
||||
handle = new Object();
|
||||
|
||||
function loop() {
|
||||
var current = new Date().getTime(),
|
||||
delta = current - start;
|
||||
|
||||
if (delta >= delay) {
|
||||
fn.call();
|
||||
start = new Date().getTime();
|
||||
}
|
||||
|
||||
handle.value = self.requestAnimationFrame(loop);
|
||||
};
|
||||
|
||||
handle.value = self.requestAnimationFrame(loop);
|
||||
return handle;
|
||||
}
|
||||
var clearRequestInterval = function (handle) {
|
||||
self.cancelAnimationFrame ? self.cancelAnimationFrame(handle.value) :
|
||||
self.webkitCancelAnimationFrame ? self.webkitCancelAnimationFrame(handle.value) :
|
||||
self.webkitCancelRequestAnimationFrame ? self.webkitCancelRequestAnimationFrame(handle.value) : /* Support for legacy API */
|
||||
self.mozCancelRequestAnimationFrame ? self.mozCancelRequestAnimationFrame(handle.value) :
|
||||
self.oCancelRequestAnimationFrame ? self.oCancelRequestAnimationFrame(handle.value) :
|
||||
self.msCancelRequestAnimationFrame ? self.msCancelRequestAnimationFrame(handle.value) :
|
||||
clearInterval(handle);
|
||||
};
|
||||
|
||||
|
||||
var lpPop;
|
||||
var request;
|
||||
var count = 0;
|
||||
var f = function (e) {
|
||||
if (e.data != null) {
|
||||
if (e.data.status == "StartUpload") {
|
||||
request = e.data.totalF;
|
||||
}
|
||||
else if (e.data.status == "Uploaded")
|
||||
{
|
||||
var b = e.data.bucket;
|
||||
var flag = true;
|
||||
for (var i = 0; i < b.length; i++) {
|
||||
if (b[i] == 0) {
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
count += b.length;
|
||||
if (count == request) {
|
||||
self.postMessage("Uploaded");
|
||||
lpPop = requestInterval(function() {
|
||||
self.postMessage("Tick");
|
||||
}, 500);
|
||||
} else {
|
||||
self.postMessage("Upload");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.data.status == "NoItem")
|
||||
{
|
||||
clearRequestInterval(lpPop);
|
||||
self.postMessage("Finish");
|
||||
}
|
||||
}
|
||||
}
|
||||
self.addEventListener("message", f, false);
|
||||
|
||||
1049
TWASys-App/wwwroot/js/libs/js-upload.js
Normal file
1049
TWASys-App/wwwroot/js/libs/js-upload.js
Normal file
File diff suppressed because it is too large
Load Diff
537
TWASys-App/wwwroot/js/libs/js-waves.js
Normal file
537
TWASys-App/wwwroot/js/libs/js-waves.js
Normal file
@ -0,0 +1,537 @@
|
||||
/*!
|
||||
* Waves v0.7.6
|
||||
* http://fian.my.id/Waves
|
||||
*
|
||||
* Copyright 2014-2018 Alfiana E. Sibuea and other contributors
|
||||
* Released under the MIT license
|
||||
* https://github.com/fians/Waves/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
;(function(window, factory) {
|
||||
'use strict';
|
||||
|
||||
// AMD. Register as an anonymous module. Wrap in function so we have access
|
||||
// to root via `this`.
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], function() {
|
||||
window.Waves = factory.call(window);
|
||||
return window.Waves;
|
||||
});
|
||||
}
|
||||
|
||||
// Node. Does not work with strict CommonJS, but only CommonJS-like
|
||||
// environments that support module.exports, like Node.
|
||||
else if (typeof exports === 'object') {
|
||||
module.exports = factory.call(window);
|
||||
}
|
||||
|
||||
// Browser globals.
|
||||
else {
|
||||
window.Waves = factory.call(window);
|
||||
}
|
||||
})(typeof global === 'object' ? global : this, function() {
|
||||
'use strict';
|
||||
|
||||
var Waves = Waves || {};
|
||||
var $$ = document.querySelectorAll.bind(document);
|
||||
var toString = Object.prototype.toString;
|
||||
var isTouchAvailable = 'ontouchstart' in window;
|
||||
|
||||
|
||||
// Find exact position of element
|
||||
function isWindow(obj) {
|
||||
return obj !== null && obj === obj.window;
|
||||
}
|
||||
|
||||
function getWindow(elem) {
|
||||
return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;
|
||||
}
|
||||
|
||||
function isObject(value) {
|
||||
var type = typeof value;
|
||||
return type === 'function' || type === 'object' && !!value;
|
||||
}
|
||||
|
||||
function isDOMNode(obj) {
|
||||
return isObject(obj) && obj.nodeType > 0;
|
||||
}
|
||||
|
||||
function getWavesElements(nodes) {
|
||||
var stringRepr = toString.call(nodes);
|
||||
|
||||
if (stringRepr === '[object String]') {
|
||||
return $$(nodes);
|
||||
} else if (isObject(nodes) && /^\[object (Array|HTMLCollection|NodeList|Object)\]$/.test(stringRepr) && nodes.hasOwnProperty('length')) {
|
||||
return nodes;
|
||||
} else if (isDOMNode(nodes)) {
|
||||
return [nodes];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function offset(elem) {
|
||||
var docElem, win,
|
||||
box = { top: 0, left: 0 },
|
||||
doc = elem && elem.ownerDocument;
|
||||
|
||||
docElem = doc.documentElement;
|
||||
|
||||
if (typeof elem.getBoundingClientRect !== typeof undefined) {
|
||||
box = elem.getBoundingClientRect();
|
||||
}
|
||||
win = getWindow(doc);
|
||||
return {
|
||||
top: box.top + win.pageYOffset - docElem.clientTop,
|
||||
left: box.left + win.pageXOffset - docElem.clientLeft
|
||||
};
|
||||
}
|
||||
|
||||
function convertStyle(styleObj) {
|
||||
var style = '';
|
||||
|
||||
for (var prop in styleObj) {
|
||||
if (styleObj.hasOwnProperty(prop)) {
|
||||
style += (prop + ':' + styleObj[prop] + ';');
|
||||
}
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
var Effect = {
|
||||
|
||||
// Effect duration
|
||||
duration: 750,
|
||||
|
||||
// Effect delay (check for scroll before showing effect)
|
||||
delay: 200,
|
||||
|
||||
show: function(e, element, velocity) {
|
||||
|
||||
// Disable right click
|
||||
if (e.button === 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
element = element || this;
|
||||
|
||||
// Create ripple
|
||||
var ripple = document.createElement('div');
|
||||
ripple.className = 'waves-ripple waves-rippling';
|
||||
element.appendChild(ripple);
|
||||
|
||||
// Get click coordinate and element width
|
||||
var pos = offset(element);
|
||||
var relativeY = 0;
|
||||
var relativeX = 0;
|
||||
// Support for touch devices
|
||||
if('touches' in e && e.touches.length) {
|
||||
relativeY = (e.touches[0].pageY - pos.top);
|
||||
relativeX = (e.touches[0].pageX - pos.left);
|
||||
}
|
||||
//Normal case
|
||||
else {
|
||||
relativeY = (e.pageY - pos.top);
|
||||
relativeX = (e.pageX - pos.left);
|
||||
}
|
||||
// Support for synthetic events
|
||||
relativeX = relativeX >= 0 ? relativeX : 0;
|
||||
relativeY = relativeY >= 0 ? relativeY : 0;
|
||||
|
||||
var scale = 'scale(' + ((element.clientWidth / 100) * 3) + ')';
|
||||
var translate = 'translate(0,0)';
|
||||
|
||||
if (velocity) {
|
||||
translate = 'translate(' + (velocity.x) + 'px, ' + (velocity.y) + 'px)';
|
||||
}
|
||||
|
||||
// Attach data to element
|
||||
ripple.setAttribute('data-hold', Date.now());
|
||||
ripple.setAttribute('data-x', relativeX);
|
||||
ripple.setAttribute('data-y', relativeY);
|
||||
ripple.setAttribute('data-scale', scale);
|
||||
ripple.setAttribute('data-translate', translate);
|
||||
|
||||
// Set ripple position
|
||||
var rippleStyle = {
|
||||
top: relativeY + 'px',
|
||||
left: relativeX + 'px'
|
||||
};
|
||||
|
||||
ripple.classList.add('waves-notransition');
|
||||
ripple.setAttribute('style', convertStyle(rippleStyle));
|
||||
ripple.classList.remove('waves-notransition');
|
||||
|
||||
// Scale the ripple
|
||||
rippleStyle['-webkit-transform'] = scale + ' ' + translate;
|
||||
rippleStyle['-moz-transform'] = scale + ' ' + translate;
|
||||
rippleStyle['-ms-transform'] = scale + ' ' + translate;
|
||||
rippleStyle['-o-transform'] = scale + ' ' + translate;
|
||||
rippleStyle.transform = scale + ' ' + translate;
|
||||
rippleStyle.opacity = '1';
|
||||
|
||||
var duration = e.type === 'mousemove' ? 2500 : Effect.duration;
|
||||
rippleStyle['-webkit-transition-duration'] = duration + 'ms';
|
||||
rippleStyle['-moz-transition-duration'] = duration + 'ms';
|
||||
rippleStyle['-o-transition-duration'] = duration + 'ms';
|
||||
rippleStyle['transition-duration'] = duration + 'ms';
|
||||
|
||||
ripple.setAttribute('style', convertStyle(rippleStyle));
|
||||
},
|
||||
|
||||
hide: function(e, element) {
|
||||
element = element || this;
|
||||
|
||||
var ripples = element.getElementsByClassName('waves-rippling');
|
||||
|
||||
for (var i = 0, len = ripples.length; i < len; i++) {
|
||||
removeRipple(e, element, ripples[i]);
|
||||
}
|
||||
|
||||
if (isTouchAvailable) {
|
||||
element.removeEventListener('touchend', Effect.hide);
|
||||
element.removeEventListener('touchcancel', Effect.hide);
|
||||
}
|
||||
|
||||
element.removeEventListener('mouseup', Effect.hide);
|
||||
element.removeEventListener('mouseleave', Effect.hide);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Collection of wrapper for HTML element that only have single tag
|
||||
* like <input> and <img>
|
||||
*/
|
||||
var TagWrapper = {
|
||||
|
||||
// Wrap <input> tag so it can perform the effect
|
||||
input: function(element) {
|
||||
|
||||
var parent = element.parentNode;
|
||||
|
||||
// If input already have parent just pass through
|
||||
if (parent.tagName.toLowerCase() === 'i' && parent.classList.contains('waves-effect')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Put element class and style to the specified parent
|
||||
var wrapper = document.createElement('i');
|
||||
wrapper.className = element.className + ' waves-input-wrapper';
|
||||
element.className = 'waves-button-input';
|
||||
|
||||
// Put element as child
|
||||
parent.replaceChild(wrapper, element);
|
||||
wrapper.appendChild(element);
|
||||
|
||||
// Apply element color and background color to wrapper
|
||||
var elementStyle = window.getComputedStyle(element, null);
|
||||
var color = elementStyle.color;
|
||||
var backgroundColor = elementStyle.backgroundColor;
|
||||
|
||||
wrapper.setAttribute('style', 'color:' + color + ';background:' + backgroundColor);
|
||||
element.setAttribute('style', 'background-color:rgba(0,0,0,0);');
|
||||
|
||||
},
|
||||
|
||||
// Wrap <img> tag so it can perform the effect
|
||||
img: function(element) {
|
||||
|
||||
var parent = element.parentNode;
|
||||
|
||||
// If input already have parent just pass through
|
||||
if (parent.tagName.toLowerCase() === 'i' && parent.classList.contains('waves-effect')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Put element as child
|
||||
var wrapper = document.createElement('i');
|
||||
parent.replaceChild(wrapper, element);
|
||||
wrapper.appendChild(element);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the effect and remove the ripple. Must be
|
||||
* a separate function to pass the JSLint...
|
||||
*/
|
||||
function removeRipple(e, el, ripple) {
|
||||
|
||||
// Check if the ripple still exist
|
||||
if (!ripple) {
|
||||
return;
|
||||
}
|
||||
|
||||
ripple.classList.remove('waves-rippling');
|
||||
|
||||
var relativeX = ripple.getAttribute('data-x');
|
||||
var relativeY = ripple.getAttribute('data-y');
|
||||
var scale = ripple.getAttribute('data-scale');
|
||||
var translate = ripple.getAttribute('data-translate');
|
||||
|
||||
// Get delay beetween mousedown and mouse leave
|
||||
var diff = Date.now() - Number(ripple.getAttribute('data-hold'));
|
||||
var delay = 350 - diff;
|
||||
|
||||
if (delay < 0) {
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
if (e.type === 'mousemove') {
|
||||
delay = 150;
|
||||
}
|
||||
|
||||
// Fade out ripple after delay
|
||||
var duration = e.type === 'mousemove' ? 2500 : Effect.duration;
|
||||
|
||||
setTimeout(function() {
|
||||
|
||||
var style = {
|
||||
top: relativeY + 'px',
|
||||
left: relativeX + 'px',
|
||||
opacity: '0',
|
||||
|
||||
// Duration
|
||||
'-webkit-transition-duration': duration + 'ms',
|
||||
'-moz-transition-duration': duration + 'ms',
|
||||
'-o-transition-duration': duration + 'ms',
|
||||
'transition-duration': duration + 'ms',
|
||||
'-webkit-transform': scale + ' ' + translate,
|
||||
'-moz-transform': scale + ' ' + translate,
|
||||
'-ms-transform': scale + ' ' + translate,
|
||||
'-o-transform': scale + ' ' + translate,
|
||||
'transform': scale + ' ' + translate
|
||||
};
|
||||
|
||||
ripple.setAttribute('style', convertStyle(style));
|
||||
|
||||
setTimeout(function() {
|
||||
try {
|
||||
el.removeChild(ripple);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}, duration);
|
||||
|
||||
}, delay);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disable mousedown event for 500ms during and after touch
|
||||
*/
|
||||
var TouchHandler = {
|
||||
|
||||
/* uses an integer rather than bool so there's no issues with
|
||||
* needing to clear timeouts if another touch event occurred
|
||||
* within the 500ms. Cannot mouseup between touchstart and
|
||||
* touchend, nor in the 500ms after touchend. */
|
||||
touches: 0,
|
||||
|
||||
allowEvent: function(e) {
|
||||
var allow = true;
|
||||
if (/^(mousedown|mousemove)$/.test(e.type) && TouchHandler.touches) {
|
||||
allow = false;
|
||||
}
|
||||
|
||||
return allow;
|
||||
},
|
||||
registerEvent: function(e) {
|
||||
var eType = e.type;
|
||||
|
||||
if (eType === 'touchstart') {
|
||||
|
||||
TouchHandler.touches += 1; // push
|
||||
|
||||
} else if (/^(touchend|touchcancel)$/.test(eType)) {
|
||||
|
||||
setTimeout(function() {
|
||||
if (TouchHandler.touches) {
|
||||
TouchHandler.touches -= 1; // pop after 500ms
|
||||
}
|
||||
}, 500);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Delegated click handler for .waves-effect element.
|
||||
* returns null when .waves-effect element not in "click tree"
|
||||
*/
|
||||
function getWavesEffectElement(e) {
|
||||
|
||||
if (TouchHandler.allowEvent(e) === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var element = null;
|
||||
var target = e.target || e.srcElement;
|
||||
|
||||
while (target.parentElement) {
|
||||
if ( (!(target instanceof SVGElement)) && target.classList.contains('waves-effect')) {
|
||||
element = target;
|
||||
break;
|
||||
}
|
||||
target = target.parentElement;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bubble the click and show effect if .waves-effect elem was found
|
||||
*/
|
||||
function showEffect(e) {
|
||||
|
||||
// Disable effect if element has "disabled" property on it
|
||||
// In some cases, the event is not triggered by the current element
|
||||
// if (e.target.getAttribute('disabled') !== null) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
var element = getWavesEffectElement(e);
|
||||
if (element !== null) {
|
||||
|
||||
// Make it sure the element has either disabled property, disabled attribute or 'disabled' class
|
||||
if (element.disabled || element.getAttribute('disabled') || element.classList.contains('disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
TouchHandler.registerEvent(e);
|
||||
|
||||
if (e.type === 'touchstart' && Effect.delay) {
|
||||
|
||||
var hidden = false;
|
||||
|
||||
var timer = setTimeout(function () {
|
||||
timer = null;
|
||||
Effect.show(e, element);
|
||||
}, Effect.delay);
|
||||
|
||||
var hideEffect = function(hideEvent) {
|
||||
|
||||
// if touch hasn't moved, and effect not yet started: start effect now
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
Effect.show(e, element);
|
||||
}
|
||||
if (!hidden) {
|
||||
hidden = true;
|
||||
Effect.hide(hideEvent, element);
|
||||
}
|
||||
|
||||
removeListeners();
|
||||
};
|
||||
|
||||
var touchMove = function(moveEvent) {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
hideEffect(moveEvent);
|
||||
|
||||
removeListeners();
|
||||
};
|
||||
|
||||
element.addEventListener('touchmove', touchMove, false);
|
||||
element.addEventListener('touchend', hideEffect, false);
|
||||
element.addEventListener('touchcancel', hideEffect, false);
|
||||
|
||||
var removeListeners = function() {
|
||||
element.removeEventListener('touchmove', touchMove);
|
||||
element.removeEventListener('touchend', hideEffect);
|
||||
element.removeEventListener('touchcancel', hideEffect);
|
||||
};
|
||||
} else {
|
||||
|
||||
Effect.show(e, element);
|
||||
|
||||
if (isTouchAvailable) {
|
||||
element.addEventListener('touchend', Effect.hide, false);
|
||||
element.addEventListener('touchcancel', Effect.hide, false);
|
||||
}
|
||||
|
||||
element.addEventListener('mouseup', Effect.hide, false);
|
||||
element.addEventListener('mouseleave', Effect.hide, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Waves.init = function(options) {
|
||||
var body = document.body;
|
||||
|
||||
options = options || {};
|
||||
|
||||
if ('duration' in options) {
|
||||
Effect.duration = options.duration;
|
||||
}
|
||||
|
||||
if ('delay' in options) {
|
||||
Effect.delay = options.delay;
|
||||
}
|
||||
|
||||
if (isTouchAvailable) {
|
||||
body.addEventListener('touchstart', showEffect, false);
|
||||
body.addEventListener('touchcancel', TouchHandler.registerEvent, false);
|
||||
body.addEventListener('touchend', TouchHandler.registerEvent, false);
|
||||
}
|
||||
|
||||
body.addEventListener('mousedown', showEffect, false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Attach Waves to dynamically loaded inputs, or add .waves-effect and other
|
||||
* waves classes to a set of elements. Set drag to true if the ripple mouseover
|
||||
* or skimming effect should be applied to the elements.
|
||||
*/
|
||||
Waves.attach = function(elements, classes) {
|
||||
|
||||
elements = getWavesElements(elements);
|
||||
|
||||
if (toString.call(classes) === '[object Array]') {
|
||||
classes = classes.join(' ');
|
||||
}
|
||||
|
||||
classes = classes ? ' ' + classes : '';
|
||||
|
||||
var element, tagName;
|
||||
|
||||
for (var i = 0, len = elements.length; i < len; i++) {
|
||||
|
||||
element = elements[i];
|
||||
tagName = element.tagName.toLowerCase();
|
||||
|
||||
if (['input', 'img'].indexOf(tagName) !== -1) {
|
||||
TagWrapper[tagName](element);
|
||||
element = element.parentElement;
|
||||
}
|
||||
|
||||
if (element.className.indexOf('waves-effect') === -1) {
|
||||
element.className += ' waves-effect' + classes;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove all ripples from an element.
|
||||
*/
|
||||
Waves.calm = function(elements) {
|
||||
elements = getWavesElements(elements);
|
||||
var mouseup = {
|
||||
type: 'mouseup',
|
||||
button: 1
|
||||
};
|
||||
|
||||
for (var i = 0, len = elements.length; i < len; i++) {
|
||||
Effect.hide(mouseup, elements[i]);
|
||||
}
|
||||
};
|
||||
return Waves;
|
||||
});
|
||||
|
||||
window.AScript.set("js-waves", true);
|
||||
1
TWASys-App/wwwroot/js/libs/js-waves.min.js
vendored
Normal file
1
TWASys-App/wwwroot/js/libs/js-waves.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
TWASys-App/wwwroot/js/libs/js-waves.min.js.map
Normal file
1
TWASys-App/wwwroot/js/libs/js-waves.min.js.map
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user