diff --git a/index.html b/index.html index ab72fe9..45d0e4e 100755 --- a/index.html +++ b/index.html @@ -8,6 +8,7 @@ /* this is needed only for live resize... */ var PAGES_VISIBLE = 1 +var PAGES_IN_RIBBON = 6 $(document).ready(function(){ $(window).resize(function() { @@ -19,17 +20,11 @@ $(document).ready(function(){ swipeStatus: swipeUpdate, // XXX change this to pinch... swipeUp: function(){ - PAGES_VISIBLE = 6 - fitNPages(PAGES_VISIBLE) + togglePageView('off') }, // XXX change this to pinch... swipeDown: function(){ - PAGES_VISIBLE = 1 - fitNPages(PAGES_VISIBLE) - // to prevent drag while zooming to affect - // the resulting position set it to current - // page... - setCurrentPage() + togglePageView('on') }, click: function(evt, elem){ if($(elem).hasClass('page')){ @@ -40,45 +35,74 @@ $(document).ready(function(){ }) // XXX add splash screen... + // XXX - fitNPages(PAGES_VISIBLE) - + togglePageView('on') }) -function swipeUpdate(evt, phase, direction, distance){ - var pages = $('.page') - var cur = $('.current.page') - var n = pages.index(cur) - var scale = getElementScale($('.scaler')) - var mag = $('.magazine') - if( phase=='move' && (direction=='left' || direction=='right') ){ - mag.addClass('unanimated') - if (direction == 'left'){ - //$('.magazine').css({left: -n*cur.width()-distance/scale}) - $('.magazine').css({left: -n*800-distance/scale}) - } else if (direction == 'right') { - //$('.magazine').css({left: -n*cur.width()+distance/scale}) - $('.magazine').css({left: -n*800+distance/scale}) +/*********************************************************************/ +// XXX move to generic lib... + +// this will create a function that will add/remove a css_class to elem +// calling the optional callbacks before and/or after. +// +// elem is a jquery compatible object; default use-case: a css selector. +// +// the resulting function understands the folowing arguments: +// - 'on' : switch mode on +// - 'off' : switch mode off +// - '?' : return current state ('on'|'off') +// - no arguments : toggle the state +// +// NOTE: of only one callback is given then it will be called after the +// class change... +// a way around this is to pass an empty function as callback_b +// +function createCSSClassToggler(elem, css_class, callback_a, callback_b){ + // prepare the pre/post callbacks... + if(callback_b == null){ + var callback_pre = null + var callback_post = callback_a + } else { + var callback_pre = callback_a + var callback_post = callback_b + } + // build the acual toggler function... + var func = function(action){ + if(action == null || action == '?'){ + var getter = action == '?' ? true : false + action = 'on' + // get current state... + if( $(elem).hasClass(css_class) ){ + action = 'off' + } + if(getter){ + // as the above actions indicate intent and not state, + // we'll need to swap the values... + return action == 'on' ? 'off' : 'on' + } } - setTimeout(function(){mag.removeClass('unanimated')}, 5) - - } else if ( phase == 'cancel') { - setCurrentPage() - - } else if ( phase =='end' ) { - // see which page is closer to the middle of the screen and set it... - // do this based on how much we dragged... - var p = Math.ceil((distance/scale)/cur.width()) - - // prev page... - if(direction == 'right') { - setCurrentPage(Math.max(n-p, 0)) - // next page... - } else if (direction == 'left'){ - setCurrentPage(Math.min(n+p, pages.length-1)) + if(callback_pre != null){ + callback_pre(action) + } + // play with the class... + if(action == 'on'){ + $(elem).addClass(css_class) + } else { + $(elem).removeClass(css_class) + } + if(callback_post != null){ + callback_post(action) } } + func.doc = 'With no arguments this will toggle between "on" and '+ + '"off".\n'+ + 'If either "on" or "off" are given then this will switch '+ + 'to that mode.\n'+ + 'If "?" is given, this will return either "on" or "off" '+ + 'depending on the current state.' + return func } @@ -105,9 +129,194 @@ function unanimated(obj, func, time){ } } +// Return a scale value for the given element(s). +// NOTE: this will only return a single scale value... +function getElementScale(elem){ + //var transform = elem.css('transform') + var vendors = ['o', 'moz', 'ms', 'webkit'] + var transform = elem.css('transform') + var res + + // go through vendor prefixes... (hate this!) + if(!transform || transform == 'none'){ + for(var i in vendors){ + transform = elem.css('-' + vendors[i] + '-transform') + if(transform && transform != 'none'){ + break + } + } + } + // no transform is set... + if(!transform || transform == 'none'){ + return 1 + } + // get the scale value -- first argument of scale/matrix... + return parseFloat((/(scale|matrix)\(([^,]*),.*\)/).exec(transform)[2]) +} + +function setElementScale(elem, scale){ + return elem.css({ + 'transform': 'scale('+scale+')', + '-moz-transform': 'scale('+scale+')', + '-o-transform': 'scale('+scale+')', + '-ms-transform': 'scale('+scale+')', + '-webkit-transform': 'scale('+scale+')', + }) +} -function setCurrentPage(n){ + + +/*********************************************************************/ + +togglePageView = createCSSClassToggler( + '.viewer', + 'page-view-mode', + null, + // post-change callback... + function(){ + if(togglePageView('?') == 'on'){ + PAGES_VISIBLE = 1 + fitPagesToViewer(PAGES_VISIBLE) + //fitNPages(PAGES_VISIBLE) + // to prevent drag while zooming to affect + // the resulting position set it to current + // page... + // XXX now this is done by fitNPages + //setCurrentPage() + } else { + PAGES_VISIBLE = PAGES_IN_RIBBON + // XXX this needs to be done before transitions... + fitPagesToContent(PAGES_VISIBLE) + //fitNPages(PAGES_VISIBLE) + } + }) + +function getPageScale(){ + return getElementScale($('.scaler')) +} + +function fitNPages(n){ + /* + if(n==null){ + n = 1 + } + var pages = $('.page') + var view = $('.viewer') + var W = view.width() + var H = view.height() + var w = pages.width() + var h = pages.height() + + var scale = W/(w*n) + + // fit vertically if needed... + if(h*scale > H){ + scale = H/h + } + + setElementScale($('.scaler'), scale) + */ + + fitPagesTo(null, n) +} + +// XXX this is a single big function because we need to thread data +// through to avoid sampling while animating... +function fitPagesTo(elem, n){ + if(n==null){ + n = 1 + } + var pages = $('.page') + var view = $('.viewer') + if(elem == null){ + elem = view + } else { + elem = $(elem) + } + + // sample data... + var vW = view.width() + var vH = view.height() + var W = elem.width() + var H = elem.height() + var w = pages.width() + var h = pages.height() + var rW = w + + // NOTE: there must be no data sampling after this point... + // this is due to the fact that we will start changing stuff next + // and if CSS transitions are at play new samples will be off... + + // do the fitting... + if(W-w/H-h > 1){ + rW = W * (h/H) + pages.width(rW) + $('.magazine').css({ + // NOTE: we can't use direct .width() here because of the transitions... + 'margin-left': -rW/2 + }) + } + if(W-w/H-h < 1){ + pages.height(H * (w/W)) + } + + // scale horizontally... + var scale = vW/(rW*n) + // or scale vertically if needed... + if(h*scale > vH){ + scale = vH/h + } + + setElementScale($('.scaler'), scale) + // update position using the new width... + setCurrentPage(null, rW) +} + +function fitPagesToViewer(n){ + fitPagesTo('.viewer', n) +} +function fitPagesToContent(n){ + fitPagesTo('.page .content', n) +} + + +function swipeUpdate(evt, phase, direction, distance){ + var pages = $('.page') + var cur = $('.current.page') + var n = pages.index(cur) + var scale = getPageScale() + var mag = $('.magazine') + + if( phase=='move' && (direction=='left' || direction=='right') ){ + mag.addClass('unanimated') + if (direction == 'left'){ + $('.magazine').css({left: -n*cur.width()-distance/scale}) + } else if (direction == 'right') { + $('.magazine').css({left: -n*cur.width()+distance/scale}) + } + setTimeout(function(){mag.removeClass('unanimated')}, 5) + + } else if ( phase == 'cancel') { + setCurrentPage() + + } else if ( phase =='end' ) { + // see which page is closer to the middle of the screen and set it... + // do this based on how much we dragged... + var p = Math.ceil((distance/scale)/cur.width()) + + // prev page... + if(direction == 'right') { + setCurrentPage(Math.max(n-p, 0)) + // next page... + } else if (direction == 'left'){ + setCurrentPage(Math.min(n+p, pages.length-1)) + } + } +} + + +function setCurrentPage(n, W){ if(n == null){ var cur = $('.current.page') n = $('.page').index(cur) @@ -122,7 +331,8 @@ function setCurrentPage(n){ cur.addClass('current') var mag = $('.magazine') - mag.css({left: -n*cur.width()}) + var W = W == null ? cur.width() : W + mag.css({left: -n*W}) return cur } @@ -183,61 +393,6 @@ function prevArticle(){ -// Return a scale value for the given element(s). -// NOTE: this will only return a single scale value... -function getElementScale(elem){ - //var transform = elem.css('transform') - var vendors = ['o', 'moz', 'ms', 'webkit'] - var transform = elem.css('transform') - var res - - // go through vendor prefixes... (hate this!) - if(!transform || transform == 'none'){ - for(var i in vendors){ - transform = elem.css('-' + vendors[i] + '-transform') - if(transform && transform != 'none'){ - break - } - } - } - // no transform is set... - if(!transform || transform == 'none'){ - return 1 - } - // get the scale value -- first argument of scale/matrix... - return parseFloat((/(scale|matrix)\(([^,]*),.*\)/).exec(transform)[2]) -} - -function setElementScale(elem, scale){ - return elem.css({ - 'transform': 'scale('+scale+')', - '-moz-transform': 'scale('+scale+')', - '-o-transform': 'scale('+scale+')', - '-ms-transform': 'scale('+scale+')', - '-webkit-transform': 'scale('+scale+')', - }) -} - - - -function fitNPages(n){ - if(n==null){ - n = 1 - } - var pages = $('.page') - var scale = $('.viewer').width()/(pages.width()*n) - - // fit vertically if needed... - if(pages.height()*scale > $('.viewer').height()){ - scale = $('.viewer').height()/pages.height() - } - - setElementScale($('.scaler'), scale) -} - - - - // XXX create magazine... function createMagazine(){ } @@ -268,8 +423,10 @@ function createPage(article, template){
- Article Cover
- some more text... +
+ Article Cover
+ some more text... +
diff --git a/magazine.css b/magazine.css index 8cd269c..eb72388 100755 --- a/magazine.css +++ b/magazine.css @@ -9,8 +9,7 @@ body { /* XXX make this browser-sized... */ display: inline-block; vertical-align: bottom; - - overflow: auto; + text-align: center; /* XXX need these to be the same as the magazine, for some reason does not work... * one way to go is to use a fixed page layout and scale things manually. @@ -22,15 +21,30 @@ body { margin-top: -300px; font-size: 12px; + + -webkit-transition: all 0.2s ease; + -moz-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + -ms-transition: all 0.2s ease; + transition: all 0.2s ease; } -.current.page { -} +.page .content { + display: inline-block; + text-align: left; + position: relative; + /* these set the "safe" marks for page content */ + width: 800px; + height: 600px; + + border: solid red 1px; +} /* general layout */ .viewer { + position: relative; /* this makes the magazine behave like a ribbon */ width: 100%; height: 100%; @@ -104,7 +118,18 @@ body { } +/* modes */ +.page-view-mode .viewer { +} +.page-view-mode .page { +} +.page-view-mode .current.page { +} + + + +/* keep this at the end... */ .unanimated { -webkit-transition: none; -moz-transition: none;