Update 14/05/2025
This commit is contained in:
@ -11,7 +11,7 @@
|
|||||||
<title></title>
|
<title></title>
|
||||||
<link rel="icon" type="image/x-icon" href="@Url.AbsoluteContent("~/images/logo/icon.png")" />
|
<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="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>
|
</head>
|
||||||
<body class="hp">
|
<body class="hp">
|
||||||
<section data-scrollbar class="main-scrollbar">
|
<section data-scrollbar class="main-scrollbar">
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import AMenu from '/js/libs/js-AMenu.js'
|
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'
|
import ALayout from '/js/libs/js-ALayout.js'
|
||||||
|
|
||||||
var asyncStyleSheets = [
|
var asyncStyleSheets = [
|
||||||
@ -7,10 +6,11 @@ var asyncStyleSheets = [
|
|||||||
'/css/atg-font/atg-admin-font.css'
|
'/css/atg-font/atg-admin-font.css'
|
||||||
];
|
];
|
||||||
window.app.loadCSS(asyncStyleSheets);
|
window.app.loadCSS(asyncStyleSheets);
|
||||||
window.isLoad_Menu = false;
|
|
||||||
|
|
||||||
class AsyncLayout extends ALayout {
|
class AsyncLayout extends ALayout {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.isLoaded = false;
|
||||||
this.layMNav = `<div class="m-header">
|
this.layMNav = `<div class="m-header">
|
||||||
<a app-nav href="${window.GetAbsoluteURL("/")}" class="c_logo d-f a-i-center c-a">
|
<a app-nav href="${window.GetAbsoluteURL("/")}" class="c_logo d-f a-i-center c-a">
|
||||||
<img src="/images/logo/logo.jpg" />
|
<img src="/images/logo/logo.jpg" />
|
||||||
@ -62,12 +62,22 @@ class AsyncLayout extends ALayout {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
dispose() {
|
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() {
|
renderMenu() {
|
||||||
window.isLoad_Menu = true;
|
this.isLoaded = true;
|
||||||
this._createFHeader();
|
this._createFHeader();
|
||||||
window.app.initNavs();
|
window.app.initNavs("Async");
|
||||||
var hHeader = document.getElementById("header").clientHeight;
|
var hHeader = document.getElementById("header").clientHeight;
|
||||||
var fHeader = document.getElementById("fHeader");
|
var fHeader = document.getElementById("fHeader");
|
||||||
|
|
||||||
@ -83,10 +93,11 @@ class AsyncLayout extends ALayout {
|
|||||||
fHeader.classList.remove("show");
|
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);
|
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);
|
var a2 = new AMenu("#fHeader .nav-mainmenu", null, null);
|
||||||
|
this.listAObject.add(a2);
|
||||||
const idE1 = window.app.on("redirect_page", (e) => {
|
const idE1 = window.app.on("redirect_page", (e) => {
|
||||||
a1.changeActive();
|
a1.changeActive();
|
||||||
a2.changeActive();
|
a2.changeActive();
|
||||||
@ -96,25 +107,9 @@ class AsyncLayout extends ALayout {
|
|||||||
window.app.initNavApp(window.GetAbsoluteURL("/Search"));
|
window.app.initNavApp(window.GetAbsoluteURL("/Search"));
|
||||||
}
|
}
|
||||||
const btnMHeader = document.getElementById("btnMHeader");
|
const btnMHeader = document.getElementById("btnMHeader");
|
||||||
btnMHeader.addEventListener(this.eventName, f);
|
// btnMHeader.addEventListener(this.eventName, f);
|
||||||
this.addSystemEvent(this.eventName, f, )
|
this.addSystemEvent(this.eventName, btnMHeader, 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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
window.ALayout.set("Async", new AsyncLayout());
|
||||||
window.AScript.set("asyncLayout", true);
|
window.AScript.set("asyncLayout", true);
|
@ -1,13 +1,29 @@
|
|||||||
import AMenu from '/js/libs/js-AMenu.js'
|
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 = [
|
var asyncStyleSheets = [
|
||||||
'https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap',
|
'https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap',
|
||||||
'/css/atg-font/atg-admin-font.css'
|
'/css/atg-font/atg-admin-font.css'
|
||||||
];
|
];
|
||||||
window.app.loadCSS(asyncStyleSheets);
|
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">
|
<a app-nav href="${window.GetAbsoluteURL("/")}" class="c_logo d-f a-i-center c-a">
|
||||||
<img src="/images/logo/logo.jpg" />
|
<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>
|
<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>
|
||||||
|
|
||||||
</div>`;
|
</div>`;
|
||||||
|
this.fHeader = `<div id="fHeader" class="f-header">
|
||||||
const fHeader = `<div id="fHeader" class="f-header">
|
|
||||||
<div class="cfull">
|
<div class="cfull">
|
||||||
<div class="c_search_header d-f a-i-center j-c-between">
|
<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">
|
<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>
|
||||||
</div>`;
|
</div>`;
|
||||||
function createFHeader() {
|
}
|
||||||
document.body.insertAdjacentHTML("afterbegin", layMNav);
|
_createFHeader() {
|
||||||
document.body.insertAdjacentHTML("afterbegin", fHeader);
|
document.body.insertAdjacentHTML("afterbegin", this.layMNav);
|
||||||
|
document.body.insertAdjacentHTML("afterbegin", this.fHeader);
|
||||||
var h = document.querySelector("#fHeader .nav-mainmenu");
|
var h = document.querySelector("#fHeader .nav-mainmenu");
|
||||||
var h2 = document.querySelector(".m-header");
|
var h2 = document.querySelector(".m-header");
|
||||||
var he2 = h2.querySelector(".nav-mainmenu");
|
var he2 = h2.querySelector(".nav-mainmenu");
|
||||||
var r = document.querySelector("#header");
|
var r = document.querySelector("#header");
|
||||||
//r.querySelector(".nav-mainmenu").childNodes.forEach(el => {
|
}
|
||||||
// he2.appendChild(el.cloneNode(true));
|
dispose() {
|
||||||
// h.appendChild(el.cloneNode(true));
|
this.isLoaded = false;
|
||||||
//})
|
|
||||||
}
|
|
||||||
|
|
||||||
window.Hide_Menu = function () {
|
|
||||||
var h = document.getElementById("header");
|
var h = document.getElementById("header");
|
||||||
var f = document.getElementById("footer");
|
var f = document.getElementById("footer");
|
||||||
var h1 = document.getElementById("fHeader");
|
var h1 = document.getElementById("fHeader");
|
||||||
h.classList.add("d-n");
|
document.querySelector(".m-header").remove();
|
||||||
f.classList.add("d-n");
|
f.removeAll();
|
||||||
h1.classList.add("d-n");
|
h.removeAll();
|
||||||
}
|
h1.remove();
|
||||||
window.Show_Menu = function () {
|
window.app.removeSytemEventParent(window.app.lName);
|
||||||
var h = document.getElementById("header");
|
window.app.removeCustomEventParent(window.app.lName);
|
||||||
var f = document.getElementById("footer");
|
super.dispose();
|
||||||
var h1 = document.getElementById("fHeader");
|
}
|
||||||
h.classList.remove("d-n");
|
renderMenu() {
|
||||||
f.classList.remove("d-n");
|
this.isLoaded = true;
|
||||||
h1.classList.remove("d-n");
|
this._createFHeader();
|
||||||
}
|
window.app.initNavs("Async1");
|
||||||
window.Load_Menu = function () {
|
|
||||||
window.isLoad_Menu = true;
|
|
||||||
window.app.on("redirect_page", (e) => {
|
|
||||||
a1.changeActive();
|
|
||||||
});
|
|
||||||
createFHeader();
|
|
||||||
window.app.initNavs();
|
|
||||||
var hHeader = document.getElementById("header").clientHeight;
|
var hHeader = document.getElementById("header").clientHeight;
|
||||||
var fHeader = document.getElementById("fHeader");
|
var fHeader = document.getElementById("fHeader");
|
||||||
var plScr = new AOverScroll();
|
|
||||||
if (window.getOS() == "iOS") {
|
if (window.getOS() == "iOS") {
|
||||||
fHeader.classList.add("ios");
|
fHeader.classList.add("ios");
|
||||||
}
|
}
|
||||||
@ -104,13 +109,23 @@ window.Load_Menu = function () {
|
|||||||
fHeader.classList.remove("show");
|
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 a1 = new AMenu("#header .nav-mainmenu", ".m-header", document.querySelectorAll(".m-navbar > .ico-menu"), true);
|
||||||
|
|
||||||
//var a2 = new AMenu("#fHeader .nav-mainmenu", null, null);
|
//var a2 = new AMenu("#fHeader .nav-mainmenu", null, null);
|
||||||
//console.log(document.getElementById("btnMHeader"));
|
//const idE1 = window.app.on("redirect_page", (e) => {
|
||||||
//document.getElementById("btnMHeader").addEventListener("click", (e) => {
|
// a1.changeActive();
|
||||||
// window.app.initNavApp(window.GetAbsoluteURL("/Search"));
|
// 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);
|
window.AScript.set("asyncLayout1", true);
|
@ -1,6 +1,6 @@
|
|||||||
export default class ALayout extends window.AObject {
|
export default class ALayout extends window.AObject {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
super();
|
||||||
}
|
}
|
||||||
renderMenu(){
|
renderMenu(){
|
||||||
|
|
||||||
|
@ -70,8 +70,13 @@ export default class AMenu extends window.AObject {
|
|||||||
if (this.isMDiffD) {
|
if (this.isMDiffD) {
|
||||||
d2.bindDropDowns(this.navM.querySelectorAll(".nav-i.has-sub"));
|
d2.bindDropDowns(this.navM.querySelectorAll(".nav-i.has-sub"));
|
||||||
}
|
}
|
||||||
|
this.dropdown = d2;
|
||||||
|
}
|
||||||
|
dispose() {
|
||||||
|
this.overlay.dispose();
|
||||||
|
this.dropdown.dispose();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateIdPage() {
|
updateIdPage() {
|
||||||
this.idPage = document.head.querySelector("meta[name=idPage]").content;
|
this.idPage = document.head.querySelector("meta[name=idPage]").content;
|
||||||
|
|
||||||
|
@ -205,6 +205,7 @@ window.AObject = class {
|
|||||||
this.systemEvents = new Map();
|
this.systemEvents = new Map();
|
||||||
this.customEvents = new Map();
|
this.customEvents = new Map();
|
||||||
this.parentEventMap = new Map();
|
this.parentEventMap = new Map();
|
||||||
|
this.listAObject = new Set();
|
||||||
this.eventName = window.getPrimaryPointerEvent();
|
this.eventName = window.getPrimaryPointerEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,10 +322,13 @@ window.AObject = class {
|
|||||||
element.removeEventListener(event, callback, false);
|
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.systemEvents.clear();
|
||||||
this.parentEventMap.clear();
|
this.parentEventMap.clear();
|
||||||
|
|
||||||
@ -362,35 +366,47 @@ window.AObject = class {
|
|||||||
removeSytemEventParent(parent) {
|
removeSytemEventParent(parent) {
|
||||||
const entries = this.parentEventMap.get(parent);
|
const entries = this.parentEventMap.get(parent);
|
||||||
if (!entries) return;
|
if (!entries) return;
|
||||||
|
let iC = 0;
|
||||||
for (const { element, event } of entries) {
|
for (const { element, eventName } of entries) {
|
||||||
const eventMap = this.systemEvents.get(element);
|
const eventMap = this.systemEvents.get(element);
|
||||||
if (eventMap) {
|
if (eventMap) {
|
||||||
const data = eventMap.get(event);
|
const data = eventMap.get(eventName);
|
||||||
|
|
||||||
if (data && typeof data.callback === 'function') {
|
if (data && typeof data.callback === 'function') {
|
||||||
element.removeEventListener(event, data.callback, false);
|
element.removeEventListener(eventName , data.callback, false);
|
||||||
eventMap.delete(event);
|
eventMap.delete(eventName);
|
||||||
// Nếu element không còn event nào, xóa khỏi systemEvents
|
// Nếu element không còn event nào, xóa khỏi systemEvents
|
||||||
if (eventMap.size === 0) {
|
if (eventMap.size === 0) {
|
||||||
this.systemEvents.delete(element);
|
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);
|
this.parentEventMap.delete(parent);
|
||||||
}
|
}
|
||||||
addCustomEvent(id, element, groups = null) {
|
addCustomEvent(id, element, groups = null) {
|
||||||
if (!this.customEvents.has(id)) {
|
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 (groups) {
|
||||||
if (!this.parentEventMap.has("Custom" + parent)) {
|
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]') {
|
constructor(container = '[app-content]') {
|
||||||
super();
|
super();
|
||||||
this.cachePage = new CacheManager();
|
this.cachePage = new CacheManager();
|
||||||
this.currentLay = null;
|
|
||||||
this.isLoadedLayout = false;
|
this.isLoadedLayout = false;
|
||||||
window.Destroy = undefined;
|
window.Destroy = undefined;
|
||||||
|
window.ALayout = new Map();
|
||||||
this.isRedirectPage = false;
|
this.isRedirectPage = false;
|
||||||
this.metaPage = document.head.querySelector("meta[name=idPage]");
|
this.metaPage = document.head.querySelector("meta[name=idPage]");
|
||||||
this.pageName = this.metaPage.getAttribute("pageName");
|
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;
|
this.mainApp = tmp.querySelector("[main-content]") ? tmp.querySelector("[main-content]") : tmp;
|
||||||
var f = function (ev) {
|
var f = function (ev) {
|
||||||
if (ev.state) {
|
if (ev.state) {
|
||||||
const obj = this.cachePage.get(ev.state.url);
|
this.cachePage.get(ev.state.url, ((result) => {
|
||||||
this.loadContentPage(obj.html);
|
if (result == null) {
|
||||||
this.metaPage.content = obj.idPage;
|
|
||||||
this.metaPage.setAttribute("isLayout", obj.isLayout);
|
} else {
|
||||||
|
this.loadContentPage(result.html);
|
||||||
|
this.metaPage.content = result.idPage;
|
||||||
|
this.metaPage.setAttribute("isLayout", result.isLayout);
|
||||||
this.trigger("redirect_page", ev.state);
|
this.trigger("redirect_page", ev.state);
|
||||||
//this.checkLayout(obj.isLayout);
|
this.checkLayout(result.lName);
|
||||||
var l = new LoadScriptAsync("Page");
|
var l = new LoadScriptAsync("Page");
|
||||||
l.processScript(obj.doc);
|
l.processScript(result.doc);
|
||||||
l.on("Loaded", (() => {
|
l.on("Loaded", (() => {
|
||||||
this.loadedPage();
|
this.loadedPage();
|
||||||
}).bind(this));
|
}).bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}).bind(this));
|
||||||
|
}
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
window.addEventListener("popstate", f);
|
window.addEventListener("popstate", f);
|
||||||
}
|
}
|
||||||
checkLayout(lName) {
|
checkLayout(lName) {
|
||||||
//if ((this.isDispLay && isLayout) == false) {
|
if (this.lName !== lName) {
|
||||||
// if (isLayout) {
|
if (this.lName !== "None") {
|
||||||
// if (window.isLoad_Menu) {
|
const l = window.ALayout.get(this.lName);
|
||||||
// window.Show_Menu();
|
l.dispose();
|
||||||
// } else {
|
}
|
||||||
// this.renderLayout();
|
this.callLoadLayout(lName);
|
||||||
// }
|
this.lName = lName;
|
||||||
// } else /*display =true -> layout false */ {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
//}
|
|
||||||
//this.isDispLay = isLayout;
|
|
||||||
if (lName === "None") {
|
|
||||||
window.Hide_Menu();
|
|
||||||
} else {
|
|
||||||
this.renderLayout();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
if (this.lName !== "None") {
|
if (this.lName !== "None") {
|
||||||
this.renderLayout();
|
this.callLoadLayout(this.lName);
|
||||||
} else {
|
} else {
|
||||||
this.isLoadedLayout = true;
|
this.isLoadedLayout = true;
|
||||||
}
|
}
|
||||||
@ -576,47 +587,7 @@ class AApp extends window.AObject {
|
|||||||
this.callLoadPage(window.location.href);
|
this.callLoadPage(window.location.href);
|
||||||
}).bind(this)();
|
}).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() {
|
scrollTop() {
|
||||||
return window.scrollY || window.smScroll.scrollTop;
|
return window.scrollY || window.smScroll.scrollTop;
|
||||||
}
|
}
|
||||||
@ -686,15 +657,15 @@ class AApp extends window.AObject {
|
|||||||
this.callLoadPage(window.GetAbsoluteURL(t));
|
this.callLoadPage(window.GetAbsoluteURL(t));
|
||||||
}
|
}
|
||||||
callLoadPage(url) {
|
callLoadPage(url) {
|
||||||
const page = this.cachePage.get(url);
|
this.cachePage.get(url, ((result) => {
|
||||||
if (page) {
|
if (result) {
|
||||||
this.setContentPage(page, url); // Set content page từ cache
|
this.setContentPage(result, url); // Set content page từ cache
|
||||||
} else {
|
} else {
|
||||||
console.log("connect new");
|
console.log("connect new");
|
||||||
this.getPage(url); // Load mới nếu chưa có trong cache
|
this.getPage(url); // Load mới nếu chưa có trong cache
|
||||||
}
|
}
|
||||||
|
}).bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
loadContentPage(content) {
|
loadContentPage(content) {
|
||||||
const tpl = document.createElement('template');
|
const tpl = document.createElement('template');
|
||||||
tpl.innerHTML = content;
|
tpl.innerHTML = content;
|
||||||
@ -707,18 +678,17 @@ class AApp extends window.AObject {
|
|||||||
document.title = page.title + " - " + this.pageName;
|
document.title = page.title + " - " + this.pageName;
|
||||||
var meta = document.head.querySelector("meta[name=idPage]");
|
var meta = document.head.querySelector("meta[name=idPage]");
|
||||||
meta.content = page.idPage;
|
meta.content = page.idPage;
|
||||||
|
|
||||||
this.checkLayout(page.lName);
|
|
||||||
meta.setAttribute("layName", page.lName);
|
meta.setAttribute("layName", page.lName);
|
||||||
|
|
||||||
this.loadContentPage(page.html);
|
this.loadContentPage(page.html);
|
||||||
window.history.pushState({"url":url}, page.title, url);
|
window.history.pushState({"url":url}, page.title, url);
|
||||||
}
|
}
|
||||||
setContentPage(page, url) {
|
setContentPage(page, url) {
|
||||||
|
|
||||||
this.contentPage(page, url);
|
this.contentPage(page, url);
|
||||||
var l = new LoadScriptAsync("Page");
|
var l = new LoadScriptAsync("Page");
|
||||||
if (this.isRedirectPage) {
|
if (this.isRedirectPage) {
|
||||||
this.trigger("redirect_page", page);
|
this.trigger("redirect_page", page);
|
||||||
|
this.checkLayout(page.lName);
|
||||||
this.isRedirectPage = false;
|
this.isRedirectPage = false;
|
||||||
}
|
}
|
||||||
l.on("Loaded", (() => {
|
l.on("Loaded", (() => {
|
||||||
@ -740,7 +710,83 @@ class AApp extends window.AObject {
|
|||||||
}.bind(this);
|
}.bind(this);
|
||||||
xhr.addEventListener("readystatechange", f, false);
|
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 oP = new DOMParser();
|
||||||
var pHtml = oP.parseFromString(o.Content, 'text/html');
|
var pHtml = oP.parseFromString(o.Content, 'text/html');
|
||||||
(function () {
|
(function () {
|
||||||
@ -765,22 +811,6 @@ class AApp extends window.AObject {
|
|||||||
l.processScript(doc);
|
l.processScript(doc);
|
||||||
}).bind(this)();
|
}).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) {
|
loadCSS(arr) {
|
||||||
for (var i = 0; i < arr.length; i++) {
|
for (var i = 0; i < arr.length; i++) {
|
||||||
var link = document.createElement('link');
|
var link = document.createElement('link');
|
||||||
@ -791,91 +821,258 @@ class AApp extends window.AObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
class CacheManager {
|
class CacheManager {
|
||||||
constructor(prefix = "cache") {
|
constructor() {
|
||||||
this.prefix = prefix;
|
this.storage = new CacheStorage("appCache");
|
||||||
this.pageMap = new Map(); // Chứa key URL → idPage
|
this.pageMap = new Map();
|
||||||
this.layoutMap = new Map(); // Chứa key idLayout → true
|
this.layoutMap = new Map();
|
||||||
this._loadFromStorage();
|
this.readyCallbacks = [];
|
||||||
|
this.isReady = false;
|
||||||
|
|
||||||
|
this._loadIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_key(id, type = "page") {
|
_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") {
|
if (type === "pI") {
|
||||||
try {
|
pending++;
|
||||||
const raw = JSON.parse(localStorage.getItem(key));
|
this.storage.get(key, (data) => {
|
||||||
if (raw) {
|
if (data) this.pageMap.set(id, data);
|
||||||
this.pageMap.set(id, raw);
|
if (--pending === 0) this._finishInit();
|
||||||
}
|
}, true);
|
||||||
} catch (e) {
|
|
||||||
console.warn("Error parsing cached page:", e);
|
|
||||||
}
|
|
||||||
} else if (type === "layout") {
|
} else if (type === "layout") {
|
||||||
this.layoutMap.set(id, true);
|
this.layoutMap.set(id, true);
|
||||||
}
|
}
|
||||||
}
|
}).bind(this));
|
||||||
}
|
if (pending === 0) this._finishInit(); // Trường hợp không có key nào là "pI"
|
||||||
getInf(id, type = "page") {
|
}).bind(this));
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const raw = localStorage.getItem(this._key(id, type));
|
_finishInit() {
|
||||||
if (!raw) return null;
|
this.isReady = true;
|
||||||
|
this.readyCallbacks.forEach(cb => cb());
|
||||||
|
this.readyCallbacks = [];
|
||||||
|
}
|
||||||
|
|
||||||
const parsed = JSON.parse(raw);
|
// Lấy thông tin trang hoặc layout
|
||||||
parsed.doc = new DOMParser().parseFromString(parsed.doc, "text/html").head;
|
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") {
|
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 {
|
} else {
|
||||||
return parsed;
|
callback(data);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
});
|
||||||
console.warn("Cache parse error:", e);
|
});
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Lưu dữ liệu page/layout theo ID
|
// Lưu dữ liệu page hoặc layout vào cache
|
||||||
set(id, obj, type = "page") {
|
set(id, obj, type = "page", callback) {
|
||||||
try {
|
this._onReady(() => {
|
||||||
const clone = {};
|
const key = this._key(id, type);
|
||||||
|
|
||||||
if (type === "page") {
|
if (type === "page") {
|
||||||
clone.html = obj.html;
|
const htmlData = {
|
||||||
clone.doc = obj.doc.innerHTML;
|
html: obj.html,
|
||||||
const pI = {
|
doc: obj.doc.innerHTML
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lưu dữ liệu htmlData vào storage
|
||||||
|
this.storage.set(key, htmlData, function () { });
|
||||||
|
const info = {
|
||||||
title: obj.title,
|
title: obj.title,
|
||||||
idPage: obj.idPage,
|
idPage: obj.idPage,
|
||||||
lName: obj.lName,
|
lName: obj.lName,
|
||||||
dynamicF: obj.dynamicF
|
dynamicF: obj.dynamicF
|
||||||
};
|
};
|
||||||
localStorage.setItem(this._key(id, "pI"), JSON.stringify(pI))
|
|
||||||
localStorage.setItem(this._key(id, type), JSON.stringify(clone));
|
// Lưu thông tin trang vào pageMap và storage
|
||||||
this.pageMap.set(id, pI);
|
this.pageMap.set(id, info);
|
||||||
}
|
this.storage.set(`pI|${id}`, info, function () { });
|
||||||
else
|
} else {
|
||||||
{
|
const layout = {
|
||||||
|
Content: obj.Content,
|
||||||
|
Scripts: obj.Scripts
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lưu dữ liệu layout vào storage
|
||||||
this.layoutMap.set(id, true);
|
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) {
|
} 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