From: Michael Ang Date: Fri, 14 May 2010 23:16:57 +0000 (+0000) Subject: Use modified dragscrollable plugin from http://github.com/raganwald/iGesture. Add... X-Git-Url: http://git.rot13.org/?p=bookreader.git;a=commitdiff_plain;h=067dbeedbf050f83f8473fca9f09b88c1551a086 Use modified dragscrollable plugin from github.com/raganwald/iGesture. Add support for pinch to zoom in/out. --- diff --git a/BookReader/BookReader.js b/BookReader/BookReader.js index 6b87964..1e2eabd 100644 --- a/BookReader/BookReader.js +++ b/BookReader/BookReader.js @@ -83,6 +83,7 @@ function BookReader() { this.constModeThumb = 3; // Zoom levels + // $$$ provide finer grained zooming this.reductionFactors = [0.5, 1, 2, 4, 8, 16]; // Object to hold parameters related to 2up mode @@ -140,6 +141,7 @@ BookReader.prototype.init = function() { } $("#BookReader").empty(); + this.initToolbar(this.mode, this.ui); // Build inside of toolbar div $("#BookReader").append("
"); $("#BRcontainer").append("
"); @@ -147,7 +149,7 @@ BookReader.prototype.init = function() { $("#BRcontainer").bind('scroll', this, function(e) { e.data.loadLeafs(); }); - + this.setupKeyListeners(); this.startLocationPolling(); @@ -196,8 +198,8 @@ BookReader.prototype.init = function() { // $$$ refactor this so it's enough to set the first index and call preparePageView // (get rid of mode-specific logic at this point) if (1 == this.mode) { - this.resizePageView(); this.firstIndex = startIndex; + this.prepareOnePageView(); this.jumpToIndex(startIndex); } else if (3 == this.mode) { this.firstIndex = startIndex; @@ -290,162 +292,27 @@ BookReader.prototype.drawLeafs = function() { } -// setDragHandler() +// bindGestures(jElement) //______________________________________________________________________________ -BookReader.prototype.setDragHandler = function(div) { - div.dragging = false; +BookReader.prototype.bindGestures = function(jElement) { - $(div).unbind('mousedown').bind('mousedown', function(e) { + jElement.unbind('gesturechange').bind('gesturechange', function(e) { e.preventDefault(); - - //console.log('mousedown at ' + e.pageY); - - this.dragging = true; - this.prevMouseX = e.pageX; - this.prevMouseY = e.pageY; - - var startX = e.pageX; - var startY = e.pageY; - var startTop = $('#BRcontainer').attr('scrollTop'); - var startLeft = $('#BRcontainer').attr('scrollLeft'); - - }); - - $(div).unbind('mousemove').bind('mousemove', function(ee) { - ee.preventDefault(); - - // console.log('mousemove ' + ee.pageX + ',' + ee.pageY); - - var offsetX = ee.pageX - this.prevMouseX; - var offsetY = ee.pageY - this.prevMouseY; - - if (this.dragging) { - $('#BRcontainer').attr('scrollTop', $('#BRcontainer').attr('scrollTop') - offsetY); - $('#BRcontainer').attr('scrollLeft', $('#BRcontainer').attr('scrollLeft') - offsetX); + if (e.originalEvent.scale > 1.5) { + br.zoom(1); + } else if (e.originalEvent.scale < 0.6) { + br.zoom(-1); } - - this.prevMouseX = ee.pageX; - this.prevMouseY = ee.pageY; - - }); - - $(div).unbind('mouseup').bind('mouseup', function(ee) { - ee.preventDefault(); - //console.log('mouseup'); - - this.dragging = false; - }); - - $(div).unbind('mouseleave').bind('mouseleave', function(e) { - e.preventDefault(); - //console.log('mouseleave'); - - this.dragging = false; }); - - $(div).unbind('mouseenter').bind('mouseenter', function(e) { - e.preventDefault(); - //console.log('mouseenter'); - this.dragging = false; - }); -} - -// setDragHandler2UP() -//______________________________________________________________________________ -BookReader.prototype.setDragHandler2UP = function(div) { - div.dragging = false; - - $(div).unbind('mousedown').bind('mousedown', function(e) { - e.preventDefault(); - - //console.log('mousedown at ' + e.pageY); - - this.dragStart = {x: e.pageX, y: e.pageY }; - this.mouseDown = true; - this.dragging = false; // wait until drag distance - this.prevMouseX = e.pageX; - this.prevMouseY = e.pageY; - - var startX = e.pageX; - var startY = e.pageY; - var startTop = $('#BRcontainer').attr('scrollTop'); - var startLeft = $('#BRcontainer').attr('scrollLeft'); - - }); - - $(div).unbind('mousemove').bind('mousemove', function(ee) { - ee.preventDefault(); - - // console.log('mousemove ' + ee.pageX + ',' + ee.pageY); - - var offsetX = ee.pageX - this.prevMouseX; - var offsetY = ee.pageY - this.prevMouseY; - - var minDragDistance = 5; // $$$ constant - - var distance = Math.max(Math.abs(offsetX), Math.abs(offsetY)); - - if (this.mouseDown && (distance > minDragDistance)) { - //console.log('drag start!'); - - this.dragging = true; - } - - if (this.dragging) { - $('#BRcontainer').attr('scrollTop', $('#BRcontainer').attr('scrollTop') - offsetY); - $('#BRcontainer').attr('scrollLeft', $('#BRcontainer').attr('scrollLeft') - offsetX); - this.prevMouseX = ee.pageX; - this.prevMouseY = ee.pageY; - } - - - }); - - /* - $(div).unbind('mouseup').bind('mouseup', function(ee) { - ee.preventDefault(); - //console.log('mouseup'); - - this.dragging = false; - this.mouseDown = false; - }); - */ - - - $(div).unbind('mouseleave').bind('mouseleave', function(e) { - e.preventDefault(); - //console.log('mouseleave'); - - this.dragging = false; - this.mouseDown = false; - }); - - $(div).unbind('mouseenter').bind('mouseenter', function(e) { - e.preventDefault(); - //console.log('mouseenter'); - - this.dragging = false; - this.mouseDown = false; - }); } BookReader.prototype.setClickHandler2UP = function( element, data, handler) { //console.log('setting handler'); //console.log(element.tagName); - $(element).unbind('click').bind('click', data, function(e) { - e.preventDefault(); - - //console.log('click!'); - - if (this.mouseDown && (!this.dragging)) { - //console.log('click not dragging!'); - handler(e); - } - - this.dragging = false; - this.mouseDown = false; + $(element).unbind('tap').bind('tap', data, function(e) { + handler(e); }); } @@ -530,8 +397,6 @@ BookReader.prototype.drawLeafsOnePage = function() { $(div).css('height', height+'px'); //$(div).text('loading...'); - this.setDragHandler(div); - $('#BRpageview').append(div); var img = document.createElement("img"); @@ -723,7 +588,7 @@ BookReader.prototype.drawLeafsThumbnail = function( seekIndex ) { // link to page in single page mode link = document.createElement("a"); $(link).data('leaf', leaf); - $(link).bind('click', function(event) { + $(link).bind('tap', function(event) { self.firstIndex = $(this).data('leaf'); self.switchMode(self.constMode1up); event.preventDefault(); @@ -1392,19 +1257,24 @@ BookReader.prototype.prepareOnePageView = function() { // var startLeaf = this.displayedIndices[0]; var startLeaf = this.currentIndex(); - + $('#BRcontainer').empty(); $('#BRcontainer').css({ overflowY: 'scroll', overflowX: 'auto' }); - + $("#BRcontainer").append("
"); + + // Attaches to first child - child must be present + $('#BRcontainer').dragscrollable(); + this.bindGestures($('#BRcontainer')); + // $$$ keep select enabled for now since disabling it breaks keyboard // nav in FF 3.6 (https://bugs.edge.launchpad.net/bookreader/+bug/544666) // BookReader.util.disableSelect($('#BRpageview')); - this.resizePageView(); + this.resizePageView(); this.jumpToIndex(startLeaf); this.displayedIndices = []; @@ -1423,6 +1293,9 @@ BookReader.prototype.prepareThumbnailView = function() { }); $("#BRcontainer").append("
"); + + $('#BRcontainer').dragscrollable(); + this.bindGestures($('#BRcontainer')); // $$$ keep select enabled for now since disabling it breaks keyboard // nav in FF 3.6 (https://bugs.edge.launchpad.net/bookreader/+bug/544666) @@ -1488,6 +1361,10 @@ BookReader.prototype.prepareTwoPageView = function(centerPercentageX, centerPerc // Add the two page view // $$$ Can we get everything set up and then append? $('#BRcontainer').append('
'); + + // Attaches to first child, so must come after we add the page view + $('#BRcontainer').dragscrollable(); + this.bindGestures($('#BRcontainer')); // $$$ calculate first then set $('#BRtwopageview').css( { @@ -2323,32 +2200,19 @@ BookReader.prototype.flipRightToLeft = function(newIndexL, newIndexR) { // setMouseHandlers2UP //______________________________________________________________________________ BookReader.prototype.setMouseHandlers2UP = function() { - /* - $(this.prefetchedImgs[this.twoPage.currentIndexL]).bind('dblclick', function() { - //self.prevPage(); - self.autoStop(); - self.left(); - }); - $(this.prefetchedImgs[this.twoPage.currentIndexR]).bind('dblclick', function() { - //self.nextPage();' - self.autoStop(); - self.right(); - }); - */ - - this.setDragHandler2UP( this.prefetchedImgs[this.twoPage.currentIndexL] ); this.setClickHandler2UP( this.prefetchedImgs[this.twoPage.currentIndexL], { self: this }, function(e) { e.data.self.left(); + e.preventDefault(); } ); - this.setDragHandler2UP( this.prefetchedImgs[this.twoPage.currentIndexR] ); this.setClickHandler2UP( this.prefetchedImgs[this.twoPage.currentIndexR], { self: this }, function(e) { e.data.self.right(); + e.preventDefault(); } ); } @@ -3257,7 +3121,7 @@ BookReader.prototype.initToolbar = function(mode, ui) { this.updateToolbarZoom(this.reduce); // Pretty format - if (ui == "embed") { + if (ui == "embed" || ui == "touch") { $("#BookReader a.logo").attr("target","_blank"); } diff --git a/BookReader/dragscrollable.js b/BookReader/dragscrollable.js new file mode 100644 index 0000000..24b7977 --- /dev/null +++ b/BookReader/dragscrollable.js @@ -0,0 +1,211 @@ +/* + * jQuery dragscrollable Plugin + * version: 1.0 (25-Jun-2009) + * Copyright (c) 2009 Miquel Herrera + * + * Portions Copyright (c) 2010 Reg Braithwaite + * Copyright (c) 2010 Internet Archive / Michael Ang + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ +;(function($){ // secure $ jQuery alias + +/** + * Adds the ability to manage elements scroll by dragging + * one or more of its descendant elements. Options parameter + * allow to specifically select which inner elements will + * respond to the drag events. + * + * options properties: + * ------------------------------------------------------------------------ + * dragSelector | jquery selector to apply to each wrapped element + * | to find which will be the dragging elements. + * | Defaults to '>:first' which is the first child of + * | scrollable element + * ------------------------------------------------------------------------ + * acceptPropagatedEvent| Will the dragging element accept propagated + * | events? default is yes, a propagated mouse event + * | on a inner element will be accepted and processed. + * | If set to false, only events originated on the + * | draggable elements will be processed. + * ------------------------------------------------------------------------ + * preventDefault | Prevents the event to propagate further effectivey + * | dissabling other default actions. Defaults to true + * ------------------------------------------------------------------------ + * + * usage examples: + * + * To add the scroll by drag to the element id=viewport when dragging its + * first child accepting any propagated events + * $('#viewport').dragscrollable(); + * + * To add the scroll by drag ability to any element div of class viewport + * when dragging its first descendant of class dragMe responding only to + * evcents originated on the '.dragMe' elements. + * $('div.viewport').dragscrollable({dragSelector:'.dragMe:first', + * acceptPropagatedEvent: false}); + * + * Notice that some 'viewports' could be nested within others but events + * would not interfere as acceptPropagatedEvent is set to false. + * + */ + +var append_namespace = function (string_of_events, ns) { + return string_of_events + .split(' ') + .map(function (name) { return name + ns; }) + .join(' '); +}; + +var left_top = function(event) { + + var x; + var y; + if (typeof(event.clientX) != 'undefined') { + x = event.clientX; + y = event.clientY; + } + else if (typeof(event.screenX) != 'undefined') { + x = event.screenX; + y = event.screenY; + } + else if (typeof(event.targetTouches) != 'undefined') { + x = event.targetTouches[0].pageX; + y = event.targetTouches[0].pageY; + } + else if (typeof(event.originalEvent) == 'undefined') { + var str = ''; + for (i in event) { + str += ', ' + i + ': ' + event[i]; + } + console.error("don't understand x and y for " + event.type + ' event: ' + str); + } + else if (typeof(event.originalEvent.clientX) != 'undefined') { + x = event.originalEvent.clientX; + y = event.originalEvent.clientY; + } + else if (typeof(event.originalEvent.screenX) != 'undefined') { + x = event.originalEvent.screenX; + y = event.originalEvent.screenY; + } + else if (typeof(event.originalEvent.targetTouches) != 'undefined') { + x = event.originalEvent.targetTouches[0].pageX; + y = event.originalEvent.targetTouches[0].pageY; + } + + return {left: x, top:y}; +}; + +$.fn.dragscrollable = function( options ) { + + var handling_element = $(this); + + var settings = $.extend( + { + dragSelector:'>:first', + acceptPropagatedEvent: true, + preventDefault: true, + dragstart: 'mousedown touchstart', + dragcontinue: 'mousemove touchmove', + dragend: 'mouseup mouseleave touchend', + dragMinDistance: 5, + namespace: '.ds' + },options || {}); + + settings.dragstart = append_namespace(settings.dragstart, settings.namespace); + settings.dragcontinue = append_namespace(settings.dragcontinue, settings.namespace); + settings.dragend = append_namespace(settings.dragend, settings.namespace); + + var dragscroll= { + dragStartHandler : function(event) { + + // mousedown, left click, check propagation + if (event.which > 1 || + (!event.data.acceptPropagatedEvent && event.target != this)){ + return false; + } + + event.data.firstCoord = left_top(event); + // Initial coordinates will be the last when dragging + event.data.lastCoord = event.data.firstCoord; + + handling_element + .bind(settings.dragcontinue, event.data, dragscroll.dragContinueHandler) + .bind(settings.dragend, event.data, dragscroll.dragEndHandler); + + if (event.data.preventDefault) { + event.preventDefault(); + return false; + } + }, + dragContinueHandler : function(event) { // User is dragging + + var lt = left_top(event); + + // How much did the mouse move? + var delta = {left: (lt.left - event.data.lastCoord.left), + top: (lt.top - event.data.lastCoord.top)}; + + // Set the scroll position relative to what ever the scroll is now + event.data.scrollable.scrollLeft( + event.data.scrollable.scrollLeft() - delta.left); + event.data.scrollable.scrollTop( + event.data.scrollable.scrollTop() - delta.top); + + // Save where the cursor is + event.data.lastCoord = lt; + + if (event.data.preventDefault) { + event.preventDefault(); + return false; + } + + }, + dragEndHandler : function(event) { // Stop scrolling + handling_element + .unbind(settings.dragcontinue) + .unbind(settings.dragend); + + // How much did the mouse move total? + var delta = {left: Math.abs(event.data.lastCoord.left - event.data.firstCoord.left), + top: Math.abs(event.data.lastCoord.top - event.data.firstCoord.top)}; + var distance = Math.max(delta.left, delta.top); + + // Trigger 'tap' if did not meet drag distance + // $$$ does not differentiate single vs multi-touch + if (distance < settings.dragMinDistance) { + $(event.originalEvent.target).trigger('tap'); + } + + // Allow event to propage if min distance was not achieved + if (event.data.preventDefault && distance > settings.dragMinDistance) { + event.preventDefault(); + return false; + } + } + } + + // set up the initial events + return this.each(function() { + // closure object data for each scrollable element + var data = {scrollable : $(this), + acceptPropagatedEvent : settings.acceptPropagatedEvent, + preventDefault : settings.preventDefault } + // Set mouse initiating event on the desired descendant + $(this).find(settings.dragSelector). + bind(settings.dragstart, data, dragscroll.dragStartHandler); + }); +}; //end plugin dragscrollable + +$.fn.removedragscrollable = function (namespace) { + if (typeof(namespace) == 'undefined') + namespace = '.ds'; + return this.each(function() { + var x = $(document).find('*').andSelf().unbind(namespace); + }); +}; + +})( jQuery ); // confine scope diff --git a/BookReader/touch/BookReaderTouch.css b/BookReader/touch/BookReaderTouch.css index fb1e9a9..8edcec4 100644 --- a/BookReader/touch/BookReaderTouch.css +++ b/BookReader/touch/BookReaderTouch.css @@ -54,4 +54,5 @@ .BRicon.play { background: url(images/control_play_icon.png) no-repeat; } .BRicon.pause { background: url(images/control_pause_icon.png) no-repeat; } -.BRicon.rollover:hover { background-position: -26px 0; } +/* Disable hover */ +.BRicon.rollover:hover { background-position: 0 0; } diff --git a/BookReaderIA/inc/BookReader.inc b/BookReaderIA/inc/BookReader.inc index fa8921e..936cf69 100644 --- a/BookReaderIA/inc/BookReader.inc +++ b/BookReaderIA/inc/BookReader.inc @@ -112,6 +112,7 @@ class BookReader +