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
}
$("#BookReader").empty();
+
this.initToolbar(this.mode, this.ui); // Build inside of toolbar div
$("#BookReader").append("<div id='BRcontainer'></div>");
$("#BRcontainer").append("<div id='BRpageview'></div>");
$("#BRcontainer").bind('scroll', this, function(e) {
e.data.loadLeafs();
});
-
+
this.setupKeyListeners();
this.startLocationPolling();
// $$$ 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;
}
-// 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);
});
}
$(div).css('height', height+'px');
//$(div).text('loading...');
- this.setDragHandler(div);
-
$('#BRpageview').append(div);
var img = document.createElement("img");
// 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();
// var startLeaf = this.displayedIndices[0];
var startLeaf = this.currentIndex();
-
+
$('#BRcontainer').empty();
$('#BRcontainer').css({
overflowY: 'scroll',
overflowX: 'auto'
});
-
+
$("#BRcontainer").append("<div id='BRpageview'></div>");
+
+ // 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 = [];
});
$("#BRcontainer").append("<div id='BRpageview'></div>");
+
+ $('#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)
// Add the two page view
// $$$ Can we get everything set up and then append?
$('#BRcontainer').append('<div id="BRtwopageview"></div>');
+
+ // Attaches to first child, so must come after we add the page view
+ $('#BRcontainer').dragscrollable();
+ this.bindGestures($('#BRcontainer'));
// $$$ calculate first then set
$('#BRtwopageview').css( {
// 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();
}
);
}
this.updateToolbarZoom(this.reduce); // Pretty format
- if (ui == "embed") {
+ if (ui == "embed" || ui == "touch") {
$("#BookReader a.logo").attr("target","_blank");
}
--- /dev/null
+/*
+ * 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