mirror of
				https://github.com/Jermolene/TiddlyWiki5
				synced 2025-10-30 23:23:02 +00:00 
			
		
		
		
	Added support for store events and basic refreshing
1s after loading you'll see the link to TiddlyWiki5 flip from italic to normal text as that tiddler is created on a timer
This commit is contained in:
		
							
								
								
									
										10
									
								
								js/App.js
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								js/App.js
									
									
									
									
									
								
							| @@ -109,6 +109,16 @@ var App = function() { | |||||||
| 		var div = document.createElement("div"); | 		var div = document.createElement("div"); | ||||||
| 		div.innerHTML = this.store.renderTiddler("text/html","PageTemplate"); | 		div.innerHTML = this.store.renderTiddler("text/html","PageTemplate"); | ||||||
| 		document.body.appendChild(div); | 		document.body.appendChild(div); | ||||||
|  | 		var me = this; | ||||||
|  | 		window.setInterval(function() { | ||||||
|  | 			me.store.addTiddler(new Tiddler({ | ||||||
|  | 				title: "TiddlyWiki5", | ||||||
|  | 				text: "This is a newly created tiddler!" | ||||||
|  | 			})); | ||||||
|  | 		},3000); | ||||||
|  | 		this.store.addEventListener("",function() { | ||||||
|  | 			me.store.refreshDomNode(div,me.store.getTiddler("PageTemplate")); | ||||||
|  | 		}); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										154
									
								
								js/WikiStore.js
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								js/WikiStore.js
									
									
									
									
									
								
							| @@ -22,6 +22,9 @@ var WikiStore = function WikiStore(options) { | |||||||
| 	this.macros = {}; | 	this.macros = {}; | ||||||
| 	this.tiddlerSerializers = {}; | 	this.tiddlerSerializers = {}; | ||||||
| 	this.tiddlerDeserializers = {}; | 	this.tiddlerDeserializers = {}; | ||||||
|  | 	this.eventListeners = []; // Array of {filter:,listener:} | ||||||
|  | 	this.eventsTriggered = false; | ||||||
|  | 	this.changedTiddlers = {}; // Hashmap of {title: "created|modified|deleted"} | ||||||
| 	this.sandbox = options.sandbox; | 	this.sandbox = options.sandbox; | ||||||
| 	this.shadows = options.shadowStore !== undefined ? options.shadowStore : new WikiStore({ | 	this.shadows = options.shadowStore !== undefined ? options.shadowStore : new WikiStore({ | ||||||
| 		shadowStore: null | 		shadowStore: null | ||||||
| @@ -42,6 +45,73 @@ WikiStore.prototype.registerTiddlerDeserializer = function(extension,mimeType,de | |||||||
| 	this.tiddlerDeserializers[mimeType] = deserializer;	 | 	this.tiddlerDeserializers[mimeType] = deserializer;	 | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | WikiStore.prototype.addEventListener = function(filter,listener) { | ||||||
|  | 	this.eventListeners.push({ | ||||||
|  | 		filter: filter, | ||||||
|  | 		listener: listener | ||||||
|  | 	});	 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | WikiStore.prototype.removeEventListener = function(listener) { | ||||||
|  | 	for(var c=this.eventListeners.length-1; c>=0; c--) { | ||||||
|  | 		var l = this.eventListeners[c]; | ||||||
|  | 		if(l.listener === listener) { | ||||||
|  | 			this.eventListeners.splice(c,1); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | Causes a tiddler to be marked as changed, so that event listeners are triggered for it | ||||||
|  | 	type: Type of change to be registered for the tiddler "created", "modified" or "deleted" | ||||||
|  | If the tiddler is already touched, the resultant touch type is as follows: | ||||||
|  |  | ||||||
|  | If the tiddler is already marked "created", | ||||||
|  | ... attempts to mark it "modified" leave it "created" | ||||||
|  | ... attempts to mark it "deleted" succeed | ||||||
|  |  | ||||||
|  | If the tiddler is already marked "modified", | ||||||
|  | ... attempts to mark it "deleted" succeed | ||||||
|  |  | ||||||
|  | If the tiddler is already marked "deleted", | ||||||
|  | ... attempts to mark it "created" succeed | ||||||
|  | ... attempts to mark it "modified" fail  | ||||||
|  |  | ||||||
|  | */ | ||||||
|  | WikiStore.prototype.touchTiddler = function(type,title) { | ||||||
|  | 	var existingType = this.changedTiddlers[title]; | ||||||
|  | 	if(existingType === undefined && type === "modified") { | ||||||
|  | 		type = "created"; | ||||||
|  | 	} | ||||||
|  | 	if(existingType === "modified" && type === "created") { | ||||||
|  | 		type = "modified"; | ||||||
|  | 	} | ||||||
|  | 	if(existingType === "deleted" && type === "created") { | ||||||
|  | 		type = "modified"; | ||||||
|  | 	} | ||||||
|  | 	this.changedTiddlers[title] = type; | ||||||
|  | 	this.triggerEvents(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | Trigger the execution of the event dispatcher at the next tick, if it is not already triggered | ||||||
|  | */ | ||||||
|  | WikiStore.prototype.triggerEvents = function() { | ||||||
|  | 	if(!this.eventsTriggered) { | ||||||
|  | 		var me = this; | ||||||
|  | 		utils.nextTick(function() { | ||||||
|  | 			var changes = me.changedTiddlers; | ||||||
|  | 			me.changedTiddlers = {}; | ||||||
|  | 			me.eventsTriggered = false; | ||||||
|  | 			for(var e=0; e<me.eventListeners.length; e++) { | ||||||
|  | 				var listener = me.eventListeners[e]; | ||||||
|  | 				listener.listener(changes); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 		this.eventsTriggered = true; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
| WikiStore.prototype.getTiddler = function(title) { | WikiStore.prototype.getTiddler = function(title) { | ||||||
| 	var t = this.tiddlers[title]; | 	var t = this.tiddlers[title]; | ||||||
| 	if(t instanceof Tiddler) { | 	if(t instanceof Tiddler) { | ||||||
| @@ -74,6 +144,7 @@ WikiStore.prototype.tiddlerExists = function(title) { | |||||||
|  |  | ||||||
| WikiStore.prototype.addTiddler = function(tiddler) { | WikiStore.prototype.addTiddler = function(tiddler) { | ||||||
| 	this.tiddlers[tiddler.fields.title] = tiddler; | 	this.tiddlers[tiddler.fields.title] = tiddler; | ||||||
|  | 	this.touchTiddler("modified",tiddler.fields.title); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| WikiStore.prototype.forEachTiddler = function(/* [sortField,[excludeTag,]]callback */) { | WikiStore.prototype.forEachTiddler = function(/* [sortField,[excludeTag,]]callback */) { | ||||||
| @@ -163,17 +234,45 @@ WikiStore.prototype.deserializeTiddlers = function(type,text,srcFields) { | |||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| WikiStore.prototype.classesForLink = function(target) { | WikiStore.prototype.adjustClassesForLink = function(classes,target) { | ||||||
| 	var className = "", | 	var externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data):[^\s'"]+(?:\/|\b)/i, | ||||||
| 		externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data):[^\s'"]+(?:\/|\b)/i; | 		setClass = function(className) { | ||||||
|  | 			if(classes.indexOf(className) === -1) { | ||||||
|  | 				classes.push(className); | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		removeClass = function(className) { | ||||||
|  | 			var p = classes.indexOf(className); | ||||||
|  | 			if(p !== -1) { | ||||||
|  | 				classes.splice(p,1); | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 	// Make sure we've got the main link class | ||||||
|  | 	setClass("tw-tiddlylink"); | ||||||
|  | 	// Check if it's an internal link | ||||||
| 	if (this.tiddlerExists(target)) { | 	if (this.tiddlerExists(target)) { | ||||||
| 		className = "linkInternalResolves"; | 		removeClass("tw-tiddlylink-external"); | ||||||
|  | 		setClass("tw-tiddlylink-internal"); | ||||||
|  | 		setClass("tw-tiddlylink-resolves"); | ||||||
|  | 		removeClass("tw-tiddlylink-missing"); | ||||||
| 	} else if(externalRegExp.test(target)) { | 	} else if(externalRegExp.test(target)) { | ||||||
| 		className = "linkExternal"; | 		setClass("tw-tiddlylink-external"); | ||||||
|  | 		removeClass("tw-tiddlylink-internal"); | ||||||
|  | 		removeClass("tw-tiddlylink-resolves"); | ||||||
|  | 		removeClass("tw-tiddlylink-missing"); | ||||||
| 	} else { | 	} else { | ||||||
| 		className = "linkInternalMissing"; | 		removeClass("tw-tiddlylink-external"); | ||||||
|  | 		setClass("tw-tiddlylink-internal"); | ||||||
|  | 		removeClass("tw-tiddlylink-resolves"); | ||||||
|  | 		setClass("tw-tiddlylink-missing"); | ||||||
| 	} | 	} | ||||||
| 	return className !== "" ? " class=\"" + className + "\"" : ""; | 	return classes; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | WikiStore.prototype.classesForLink = function(target) { | ||||||
|  | 	var classes = ["tw-tiddlylink"]; | ||||||
|  | 	this.adjustClassesForLink(classes,target); | ||||||
|  | 	return " class=\"" + classes.join(" ") + "\""; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| WikiStore.prototype.parseText = function(type,text) { | WikiStore.prototype.parseText = function(type,text) { | ||||||
| @@ -258,6 +357,47 @@ WikiStore.prototype.renderTiddler = function(type,title,asTitle) { | |||||||
| 	return null; | 	return null; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | Refresh a DOM node so that it reflects the current state of the store | ||||||
|  |  | ||||||
|  | The refresh processing is: | ||||||
|  |  | ||||||
|  | 1. If the node is a link, check the link classes correctly reflect the status of the target tiddler. Recursively process any children. Exit | ||||||
|  | 2. If the node is a macro, and dependencies have changed, re-render the macro into the DOM node. Exit | ||||||
|  | 3. If the node is a macro and the dependencies haven't changed, recursively process each child node of the macro. Exit | ||||||
|  |  | ||||||
|  | Arguments | ||||||
|  | 	node - the DOM node to be processed | ||||||
|  | 	tiddler - the tiddler providing context for the rendering | ||||||
|  |  | ||||||
|  | */ | ||||||
|  | WikiStore.prototype.refreshDomNode = function(node,tiddler) { | ||||||
|  | 	// Process links | ||||||
|  | 	if(node.className) { | ||||||
|  | 		var classes = node.className.split(" "); | ||||||
|  | 		if(classes.indexOf("tw-tiddlylink") !== -1) { | ||||||
|  | 			var target = node.getAttribute("href"); | ||||||
|  | 			node.className = this.adjustClassesForLink(classes,target).join(" "); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// Process macros | ||||||
|  | 	var macro = node.getAttribute && node.getAttribute("data-tw-macro"), | ||||||
|  | 		params = node.getAttribute && node.getAttribute("data-tw-params"); | ||||||
|  | 	if(macro && params) { | ||||||
|  | 	} | ||||||
|  | 	// Process children | ||||||
|  | 	if(node.hasChildNodes()) { | ||||||
|  | 		this.refreshDomChildren(node,tiddler); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | WikiStore.prototype.refreshDomChildren = function(node,tiddler) { | ||||||
|  | 	var nodes = node.childNodes; | ||||||
|  | 	for(var c=0; c<nodes.length; c++) { | ||||||
|  | 		this.refreshDomNode(nodes[c],tiddler); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
| WikiStore.prototype.installMacro = function(macro) { | WikiStore.prototype.installMacro = function(macro) { | ||||||
| 	this.macros[macro.name] = macro; | 	this.macros[macro.name] = macro; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -81,17 +81,17 @@ a:hover { | |||||||
|     color: #fff; |     color: #fff; | ||||||
| } | } | ||||||
|  |  | ||||||
| a.linkExternal { | a.tw-tiddlylink { | ||||||
|     font-style: normal; |     font-style: normal; | ||||||
|     font-weight: normal; |     font-weight: normal; | ||||||
| } | } | ||||||
|  |  | ||||||
| a.linkInternalResolves { | a.tw-tiddlylink-resolves { | ||||||
|     font-style: normal; |     font-style: normal; | ||||||
|     font-weight: bold; |     font-weight: bold; | ||||||
| } | } | ||||||
|  |  | ||||||
| a.linkInternalMissing { | a.tw-tiddlylink-missing { | ||||||
|     font-style: italic; |     font-style: italic; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jeremy Ruston
					Jeremy Ruston