mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-11-22 10:14:51 +00:00
Revamp markdown plugin (#6528)
* Rename markdown to markdown-legacy * Change how default renderWikiTextPragma value is displayed To prevent out-of-sync, dynamically display the default value of renderWikiTextPragma from the shadow tiddler instead of hard coding the text in the "usage.tid". * Repackage remarkable-based markdown plugin as markdown-legacy - Rename plugin title to $:/plugins/tiddlywiki/markdown-legacy - Add support for "text/markdown" MIME type and set that as the default when creating new markdown tiddlers * Create new markdown plugin * add support to text/markdown MIME type * remove linkify and linkNewWindow config options - linkify feature should be controlled by "extlink" TW parser rule; enabling markdown's linkify option will interfere with parsing - remove the possibility to open external links in the same tab/window to match TW's behavior * Ignore latex-parser wikirule in rednerWikiTextPragma * Prevent camel-case link text from generating a link * Update editions/markdowndemo * Produce better parse tree * Improve markdown/tiddlywiki integration - widget block should not interrupt paragraph - ignore tw-syntax links inside markdown-syntax links - remove repeated renderWikiTextPragma parsing - more efficient findNextMatch when examining tw rules * Update user docs * Replace includes() with indexOf() for legacy browsers
This commit is contained in:
@@ -3,338 +3,264 @@ title: $:/plugins/tiddlywiki/markdown/wrapper.js
|
||||
type: application/javascript
|
||||
module-type: parser
|
||||
|
||||
Wraps up the remarkable parser for use as a Parser in TiddlyWiki
|
||||
Wraps up the markdown-it parser for use as a Parser in TiddlyWiki
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
(function(realRequire){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var r = require("$:/plugins/tiddlywiki/markdown/remarkable.js");
|
||||
var require = function(m) {
|
||||
return realRequire("$:/plugins/tiddlywiki/markdown/" + m + ".js");
|
||||
};
|
||||
|
||||
var Remarkable = r.Remarkable,
|
||||
linkify = r.linkify,
|
||||
utils = r.utils;
|
||||
var MarkdownIt = require("markdown-it");
|
||||
|
||||
///// Set up configuration options /////
|
||||
function parseAsBoolean(tiddlerName) {
|
||||
return $tw.wiki.getTiddlerText(tiddlerName).toLowerCase() === "true";
|
||||
return $tw.wiki.getTiddlerText(tiddlerName,"false").trim().toLowerCase() === "true";
|
||||
}
|
||||
|
||||
var pluginOpts = {
|
||||
linkNewWindow: parseAsBoolean("$:/config/markdown/linkNewWindow"),
|
||||
renderWikiText: parseAsBoolean("$:/config/markdown/renderWikiText"),
|
||||
renderWikiTextPragma: $tw.wiki.getTiddlerText("$:/config/markdown/renderWikiTextPragma").trim()
|
||||
};
|
||||
var remarkableOpts = {
|
||||
|
||||
var markdownOpts = {
|
||||
html: true,
|
||||
xhtmlOut: true,
|
||||
breaks: parseAsBoolean("$:/config/markdown/breaks"),
|
||||
quotes: $tw.wiki.getTiddlerText("$:/config/markdown/quotes"),
|
||||
typographer: parseAsBoolean("$:/config/markdown/typographer")
|
||||
quotes: $tw.wiki.getTiddlerText("$:/config/markdown/quotes").trim(),
|
||||
typographer: parseAsBoolean("$:/config/markdown/typographer"),
|
||||
linkify: parseAsBoolean("$:/config/markdown/linkify")
|
||||
};
|
||||
var accumulatingTypes = {
|
||||
"text": true,
|
||||
"softbreak": true
|
||||
};
|
||||
// If rendering WikiText, we treat katex nodes as text.
|
||||
if(pluginOpts.renderWikiText) {
|
||||
accumulatingTypes["katex"] = true;
|
||||
}
|
||||
|
||||
var md = new Remarkable(remarkableOpts);
|
||||
// Retrieve needed TW rule classes and instantiated rules
|
||||
function setupWikiRules(pluginOptions) {
|
||||
var results = {};
|
||||
|
||||
// If tiddlywiki/katex plugin is present, use remarkable-katex to enable katex support.
|
||||
if($tw.modules.titles["$:/plugins/tiddlywiki/katex/katex.min.js"]) {
|
||||
var rk = require("$:/plugins/tiddlywiki/markdown/remarkable-katex.js");
|
||||
md = md.use(rk);
|
||||
}
|
||||
function collectAllRules(classes,type) {
|
||||
var rulesInfo = [], key,
|
||||
self = wikiParser;
|
||||
for(key in classes) {
|
||||
// instantiate the rule
|
||||
var RuleClass = classes[key];
|
||||
var rule = new RuleClass(self);
|
||||
rule.name = key;
|
||||
rule.class = RuleClass;
|
||||
rule.is = {};
|
||||
rule.is[type] = true;
|
||||
rule.init(self);
|
||||
|
||||
if(parseAsBoolean("$:/config/markdown/linkify")) {
|
||||
md = md.use(linkify);
|
||||
}
|
||||
|
||||
function findTagWithType(nodes, startPoint, type, level) {
|
||||
for (var i = startPoint; i < nodes.length; i++) {
|
||||
if(nodes[i].type === type && nodes[i].level === level) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remarkable creates nodes that look like:
|
||||
* [
|
||||
* { type: 'paragraph_open'},
|
||||
* { type: 'inline', content: 'Hello World', children:[{type: 'text', content: 'Hello World'}]},
|
||||
* { type: 'paragraph_close'}
|
||||
* ]
|
||||
*
|
||||
* But TiddlyWiki wants the Parser (https://tiddlywiki.com/dev/static/Parser.html) to emit nodes like:
|
||||
*
|
||||
* [
|
||||
* { type: 'element', tag: 'p', children: [{type: 'text', text: 'Hello World'}]}
|
||||
* ]
|
||||
*/
|
||||
function convertNodes(remarkableTree, isStartOfInline) {
|
||||
let out = [];
|
||||
var accumulatedText = '';
|
||||
function withChildren(currentIndex, currentLevel, closingType, nodes, callback) {
|
||||
var j = findTagWithType(nodes, currentIndex + 1, closingType, currentLevel);
|
||||
if(j === false) {
|
||||
console.error("Failed to find a " + closingType + " node after position " + currentIndex);
|
||||
console.log(nodes);
|
||||
return currentIndex + 1;
|
||||
}
|
||||
let children = convertNodes(nodes.slice(currentIndex + 1, j));
|
||||
callback(children);
|
||||
return j;
|
||||
}
|
||||
function wrappedElement(elementTag, currentIndex, currentLevel, closingType, nodes) {
|
||||
return withChildren(currentIndex, currentLevel, closingType, nodes, function(children) {
|
||||
out.push({
|
||||
type: "element",
|
||||
tag: elementTag,
|
||||
children: children
|
||||
rulesInfo.push({
|
||||
rule: rule,
|
||||
matchIndex: -1
|
||||
});
|
||||
};
|
||||
return rulesInfo;
|
||||
}
|
||||
|
||||
// first pass: get all rule classes
|
||||
var wikiParser = new $tw.Wiki.parsers["text/vnd.tiddlywiki"](null, '', {parseAsInline: true, wiki: $tw.wiki});
|
||||
|
||||
// restore all possible rules from each rule class
|
||||
wikiParser.pragmaRules = collectAllRules(wikiParser.pragmaRuleClasses,'pragma');
|
||||
wikiParser.blockRules = collectAllRules(wikiParser.blockRuleClasses,'block');
|
||||
wikiParser.inlineRules = collectAllRules(wikiParser.inlineRuleClasses,'inline');
|
||||
|
||||
var pragma = pluginOptions.renderWikiText
|
||||
? "\\rules except latex-parser extlink\n" + pluginOptions.renderWikiTextPragma
|
||||
: "\\rules only html entity commentinline commentblock";
|
||||
|
||||
wikiParser.pos = 0;
|
||||
wikiParser.source = pragma;
|
||||
wikiParser.sourceLength = pragma.length;
|
||||
|
||||
// second pass: remove uninterested rules based on \rules pragma
|
||||
wikiParser.parsePragmas();
|
||||
|
||||
results.blockRules = {};
|
||||
results.inlineRules = {}
|
||||
results.blockRuleClasses = {};
|
||||
results.inlineRuleClasses = {};
|
||||
|
||||
// save the rule sets for future markdown parsing
|
||||
wikiParser.blockRules.forEach(function(ruleinfo) {
|
||||
results.blockRules[ruleinfo.rule.name] = ruleinfo;
|
||||
results.blockRuleClasses[ruleinfo.rule.name] = ruleinfo.rule.class;
|
||||
});
|
||||
wikiParser.inlineRules.forEach(function(ruleinfo) {
|
||||
results.inlineRules[ruleinfo.rule.name] = ruleinfo;
|
||||
results.inlineRuleClasses[ruleinfo.rule.name] = ruleinfo.rule.class;
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
// Creates markdown-it parser
|
||||
function createMarkdownEngine(markdownItOptions, pluginOptions) {
|
||||
var md = new MarkdownIt(markdownItOptions)
|
||||
.use(require("markdown-it-sub"))
|
||||
.use(require("markdown-it-sup"))
|
||||
.use(require("markdown-it-ins"))
|
||||
.use(require("markdown-it-mark"))
|
||||
.use(require("markdown-it-footnote"))
|
||||
.use(require("markdown-it-deflist"));
|
||||
|
||||
var results = setupWikiRules(pluginOptions);
|
||||
|
||||
MarkdownParser.prototype.blockRuleClasses = results.blockRuleClasses;
|
||||
MarkdownParser.prototype.blockRules = results.blockRules;
|
||||
|
||||
MarkdownParser.prototype.inlineRuleClasses = results.inlineRuleClasses;
|
||||
MarkdownParser.prototype.inlineRules = results.inlineRules;
|
||||
|
||||
if(pluginOptions.renderWikiText && $tw.modules.titles["$:/plugins/tiddlywiki/katex/katex.min.js"]) {
|
||||
md.use(require("markdown-it-katex"));
|
||||
}
|
||||
|
||||
md.use(require("markdown-it-tiddlywiki"),{
|
||||
renderWikiText: pluginOptions.renderWikiText,
|
||||
blockRules: results.blockRules,
|
||||
inlineRules: results.inlineRules
|
||||
});
|
||||
|
||||
$tw.utils.each(['image','prettylink','prettyextlink'], function(rule) {
|
||||
if(MarkdownParser.prototype.inlineRules[rule]) {
|
||||
// delegate to md; ignore the rule class in WikiParser
|
||||
delete MarkdownParser.prototype.inlineRuleClasses[rule];
|
||||
}
|
||||
});
|
||||
return md;
|
||||
}
|
||||
|
||||
/// Parse tree post processing ///
|
||||
|
||||
function deactivateLinks(tree) {
|
||||
$tw.utils.each(tree,function(node) {
|
||||
if(node.type === "link") {
|
||||
node.type = "text";
|
||||
node.text = node.children[0].text;
|
||||
delete node.attributes;
|
||||
delete node.children;
|
||||
delete node.attributes;
|
||||
} else {
|
||||
deactivateLinks(node.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// true if the node contains "_codified_" class attribute
|
||||
function isCodified(node) {
|
||||
return node.attributes
|
||||
&& node.attributes.class
|
||||
&& node.attributes.class.type === "string"
|
||||
&& (node.attributes.class.value.split(" ").indexOf("_codified_") !== -1);
|
||||
}
|
||||
|
||||
function decodeEntities(s) {
|
||||
return s.replace(/(&#?[a-zA-Z0-9]{2,8};)/g,$tw.utils.entityDecode);
|
||||
}
|
||||
|
||||
// Add e"..." and e'....' syntax to enable decoding of HTML entities
|
||||
// in string literals.
|
||||
function parseStringLiteralExtended(source,pos) {
|
||||
var node = {
|
||||
type: "string",
|
||||
start: pos
|
||||
};
|
||||
var reString = /(?:"""([\s\S]*?)"""|e?"([^"]*)")|(?:e?'([^']*)')/g;
|
||||
reString.lastIndex = pos;
|
||||
var match = reString.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.value = match[1] !== undefined ? match[1] :
|
||||
(match[2] !== undefined ? match[2] : match[3]);
|
||||
node.end = pos + match[0].length;
|
||||
if(match[0].charAt(0) === "e") {
|
||||
node.value = decodeEntities(node.value);
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function processWikiTree(tree,hasWikiLinkRule) {
|
||||
var stack = [].concat(tree);
|
||||
|
||||
var mergeable = function(node) {
|
||||
return node.type === "element" && node.tag === "p" && (!node.attributes || Object.keys(node.attributes).length === 0);
|
||||
};
|
||||
|
||||
while(stack.length) {
|
||||
var node = stack.pop();
|
||||
if(node.type === "element" && node.tag === "p") {
|
||||
// reduce nested <p> nodes
|
||||
while(node.children && node.children.length === 1 && mergeable(node.children[0])) {
|
||||
node.children = node.children[0].children;
|
||||
}
|
||||
} else if(hasWikiLinkRule && isCodified(node)) {
|
||||
deactivateLinks(node.children);
|
||||
continue;
|
||||
}
|
||||
if(node.children && node.children.length > 0) {
|
||||
stack.push.apply(stack,node.children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// to extend MarkdownIt outside of this module, do:
|
||||
//
|
||||
// md = $tw.Wiki.parsers["text/markdown"].prototype.md;
|
||||
// md.use(plugin[, options]);
|
||||
MarkdownParser.prototype.md = createMarkdownEngine(markdownOpts,pluginOpts);
|
||||
|
||||
function MarkdownParser(type,text,options) {
|
||||
var env = {}
|
||||
var md = this.md;
|
||||
var mdTree = md.parse(text,env);
|
||||
var textToParse = '<div class="markdown">\n' + md.renderer.render(mdTree,md.options,env) + '</div>';
|
||||
|
||||
//console.log(JSON.stringify(mdTree,null,2));
|
||||
//console.log("\n----------------\n" + textToParse);
|
||||
|
||||
var wikiParser;
|
||||
|
||||
var origParseStringLiteral = $tw.utils.parseStringLiteral;
|
||||
$tw.utils.parseStringLiteral = parseStringLiteralExtended;
|
||||
|
||||
try {
|
||||
wikiParser = new $tw.Wiki.parsers["text/vnd.tiddlywiki"](null,textToParse,{
|
||||
parseAsInline: true,
|
||||
wiki: options.wiki,
|
||||
rules: { pragma: {}, block: this.blockRuleClasses, inline: this.inlineRuleClasses }
|
||||
});
|
||||
}
|
||||
|
||||
for (var i = 0; i < remarkableTree.length; i++) {
|
||||
var currentNode = remarkableTree[i];
|
||||
switch (currentNode.type) {
|
||||
case "paragraph_open":
|
||||
// If the paragraph is a "tight" layout paragraph, don't wrap children in a <p> tag.
|
||||
if(currentNode.tight) {
|
||||
i = withChildren(i, currentNode.level, "paragraph_close", remarkableTree, function(children) {
|
||||
Array.prototype.push.apply(out, children);
|
||||
});
|
||||
} else {
|
||||
i = wrappedElement("p", i, currentNode.level, "paragraph_close", remarkableTree);
|
||||
}
|
||||
break;
|
||||
|
||||
case "heading_open":
|
||||
i = wrappedElement("h" + currentNode.hLevel, i, currentNode.level, "heading_close", remarkableTree);
|
||||
break;
|
||||
|
||||
case "bullet_list_open":
|
||||
i = wrappedElement("ul", i, currentNode.level, "bullet_list_close", remarkableTree);
|
||||
break;
|
||||
|
||||
case "ordered_list_open":
|
||||
i = wrappedElement('ol', i, currentNode.level,'ordered_list_close', remarkableTree);
|
||||
break;
|
||||
|
||||
case "list_item_open":
|
||||
i = wrappedElement("li", i, currentNode.level, "list_item_close", remarkableTree);
|
||||
break;
|
||||
|
||||
case "link_open":
|
||||
i = withChildren(i, currentNode.level, "link_close", remarkableTree, function(children) {
|
||||
if(currentNode.href[0] !== "#") {
|
||||
// External link
|
||||
var attributes = {
|
||||
class: { type: "string", value: "tc-tiddlylink-external" },
|
||||
href: { type: "string", value: currentNode.href },
|
||||
rel: { type: "string", value: "noopener noreferrer" }
|
||||
};
|
||||
if(pluginOpts.linkNewWindow) {
|
||||
attributes.target = { type: "string", value: "_blank" };
|
||||
}
|
||||
out.push({
|
||||
type: "element",
|
||||
tag: "a",
|
||||
attributes: attributes,
|
||||
children: children
|
||||
});
|
||||
} else {
|
||||
// Internal link
|
||||
out.push({
|
||||
type: "link",
|
||||
attributes: {
|
||||
to: { type: "string", value: $tw.utils.decodeURISafe(currentNode.href.substr(1)) }
|
||||
},
|
||||
children: children
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case "code":
|
||||
out.push({
|
||||
type: "element",
|
||||
tag: currentNode.block ? "pre" : "code",
|
||||
children: [{ type: "text", text: currentNode.content }]
|
||||
});
|
||||
break;
|
||||
|
||||
case "fence":
|
||||
out.push({
|
||||
type: "codeblock",
|
||||
attributes: {
|
||||
language: { type: "string", value: currentNode.params },
|
||||
code: { type: "string", value: currentNode.content }
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case "image":
|
||||
out.push({
|
||||
type: "image",
|
||||
attributes: {
|
||||
tooltip: { type: "string", value: currentNode.alt },
|
||||
source: { type: "string", value: $tw.utils.decodeURIComponentSafe(currentNode.src) }
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case "softbreak":
|
||||
if(remarkableOpts.breaks) {
|
||||
out.push({
|
||||
type: "element",
|
||||
tag: "br",
|
||||
});
|
||||
} else {
|
||||
accumulatedText = accumulatedText + '\n';
|
||||
}
|
||||
break;
|
||||
|
||||
case "hardbreak":
|
||||
out.push({
|
||||
type: "element",
|
||||
tag: "br",
|
||||
});
|
||||
break;
|
||||
|
||||
case "th_open":
|
||||
case "td_open":
|
||||
var elementTag = currentNode.type.slice(0, 2);
|
||||
i = withChildren(i, currentNode.level, elementTag + "_close", remarkableTree, function(children) {
|
||||
var attributes = {};
|
||||
if(currentNode.align) {
|
||||
attributes.style = { type: "string", value: "text-align:" + currentNode.align };
|
||||
}
|
||||
out.push({
|
||||
type: "element",
|
||||
tag: elementTag,
|
||||
attributes: attributes,
|
||||
children: children
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
||||
case "hr":
|
||||
out.push({
|
||||
type: 'element',
|
||||
tag: 'hr',
|
||||
});
|
||||
break;
|
||||
|
||||
case "inline":
|
||||
out = out.concat(convertNodes(currentNode.children, true));
|
||||
break;
|
||||
|
||||
case "text":
|
||||
// We need to merge this text block with the upcoming text block and parse it all together.
|
||||
accumulatedText = accumulatedText + currentNode.content;
|
||||
break;
|
||||
|
||||
case "katex":
|
||||
// If rendering WikiText, convert the katex node back to text for parsing by the WikiText LaTeX parser.
|
||||
if(pluginOpts.renderWikiText) {
|
||||
// If this is a block, add a newline to trigger the KaTeX plugins block detection.
|
||||
var displayModeSuffix = currentNode.block ? "\n" : "";
|
||||
accumulatedText = accumulatedText + "$$" + currentNode.content + displayModeSuffix + "$$";
|
||||
} else {
|
||||
out.push({
|
||||
type: "latex",
|
||||
attributes: {
|
||||
text: { type: "text", value: currentNode.content },
|
||||
displayMode: { type: "text", value: currentNode.block ? "true" : "false" }
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if(currentNode.type.substr(currentNode.type.length - 5) === "_open") {
|
||||
var tagName = currentNode.type.substr(0, currentNode.type.length - 5);
|
||||
i = wrappedElement(tagName, i, currentNode.level, tagName + "_close", remarkableTree);
|
||||
} else {
|
||||
console.error("Unknown node type: " + currentNode.type, currentNode);
|
||||
out.push({
|
||||
type: "text",
|
||||
text: currentNode.content
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
// We test to see if we process the block now, or if there's
|
||||
// more to accumulate first.
|
||||
if(accumulatedText
|
||||
&& (
|
||||
remarkableOpts.breaks ||
|
||||
(i+1) >= remarkableTree.length ||
|
||||
!accumulatingTypes[remarkableTree[i+1].type]
|
||||
)
|
||||
) {
|
||||
// The Markdown compiler thinks this is just text.
|
||||
// Hand off to the WikiText parser to see if there's more to render
|
||||
// But only if it's configured to, and we have more than whitespace
|
||||
if(!pluginOpts.renderWikiText || accumulatedText.match(/^\s*$/)) {
|
||||
out.push({
|
||||
type: "text",
|
||||
text: accumulatedText
|
||||
});
|
||||
} else {
|
||||
// If we're inside a block element (div, p, td, h1), and this is the first child in the tree,
|
||||
// handle as a block-level parse. Otherwise not.
|
||||
var parseAsInline = !(isStartOfInline && i === 0);
|
||||
var textToParse = accumulatedText;
|
||||
if(pluginOpts.renderWikiTextPragma !== "") {
|
||||
textToParse = pluginOpts.renderWikiTextPragma + "\n" + textToParse;
|
||||
}
|
||||
var wikiParser = $tw.wiki.parseText("text/vnd.tiddlywiki", textToParse, {
|
||||
parseAsInline: parseAsInline
|
||||
});
|
||||
var rs = wikiParser.tree;
|
||||
|
||||
// If we parsed as a block, but the root element the WikiText parser gave is a paragraph,
|
||||
// we should discard the paragraph, since the way Remarkable nests its nodes, this "inline"
|
||||
// node is always inside something else that's a block-level element
|
||||
if(!parseAsInline
|
||||
&& rs.length === 1
|
||||
&& rs[0].type === "element"
|
||||
&& rs[0].tag === "p"
|
||||
) {
|
||||
rs = rs[0].children;
|
||||
}
|
||||
|
||||
// If the original text element started with a space, add it back in
|
||||
if(rs.length > 0
|
||||
&& rs[0].type === "text"
|
||||
&& (accumulatedText[0] === " " || accumulatedText[0] === "\n")
|
||||
) {
|
||||
rs[0].text = " " + rs[0].text;
|
||||
}
|
||||
out = out.concat(rs);
|
||||
}
|
||||
accumulatedText = '';
|
||||
}
|
||||
catch (err) {
|
||||
wikiParser = $tw.wiki.parseText("text/vnd.tiddlywiki",
|
||||
"<strong>Error encountered while parsing the tiddler:</strong><p>" + err.message + "</p>",
|
||||
{parseAsInline: false, wiki: options.wiki});
|
||||
}
|
||||
return out;
|
||||
finally {
|
||||
$tw.utils.parseStringLiteral = origParseStringLiteral;
|
||||
}
|
||||
if(wikiParser.tree.length > 0) {
|
||||
var hasWikiLinkRule = false;
|
||||
// see if wikilink rule has been invoked
|
||||
$tw.utils.each(wikiParser.inlineRules,function(ruleInfo) {
|
||||
if(ruleInfo.rule.name === "wikilink") {
|
||||
hasWikiLinkRule = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
processWikiTree(wikiParser.tree,hasWikiLinkRule);
|
||||
}
|
||||
this.tree = wikiParser.tree;
|
||||
this.source = text;
|
||||
this.type = type || "text/markdown";
|
||||
this.wiki = options.wiki;
|
||||
}
|
||||
|
||||
var MarkdownParser = function(type, text, options) {
|
||||
var tree = md.parse(text, {});
|
||||
//console.debug(tree);
|
||||
tree = convertNodes(tree);
|
||||
//console.debug(tree);
|
||||
|
||||
this.tree = tree;
|
||||
};
|
||||
|
||||
exports["text/markdown"] = MarkdownParser;
|
||||
exports["text/x-markdown"] = MarkdownParser;
|
||||
|
||||
})();
|
||||
})(require);
|
||||
|
||||
Reference in New Issue
Block a user