diff --git a/core/modules/filters/wikify.js b/core/modules/filters/wikify.js new file mode 100644 index 000000000..c9b488372 --- /dev/null +++ b/core/modules/filters/wikify.js @@ -0,0 +1,37 @@ +/*\ +title: $:/core/modules/filters/wikify.js +type: application/javascript +module-type: filteroperator + +Filter operator wikifying each string in the input list and returning the result as a list of strings + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +/* +Export our filter function +*/ +exports.wikify = function(source,operator,options) { + var output = operator.operands[0], + mode = operator.operands[1], + type = operator.operands[2], + results = []; + source(function(tiddler,title) { + var wikifier = new $tw.utils.Wikifier({ + wiki: options.wiki, + widget: options.widget, + text: title, + type: type, + mode: mode, + output: output + }); + results.push(wikifier.getResult()); + }); + return results; +}; + +})(); diff --git a/core/modules/utils/wikifier.js b/core/modules/utils/wikifier.js new file mode 100644 index 000000000..ffb887e8d --- /dev/null +++ b/core/modules/utils/wikifier.js @@ -0,0 +1,108 @@ +/*\ +title: $:/core/modules/utils/wikifier.js +type: application/javascript +module-type: utils + +A higher level helper class for wikification and parsing + +\*/ +(function(){ + +/* +Options include: +wiki: wiki to be used for wikification +widget: optional widget to be used as parent of wikified text +text: text to be parsed/wikified +type: type of the text +mode: inline or block +output: text, formattedtext, html, parsetree or widgettree +*/ +function Wikifier(options) { + this.wiki = options.wiki || $tw.wiki; + this.widget = options.widget || $tw.rootWidget; + this.text = options.text || ""; + this.type = options.type || ""; + this.mode = options.mode || "block"; + this.output = options.output || "text"; + // Create the parse tree + this.parser = this.wiki.parseText(this.type,this.text,{ + parseAsInline: this.mode === "inline" + }); + // Create the widget tree + this.widgetNode = this.wiki.makeWidget(this.parser,{ + document: $tw.fakeDocument, + parentWidget: this.widget + }); + // Render the widget tree to the container + this.container = $tw.fakeDocument.createElement("div"); + this.widgetNode.render(this.container,null); +}; + +Wikifier.prototype.refresh = function(changedTiddlers) { + // Refresh the widget tree + return this.widgetNode.refresh(changedTiddlers); +}; + +/* +Return the result string +*/ +Wikifier.prototype.getResult = function() { + var result; + switch(this.output) { + case "text": + result = this.container.textContent; + break; + case "formattedtext": + result = this.container.formattedTextContent; + break; + case "html": + result = this.container.innerHTML; + break; + case "parsetree": + result = JSON.stringify(this.parser.tree,0,$tw.config.preferences.jsonSpaces); + break; + case "widgettree": + result = JSON.stringify(this.getWidgetTree(),0,$tw.config.preferences.jsonSpaces); + break; + } + return result; +}; + +/* +Return a string of the widget tree +*/ +Wikifier.prototype.getWidgetTree = function() { + var copyNode = function(widgetNode,resultNode) { + var type = widgetNode.parseTreeNode.type; + resultNode.type = type; + switch(type) { + case "element": + resultNode.tag = widgetNode.parseTreeNode.tag; + break; + case "text": + resultNode.text = widgetNode.parseTreeNode.text; + break; + } + if(Object.keys(widgetNode.attributes || {}).length > 0) { + resultNode.attributes = {}; + $tw.utils.each(widgetNode.attributes,function(attr,attrName) { + resultNode.attributes[attrName] = widgetNode.getAttribute(attrName); + }); + } + if(Object.keys(widgetNode.children || {}).length > 0) { + resultNode.children = []; + $tw.utils.each(widgetNode.children,function(widgetChildNode) { + var node = {}; + resultNode.children.push(node); + copyNode(widgetChildNode,node); + }); + } + }, + results = {}; + copyNode(this.widgetNode,results); + return results; +}; + +exports.Wikifier = Wikifier; + +})(); diff --git a/core/modules/widgets/wikify.js b/core/modules/widgets/wikify.js index 1830b2048..987c3ab8a 100644 --- a/core/modules/widgets/wikify.js +++ b/core/modules/widgets/wikify.js @@ -39,89 +39,22 @@ Compute the internal state of the widget WikifyWidget.prototype.execute = function() { // Get our parameters this.wikifyName = this.getAttribute("name"); - this.wikifyText = this.getAttribute("text"); - this.wikifyType = this.getAttribute("type"); - this.wikifyMode = this.getAttribute("mode","block"); - this.wikifyOutput = this.getAttribute("output","text"); - // Create the parse tree - this.wikifyParser = this.wiki.parseText(this.wikifyType,this.wikifyText,{ - parseAsInline: this.wikifyMode === "inline" - }); - // Create the widget tree - this.wikifyWidgetNode = this.wiki.makeWidget(this.wikifyParser,{ - document: $tw.fakeDocument, - parentWidget: this - }); - // Render the widget tree to the container - this.wikifyContainer = $tw.fakeDocument.createElement("div"); - this.wikifyWidgetNode.render(this.wikifyContainer,null); - this.wikifyResult = this.getResult(); + // Create the wikifier + this.wikifier = new $tw.utils.Wikifier({ + wiki: this.wiki, + widget: this, + text: this.getAttribute("text"), + type: this.getAttribute("type"), + mode: this.getAttribute("mode","block"), + output: this.getAttribute("output","text") + }); + this.wikifyResult = this.wikifier.getResult(); // Set context variable this.setVariable(this.wikifyName,this.wikifyResult); // Construct the child widgets this.makeChildWidgets(); }; -/* -Return the result string -*/ -WikifyWidget.prototype.getResult = function() { - var result; - switch(this.wikifyOutput) { - case "text": - result = this.wikifyContainer.textContent; - break; - case "formattedtext": - result = this.wikifyContainer.formattedTextContent; - break; - case "html": - result = this.wikifyContainer.innerHTML; - break; - case "parsetree": - result = JSON.stringify(this.wikifyParser.tree,0,$tw.config.preferences.jsonSpaces); - break; - case "widgettree": - result = JSON.stringify(this.getWidgetTree(),0,$tw.config.preferences.jsonSpaces); - break; - } - return result; -}; - -/* -Return a string of the widget tree -*/ -WikifyWidget.prototype.getWidgetTree = function() { - var copyNode = function(widgetNode,resultNode) { - var type = widgetNode.parseTreeNode.type; - resultNode.type = type; - switch(type) { - case "element": - resultNode.tag = widgetNode.parseTreeNode.tag; - break; - case "text": - resultNode.text = widgetNode.parseTreeNode.text; - break; - } - if(Object.keys(widgetNode.attributes || {}).length > 0) { - resultNode.attributes = {}; - $tw.utils.each(widgetNode.attributes,function(attr,attrName) { - resultNode.attributes[attrName] = widgetNode.getAttribute(attrName); - }); - } - if(Object.keys(widgetNode.children || {}).length > 0) { - resultNode.children = []; - $tw.utils.each(widgetNode.children,function(widgetChildNode) { - var node = {}; - resultNode.children.push(node); - copyNode(widgetChildNode,node); - }); - } - }, - results = {}; - copyNode(this.wikifyWidgetNode,results); - return results; -}; - /* Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering */ @@ -133,9 +66,9 @@ WikifyWidget.prototype.refresh = function(changedTiddlers) { return true; } else { // Refresh the widget tree - if(this.wikifyWidgetNode.refresh(changedTiddlers)) { + if(this.wikifier.refresh(changedTiddlers)) { // Check if there was any change - var result = this.getResult(); + var result = this.wikifier.getResult(); if(result !== this.wikifyResult) { // If so, save the change this.wikifyResult = result; diff --git a/editions/test/tiddlers/tests/data/operators/wikify/HtmlMode.tid b/editions/test/tiddlers/tests/data/operators/wikify/HtmlMode.tid new file mode 100644 index 000000000..9f6cf01ed --- /dev/null +++ b/editions/test/tiddlers/tests/data/operators/wikify/HtmlMode.tid @@ -0,0 +1,21 @@ +title: Operators/Wikify/TextMode +description: Simple wikify operator +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] + +title: Output + +\parsermode inline +<$text text={{{ [subfilter{Filter}] }}}/> ++ +title: Filter + +[{Text}wikify[html],[inline],[text/vnd.tiddlywiki]] ++ +title: Text + +This is ''the text'' that is __wikified__ ++ +title: ExpectedResult + +This is <strong>the text</strong> that is <u>wikified</u> \ No newline at end of file diff --git a/editions/test/tiddlers/tests/data/operators/wikify/ParseTreeMode.tid b/editions/test/tiddlers/tests/data/operators/wikify/ParseTreeMode.tid new file mode 100644 index 000000000..237676d8d --- /dev/null +++ b/editions/test/tiddlers/tests/data/operators/wikify/ParseTreeMode.tid @@ -0,0 +1,64 @@ +title: Operators/Wikify/ParseTreeMode +description: Simple wikify operator +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] + +title: Output + +\parsermode inline +<$text text={{{ [subfilter{Filter}] }}}/> ++ +title: Filter + +[{Text}wikify[parsetree],[inline],[text/vnd.tiddlywiki]] ++ +title: Text + +This is ''the text'' that is __wikified__ ++ +title: ExpectedResult + +[ + { + "type": "text", + "text": "This is ", + "start": 0, + "end": 8 + }, + { + "type": "element", + "tag": "strong", + "children": [ + { + "type": "text", + "text": "the text", + "start": 10, + "end": 18 + } + ], + "start": 8, + "end": 20, + "rule": "bold" + }, + { + "type": "text", + "text": " that is ", + "start": 20, + "end": 29 + }, + { + "type": "element", + "tag": "u", + "children": [ + { + "type": "text", + "text": "wikified", + "start": 31, + "end": 39 + } + ], + "start": 29, + "end": 41, + "rule": "underscore" + } +] \ No newline at end of file diff --git a/editions/test/tiddlers/tests/data/operators/wikify/TextMode.tid b/editions/test/tiddlers/tests/data/operators/wikify/TextMode.tid new file mode 100644 index 000000000..2f4f844bc --- /dev/null +++ b/editions/test/tiddlers/tests/data/operators/wikify/TextMode.tid @@ -0,0 +1,21 @@ +title: Operators/Wikify/TextMode +description: Simple wikify operator +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] + +title: Output + +\parsermode inline +<$text text={{{ [subfilter{Filter}] }}}/> ++ +title: Filter + +[{Text}wikify[text],[inline],[text/vnd.tiddlywiki]] ++ +title: Text + +This is ''the text'' that is __wikified__ ++ +title: ExpectedResult + +This is the text that is wikified \ No newline at end of file