2013-02-12 01:28:52 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
|
|
|
|
* XXX add copyright and licence info...
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
2013-02-12 04:14:48 +04:00
|
|
|
var PAGES_IN_RIBBON = 4
|
|
|
|
|
|
2013-02-12 02:23:29 +04:00
|
|
|
|
|
|
|
|
|
2013-02-12 01:28:52 +04:00
|
|
|
/********************************************************** layout ***/
|
|
|
|
|
|
|
|
|
|
var togglePageFitMode = createCSSClassToggler(
|
2013-02-12 04:14:48 +04:00
|
|
|
'.viewer',
|
|
|
|
|
'.page-fit-to-viewer',
|
|
|
|
|
function(action){
|
|
|
|
|
if(action == 'on'){
|
|
|
|
|
console.log('fitting pages to view...')
|
|
|
|
|
var n = getPageNumber()
|
|
|
|
|
var scale = getMagazineScale()
|
|
|
|
|
$('.page:not(.no-resize)').width($('.viewer').width()/scale)
|
|
|
|
|
} else {
|
|
|
|
|
console.log('restoring page sizes...')
|
|
|
|
|
var n = getPageNumber()
|
|
|
|
|
$('.page:not(.no-resize)').width('')
|
|
|
|
|
}
|
2013-02-12 01:28:52 +04:00
|
|
|
setCurrentPage(n)
|
2013-02-12 04:14:48 +04:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var togglePageView = createCSSClassToggler(
|
|
|
|
|
'.viewer',
|
|
|
|
|
'.full-page-view-mode',
|
|
|
|
|
// XXX make this support transitions...
|
|
|
|
|
function(action){
|
|
|
|
|
var view = $('.viewer')
|
|
|
|
|
var page = $('.page')
|
|
|
|
|
|
|
|
|
|
if(action == 'on'){
|
|
|
|
|
var W = view.width()
|
|
|
|
|
var H = view.height()
|
|
|
|
|
var w = page.width()
|
|
|
|
|
var h = page.height()
|
|
|
|
|
|
|
|
|
|
// XXX this is not correct...
|
|
|
|
|
// ...need to fit one rectangel (page) into another (viewer)
|
|
|
|
|
if(W >= H){
|
|
|
|
|
// fit to width...
|
|
|
|
|
var scale = W/w
|
|
|
|
|
} else {
|
|
|
|
|
// fit to height...
|
|
|
|
|
var scale = H/h
|
|
|
|
|
}
|
|
|
|
|
setMagazineScale(scale)
|
|
|
|
|
unanimated($('.magazine, .viewer'), togglePageFitMode)('on')
|
|
|
|
|
} else {
|
|
|
|
|
unanimated($('.magazine, .viewer'), togglePageFitMode)('off')
|
|
|
|
|
|
|
|
|
|
var W = view.width()
|
|
|
|
|
var H = view.height()
|
|
|
|
|
var w = page.width()
|
|
|
|
|
var h = page.height()
|
|
|
|
|
|
|
|
|
|
scale = W/(w*PAGES_IN_RIBBON)
|
|
|
|
|
setMagazineScale(scale)
|
|
|
|
|
}
|
|
|
|
|
// NOTE: can't disable transitions on this one because ScrollTo
|
|
|
|
|
// uses jQuery animation...
|
|
|
|
|
setCurrentPage()
|
|
|
|
|
})
|
2013-02-12 01:28:52 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-02-19 19:34:03 +04:00
|
|
|
/************************************************** event handlers ***/
|
|
|
|
|
|
2013-02-19 20:08:05 +04:00
|
|
|
// XXX make this more universal...
|
2013-02-19 20:38:09 +04:00
|
|
|
// - h/v scroll
|
|
|
|
|
// - general configuration
|
|
|
|
|
// - optional events...
|
2013-02-19 20:08:05 +04:00
|
|
|
// XXX should we use a callback or an event???
|
2013-02-19 20:48:39 +04:00
|
|
|
// XXX make this get the scrolled item automatically...
|
|
|
|
|
// ...now $('.magazine') is hardcoded...
|
2013-02-19 19:34:03 +04:00
|
|
|
function makeScrollHandler(root, callback){
|
|
|
|
|
|
|
|
|
|
// local data...
|
|
|
|
|
var scrolling = false
|
|
|
|
|
var touch = false
|
|
|
|
|
var touches = 0
|
|
|
|
|
var start
|
|
|
|
|
var prev_x
|
2013-02-19 20:38:09 +04:00
|
|
|
var prev_y
|
2013-02-19 19:34:03 +04:00
|
|
|
var prev_t
|
2013-02-19 20:38:09 +04:00
|
|
|
var bounds
|
2013-02-19 19:34:03 +04:00
|
|
|
var shift
|
|
|
|
|
var scale
|
|
|
|
|
var x
|
2013-02-19 20:38:09 +04:00
|
|
|
var y
|
2013-02-19 19:34:03 +04:00
|
|
|
var t
|
|
|
|
|
var dx
|
|
|
|
|
var dt
|
|
|
|
|
|
2013-02-19 20:38:09 +04:00
|
|
|
// XXX at this point this is not used...
|
|
|
|
|
var config = {
|
|
|
|
|
hScroll: true,
|
|
|
|
|
vScroll: false,
|
|
|
|
|
|
|
|
|
|
enableEvents: false,
|
|
|
|
|
autoCancelEvents: false,
|
|
|
|
|
eventBounds: 5,
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-19 19:34:03 +04:00
|
|
|
function startMoveHandler(evt, callback){
|
|
|
|
|
prev_t = event.timeStamp || Date.now();
|
2013-02-19 20:38:09 +04:00
|
|
|
if(config.autoCancelEvents){
|
|
|
|
|
bounds = {
|
|
|
|
|
left: config.eventBounds,
|
|
|
|
|
right: root.width() - config.eventBounds,
|
|
|
|
|
top: config.eventBounds,
|
|
|
|
|
bottom: root.height() - config.eventBounds
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-02-19 19:34:03 +04:00
|
|
|
setTransitionDuration($('.magazine'), 0)
|
|
|
|
|
if(event.touches != null){
|
|
|
|
|
touch = true
|
|
|
|
|
}
|
|
|
|
|
scrolling = true
|
|
|
|
|
scroller.state = 'scrolling'
|
|
|
|
|
//root.trigger('userScrollStart')
|
|
|
|
|
//togglePageDragging('on')
|
|
|
|
|
shift = getMagazineShift()
|
|
|
|
|
scale = getMagazineScale()
|
|
|
|
|
// get the user coords...
|
|
|
|
|
prev_x = touch ? event.touches[0].pageX : evt.clientX
|
|
|
|
|
start = prev_x
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
// XXX add limits to this...
|
2013-02-19 20:08:05 +04:00
|
|
|
// XXX slow down drag when at limit...
|
2013-02-19 19:34:03 +04:00
|
|
|
// XXX try and make this adaptive to stay ahead of the lags...
|
|
|
|
|
function moveHandler(evt){
|
|
|
|
|
evt.preventDefault()
|
|
|
|
|
t = event.timeStamp || Date.now();
|
|
|
|
|
// get the user coords...
|
|
|
|
|
x = touch ? event.touches[0].pageX : evt.clientX
|
|
|
|
|
touches = touch ? event.touches.length : 0
|
2013-02-19 20:38:09 +04:00
|
|
|
|
|
|
|
|
// XXX needs testing...
|
2013-02-19 20:48:39 +04:00
|
|
|
// check scroll bounds...
|
|
|
|
|
if(bounds != null){
|
2013-02-19 20:38:09 +04:00
|
|
|
if(config.hScroll && (x <= bounds.left || x >= bounds.right)
|
|
|
|
|
|| config.vScroll && (y <= bounds.top || y >= bounds.bottom)){
|
|
|
|
|
// XXX cancel the touch event and trigger the end handler...
|
|
|
|
|
return endMoveHandler(evt)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do the actual scroll...
|
2013-02-19 19:34:03 +04:00
|
|
|
if(scrolling){
|
|
|
|
|
shift += x - prev_x
|
|
|
|
|
setElementTransform($('.magazine'), shift, scale)
|
|
|
|
|
|
2013-02-19 20:48:39 +04:00
|
|
|
// XXX these should be done every time the event is caught or
|
|
|
|
|
// just while scrolling?
|
|
|
|
|
dx = x - prev_x
|
|
|
|
|
dt = t - prev_t
|
|
|
|
|
prev_t = t
|
|
|
|
|
prev_x = x
|
|
|
|
|
|
|
|
|
|
//root.trigger('userScroll')
|
|
|
|
|
}
|
2013-02-19 19:34:03 +04:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
function endMoveHandler(evt){
|
|
|
|
|
// XXX get real transition duration...
|
|
|
|
|
setTransitionDuration($('.magazine'), 200)
|
|
|
|
|
x = touch ? event.changedTouches[0].pageX : evt.clientX
|
|
|
|
|
touch = false
|
|
|
|
|
scrolling = false
|
|
|
|
|
scroller.state = 'waiting'
|
|
|
|
|
touches = 0
|
2013-02-19 20:48:39 +04:00
|
|
|
bounds = null
|
2013-02-19 19:34:03 +04:00
|
|
|
//togglePageDragging('off')
|
|
|
|
|
// XXX add speed to this...
|
|
|
|
|
//root.trigger('userScrollEnd')
|
|
|
|
|
callback && callback(dx/dt, start - x)
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var scroller = {
|
|
|
|
|
start: function(){
|
|
|
|
|
this.state = 'waiting'
|
|
|
|
|
// XXX STUB: this makes starting the scroll a bit sluggish,
|
|
|
|
|
// find a faster way...
|
|
|
|
|
//togglePageDragging('on')
|
|
|
|
|
|
|
|
|
|
// NOTE: if we bind both touch and mouse events, on touch devices they
|
|
|
|
|
// might start interfering with each other...
|
|
|
|
|
if('ontouchmove' in window){
|
|
|
|
|
root
|
|
|
|
|
.on('touchstart', startMoveHandler)
|
|
|
|
|
.on('touchmove', moveHandler)
|
|
|
|
|
.on('touchend', endMoveHandler)
|
2013-02-19 20:38:09 +04:00
|
|
|
.on('touchcancel', endMoveHandler)
|
2013-02-19 19:34:03 +04:00
|
|
|
} else {
|
|
|
|
|
root
|
|
|
|
|
.on('mousedown', startMoveHandler)
|
|
|
|
|
.on('mousemove', moveHandler)
|
|
|
|
|
.on('mouseup', endMoveHandler)
|
|
|
|
|
}
|
|
|
|
|
return this
|
|
|
|
|
},
|
|
|
|
|
stop: function(){
|
|
|
|
|
this.state = 'stopped'
|
|
|
|
|
if('ontouchmove' in window){
|
|
|
|
|
root
|
|
|
|
|
.off('touchstart', startMoveHandler)
|
|
|
|
|
.off('touchmove', moveHandler)
|
|
|
|
|
.off('touchend', endMoveHandler)
|
|
|
|
|
} else {
|
|
|
|
|
root
|
|
|
|
|
.off('mousedown', startMoveHandler)
|
|
|
|
|
.off('mousemove', moveHandler)
|
|
|
|
|
.off('mouseup', endMoveHandler)
|
|
|
|
|
}
|
|
|
|
|
return this
|
|
|
|
|
},
|
2013-02-19 20:48:39 +04:00
|
|
|
// XXX check...
|
2013-02-19 20:08:05 +04:00
|
|
|
setCallback: function(func){
|
|
|
|
|
this.callback = func
|
|
|
|
|
},
|
2013-02-19 19:34:03 +04:00
|
|
|
// NOTE: this is updated live but not used by the system in any way...
|
|
|
|
|
state: 'stopped'
|
|
|
|
|
}
|
|
|
|
|
return scroller
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-02-12 01:28:52 +04:00
|
|
|
/********************************************************* helpers ***/
|
|
|
|
|
|
2013-02-19 20:08:05 +04:00
|
|
|
// XXX make this more acurate...
|
|
|
|
|
// ...should check mode or if we are in a ribbon...
|
2013-02-19 22:52:54 +04:00
|
|
|
var NAVIGATION_MODE_THRESHOLD = 0.7
|
2013-02-19 20:08:05 +04:00
|
|
|
function isNavigationViewRelative(){
|
2013-02-19 22:52:54 +04:00
|
|
|
return getMagazineScale() <= NAVIGATION_MODE_THRESHOLD
|
2013-02-19 20:08:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-02-19 19:34:03 +04:00
|
|
|
// XXX there is something here that depends on scale that is either not
|
|
|
|
|
// compensated, or is over compensated...
|
|
|
|
|
function getMagazineOffset(page, scale, align){
|
|
|
|
|
if(page == null){
|
|
|
|
|
page = $('.current.page')
|
|
|
|
|
}
|
|
|
|
|
if(scale == null){
|
|
|
|
|
scale = getMagazineScale()
|
|
|
|
|
}
|
|
|
|
|
if(align == null){
|
|
|
|
|
align = getPageAlign(page)
|
|
|
|
|
}
|
|
|
|
|
var mag = $('.magazine')
|
|
|
|
|
|
|
|
|
|
// calculate the align offset...
|
|
|
|
|
if(align == 'left'){
|
|
|
|
|
var offset = 0
|
|
|
|
|
|
|
|
|
|
} else if(align == 'right'){
|
|
|
|
|
var offset = $('.viewer').width() - page.width()*scale
|
|
|
|
|
|
|
|
|
|
// center (default)
|
|
|
|
|
} else {
|
|
|
|
|
var offset = $('.viewer').width()/2 - (page.width()/2)*scale
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var w = mag.outerWidth(true)
|
|
|
|
|
// XXX this depends on scale...
|
|
|
|
|
var pos = page.position().left//*scale
|
|
|
|
|
|
|
|
|
|
return -((w - w*scale)/2 + pos) + offset
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-02-19 05:35:42 +04:00
|
|
|
// XXX make this work for narrow and left/right alligned pages...
|
2013-02-12 01:28:52 +04:00
|
|
|
function getPageNumber(page){
|
2013-02-19 20:08:05 +04:00
|
|
|
// a page is given explicitly, get the next one...
|
2013-02-12 01:28:52 +04:00
|
|
|
if(page != null){
|
|
|
|
|
return $('.page').index($(page))
|
|
|
|
|
}
|
2013-02-12 18:50:40 +04:00
|
|
|
|
2013-02-19 20:08:05 +04:00
|
|
|
// get the next page relative to the current...
|
|
|
|
|
if(!isNavigationViewRelative()){
|
2013-02-12 02:23:29 +04:00
|
|
|
return $('.page').index($('.current.page'))
|
2013-02-12 18:50:40 +04:00
|
|
|
|
2013-02-19 20:08:05 +04:00
|
|
|
// get the closest page to view center...
|
|
|
|
|
// NOTE: this ignores page aligns and only gets the page who's center
|
|
|
|
|
// is closer to view's center
|
2013-02-12 02:23:29 +04:00
|
|
|
} else {
|
2013-02-19 20:08:05 +04:00
|
|
|
var scale = getMagazineScale()
|
2013-02-14 05:47:25 +04:00
|
|
|
var o = -$($('.magazine')[0]).offset().left - $('.viewer').offset().left
|
2013-02-12 02:23:29 +04:00
|
|
|
var W = $('.viewer').width()
|
|
|
|
|
var cur = -1
|
|
|
|
|
var res = $('.page').map(function(i, e){
|
|
|
|
|
e = $(e)
|
|
|
|
|
var l = e.position().left
|
|
|
|
|
var w = e.width()*scale
|
2013-02-14 05:47:25 +04:00
|
|
|
return Math.abs((l+(w/2)) - (o+(W/2)))
|
2013-02-19 19:34:03 +04:00
|
|
|
}).toArray()
|
|
|
|
|
cur = res.indexOf(Math.min.apply(Math, res))
|
2013-02-12 02:23:29 +04:00
|
|
|
return cur
|
|
|
|
|
}
|
2013-02-12 01:28:52 +04:00
|
|
|
}
|
|
|
|
|
|
2013-02-12 03:45:39 +04:00
|
|
|
|
2013-02-12 03:05:20 +04:00
|
|
|
function getMagazineScale(){
|
|
|
|
|
return getElementScale($('.magazine'))
|
|
|
|
|
}
|
|
|
|
|
function setMagazineScale(scale){
|
|
|
|
|
var mag = $('.magazine')
|
2013-02-19 19:34:03 +04:00
|
|
|
var cur = $('.current.page')
|
|
|
|
|
|
2013-02-19 20:08:05 +04:00
|
|
|
// center-align ribbon view pages...
|
2013-02-19 20:38:09 +04:00
|
|
|
var align = isNavigationViewRelative() ? 'center' : null
|
2013-02-19 20:08:05 +04:00
|
|
|
var left = getMagazineOffset(cur, scale, align)
|
2013-02-19 19:34:03 +04:00
|
|
|
|
|
|
|
|
setElementTransform(mag, left, scale)
|
2013-02-19 20:08:05 +04:00
|
|
|
|
|
|
|
|
return mag
|
2013-02-12 03:05:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-02-12 01:28:52 +04:00
|
|
|
/********************************************************* actions ***/
|
|
|
|
|
|
|
|
|
|
function setCurrentPage(n){
|
|
|
|
|
if(n == null){
|
|
|
|
|
n = getPageNumber()
|
|
|
|
|
}
|
2013-02-12 03:05:20 +04:00
|
|
|
var scale = getMagazineScale()
|
2013-02-12 01:28:52 +04:00
|
|
|
var l = $('.page').length
|
2013-02-19 20:48:39 +04:00
|
|
|
// normalize the number...
|
2013-02-12 01:28:52 +04:00
|
|
|
n = n < 0 ? l - n : n
|
|
|
|
|
n = n < -l ? 0 : n
|
|
|
|
|
n = n >= l ? l - 1 : n
|
2013-02-19 19:34:03 +04:00
|
|
|
|
2013-02-12 01:28:52 +04:00
|
|
|
$('.current.page').removeClass('current')
|
|
|
|
|
$($('.page')[n]).addClass('current')
|
2013-02-19 19:34:03 +04:00
|
|
|
|
2013-02-12 01:28:52 +04:00
|
|
|
var cur = $('.current.page')
|
2013-02-19 19:34:03 +04:00
|
|
|
|
2013-02-19 20:08:05 +04:00
|
|
|
// center-align pages in ribbon view...
|
2013-02-19 20:38:09 +04:00
|
|
|
var align = isNavigationViewRelative() ? 'center' : null
|
2013-02-19 20:08:05 +04:00
|
|
|
var left = getMagazineOffset(cur, null, align)
|
2013-02-19 19:34:03 +04:00
|
|
|
|
|
|
|
|
setElementTransform($('.magazine'), left, scale)
|
|
|
|
|
|
2013-02-13 01:05:26 +04:00
|
|
|
return cur
|
2013-02-12 01:28:52 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-02-19 05:35:42 +04:00
|
|
|
function nextPage(page){
|
|
|
|
|
setCurrentPage(getPageNumber(page)+1)
|
2013-02-12 01:28:52 +04:00
|
|
|
}
|
2013-02-19 05:35:42 +04:00
|
|
|
function prevPage(page){
|
|
|
|
|
var n = getPageNumber(page)-1
|
2013-02-12 01:28:52 +04:00
|
|
|
n = n < 0 ? 0 : n
|
|
|
|
|
setCurrentPage(n)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function firstPage(){
|
|
|
|
|
setCurrentPage(0)
|
|
|
|
|
}
|
|
|
|
|
function lastPage(){
|
|
|
|
|
setCurrentPage(-1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
// vim:set ts=4 sw=4 :
|