Update 14/05/2025
This commit is contained in:
@ -11,7 +11,7 @@
|
||||
<title></title>
|
||||
<link rel="icon" type="image/x-icon" href="@Url.AbsoluteContent("~/images/logo/icon.png")" />
|
||||
<link rel="preload" as="script" href="@Url.AbsoluteContent("~/js/libs/js-core.js")">
|
||||
<link rel="preload" as="style" href="@Url.AbsoluteContent("~/css/atg-lib/atg-core.css")" />
|
||||
<link rel="preload" as="style" href="@Url.AbsoluteContent("~/css/atg-lib/atg-core.css")" onload="this.onload=null;" />
|
||||
</head>
|
||||
<body class="hp">
|
||||
<section data-scrollbar class="main-scrollbar">
|
||||
|
@ -1,5 +1,4 @@
|
||||
import AMenu from '/js/libs/js-AMenu.js'
|
||||
import AOverScroll from '/js/ext_libs/js-AOverScroll.js'
|
||||
import ALayout from '/js/libs/js-ALayout.js'
|
||||
|
||||
var asyncStyleSheets = [
|
||||
@ -7,10 +6,11 @@ var asyncStyleSheets = [
|
||||
'/css/atg-font/atg-admin-font.css'
|
||||
];
|
||||
window.app.loadCSS(asyncStyleSheets);
|
||||
window.isLoad_Menu = false;
|
||||
|
||||
class AsyncLayout extends ALayout {
|
||||
constructor() {
|
||||
super();
|
||||
this.isLoaded = false;
|
||||
this.layMNav = `<div class="m-header">
|
||||
<a app-nav href="${window.GetAbsoluteURL("/")}" class="c_logo d-f a-i-center c-a">
|
||||
<img src="/images/logo/logo.jpg" />
|
||||
@ -62,12 +62,22 @@ class AsyncLayout extends ALayout {
|
||||
})
|
||||
}
|
||||
dispose() {
|
||||
|
||||
this.isLoaded = false;
|
||||
var h = document.getElementById("header");
|
||||
var f = document.getElementById("footer");
|
||||
var h1 = document.getElementById("fHeader");
|
||||
document.querySelector(".m-header").remove();
|
||||
f.removeAll();
|
||||
h.removeAll();
|
||||
h1.remove();
|
||||
window.app.removeSytemEventParent(window.app.lName);
|
||||
window.app.removeCustomEventParent(window.app.lName);
|
||||
super.dispose();
|
||||
}
|
||||
renderMenu() {
|
||||
window.isLoad_Menu = true;
|
||||
this.isLoaded = true;
|
||||
this._createFHeader();
|
||||
window.app.initNavs();
|
||||
window.app.initNavs("Async");
|
||||
var hHeader = document.getElementById("header").clientHeight;
|
||||
var fHeader = document.getElementById("fHeader");
|
||||
|
||||
@ -83,10 +93,11 @@ class AsyncLayout extends ALayout {
|
||||
fHeader.classList.remove("show");
|
||||
}
|
||||
});
|
||||
this.addCustomEvent(idE0, window.app, "Asyc");
|
||||
this.addCustomEvent(idE0, window.app, "Async");
|
||||
var a1 = new AMenu("#header .nav-mainmenu", ".m-header", document.querySelectorAll(".m-navbar > .ico-menu"), true);
|
||||
|
||||
this.listAObject.add(a1);
|
||||
var a2 = new AMenu("#fHeader .nav-mainmenu", null, null);
|
||||
this.listAObject.add(a2);
|
||||
const idE1 = window.app.on("redirect_page", (e) => {
|
||||
a1.changeActive();
|
||||
a2.changeActive();
|
||||
@ -96,25 +107,9 @@ class AsyncLayout extends ALayout {
|
||||
window.app.initNavApp(window.GetAbsoluteURL("/Search"));
|
||||
}
|
||||
const btnMHeader = document.getElementById("btnMHeader");
|
||||
btnMHeader.addEventListener(this.eventName, f);
|
||||
this.addSystemEvent(this.eventName, f, )
|
||||
}
|
||||
hideMenu() {
|
||||
var h = document.getElementById("header");
|
||||
var f = document.getElementById("footer");
|
||||
var h1 = document.getElementById("fHeader");
|
||||
h.classList.add("d-n");
|
||||
f.classList.add("d-n");
|
||||
h1.classList.add("d-n");
|
||||
}
|
||||
showMenu() {
|
||||
var h = document.getElementById("header");
|
||||
var f = document.getElementById("footer");
|
||||
var h1 = document.getElementById("fHeader");
|
||||
h.classList.remove("d-n");
|
||||
f.classList.remove("d-n");
|
||||
h1.classList.remove("d-n");
|
||||
// btnMHeader.addEventListener(this.eventName, f);
|
||||
this.addSystemEvent(this.eventName, btnMHeader, f);
|
||||
}
|
||||
}
|
||||
|
||||
window.ALayout.set("Async", new AsyncLayout());
|
||||
window.AScript.set("asyncLayout", true);
|
@ -1,13 +1,29 @@
|
||||
import AMenu from '/js/libs/js-AMenu.js'
|
||||
import AOverScroll from '/js/ext_libs/js-AOverScroll.js'
|
||||
import ALayout from '/js/libs/js-ALayout.js'
|
||||
|
||||
|
||||
var asyncStyleSheets = [
|
||||
'https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap',
|
||||
'/css/atg-font/atg-admin-font.css'
|
||||
];
|
||||
window.app.loadCSS(asyncStyleSheets);
|
||||
window.isLoad_Menu = false;
|
||||
const layMNav = `<div class="m-header">
|
||||
|
||||
window.Load_Menu = function () {
|
||||
|
||||
//var a1 = new AMenu("#header .nav-mainmenu", ".m-header", document.querySelectorAll(".m-navbar > .ico-menu"), true);
|
||||
|
||||
//var a2 = new AMenu("#fHeader .nav-mainmenu", null, null);
|
||||
//console.log(document.getElementById("btnMHeader"));
|
||||
//document.getElementById("btnMHeader").addEventListener("click", (e) => {
|
||||
// window.app.initNavApp(window.GetAbsoluteURL("/Search"));
|
||||
//});
|
||||
|
||||
}
|
||||
class Async1Layout extends ALayout {
|
||||
constructor() {
|
||||
super();
|
||||
this.isLoaded = false;
|
||||
this.layMNav = `<div class="m-header">
|
||||
<a app-nav href="${window.GetAbsoluteURL("/")}" class="c_logo d-f a-i-center c-a">
|
||||
<img src="/images/logo/logo.jpg" />
|
||||
<span class="d-f no-wrap ml-2"><b class="lg">VIN</b> <b class="lg lg1">FONT</b></span>
|
||||
@ -19,8 +35,7 @@ const layMNav = `<div class="m-header">
|
||||
</div>
|
||||
|
||||
</div>`;
|
||||
|
||||
const fHeader = `<div id="fHeader" class="f-header">
|
||||
this.fHeader = `<div id="fHeader" class="f-header">
|
||||
<div class="cfull">
|
||||
<div class="c_search_header d-f a-i-center j-c-between">
|
||||
<div class="c_filter c-6 c-s-4 c-l-2">
|
||||
@ -53,45 +68,35 @@ const fHeader = `<div id="fHeader" class="f-header">
|
||||
|
||||
</div>
|
||||
</div>`;
|
||||
function createFHeader() {
|
||||
document.body.insertAdjacentHTML("afterbegin", layMNav);
|
||||
document.body.insertAdjacentHTML("afterbegin", fHeader);
|
||||
}
|
||||
_createFHeader() {
|
||||
document.body.insertAdjacentHTML("afterbegin", this.layMNav);
|
||||
document.body.insertAdjacentHTML("afterbegin", this.fHeader);
|
||||
var h = document.querySelector("#fHeader .nav-mainmenu");
|
||||
var h2 = document.querySelector(".m-header");
|
||||
var he2 = h2.querySelector(".nav-mainmenu");
|
||||
var r = document.querySelector("#header");
|
||||
//r.querySelector(".nav-mainmenu").childNodes.forEach(el => {
|
||||
// he2.appendChild(el.cloneNode(true));
|
||||
// h.appendChild(el.cloneNode(true));
|
||||
//})
|
||||
}
|
||||
|
||||
window.Hide_Menu = function () {
|
||||
dispose() {
|
||||
this.isLoaded = false;
|
||||
var h = document.getElementById("header");
|
||||
var f = document.getElementById("footer");
|
||||
var h1 = document.getElementById("fHeader");
|
||||
h.classList.add("d-n");
|
||||
f.classList.add("d-n");
|
||||
h1.classList.add("d-n");
|
||||
document.querySelector(".m-header").remove();
|
||||
f.removeAll();
|
||||
h.removeAll();
|
||||
h1.remove();
|
||||
window.app.removeSytemEventParent(window.app.lName);
|
||||
window.app.removeCustomEventParent(window.app.lName);
|
||||
super.dispose();
|
||||
}
|
||||
window.Show_Menu = function () {
|
||||
var h = document.getElementById("header");
|
||||
var f = document.getElementById("footer");
|
||||
var h1 = document.getElementById("fHeader");
|
||||
h.classList.remove("d-n");
|
||||
f.classList.remove("d-n");
|
||||
h1.classList.remove("d-n");
|
||||
}
|
||||
window.Load_Menu = function () {
|
||||
window.isLoad_Menu = true;
|
||||
window.app.on("redirect_page", (e) => {
|
||||
a1.changeActive();
|
||||
});
|
||||
createFHeader();
|
||||
window.app.initNavs();
|
||||
renderMenu() {
|
||||
this.isLoaded = true;
|
||||
this._createFHeader();
|
||||
window.app.initNavs("Async1");
|
||||
var hHeader = document.getElementById("header").clientHeight;
|
||||
var fHeader = document.getElementById("fHeader");
|
||||
var plScr = new AOverScroll();
|
||||
|
||||
if (window.getOS() == "iOS") {
|
||||
fHeader.classList.add("ios");
|
||||
}
|
||||
@ -104,13 +109,23 @@ window.Load_Menu = function () {
|
||||
fHeader.classList.remove("show");
|
||||
}
|
||||
});
|
||||
//this.addCustomEvent(idE0, window.app, "Async1");
|
||||
//var a1 = new AMenu("#header .nav-mainmenu", ".m-header", document.querySelectorAll(".m-navbar > .ico-menu"), true);
|
||||
|
||||
//var a2 = new AMenu("#fHeader .nav-mainmenu", null, null);
|
||||
//console.log(document.getElementById("btnMHeader"));
|
||||
//document.getElementById("btnMHeader").addEventListener("click", (e) => {
|
||||
// window.app.initNavApp(window.GetAbsoluteURL("/Search"));
|
||||
//const idE1 = window.app.on("redirect_page", (e) => {
|
||||
// a1.changeActive();
|
||||
// a2.changeActive();
|
||||
//});
|
||||
//this.addCustomEvent(idE1, window.app, "Async");
|
||||
//const f = function (e) {
|
||||
// window.app.initNavApp(window.GetAbsoluteURL("/Search"));
|
||||
//}
|
||||
//const btnMHeader = document.getElementById("btnMHeader");
|
||||
//// btnMHeader.addEventListener(this.eventName, f);
|
||||
//this.addSystemEvent(this.eventName, btnMHeader, f);
|
||||
}
|
||||
|
||||
}
|
||||
window.ALayout.set("Async1", new Async1Layout());
|
||||
window.AScript.set("asyncLayout1", true);
|
@ -1,6 +1,6 @@
|
||||
export default class ALayout extends window.AObject {
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
}
|
||||
renderMenu(){
|
||||
|
||||
|
@ -70,8 +70,13 @@ export default class AMenu extends window.AObject {
|
||||
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;
|
||||
|
||||
|
@ -205,6 +205,7 @@ window.AObject = class {
|
||||
this.systemEvents = new Map();
|
||||
this.customEvents = new Map();
|
||||
this.parentEventMap = new Map();
|
||||
this.listAObject = new Set();
|
||||
this.eventName = window.getPrimaryPointerEvent();
|
||||
}
|
||||
|
||||
@ -321,10 +322,13 @@ window.AObject = class {
|
||||
element.removeEventListener(event, callback, false);
|
||||
}
|
||||
}
|
||||
for (const [id, evM] of this.customEvents.entries()) {
|
||||
|
||||
for (const [id, obj] of this.customEvents.entries()) {
|
||||
obj.ele.offById(id);
|
||||
}
|
||||
|
||||
for (const id of this.listAObject) {
|
||||
id.dispose();
|
||||
}
|
||||
this.listAObject.clear();
|
||||
this.systemEvents.clear();
|
||||
this.parentEventMap.clear();
|
||||
|
||||
@ -362,35 +366,47 @@ window.AObject = class {
|
||||
removeSytemEventParent(parent) {
|
||||
const entries = this.parentEventMap.get(parent);
|
||||
if (!entries) return;
|
||||
|
||||
for (const { element, event } of entries) {
|
||||
let iC = 0;
|
||||
for (const { element, eventName } of entries) {
|
||||
const eventMap = this.systemEvents.get(element);
|
||||
if (eventMap) {
|
||||
const data = eventMap.get(event);
|
||||
const data = eventMap.get(eventName);
|
||||
|
||||
if (data && typeof data.callback === 'function') {
|
||||
element.removeEventListener(event, data.callback, false);
|
||||
eventMap.delete(event);
|
||||
element.removeEventListener(eventName , data.callback, false);
|
||||
eventMap.delete(eventName);
|
||||
// Nếu element không còn event nào, xóa khỏi systemEvents
|
||||
if (eventMap.size === 0) {
|
||||
this.systemEvents.delete(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
this.parentEventMap.delete(parent);
|
||||
}
|
||||
removeCustomEventParent(parent) {
|
||||
const entries = this.parentEventMap.get("Custom" + parent);
|
||||
if (!entries) return;
|
||||
for (const { id, element } of entries) {
|
||||
const eventMap = this.customEvents.get(id);
|
||||
if (eventMap) {
|
||||
eventMap.ele.offById(eventMap.id);
|
||||
this.customEvents.delete(id);
|
||||
}
|
||||
|
||||
}
|
||||
this.parentEventMap.delete(parent);
|
||||
}
|
||||
addCustomEvent(id, element, groups = null) {
|
||||
if (!this.customEvents.has(id)) {
|
||||
this.customEvents.set(id, new Set());
|
||||
|
||||
this.customEvents.set(id, { "ele":element, "groups":groups });
|
||||
}
|
||||
const eventMap = this.customEvents.get(id);
|
||||
eventMap.add(element, groups);
|
||||
if (groups) {
|
||||
if (!this.parentEventMap.has("Custom" + parent)) {
|
||||
this.parentEventMap.set(("Custom" + parent, new Set());
|
||||
this.parentEventMap.set("Custom" + parent, new Map());
|
||||
}
|
||||
this.parentEventMap.get("Custom" + parent).add({ id, element });
|
||||
this.parentEventMap.get("Custom" + parent).set(id, element);
|
||||
}
|
||||
|
||||
}
|
||||
@ -509,9 +525,9 @@ class AApp extends window.AObject {
|
||||
constructor(container = '[app-content]') {
|
||||
super();
|
||||
this.cachePage = new CacheManager();
|
||||
this.currentLay = null;
|
||||
this.isLoadedLayout = false;
|
||||
window.Destroy = undefined;
|
||||
window.ALayout = new Map();
|
||||
this.isRedirectPage = false;
|
||||
this.metaPage = document.head.querySelector("meta[name=idPage]");
|
||||
this.pageName = this.metaPage.getAttribute("pageName");
|
||||
@ -520,45 +536,40 @@ class AApp extends window.AObject {
|
||||
this.mainApp = tmp.querySelector("[main-content]") ? tmp.querySelector("[main-content]") : tmp;
|
||||
var f = function (ev) {
|
||||
if (ev.state) {
|
||||
const obj = this.cachePage.get(ev.state.url);
|
||||
this.loadContentPage(obj.html);
|
||||
this.metaPage.content = obj.idPage;
|
||||
this.metaPage.setAttribute("isLayout", obj.isLayout);
|
||||
this.cachePage.get(ev.state.url, ((result) => {
|
||||
if (result == null) {
|
||||
|
||||
} else {
|
||||
this.loadContentPage(result.html);
|
||||
this.metaPage.content = result.idPage;
|
||||
this.metaPage.setAttribute("isLayout", result.isLayout);
|
||||
this.trigger("redirect_page", ev.state);
|
||||
//this.checkLayout(obj.isLayout);
|
||||
this.checkLayout(result.lName);
|
||||
var l = new LoadScriptAsync("Page");
|
||||
l.processScript(obj.doc);
|
||||
l.processScript(result.doc);
|
||||
l.on("Loaded", (() => {
|
||||
this.loadedPage();
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
}).bind(this));
|
||||
}
|
||||
}.bind(this);
|
||||
window.addEventListener("popstate", f);
|
||||
}
|
||||
checkLayout(lName) {
|
||||
//if ((this.isDispLay && isLayout) == false) {
|
||||
// if (isLayout) {
|
||||
// if (window.isLoad_Menu) {
|
||||
// window.Show_Menu();
|
||||
// } else {
|
||||
// this.renderLayout();
|
||||
// }
|
||||
// } else /*display =true -> layout false */ {
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
//}
|
||||
//this.isDispLay = isLayout;
|
||||
if (lName === "None") {
|
||||
window.Hide_Menu();
|
||||
} else {
|
||||
this.renderLayout();
|
||||
if (this.lName !== lName) {
|
||||
if (this.lName !== "None") {
|
||||
const l = window.ALayout.get(this.lName);
|
||||
l.dispose();
|
||||
}
|
||||
this.callLoadLayout(lName);
|
||||
this.lName = lName;
|
||||
}
|
||||
}
|
||||
render() {
|
||||
if (this.lName !== "None") {
|
||||
this.renderLayout();
|
||||
this.callLoadLayout(this.lName);
|
||||
} else {
|
||||
this.isLoadedLayout = true;
|
||||
}
|
||||
@ -576,47 +587,7 @@ class AApp extends window.AObject {
|
||||
this.callLoadPage(window.location.href);
|
||||
}).bind(this)();
|
||||
}
|
||||
renderLayout() {
|
||||
(function () {
|
||||
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", this.addAttributeURL(window.location.href, "?vr=lAsync"));
|
||||
xhr.send();
|
||||
var f = function (evt) {
|
||||
if (evt.currentTarget.readyState == 4 && evt.currentTarget.status == 200) {
|
||||
if (evt.currentTarget.responseText) {
|
||||
var jP = JSON.parse(evt.currentTarget.responseText);
|
||||
this.loadLayout(jP, window.location.href);
|
||||
}
|
||||
}
|
||||
}.bind(this);
|
||||
xhr.addEventListener("readystatechange", f, false);
|
||||
}).bind(this)();
|
||||
}
|
||||
loadedPage() {
|
||||
this.metaPage = document.head.querySelector("meta[name=idPage]");
|
||||
if (this.metaPage != null && this.isLoadedLayout) {
|
||||
const tmp = this.cachePage.getInf(window.location.href);
|
||||
if (tmp != null && tmp.dynamicF != null) {
|
||||
|
||||
if (window[tmp.dynamicF] != null) window[tmp.dynamicF]();
|
||||
} else {
|
||||
if (window["L" + this.metaPage.content] != null) window["L" + this.metaPage.content]();
|
||||
}
|
||||
this.initNavs(this.metaPage.content);
|
||||
this.trigger("pageLoaded", null);
|
||||
} else {
|
||||
window.requestTimeout(this.loadedPage.bind(this), 10, window.registerCancel);
|
||||
}
|
||||
}
|
||||
loadedLayout() {
|
||||
if (!window.isLoad_Menu) {
|
||||
window.Load_Menu();
|
||||
this.isLoadedLayout = true;
|
||||
}
|
||||
this.trigger("layoutLoaded", null);
|
||||
}
|
||||
scrollTop() {
|
||||
return window.scrollY || window.smScroll.scrollTop;
|
||||
}
|
||||
@ -686,15 +657,15 @@ class AApp extends window.AObject {
|
||||
this.callLoadPage(window.GetAbsoluteURL(t));
|
||||
}
|
||||
callLoadPage(url) {
|
||||
const page = this.cachePage.get(url);
|
||||
if (page) {
|
||||
this.setContentPage(page, url); // Set content page từ cache
|
||||
this.cachePage.get(url, ((result) => {
|
||||
if (result) {
|
||||
this.setContentPage(result, url); // Set content page từ cache
|
||||
} else {
|
||||
console.log("connect new");
|
||||
this.getPage(url); // Load mới nếu chưa có trong cache
|
||||
}
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
loadContentPage(content) {
|
||||
const tpl = document.createElement('template');
|
||||
tpl.innerHTML = content;
|
||||
@ -707,18 +678,17 @@ class AApp extends window.AObject {
|
||||
document.title = page.title + " - " + this.pageName;
|
||||
var meta = document.head.querySelector("meta[name=idPage]");
|
||||
meta.content = page.idPage;
|
||||
|
||||
this.checkLayout(page.lName);
|
||||
meta.setAttribute("layName", page.lName);
|
||||
|
||||
this.loadContentPage(page.html);
|
||||
window.history.pushState({"url":url}, page.title, url);
|
||||
}
|
||||
setContentPage(page, url) {
|
||||
|
||||
this.contentPage(page, url);
|
||||
var l = new LoadScriptAsync("Page");
|
||||
if (this.isRedirectPage) {
|
||||
this.trigger("redirect_page", page);
|
||||
this.checkLayout(page.lName);
|
||||
this.isRedirectPage = false;
|
||||
}
|
||||
l.on("Loaded", (() => {
|
||||
@ -740,7 +710,83 @@ class AApp extends window.AObject {
|
||||
}.bind(this);
|
||||
xhr.addEventListener("readystatechange", f, false);
|
||||
}
|
||||
loadLayout(o, url) {
|
||||
loadPage(o, url) {
|
||||
const title = o.Title;
|
||||
const idPage = o.PageId;
|
||||
const doc2 = new DOMParser().parseFromString(o.Scripts, "text/html");
|
||||
const doc = doc2.firstChild.querySelector("head");
|
||||
const dF = doc.querySelector("script[dynamic]");
|
||||
const obj = {
|
||||
html: o.Content,
|
||||
title: title,
|
||||
idPage: idPage,
|
||||
lName: o.LayoutName,
|
||||
doc: doc,
|
||||
dynamicF: dF ? dF.getAttribute("dynamic") : null
|
||||
};
|
||||
this.cachePage.set(url, obj);
|
||||
this.setContentPage(obj, url);
|
||||
}
|
||||
loadedPage() {
|
||||
this.metaPage = document.head.querySelector("meta[name=idPage]");
|
||||
if (this.metaPage != null && this.isLoadedLayout) {
|
||||
this.cachePage.getInf(window.location.href, ((tmp) => {
|
||||
if (tmp != null && tmp.dynamicF != null) {
|
||||
|
||||
if (window[tmp.dynamicF] != null) window[tmp.dynamicF]();
|
||||
} else {
|
||||
if (window["L" + this.metaPage.content] != null) window["L" + this.metaPage.content]();
|
||||
}
|
||||
this.initNavs(this.metaPage.content);
|
||||
this.trigger("pageLoaded", null);
|
||||
}).bind(this));
|
||||
|
||||
} else {
|
||||
window.requestTimeout(this.loadedPage.bind(this), 10, window.registerCancel);
|
||||
}
|
||||
}
|
||||
callLoadLayout(lName) {
|
||||
this.cachePage.get(lName, ((result) => {
|
||||
if (result) {
|
||||
this.setLayout(result); // Set content page từ cache
|
||||
} else {
|
||||
console.log("connect new Layout");
|
||||
this.loadLayout(); // Load mới nếu chưa có trong cache
|
||||
}
|
||||
|
||||
}).bind(this), "layout");
|
||||
|
||||
}
|
||||
loadLayout() {
|
||||
(function () {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", this.addAttributeURL(window.location.href, "?vr=lAsync"));
|
||||
xhr.send();
|
||||
var f = function (evt) {
|
||||
if (evt.currentTarget.readyState == 4 && evt.currentTarget.status == 200) {
|
||||
if (evt.currentTarget.responseText) {
|
||||
var jP = JSON.parse(evt.currentTarget.responseText);
|
||||
this.setLayout(jP);
|
||||
this.cachePage.set(this.lName, jP, "layout");
|
||||
}
|
||||
}
|
||||
}.bind(this);
|
||||
xhr.addEventListener("readystatechange", f, false);
|
||||
}).bind(this)();
|
||||
}
|
||||
loadedLayout() {
|
||||
if (this.lName !== "None") {
|
||||
const l = window.ALayout.get(this.lName);
|
||||
if (!l.isLoaded) {
|
||||
console.log("render M");
|
||||
l.renderMenu();
|
||||
this.isLoadedLayout = true;
|
||||
this.trigger("layoutLoaded", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
setLayout(o) {
|
||||
|
||||
var oP = new DOMParser();
|
||||
var pHtml = oP.parseFromString(o.Content, 'text/html');
|
||||
(function () {
|
||||
@ -765,22 +811,6 @@ class AApp extends window.AObject {
|
||||
l.processScript(doc);
|
||||
}).bind(this)();
|
||||
}
|
||||
loadPage(o, url) {
|
||||
const title = o.Title;
|
||||
const idPage = o.PageId;
|
||||
const doc2 = new DOMParser().parseFromString(o.Scripts, "text/html");
|
||||
const doc = doc2.firstChild.querySelector("head");
|
||||
const dF = doc.querySelector("script[dynamic]");
|
||||
const obj = {
|
||||
html: o.Content,
|
||||
title: title,
|
||||
idPage: idPage,
|
||||
doc: doc,
|
||||
dynamicF: dF ? dF.getAttribute("dynamic"):null
|
||||
};
|
||||
this.cachePage.set(url, obj);
|
||||
this.setContentPage(obj, url);
|
||||
}
|
||||
loadCSS(arr) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var link = document.createElement('link');
|
||||
@ -791,91 +821,258 @@ class AApp extends window.AObject {
|
||||
}
|
||||
}
|
||||
class CacheManager {
|
||||
constructor(prefix = "cache") {
|
||||
this.prefix = prefix;
|
||||
this.pageMap = new Map(); // Chứa key URL → idPage
|
||||
this.layoutMap = new Map(); // Chứa key idLayout → true
|
||||
this._loadFromStorage();
|
||||
constructor() {
|
||||
this.storage = new CacheStorage("appCache");
|
||||
this.pageMap = new Map();
|
||||
this.layoutMap = new Map();
|
||||
this.readyCallbacks = [];
|
||||
this.isReady = false;
|
||||
|
||||
this._loadIndex();
|
||||
}
|
||||
|
||||
|
||||
_key(id, type = "page") {
|
||||
return `${this.prefix}|;${type}|;${id}`;
|
||||
return `${type}|${id}`;
|
||||
}
|
||||
_loadFromStorage() {
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (!key.startsWith(this.prefix)) continue;
|
||||
|
||||
const [_, type, id] = key.split("|;");
|
||||
_onReady(callback) {
|
||||
if (this.isReady) {
|
||||
callback();
|
||||
} else {
|
||||
this.readyCallbacks.push(callback);
|
||||
}
|
||||
}
|
||||
|
||||
_loadIndex() {
|
||||
this.storage.getAllKeys(((keys) => {
|
||||
let pending = 0;
|
||||
keys.forEach(((key) => {
|
||||
if (!key.startsWith(`${this.storage.prefix}|`)) return;
|
||||
|
||||
const shortKey = key.replace(`${this.storage.prefix}|`, "");
|
||||
const [type, id] = shortKey.split("|");
|
||||
|
||||
if (type === "pI") {
|
||||
try {
|
||||
const raw = JSON.parse(localStorage.getItem(key));
|
||||
if (raw) {
|
||||
this.pageMap.set(id, raw);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Error parsing cached page:", e);
|
||||
}
|
||||
pending++;
|
||||
this.storage.get(key, (data) => {
|
||||
if (data) this.pageMap.set(id, data);
|
||||
if (--pending === 0) this._finishInit();
|
||||
}, true);
|
||||
} else if (type === "layout") {
|
||||
this.layoutMap.set(id, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
getInf(id, type = "page") {
|
||||
if (type === "page") {
|
||||
return this.pageMap.get(id);
|
||||
}
|
||||
else {
|
||||
return this.layoutMap.get(id);
|
||||
}
|
||||
}
|
||||
// Lấy dữ liệu theo URL hoặc ID
|
||||
get(id, type = "page") {
|
||||
try {
|
||||
if ((type === "page" && !this.pageMap.has(id)) || (type === "layout" && !this.layoutMap.has(id))) {
|
||||
return null; // Nếu không có trong Map thì coi như không tồn tại
|
||||
}).bind(this));
|
||||
if (pending === 0) this._finishInit(); // Trường hợp không có key nào là "pI"
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
const raw = localStorage.getItem(this._key(id, type));
|
||||
if (!raw) return null;
|
||||
_finishInit() {
|
||||
this.isReady = true;
|
||||
this.readyCallbacks.forEach(cb => cb());
|
||||
this.readyCallbacks = [];
|
||||
}
|
||||
|
||||
const parsed = JSON.parse(raw);
|
||||
parsed.doc = new DOMParser().parseFromString(parsed.doc, "text/html").head;
|
||||
// Lấy thông tin trang hoặc layout
|
||||
getInf(id, callback, type = "page") {
|
||||
this._onReady(() => {
|
||||
(type === "page") ? callback(this.pageMap.get(id)) : callback(this.layoutMap.get(id));
|
||||
});
|
||||
}
|
||||
|
||||
// Lấy dữ liệu từ cache (localStorage hoặc IndexedDB nếu cần)
|
||||
get(id, callback, type = "page") {
|
||||
this._onReady(() => {
|
||||
const key = this._key(id, type);
|
||||
this.storage.get(key, (data) => {
|
||||
if (!data) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "page") {
|
||||
return Object.assign(parsed, this.pageMap.get(id), { url: id });
|
||||
const pInfo = this.pageMap.get(id);
|
||||
if (!pInfo) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
data.doc = new DOMParser().parseFromString(data.doc, "text/html").head;
|
||||
callback(Object.assign(data, pInfo, { url: id }));
|
||||
} else {
|
||||
return parsed;
|
||||
callback(data);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Cache parse error:", e);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
// Lưu dữ liệu page/layout theo ID
|
||||
set(id, obj, type = "page") {
|
||||
try {
|
||||
const clone = {};
|
||||
|
||||
// Lưu dữ liệu page hoặc layout vào cache
|
||||
set(id, obj, type = "page", callback) {
|
||||
this._onReady(() => {
|
||||
const key = this._key(id, type);
|
||||
|
||||
if (type === "page") {
|
||||
clone.html = obj.html;
|
||||
clone.doc = obj.doc.innerHTML;
|
||||
const pI = {
|
||||
const htmlData = {
|
||||
html: obj.html,
|
||||
doc: obj.doc.innerHTML
|
||||
};
|
||||
|
||||
// Lưu dữ liệu htmlData vào storage
|
||||
this.storage.set(key, htmlData, function () { });
|
||||
const info = {
|
||||
title: obj.title,
|
||||
idPage: obj.idPage,
|
||||
lName: obj.lName,
|
||||
dynamicF: obj.dynamicF
|
||||
};
|
||||
localStorage.setItem(this._key(id, "pI"), JSON.stringify(pI))
|
||||
localStorage.setItem(this._key(id, type), JSON.stringify(clone));
|
||||
this.pageMap.set(id, pI);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Lưu thông tin trang vào pageMap và storage
|
||||
this.pageMap.set(id, info);
|
||||
this.storage.set(`pI|${id}`, info, function () { });
|
||||
} else {
|
||||
const layout = {
|
||||
Content: obj.Content,
|
||||
Scripts: obj.Scripts
|
||||
};
|
||||
|
||||
// Lưu dữ liệu layout vào storage
|
||||
this.layoutMap.set(id, true);
|
||||
this.storage.set(key, layout, function () {
|
||||
// callback(null); // Gọi callback khi lưu thành công
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
class CacheStorage {
|
||||
constructor(prefix = "cache", maxAgeMs = 3 * 24 * 60 * 60 * 1000) {
|
||||
this.prefix = prefix;
|
||||
this.maxAgeMs = maxAgeMs;
|
||||
this.db = null;
|
||||
this.useIndexedDB = false;
|
||||
this.queue = [];
|
||||
this.ready = false;
|
||||
this._initDB();
|
||||
this.cleanupExpired();
|
||||
}
|
||||
|
||||
_key(key) {
|
||||
return `${this.prefix}|${key}`;
|
||||
}
|
||||
|
||||
_initDB() {
|
||||
const req = indexedDB.open(`${this.prefix}_db`, 1);
|
||||
req.onupgradeneeded = (e) => {
|
||||
const store = e.target.result.createObjectStore("cache", { keyPath: "key" });
|
||||
try {
|
||||
store.add({ id: 1, value: "test data" });
|
||||
store.delete("1");
|
||||
} catch (e) {
|
||||
console.warn("Failed to store cache:", e);
|
||||
this.ready = true;
|
||||
this.db = null;
|
||||
this.useIndexedDB = false;
|
||||
}
|
||||
};
|
||||
req.onsuccess = (event) => {
|
||||
this.db = req.result;
|
||||
this.ready = true;
|
||||
this._flushQueue();
|
||||
};
|
||||
req.onerror = () => {
|
||||
console.warn("IndexedDB failed, fallback to localStorage");
|
||||
this.ready = true;
|
||||
this.db = null;
|
||||
this._flushQueue();
|
||||
};
|
||||
}
|
||||
_flushQueue() {
|
||||
while (this.queue.length) {
|
||||
const fn = this.queue.shift();
|
||||
fn();
|
||||
}
|
||||
}
|
||||
|
||||
_onReady(fn) {
|
||||
if (this.ready) fn();
|
||||
else this.queue.push(fn);
|
||||
}
|
||||
|
||||
get(key, callback, f=false) {
|
||||
this._onReady(() => {
|
||||
if (this.db) {
|
||||
const tx = this.db.transaction("cache", "readonly");
|
||||
const store = tx.objectStore("cache");
|
||||
const req = store.get(f ? key : this._key(key));
|
||||
req.onsuccess = () => callback(req.result ? req.result.value : null);
|
||||
req.onerror = () => callback(null);
|
||||
} else {
|
||||
try {
|
||||
const raw = localStorage.getItem(this._key(key));
|
||||
const parsed = raw ? JSON.parse(raw) : null;
|
||||
callback(parsed.data);
|
||||
} catch {
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
getAllKeys(callback) {
|
||||
this._onReady(() => {
|
||||
if (this.db) {
|
||||
const tx = this.db.transaction("cache", "readonly");
|
||||
const store = tx.objectStore("cache");
|
||||
const req = store.getAllKeys();
|
||||
req.onsuccess = () => {
|
||||
callback(req.result);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
set(key, data, callback = () => { }) {
|
||||
this._onReady(() => {
|
||||
if (this.db) {
|
||||
const tx = this.db.transaction("cache", "readwrite");
|
||||
const store = tx.objectStore("cache");
|
||||
store.put({ key: this._key(key), value: data, ts: Date.now() });
|
||||
tx.oncomplete = () => callback(null);
|
||||
tx.onerror = (e) => callback(e);
|
||||
} else {
|
||||
try {
|
||||
console.log("Run Local");
|
||||
localStorage.setItem(this._key(key), JSON.stringify({ data, ts: Date.now() }));
|
||||
callback(null);
|
||||
} catch (e) {
|
||||
|
||||
callback(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
remove(key) {
|
||||
const fullKey = this._key(key);
|
||||
localStorage.removeItem(fullKey);
|
||||
if (this.db) {
|
||||
try {
|
||||
const tx = this.db.transaction("cache", "readwrite");
|
||||
const store = tx.objectStore("cache");
|
||||
store.delete(fullKey);
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
|
||||
cleanupExpired() {
|
||||
const now = Date.now();
|
||||
for (let i = localStorage.length - 1; i >= 0; i--) {
|
||||
const key = localStorage.key(i);
|
||||
if (!key.startsWith(this.prefix)) continue;
|
||||
try {
|
||||
const raw = JSON.parse(localStorage.getItem(key));
|
||||
if (raw && raw.ts && now - raw.ts > this.maxAgeMs) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
} catch {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user