mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
3632 lines
89 KiB
JavaScript
3632 lines
89 KiB
JavaScript
Monocle = {
|
|
VERSION: "2.0.0"
|
|
};
|
|
|
|
|
|
Monocle.pieceLoaded = function (piece) {
|
|
if (typeof onMonoclePiece == 'function') {
|
|
onMonoclePiece(piece);
|
|
}
|
|
}
|
|
|
|
|
|
Monocle.defer = function (fn, time) {
|
|
if (fn && typeof fn == "function") {
|
|
return setTimeout(fn, time || 0);
|
|
}
|
|
}
|
|
|
|
|
|
Monocle.Browser = { engine: 'W3C' }
|
|
|
|
Monocle.Browser.is = {
|
|
IE: (!!(window.attachEvent && navigator.userAgent.indexOf('Opera') === -1)) &&
|
|
(Monocle.Browser.engine = "IE"),
|
|
Opera: navigator.userAgent.indexOf('Opera') > -1 &&
|
|
(Monocle.Browser.engine = "Opera"),
|
|
WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1 &&
|
|
(Monocle.Browser.engine = "WebKit"),
|
|
Gecko: navigator.userAgent.indexOf('Gecko') > -1 &&
|
|
navigator.userAgent.indexOf('KHTML') === -1 &&
|
|
(Monocle.Browser.engine = "Gecko"),
|
|
MobileSafari: !!navigator.userAgent.match(/AppleWebKit.*Mobile/)
|
|
} // ... with thanks to PrototypeJS.
|
|
|
|
|
|
Monocle.Browser.on = {
|
|
iPhone: navigator.userAgent.indexOf("iPhone") != -1,
|
|
iPad: navigator.userAgent.indexOf("iPad") != -1,
|
|
BlackBerry: navigator.userAgent.indexOf("BlackBerry") != -1,
|
|
Android: navigator.userAgent.indexOf('Android') != -1,
|
|
MacOSX: navigator.userAgent.indexOf('Mac OS X') != -1,
|
|
Kindle3: navigator.userAgent.match(/Kindle\/3/)
|
|
}
|
|
|
|
|
|
if (Monocle.Browser.is.MobileSafari) {
|
|
(function () {
|
|
var ver = navigator.userAgent.match(/ OS ([\d_]+)/);
|
|
if (ver) {
|
|
Monocle.Browser.iOSVersion = ver[1].replace(/_/g, '.');
|
|
} else {
|
|
console.warn("Unknown MobileSafari user agent: "+navigator.userAgent);
|
|
}
|
|
})();
|
|
}
|
|
Monocle.Browser.iOSVersionBelow = function (strOrNum) {
|
|
return Monocle.Browser.iOSVersion && Monocle.Browser.iOSVersion < strOrNum;
|
|
}
|
|
|
|
|
|
Monocle.Browser.CSSProps = {
|
|
engines: ["W3C", "WebKit", "Gecko", "Opera", "IE", "Konqueror"],
|
|
prefixes: ["", "-webkit-", "-moz-", "-o-", "-ms-", "-khtml-"],
|
|
domprefixes: ["", "Webkit", "Moz", "O", "ms", "Khtml"],
|
|
guineapig: document.createElement('div')
|
|
}
|
|
|
|
|
|
Monocle.Browser.CSSProps.capStr = function (wd) {
|
|
return wd ? wd.charAt(0).toUpperCase() + wd.substr(1) : "";
|
|
}
|
|
|
|
|
|
Monocle.Browser.CSSProps.toDOMProps = function (prop, prefix) {
|
|
var parts = prop.split('-');
|
|
for (var i = parts.length; i > 0; --i) {
|
|
parts[i] = Monocle.Browser.CSSProps.capStr(parts[i]);
|
|
}
|
|
|
|
if (typeof(prefix) != 'undefined' && prefix != null) {
|
|
if (prefix) {
|
|
parts[0] = Monocle.Browser.CSSProps.capStr(parts[0]);
|
|
return prefix+parts.join('');
|
|
} else {
|
|
return parts.join('');
|
|
}
|
|
}
|
|
|
|
var props = [parts.join('')];
|
|
parts[0] = Monocle.Browser.CSSProps.capStr(parts[0]);
|
|
for (i = 0; i < Monocle.Browser.CSSProps.prefixes.length; ++i) {
|
|
var pf = Monocle.Browser.CSSProps.domprefixes[i];
|
|
if (!pf) { continue; }
|
|
props.push(pf+parts.join(''));
|
|
}
|
|
return props;
|
|
}
|
|
|
|
|
|
Monocle.Browser.CSSProps.toDOMProp = function (prop) {
|
|
return Monocle.Browser.CSSProps.toDOMProps(
|
|
prop,
|
|
Monocle.Browser.CSSProps.domprefixes[
|
|
Monocle.Browser.CSSProps.engines.indexOf(Monocle.Browser.engine)
|
|
]
|
|
);
|
|
}
|
|
|
|
|
|
Monocle.Browser.CSSProps.isSupported = function (props) {
|
|
for (var i in props) {
|
|
if (Monocle.Browser.CSSProps.guineapig.style[props[i]] !== undefined) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
} // Thanks modernizr!
|
|
|
|
|
|
Monocle.Browser.CSSProps.isSupportedForAnyPrefix = function (prop) {
|
|
return Monocle.Browser.CSSProps.isSupported(
|
|
Monocle.Browser.CSSProps.toDOMProps(prop)
|
|
);
|
|
}
|
|
|
|
|
|
Monocle.Browser.CSSProps.supportsMediaQuery = function (query) {
|
|
var gpid = "monocle_guineapig";
|
|
var div = Monocle.Browser.CSSProps.guineapig;
|
|
div.id = gpid;
|
|
var st = document.createElement('style');
|
|
st.textContent = query+'{#'+gpid+'{height:3px}}';
|
|
(document.head || document.getElementsByTagName('head')[0]).appendChild(st);
|
|
document.documentElement.appendChild(div);
|
|
|
|
var result = Monocle.Browser.CSSProps.guineapig.offsetHeight === 3;
|
|
|
|
st.parentNode.removeChild(st);
|
|
div.parentNode.removeChild(div);
|
|
|
|
return result;
|
|
} // Thanks modernizr!
|
|
|
|
|
|
Monocle.Browser.CSSProps.supportsMediaQueryProperty = function (prop) {
|
|
return Monocle.Browser.CSSProps.supportsMediaQuery(
|
|
'@media ('+Monocle.Browser.CSSProps.prefixes.join(prop+'),(')+'monocle__)'
|
|
);
|
|
}
|
|
|
|
|
|
|
|
Monocle.Browser.has = {}
|
|
Monocle.Browser.has.touch = ('ontouchstart' in window) ||
|
|
Monocle.Browser.CSSProps.supportsMediaQueryProperty('touch-enabled');
|
|
Monocle.Browser.has.columns = Monocle.Browser.CSSProps.isSupportedForAnyPrefix(
|
|
'column-width'
|
|
);
|
|
Monocle.Browser.has.transform3d = Monocle.Browser.CSSProps.isSupported([
|
|
'perspectiveProperty',
|
|
'WebkitPerspective',
|
|
'MozPerspective',
|
|
'OPerspective',
|
|
'msPerspective'
|
|
]) && Monocle.Browser.CSSProps.supportsMediaQueryProperty('transform-3d');
|
|
Monocle.Browser.has.embedded = (top != self);
|
|
|
|
Monocle.Browser.has.iframeTouchBug = Monocle.Browser.iOSVersionBelow("4.2");
|
|
|
|
Monocle.Browser.has.selectThruBug = Monocle.Browser.iOSVersionBelow("4.2");
|
|
|
|
Monocle.Browser.has.mustScrollSheaf = Monocle.Browser.is.MobileSafari;
|
|
Monocle.Browser.has.iframeDoubleWidthBug =
|
|
Monocle.Browser.has.mustScrollSheaf || Monocle.Browser.on.Kindle3;
|
|
|
|
Monocle.Browser.has.floatColumnBug = Monocle.Browser.is.WebKit;
|
|
|
|
Monocle.Browser.has.relativeIframeWidthBug = Monocle.Browser.on.Android;
|
|
|
|
|
|
Monocle.Browser.has.jumpFlickerBug =
|
|
Monocle.Browser.on.MacOSX && Monocle.Browser.is.WebKit;
|
|
|
|
|
|
Monocle.Browser.has.columnOverflowPaintBug = Monocle.Browser.is.WebKit &&
|
|
!Monocle.Browser.is.MobileSafari &&
|
|
navigator.userAgent.indexOf("AppleWebKit/534") > 0;
|
|
|
|
|
|
if (typeof window.console == "undefined") {
|
|
window.console = {
|
|
messages: [],
|
|
log: function (msg) {
|
|
this.messages.push(msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
window.console.compatDir = function (obj) {
|
|
var stringify = function (o) {
|
|
var parts = [];
|
|
for (x in o) {
|
|
parts.push(x + ": " + o[x]);
|
|
}
|
|
return parts.join("; ");
|
|
}
|
|
|
|
window.console.log(stringify(obj));
|
|
}
|
|
|
|
|
|
if (!Array.prototype.indexOf) {
|
|
Array.prototype.indexOf = function(elt /*, from*/) {
|
|
var len = this.length >>> 0;
|
|
|
|
var from = Number(arguments[1]) || 0;
|
|
from = (from < 0)
|
|
? Math.ceil(from)
|
|
: Math.floor(from);
|
|
if (from < 0) {
|
|
from += len;
|
|
}
|
|
|
|
for (; from < len; from++) {
|
|
if (from in this && this[from] === elt) {
|
|
return from;
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
}
|
|
|
|
|
|
Monocle.pieceLoaded('compat');
|
|
Monocle.Factory = function (element, label, index, reader) {
|
|
|
|
var API = { constructor: Monocle.Factory };
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
element: element,
|
|
label: label,
|
|
index: index,
|
|
reader: reader,
|
|
prefix: reader.properties.classPrefix || ''
|
|
}
|
|
|
|
|
|
function initialize() {
|
|
if (!p.label) { return; }
|
|
var node = p.reader.properties.graph;
|
|
node[p.label] = node[p.label] || [];
|
|
if (typeof p.index == 'undefined' && node[p.label][p.index]) {
|
|
throw('Element already exists in graph: '+p.label+'['+p.index+']');
|
|
} else {
|
|
p.index = p.index || node[p.label].length;
|
|
}
|
|
node[p.label][p.index] = p.element;
|
|
|
|
addClass(p.label);
|
|
}
|
|
|
|
|
|
function find(oLabel, oIndex) {
|
|
if (!p.reader.properties.graph[oLabel]) {
|
|
return null;
|
|
}
|
|
return p.reader.properties.graph[oLabel][oIndex || 0];
|
|
}
|
|
|
|
|
|
function claim(oElement, oLabel, oIndex) {
|
|
return oElement.dom = new Monocle.Factory(
|
|
oElement,
|
|
oLabel,
|
|
oIndex,
|
|
p.reader
|
|
);
|
|
}
|
|
|
|
|
|
function make(tagName, oLabel, index_or_options, or_options) {
|
|
var oIndex, options;
|
|
if (arguments.length == 1) {
|
|
oLabel = null,
|
|
oIndex = 0;
|
|
options = {};
|
|
} else if (arguments.length == 2) {
|
|
oIndex = 0;
|
|
options = {};
|
|
} else if (arguments.length == 4) {
|
|
oIndex = arguments[2];
|
|
options = arguments[3];
|
|
} else if (arguments.length == 3) {
|
|
var lastArg = arguments[arguments.length - 1];
|
|
if (typeof lastArg == "number") {
|
|
oIndex = lastArg;
|
|
options = {};
|
|
} else {
|
|
oIndex = 0;
|
|
options = lastArg;
|
|
}
|
|
}
|
|
|
|
var oElement = document.createElement(tagName);
|
|
claim(oElement, oLabel, oIndex);
|
|
if (options['class']) {
|
|
oElement.className += " "+p.prefix+options['class'];
|
|
}
|
|
if (options['html']) {
|
|
oElement.innerHTML = options['html'];
|
|
}
|
|
if (options['text']) {
|
|
oElement.appendChild(document.createTextNode(options['text']));
|
|
}
|
|
|
|
return oElement;
|
|
}
|
|
|
|
|
|
function append(tagName, oLabel, index_or_options, or_options) {
|
|
var oElement = make.apply(this, arguments);
|
|
p.element.appendChild(oElement);
|
|
return oElement;
|
|
}
|
|
|
|
|
|
function address() {
|
|
return [p.label, p.index, p.reader];
|
|
}
|
|
|
|
|
|
function setStyles(rules) {
|
|
return Monocle.Styles.applyRules(p.element, rules);
|
|
}
|
|
|
|
|
|
function setBetaStyle(property, value) {
|
|
return Monocle.Styles.affix(p.element, property, value);
|
|
}
|
|
|
|
|
|
|
|
function hasClass(name) {
|
|
name = p.prefix + name;
|
|
var klass = p.element.className;
|
|
if (!klass) { return false; }
|
|
if (klass == name) { return true; }
|
|
return new RegExp("(^|\\s)"+name+"(\\s|$)").test(klass);
|
|
}
|
|
|
|
|
|
function addClass(name) {
|
|
if (hasClass(name)) { return; }
|
|
var gap = p.element.className ? ' ' : '';
|
|
return p.element.className += gap+p.prefix+name;
|
|
}
|
|
|
|
|
|
function removeClass(name) {
|
|
var reName = new RegExp("(^|\\s+)"+p.prefix+name+"(\\s+|$)");
|
|
var reTrim = /^\s+|\s+$/g;
|
|
var klass = p.element.className;
|
|
p.element.className = klass.replace(reName, ' ').replace(reTrim, '');
|
|
return p.element.className;
|
|
}
|
|
|
|
|
|
API.find = find;
|
|
API.claim = claim;
|
|
API.make = make;
|
|
API.append = append;
|
|
API.address = address;
|
|
|
|
API.setStyles = setStyles;
|
|
API.setBetaStyle = setBetaStyle;
|
|
API.hasClass = hasClass;
|
|
API.addClass = addClass;
|
|
API.removeClass = removeClass;
|
|
|
|
initialize();
|
|
|
|
return API;
|
|
}
|
|
|
|
Monocle.pieceLoaded('factory');
|
|
Monocle.Events = {}
|
|
|
|
|
|
Monocle.Events.dispatch = function (elem, evtType, data, cancelable) {
|
|
if (!document.createEvent) {
|
|
return true;
|
|
}
|
|
var evt = document.createEvent("Events");
|
|
evt.initEvent(evtType, false, cancelable || false);
|
|
evt.m = data;
|
|
try {
|
|
return elem.dispatchEvent(evt);
|
|
} catch(e) {
|
|
console.warn("Failed to dispatch event: "+evtType);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
Monocle.Events.listen = function (elem, evtType, fn, useCapture) {
|
|
if (elem.addEventListener) {
|
|
return elem.addEventListener(evtType, fn, useCapture || false);
|
|
} else if (elem.attachEvent) {
|
|
return elem.attachEvent('on'+evtType, fn);
|
|
}
|
|
}
|
|
|
|
|
|
Monocle.Events.deafen = function (elem, evtType, fn, useCapture) {
|
|
if (elem.removeEventListener) {
|
|
return elem.removeEventListener(evtType, fn, useCapture || false);
|
|
} else if (elem.detachEvent) {
|
|
try {
|
|
return elem.detachEvent('on'+evtType, fn);
|
|
} catch(e) {}
|
|
}
|
|
}
|
|
|
|
|
|
Monocle.Events.listenForContact = function (elem, fns, options) {
|
|
var listeners = {};
|
|
|
|
var cursorInfo = function (evt, ci) {
|
|
evt.m = {
|
|
pageX: ci.pageX,
|
|
pageY: ci.pageY
|
|
};
|
|
|
|
var target = evt.target || evt.srcElement;
|
|
while (target.nodeType != 1 && target.parentNode) {
|
|
target = target.parentNode;
|
|
}
|
|
|
|
var offset = offsetFor(evt, target);
|
|
evt.m.offsetX = offset[0];
|
|
evt.m.offsetY = offset[1];
|
|
|
|
if (evt.currentTarget) {
|
|
offset = offsetFor(evt, evt.currentTarget);
|
|
evt.m.registrantX = offset[0];
|
|
evt.m.registrantY = offset[1];
|
|
}
|
|
|
|
return evt;
|
|
}
|
|
|
|
|
|
var offsetFor = function (evt, elem) {
|
|
var r;
|
|
if (elem.getBoundingClientRect) {
|
|
var er = elem.getBoundingClientRect();
|
|
var dr = document.body.getBoundingClientRect();
|
|
r = { left: er.left - dr.left, top: er.top - dr.top };
|
|
} else {
|
|
r = { left: elem.offsetLeft, top: elem.offsetTop }
|
|
while (elem = elem.parentNode) {
|
|
if (elem.offsetLeft || elem.offsetTop) {
|
|
r.left += elem.offsetLeft;
|
|
r.top += elem.offsetTop;
|
|
}
|
|
}
|
|
}
|
|
return [evt.m.pageX - r.left, evt.m.pageY - r.top];
|
|
}
|
|
|
|
|
|
var capture = (options && options.useCapture) || false;
|
|
|
|
if (!Monocle.Browser.has.touch) {
|
|
if (fns.start) {
|
|
listeners.mousedown = function (evt) {
|
|
if (evt.button != 0) { return; }
|
|
fns.start(cursorInfo(evt, evt));
|
|
}
|
|
Monocle.Events.listen(elem, 'mousedown', listeners.mousedown, capture);
|
|
}
|
|
if (fns.move) {
|
|
listeners.mousemove = function (evt) {
|
|
fns.move(cursorInfo(evt, evt));
|
|
}
|
|
Monocle.Events.listen(elem, 'mousemove', listeners.mousemove, capture);
|
|
}
|
|
if (fns.end) {
|
|
listeners.mouseup = function (evt) {
|
|
fns.end(cursorInfo(evt, evt));
|
|
}
|
|
Monocle.Events.listen(elem, 'mouseup', listeners.mouseup, capture);
|
|
}
|
|
if (fns.cancel) {
|
|
listeners.mouseout = function (evt) {
|
|
obj = evt.relatedTarget || evt.fromElement;
|
|
while (obj && (obj = obj.parentNode)) {
|
|
if (obj == elem) { return; }
|
|
}
|
|
fns.cancel(cursorInfo(evt, evt));
|
|
}
|
|
Monocle.Events.listen(elem, 'mouseout', listeners.mouseout, capture);
|
|
}
|
|
} else {
|
|
if (fns.start) {
|
|
listeners.start = function (evt) {
|
|
if (evt.touches.length > 1) { return; }
|
|
fns.start(cursorInfo(evt, evt.targetTouches[0]));
|
|
}
|
|
}
|
|
if (fns.move) {
|
|
listeners.move = function (evt) {
|
|
if (evt.touches.length > 1) { return; }
|
|
fns.move(cursorInfo(evt, evt.targetTouches[0]));
|
|
}
|
|
}
|
|
if (fns.end) {
|
|
listeners.end = function (evt) {
|
|
fns.end(cursorInfo(evt, evt.changedTouches[0]));
|
|
evt.preventDefault();
|
|
}
|
|
}
|
|
if (fns.cancel) {
|
|
listeners.cancel = function (evt) {
|
|
fns.cancel(cursorInfo(evt, evt.changedTouches[0]));
|
|
}
|
|
}
|
|
|
|
if (Monocle.Browser.has.iframeTouchBug) {
|
|
Monocle.Events.tMonitor = Monocle.Events.tMonitor ||
|
|
new Monocle.Events.TouchMonitor();
|
|
Monocle.Events.tMonitor.listen(elem, listeners, options);
|
|
} else {
|
|
for (etype in listeners) {
|
|
Monocle.Events.listen(elem, 'touch'+etype, listeners[etype], capture);
|
|
}
|
|
}
|
|
}
|
|
|
|
return listeners;
|
|
}
|
|
|
|
|
|
Monocle.Events.deafenForContact = function (elem, listeners) {
|
|
var prefix = "";
|
|
if (Monocle.Browser.has.touch) {
|
|
prefix = Monocle.Browser.has.iframeTouchBug ? "contact" : "touch";
|
|
}
|
|
|
|
for (evtType in listeners) {
|
|
Monocle.Events.deafen(elem, prefix + evtType, listeners[evtType]);
|
|
}
|
|
}
|
|
|
|
|
|
Monocle.Events.listenForTap = function (elem, fn, activeClass) {
|
|
var startPos;
|
|
|
|
if (Monocle.Browser.on.Kindle3) {
|
|
Monocle.Events.listen(elem, 'click', function () {});
|
|
}
|
|
|
|
var annul = function () {
|
|
startPos = null;
|
|
if (activeClass && elem.dom) { elem.dom.removeClass(activeClass); }
|
|
}
|
|
|
|
var annulIfOutOfBounds = function (evt) {
|
|
if (evt.type.match(/^mouse/)) {
|
|
return;
|
|
}
|
|
if (Monocle.Browser.is.MobileSafari && Monocle.Browser.iOSVersion < "3.2") {
|
|
return;
|
|
}
|
|
if (
|
|
evt.m.registrantX < 0 || evt.m.registrantX > elem.offsetWidth ||
|
|
evt.m.registrantY < 0 || evt.m.registrantY > elem.offsetHeight
|
|
) {
|
|
annul();
|
|
} else {
|
|
evt.preventDefault();
|
|
}
|
|
}
|
|
|
|
return Monocle.Events.listenForContact(
|
|
elem,
|
|
{
|
|
start: function (evt) {
|
|
startPos = [evt.m.pageX, evt.m.pageY];
|
|
evt.preventDefault();
|
|
if (activeClass && elem.dom) { elem.dom.addClass(activeClass); }
|
|
},
|
|
move: annulIfOutOfBounds,
|
|
end: function (evt) {
|
|
annulIfOutOfBounds(evt);
|
|
if (startPos) {
|
|
evt.m.startOffset = startPos;
|
|
fn(evt);
|
|
}
|
|
annul();
|
|
},
|
|
cancel: annul
|
|
},
|
|
{
|
|
useCapture: false
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
Monocle.Events.deafenForTap = Monocle.Events.deafenForContact;
|
|
|
|
|
|
Monocle.Events.TouchMonitor = function () {
|
|
if (Monocle.Events == this) {
|
|
return new Monocle.Events.TouchMonitor();
|
|
}
|
|
|
|
var API = { constructor: Monocle.Events.TouchMonitor }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
touching: null,
|
|
edataPrev: null,
|
|
originator: null,
|
|
brokenModel_4_1: navigator.userAgent.match(/ OS 4_1/)
|
|
}
|
|
|
|
|
|
function listenOnIframe(iframe) {
|
|
if (iframe.contentDocument) {
|
|
enableTouchProxy(iframe.contentDocument);
|
|
iframe.contentDocument.isTouchFrame = true;
|
|
}
|
|
|
|
if (p.brokenModel_4_1) {
|
|
enableTouchProxy(iframe);
|
|
}
|
|
}
|
|
|
|
|
|
function listen(element, fns, useCapture) {
|
|
for (etype in fns) {
|
|
Monocle.Events.listen(element, 'contact'+etype, fns[etype], useCapture);
|
|
}
|
|
enableTouchProxy(element, useCapture);
|
|
}
|
|
|
|
|
|
function enableTouchProxy(element, useCapture) {
|
|
if (element.monocleTouchProxy) {
|
|
return;
|
|
}
|
|
element.monocleTouchProxy = true;
|
|
|
|
var fn = function (evt) { touchProxyHandler(element, evt) }
|
|
Monocle.Events.listen(element, "touchstart", fn, useCapture);
|
|
Monocle.Events.listen(element, "touchmove", fn, useCapture);
|
|
Monocle.Events.listen(element, "touchend", fn, useCapture);
|
|
Monocle.Events.listen(element, "touchcancel", fn, useCapture);
|
|
}
|
|
|
|
|
|
function touchProxyHandler(element, evt) {
|
|
var edata = {
|
|
start: evt.type == "touchstart",
|
|
move: evt.type == "touchmove",
|
|
end: evt.type == "touchend" || evt.type == "touchcancel",
|
|
time: new Date().getTime(),
|
|
frame: element.isTouchFrame
|
|
}
|
|
|
|
if (!p.touching) {
|
|
p.originator = element;
|
|
}
|
|
|
|
var target = element;
|
|
var touch = evt.touches[0] || evt.changedTouches[0];
|
|
target = document.elementFromPoint(touch.screenX, touch.screenY);
|
|
|
|
if (target) {
|
|
translateTouchEvent(element, target, evt, edata);
|
|
}
|
|
}
|
|
|
|
|
|
function translateTouchEvent(element, target, evt, edata) {
|
|
if (
|
|
p.brokenModel_4_1 &&
|
|
!edata.frame &&
|
|
!p.touching &&
|
|
edata.start &&
|
|
p.edataPrev &&
|
|
p.edataPrev.end &&
|
|
(edata.time - p.edataPrev.time) < 30
|
|
) {
|
|
evt.preventDefault();
|
|
return;
|
|
}
|
|
|
|
if (!p.touching && !edata.end) {
|
|
return fireStart(evt, target, edata);
|
|
}
|
|
|
|
if (edata.move && p.touching) {
|
|
return fireMove(evt, edata);
|
|
}
|
|
|
|
if (p.brokenModel_4_1) {
|
|
if (p.touching && !edata.frame) {
|
|
return fireProvisionalEnd(evt, edata);
|
|
}
|
|
} else {
|
|
if (edata.end && p.touching) {
|
|
return fireProvisionalEnd(evt, edata);
|
|
}
|
|
}
|
|
|
|
if (
|
|
p.brokenModel_4_1 &&
|
|
p.originator != element &&
|
|
edata.frame &&
|
|
edata.end
|
|
) {
|
|
evt.preventDefault();
|
|
return;
|
|
}
|
|
|
|
if (edata.frame && edata.end && p.touching) {
|
|
return fireProvisionalEnd(evt, edata);
|
|
}
|
|
}
|
|
|
|
|
|
function fireStart(evt, target, edata) {
|
|
p.touching = target;
|
|
p.edataPrev = edata;
|
|
return fireTouchEvent(p.touching, 'start', evt);
|
|
}
|
|
|
|
|
|
function fireMove(evt, edata) {
|
|
clearProvisionalEnd();
|
|
p.edataPrev = edata;
|
|
return fireTouchEvent(p.touching, 'move', evt);
|
|
}
|
|
|
|
|
|
function fireEnd(evt, edata) {
|
|
var result = fireTouchEvent(p.touching, 'end', evt);
|
|
p.edataPrev = edata;
|
|
p.touching = null;
|
|
return result;
|
|
}
|
|
|
|
|
|
function fireProvisionalEnd(evt, edata) {
|
|
clearProvisionalEnd();
|
|
var mimicEvt = mimicTouchEvent(p.touching, 'end', evt);
|
|
p.edataPrev = edata;
|
|
|
|
p.provisionalEnd = setTimeout(
|
|
function() {
|
|
if (p.touching) {
|
|
p.touching.dispatchEvent(mimicEvt);
|
|
p.touching = null;
|
|
}
|
|
},
|
|
30
|
|
);
|
|
}
|
|
|
|
|
|
function clearProvisionalEnd() {
|
|
if (p.provisionalEnd) {
|
|
clearTimeout(p.provisionalEnd);
|
|
p.provisionalEnd = null;
|
|
}
|
|
}
|
|
|
|
|
|
function mimicTouchEvent(target, newtype, evt) {
|
|
var cloneTouch = function (t) {
|
|
return document.createTouch(
|
|
document.defaultView,
|
|
target,
|
|
t.identifier,
|
|
t.screenX,
|
|
t.screenY,
|
|
t.screenX,
|
|
t.screenY
|
|
);
|
|
}
|
|
|
|
var findTouch = function (id) {
|
|
for (var i = 0; i < touches.all.length; ++i) {
|
|
if (touches.all[i].identifier == id) {
|
|
return touches.all[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
var touches = { all: [], target: [], changed: [] };
|
|
for (var i = 0; i < evt.touches.length; ++i) {
|
|
touches.all.push(cloneTouch(evt.touches[i]));
|
|
}
|
|
for (var i = 0; i < evt.targetTouches.length; ++i) {
|
|
touches.target.push(
|
|
findTouch(evt.targetTouches[i].identifier) ||
|
|
cloneTouch(evt.targetTouches[i])
|
|
);
|
|
}
|
|
for (var i = 0; i < evt.changedTouches.length; ++i) {
|
|
touches.changed.push(
|
|
findTouch(evt.changedTouches[i].identifier) ||
|
|
cloneTouch(evt.changedTouches[i])
|
|
);
|
|
}
|
|
|
|
var mimicEvt = document.createEvent('TouchEvent');
|
|
mimicEvt.initTouchEvent(
|
|
"contact"+newtype,
|
|
true,
|
|
true,
|
|
document.defaultView,
|
|
evt.detail,
|
|
evt.screenX,
|
|
evt.screenY,
|
|
evt.screenX,
|
|
evt.screenY,
|
|
evt.ctrlKey,
|
|
evt.altKey,
|
|
evt.shiftKey,
|
|
evt.metaKey,
|
|
document.createTouchList.apply(document, touches.all),
|
|
document.createTouchList.apply(document, touches.target),
|
|
document.createTouchList.apply(document, touches.changed),
|
|
evt.scale,
|
|
evt.rotation
|
|
);
|
|
|
|
return mimicEvt;
|
|
}
|
|
|
|
|
|
function fireTouchEvent(target, newtype, evt) {
|
|
var mimicEvt = mimicTouchEvent(target, newtype, evt);
|
|
var result = target.dispatchEvent(mimicEvt);
|
|
if (!result) {
|
|
evt.preventDefault();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
API.listen = listen;
|
|
API.listenOnIframe = listenOnIframe;
|
|
|
|
return API;
|
|
}
|
|
|
|
|
|
Monocle.Events.listenOnIframe = function (frame) {
|
|
if (!Monocle.Browser.has.iframeTouchBug) {
|
|
return;
|
|
}
|
|
Monocle.Events.tMonitor = Monocle.Events.tMonitor ||
|
|
new Monocle.Events.TouchMonitor();
|
|
Monocle.Events.tMonitor.listenOnIframe(frame);
|
|
}
|
|
|
|
Monocle.pieceLoaded('events');
|
|
Monocle.Styles = {
|
|
applyRules: function (elem, rules) {
|
|
if (typeof rules != 'string') {
|
|
var parts = [];
|
|
for (var declaration in rules) {
|
|
parts.push(declaration+": "+rules[declaration]+";")
|
|
}
|
|
rules = parts.join(" ");
|
|
}
|
|
elem.style.cssText += ';'+rules;
|
|
return elem.style.cssText;
|
|
},
|
|
|
|
affix: function (elem, property, value) {
|
|
var target = elem.style ? elem.style : elem;
|
|
target[Monocle.Browser.CSSProps.toDOMProp(property)] = value;
|
|
},
|
|
|
|
setX: function (elem, x) {
|
|
var s = elem.style;
|
|
if (typeof x == "number") { x += "px"; }
|
|
if (Monocle.Browser.has.transform3d) {
|
|
s.webkitTransform = "translate3d("+x+", 0, 0)";
|
|
} else {
|
|
s.webkitTransform = "translateX("+x+")";
|
|
}
|
|
s.MozTransform = s.OTransform = s.transform = "translateX("+x+")";
|
|
return x;
|
|
},
|
|
|
|
setY: function (elem, y) {
|
|
var s = elem.style;
|
|
if (typeof y == "number") { y += "px"; }
|
|
if (Monocle.Browser.has.transform3d) {
|
|
s.webkitTransform = "translate3d(0, "+y+", 0)";
|
|
} else {
|
|
s.webkitTransform = "translateY("+y+")";
|
|
}
|
|
s.MozTransform = s.OTransform = s.transform = "translateY("+y+")";
|
|
return y;
|
|
}
|
|
}
|
|
|
|
|
|
Monocle.Styles.container = {
|
|
"position": "absolute",
|
|
"top": "0",
|
|
"left": "0",
|
|
"bottom": "0",
|
|
"right": "0"
|
|
}
|
|
|
|
Monocle.Styles.page = {
|
|
"position": "absolute",
|
|
"z-index": "1",
|
|
"-webkit-user-select": "none",
|
|
"-moz-user-select": "none",
|
|
"user-select": "none",
|
|
"-webkit-transform": "translate3d(0,0,0)"
|
|
|
|
/*
|
|
"background": "white",
|
|
"top": "0",
|
|
"left": "0",
|
|
"bottom": "0",
|
|
"right": "0"
|
|
*/
|
|
}
|
|
|
|
Monocle.Styles.sheaf = {
|
|
"position": "absolute",
|
|
"overflow": "hidden" // Required by MobileSafari to constrain inner iFrame.
|
|
|
|
/*
|
|
"top": "0",
|
|
"left": "0",
|
|
"bottom": "0",
|
|
"right": "0"
|
|
*/
|
|
}
|
|
|
|
Monocle.Styles.component = {
|
|
"display": "block",
|
|
"width": "100%",
|
|
"height": "100%",
|
|
"border": "none",
|
|
"overflow": "hidden",
|
|
"-webkit-user-select": "none",
|
|
"-moz-user-select": "none",
|
|
"user-select": "none"
|
|
}
|
|
|
|
Monocle.Styles.control = {
|
|
"z-index": "100",
|
|
"cursor": "pointer"
|
|
}
|
|
|
|
Monocle.Styles.overlay = {
|
|
"position": "absolute",
|
|
"display": "none",
|
|
"width": "100%",
|
|
"height": "100%",
|
|
"z-index": "1000"
|
|
}
|
|
|
|
|
|
|
|
Monocle.pieceLoaded('styles');
|
|
Monocle.Reader = function (node, bookData, options, onLoadCallback) {
|
|
if (Monocle == this) {
|
|
return new Monocle.Reader(node, bookData, options, onLoadCallback);
|
|
}
|
|
|
|
var API = { constructor: Monocle.Reader }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
initialized: false,
|
|
|
|
book: null,
|
|
|
|
graph: {},
|
|
|
|
pageStylesheets: [],
|
|
|
|
systemId: (options ? options.systemId : null) || k.DEFAULT_SYSTEM_ID,
|
|
|
|
classPrefix: k.DEFAULT_CLASS_PREFIX,
|
|
|
|
controls: [],
|
|
|
|
resizeTimer: null
|
|
}
|
|
|
|
var dom;
|
|
|
|
|
|
function initialize(node, bookData, options, onLoadCallback) {
|
|
var box = typeof(node) == "string" ? document.getElementById(node) : node;
|
|
dom = API.dom = box.dom = new Monocle.Factory(box, 'box', 0, API);
|
|
|
|
options = options || {}
|
|
|
|
dispatchEvent("monocle:initializing");
|
|
|
|
var bk;
|
|
if (bookData) {
|
|
bk = new Monocle.Book(bookData);
|
|
} else {
|
|
bk = Monocle.Book.fromNodes([box.cloneNode(true)]);
|
|
}
|
|
box.innerHTML = "";
|
|
|
|
positionBox();
|
|
|
|
attachFlipper(options.flipper);
|
|
|
|
createReaderElements();
|
|
|
|
p.defaultStyles = addPageStyles(k.DEFAULT_STYLE_RULES, false);
|
|
if (options.stylesheet) {
|
|
p.initialStyles = addPageStyles(options.stylesheet, false);
|
|
}
|
|
|
|
primeFrames(options.primeURL, function () {
|
|
applyStyles();
|
|
|
|
listen('monocle:componentchange', persistPageStylesOnComponentChange);
|
|
|
|
p.flipper.listenForInteraction(options.panels);
|
|
|
|
setBook(bk, options.place, function () {
|
|
p.initialized = true;
|
|
if (onLoadCallback) { onLoadCallback(API); }
|
|
dispatchEvent("monocle:loaded");
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
function positionBox() {
|
|
var currPosVal;
|
|
var box = dom.find('box');
|
|
if (document.defaultView) {
|
|
var currStyle = document.defaultView.getComputedStyle(box, null);
|
|
currPosVal = currStyle.getPropertyValue('position');
|
|
} else if (box.currentStyle) {
|
|
currPosVal = box.currentStyle.position
|
|
}
|
|
if (["absolute", "relative"].indexOf(currPosVal) == -1) {
|
|
box.style.position = "relative";
|
|
}
|
|
}
|
|
|
|
|
|
function attachFlipper(flipperClass) {
|
|
if (!Monocle.Browser.has.columns) {
|
|
flipperClass = Monocle.Flippers[k.FLIPPER_LEGACY_CLASS];
|
|
if (!flipperClass) {
|
|
return dom.append(
|
|
'div',
|
|
'abortMsg',
|
|
{ 'class': k.abortMessage.CLASSNAME, 'html': k.abortMessage.TEXT }
|
|
);
|
|
}
|
|
} else if (!flipperClass) {
|
|
flipperClass = Monocle.Flippers[k.FLIPPER_DEFAULT_CLASS];
|
|
if (!flipperClass) {
|
|
throw("No flipper class");
|
|
}
|
|
}
|
|
p.flipper = new flipperClass(API, null, p.readerOptions);
|
|
}
|
|
|
|
|
|
function createReaderElements() {
|
|
var cntr = dom.append('div', 'container');
|
|
for (var i = 0; i < p.flipper.pageCount; ++i) {
|
|
var page = cntr.dom.append('div', 'page', i);
|
|
page.m = { reader: API, pageIndex: i, place: null }
|
|
page.m.sheafDiv = page.dom.append('div', 'sheaf', i);
|
|
page.m.activeFrame = page.m.sheafDiv.dom.append('iframe', 'component', i);
|
|
page.m.activeFrame.m = { 'pageDiv': page }
|
|
p.flipper.addPage(page);
|
|
Monocle.Events.listenOnIframe(page.m.activeFrame);
|
|
}
|
|
dom.append('div', 'overlay');
|
|
dispatchEvent("monocle:loading");
|
|
}
|
|
|
|
|
|
function primeFrames(url, callback) {
|
|
url = url || "about:blank";
|
|
|
|
var pageMax = p.flipper.pageCount;
|
|
var pageCount = 0;
|
|
|
|
var cb = function (evt) {
|
|
var frame = evt.target || evt.srcElement;
|
|
Monocle.Events.deafen(frame, 'load', cb);
|
|
if (Monocle.Browser.is.WebKit) {
|
|
frame.contentDocument.documentElement.style.overflow = "hidden";
|
|
}
|
|
dispatchEvent('monocle:frameprimed', { frame: frame, pageIndex: pageCount });
|
|
if ((pageCount += 1) == pageMax) {
|
|
Monocle.defer(callback);
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < pageMax; ++i) {
|
|
var page = dom.find('page', i);
|
|
page.m.activeFrame.style.visibility = "hidden";
|
|
page.m.activeFrame.setAttribute('frameBorder', 0);
|
|
page.m.activeFrame.setAttribute('scrolling', 'no');
|
|
Monocle.Events.listen(page.m.activeFrame, 'load', cb);
|
|
page.m.activeFrame.src = url;
|
|
}
|
|
}
|
|
|
|
|
|
function applyStyles() {
|
|
dom.find('container').dom.setStyles(Monocle.Styles.container);
|
|
for (var i = 0; i < p.flipper.pageCount; ++i) {
|
|
var page = dom.find('page', i);
|
|
page.dom.setStyles(Monocle.Styles.page);
|
|
dom.find('sheaf', i).dom.setStyles(Monocle.Styles.sheaf);
|
|
var cmpt = dom.find('component', i)
|
|
cmpt.dom.setStyles(Monocle.Styles.component);
|
|
Monocle.Styles.applyRules(cmpt.contentDocument.body, Monocle.Styles.body);
|
|
}
|
|
lockFrameWidths();
|
|
dom.find('overlay').dom.setStyles(Monocle.Styles.overlay);
|
|
dispatchEvent('monocle:styles');
|
|
}
|
|
|
|
|
|
function lockingFrameWidths() {
|
|
if (!Monocle.Browser.has.relativeIframeWidthBug) { return; }
|
|
for (var i = 0, cmpt; cmpt = dom.find('component', i); ++i) {
|
|
cmpt.style.display = "none";
|
|
}
|
|
}
|
|
|
|
|
|
function lockFrameWidths() {
|
|
if (!Monocle.Browser.has.relativeIframeWidthBug) { return; }
|
|
for (var i = 0, cmpt; cmpt = dom.find('component', i); ++i) {
|
|
cmpt.style.width = cmpt.parentNode.offsetWidth+"px";
|
|
cmpt.style.display = "block";
|
|
}
|
|
}
|
|
|
|
|
|
function setBook(bk, place, callback) {
|
|
p.book = bk;
|
|
var pageCount = 0;
|
|
if (typeof callback == 'function') {
|
|
var watcher = function (evt) {
|
|
dispatchEvent('monocle:firstcomponentchange', evt.m);
|
|
if ((pageCount += 1) == p.flipper.pageCount) {
|
|
deafen('monocle:componentchange', watcher);
|
|
callback();
|
|
}
|
|
}
|
|
listen('monocle:componentchange', watcher);
|
|
}
|
|
p.flipper.moveTo(place || { page: 1 });
|
|
}
|
|
|
|
|
|
function getBook() {
|
|
return p.book;
|
|
}
|
|
|
|
|
|
function resized() {
|
|
if (!p.initialized) {
|
|
console.warn('Attempt to resize book before initialization.');
|
|
}
|
|
lockingFrameWidths();
|
|
if (!dispatchEvent("monocle:resizing", {}, true)) {
|
|
return;
|
|
}
|
|
clearTimeout(p.resizeTimer);
|
|
p.resizeTimer = setTimeout(
|
|
function () {
|
|
lockFrameWidths();
|
|
p.flipper.moveTo({ page: pageNumber() });
|
|
dispatchEvent("monocle:resize");
|
|
},
|
|
k.durations.RESIZE_DELAY
|
|
);
|
|
}
|
|
|
|
|
|
function pageNumber(pageDiv) {
|
|
var place = getPlace(pageDiv);
|
|
return place ? (place.pageNumber() || 1) : 1;
|
|
}
|
|
|
|
|
|
function getPlace(pageDiv) {
|
|
if (!p.initialized) {
|
|
console.warn('Attempt to access place before initialization.');
|
|
}
|
|
return p.flipper.getPlace(pageDiv);
|
|
}
|
|
|
|
|
|
function moveTo(locus, callback) {
|
|
if (!p.initialized) {
|
|
console.warn('Attempt to move place before initialization.');
|
|
}
|
|
var fn = callback;
|
|
if (!locus.direction) {
|
|
dispatchEvent('monocle:jumping', { locus: locus });
|
|
fn = function () {
|
|
dispatchEvent('monocle:jump', { locus: locus });
|
|
if (callback) { callback(); }
|
|
}
|
|
}
|
|
p.flipper.moveTo(locus, fn);
|
|
}
|
|
|
|
|
|
function skipToChapter(src) {
|
|
var locus = p.book.locusOfChapter(src);
|
|
if (locus) {
|
|
moveTo(locus);
|
|
return true;
|
|
} else {
|
|
dispatchEvent("monocle:notfound", { href: src });
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
function addControl(ctrl, cType, options) {
|
|
for (var i = 0; i < p.controls.length; ++i) {
|
|
if (p.controls[i].control == ctrl) {
|
|
console.warn("Already added control: " + ctrl);
|
|
return;
|
|
}
|
|
}
|
|
|
|
options = options || {};
|
|
|
|
var ctrlData = {
|
|
control: ctrl,
|
|
elements: [],
|
|
controlType: cType
|
|
}
|
|
p.controls.push(ctrlData);
|
|
|
|
var ctrlElem;
|
|
var cntr = dom.find('container'), overlay = dom.find('overlay');
|
|
if (!cType || cType == "standard") {
|
|
ctrlElem = ctrl.createControlElements(cntr);
|
|
cntr.appendChild(ctrlElem);
|
|
ctrlData.elements.push(ctrlElem);
|
|
} else if (cType == "page") {
|
|
for (var i = 0; i < p.flipper.pageCount; ++i) {
|
|
var page = dom.find('page', i);
|
|
var runner = ctrl.createControlElements(page);
|
|
page.appendChild(runner);
|
|
ctrlData.elements.push(runner);
|
|
}
|
|
} else if (cType == "modal" || cType == "popover" || cType == "hud") {
|
|
ctrlElem = ctrl.createControlElements(overlay);
|
|
overlay.appendChild(ctrlElem);
|
|
ctrlData.elements.push(ctrlElem);
|
|
ctrlData.usesOverlay = true;
|
|
} else if (cType == "invisible") {
|
|
if (
|
|
typeof(ctrl.createControlElements) == "function" &&
|
|
(ctrlElem = ctrl.createControlElements(cntr))
|
|
) {
|
|
cntr.appendChild(ctrlElem);
|
|
ctrlData.elements.push(ctrlElem);
|
|
}
|
|
} else {
|
|
console.warn("Unknown control type: " + cType);
|
|
}
|
|
|
|
for (var i = 0; i < ctrlData.elements.length; ++i) {
|
|
Monocle.Styles.applyRules(ctrlData.elements[i], Monocle.Styles.control);
|
|
}
|
|
|
|
if (options.hidden) {
|
|
hideControl(ctrl);
|
|
} else {
|
|
showControl(ctrl);
|
|
}
|
|
|
|
if (typeof ctrl.assignToReader == 'function') {
|
|
ctrl.assignToReader(API);
|
|
}
|
|
|
|
return ctrl;
|
|
}
|
|
|
|
|
|
function dataForControl(ctrl) {
|
|
for (var i = 0; i < p.controls.length; ++i) {
|
|
if (p.controls[i].control == ctrl) {
|
|
return p.controls[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function hideControl(ctrl) {
|
|
var controlData = dataForControl(ctrl);
|
|
if (!controlData) {
|
|
console.warn("No data for control: " + ctrl);
|
|
return;
|
|
}
|
|
if (controlData.hidden) {
|
|
return;
|
|
}
|
|
for (var i = 0; i < controlData.elements.length; ++i) {
|
|
controlData.elements[i].style.display = "none";
|
|
}
|
|
if (controlData.usesOverlay) {
|
|
var overlay = dom.find('overlay');
|
|
overlay.style.display = "none";
|
|
Monocle.Events.deafenForContact(overlay, overlay.listeners);
|
|
}
|
|
controlData.hidden = true;
|
|
if (ctrl.properties) {
|
|
ctrl.properties.hidden = true;
|
|
}
|
|
dispatchEvent('controlhide', ctrl, false);
|
|
}
|
|
|
|
|
|
function showControl(ctrl) {
|
|
var controlData = dataForControl(ctrl);
|
|
if (!controlData) {
|
|
console.warn("No data for control: " + ctrl);
|
|
return false;
|
|
}
|
|
|
|
if (showingControl(ctrl)) {
|
|
return false;
|
|
}
|
|
|
|
var overlay = dom.find('overlay');
|
|
if (controlData.usesOverlay && controlData.controlType != "hud") {
|
|
for (var i = 0, ii = p.controls.length; i < ii; ++i) {
|
|
if (p.controls[i].usesOverlay && !p.controls[i].hidden) {
|
|
return false;
|
|
}
|
|
}
|
|
overlay.style.display = "block";
|
|
}
|
|
|
|
for (var i = 0; i < controlData.elements.length; ++i) {
|
|
controlData.elements[i].style.display = "block";
|
|
}
|
|
|
|
if (controlData.controlType == "popover") {
|
|
overlay.listeners = Monocle.Events.listenForContact(
|
|
overlay,
|
|
{
|
|
start: function (evt) {
|
|
var obj = evt.target || window.event.srcElement;
|
|
do {
|
|
if (obj == controlData.elements[0]) { return true; }
|
|
} while (obj && (obj = obj.parentNode));
|
|
hideControl(ctrl);
|
|
},
|
|
move: function (evt) {
|
|
evt.preventDefault();
|
|
}
|
|
}
|
|
);
|
|
}
|
|
controlData.hidden = false;
|
|
if (ctrl.properties) {
|
|
ctrl.properties.hidden = false;
|
|
}
|
|
dispatchEvent('controlshow', ctrl, false);
|
|
return true;
|
|
}
|
|
|
|
|
|
function showingControl(ctrl) {
|
|
var controlData = dataForControl(ctrl);
|
|
return controlData.hidden == false;
|
|
}
|
|
|
|
|
|
function dispatchEvent(evtType, data, cancelable) {
|
|
return Monocle.Events.dispatch(dom.find('box'), evtType, data, cancelable);
|
|
}
|
|
|
|
|
|
function listen(evtType, fn, useCapture) {
|
|
Monocle.Events.listen(dom.find('box'), evtType, fn, useCapture);
|
|
}
|
|
|
|
|
|
function deafen(evtType, fn) {
|
|
Monocle.Events.deafen(dom.find('box'), evtType, fn);
|
|
}
|
|
|
|
|
|
/* PAGE STYLESHEETS */
|
|
|
|
function addPageStyles(styleRules, restorePlace) {
|
|
return changingStylesheet(function () {
|
|
p.pageStylesheets.push(styleRules);
|
|
var sheetIndex = p.pageStylesheets.length - 1;
|
|
|
|
for (var i = 0; i < p.flipper.pageCount; ++i) {
|
|
var doc = dom.find('component', i).contentDocument;
|
|
addPageStylesheet(doc, sheetIndex);
|
|
}
|
|
return sheetIndex;
|
|
}, restorePlace);
|
|
}
|
|
|
|
|
|
function updatePageStyles(sheetIndex, styleRules, restorePlace) {
|
|
return changingStylesheet(function () {
|
|
p.pageStylesheets[sheetIndex] = styleRules;
|
|
if (typeof styleRules.join == "function") {
|
|
styleRules = styleRules.join("\n");
|
|
}
|
|
for (var i = 0; i < p.flipper.pageCount; ++i) {
|
|
var doc = dom.find('component', i).contentDocument;
|
|
var styleTag = doc.getElementById('monStylesheet'+sheetIndex);
|
|
if (!styleTag) {
|
|
console.warn('No such stylesheet: ' + sheetIndex);
|
|
return;
|
|
}
|
|
if (styleTag.styleSheet) {
|
|
styleTag.styleSheet.cssText = styleRules;
|
|
} else {
|
|
styleTag.replaceChild(
|
|
doc.createTextNode(styleRules),
|
|
styleTag.firstChild
|
|
);
|
|
}
|
|
}
|
|
}, restorePlace);
|
|
}
|
|
|
|
|
|
function removePageStyles(sheetIndex, restorePlace) {
|
|
return changingStylesheet(function () {
|
|
p.pageStylesheets[sheetIndex] = null;
|
|
for (var i = 0; i < p.flipper.pageCount; ++i) {
|
|
var doc = dom.find('component', i).contentDocument;
|
|
var styleTag = doc.getElementById('monStylesheet'+sheetIndex);
|
|
styleTag.parentNode.removeChild(styleTag);
|
|
}
|
|
}, restorePlace);
|
|
}
|
|
|
|
|
|
function persistPageStylesOnComponentChange(evt) {
|
|
var doc = evt.m['document'];
|
|
doc.documentElement.id = p.systemId;
|
|
for (var i = 0; i < p.pageStylesheets.length; ++i) {
|
|
if (p.pageStylesheets[i]) {
|
|
addPageStylesheet(doc, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function changingStylesheet(callback, restorePlace) {
|
|
restorePlace = (restorePlace === false) ? false : true;
|
|
if (restorePlace) {
|
|
dispatchEvent("monocle:stylesheetchanging", {});
|
|
}
|
|
var result = callback();
|
|
if (restorePlace) {
|
|
p.flipper.moveTo({ page: pageNumber() });
|
|
Monocle.defer(
|
|
function () { dispatchEvent("monocle:stylesheetchange", {}); }
|
|
);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
function addPageStylesheet(doc, sheetIndex) {
|
|
var styleRules = p.pageStylesheets[sheetIndex];
|
|
|
|
if (!styleRules) {
|
|
return;
|
|
}
|
|
|
|
var head = doc.getElementsByTagName('head')[0];
|
|
if (!head) {
|
|
if (!doc.documentElement) { return; } // FIXME: IE doesn't like docElem.
|
|
head = doc.createElement('head');
|
|
doc.documentElement.appendChild(head);
|
|
}
|
|
|
|
if (typeof styleRules.join == "function") {
|
|
styleRules = styleRules.join("\n");
|
|
}
|
|
|
|
var styleTag = doc.createElement('style');
|
|
styleTag.type = 'text/css';
|
|
styleTag.id = "monStylesheet"+sheetIndex;
|
|
if (styleTag.styleSheet) {
|
|
styleTag.styleSheet.cssText = styleRules;
|
|
} else {
|
|
styleTag.appendChild(doc.createTextNode(styleRules));
|
|
}
|
|
|
|
head.appendChild(styleTag);
|
|
|
|
return styleTag;
|
|
}
|
|
|
|
|
|
function visiblePages() {
|
|
return p.flipper.visiblePages ? p.flipper.visiblePages() : [dom.find('page')];
|
|
}
|
|
|
|
|
|
API.getBook = getBook;
|
|
API.getPlace = getPlace;
|
|
API.moveTo = moveTo;
|
|
API.skipToChapter = skipToChapter;
|
|
API.resized = resized;
|
|
API.addControl = addControl;
|
|
API.hideControl = hideControl;
|
|
API.showControl = showControl;
|
|
API.showingControl = showingControl;
|
|
API.dispatchEvent = dispatchEvent;
|
|
API.listen = listen;
|
|
API.deafen = deafen;
|
|
API.addPageStyles = addPageStyles;
|
|
API.updatePageStyles = updatePageStyles;
|
|
API.removePageStyles = removePageStyles;
|
|
API.visiblePages = visiblePages;
|
|
|
|
initialize(node, bookData, options, onLoadCallback);
|
|
|
|
return API;
|
|
}
|
|
|
|
Monocle.Reader.durations = {
|
|
RESIZE_DELAY: 100
|
|
}
|
|
Monocle.Reader.abortMessage = {
|
|
CLASSNAME: "monocleAbortMessage",
|
|
TEXT: "Your browser does not support this technology."
|
|
}
|
|
Monocle.Reader.DEFAULT_SYSTEM_ID = 'RS:monocle'
|
|
Monocle.Reader.DEFAULT_CLASS_PREFIX = 'monelem_'
|
|
Monocle.Reader.FLIPPER_DEFAULT_CLASS = "Slider";
|
|
Monocle.Reader.FLIPPER_LEGACY_CLASS = "Legacy";
|
|
Monocle.Reader.DEFAULT_STYLE_RULES = [
|
|
"html#RS\\:monocle * {" +
|
|
"-webkit-font-smoothing: subpixel-antialiased;" +
|
|
"text-rendering: auto !important;" +
|
|
"word-wrap: break-word !important;" +
|
|
"overflow: visible !important;" +
|
|
(Monocle.Browser.has.floatColumnBug ? "float: none !important;" : "") +
|
|
"}",
|
|
"html#RS\\:monocle body {" +
|
|
"margin: 0 !important;" +
|
|
"padding: 0 !important;" +
|
|
"-webkit-text-size-adjust: none;" +
|
|
"}",
|
|
"html#RS\\:monocle body * {" +
|
|
"max-width: 100% !important;" +
|
|
"}",
|
|
"html#RS\\:monocle img, html#RS\\:monocle video, html#RS\\:monocle object {" +
|
|
"max-height: 95% !important;" +
|
|
"}"
|
|
]
|
|
|
|
if (Monocle.Browser.has.columnOverflowPaintBug) {
|
|
Monocle.Reader.DEFAULT_STYLE_RULES.push(
|
|
"::-webkit-scrollbar { width: 0; height: 0; }"
|
|
)
|
|
}
|
|
|
|
|
|
Monocle.pieceLoaded('reader');
|
|
/* BOOK */
|
|
|
|
/* The Book handles movement through the content by the reader page elements.
|
|
*
|
|
* It's responsible for instantiating components as they are required,
|
|
* and for calculating which component and page number to move to (based on
|
|
* requests from the Reader).
|
|
*
|
|
* It should set and know the place of each page element too.
|
|
*
|
|
*/
|
|
Monocle.Book = function (dataSource) {
|
|
if (Monocle == this) { return new Monocle.Book(dataSource); }
|
|
|
|
var API = { constructor: Monocle.Book }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
dataSource: dataSource,
|
|
components: [],
|
|
chapters: {} // flat arrays of chapters per component
|
|
}
|
|
|
|
|
|
function initialize() {
|
|
p.componentIds = dataSource.getComponents();
|
|
p.contents = dataSource.getContents();
|
|
p.lastCIndex = p.componentIds.length - 1;
|
|
}
|
|
|
|
|
|
function pageNumberAt(pageDiv, locus) {
|
|
locus.load = false;
|
|
var currComponent = pageDiv.m.activeFrame ?
|
|
pageDiv.m.activeFrame.m.component :
|
|
null;
|
|
var component = null;
|
|
var cIndex = p.componentIds.indexOf(locus.componentId);
|
|
if (cIndex < 0 && !currComponent) {
|
|
locus.load = true;
|
|
locus.componentId = p.componentIds[0];
|
|
return locus;
|
|
} else if (
|
|
cIndex < 0 &&
|
|
locus.componentId &&
|
|
currComponent.properties.id != locus.componentId
|
|
) {
|
|
pageDiv.m.reader.dispatchEvent(
|
|
"monocle:notfound",
|
|
{ href: locus.componentId }
|
|
);
|
|
return null;
|
|
} else if (cIndex < 0) {
|
|
component = currComponent;
|
|
locus.componentId = pageDiv.m.activeFrame.m.component.properties.id;
|
|
cIndex = p.componentIds.indexOf(locus.componentId);
|
|
} else if (!p.components[cIndex] || p.components[cIndex] != currComponent) {
|
|
locus.load = true;
|
|
return locus;
|
|
} else {
|
|
component = currComponent;
|
|
}
|
|
|
|
var result = { load: false, componentId: locus.componentId, page: 1 }
|
|
|
|
var lastPageNum = { 'old': component.lastPageNumber() }
|
|
var changedDims = component.updateDimensions(pageDiv);
|
|
lastPageNum['new'] = component.lastPageNumber();
|
|
|
|
if (typeof(locus.page) == "number") {
|
|
result.page = locus.page;
|
|
} else if (typeof(locus.pagesBack) == "number") {
|
|
result.page = lastPageNum['new'] + locus.pagesBack;
|
|
} else if (typeof(locus.percent) == "number") {
|
|
var place = new Monocle.Place();
|
|
place.setPlace(component, 1);
|
|
result.page = place.pageAtPercentageThrough(locus.percent);
|
|
} else if (typeof(locus.direction) == "number") {
|
|
if (!pageDiv.m.place) {
|
|
console.warn("Can't move in a direction if pageDiv has no place.");
|
|
}
|
|
result.page = pageDiv.m.place.pageNumber();
|
|
result.page += locus.direction;
|
|
} else if (typeof(locus.anchor) == "string") {
|
|
result.page = component.pageForChapter(locus.anchor, pageDiv);
|
|
} else if (typeof(locus.xpath) == "string") {
|
|
result.page = component.pageForXPath(locus.xpath, pageDiv);
|
|
} else if (typeof(locus.position) == "string") {
|
|
if (locus.position == "start") {
|
|
result.page = 1;
|
|
} else if (locus.position == "end") {
|
|
result.page = lastPageNum['new'];
|
|
}
|
|
} else {
|
|
console.warn("Unrecognised locus: " + locus);
|
|
}
|
|
|
|
if (changedDims && lastPageNum['old']) {
|
|
result.page = Math.round(
|
|
lastPageNum['new'] * (result.page / lastPageNum['old'])
|
|
);
|
|
}
|
|
|
|
if (result.page < 1) {
|
|
if (cIndex == 0) {
|
|
result.page = 1;
|
|
result.boundarystart = true;
|
|
} else {
|
|
result.load = true;
|
|
result.componentId = p.componentIds[cIndex - 1];
|
|
result.pagesBack = result.page;
|
|
result.page = null;
|
|
}
|
|
} else if (result.page > lastPageNum['new']) {
|
|
if (cIndex == p.lastCIndex) {
|
|
result.page = lastPageNum['new'];
|
|
result.boundaryend = true;
|
|
} else {
|
|
result.load = true;
|
|
result.componentId = p.componentIds[cIndex + 1];
|
|
result.page -= lastPageNum['new'];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
function setPageAt(pageDiv, locus) {
|
|
locus = pageNumberAt(pageDiv, locus);
|
|
if (locus && !locus.load) {
|
|
var evtData = { locus: locus, page: pageDiv }
|
|
if (locus.boundarystart) {
|
|
pageDiv.m.reader.dispatchEvent('monocle:boundarystart', evtData);
|
|
} else if (locus.boundaryend) {
|
|
pageDiv.m.reader.dispatchEvent('monocle:boundaryend', evtData);
|
|
} else {
|
|
var component = p.components[p.componentIds.indexOf(locus.componentId)];
|
|
pageDiv.m.place = pageDiv.m.place || new Monocle.Place();
|
|
pageDiv.m.place.setPlace(component, locus.page);
|
|
|
|
var evtData = {
|
|
page: pageDiv,
|
|
locus: locus,
|
|
pageNumber: pageDiv.m.place.pageNumber(),
|
|
componentId: locus.componentId
|
|
}
|
|
pageDiv.m.reader.dispatchEvent("monocle:pagechange", evtData);
|
|
}
|
|
}
|
|
return locus;
|
|
}
|
|
|
|
|
|
function loadPageAt(pageDiv, locus, callback, progressCallback) {
|
|
var cIndex = p.componentIds.indexOf(locus.componentId);
|
|
if (!locus.load || cIndex < 0) {
|
|
locus = pageNumberAt(pageDiv, locus);
|
|
}
|
|
|
|
if (!locus) {
|
|
return;
|
|
}
|
|
|
|
if (!locus.load) {
|
|
callback(locus);
|
|
return;
|
|
}
|
|
|
|
var findPageNumber = function () {
|
|
locus = setPageAt(pageDiv, locus);
|
|
if (!locus) {
|
|
return;
|
|
} else if (locus.load) {
|
|
loadPageAt(pageDiv, locus, callback, progressCallback)
|
|
} else {
|
|
callback(locus);
|
|
}
|
|
}
|
|
|
|
var pgFindPageNumber = function () {
|
|
progressCallback ? progressCallback(findPageNumber) : findPageNumber();
|
|
}
|
|
|
|
var applyComponent = function (component) {
|
|
component.applyTo(pageDiv, pgFindPageNumber);
|
|
}
|
|
|
|
var pgApplyComponent = function (component) {
|
|
progressCallback ?
|
|
progressCallback(function () { applyComponent(component) }) :
|
|
applyComponent(component);
|
|
}
|
|
|
|
loadComponent(cIndex, pgApplyComponent, pageDiv);
|
|
}
|
|
|
|
|
|
function setOrLoadPageAt(pageDiv, locus, callback, onProgress, onFail) {
|
|
locus = setPageAt(pageDiv, locus);
|
|
if (!locus) {
|
|
if (onFail) { onFail(); }
|
|
} else if (locus.load) {
|
|
loadPageAt(pageDiv, locus, callback, onProgress);
|
|
} else {
|
|
callback(locus);
|
|
}
|
|
}
|
|
|
|
|
|
function loadComponent(index, callback, pageDiv) {
|
|
if (p.components[index]) {
|
|
return callback(p.components[index]);
|
|
}
|
|
var cmptId = p.componentIds[index];
|
|
if (pageDiv) {
|
|
var evtData = { 'page': pageDiv, 'component': cmptId, 'index': index };
|
|
pageDiv.m.reader.dispatchEvent('monocle:componentloading', evtData);
|
|
}
|
|
var fn = function (cmptSource) {
|
|
if (pageDiv) {
|
|
evtData['source'] = cmptSource;
|
|
pageDiv.m.reader.dispatchEvent('monocle:componentloaded', evtData);
|
|
html = evtData['html'];
|
|
}
|
|
p.components[index] = new Monocle.Component(
|
|
API,
|
|
cmptId,
|
|
index,
|
|
chaptersForComponent(cmptId),
|
|
cmptSource
|
|
);
|
|
callback(p.components[index]);
|
|
}
|
|
var cmptSource = p.dataSource.getComponent(cmptId, fn);
|
|
if (cmptSource && !p.components[index]) {
|
|
fn(cmptSource);
|
|
}
|
|
}
|
|
|
|
|
|
function chaptersForComponent(cmptId) {
|
|
if (p.chapters[cmptId]) {
|
|
return p.chapters[cmptId];
|
|
}
|
|
p.chapters[cmptId] = [];
|
|
var matcher = new RegExp('^'+cmptId+"(\#(.+)|$)");
|
|
var matches;
|
|
var recurser = function (chp) {
|
|
if (matches = chp.src.match(matcher)) {
|
|
p.chapters[cmptId].push({
|
|
title: chp.title,
|
|
fragment: matches[2] || null
|
|
});
|
|
}
|
|
if (chp.children) {
|
|
for (var i = 0; i < chp.children.length; ++i) {
|
|
recurser(chp.children[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < p.contents.length; ++i) {
|
|
recurser(p.contents[i]);
|
|
}
|
|
return p.chapters[cmptId];
|
|
}
|
|
|
|
|
|
function locusOfChapter(src) {
|
|
var matcher = new RegExp('^(.+?)(#(.*))?$');
|
|
var matches = src.match(matcher);
|
|
if (!matches) { return null; }
|
|
var cmptId = componentIdMatching(matches[1]);
|
|
if (!cmptId) { return null; }
|
|
var locus = { componentId: cmptId }
|
|
matches[3] ? locus.anchor = matches[3] : locus.position = "start";
|
|
return locus;
|
|
}
|
|
|
|
|
|
function componentIdMatching(str) {
|
|
return p.componentIds.indexOf(str) >= 0 ? str : null;
|
|
}
|
|
|
|
|
|
API.getMetaData = dataSource.getMetaData;
|
|
API.pageNumberAt = pageNumberAt;
|
|
API.setPageAt = setPageAt;
|
|
API.loadPageAt = loadPageAt;
|
|
API.setOrLoadPageAt = setOrLoadPageAt;
|
|
API.chaptersForComponent = chaptersForComponent;
|
|
API.locusOfChapter = locusOfChapter;
|
|
|
|
initialize();
|
|
|
|
return API;
|
|
}
|
|
|
|
|
|
Monocle.Book.fromNodes = function (nodes) {
|
|
var bookData = {
|
|
getComponents: function () {
|
|
return ['anonymous'];
|
|
},
|
|
getContents: function () {
|
|
return [];
|
|
},
|
|
getComponent: function (n) {
|
|
return { 'nodes': nodes };
|
|
},
|
|
getMetaData: function (key) {
|
|
}
|
|
}
|
|
|
|
return new Monocle.Book(bookData);
|
|
}
|
|
|
|
Monocle.pieceLoaded('book');
|
|
|
|
Monocle.Place = function () {
|
|
|
|
var API = { constructor: Monocle.Place }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
component: null,
|
|
percent: null
|
|
}
|
|
|
|
|
|
function setPlace(cmpt, pageN) {
|
|
p.component = cmpt;
|
|
p.percent = pageN / cmpt.lastPageNumber();
|
|
p.chapter = null;
|
|
}
|
|
|
|
|
|
function setPercentageThrough(cmpt, percent) {
|
|
p.component = cmpt;
|
|
p.percent = percent;
|
|
p.chapter = null;
|
|
}
|
|
|
|
|
|
function componentId() {
|
|
return p.component.properties.id;
|
|
}
|
|
|
|
|
|
function percentAtTopOfPage() {
|
|
return p.percent - 1.0 / p.component.lastPageNumber();
|
|
}
|
|
|
|
|
|
function percentAtBottomOfPage() {
|
|
return p.percent;
|
|
}
|
|
|
|
|
|
function pageAtPercentageThrough(percent) {
|
|
return Math.max(Math.round(p.component.lastPageNumber() * percent), 1);
|
|
}
|
|
|
|
|
|
function pageNumber() {
|
|
return pageAtPercentageThrough(p.percent);
|
|
}
|
|
|
|
|
|
function chapterInfo() {
|
|
if (p.chapter) {
|
|
return p.chapter;
|
|
}
|
|
return p.chapter = p.component.chapterForPage(pageNumber());
|
|
}
|
|
|
|
|
|
function chapterTitle() {
|
|
var chp = chapterInfo();
|
|
return chp ? chp.title : null;
|
|
}
|
|
|
|
|
|
function chapterSrc() {
|
|
var src = componentId();
|
|
var cinfo = chapterInfo();
|
|
if (cinfo && cinfo.fragment) {
|
|
src += "#" + cinfo.fragment;
|
|
}
|
|
return src;
|
|
}
|
|
|
|
|
|
function getLocus(options) {
|
|
options = options || {};
|
|
var locus = {
|
|
page: pageNumber(),
|
|
componentId: componentId()
|
|
}
|
|
if (options.direction) {
|
|
locus.page += options.direction;
|
|
} else {
|
|
locus.percent = percentAtBottomOfPage();
|
|
}
|
|
return locus;
|
|
}
|
|
|
|
|
|
function percentageOfBook() {
|
|
componentIds = p.component.properties.book.properties.componentIds;
|
|
componentSize = 1.0 / componentIds.length;
|
|
var pc = componentIds.indexOf(componentId()) * componentSize;
|
|
pc += componentSize * p.percent;
|
|
return pc;
|
|
}
|
|
|
|
|
|
function onFirstPageOfBook() {
|
|
return p.component.properties.index == 0 && pageNumber() == 1;
|
|
}
|
|
|
|
|
|
function onLastPageOfBook() {
|
|
return (
|
|
p.component.properties.index ==
|
|
p.component.properties.book.properties.lastCIndex &&
|
|
pageNumber() == p.component.lastPageNumber()
|
|
);
|
|
}
|
|
|
|
|
|
API.setPlace = setPlace;
|
|
API.setPercentageThrough = setPercentageThrough;
|
|
API.componentId = componentId;
|
|
API.percentAtTopOfPage = percentAtTopOfPage;
|
|
API.percentAtBottomOfPage = percentAtBottomOfPage;
|
|
API.percentageThrough = percentAtBottomOfPage;
|
|
API.pageAtPercentageThrough = pageAtPercentageThrough;
|
|
API.pageNumber = pageNumber;
|
|
API.chapterInfo = chapterInfo;
|
|
API.chapterTitle = chapterTitle;
|
|
API.chapterSrc = chapterSrc;
|
|
API.getLocus = getLocus;
|
|
API.percentageOfBook = percentageOfBook;
|
|
API.onFirstPageOfBook = onFirstPageOfBook;
|
|
API.onLastPageOfBook = onLastPageOfBook;
|
|
|
|
return API;
|
|
}
|
|
|
|
|
|
Monocle.Place.FromPageNumber = function (component, pageNumber) {
|
|
var place = new Monocle.Place();
|
|
place.setPlace(component, pageNumber);
|
|
return place;
|
|
}
|
|
|
|
Monocle.Place.FromPercentageThrough = function (component, percent) {
|
|
var place = new Monocle.Place();
|
|
place.setPercentageThrough(component, percent);
|
|
return place;
|
|
}
|
|
|
|
Monocle.pieceLoaded('place');
|
|
/* COMPONENT */
|
|
|
|
Monocle.Component = function (book, id, index, chapters, source) {
|
|
|
|
var API = { constructor: Monocle.Component }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
book: book,
|
|
|
|
id: id,
|
|
|
|
index: index,
|
|
|
|
chapters: chapters,
|
|
|
|
source: source
|
|
}
|
|
|
|
|
|
function applyTo(pageDiv, callback) {
|
|
var evtData = { 'page': pageDiv, 'source': p.source };
|
|
pageDiv.m.reader.dispatchEvent('monocle:componentchanging', evtData);
|
|
|
|
return loadFrame(
|
|
pageDiv,
|
|
function () {
|
|
setupFrame(pageDiv, pageDiv.m.activeFrame);
|
|
callback(pageDiv, API);
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
function loadFrame(pageDiv, callback) {
|
|
var frame = pageDiv.m.activeFrame;
|
|
|
|
frame.m.component = API;
|
|
|
|
frame.style.visibility = "hidden";
|
|
|
|
|
|
if (p.source.html || (typeof p.source == "string")) { // HTML
|
|
return loadFrameFromHTML(p.source.html || p.source, frame, callback);
|
|
} else if (p.source.url) { // URL
|
|
return loadFrameFromURL(p.source.url, frame, callback);
|
|
} else if (p.source.nodes) { // NODES
|
|
return loadFrameFromNodes(p.source.nodes, frame, callback);
|
|
} else if (p.source.doc) { // DOCUMENT
|
|
return loadFrameFromDocument(p.source.doc, frame, callback);
|
|
}
|
|
}
|
|
|
|
|
|
function loadFrameFromHTML(src, frame, callback) {
|
|
src = src.replace(/\s+/g, ' ');
|
|
|
|
src = src.replace(/\'/g, '\\\'');
|
|
|
|
|
|
if (Monocle.Browser.is.Gecko) {
|
|
var doctypeFragment = "<!DOCTYPE[^>]*>";
|
|
src = src.replace(new RegExp(doctypeFragment, 'm'), '');
|
|
}
|
|
|
|
src = "javascript: '" + src + "';";
|
|
|
|
frame.onload = function () {
|
|
frame.onload = null;
|
|
Monocle.defer(callback);
|
|
}
|
|
frame.src = src;
|
|
}
|
|
|
|
|
|
function loadFrameFromURL(url, frame, callback) {
|
|
if (!url.match(/^\//)) {
|
|
var link = document.createElement('a');
|
|
link.setAttribute('href', url);
|
|
url = link.href;
|
|
delete(link);
|
|
}
|
|
frame.onload = function () {
|
|
frame.onload = null;
|
|
Monocle.defer(callback);
|
|
}
|
|
frame.contentWindow.location.replace(url);
|
|
}
|
|
|
|
|
|
function loadFrameFromNodes(nodes, frame, callback) {
|
|
var destDoc = frame.contentDocument;
|
|
destDoc.documentElement.innerHTML = "";
|
|
var destHd = destDoc.createElement("head");
|
|
var destBdy = destDoc.createElement("body");
|
|
|
|
for (var i = 0; i < nodes.length; ++i) {
|
|
var node = destDoc.importNode(nodes[i], true);
|
|
destBdy.appendChild(node);
|
|
}
|
|
|
|
var oldHead = destDoc.getElementsByTagName('head')[0];
|
|
if (oldHead) {
|
|
destDoc.documentElement.replaceChild(destHd, oldHead);
|
|
} else {
|
|
destDoc.documentElement.appendChild(destHd);
|
|
}
|
|
if (destDoc.body) {
|
|
destDoc.documentElement.replaceChild(destBdy, destDoc.body);
|
|
} else {
|
|
destDoc.documentElement.appendChild(destBdy);
|
|
}
|
|
|
|
if (callback) { callback(); }
|
|
}
|
|
|
|
|
|
function loadFrameFromDocument(srcDoc, frame, callback) {
|
|
var destDoc = frame.contentDocument;
|
|
|
|
var srcBases = srcDoc.getElementsByTagName('base');
|
|
if (srcBases[0]) {
|
|
var head = destDoc.getElementsByTagName('head')[0];
|
|
if (!head) {
|
|
try {
|
|
head = destDoc.createElement('head');
|
|
if (destDoc.body) {
|
|
destDoc.insertBefore(head, destDoc.body);
|
|
} else {
|
|
destDoc.appendChild(head);
|
|
}
|
|
} catch (e) {
|
|
head = destDoc.body;
|
|
}
|
|
}
|
|
var bases = destDoc.getElementsByTagName('base');
|
|
var base = bases[0] ? bases[0] : destDoc.createElement('base');
|
|
base.setAttribute('href', srcBases[0].getAttribute('href'));
|
|
head.appendChild(base);
|
|
}
|
|
|
|
destDoc.replaceChild(
|
|
destDoc.importNode(srcDoc.documentElement, true),
|
|
destDoc.documentElement
|
|
);
|
|
|
|
|
|
Monocle.defer(callback);
|
|
}
|
|
|
|
|
|
function setupFrame(pageDiv, frame) {
|
|
Monocle.Events.listenOnIframe(frame);
|
|
|
|
var evtData = {
|
|
'page': pageDiv,
|
|
'document': frame.contentDocument,
|
|
'component': API
|
|
};
|
|
pageDiv.m.reader.dispatchEvent('monocle:componentchange', evtData);
|
|
|
|
var doc = frame.contentDocument;
|
|
var win = doc.defaultView;
|
|
var currStyle = win.getComputedStyle(doc.body, null);
|
|
var lh = parseFloat(currStyle.getPropertyValue('line-height'));
|
|
var fs = parseFloat(currStyle.getPropertyValue('font-size'));
|
|
doc.body.style.lineHeight = lh / fs;
|
|
|
|
p.pageLength = pageDiv.m.dimensions.measure();
|
|
frame.style.visibility = "visible";
|
|
|
|
locateChapters(pageDiv);
|
|
}
|
|
|
|
|
|
function updateDimensions(pageDiv) {
|
|
if (pageDiv.m.dimensions.hasChanged()) {
|
|
p.pageLength = pageDiv.m.dimensions.measure();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
function locateChapters(pageDiv) {
|
|
if (p.chapters[0] && typeof p.chapters[0].percent == "number") {
|
|
return;
|
|
}
|
|
var doc = pageDiv.m.activeFrame.contentDocument;
|
|
for (var i = 0; i < p.chapters.length; ++i) {
|
|
var chp = p.chapters[i];
|
|
chp.percent = 0;
|
|
if (chp.fragment) {
|
|
var node = doc.getElementById(chp.fragment);
|
|
chp.percent = pageDiv.m.dimensions.percentageThroughOfNode(node);
|
|
}
|
|
}
|
|
return p.chapters;
|
|
}
|
|
|
|
|
|
function chapterForPage(pageN) {
|
|
var cand = null;
|
|
var percent = (pageN - 1) / p.pageLength;
|
|
for (var i = 0; i < p.chapters.length; ++i) {
|
|
if (percent >= p.chapters[i].percent) {
|
|
cand = p.chapters[i];
|
|
} else {
|
|
return cand;
|
|
}
|
|
}
|
|
return cand;
|
|
}
|
|
|
|
|
|
function pageForChapter(fragment, pageDiv) {
|
|
if (!fragment) {
|
|
return 1;
|
|
}
|
|
for (var i = 0; i < p.chapters.length; ++i) {
|
|
if (p.chapters[i].fragment == fragment) {
|
|
return percentToPageNumber(p.chapters[i].percent);
|
|
}
|
|
}
|
|
var doc = pageDiv.m.activeFrame.contentDocument;
|
|
var node = doc.getElementById(fragment);
|
|
var percent = pageDiv.m.dimensions.percentageThroughOfNode(node);
|
|
return percentToPageNumber(percent);
|
|
}
|
|
|
|
|
|
function pageForXPath(xpath, pageDiv) {
|
|
var doc = pageDiv.m.activeFrame.contentDocument;
|
|
var percent = 0;
|
|
if (typeof doc.evaluate == "function") {
|
|
var node = doc.evaluate(
|
|
xpath,
|
|
doc,
|
|
null,
|
|
9,
|
|
null
|
|
).singleNodeValue;
|
|
var percent = pageDiv.m.dimensions.percentageThroughOfNode(node);
|
|
}
|
|
return percentToPageNumber(percent);
|
|
}
|
|
|
|
|
|
function percentToPageNumber(pc) {
|
|
return Math.floor(pc * p.pageLength) + 1;
|
|
}
|
|
|
|
|
|
function lastPageNumber() {
|
|
return p.pageLength;
|
|
}
|
|
|
|
|
|
API.applyTo = applyTo;
|
|
API.updateDimensions = updateDimensions;
|
|
API.chapterForPage = chapterForPage;
|
|
API.pageForChapter = pageForChapter;
|
|
API.pageForXPath = pageForXPath;
|
|
API.lastPageNumber = lastPageNumber;
|
|
|
|
return API;
|
|
}
|
|
|
|
Monocle.pieceLoaded('component');
|
|
|
|
Monocle.Dimensions = {}
|
|
Monocle.Controls = {};
|
|
Monocle.Flippers = {};
|
|
Monocle.Panels = {};
|
|
|
|
Monocle.Controls.Panel = function () {
|
|
|
|
var API = { constructor: Monocle.Controls.Panel }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
evtCallbacks: {}
|
|
}
|
|
|
|
function createControlElements(cntr) {
|
|
p.div = cntr.dom.make('div', k.CLS.panel);
|
|
p.div.dom.setStyles(k.DEFAULT_STYLES);
|
|
Monocle.Events.listenForContact(
|
|
p.div,
|
|
{
|
|
'start': start,
|
|
'move': move,
|
|
'end': end,
|
|
'cancel': cancel
|
|
},
|
|
{ useCapture: false }
|
|
);
|
|
return p.div;
|
|
}
|
|
|
|
|
|
function listenTo(evtCallbacks) {
|
|
p.evtCallbacks = evtCallbacks;
|
|
}
|
|
|
|
|
|
function deafen() {
|
|
p.evtCallbacks = {}
|
|
}
|
|
|
|
|
|
function start(evt) {
|
|
p.contact = true;
|
|
evt.m.offsetX += p.div.offsetLeft;
|
|
evt.m.offsetY += p.div.offsetTop;
|
|
expand();
|
|
invoke('start', evt);
|
|
}
|
|
|
|
|
|
function move(evt) {
|
|
if (!p.contact) {
|
|
return;
|
|
}
|
|
invoke('move', evt);
|
|
}
|
|
|
|
|
|
function end(evt) {
|
|
if (!p.contact) {
|
|
return;
|
|
}
|
|
Monocle.Events.deafenForContact(p.div, p.listeners);
|
|
contract();
|
|
p.contact = false;
|
|
invoke('end', evt);
|
|
}
|
|
|
|
|
|
function cancel(evt) {
|
|
if (!p.contact) {
|
|
return;
|
|
}
|
|
Monocle.Events.deafenForContact(p.div, p.listeners);
|
|
contract();
|
|
p.contact = false;
|
|
invoke('cancel', evt);
|
|
}
|
|
|
|
|
|
function invoke(evtType, evt) {
|
|
if (p.evtCallbacks[evtType]) {
|
|
p.evtCallbacks[evtType](API, evt.m.offsetX, evt.m.offsetY);
|
|
}
|
|
evt.preventDefault();
|
|
}
|
|
|
|
|
|
function expand() {
|
|
if (p.expanded) {
|
|
return;
|
|
}
|
|
p.div.dom.addClass(k.CLS.expanded);
|
|
p.expanded = true;
|
|
}
|
|
|
|
|
|
function contract(evt) {
|
|
if (!p.expanded) {
|
|
return;
|
|
}
|
|
p.div.dom.removeClass(k.CLS.expanded);
|
|
p.expanded = false;
|
|
}
|
|
|
|
|
|
API.createControlElements = createControlElements;
|
|
API.listenTo = listenTo;
|
|
API.deafen = deafen;
|
|
API.expand = expand;
|
|
API.contract = contract;
|
|
|
|
return API;
|
|
}
|
|
|
|
|
|
Monocle.Controls.Panel.CLS = {
|
|
panel: 'panel',
|
|
expanded: 'controls_panel_expanded'
|
|
}
|
|
Monocle.Controls.Panel.DEFAULT_STYLES = {
|
|
position: 'absolute',
|
|
height: '100%'
|
|
}
|
|
|
|
|
|
Monocle.pieceLoaded('controls/panel');
|
|
Monocle.Panels.TwoPane = function (flipper, evtCallbacks) {
|
|
|
|
var API = { constructor: Monocle.Panels.TwoPane }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {}
|
|
|
|
|
|
function initialize() {
|
|
p.panels = {
|
|
forwards: new Monocle.Controls.Panel(),
|
|
backwards: new Monocle.Controls.Panel()
|
|
}
|
|
|
|
for (dir in p.panels) {
|
|
flipper.properties.reader.addControl(p.panels[dir]);
|
|
p.panels[dir].listenTo(evtCallbacks);
|
|
p.panels[dir].properties.direction = flipper.constants[dir.toUpperCase()];
|
|
var style = { "width": k.WIDTH };
|
|
style[(dir == "forwards" ? "right" : "left")] = 0;
|
|
p.panels[dir].properties.div.dom.setStyles(style);
|
|
}
|
|
}
|
|
|
|
|
|
initialize();
|
|
|
|
return API;
|
|
}
|
|
|
|
Monocle.Panels.TwoPane.WIDTH = "50%";
|
|
|
|
Monocle.pieceLoaded('panels/twopane');
|
|
Monocle.Dimensions.Vert = function (pageDiv) {
|
|
|
|
var API = { constructor: Monocle.Dimensions.Vert }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
page: pageDiv,
|
|
reader: pageDiv.m.reader
|
|
}
|
|
|
|
|
|
function initialize() {
|
|
p.reader.listen('monocle:componentchange', componentChanged);
|
|
}
|
|
|
|
|
|
function hasChanged() {
|
|
return getBodyHeight() != p.bodyHeight || getPageHeight != p.pageHeight;
|
|
}
|
|
|
|
|
|
function measure() {
|
|
p.bodyHeight = getBodyHeight();
|
|
p.pageHeight = getPageHeight();
|
|
p.length = Math.ceil(p.bodyHeight / p.pageHeight);
|
|
return p.length;
|
|
}
|
|
|
|
|
|
function pages() {
|
|
return p.length;
|
|
}
|
|
|
|
|
|
function getBodyHeight() {
|
|
return p.page.m.activeFrame.contentDocument.body.scrollHeight;
|
|
}
|
|
|
|
|
|
function getPageHeight() {
|
|
return p.page.m.activeFrame.offsetHeight - k.GUTTER;
|
|
}
|
|
|
|
|
|
function percentageThroughOfNode(target) {
|
|
if (!target) {
|
|
return 0;
|
|
}
|
|
var doc = p.page.m.activeFrame.contentDocument;
|
|
var offset = 0;
|
|
if (target.getBoundingClientRect) {
|
|
offset = target.getBoundingClientRect().top;
|
|
offset -= doc.body.getBoundingClientRect().top;
|
|
} else {
|
|
var oldScrollTop = doc.body.scrollTop;
|
|
target.scrollIntoView();
|
|
offset = doc.body.scrollTop;
|
|
doc.body.scrollLeft = 0;
|
|
doc.body.scrollTop = oldScrollTop;
|
|
}
|
|
|
|
var percent = offset / p.bodyHeight;
|
|
return percent;
|
|
}
|
|
|
|
|
|
function componentChanged(evt) {
|
|
if (evt.m['page'] != p.page) { return; }
|
|
var sheaf = p.page.m.sheafDiv;
|
|
var cmpt = p.page.m.activeFrame;
|
|
sheaf.dom.setStyles(k.SHEAF_STYLES);
|
|
cmpt.dom.setStyles(k.COMPONENT_STYLES);
|
|
var doc = evt.m['document'];
|
|
doc.documentElement.style.overflow = 'hidden';
|
|
doc.body.style.marginRight = '10px !important';
|
|
cmpt.contentWindow.scrollTo(0,0);
|
|
}
|
|
|
|
|
|
function locusToOffset(locus) {
|
|
return p.pageHeight * (locus.page - 1);
|
|
}
|
|
|
|
|
|
API.hasChanged = hasChanged;
|
|
API.measure = measure;
|
|
API.pages = pages;
|
|
API.percentageThroughOfNode = percentageThroughOfNode;
|
|
API.locusToOffset = locusToOffset;
|
|
|
|
initialize();
|
|
|
|
return API;
|
|
}
|
|
|
|
Monocle.Dimensions.Vert.GUTTER = 10;
|
|
Monocle.Flippers.Legacy = function (reader) {
|
|
|
|
var API = { constructor: Monocle.Flippers.Legacy }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
pageCount: 1,
|
|
divs: {}
|
|
}
|
|
|
|
|
|
function initialize() {
|
|
p.reader = reader;
|
|
}
|
|
|
|
|
|
function addPage(pageDiv) {
|
|
pageDiv.m.dimensions = new Monocle.Dimensions.Vert(pageDiv);
|
|
}
|
|
|
|
|
|
function getPlace() {
|
|
return page().m.place;
|
|
}
|
|
|
|
|
|
function moveTo(locus, callback) {
|
|
var fn = frameToLocus;
|
|
if (typeof callback == "function") {
|
|
fn = function (locus) { frameToLocus(locus); callback(locus); }
|
|
}
|
|
p.reader.getBook().setOrLoadPageAt(page(), locus, fn);
|
|
}
|
|
|
|
|
|
function listenForInteraction(panelClass) {
|
|
if (typeof panelClass != "function") {
|
|
panelClass = k.DEFAULT_PANELS_CLASS;
|
|
if (!panelClass) {
|
|
console.warn("Invalid panel class.")
|
|
}
|
|
}
|
|
p.panels = new panelClass(API, { 'end': turn });
|
|
}
|
|
|
|
|
|
function page() {
|
|
return p.reader.dom.find('page');
|
|
}
|
|
|
|
|
|
function turn(panel) {
|
|
var dir = panel.properties.direction;
|
|
var place = getPlace();
|
|
if (
|
|
(dir < 0 && place.onFirstPageOfBook()) ||
|
|
(dir > 0 && place.onLastPageOfBook())
|
|
) { return; }
|
|
moveTo({ page: getPlace().pageNumber() + dir });
|
|
}
|
|
|
|
|
|
function frameToLocus(locus) {
|
|
var cmpt = p.reader.dom.find('component');
|
|
var win = cmpt.contentWindow;
|
|
var srcY = scrollPos(win);
|
|
var dims = page().m.dimensions;
|
|
var pageHeight = dims.properties.pageHeight;
|
|
var destY = dims.locusToOffset(locus);
|
|
|
|
if (Math.abs(destY - srcY) > pageHeight) {
|
|
return win.scrollTo(0, destY);
|
|
}
|
|
|
|
showIndicator(win, srcY < destY ? srcY + pageHeight : srcY);
|
|
Monocle.defer(
|
|
function () { smoothScroll(win, srcY, destY, 300, scrollingFinished); },
|
|
150
|
|
);
|
|
}
|
|
|
|
|
|
function scrollPos(win) {
|
|
if (win.pageYOffset) {
|
|
return win.pageYOffset;
|
|
}
|
|
if (win.document.documentElement && win.document.documentElement.scrollTop) {
|
|
return win.document.documentElement.scrollTop;
|
|
}
|
|
if (win.document.body.scrollTop) {
|
|
return win.document.body.scrollTop;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
function smoothScroll(win, currY, finalY, duration, callback) {
|
|
clearTimeout(win.smoothScrollInterval);
|
|
var stamp = (new Date()).getTime();
|
|
var frameRate = 40;
|
|
var step = (finalY - currY) * (frameRate / duration);
|
|
var stepFn = function () {
|
|
var destY = currY + step;
|
|
if (
|
|
(new Date()).getTime() - stamp > duration ||
|
|
Math.abs(currY - finalY) < Math.abs((currY + step) - finalY)
|
|
) {
|
|
clearTimeout(win.smoothScrollInterval);
|
|
win.scrollTo(0, finalY);
|
|
if (callback) { callback(); }
|
|
} else {
|
|
win.scrollTo(0, destY);
|
|
currY = destY;
|
|
}
|
|
}
|
|
win.smoothScrollInterval = setInterval(stepFn, frameRate);
|
|
}
|
|
|
|
|
|
function scrollingFinished() {
|
|
hideIndicator(page().m.activeFrame.contentWindow);
|
|
p.reader.dispatchEvent('monocle:turn');
|
|
}
|
|
|
|
|
|
function showIndicator(win, pos) {
|
|
if (p.hideTO) { clearTimeout(p.hideTO); }
|
|
|
|
var doc = win.document;
|
|
if (!doc.body.indicator) {
|
|
doc.body.indicator = createIndicator(doc);
|
|
doc.body.appendChild(doc.body.indicator);
|
|
}
|
|
doc.body.indicator.line.style.display = "block";
|
|
doc.body.indicator.style.opacity = 1;
|
|
positionIndicator(pos);
|
|
}
|
|
|
|
|
|
function hideIndicator(win) {
|
|
var doc = win.document;
|
|
p.hideTO = Monocle.defer(
|
|
function () {
|
|
if (!doc.body.indicator) {
|
|
doc.body.indicator = createIndicator(doc);
|
|
doc.body.appendChild(doc.body.indicator);
|
|
}
|
|
var dims = page().m.dimensions;
|
|
positionIndicator(
|
|
dims.locusToOffset(getPlace().getLocus()) + dims.properties.pageHeight
|
|
)
|
|
doc.body.indicator.line.style.display = "none";
|
|
doc.body.indicator.style.opacity = 0.5;
|
|
},
|
|
600
|
|
);
|
|
}
|
|
|
|
|
|
function createIndicator(doc) {
|
|
var iBox = doc.createElement('div');
|
|
doc.body.appendChild(iBox);
|
|
Monocle.Styles.applyRules(iBox, k.STYLES.iBox);
|
|
|
|
iBox.arrow = doc.createElement('div');
|
|
iBox.appendChild(iBox.arrow);
|
|
Monocle.Styles.applyRules(iBox.arrow, k.STYLES.arrow);
|
|
|
|
iBox.line = doc.createElement('div');
|
|
iBox.appendChild(iBox.line);
|
|
Monocle.Styles.applyRules(iBox.line, k.STYLES.line);
|
|
|
|
return iBox;
|
|
}
|
|
|
|
|
|
function positionIndicator(y) {
|
|
var p = page();
|
|
var doc = p.m.activeFrame.contentDocument;
|
|
var maxHeight = p.m.dimensions.properties.bodyHeight;
|
|
maxHeight -= doc.body.indicator.offsetHeight;
|
|
if (y > maxHeight) {
|
|
y = maxHeight;
|
|
}
|
|
doc.body.indicator.style.top = y + "px";
|
|
}
|
|
|
|
|
|
API.pageCount = p.pageCount;
|
|
API.addPage = addPage;
|
|
API.getPlace = getPlace;
|
|
API.moveTo = moveTo;
|
|
API.listenForInteraction = listenForInteraction;
|
|
|
|
initialize();
|
|
|
|
return API;
|
|
}
|
|
|
|
Monocle.Flippers.Legacy.FORWARDS = 1;
|
|
Monocle.Flippers.Legacy.BACKWARDS = -1;
|
|
Monocle.Flippers.Legacy.DEFAULT_PANELS_CLASS = Monocle.Panels.TwoPane;
|
|
|
|
Monocle.Flippers.Legacy.STYLES = {
|
|
iBox: {
|
|
'position': 'absolute',
|
|
'right': 0,
|
|
'left': 0,
|
|
'height': '10px'
|
|
},
|
|
arrow: {
|
|
'position': 'absolute',
|
|
'right': 0,
|
|
'height': '10px',
|
|
'width': '10px',
|
|
'background': '#333',
|
|
'border-radius': '6px'
|
|
},
|
|
line: {
|
|
'width': '100%',
|
|
'border-top': '2px dotted #333',
|
|
'margin-top': '5px'
|
|
}
|
|
}
|
|
|
|
Monocle.pieceLoaded('flippers/legacy');
|
|
Monocle.Dimensions.Columns = function (pageDiv) {
|
|
|
|
var API = { constructor: Monocle.Dimensions.Columns }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
page: pageDiv,
|
|
reader: pageDiv.m.reader,
|
|
dirty: true
|
|
}
|
|
|
|
|
|
function initialize() {
|
|
p.reader.listen('monocle:componentchange', componentChanged);
|
|
}
|
|
|
|
|
|
function hasChanged() {
|
|
if (p.dirty) { return true; }
|
|
var newMeasurements = rawMeasurements();
|
|
return (
|
|
(!p.measurements) ||
|
|
(p.measurements.width != newMeasurements.width) ||
|
|
(p.measurements.height != newMeasurements.height) ||
|
|
(p.measurements.scrollWidth != newMeasurements.scrollWidth)
|
|
);
|
|
}
|
|
|
|
|
|
function measure() {
|
|
setColumnWidth();
|
|
p.measurements = rawMeasurements();
|
|
|
|
if (
|
|
Monocle.Browser.has.iframeDoubleWidthBug &&
|
|
p.measurements.scrollWidth == p.measurements.width * 2
|
|
) {
|
|
var doc = p.page.m.activeFrame.contentDocument;
|
|
var lc;
|
|
for (var i = doc.body.childNodes.length - 1; i >= 0; --i) {
|
|
lc = doc.body.childNodes[i];
|
|
if (lc.getBoundingClientRect) { break; }
|
|
}
|
|
if (!lc || !lc.getBoundingClientRect) {
|
|
console.warn('Empty document for page['+p.page.m.pageIndex+']');
|
|
p.measurements.scrollWidth = p.measurements.width;
|
|
} else {
|
|
var bcr = lc.getBoundingClientRect();
|
|
if (
|
|
bcr.right > p.measurements.width ||
|
|
bcr.bottom > p.measurements.height
|
|
) {
|
|
p.measurements.scrollWidth = p.measurements.width * 2;
|
|
} else {
|
|
p.measurements.scrollWidth = p.measurements.width;
|
|
}
|
|
}
|
|
}
|
|
|
|
p.length = Math.ceil(p.measurements.scrollWidth / p.measurements.width);
|
|
p.dirty = false;
|
|
return p.length;
|
|
}
|
|
|
|
|
|
function pages() {
|
|
if (p.dirty) {
|
|
console.warn('Accessing pages() when dimensions are dirty.')
|
|
return 0;
|
|
}
|
|
return p.length;
|
|
}
|
|
|
|
|
|
function percentageThroughOfNode(target) {
|
|
if (!target) {
|
|
return 0;
|
|
}
|
|
var doc = p.page.m.activeFrame.contentDocument;
|
|
var offset = 0;
|
|
if (target.getBoundingClientRect) {
|
|
offset = target.getBoundingClientRect().left;
|
|
offset -= doc.body.getBoundingClientRect().left;
|
|
} else {
|
|
var scroller = scrollerElement();
|
|
var oldScrollLeft = scroller.scrollLeft;
|
|
target.scrollIntoView();
|
|
offset = scroller.scrollLeft;
|
|
scroller.scrollTop = 0;
|
|
scroller.scrollLeft = oldScrollLeft;
|
|
}
|
|
|
|
var percent = offset / p.measurements.scrollWidth;
|
|
return percent;
|
|
}
|
|
|
|
|
|
function componentChanged(evt) {
|
|
if (evt.m['page'] != p.page) { return; }
|
|
var doc = evt.m['document'];
|
|
if (Monocle.Browser.has.columnOverflowPaintBug) {
|
|
var div = doc.createElement('div');
|
|
Monocle.Styles.applyRules(div, k.BODY_STYLES);
|
|
div.style.cssText += "overflow: scroll !important;";
|
|
while (doc.body.childNodes.length) {
|
|
div.appendChild(doc.body.firstChild);
|
|
}
|
|
doc.body.appendChild(div);
|
|
} else {
|
|
Monocle.Styles.applyRules(doc.body, k.BODY_STYLES);
|
|
|
|
if (Monocle.Browser.is.WebKit) {
|
|
doc.documentElement.style.overflow = 'hidden';
|
|
}
|
|
}
|
|
|
|
p.dirty = true;
|
|
}
|
|
|
|
|
|
function setColumnWidth() {
|
|
var cw = p.page.m.sheafDiv.clientWidth;
|
|
if (currBodyStyleValue('column-width') != cw+"px") {
|
|
Monocle.Styles.affix(columnedElement(), 'column-width', cw+"px");
|
|
p.dirty = true;
|
|
}
|
|
}
|
|
|
|
|
|
function rawMeasurements() {
|
|
var sheaf = p.page.m.sheafDiv;
|
|
return {
|
|
width: sheaf.clientWidth,
|
|
height: sheaf.clientHeight,
|
|
scrollWidth: scrollerWidth()
|
|
}
|
|
}
|
|
|
|
|
|
function scrollerElement() {
|
|
if (Monocle.Browser.has.mustScrollSheaf) {
|
|
return p.page.m.sheafDiv;
|
|
} else {
|
|
return columnedElement();
|
|
}
|
|
}
|
|
|
|
|
|
function columnedElement() {
|
|
var elem = p.page.m.activeFrame.contentDocument.body;
|
|
return Monocle.Browser.has.columnOverflowPaintBug ? elem.firstChild : elem;
|
|
}
|
|
|
|
|
|
function scrollerWidth() {
|
|
var bdy = p.page.m.activeFrame.contentDocument.body;
|
|
if (Monocle.Browser.has.iframeDoubleWidthBug) {
|
|
if (Monocle.Browser.on.Kindle3) {
|
|
return scrollerElement().scrollWidth;
|
|
} else if (Monocle.Browser.on.Android) {
|
|
return bdy.scrollWidth;
|
|
} else if (Monocle.Browser.iOSVersion < "4.1") {
|
|
var hbw = bdy.scrollWidth / 2;
|
|
var sew = scrollerElement().scrollWidth;
|
|
return Math.max(sew, hbw);
|
|
} else {
|
|
bdy.scrollWidth; // Throw one away. Nuts.
|
|
var hbw = bdy.scrollWidth / 2;
|
|
return hbw;
|
|
}
|
|
} else if (bdy.getBoundingClientRect) {
|
|
var elems = bdy.getElementsByTagName('*');
|
|
var bdyRect = bdy.getBoundingClientRect();
|
|
var l = bdyRect.left, r = bdyRect.right;
|
|
for (var i = elems.length - 1; i >= 0; --i) {
|
|
var rect = elems[i].getBoundingClientRect();
|
|
l = Math.min(l, rect.left);
|
|
r = Math.max(r, rect.right);
|
|
}
|
|
return Math.abs(l) + Math.abs(r);
|
|
}
|
|
|
|
return scrollerElement().scrollWidth;
|
|
}
|
|
|
|
|
|
function currBodyStyleValue(property) {
|
|
var win = p.page.m.activeFrame.contentWindow;
|
|
var doc = win.document;
|
|
if (!doc.body) { return null; }
|
|
var currStyle = win.getComputedStyle(doc.body, null);
|
|
return currStyle.getPropertyValue(property);
|
|
}
|
|
|
|
|
|
function locusToOffset(locus) {
|
|
return 0 - (p.measurements.width * (locus.page - 1));
|
|
}
|
|
|
|
|
|
function translateToLocus(locus) {
|
|
var offset = locusToOffset(locus);
|
|
p.page.m.offset = 0 - offset;
|
|
if (k.SETX && !Monocle.Browser.has.columnOverflowPaintBug) {
|
|
var bdy = p.page.m.activeFrame.contentDocument.body;
|
|
Monocle.Styles.affix(bdy, "transform", "translateX("+offset+"px)");
|
|
} else {
|
|
var scrElem = scrollerElement();
|
|
scrElem.scrollLeft = 0 - offset;
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
|
|
API.hasChanged = hasChanged;
|
|
API.measure = measure;
|
|
API.pages = pages;
|
|
API.percentageThroughOfNode = percentageThroughOfNode;
|
|
|
|
API.locusToOffset = locusToOffset;
|
|
API.translateToLocus = translateToLocus;
|
|
|
|
initialize();
|
|
|
|
return API;
|
|
}
|
|
|
|
|
|
Monocle.Dimensions.Columns.BODY_STYLES = {
|
|
"position": "absolute",
|
|
"height": "100%",
|
|
"-webkit-column-gap": "0",
|
|
"-webkit-column-fill": "auto",
|
|
"-moz-column-gap": "0",
|
|
"-moz-column-fill": "auto",
|
|
"column-gap": "0",
|
|
"column-fill": "auto"
|
|
}
|
|
|
|
Monocle.Dimensions.Columns.SETX = true; // Set to false for scrollLeft.
|
|
|
|
if (Monocle.Browser.has.iframeDoubleWidthBug) {
|
|
Monocle.Dimensions.Columns.BODY_STYLES["min-width"] = "200%";
|
|
} else {
|
|
Monocle.Dimensions.Columns.BODY_STYLES["width"] = "100%";
|
|
}
|
|
Monocle.Flippers.Slider = function (reader) {
|
|
if (Monocle.Flippers == this) {
|
|
return new Monocle.Flippers.Slider(reader);
|
|
}
|
|
|
|
var API = { constructor: Monocle.Flippers.Slider }
|
|
var k = API.constants = API.constructor;
|
|
var p = API.properties = {
|
|
pageCount: 2,
|
|
activeIndex: 1,
|
|
turnData: {}
|
|
}
|
|
|
|
|
|
function initialize() {
|
|
p.reader = reader;
|
|
}
|
|
|
|
|
|
function addPage(pageDiv) {
|
|
pageDiv.m.dimensions = new Monocle.Dimensions.Columns(pageDiv);
|
|
|
|
Monocle.Styles.setX(pageDiv, "0px");
|
|
}
|
|
|
|
|
|
function visiblePages() {
|
|
return [upperPage()];
|
|
}
|
|
|
|
|
|
function listenForInteraction(panelClass) {
|
|
interactiveMode(true);
|
|
interactiveMode(false);
|
|
|
|
if (typeof panelClass != "function") {
|
|
panelClass = k.DEFAULT_PANELS_CLASS;
|
|
if (!panelClass) {
|
|
console.warn("Invalid panel class.")
|
|
}
|
|
}
|
|
var q = function (action, panel, x) {
|
|
var dir = panel.properties.direction;
|
|
if (action == "lift") {
|
|
lift(dir, x);
|
|
} else if (action == "release") {
|
|
release(dir, x);
|
|
}
|
|
}
|
|
p.panels = new panelClass(
|
|
API,
|
|
{
|
|
'start': function (panel, x) { q('lift', panel, x); },
|
|
'move': function (panel, x) { turning(panel.properties.direction, x); },
|
|
'end': function (panel, x) { q('release', panel, x); },
|
|
'cancel': function (panel, x) { q('release', panel, x); }
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
function interactiveMode(bState) {
|
|
p.reader.dispatchEvent('monocle:interactive:'+(bState ? 'on' : 'off'));
|
|
if (!Monocle.Browser.has.selectThruBug) {
|
|
return;
|
|
}
|
|
if (p.interactive = bState) {
|
|
if (p.activeIndex != 0) {
|
|
var place = getPlace();
|
|
if (place) {
|
|
setPage(
|
|
p.reader.dom.find('page', 0),
|
|
place.getLocus(),
|
|
function () {
|
|
flipPages();
|
|
prepareNextPage();
|
|
}
|
|
);
|
|
} else {
|
|
flipPages();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function getPlace(pageDiv) {
|
|
pageDiv = pageDiv || upperPage();
|
|
return pageDiv.m ? pageDiv.m.place : null;
|
|
}
|
|
|
|
|
|
function moveTo(locus, callback) {
|
|
var fn = function () {
|
|
prepareNextPage(function () {
|
|
if (typeof callback == "function") { callback(); }
|
|
announceTurn();
|
|
});
|
|
}
|
|
setPage(upperPage(), locus, fn);
|
|
}
|
|
|
|
|
|
function setPage(pageDiv, locus, callback) {
|
|
ensureWaitControl();
|
|
p.reader.getBook().setOrLoadPageAt(
|
|
pageDiv,
|
|
locus,
|
|
function (locus) {
|
|
pageDiv.m.dimensions.translateToLocus(locus);
|
|
if (callback) { callback(); }
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
function upperPage() {
|
|
return p.reader.dom.find('page', p.activeIndex);
|
|
}
|
|
|
|
|
|
function lowerPage() {
|
|
return p.reader.dom.find('page', (p.activeIndex + 1) % 2);
|
|
}
|
|
|
|
|
|
function flipPages() {
|
|
upperPage().style.zIndex = 1;
|
|
lowerPage().style.zIndex = 2;
|
|
return p.activeIndex = (p.activeIndex + 1) % 2;
|
|
}
|
|
|
|
|
|
function lift(dir, boxPointX) {
|
|
if (p.turnData.lifting || p.turnData.releasing) { return; }
|
|
|
|
p.turnData.points = {
|
|
start: boxPointX,
|
|
min: boxPointX,
|
|
max: boxPointX
|
|
}
|
|
p.turnData.lifting = true;
|
|
|
|
if (dir == k.FORWARDS) {
|
|
if (getPlace().onLastPageOfBook()) {
|
|
p.reader.dispatchEvent(
|
|
'monocle:boundaryend',
|
|
{
|
|
locus: getPlace().getLocus({ direction : dir }),
|
|
page: upperPage()
|
|
}
|
|
);
|
|
resetTurnData();
|
|
return;
|
|
}
|
|
onGoingForward(boxPointX);
|
|
} else if (dir == k.BACKWARDS) {
|
|
if (getPlace().onFirstPageOfBook()) {
|
|
p.reader.dispatchEvent(
|
|
'monocle:boundarystart',
|
|
{
|
|
locus: getPlace().getLocus({ direction : dir }),
|
|
page: upperPage()
|
|
}
|
|
);
|
|
resetTurnData();
|
|
return;
|
|
}
|
|
onGoingBackward(boxPointX);
|
|
} else {
|
|
console.warn("Invalid direction: " + dir);
|
|
}
|
|
}
|
|
|
|
|
|
function turning(dir, boxPointX) {
|
|
if (!p.turnData.points) { return; }
|
|
if (p.turnData.lifting || p.turnData.releasing) { return; }
|
|
checkPoint(boxPointX);
|
|
slideToCursor(boxPointX, null, "0");
|
|
}
|
|
|
|
|
|
function release(dir, boxPointX) {
|
|
if (!p.turnData.points) {
|
|
return;
|
|
}
|
|
if (p.turnData.lifting) {
|
|
p.turnData.releaseArgs = [dir, boxPointX];
|
|
return;
|
|
}
|
|
if (p.turnData.releasing) {
|
|
return;
|
|
}
|
|
|
|
checkPoint(boxPointX);
|
|
|
|
p.turnData.releasing = true;
|
|
showWaitControl(lowerPage());
|
|
|
|
if (dir == k.FORWARDS) {
|
|
if (
|
|
p.turnData.points.tap ||
|
|
p.turnData.points.start - boxPointX > 60 ||
|
|
p.turnData.points.min >= boxPointX
|
|
) {
|
|
slideOut(afterGoingForward);
|
|
} else {
|
|
slideIn(afterCancellingForward);
|
|
}
|
|
} else if (dir == k.BACKWARDS) {
|
|
if (
|
|
p.turnData.points.tap ||
|
|
boxPointX - p.turnData.points.start > 60 ||
|
|
p.turnData.points.max <= boxPointX
|
|
) {
|
|
slideIn(afterGoingBackward);
|
|
} else {
|
|
slideOut(afterCancellingBackward);
|
|
}
|
|
} else {
|
|
console.warn("Invalid direction: " + dir);
|
|
}
|
|
}
|
|
|
|
|
|
function checkPoint(boxPointX) {
|
|
p.turnData.points.min = Math.min(p.turnData.points.min, boxPointX);
|
|
p.turnData.points.max = Math.max(p.turnData.points.max, boxPointX);
|
|
p.turnData.points.tap = p.turnData.points.max - p.turnData.points.min < 10;
|
|
}
|
|
|
|
|
|
function onGoingForward(x) {
|
|
lifted(x);
|
|
}
|
|
|
|
|
|
function onGoingBackward(x) {
|
|
var lp = lowerPage(), up = upperPage();
|
|
showWaitControl(up);
|
|
jumpOut(lp, // move lower page off-screen
|
|
function () {
|
|
flipPages(); // flip lower to upper
|
|
setPage( // set upper page to previous
|
|
lp,
|
|
getPlace(lowerPage()).getLocus({ direction: k.BACKWARDS }),
|
|
function () {
|
|
lifted(x);
|
|
hideWaitControl(up);
|
|
}
|
|
);
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
function afterGoingForward() {
|
|
var up = upperPage(), lp = lowerPage();
|
|
if (p.interactive) {
|
|
showWaitControl(up);
|
|
showWaitControl(lp);
|
|
setPage( // set upper (off screen) to current
|
|
up,
|
|
getPlace().getLocus({ direction: k.FORWARDS }),
|
|
function () {
|
|
jumpIn(up, function () { prepareNextPage(announceTurn); });
|
|
}
|
|
);
|
|
} else {
|
|
showWaitControl(lp);
|
|
flipPages();
|
|
jumpIn(up, function () { prepareNextPage(announceTurn); });
|
|
}
|
|
}
|
|
|
|
|
|
function afterGoingBackward() {
|
|
if (p.interactive) {
|
|
setPage( // set lower page to current
|
|
lowerPage(),
|
|
getPlace().getLocus(),
|
|
function () {
|
|
flipPages(); // flip lower to upper
|
|
prepareNextPage(announceTurn);
|
|
}
|
|
);
|
|
} else {
|
|
announceTurn();
|
|
}
|
|
}
|
|
|
|
|
|
function afterCancellingForward() {
|
|
resetTurnData();
|
|
}
|
|
|
|
|
|
function afterCancellingBackward() {
|
|
flipPages(); // flip upper to lower
|
|
jumpIn( // move lower back onto screen
|
|
lowerPage(),
|
|
function () { prepareNextPage(resetTurnData); }
|
|
);
|
|
}
|
|
|
|
|
|
function prepareNextPage(callback) {
|
|
setPage(
|
|
lowerPage(),
|
|
getPlace().getLocus({ direction: k.FORWARDS }),
|
|
callback
|
|
);
|
|
}
|
|
|
|
|
|
function lifted(x) {
|
|
p.turnData.lifting = false;
|
|
var releaseArgs = p.turnData.releaseArgs;
|
|
if (releaseArgs) {
|
|
p.turnData.releaseArgs = null;
|
|
release(releaseArgs[0], releaseArgs[1]);
|
|
} else if (x) {
|
|
slideToCursor(x);
|
|
}
|
|
}
|
|
|
|
|
|
function announceTurn() {
|
|
p.reader.dispatchEvent('monocle:turn');
|
|
resetTurnData();
|
|
}
|
|
|
|
|
|
function resetTurnData() {
|
|
hideWaitControl(upperPage());
|
|
hideWaitControl(lowerPage());
|
|
p.turnData = {};
|
|
}
|
|
|
|
|
|
function setX(elem, x, options, callback) {
|
|
var duration;
|
|
|
|
if (!options.duration) {
|
|
duration = 0;
|
|
} else {
|
|
duration = parseInt(options['duration']);
|
|
}
|
|
|
|
if (typeof(x) == "number") { x = x + "px"; }
|
|
|
|
if (typeof WebKitTransitionEvent != "undefined") {
|
|
if (duration) {
|
|
transition = '-webkit-transform';
|
|
transition += ' ' + duration + "ms";
|
|
transition += ' ' + (options['timing'] || 'linear');
|
|
transition += ' ' + (options['delay'] || 0) + 'ms';
|
|
} else {
|
|
transition = 'none';
|
|
}
|
|
elem.style.webkitTransition = transition;
|
|
if (Monocle.Browser.has.transform3d) {
|
|
elem.style.webkitTransform = "translate3d("+x+",0,0)";
|
|
} else {
|
|
elem.style.webkitTransform = "translateX("+x+")";
|
|
}
|
|
|
|
} else if (duration > 0) {
|
|
clearTimeout(elem.setXTransitionInterval)
|
|
|
|
var stamp = (new Date()).getTime();
|
|
var frameRate = 40;
|
|
var finalX = parseInt(x);
|
|
var currX = getX(elem);
|
|
var step = (finalX - currX) * (frameRate / duration);
|
|
var stepFn = function () {
|
|
var destX = currX + step;
|
|
if (
|
|
(new Date()).getTime() - stamp > duration ||
|
|
Math.abs(currX - finalX) <= Math.abs((currX + step) - finalX)
|
|
) {
|
|
clearTimeout(elem.setXTransitionInterval);
|
|
Monocle.Styles.setX(elem, finalX);
|
|
if (elem.setXTCB) {
|
|
elem.setXTCB();
|
|
}
|
|
} else {
|
|
Monocle.Styles.setX(elem, destX);
|
|
currX = destX;
|
|
}
|
|
}
|
|
|
|
elem.setXTransitionInterval = setInterval(stepFn, frameRate);
|
|
} else {
|
|
Monocle.Styles.setX(elem, x);
|
|
}
|
|
|
|
if (elem.setXTCB) {
|
|
Monocle.Events.deafen(elem, 'webkitTransitionEnd', elem.setXTCB);
|
|
elem.setXTCB = null;
|
|
}
|
|
|
|
elem.setXTCB = function () {
|
|
if (callback) { callback(); }
|
|
}
|
|
|
|
var sX = getX(elem);
|
|
if (!duration || sX == parseInt(x)) {
|
|
elem.setXTCB();
|
|
} else {
|
|
Monocle.Events.listen(elem, 'webkitTransitionEnd', elem.setXTCB);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
function setX(elem, x, options, callback) {
|
|
var duration, transition;
|
|
|
|
if (!Monocle.Browser.has.transitions) {
|
|
duration = 0;
|
|
} else if (!options.duration) {
|
|
duration = 0;
|
|
} else {
|
|
duration = parseInt(options['duration']);
|
|
}
|
|
|
|
if (typeof(x) == "number") { x = x + "px"; }
|
|
|
|
if (duration) {
|
|
transition = duration + "ms";
|
|
transition += ' ' + (options['timing'] || 'linear');
|
|
transition += ' ' + (options['delay'] || 0) + 'ms';
|
|
} else {
|
|
transition = "none";
|
|
}
|
|
|
|
if (elem.setXTCB) {
|
|
Monocle.Events.deafen(elem, 'webkitTransitionEnd', elem.setXTCB);
|
|
Monocle.Events.deafen(elem, 'transitionend', elem.setXTCB);
|
|
elem.setXTCB = null;
|
|
}
|
|
|
|
elem.setXTCB = function () {
|
|
if (callback) { callback(); }
|
|
}
|
|
|
|
elem.dom.setBetaStyle('transition', transition);
|
|
if (Monocle.Browser.has.transform3d) {
|
|
elem.dom.setBetaStyle('transform', 'translate3d('+x+',0,0)');
|
|
} else {
|
|
elem.dom.setBetaStyle('transform', 'translateX('+x+')');
|
|
}
|
|
|
|
if (!duration) {
|
|
elem.setXTCB();
|
|
} else {
|
|
Monocle.Events.listen(elem, 'webkitTransitionEnd', elem.setXTCB);
|
|
Monocle.Events.listen(elem, 'transitionend', elem.setXTCB);
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
function getX(elem) {
|
|
if (typeof WebKitCSSMatrix == "object") {
|
|
var matrix = window.getComputedStyle(elem).webkitTransform;
|
|
matrix = new WebKitCSSMatrix(matrix);
|
|
return matrix.m41;
|
|
} else {
|
|
var prop = elem.style.MozTransform;
|
|
if (!prop || prop == "") { return 0; }
|
|
return parseFloat((/translateX\((\-?.*)px\)/).exec(prop)[1]) || 0;
|
|
}
|
|
}
|
|
|
|
|
|
function jumpIn(pageDiv, callback) {
|
|
var dur = Monocle.Browser.has.jumpFlickerBug ? 1 : 0;
|
|
Monocle.defer(function () {
|
|
setX(pageDiv, 0, { duration: dur }, callback);
|
|
});
|
|
}
|
|
|
|
|
|
function jumpOut(pageDiv, callback) {
|
|
var dur = Monocle.Browser.has.jumpFlickerBug ? 1 : 0;
|
|
Monocle.defer(function () {
|
|
setX(pageDiv, 0 - pageDiv.offsetWidth, { duration: dur }, callback);
|
|
});
|
|
}
|
|
|
|
|
|
|
|
function slideIn(callback) {
|
|
var slideOpts = {
|
|
duration: k.durations.SLIDE,
|
|
timing: 'ease-in'
|
|
};
|
|
Monocle.defer(function () {
|
|
setX(upperPage(), 0, slideOpts, callback);
|
|
});
|
|
}
|
|
|
|
|
|
function slideOut(callback) {
|
|
var slideOpts = {
|
|
duration: k.durations.SLIDE,
|
|
timing: 'ease-in'
|
|
};
|
|
Monocle.defer(function () {
|
|
setX(upperPage(), 0 - upperPage().offsetWidth, slideOpts, callback);
|
|
});
|
|
}
|
|
|
|
|
|
function slideToCursor(cursorX, callback, duration) {
|
|
setX(
|
|
upperPage(),
|
|
Math.min(0, cursorX - upperPage().offsetWidth),
|
|
{ duration: duration || k.durations.FOLLOW_CURSOR },
|
|
callback
|
|
);
|
|
}
|
|
|
|
|
|
function ensureWaitControl() {
|
|
if (p.waitControl) { return; }
|
|
p.waitControl = {
|
|
createControlElements: function (holder) {
|
|
return holder.dom.make('div', 'flippers_slider_wait');
|
|
}
|
|
}
|
|
p.reader.addControl(p.waitControl, 'page');
|
|
}
|
|
|
|
|
|
function showWaitControl(page) {
|
|
var ctrl = p.reader.dom.find('flippers_slider_wait', page.m.pageIndex);
|
|
ctrl.style.visibility = "visible";
|
|
}
|
|
|
|
|
|
function hideWaitControl(page) {
|
|
var ctrl = p.reader.dom.find('flippers_slider_wait', page.m.pageIndex);
|
|
ctrl.style.visibility = "hidden";
|
|
}
|
|
|
|
API.pageCount = p.pageCount;
|
|
API.addPage = addPage;
|
|
API.getPlace = getPlace;
|
|
API.moveTo = moveTo;
|
|
API.listenForInteraction = listenForInteraction;
|
|
|
|
API.visiblePages = visiblePages;
|
|
API.interactiveMode = interactiveMode;
|
|
|
|
initialize();
|
|
|
|
return API;
|
|
}
|
|
|
|
|
|
Monocle.Flippers.Slider.DEFAULT_PANELS_CLASS = Monocle.Panels.TwoPane;
|
|
Monocle.Flippers.Slider.FORWARDS = 1;
|
|
Monocle.Flippers.Slider.BACKWARDS = -1;
|
|
Monocle.Flippers.Slider.durations = {
|
|
SLIDE: 220,
|
|
FOLLOW_CURSOR: 100
|
|
}
|
|
|
|
Monocle.pieceLoaded('flippers/slider');
|
|
|
|
Monocle.pieceLoaded('monocle');
|