Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

fix(gesture): tapping a submit button fires two submit events on mobile #11729

Merged
merged 1 commit into from
May 30, 2019
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion src/components/tabs/demoDynamicTabs/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

function AppCtrl ($scope, $log) {
var tabs = [
{ title: 'Zero (AKA 0, Cero, One - One, -Nineteen + 19, and so forth and so on and continuing into what seems like infinity.)', content: 'Woah...that is a really long title!' },
{ title: 'Zero (AKA 0, Cero, One - One, -Nineteen + 19, and so forth and so on and continuing into what seems like infinity)', content: 'Whoa...that is a really long title!' },
{ title: 'One', content: "Tabs will become paginated if there isn't enough room for them."},
{ title: 'Two', content: "You can swipe left and right on a mobile device to change tabs."},
{ title: 'Three', content: "You can bind the selected tab via the selected attribute on the md-tabs element."},
Expand Down
100 changes: 70 additions & 30 deletions src/core/services/gesture/gesture.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ var lastLabelClickPos = null;
// Used to attach event listeners once when multiple ng-apps are running.
var isInitialized = false;

var userAgent = navigator.userAgent || navigator.vendor || window.opera;
var isIos = userAgent.match(/ipad|iphone|ipod/i);
var isAndroid = userAgent.match(/android/i);

/**
* @ngdoc module
* @name material.core.gestures
Expand Down Expand Up @@ -110,9 +114,6 @@ MdGestureProvider.prototype = {
* @ngInject
*/
function MdGesture($$MdGestureHandler, $$rAF, $timeout) {
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
var isIos = userAgent.match(/ipad|iphone|ipod/i);
var isAndroid = userAgent.match(/android/i);
var touchActionProperty = getTouchAction();
var hasJQuery = (typeof window.jQuery !== 'undefined') && (angular.element === window.jQuery);

Expand Down Expand Up @@ -477,7 +478,7 @@ function MdGestureHandler() {

return GestureHandler;

/*
/**
* Dispatch an event with jQuery
* TODO: Make sure this sends bubbling events
*
Expand Down Expand Up @@ -519,24 +520,52 @@ function MdGestureHandler() {
var eventObj;

if (eventType === 'click' || eventType === 'mouseup' || eventType === 'mousedown') {
eventObj = document.createEvent('MouseEvents');
eventObj.initMouseEvent(
eventType, true, true, window, srcEvent.detail,
eventPointer.x, eventPointer.y, eventPointer.x, eventPointer.y,
srcEvent.ctrlKey, srcEvent.altKey, srcEvent.shiftKey, srcEvent.metaKey,
srcEvent.button, srcEvent.relatedTarget || null
);

if (typeof window.MouseEvent === "function") {
eventObj = new MouseEvent(eventType, {
bubbles: true,
cancelable: true,
screenX: Number(srcEvent.screenX),
screenY: Number(srcEvent.screenY),
clientX: Number(eventPointer.x),
clientY: Number(eventPointer.y),
ctrlKey: srcEvent.ctrlKey,
altKey: srcEvent.altKey,
shiftKey: srcEvent.shiftKey,
metaKey: srcEvent.metaKey,
button: srcEvent.button,
buttons: srcEvent.buttons,
relatedTarget: srcEvent.relatedTarget || null
});
} else {
eventObj = document.createEvent('MouseEvents');
// This has been deprecated
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
eventObj.initMouseEvent(
eventType, true, true, window, srcEvent.detail,
eventPointer.x, eventPointer.y, eventPointer.x, eventPointer.y,
srcEvent.ctrlKey, srcEvent.altKey, srcEvent.shiftKey, srcEvent.metaKey,
srcEvent.button, srcEvent.relatedTarget || null
);
}
} else {
eventObj = document.createEvent('CustomEvent');
eventObj.initCustomEvent(eventType, true, true, {});
if (typeof window.CustomEvent === "function") {
eventObj = new CustomEvent(eventType, {
bubbles: true,
cancelable: true,
detail: {}
});
} else {
// This has been deprecated
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/initCustomEvent
eventObj = document.createEvent('CustomEvent');
eventObj.initCustomEvent(eventType, true, true, {});
}
}
eventObj.$material = true;
eventObj.pointer = eventPointer;
eventObj.srcEvent = srcEvent;
eventPointer.target.dispatchEvent(eventObj);
}

}

/**
Expand Down Expand Up @@ -589,18 +618,26 @@ function attachToDocument($mdGesture, $$MdGestureHandler) {
}
}

/**
* Ignore click events that don't come from AngularJS Material, Ionic, Input Label clicks,
* or key presses that generate click events. This helps to ignore the ghost tap events on
* older mobile browsers that get sent after a 300-400ms delay.
* @param ev MouseEvent or modified MouseEvent with $material, pointer, and other fields
*/
function clickHijacker(ev) {
var isKeyClick = ev.clientX === 0 && ev.clientY === 0;
var isSubmitEvent = ev.target && ev.target.type === 'submit';
if (!isKeyClick && !ev.$material && !ev.isIonicTap
&& !isInputEventFromLabelClick(ev)
&& !isSubmitEvent) {
var isKeyClick;
if (isIos) {
isKeyClick = angular.isDefined(ev.webkitForce) && ev.webkitForce === 0;
} else {
isKeyClick = ev.clientX === 0 && ev.clientY === 0;
}
if (!isKeyClick && !ev.$material && !ev.isIonicTap && !isInputEventFromLabelClick(ev)) {
ev.preventDefault();
ev.stopPropagation();
lastLabelClickPos = null;
} else {
lastLabelClickPos = null;
if (ev.target.tagName.toLowerCase() == 'label') {
if (ev.target.tagName.toLowerCase() === 'label') {
lastLabelClickPos = {x: ev.x, y: ev.y};
}
}
Expand All @@ -621,10 +658,10 @@ function attachToDocument($mdGesture, $$MdGestureHandler) {
lastPointer = pointer = null;
});

/*
/**
* When a DOM event happens, run all registered gesture handlers' lifecycle
* methods which match the DOM event.
* Eg when a 'touchstart' event happens, runHandlers('start') will call and
* Eg. when a 'touchstart' event happens, runHandlers('start') will call and
* run `handler.cancel()` and `handler.start()` on all registered handlers.
*/
function runHandlers(handlerEvent, event) {
Expand All @@ -638,7 +675,6 @@ function attachToDocument($mdGesture, $$MdGestureHandler) {
handler.cancel();
}
handler[handlerEvent](event, pointer);

}
}
}
Expand All @@ -665,18 +701,22 @@ function attachToDocument($mdGesture, $$MdGestureHandler) {

runHandlers('start', ev);
}
/*

/**
* If a move event happens of the right type, update the pointer and run all the move handlers.
* "of the right type": if a mousemove happens but our pointer started with a touch event, do nothing.
* "of the right type": if a mousemove happens but our pointer started with a touch event, do
* nothing.
*/
function gestureMove(ev) {
if (!pointer || !typesMatch(ev, pointer)) return;

updatePointerState(ev, pointer);
runHandlers('move', ev);
}
/*
* If an end event happens of the right type, update the pointer, run endHandlers, and save the pointer as 'lastPointer'

/**
* If an end event happens of the right type, update the pointer, run endHandlers, and save the
* pointer as 'lastPointer'.
*/
function gestureEnd(ev) {
if (!pointer || !typesMatch(ev, pointer)) return;
Expand Down Expand Up @@ -740,8 +780,8 @@ function typesMatch(ev, pointer) {
*/
function isInputEventFromLabelClick(event) {
return lastLabelClickPos
&& lastLabelClickPos.x == event.x
&& lastLabelClickPos.y == event.y;
&& lastLabelClickPos.x === event.x
&& lastLabelClickPos.y === event.y;
}

/*
Expand Down