From e9967fa22781d922ba4eb8fb44fe72d200ac4b14 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 10 Nov 2025 21:04:10 +0000
Subject: [PATCH] =IconsManager.php update
---
assets/js/concise/SimpleCache.js | 415 ++++++----------------------------------------------------
1 files changed, 45 insertions(+), 370 deletions(-)
diff --git a/assets/js/concise/SimpleCache.js b/assets/js/concise/SimpleCache.js
index e4c018f..30f074c 100644
--- a/assets/js/concise/SimpleCache.js
+++ b/assets/js/concise/SimpleCache.js
@@ -24,15 +24,9 @@
...config
};
- // Check if Cache API is available
- this.cacheAvailable = 'caches' in window;
-
- if(!this.cacheAvailable){
- console.warn('Browser Cache API unavailable, reverting to LocalStorage');
- }
// Initialize memory cache
- this._memoryCache = new Map();
+ this._cache = new Map();
this.subscribers = new Set();
}
@@ -41,8 +35,8 @@
* @returns {number} Number of items cleared
*/
clearMemoryCache() {
- const count = this._memoryCache.size;
- this._memoryCache.clear();
+ const count = this._cache.size;
+ this._cache.clear();
console.log(`Cleared ${count} items from memory cache`);
return count;
@@ -51,295 +45,40 @@
/**
* Get a setting value
*/
- async get(key) {
+ get(key) {
+ //Check memory cache first
+ if (this._cache.has(key)) {
+ return this._cache.get(key);
+ }
+
let cacheKey = `${this.base}_${key}`;
-
- const cachedItem = await this.getCacheItem(cacheKey);
-
- if (!cachedItem) {
+ let item;
+ try {
+ item = localStorage.getItem(cacheKey);
+ if (!item) {
+ return null;
+ }
+ item = JSON.parse(item);
+ } catch (error) {
+ console.warn('Error getting from localStorage:', error);
return null;
}
- // Deserialize data back to original type
- return this.deserializeData(cachedItem.data, cachedItem.dataType);
+ if (item) {
+ this._cache.set(key, item);
+ }
+ return item;
}
/**
* Set a setting value
*/
- async set(key, value) {
+ set(key, value) {
+ this._cache.set(key, value);
let cacheKey = `${this.base}_${key}`;
- // Serialize data with type preservation
- const serializedData = this.serializeData(value);
- const cacheItem = {
- data: serializedData.data,
- dataType: serializedData.type,
- timestamp: Date.now(),
- };
-
- await this.setCacheItem(cacheKey, cacheItem);
-
- // Notify subscribers
- this.notify('cache-saved', { key, value });
- }
-
- remove(key) {
- let cacheKey = `${this.base}_${key}`;
- //TODO: Actually remove it
- }
-
- serializeData(data) {
- // Handle null/undefined
- if (data === null || data === undefined) {
- return { data, type: 'primitive' };
- }
-
- // Handle Maps
- if (data instanceof Map) {
- return {
- data: Array.from(data.entries()),
- type: 'Map'
- };
- }
-
- // Handle Sets
- if (data instanceof Set) {
- return {
- data: Array.from(data),
- type: 'Set'
- };
- }
-
- // Handle Dates
- if (data instanceof Date) {
- return {
- data: data.toISOString(),
- type: 'Date'
- };
- }
-
- // Handle RegExp
- if (data instanceof RegExp) {
- return {
- data: { source: data.source, flags: data.flags },
- type: 'RegExp'
- };
- }
-
- // Handle Arrays (check before general objects)
- if (Array.isArray(data)) {
- // Recursively serialize array elements that might contain Maps/Sets
- return {
- data: data.map(item => this.serializeData(item)),
- type: 'Array'
- };
- }
-
- // Handle plain objects
- if (data && typeof data === 'object' && data.constructor === Object) {
- const serializedObj = {};
- for (const [key, value] of Object.entries(data)) {
- serializedObj[key] = this.serializeData(value);
- }
- return {
- data: serializedObj,
- type: 'Object'
- };
- }
-
- // Handle primitives (string, number, boolean)
- return { data, type: 'primitive' };
- }
-
- deserializeData(data, type) {
- if (!type || type === 'primitive') {
- return data;
- }
-
- switch (type) {
- case 'Map':
- return new Map(data);
-
- case 'Set':
- return new Set(data);
-
- case 'Date':
- return new Date(data);
-
- case 'RegExp':
- return new RegExp(data.source, data.flags);
-
- case 'Array':
- // Recursively deserialize array elements
- return data.map(item =>
- this.deserializeData(item.data, item.type)
- );
-
- case 'Object':
- const restoredObj = {};
- for (const [key, value] of Object.entries(data)) {
- restoredObj[key] = this.deserializeData(value.data, value.type);
- }
- return restoredObj;
-
- default:
- console.warn(`Unknown data type: ${type}, returning as-is`);
- return data;
- }
- }
- /**********************************************************
- CACHE
- **********************************************************/
- /**
- * Main method to get an item from cache
- * Tries Browser Cache API first, falls back to localStorage
- *
- * @param {string} key - Cache key
- * @returns {Promise<any>} - Cached item or null
- */
- async getCacheItem(key) {
- //Check memory cache first
- if (this._memoryCache.has(key)) {
- return this._memoryCache.get(key);
- }
-
- // Then check persistent cache
- const item = this.cacheAvailable ?
- await this.getBrowserCacheItem(key) :
- this.getLocalStorageItem(key);
-
- // Store in memory cache if found
- if (item) {
- this._memoryCache.set(key, item);
- }
-
- return item;
- }
-
- /**
- * Main method to set an item in cache
- * Uses Browser Cache API if available, falls back to localStorage
- *
- * @param {string} key - Cache key
- * @param {any} item - Item to cache
- * @returns {Promise<void>}
- */
- async setCacheItem(key, item) {
- // Always store in memory cache
- this._memoryCache.set(key, item);
-
- return this.cacheAvailable ?
- await this.setBrowserCacheItem(key, item) :
- this.setLocalStorageItem(key, item);
- }
-
- /**
- * Remove an item from cache
- *
- * @param {string} key - Cache key
- * @returns {Promise<void>}
- */
- async removeCacheItem(key) {
- // Remove from memory cache
- this._memoryCache.delete(key);
-
- return this.cacheAvailable ?
- await this.removeBrowserCacheItem(key) :
- this.removeLocalStorageItem(key);
- }
- /*********************************************************************
- BROWSER CACHE
- *********************************************************************/
- /**
- * Get item from Browser Cache API
- *
- * @param {string} key - Cache key
- * @returns {Promise<any>} - Cached item or null
- */
- async getBrowserCacheItem(key) {
try {
- const cache = await caches.open(this.config.namespace);
- const response = await cache.match(key);
-
- if (!response) {
- return null;
- }
-
- return await response.json();
- } catch (error) {
- console.warn('Error getting from Browser Cache API:', error);
- return null;
- }
- }
-
- /**
- * Set item in Browser Cache API
- *
- * @param {string} key - Cache key
- * @param {any} item - Item to cache
- * @returns {Promise<void>}
- */
- async setBrowserCacheItem(key, item) {
- try {
- const cache = await caches.open(this.config.namespace);
- const response = new Response(JSON.stringify(item), {
- headers: { 'Content-Type': 'application/json' }
- });
-
- await cache.put(key, response);
- } catch (error) {
- console.warn('Error setting in Browser Cache API:', error);
- }
- }
-
- /**
- * Remove item from Browser Cache API
- *
- * @param {string} key - Cache key
- * @returns {Promise<void>}
- */
- async removeBrowserCacheItem(key) {
- try {
- const cache = await caches.open(this.config.namespace);
- await cache.delete(key);
- } catch (error) {
- console.warn('Error removing from Browser Cache API:', error);
- }
- }
- /*************************************************************************
- LOCAL STORAGE
- *************************************************************************/
- /**
- * Get item from localStorage
- *
- * @param {string} key - Cache key
- * @returns {object|null} - Cached item or null
- */
- getLocalStorageItem(key) {
- try {
- const stored = localStorage.getItem(key);
-
- if (!stored) {
- return null;
- }
-
- return JSON.parse(stored);
- } catch (error) {
- console.warn('Error getting from localStorage:', error);
- return null;
- }
- }
-
- /**
- * Set item in localStorage
- *
- * @param {string} key - Cache key
- * @param {any} item - Item to cache
- */
- setLocalStorageItem(key, item) {
- try {
- localStorage.setItem(key, JSON.stringify(item));
+ localStorage.setItem(cacheKey, JSON.stringify(value));
} catch (error) {
// Handle quota exceeded
if (error instanceof DOMException && error.code === 22) {
@@ -353,16 +92,15 @@
console.warn('Error setting localStorage item:', error);
}
}
+
+ // Notify subscribers
+ this.notify('cache-saved', { key, value });
}
- /**
- * Remove item from localStorage
- *
- * @param {string} key - Cache key
- */
- removeLocalStorageItem(key) {
+ remove(key) {
+ let cacheKey = `${this.base}_${key}`;
try {
- localStorage.removeItem(key);
+ localStorage.removeItem(cacheKey);
} catch (error) {
console.warn('Error removing localStorage item:', error);
}
@@ -403,65 +141,20 @@
console.warn('Error cleaning up localStorage:', error);
}
}
- /************************************************************************
- CLEANUP
- ************************************************************************/
- /**
- * Clean expired items from cache
- *
- * @returns {Promise<void>}
- */
- async cleanExpired() {
- const now = Date.now();
- const maxAge = this.config.TTL;
- if (this.cacheAvailable) {
- try {
- const cache = await caches.open(this.options.namespace);
- const keys = await cache.keys();
-
- for (const request of keys) {
- const response = await cache.match(request);
-
- try {
- const cacheItem = await response.json();
- if (now - cacheItem.timestamp > maxAge) {
- await cache.delete(request);
- }
- } catch (e) {
- // If we can't parse it, just leave it alone
- }
+ async loadFromCache() {
+ for (let i = 0; i < localStorage.length; i++) {
+ const key = localStorage.key(i);
+ // Check if key starts with this cache's base prefix
+ if (key.startsWith(`${this.base}_`)) {
+ let cleanKey = key.replace(`${this.base}_`, '');
+ try {
+ // Parse the JSON value before caching
+ const value = JSON.parse(localStorage.getItem(key));
+ this._cache.set(cleanKey, value);
+ } catch (error) {
+ console.warn(`Failed to parse cached value for ${key}:`, error);
}
- } catch (error) {
- console.warn('Error cleaning browser cache:', error);
- }
- } else {
- // Clean localStorage
- try {
- for (let i = 0; i < localStorage.length; i++) {
- const key = localStorage.key(i);
-
- if (key && key.startsWith(this.options.namespace)) {
- try {
- const item = JSON.parse(localStorage.getItem(key));
-
- if (now - item.timestamp > maxAge) {
- localStorage.removeItem(key);
- }
- } catch (e) {
- // Skip invalid items
- }
- }
- }
- } catch (error) {
- console.warn('Error cleaning localStorage cache:', error);
- }
- }
-
- // Clean memory cache
- for (const [key, item] of this._memoryCache.entries()) {
- if (now - item.timestamp > maxAge) {
- this._memoryCache.delete(key);
}
}
}
@@ -472,29 +165,12 @@
* @returns {Promise<void>}
*/
async clear() {
- // Clear memory cache
- this._memoryCache.clear();
+ this._cache.clear();
- if (this.cacheAvailable) {
- try {
- await caches.delete(this.options.namespace);
- } catch (error) {
- console.warn('Error clearing browser cache:', error);
- }
- }
-
- // Also clear localStorage in case we've used it as fallback
- this.clearLocalStorage();
- }
-
- /**
- * Clear just localStorage cache
- */
- clearLocalStorage() {
try {
for (let i = localStorage.length - 1; i >= 0; i--) {
const key = localStorage.key(i);
- if (key && key.startsWith(this.options.namespace)) {
+ if (key && key.startsWith(this.config.namespace)) {
localStorage.removeItem(key);
}
}
@@ -502,7 +178,6 @@
console.warn('Error clearing localStorage cache:', error);
}
}
- /************************** OLD **********************************/
/**
* Subscribe to setting changes
--
Gitblit v1.10.0