Skip to content

Commit

Permalink
fix(tap): Do not preventDefault after input focus, #1068
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdbradley committed Apr 7, 2014
1 parent a19e3b6 commit a977332
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 49 deletions.
87 changes: 52 additions & 35 deletions js/ext/angular/test/service/ionicTap.unit.js
Expand Up @@ -23,34 +23,6 @@ describe('Ionic Tap', function() {
expect(targetEle.isFocused).toEqual(true);
});

it('Should preventDefault on an input', function() {
var targetEle = {
dispatchEvent: function() {},
focus: function() {}
};

ionic.tap.setTouchStart({ clientX: 100, clientY: 100 });
var e = {
clientX: 100, clientY: 100,
preventDefault: function() { this.preventedDefault = true }
};

targetEle.tagName = 'INPUT';
ionic.tap.simulateClick(targetEle, e);
expect(e.preventedDefault).toEqual(true);
e.preventedDefault = false;

targetEle.tagName = 'TEXTAREA';
ionic.tap.simulateClick(targetEle, e);
expect(e.preventedDefault).toEqual(true);
e.preventedDefault = false;

targetEle.tagName = 'DIV';
ionic.tap.simulateClick(targetEle, e);
expect(e.preventedDefault).toEqual(false);
e.preventedDefault = false;
});

it('Should setTouchStart and hasTouchScrolled true if >= touch tolerance', function() {
ionic.tap.setTouchStart({ clientX: 100, clientY: 100 });

Expand Down Expand Up @@ -183,13 +155,6 @@ describe('Ionic Tap', function() {
expect( ionic.tap.ignoreSimulateClick(targetEle) ).toEqual(true);
});

it('Should ignoreSimulateClick for input[file] elements', function() {
// Reported that on Android input[file] does not open using the tap
var targetEle = document.createElement('input');
targetEle.type = 'file';
expect( ionic.tap.ignoreSimulateClick(targetEle) ).toEqual(true);
});

it('Should ignoreSimulateClick for input[range] elements', function() {
// Range and tap do not agree, probably because it doesn't have a delay to begin with
var targetEle = document.createElement('input');
Expand Down Expand Up @@ -227,4 +192,56 @@ describe('Ionic Tap', function() {
expect(ionic.tap.isTapElement('P')).toEqual(false);
});

it('Should focus input', function() {
var ele = {
tagName: 'input',
focus: function(){ this.hasFocus=true; }
}
ionic.tap.handleFocus(ele);
expect( ele.hasFocus ).toEqual(true);
});

it('Should focus textarea', function() {
var ele = {
tagName: 'textarea',
focus: function(){ this.hasFocus=true; }
}
ionic.tap.handleFocus(ele);
expect( ele.hasFocus ).toEqual(true);
});

it('Should focus select', function() {
var ele = {
tagName: 'select',
focus: function(){ this.hasFocus=true; }
}
ionic.tap.handleFocus(ele);
expect( ele.hasFocus ).toEqual(true);
});

it('Should not focus on common elements', function() {
var tags = ['div', 'span', 'i', 'body', 'section', 'article', 'aside', 'li', 'p', 'header', 'button', 'ion-content'];
for(var x=0; x<tags.length; x++) {
var ele = {
tagName: tags[x],
focus: function(){ this.hasFocus=true; }
}
ionic.tap.handleFocus(ele);
expect( ele.hasFocus ).toBeUndefined();
}
});

it('Should not focus on an input that already has focus', function() {
var ele = {
tagName: 'input',
focus: function(){ this.hasFocus=true; }
}
ionic.tap.handleFocus(ele);
expect( ele.hasFocus ).toEqual(true);

ele.focus = function(){ this.hasSecondFocus=true }
ionic.tap.handleFocus(ele);
expect( ele.hasSecondFocus ).toBeUndefined();
});

});
41 changes: 27 additions & 14 deletions js/utils/tap.js
Expand Up @@ -11,6 +11,7 @@
var startCoordinates = {}; // used to remember where the coordinates of the start of a touch
var clickPreventTimerId;
var _hasTouchScrolled = false; // if the touchmove already exceeded the touchmove tolerance
var _activeElement; // the element which has focus


ionic.tap = {
Expand Down Expand Up @@ -74,15 +75,8 @@

ele.dispatchEvent(clickEvent);

if( ele.tagName.match(/input|textarea/i) ) {
ele.focus();
e.preventDefault();
} else if( ele.tagName == 'SELECT' ) {
// select simulateClick should not preventDefault or else no options dialog
ele.focus();
} else {
ionic.tap.blurActive();
}
// if it's an input, focus in on the target, otherwise blur
ionic.tap.handleFocus(ele);

// remember the coordinates of this tap so if it happens again we can ignore it
// but only if the coordinates are not already being actively disabled
Expand All @@ -98,7 +92,20 @@
},

ignoreSimulateClick: function(ele) {
return ele.disabled || ele.type === 'file' || ele.type === 'range';
return ele.disabled || ele.type === 'range';
},

handleFocus: function(ele) {
if(ionic.tap.activeElement() !== ele) {
// only set the focus if it doesn't already have it
if( ele.tagName.match(/input|textarea|select/i) ) {
ionic.tap.activeElement(ele);
ele.focus();
} else {
ionic.tap.activeElement(null);
ionic.tap.blurActive();
}
}
},

preventGhostClick: function(e) {
Expand Down Expand Up @@ -217,16 +224,22 @@
},

blurActive: function() {
var ele = document.activeElement;
if(ele && (ele.tagName === "INPUT" ||
ele.tagName === "TEXTAREA")) {
// using a timeout to prevent funky scrolling while a keyboard hides
var ele = ionic.tap.activeElement();
if(ele && ele.tagName.match(/input|textarea|select/i) ) {
setTimeout(function(){
ele.blur();
ionic.tap.activeElement(null);
}, 400);
}
},

activeElement: function(ele) {
if(arguments.length) {
_activeElement = ele;
}
return _activeElement || document.activeElement;
},

setTouchStart: function(e) {
_hasTouchScrolled = false;
startCoordinates = ionic.tap.getCoordinates(e);
Expand Down

0 comments on commit a977332

Please sign in to comment.