You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
3.6 KiB
160 lines
3.6 KiB
var util = require("util");
|
|
var _ = require("underscore");
|
|
|
|
exports.writer = writer;
|
|
|
|
function writer(options) {
|
|
options = options || {};
|
|
if (options.prettyPrint) {
|
|
return prettyWriter();
|
|
} else {
|
|
return simpleWriter();
|
|
}
|
|
}
|
|
|
|
|
|
var indentedElements = {
|
|
div: true,
|
|
p: true,
|
|
ul: true,
|
|
li: true
|
|
};
|
|
|
|
|
|
function prettyWriter() {
|
|
var indentationLevel = 0;
|
|
var indentation = " ";
|
|
var stack = [];
|
|
var start = true;
|
|
var inText = false;
|
|
|
|
var writer = simpleWriter();
|
|
|
|
function open(tagName, attributes) {
|
|
if (indentedElements[tagName]) {
|
|
indent();
|
|
}
|
|
stack.push(tagName);
|
|
writer.open(tagName, attributes);
|
|
if (indentedElements[tagName]) {
|
|
indentationLevel++;
|
|
}
|
|
start = false;
|
|
}
|
|
|
|
function close(tagName) {
|
|
if (indentedElements[tagName]) {
|
|
indentationLevel--;
|
|
indent();
|
|
}
|
|
stack.pop();
|
|
writer.close(tagName);
|
|
}
|
|
|
|
function text(value) {
|
|
startText();
|
|
var text = isInPre() ? value : value.replace("\n", "\n" + indentation);
|
|
writer.text(text);
|
|
}
|
|
|
|
function selfClosing(tagName, attributes) {
|
|
indent();
|
|
writer.selfClosing(tagName, attributes);
|
|
}
|
|
|
|
function insideIndentedElement() {
|
|
return stack.length === 0 || indentedElements[stack[stack.length - 1]];
|
|
}
|
|
|
|
function startText() {
|
|
if (!inText) {
|
|
indent();
|
|
inText = true;
|
|
}
|
|
}
|
|
|
|
function indent() {
|
|
inText = false;
|
|
if (!start && insideIndentedElement() && !isInPre()) {
|
|
writer._append("\n");
|
|
for (var i = 0; i < indentationLevel; i++) {
|
|
writer._append(indentation);
|
|
}
|
|
}
|
|
}
|
|
|
|
function isInPre() {
|
|
return _.some(stack, function(tagName) {
|
|
return tagName === "pre";
|
|
});
|
|
}
|
|
|
|
return {
|
|
asString: writer.asString,
|
|
open: open,
|
|
close: close,
|
|
text: text,
|
|
selfClosing: selfClosing
|
|
};
|
|
}
|
|
|
|
|
|
function simpleWriter() {
|
|
var fragments = [];
|
|
|
|
function open(tagName, attributes) {
|
|
var attributeString = generateAttributeString(attributes);
|
|
fragments.push(util.format("<%s%s>", tagName, attributeString));
|
|
}
|
|
|
|
function close(tagName) {
|
|
fragments.push(util.format("</%s>", tagName));
|
|
}
|
|
|
|
function selfClosing(tagName, attributes) {
|
|
var attributeString = generateAttributeString(attributes);
|
|
fragments.push(util.format("<%s%s />", tagName, attributeString));
|
|
}
|
|
|
|
function generateAttributeString(attributes) {
|
|
return _.map(attributes, function(value, key) {
|
|
return util.format(' %s="%s"', key, escapeHtmlAttribute(value));
|
|
}).join("");
|
|
}
|
|
|
|
function text(value) {
|
|
fragments.push(escapeHtmlText(value));
|
|
}
|
|
|
|
function append(html) {
|
|
fragments.push(html);
|
|
}
|
|
|
|
function asString() {
|
|
return fragments.join("");
|
|
}
|
|
|
|
return {
|
|
asString: asString,
|
|
open: open,
|
|
close: close,
|
|
text: text,
|
|
selfClosing: selfClosing,
|
|
_append: append
|
|
};
|
|
}
|
|
|
|
function escapeHtmlText(value) {
|
|
return value
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>');
|
|
}
|
|
|
|
function escapeHtmlAttribute(value) {
|
|
return value
|
|
.replace(/&/g, '&')
|
|
.replace(/"/g, '"')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>');
|
|
}
|
|
|