mirror of
https://github.com/flynx/PortableMag.git
synced 2025-10-28 10:40:07 +00:00
migrated to iScroll5 and a partial rewrite...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
48b30ccb5a
commit
fc8b17910e
@ -19,7 +19,7 @@
|
||||
</author>
|
||||
|
||||
|
||||
<!--preference name="orientation" value="landscape" /-->
|
||||
<preference name="orientation" value="landscape" />
|
||||
<preference name="fullscreen" value="true" />
|
||||
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
.top-toolbar, .bottom-toolbar {
|
||||
font-size: 14px;
|
||||
color: silver;
|
||||
box-shadow: 5px 5px 50px 5px #444 inset;
|
||||
/*box-shadow: 5px 5px 50px 5px #444 inset;*/
|
||||
}
|
||||
|
||||
.top-toolbar .title,
|
||||
@ -154,8 +154,8 @@
|
||||
.light-viewer .bottom-toolbar {
|
||||
font-size: 14px;
|
||||
color: silver;
|
||||
background: white;
|
||||
box-shadow: 5px 5px 50px 20px #eee;
|
||||
/*background: white;
|
||||
box-shadow: 5px 5px 50px 20px #eee;*/
|
||||
}
|
||||
.light-viewer .top-toolbar a,
|
||||
.light-viewer .bottom-toolbar a {
|
||||
@ -240,8 +240,8 @@
|
||||
.dark-viewer .bottom-toolbar {
|
||||
font-size: 14px;
|
||||
color: gray;
|
||||
background: black;
|
||||
box-shadow: none;
|
||||
/*background: black;
|
||||
box-shadow: none;*/
|
||||
}
|
||||
|
||||
.dark-viewer .top-toolbar a,
|
||||
|
||||
@ -299,7 +299,8 @@ body {
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
|
||||
background: #555;
|
||||
/*background: #555;*/
|
||||
background: transparent;
|
||||
opacity: 0.9;
|
||||
|
||||
height: 50px;
|
||||
@ -319,12 +320,6 @@ body {
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
.page-view-mode .top-toolbar,
|
||||
.page-view-mode .bottom-toolbar,
|
||||
.full-page-view-mode .top-toolbar,
|
||||
.full-page-view-mode .bottom-toolbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* title */
|
||||
.top-toolbar .title,
|
||||
@ -560,6 +555,7 @@ body {
|
||||
|
||||
.page-view-mode .top-toolbar,
|
||||
.page-view-mode .bottom-toolbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.page-view-mode .page .content {
|
||||
|
||||
1565
ext-lib/iscroll-infinite.js
Executable file
1565
ext-lib/iscroll-infinite.js
Executable file
File diff suppressed because it is too large
Load Diff
594
ext-lib/iscroll-lite.js
Executable file
594
ext-lib/iscroll-lite.js
Executable file
@ -0,0 +1,594 @@
|
||||
/*!
|
||||
* iScroll Lite base on iScroll v4.1.6 ~ Copyright (c) 2011 Matteo Spinelli, http://cubiq.org
|
||||
* Released under MIT license, http://cubiq.org/license
|
||||
*/
|
||||
|
||||
(function(){
|
||||
var m = Math,
|
||||
mround = function (r) { return r >> 0; },
|
||||
vendor = (/webkit/i).test(navigator.appVersion) ? 'webkit' :
|
||||
(/firefox/i).test(navigator.userAgent) ? 'Moz' :
|
||||
'opera' in window ? 'O' : '',
|
||||
|
||||
// Browser capabilities
|
||||
isAndroid = (/android/gi).test(navigator.appVersion),
|
||||
isIDevice = (/iphone|ipad/gi).test(navigator.appVersion),
|
||||
isPlaybook = (/playbook/gi).test(navigator.appVersion),
|
||||
isTouchPad = (/hp-tablet/gi).test(navigator.appVersion),
|
||||
|
||||
has3d = 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix(),
|
||||
hasTouch = 'ontouchstart' in window && !isTouchPad,
|
||||
hasTransform = vendor + 'Transform' in document.documentElement.style,
|
||||
hasTransitionEnd = isIDevice || isPlaybook,
|
||||
|
||||
nextFrame = (function() {
|
||||
return window.requestAnimationFrame
|
||||
|| window.webkitRequestAnimationFrame
|
||||
|| window.mozRequestAnimationFrame
|
||||
|| window.oRequestAnimationFrame
|
||||
|| window.msRequestAnimationFrame
|
||||
|| function(callback) { return setTimeout(callback, 17); }
|
||||
})(),
|
||||
cancelFrame = (function () {
|
||||
return window.cancelRequestAnimationFrame
|
||||
|| window.webkitCancelAnimationFrame
|
||||
|| window.webkitCancelRequestAnimationFrame
|
||||
|| window.mozCancelRequestAnimationFrame
|
||||
|| window.oCancelRequestAnimationFrame
|
||||
|| window.msCancelRequestAnimationFrame
|
||||
|| clearTimeout
|
||||
})(),
|
||||
|
||||
// Events
|
||||
RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize',
|
||||
START_EV = hasTouch ? 'touchstart' : 'mousedown',
|
||||
MOVE_EV = hasTouch ? 'touchmove' : 'mousemove',
|
||||
END_EV = hasTouch ? 'touchend' : 'mouseup',
|
||||
CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup',
|
||||
|
||||
// Helpers
|
||||
trnOpen = 'translate' + (has3d ? '3d(' : '('),
|
||||
trnClose = has3d ? ',0)' : ')',
|
||||
|
||||
// Constructor
|
||||
iScroll = function (el, options) {
|
||||
var that = this,
|
||||
doc = document,
|
||||
i;
|
||||
|
||||
that.wrapper = typeof el == 'object' ? el : doc.getElementById(el);
|
||||
that.wrapper.style.overflow = 'hidden';
|
||||
that.scroller = that.wrapper.children[0];
|
||||
|
||||
// Default options
|
||||
that.options = {
|
||||
hScroll: true,
|
||||
vScroll: true,
|
||||
x: 0,
|
||||
y: 0,
|
||||
bounce: true,
|
||||
bounceLock: false,
|
||||
momentum: true,
|
||||
lockDirection: true,
|
||||
useTransform: true,
|
||||
useTransition: false,
|
||||
|
||||
// Events
|
||||
onRefresh: null,
|
||||
onBeforeScrollStart: function (e) { e.preventDefault(); },
|
||||
onScrollStart: null,
|
||||
onBeforeScrollMove: null,
|
||||
onScrollMove: null,
|
||||
onBeforeScrollEnd: null,
|
||||
onScrollEnd: null,
|
||||
onTouchEnd: null,
|
||||
onDestroy: null
|
||||
};
|
||||
|
||||
// User defined options
|
||||
for (i in options) that.options[i] = options[i];
|
||||
|
||||
// Set starting position
|
||||
that.x = that.options.x;
|
||||
that.y = that.options.y;
|
||||
|
||||
// Normalize options
|
||||
that.options.useTransform = hasTransform ? that.options.useTransform : false;
|
||||
that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar;
|
||||
that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar;
|
||||
that.options.useTransition = hasTransitionEnd && that.options.useTransition;
|
||||
|
||||
// Set some default styles
|
||||
that.scroller.style[vendor + 'TransitionProperty'] = that.options.useTransform ? '-' + vendor.toLowerCase() + '-transform' : 'top left';
|
||||
that.scroller.style[vendor + 'TransitionDuration'] = '0';
|
||||
that.scroller.style[vendor + 'TransformOrigin'] = '0 0';
|
||||
if (that.options.useTransition) that.scroller.style[vendor + 'TransitionTimingFunction'] = 'cubic-bezier(0.33,0.66,0.66,1)';
|
||||
|
||||
if (that.options.useTransform) that.scroller.style[vendor + 'Transform'] = trnOpen + that.x + 'px,' + that.y + 'px' + trnClose;
|
||||
else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px';
|
||||
|
||||
that.refresh();
|
||||
|
||||
that._bind(RESIZE_EV, window);
|
||||
that._bind(START_EV);
|
||||
if (!hasTouch) that._bind('mouseout', that.wrapper);
|
||||
};
|
||||
|
||||
// Prototype
|
||||
iScroll.prototype = {
|
||||
enabled: true,
|
||||
x: 0,
|
||||
y: 0,
|
||||
steps: [],
|
||||
scale: 1,
|
||||
|
||||
handleEvent: function (e) {
|
||||
var that = this;
|
||||
switch(e.type) {
|
||||
case START_EV:
|
||||
if (!hasTouch && e.button !== 0) return;
|
||||
that._start(e);
|
||||
break;
|
||||
case MOVE_EV: that._move(e); break;
|
||||
case END_EV:
|
||||
case CANCEL_EV: that._end(e); break;
|
||||
case RESIZE_EV: that._resize(); break;
|
||||
case 'mouseout': that._mouseout(e); break;
|
||||
case 'webkitTransitionEnd': that._transitionEnd(e); break;
|
||||
}
|
||||
},
|
||||
|
||||
_resize: function () {
|
||||
this.refresh();
|
||||
},
|
||||
|
||||
_pos: function (x, y) {
|
||||
x = this.hScroll ? x : 0;
|
||||
y = this.vScroll ? y : 0;
|
||||
|
||||
if (this.options.useTransform) {
|
||||
this.scroller.style[vendor + 'Transform'] = trnOpen + x + 'px,' + y + 'px' + trnClose + ' scale(' + this.scale + ')';
|
||||
} else {
|
||||
x = mround(x);
|
||||
y = mround(y);
|
||||
this.scroller.style.left = x + 'px';
|
||||
this.scroller.style.top = y + 'px';
|
||||
}
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
},
|
||||
|
||||
_start: function (e) {
|
||||
var that = this,
|
||||
point = hasTouch ? e.touches[0] : e,
|
||||
matrix, x, y;
|
||||
|
||||
if (!that.enabled) return;
|
||||
|
||||
if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e);
|
||||
|
||||
if (that.options.useTransition) that._transitionTime(0);
|
||||
|
||||
that.moved = false;
|
||||
that.animating = false;
|
||||
that.zoomed = false;
|
||||
that.distX = 0;
|
||||
that.distY = 0;
|
||||
that.absDistX = 0;
|
||||
that.absDistY = 0;
|
||||
that.dirX = 0;
|
||||
that.dirY = 0;
|
||||
|
||||
if (that.options.momentum) {
|
||||
if (that.options.useTransform) {
|
||||
// Very lame general purpose alternative to CSSMatrix
|
||||
matrix = getComputedStyle(that.scroller, null)[vendor + 'Transform'].replace(/[^0-9-.,]/g, '').split(',');
|
||||
x = matrix[4] * 1;
|
||||
y = matrix[5] * 1;
|
||||
} else {
|
||||
x = getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '') * 1;
|
||||
y = getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '') * 1;
|
||||
}
|
||||
|
||||
if (x != that.x || y != that.y) {
|
||||
if (that.options.useTransition) that._unbind('webkitTransitionEnd');
|
||||
else cancelFrame(that.aniTime);
|
||||
that.steps = [];
|
||||
that._pos(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
that.startX = that.x;
|
||||
that.startY = that.y;
|
||||
that.pointX = point.pageX;
|
||||
that.pointY = point.pageY;
|
||||
|
||||
that.startTime = e.timeStamp || Date.now();
|
||||
|
||||
if (that.options.onScrollStart) that.options.onScrollStart.call(that, e);
|
||||
|
||||
that._bind(MOVE_EV);
|
||||
that._bind(END_EV);
|
||||
that._bind(CANCEL_EV);
|
||||
},
|
||||
|
||||
_move: function (e) {
|
||||
var that = this,
|
||||
point = hasTouch ? e.touches[0] : e,
|
||||
deltaX = point.pageX - that.pointX,
|
||||
deltaY = point.pageY - that.pointY,
|
||||
newX = that.x + deltaX,
|
||||
newY = that.y + deltaY,
|
||||
timestamp = e.timeStamp || Date.now();
|
||||
|
||||
if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e);
|
||||
|
||||
that.pointX = point.pageX;
|
||||
that.pointY = point.pageY;
|
||||
|
||||
// Slow down if outside of the boundaries
|
||||
if (newX > 0 || newX < that.maxScrollX) {
|
||||
newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX;
|
||||
}
|
||||
if (newY > 0 || newY < that.maxScrollY) {
|
||||
newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= 0 || that.maxScrollY >= 0 ? 0 : that.maxScrollY;
|
||||
}
|
||||
|
||||
that.distX += deltaX;
|
||||
that.distY += deltaY;
|
||||
that.absDistX = m.abs(that.distX);
|
||||
that.absDistY = m.abs(that.distY);
|
||||
|
||||
if (that.absDistX < 6 && that.absDistY < 6) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Lock direction
|
||||
if (that.options.lockDirection) {
|
||||
if (that.absDistX > that.absDistY + 5) {
|
||||
newY = that.y;
|
||||
deltaY = 0;
|
||||
} else if (that.absDistY > that.absDistX + 5) {
|
||||
newX = that.x;
|
||||
deltaX = 0;
|
||||
}
|
||||
}
|
||||
|
||||
that.moved = true;
|
||||
that._pos(newX, newY);
|
||||
that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
|
||||
that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
|
||||
|
||||
if (timestamp - that.startTime > 300) {
|
||||
that.startTime = timestamp;
|
||||
that.startX = that.x;
|
||||
that.startY = that.y;
|
||||
}
|
||||
|
||||
if (that.options.onScrollMove) that.options.onScrollMove.call(that, e);
|
||||
},
|
||||
|
||||
_end: function (e) {
|
||||
if (hasTouch && e.touches.length != 0) return;
|
||||
|
||||
var that = this,
|
||||
point = hasTouch ? e.changedTouches[0] : e,
|
||||
target, ev,
|
||||
momentumX = { dist:0, time:0 },
|
||||
momentumY = { dist:0, time:0 },
|
||||
duration = (e.timeStamp || Date.now()) - that.startTime,
|
||||
newPosX = that.x,
|
||||
newPosY = that.y,
|
||||
newDuration;
|
||||
|
||||
that._unbind(MOVE_EV);
|
||||
that._unbind(END_EV);
|
||||
that._unbind(CANCEL_EV);
|
||||
|
||||
if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e);
|
||||
|
||||
if (!that.moved) {
|
||||
if (hasTouch) {
|
||||
// Find the last touched element
|
||||
target = point.target;
|
||||
while (target.nodeType != 1) target = target.parentNode;
|
||||
|
||||
if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') {
|
||||
ev = document.createEvent('MouseEvents');
|
||||
ev.initMouseEvent('click', true, true, e.view, 1,
|
||||
point.screenX, point.screenY, point.clientX, point.clientY,
|
||||
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
|
||||
0, null);
|
||||
ev._fake = true;
|
||||
target.dispatchEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
that._resetPos(200);
|
||||
|
||||
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (duration < 300 && that.options.momentum) {
|
||||
momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX;
|
||||
momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y : 0), that.options.bounce ? that.wrapperH : 0) : momentumY;
|
||||
|
||||
newPosX = that.x + momentumX.dist;
|
||||
newPosY = that.y + momentumY.dist;
|
||||
|
||||
if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 };
|
||||
if ((that.y > 0 && newPosY > 0) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 };
|
||||
}
|
||||
|
||||
if (momentumX.dist || momentumY.dist) {
|
||||
newDuration = m.max(m.max(momentumX.time, momentumY.time), 10);
|
||||
|
||||
that.scrollTo(mround(newPosX), mround(newPosY), newDuration);
|
||||
|
||||
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
|
||||
return;
|
||||
}
|
||||
|
||||
that._resetPos(200);
|
||||
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
|
||||
},
|
||||
|
||||
_resetPos: function (time) {
|
||||
var that = this,
|
||||
resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x,
|
||||
resetY = that.y >= 0 || that.maxScrollY > 0 ? 0 : that.y < that.maxScrollY ? that.maxScrollY : that.y;
|
||||
|
||||
if (resetX == that.x && resetY == that.y) {
|
||||
if (that.moved) {
|
||||
if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); // Execute custom code on scroll end
|
||||
that.moved = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
that.scrollTo(resetX, resetY, time || 0);
|
||||
},
|
||||
|
||||
_mouseout: function (e) {
|
||||
var t = e.relatedTarget;
|
||||
|
||||
if (!t) {
|
||||
this._end(e);
|
||||
return;
|
||||
}
|
||||
|
||||
while (t = t.parentNode) if (t == this.wrapper) return;
|
||||
|
||||
this._end(e);
|
||||
},
|
||||
|
||||
_transitionEnd: function (e) {
|
||||
var that = this;
|
||||
|
||||
if (e.target != that.scroller) return;
|
||||
|
||||
that._unbind('webkitTransitionEnd');
|
||||
|
||||
that._startAni();
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Utilities
|
||||
*
|
||||
*/
|
||||
_startAni: function () {
|
||||
var that = this,
|
||||
startX = that.x, startY = that.y,
|
||||
startTime = Date.now(),
|
||||
step, easeOut,
|
||||
animate;
|
||||
|
||||
if (that.animating) return;
|
||||
|
||||
if (!that.steps.length) {
|
||||
that._resetPos(400);
|
||||
return;
|
||||
}
|
||||
|
||||
step = that.steps.shift();
|
||||
|
||||
if (step.x == startX && step.y == startY) step.time = 0;
|
||||
|
||||
that.animating = true;
|
||||
that.moved = true;
|
||||
|
||||
if (that.options.useTransition) {
|
||||
that._transitionTime(step.time);
|
||||
that._pos(step.x, step.y);
|
||||
that.animating = false;
|
||||
if (step.time) that._bind('webkitTransitionEnd');
|
||||
else that._resetPos(0);
|
||||
return;
|
||||
}
|
||||
|
||||
animate = function () {
|
||||
var now = Date.now(),
|
||||
newX, newY;
|
||||
|
||||
if (now >= startTime + step.time) {
|
||||
that._pos(step.x, step.y);
|
||||
that.animating = false;
|
||||
if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that); // Execute custom code on animation end
|
||||
that._startAni();
|
||||
return;
|
||||
}
|
||||
|
||||
now = (now - startTime) / step.time - 1;
|
||||
easeOut = m.sqrt(1 - now * now);
|
||||
newX = (step.x - startX) * easeOut + startX;
|
||||
newY = (step.y - startY) * easeOut + startY;
|
||||
that._pos(newX, newY);
|
||||
if (that.animating) that.aniTime = nextFrame(animate);
|
||||
};
|
||||
|
||||
animate();
|
||||
},
|
||||
|
||||
_transitionTime: function (time) {
|
||||
this.scroller.style[vendor + 'TransitionDuration'] = time + 'ms';
|
||||
},
|
||||
|
||||
_momentum: function (dist, time, maxDistUpper, maxDistLower, size) {
|
||||
var deceleration = 0.0006,
|
||||
speed = m.abs(dist) / time,
|
||||
newDist = (speed * speed) / (2 * deceleration),
|
||||
newTime = 0, outsideDist = 0;
|
||||
|
||||
// Proportinally reduce speed if we are outside of the boundaries
|
||||
if (dist > 0 && newDist > maxDistUpper) {
|
||||
outsideDist = size / (6 / (newDist / speed * deceleration));
|
||||
maxDistUpper = maxDistUpper + outsideDist;
|
||||
speed = speed * maxDistUpper / newDist;
|
||||
newDist = maxDistUpper;
|
||||
} else if (dist < 0 && newDist > maxDistLower) {
|
||||
outsideDist = size / (6 / (newDist / speed * deceleration));
|
||||
maxDistLower = maxDistLower + outsideDist;
|
||||
speed = speed * maxDistLower / newDist;
|
||||
newDist = maxDistLower;
|
||||
}
|
||||
|
||||
newDist = newDist * (dist < 0 ? -1 : 1);
|
||||
newTime = speed / deceleration;
|
||||
|
||||
return { dist: newDist, time: mround(newTime) };
|
||||
},
|
||||
|
||||
_offset: function (el) {
|
||||
var left = -el.offsetLeft,
|
||||
top = -el.offsetTop;
|
||||
|
||||
while (el = el.offsetParent) {
|
||||
left -= el.offsetLeft;
|
||||
top -= el.offsetTop;
|
||||
}
|
||||
|
||||
return { left: left, top: top };
|
||||
},
|
||||
|
||||
_bind: function (type, el, bubble) {
|
||||
(el || this.scroller).addEventListener(type, this, !!bubble);
|
||||
},
|
||||
|
||||
_unbind: function (type, el, bubble) {
|
||||
(el || this.scroller).removeEventListener(type, this, !!bubble);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Public methods
|
||||
*
|
||||
*/
|
||||
destroy: function () {
|
||||
var that = this;
|
||||
|
||||
that.scroller.style[vendor + 'Transform'] = '';
|
||||
|
||||
// Remove the event listeners
|
||||
that._unbind(RESIZE_EV, window);
|
||||
that._unbind(START_EV);
|
||||
that._unbind(MOVE_EV);
|
||||
that._unbind(END_EV);
|
||||
that._unbind(CANCEL_EV);
|
||||
that._unbind('mouseout', that.wrapper);
|
||||
if (that.options.useTransition) that._unbind('webkitTransitionEnd');
|
||||
|
||||
if (that.options.onDestroy) that.options.onDestroy.call(that);
|
||||
},
|
||||
|
||||
refresh: function () {
|
||||
var that = this,
|
||||
offset;
|
||||
|
||||
that.wrapperW = that.wrapper.clientWidth;
|
||||
that.wrapperH = that.wrapper.clientHeight;
|
||||
|
||||
that.scrollerW = that.scroller.offsetWidth;
|
||||
that.scrollerH = that.scroller.offsetHeight;
|
||||
that.maxScrollX = that.wrapperW - that.scrollerW;
|
||||
that.maxScrollY = that.wrapperH - that.scrollerH;
|
||||
that.dirX = 0;
|
||||
that.dirY = 0;
|
||||
|
||||
that.hScroll = that.options.hScroll && that.maxScrollX < 0;
|
||||
that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH);
|
||||
|
||||
offset = that._offset(that.wrapper);
|
||||
that.wrapperOffsetLeft = -offset.left;
|
||||
that.wrapperOffsetTop = -offset.top;
|
||||
|
||||
|
||||
that.scroller.style[vendor + 'TransitionDuration'] = '0';
|
||||
|
||||
that._resetPos(200);
|
||||
},
|
||||
|
||||
scrollTo: function (x, y, time, relative) {
|
||||
var that = this,
|
||||
step = x,
|
||||
i, l;
|
||||
|
||||
that.stop();
|
||||
|
||||
if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }];
|
||||
|
||||
for (i=0, l=step.length; i<l; i++) {
|
||||
if (step[i].relative) { step[i].x = that.x - step[i].x; step[i].y = that.y - step[i].y; }
|
||||
that.steps.push({ x: step[i].x, y: step[i].y, time: step[i].time || 0 });
|
||||
}
|
||||
|
||||
that._startAni();
|
||||
},
|
||||
|
||||
scrollToElement: function (el, time) {
|
||||
var that = this, pos;
|
||||
el = el.nodeType ? el : that.scroller.querySelector(el);
|
||||
if (!el) return;
|
||||
|
||||
pos = that._offset(el);
|
||||
pos.left += that.wrapperOffsetLeft;
|
||||
pos.top += that.wrapperOffsetTop;
|
||||
|
||||
pos.left = pos.left > 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left;
|
||||
pos.top = pos.top > 0 ? 0 : pos.top < that.maxScrollY ? that.maxScrollY : pos.top;
|
||||
time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time;
|
||||
|
||||
that.scrollTo(pos.left, pos.top, time);
|
||||
},
|
||||
|
||||
disable: function () {
|
||||
this.stop();
|
||||
this._resetPos(0);
|
||||
this.enabled = false;
|
||||
|
||||
// If disabled after touchstart we make sure that there are no left over events
|
||||
this._unbind(MOVE_EV);
|
||||
this._unbind(END_EV);
|
||||
this._unbind(CANCEL_EV);
|
||||
},
|
||||
|
||||
enable: function () {
|
||||
this.enabled = true;
|
||||
},
|
||||
|
||||
stop: function () {
|
||||
cancelFrame(this.aniTime);
|
||||
this.steps = [];
|
||||
this.moved = false;
|
||||
this.animating = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof exports !== 'undefined') exports.iScroll = iScroll;
|
||||
else window.iScroll = iScroll;
|
||||
|
||||
})();
|
||||
2015
ext-lib/iscroll-probe.js
Executable file
2015
ext-lib/iscroll-probe.js
Executable file
File diff suppressed because it is too large
Load Diff
2172
ext-lib/iscroll-zoom.js
Executable file
2172
ext-lib/iscroll-zoom.js
Executable file
File diff suppressed because it is too large
Load Diff
2918
ext-lib/iscroll.js
2918
ext-lib/iscroll.js
File diff suppressed because it is too large
Load Diff
274
index.html
274
index.html
@ -34,6 +34,7 @@
|
||||
.magazine {
|
||||
left: 150px;
|
||||
margin-left: 0px;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.page {
|
||||
@ -89,6 +90,9 @@
|
||||
<script src="ext-lib/jszip-inflate.js"></script>
|
||||
<!--script src="ext-lib\jszip-deflate.js"></script-->
|
||||
|
||||
<script src="ext-lib/iscroll.js"></script>
|
||||
<script src="ext-lib/iscroll-zoom.js"></script>
|
||||
|
||||
<script src="lib/jli.js"></script>
|
||||
<script src="lib/scroller.js"></script>
|
||||
<script src="lib/keyboard.js"></script>
|
||||
@ -242,8 +246,90 @@ function handleFileSelect(evt) {
|
||||
}
|
||||
}
|
||||
|
||||
// XXX these stubs override the magazine API and use iScroll...
|
||||
|
||||
$(document).ready(function(){
|
||||
// XXX need to account for page align...
|
||||
// XXX this works only for big pages...
|
||||
function getVisiblePage(){
|
||||
var offset = $('.magazine').offset().left
|
||||
var width = $('.viewer').width()
|
||||
var pages = $('.page')
|
||||
// filter the closest page to the viewer...
|
||||
.filter(function(){
|
||||
var page = $(this)
|
||||
var p = page.position().left + offset
|
||||
return p >= 0 && p < width/2
|
||||
|| p < 0 && p + page.width() >= width/2
|
||||
})
|
||||
// select the best candidate...
|
||||
// XXX
|
||||
return pages
|
||||
}
|
||||
|
||||
|
||||
/************************************************ iScroll5 Actions ***/
|
||||
|
||||
// XXX next/prev page work but only when BOTH:
|
||||
// - MagazineScroller.zoom is set to 1
|
||||
// - current page is focused
|
||||
|
||||
// XXX zoom != 1 messes up both iScroll5 navigation AND PortableMag navigation...
|
||||
|
||||
// XXX we do not need the snap feature, flick event is enough to do next/prev page...
|
||||
|
||||
// XXX make centered page account for page align...
|
||||
|
||||
|
||||
function enableFreeScroll(){
|
||||
MagazineScroller.options.scrollY = true
|
||||
MagazineScroller.options.freeScroll = true
|
||||
MagazineScroller.refresh()
|
||||
}
|
||||
|
||||
function disableFreeScroll(){
|
||||
MagazineScroller.options.scrollY = false
|
||||
MagazineScroller.options.freeScroll = false
|
||||
MagazineScroller.refresh()
|
||||
}
|
||||
|
||||
|
||||
// Actions...
|
||||
|
||||
// XXX this needs correct reference point calc...
|
||||
function zoomTo(n, scale, time){
|
||||
// calculate page projection center...
|
||||
var page = setCurrent(n)
|
||||
|
||||
var sc = getMagazineScale()
|
||||
var st = scale
|
||||
|
||||
var d = st / sc
|
||||
|
||||
var W = $('.viewer').width()
|
||||
var w = page.width()*sc
|
||||
var o = page.offset().left
|
||||
|
||||
var C = W/2
|
||||
var c = o + w/2
|
||||
|
||||
// left border -> 0
|
||||
// centered -> C = c -> independent of d
|
||||
// right border -> W
|
||||
|
||||
console.log('>>>', c, C, d, (c-C)*d)
|
||||
|
||||
// XXX this works iff d == 2
|
||||
|
||||
MagazineScroller.zoom(scale, C + (c-C)*d, null, time)
|
||||
|
||||
//return page
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
$(function(){
|
||||
|
||||
// this is to fix some sort of bug baking things align in a wrong
|
||||
// way at startup...
|
||||
@ -259,18 +345,166 @@ $(document).ready(function(){
|
||||
$(document)
|
||||
.keydown(makeKeyboardHandler(KEYBOARD_CONFIG))
|
||||
|
||||
window.MagazineScroller = makeScrollHandler($('.viewer'), {
|
||||
hScroll: true,
|
||||
vScroll: false,
|
||||
// XXX still a bit flacky...
|
||||
preCallback: function(){stopAnimation($('.magazine'))},
|
||||
// XXX...
|
||||
//scrollCallback: function(){ updateNavigator() },
|
||||
//enableMultiClicks: true,
|
||||
transitionEasing: 'cubic-bezier(0.33,0.66,0.66,1)',
|
||||
}).start()
|
||||
window.MagazineScroller = new IScroll('.viewer', {
|
||||
tap: true,
|
||||
|
||||
scrollX: true,
|
||||
scrollY: false,
|
||||
|
||||
scrollbars: true,
|
||||
fadeScrollbars: true,
|
||||
interactiveScrollbars: true,
|
||||
shrinkScrollbars: 'clip',
|
||||
|
||||
//bounce: false,
|
||||
|
||||
zoom: true,
|
||||
// XXX calc these dynamically depending on viewer size/resolution...
|
||||
zoomMin: 0.2,
|
||||
zoomMax: 2,
|
||||
})
|
||||
|
||||
window.MULTI_FINGER_RELEASE_TIMEOUT = 50
|
||||
|
||||
$('.viewer')
|
||||
.on('tap', function(){
|
||||
// XXX for some reason this does not focus the page clicked
|
||||
// if it's not the current and we are in page view...
|
||||
focusPage(event.target, togglePageView('?') == 'on' ? 'auto' : 'center')
|
||||
|
||||
handleCaption(event.target)
|
||||
})
|
||||
.on('touchstart', function(){
|
||||
// This is here to recover from touching a finger after
|
||||
// lifting it before the timeout...
|
||||
if(event.touches.length > 2){
|
||||
delete window._THIRD_FINGER_LIFTED
|
||||
}
|
||||
if(event.touches.length > 1){
|
||||
delete window._SECOND_FINGER_LIFTED
|
||||
}
|
||||
})
|
||||
.on('mouseup touchend', function(){
|
||||
var now = Date.now()
|
||||
|
||||
// handle the touchend only if ALL fingers are lifted...
|
||||
if(event.touches != null){
|
||||
// count touches within a timeout to handle multytouch swipes...
|
||||
if(event.touches.length == 2){
|
||||
window._THIRD_FINGER_LIFTED = now
|
||||
} else if(event.touches.length == 1){
|
||||
window._SECOND_FINGER_LIFTED = now
|
||||
}
|
||||
|
||||
// if we are still touching skip any action...
|
||||
if(event.touches.length > 0){
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// three finger action...
|
||||
if(window._THIRD_FINGER_LIFTED != null
|
||||
&& now - _THIRD_FINGER_LIFTED <= MULTI_FINGER_RELEASE_TIMEOUT){
|
||||
// first/last pages...
|
||||
if(MagazineScroller.directionX > 0){
|
||||
setTimeout(last, 0)
|
||||
} else if(MagazineScroller.directionX < 0){
|
||||
setTimeout(first, 0)
|
||||
}
|
||||
|
||||
// two finger action...
|
||||
} else if(window._SECOND_FINGER_LIFTED != null
|
||||
&& now - _SECOND_FINGER_LIFTED <= MULTI_FINGER_RELEASE_TIMEOUT){
|
||||
// next/prev cover...
|
||||
if(MagazineScroller.directionX > 0){
|
||||
setTimeout(nextCover, 0)
|
||||
} else if(MagazineScroller.directionX < 0){
|
||||
setTimeout(prevCover, 0)
|
||||
}
|
||||
|
||||
// single finger action...
|
||||
} else {
|
||||
if(togglePageView('?') == 'on'){
|
||||
// next/prev page...
|
||||
if(MagazineScroller.directionX > 0){
|
||||
setTimeout(nextPage, 0)
|
||||
} else if(MagazineScroller.directionX < 0){
|
||||
setTimeout(prevPage, 0)
|
||||
}
|
||||
|
||||
} else {
|
||||
setCurrent()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
// XXX do we really need this???
|
||||
window.MagazineScroller
|
||||
.on('flick', function(){
|
||||
if(togglePageView('?') == 'on'){
|
||||
if(this.directionX > 0){
|
||||
setTimeout(nextPage, 0)
|
||||
} else if(this.directionX < 0){
|
||||
setTimeout(prevPage, 0)
|
||||
}
|
||||
}
|
||||
})
|
||||
*/
|
||||
|
||||
window.MagazineScroller
|
||||
.on('scrollCancel', function(){
|
||||
if(togglePageView('?') == 'on'){
|
||||
focusPage(setCurrent(centeredPage()))
|
||||
}
|
||||
})
|
||||
|
||||
// XXX is this needed???
|
||||
window.MagazineScroller
|
||||
.on('scrollEnd', function(){
|
||||
// focus page that we end up on...
|
||||
if(!togglePageView('?') == 'on'){
|
||||
setCurrent()
|
||||
}
|
||||
})
|
||||
|
||||
// zooming...
|
||||
// XXX needs testing on device...
|
||||
window.MagazineScroller
|
||||
.on('zoomStart', function(){
|
||||
window._START_SCALE = getMagazineScale()
|
||||
})
|
||||
window.MagazineScroller
|
||||
.on('zoomEnd', function(){
|
||||
var s = getMagazineScale()
|
||||
|
||||
// XXX add issue support...
|
||||
//var state = togglePageView('?')
|
||||
|
||||
// zoom in...
|
||||
if(window._START_SCALE > s){
|
||||
togglePageView('off')
|
||||
|
||||
// zoom out...
|
||||
} else {
|
||||
togglePageView('on')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
$('.magazine')
|
||||
.css({
|
||||
'-webkit-transform-origin': '0px 50%',
|
||||
'left': 0,
|
||||
})
|
||||
|
||||
$('.viewer')
|
||||
.on('mouseup tapup', function(){
|
||||
//MagazineScroller.scrollToElement(getVisiblePage()[0], 300, true, true)
|
||||
})
|
||||
|
||||
/*
|
||||
.on('scrollCancelled', function(){ setCurrentPage() })
|
||||
.on('shortClick', handleCaption)
|
||||
.on('shortClick', handleClick)
|
||||
@ -279,6 +513,7 @@ $(document).ready(function(){
|
||||
.on('swipeRight', handleSwipeRight)
|
||||
.on('swipeUp swipeDown', function(){ togglePageView('off') })
|
||||
.on('screenReleased', handleScrollRelease)
|
||||
*/
|
||||
|
||||
.on('pageChanged', updatePageNumberIndicator)
|
||||
.on('magazineDataLoaded', loadMagazineChrome)
|
||||
@ -299,26 +534,28 @@ $(document).ready(function(){
|
||||
|
||||
togglePageView('on')
|
||||
// XXX this still depends on touchSwipe...
|
||||
setupNavigator()
|
||||
loadMagazineChrome()
|
||||
setCurrentPage(0)
|
||||
//setupNavigator()
|
||||
//loadMagazineChrome()
|
||||
//setCurrentPage(0)
|
||||
|
||||
toggleThemes('none')
|
||||
//toggleThemes('none')
|
||||
|
||||
|
||||
setupEditor()
|
||||
//setupEditor()
|
||||
|
||||
$('.dpi').text(getDPI())
|
||||
|
||||
|
||||
// hide the splash...
|
||||
setTimeout(function(){
|
||||
//setCurrentPage(0)
|
||||
|
||||
focusPage(0, null, 0)
|
||||
|
||||
$('.splash').fadeOut()
|
||||
}, 350)
|
||||
// remove the spinner...
|
||||
setTimeout(function(){
|
||||
$('#spinner').spin(false)
|
||||
MagazineScroller.refresh()
|
||||
}, 500)
|
||||
|
||||
})
|
||||
@ -944,7 +1181,6 @@ $(document).ready(function(){
|
||||
</div>
|
||||
<!-- Magazine Viewer (end) ------------------------------------------>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- Magazine Chrome (end) -->
|
||||
|
||||
|
||||
@ -138,17 +138,23 @@ var KEYBOARD_CONFIG = {
|
||||
}
|
||||
},
|
||||
|
||||
Home: firstPage,
|
||||
End: lastPage,
|
||||
//Home: firstPage,
|
||||
//End: lastPage,
|
||||
Home: function(){ first() },
|
||||
End: function(){ last() },
|
||||
Left: {
|
||||
default: function(){ prevPage() },
|
||||
shift: prevBookmark,
|
||||
ctrl: prevArticle,
|
||||
//default: function(){ prevPage() },
|
||||
default: function(){ prev() },
|
||||
//shift: prevBookmark,
|
||||
//ctrl: prevArticle,
|
||||
ctrl: function(){ prevCover() },
|
||||
},
|
||||
Right: {
|
||||
default: function(){ nextPage() },
|
||||
shift: nextBookmark,
|
||||
ctrl: nextArticle,
|
||||
//default: function(){ nextPage() },
|
||||
default: function(){ next() },
|
||||
//shift: nextBookmark,
|
||||
//ctrl: nextArticle,
|
||||
ctrl: function(){ nextCover() },
|
||||
},
|
||||
Space: {
|
||||
default: 'Right',
|
||||
|
||||
405
layout.js
405
layout.js
@ -4,8 +4,6 @@
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
var SNAP_TO_PAGES_IN_RIBBON = false
|
||||
|
||||
var DEFAULT_TRANSITION_DURATION = 200
|
||||
|
||||
var INNERTIA_SCALE = 0.25
|
||||
@ -23,61 +21,6 @@ var toggleThemes = createCSSClassToggler('.chrome', [
|
||||
])
|
||||
|
||||
|
||||
// NOTE: this should not change anything unless the screen size changes...
|
||||
function fitScreenSizedPages(){
|
||||
var s = getPageTargetScale(1)
|
||||
var W = $('.viewer').width()
|
||||
$(SCREEN_SIZED_PAGES).width(W / s)
|
||||
}
|
||||
|
||||
var togglePageFitMode = createCSSClassToggler(
|
||||
'.chrome',
|
||||
'page-fit-to-viewer',
|
||||
function(action){
|
||||
if(action == 'on'){
|
||||
var n = getPageNumber()
|
||||
var scale = getMagazineScale()
|
||||
$(RESIZABLE_PAGES)
|
||||
.width($('.viewer').width() / scale)
|
||||
} else {
|
||||
var n = getPageNumber()
|
||||
$(RESIZABLE_PAGES).width('')
|
||||
}
|
||||
fitScreenSizedPages()
|
||||
setCurrentPage(n)
|
||||
})
|
||||
|
||||
|
||||
var togglePageView = createCSSClassToggler(
|
||||
'.chrome',
|
||||
'full-page-view-mode',
|
||||
function(action){
|
||||
var view = $('.viewer')
|
||||
var page = $('.page')
|
||||
|
||||
// XXX
|
||||
setTransitionDuration($('.magazine'), 0)
|
||||
var n = getPageNumber()
|
||||
|
||||
if(action == 'on'){
|
||||
var scale = getPageTargetScale(1).value
|
||||
setMagazineScale(scale)
|
||||
//unanimated($('.magazine, .viewer'), togglePageFitMode)('on')
|
||||
togglePageFitMode('on')
|
||||
$('.viewer').trigger('fullScreenMode')
|
||||
} else {
|
||||
//unanimated($('.magazine, .viewer'), togglePageFitMode)('off')
|
||||
togglePageFitMode('off')
|
||||
var scale = getPageTargetScale(PAGES_IN_RIBBON).value
|
||||
setMagazineScale(scale)
|
||||
$('.viewer').trigger('ribbonMode')
|
||||
}
|
||||
// NOTE: can't disable transitions on this one because ScrollTo
|
||||
// uses jQuery animation...
|
||||
setCurrentPage(n)
|
||||
})
|
||||
|
||||
|
||||
// XXX this is neither final nor usable...
|
||||
function prepareInlineCaptions(){
|
||||
$('.page img[title]').each(function(){
|
||||
@ -90,30 +33,12 @@ function prepareInlineCaptions(){
|
||||
|
||||
/************************************************** event handlers ***/
|
||||
|
||||
// Click
|
||||
// - in full page do the default click, if clicked on other page, select
|
||||
// - in ribbon, open clicked page in full mode
|
||||
function handleClick(evt, data){
|
||||
var target = getPageNumber(data.orig_event.target)
|
||||
if(target != -1){
|
||||
var mag = $('.magazine')
|
||||
|
||||
if(togglePageView('?') == 'on'){
|
||||
setTransitionDuration(mag, DEFAULT_TRANSITION_DURATION)
|
||||
} else {
|
||||
togglePageView('on')
|
||||
}
|
||||
setCurrentPage(target)
|
||||
|
||||
//setTransitionEasing(mag, 'ease')
|
||||
setTransitionEasing(mag, 'cubic-bezier(0.33,0.66,0.66,1)')
|
||||
}
|
||||
}
|
||||
|
||||
// Click on caption...
|
||||
// XXX add inline caption support...
|
||||
function handleCaption(evt, data){
|
||||
elem = $(data.orig_event.target)
|
||||
function handleCaption(elem){
|
||||
//elem = $(data.orig_event.target)
|
||||
elem = elem == null ? $('.current.page').find('.caption') : $(elem)
|
||||
|
||||
if(elem.is('.image-fit-height, .image-fit, .image-with-caption')
|
||||
|| elem.parents('.image-fit-height, .image-fit, .image-with-caption').length > 0){
|
||||
|
||||
@ -136,328 +61,6 @@ function handleCaption(evt, data){
|
||||
}
|
||||
|
||||
|
||||
// Long Click
|
||||
// - in full page, go to ribbon
|
||||
// - in ribbon, center clicked page
|
||||
function handleLongClick(evt, data){
|
||||
var target = getPageNumber(data.orig_event.target)
|
||||
if(target != -1){
|
||||
var mag = $('.magazine')
|
||||
|
||||
if(togglePageView('?') == 'on'){
|
||||
togglePageView('off')
|
||||
} else {
|
||||
setTransitionDuration(mag, DEFAULT_TRANSITION_DURATION)
|
||||
}
|
||||
setCurrentPage(target)
|
||||
|
||||
//setTransitionEasing(mag, 'ease')
|
||||
setTransitionEasing(mag, 'cubic-bezier(0.33,0.66,0.66,1)')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Swipe Left/Right
|
||||
// - in full page, next/prev page select
|
||||
// - in ribbon, kinetic scroll
|
||||
// - with two fingers, select next/prev article
|
||||
function makeSwipeHandler(actionA, actionB){
|
||||
return function(evt, data){
|
||||
// ribbon mode...
|
||||
if(togglePageView('?') == 'off'){
|
||||
|
||||
// article navigation...
|
||||
if(data.touches >= 2){
|
||||
actionB($('.current.page'))
|
||||
return
|
||||
}
|
||||
|
||||
// this makes things snap...
|
||||
if(SNAP_TO_PAGES_IN_RIBBON){
|
||||
setCurrentPage()
|
||||
return
|
||||
}
|
||||
|
||||
return handleScrollRelease(evt, data)
|
||||
}
|
||||
// full page view...
|
||||
var mag = $('.magazine')
|
||||
//setTransitionEasing(mag, 'ease-out')
|
||||
setTransitionEasing(mag, 'cubic-bezier(0.33,0.66,0.66,1)')
|
||||
|
||||
if(data.touches >= 2){
|
||||
actionB($('.current.page'))
|
||||
} else {
|
||||
actionA($('.current.page'))
|
||||
}
|
||||
}
|
||||
}
|
||||
var handleSwipeLeft = makeSwipeHandler(prevPage, prevArticle)
|
||||
var handleSwipeRight = makeSwipeHandler(nextPage, nextArticle)
|
||||
|
||||
|
||||
// XXX
|
||||
GLOBAL_SCROLL_CALLBACK = null
|
||||
|
||||
// Scroll Release
|
||||
// - check bounds and if out center first/last page
|
||||
// - filter out "throw" speeds below threshold
|
||||
// - do inertial scroll (within check bounds)
|
||||
// - snap to pages
|
||||
//
|
||||
// NOTE: this will also handle swipeUp/swopeDown as we do not
|
||||
// explicitly bind them...
|
||||
// NOTE: at this point this ONLY handles horizontal scroll...
|
||||
//
|
||||
// XXX restore all the changed values...
|
||||
// XXX this may kill the ipad...
|
||||
function handleScrollRelease(evt, data){
|
||||
console.log(callback)
|
||||
var callback = GLOBAL_SCROLL_CALLBACK
|
||||
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))
|
||||
var t = DEFAULT_TRANSITION_DURATION
|
||||
// XXX this is only horizontal at this point...
|
||||
var at = getElementShift(mag).left
|
||||
var d = MAX_DISTANCE_TO_SCROLL != null ? MAX_DISTANCE_TO_SCROLL : Infinity
|
||||
var s = sign(speed) >= 0 ? 1 : -1
|
||||
var to = (at + (Math.min(Math.abs(t*speed*INNERTIA_SCALE), d) * s))
|
||||
var first = getMagazineOffset(pages.first(), null, 'center')
|
||||
var last = getMagazineOffset(pages.last(), null, 'center')
|
||||
|
||||
var easing = 'cubic-bezier(0.33,0.66,0.66,1)'
|
||||
|
||||
// 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
|
||||
//easing = 'linear'
|
||||
} else if(to < last){
|
||||
// trim the time proportionally...
|
||||
var _t = t
|
||||
t = Math.abs(t * ((at-last)/(at-to)))
|
||||
to = last
|
||||
//easing = 'linear'
|
||||
|
||||
} else {
|
||||
//easing = 'ease-out'
|
||||
}
|
||||
|
||||
animateElementTo(mag, to, t, easing, speed, callback)
|
||||
|
||||
// check scroll bounds...
|
||||
// do not let the user scroll out of view...
|
||||
} else {
|
||||
if(at > first){
|
||||
//animateElementTo(mag, first, DEFAULT_TRANSITION_DURATION, 'ease-in')
|
||||
animateElementTo(mag, first,
|
||||
DEFAULT_TRANSITION_DURATION,
|
||||
easing,
|
||||
null,
|
||||
callback)
|
||||
|
||||
} else if(at < last){
|
||||
//animateElementTo(mag, last, DEFAULT_TRANSITION_DURATION, 'ease-in')
|
||||
animateElementTo(mag, last,
|
||||
DEFAULT_TRANSITION_DURATION,
|
||||
easing,
|
||||
null,
|
||||
callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************* helpers ***/
|
||||
|
||||
function getPageInMagazineOffset(page, scale){
|
||||
if(page == null){
|
||||
page = $('.current.page')
|
||||
} else if(typeof(page) == typeof(7)){
|
||||
page = $($('.page')[page])
|
||||
}
|
||||
|
||||
return page.position().left / (scale == null ? getMagazineScale() : scale)
|
||||
}
|
||||
|
||||
|
||||
// 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 no current page get the first...
|
||||
if(page.length == 0){
|
||||
page = $('.page').first()
|
||||
}
|
||||
}
|
||||
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 = getPageInMagazineOffset(page, scale)
|
||||
var pos = page.position().left//*scale
|
||||
|
||||
var l = 0
|
||||
|
||||
return -((w - w*scale)/2 + pos) + offset
|
||||
}
|
||||
|
||||
|
||||
function getPageNumber(page){
|
||||
// a page/element is given explicitly...
|
||||
if(page != null){
|
||||
page = $(page)
|
||||
if(!page.hasClass('page')){
|
||||
page = page.parents('.page')
|
||||
}
|
||||
return $('.page').index(page)
|
||||
}
|
||||
|
||||
// current page index...
|
||||
if(togglePageView('?') == 'on'){
|
||||
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')
|
||||
if(cur.length == 0){
|
||||
cur = $('.page').first()
|
||||
}
|
||||
|
||||
// center-align ribbon view pages...
|
||||
var align = togglePageView('?') == 'off' ? 'center' : null
|
||||
var left = getMagazineOffset(cur, scale, align)
|
||||
|
||||
setElementTransform(mag, left, scale)
|
||||
|
||||
return mag
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************* actions ***/
|
||||
|
||||
function setCurrentPage(n, use_transitions){
|
||||
if(n == null){
|
||||
n = getPageNumber()
|
||||
}
|
||||
if(typeof(n) != typeof(3)){
|
||||
n = getPageNumber(n)
|
||||
}
|
||||
var l = $('.page').length
|
||||
// normalize the number...
|
||||
n = n < 0 ? l - n : n
|
||||
n = n < -l ? 0 : n
|
||||
n = n >= l ? l - 1 : n
|
||||
use_transitions = use_transitions != null ?
|
||||
use_transitions
|
||||
: USE_TRANSITIONS_FOR_ANIMATION
|
||||
|
||||
$('.current.page').removeClass('current')
|
||||
$($('.page')[n]).addClass('current')
|
||||
|
||||
var cur = $('.current.page')
|
||||
|
||||
// center-align pages in ribbon view...
|
||||
var align = togglePageView('?') == 'off' ? 'center' : null
|
||||
var left = getMagazineOffset(cur, null, align)
|
||||
|
||||
if(use_transitions){
|
||||
setElementTransform($('.magazine'), left)
|
||||
|
||||
} else {
|
||||
animateElementTo($('.magazine'), left)
|
||||
}
|
||||
|
||||
$('.viewer').trigger('pageChanged', n)
|
||||
|
||||
$(':focus').blur()
|
||||
return cur
|
||||
}
|
||||
|
||||
|
||||
function nextPage(page){
|
||||
// XXX is this the right place for this?
|
||||
setTransitionDuration($('.magazine'), DEFAULT_TRANSITION_DURATION)
|
||||
setCurrentPage(getPageNumber(page)+1)
|
||||
}
|
||||
function prevPage(page){
|
||||
// XXX is this the right place for this?
|
||||
setTransitionDuration($('.magazine'), DEFAULT_TRANSITION_DURATION)
|
||||
var n = getPageNumber(page)-1
|
||||
n = n < 0 ? 0 : n
|
||||
setCurrentPage(n)
|
||||
}
|
||||
|
||||
|
||||
function firstPage(){
|
||||
// XXX is this the right place for this?
|
||||
setTransitionDuration($('.magazine'), DEFAULT_TRANSITION_DURATION)
|
||||
setCurrentPage(0)
|
||||
}
|
||||
function lastPage(){
|
||||
// XXX is this the right place for this?
|
||||
setTransitionDuration($('.magazine'), DEFAULT_TRANSITION_DURATION)
|
||||
setCurrentPage(-1)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* vim:set ts=4 sw=4 : */
|
||||
|
||||
814
magazine.js
814
magazine.js
@ -55,6 +55,12 @@ var FULL_HISTORY_ENABLED = false
|
||||
// if true, use CSS3 transforms to scroll, of false, use left.
|
||||
var USE_TRANSFORM = true
|
||||
|
||||
var SCROLL_TIME = 400
|
||||
|
||||
var BOUNCE_LENGTH = 10
|
||||
var BOUNCE_TIME_DIVIDER = 5
|
||||
|
||||
|
||||
// list of css classes of pages that will not allow page fitting.
|
||||
var NO_RESIZE_CLASSES = [
|
||||
'no-resize',
|
||||
@ -119,20 +125,23 @@ var _PAGE_VIEW
|
||||
// - single page mode (.page-view-mode)
|
||||
// - thumbnail/ribbon mode
|
||||
var togglePageView = createCSSClassToggler(
|
||||
'.viewer',
|
||||
'.chrome',
|
||||
'page-view-mode',
|
||||
// post-change callback...
|
||||
function(action){
|
||||
if(action == 'on'){
|
||||
fitNPages(1, !FIT_PAGE_TO_VIEW)
|
||||
MagazineScroller.options.momentum = false
|
||||
_PAGE_VIEW = true
|
||||
} else {
|
||||
fitNPages(PAGES_IN_RIBBON)
|
||||
MagazineScroller.options.momentum = true
|
||||
_PAGE_VIEW = false
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
// this will simply update the current view...
|
||||
function updateView(){
|
||||
return togglePageView(togglePageView('?'))
|
||||
@ -142,6 +151,68 @@ function updateView(){
|
||||
|
||||
/********************************************************* helpers ***/
|
||||
|
||||
function centeredPageNumber(){
|
||||
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 centeredPage(){
|
||||
return $('.page').eq(centeredPageNumber())
|
||||
}
|
||||
|
||||
|
||||
function visiblePages(partial){
|
||||
var W = $('.viewer').width()
|
||||
var scale = getMagazineScale()
|
||||
|
||||
return $('.page').filter(function(_, page){
|
||||
page = $(page)
|
||||
|
||||
// XXX this calculates the offset from the document rather than the magazine...
|
||||
var o = page.offset().left
|
||||
|
||||
// page out of view (right)...
|
||||
if(o >= W){
|
||||
return false
|
||||
}
|
||||
|
||||
var w = page.width() * scale
|
||||
|
||||
if(o < 0){
|
||||
// partial left...
|
||||
if(partial && o + w > 0){
|
||||
return true
|
||||
}
|
||||
|
||||
// page out of view (left)...
|
||||
return false
|
||||
}
|
||||
|
||||
// partial right...
|
||||
if(partial && W - o < w){
|
||||
return true
|
||||
}
|
||||
|
||||
// page compleately in view...
|
||||
if(W - o >= w){
|
||||
return true
|
||||
}
|
||||
|
||||
// NOTE: we should not get here but just in case...
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function isPageResizable(page){
|
||||
if(page == null){
|
||||
page = $('.current.page')
|
||||
@ -223,35 +294,64 @@ function getMagazineTitle(){
|
||||
|
||||
|
||||
function getMagazineScale(){
|
||||
return getElementScale($('.scaler'))
|
||||
return getElementScale($('.magazine'))
|
||||
}
|
||||
function setPageScale(scale){
|
||||
return setElementTransform($('.scaler'), null, scale)
|
||||
function setMagazineScale(scale){
|
||||
var mag = $('.magazine')
|
||||
var cur = $('.current.page')
|
||||
if(cur.length == 0){
|
||||
cur = $('.page').first()
|
||||
}
|
||||
|
||||
// center-align ribbon view pages...
|
||||
var align = togglePageView('?') == 'off' ? 'center' : null
|
||||
var left = getMagazineOffset(cur, scale, align)
|
||||
|
||||
//setElementTransform(mag, left, scale)
|
||||
MagazineScroller.zoom(scale)
|
||||
|
||||
return mag
|
||||
}
|
||||
|
||||
|
||||
// NOTE: if page is not given get the current page number...
|
||||
function getPageNumber(page){
|
||||
if(page == null){
|
||||
page = $('.current.page')
|
||||
} else {
|
||||
// a page/element is given explicitly...
|
||||
if(page != null){
|
||||
page = $(page)
|
||||
if(!page.hasClass('page')){
|
||||
page = page.parents('.page')
|
||||
}
|
||||
return $('.page').index(page)
|
||||
}
|
||||
|
||||
// current page index...
|
||||
if(togglePageView('?') == 'on'){
|
||||
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 {
|
||||
return centeredPageNumber()
|
||||
}
|
||||
return $('.page').index(page)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// NOTE: negative values will yield results from the tail...
|
||||
function getPageAt(n){
|
||||
var page = $('.page')
|
||||
if(n < 0){
|
||||
n = page.length + n
|
||||
}
|
||||
return $(page[n])
|
||||
return $(page).eq(n)
|
||||
}
|
||||
|
||||
function shiftMagazineTo(offset){
|
||||
setElementTransform($('.magazine'), offset)
|
||||
MagazineScroller.scrollTo(offset, 0, 200)
|
||||
//setElementTransform($('.magazine'), offset)
|
||||
}
|
||||
|
||||
// XXX this is almost the same as getElementScale...
|
||||
@ -386,373 +486,374 @@ function viewResizeHandler(){
|
||||
}
|
||||
|
||||
|
||||
// swipe state handler
|
||||
// this handles single and double finger swipes and dragging
|
||||
// while draggign this triggers magazineDragging event on the viewer...
|
||||
// NOTE: this will trigger 'magazineDragging' event on the viewer on
|
||||
// each call while dragging...
|
||||
// XXX for some reason with finger count of 3 and greater, touchSwipe
|
||||
// dies on android...
|
||||
function makeSwipeHandler(){
|
||||
var pages
|
||||
var cur
|
||||
var n
|
||||
var scale
|
||||
var mag
|
||||
var pos
|
||||
var viewer = $('.viewer')
|
||||
|
||||
return function(evt, phase, direction, distance, duration, fingers){
|
||||
|
||||
if(phase == 'start'){
|
||||
// NOTE: this is used with the "unanimated" trick, we will make
|
||||
// dragging real-time...
|
||||
togglePageDragging('on')
|
||||
|
||||
// setup the data for the drag...
|
||||
pages = $('.page')
|
||||
cur = $('.current.page')
|
||||
n = pages.index(cur)
|
||||
scale = getMagazineScale()
|
||||
mag = $('.magazine')
|
||||
pos = $('.navigator .bar .indicator')
|
||||
|
||||
// XXX make this drag pages that are larger than view before dragging outside...
|
||||
} else if(phase=='move'
|
||||
// see if wee need to drag the page and allways drag the ribbon...
|
||||
&& (DRAG_FULL_PAGE || !_PAGE_VIEW)
|
||||
&& (direction=='left' || direction=='right')){
|
||||
if(direction == 'left'){
|
||||
shiftMagazineTo(-cur.position().left/scale - distance/scale)
|
||||
} else if(direction == 'right') {
|
||||
shiftMagazineTo(-cur.position().left/scale + distance/scale)
|
||||
}
|
||||
viewer.trigger('magazineDragging')
|
||||
|
||||
} else if(phase == 'cancel'){
|
||||
togglePageDragging('off')
|
||||
setCurrentPage()
|
||||
|
||||
} else if(phase =='end' ){
|
||||
togglePageDragging('off')
|
||||
// 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'){
|
||||
// 2 fingers moves to closest article...
|
||||
if(fingers == 2){
|
||||
prevArticle()
|
||||
// 3+ fingers moves to bookmark...
|
||||
} else if(fingers >= 3){
|
||||
prevBookmark()
|
||||
} else {
|
||||
setCurrentPage(Math.max(n-p, 0))
|
||||
}
|
||||
// next page...
|
||||
} else if(direction == 'left'){
|
||||
if(fingers == 2){
|
||||
nextArticle()
|
||||
} else if(fingers >= 3){
|
||||
nextBookmark()
|
||||
} else {
|
||||
setCurrentPage(Math.min(n+p, pages.length-1))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************** layout ***/
|
||||
|
||||
// mode can be:
|
||||
// - viewer
|
||||
// - content
|
||||
//
|
||||
// XXX should this calculate offset????
|
||||
function fitPagesTo(mode, cur, time, scale){
|
||||
mode = mode == null ? 'content' : mode
|
||||
cur = cur == null ? centeredPageNumber() : cur
|
||||
time = time == null ? 0 : time
|
||||
scale = scale == null ? getMagazineScale() : scale
|
||||
|
||||
// fit to content...
|
||||
if(mode == 'content'){
|
||||
var target_width = 'auto'
|
||||
var target_height = 'auto'
|
||||
|
||||
// fit to viewer...
|
||||
} else if(mode == 'viewer'){
|
||||
var viewer = $('.viewer')
|
||||
var W = viewer.width()
|
||||
var H = viewer.height()
|
||||
// XXX is this a good way to sample content size???
|
||||
var content = $('.content')
|
||||
var w = content.width()
|
||||
var h = content.height()
|
||||
|
||||
// need to calc width only...
|
||||
if(W/H > w/h){
|
||||
s = H/h
|
||||
w = W/s
|
||||
h = h
|
||||
|
||||
// need to calc height only...
|
||||
} else if(W/H > w/h){
|
||||
s = W/w
|
||||
h = H/s
|
||||
w = w
|
||||
|
||||
// set both width and height to defaults (content and page ratios match)...
|
||||
} else {
|
||||
s = W/h
|
||||
h = h
|
||||
w = w
|
||||
}
|
||||
var target_width = w
|
||||
var target_height = h
|
||||
|
||||
// bad mode...
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
var pages = $('.page')
|
||||
var offset = 0
|
||||
|
||||
$(RESIZABLE_PAGES)
|
||||
.each(function(_, e){
|
||||
var E = $(e)
|
||||
var w = target_width == 'auto' ? E.find('.content').width() : target_width
|
||||
var h = target_height == 'auto' ? E.find('.content').height() : target_height
|
||||
|
||||
// offset...
|
||||
if(pages.index(e) < cur){
|
||||
offset += (E.width() - w)
|
||||
}
|
||||
// offset half the current page...
|
||||
if(pages.index(e) == cur){
|
||||
// XXX to be more accurate we can use distance from page
|
||||
// center rather than 1/2...
|
||||
offset += ((E.width() - w)/2)
|
||||
}
|
||||
|
||||
if(time <= 0){
|
||||
e.style.width = w
|
||||
e.style.height = h
|
||||
} else {
|
||||
E.animate({
|
||||
width: w,
|
||||
height: h,
|
||||
}, time, 'linear')
|
||||
}
|
||||
})
|
||||
|
||||
//$(NON_RESIZABLE_PAGES).width('auto')
|
||||
$(NON_RESIZABLE_PAGES)
|
||||
.each(function(_, e){
|
||||
e.style.width = 'auto'
|
||||
})
|
||||
|
||||
MagazineScroller.scrollBy(offset*scale, 0, time)
|
||||
|
||||
setTimeout(function(){
|
||||
MagazineScroller.refresh()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
|
||||
// NOTE: if n is not given then it defaults to 1
|
||||
// NOTE: if n > 1 and fit_to_content is not given it defaults to true
|
||||
// NOTE: if n is 1 then fit_to_content bool argument controls wether:
|
||||
// - the page will be stretched to viewer (false)
|
||||
// - or to content (true)
|
||||
// XXX need to align/focus the corrent page...
|
||||
// case:
|
||||
// when current page is pushed off center by a resized page...
|
||||
function fitNPages(n, fit_to_content){
|
||||
if(n == null){
|
||||
n = 1
|
||||
}
|
||||
if(n > 1 && fit_to_content == null){
|
||||
fit_to_content = true
|
||||
}
|
||||
var view = $('.viewer')
|
||||
if(USE_REAL_PAGE_SIZES){
|
||||
var page = $(RESIZABLE_PAGES)
|
||||
} else {
|
||||
var page = $('.page')
|
||||
}
|
||||
var content = $('.content')
|
||||
var cur = $('.current.page')
|
||||
|
||||
var W = view.width()
|
||||
var H = view.height()
|
||||
var cW = content.width()
|
||||
var cH = content.height()
|
||||
|
||||
// to compensate for transitions, no data sampling should be beyound
|
||||
// this point, as we will start changing things next...
|
||||
|
||||
n = n == null ? 1 : n
|
||||
var scale = getPageTargetScale(n, fit_to_content)
|
||||
// cache some data...
|
||||
var target_width = scale.width
|
||||
var target_height = scale.height
|
||||
var rW = scale.result_width
|
||||
|
||||
// NOTE: we need to calculate the offset as the actual widths during
|
||||
// the animation are not correct... so just looking at .position()
|
||||
// will be counterproductive...
|
||||
if(!USE_REAL_PAGE_SIZES && fit_to_content){
|
||||
var offset = rW * getPageNumber()-1
|
||||
if(n == 1){
|
||||
fitPagesTo('viewer')
|
||||
} else {
|
||||
// calculate the target offset...
|
||||
if(USE_REAL_PAGE_SIZES){
|
||||
var rpages = $(RESIZABLE_PAGES+', .current.page')
|
||||
} else {
|
||||
var rpages = page
|
||||
}
|
||||
var i = rpages.index(cur)
|
||||
var offset = rW * i-1
|
||||
// now do the no-resize elements...
|
||||
if(USE_REAL_PAGE_SIZES){
|
||||
var nrpages = $(NON_RESIZABLE_PAGES+', .current.page')
|
||||
i = nrpages.index(cur)
|
||||
nrpages.splice(i)
|
||||
nrpages.each(function(_, e){
|
||||
offset += $(e).children('.content').width()
|
||||
})
|
||||
}
|
||||
fitPagesTo('content')
|
||||
}
|
||||
|
||||
// align the magazine...
|
||||
if(USE_REAL_PAGE_SIZES){
|
||||
if(!isPageResizable(cur)){
|
||||
var align = getPageAlign(cur)
|
||||
|
||||
// center align if explicitly required or if we are in a ribbon...
|
||||
if(n > 1 || align == 'center'){
|
||||
rW = cur.children('.content').width()
|
||||
|
||||
// align left...
|
||||
} else if(align == 'left'){
|
||||
rW = $('.viewer').width()/scale
|
||||
|
||||
// align right...
|
||||
} else if(align == 'right'){
|
||||
var v = $('.viewer')
|
||||
rW = (v.width()/scale/2 - (v.width()/scale-cur.width()))*2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now do the actual modification...
|
||||
|
||||
// do the scaling...
|
||||
setElementScale($('.scaler'), scale)
|
||||
|
||||
// XXX for some reason setting size "auto" will first shrink the whole
|
||||
// page to 0 and then instantly set it to the correct size...
|
||||
//page
|
||||
// .width(target_width)
|
||||
// .height(target_height)
|
||||
//if(USE_REAL_PAGE_SIZES){
|
||||
// $(NON_RESIZABLE_PAGES).width('auto')
|
||||
//}
|
||||
|
||||
// NOTE: we only need the .scaler animated, the rest just plays havoc with
|
||||
// the transition...
|
||||
// XXX this still jumps to offset on left/right aligned pages but 1) on
|
||||
// fast transitions it is not noticable and 2) it is way better than
|
||||
// the effect that was before...
|
||||
unanimated($('.page, .content, .magazine'), function(){
|
||||
// NOTE: this is not done directly as to avoid artifacts asociated with
|
||||
// setting 'auto' to all the elements, which makes them first slowly
|
||||
// shrink down to 0 and then appear correctly sized in an instant.
|
||||
page.each(function(_, e){
|
||||
if(target_width == 'auto'){
|
||||
e.style.width = $(e).find('.content').width()
|
||||
e.style.height = $(e).find('.content').height()
|
||||
} else {
|
||||
e.style.width = target_width
|
||||
e.style.height = target_height
|
||||
}
|
||||
})
|
||||
if(USE_REAL_PAGE_SIZES){
|
||||
//$(NON_RESIZABLE_PAGES).width('auto')
|
||||
$(NON_RESIZABLE_PAGES).each(function(_, e){
|
||||
e.style.width = 'auto'
|
||||
})
|
||||
}
|
||||
// fix position...
|
||||
setCurrentPage(null, offset, rW)
|
||||
}, 200)()
|
||||
MagazineScroller.zoom(scale)
|
||||
MagazineScroller.refresh()
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************* actions ***/
|
||||
|
||||
// NOTE: "width" is used ONLY to center the page.
|
||||
// NOTE: if n is not given it will be set to current page number
|
||||
// NOTE: if width is not given it will be set to current page width.
|
||||
// NOTE: n can be:
|
||||
// - page number
|
||||
// - page element
|
||||
// NOTE: this will fire a 'pageChanged(n)' event on the viewer each time
|
||||
// it is called...
|
||||
// NOTE: this now supports negative indexes to count pages from the end...
|
||||
function setCurrentPage(n, offset, width){
|
||||
var page = $('.page')
|
||||
// setup n and cur...
|
||||
// no n is given, do the defaultdance
|
||||
if(n == null){
|
||||
var cur = $('.current.page')
|
||||
// no current page...
|
||||
// try to land on the magazine cover...
|
||||
if(cur.length == 0){
|
||||
cur = $('.magazine > .cover')
|
||||
}
|
||||
// try the first cover...
|
||||
if(cur.length == 0){
|
||||
cur = $('.cover.page')
|
||||
}
|
||||
// try first page...
|
||||
if(cur.length == 0){
|
||||
cur = page.first()
|
||||
}
|
||||
// no pages to work with...
|
||||
if(cur.length == 0){
|
||||
return
|
||||
}
|
||||
n = page.index(cur)
|
||||
// Set the .current class...
|
||||
//
|
||||
// page can be:
|
||||
// - null - centered page in view
|
||||
// - number - page number/index
|
||||
// - page - a page element
|
||||
// - elem - resolves to a containing page element
|
||||
function setCurrent(page){
|
||||
var pages = $('.page')
|
||||
page = page == null ? pages.eq(centeredPageNumber())
|
||||
: typeof(page) == typeof(123) ? pages.eq(Math.max(0, Math.min(page, pages.length-1)))
|
||||
: !$(page).eq(0).hasClass('page') ? $(page).eq(0).parents('.page').eq(0)
|
||||
: $(page).eq(0)
|
||||
|
||||
// n is a number...
|
||||
} else if(typeof(n) == typeof(1)) {
|
||||
// normalize n...
|
||||
if(n >= page.length){
|
||||
n = page.length-1
|
||||
} else if(-n > page.length){
|
||||
n = 0
|
||||
}
|
||||
var cur = getPageAt(n)
|
||||
|
||||
// n is an element, likely...
|
||||
} else {
|
||||
var cur = $(n)
|
||||
n = $('.page').index(cur)
|
||||
//n = page.index(cur)
|
||||
}
|
||||
|
||||
// default width...
|
||||
if(width == null){
|
||||
width = cur.width()
|
||||
if(USE_REAL_PAGE_SIZES && togglePageView('?') == 'on'){
|
||||
var align = getPageAlign(cur)
|
||||
var scale = getMagazineScale()
|
||||
if(align == 'center'){
|
||||
width = cur.width()
|
||||
|
||||
} else if(align == 'left'){
|
||||
width = $('.viewer').width()/scale
|
||||
|
||||
} else if(align == 'right'){
|
||||
var v = $('.viewer')
|
||||
width = (v.width()/scale/2 - (v.width()/scale-cur.width()))*2
|
||||
}
|
||||
}
|
||||
if(page.hasClass('current')){
|
||||
return page
|
||||
}
|
||||
|
||||
// set the class...
|
||||
$('.current.page').removeClass('current')
|
||||
cur.addClass('current')
|
||||
|
||||
// NOTE: this will be wrong during a transition, that's why we
|
||||
// can pass the pre-calculated offset as an argument...
|
||||
shiftMagazineTo(-(offset == null ?
|
||||
cur.position()['left']/getMagazineScale()
|
||||
: offset))
|
||||
|
||||
// center the pages correctly...
|
||||
// NOTE: this is the main reason we need width, and we can get it
|
||||
// pre-calculated because of ongoing transitions make it
|
||||
// pointless to read it...
|
||||
$('.magazine').css({
|
||||
'margin-left': -width/2
|
||||
})
|
||||
|
||||
$('.viewer').trigger('pageChanged', n)
|
||||
|
||||
return cur
|
||||
return page.addClass('current')
|
||||
}
|
||||
|
||||
|
||||
function goToMagazineCover(){
|
||||
return setCurrentPage(0)
|
||||
// Focus a page...
|
||||
//
|
||||
// NOTE: n is a setCurrent(..) compatible value...
|
||||
// NOTE: if n is out of bounds (n < 0 | n >= length) this will focus the
|
||||
// first/last page and bounce...
|
||||
function focusPage(n, align, time){
|
||||
// XXX the default needs to depend on the scale...
|
||||
align = align == null ? 'auto' : align
|
||||
time = time == null ? SCROLL_TIME : time
|
||||
|
||||
var page = setCurrent(n)
|
||||
var pages = $('.page')
|
||||
|
||||
align = align == 'auto' ? getPageAlign(page) : align
|
||||
|
||||
// magazine offset...
|
||||
var m = page.position().left
|
||||
// base value for 'left' align...
|
||||
var o = 0
|
||||
|
||||
var w = page.width() * getMagazineScale()
|
||||
var W = $('.viewer').width()
|
||||
|
||||
if(align != 'left'){
|
||||
|
||||
// right...
|
||||
if(align == 'right'){
|
||||
o = W - w
|
||||
|
||||
// center / default...
|
||||
} else {
|
||||
o = W/2 - w/2
|
||||
}
|
||||
}
|
||||
|
||||
// compensate for first/last page align to screen (optional???)...
|
||||
var offset = page.offset().left
|
||||
var f = pages.first().offset().left
|
||||
if(f + o - offset >= 0){
|
||||
o = 0
|
||||
m = 0
|
||||
}
|
||||
var last = $('.page').last()
|
||||
var l = last.offset().left
|
||||
if(l + o - offset <= W - w){
|
||||
o = 0
|
||||
m = last.position().left + last.width()*getMagazineScale() - W
|
||||
}
|
||||
|
||||
// do the bounce...
|
||||
if(time > 0){
|
||||
var i = pages.index(page)
|
||||
var l = pages.length
|
||||
if(n < 0){
|
||||
o += BOUNCE_LENGTH*getMagazineScale()
|
||||
time /= BOUNCE_TIME_DIVIDER
|
||||
}
|
||||
if(n >= l){
|
||||
o -= BOUNCE_LENGTH*getMagazineScale()
|
||||
time /= BOUNCE_TIME_DIVIDER
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this does not care about the zoom...
|
||||
MagazineScroller.scrollTo(-m + o, 0, time)
|
||||
|
||||
return page
|
||||
}
|
||||
function goToMagazineEnd(){
|
||||
return setCurrentPage(-1)
|
||||
|
||||
|
||||
// Focus first/last page...
|
||||
//
|
||||
// NOTE: if we are already at the first/last page, do a bounce...
|
||||
function first(align){
|
||||
// visually show that we are at the start...
|
||||
if($('.magazine').offset().left >= 0){
|
||||
return focusPage(-1, align)
|
||||
}
|
||||
return focusPage(0, align)
|
||||
}
|
||||
function goToArticleCover(){
|
||||
// try and get the actual first cover...
|
||||
var cover = $('.current.page')
|
||||
.parents('.article')
|
||||
.find('.cover.page')
|
||||
.first()
|
||||
if(cover.length == 0){
|
||||
// no cover, get the first page...
|
||||
return setCurrentPage(
|
||||
$('.current.page')
|
||||
.parents('.article')
|
||||
.find('.page')
|
||||
.first())
|
||||
function last(align){
|
||||
var mag = $('.magazine')
|
||||
var l = mag.offset().left
|
||||
var end = mag.offset().left + mag.width()*getMagazineScale()
|
||||
var i = $('.page').length-1
|
||||
|
||||
if(end <= $('.viewer').width()+1){
|
||||
return focusPage(i+1, align)
|
||||
}
|
||||
return focusPage(i, align)
|
||||
}
|
||||
|
||||
|
||||
// Focus a page of class cls adjacent to current in direction...
|
||||
//
|
||||
// direction can be:
|
||||
// - 'next' - next page
|
||||
// - 'prev' - previous page
|
||||
//
|
||||
// If cls is not given, then all pages (.page) are considered.
|
||||
//
|
||||
// NOTE: if we are already at the first/last page and direction is
|
||||
// prev/next resp. then do a bounce...
|
||||
function step(direction, cls, align){
|
||||
cls = cls == null ? '' : cls
|
||||
|
||||
var page = visiblePages(true).filter('.current').eq(0)
|
||||
var pages = $('.page')
|
||||
|
||||
if(page.length == 0){
|
||||
page = setCurrent()
|
||||
}
|
||||
|
||||
var i = pages.index(page)
|
||||
var l = pages.length
|
||||
|
||||
// if we are at the first/last page do the bounce dance...
|
||||
// bounce first...
|
||||
if(i == 0 && direction == 'prev'){
|
||||
return focusPage(-1, align)
|
||||
}
|
||||
|
||||
// bounce last...
|
||||
if(i == l-1 && direction == 'next'){
|
||||
return focusPage(l, align)
|
||||
}
|
||||
|
||||
var to = page[direction+'All']('.page'+cls)
|
||||
|
||||
// if we have no pages on the same level, to a deeper search...
|
||||
if(to.length == 0){
|
||||
if(direction == 'next'){
|
||||
to = pages.slice(i+1).filter('.page'+cls).first()
|
||||
} else {
|
||||
to = pages.slice(0, i).filter('.page'+cls).last()
|
||||
}
|
||||
}
|
||||
|
||||
// still no candidates, then we can't do a thing...
|
||||
if(to.length == 0){
|
||||
to = page
|
||||
}
|
||||
|
||||
return focusPage(to.eq(0), align)
|
||||
}
|
||||
|
||||
|
||||
// Focus next/prev page shorthands...
|
||||
//
|
||||
function nextPage(cls, align){ return step('next', cls, align) }
|
||||
function prevPage(cls, align){ return step('prev', cls, align) }
|
||||
|
||||
|
||||
// Focus next/prev cover page shorthands...
|
||||
//
|
||||
function nextCover(cls, align){
|
||||
cls = cls == null ? '' : cls
|
||||
return step('next', '.cover'+cls, align)
|
||||
}
|
||||
function prevCover(cls, align){
|
||||
cls = cls == null ? '' : cls
|
||||
return step('prev', '.cover'+cls, align)
|
||||
}
|
||||
|
||||
|
||||
// Move the view a screen width (.viewer) left/right...
|
||||
//
|
||||
// NOTE: if we are at magazine start/end and try to move left/right resp.
|
||||
// this will do a bounce...
|
||||
function nextScreen(time){
|
||||
time = time == null ? SCROLL_TIME : time
|
||||
var W = $('.viewer').width()
|
||||
var mag = $('.magazine')
|
||||
var o = mag.position().left
|
||||
var w = mag.width()*getMagazineScale()
|
||||
|
||||
// we reached the end...
|
||||
if(w + o < 2*W){
|
||||
// NOTE: we use focusPage(..) to handle stuff like bounces...
|
||||
return focusPage($('.page').length)
|
||||
}
|
||||
|
||||
MagazineScroller.scrollTo(o-W, 0, time)
|
||||
return setCurrent()
|
||||
}
|
||||
function prevScreen(time){
|
||||
time = time == null ? SCROLL_TIME : time
|
||||
var W = $('.viewer').width()
|
||||
var o = $('.magazine').position().left
|
||||
|
||||
// we reached the start...
|
||||
if(-o < W){
|
||||
// NOTE: we use focusPage(..) to handle stuff like bounces...
|
||||
return focusPage(-1)
|
||||
}
|
||||
|
||||
MagazineScroller.scrollTo(o+W, 0, time)
|
||||
return setCurrent()
|
||||
}
|
||||
|
||||
|
||||
// Mode-aware next/prev high-level actions...
|
||||
//
|
||||
// Supported modes:
|
||||
// - page view - focus next/prev page
|
||||
// - magazine view - view next/prev screen
|
||||
//
|
||||
function next(){
|
||||
if(togglePageView('?') == 'on'){
|
||||
return nextPage()
|
||||
} else {
|
||||
return setCurrentPage(cover)
|
||||
return nextScreen()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function nextPage(){
|
||||
var pages = $('.page')
|
||||
var cur = $('.current.page')
|
||||
return setCurrentPage(Math.min(pages.index(cur)+1, pages.length-1))
|
||||
}
|
||||
function prevPage(){
|
||||
var pages = $('.page')
|
||||
var cur = $('.current.page')
|
||||
return setCurrentPage(Math.max(pages.index(cur)-1, 0))
|
||||
}
|
||||
|
||||
|
||||
function nextArticle(){
|
||||
var cur = $('.current.page').parents('.article')
|
||||
// we are at the magazine cover...
|
||||
if(cur.length == 0){
|
||||
return setCurrentPage(
|
||||
$('.magazine .article .page:first-child').first())
|
||||
function prev(){
|
||||
if(togglePageView('?') == 'on'){
|
||||
return prevPage()
|
||||
} else {
|
||||
return prevScreen()
|
||||
}
|
||||
// just find the next one...
|
||||
var articles = $('.magazine .article')
|
||||
return setCurrentPage(
|
||||
$(articles[Math.min(articles.index(cur)+1, articles.length-1)])
|
||||
.find('.page')
|
||||
.first())
|
||||
}
|
||||
function prevArticle(){
|
||||
var cur = $('.current.page').parents('.article')
|
||||
// we are at the magazine cover...
|
||||
if(cur.length == 0){
|
||||
//return $('.current.page')
|
||||
return setCurrentPage()
|
||||
}
|
||||
// just find the prev one...
|
||||
var articles = $('.magazine .article')
|
||||
return setCurrentPage(
|
||||
$(articles[Math.max(articles.index(cur)-1, 0)])
|
||||
.find('.page')
|
||||
.first())
|
||||
}
|
||||
|
||||
|
||||
@ -809,6 +910,7 @@ function clearBookmarks(){
|
||||
// NOTE: this will trigger the folowing events on the viewer:
|
||||
// - bookmarkAdded(n)
|
||||
// - bookmarkRemoved(n)
|
||||
// XXX rewrite...
|
||||
function toggleBookmark(n){
|
||||
if(n == null){
|
||||
n = getPageNumber()
|
||||
@ -841,21 +943,13 @@ function toggleBookmark(n){
|
||||
return res
|
||||
}
|
||||
|
||||
function nextBookmark(){
|
||||
var pages = $('.page')
|
||||
pages = $(pages.splice(getPageNumber()+1))
|
||||
page = pages.children('.bookmark').first().parents('.page')
|
||||
if(page.length != 0){
|
||||
return setCurrentPage(page)
|
||||
}
|
||||
function nextBookmark(cls, align){
|
||||
cls = cls == null ? '' : cls
|
||||
return step('next', '.bookmark'+cls, align)
|
||||
}
|
||||
function prevBookmark(){
|
||||
var pages = $('.page')
|
||||
pages.splice(getPageNumber())
|
||||
page = pages.children('.bookmark').last().parents('.page')
|
||||
if(page.length != 0){
|
||||
return setCurrentPage(page)
|
||||
}
|
||||
function prevBookmark(cls, align){
|
||||
cls = cls == null ? '' : cls
|
||||
return step('prev', '.bookmark'+cls, align)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user