mirror of
				https://github.com/flynx/PortableMag.git
				synced 2025-10-31 03:50:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			312 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			312 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| /**********************************************************************
 | |
| *
 | |
| * XXX add copyright and licence info...
 | |
| *
 | |
| **********************************************************************/
 | |
| 
 | |
| var PAGES_IN_RIBBON = 4
 | |
| 
 | |
| var SNAP_TO_PAGES_IN_RIBBON = false
 | |
| var DEFAULT_TRANSITION_DURATION = 200
 | |
| var INNERTIA_SCALE = 0.25
 | |
| 
 | |
| 
 | |
| 
 | |
| /********************************************************** layout ***/
 | |
| 
 | |
| var togglePageFitMode = createCSSClassToggler(
 | |
| 		'.viewer', 
 | |
| 		'.page-fit-to-viewer', 
 | |
| 		function(action){
 | |
| 			if(action == 'on'){
 | |
| 				var n = getPageNumber()
 | |
| 				var scale = getMagazineScale()
 | |
| 				$('.page:not(.no-resize)').width($('.viewer').width()/scale)
 | |
| 			} else {
 | |
| 				var n = getPageNumber()
 | |
| 				$('.page:not(.no-resize)').width('')
 | |
| 			}
 | |
| 			setCurrentPage(n)
 | |
| 		})
 | |
| 
 | |
| 
 | |
| 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 scale = getPageTargetScale(1)
 | |
| 				setMagazineScale(scale)
 | |
| 				unanimated($('.magazine, .viewer'), togglePageFitMode)('on')
 | |
| 			} else {
 | |
| 				unanimated($('.magazine, .viewer'), togglePageFitMode)('off')
 | |
| 				var scale = getPageTargetScale(PAGES_IN_RIBBON)
 | |
| 				setMagazineScale(scale)
 | |
| 			}
 | |
| 			// NOTE: can't disable transitions on this one because ScrollTo
 | |
| 			// 		uses jQuery animation...
 | |
| 			setCurrentPage()
 | |
| 		})
 | |
| 
 | |
| 
 | |
| 
 | |
| /************************************************** event handlers ***/
 | |
| 
 | |
| function handleClick(evt, data){
 | |
| 	// get page target and select it if it's within a page...
 | |
| 	var target = $(data.orig_event.target)
 | |
| 	target = getPageNumber(
 | |
| 				target.hasClass('page') ? target 
 | |
| 					: target.parents('.page'))
 | |
| 	if(target != -1){
 | |
| 		var mag = $('.magazine')
 | |
| 
 | |
| 		togglePageView()
 | |
| 		setCurrentPage(target)
 | |
| 
 | |
| 		setTransitionDuration(mag, DEFAULT_TRANSITION_DURATION)
 | |
| 		setTransitionEasing(mag, 'ease')
 | |
| 	}
 | |
| }
 | |
| 
 | |
| function makeSwipeHandler(action){
 | |
| 	return function(evt, data){
 | |
| 		// ribbon mode...
 | |
| 		if(isNavigationViewRelative()){
 | |
| 			return handleScrollRelease(evt, data)
 | |
| 		}
 | |
| 		// full page view...
 | |
| 		var mag = $('.magazine')
 | |
| 		setTransitionDuration(mag, DEFAULT_TRANSITION_DURATION)
 | |
| 		setTransitionEasing(mag, 'ease-out')
 | |
| 
 | |
| 		action($('.current.page'))
 | |
| 	}
 | |
| }
 | |
| var handleSwipeLeft = makeSwipeHandler(prevPage)
 | |
| var handleSwipeRight = makeSwipeHandler(nextPage)
 | |
| 
 | |
| // do snap and innertia...
 | |
| // NOTE: this will also handle swipeUp/swopeDown as we do not 
 | |
| //		explicitly bind them...
 | |
| // XXX restore all the changed values...
 | |
| function handleScrollRelease(evt, data){
 | |
| 	// this makes things snap...
 | |
| 	if(SNAP_TO_PAGES_IN_RIBBON || !isNavigationViewRelative()){
 | |
| 		setCurrentPage()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	var speed = data.speed.x
 | |
| 	var pages = $('.page')
 | |
| 	var mag = $('.magazine')
 | |
| 	// innertial scroll...
 | |
| 	// XXX make this generic...
 | |
| 	var t = DEFAULT_TRANSITION_DURATION * (1+Math.abs(speed))
 | |
| 	// XXX this is only horisontal at this point...
 | |
| 	var at = getElementShift(mag).left
 | |
| 	var to = (at + (t*speed*INNERTIA_SCALE))
 | |
| 	var first = getMagazineOffset(pages.first(), null, 'center')
 | |
| 	var last = getMagazineOffset(pages.last(), null, 'center')
 | |
| 
 | |
| 	// filter out really small speeds...
 | |
| 	if(Math.abs(speed) > 0.5){
 | |
| 		// check bounds...
 | |
| 		// NOTE: need to cut the distance and time if we are going the 
 | |
| 		//		hit the bounds...
 | |
| 		if(to > first){
 | |
| 			// trim the time proportionally...
 | |
| 			var _t = t
 | |
| 			t = Math.abs(t * ((at-first)/(at-to)))
 | |
| 			to = first
 | |
| 			setTransitionEasing(mag, 'linear')
 | |
| 		} else if(to < last){
 | |
| 			// trim the time proportionally...
 | |
| 			var _t = t
 | |
| 			t = Math.abs(t * ((at-last)/(at-to)))
 | |
| 			to = last
 | |
| 			setTransitionEasing(mag, 'linear')
 | |
| 
 | |
| 		} else {
 | |
| 			setTransitionEasing(mag, 'ease-out')
 | |
| 		}
 | |
| 
 | |
| 		setTransitionDuration(mag, t)
 | |
| 		setElementTransform(mag, to)
 | |
| 
 | |
| 		// restore defaults...
 | |
| 		// XXX this is a bit dumb at this point...
 | |
| 		// XXX run this as a transition end handler...
 | |
| 		setTimeout(function(){
 | |
| 			setTransitionEasing(mag, 'ease-out')
 | |
| 			setTransitionDuration(mag, DEFAULT_TRANSITION_DURATION)
 | |
| 		}, t+10)
 | |
| 
 | |
| 	// check scroll bounds...
 | |
| 	// do not let the user scroll out of view...
 | |
| 	} else {
 | |
| 		if(at > first){
 | |
| 			setTransitionEasing(mag, 'ease-in')
 | |
| 			setTransitionDuration(mag, DEFAULT_TRANSITION_DURATION/2)
 | |
| 			setElementTransform(mag, first)
 | |
| 
 | |
| 		} else if(at < last){
 | |
| 			setTransitionEasing(mag, 'ease-in')
 | |
| 			setTransitionDuration(mag, DEFAULT_TRANSITION_DURATION/2)
 | |
| 			setElementTransform(mag, last)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /********************************************************* helpers ***/
 | |
| 
 | |
| // XXX make this more acurate...
 | |
| // 		...should check mode or if we are in a ribbon...
 | |
| var NAVIGATION_MODE_THRESHOLD = 0.7
 | |
| function isNavigationViewRelative(){
 | |
| 	return getMagazineScale() <= NAVIGATION_MODE_THRESHOLD
 | |
| }
 | |
| 
 | |
| 
 | |
| // 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
 | |
| 	}
 | |
| 
 | |
| 	// NOTE: this without scaling also represents the inner width of 
 | |
| 	// 		the viewer...
 | |
| 	var w = mag.outerWidth(true)
 | |
| 	// XXX this depends on scale...
 | |
| 	var pos = page.position().left//*scale
 | |
| 
 | |
| 	var l = 0
 | |
| 
 | |
| 	return -((w - w*scale)/2 + pos) + offset
 | |
| }
 | |
| 
 | |
| 
 | |
| function getPageNumber(page){
 | |
| 	// a page is given explicitly, get the next one...
 | |
| 	if(page != null){
 | |
| 		return $('.page').index($(page))
 | |
| 	}
 | |
| 
 | |
| 	// get the next page relative to the current... 
 | |
| 	if(!isNavigationViewRelative()){
 | |
| 		return $('.page').index($('.current.page'))
 | |
| 
 | |
| 	// 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
 | |
| 	} else {
 | |
| 		var scale = getMagazineScale()
 | |
| 		var o = -$($('.magazine')[0]).offset().left - $('.viewer').offset().left
 | |
| 		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
 | |
| 			return Math.abs((l+(w/2)) - (o+(W/2)))
 | |
| 		}).toArray()
 | |
| 		cur = res.indexOf(Math.min.apply(Math, res))
 | |
| 		return cur
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| function getMagazineScale(){
 | |
| 	return getElementScale($('.magazine'))
 | |
| }
 | |
| function setMagazineScale(scale){
 | |
| 	var mag = $('.magazine')
 | |
| 	var cur = $('.current.page')
 | |
| 
 | |
| 	// center-align ribbon view pages...
 | |
| 	var align = isNavigationViewRelative() ? 'center' : null
 | |
| 	var left = getMagazineOffset(cur, scale, align)
 | |
| 
 | |
| 	setElementTransform(mag, left, scale)
 | |
| 
 | |
| 	return mag
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /********************************************************* actions ***/
 | |
| 
 | |
| function setCurrentPage(n){
 | |
| 	if(n == null){
 | |
| 		n = getPageNumber()
 | |
| 	}
 | |
| 	var scale = getMagazineScale()
 | |
| 	var l = $('.page').length
 | |
| 	// normalize the number...
 | |
| 	n = n < 0 ? l - n : n
 | |
| 	n = n < -l ? 0 : n
 | |
| 	n = n >= l ? l - 1 : n
 | |
| 
 | |
| 	$('.current.page').removeClass('current')
 | |
| 	$($('.page')[n]).addClass('current')
 | |
| 
 | |
| 	var cur = $('.current.page')
 | |
| 
 | |
| 	// center-align pages in ribbon view...
 | |
| 	var align = isNavigationViewRelative() ? 'center' : null
 | |
| 	var left = getMagazineOffset(cur, null, align)
 | |
| 
 | |
| 	setElementTransform($('.magazine'), left, scale)
 | |
| 
 | |
| 	return cur
 | |
| }
 | |
| 
 | |
| 
 | |
| function nextPage(page){
 | |
| 	setCurrentPage(getPageNumber(page)+1)
 | |
| }
 | |
| function prevPage(page){
 | |
| 	var n = getPageNumber(page)-1
 | |
| 	n = n < 0 ? 0 : n
 | |
| 	setCurrentPage(n)
 | |
| }
 | |
| 
 | |
| 
 | |
| function firstPage(){
 | |
| 	setCurrentPage(0)
 | |
| }
 | |
| function lastPage(){
 | |
| 	setCurrentPage(-1)
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*********************************************************************/
 | |
| // vim:set ts=4 sw=4 :
 |