mirror of
https://github.com/iconify/iconify.git
synced 2025-01-06 07:20:40 +00:00
Use browser storage with API
This commit is contained in:
parent
0e0b6b66ef
commit
882be420f9
@ -85,10 +85,6 @@
|
||||
"require": "./lib/browser-storage/index.cjs",
|
||||
"import": "./lib/browser-storage/index.mjs"
|
||||
},
|
||||
"./lib/browser-storage/load": {
|
||||
"require": "./lib/browser-storage/load.cjs",
|
||||
"import": "./lib/browser-storage/load.mjs"
|
||||
},
|
||||
"./lib/browser-storage/mock": {
|
||||
"require": "./lib/browser-storage/mock.cjs",
|
||||
"import": "./lib/browser-storage/mock.mjs"
|
||||
@ -105,10 +101,6 @@
|
||||
"require": "./lib/builder/functions.cjs",
|
||||
"import": "./lib/builder/functions.mjs"
|
||||
},
|
||||
"./lib/cache": {
|
||||
"require": "./lib/cache.cjs",
|
||||
"import": "./lib/cache.mjs"
|
||||
},
|
||||
"./lib/icon/list": {
|
||||
"require": "./lib/icon/list.cjs",
|
||||
"import": "./lib/icon/list.mjs"
|
||||
|
@ -12,7 +12,7 @@ import { getStorage, addIconSet } from '../storage/storage';
|
||||
import { listToIcons } from '../icon/list';
|
||||
import { allowSimpleNames, getIconData } from '../storage/functions';
|
||||
import { sendAPIQuery } from './query';
|
||||
import { cache } from '../cache';
|
||||
import { storeInBrowserStorage } from '../browser-storage/store';
|
||||
|
||||
// Empty abort callback for loadIcons()
|
||||
function emptyCallback(): void {
|
||||
@ -207,9 +207,10 @@ function loadNewIcons(provider: string, prefix: string, icons: string[]): void {
|
||||
});
|
||||
|
||||
// Cache API response
|
||||
if (cache.store) {
|
||||
cache.store(provider, data as IconifyJSON);
|
||||
}
|
||||
storeInBrowserStorage(
|
||||
provider,
|
||||
data as IconifyJSON
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import type {
|
||||
BrowserStorageConfig,
|
||||
BrowserStorageCount,
|
||||
BrowserStorageEmptyList,
|
||||
BrowserStorageStatus,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
@ -31,8 +32,8 @@ export const browserStorageEmptyItems: BrowserStorageEmptyList = {
|
||||
/**
|
||||
* Flag to check if storage has been loaded
|
||||
*/
|
||||
export let browserStorageLoaded = false;
|
||||
export let browserStorageStatus: BrowserStorageStatus = false;
|
||||
|
||||
export function setBrowserStorageStatus(loaded: boolean) {
|
||||
browserStorageLoaded = loaded;
|
||||
export function setBrowserStorageStatus(status: BrowserStorageStatus) {
|
||||
browserStorageStatus = status;
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
import { browserCachePrefix } from './config';
|
||||
import { getBrowserStorageItemsCount } from './count';
|
||||
|
||||
/**
|
||||
* Destroy old cache
|
||||
*/
|
||||
export function destroyBrowserStorage(storage: typeof localStorage): void {
|
||||
try {
|
||||
const total = getBrowserStorageItemsCount(storage);
|
||||
for (let i = 0; i < total; i++) {
|
||||
storage.removeItem(browserCachePrefix + i.toString());
|
||||
}
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
}
|
@ -1,11 +1,137 @@
|
||||
import { cache } from '../cache';
|
||||
import { loadBrowserStorageCache } from './load';
|
||||
import { storeInBrowserStorage } from './store';
|
||||
import { addIconSet, getStorage } from '../storage/storage';
|
||||
import {
|
||||
browserCachePrefix,
|
||||
browserCacheVersion,
|
||||
browserCacheVersionKey,
|
||||
browserStorageCacheExpiration,
|
||||
browserStorageHour,
|
||||
} from './config';
|
||||
import {
|
||||
getBrowserStorageItemsCount,
|
||||
setBrowserStorageItemsCount,
|
||||
} from './count';
|
||||
import {
|
||||
browserStorageConfig,
|
||||
browserStorageEmptyItems,
|
||||
browserStorageStatus,
|
||||
setBrowserStorageStatus,
|
||||
} from './data';
|
||||
import { getBrowserStorage } from './global';
|
||||
import type { BrowserStorageConfig, BrowserStorageItem } from './types';
|
||||
|
||||
/**
|
||||
* Init browser storage
|
||||
* Load icons from cache
|
||||
*/
|
||||
export function initBrowserStorage() {
|
||||
cache.store = storeInBrowserStorage;
|
||||
loadBrowserStorageCache();
|
||||
if (browserStorageStatus === true) {
|
||||
return;
|
||||
}
|
||||
setBrowserStorageStatus('loading');
|
||||
|
||||
// Minimum time
|
||||
const minTime =
|
||||
Math.floor(Date.now() / browserStorageHour) -
|
||||
browserStorageCacheExpiration;
|
||||
|
||||
// Load data from storage
|
||||
function load(key: keyof BrowserStorageConfig): void {
|
||||
const func = getBrowserStorage(key);
|
||||
if (!func) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get one item from storage
|
||||
const getItem = (index: number): boolean => {
|
||||
const name = browserCachePrefix + index.toString();
|
||||
const item = func.getItem(name);
|
||||
|
||||
if (typeof item !== 'string') {
|
||||
// Does not exist
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get item, validate it
|
||||
let valid = true;
|
||||
try {
|
||||
// Parse, check time stamp
|
||||
const data = JSON.parse(item) as BrowserStorageItem;
|
||||
if (
|
||||
typeof data !== 'object' ||
|
||||
typeof data.cached !== 'number' ||
|
||||
data.cached < minTime ||
|
||||
typeof data.provider !== 'string' ||
|
||||
typeof data.data !== 'object' ||
|
||||
typeof data.data.prefix !== 'string'
|
||||
) {
|
||||
valid = false;
|
||||
} else {
|
||||
// Add icon set
|
||||
const provider = data.provider;
|
||||
const prefix = data.data.prefix;
|
||||
const storage = getStorage(provider, prefix);
|
||||
valid = addIconSet(storage, data.data).length > 0;
|
||||
}
|
||||
} catch (err) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
func.removeItem(name);
|
||||
}
|
||||
return valid;
|
||||
};
|
||||
|
||||
try {
|
||||
// Get version
|
||||
const version = func.getItem(browserCacheVersionKey);
|
||||
if (version !== browserCacheVersion) {
|
||||
if (version) {
|
||||
// Version is set, but invalid - remove old entries
|
||||
try {
|
||||
const total = getBrowserStorageItemsCount(func);
|
||||
for (let i = 0; i < total; i++) {
|
||||
func.removeItem(browserCachePrefix + i.toString());
|
||||
}
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
// Empty data
|
||||
try {
|
||||
func.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
setBrowserStorageItemsCount(func, key, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get number of stored items
|
||||
let total = getBrowserStorageItemsCount(func);
|
||||
for (let i = total - 1; i >= 0; i--) {
|
||||
if (!getItem(i)) {
|
||||
// Remove item
|
||||
if (i === total - 1) {
|
||||
// Last item - reduce country
|
||||
total--;
|
||||
} else {
|
||||
// Mark as empty
|
||||
browserStorageEmptyItems[key].push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update total
|
||||
setBrowserStorageItemsCount(func, key, total);
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
for (const key in browserStorageConfig) {
|
||||
load(key as keyof BrowserStorageConfig);
|
||||
}
|
||||
|
||||
setBrowserStorageStatus(true);
|
||||
}
|
||||
|
@ -1,151 +0,0 @@
|
||||
import { addIconSet, getStorage } from '../storage/storage';
|
||||
import {
|
||||
browserCachePrefix,
|
||||
browserCacheVersion,
|
||||
browserCacheVersionKey,
|
||||
browserStorageCacheExpiration,
|
||||
browserStorageHour,
|
||||
} from './config';
|
||||
import {
|
||||
getBrowserStorageItemsCount,
|
||||
setBrowserStorageItemsCount,
|
||||
} from './count';
|
||||
import {
|
||||
browserStorageConfig,
|
||||
browserStorageEmptyItems,
|
||||
browserStorageLoaded,
|
||||
setBrowserStorageStatus,
|
||||
} from './data';
|
||||
import { getBrowserStorage } from './global';
|
||||
import type { BrowserStorageConfig, BrowserStorageItem } from './types';
|
||||
|
||||
/**
|
||||
* Destroy old cache
|
||||
*/
|
||||
function destroyBrowserStorage(storage: typeof localStorage): void {
|
||||
try {
|
||||
const total = getBrowserStorageItemsCount(storage);
|
||||
for (let i = 0; i < total; i++) {
|
||||
storage.removeItem(browserCachePrefix + i.toString());
|
||||
}
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize storage
|
||||
*/
|
||||
function initBrowserStorage(
|
||||
storage: typeof localStorage,
|
||||
key: keyof BrowserStorageConfig
|
||||
): void {
|
||||
try {
|
||||
storage.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
setBrowserStorageItemsCount(storage, key, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load icons from cache
|
||||
*/
|
||||
export function loadBrowserStorageCache() {
|
||||
if (browserStorageLoaded) {
|
||||
return;
|
||||
}
|
||||
setBrowserStorageStatus(true);
|
||||
|
||||
// Minimum time
|
||||
const minTime =
|
||||
Math.floor(Date.now() / browserStorageHour) -
|
||||
browserStorageCacheExpiration;
|
||||
|
||||
// Load data from storage
|
||||
function load(key: keyof BrowserStorageConfig): void {
|
||||
const func = getBrowserStorage(key);
|
||||
if (!func) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get one item from storage
|
||||
const getItem = (index: number): boolean => {
|
||||
const name = browserCachePrefix + index.toString();
|
||||
const item = func.getItem(name);
|
||||
|
||||
if (typeof item !== 'string') {
|
||||
// Does not exist
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get item, validate it
|
||||
let valid = true;
|
||||
try {
|
||||
// Parse, check time stamp
|
||||
const data = JSON.parse(item) as BrowserStorageItem;
|
||||
if (
|
||||
typeof data !== 'object' ||
|
||||
typeof data.cached !== 'number' ||
|
||||
data.cached < minTime ||
|
||||
typeof data.provider !== 'string' ||
|
||||
typeof data.data !== 'object' ||
|
||||
typeof data.data.prefix !== 'string'
|
||||
) {
|
||||
valid = false;
|
||||
} else {
|
||||
// Add icon set
|
||||
const provider = data.provider;
|
||||
const prefix = data.data.prefix;
|
||||
const storage = getStorage(provider, prefix);
|
||||
valid = addIconSet(storage, data.data).length > 0;
|
||||
}
|
||||
} catch (err) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
func.removeItem(name);
|
||||
}
|
||||
return valid;
|
||||
};
|
||||
|
||||
try {
|
||||
// Get version
|
||||
const version = func.getItem(browserCacheVersionKey);
|
||||
if (version !== browserCacheVersion) {
|
||||
if (version) {
|
||||
// Version is set, but invalid - remove old entries
|
||||
destroyBrowserStorage(func);
|
||||
}
|
||||
// Empty data
|
||||
initBrowserStorage(func, key);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get number of stored items
|
||||
let total = getBrowserStorageItemsCount(func);
|
||||
for (let i = total - 1; i >= 0; i--) {
|
||||
if (!getItem(i)) {
|
||||
// Remove item
|
||||
if (i === total - 1) {
|
||||
// Last item - reduce country
|
||||
total--;
|
||||
} else {
|
||||
// Mark as empty
|
||||
browserStorageEmptyItems[key].push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update total
|
||||
setBrowserStorageItemsCount(func, key, total);
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
for (const key in browserStorageConfig) {
|
||||
load(key as keyof BrowserStorageConfig);
|
||||
}
|
||||
}
|
@ -1,26 +1,22 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
import type { CacheIcons } from '../cache';
|
||||
import { browserCachePrefix, browserStorageHour } from './config';
|
||||
import { setBrowserStorageItemsCount } from './count';
|
||||
import {
|
||||
browserStorageConfig,
|
||||
browserStorageEmptyItems,
|
||||
browserStorageItemsCount,
|
||||
browserStorageLoaded,
|
||||
browserStorageStatus,
|
||||
} from './data';
|
||||
import { getBrowserStorage } from './global';
|
||||
import { loadBrowserStorageCache } from './load';
|
||||
import { initBrowserStorage } from './index';
|
||||
import type { BrowserStorageConfig, BrowserStorageItem } from './types';
|
||||
|
||||
/**
|
||||
* Function to cache icons
|
||||
*/
|
||||
export const storeInBrowserStorage: CacheIcons = (
|
||||
provider: string,
|
||||
data: IconifyJSON
|
||||
): void => {
|
||||
if (!browserStorageLoaded) {
|
||||
loadBrowserStorageCache();
|
||||
export function storeInBrowserStorage(provider: string, data: IconifyJSON) {
|
||||
if (!browserStorageStatus) {
|
||||
initBrowserStorage();
|
||||
}
|
||||
|
||||
function store(key: keyof BrowserStorageConfig): boolean {
|
||||
@ -75,4 +71,4 @@ export const storeInBrowserStorage: CacheIcons = (
|
||||
if (!store('local')) {
|
||||
store('session');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -21,3 +21,6 @@ export interface BrowserStorageItem {
|
||||
provider: string;
|
||||
data: IconifyJSON;
|
||||
}
|
||||
|
||||
// Status: not loaded, loading, loaded
|
||||
export type BrowserStorageStatus = false | 'loading' | true;
|
||||
|
@ -1,15 +0,0 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
|
||||
/**
|
||||
* Function to cache loaded icons set
|
||||
*/
|
||||
export type CacheIcons = (provider: string, data: IconifyJSON) => void;
|
||||
|
||||
/**
|
||||
* Module
|
||||
*/
|
||||
interface CacheModule {
|
||||
store?: CacheIcons;
|
||||
}
|
||||
|
||||
export const cache: CacheModule = {};
|
12
packages/core/tests/cache/basic-test.ts
vendored
12
packages/core/tests/cache/basic-test.ts
vendored
@ -1,4 +1,4 @@
|
||||
import { loadBrowserStorageCache } from '../../lib/browser-storage/load';
|
||||
import { initBrowserStorage } from '../../lib/browser-storage';
|
||||
import {
|
||||
browserStorageItemsCount,
|
||||
browserStorageConfig,
|
||||
@ -28,7 +28,7 @@ describe('Testing mocked localStorage', () => {
|
||||
});
|
||||
|
||||
// Attempt to load
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Everything should be disabled
|
||||
expect(browserStorageConfig).toEqual({
|
||||
@ -59,7 +59,7 @@ describe('Testing mocked localStorage', () => {
|
||||
});
|
||||
|
||||
// Attempt to load
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// sessionStorage should be disabled
|
||||
expect(browserStorageConfig).toEqual({
|
||||
@ -118,7 +118,7 @@ describe('Testing mocked localStorage', () => {
|
||||
});
|
||||
|
||||
// Attempt to load
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Everything should be disabled because read-only mock throws errors
|
||||
expect(browserStorageConfig).toEqual({
|
||||
@ -172,7 +172,7 @@ describe('Testing mocked localStorage', () => {
|
||||
});
|
||||
|
||||
// Attempt to load
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// sessionStorage should be disabled
|
||||
expect(browserStorageConfig).toEqual({
|
||||
@ -204,7 +204,7 @@ describe('Testing mocked localStorage', () => {
|
||||
});
|
||||
|
||||
// Attempt to load
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Everything should be working
|
||||
expect(browserStorageConfig).toEqual({
|
||||
|
18
packages/core/tests/cache/loading-test.ts
vendored
18
packages/core/tests/cache/loading-test.ts
vendored
@ -1,6 +1,6 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
import type { BrowserStorageItem } from '../../lib/browser-storage/types';
|
||||
import { loadBrowserStorageCache } from '../../lib/browser-storage/load';
|
||||
import { initBrowserStorage } from '../../lib/browser-storage';
|
||||
import {
|
||||
browserStorageItemsCount,
|
||||
browserStorageConfig,
|
||||
@ -52,7 +52,7 @@ describe('Testing loading from localStorage', () => {
|
||||
expect(iconExists(icons, 'foo')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should exist now
|
||||
expect(iconExists(icons, 'foo')).toBe(true);
|
||||
@ -109,7 +109,7 @@ describe('Testing loading from localStorage', () => {
|
||||
expect(iconExists(icons2, 'foo')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should exist now
|
||||
expect(iconExists(icons, 'foo')).toBe(true);
|
||||
@ -166,7 +166,7 @@ describe('Testing loading from localStorage', () => {
|
||||
expect(iconExists(icons, 'foo')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should not have loaded
|
||||
expect(iconExists(icons, 'foo')).toBe(false);
|
||||
@ -220,7 +220,7 @@ describe('Testing loading from localStorage', () => {
|
||||
expect(iconExists(icons, 'foo')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should not have loaded
|
||||
expect(iconExists(icons, 'foo')).toBe(false);
|
||||
@ -272,7 +272,7 @@ describe('Testing loading from localStorage', () => {
|
||||
expect(iconExists(icons, 'foo')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should not have loaded
|
||||
expect(iconExists(icons, 'foo')).toBe(false);
|
||||
@ -324,7 +324,7 @@ describe('Testing loading from localStorage', () => {
|
||||
expect(iconExists(icons, 'foo')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should exist now
|
||||
expect(iconExists(icons, 'foo')).toBe(true);
|
||||
@ -392,7 +392,7 @@ describe('Testing loading from localStorage', () => {
|
||||
expect(iconExists(icons, 'foo4')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Icons should exist now
|
||||
expect(iconExists(icons, 'foo1')).toBe(true);
|
||||
@ -476,7 +476,7 @@ describe('Testing loading from localStorage', () => {
|
||||
}
|
||||
|
||||
// Load localStorage
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Icons should exist now, except for number 4
|
||||
for (let i = 0; i < 6; i++) {
|
||||
|
12
packages/core/tests/cache/saving-test.ts
vendored
12
packages/core/tests/cache/saving-test.ts
vendored
@ -1,7 +1,7 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
import type { BrowserStorageItem } from '../../lib/browser-storage/types';
|
||||
import { storeInBrowserStorage } from '../../lib/browser-storage/store';
|
||||
import { loadBrowserStorageCache } from '../../lib/browser-storage/load';
|
||||
import { initBrowserStorage } from '../../lib/browser-storage';
|
||||
import {
|
||||
browserStorageItemsCount,
|
||||
browserStorageConfig,
|
||||
@ -188,7 +188,7 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Load data
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
@ -281,7 +281,7 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Load data
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
@ -399,7 +399,7 @@ describe('Testing saving to localStorage', () => {
|
||||
expect(iconExists(icons, 'foo1')).toBe(false);
|
||||
|
||||
// Load cache
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
@ -516,7 +516,7 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Load data
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
@ -631,7 +631,7 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Load data
|
||||
loadBrowserStorageCache();
|
||||
initBrowserStorage();
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
|
Loading…
Reference in New Issue
Block a user