Skip to content

Commit

Permalink
Changed prefixed method to return live object and added third arg to …
Browse files Browse the repository at this point in the history
…bind to
  • Loading branch information
ryanseddon committed Jan 30, 2012
1 parent 7efcb78 commit 16a056d
Showing 1 changed file with 128 additions and 8 deletions.
136 changes: 128 additions & 8 deletions modernizr.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,126 @@ window.Modernizr = (function( window, document, undefined ) {
};
}

// Taken from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js
// ES-5 15.3.4.5
// http://es5.github.com/#x15.3.4.5

if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) { // .length is 1
// 1. Let Target be the this value.
var target = this;
// 2. If IsCallable(Target) is false, throw a TypeError exception.
if (typeof target != "function") {
throw new TypeError(); // TODO message
}
// 3. Let A be a new (possibly empty) internal list of all of the
// argument values provided after thisArg (arg1, arg2 etc), in order.
// XXX slicedArgs will stand in for "A" if used
var args = slice.call(arguments, 1); // for normal call
// 4. Let F be a new native ECMAScript object.
// 11. Set the [[Prototype]] internal property of F to the standard
// built-in Function prototype object as specified in 15.3.3.1.
// 12. Set the [[Call]] internal property of F as described in
// 15.3.4.5.1.
// 13. Set the [[Construct]] internal property of F as described in
// 15.3.4.5.2.
// 14. Set the [[HasInstance]] internal property of F as described in
// 15.3.4.5.3.
var bound = function () {

if (this instanceof bound) {
// 15.3.4.5.2 [[Construct]]
// When the [[Construct]] internal method of a function object,
// F that was created using the bind function is called with a
// list of arguments ExtraArgs, the following steps are taken:
// 1. Let target be the value of F's [[TargetFunction]]
// internal property.
// 2. If target has no [[Construct]] internal method, a
// TypeError exception is thrown.
// 3. Let boundArgs be the value of F's [[BoundArgs]] internal
// property.
// 4. Let args be a new list containing the same values as the
// list boundArgs in the same order followed by the same
// values as the list ExtraArgs in the same order.
// 5. Return the result of calling the [[Construct]] internal
// method of target providing args as the arguments.

var F = function(){};
F.prototype = target.prototype;
var self = new F;

var result = target.apply(
self,
args.concat(slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return self;

} else {
// 15.3.4.5.1 [[Call]]
// When the [[Call]] internal method of a function object, F,
// which was created using the bind function is called with a
// this value and a list of arguments ExtraArgs, the following
// steps are taken:
// 1. Let boundArgs be the value of F's [[BoundArgs]] internal
// property.
// 2. Let boundThis be the value of F's [[BoundThis]] internal
// property.
// 3. Let target be the value of F's [[TargetFunction]] internal
// property.
// 4. Let args be a new list containing the same values as the
// list boundArgs in the same order followed by the same
// values as the list ExtraArgs in the same order.
// 5. Return the result of calling the [[Call]] internal method
// of target providing boundThis as the this value and
// providing args as the arguments.

// equiv: target.call(this, ...boundArgs, ...args)
return target.apply(
that,
args.concat(slice.call(arguments))
);

}

};
// XXX bound.length is never writable, so don't even try
//
// 15. If the [[Class]] internal property of Target is "Function", then
// a. Let L be the length property of Target minus the length of A.
// b. Set the length own property of F to either 0 or L, whichever is
// larger.
// 16. Else set the length own property of F to 0.
// 17. Set the attributes of the length own property of F to the values
// specified in 15.3.5.1.

// TODO
// 18. Set the [[Extensible]] internal property of F to true.

// TODO
// 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
// 20. Call the [[DefineOwnProperty]] internal method of F with
// arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
// thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
// false.
// 21. Call the [[DefineOwnProperty]] internal method of F with
// arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
// [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
// and false.

// TODO
// NOTE Function objects created using Function.prototype.bind do not
// have a prototype property or the [[Code]], [[FormalParameters]], and
// [[Scope]] internal properties.
// XXX can't delete prototype in pure-js.

// 22. Return F.
return bound;
};
}

/**
* setCss applies given styles to the Modernizr DOM node.
*/
Expand Down Expand Up @@ -247,10 +367,10 @@ window.Modernizr = (function( window, document, undefined ) {
* testDOMProps is a generic DOM property test; if a browser supports
* a certain property, it won't return undefined for it.
*/
function testDOMProps( props, obj ) {
function testDOMProps( props, obj, elem ) {
for ( var i in props ) {
if ( obj[ props[i] ] !== undefined) {
return props[i];
return elem ? obj[props[i]].bind(elem) : obj[props[i]];
}
}
return false;
Expand All @@ -262,7 +382,7 @@ window.Modernizr = (function( window, document, undefined ) {
* the element including the non-vendor prefixed one, for forward-
* compatibility.
*/
function testPropsAll( prop, prefixed ) {
function testPropsAll( prop, prefixed, elem ) {

var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1),
props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
Expand All @@ -271,7 +391,7 @@ window.Modernizr = (function( window, document, undefined ) {
return testProps(props, prefixed);
} else {
props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
return testDOMProps(props, prefixed);
return testDOMProps(props, prefixed, elem);
}
}

Expand Down Expand Up @@ -445,8 +565,8 @@ window.Modernizr = (function( window, document, undefined ) {
return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
};

// Mozilla is targeting to land MozWebSocket for FF6
// bugzil.la/659324
// FIXME: Once FF10 is sunsetted, we can drop prefixed MozWebSocket
// bugzil.la/695635
tests['websockets'] = function() {
for ( var i = -1, len = cssomPrefixes.length; ++i < len; ){
if ( window[cssomPrefixes[i] + 'WebSocket'] ){
Expand Down Expand Up @@ -1124,12 +1244,12 @@ window.Modernizr = (function( window, document, undefined ) {
// },
// transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];

Modernizr.prefixed = function(prop, obj){
Modernizr.prefixed = function(prop, obj, elem){
if(!obj) {
return testPropsAll(prop, 'pfx');
} else {
// Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
return testPropsAll(prop, obj);
return testPropsAll(prop, obj, elem);
}
};

Expand Down

3 comments on commit 16a056d

@SlexAxton
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we lose all the es5-shim comments? Just for fun.

@ryanseddon
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They've been dropped (I'd planned to do this I just did quick snatch and grab off the es5-shim repo)

@SlexAxton
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tite.

Please sign in to comment.