From 8af018b1facff1dee753f0cf4c341f0a91285d6a Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Tue, 8 Apr 2014 14:28:11 -0500 Subject: [PATCH] fix(scroll): Allow scrolling when touchstart target is an input, #1078 --- js/ext/angular/test/service/ionicTap.unit.js | 95 ++++++++++++++++++++ js/utils/tap.js | 8 ++ js/views/scrollView.js | 10 +-- 3 files changed, 105 insertions(+), 8 deletions(-) diff --git a/js/ext/angular/test/service/ionicTap.unit.js b/js/ext/angular/test/service/ionicTap.unit.js index 5445b9a3ba5..5406a9c2c3e 100644 --- a/js/ext/angular/test/service/ionicTap.unit.js +++ b/js/ext/angular/test/service/ionicTap.unit.js @@ -290,4 +290,99 @@ describe('Ionic Tap', function() { expect( ionic.tap.ignoreTapInspect(e) ).toEqual(false); }); + it('Should not prevent scrolling', function() { + var target = document.createElement('div'); + var e = { + target: target + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(false); + }); + + it('Should prevent scrolling because the event has defaultedPrevented', function() { + var target = document.createElement('div'); + var e = { + target: target, + defaultPrevented: true + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(true); + }); + + it('Should not prevent scrolling if the target was an input or textarea', function() { + var target = document.createElement('input'); + var e = { + target: target + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(false); + }); + + it('Should prevent scrolling if the target was an input or textarea, and the target is the same as the active element', function() { + var target = document.createElement('input'); + ionic.tap.activeElement(target); + var e = { + target: target + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(true); + }); + + it('Should not prevent scrolling if the target isContentEditable', function() { + var target = document.createElement('div'); + target.isContentEditable = true; + var e = { + target: target + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(false); + }); + + it('Should prevent scrolling if the target has dataset.preventScroll', function() { + var target = document.createElement('div'); + target.setAttribute('data-prevent-scroll', 'true'); + var e = { + target: target + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(true); + + target = document.createElement('div'); + target.dataset.preventScroll = true; + e = { + target: target + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(true); + + target = document.createElement('div'); + target.dataset.preventScroll = 'true'; + e = { + target: target + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(true); + }); + + it('Should prevent scrolling if the browser doesnt support dataset but target has data-prevent-default attribute', function() { + var target = { + tagName: 'div', + getAttribute: function(val) { + if(val === 'data-prevent-default') { + return 'true'; + } + } + } + var e = { + target: target + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(true); + }); + + it('Should prevent scrolling if the target is an object or embed', function() { + var target = document.createElement('object'); + var e = { + target: target + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(true); + + target = document.createElement('embed'); + e = { + target: target + }; + expect( ionic.tap.ignoreScrollStart(e) ).toEqual(true); + }); + }); diff --git a/js/utils/tap.js b/js/utils/tap.js index ca970b6758c..a8720aa6caf 100644 --- a/js/utils/tap.js +++ b/js/utils/tap.js @@ -263,6 +263,14 @@ reset: function() { tapCoordinates = {}; startCoordinates = {}; + }, + + ignoreScrollStart: function(e) { + return (e.defaultPrevented) || // defaultPrevented has been assigned by another component handling the event + (e.target.tagName.match(/input|textarea/i) && ionic.tap.activeElement() === e.target) || // target is the active element, so its a second tap to select input text + (e.target.isContentEditable) || + (e.target.dataset ? e.target.dataset.preventScroll : e.target.getAttribute('data-prevent-default')) == 'true' || // manually set within an elements attributes + (!!e.target.tagName.match(/object|embed/i)); // flash/movie/object touches should not try to scroll } }; diff --git a/js/views/scrollView.js b/js/views/scrollView.js index 0b0264200be..d42bc26fa2f 100644 --- a/js/views/scrollView.js +++ b/js/views/scrollView.js @@ -616,16 +616,10 @@ ionic.views.Scroll = ionic.views.View.inherit({ e.stopPropagation(); }); - function shouldIgnorePress(e) { - return e.target.tagName.match(/input|textarea|select|object|embed/i) || - e.target.isContentEditable || - (e.target.dataset ? e.target.dataset.preventScroll : e.target.getAttribute('data-prevent-default') == 'true'); - } - if ('ontouchstart' in window) { container.addEventListener("touchstart", function(e) { - if (e.defaultPrevented || shouldIgnorePress(e)) { + if ( ionic.tap.ignoreScrollStart(e) ) { return; } self.doTouchStart(e.touches, e.timeStamp); @@ -648,7 +642,7 @@ ionic.views.Scroll = ionic.views.View.inherit({ var mousedown = false; container.addEventListener("mousedown", function(e) { - if (e.defaultPrevented || shouldIgnorePress(e)) { + if ( ionic.tap.ignoreScrollStart(e) ) { return; } self.doTouchStart([{