Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 90 additions & 45 deletions pointer_events_polyfill.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,113 @@
/*
/*!
* Pointer Events Polyfill: Adds support for the style attribute "pointer-events: none" to browsers without this feature (namely, IE).
* (c) 2013, Kent Mewhort, licensed under BSD. See LICENSE.txt for details.
*
* Modifications for clicks on LABEL tags associated with radios or checkboxes where simulated event triggers do not
* bubble to their corresponding input fields when the events are $.delegate'd on IE9
*/

// constructor
function PointerEventsPolyfill(options){
(function($) {
"use strict";

// constructor
var PointerEventsPolyfill = function(options) {
// set defaults
this.options = {
selector: '*',
mouseEvents: ['click','dblclick','mousedown','mouseup'],
usePolyfillIf: function(){
if(navigator.appName == 'Microsoft Internet Explorer')
{
var agent = navigator.userAgent;
if (agent.match(/MSIE ([0-9]{1,}[\.0-9]{0,})/) != null){
var version = parseFloat( RegExp.$1 );
if(version < 11)
return true;
}
selector: "*",
mouseEvents: ["click","dblclick","mousedown","mouseup"],
usePolyfillIf: function() {
if(navigator.appName === "Microsoft Internet Explorer") {
var agent = navigator.userAgent;
if (agent.match(/MSIE ([0-9]{1,}[\.0-9]{0,})/)) {
var version = parseFloat( RegExp.$1 );
if(version < 11) {
return true;
}
return false;
}
}
return false;
}
};
if(options){
var obj = this;
$.each(options, function(k,v){
obj.options[k] = v;
});

if(options) {
var self = this;
$.each(options, function(k, v) {
self.options[k] = v;
});
}

if(this.options.usePolyfillIf())
if(this.options.usePolyfillIf()) {
this.register_mouse_events();
}
}
};

// singleton initializer
PointerEventsPolyfill.initialize = function(options){
if(PointerEventsPolyfill.singleton == null)
// singleton initializer
PointerEventsPolyfill.initialize = function(options){
if(!PointerEventsPolyfill.singleton) {
PointerEventsPolyfill.singleton = new PointerEventsPolyfill(options);
}
return PointerEventsPolyfill.singleton;
}
};

// handle mouse events w/ support for pointer-events: none
PointerEventsPolyfill.prototype.register_mouse_events = function(){
// handle mouse events w/ support for pointer-events: none
PointerEventsPolyfill.prototype.register_mouse_events = function() {
// register on all elements (and all future elements) matching the selector
$(document).on(this.options.mouseEvents.join(" "), this.options.selector, function(e){
if($(this).css('pointer-events') == 'none'){
// peak at the element below
var origDisplayAttribute = $(this).css('display');
$(this).css('display','none');
$(document).on(this.options.mouseEvents.join(" "), this.options.selector, function(e) {
var origDisplayAttribute,
underneathElem,
$target,
$nestedInput,
idAttr;

if($(this).css("pointer-events") === "none") {
// peek at the element below
origDisplayAttribute = $(this).css("display");
$(this).css("display","none");

var underneathElem = document.elementFromPoint(e.clientX, e.clientY);
underneathElem = document.elementFromPoint(e.clientX, e.clientY);

if(origDisplayAttribute)
$(this)
.css('display', origDisplayAttribute);
else
$(this).css('display','');
// restore the previous css display attribute of the event target element
if(origDisplayAttribute) {
$(this).css("display", origDisplayAttribute);
} else {
$(this).css("display","");
}

// fire the mouse event on the element below
e.target = underneathElem;
$(underneathElem).trigger(e);
// Assume the intended target was the underneathElem
$target = $(underneathElem);

return false;
// clicks on labels are special, resolve the INPUT tag it relates to if possible and make that the target
if($target.prop("tagName") === "LABEL") {
if((idAttr = $target.attr("for"))) {
$target = $("#" + idAttr);
} else {
$nestedInput = $target.find("input");
if($nestedInput.length > 0) {
$target = $nestedInput.first();
}
}
}
return true;

// trigger a synthesized mouse event on the element below
var newEvent = $.extend(new $.Event(e.type), {
which: (typeof e.which !== "undefined") ? e.which : 1,
clientX: e.clientX,
clientY: e.clientY,
pageX: e.pageX,
pageY: e.pageY,
screenX: e.screenX,
screenY: e.screenY
});

$target.trigger(newEvent);

return false;
}
return true;
});
}
};

// global exports
window.PointerEventsPolyfill = PointerEventsPolyfill;

})(window.jQuery);