mirror of
				https://github.com/Jermolene/TiddlyWiki5
				synced 2025-10-31 15:42:59 +00:00 
			
		
		
		
	Introduce refactored wiki parser and renderer
This is a half-way through a big refactoring of the parsing and rendering infrastructure. The main change is to separate the parse and render trees, which makes the code a lot cleaner. The new parser isn't yet functional enough to replace the existing parser so for the moment you have to manually invoke it with `$tw.testNewParser()` in your browser console. I really ought to use branches for this kind of thing...
This commit is contained in:
		
							
								
								
									
										151
									
								
								core/modules/rendertree/renderers/element.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								core/modules/rendertree/renderers/element.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| /*\ | ||||
| title: $:/core/modules/rendertree/renderers/element.js | ||||
| type: application/javascript | ||||
| module-type: wikirenderer | ||||
|  | ||||
| Element renderer | ||||
|  | ||||
| \*/ | ||||
| (function(){ | ||||
|  | ||||
| /*jslint node: true, browser: true */ | ||||
| /*global $tw: false */ | ||||
| "use strict"; | ||||
|  | ||||
| /* | ||||
| Element renderer | ||||
| */ | ||||
| var ElementRenderer = function(renderTree,renderContext,parseTreeNode) { | ||||
| 	// Store state information | ||||
| 	this.renderTree = renderTree; | ||||
| 	this.renderContext = renderContext; | ||||
| 	this.parseTreeNode = parseTreeNode; | ||||
| 	// Compute our dependencies | ||||
| 	this.dependencies = {}; | ||||
| 	var self = this; | ||||
| 	$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) { | ||||
| 		if(attribute.type === "indirect") { | ||||
| 			var tr = $tw.utils.parseTextReference(attribute.textReference); | ||||
| 			if(tr.title) { | ||||
| 				self.dependencies[tr.title] = true; | ||||
| 			} else { | ||||
| 				self.dependencies[renderContext.tiddlerTitle] = true; | ||||
| 			} | ||||
| 		} | ||||
| 	}); | ||||
| 	// Compute our attributes | ||||
| 	this.computeAttributes(); | ||||
| 	// Create the renderers for the child nodes | ||||
| 	this.children = this.renderTree.createRenderers(this.renderContext,this.parseTreeNode.children); | ||||
| }; | ||||
|  | ||||
| ElementRenderer.prototype.computeAttributes = function() { | ||||
| 	this.attributes = {}; | ||||
| 	var self = this; | ||||
| 	$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) { | ||||
| 		if(attribute.type === "indirect") { | ||||
| 			self.attributes[name] = self.renderTree.wiki.getTextReference(attribute.textReference,self.renderContext.tiddlerTitle); | ||||
| 		} else { // String attribute | ||||
| 			self.attributes[name] = attribute.value; | ||||
| 		} | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| ElementRenderer.prototype.render = function(type) { | ||||
| 	var isHtml = type === "text/html", | ||||
| 		output = [],attr,a,v; | ||||
| 	if(isHtml) { | ||||
| 		output.push("<",this.parseTreeNode.tag); | ||||
| 		if(this.attributes) { | ||||
| 			attr = []; | ||||
| 			for(a in this.attributes) { | ||||
| 				attr.push(a); | ||||
| 			} | ||||
| 			attr.sort(); | ||||
| 			for(a=0; a<attr.length; a++) { | ||||
| 				v = this.attributes[attr[a]]; | ||||
| 				if(v !== undefined) { | ||||
| 					if($tw.utils.isArray(v)) { | ||||
| 						v = v.join(" "); | ||||
| 					} else if(typeof v === "object") { | ||||
| 						var s = []; | ||||
| 						for(var p in v) { | ||||
| 							s.push(p + ":" + v[p] + ";"); | ||||
| 						} | ||||
| 						v = s.join(""); | ||||
| 					} | ||||
| 					output.push(" ",attr[a],"='",$tw.utils.htmlEncode(v),"'"); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if(!this.children || this.children.length === 0) { | ||||
| 			output.push("/"); | ||||
| 		} | ||||
| 		output.push(">"); | ||||
| 	} | ||||
| 	if(this.children && this.children.length > 0) { | ||||
| 		$tw.utils.each(this.children,function(node) { | ||||
| 			if(node.render) { | ||||
| 				output.push(node.render(type)); | ||||
| 			} | ||||
| 		}); | ||||
| 		if(isHtml) { | ||||
| 			output.push("</",this.parseTreeNode.tag,">"); | ||||
| 		} | ||||
| 	} | ||||
| 	return output.join(""); | ||||
| }; | ||||
|  | ||||
| ElementRenderer.prototype.renderInDom = function() { | ||||
| 	// Create the element | ||||
| 	this.domNode = document.createElement(this.parseTreeNode.tag); | ||||
| 	// Assign the attributes | ||||
| 	this.assignAttributes(); | ||||
| 	// Render any child nodes | ||||
| 	var self = this; | ||||
| 	$tw.utils.each(this.children,function(node) { | ||||
| 		if(node.renderInDom) { | ||||
| 			self.domNode.appendChild(node.renderInDom()); | ||||
| 		} | ||||
| 	}); | ||||
| 	// Assign any specified event handlers | ||||
| 	$tw.utils.addEventListeners(this.domNode,this.parseTreeNode.events); | ||||
| 	// Return the dom node | ||||
| 	return this.domNode; | ||||
| }; | ||||
|  | ||||
| ElementRenderer.prototype.assignAttributes = function() { | ||||
| 	var self = this; | ||||
| 	$tw.utils.each(this.attributes,function(v,a) { | ||||
| 		if(v !== undefined) { | ||||
| 			if($tw.utils.isArray(v)) { // Ahem, could there be arrays other than className? | ||||
| 				self.domNode.className = v.join(" ");  | ||||
| 			} else if (typeof v === "object") { // ...or objects other than style? | ||||
| 				for(var p in v) { | ||||
| 					self.domNode.style[$tw.utils.unHyphenateCss(p)] = v[p]; | ||||
| 				} | ||||
| 			} else { | ||||
| 				self.domNode.setAttribute(a,v); | ||||
| 			} | ||||
| 		} | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| ElementRenderer.prototype.refreshInDom = function(changes) { | ||||
| 	// Check if any of our dependencies have changed | ||||
| 	if($tw.utils.checkDependencies(this.dependencies,changes)) { | ||||
| 		// Update our attributes | ||||
| 		this.computeAttributes(); | ||||
| 		this.assignAttributes(); | ||||
| 	} | ||||
| 	// Refresh any child nodes | ||||
| 	$tw.utils.each(this.children,function(node) { | ||||
| 		if(node.refreshInDom) { | ||||
| 			node.refreshInDom(changes); | ||||
| 		} | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| exports.element = ElementRenderer | ||||
|  | ||||
| })(); | ||||
		Reference in New Issue
	
	Block a user
	 Jeremy Ruston
					Jeremy Ruston