Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add strong touch event handling for scrollable.js #1064

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
211 changes: 199 additions & 12 deletions src/scrollable/scrollable.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,27 +289,214 @@
}

// touch event
if (conf.touch) {
if (conf.touch && ('ontouchstart' in document)) {
var touch = {};
// yes, you want a limit to not launch scrollable on tiny moves
// this value can come from configuration, but I do not want to be too intrusive
var touchMinDelta = conf.touchMinDelta || 25;

// polyfill part
( function(){
// find best way to get the TouchList prototype
var proto;

// standard method
if( window.TouchList ) {
proto = window.TouchList.prototype;
// can we look for document.createTouchList
} else if( 'createTouchList' in document ) {
// get prototype of this
if( 'getPrototypeOf' in window.Object ) {
proto = window.Object.getPrototypeOf( document.createTouchList() );
} else if( typeof 'xx'.__proto__ === 'object' ) {
proto = document.createTouchList().__proto__;
} else {
// may break
proto = document.createTouchList().constructor.prototype;
}
} else {
// oups...
return;
}

// at this point proto is OK
// prototype the method if not exists
if(!('identifiedTouch' in proto)) {
proto.identifiedTouch = function( id ) {
var i = this.length, t;
while( i-- ) {
t = this.item( i );
// found, stop and return it
if( t.identifier === id ) return t;
}
// not found
return false;
};
}
} )();

itemWrap[0].ontouchstart = function(e) {
var t = e.touches[0];
touch.x = t.clientX;
touch.y = t.clientY;
// at first, look if it is not a second touch
// touch identifier can be 0
if(touch.id === undefined) {
// we want the first touch that trigger the event
var t = e.changedTouches[0];
touch.id = t.identifier;
touch.x = t.clientX;
touch.y = t.clientY;
}
};

itemWrap[0].ontouchmove = function(e) {

// only deal with one finger
if (e.touches.length == 1 && !itemWrap.is(":animated")) {
var t = e.touches[0],
deltaX = touch.x - t.clientX,
deltaY = touch.y - t.clientY;

self[vertical && deltaY > 0 || !vertical && deltaX > 0 ? 'next' : 'prev']();
e.preventDefault();
// do the current touch still on contact
// - first contact (registered)
// - second contact (not regisetred)
// - remove first contact (unregistred)
// - move second contact
// = will trigger a touchmove event from the second contact, but the
// first one is not available anymore
// touch identifier can be 0
if (touch.id !== undefined && !itemWrap.is(":animated")) {

// look if the current touch has trigger the event
var t = e.changedTouches.identifiedTouch(touch.id);
if (t) {
// ok, we can do the job now
// >0 from right to left, <0 from left to right
var deltaX = touch.x - t.clientX;
var absdeltaX = Math.abs( deltaX );
// >0 from bottom to top, <0 from top to bottom
var deltaY = touch.y - t.clientY;
var absdeltaY = Math.abs( deltaY );

// look for the biggest one to determine vertical or horizontal move
if (absdeltaX > absdeltaY) {
// horizontal move

// if the scrollable is vertical, do not do anything
if(vertical) return true;

// prevent tiny move
if(absdeltaX > touchMinDelta){
// we are ok, we can process move
// >0 from right to left: move left, next
// <0 from left to right: move right, prev
self[ deltaX > 0 ? 'next' : 'prev']();

// reassign x/y
touch.x = t.clientX;
touch.y = t.clientY;
}

// prevent default, even on tiny moves
e.preventDefault();

} else if (absdeltaX < absdeltaY) {
// vertical move

// if the scrollable is not vertical, do not do anything
if (!vertical) return true;

// prevent tiny move
if(absdeltaY > touchMinDelta){
// we are ok, we can process move
// >0 from bottom to top: move up, next
// <0 from top to bottom: move down, prev
self[ deltaY > 0 ? 'next' : 'prev']();

// reassign x/y
touch.x = t.clientX;
touch.y = t.clientY;
}

// prevent default, even on tiny moves
e.preventDefault();

} else {
// can be both
if (vertical) {
// consider vertical

// prevent tiny move
if(absdeltaY > touchMinDelta){
// we are ok, we can process move
// >0 from bottom to top: move up, next
// <0 from top to bottom: move down, prev
self[ deltaY > 0 ? 'next' : 'prev']();

// reassign x/y
touch.x = t.clientX;
touch.y = t.clientY;
}

// prevent default, even on tiny moves
e.preventDefault();
} else {
// consider horizontal

// prevent tiny move
if(absdeltaX > touchMinDelta){
// we are ok, we can process move
// >0 from right to left: move left, next
// <0 from left to right: move right, prev
self[ deltaX > 0 ? 'next' : 'prev']();

// reassign x/y
touch.x = t.clientX;
touch.y = t.clientY;
}

// prevent default, even on tiny moves
e.preventDefault();
}
}
}
}
};

itemWrap[0].ontouchend = function(e) {
// do the current touch still on contact
// touch identifier can be 0
if (touch.id !== undefined) {
// look if the current touch has trigger the event
if(e.changedTouches.identifiedTouch(touch.id)) {
// ok, unregister
touch = {};
// if there was a move, a touchmove should have
// been trigger before this event
}
}
};

itemWrap[0].ontouchcancel = function(e) {
// do the current touch still on contact
// touch identifier can be 0
if (touch.id !== undefined) {
// look if the current touch has trigger the event
if(e.changedTouches.identifiedTouch(touch.id)) {
// ok, unregister
touch = {};
// if there was a move, a touchmove should have
// been trigger before this event
}
}
};

itemWrap[0].ontouchleave = function(e) {
// do the current touch still on contact
// touch identifier can be 0
if (touch.id !== undefined) {
// look if the current touch has trigger the event
if(e.changedTouches.identifiedTouch(touch.id)) {
// ok, unregister
touch = {};
// if there was a move, a touchmove should have
// been trigger before this event
}
}
};

}

if (conf.keyboard) {
Expand Down