Skip to content

Instantly share code, notes, and snippets.

@gbakernet
Forked from nzakas/es6proxy.htm
Created September 8, 2011 22:52
Show Gist options
  • Save gbakernet/1205005 to your computer and use it in GitHub Desktop.
Save gbakernet/1205005 to your computer and use it in GitHub Desktop.
Example of ES6 Proxy
<!DOCTYPE html>
<!--
This is a simple experiment relying on ECMAScript 6 Proxies. To try this out,
use Aurora (http://www.mozilla.org/en-US/firefox/channel/).
The goal was to create a HTML writer where the method names were really just
the HTML tags names, but without manually creating each method. This uses
a Proxy to create a shell to an underlying writer object that checks each
method name to see if it's in a list of known tags.
-->
<html>
<body>
<script>
/*
* The constructor name I want is HTMLWriter.
*/
var HTMLWriter = (function(){
/*
* Lazily-incomplete list of HTML tags.
*/
var tags = [
"a", "abbr", "acronym", "address", "applet", "area",
"b", "base", "basefont", "bdo", "big", "blockquote",
"body", "br", "button",
"caption", "center", "cite", "code", "col", "colgroup",
"dd", "del", "dir", "div", "dfn", "dl", "dt",
"em",
"fieldset", "font", "form", "frame", "frameset",
"h1", "h2", "h3", "h4", "h5", "h6", "head", "hr", "html",
"i", "iframe", "img", "input", "ins", "isindex",
"kbd",
"label", "legend", "li", "link",
"map", "menu", "meta",
"noframes", "noscript",
"object", "ol", "optgroup", "option",
"p", "param", "pre",
"q",
"s", "samp", "script", "select", "small", "span", "strike",
"strong", "style", "sub", "sup",
"table", "tbody", "td", "textarea", "tfoot", "th", "thead",
"title", "tr", "tt",
"u", "ul",
"var"
];
/*
* Define an internal-only type. Code taken from:
* http://www.nczonline.net/blog/2009/02/17/mozilla-javascript-extension-nosuchmethod/
*/
function InternalHTMLWriter(){
this._work = [];
}
InternalHTMLWriter.prototype = {
escape: function (text){
return text.replace(/[><"&]/g, function(c){
switch(c){
case ">": return "&gt;";
case "<": return "&lt;";
case "\"": return "&quot;";
case "&": return "&amp;";
}
});
},
startTag: function(tagName, attributes){
this._work.push("<" + tagName);
if (attributes){
var name, value;
for (name in attributes){
if (attributes.hasOwnProperty(name)){
value = this.escape(attributes[name]);
this._work.push(" " + name + "=\"" + value + "\"");
}
}
}
this._work.push(">");
return this;
},
text: function(text){
this._work.push(this.escape(text));
return this;
},
endTag: function(tagName){
this._work.push("</" + tagName + ">");
return this;
},
toString: function(){
return this._work.join("");
}
};
/*
* Output a pseudo-constructor. It's not a real constructor,
* since it just returns the proxy object, but I like the
* "new" pattern vs. factory functions.
*/
return function(){
var writer = new InternalHTMLWriter(),
proxy = Proxy.create({
/*
* Only really need getter, don't want anything else going on.
*/
get: function(receiver, name){
var tagName,
closeTag = false;
if (name in writer){
return writer[name];
} else {
if (tags.indexOf(name) > -1){
tagName = name;
} else if (name.charAt(0) == "x" && tags.indexOf(name.substring(1)) > -1){
tagName = name.substring(1);
closeTag = true;
}
if (tagName){
return function(){
if (!closeTag){
writer.startTag(tagName, arguments[0]);
} else {
writer.endTag(tagName);
}
return receiver;
};
}
}
},
/*
* Don't allow fixing.
*/
fix: function(){
return undefined;
}
});
return proxy;
};
})();
//hmmm...doesn't look like magic way down here
var w = new HTMLWriter();
w.html()
.head().title().text("Example & Test").xtitle().xhead()
.body().text("Hello world!").xbody()
.xhtml();
console.log(w);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment