From 86d45f1c3d7f617223d1c13e6fd8aa588b13c486 Mon Sep 17 00:00:00 2001 From: btheado Date: Tue, 13 Jun 2023 04:50:00 -0500 Subject: [PATCH] Request permission to protect local storage from eviction (#7398) * Request the browser to never evict the persistent storage * Store browser storage persisted state in a tiddler * Factor out some code into helper functions * Display status of persistence request in the settings page --- .../tiddlywiki/browser-storage/settings.tid | 10 ++++ plugins/tiddlywiki/browser-storage/startup.js | 49 ++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/plugins/tiddlywiki/browser-storage/settings.tid b/plugins/tiddlywiki/browser-storage/settings.tid index 7bf0e26e5..eb2e27940 100644 --- a/plugins/tiddlywiki/browser-storage/settings.tid +++ b/plugins/tiddlywiki/browser-storage/settings.tid @@ -28,6 +28,16 @@ This setting allows a custom alert message to be displayed when an attempt to st <$link to="$:/config/BrowserStorage/QuotaExceededAlert">Quota Exceeded Alert: <$edit-text tiddler="$:/config/BrowserStorage/QuotaExceededAlert" default="" tag="input" size="50"/> +! Prevent browser from evicting local storage + +Permission for local storage persistence: ''{{$:/info/browser/storage/persisted}}'' + +The first time a tiddler is saved to local storage a request will be made to prevent automatic eviction of local storage for this site. This means the data will not be cleared unless the user manually clears it. + +Old browsers may not support this feature. New browsers might not support the feature if the wiki is hosted on a non-localhost unencrypted http connection. + +Some browsers will explicitly prompt the user for permission. Other browsers may automatically grant or deny the request based on site usage or based on whether the site is bookmarked. + ! Startup Log The tiddler $:/temp/BrowserStorage/Log contains a log of the tiddlers that were loaded from local storage at startup: diff --git a/plugins/tiddlywiki/browser-storage/startup.js b/plugins/tiddlywiki/browser-storage/startup.js index 69cc5119e..552de93d2 100644 --- a/plugins/tiddlywiki/browser-storage/startup.js +++ b/plugins/tiddlywiki/browser-storage/startup.js @@ -19,7 +19,8 @@ exports.after = ["startup"]; exports.synchronous = true; var ENABLED_TITLE = "$:/config/BrowserStorage/Enabled", - SAVE_FILTER_TITLE = "$:/config/BrowserStorage/SaveFilter"; + SAVE_FILTER_TITLE = "$:/config/BrowserStorage/SaveFilter", + PERSISTED_STATE_TITLE = "$:/info/browser/storage/persisted"; var BrowserStorageUtil = require("$:/plugins/tiddlywiki/browser-storage/util.js").BrowserStorageUtil; @@ -53,6 +54,48 @@ exports.startup = function() { $tw.wiki.addTiddler({title: ENABLED_TITLE, text: "no"}); $tw.browserStorage.clearLocalStorage(); }); + // Helpers for protecting storage from eviction + var setPersistedState = function(state) { + $tw.wiki.addTiddler({title: PERSISTED_STATE_TITLE, text: state}); + }, + requestPersistence = function() { + setPersistedState("requested"); + navigator.storage.persist().then(function(persisted) { + console.log("Request for persisted storage " + (persisted ? "granted" : "denied")); + setPersistedState(persisted ? "granted" : "denied"); + }); + }, + persistPermissionRequested = false, + requestPersistenceOnFirstSave = function() { + $tw.hooks.addHook("th-saving-tiddler", function(tiddler) { + if (!persistPermissionRequested) { + var filteredChanges = filterFn.call($tw.wiki, function(iterator) { + iterator(tiddler,tiddler.getFieldString("title")); + }); + if (filteredChanges.length > 0) { + // The tiddler will be saved to local storage, so request persistence + requestPersistence(); + persistPermissionRequested = true; + } + } + return tiddler; + }); + }; + // Request the browser to never evict the localstorage. Some browsers such as firefox + // will prompt the user. To make the decision easier for the user only prompt them + // when they click the save button on a tiddler which will be stored to localstorage. + if (navigator.storage && navigator.storage.persist) { + navigator.storage.persisted().then(function(isPersisted) { + if (!isPersisted) { + setPersistedState("not requested yet"); + requestPersistenceOnFirstSave(); + } else { + setPersistedState("granted"); + } + }); + } else { + setPersistedState("feature not available"); + } // Track tiddler changes $tw.wiki.addEventListener("change",function(changes) { // Bail if browser storage is disabled @@ -76,6 +119,10 @@ exports.startup = function() { if(title === ENABLED_TITLE) { return; } + // This should always be queried from the browser, so don't store it in local storage + if(title === PERSISTED_STATE_TITLE) { + return; + } // Save the tiddler $tw.browserStorage.saveTiddlerToLocalStorage(title); });