Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Modernizr.prefixed(str,obj) to use Function.prototype.bind? #478

Closed
paulirish opened this Issue · 14 comments

3 participants

@paulirish
Owner

or just

 return function(){ return x.apply(navigator, arguments); }

The reason why

Some recent examples from user tests..

window[ Modernizr.prefixed('requestAnimationFrame', window) ]
battery = nav[ Modernizr.prefixed('battery', nav) ];
window[ Modernizr.prefixed('StorageInfo', window) ];

The double window/nav references kinda suck.. wondering if we just automatically bind the scope of it so we can pass back a function.

Hmmm

But would we only do this if the resulting thing is a function? And still just pass back a string otherwise?

how about Modernizr.prefixed('performance', window); .. pass back object or string?

Also to consider..

HTMLElement.prototype.webkitMatchesSelector
// so
Modernizr.prefixed('webkitMatchesSelector', HTMLElement.prototype); // return value ??

so we should make a call..what do we return?

  1. always return a string? (current behavior)
  2. return bound function in the case of functions?
  3. return actual reference for all cases (matchesSelector example disqualifies this)
  4. require a 3rd param to use as the binding scope (see comment below)
@ryanseddon ryanseddon was assigned
@paulirish
Owner

a possibility for scoping for the last example from alex... use a 3rd param.

var myelem = evt.target;
var ms = Modernizr.prefixed( 'matchesSelector', HTMLElement.prototype, myelem)
if (ms('.item')) ...
@ryanseddon
Owner

That is a tough one. I would argue that this about detecting and not creating a helper method, however being both would be advantageous. I could play around with a 3rd arg and see how it feels?

@paulirish
Owner

I think i wanna do the autobind.

questions:

  1. bind to 2nd arg automatically if its typeof .. == 'function' (and no 3rd arg) ?
  2. require 3rd arg to opt into binding

.

  • what to do about objects (like window.msPerformance) and props? return references and values or string as we do it today..
@SlexAxton
Owner

Sorry was mobile earlier and couldn't chime in. I think we can do this pretty easily with something like the following:

Normal Case

// Since 'requestAnimationFrame' exists on window as a function, 
// return the function bound to window
Modernizr.prefixed('requestAnimationFrame', window)

Override to string:

// Passing false as a third param disables the possibility 
// of a function return, always a string
Modernizr.prefixed('requestAnimationFrame', window, false) // window.webkitRequestAnimationFrame

Override to other binding:

// force a binding by passing the bound object.
// This could be avoided by just passing in the element as the second param (as long as we look into prototypes).
Modernizr.prefixed( 'matchesSelector', HTMLElement.prototype, document.getElementById('theid'))

Downsides I can see:

  • Performance: it will be faster to get a string back once, and use it on all elements.
  • The case of no function being found returns a string, but when it's found it returns a function, so you'd have to test the output. This could be a bad thing.
@SlexAxton
Owner

Perhaps that means you should have to opt in for it. Always returns a string, unless you pass a third param.

pass true for us to auto use the 2nd arg, and any other object to bind to that instead.

Further if you expect a function back, the result should be falsey if it doesn't exist (instead of the raw string like in the string version of the function). A noop function could potentially work, but I haven't thought into that much.

@paulirish
Owner

It should be falsy return if the test fails.. which would allow for a nice rAF polyfill

window.rAF = Modernizr.prefixed('requestAnimationFrame', window) || function(){ ... 

The rest sounds good to me. I would prefer to return the function / object / prop value when possible instead of its name.

Trying to think of any prefixed property names that are just string values or numbers...

@ryanseddon
Owner

Check out some early code in the prefixed branch 16a056d

I just grabbed the Function.prototype.bind shim from es5-shim

window.rAF = Modernizr.prefixed('requestAnimationFrame', window) || function(){ ...

This will now work as expected either returning a reference to rAF of false and falling back to function

// Passing in the 3rd arg will bind to that
// e.g. ms("div") -> true
var ms = Modernizr.prefixed("matchesSelector", HTMLElement.prototype, document.querySelector("div"))

So the three possible results that this change can get:

  • false
  • reference to object
  • reference to object with binding
@ryanseddon
Owner

Also it doesn't do any hand holding so if someone tries to pass in something silly for the 3rd arg it will throw.

@paulirish
Owner

ryan you got a patch for this alls et?

@paulirish
Owner

I just merged in Ryan's branch. Considering this ticket closed code-wise but we'll have to add docs.

@paulirish
Owner

Okay. code and tests updated. lots of tests!

i think this is basically what @SlexAxton proposed here
#478 (comment)

I have some extra checks so we're not calling .bind() on a non-function.
i think the tests explain the API the best, but

  • if prefixed(str,obj) identifies a fn then its auto-bind()'d to obj
  • if the third arg exists and is truthy, then the fn is bind()'d to it.
  • if the third arg is false, then its always returns the stringed name of the prop/method
  • if prefixed(str,obj) finds something that is a non-function, it just returns that.
@paulirish
Owner

Done except for docs.

@ryanseddon
Owner

I approve this commit, good stuff!

@paulirish
Owner

docs added.

@paulirish paulirish closed this
@patrickkettner patrickkettner referenced this issue from a commit in patrickkettner/Modernizr
@paulirish paulirish more robust prefixed() code and unit tests. ref #478 b82a322
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.