/* Functions concerned with parsing representations of tiddlers */ /*jslint node: true */ "use strict"; var utils = require("./Utils.js"), util = require("util"); var tiddlerInput = exports; /* Parse a tiddler given its mimetype, and merge the results into a hashmap of tiddler fields. A file extension can be passed as a shortcut for the mimetype, as shown in tiddlerUtils.fileExtensionMappings. For example ".txt" file extension is mapped to the "text/plain" mimetype. Special processing to extract embedded metadata is applied to some mimetypes. */ tiddlerInput.parseTiddlerFile = function(text,type,fields) { // Map extensions to mimetpyes var fileExtensionMapping = tiddlerInput.fileExtensionMappings[type]; if(fileExtensionMapping) type = fileExtensionMapping; // Invoke the parser for the specified mimetype var parser = tiddlerInput.parseTiddlerFileByMimeType[type]; if(!parser) parser = tiddlerInput.parseTiddlerFileByMimeType["text/plain"]; return parser(text,fields); }; tiddlerInput.fileExtensionMappings = { ".txt": "text/plain", ".html": "text/html", ".tiddler": "application/x-tiddler-html-div", ".tid": "application/x-tiddler", ".js": "application/javascript", ".json": "application/json", ".tiddlywiki": "application/x-tiddlywiki" }; tiddlerInput.parseTiddlerFileByMimeType = { "text/plain": function(text,fields) { fields.text = text; return [fields]; }, "text/html": function(text,fields) { fields.text = text; return [fields]; }, "application/x-tiddler-html-div": function(text,fields) { return [tiddlerInput.parseTiddlerDiv(text,fields)]; }, "application/x-tiddler": function(text,fields) { var split = text.indexOf("\n\n"); if(split === -1) { split = text.length; } fields = tiddlerInput.parseMetaDataBlock(text.substr(0,split),fields); fields.text = text.substr(split + 2); return [fields]; }, "application/javascript": function(text,fields) { fields.text = text; return [fields]; }, "application/json": function(text,fields) { var tiddlers = JSON.parse(text), result = [], getKnownFields = function(tid) { var fields = {}; "title text created creator modified modifier type tags".split(" ").forEach(function(value) { fields[value] = tid[value]; }); return fields; }; for(var t=0; t\s*)/gi, startPos = storeAreaPos[0]; endOfDivRegExp.lastIndex = startPos; var match = endOfDivRegExp.exec(text); while(match && startPos < storeAreaPos[1]) { var endPos = endOfDivRegExp.lastIndex, tiddlerFields = tiddlerInput.parseTiddlerDiv(text.substring(startPos,endPos),fields); tiddlerFields.text = utils.htmlDecode(tiddlerFields.text); results.push(tiddlerFields); startPos = endPos; match = endOfDivRegExp.exec(text); } } return results; } }; tiddlerInput.locateStoreArea = function(tiddlywikidoc) { var startSaveArea = '
', startSaveAreaRegExp = /
/gi, endSaveArea = '', endSaveAreaCaps = '', posOpeningDiv = tiddlywikidoc.search(startSaveAreaRegExp), limitClosingDiv = tiddlywikidoc.indexOf("<"+"!--POST-STOREAREA--"+">"); if(limitClosingDiv == -1) { limitClosingDiv = tiddlywikidoc.indexOf("<"+"!--POST-BODY-START--"+">"); } var start = limitClosingDiv == -1 ? tiddlywikidoc.length : limitClosingDiv, posClosingDiv = tiddlywikidoc.lastIndexOf(endSaveArea,start); if(posClosingDiv == -1) { posClosingDiv = tiddlywikidoc.lastIndexOf(endSaveAreaCaps,start); } return (posOpeningDiv != -1 && posClosingDiv != -1) ? [posOpeningDiv + startSaveArea.length,posClosingDiv] : null; }; /* Parse a block of metadata and merge the results into a hashmap of tiddler fields. The block consists of newline delimited lines consisting of the field name, a colon, and then the value. For example: title: Safari modifier: blaine created: 20110211110700 modified: 20110211131020 tags: browsers issues creator: psd */ tiddlerInput.parseMetaDataBlock = function(metaData,fields) { var result = {}; if(fields) { for(var t in fields) { result[t] = fields[t]; } } metaData.split("\n").forEach(function(line) { var p = line.indexOf(":"); if(p !== -1) { var field = line.substr(0, p).trim(); var value = line.substr(p+1).trim(); result[field] = value; } }); return result; }; /* Parse an old-style tiddler DIV. It looks like this:
The text of the tiddler (without the expected HTML encoding).
Note that the field attributes are HTML encoded, but that the body of the
 tag is not.
*/
tiddlerInput.parseTiddlerDiv = function(text,fields) {
	var result = {};
	if(fields) {
		for(var t in fields) {
			result[t] = fields[t];		
		}
	}
	var divRegExp = /^\s*]*)>((?:.|\n)*)<\/div>\s*$/gi,
		subDivRegExp = /^\s*
((?:.|\n)*)<\/pre>\s*$/gi,
		attrRegExp = /\s*([^=\s]+)\s*=\s*"([^"]*)"/gi,
		match = divRegExp.exec(text);
	if(match) {
		var subMatch = subDivRegExp.exec(match[2]); // Body of the 
tag if(subMatch) { result.text = subMatch[1]; } else { result.text = match[2]; } var attrMatch; do { attrMatch = attrRegExp.exec(match[1]); if(attrMatch) { var name = attrMatch[1]; var value = attrMatch[2]; result[name] = value; } } while(attrMatch); } return result; };