Skip to content
This repository was archived by the owner on May 7, 2025. It is now read-only.

Commit 057fb09

Browse files
committed
Merge branch 'feature/touchSwipe' into feature/ApacheCordova
2 parents 54c899f + a462b84 commit 057fb09

File tree

5 files changed

+2561
-1306
lines changed

5 files changed

+2561
-1306
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
.divshot-cache
33
node_modules
44
build
5-
local_test_data
5+
local_test_data
6+
_

css/readium_js.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
html.disable-ie-back-swipe {
2+
overflow-x: scroll;
3+
-ms-overflow-style: none;
4+
-ms-scroll-chaining: none;
5+
}
16
html {
27
height: 100%;
38
margin: 0;
@@ -10,6 +15,7 @@ body {
1015
margin: 0;
1116
position: absolute;
1217
overflow: hidden;
18+
-ms-overflow-style: -ms-autohiding-scrollbar;
1319
box-sizing:border-box;
1420
-moz-box-sizing:border-box; /* Firefox */
1521
-webkit-box-sizing:border-box; /* Safari */

lib/gestures.js

Lines changed: 292 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,76 +11,318 @@
1111
// used to endorse or promote products derived from this software without specific
1212
// prior written permission.
1313

14-
define(['jquery','jquery_hammer','hammer'], function($,jqueryHammer,Hammer) {
14+
define(['jquery','hammer'], function($,Hammer) {
1515

1616
var gesturesHandler = function(reader, viewport){
1717

18-
var onSwipeLeft = function(){
18+
var quiet = false;
19+
20+
var onSwipeLeft = function() {
21+
if (!quiet) console.debug("READIUM swipeleft (openPageRight)");
1922
reader.openPageRight();
2023
};
2124

22-
var onSwipeRight = function(){
25+
var onSwipeRight = function() {
26+
if (!quiet) console.debug("READIUM swiperight (openPageLeft)");
2327
reader.openPageLeft();
2428
};
2529

2630
var isGestureHandled = function() {
2731
var viewType = reader.getCurrentViewType();
28-
29-
return viewType === ReadiumSDK.Views.ReaderView.VIEW_TYPE_FIXED || viewType == ReadiumSDK.Views.ReaderView.VIEW_TYPE_COLUMNIZED;
32+
return viewType === ReadiumSDK.Views.ReaderView.VIEW_TYPE_FIXED || viewType == ReadiumSDK.Views.ReaderView.VIEW_TYPE_COLUMNIZED; // Excludes SCROLL
3033
};
3134

32-
this.initialize= function(){
35+
if (navigator.msMaxTouchPoints) {
36+
if (/Windows Phone/.test(navigator.userAgent)) {
37+
document.documentElement.classList.add('disable-ie-back-swipe');
38+
} else {
39+
try {
40+
var metroTestElement = document.createElement('div');
41+
metroTestElement.style.cssText = 'position:absolute;z-index:-1;top:0;right:0;bottom:-10px;width:1px';
42+
document.body.appendChild(metroTestElement);
43+
if (Math.round(window.outerWidth - metroTestElement.offsetLeft) === 1) {
44+
document.documentElement.classList.add('disable-ie-back-swipe');
45+
}
46+
document.body.removeChild(metroTestElement);
47+
} catch (e) { // window.outerWidth throws error if in IE showModalDialog
48+
}
49+
}
50+
}
51+
52+
var setupTouchDefaultActionSuppressor = function(doc, isTopLevel) {
53+
54+
var touchDown = false;
55+
var touchIdentifier = 0;
56+
var touchStartX = 0;
57+
var touchStartY = 0;
58+
var lockDragX = false;
59+
var lockDragY = false;
60+
61+
/*
62+
if (window.navigator.msPointerEnabled) {
63+
doc.addEventListener("MSPointerCancel", function (e) {
64+
if (!quiet) console.debug("DOC MSPointerCancel");
65+
e.preventDefault();
66+
}, false);
67+
doc.addEventListener("MSGestureInit", function (e) {
68+
if (!quiet) console.debug("DOC MSGestureInit");
69+
e.preventDefault();
70+
}, false);
71+
doc.addEventListener("MSHoldVisual", function (e) {
72+
if (!quiet) console.debug("DOC MSHoldVisual");
73+
e.preventDefault();
74+
}, false);
75+
}
76+
*/
77+
78+
doc.documentElement.addEventListener(window.navigator.msPointerEnabled ? "MSPointerDown" : "touchstart", function(ev) {
79+
if (window.navigator.msPointerEnabled && !ev.isPrimary) return;
80+
81+
if (touchDown) return;
82+
83+
touchDown = true;
84+
85+
lockDragX = false;
86+
lockDragY = false;
87+
88+
touchIdentifier = window.navigator.msPointerEnabled ? 1 : ev.touches.item(0).identifier;
89+
90+
touchStartX = window.navigator.msPointerEnabled ? ev.clientX : ev.touches.item(0).clientX;
91+
touchStartY = window.navigator.msPointerEnabled ? ev.clientY : ev.touches.item(0).clientY;
92+
93+
if (!quiet) console.debug("DOC touchstart");
94+
95+
if (isTopLevel)
96+
if (!quiet) console.debug("isTopLevel");
97+
98+
}, false); // !useCapture
99+
100+
var upOut1 = function(ev) {
101+
if (window.navigator.msPointerEnabled && !ev.isPrimary) return;
102+
103+
if (window.navigator.msPointerEnabled && touchIdentifier !== 1) {
104+
105+
if (!quiet) console.debug("DOC multi touch skip");
106+
return;
107+
}
108+
if (!window.navigator.msPointerEnabled) {
109+
110+
var found = false;
111+
for (var i = 0; i < ev.changedTouches.length; i++) {
112+
if (touchIdentifier == ev.changedTouches.item(i).identifier) {
113+
found = true;
114+
break;
115+
}
116+
}
117+
118+
if (!found) {
119+
if (!quiet) console.debug("DOC multi touch skip");
120+
return;
121+
}
122+
}
123+
124+
touchDown = false;
125+
touchIdentifier = 0;
126+
lockDragX = false;
127+
lockDragY = false;
128+
129+
if (!quiet) console.debug("DOC touchend");
130+
131+
if (isTopLevel)
132+
if (!quiet) console.debug("isTopLevel");
133+
};
134+
doc.addEventListener(window.navigator.msPointerEnabled ? "MSPointerUp" : "touchend", upOut1, true); // useCapture
135+
/*
136+
if (window.navigator.msPointerEnabled) {
137+
doc.addEventListener("MSPointerOut", upOut1);
138+
}
139+
*/
140+
141+
doc.addEventListener(window.navigator.msPointerEnabled ? "MSPointerMove" : "touchmove", function(ev) {
142+
143+
if (!touchDown) return;
144+
145+
if (window.navigator.msPointerEnabled && !ev.isPrimary) return;
146+
147+
if (touchIdentifier !== (window.navigator.msPointerEnabled ? 1 : ev.touches.item(0).identifier)) {
148+
149+
if (!quiet) console.debug("DOC multi touch skip");
150+
return;
151+
}
152+
153+
if (!quiet) console.debug("DOC touchmove");
154+
155+
if (!ev.cancelable) {
156+
if (!quiet) console.debug("DOC !CANCELABLE");
157+
return;
158+
}
159+
160+
if (ev.target && ev.target.ownerDocument.allowDefault) {
161+
ev.target.ownerDocument.allowDefault = false;
162+
163+
if (!quiet) console.debug("DOC allowDefault");
164+
return;
165+
}
166+
167+
if (!quiet) console.debug("DOC preventDefault");
168+
169+
ev.preventDefault();
170+
}, false); // NOT useCapture (so that ev.stopPropagation() can be used from a registered listener below in the DOM tree, thereby allowing the default browser action, such as scrolling of overflow containers ... otherwise, preventDefault() is invoked, which results in disabling certain browser-specific behaviours like overflow bounce / rubber banding, swipe history navigation, etc.)
171+
172+
173+
doc.documentElement.addEventListener(window.navigator.msPointerEnabled ? "MSPointerMove" : "touchmove", function(ev) {
174+
175+
if (!touchDown) return;
176+
177+
if (window.navigator.msPointerEnabled && !ev.isPrimary) return;
178+
179+
if (touchIdentifier !== (window.navigator.msPointerEnabled ? 1 : ev.touches.item(0).identifier)) {
180+
181+
if (!quiet) console.debug("DOC multi touch skip");
182+
return;
183+
}
184+
185+
if (!quiet) console.debug("touchmove");
186+
187+
if (!ev.cancelable) {
188+
if (!quiet) console.debug("!CANCELABLE");
189+
return;
190+
}
191+
192+
if (!quiet) console.debug("touchStartX: " + touchStartX);
193+
if (!quiet) console.debug("touchStartY: " + touchStartY);
194+
195+
var touchStartX_ = window.navigator.msPointerEnabled ? ev.clientX : ev.touches.item(0).clientX;
196+
var touchStartY_ = window.navigator.msPointerEnabled ? ev.clientY : ev.touches.item(0).clientY;
197+
198+
if (!quiet) console.debug("touchStartX_: " + touchStartX_);
199+
if (!quiet) console.debug("touchStartY_: " + touchStartY_);
200+
201+
var touchDeltaX = touchStartX - touchStartX_;
202+
var touchDeltaY = touchStartY - touchStartY_;
203+
204+
if (!quiet) console.debug("touchDeltaX: " + touchDeltaX);
205+
if (!quiet) console.debug("touchDeltaY: " + touchDeltaY);
206+
207+
if (Math.abs(touchDeltaX) <= 1 && Math.abs(touchDeltaY) <= 1) {
208+
if (!quiet) console.debug("touchDelta too small...");
209+
210+
//ev.stopPropagation();
211+
return;
212+
}
213+
214+
if (Math.abs(touchDeltaX) > Math.abs(touchDeltaY)) {
215+
lockDragX = true;
216+
lockDragY = false;
217+
} else {
218+
lockDragX = false;
219+
lockDragY = true;
220+
}
221+
222+
if (!quiet) console.debug("lockDragX: " + lockDragX);
223+
if (!quiet) console.debug("lockDragY: " + lockDragY);
224+
225+
touchStartX = touchStartX_;
226+
touchStartY = touchStartY_;
227+
228+
var target = ev.target;
229+
while (target) {
230+
231+
if (!quiet) console.debug("target: ");
232+
if (!quiet) console.debug(target);
233+
234+
if (typeof target.scrollTop === "undefined") {
235+
if (!quiet) console.debug("undefined target.scrollTop");
236+
237+
if (!isTopLevel) {
238+
if (!quiet) console.debug("!isTopLevel");
239+
//target.allowDefault = true;
240+
ev.stopPropagation();
241+
}
242+
243+
break;
244+
}
245+
246+
var $target = $(target);
247+
248+
var scrollTop = target.scrollTop;
249+
var scrollLeft = target.scrollLeft;
250+
251+
var scrollBottom = scrollTop + target.offsetHeight; //$target.height();
252+
var scrollRight = scrollLeft + target.offsetWidth; //$target.width();
253+
254+
var needsScroll =
255+
lockDragX && touchDeltaX < 0 && scrollLeft != 0 ||
256+
lockDragX && touchDeltaX > 0 && scrollRight != target.scrollWidth ||
257+
lockDragY && touchDeltaY < 0 && scrollTop != 0 ||
258+
lockDragY && touchDeltaY > 0 && scrollBottom != target.scrollHeight;
259+
260+
if (needsScroll) {
261+
if (!quiet) console.debug("needsScroll");
262+
263+
if (!quiet) console.debug("target: ");
264+
if (!quiet) console.debug(target);
265+
266+
if (!quiet) console.debug("scrollLeft: " + scrollLeft);
267+
if (!quiet) console.debug("scrollTop: " + scrollTop);
268+
if (!quiet) console.debug("scrollBottom: " + scrollBottom);
269+
if (!quiet) console.debug("scrollRight: " + scrollRight);
270+
if (!quiet) console.debug("target.scrollWidth: " + target.scrollWidth);
271+
if (!quiet) console.debug("target.scrollHeight: " + target.scrollHeight);
272+
273+
274+
//target.ownerDocument.allowDefault = true;
275+
ev.stopPropagation();
276+
return;
277+
}
278+
279+
target = target.parentNode;
280+
}
281+
});
282+
}
283+
284+
this.initialize = function() {
285+
286+
delete Hammer.defaults.cssProps.userSelect;
33287

34288
reader.on(ReadiumSDK.Events.CONTENT_DOCUMENT_LOADED, function(iframe,s) {
35-
//set hammer's document root
36-
Hammer.DOCUMENT = iframe.contents();
37-
//hammer's internal touch events need to be redefined? (doesn't work without)
38-
Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect);
39-
Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect);
40-
41-
//set up the hammer gesture events
42-
//swiping handlers
43-
var swipingOptions = {prevent_mouseevents: true};
44-
Hammer(Hammer.DOCUMENT,swipingOptions).on("swipeleft", function() {
45-
onSwipeLeft();
289+
290+
var iframeDocument = iframe[0].contentWindow.document;
291+
return;
292+
setupTouchDefaultActionSuppressor(iframeDocument, false);
293+
return;
294+
var iframeHtml = iframeDocument.documentElement;
295+
296+
var iframeHammer = new Hammer.Manager(iframeHtml, { touchAction: "auto" });
297+
298+
var swipe = new Hammer.Swipe({ enable: isGestureHandled, direction: Hammer.DIRECTION_HORIZONTAL });
299+
300+
iframeHammer.add([swipe]);
301+
302+
iframeHammer.on("swipeleft", function(ev) {
303+
if (!quiet) console.debug("HAMMER swipeleft");
304+
305+
if (isGestureHandled()) {
306+
ev.preventDefault();
307+
308+
onSwipeLeft();
309+
}
46310
});
47-
Hammer(Hammer.DOCUMENT,swipingOptions).on("swiperight", function() {
48-
onSwipeRight();
311+
312+
iframeHammer.on("swiperight", function(ev) {
313+
if (!quiet) console.debug("HAMMER swiperight");
314+
315+
if (isGestureHandled()) {
316+
ev.preventDefault();
317+
318+
onSwipeRight();
319+
}
49320
});
50-
51-
//remove stupid ipad safari elastic scrolling
52-
//TODO: test this with reader ScrollView and FixedView
53-
$(Hammer.DOCUMENT).on(
54-
'touchmove',
55-
function(e) {
56-
//hack: check if we are not dealing with a scrollview
57-
if(isGestureHandled()){
58-
e.preventDefault();
59-
}
60-
}
61-
);
62321
});
63322

64-
//remove stupid ipad safari elastic scrolling (improves UX for gestures)
65-
//TODO: test this with reader ScrollView and FixedView
66-
$(viewport).on(
67-
'touchmove',
68-
function(e) {
69-
if(isGestureHandled()) {
70-
e.preventDefault();
71-
}
72-
}
73-
);
74-
75-
//handlers on viewport
76-
$(viewport).hammer().on("swipeleft", function() {
77-
onSwipeLeft();
78-
});
79-
$(viewport).hammer().on("swiperight", function() {
80-
onSwipeRight();
81-
});
323+
setupTouchDefaultActionSuppressor(document, true);
82324
};
83-
84325
};
326+
85327
return gesturesHandler;
86328
});

0 commit comments

Comments
 (0)