diff --git a/domTree.js b/domTree.js
index 79a0ee22a..0fb5eb0b4 100644
--- a/domTree.js
+++ b/domTree.js
@@ -1,7 +1,10 @@
// These objects store the data about the DOM nodes we create, as well as some
-// extra data. They can then be transformed into real DOM nodes with the toDOM
-// function. They are useful for both storing extra properties on the nodes, as
-// well as providing a way to easily work with the DOM.
+// extra data. They can then be transformed into real DOM nodes with the toNode
+// function or HTML markup using toMarkup. They are useful for both storing
+// extra properties on the nodes, as well as providing a way to easily work
+// with the DOM.
+
+var utils = require("./utils");
var createClass = function(classes) {
classes = classes.slice();
@@ -23,7 +26,7 @@ function span(classes, children, height, depth, maxFontSize, style) {
this.style = style || {};
}
-span.prototype.toDOM = function() {
+span.prototype.toNode = function() {
var span = document.createElement("span");
span.className = createClass(this.classes);
@@ -35,12 +38,44 @@ span.prototype.toDOM = function() {
}
for (var i = 0; i < this.children.length; i++) {
- span.appendChild(this.children[i].toDOM());
+ span.appendChild(this.children[i].toNode());
}
return span;
};
+span.prototype.toMarkup = function() {
+ var markup = "";
+
+ for (var i = 0; i < this.children.length; i++) {
+ markup += this.children[i].toMarkup();
+ }
+
+ markup += "";
+
+ return markup;
+};
+
function documentFragment(children, height, depth, maxFontSize) {
this.children = children || [];
this.height = height || 0;
@@ -48,16 +83,26 @@ function documentFragment(children, height, depth, maxFontSize) {
this.maxFontSize = maxFontSize || 0;
}
-documentFragment.prototype.toDOM = function() {
+documentFragment.prototype.toNode = function() {
var frag = document.createDocumentFragment();
for (var i = 0; i < this.children.length; i++) {
- frag.appendChild(this.children[i].toDOM());
+ frag.appendChild(this.children[i].toNode());
}
return frag;
};
+documentFragment.prototype.toMarkup = function() {
+ var markup = "";
+
+ for (var i = 0; i < this.children.length; i++) {
+ markup += this.children[i].toMarkup();
+ }
+
+ return markup;
+};
+
function symbolNode(value, height, depth, italic, classes, style) {
this.value = value || "";
this.height = height || 0;
@@ -68,7 +113,7 @@ function symbolNode(value, height, depth, italic, classes, style) {
this.maxFontSize = 0;
}
-symbolNode.prototype.toDOM = function() {
+symbolNode.prototype.toNode = function() {
var node = document.createTextNode(this.value);
var span = null;
@@ -97,6 +142,47 @@ symbolNode.prototype.toDOM = function() {
}
};
+symbolNode.prototype.toMarkup = function() {
+ // TODO(alpert): More duplication than I'd like from
+ // span.prototype.toMarkup and symbolNode.prototype.toNode...
+ var needsSpan = false;
+
+ var markup = " 0) {
+ styles += "margin-right:" + this.italic + "em;";
+ }
+ for (var style in this.style) {
+ if (this.style.hasOwnProperty(style)) {
+ styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
+ }
+ }
+
+ if (styles) {
+ needsSpan = true;
+ markup += " style=\"" + utils.escape(styles) + "\"";
+ }
+
+ var escaped = utils.escape(this.value);
+ if (needsSpan) {
+ markup += ">";
+ markup += escaped;
+ markup += "";
+ return markup;
+ } else {
+ return escaped;
+ }
+};
+
module.exports = {
span: span,
documentFragment: documentFragment,
diff --git a/katex.js b/katex.js
index 5f0a660f5..2de9e5662 100644
--- a/katex.js
+++ b/katex.js
@@ -8,12 +8,18 @@ var process = function(toParse, baseNode) {
utils.clearNode(baseNode);
var tree = parseTree(toParse);
- var node = buildTree(tree).toDOM();
+ var node = buildTree(tree).toNode();
baseNode.appendChild(node);
};
+var renderToString = function(toParse) {
+ var tree = parseTree(toParse);
+ return buildTree(tree).toMarkup();
+};
+
module.exports = {
process: process,
+ renderToString: renderToString,
ParseError: ParseError
};
diff --git a/test/katex-spec.js b/test/katex-spec.js
index 4caae2fe8..d03c34a11 100644
--- a/test/katex-spec.js
+++ b/test/katex-spec.js
@@ -1,3 +1,4 @@
+var katex = require("../katex");
var buildTree = require("../buildTree");
var parseTree = require("../parseTree");
var ParseError = require("../ParseError");
@@ -986,3 +987,14 @@ describe("A bin builder", function() {
expect(getBuilt("\\blue{x+}+y")[1].classes).toContain("mord");
});
});
+
+describe("A markup generator", function() {
+ it("marks trees up", function() {
+ // Just a few quick sanity checks here...
+ var markup = katex.renderToString("\\sigma^2");
+ expect(markup.indexOf("": ">",
+ "<": "<",
+ "\"": """,
+ "'": "'"
+};
+
+var ESCAPE_REGEX = /[&><"']/g;
+
+function escaper(match) {
+ return ESCAPE_LOOKUP[match];
+}
+
+/**
+ * Escapes text to prevent scripting attacks.
+ *
+ * @param {*} text Text value to escape.
+ * @return {string} An escaped string.
+ */
+function escape(text) {
+ return ('' + text).replace(ESCAPE_REGEX, escaper);
+}
+
var setTextContent;
if (typeof document !== "undefined") {
@@ -40,6 +71,8 @@ function clearNode(node) {
module.exports = {
contains: contains,
+ escape: escape,
+ hyphenate: hyphenate,
indexOf: indexOf,
setTextContent: setTextContent,
clearNode: clearNode