Allow browser storage plugin to delete existing tiddlers (#6625)

* Do not remove localstorage items while looping

While looping over all the browser storage items by index, the items
should not be removed because removing alters the index positions. The
item following the removed one will be skipped by the loop.

Instead, accumulate a list of keys to remove and remove them after the
loop.

* Implement full delete support for browser storage plugin

Before, deletes only worked for tiddlers which are only present in the
localstorage. Now deleted tiddlers are marked in localstorage using an
empty string value.

At startup, the localstorage tiddlers with empty strings will be deleted
from the wiki if they are still present. If they are already gone from
the wiki, then the blank localstorage entry will be deleted.

* Document drawbacks to using '[all[]]' and provide an alternative
This commit is contained in:
btheado 2022-04-12 17:11:37 -04:00 committed by GitHub
parent 73138b79aa
commit 8a9d48e055
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 28 additions and 5 deletions

View File

@ -26,6 +26,7 @@ if(Object.prototype.hasOwnProperty.call($tw.hooks.names,hookName)) {
// Load tiddlers from browser storage
function hookBootTiddlersLoaded() {
var url = window.location.pathname,
keysToDelete = [],
log = [];
// Check that browser storage is available
try {
@ -55,16 +56,32 @@ function hookBootTiddlersLoaded() {
existingTiddler = $tw.wiki.getTiddler(title);
if(existingTiddler && existingTiddler.isEqual(incomingTiddler)) {
// If the incoming tiddler is the same as the existing then we can delete the local storage version
window.localStorage.removeItem(key);
// Defer deletion until after this loop, since deleting will shift the index and cause the
// index+1 item to be skipped.
keysToDelete.push(key);
} else {
$tw.wiki.addTiddler(incomingTiddler);
log.push(title);
}
}
}
} else {
// Empty value means the tiddler is marked as deleted
var title = parts.slice(2).join("#"),
existingTiddler = $tw.wiki.getTiddler(title);
if(existingTiddler) {
// The tiddler still exists in the wiki. Delete it so it won't be visible.
$tw.wiki.deleteTiddler(title);
} else {
// The tiddler is already missing from the wiki, so delete the blank local storage entry
keysToDelete.push(key);
}
}
}
}
$tw.utils.each(keysToDelete,function(key) {
window.localStorage.removeItem(key);
});
// Make sure that all the tiddlers we've loaded are marked as dirty at startup
Array.prototype.push.apply($tw.boot.preloadDirty,log);
// Save the log

View File

@ -15,5 +15,4 @@ Please use this plugin with caution. There are a number of unresolved issues and
* Innerwikis read the local storage of their parent wikis
* This plugin does not interfere with the existing saver mechanism, so you'll still get warnings when refreshing the page, even if your changes are safely committed to local storage
* Deleted tiddlers will be restored when the wiki is refreshed
* There is a possibility that tiddlers might be transferred between different wikis if they are accessed via the same URL. This is particularly likely when running in local client server configuration under Node.js

View File

@ -14,7 +14,11 @@ Click this button to clear browser storage and disable its use:
! Save Filter
This filter determines which tiddlers will be saved to local storage. By default, it contains `[prefix[$:/state/]] -[prefix[$:/state/popup/]]` to just save state tiddlers except popup state tiddlers, thus preserving selected tabs, and the open/closed status of table of contents entries. Other useful values include `[all[]]` meaning that it will attempt to save all tiddlers.
This filter determines which tiddlers will be saved to local storage.
* `[prefix[$:/state/]] -[prefix[$:/state/popup/]]` - the default value. Save state tiddlers except popup state tiddlers, thus preserving selected tabs and the open/closed status of table of contents entries. Any other tiddlers created or changed will be lost after reloading the page.
* `[all[]]` - attempt to save all changed tiddlers. This means even popup state tiddlers and temporary tiddlers will be saved. In addition, when a plugin is installed, all the shadow tiddlers are individually "exploded" into local storage. Deleting the plugin requires deleting all the tiddlers individually. Not recommended unless these issues are unimportant.
* `[all[]] -[is[shadow]!is[tiddler]] -[prefix[$:/state/popup/]] -[prefix[$:/temp/]] -[prefix[$:/HistoryList]]` - save all tiddlers except unmodified shadow tiddlers, popup state tiddlers, temp tiddlers and the history list. Solves the aforementioned issues with `[all[]]`. Recommended.
<$link to="$:/config/BrowserStorage/SaveFilter">Browser Storage Save Filter</$link>: <$edit-text tiddler="$:/config/BrowserStorage/SaveFilter" default="" tag="input" size="50"/>

View File

@ -100,9 +100,12 @@ function saveTiddlerToLocalStorage(title,options) {
}
}
} else {
console.log("browser-storage: Deleting",title);
// In local storage, use the special value of empty string to mark the tiddler as deleted
// On future page loads, if the tiddler is already gone from startup then the blank entry
// will be removed from localstorage. Otherwise, the tiddler will be deleted.
console.log("browser-storage: Blanking",title);
try {
window.localStorage.removeItem(options.prefix + title);
window.localStorage.setItem(options.prefix + title, "");
} catch(e) {
console.log("Browser-storage error:",e);
}