-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1230 from dbauszus-glx/user-IndexedDB
User IndexedDB
- Loading branch information
Showing
7 changed files
with
330 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
export function userIDB(plugin, mapview) { | ||
|
||
if (!mapp.user?.email) { | ||
|
||
console.warn(`The userIDB plugin requires a mapp.user`) | ||
return; | ||
} | ||
|
||
// Find the btnColumn element. | ||
const btnColumn = document.getElementById('mapButton'); | ||
|
||
if (!btnColumn) return; | ||
|
||
plugin.title ??= "Update userIDB locale" | ||
|
||
// Append the plugin btn to the btnColumn. | ||
btnColumn.append(mapp.utils.html.node` | ||
<button | ||
title=${plugin.title} | ||
onclick=${()=>{ | ||
mapview.locale.layers.forEach(layer => { | ||
if (typeof layer !== 'object') return; | ||
updateLayer(layer, mapview.layers[layer.key]) | ||
}) | ||
mapp.utils.userIndexedDB.put('locales', mapview.locale) | ||
alert(`User ${mapp.user.email} IndexedDB updated.`) | ||
}}> | ||
<div class="mask-icon" style="mask-image:url(https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsoutlined/rule_settings/default/24px.svg)">`); | ||
} | ||
|
||
function updateLayer(layer, _layer) { | ||
|
||
if (!_layer) return; | ||
|
||
Object.keys(_layer).forEach(key => { | ||
|
||
if (_layer[key] === undefined) return; | ||
|
||
if (_layer[key] === null) { | ||
layer[key] = null; | ||
} | ||
|
||
if (typeof _layer[key] === 'function') return; | ||
|
||
if (typeof _layer[key] === 'object') return; | ||
|
||
layer[key] = _layer[key] | ||
}) | ||
|
||
return layer; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
/** | ||
* ### mapp.utils.userIndexedDB | ||
* This [indexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Basic_Terminology) implementation allows to store, get, and update a locale object from the 'locales' object store in a user indexedDB. | ||
* | ||
* There are many different operations that the indexedDB can handle. Typically the operations are CRUD. | ||
* | ||
* The `userIndexDB` methods have all been moved to the `mapp.utils` object. | ||
* | ||
* The logic for initialisation for the userIndexedDB object is the following: | ||
* - `userIndexedDB.open(store)` will open a DB with the following name `${mapp.user.email} - {mapp.user.title}. | ||
* - The database will not be created if there is a pre-existing DB. | ||
* - The creation will trigger the `onupgradeneeded` event which checks whether the request `store` exists in the userIndexedDB. | ||
* | ||
* The `process.env.TITLE` will be added to the user object in the cookie module. | ||
* The `user.title` is required to generate a unique indexedDB for each user[email/instance[title]] | ||
* | ||
* All object stores use the key value as a keypath for object indicies. | ||
* | ||
* Adding the url parameter `useridb=true` will ask the default script to get the keyed locale from the user indexedDB. | ||
* The userLocale will be assigned as locale if available. | ||
* | ||
* ```js | ||
* if (mapp.hooks.current.useridb) { | ||
let userLocale = await mapp.utils.userIndexedDB.get('locales', locale.key) | ||
if (!userLocale) { | ||
await mapp.utils.userIndexedDB.add('locales', locale) | ||
} else { | ||
locale = userLocale | ||
} | ||
} | ||
* ``` | ||
* | ||
* The userIDB plugin adds a button to put [update] the locale in the user indexedDB. | ||
* | ||
* ```js | ||
* export function userIDB(plugin, mapview) { | ||
// Find the btnColumn element. | ||
const btnColumn = document.getElementById('mapButton'); | ||
if (!btnColumn) return; | ||
// Append the plugin btn to the btnColumn. | ||
btnColumn.append(mapp.utils.html.node` | ||
<button | ||
title="Update userIDB locale" | ||
onclick=${()=>{ | ||
mapp.utils.userIndexedDB.put('locales', mapview.locale) | ||
}}> | ||
<div class="mask-icon" style="mask-image:url(https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsoutlined/rule_settings/default/24px.svg)">`); | ||
} | ||
* ``` | ||
* This can be tested but updating the mapview.locale in another plugin, e.g. dark_mode | ||
* | ||
* The enabled status will be stored with the local applying the setting when the locale is loaded with the useridb=true url param. | ||
* | ||
* ```js | ||
* mapp.plugins.dark_mode = (plugin, mapview) => { | ||
// Get the map button | ||
const mapButton = document.getElementById("mapButton"); | ||
// If mapbutton doesn't exist, return (for custom views). | ||
if (!mapButton) return; | ||
// toggle dark_mode if enabled in config. | ||
mapview.locale.dark_mode.enabled && toggleDarkMode() | ||
// If the button container exists, append the dark mode button. | ||
mapButton.append(mapp.utils.html.node` | ||
<button | ||
title="Color Mode" | ||
class="btn-color-mode" | ||
onclick=${()=>{ | ||
mapview.locale.dark_mode.enabled = toggleDarkMode() | ||
}}> | ||
<div class="mask-icon">`); | ||
} | ||
* ``` | ||
* | ||
* @module /utils/userIndexedDB | ||
*/ | ||
|
||
let IDB | ||
|
||
/** | ||
* @param {Object} store | ||
* @returns {Promise} OpenDBPromise | ||
*/ | ||
export async function openDB(_store) { | ||
|
||
const store = _store.toString() | ||
|
||
const OpenDBPromise = new Promise((resolve, reject) => { | ||
|
||
// will create a new database if db/version doesn't exist. | ||
const IDBRequest = indexedDB.open(`${mapp.user.email} - ${mapp.user.title}`, 3); | ||
|
||
IDBRequest.onerror = (event) => { | ||
console.error(IDBRequest.error) | ||
resolve(IDBRequest) | ||
}; | ||
|
||
IDBRequest.onsuccess = (event) => { | ||
|
||
if (!event.target.result.objectStoreNames.contains(store)) { | ||
|
||
console.warn(`UserIDB doesn't contain "${store}" objectStore.`) | ||
|
||
IDB = null | ||
resolve() | ||
} | ||
|
||
IDB = event.target.result | ||
resolve() | ||
} | ||
|
||
// will be called on database versioning. | ||
IDBRequest.onupgradeneeded = (event) => { | ||
|
||
// onsuccess method will be called after the object store is created. | ||
event.target.result.createObjectStore(store, { keyPath: 'key' }); | ||
}; | ||
}) | ||
|
||
await OpenDBPromise | ||
|
||
return OpenDBPromise | ||
} | ||
|
||
/** | ||
* - deletes the user indexedDB. | ||
* @function deleteDB | ||
*/ | ||
export function deleteDB() { | ||
|
||
if (!mapp.user) return; | ||
|
||
indexedDB.deleteDatabase(`${mapp.user.email} - ${mapp.user.title}`) | ||
|
||
console.log('Database deleted') | ||
} | ||
|
||
/** | ||
* - Adds the keyed object to the named store. | ||
* - The key will be returned on success. | ||
* - Adding the same keyed object twice will result in an error. | ||
* @function add | ||
* @param {Object} store | ||
* @param {Object} obj | ||
* @returns {Promise} addPromise | ||
*/ | ||
export async function add(store, obj) { | ||
|
||
if (!IDB) await openDB(store) | ||
|
||
const addPromise = new Promise((resolve, reject) => { | ||
|
||
const IDBTransaction = IDB.transaction([store], 'readwrite'); | ||
|
||
const objectStore = IDBTransaction.objectStore(store) | ||
|
||
const IDBRequest = objectStore.add(obj); | ||
|
||
IDBRequest.onerror = (event) => { | ||
console.error(IDBRequest.error) | ||
resolve(IDBRequest) | ||
}; | ||
|
||
IDBRequest.onsuccess = (event) => { | ||
resolve(event.target.result) | ||
}; | ||
}) | ||
|
||
await addPromise | ||
|
||
return addPromise | ||
} | ||
|
||
/** | ||
* - Gets the keyed object from the named store. | ||
* @param {Object} store | ||
* @param {string} key | ||
* @returns {Promise} getPromise | ||
*/ | ||
export async function get(store, key) { | ||
|
||
if (!IDB) await openDB(store) | ||
|
||
const getPromise = new Promise((resolve, reject) => { | ||
|
||
const IDBTransaction = IDB.transaction([store], 'readwrite'); | ||
|
||
const objectStore = IDBTransaction.objectStore(store) | ||
|
||
const IDBRequest = objectStore.get(key); | ||
|
||
IDBRequest.onerror = (event) => { | ||
console.error(IDBRequest.error) | ||
reject(IDBRequest) | ||
}; | ||
|
||
IDBRequest.onsuccess = (event) => { | ||
resolve(IDBRequest.result) | ||
}; | ||
}) | ||
|
||
await getPromise | ||
|
||
return getPromise | ||
} | ||
|
||
/** | ||
* - puts the keyed object to the named store. | ||
* - This will override the existing keyed object. | ||
* - Updates work by replacing (put) the same keyed object into an user indexedDB. | ||
* @param {Object} store | ||
* @param {Object} obj | ||
* @returns {Promise} updatePromise | ||
*/ | ||
export async function put(store, obj) { | ||
|
||
if (!IDB) await openDB(store) | ||
|
||
const updatePromise = new Promise((resolve, reject) => { | ||
|
||
const IDBTransaction = IDB.transaction([store], 'readwrite'); | ||
|
||
const objectStore = IDBTransaction.objectStore(store) | ||
|
||
const IDBRequest = objectStore.put(obj); | ||
|
||
IDBRequest.onerror = (event) => { | ||
console.error(IDBRequest.error) | ||
reject(IDBRequest) | ||
}; | ||
|
||
IDBRequest.onsuccess = (event) => { | ||
resolve(IDBRequest.result) | ||
}; | ||
}) | ||
|
||
await updatePromise | ||
|
||
return updatePromise | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters