JSFiddle - React, Tailwind, and code Playground

by BramVanroy

HTML

<div id="wrapper">
    <h1>XPath beautifier for GrETEL</h1>
    <div id="input">
        <h2>Input</h2>
        <textarea name="xpath-input" autofocus>//node[@cat="cp" and node[@rel="cmp" and @word="dat" and @root="dat" and @pos="comp"] and node[@rel="body" and @cat="ssub" and node[@rel="su" and @pos="pron"] and node[@rel="predc" and @pos="adj"] and node[@rel="hd" and @root="ben" and @pos="verb"]]]
</textarea>
        <input type="submit" value="Beautify!" class="s"/>
    </div>
    <div id="output">
        <h2>Output</h2>
        <pre></pre>
    </div>
</div>

CSS

#wrapper {
    width: 100%;
    max-width: 1024px;
    margin: 0 auto;
}
textarea, #output > pre {
    resize: vertical;
    overflow: auto;	
    
    line-height: 1.5em;
    font-size: 11px;
    font-family: "Lucida Console", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
    
    display: block;
    width: 95%;
    max-width: 960px;    
    min-height: 90px;
    margin: 10px auto;
    padding: 2px 4px;
    
    border: 1px solid #ddd;
    border-radius: 3px;
    box-shadow: 0 2px #ddd;
    
    color: #333;
    
    -moz-tab-size: 6;
    -o-tab-size: 6;
    tab-size: 6;
}
#output > pre {
    resize: none;
}

textarea:focus, #output > pre.beautified  {
    outline: 0 none;
    border-color: #bbb;
    box-shadow: 0 2px #bbb;
}

input[type="submit"] {
    margin-left: 2.5%;
    display: block;   
    padding: 0.32em 0.48em;
    
    border-radius: 4px;
    border: 2px solid transparent;
    
    background-color: #4679BD;
    
    color: #fff;
    font-variant: small-caps;
    letter-spacing: 1px;
    
    cursor: pointer;
}

input[type="submit"]:hover {
    border-bottom: 2px solid #2e61a3;
}

input[type="submit"]:focus {
    border: 2px solid #fff;
    box-shadow: 0 0 0 1px #6096DB, inset 0 -11px 20px rgba(0, 0, 0, 0.12);
    outline: 0 none;
    left: 0;
    
    -moz-transform: translateY(2px);
    -webkit-transform: translateY(2px);
    -o-transform: translateY(2px);
    -ms-transform: translateY(2px);
    transform: translateY(2px);
}

html, body {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
}

h1, h2 {
    padding: 0 2.5%;
    color: #333;
    font-family: Garamond, serif;
}
h1 {
    border-bottom: 2px solid #333;
    padding-bottom: 6px;
}

JavaScript

var a = $("textarea[name='xpath-input']"),
    b = $("#output > pre");

$(".s").click(function() {
    b.html(indent(a.val()));
});

b.html(indent(a.val()));

a.focus(function() {
   if (b.hasClass("beautified")) b.removeClass("beautified");
});

function indent(str)
{
    var tabs = function(n) { return new Array(n+1).join('\t'); }

    var tokens = str.match(/\[|\]|and|(?:(?!and)[^\[\]])+/g);
    var depth = 0;
    var result = '';
    for (var i = 0; i < tokens.length; ++i)
    {
        var token = tokens[i];
        switch(token)
        {
        case '[':
            ++depth;
            result += token + '\n' + tabs(depth);
            break;
        case ']':
            --depth;
            result += '\n' + tabs(depth) + token;
            break;
        case 'and':
            result += token + '\n' + tabs(depth);
            break;
        default:
            result += token;
            break;
        }
    }
    
    result = result.replace(/^(\t*)[]+/gm, '$1');
    
    return result;
}