Sometime back this thread on HackerNews gained quite some traction. Basically, it’s a small project called MiniCodeEditor which is a tiny and minimal version of an online code playground like CSSDeck.
My purpose here is to simply explain the 168 bytes code:
[html]
<body oninput=’e.firstChild.srcdoc=t2[v="value"]+"<script>"+t0[v]+"</script><style>"+t1[v]’onload=’for(i=3;i–;)e.innerHTML+="<textarea id=t"+i+" rows=9>"’id=e><iframe>
[/html]
Note: This piece of code will work on modern browsers only (Chrome, Safari and Firefox).
Creating Code Editors
The code editors (textareas) are created by this piece of code:
[html]
onload=’for(i=3;i–;)e.innerHTML+="<textarea id=t"+i+" rows=9>"’
[/html]
The for loop executes thrice to append 3 textareas with IDs t[1-3] to the body. As the conditional expression i-- becomes 0 which is a falsy value, the loop ends.
Rendering the HTML/CSS/JS Code in the Iframe Sandbox
The piece of code that is responsible for concatenating all the html/css/js code from various textareas and chuck it into the iframe is this:
[html]
oninput=’e.firstChild.srcdoc=t2[v="value"]+"<script>"+t0[v]+"</script><style>"+t1[v]’
[/html]
The srcdoc attribute of the iframe referenced by e.firstChild is set to the concatenated value of the html, js and css (in that order) textareas. This happens when the input event is fired, which is raised instantly when the content of an input or textarea element is changed (event propagation).
One super interesting trick used here is this:
[text]
t2[v="value"] … t0[v] … t1[v]
[/text]
The string value gets saved to a new variable v which is reused later. This saves exactly 1 character over:
[text]
t2.value … t0.value … t1.value
[/text]
Cross Browser Compatibility
You’ll find a cross-browser version on the project’s webpage which looks like this:
[html]
<body id=e><script>for(i=4;–i;)e.innerHTML+="<textarea id=t"+i+" placeholder="+[,"JS","CSS","HTML"][i]+" rows=9 onkeydown=’if((K=event).keyCode==9){K.preventDefault();s=this.selectionStart;this.value=this.value.substring(0,this.selectionStart)+\"\t\"+this.value.substring(this.selectionEnd);this.selectionEnd=s+1}’>"+(unescape((l=location).hash.slice(1,-1)).split("\x7F")[i-1]||"");onload=onkeyup=function(a){q=[(E=escape)(j=t1[v="value"]),E(c=t2[v]),E(h=t3[v])].join("\x7f")+1;(H=history)&&H.replaceState?H.replaceState(0,0,"#"+q):location.hash=q;I=h||c||j?h+"<script>"+j+"<\/script><style>"+c:"<pre>Result";navigator.userAgent.match(/IE|Tr/)?((D=e.lastChild.contentWindow.document).write(I),D.close()):frames[0].location.replace("data:text/html,"+escape(I))}</script><iframe>
[/html]
A prettier version of this code is this:
[html]
<body id=e>
<script>
for (i = 4; –i;) e.innerHTML += "<textarea id=t" + i + " placeholder=" + [, "JS", "CSS", "HTML"][i] + " rows=9 onkeydown=’if((K=event).keyCode==9){K.preventDefault();s=this.selectionStart;this.value=this.value.substring(0,this.selectionStart)+\"\t\"+this.value.substring(this.selectionEnd);this.selectionEnd=s+1}’>" + (unescape((l = location).hash.slice(1, -1)).split("\x7F")[i – 1] || "");
onload = onkeyup = function (a) {
q = [(E = escape)(j = t1[v = "value"]), E(c = t2[v]), E(h = t3[v])].join("\x7f") + 1;
(H = history) && H.replaceState ? H.replaceState(0, 0, "#" + q) : location.hash = q;
I = h || c || j ? h + "<script>" + j + "<\/script><style>" + c : "<pre>Result";
navigator.userAgent.match(/IE|Tr/) ? ((D = e.lastChild.contentWindow.document).write(I), D.close()) : frames[0].location.replace("data:text/html," + escape(I))
}
</script>
<iframe>
[/html]
Similar to the previous version, this piece of code also starts by creating 3 textareas with keydown events that checks for the tab key to allow indentations.
This version has an interesting auto-save feature too, as you write the code. When we type in any of the boxes, it concatenates all the code with a separator which is the non-printable DEL (\x7f) character and saves them into the browser hash string. This piece is achieved by the listener attached to the load and keyup events of the window (global) object.
So even after a refresh, the code will simply break the hash string on the separator and set the values for different code boxes. The code that helps with the setting of the values is this (as a value of the textarea tag in the first line of the JS code):
[js]
(unescape((l = location).hash.slice(1, -1)).split("\x7F")[i – 1] || "");
[/js]
Conclusion
This project might not have a practical usage but is really fun as there are a couple of tricks employed in order to make the code really short and yet produce some meaningful result.