summaryrefslogtreecommitdiffstats
path: root/ogcp
diff options
context:
space:
mode:
authorAlejandro Sirgo Rica <asirgo@soleta.eu>2024-09-16 17:29:14 +0200
committerAlejandro Sirgo Rica <asirgo@soleta.eu>2024-09-16 17:29:14 +0200
commitf03077edb70e939bfb447fea4cf46340f736b657 (patch)
treeb59e2d4eb5748d13db4123396446a6f087035475 /ogcp
parent7296372e9c7ff7c354c86c00fa4fbcfbd71df355 (diff)
js: add ogStorage to prevent localStorage key collission
Define ogStorage class to manage the localStorage operations. The new keys are constructed with the following structure: "group-context-id" Where group is either "show" for the collapsed items in the sidebar, or "check" for the selected checkboxes of the sidebar. Add sotrage versioning to delete obsolete localStorage when a new design for the storage is included in ogCP.
Diffstat (limited to 'ogcp')
-rw-r--r--ogcp/static/js/ogcp.js113
-rw-r--r--ogcp/templates/base.html2
-rw-r--r--ogcp/templates/images.html2
-rw-r--r--ogcp/templates/macros.html2
-rw-r--r--ogcp/templates/repos.html2
5 files changed, 77 insertions, 44 deletions
diff --git a/ogcp/static/js/ogcp.js b/ogcp/static/js/ogcp.js
index d445094..943fccf 100644
--- a/ogcp/static/js/ogcp.js
+++ b/ogcp/static/js/ogcp.js
@@ -3,6 +3,61 @@ const macs = new Map();
const Interval = 1000;
let updateTimeoutId = null;
+const StorageGroup = Object.freeze({
+ SHOW: 'show',
+ CHECK: 'check',
+});
+
+class ogStorage {
+ static STORAGE_VERSION = Object.freeze(1);
+
+ static store(group, context, elemId, value) {
+ const key = `${group}-${context}-${elemId}`;
+ localStorage.setItem(key, value);
+ }
+
+ static remove(group, context, elemId) {
+ const key = `${group}-${context}-${elemId}`;
+ localStorage.removeItem(key);
+ }
+
+ static hasKey(group, context, elemId) {
+ const key = `${group}-${context}-${elemId}`;
+ return localStorage.getItem(key) !== null;
+ }
+
+ static deleteInvalidStorage(items, group, context) {
+ if (localStorage.getItem('storageVersion') < ogStorage.STORAGE_VERSION) {
+ localStorage.clear();
+ localStorage.setItem('storageVersion', ogStorage.STORAGE_VERSION);
+ return
+ }
+
+ const prefix = `${group}-${context}`;
+ const existingKeys = items.map(function() {
+ return `${group}-${context}-${this.id}`;
+ }).get();
+
+ for (let i = 0; i < localStorage.length; i++) {
+ const key = localStorage.key(i);
+
+ if (!key.startsWith(prefix)) {
+ continue;
+ }
+ if (!existingKeys.includes(key)) {
+ localStorage.removeItem(key);
+ }
+ }
+ }
+
+ static storeCheckboxStatus(checkbox, context) {
+ if (checkbox.checked)
+ ogStorage.store(StorageGroup.CHECK, context, checkbox.id, "");
+ else
+ ogStorage.remove(StorageGroup.CHECK, context, checkbox.id);
+ }
+}
+
async function show_client_mac(pill_id) {
const pill = $('#' +pill_id);
@@ -54,13 +109,6 @@ function showSelectedClientsOnEvents() {
});
}
-function storeCheckboxStatus(checkbox, context) {
- if (checkbox.checked)
- localStorage.setItem(context + checkbox.id, "check");
- else
- localStorage.removeItem(context + checkbox.id);
-}
-
function findParentCheckboxes(element) {
const $element = $(element);
const parents = $element.parentsUntil('#scopes').not('ul');
@@ -89,27 +137,10 @@ function setParentStatus(checkboxes) {
});
}
-function deleteInvalidStorageItems(items, context) {
- const existingIds = items.map(function() {
- return context + this.id;
- }).get();
-
- for (let i = 0; i < localStorage.length; i++) {
- const key = localStorage.key(i);
-
- if (!key.startsWith(context)) {
- continue;
- }
- if (!existingIds.includes(key)) {
- localStorage.removeItem(key);
- }
- }
-}
-
function configureCommandCheckboxes(context) {
const checkboxes = $('input:checkbox[form="scopesForm"]');
- deleteInvalidStorageItems(checkboxes, context);
+ ogStorage.deleteInvalidStorage(checkboxes, StorageGroup.CHECK, context);
// Ensure the form fields are sent
$('#scopesForm').on('submit', function() {
@@ -151,7 +182,7 @@ function configureCommandCheckboxes(context) {
checkboxes.each(function() {
showSelectedClient(this);
- storeCheckboxStatus(this, context);
+ ogStorage.storeCheckboxStatus(this, context);
});
});
}
@@ -160,33 +191,35 @@ function keepSelectedClients(context) {
const checkboxes = $('#sidebar input:checkbox')
checkboxes.on('change', function (event) {
- storeCheckboxStatus(this, context);
+ ogStorage.storeCheckboxStatus(this, context);
});
- deleteInvalidStorageItems(checkboxes, context);
+ ogStorage.deleteInvalidStorage(checkboxes, StorageGroup.CHECK, context);
checkboxes.each(function () {
- if (localStorage.getItem(context + this.id) == 'check') {
+ if (ogStorage.hasKey(StorageGroup.CHECK, context, this.id)) {
this.checked = true;
$(this).trigger('show-client');
}
});
}
-function keepTreeState(selector) {
- const tree = $(selector + ' .collapse');
+function keepTreeState(selector, context) {
+ const tree_items = $(selector + ' .collapse');
+
+ ogStorage.deleteInvalidStorage(tree_items, StorageGroup.SHOW, context);
- tree.on('hidden.bs.collapse', function (event) {
+ tree_items.on('hidden.bs.collapse', function (event) {
event.stopPropagation();
- localStorage.removeItem(this.id);
+ ogStorage.remove(StorageGroup.SHOW, context, this.id)
});
- tree.on('shown.bs.collapse', function (event) {
+ tree_items.on('shown.bs.collapse', function (event) {
event.stopPropagation();
- localStorage.setItem(this.id, 'show');
+ ogStorage.store(StorageGroup.SHOW, context, this.id, "")
});
- tree.each(function () {
- if (localStorage.getItem(this.id) == 'show') {
+ tree_items.each(function () {
+ if (ogStorage.hasKey(StorageGroup.SHOW, context, this.id)) {
$(this).collapse('show');
} else {
$(this).siblings('a').addClass('collapsed');
@@ -324,14 +357,14 @@ function checkFolderParent(context) {
folder.on('change', function() {
const folder_parent = $('#' + $.escapeSelector(this.dataset.parentInput));
folder_parent.prop('checked', this.checked);
- storeCheckboxStatus(folder_parent.get(0), context);
+ ogStorage.storeCheckboxStatus(folder_parent.get(0), context);
});
}
function limitCheckboxes(context) {
const checkboxes = $('#sidebar input:checkbox');
- deleteInvalidStorageItems(checkboxes, context);
+ ogStorage.deleteInvalidStorage(checkboxes, StorageGroup.CHECK, context);
checkboxes.on('change', function () {
const currentCheckbox = $(this);
@@ -353,7 +386,7 @@ function limitCheckboxes(context) {
checkCheckbox('scope-server');
checkboxes.each(function() {
- storeCheckboxStatus(this, context);
+ ogStorage.storeCheckboxStatus(this, context);
showSelectedClient(this);
});
});
diff --git a/ogcp/templates/base.html b/ogcp/templates/base.html
index 80a5f7a..5aa84c6 100644
--- a/ogcp/templates/base.html
+++ b/ogcp/templates/base.html
@@ -111,7 +111,7 @@
<!-- ChartJS -->
<script src="{{ url_for('static', filename='AdminLTE/plugins/chart.js/Chart.min.js') }}"></script>
- <script src="{{ url_for('static', filename='js/ogcp.js') }}?v=22"></script>
+ <script src="{{ url_for('static', filename='js/ogcp.js') }}?v=24"></script>
<script>
// error messages
diff --git a/ogcp/templates/images.html b/ogcp/templates/images.html
index 7a16a0d..06d614a 100644
--- a/ogcp/templates/images.html
+++ b/ogcp/templates/images.html
@@ -14,7 +14,7 @@
// in the scope
document.addEventListener('readystatechange', () => {
if (document.readyState === 'complete') {
- keepTreeState('#servers');
+ keepTreeState('#servers', 'images');
keepSelectedClients('images');
checkOnChange('image-server');
}
diff --git a/ogcp/templates/macros.html b/ogcp/templates/macros.html
index 16b3017..790da6d 100644
--- a/ogcp/templates/macros.html
+++ b/ogcp/templates/macros.html
@@ -10,7 +10,7 @@
if (document.readyState === 'complete') {
showSelectedClientsOnEvents();
updateScopeState();
- keepTreeState('#scopes');
+ keepTreeState('#scopes', 'scopes');
let context = {{ selection_mode | tojson | safe }};
{% if selection_mode == 'commands' %}
configureCommandCheckboxes(context);
diff --git a/ogcp/templates/repos.html b/ogcp/templates/repos.html
index 2f5fe1b..7983930 100644
--- a/ogcp/templates/repos.html
+++ b/ogcp/templates/repos.html
@@ -43,7 +43,7 @@
// in the scope
document.addEventListener('readystatechange', () => {
if (document.readyState === 'complete') {
- keepTreeState('#repos-list')
+ keepTreeState('#repos-list', 'repos');
keepSelectedClients('repos');
checkOnChange('repos-server');
}