aboutsummaryrefslogtreecommitdiff
path: root/lib/html
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2015-10-13 23:29:41 +0100
committerMichael Williamson <mike@zwobble.org>2015-10-13 23:49:31 +0100
commit7b7ce0d563ddc07172b0f241a5c3baf344f256e8 (patch)
tree43f5fddf920d47e281a30139bde99da5a689d667 /lib/html
parente04d054a1b414e843fa6d6f5ee1ae75c0df533b1 (diff)
Collapse similar HTML elements
Diffstat (limited to 'lib/html')
-rw-r--r--lib/html/ast.js31
-rw-r--r--lib/html/index.js38
-rw-r--r--lib/html/simplify.js43
3 files changed, 100 insertions, 12 deletions
diff --git a/lib/html/ast.js b/lib/html/ast.js
index afecfce..96aa6c6 100644
--- a/lib/html/ast.js
+++ b/lib/html/ast.js
@@ -20,24 +20,49 @@ function elementWithTag(tag, children) {
return {
type: "element",
tag: tag,
- children: collapseFragments(children)
+ children: collapseFragments(children),
+ isEmpty: _.all(children, function(child) {
+ return child.isEmpty;
+ }),
+ appendChild: appendChild
+ };
+}
+
+function appendChild(child) {
+ this.children.push(child);
+ this.isEmpty = this.isEmpty && child.isEmpty;
+}
+
+function selfClosingElement(tagName, attributes) {
+ return {
+ type: "selfClosingElement",
+ tagName: tagName,
+ attributes: attributes
};
}
function text(value) {
return {
type: "text",
- value: value
+ value: value,
+ isEmpty: !value
};
}
+var forceWrite = {
+ type: "forceWrite",
+ isEmpty: false
+};
+
function collapseFragments(elements) {
return _.flatten((elements || []).map(function(element) {
return element.type === "fragment" ? element.children : [element];
- }), true)
+ }), true);
}
exports.fragment = fragment;
exports.element = element;
exports.elementWithTag = elementWithTag;
+exports.selfClosingElement = selfClosingElement;
exports.text = text;
+exports.forceWrite = forceWrite;
diff --git a/lib/html/index.js b/lib/html/index.js
index 41d348f..f74a98f 100644
--- a/lib/html/index.js
+++ b/lib/html/index.js
@@ -3,7 +3,9 @@ var ast = require("./ast");
exports.fragment = ast.fragment;
exports.element = ast.element;
exports.elementWithTag = ast.elementWithTag;
+exports.selfClosingElement = ast.selfClosingElement;
exports.text = ast.text;
+exports.forceWrite = ast.forceWrite;
function pathToNode(path, children) {
var result = ast.fragment(children);
@@ -15,3 +17,39 @@ function pathToNode(path, children) {
exports.pathToNode = pathToNode;
exports.simplify = require("./simplify");
+
+function write(writer, node) {
+ toStrings[node.type](writer, node);
+}
+
+var toStrings = {
+ fragment: generateFragmentString,
+ element: generateElementString,
+ selfClosingElement: generateSelfClosingElementString,
+ text: generateTextString,
+ forceWrite: function() { }
+};
+
+function generateFragmentString(writer, node) {
+ node.children.forEach(function(child) {
+ write(writer, child);
+ });
+}
+
+function generateElementString(writer, node) {
+ writer.open(node.tag.tagName, node.tag.attributes);
+ node.children.forEach(function(child) {
+ write(writer, child);
+ });
+ writer.close(node.tag.tagName);
+}
+
+function generateSelfClosingElementString(writer, node) {
+ writer.selfClosing(node.tagName, node.attributes);
+}
+
+function generateTextString(writer, node) {
+ writer.text(node.value);
+}
+
+exports.write = write;
diff --git a/lib/html/simplify.js b/lib/html/simplify.js
index 291e5d4..8ab4a1f 100644
--- a/lib/html/simplify.js
+++ b/lib/html/simplify.js
@@ -1,15 +1,15 @@
-var _ = require("underscore");
-
var ast = require("./ast");
function simplify(node) {
- return simplifiers[node.type](node);
-};
+ return removeEmpty(simplifiers[node.type](node));
+}
var simplifiers = {
fragment: simplifyFragment,
element: simplifyElement,
- text: simplifyText
+ selfClosingElement: identity,
+ text: identity,
+ forceWrite: identity
};
function simplifyFragment(node) {
@@ -20,8 +20,8 @@ function simplifyElement(node) {
return ast.elementWithTag(node.tag, simplifyNodes(node.children));
}
-function simplifyText(node) {
- return node;
+function identity(value) {
+ return value;
}
function simplifyNodes(nodes) {
@@ -29,10 +29,10 @@ function simplifyNodes(nodes) {
nodes.map(simplify).forEach(function(child) {
var lastChild = children[children.length - 1];
- if (child.type === "element" && !child.tag.fresh && lastChild && child.tag.matchesElement(lastChild.tag)) {
+ if (child.type === "element" && !child.tag.fresh && lastChild && lastChild.type === "element" && child.tag.matchesElement(lastChild.tag)) {
child.children.forEach(function(grandChild) {
// Mutation is fine since simplifying elements create a copy of the children.
- lastChild.children.push(grandChild);
+ lastChild.appendChild(grandChild);
});
} else {
children.push(child);
@@ -41,4 +41,29 @@ function simplifyNodes(nodes) {
return children;
}
+function removeEmpty(node) {
+ return emptiers[node.type](node);
+}
+
+var emptiers = {
+ fragment: fragmentEmptier,
+ element: elementEmptier,
+ selfClosingElement: identity,
+ text: identity,
+ forceWrite: identity
+};
+
+function fragmentEmptier(fragment) {
+ return ast.fragment(fragment.children.filter(function(child) {
+ return !child.isEmpty;
+ }));
+}
+
+function elementEmptier(element) {
+ return ast.elementWithTag(element.tag, element.children.filter(function(child) {
+ return !child.isEmpty;
+ }));
+}
+
+
module.exports = simplify;