Use modified dragscrollable plugin from http://github.com/raganwald/iGesture. Add...
[bookreader.git] / BookReader / dragscrollable.js
1 /*
2  * jQuery dragscrollable Plugin
3  * version: 1.0 (25-Jun-2009)
4  * Copyright (c) 2009 Miquel Herrera
5  *
6  * Portions Copyright (c) 2010 Reg Braithwaite
7  *          Copyright (c) 2010 Internet Archive / Michael Ang
8  *
9  * Dual licensed under the MIT and GPL licenses:
10  *   http://www.opensource.org/licenses/mit-license.php
11  *   http://www.gnu.org/licenses/gpl.html
12  *
13  */
14 ;(function($){ // secure $ jQuery alias
15
16 /**
17  * Adds the ability to manage elements scroll by dragging
18  * one or more of its descendant elements. Options parameter
19  * allow to specifically select which inner elements will
20  * respond to the drag events.
21  * 
22  * options properties:
23  * ------------------------------------------------------------------------             
24  *  dragSelector         | jquery selector to apply to each wrapped element 
25  *                       | to find which will be the dragging elements. 
26  *                       | Defaults to '>:first' which is the first child of 
27  *                       | scrollable element
28  * ------------------------------------------------------------------------             
29  *  acceptPropagatedEvent| Will the dragging element accept propagated 
30  *                           | events? default is yes, a propagated mouse event 
31  *                           | on a inner element will be accepted and processed.
32  *                           | If set to false, only events originated on the
33  *                           | draggable elements will be processed.
34  * ------------------------------------------------------------------------
35  *  preventDefault       | Prevents the event to propagate further effectivey
36  *                       | dissabling other default actions. Defaults to true
37  * ------------------------------------------------------------------------
38  *  
39  *  usage examples:
40  *
41  *  To add the scroll by drag to the element id=viewport when dragging its 
42  *  first child accepting any propagated events
43  *      $('#viewport').dragscrollable(); 
44  *
45  *  To add the scroll by drag ability to any element div of class viewport
46  *  when dragging its first descendant of class dragMe responding only to
47  *  evcents originated on the '.dragMe' elements.
48  *      $('div.viewport').dragscrollable({dragSelector:'.dragMe:first',
49  *                                                                        acceptPropagatedEvent: false});
50  *
51  *  Notice that some 'viewports' could be nested within others but events
52  *  would not interfere as acceptPropagatedEvent is set to false.
53  *              
54  */
55
56 var append_namespace = function (string_of_events, ns) {
57         return string_of_events
58                 .split(' ')
59                         .map(function (name) { return name + ns; })
60                                 .join(' ');
61 };
62
63 var left_top = function(event) {
64         
65         var x;
66         var y;
67         if (typeof(event.clientX) != 'undefined') {
68                 x = event.clientX;
69                 y = event.clientY;
70         }
71         else if (typeof(event.screenX) != 'undefined') {
72                 x = event.screenX;
73                 y = event.screenY;
74         }
75         else if (typeof(event.targetTouches) != 'undefined') {
76                 x = event.targetTouches[0].pageX;
77                 y = event.targetTouches[0].pageY;
78         }
79         else if (typeof(event.originalEvent) == 'undefined') {
80                 var str = '';
81                 for (i in event) {
82                         str += ', ' + i + ': ' + event[i];
83                 }
84                 console.error("don't understand x and y for " + event.type + ' event: ' + str);
85         }
86         else if (typeof(event.originalEvent.clientX) != 'undefined') {
87                 x = event.originalEvent.clientX;
88                 y = event.originalEvent.clientY;
89         }
90         else if (typeof(event.originalEvent.screenX) != 'undefined') {
91                 x = event.originalEvent.screenX;
92                 y = event.originalEvent.screenY;
93         }
94         else if (typeof(event.originalEvent.targetTouches) != 'undefined') {
95                 x = event.originalEvent.targetTouches[0].pageX;
96                 y = event.originalEvent.targetTouches[0].pageY;
97         }
98         
99         return {left: x, top:y};
100 };
101
102 $.fn.dragscrollable = function( options ) {
103         
104         var handling_element = $(this);
105    
106         var settings = $.extend(
107                 {   
108                         dragSelector:'>:first',
109                         acceptPropagatedEvent: true,
110             preventDefault: true,
111                         dragstart: 'mousedown touchstart',
112                         dragcontinue: 'mousemove touchmove',
113                         dragend: 'mouseup mouseleave touchend',
114                         dragMinDistance: 5,
115                         namespace: '.ds'
116                 },options || {});
117         
118         settings.dragstart = append_namespace(settings.dragstart, settings.namespace);
119         settings.dragcontinue = append_namespace(settings.dragcontinue, settings.namespace);
120         settings.dragend = append_namespace(settings.dragend, settings.namespace);
121
122         var dragscroll= {
123                 dragStartHandler : function(event) {
124                         
125                         // mousedown, left click, check propagation
126                         if (event.which > 1 ||
127                                 (!event.data.acceptPropagatedEvent && event.target != this)){ 
128                                 return false; 
129                         }
130                         
131                         event.data.firstCoord = left_top(event);
132                         // Initial coordinates will be the last when dragging
133                         event.data.lastCoord = event.data.firstCoord;
134                         
135                         handling_element
136                                 .bind(settings.dragcontinue, event.data, dragscroll.dragContinueHandler)
137                                 .bind(settings.dragend, event.data, dragscroll.dragEndHandler);
138                 
139                         if (event.data.preventDefault) {
140                 event.preventDefault();
141                 return false;
142             }
143                 },
144                 dragContinueHandler : function(event) { // User is dragging
145                         
146                         var lt = left_top(event);
147                         
148                         // How much did the mouse move?
149                         var delta = {left: (lt.left - event.data.lastCoord.left),
150                                                  top: (lt.top - event.data.lastCoord.top)};
151                         
152                         // Set the scroll position relative to what ever the scroll is now
153                         event.data.scrollable.scrollLeft(
154                                                         event.data.scrollable.scrollLeft() - delta.left);
155                         event.data.scrollable.scrollTop(
156                                                         event.data.scrollable.scrollTop() - delta.top);
157                         
158                         // Save where the cursor is
159                         event.data.lastCoord = lt;
160                         
161                         if (event.data.preventDefault) {
162                 event.preventDefault();
163                 return false;
164             }
165
166                 },
167                 dragEndHandler : function(event) { // Stop scrolling
168                         handling_element
169                                 .unbind(settings.dragcontinue)
170                                 .unbind(settings.dragend);
171                                 
172                         // How much did the mouse move total?
173                         var delta = {left: Math.abs(event.data.lastCoord.left - event.data.firstCoord.left),
174                                                  top: Math.abs(event.data.lastCoord.top - event.data.firstCoord.top)};
175                         var distance = Math.max(delta.left, delta.top);
176                         
177                         // Trigger 'tap' if did not meet drag distance
178                         // $$$ does not differentiate single vs multi-touch
179                         if (distance < settings.dragMinDistance) {
180                             $(event.originalEvent.target).trigger('tap');
181                         }
182                         
183                         // Allow event to propage if min distance was not achieved
184                         if (event.data.preventDefault && distance > settings.dragMinDistance) {
185                 event.preventDefault();
186                 return false;
187             }
188                 }
189         }
190         
191         // set up the initial events
192         return this.each(function() {
193                 // closure object data for each scrollable element
194                 var data = {scrollable : $(this),
195                                         acceptPropagatedEvent : settings.acceptPropagatedEvent,
196                     preventDefault : settings.preventDefault }
197                 // Set mouse initiating event on the desired descendant
198                 $(this).find(settings.dragSelector).
199                                                 bind(settings.dragstart, data, dragscroll.dragStartHandler);
200         });
201 }; //end plugin dragscrollable
202
203 $.fn.removedragscrollable = function (namespace) {
204         if (typeof(namespace) == 'undefined')
205                 namespace = '.ds';
206         return this.each(function() {
207                 var x = $(document).find('*').andSelf().unbind(namespace);
208         });
209 };
210
211 })( jQuery ); // confine scope