JavaScript Ninja – Passive-Event Detector

You’ve probably know this one,
a variation of it is at the Mozilla-docs for addEventListener and Modernizer too.

It uses Object.defineProperty and a accessor descriptor with a getter. Older browsers may give you an error for using Object.defineProperty.

In those examples I am an event-listener with an
explicit assignment to "touchend",
instead of “foo” or “test” which might also work fine.

Since passive-event was specifically designed for
pointer/touch events, it is in our best interest to
test any browser implementation, even ones that might
choose to provide passive-functionality to just the
pointer/touch events.

It is not too pricey to use “real event”, since it is released right-away,
assigned to a plain-event handler and "touchend" itself is
executed at the end of the touch events-queue.

//VARIATION #1 - will work fine for "newer browsers".
self.is_support_passive = (function(){ "use strict";
  var is_support_passive = false
     ,descriptor         = {}
     ,opts               = {}
     ;

  function getter(){
    is_support_passive = true;
    return true;
  }

  descriptor.enumerable   = true;
  descriptor.configurable = true;
  descriptor.get          = getter;
  descriptor.set          = undefined;

  Object.defineProperty(opts, "passive", descriptor);

  window.addEventListener("touchend", null, opts);

  return is_support_passive;
}());

console.log(
  self.is_support_passive
);

/*
Above code will fail on some old browsers with error/exception of
"Object.defineProperty is not a function"
using __defineGetter__ is an alternative (see support_passive_event_handler_options_old_browser_getter_support.js)
but since the lack of Object.defineProperty is a pointer to viewer using an old browser,
you can also 99%-safely say you don't have any passive-event support.

Also - some Firefox versions will fail-silently when using null as an event-handler,
so the next variation will use an actual (but simple) event-handler.
*/

A more compatible example,
it is not assigning null but an actual event-handler,
(which will make some versions of SpiderMonkey (Firefox) on OSX, report false “no support”),
also it avoids Object.defineProperty in favor of an older feature called __defineGetter__, it is pretty much just to avoid “testing” another feature.

//VARIATION #2 - will support "older/basic headless-browsers".
self.is_support_passive = (function(){ "use strict";
  var is_support_passive = false
     ,opts               = {}
     ;

  function getter(){
    is_support_passive = true;
    return true;
  }

  function event_handler(ev){
    return true;
  }

  Object.prototype.__defineGetter__.call(opts, "passive", getter);

  window.addEventListener("touchend",    event_handler, opts);
  window.removeEventListener("touchend", event_handler, opts);

  return is_support_passive;
}());

console.log(
  self.is_support_passive
);

Final example takes into account that you might want
to check for support on even older platforms,
so a try/catch block will preserve the existing (initial) value false,
silently gulp-up any error/exceptions.

//VARIATION #3 - will support all low-end browsers.
self.is_support_passive = (function(){ "use strict";
  var is_support_passive = false
     ,opts               = {}
     ;

  function getter(){
    is_support_passive = true;
    return true;
  }

  function event_handler(ev){
    return true;
  }

  try{
  Object.prototype.__defineGetter__.call(opts, "passive", getter);
  window.addEventListener("touchend",    event_handler, opts);
  window.removeEventListener("touchend", event_handler, opts);
  }catch(err){}

  return is_support_passive;
}());

console.log(
  self.is_support_passive
);

Third example is also available here:
https://github.com/Modernizr/Modernizr/issues/1894#issuecomment-331563798.