mirror of
				https://github.com/Jermolene/TiddlyWiki5
				synced 2025-10-31 15:42:59 +00:00 
			
		
		
		
	Automatic sync of tiddler changes in browser storage when sync connection is re-established (#7169)
* Add automatic sync of tiddler changes in browswer-storage on restoration of server connection in tiddlywebadaptor * Fix issue with new tiddlers not being synced. * Fix issue with new tiddlers not being synced. * Added logging * Modified browser-storage plugin. Refactored into utility class. * Modified browser-storage plugin. Refactored into utility class. * Fix: browser storage config tiddler created on load only if not already exists * Fix: Removed extra indent in util.js
This commit is contained in:
		| @@ -14,7 +14,6 @@ $tw = window.$tw || Object.create(null); | |||||||
| $tw.hooks = $tw.hooks || { names: {}}; | $tw.hooks = $tw.hooks || { names: {}}; | ||||||
| $tw.boot = $tw.boot || {}; | $tw.boot = $tw.boot || {}; | ||||||
| $tw.boot.preloadDirty = $tw.boot.preloadDirty || []; | $tw.boot.preloadDirty = $tw.boot.preloadDirty || []; | ||||||
|  |  | ||||||
| // Hook the point in the startup process when the tiddlers have been loaded but plugins not unpacked | // Hook the point in the startup process when the tiddlers have been loaded but plugins not unpacked | ||||||
| var hookName = "th-boot-tiddlers-loaded"; | var hookName = "th-boot-tiddlers-loaded"; | ||||||
| if(Object.prototype.hasOwnProperty.call($tw.hooks.names,hookName)) { | if(Object.prototype.hasOwnProperty.call($tw.hooks.names,hookName)) { | ||||||
|   | |||||||
| @@ -19,19 +19,29 @@ exports.after = ["startup"]; | |||||||
| exports.synchronous = true; | exports.synchronous = true; | ||||||
|  |  | ||||||
| var ENABLED_TITLE = "$:/config/BrowserStorage/Enabled", | var ENABLED_TITLE = "$:/config/BrowserStorage/Enabled", | ||||||
| 	SAVE_FILTER_TITLE = "$:/config/BrowserStorage/SaveFilter", | 	SAVE_FILTER_TITLE = "$:/config/BrowserStorage/SaveFilter"; | ||||||
| 	QUOTA_EXCEEDED_ALERT_TITLE = "$:/config/BrowserStorage/QuotaExceededAlert", |  | ||||||
| 	DEFAULT_QUOTA_EXCEEDED_ALERT_PREFIX = "Quota exceeded attempting to store `", | var BrowserStorageUtil = require("$:/plugins/tiddlywiki/browser-storage/util.js").BrowserStorageUtil; | ||||||
| 	DEFAULT_QUOTA_EXCEEDED_ALERT_SUFFIX = "` in browser local storage"; |  | ||||||
|  |  | ||||||
| exports.startup = function() { | exports.startup = function() { | ||||||
| 	var self = this; | 	var self = this; | ||||||
|  | 	 | ||||||
|  |         // If not exists, add ENABLED tiddler with default value "yes" | ||||||
|  |         if(!$tw.wiki.getTiddler(ENABLED_TITLE)) { | ||||||
|  |                 $tw.wiki.addTiddler({title: ENABLED_TITLE, text: "yes"}); | ||||||
|  |         } | ||||||
| 	// Compute our prefix for local storage keys | 	// Compute our prefix for local storage keys | ||||||
| 	var prefix = "tw5#" + window.location.pathname + "#"; | 	var prefix = "tw5#" + window.location.pathname + "#"; | ||||||
| 	// Make a logger | 	// Make a logger | ||||||
| 	var logger = new $tw.utils.Logger("browser-storage",{ | 	var logger = new $tw.utils.Logger("browser-storage",{ | ||||||
| 			colour: "cyan" | 			colour: "cyan" | ||||||
| 		}); | 		}); | ||||||
|  | 	// Add browserStorage object to $tw | ||||||
|  | 	$tw.browserStorage = new BrowserStorageUtil($tw.wiki,{ | ||||||
|  | 		enabledTitle: ENABLED_TITLE, | ||||||
|  | 		prefix: prefix, | ||||||
|  | 		logger: logger | ||||||
|  | 	}); | ||||||
| 	// Function to compile the filter | 	// Function to compile the filter | ||||||
| 	var filterFn, | 	var filterFn, | ||||||
| 		compileFilter = function() { | 		compileFilter = function() { | ||||||
| @@ -41,7 +51,7 @@ exports.startup = function() { | |||||||
| 	// Listen for tm-clear-browser-storage messages | 	// Listen for tm-clear-browser-storage messages | ||||||
| 	$tw.rootWidget.addEventListener("tm-clear-browser-storage",function(event) { | 	$tw.rootWidget.addEventListener("tm-clear-browser-storage",function(event) { | ||||||
| 		$tw.wiki.addTiddler({title: ENABLED_TITLE, text: "no"}); | 		$tw.wiki.addTiddler({title: ENABLED_TITLE, text: "no"}); | ||||||
| 		clearLocalStorage(); | 		$tw.browserStorage.clearLocalStorage(); | ||||||
| 	}); | 	}); | ||||||
| 	// Track tiddler changes | 	// Track tiddler changes | ||||||
| 	$tw.wiki.addEventListener("change",function(changes) { | 	$tw.wiki.addEventListener("change",function(changes) { | ||||||
| @@ -67,65 +77,9 @@ exports.startup = function() { | |||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 			// Save the tiddler | 			// Save the tiddler | ||||||
| 			saveTiddlerToLocalStorage(title,{ | 			$tw.browserStorage.saveTiddlerToLocalStorage(title); | ||||||
| 				logger: logger, |  | ||||||
| 				prefix: prefix |  | ||||||
| 			}); |  | ||||||
| 		}); | 		}); | ||||||
| 	}); | 	}); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| function saveTiddlerToLocalStorage(title,options) { |  | ||||||
| 	options = options || {}; |  | ||||||
| 	// Get the tiddler |  | ||||||
| 	var tiddler = $tw.wiki.getTiddler(title); |  | ||||||
| 	if(tiddler) { |  | ||||||
| 		console.log("browser-storage: Saving",title); |  | ||||||
| 		// Get the JSON of the tiddler				 |  | ||||||
| 		var json = JSON.stringify(tiddler.getFieldStrings()); |  | ||||||
| 		// Try to save it to local storage |  | ||||||
| 		try { |  | ||||||
| 			window.localStorage.setItem(options.prefix + title,json); |  | ||||||
| 		} catch(e) { |  | ||||||
| 			if(e.name === "QuotaExceededError") { |  | ||||||
| 				// Complain if we failed |  | ||||||
| 				var msg = $tw.wiki.getTiddlerText(QUOTA_EXCEEDED_ALERT_TITLE,DEFAULT_QUOTA_EXCEEDED_ALERT_PREFIX + title + DEFAULT_QUOTA_EXCEEDED_ALERT_SUFFIX); |  | ||||||
| 				if(options.logger) { |  | ||||||
| 					options.logger.alert(msg); |  | ||||||
| 				} |  | ||||||
| 				// No point in keeping old values around for this tiddler |  | ||||||
| 				window.localStorage.removeItem(options.prefix + title); |  | ||||||
| 			} else { |  | ||||||
| 				console.log("Browser-storage error:",e); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		// 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.setItem(options.prefix + title, ""); |  | ||||||
| 		} catch(e) { |  | ||||||
| 			console.log("Browser-storage error:",e); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function clearLocalStorage() { |  | ||||||
| 	var url = window.location.pathname, |  | ||||||
| 		log = []; |  | ||||||
| 	// Step through each browser storage item |  | ||||||
| 	if(window.localStorage) { |  | ||||||
| 		for(var index=window.localStorage.length - 1; index>=0; index--) { |  | ||||||
| 			var key = window.localStorage.key(index), |  | ||||||
| 				parts = key.split("#"); |  | ||||||
| 			// Delete it if it is ours |  | ||||||
| 			if(parts[0] === "tw5" && parts[1] === url) { |  | ||||||
| 				window.localStorage.removeItem(key); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| })(); | })(); | ||||||
|   | |||||||
							
								
								
									
										106
									
								
								plugins/tiddlywiki/browser-storage/util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								plugins/tiddlywiki/browser-storage/util.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | |||||||
|  | /*\ | ||||||
|  | title: $:/plugins/tiddlywiki/browser-storage/util.js | ||||||
|  | type: application/javascript | ||||||
|  | module-type: library | ||||||
|  |  | ||||||
|  | Utility methods for browser-storage plugin | ||||||
|  |  | ||||||
|  | \*/ | ||||||
|  |  | ||||||
|  | (function(){ | ||||||
|  |  | ||||||
|  | /*jslint node: true, browser: true */ | ||||||
|  | /*global $tw: false */ | ||||||
|  | "use strict"; | ||||||
|  |  | ||||||
|  | function BrowserStorageUtil(wiki,options) { | ||||||
|  |     this.options = options || {}; | ||||||
|  |     this.wiki = wiki; | ||||||
|  |     this.cachedTiddlers = []; | ||||||
|  |     this.QUOTA_EXCEEDED_ALERT_TITLE = "$:/config/BrowserStorage/QuotaExceededAlert"; | ||||||
|  |     this.DEFAULT_QUOTA_EXCEEDED_ALERT_PREFIX = "Quota exceeded attempting to store `"; | ||||||
|  |     this.DEFAULT_QUOTA_EXCEEDED_ALERT_SUFFIX = "` in browser local storage"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | BrowserStorageUtil.prototype.isEnabled = function() { | ||||||
|  |     return $tw.wiki.getTiddlerText(this.options.enabledTitle) === "yes"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | BrowserStorageUtil.prototype.cachePreloadTiddlers = function() { | ||||||
|  |     var self = this; | ||||||
|  |     $tw.utils.each($tw.boot.preloadDirty, function(item){ | ||||||
|  |         var tiddler = $tw.wiki.getTiddler(item); | ||||||
|  |         self.cachedTiddlers.push(tiddler); | ||||||
|  |     }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | BrowserStorageUtil.prototype.addCachedTiddlers = function() { | ||||||
|  |     var self = this; | ||||||
|  |     if(this.cachedTiddlers.length > 0) { | ||||||
|  |         $tw.utils.each(this.cachedTiddlers, function(item){ | ||||||
|  |             $tw.wiki.addTiddler(item); | ||||||
|  |         }); | ||||||
|  |         this.cachedTiddlers.length = 0; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | BrowserStorageUtil.prototype.removeTiddlerFromLocalStorage = function(title) { | ||||||
|  |     console.log("browser-storage: Removing", title); | ||||||
|  |     window.localStorage.removeItem(this.options.prefix + title); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | BrowserStorageUtil.prototype.saveTiddlerToLocalStorage = function(title) { | ||||||
|  |     // Get the tiddler | ||||||
|  |     var tiddler = $tw.wiki.getTiddler(title); | ||||||
|  |     if(tiddler) { | ||||||
|  |         console.log("browser-storage: Saving",title); | ||||||
|  |         // Get the JSON of the tiddler				 | ||||||
|  |         var json = JSON.stringify(tiddler.getFieldStrings()); | ||||||
|  |         // Try to save it to local storage | ||||||
|  |         try { | ||||||
|  |             window.localStorage.setItem(this.options.prefix + title,json); | ||||||
|  |         } catch(e) { | ||||||
|  |             if(e.name === "QuotaExceededError") { | ||||||
|  |                 // Complain if we failed | ||||||
|  |                 var msg = $tw.wiki.getTiddlerText(this.QUOTA_EXCEEDED_ALERT_TITLE,this.DEFAULT_QUOTA_EXCEEDED_ALERT_PREFIX + title + this.DEFAULT_QUOTA_EXCEEDED_ALERT_SUFFIX); | ||||||
|  |                 if(this.options.logger) { | ||||||
|  |                     this.options.logger.alert(msg); | ||||||
|  |                 } | ||||||
|  |                 // No point in keeping old values around for this tiddler | ||||||
|  |                 window.localStorage.removeItem(this.options.prefix + title); | ||||||
|  |             } else { | ||||||
|  |                 console.log("Browser-storage error:",e); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         // 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.setItem(this.options.prefix + title, ""); | ||||||
|  |         } catch(e) { | ||||||
|  |             console.log("Browser-storage error:",e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | BrowserStorageUtil.prototype.clearLocalStorage = function() { | ||||||
|  |     var url = window.location.pathname, | ||||||
|  |         log = []; | ||||||
|  |     // Step through each browser storage item | ||||||
|  |     if(window.localStorage) { | ||||||
|  |         for(var index=window.localStorage.length - 1; index>=0; index--) { | ||||||
|  |             var key = window.localStorage.key(index), | ||||||
|  |                 parts = key.split("#"); | ||||||
|  |             // Delete it if it is ours | ||||||
|  |             if(parts[0] === "tw5" && parts[1] === url) { | ||||||
|  |                 window.localStorage.removeItem(key); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | exports.BrowserStorageUtil = BrowserStorageUtil; | ||||||
|  |  | ||||||
|  | })(); | ||||||
| @@ -76,6 +76,10 @@ TiddlyWebAdaptor.prototype.getStatus = function(callback) { | |||||||
| 			if(err) { | 			if(err) { | ||||||
| 				return callback(err); | 				return callback(err); | ||||||
| 			} | 			} | ||||||
|  | 			//If Browser-Storage plugin is present, cache pre-loaded tiddlers and add back after sync from server completes  | ||||||
|  | 			if($tw.browserStorage && $tw.browserStorage.isEnabled()) { | ||||||
|  | 				$tw.browserStorage.cachePreloadTiddlers(); | ||||||
|  | 			} | ||||||
| 			// Decode the status JSON | 			// Decode the status JSON | ||||||
| 			var json = null; | 			var json = null; | ||||||
| 			try { | 			try { | ||||||
| @@ -188,6 +192,10 @@ TiddlyWebAdaptor.prototype.getSkinnyTiddlers = function(callback) { | |||||||
| 			} | 			} | ||||||
| 			// Invoke the callback with the skinny tiddlers | 			// Invoke the callback with the skinny tiddlers | ||||||
| 			callback(null,tiddlers); | 			callback(null,tiddlers); | ||||||
|  | 			// If Browswer Storage tiddlers were cached on reloading the wiki, add them after sync from server completes in the above callback. | ||||||
|  | 			if($tw.browserStorage && $tw.browserStorage.isEnabled()) {  | ||||||
|  | 				$tw.browserStorage.addCachedTiddlers(); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	}); | 	}); | ||||||
| }; | }; | ||||||
| @@ -211,6 +219,10 @@ TiddlyWebAdaptor.prototype.saveTiddler = function(tiddler,callback,options) { | |||||||
| 			if(err) { | 			if(err) { | ||||||
| 				return callback(err); | 				return callback(err); | ||||||
| 			} | 			} | ||||||
|  | 			//If Browser-Storage plugin is present, remove tiddler from local storage after successful sync to the server | ||||||
|  | 			if($tw.browserStorage && $tw.browserStorage.isEnabled()) { | ||||||
|  | 				$tw.browserStorage.removeTiddlerFromLocalStorage(tiddler.fields.title) | ||||||
|  | 			} | ||||||
| 			// Save the details of the new revision of the tiddler | 			// Save the details of the new revision of the tiddler | ||||||
| 			var etag = request.getResponseHeader("Etag"); | 			var etag = request.getResponseHeader("Etag"); | ||||||
| 			if(!etag) { | 			if(!etag) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 fkmiec
					fkmiec