Skip to content

Instantly share code, notes, and snippets.

@curran
Last active June 8, 2016 07:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save curran/8f65dc5fbdd07fb0271a2a66479e4be9 to your computer and use it in GitHub Desktop.
Save curran/8f65dc5fbdd07fb0271a2a66479e4be9 to your computer and use it in GitHub Desktop.
Indenter
license: mit

I was searching for a way to indent a generated HTML fragment string, and was frustrated that all the packages I could find for doing this seem overly complex for the task at hand:

So I thought to myself, how hard could it be to write a function that indents HTML? It should be about a page of code, and would be a fun little puzzle. This is the result from the experiment, a small function that indents an HTML or XML fragment string.

If you find this useful and would like it released as a proper package, please let me know.

Built with blockbuilder.org

web counter
<!DOCTYPE html>
<head>
<meta charset="utf-8">
</head>
<body>
<pre id="indented-pre" style="font-size: 1.78em"></pre>
<script>
// Indents an HTML or XML fragment string.
function indent(str, numSpaces){
// The number of spaces to indent by (integer, defaults to 2).
if(typeof numSpaces === "undefined"){
numSpaces = 2;
}
var spaces = "";
for(var i = 0; i < numSpaces; i++){
spaces += " ";
}
// The current indentation level (integer).
var indentation = 0;
// The child count context stack.
var stack = [];
// The output string buffer (array of strings).
var output = [];
// For each character...
for (var i = 0; i < str.length; i++){
// Detect opening or closing tags.
if(str[i] === "<"){
// Detect a closing tag.
if(i < str.length - 1 && str[i + 1] === "/"){
// If there are any children, decrease indent.
if(stack.pop() !== 0){
indentation--;
} else {
// If there are no childten,
// place closing tags on the same line as their opening tag.
output.push("<");
continue;
}
// Detect an opening tag.
} else {
// Increase indentation only if this is the first child.
if(stack[stack.length - 1] === 0){
indentation++;
}
// Increment the child count for the current context.
stack[stack.length - 1]++;
// Push a new child count context onto the stack.
stack.push(0);
}
// Output a newline.
if(i !== 0){
output.push("\n");
}
// Output indentation spaces.
for(var j = 0; j < indentation; j++){
output.push(spaces);
}
}
// Append the current character to the output buffer.
output.push(str[i]);
}
// Concatenate the array of strings in the output buffer.
return output.join("");
}
// A generated HTML fragment string that we want indented.
var str = '<svg height="500" width="960"><g class="reactive-vis-margin-g" transform="translate(50,50)"><g class="reactive-vis-scatter-layer"><g class="reactive-vis-scatter-mark" transform="translate(0,0)" height="10" width="10"><circle class="reactive-vis-circle"></circle></g><g class="reactive-vis-scatter-mark" transform="translate(66.15384615384647,400)" height="16.690459207925603" width="16.690459207925603"><circle class="reactive-vis-circle"></circle></g><g class="reactive-vis-scatter-mark" transform="translate(793.8461538461535,50.00000000000006)" height="20" width="20"><circle class="reactive-vis-circle"></circle></g><g class="reactive-vis-scatter-mark" transform="translate(860,200)" height="19.820624179302296" width="19.820624179302296"><circle class="reactive-vis-circle"></circle></g></g></g></svg>';
// Compute the indented string.
var indented = indent(str);
// Display the indented string in the <pre> tag.
var pre = document.getElementById("indented-pre");
pre.textContent = indented;
// Vary the indentation to demonstrate the functionality clearly.
setInterval(function (){
var numSpaces = Math.floor((Math.sin(Date.now() / 1000) + 1) * 6);
pre.textContent = indent(str, numSpaces);
}, 200);
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment