/** * 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 * `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. * * Similar functions for working with MathML nodes exist in mathMLTree.js. */ var utils = require("./utils"); /** * Create an HTML className based on a list of classes. In addition to joining * with spaces, we also remove null or empty classes. */ var createClass = function(classes) { classes = classes.slice(); for (var i = classes.length - 1; i >= 0; i--) { if (!classes[i]) { classes.splice(i, 1); } } return classes.join(" "); }; /** * This node represents a span node, with a className, a list of children, and * an inline style. It also contains information about its height, depth, and * maxFontSize. */ function span(classes, children, height, depth, maxFontSize, style) { this.classes = classes || []; this.children = children || []; this.height = height || 0; this.depth = depth || 0; this.maxFontSize = maxFontSize || 0; this.style = style || {}; this.attributes = {}; } /** * Sets an arbitrary attribute on the span. Warning: use this wisely. Not all * browsers support attributes the same, and having too many custom attributes * is probably bad. */ span.prototype.setAttribute = function(attribute, value) { this.attributes[attribute] = value; }; /** * Convert the span into an HTML node */ span.prototype.toNode = function() { var span = document.createElement("span"); // Apply the class span.className = createClass(this.classes); // Apply inline styles for (var style in this.style) { if (Object.prototype.hasOwnProperty.call(this.style, style)) { span.style[style] = this.style[style]; } } // Apply attributes for (var attr in this.attributes) { if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { span.setAttribute(attr, this.attributes[attr]); } } // Append the children, also as HTML nodes for (var i = 0; i < this.children.length; i++) { span.appendChild(this.children[i].toNode()); } return span; }; /** * Convert the span into an HTML markup string */ span.prototype.toMarkup = function() { var markup = " 0) { span = document.createElement("span"); span.style.marginRight = this.italic + "em"; } if (this.classes.length > 0) { span = span || document.createElement("span"); span.className = createClass(this.classes); } for (var style in this.style) { if (this.style.hasOwnProperty(style)) { span = span || document.createElement("span"); span.style[style] = this.style[style]; } } if (span) { span.appendChild(node); return span; } else { return node; } }; /** * Creates markup for a symbol node. */ 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, symbolNode: symbolNode, };