-
-
Save thingsinjars/1466219 to your computer and use it in GitHub Desktop.
function( | |
constructor, //The group to make chainable - | |
// e.g. Window.Element, Window.Node, Window.DOMTokenList etc... | |
prototype, //Placeholder | |
method //Placeholder | |
) { | |
prototype = constructor.prototype; //Shorthand to work with the prototype of the constructor | |
for (method in prototype) // For every method on this object | |
if (prototype[method].call) // ...if it's a function | |
prototype[method] = (function(method) { // Make every function | |
return function() { // into another function | |
return method.apply(this, arguments) // which does its job then either returns itself if that was the default behaviour | |
|| // or | |
this; // returns itself here | |
} | |
})(prototype[method]) // pass in the method we want to be working with | |
} |
function(a,b,c){b=a.prototype;for(c in b)if(b[c].call)b[c]=(function(d){return function(){return d.apply(this,arguments)||this}})(b[c])} |
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
Version 2, December 2004 | |
Copyright (C) 2011 YOUR_NAME_HERE <YOUR_URL_HERE> | |
Everyone is permitted to copy and distribute verbatim or modified | |
copies of this license document, and changing it is allowed as long | |
as the name is changed. | |
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
0. You just DO WHAT THE FUCK YOU WANT TO. |
{ | |
"name": "chainableDomManipulation", | |
"description": "Extremely minimal chainable DOM manipulation based on Chainvas", | |
"keywords": [ | |
"html", | |
"DOM", | |
"chaining" | |
] | |
} |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<title>Chain anything</title> | |
<div>Expected value: <b><a href="http://140byt.es/" title="tiny awsm" data-monkeys="∞">140byt.es</a></b></div> | |
<div>Actual value: <b id="ret"></b></div> | |
<script> | |
// This is paired with the propertize gist to cover chainability and setting properties | |
//This is a very, very minimal version of the functionality of Chainvas (http://lea.verou.me/chainvas/) to make anything chainable | |
var chainer = function(a,b,c){b=a.prototype;for(c in b)if(b[c].call)b[c]=(function(d){return function(){return d.apply(this,arguments)||this}})(b[c])} | |
// see https://gist.github.com/gists/1466253 | |
var propertize = function(a,b,c){a.prototype.prop=function(){b=arguments;if(1 in b)this[b[0]]=b[1];else{b=b[0];for(c in b)this[c]=b[c]}return this}} | |
chainer(window.Element); | |
propertize(window.Element); | |
document.getElementById('ret').appendChild( | |
document.createElement('a') | |
.prop({ | |
'href': 'http://140byt.es/', | |
'title': 'tiny awsm' | |
}) | |
.prop('innerHTML', '140byt.es') | |
.setAttribute('data-monkeys', '∞') | |
.addEventListener('click', function(){ alert('Urk! Alert!')}, false) | |
); | |
</script> |
I took out the extra check
if (prototype[method] && // If it exists and...
as we only get to the check when we are iterating through the object so we know it already exists. It's now at 140bytes exactly.
You can eliminate a bunch of curly brackets.
You're right. I've just taken out four of them. Thanks
Nice idea and great job!
A little code minimizing hint: extra scope for closure may also be created using with
.This and some Byte-saving techniques makes the code shorter:
// 114 bytes
function(a,b){for(a in b=a.prototype)with({d:b[a]})d.call?b[a]=function(){return d.apply(this,arguments)||this}:0}
Dang, that's a clever shuffle. I'd never have considered using a with there.
I've updated the code and (I think) annotated it right.
Hawt stuff!
The problem is that with using the || operator, you return this
even when the result was going to be null
or 0
or the empty string, all three being quite common.
Ah, well spotted, thanks.
Thanks to @subzey's clever shuffling, there's enough space to put in a strict undefined
check and return correctly on null
or 0
. There might still be a clever way to remove the c
variable introduced here but I shan't attempt to figure it out tonight, I don't think.
My initial hope of combining chain and prop together looks to be a bit unobtainable. Still, they both function fine on their own.
I suppose, []._
may be replaced by a._
. a
is "inherited" from outer scope and is surely a string
Done. I must get round to putting together some performance tests at some point.
*edit: http://jsperf.com/trialchainifytest
Not sure I've got the setup quite right but, anyway, it's not too bad for performance.
Love it... using the call property to detect a function is brilliantly simply yet rarely seen. Does it work cross browser?
That’s duck typing, and not usually considered a good practice (although in this case it saves characters). Don't do it when # of bytes is not such a huge issue.
True, a simple {call:true} would make it unstuck.
Uh-oh, if any prototype property will be null
or undefined
, function throws TypeError
.
I suppose, typeof
should be used, it's just 140 bytes:
function(a,b,c){for(a in b=a.prototype)with({d:b[a]})typeof d=='function'?b[a]=function(){return(c=d.apply(this,arguments))===a._?this:c}:0}
I started messing around testing whether something is a function by using (typeof d)[0]=='f'
before deciding it just felt wrong.
Besides, I don't think it works in IE7.
But this works in IE7+
/^f/.test(typeof b)
Well, saves 1 byte.
Since with() is deprecated and unreliable, I remade your function to not use with().
chainify = function(a,b){for(b in a)(function(c){a[b]=function(){c.apply(this,arguments);return this}})(a[b])}
chainify(window.Element.prototype)
Feel free to use it :)
Note: These updates include calling the function on window.Element or window.Element.prototype
Seperate functions --------------------
Original prop - 174 bytes
var propertize=function(a,b,c){a.prototype.prop=function(){if(b=arguments,1 in b)this[b[0]]=b[1];else{b=b[0];for(c in b)this[c]=b[c]}return this}};propertize(window.Element);
Updated prop - 141 bytes
!function(a,b,c){a.prototype.prop=function(){b=arguments,1 in b?this[b[0]]=b[1]:b=b[0];for(c in b)this[c]=b[c];return this}}(window.Element);
Original chanify - 166 bytes
var chainify=function(a,b,c){for(a in b=a.prototype)with({d:b[a]})d.call?b[a]=function(){return(c=d.apply(this,arguments))===[]._?this:c}:0};chainify(window.Element);
Updated chanify - 129 bytes
!function(a,b){for(b in a=a.prototype)(function(c){a[b]=function(){return c.apply(this,arguments),this}})(a[b])}(window.Element);
Combined functions --------------------
Original prop and chanify - 336 bytes
var propertize=function(a,b,c){a.prototype.prop=function(){if(b=arguments,1 in b)this[b[0]]=b[1];else{b=b[0];for(c in b)this[c]=b[c]}return this}},chainify=function(a,b,c){for(a in b=a.prototype)with({d:b[a]})d.call?b[a]=function(){return(c=d.apply(this,arguments))===[]._?this:c}:0};propertize(window.Element),chainify(window.Element);
Updated prop and chanify - 228 bytes
!function(a,b,c){a.prop=function(){b=arguments,1 in b?this[b[0]]=b[1]:b=b[0];for(c in b)this[c]=b[c];return this};for(b in a=a)(function(c){a[b]=function(){return c.apply(this,arguments),this}})(a[b])}(window.Element.prototype);
@tjbenton awesome! use codeblocks...
@thingsinjars, need update of the gist because it is 2015 now :)
Based on above
propertize - 123 bytes
function(a,b,c){a.prototype.prop=function(){b=arguments,1 in b?this[b[0]]=b[1]:b=b[0];for(c in b)this[c]=b[c];return this}}
chainify - 111 bytes
function(a,b){for(b in a=a.prototype)(function(c){a[b]=function(){return c.apply(this,arguments),this}})(a[b])}
Combined propertize + chainify - 200 bytes - test pass!
function(a,b,c){a.prop=function(){b=arguments,1 in b?this[b[0]]=b[1]:b=b[0];for(c in b)this[c]=b[c];return this};for(b in a=a)(function(c){a[b]=function(){return c.apply(this,arguments),this}})(a[b])}
test pass
This is currently at 146 bytes so there's a little room for improvement.
The test file references the chainable property setter (https://gist.github.com/1466253) as I was working on them both at the same time although I could probably separate them into smaller test cases.
It started off as a minimal implementation of Lea Verou's Chainvas