From 425be8a1966680dfc82dfcb19644d2c1c1c5c251 Mon Sep 17 00:00:00 2001 From: Vladimir Varankin Date: Wed, 8 Jul 2015 00:52:11 +0300 Subject: [PATCH] jquery__events_type_pointernative: pointerdown event works incorrectly in IE Edge Use native `PointerEvent` if supported. fix #1066 Optimise PointerMap class: use native Map class if supported (port of jquery/PEP#190). --- .../_type/jquery__event_type_pointernative.js | 126 ++++++++---------- 1 file changed, 57 insertions(+), 69 deletions(-) diff --git a/common.blocks/jquery/__event/_type/jquery__event_type_pointernative.js b/common.blocks/jquery/__event/_type/jquery__event_type_pointernative.js index 1a6374701..0bb64645e 100644 --- a/common.blocks/jquery/__event/_type/jquery__event_type_pointernative.js +++ b/common.blocks/jquery/__event/_type/jquery__event_type_pointernative.js @@ -1,6 +1,3 @@ -/*! - * Basic pointer events polyfill - */ ;(function(global, factory) { if(typeof modules === 'object' && modules.isDefined('jquery')) { @@ -14,7 +11,17 @@ if(typeof modules === 'object' && modules.isDefined('jquery')) { }(this, function(window, $) { -// include "jquery-pointerevents.js" +var jqEvent = $.event; + +// NOTE: Remove jQuery special fixes for pointerevents – we fix them ourself +delete jqEvent.special.pointerenter; +delete jqEvent.special.pointerleave; + +if(window.PointerEvent) { + // Have native PointerEvent support, nothing to do than + return; +} + /*! * Most of source code is taken from PointerEvents Polyfill * written by Polymer Team (https://github.com/Polymer/PointerEvents) @@ -22,17 +29,11 @@ if(typeof modules === 'object' && modules.isDefined('jquery')) { */ var doc = document, - USE_NATIVE_MAP = window.Map && window.Map.prototype.forEach, HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE === 'number', - POINTERS_FN = function() { return this.size }, - jqEvent = $.event; - -// NOTE: Remove jQuery special fixes for pointerevents – we fix them ourself -delete jqEvent.special.pointerenter; -delete jqEvent.special.pointerleave; + undef; /*! - * Returns a snapshot of inEvent, with writable properties. + * Returns a snapshot of the event, with writable properties. * * @param {Event} event An event that contains properties to copy. * @returns {Object} An object containing shallow copies of `inEvent`'s @@ -130,68 +131,53 @@ function PointerEvent(type, params) { return e; } -/*! - * Implements a map of pointer states - * @returns {PointerMap} - * @constructor - */ -function PointerMap() { - if(USE_NATIVE_MAP) { - var m = new Map(); - m.pointers = POINTERS_FN; - return m; - } - - this.keys = []; - this.values = []; +function SparseArrayMap() { + this.array = []; + this.size = 0; } -PointerMap.prototype = { - set : function(id, event) { - var i = this.keys.indexOf(id); - if(i > -1) { - this.values[i] = event; - } else { - this.keys.push(id); - this.values.push(event); +SparseArrayMap.prototype = { + set : function(k, v) { + if(v === undef) { + return this.delete(k); + } + if(!this.has(k)) { + this.size++; } + this.array[k] = v; }, - has : function(id) { - return this.keys.indexOf(id) > -1; + has : function(k) { + return this.array[k] !== undef; }, - 'delete' : function(id) { - var i = this.keys.indexOf(id); - if(i > -1) { - this.keys.splice(i, 1); - this.values.splice(i, 1); + delete : function(k) { + if(this.has(k)){ + delete this.array[k]; + this.size--; } }, - get : function(id) { - var i = this.keys.indexOf(id); - return this.values[i]; + get : function(k) { + return this.array[k]; }, clear : function() { - this.keys.length = 0; - this.values.length = 0; + this.array.length = 0; + this.size = 0; }, + // return value, key, map forEach : function(callback, ctx) { - var keys = this.keys; - this.values.forEach(function(v, i) { - callback.call(ctx, v, keys[i], this); + return this.array.forEach(function(v, k) { + callback.call(ctx, v, k, this); }, this); - }, - - pointers : function() { - return this.keys.length; } }; -var pointermap = new PointerMap(); +// jscs:disable requireMultipleVarDecl +var PointerMap = window.Map && window.Map.prototype.forEach? Map : SparseArrayMap, + pointerMap = new PointerMap(); var dispatcher = { eventMap : {}, @@ -435,12 +421,12 @@ var mouseEvents = { mousedown : function(event) { if(!this.isEventSimulatedFromTouch(event)) { - if(pointermap.has(MOUSE_POINTER_ID)) { + if(pointerMap.has(MOUSE_POINTER_ID)) { // http://crbug/149091 this.cancel(event); } - pointermap.set(MOUSE_POINTER_ID, event); + pointerMap.set(MOUSE_POINTER_ID, event); var e = this.prepareEvent(event); dispatcher.down(e); @@ -456,7 +442,7 @@ var mouseEvents = { mouseup : function(event) { if(!this.isEventSimulatedFromTouch(event)) { - var p = pointermap.get(MOUSE_POINTER_ID); + var p = pointerMap.get(MOUSE_POINTER_ID); if(p && p.button === event.button) { var e = this.prepareEvent(event); dispatcher.up(e); @@ -486,7 +472,7 @@ var mouseEvents = { }, cleanupMouse : function() { - pointermap['delete'](MOUSE_POINTER_ID); + pointerMap['delete'](MOUSE_POINTER_ID); } }; @@ -519,8 +505,8 @@ var touchEvents = { * Sets primary touch if there no pointers, or the only pointer is the mouse */ setPrimaryTouch : function(touch) { - if(pointermap.pointers() === 0 || - (pointermap.pointers() === 1 && pointermap.has(MOUSE_POINTER_ID))) { + if(pointerMap.size === 0 || + (pointerMap.size === 1 && pointerMap.has(MOUSE_POINTER_ID))) { this.firstTouch = touch.identifier; this.firstXY = { X : touch.clientX, Y : touch.clientY }; this.scrolling = null; @@ -532,7 +518,9 @@ var touchEvents = { removePrimaryPointer : function(pointer) { if(pointer.isPrimary) { this.firstTouch = null; - // this.firstXY = null; + // TODO(@narqo): It seems that, flushing `firstXY` flag explicitly in `touchmove` handler is enough. + // Original code from polymer doing `this.firstXY = null` on every `removePrimaryPointer` call, but looks + // like it is harmful in some of our usecases. this.resetClickCount(); } }, @@ -622,12 +610,12 @@ var touchEvents = { */ vacuumTouches : function(touchEvent) { var touches = touchEvent.touches; - // pointermap.pointers() should be less than length of touches here, as the touchstart has not + // `pointermap.size` should be less than length of touches here, as the touchstart has not // been processed yet. - if(pointermap.pointers() >= touches.length) { + if(pointerMap.size >= touches.length) { var d = []; - pointermap.forEach(function(pointer, pointerId) { + pointerMap.forEach(function(pointer, pointerId) { // Never remove pointerId == 1, which is mouse. // Touch identifiers are 2 smaller than their pointerId, which is the // index in pointermap. @@ -707,7 +695,7 @@ var touchEvents = { overDown : function(pEvent) { var target = pEvent.target; - pointermap.set(pEvent.pointerId, { + pointerMap.set(pEvent.pointerId, { target : target, outTarget : target, outEvent : pEvent @@ -718,7 +706,7 @@ var touchEvents = { }, moveOverOut : function(pEvent) { - var pointer = pointermap.get(pEvent.pointerId); + var pointer = pointerMap.get(pEvent.pointerId); // a finger drifted off the screen, ignore it if(!pointer) { @@ -767,7 +755,7 @@ var touchEvents = { }, cleanUpPointer : function(pEvent) { - pointermap['delete'](pEvent.pointerId); + pointerMap['delete'](pEvent.pointerId); this.removePrimaryPointer(pEvent); } }; @@ -805,7 +793,7 @@ var msEvents = { }, MSPointerDown : function(event) { - pointermap.set(event.pointerId, event); + pointerMap.set(event.pointerId, event); var e = this.prepareEvent(event); dispatcher.down(e); }, @@ -838,7 +826,7 @@ var msEvents = { }, cleanup : function(id) { - pointermap['delete'](id); + pointerMap['delete'](id); } };