mirror of
				https://github.com/Jermolene/TiddlyWiki5
				synced 2025-10-31 15:42:59 +00:00 
			
		
		
		
	Added basic support for HTML rendering
This commit is contained in:
		| @@ -40,15 +40,62 @@ var WikiTextParser = function(text) { | |||||||
| 	this.subWikify(this.tree); | 	this.subWikify(this.tree); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| WikiTextParser.prototype.outputText = function(place,startPos,endPos) | // Render the tiddler as HTML from its parse tree | ||||||
| { | //	type - MIME type of required output | ||||||
|  | //	store - store object providing context for inter-tiddler operations | ||||||
|  | //  title - render the tree as if it came from a tiddler of this title | ||||||
|  | WikiTextParser.prototype.render = function(type,store,title) { | ||||||
|  | 	if(type === "text/html") { | ||||||
|  | 		return this.renderAsHtml(store,title); | ||||||
|  | 	} else { | ||||||
|  | 		return null; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | WikiTextParser.prototype.renderAsHtml = function(store,title) { | ||||||
|  | 	var output = []; | ||||||
|  | 	var renderElement = function(element, selfClosing) { | ||||||
|  | 		var tagBits = [element.type]; | ||||||
|  | 		if(element.attributes) { | ||||||
|  | 			for(var a in element.attributes) { | ||||||
|  | 				tagBits.push(a + "=\"" + element.attributes[a] + "\""); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		output.push("<" + tagBits.join(" ") + (selfClosing ? " /" : "") + ">"); | ||||||
|  | 		if(!selfClosing) { | ||||||
|  | 			if(element.children) { | ||||||
|  | 				renderSubTree(element.children); | ||||||
|  | 			} | ||||||
|  | 			output.push("</" + element.type + ">"); | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 	var renderSubTree = function(tree) { | ||||||
|  | 		for(var t=0; t<tree.length; t++) { | ||||||
|  | 			switch(tree[t].type) { | ||||||
|  | 				case "text": | ||||||
|  | 					output.push(tree[t].value); | ||||||
|  | 					break; | ||||||
|  | 				case "br": | ||||||
|  | 				case "img": | ||||||
|  | 					renderElement(tree[t],true); // Self closing elements | ||||||
|  | 					break; | ||||||
|  | 				default: | ||||||
|  | 					renderElement(tree[t]); | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 	renderSubTree(this.tree); | ||||||
|  | 	return output.join("");	 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | WikiTextParser.prototype.outputText = function(place,startPos,endPos) { | ||||||
| 	if(startPos < endPos) { | 	if(startPos < endPos) { | ||||||
| 		place.push({type: "text", value: this.source.substring(startPos,endPos)}); | 		place.push({type: "text", value: this.source.substring(startPos,endPos)}); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| WikiTextParser.prototype.subWikify = function(output,terminator) | WikiTextParser.prototype.subWikify = function(output,terminator) { | ||||||
| { |  | ||||||
| 	// Handle the terminated and unterminated cases separately, this speeds up wikifikation by about 30% | 	// Handle the terminated and unterminated cases separately, this speeds up wikifikation by about 30% | ||||||
| 	if(terminator) | 	if(terminator) | ||||||
| 		this.subWikifyTerm(output,new RegExp("(" + terminator + ")","mg")); | 		this.subWikifyTerm(output,new RegExp("(" + terminator + ")","mg")); | ||||||
| @@ -56,8 +103,7 @@ WikiTextParser.prototype.subWikify = function(output,terminator) | |||||||
| 		this.subWikifyUnterm(output); | 		this.subWikifyUnterm(output); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| WikiTextParser.prototype.subWikifyUnterm = function(output) | WikiTextParser.prototype.subWikifyUnterm = function(output) { | ||||||
| { |  | ||||||
| 	// subWikify can be indirectly recursive, so we need to save the old output pointer | 	// subWikify can be indirectly recursive, so we need to save the old output pointer | ||||||
| 	var oldOutput = this.output; | 	var oldOutput = this.output; | ||||||
| 	this.output = output; | 	this.output = output; | ||||||
| @@ -94,8 +140,7 @@ WikiTextParser.prototype.subWikifyUnterm = function(output) | |||||||
| 	this.output = oldOutput; | 	this.output = oldOutput; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| WikiTextParser.prototype.subWikifyTerm = function(output,terminatorRegExp) | WikiTextParser.prototype.subWikifyTerm = function(output,terminatorRegExp) { | ||||||
| { |  | ||||||
| 	// subWikify can be indirectly recursive, so we need to save the old output pointer | 	// subWikify can be indirectly recursive, so we need to save the old output pointer | ||||||
| 	var oldOutput = this.output; | 	var oldOutput = this.output; | ||||||
| 	this.output = output; | 	this.output = output; | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ WikiTextRules.createElementAndWikify = function(w) { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| WikiTextRules.setAttr = function(e,attr,value) { | WikiTextRules.setAttr = function(e,attr,value) { | ||||||
| 	if(!"attributes" in e) { | 	if(!e.attributes) { | ||||||
| 		e.attributes = {}; | 		e.attributes = {}; | ||||||
| 	} | 	} | ||||||
| 	e.attributes[attr] = value; | 	e.attributes[attr] = value; | ||||||
| @@ -165,7 +165,8 @@ WikiTextRules.rules = [ | |||||||
| 					rowContainer.attributes.align = rowCount === 0 ? "top" : "bottom"; | 					rowContainer.attributes.align = rowCount === 0 ? "top" : "bottom"; | ||||||
| 					w.subWikifyTerm(rowContainer.children,this.rowTermRegExp); | 					w.subWikifyTerm(rowContainer.children,this.rowTermRegExp); | ||||||
| 				} else { | 				} else { | ||||||
| 					var theRow = {type: "tr", className: rowCount%2 ? "oddRow" : "evenRow", children: []}; | 					var theRow = {type: "tr", children: []}; | ||||||
|  | 					WikiTextRules.setAttr(theRow,"className",rowCount%2 ? "oddRow" : "evenRow") | ||||||
| 					rowContainer.children.push(theRow); | 					rowContainer.children.push(theRow); | ||||||
| 					this.rowHandler(w,theRow,prevColumns); | 					this.rowHandler(w,theRow,prevColumns); | ||||||
| 					rowCount++; | 					rowCount++; | ||||||
| @@ -188,10 +189,10 @@ WikiTextRules.rules = [ | |||||||
| 				var last = prevColumns[col]; | 				var last = prevColumns[col]; | ||||||
| 				if(last) { | 				if(last) { | ||||||
| 					last.rowSpanCount++; | 					last.rowSpanCount++; | ||||||
| 					last.element.attributes.rowspan = last.rowSpanCount; | 					WikiTextRules.setAttr(last.element,"rowspan",last.rowSpanCount); | ||||||
| 					last.element.attributes.valign = "center"; | 					WikiTextRules.setAttr(last.element,"valign","center"); | ||||||
| 					if(colSpanCount > 1) { | 					if(colSpanCount > 1) { | ||||||
| 						last.element.attributes.colspan = colSpanCount; | 						WikiTextRules.setAttr(last.element,"colspan",colSpanCount); | ||||||
| 						colSpanCount = 1; | 						colSpanCount = 1; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| @@ -203,7 +204,7 @@ WikiTextRules.rules = [ | |||||||
| 			} else if(cellMatch[2]) { | 			} else if(cellMatch[2]) { | ||||||
| 				// End of row | 				// End of row | ||||||
| 				if(prevCell && colSpanCount > 1) { | 				if(prevCell && colSpanCount > 1) { | ||||||
| 					prevCell.attributes.colspan = colSpanCount; | 					WikiTextRules.setAttr(prevCell,"colspan",colSpanCount); | ||||||
| 				} | 				} | ||||||
| 				w.nextMatch = this.cellRegExp.lastIndex; | 				w.nextMatch = this.cellRegExp.lastIndex; | ||||||
| 				break; | 				break; | ||||||
| @@ -230,15 +231,15 @@ WikiTextRules.rules = [ | |||||||
| 				prevCell = cell; | 				prevCell = cell; | ||||||
| 				prevColumns[col] = {rowSpanCount:1,element:cell}; | 				prevColumns[col] = {rowSpanCount:1,element:cell}; | ||||||
| 				if(colSpanCount > 1) { | 				if(colSpanCount > 1) { | ||||||
| 					cell.attributes.colspan = colSpanCount; | 					WikiTextRules.setAttr(cell,"colspan",colSpanCount); | ||||||
| 					colSpanCount = 1; | 					colSpanCount = 1; | ||||||
| 				} | 				} | ||||||
| 				WikiTextRules.applyCssHelper(cell,styles); | 				WikiTextRules.applyCssHelper(cell,styles); | ||||||
| 				w.subWikifyTerm(cell,this.cellTermRegExp); | 				w.subWikifyTerm(cell,this.cellTermRegExp); | ||||||
| 				if(w.matchText.substr(w.matchText.length-2,1) == " ") // spaceRight | 				if(w.matchText.substr(w.matchText.length-2,1) == " ") // spaceRight | ||||||
| 					cell.attributes.align = spaceLeft ? "center" : "left"; | 					WikiTextRules.setAttr(cell,"align",spaceLeft ? "center" : "left"); | ||||||
| 				else if(spaceLeft) | 				else if(spaceLeft) | ||||||
| 					cell.attributes.align = "right"; | 					WikiTextRules.setAttr(cell,"align","right"); | ||||||
| 				w.nextMatch--; | 				w.nextMatch--; | ||||||
| 			} | 			} | ||||||
| 			col++; | 			col++; | ||||||
| @@ -354,7 +355,7 @@ WikiTextRules.rules = [ | |||||||
| 			} | 			} | ||||||
| 			currLevel = newLevel; | 			currLevel = newLevel; | ||||||
| 			w.subWikifyTerm(stack[stack.length-1],this.termRegExp); | 			w.subWikifyTerm(stack[stack.length-1],this.termRegExp); | ||||||
| 			stack[stack.length-1].push({type: "br", attributes: {}}); | 			stack[stack.length-1].push({type: "br"}); | ||||||
| 			this.lookaheadRegExp.lastIndex = w.nextMatch; | 			this.lookaheadRegExp.lastIndex = w.nextMatch; | ||||||
| 			var lookaheadMatch = this.lookaheadRegExp.exec(w.source); | 			var lookaheadMatch = this.lookaheadRegExp.exec(w.source); | ||||||
| 			matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch; | 			matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch; | ||||||
| @@ -371,7 +372,7 @@ WikiTextRules.rules = [ | |||||||
| 	match: "^----+$\\n?|<hr ?/?>\\n?", | 	match: "^----+$\\n?|<hr ?/?>\\n?", | ||||||
| 	handler: function(w) | 	handler: function(w) | ||||||
| 	{ | 	{ | ||||||
| 		var e = {type: "hr", attributes: {}}; | 		var e = {type: "hr"}; | ||||||
| 		w.output.push(e); | 		w.output.push(e); | ||||||
| 	} | 	} | ||||||
| }, | }, | ||||||
| @@ -442,13 +443,15 @@ WikiTextRules.rules = [ | |||||||
| 				// Pretty bracketted link | 				// Pretty bracketted link | ||||||
| 				var link = lookaheadMatch[3]; | 				var link = lookaheadMatch[3]; | ||||||
| 				if(!lookaheadMatch[2] && WikiTextRules.isExternalLink(w,link)) { | 				if(!lookaheadMatch[2] && WikiTextRules.isExternalLink(w,link)) { | ||||||
| 					e = {type: "a", href: link, children: []}; | 					e = {type: "a", children: []}; | ||||||
| 				} else { | 				} else { | ||||||
| 					e = {type: "tiddlerLink", href: link, children: []}; | 					e = {type: "tiddlerLink", children: []}; | ||||||
| 				} | 				} | ||||||
|  | 				WikiTextRules.setAttr(e,"href",link); | ||||||
| 			} else { | 			} else { | ||||||
| 				// Simple bracketted link | 				// Simple bracketted link | ||||||
| 				e = {type: "tiddlerLink", href: text, children: []}; | 				e = {type: "tiddlerLink", children: []}; | ||||||
|  | 				WikiTextRules.setAttr(e,"href",text); | ||||||
| 			} | 			} | ||||||
| 			w.output.push(e); | 			w.output.push(e); | ||||||
| 			e.children.push({type: "text", value: text}); | 			e.children.push({type: "text", value: text}); | ||||||
| @@ -476,7 +479,8 @@ WikiTextRules.rules = [ | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if(w.autoLinkWikiWords) { | 		if(w.autoLinkWikiWords) { | ||||||
| 			var link = {type: "tiddlerLink", href: w.matchText, children: []}; | 			var link = {type: "tiddlerLink", children: []}; | ||||||
|  | 			WikiTextRules.setAttr(link,"href",w.matchText); | ||||||
| 			w.output.push(link); | 			w.output.push(link); | ||||||
| 			w.outputText(link.children,w.matchStart,w.nextMatch); | 			w.outputText(link.children,w.matchStart,w.nextMatch); | ||||||
| 		} else { | 		} else { | ||||||
| @@ -490,7 +494,8 @@ WikiTextRules.rules = [ | |||||||
| 	match: textPrimitives.urlPattern, | 	match: textPrimitives.urlPattern, | ||||||
| 	handler: function(w) | 	handler: function(w) | ||||||
| 	{ | 	{ | ||||||
| 		var e = {type: "a", href: w.matchText, children: []}; | 		var e = {type: "a", children: []}; | ||||||
|  | 		WikiTextRules.setAttr(e,"href",w.matchText); | ||||||
| 		w.output.push(e); | 		w.output.push(e); | ||||||
| 		w.outputText(e.children,w.matchStart,w.nextMatch); | 		w.outputText(e.children,w.matchStart,w.nextMatch); | ||||||
| 	} | 	} | ||||||
| @@ -510,15 +515,16 @@ WikiTextRules.rules = [ | |||||||
| 			if(lookaheadMatch[5]) { | 			if(lookaheadMatch[5]) { | ||||||
| 				var link = lookaheadMatch[5],t; | 				var link = lookaheadMatch[5],t; | ||||||
| 				if(WikiTextRules.isExternalLink(w,link)) { | 				if(WikiTextRules.isExternalLink(w,link)) { | ||||||
| 					t = {type: "a", href: link, children: []}; | 					t = {type: "a", children: []}; | ||||||
| 					w.output.push(t); | 					w.output.push(t); | ||||||
| 					e = t.children; | 					e = t.children; | ||||||
| 				} else { | 				} else { | ||||||
| 					t = {type: "tiddlerLink", href: link, children: []}; | 					t = {type: "tiddlerLink", children: []}; | ||||||
| 					w.output.push(t); | 					w.output.push(t); | ||||||
| 					e = t.children; | 					e = t.children; | ||||||
| 				} | 				} | ||||||
| 				t.attributes.className = "imageLink"; | 				WikiTextRules.setAttr(t,"href",link); | ||||||
|  | 				WikiTextRules.setAttr(t,"className","imageLink"); | ||||||
| 			} | 			} | ||||||
| 			var img = {type: "img"}; | 			var img = {type: "img"}; | ||||||
| 			e.push(img); | 			e.push(img); | ||||||
| @@ -530,7 +536,7 @@ WikiTextRules.rules = [ | |||||||
| 				WikiTextRules.setAttr(img,"title",lookaheadMatch[3]); | 				WikiTextRules.setAttr(img,"title",lookaheadMatch[3]); | ||||||
| 				WikiTextRules.setAttr(img,"alt",lookaheadMatch[3]); | 				WikiTextRules.setAttr(img,"alt",lookaheadMatch[3]); | ||||||
| 			} | 			} | ||||||
| 			img.src = lookaheadMatch[4]; | 			WikiTextRules.setAttr(img,"src",lookaheadMatch[4]); | ||||||
| 			w.nextMatch = this.lookaheadRegExp.lastIndex; | 			w.nextMatch = this.lookaheadRegExp.lastIndex; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -623,7 +629,7 @@ WikiTextRules.rules = [ | |||||||
| 	{ | 	{ | ||||||
| 		switch(w.matchText) { | 		switch(w.matchText) { | ||||||
| 		case "@@": | 		case "@@": | ||||||
| 			var e = {type: "span", attributes: {}, children: []}; | 			var e = {type: "span", children: []}; | ||||||
| 			w.output.push(e); | 			w.output.push(e); | ||||||
| 			var styles = WikiTextRules.inlineCssHelper(w); | 			var styles = WikiTextRules.inlineCssHelper(w); | ||||||
| 			if(styles.length === 0) | 			if(styles.length === 0) | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								wikitest.js
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								wikitest.js
									
									
									
									
									
								
							| @@ -13,12 +13,17 @@ var wikiTest = function(spec) { | |||||||
| 		store = new TiddlyWiki(), | 		store = new TiddlyWiki(), | ||||||
| 		w; | 		w; | ||||||
| 	for(t=0; t<spec.tiddlers.length; t++) { | 	for(t=0; t<spec.tiddlers.length; t++) { | ||||||
| 		store.addTiddler(new Tiddler(spec.tiddlers[t])); | 		var tid = new Tiddler(spec.tiddlers[t]); | ||||||
|  | 		store.addTiddler(tid); | ||||||
|  |  | ||||||
|  | console.error("%s in HTML:\n%s",tid.fields.title,tid.getParseTree().render("text/html",store,tid.fields.title)); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
| 	for(t=0; t<spec.tests.length; t++) { | 	for(t=0; t<spec.tests.length; t++) { | ||||||
| 		w = store.getTiddler(spec.tests[t].tiddler).getParseTree().tree; | 		w = store.getTiddler(spec.tests[t].tiddler).getParseTree().tree; | ||||||
| 		if(JSON.stringify(w) !== JSON.stringify(spec.tests[t].output)) { | 		if(JSON.stringify(w) !== JSON.stringify(spec.tests[t].output)) { | ||||||
| 			console.error("Failed at tiddler: " + spec.tests[t].tiddler + " with JSON:\n" + util.inspect(w,false,8)); | 			console.error("Failed at tiddler: " + spec.tests[t].tiddler + " with JSON:\n" + util.inspect(w,false,8) + "\nTarget was:\n" + util.inspect(spec.tests[t].output,false,8)); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| @@ -41,8 +46,8 @@ wikiTest({ tiddlers: | |||||||
|           { type: 'text', |           { type: 'text', | ||||||
|             value: ' of the first tiddler, with a link to the ' }, |             value: ' of the first tiddler, with a link to the ' }, | ||||||
|           { type: 'tiddlerLink', |           { type: 'tiddlerLink', | ||||||
|             href: 'SecondTiddler', |             children: [ { type: 'text', value: 'SecondTiddler' } ], | ||||||
|             children: [ { type: 'text', value: 'SecondTiddler' } ] }, |           	attributes: {href: 'SecondTiddler'} }, | ||||||
|           { type: 'text', value: ', too.' } ] }, |           { type: 'text', value: ', too.' } ] }, | ||||||
|      { tiddler: 'SecondTiddler', |      { tiddler: 'SecondTiddler', | ||||||
|        output:  |        output:  | ||||||
| @@ -66,14 +71,14 @@ wikiTest({ tiddlers: | |||||||
|        output:  |        output:  | ||||||
| 		[ { type: 'text', value: 'An explicit link ' }, | 		[ { type: 'text', value: 'An explicit link ' }, | ||||||
| 		  { type: 'tiddlerLink', | 		  { type: 'tiddlerLink', | ||||||
| 		    href: 'Fourth Tiddler', | 		    children: [ { type: 'text', value: 'Fourth Tiddler' } ], | ||||||
| 		    children: [ { type: 'text', value: 'Fourth Tiddler' } ] }, | 		    attributes: { href: 'Fourth Tiddler' } }, | ||||||
| 		  { type: 'text', value: ' and ' }, | 		  { type: 'text', value: ' and ' }, | ||||||
| 		  { type: 'tiddlerLink', | 		  { type: 'tiddlerLink', | ||||||
| 		    href: 'Fourth Tiddler', | 		    children: [ { type: 'text', value: 'a pretty link' } ], | ||||||
| 		    children: [ { type: 'text', value: 'a pretty link' } ] } ] }, | 		    attributes: { href: 'Fourth Tiddler' } } ] }, | ||||||
|      { tiddler: 'Fourth Tiddler', |      { tiddler: 'Fourth Tiddler', | ||||||
|        output:  |        output:  | ||||||
|         [ { type: 'text', value: 'An image ' }, |         [ { type: 'text', value: 'An image ' }, | ||||||
| 		  { type: 'img', src: 'Something.jpg' } ] } ] } | 		  { type: 'img',  attributes: {src: 'Something.jpg' } } ] } ] } | ||||||
| ); | ); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jeremy Ruston
					Jeremy Ruston