home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Narzedzia / Calibre / calibre-0.8.18.msi / file_339 < prev    next >
Text File  |  2011-06-15  |  91KB  |  3,632 lines

  1. Monocle = {
  2.   VERSION: "2.0.0"
  3. };
  4.  
  5.  
  6. Monocle.pieceLoaded = function (piece) {
  7.   if (typeof onMonoclePiece == 'function') {
  8.     onMonoclePiece(piece);
  9.   }
  10. }
  11.  
  12.  
  13. Monocle.defer = function (fn, time) {
  14.   if (fn && typeof fn == "function") {
  15.     return setTimeout(fn, time || 0);
  16.   }
  17. }
  18.  
  19.  
  20. Monocle.Browser = { engine: 'W3C' }
  21.  
  22. Monocle.Browser.is = {
  23.   IE: (!!(window.attachEvent && navigator.userAgent.indexOf('Opera') === -1)) &&
  24.     (Monocle.Browser.engine = "IE"),
  25.   Opera: navigator.userAgent.indexOf('Opera') > -1 &&
  26.     (Monocle.Browser.engine = "Opera"),
  27.   WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1 &&
  28.     (Monocle.Browser.engine = "WebKit"),
  29.   Gecko: navigator.userAgent.indexOf('Gecko') > -1 &&
  30.     navigator.userAgent.indexOf('KHTML') === -1 &&
  31.     (Monocle.Browser.engine = "Gecko"),
  32.   MobileSafari: !!navigator.userAgent.match(/AppleWebKit.*Mobile/)
  33. } // ... with thanks to PrototypeJS.
  34.  
  35.  
  36. Monocle.Browser.on = {
  37.   iPhone: navigator.userAgent.indexOf("iPhone") != -1,
  38.   iPad: navigator.userAgent.indexOf("iPad") != -1,
  39.   BlackBerry: navigator.userAgent.indexOf("BlackBerry") != -1,
  40.   Android: navigator.userAgent.indexOf('Android') != -1,
  41.   MacOSX: navigator.userAgent.indexOf('Mac OS X') != -1,
  42.   Kindle3: navigator.userAgent.match(/Kindle\/3/)
  43. }
  44.  
  45.  
  46. if (Monocle.Browser.is.MobileSafari) {
  47.   (function () {
  48.     var ver = navigator.userAgent.match(/ OS ([\d_]+)/);
  49.     if (ver) {
  50.       Monocle.Browser.iOSVersion = ver[1].replace(/_/g, '.');
  51.     } else {
  52.       console.warn("Unknown MobileSafari user agent: "+navigator.userAgent);
  53.     }
  54.   })();
  55. }
  56. Monocle.Browser.iOSVersionBelow = function (strOrNum) {
  57.   return Monocle.Browser.iOSVersion && Monocle.Browser.iOSVersion < strOrNum;
  58. }
  59.  
  60.  
  61. Monocle.Browser.CSSProps = {
  62.   engines: ["W3C", "WebKit", "Gecko", "Opera", "IE", "Konqueror"],
  63.   prefixes: ["", "-webkit-", "-moz-", "-o-", "-ms-", "-khtml-"],
  64.   domprefixes: ["", "Webkit", "Moz", "O", "ms", "Khtml"],
  65.   guineapig: document.createElement('div')
  66. }
  67.  
  68.  
  69. Monocle.Browser.CSSProps.capStr = function (wd) {
  70.   return wd ? wd.charAt(0).toUpperCase() + wd.substr(1) : "";
  71. }
  72.  
  73.  
  74. Monocle.Browser.CSSProps.toDOMProps = function (prop, prefix) {
  75.   var parts = prop.split('-');
  76.   for (var i = parts.length; i > 0; --i) {
  77.     parts[i] = Monocle.Browser.CSSProps.capStr(parts[i]);
  78.   }
  79.  
  80.   if (typeof(prefix) != 'undefined' && prefix != null) {
  81.     if (prefix) {
  82.       parts[0] = Monocle.Browser.CSSProps.capStr(parts[0]);
  83.       return prefix+parts.join('');
  84.     } else {
  85.       return parts.join('');
  86.     }
  87.   }
  88.  
  89.   var props = [parts.join('')];
  90.   parts[0] = Monocle.Browser.CSSProps.capStr(parts[0]);
  91.   for (i = 0; i < Monocle.Browser.CSSProps.prefixes.length; ++i) {
  92.     var pf = Monocle.Browser.CSSProps.domprefixes[i];
  93.     if (!pf) { continue; }
  94.     props.push(pf+parts.join(''));
  95.   }
  96.   return props;
  97. }
  98.  
  99.  
  100. Monocle.Browser.CSSProps.toDOMProp = function (prop) {
  101.   return Monocle.Browser.CSSProps.toDOMProps(
  102.     prop,
  103.     Monocle.Browser.CSSProps.domprefixes[
  104.       Monocle.Browser.CSSProps.engines.indexOf(Monocle.Browser.engine)
  105.     ]
  106.   );
  107. }
  108.  
  109.  
  110. Monocle.Browser.CSSProps.isSupported = function (props) {
  111.   for (var i in props) {
  112.     if (Monocle.Browser.CSSProps.guineapig.style[props[i]] !== undefined) {
  113.       return true;
  114.     }
  115.   }
  116.   return false;
  117. } // Thanks modernizr!
  118.  
  119.  
  120. Monocle.Browser.CSSProps.isSupportedForAnyPrefix = function (prop) {
  121.   return Monocle.Browser.CSSProps.isSupported(
  122.     Monocle.Browser.CSSProps.toDOMProps(prop)
  123.   );
  124. }
  125.  
  126.  
  127. Monocle.Browser.CSSProps.supportsMediaQuery = function (query) {
  128.   var gpid = "monocle_guineapig";
  129.   var div = Monocle.Browser.CSSProps.guineapig;
  130.   div.id = gpid;
  131.   var st = document.createElement('style');
  132.   st.textContent = query+'{#'+gpid+'{height:3px}}';
  133.   (document.head || document.getElementsByTagName('head')[0]).appendChild(st);
  134.   document.documentElement.appendChild(div);
  135.  
  136.   var result = Monocle.Browser.CSSProps.guineapig.offsetHeight === 3;
  137.  
  138.   st.parentNode.removeChild(st);
  139.   div.parentNode.removeChild(div);
  140.  
  141.   return result;
  142. } // Thanks modernizr!
  143.  
  144.  
  145. Monocle.Browser.CSSProps.supportsMediaQueryProperty = function (prop) {
  146.   return Monocle.Browser.CSSProps.supportsMediaQuery(
  147.     '@media ('+Monocle.Browser.CSSProps.prefixes.join(prop+'),(')+'monocle__)'
  148.   );
  149. }
  150.  
  151.  
  152.  
  153. Monocle.Browser.has = {}
  154. Monocle.Browser.has.touch = ('ontouchstart' in window) ||
  155.   Monocle.Browser.CSSProps.supportsMediaQueryProperty('touch-enabled');
  156. Monocle.Browser.has.columns = Monocle.Browser.CSSProps.isSupportedForAnyPrefix(
  157.   'column-width'
  158. );
  159. Monocle.Browser.has.transform3d = Monocle.Browser.CSSProps.isSupported([
  160.   'perspectiveProperty',
  161.   'WebkitPerspective',
  162.   'MozPerspective',
  163.   'OPerspective',
  164.   'msPerspective'
  165. ]) && Monocle.Browser.CSSProps.supportsMediaQueryProperty('transform-3d');
  166. Monocle.Browser.has.embedded = (top != self);
  167.  
  168. Monocle.Browser.has.iframeTouchBug = Monocle.Browser.iOSVersionBelow("4.2");
  169.  
  170. Monocle.Browser.has.selectThruBug = Monocle.Browser.iOSVersionBelow("4.2");
  171.  
  172. Monocle.Browser.has.mustScrollSheaf = Monocle.Browser.is.MobileSafari;
  173. Monocle.Browser.has.iframeDoubleWidthBug =
  174.   Monocle.Browser.has.mustScrollSheaf || Monocle.Browser.on.Kindle3;
  175.  
  176. Monocle.Browser.has.floatColumnBug = Monocle.Browser.is.WebKit;
  177.  
  178. Monocle.Browser.has.relativeIframeWidthBug = Monocle.Browser.on.Android;
  179.  
  180.  
  181. Monocle.Browser.has.jumpFlickerBug =
  182.   Monocle.Browser.on.MacOSX && Monocle.Browser.is.WebKit;
  183.  
  184.  
  185. Monocle.Browser.has.columnOverflowPaintBug = Monocle.Browser.is.WebKit &&
  186.   !Monocle.Browser.is.MobileSafari &&
  187.   navigator.userAgent.indexOf("AppleWebKit/534") > 0;
  188.  
  189.  
  190. if (typeof window.console == "undefined") {
  191.   window.console = {
  192.     messages: [],
  193.     log: function (msg) {
  194.       this.messages.push(msg);
  195.     }
  196.   }
  197. }
  198.  
  199.  
  200. window.console.compatDir = function (obj) {
  201.   var stringify = function (o) {
  202.     var parts = [];
  203.     for (x in o) {
  204.       parts.push(x + ": " + o[x]);
  205.     }
  206.     return parts.join("; ");
  207.   }
  208.  
  209.   window.console.log(stringify(obj));
  210. }
  211.  
  212.  
  213. if (!Array.prototype.indexOf) {
  214.   Array.prototype.indexOf = function(elt /*, from*/) {
  215.     var len = this.length >>> 0;
  216.  
  217.     var from = Number(arguments[1]) || 0;
  218.     from = (from < 0)
  219.       ? Math.ceil(from)
  220.       : Math.floor(from);
  221.     if (from < 0) {
  222.       from += len;
  223.     }
  224.  
  225.     for (; from < len; from++) {
  226.       if (from in this && this[from] === elt) {
  227.         return from;
  228.       }
  229.     }
  230.     return -1;
  231.   };
  232. }
  233.  
  234.  
  235. Monocle.pieceLoaded('compat');
  236. Monocle.Factory = function (element, label, index, reader) {
  237.  
  238.   var API = { constructor: Monocle.Factory };
  239.   var k = API.constants = API.constructor;
  240.   var p = API.properties = {
  241.     element: element,
  242.     label: label,
  243.     index: index,
  244.     reader: reader,
  245.     prefix: reader.properties.classPrefix || ''
  246.   }
  247.  
  248.  
  249.   function initialize() {
  250.     if (!p.label) { return; }
  251.     var node = p.reader.properties.graph;
  252.     node[p.label] = node[p.label] || [];
  253.     if (typeof p.index == 'undefined' && node[p.label][p.index]) {
  254.       throw('Element already exists in graph: '+p.label+'['+p.index+']');
  255.     } else {
  256.       p.index = p.index || node[p.label].length;
  257.     }
  258.     node[p.label][p.index] = p.element;
  259.  
  260.     addClass(p.label);
  261.   }
  262.  
  263.  
  264.   function find(oLabel, oIndex) {
  265.     if (!p.reader.properties.graph[oLabel]) {
  266.       return null;
  267.     }
  268.     return p.reader.properties.graph[oLabel][oIndex || 0];
  269.   }
  270.  
  271.  
  272.   function claim(oElement, oLabel, oIndex) {
  273.     return oElement.dom = new Monocle.Factory(
  274.       oElement,
  275.       oLabel,
  276.       oIndex,
  277.       p.reader
  278.     );
  279.   }
  280.  
  281.  
  282.   function make(tagName, oLabel, index_or_options, or_options) {
  283.     var oIndex, options;
  284.     if (arguments.length == 1) {
  285.       oLabel = null,
  286.       oIndex = 0;
  287.       options = {};
  288.     } else if (arguments.length == 2) {
  289.       oIndex = 0;
  290.       options = {};
  291.     } else if (arguments.length == 4) {
  292.       oIndex = arguments[2];
  293.       options = arguments[3];
  294.     } else if (arguments.length == 3) {
  295.       var lastArg = arguments[arguments.length - 1];
  296.       if (typeof lastArg == "number") {
  297.         oIndex = lastArg;
  298.         options = {};
  299.       } else {
  300.         oIndex = 0;
  301.         options = lastArg;
  302.       }
  303.     }
  304.  
  305.     var oElement = document.createElement(tagName);
  306.     claim(oElement, oLabel, oIndex);
  307.     if (options['class']) {
  308.       oElement.className += " "+p.prefix+options['class'];
  309.     }
  310.     if (options['html']) {
  311.       oElement.innerHTML = options['html'];
  312.     }
  313.     if (options['text']) {
  314.       oElement.appendChild(document.createTextNode(options['text']));
  315.     }
  316.  
  317.     return oElement;
  318.   }
  319.  
  320.  
  321.   function append(tagName, oLabel, index_or_options, or_options) {
  322.     var oElement = make.apply(this, arguments);
  323.     p.element.appendChild(oElement);
  324.     return oElement;
  325.   }
  326.  
  327.  
  328.   function address() {
  329.     return [p.label, p.index, p.reader];
  330.   }
  331.  
  332.  
  333.   function setStyles(rules) {
  334.     return Monocle.Styles.applyRules(p.element, rules);
  335.   }
  336.  
  337.  
  338.   function setBetaStyle(property, value) {
  339.     return Monocle.Styles.affix(p.element, property, value);
  340.   }
  341.  
  342.  
  343.  
  344.   function hasClass(name) {
  345.     name = p.prefix + name;
  346.     var klass = p.element.className;
  347.     if (!klass) { return false; }
  348.     if (klass == name) { return true; }
  349.     return new RegExp("(^|\\s)"+name+"(\\s|$)").test(klass);
  350.   }
  351.  
  352.  
  353.   function addClass(name) {
  354.     if (hasClass(name)) { return; }
  355.     var gap = p.element.className ? ' ' : '';
  356.     return p.element.className += gap+p.prefix+name;
  357.   }
  358.  
  359.  
  360.   function removeClass(name) {
  361.     var reName = new RegExp("(^|\\s+)"+p.prefix+name+"(\\s+|$)");
  362.     var reTrim = /^\s+|\s+$/g;
  363.     var klass = p.element.className;
  364.     p.element.className = klass.replace(reName, ' ').replace(reTrim, '');
  365.     return p.element.className;
  366.   }
  367.  
  368.  
  369.   API.find = find;
  370.   API.claim = claim;
  371.   API.make = make;
  372.   API.append = append;
  373.   API.address = address;
  374.  
  375.   API.setStyles = setStyles;
  376.   API.setBetaStyle = setBetaStyle;
  377.   API.hasClass = hasClass;
  378.   API.addClass = addClass;
  379.   API.removeClass = removeClass;
  380.  
  381.   initialize();
  382.  
  383.   return API;
  384. }
  385.  
  386. Monocle.pieceLoaded('factory');
  387. Monocle.Events = {}
  388.  
  389.  
  390. Monocle.Events.dispatch = function (elem, evtType, data, cancelable) {
  391.   if (!document.createEvent) {
  392.     return true;
  393.   }
  394.   var evt = document.createEvent("Events");
  395.   evt.initEvent(evtType, false, cancelable || false);
  396.   evt.m = data;
  397.   try {
  398.     return elem.dispatchEvent(evt);
  399.   } catch(e) {
  400.     console.warn("Failed to dispatch event: "+evtType);
  401.     return false;
  402.   }
  403. }
  404.  
  405.  
  406. Monocle.Events.listen = function (elem, evtType, fn, useCapture) {
  407.   if (elem.addEventListener) {
  408.     return elem.addEventListener(evtType, fn, useCapture || false);
  409.   } else if (elem.attachEvent) {
  410.     return elem.attachEvent('on'+evtType, fn);
  411.   }
  412. }
  413.  
  414.  
  415. Monocle.Events.deafen = function (elem, evtType, fn, useCapture) {
  416.   if (elem.removeEventListener) {
  417.     return elem.removeEventListener(evtType, fn, useCapture || false);
  418.   } else if (elem.detachEvent) {
  419.     try {
  420.       return elem.detachEvent('on'+evtType, fn);
  421.     } catch(e) {}
  422.   }
  423. }
  424.  
  425.  
  426. Monocle.Events.listenForContact = function (elem, fns, options) {
  427.   var listeners = {};
  428.  
  429.   var cursorInfo = function (evt, ci) {
  430.     evt.m = {
  431.       pageX: ci.pageX,
  432.       pageY: ci.pageY
  433.     };
  434.  
  435.     var target = evt.target || evt.srcElement;
  436.     while (target.nodeType != 1 && target.parentNode) {
  437.       target = target.parentNode;
  438.     }
  439.  
  440.     var offset = offsetFor(evt, target);
  441.     evt.m.offsetX = offset[0];
  442.     evt.m.offsetY = offset[1];
  443.  
  444.     if (evt.currentTarget) {
  445.       offset = offsetFor(evt, evt.currentTarget);
  446.       evt.m.registrantX = offset[0];
  447.       evt.m.registrantY = offset[1];
  448.     }
  449.  
  450.     return evt;
  451.   }
  452.  
  453.  
  454.   var offsetFor = function (evt, elem) {
  455.     var r;
  456.     if (elem.getBoundingClientRect) {
  457.       var er = elem.getBoundingClientRect();
  458.       var dr = document.body.getBoundingClientRect();
  459.       r = { left: er.left - dr.left, top: er.top - dr.top };
  460.     } else {
  461.       r = { left: elem.offsetLeft, top: elem.offsetTop }
  462.       while (elem = elem.parentNode) {
  463.         if (elem.offsetLeft || elem.offsetTop) {
  464.           r.left += elem.offsetLeft;
  465.           r.top += elem.offsetTop;
  466.         }
  467.       }
  468.     }
  469.     return [evt.m.pageX - r.left, evt.m.pageY - r.top];
  470.   }
  471.  
  472.  
  473.   var capture = (options && options.useCapture) || false;
  474.  
  475.   if (!Monocle.Browser.has.touch) {
  476.     if (fns.start) {
  477.       listeners.mousedown = function (evt) {
  478.         if (evt.button != 0) { return; }
  479.         fns.start(cursorInfo(evt, evt));
  480.       }
  481.       Monocle.Events.listen(elem, 'mousedown', listeners.mousedown, capture);
  482.     }
  483.     if (fns.move) {
  484.       listeners.mousemove = function (evt) {
  485.         fns.move(cursorInfo(evt, evt));
  486.       }
  487.       Monocle.Events.listen(elem, 'mousemove', listeners.mousemove, capture);
  488.     }
  489.     if (fns.end) {
  490.       listeners.mouseup = function (evt) {
  491.         fns.end(cursorInfo(evt, evt));
  492.       }
  493.       Monocle.Events.listen(elem, 'mouseup', listeners.mouseup, capture);
  494.     }
  495.     if (fns.cancel) {
  496.       listeners.mouseout = function (evt) {
  497.         obj = evt.relatedTarget || evt.fromElement;
  498.         while (obj && (obj = obj.parentNode)) {
  499.           if (obj == elem) { return; }
  500.         }
  501.         fns.cancel(cursorInfo(evt, evt));
  502.       }
  503.       Monocle.Events.listen(elem, 'mouseout', listeners.mouseout, capture);
  504.     }
  505.   } else {
  506.     if (fns.start) {
  507.       listeners.start = function (evt) {
  508.         if (evt.touches.length > 1) { return; }
  509.         fns.start(cursorInfo(evt, evt.targetTouches[0]));
  510.       }
  511.     }
  512.     if (fns.move) {
  513.       listeners.move = function (evt) {
  514.         if (evt.touches.length > 1) { return; }
  515.         fns.move(cursorInfo(evt, evt.targetTouches[0]));
  516.       }
  517.     }
  518.     if (fns.end) {
  519.       listeners.end = function (evt) {
  520.         fns.end(cursorInfo(evt, evt.changedTouches[0]));
  521.         evt.preventDefault();
  522.       }
  523.     }
  524.     if (fns.cancel) {
  525.       listeners.cancel = function (evt) {
  526.         fns.cancel(cursorInfo(evt, evt.changedTouches[0]));
  527.       }
  528.     }
  529.  
  530.     if (Monocle.Browser.has.iframeTouchBug) {
  531.       Monocle.Events.tMonitor = Monocle.Events.tMonitor ||
  532.         new Monocle.Events.TouchMonitor();
  533.       Monocle.Events.tMonitor.listen(elem, listeners, options);
  534.     } else {
  535.       for (etype in listeners) {
  536.         Monocle.Events.listen(elem, 'touch'+etype, listeners[etype], capture);
  537.       }
  538.     }
  539.   }
  540.  
  541.   return listeners;
  542. }
  543.  
  544.  
  545. Monocle.Events.deafenForContact = function (elem, listeners) {
  546.   var prefix = "";
  547.   if (Monocle.Browser.has.touch) {
  548.     prefix = Monocle.Browser.has.iframeTouchBug ? "contact" : "touch";
  549.   }
  550.  
  551.   for (evtType in listeners) {
  552.     Monocle.Events.deafen(elem, prefix + evtType, listeners[evtType]);
  553.   }
  554. }
  555.  
  556.  
  557. Monocle.Events.listenForTap = function (elem, fn, activeClass) {
  558.   var startPos;
  559.  
  560.   if (Monocle.Browser.on.Kindle3) {
  561.     Monocle.Events.listen(elem, 'click', function () {});
  562.   }
  563.  
  564.   var annul = function () {
  565.     startPos = null;
  566.     if (activeClass && elem.dom) { elem.dom.removeClass(activeClass); }
  567.   }
  568.  
  569.   var annulIfOutOfBounds = function (evt) {
  570.     if (evt.type.match(/^mouse/)) {
  571.       return;
  572.     }
  573.     if (Monocle.Browser.is.MobileSafari && Monocle.Browser.iOSVersion < "3.2") {
  574.       return;
  575.     }
  576.     if (
  577.       evt.m.registrantX < 0 || evt.m.registrantX > elem.offsetWidth ||
  578.       evt.m.registrantY < 0 || evt.m.registrantY > elem.offsetHeight
  579.     ) {
  580.       annul();
  581.     } else {
  582.       evt.preventDefault();
  583.     }
  584.   }
  585.  
  586.   return Monocle.Events.listenForContact(
  587.     elem,
  588.     {
  589.       start: function (evt) {
  590.         startPos = [evt.m.pageX, evt.m.pageY];
  591.         evt.preventDefault();
  592.         if (activeClass && elem.dom) { elem.dom.addClass(activeClass); }
  593.       },
  594.       move: annulIfOutOfBounds,
  595.       end: function (evt) {
  596.         annulIfOutOfBounds(evt);
  597.         if (startPos) {
  598.           evt.m.startOffset = startPos;
  599.           fn(evt);
  600.         }
  601.         annul();
  602.       },
  603.       cancel: annul
  604.     },
  605.     {
  606.       useCapture: false
  607.     }
  608.   );
  609. }
  610.  
  611.  
  612. Monocle.Events.deafenForTap = Monocle.Events.deafenForContact;
  613.  
  614.  
  615. Monocle.Events.TouchMonitor = function () {
  616.   if (Monocle.Events == this) {
  617.     return new Monocle.Events.TouchMonitor();
  618.   }
  619.  
  620.   var API = { constructor: Monocle.Events.TouchMonitor }
  621.   var k = API.constants = API.constructor;
  622.   var p = API.properties = {
  623.     touching: null,
  624.     edataPrev: null,
  625.     originator: null,
  626.     brokenModel_4_1: navigator.userAgent.match(/ OS 4_1/)
  627.   }
  628.  
  629.  
  630.   function listenOnIframe(iframe) {
  631.     if (iframe.contentDocument) {
  632.       enableTouchProxy(iframe.contentDocument);
  633.       iframe.contentDocument.isTouchFrame = true;
  634.     }
  635.  
  636.     if (p.brokenModel_4_1) {
  637.       enableTouchProxy(iframe);
  638.     }
  639.   }
  640.  
  641.  
  642.   function listen(element, fns, useCapture) {
  643.     for (etype in fns) {
  644.       Monocle.Events.listen(element, 'contact'+etype, fns[etype], useCapture);
  645.     }
  646.     enableTouchProxy(element, useCapture);
  647.   }
  648.  
  649.  
  650.   function enableTouchProxy(element, useCapture) {
  651.     if (element.monocleTouchProxy) {
  652.       return;
  653.     }
  654.     element.monocleTouchProxy = true;
  655.  
  656.     var fn = function (evt) { touchProxyHandler(element, evt) }
  657.     Monocle.Events.listen(element, "touchstart", fn, useCapture);
  658.     Monocle.Events.listen(element, "touchmove", fn, useCapture);
  659.     Monocle.Events.listen(element, "touchend", fn, useCapture);
  660.     Monocle.Events.listen(element, "touchcancel", fn, useCapture);
  661.   }
  662.  
  663.  
  664.   function touchProxyHandler(element, evt) {
  665.     var edata = {
  666.       start: evt.type == "touchstart",
  667.       move: evt.type == "touchmove",
  668.       end: evt.type == "touchend" || evt.type == "touchcancel",
  669.       time: new Date().getTime(),
  670.       frame: element.isTouchFrame
  671.     }
  672.  
  673.     if (!p.touching) {
  674.       p.originator = element;
  675.     }
  676.  
  677.     var target = element;
  678.     var touch = evt.touches[0] || evt.changedTouches[0];
  679.     target = document.elementFromPoint(touch.screenX, touch.screenY);
  680.  
  681.     if (target) {
  682.       translateTouchEvent(element, target, evt, edata);
  683.     }
  684.   }
  685.  
  686.  
  687.   function translateTouchEvent(element, target, evt, edata) {
  688.     if (
  689.       p.brokenModel_4_1 &&
  690.       !edata.frame &&
  691.       !p.touching &&
  692.       edata.start &&
  693.       p.edataPrev &&
  694.       p.edataPrev.end &&
  695.       (edata.time - p.edataPrev.time) < 30
  696.     ) {
  697.       evt.preventDefault();
  698.       return;
  699.     }
  700.  
  701.     if (!p.touching && !edata.end) {
  702.       return fireStart(evt, target, edata);
  703.     }
  704.  
  705.     if (edata.move && p.touching) {
  706.       return fireMove(evt, edata);
  707.     }
  708.  
  709.     if (p.brokenModel_4_1) {
  710.       if (p.touching && !edata.frame) {
  711.         return fireProvisionalEnd(evt, edata);
  712.       }
  713.     } else {
  714.       if (edata.end && p.touching) {
  715.         return fireProvisionalEnd(evt, edata);
  716.       }
  717.     }
  718.  
  719.     if (
  720.       p.brokenModel_4_1 &&
  721.       p.originator != element &&
  722.       edata.frame &&
  723.       edata.end
  724.     ) {
  725.       evt.preventDefault();
  726.       return;
  727.     }
  728.  
  729.     if (edata.frame && edata.end && p.touching) {
  730.       return fireProvisionalEnd(evt, edata);
  731.     }
  732.   }
  733.  
  734.  
  735.   function fireStart(evt, target, edata) {
  736.     p.touching = target;
  737.     p.edataPrev = edata;
  738.     return fireTouchEvent(p.touching, 'start', evt);
  739.   }
  740.  
  741.  
  742.   function fireMove(evt, edata) {
  743.     clearProvisionalEnd();
  744.     p.edataPrev = edata;
  745.     return fireTouchEvent(p.touching, 'move', evt);
  746.   }
  747.  
  748.  
  749.   function fireEnd(evt, edata) {
  750.     var result = fireTouchEvent(p.touching, 'end', evt);
  751.     p.edataPrev = edata;
  752.     p.touching = null;
  753.     return result;
  754.   }
  755.  
  756.  
  757.   function fireProvisionalEnd(evt, edata) {
  758.     clearProvisionalEnd();
  759.     var mimicEvt = mimicTouchEvent(p.touching, 'end', evt);
  760.     p.edataPrev = edata;
  761.  
  762.     p.provisionalEnd = setTimeout(
  763.       function() {
  764.         if (p.touching) {
  765.           p.touching.dispatchEvent(mimicEvt);
  766.           p.touching = null;
  767.         }
  768.       },
  769.       30
  770.     );
  771.   }
  772.  
  773.  
  774.   function clearProvisionalEnd() {
  775.     if (p.provisionalEnd) {
  776.       clearTimeout(p.provisionalEnd);
  777.       p.provisionalEnd = null;
  778.     }
  779.   }
  780.  
  781.  
  782.   function mimicTouchEvent(target, newtype, evt) {
  783.     var cloneTouch = function (t) {
  784.       return document.createTouch(
  785.         document.defaultView,
  786.         target,
  787.         t.identifier,
  788.         t.screenX,
  789.         t.screenY,
  790.         t.screenX,
  791.         t.screenY
  792.       );
  793.     }
  794.  
  795.     var findTouch = function (id) {
  796.       for (var i = 0; i < touches.all.length; ++i) {
  797.         if (touches.all[i].identifier == id) {
  798.           return touches.all[i];
  799.         }
  800.       }
  801.     }
  802.  
  803.     var touches = { all: [], target: [], changed: [] };
  804.     for (var i = 0; i < evt.touches.length; ++i) {
  805.       touches.all.push(cloneTouch(evt.touches[i]));
  806.     }
  807.     for (var i = 0; i < evt.targetTouches.length; ++i) {
  808.       touches.target.push(
  809.         findTouch(evt.targetTouches[i].identifier) ||
  810.         cloneTouch(evt.targetTouches[i])
  811.       );
  812.     }
  813.     for (var i = 0; i < evt.changedTouches.length; ++i) {
  814.       touches.changed.push(
  815.         findTouch(evt.changedTouches[i].identifier) ||
  816.         cloneTouch(evt.changedTouches[i])
  817.       );
  818.     }
  819.  
  820.     var mimicEvt = document.createEvent('TouchEvent');
  821.     mimicEvt.initTouchEvent(
  822.       "contact"+newtype,
  823.       true,
  824.       true,
  825.       document.defaultView,
  826.       evt.detail,
  827.       evt.screenX,
  828.       evt.screenY,
  829.       evt.screenX,
  830.       evt.screenY,
  831.       evt.ctrlKey,
  832.       evt.altKey,
  833.       evt.shiftKey,
  834.       evt.metaKey,
  835.       document.createTouchList.apply(document, touches.all),
  836.       document.createTouchList.apply(document, touches.target),
  837.       document.createTouchList.apply(document, touches.changed),
  838.       evt.scale,
  839.       evt.rotation
  840.     );
  841.  
  842.     return mimicEvt;
  843.   }
  844.  
  845.  
  846.   function fireTouchEvent(target, newtype, evt) {
  847.     var mimicEvt = mimicTouchEvent(target, newtype, evt);
  848.     var result = target.dispatchEvent(mimicEvt);
  849.     if (!result) {
  850.       evt.preventDefault();
  851.     }
  852.     return result;
  853.   }
  854.  
  855.  
  856.   API.listen = listen;
  857.   API.listenOnIframe = listenOnIframe;
  858.  
  859.   return API;
  860. }
  861.  
  862.  
  863. Monocle.Events.listenOnIframe = function (frame) {
  864.   if (!Monocle.Browser.has.iframeTouchBug) {
  865.     return;
  866.   }
  867.   Monocle.Events.tMonitor = Monocle.Events.tMonitor ||
  868.     new Monocle.Events.TouchMonitor();
  869.   Monocle.Events.tMonitor.listenOnIframe(frame);
  870. }
  871.  
  872. Monocle.pieceLoaded('events');
  873. Monocle.Styles = {
  874.   applyRules: function (elem, rules) {
  875.     if (typeof rules != 'string') {
  876.       var parts = [];
  877.       for (var declaration in rules) {
  878.         parts.push(declaration+": "+rules[declaration]+";")
  879.       }
  880.       rules = parts.join(" ");
  881.     }
  882.     elem.style.cssText += ';'+rules;
  883.     return elem.style.cssText;
  884.   },
  885.  
  886.   affix: function (elem, property, value) {
  887.     var target = elem.style ? elem.style : elem;
  888.     target[Monocle.Browser.CSSProps.toDOMProp(property)] = value;
  889.   },
  890.  
  891.   setX: function (elem, x) {
  892.     var s = elem.style;
  893.     if (typeof x == "number") { x += "px"; }
  894.     if (Monocle.Browser.has.transform3d) {
  895.       s.webkitTransform = "translate3d("+x+", 0, 0)";
  896.     } else {
  897.       s.webkitTransform = "translateX("+x+")";
  898.     }
  899.     s.MozTransform = s.OTransform = s.transform = "translateX("+x+")";
  900.     return x;
  901.   },
  902.  
  903.   setY: function (elem, y) {
  904.     var s = elem.style;
  905.     if (typeof y == "number") { y += "px"; }
  906.     if (Monocle.Browser.has.transform3d) {
  907.       s.webkitTransform = "translate3d(0, "+y+", 0)";
  908.     } else {
  909.       s.webkitTransform = "translateY("+y+")";
  910.     }
  911.     s.MozTransform = s.OTransform = s.transform = "translateY("+y+")";
  912.     return y;
  913.   }
  914. }
  915.  
  916.  
  917. Monocle.Styles.container = {
  918.   "position": "absolute",
  919.   "top": "0",
  920.   "left": "0",
  921.   "bottom": "0",
  922.   "right": "0"
  923. }
  924.  
  925. Monocle.Styles.page = {
  926.   "position": "absolute",
  927.   "z-index": "1",
  928.   "-webkit-user-select": "none",
  929.   "-moz-user-select": "none",
  930.   "user-select": "none",
  931.   "-webkit-transform": "translate3d(0,0,0)"
  932.  
  933.   /*
  934.   "background": "white",
  935.   "top": "0",
  936.   "left": "0",
  937.   "bottom": "0",
  938.   "right": "0"
  939.   */
  940. }
  941.  
  942. Monocle.Styles.sheaf = {
  943.   "position": "absolute",
  944.   "overflow": "hidden" // Required by MobileSafari to constrain inner iFrame.
  945.  
  946.   /*
  947.   "top": "0",
  948.   "left": "0",
  949.   "bottom": "0",
  950.   "right": "0"
  951.   */
  952. }
  953.  
  954. Monocle.Styles.component = {
  955.   "display": "block",
  956.   "width": "100%",
  957.   "height": "100%",
  958.   "border": "none",
  959.   "overflow": "hidden",
  960.   "-webkit-user-select": "none",
  961.   "-moz-user-select": "none",
  962.   "user-select": "none"
  963. }
  964.  
  965. Monocle.Styles.control = {
  966.   "z-index": "100",
  967.   "cursor": "pointer"
  968. }
  969.  
  970. Monocle.Styles.overlay = {
  971.   "position": "absolute",
  972.   "display": "none",
  973.   "width": "100%",
  974.   "height": "100%",
  975.   "z-index": "1000"
  976. }
  977.  
  978.  
  979.  
  980. Monocle.pieceLoaded('styles');
  981. Monocle.Reader = function (node, bookData, options, onLoadCallback) {
  982.   if (Monocle == this) {
  983.     return new Monocle.Reader(node, bookData, options, onLoadCallback);
  984.   }
  985.  
  986.   var API = { constructor: Monocle.Reader }
  987.   var k = API.constants = API.constructor;
  988.   var p = API.properties = {
  989.     initialized: false,
  990.  
  991.     book: null,
  992.  
  993.     graph: {},
  994.  
  995.     pageStylesheets: [],
  996.  
  997.     systemId: (options ? options.systemId : null) || k.DEFAULT_SYSTEM_ID,
  998.  
  999.     classPrefix: k.DEFAULT_CLASS_PREFIX,
  1000.  
  1001.     controls: [],
  1002.  
  1003.     resizeTimer: null
  1004.   }
  1005.  
  1006.   var dom;
  1007.  
  1008.  
  1009.   function initialize(node, bookData, options, onLoadCallback) {
  1010.     var box = typeof(node) == "string" ?  document.getElementById(node) : node;
  1011.     dom = API.dom = box.dom = new Monocle.Factory(box, 'box', 0, API);
  1012.  
  1013.     options = options || {}
  1014.  
  1015.     dispatchEvent("monocle:initializing");
  1016.  
  1017.     var bk;
  1018.     if (bookData) {
  1019.       bk = new Monocle.Book(bookData);
  1020.     } else {
  1021.       bk = Monocle.Book.fromNodes([box.cloneNode(true)]);
  1022.     }
  1023.     box.innerHTML = "";
  1024.  
  1025.     positionBox();
  1026.  
  1027.     attachFlipper(options.flipper);
  1028.  
  1029.     createReaderElements();
  1030.  
  1031.     p.defaultStyles = addPageStyles(k.DEFAULT_STYLE_RULES, false);
  1032.     if (options.stylesheet) {
  1033.       p.initialStyles = addPageStyles(options.stylesheet, false);
  1034.     }
  1035.  
  1036.     primeFrames(options.primeURL, function () {
  1037.       applyStyles();
  1038.  
  1039.       listen('monocle:componentchange', persistPageStylesOnComponentChange);
  1040.  
  1041.       p.flipper.listenForInteraction(options.panels);
  1042.  
  1043.       setBook(bk, options.place, function () {
  1044.         p.initialized = true;
  1045.         if (onLoadCallback) { onLoadCallback(API); }
  1046.         dispatchEvent("monocle:loaded");
  1047.       });
  1048.     });
  1049.   }
  1050.  
  1051.  
  1052.   function positionBox() {
  1053.     var currPosVal;
  1054.     var box = dom.find('box');
  1055.     if (document.defaultView) {
  1056.       var currStyle = document.defaultView.getComputedStyle(box, null);
  1057.       currPosVal = currStyle.getPropertyValue('position');
  1058.     } else if (box.currentStyle) {
  1059.       currPosVal = box.currentStyle.position
  1060.     }
  1061.     if (["absolute", "relative"].indexOf(currPosVal) == -1) {
  1062.       box.style.position = "relative";
  1063.     }
  1064.   }
  1065.  
  1066.  
  1067.   function attachFlipper(flipperClass) {
  1068.     if (!Monocle.Browser.has.columns) {
  1069.       flipperClass = Monocle.Flippers[k.FLIPPER_LEGACY_CLASS];
  1070.       if (!flipperClass) {
  1071.         return dom.append(
  1072.           'div',
  1073.           'abortMsg',
  1074.           { 'class': k.abortMessage.CLASSNAME, 'html': k.abortMessage.TEXT }
  1075.         );
  1076.       }
  1077.     } else if (!flipperClass) {
  1078.       flipperClass = Monocle.Flippers[k.FLIPPER_DEFAULT_CLASS];
  1079.       if (!flipperClass) {
  1080.         throw("No flipper class");
  1081.       }
  1082.     }
  1083.     p.flipper = new flipperClass(API, null, p.readerOptions);
  1084.   }
  1085.  
  1086.  
  1087.   function createReaderElements() {
  1088.     var cntr = dom.append('div', 'container');
  1089.     for (var i = 0; i < p.flipper.pageCount; ++i) {
  1090.       var page = cntr.dom.append('div', 'page', i);
  1091.       page.m = { reader: API, pageIndex: i, place: null }
  1092.       page.m.sheafDiv = page.dom.append('div', 'sheaf', i);
  1093.       page.m.activeFrame = page.m.sheafDiv.dom.append('iframe', 'component', i);
  1094.       page.m.activeFrame.m = { 'pageDiv': page }
  1095.       p.flipper.addPage(page);
  1096.       Monocle.Events.listenOnIframe(page.m.activeFrame);
  1097.     }
  1098.     dom.append('div', 'overlay');
  1099.     dispatchEvent("monocle:loading");
  1100.   }
  1101.  
  1102.  
  1103.   function primeFrames(url, callback) {
  1104.     url = url || "about:blank";
  1105.  
  1106.     var pageMax = p.flipper.pageCount;
  1107.     var pageCount = 0;
  1108.  
  1109.     var cb = function (evt) {
  1110.       var frame = evt.target || evt.srcElement;
  1111.       Monocle.Events.deafen(frame, 'load', cb);
  1112.       if (Monocle.Browser.is.WebKit) {
  1113.         frame.contentDocument.documentElement.style.overflow = "hidden";
  1114.       }
  1115.       dispatchEvent('monocle:frameprimed', { frame: frame, pageIndex: pageCount });
  1116.       if ((pageCount += 1) == pageMax) {
  1117.         Monocle.defer(callback);
  1118.       }
  1119.     }
  1120.  
  1121.     for (var i = 0; i < pageMax; ++i) {
  1122.       var page = dom.find('page', i);
  1123.       page.m.activeFrame.style.visibility = "hidden";
  1124.       page.m.activeFrame.setAttribute('frameBorder', 0);
  1125.       page.m.activeFrame.setAttribute('scrolling', 'no');
  1126.       Monocle.Events.listen(page.m.activeFrame, 'load', cb);
  1127.       page.m.activeFrame.src = url;
  1128.     }
  1129.   }
  1130.  
  1131.  
  1132.   function applyStyles() {
  1133.     dom.find('container').dom.setStyles(Monocle.Styles.container);
  1134.     for (var i = 0; i < p.flipper.pageCount; ++i) {
  1135.       var page = dom.find('page', i);
  1136.       page.dom.setStyles(Monocle.Styles.page);
  1137.       dom.find('sheaf', i).dom.setStyles(Monocle.Styles.sheaf);
  1138.       var cmpt = dom.find('component', i)
  1139.       cmpt.dom.setStyles(Monocle.Styles.component);
  1140.       Monocle.Styles.applyRules(cmpt.contentDocument.body, Monocle.Styles.body);
  1141.     }
  1142.     lockFrameWidths();
  1143.     dom.find('overlay').dom.setStyles(Monocle.Styles.overlay);
  1144.     dispatchEvent('monocle:styles');
  1145.   }
  1146.  
  1147.  
  1148.   function lockingFrameWidths() {
  1149.     if (!Monocle.Browser.has.relativeIframeWidthBug) { return; }
  1150.     for (var i = 0, cmpt; cmpt = dom.find('component', i); ++i) {
  1151.       cmpt.style.display = "none";
  1152.     }
  1153.   }
  1154.  
  1155.  
  1156.   function lockFrameWidths() {
  1157.     if (!Monocle.Browser.has.relativeIframeWidthBug) { return; }
  1158.     for (var i = 0, cmpt; cmpt = dom.find('component', i); ++i) {
  1159.       cmpt.style.width = cmpt.parentNode.offsetWidth+"px";
  1160.       cmpt.style.display = "block";
  1161.     }
  1162.   }
  1163.  
  1164.  
  1165.   function setBook(bk, place, callback) {
  1166.     p.book = bk;
  1167.     var pageCount = 0;
  1168.     if (typeof callback == 'function') {
  1169.       var watcher = function (evt) {
  1170.         dispatchEvent('monocle:firstcomponentchange', evt.m);
  1171.         if ((pageCount += 1) == p.flipper.pageCount) {
  1172.           deafen('monocle:componentchange', watcher);
  1173.           callback();
  1174.         }
  1175.       }
  1176.       listen('monocle:componentchange', watcher);
  1177.     }
  1178.     p.flipper.moveTo(place || { page: 1 });
  1179.   }
  1180.  
  1181.  
  1182.   function getBook() {
  1183.     return p.book;
  1184.   }
  1185.  
  1186.  
  1187.   function resized() {
  1188.     if (!p.initialized) {
  1189.       console.warn('Attempt to resize book before initialization.');
  1190.     }
  1191.     lockingFrameWidths();
  1192.     if (!dispatchEvent("monocle:resizing", {}, true)) {
  1193.       return;
  1194.     }
  1195.     clearTimeout(p.resizeTimer);
  1196.     p.resizeTimer = setTimeout(
  1197.       function () {
  1198.         lockFrameWidths();
  1199.         p.flipper.moveTo({ page: pageNumber() });
  1200.         dispatchEvent("monocle:resize");
  1201.       },
  1202.       k.durations.RESIZE_DELAY
  1203.     );
  1204.   }
  1205.  
  1206.  
  1207.   function pageNumber(pageDiv) {
  1208.     var place = getPlace(pageDiv);
  1209.     return place ? (place.pageNumber() || 1) : 1;
  1210.   }
  1211.  
  1212.  
  1213.   function getPlace(pageDiv) {
  1214.     if (!p.initialized) {
  1215.       console.warn('Attempt to access place before initialization.');
  1216.     }
  1217.     return p.flipper.getPlace(pageDiv);
  1218.   }
  1219.  
  1220.  
  1221.   function moveTo(locus, callback) {
  1222.     if (!p.initialized) {
  1223.       console.warn('Attempt to move place before initialization.');
  1224.     }
  1225.     var fn = callback;
  1226.     if (!locus.direction) {
  1227.       dispatchEvent('monocle:jumping', { locus: locus });
  1228.       fn = function () {
  1229.         dispatchEvent('monocle:jump', { locus: locus });
  1230.         if (callback) { callback(); }
  1231.       }
  1232.     }
  1233.     p.flipper.moveTo(locus, fn);
  1234.   }
  1235.  
  1236.  
  1237.   function skipToChapter(src) {
  1238.     var locus = p.book.locusOfChapter(src);
  1239.     if (locus) {
  1240.       moveTo(locus);
  1241.       return true;
  1242.     } else {
  1243.       dispatchEvent("monocle:notfound", { href: src });
  1244.       return false;
  1245.     }
  1246.   }
  1247.  
  1248.  
  1249.   function addControl(ctrl, cType, options) {
  1250.     for (var i = 0; i < p.controls.length; ++i) {
  1251.       if (p.controls[i].control == ctrl) {
  1252.         console.warn("Already added control: " + ctrl);
  1253.         return;
  1254.       }
  1255.     }
  1256.  
  1257.     options = options || {};
  1258.  
  1259.     var ctrlData = {
  1260.       control: ctrl,
  1261.       elements: [],
  1262.       controlType: cType
  1263.     }
  1264.     p.controls.push(ctrlData);
  1265.  
  1266.     var ctrlElem;
  1267.     var cntr = dom.find('container'), overlay = dom.find('overlay');
  1268.     if (!cType || cType == "standard") {
  1269.       ctrlElem = ctrl.createControlElements(cntr);
  1270.       cntr.appendChild(ctrlElem);
  1271.       ctrlData.elements.push(ctrlElem);
  1272.     } else if (cType == "page") {
  1273.       for (var i = 0; i < p.flipper.pageCount; ++i) {
  1274.         var page = dom.find('page', i);
  1275.         var runner = ctrl.createControlElements(page);
  1276.         page.appendChild(runner);
  1277.         ctrlData.elements.push(runner);
  1278.       }
  1279.     } else if (cType == "modal" || cType == "popover" || cType == "hud") {
  1280.       ctrlElem = ctrl.createControlElements(overlay);
  1281.       overlay.appendChild(ctrlElem);
  1282.       ctrlData.elements.push(ctrlElem);
  1283.       ctrlData.usesOverlay = true;
  1284.     } else if (cType == "invisible") {
  1285.       if (
  1286.         typeof(ctrl.createControlElements) == "function" &&
  1287.         (ctrlElem = ctrl.createControlElements(cntr))
  1288.       ) {
  1289.         cntr.appendChild(ctrlElem);
  1290.         ctrlData.elements.push(ctrlElem);
  1291.       }
  1292.     } else {
  1293.       console.warn("Unknown control type: " + cType);
  1294.     }
  1295.  
  1296.     for (var i = 0; i < ctrlData.elements.length; ++i) {
  1297.       Monocle.Styles.applyRules(ctrlData.elements[i], Monocle.Styles.control);
  1298.     }
  1299.  
  1300.     if (options.hidden) {
  1301.       hideControl(ctrl);
  1302.     } else {
  1303.       showControl(ctrl);
  1304.     }
  1305.  
  1306.     if (typeof ctrl.assignToReader == 'function') {
  1307.       ctrl.assignToReader(API);
  1308.     }
  1309.  
  1310.     return ctrl;
  1311.   }
  1312.  
  1313.  
  1314.   function dataForControl(ctrl) {
  1315.     for (var i = 0; i < p.controls.length; ++i) {
  1316.       if (p.controls[i].control == ctrl) {
  1317.         return p.controls[i];
  1318.       }
  1319.     }
  1320.   }
  1321.  
  1322.  
  1323.   function hideControl(ctrl) {
  1324.     var controlData = dataForControl(ctrl);
  1325.     if (!controlData) {
  1326.       console.warn("No data for control: " + ctrl);
  1327.       return;
  1328.     }
  1329.     if (controlData.hidden) {
  1330.       return;
  1331.     }
  1332.     for (var i = 0; i < controlData.elements.length; ++i) {
  1333.       controlData.elements[i].style.display = "none";
  1334.     }
  1335.     if (controlData.usesOverlay) {
  1336.       var overlay = dom.find('overlay');
  1337.       overlay.style.display = "none";
  1338.       Monocle.Events.deafenForContact(overlay, overlay.listeners);
  1339.     }
  1340.     controlData.hidden = true;
  1341.     if (ctrl.properties) {
  1342.       ctrl.properties.hidden = true;
  1343.     }
  1344.     dispatchEvent('controlhide', ctrl, false);
  1345.   }
  1346.  
  1347.  
  1348.   function showControl(ctrl) {
  1349.     var controlData = dataForControl(ctrl);
  1350.     if (!controlData) {
  1351.       console.warn("No data for control: " + ctrl);
  1352.       return false;
  1353.     }
  1354.  
  1355.     if (showingControl(ctrl)) {
  1356.       return false;
  1357.     }
  1358.  
  1359.     var overlay = dom.find('overlay');
  1360.     if (controlData.usesOverlay && controlData.controlType != "hud") {
  1361.       for (var i = 0, ii = p.controls.length; i < ii; ++i) {
  1362.         if (p.controls[i].usesOverlay && !p.controls[i].hidden) {
  1363.           return false;
  1364.         }
  1365.       }
  1366.       overlay.style.display = "block";
  1367.     }
  1368.  
  1369.     for (var i = 0; i < controlData.elements.length; ++i) {
  1370.       controlData.elements[i].style.display = "block";
  1371.     }
  1372.  
  1373.     if (controlData.controlType == "popover") {
  1374.       overlay.listeners = Monocle.Events.listenForContact(
  1375.         overlay,
  1376.         {
  1377.           start: function (evt) {
  1378.             var obj = evt.target || window.event.srcElement;
  1379.             do {
  1380.               if (obj == controlData.elements[0]) { return true; }
  1381.             } while (obj && (obj = obj.parentNode));
  1382.             hideControl(ctrl);
  1383.           },
  1384.           move: function (evt) {
  1385.             evt.preventDefault();
  1386.           }
  1387.         }
  1388.       );
  1389.     }
  1390.     controlData.hidden = false;
  1391.     if (ctrl.properties) {
  1392.       ctrl.properties.hidden = false;
  1393.     }
  1394.     dispatchEvent('controlshow', ctrl, false);
  1395.     return true;
  1396.   }
  1397.  
  1398.  
  1399.   function showingControl(ctrl) {
  1400.     var controlData = dataForControl(ctrl);
  1401.     return controlData.hidden == false;
  1402.   }
  1403.  
  1404.  
  1405.   function dispatchEvent(evtType, data, cancelable) {
  1406.     return Monocle.Events.dispatch(dom.find('box'), evtType, data, cancelable);
  1407.   }
  1408.  
  1409.  
  1410.   function listen(evtType, fn, useCapture) {
  1411.     Monocle.Events.listen(dom.find('box'), evtType, fn, useCapture);
  1412.   }
  1413.  
  1414.  
  1415.   function deafen(evtType, fn) {
  1416.     Monocle.Events.deafen(dom.find('box'), evtType, fn);
  1417.   }
  1418.  
  1419.  
  1420.   /* PAGE STYLESHEETS */
  1421.  
  1422.   function addPageStyles(styleRules, restorePlace) {
  1423.     return changingStylesheet(function () {
  1424.       p.pageStylesheets.push(styleRules);
  1425.       var sheetIndex = p.pageStylesheets.length - 1;
  1426.  
  1427.       for (var i = 0; i < p.flipper.pageCount; ++i) {
  1428.         var doc = dom.find('component', i).contentDocument;
  1429.         addPageStylesheet(doc, sheetIndex);
  1430.       }
  1431.       return sheetIndex;
  1432.     }, restorePlace);
  1433.   }
  1434.  
  1435.  
  1436.   function updatePageStyles(sheetIndex, styleRules, restorePlace) {
  1437.     return changingStylesheet(function () {
  1438.       p.pageStylesheets[sheetIndex] = styleRules;
  1439.       if (typeof styleRules.join == "function") {
  1440.         styleRules = styleRules.join("\n");
  1441.       }
  1442.       for (var i = 0; i < p.flipper.pageCount; ++i) {
  1443.         var doc = dom.find('component', i).contentDocument;
  1444.         var styleTag = doc.getElementById('monStylesheet'+sheetIndex);
  1445.         if (!styleTag) {
  1446.           console.warn('No such stylesheet: ' + sheetIndex);
  1447.           return;
  1448.         }
  1449.         if (styleTag.styleSheet) {
  1450.           styleTag.styleSheet.cssText = styleRules;
  1451.         } else {
  1452.           styleTag.replaceChild(
  1453.             doc.createTextNode(styleRules),
  1454.             styleTag.firstChild
  1455.           );
  1456.         }
  1457.       }
  1458.     }, restorePlace);
  1459.   }
  1460.  
  1461.  
  1462.   function removePageStyles(sheetIndex, restorePlace) {
  1463.     return changingStylesheet(function () {
  1464.       p.pageStylesheets[sheetIndex] = null;
  1465.       for (var i = 0; i < p.flipper.pageCount; ++i) {
  1466.         var doc = dom.find('component', i).contentDocument;
  1467.         var styleTag = doc.getElementById('monStylesheet'+sheetIndex);
  1468.         styleTag.parentNode.removeChild(styleTag);
  1469.       }
  1470.     }, restorePlace);
  1471.   }
  1472.  
  1473.  
  1474.   function persistPageStylesOnComponentChange(evt) {
  1475.     var doc = evt.m['document'];
  1476.     doc.documentElement.id = p.systemId;
  1477.     for (var i = 0; i < p.pageStylesheets.length; ++i) {
  1478.       if (p.pageStylesheets[i]) {
  1479.         addPageStylesheet(doc, i);
  1480.       }
  1481.     }
  1482.   }
  1483.  
  1484.  
  1485.   function changingStylesheet(callback, restorePlace) {
  1486.     restorePlace = (restorePlace === false) ? false : true;
  1487.     if (restorePlace) {
  1488.       dispatchEvent("monocle:stylesheetchanging", {});
  1489.     }
  1490.     var result = callback();
  1491.     if (restorePlace) {
  1492.       p.flipper.moveTo({ page: pageNumber() });
  1493.       Monocle.defer(
  1494.         function () { dispatchEvent("monocle:stylesheetchange", {}); }
  1495.       );
  1496.     }
  1497.     return result;
  1498.   }
  1499.  
  1500.  
  1501.   function addPageStylesheet(doc, sheetIndex) {
  1502.     var styleRules = p.pageStylesheets[sheetIndex];
  1503.  
  1504.     if (!styleRules) {
  1505.       return;
  1506.     }
  1507.  
  1508.     var head = doc.getElementsByTagName('head')[0];
  1509.     if (!head) {
  1510.       if (!doc.documentElement) { return; } // FIXME: IE doesn't like docElem.
  1511.       head = doc.createElement('head');
  1512.       doc.documentElement.appendChild(head);
  1513.     }
  1514.  
  1515.     if (typeof styleRules.join == "function") {
  1516.       styleRules = styleRules.join("\n");
  1517.     }
  1518.  
  1519.     var styleTag = doc.createElement('style');
  1520.     styleTag.type = 'text/css';
  1521.     styleTag.id = "monStylesheet"+sheetIndex;
  1522.     if (styleTag.styleSheet) {
  1523.       styleTag.styleSheet.cssText = styleRules;
  1524.     } else {
  1525.       styleTag.appendChild(doc.createTextNode(styleRules));
  1526.     }
  1527.  
  1528.     head.appendChild(styleTag);
  1529.  
  1530.     return styleTag;
  1531.   }
  1532.  
  1533.  
  1534.   function visiblePages() {
  1535.     return p.flipper.visiblePages ? p.flipper.visiblePages() : [dom.find('page')];
  1536.   }
  1537.  
  1538.  
  1539.   API.getBook = getBook;
  1540.   API.getPlace = getPlace;
  1541.   API.moveTo = moveTo;
  1542.   API.skipToChapter = skipToChapter;
  1543.   API.resized = resized;
  1544.   API.addControl = addControl;
  1545.   API.hideControl = hideControl;
  1546.   API.showControl = showControl;
  1547.   API.showingControl = showingControl;
  1548.   API.dispatchEvent = dispatchEvent;
  1549.   API.listen = listen;
  1550.   API.deafen = deafen;
  1551.   API.addPageStyles = addPageStyles;
  1552.   API.updatePageStyles = updatePageStyles;
  1553.   API.removePageStyles = removePageStyles;
  1554.   API.visiblePages = visiblePages;
  1555.  
  1556.   initialize(node, bookData, options, onLoadCallback);
  1557.  
  1558.   return API;
  1559. }
  1560.  
  1561. Monocle.Reader.durations = {
  1562.   RESIZE_DELAY: 100
  1563. }
  1564. Monocle.Reader.abortMessage = {
  1565.   CLASSNAME: "monocleAbortMessage",
  1566.   TEXT: "Your browser does not support this technology."
  1567. }
  1568. Monocle.Reader.DEFAULT_SYSTEM_ID = 'RS:monocle'
  1569. Monocle.Reader.DEFAULT_CLASS_PREFIX = 'monelem_'
  1570. Monocle.Reader.FLIPPER_DEFAULT_CLASS = "Slider";
  1571. Monocle.Reader.FLIPPER_LEGACY_CLASS = "Legacy";
  1572. Monocle.Reader.DEFAULT_STYLE_RULES = [
  1573.   "html#RS\\:monocle * {" +
  1574.     "-webkit-font-smoothing: subpixel-antialiased;" +
  1575.     "text-rendering: auto !important;" +
  1576.     "word-wrap: break-word !important;" +
  1577.     "overflow: visible !important;" +
  1578.     (Monocle.Browser.has.floatColumnBug ? "float: none !important;" : "") +
  1579.   "}",
  1580.   "html#RS\\:monocle body {" +
  1581.     "margin: 0 !important;" +
  1582.     "padding: 0 !important;" +
  1583.     "-webkit-text-size-adjust: none;" +
  1584.   "}",
  1585.   "html#RS\\:monocle body * {" +
  1586.     "max-width: 100% !important;" +
  1587.   "}",
  1588.   "html#RS\\:monocle img, html#RS\\:monocle video, html#RS\\:monocle object {" +
  1589.     "max-height: 95% !important;" +
  1590.   "}"
  1591. ]
  1592.  
  1593. if (Monocle.Browser.has.columnOverflowPaintBug) {
  1594.   Monocle.Reader.DEFAULT_STYLE_RULES.push(
  1595.     "::-webkit-scrollbar { width: 0; height: 0; }"
  1596.   )
  1597. }
  1598.  
  1599.  
  1600. Monocle.pieceLoaded('reader');
  1601. /* BOOK */
  1602.  
  1603. /* The Book handles movement through the content by the reader page elements.
  1604.  *
  1605.  * It's responsible for instantiating components as they are required,
  1606.  * and for calculating which component and page number to move to (based on
  1607.  * requests from the Reader).
  1608.  *
  1609.  * It should set and know the place of each page element too.
  1610.  *
  1611.  */
  1612. Monocle.Book = function (dataSource) {
  1613.   if (Monocle == this) { return new Monocle.Book(dataSource); }
  1614.  
  1615.   var API = { constructor: Monocle.Book }
  1616.   var k = API.constants = API.constructor;
  1617.   var p = API.properties = {
  1618.     dataSource: dataSource,
  1619.     components: [],
  1620.     chapters: {} // flat arrays of chapters per component
  1621.   }
  1622.  
  1623.  
  1624.   function initialize() {
  1625.     p.componentIds = dataSource.getComponents();
  1626.     p.contents = dataSource.getContents();
  1627.     p.lastCIndex = p.componentIds.length - 1;
  1628.   }
  1629.  
  1630.  
  1631.   function pageNumberAt(pageDiv, locus) {
  1632.     locus.load = false;
  1633.     var currComponent = pageDiv.m.activeFrame ?
  1634.       pageDiv.m.activeFrame.m.component :
  1635.       null;
  1636.     var component = null;
  1637.     var cIndex = p.componentIds.indexOf(locus.componentId);
  1638.     if (cIndex < 0 && !currComponent) {
  1639.       locus.load = true;
  1640.       locus.componentId = p.componentIds[0];
  1641.       return locus;
  1642.     } else if (
  1643.       cIndex < 0 &&
  1644.       locus.componentId &&
  1645.       currComponent.properties.id != locus.componentId
  1646.     ) {
  1647.       pageDiv.m.reader.dispatchEvent(
  1648.         "monocle:notfound",
  1649.         { href: locus.componentId }
  1650.       );
  1651.       return null;
  1652.     } else if (cIndex < 0) {
  1653.       component = currComponent;
  1654.       locus.componentId = pageDiv.m.activeFrame.m.component.properties.id;
  1655.       cIndex = p.componentIds.indexOf(locus.componentId);
  1656.     } else if (!p.components[cIndex] || p.components[cIndex] != currComponent) {
  1657.       locus.load = true;
  1658.       return locus;
  1659.     } else {
  1660.       component = currComponent;
  1661.     }
  1662.  
  1663.     var result = { load: false, componentId: locus.componentId, page: 1 }
  1664.  
  1665.     var lastPageNum = { 'old': component.lastPageNumber() }
  1666.     var changedDims = component.updateDimensions(pageDiv);
  1667.     lastPageNum['new'] = component.lastPageNumber();
  1668.  
  1669.     if (typeof(locus.page) == "number") {
  1670.       result.page = locus.page;
  1671.     } else if (typeof(locus.pagesBack) == "number") {
  1672.       result.page = lastPageNum['new'] + locus.pagesBack;
  1673.     } else if (typeof(locus.percent) == "number") {
  1674.       var place = new Monocle.Place();
  1675.       place.setPlace(component, 1);
  1676.       result.page = place.pageAtPercentageThrough(locus.percent);
  1677.     } else if (typeof(locus.direction) == "number") {
  1678.       if (!pageDiv.m.place) {
  1679.         console.warn("Can't move in a direction if pageDiv has no place.");
  1680.       }
  1681.       result.page = pageDiv.m.place.pageNumber();
  1682.       result.page += locus.direction;
  1683.     } else if (typeof(locus.anchor) == "string") {
  1684.       result.page = component.pageForChapter(locus.anchor, pageDiv);
  1685.     } else if (typeof(locus.xpath) == "string") {
  1686.       result.page = component.pageForXPath(locus.xpath, pageDiv);
  1687.     } else if (typeof(locus.position) == "string") {
  1688.       if (locus.position == "start") {
  1689.         result.page = 1;
  1690.       } else if (locus.position == "end") {
  1691.         result.page = lastPageNum['new'];
  1692.       }
  1693.     } else {
  1694.       console.warn("Unrecognised locus: " + locus);
  1695.     }
  1696.  
  1697.     if (changedDims && lastPageNum['old']) {
  1698.       result.page = Math.round(
  1699.         lastPageNum['new'] * (result.page / lastPageNum['old'])
  1700.       );
  1701.     }
  1702.  
  1703.     if (result.page < 1) {
  1704.       if (cIndex == 0) {
  1705.         result.page = 1;
  1706.         result.boundarystart = true;
  1707.       } else {
  1708.         result.load = true;
  1709.         result.componentId = p.componentIds[cIndex - 1];
  1710.         result.pagesBack = result.page;
  1711.         result.page = null;
  1712.       }
  1713.     } else if (result.page > lastPageNum['new']) {
  1714.       if (cIndex == p.lastCIndex) {
  1715.         result.page = lastPageNum['new'];
  1716.         result.boundaryend = true;
  1717.       } else {
  1718.         result.load = true;
  1719.         result.componentId = p.componentIds[cIndex + 1];
  1720.         result.page -= lastPageNum['new'];
  1721.       }
  1722.     }
  1723.  
  1724.     return result;
  1725.   }
  1726.  
  1727.  
  1728.   function setPageAt(pageDiv, locus) {
  1729.     locus = pageNumberAt(pageDiv, locus);
  1730.     if (locus && !locus.load) {
  1731.       var evtData = { locus: locus, page: pageDiv }
  1732.       if (locus.boundarystart) {
  1733.         pageDiv.m.reader.dispatchEvent('monocle:boundarystart', evtData);
  1734.       } else if (locus.boundaryend) {
  1735.         pageDiv.m.reader.dispatchEvent('monocle:boundaryend', evtData);
  1736.       } else {
  1737.         var component = p.components[p.componentIds.indexOf(locus.componentId)];
  1738.         pageDiv.m.place = pageDiv.m.place || new Monocle.Place();
  1739.         pageDiv.m.place.setPlace(component, locus.page);
  1740.  
  1741.         var evtData = {
  1742.           page: pageDiv,
  1743.           locus: locus,
  1744.           pageNumber: pageDiv.m.place.pageNumber(),
  1745.           componentId: locus.componentId
  1746.         }
  1747.         pageDiv.m.reader.dispatchEvent("monocle:pagechange", evtData);
  1748.       }
  1749.     }
  1750.     return locus;
  1751.   }
  1752.  
  1753.  
  1754.   function loadPageAt(pageDiv, locus, callback, progressCallback) {
  1755.     var cIndex = p.componentIds.indexOf(locus.componentId);
  1756.     if (!locus.load || cIndex < 0) {
  1757.       locus = pageNumberAt(pageDiv, locus);
  1758.     }
  1759.  
  1760.     if (!locus) {
  1761.       return;
  1762.     }
  1763.  
  1764.     if (!locus.load) {
  1765.       callback(locus);
  1766.       return;
  1767.     }
  1768.  
  1769.     var findPageNumber = function () {
  1770.       locus = setPageAt(pageDiv, locus);
  1771.       if (!locus) {
  1772.         return;
  1773.       } else if (locus.load) {
  1774.         loadPageAt(pageDiv, locus, callback, progressCallback)
  1775.       } else {
  1776.         callback(locus);
  1777.       }
  1778.     }
  1779.  
  1780.     var pgFindPageNumber = function () {
  1781.       progressCallback ? progressCallback(findPageNumber) : findPageNumber();
  1782.     }
  1783.  
  1784.     var applyComponent = function (component) {
  1785.       component.applyTo(pageDiv, pgFindPageNumber);
  1786.     }
  1787.  
  1788.     var pgApplyComponent = function (component) {
  1789.       progressCallback ?
  1790.         progressCallback(function () { applyComponent(component) }) :
  1791.         applyComponent(component);
  1792.     }
  1793.  
  1794.     loadComponent(cIndex, pgApplyComponent, pageDiv);
  1795.   }
  1796.  
  1797.  
  1798.   function setOrLoadPageAt(pageDiv, locus, callback, onProgress, onFail) {
  1799.     locus = setPageAt(pageDiv, locus);
  1800.     if (!locus) {
  1801.       if (onFail) { onFail(); }
  1802.     } else if (locus.load) {
  1803.       loadPageAt(pageDiv, locus, callback, onProgress);
  1804.     } else {
  1805.       callback(locus);
  1806.     }
  1807.   }
  1808.  
  1809.  
  1810.   function loadComponent(index, callback, pageDiv) {
  1811.     if (p.components[index]) {
  1812.       return callback(p.components[index]);
  1813.     }
  1814.     var cmptId = p.componentIds[index];
  1815.     if (pageDiv) {
  1816.       var evtData = { 'page': pageDiv, 'component': cmptId, 'index': index };
  1817.       pageDiv.m.reader.dispatchEvent('monocle:componentloading', evtData);
  1818.     }
  1819.     var fn = function (cmptSource) {
  1820.       if (pageDiv) {
  1821.         evtData['source'] = cmptSource;
  1822.         pageDiv.m.reader.dispatchEvent('monocle:componentloaded', evtData);
  1823.         html = evtData['html'];
  1824.       }
  1825.       p.components[index] = new Monocle.Component(
  1826.         API,
  1827.         cmptId,
  1828.         index,
  1829.         chaptersForComponent(cmptId),
  1830.         cmptSource
  1831.       );
  1832.       callback(p.components[index]);
  1833.     }
  1834.     var cmptSource = p.dataSource.getComponent(cmptId, fn);
  1835.     if (cmptSource && !p.components[index]) {
  1836.       fn(cmptSource);
  1837.     }
  1838.   }
  1839.  
  1840.  
  1841.   function chaptersForComponent(cmptId) {
  1842.     if (p.chapters[cmptId]) {
  1843.       return p.chapters[cmptId];
  1844.     }
  1845.     p.chapters[cmptId] = [];
  1846.     var matcher = new RegExp('^'+cmptId+"(\#(.+)|$)");
  1847.     var matches;
  1848.     var recurser = function (chp) {
  1849.       if (matches = chp.src.match(matcher)) {
  1850.         p.chapters[cmptId].push({
  1851.           title: chp.title,
  1852.           fragment: matches[2] || null
  1853.         });
  1854.       }
  1855.       if (chp.children) {
  1856.         for (var i = 0; i < chp.children.length; ++i) {
  1857.           recurser(chp.children[i]);
  1858.         }
  1859.       }
  1860.     }
  1861.  
  1862.     for (var i = 0; i < p.contents.length; ++i) {
  1863.       recurser(p.contents[i]);
  1864.     }
  1865.     return p.chapters[cmptId];
  1866.   }
  1867.  
  1868.  
  1869.   function locusOfChapter(src) {
  1870.     var matcher = new RegExp('^(.+?)(#(.*))?$');
  1871.     var matches = src.match(matcher);
  1872.     if (!matches) { return null; }
  1873.     var cmptId = componentIdMatching(matches[1]);
  1874.     if (!cmptId) { return null; }
  1875.     var locus = { componentId: cmptId }
  1876.     matches[3] ? locus.anchor = matches[3] : locus.position = "start";
  1877.     return locus;
  1878.   }
  1879.  
  1880.  
  1881.   function componentIdMatching(str) {
  1882.     return p.componentIds.indexOf(str) >= 0 ? str : null;
  1883.   }
  1884.  
  1885.  
  1886.   API.getMetaData = dataSource.getMetaData;
  1887.   API.pageNumberAt = pageNumberAt;
  1888.   API.setPageAt = setPageAt;
  1889.   API.loadPageAt = loadPageAt;
  1890.   API.setOrLoadPageAt = setOrLoadPageAt;
  1891.   API.chaptersForComponent = chaptersForComponent;
  1892.   API.locusOfChapter = locusOfChapter;
  1893.  
  1894.   initialize();
  1895.  
  1896.   return API;
  1897. }
  1898.  
  1899.  
  1900. Monocle.Book.fromNodes = function (nodes) {
  1901.   var bookData = {
  1902.     getComponents: function () {
  1903.       return ['anonymous'];
  1904.     },
  1905.     getContents: function () {
  1906.       return [];
  1907.     },
  1908.     getComponent: function (n) {
  1909.       return { 'nodes': nodes };
  1910.     },
  1911.     getMetaData: function (key) {
  1912.     }
  1913.   }
  1914.  
  1915.   return new Monocle.Book(bookData);
  1916. }
  1917.  
  1918. Monocle.pieceLoaded('book');
  1919.  
  1920. Monocle.Place = function () {
  1921.  
  1922.   var API = { constructor: Monocle.Place }
  1923.   var k = API.constants = API.constructor;
  1924.   var p = API.properties = {
  1925.     component: null,
  1926.     percent: null
  1927.   }
  1928.  
  1929.  
  1930.   function setPlace(cmpt, pageN) {
  1931.     p.component = cmpt;
  1932.     p.percent = pageN / cmpt.lastPageNumber();
  1933.     p.chapter = null;
  1934.   }
  1935.  
  1936.  
  1937.   function setPercentageThrough(cmpt, percent) {
  1938.     p.component = cmpt;
  1939.     p.percent = percent;
  1940.     p.chapter = null;
  1941.   }
  1942.  
  1943.  
  1944.   function componentId() {
  1945.     return p.component.properties.id;
  1946.   }
  1947.  
  1948.  
  1949.   function percentAtTopOfPage() {
  1950.     return p.percent - 1.0 / p.component.lastPageNumber();
  1951.   }
  1952.  
  1953.  
  1954.   function percentAtBottomOfPage() {
  1955.     return p.percent;
  1956.   }
  1957.  
  1958.  
  1959.   function pageAtPercentageThrough(percent) {
  1960.     return Math.max(Math.round(p.component.lastPageNumber() * percent), 1);
  1961.   }
  1962.  
  1963.  
  1964.   function pageNumber() {
  1965.     return pageAtPercentageThrough(p.percent);
  1966.   }
  1967.  
  1968.  
  1969.   function chapterInfo() {
  1970.     if (p.chapter) {
  1971.       return p.chapter;
  1972.     }
  1973.     return p.chapter = p.component.chapterForPage(pageNumber());
  1974.   }
  1975.  
  1976.  
  1977.   function chapterTitle() {
  1978.     var chp = chapterInfo();
  1979.     return chp ? chp.title : null;
  1980.   }
  1981.  
  1982.  
  1983.   function chapterSrc() {
  1984.     var src = componentId();
  1985.     var cinfo = chapterInfo();
  1986.     if (cinfo && cinfo.fragment) {
  1987.       src += "#" + cinfo.fragment;
  1988.     }
  1989.     return src;
  1990.   }
  1991.  
  1992.  
  1993.   function getLocus(options) {
  1994.     options = options || {};
  1995.     var locus = {
  1996.       page: pageNumber(),
  1997.       componentId: componentId()
  1998.     }
  1999.     if (options.direction) {
  2000.       locus.page += options.direction;
  2001.     } else {
  2002.       locus.percent = percentAtBottomOfPage();
  2003.     }
  2004.     return locus;
  2005.   }
  2006.  
  2007.  
  2008.   function percentageOfBook() {
  2009.     componentIds = p.component.properties.book.properties.componentIds;
  2010.     componentSize = 1.0 / componentIds.length;
  2011.     var pc = componentIds.indexOf(componentId()) * componentSize;
  2012.     pc += componentSize * p.percent;
  2013.     return pc;
  2014.   }
  2015.  
  2016.  
  2017.   function onFirstPageOfBook() {
  2018.     return p.component.properties.index == 0 && pageNumber() == 1;
  2019.   }
  2020.  
  2021.  
  2022.   function onLastPageOfBook() {
  2023.     return (
  2024.       p.component.properties.index ==
  2025.         p.component.properties.book.properties.lastCIndex &&
  2026.       pageNumber() == p.component.lastPageNumber()
  2027.     );
  2028.   }
  2029.  
  2030.  
  2031.   API.setPlace = setPlace;
  2032.   API.setPercentageThrough = setPercentageThrough;
  2033.   API.componentId = componentId;
  2034.   API.percentAtTopOfPage = percentAtTopOfPage;
  2035.   API.percentAtBottomOfPage = percentAtBottomOfPage;
  2036.   API.percentageThrough = percentAtBottomOfPage;
  2037.   API.pageAtPercentageThrough = pageAtPercentageThrough;
  2038.   API.pageNumber = pageNumber;
  2039.   API.chapterInfo = chapterInfo;
  2040.   API.chapterTitle = chapterTitle;
  2041.   API.chapterSrc = chapterSrc;
  2042.   API.getLocus = getLocus;
  2043.   API.percentageOfBook = percentageOfBook;
  2044.   API.onFirstPageOfBook = onFirstPageOfBook;
  2045.   API.onLastPageOfBook = onLastPageOfBook;
  2046.  
  2047.   return API;
  2048. }
  2049.  
  2050.  
  2051. Monocle.Place.FromPageNumber = function (component, pageNumber) {
  2052.   var place = new Monocle.Place();
  2053.   place.setPlace(component, pageNumber);
  2054.   return place;
  2055. }
  2056.  
  2057. Monocle.Place.FromPercentageThrough = function (component, percent) {
  2058.   var place = new Monocle.Place();
  2059.   place.setPercentageThrough(component, percent);
  2060.   return place;
  2061. }
  2062.  
  2063. Monocle.pieceLoaded('place');
  2064. /* COMPONENT */
  2065.  
  2066. Monocle.Component = function (book, id, index, chapters, source) {
  2067.  
  2068.   var API = { constructor: Monocle.Component }
  2069.   var k = API.constants = API.constructor;
  2070.   var p = API.properties = {
  2071.     book: book,
  2072.  
  2073.     id: id,
  2074.  
  2075.     index: index,
  2076.  
  2077.     chapters: chapters,
  2078.  
  2079.     source: source
  2080.   }
  2081.  
  2082.  
  2083.   function applyTo(pageDiv, callback) {
  2084.     var evtData = { 'page': pageDiv, 'source': p.source };
  2085.     pageDiv.m.reader.dispatchEvent('monocle:componentchanging', evtData);
  2086.  
  2087.     return loadFrame(
  2088.       pageDiv,
  2089.       function () {
  2090.         setupFrame(pageDiv, pageDiv.m.activeFrame);
  2091.         callback(pageDiv, API);
  2092.       }
  2093.     );
  2094.   }
  2095.  
  2096.  
  2097.   function loadFrame(pageDiv, callback) {
  2098.     var frame = pageDiv.m.activeFrame;
  2099.  
  2100.     frame.m.component = API;
  2101.  
  2102.     frame.style.visibility = "hidden";
  2103.  
  2104.  
  2105.     if (p.source.html || (typeof p.source == "string")) {   // HTML
  2106.       return loadFrameFromHTML(p.source.html || p.source, frame, callback);
  2107.     } else if (p.source.url) {                              // URL
  2108.       return loadFrameFromURL(p.source.url, frame, callback);
  2109.     } else if (p.source.nodes) {                            // NODES
  2110.       return loadFrameFromNodes(p.source.nodes, frame, callback);
  2111.     } else if (p.source.doc) {                              // DOCUMENT
  2112.       return loadFrameFromDocument(p.source.doc, frame, callback);
  2113.     }
  2114.   }
  2115.  
  2116.  
  2117.   function loadFrameFromHTML(src, frame, callback) {
  2118.     src = src.replace(/\s+/g, ' ');
  2119.  
  2120.     src = src.replace(/\'/g, '\\\'');
  2121.  
  2122.  
  2123.     if (Monocle.Browser.is.Gecko) {
  2124.       var doctypeFragment = "<!DOCTYPE[^>]*>";
  2125.       src = src.replace(new RegExp(doctypeFragment, 'm'), '');
  2126.     }
  2127.  
  2128.     src = "javascript: '" + src + "';";
  2129.  
  2130.     frame.onload = function () {
  2131.       frame.onload = null;
  2132.       Monocle.defer(callback);
  2133.     }
  2134.     frame.src = src;
  2135.   }
  2136.  
  2137.  
  2138.   function loadFrameFromURL(url, frame, callback) {
  2139.     if (!url.match(/^\//)) {
  2140.       var link = document.createElement('a');
  2141.       link.setAttribute('href', url);
  2142.       url = link.href;
  2143.       delete(link);
  2144.     }
  2145.     frame.onload = function () {
  2146.       frame.onload = null;
  2147.       Monocle.defer(callback);
  2148.     }
  2149.     frame.contentWindow.location.replace(url);
  2150.   }
  2151.  
  2152.  
  2153.   function loadFrameFromNodes(nodes, frame, callback) {
  2154.     var destDoc = frame.contentDocument;
  2155.     destDoc.documentElement.innerHTML = "";
  2156.     var destHd = destDoc.createElement("head");
  2157.     var destBdy = destDoc.createElement("body");
  2158.  
  2159.     for (var i = 0; i < nodes.length; ++i) {
  2160.       var node = destDoc.importNode(nodes[i], true);
  2161.       destBdy.appendChild(node);
  2162.     }
  2163.  
  2164.     var oldHead = destDoc.getElementsByTagName('head')[0];
  2165.     if (oldHead) {
  2166.       destDoc.documentElement.replaceChild(destHd, oldHead);
  2167.     } else {
  2168.       destDoc.documentElement.appendChild(destHd);
  2169.     }
  2170.     if (destDoc.body) {
  2171.       destDoc.documentElement.replaceChild(destBdy, destDoc.body);
  2172.     } else {
  2173.       destDoc.documentElement.appendChild(destBdy);
  2174.     }
  2175.  
  2176.     if (callback) { callback(); }
  2177.   }
  2178.  
  2179.  
  2180.   function loadFrameFromDocument(srcDoc, frame, callback) {
  2181.     var destDoc = frame.contentDocument;
  2182.  
  2183.     var srcBases = srcDoc.getElementsByTagName('base');
  2184.     if (srcBases[0]) {
  2185.       var head = destDoc.getElementsByTagName('head')[0];
  2186.       if (!head) {
  2187.         try {
  2188.           head = destDoc.createElement('head');
  2189.           if (destDoc.body) {
  2190.             destDoc.insertBefore(head, destDoc.body);
  2191.           } else {
  2192.             destDoc.appendChild(head);
  2193.           }
  2194.         } catch (e) {
  2195.           head = destDoc.body;
  2196.         }
  2197.       }
  2198.       var bases = destDoc.getElementsByTagName('base');
  2199.       var base = bases[0] ? bases[0] : destDoc.createElement('base');
  2200.       base.setAttribute('href', srcBases[0].getAttribute('href'));
  2201.       head.appendChild(base);
  2202.     }
  2203.  
  2204.     destDoc.replaceChild(
  2205.       destDoc.importNode(srcDoc.documentElement, true),
  2206.       destDoc.documentElement
  2207.     );
  2208.  
  2209.  
  2210.     Monocle.defer(callback);
  2211.   }
  2212.  
  2213.  
  2214.   function setupFrame(pageDiv, frame) {
  2215.     Monocle.Events.listenOnIframe(frame);
  2216.  
  2217.     var evtData = {
  2218.       'page': pageDiv,
  2219.       'document': frame.contentDocument,
  2220.       'component': API
  2221.     };
  2222.     pageDiv.m.reader.dispatchEvent('monocle:componentchange', evtData);
  2223.  
  2224.     var doc = frame.contentDocument;
  2225.     var win = doc.defaultView;
  2226.     var currStyle = win.getComputedStyle(doc.body, null);
  2227.     var lh = parseFloat(currStyle.getPropertyValue('line-height'));
  2228.     var fs = parseFloat(currStyle.getPropertyValue('font-size'));
  2229.     doc.body.style.lineHeight = lh / fs;
  2230.  
  2231.     p.pageLength = pageDiv.m.dimensions.measure();
  2232.     frame.style.visibility = "visible";
  2233.  
  2234.     locateChapters(pageDiv);
  2235.   }
  2236.  
  2237.  
  2238.   function updateDimensions(pageDiv) {
  2239.     if (pageDiv.m.dimensions.hasChanged()) {
  2240.       p.pageLength = pageDiv.m.dimensions.measure();
  2241.       return true;
  2242.     } else {
  2243.       return false;
  2244.     }
  2245.   }
  2246.  
  2247.  
  2248.   function locateChapters(pageDiv) {
  2249.     if (p.chapters[0] && typeof p.chapters[0].percent == "number") {
  2250.       return;
  2251.     }
  2252.     var doc = pageDiv.m.activeFrame.contentDocument;
  2253.     for (var i = 0; i < p.chapters.length; ++i) {
  2254.       var chp = p.chapters[i];
  2255.       chp.percent = 0;
  2256.       if (chp.fragment) {
  2257.         var node = doc.getElementById(chp.fragment);
  2258.         chp.percent = pageDiv.m.dimensions.percentageThroughOfNode(node);
  2259.       }
  2260.     }
  2261.     return p.chapters;
  2262.   }
  2263.  
  2264.  
  2265.   function chapterForPage(pageN) {
  2266.     var cand = null;
  2267.     var percent = (pageN - 1) / p.pageLength;
  2268.     for (var i = 0; i < p.chapters.length; ++i) {
  2269.       if (percent >= p.chapters[i].percent) {
  2270.         cand = p.chapters[i];
  2271.       } else {
  2272.         return cand;
  2273.       }
  2274.     }
  2275.     return cand;
  2276.   }
  2277.  
  2278.  
  2279.   function pageForChapter(fragment, pageDiv) {
  2280.     if (!fragment) {
  2281.       return 1;
  2282.     }
  2283.     for (var i = 0; i < p.chapters.length; ++i) {
  2284.       if (p.chapters[i].fragment == fragment) {
  2285.         return percentToPageNumber(p.chapters[i].percent);
  2286.       }
  2287.     }
  2288.     var doc = pageDiv.m.activeFrame.contentDocument;
  2289.     var node = doc.getElementById(fragment);
  2290.     var percent = pageDiv.m.dimensions.percentageThroughOfNode(node);
  2291.     return percentToPageNumber(percent);
  2292.   }
  2293.  
  2294.  
  2295.   function pageForXPath(xpath, pageDiv) {
  2296.     var doc = pageDiv.m.activeFrame.contentDocument;
  2297.     var percent = 0;
  2298.     if (typeof doc.evaluate == "function") {
  2299.       var node = doc.evaluate(
  2300.         xpath,
  2301.         doc,
  2302.         null,
  2303.         9,
  2304.         null
  2305.       ).singleNodeValue;
  2306.       var percent = pageDiv.m.dimensions.percentageThroughOfNode(node);
  2307.     }
  2308.     return percentToPageNumber(percent);
  2309.   }
  2310.  
  2311.  
  2312.   function percentToPageNumber(pc) {
  2313.     return Math.floor(pc * p.pageLength) + 1;
  2314.   }
  2315.  
  2316.  
  2317.   function lastPageNumber() {
  2318.     return p.pageLength;
  2319.   }
  2320.  
  2321.  
  2322.   API.applyTo = applyTo;
  2323.   API.updateDimensions = updateDimensions;
  2324.   API.chapterForPage = chapterForPage;
  2325.   API.pageForChapter = pageForChapter;
  2326.   API.pageForXPath = pageForXPath;
  2327.   API.lastPageNumber = lastPageNumber;
  2328.  
  2329.   return API;
  2330. }
  2331.  
  2332. Monocle.pieceLoaded('component');
  2333.  
  2334. Monocle.Dimensions = {}
  2335. Monocle.Controls = {};
  2336. Monocle.Flippers = {};
  2337. Monocle.Panels = {};
  2338.  
  2339. Monocle.Controls.Panel = function () {
  2340.  
  2341.   var API = { constructor: Monocle.Controls.Panel }
  2342.   var k = API.constants = API.constructor;
  2343.   var p = API.properties = {
  2344.     evtCallbacks: {}
  2345.   }
  2346.  
  2347.   function createControlElements(cntr) {
  2348.     p.div = cntr.dom.make('div', k.CLS.panel);
  2349.     p.div.dom.setStyles(k.DEFAULT_STYLES);
  2350.     Monocle.Events.listenForContact(
  2351.       p.div,
  2352.       {
  2353.         'start': start,
  2354.         'move': move,
  2355.         'end': end,
  2356.         'cancel': cancel
  2357.       },
  2358.       { useCapture: false }
  2359.     );
  2360.     return p.div;
  2361.   }
  2362.  
  2363.  
  2364.   function listenTo(evtCallbacks) {
  2365.     p.evtCallbacks = evtCallbacks;
  2366.   }
  2367.  
  2368.  
  2369.   function deafen() {
  2370.     p.evtCallbacks = {}
  2371.   }
  2372.  
  2373.  
  2374.   function start(evt) {
  2375.     p.contact = true;
  2376.     evt.m.offsetX += p.div.offsetLeft;
  2377.     evt.m.offsetY += p.div.offsetTop;
  2378.     expand();
  2379.     invoke('start', evt);
  2380.   }
  2381.  
  2382.  
  2383.   function move(evt) {
  2384.     if (!p.contact) {
  2385.       return;
  2386.     }
  2387.     invoke('move', evt);
  2388.   }
  2389.  
  2390.  
  2391.   function end(evt) {
  2392.     if (!p.contact) {
  2393.       return;
  2394.     }
  2395.     Monocle.Events.deafenForContact(p.div, p.listeners);
  2396.     contract();
  2397.     p.contact = false;
  2398.     invoke('end', evt);
  2399.   }
  2400.  
  2401.  
  2402.   function cancel(evt) {
  2403.     if (!p.contact) {
  2404.       return;
  2405.     }
  2406.     Monocle.Events.deafenForContact(p.div, p.listeners);
  2407.     contract();
  2408.     p.contact = false;
  2409.     invoke('cancel', evt);
  2410.   }
  2411.  
  2412.  
  2413.   function invoke(evtType, evt) {
  2414.     if (p.evtCallbacks[evtType]) {
  2415.       p.evtCallbacks[evtType](API, evt.m.offsetX, evt.m.offsetY);
  2416.     }
  2417.     evt.preventDefault();
  2418.   }
  2419.  
  2420.  
  2421.   function expand() {
  2422.     if (p.expanded) {
  2423.       return;
  2424.     }
  2425.     p.div.dom.addClass(k.CLS.expanded);
  2426.     p.expanded = true;
  2427.   }
  2428.  
  2429.  
  2430.   function contract(evt) {
  2431.     if (!p.expanded) {
  2432.       return;
  2433.     }
  2434.     p.div.dom.removeClass(k.CLS.expanded);
  2435.     p.expanded = false;
  2436.   }
  2437.  
  2438.  
  2439.   API.createControlElements = createControlElements;
  2440.   API.listenTo = listenTo;
  2441.   API.deafen = deafen;
  2442.   API.expand = expand;
  2443.   API.contract = contract;
  2444.  
  2445.   return API;
  2446. }
  2447.  
  2448.  
  2449. Monocle.Controls.Panel.CLS = {
  2450.   panel: 'panel',
  2451.   expanded: 'controls_panel_expanded'
  2452. }
  2453. Monocle.Controls.Panel.DEFAULT_STYLES = {
  2454.   position: 'absolute',
  2455.   height: '100%'
  2456. }
  2457.  
  2458.  
  2459. Monocle.pieceLoaded('controls/panel');
  2460. Monocle.Panels.TwoPane = function (flipper, evtCallbacks) {
  2461.  
  2462.   var API = { constructor: Monocle.Panels.TwoPane }
  2463.   var k = API.constants = API.constructor;
  2464.   var p = API.properties = {}
  2465.  
  2466.  
  2467.   function initialize() {
  2468.     p.panels = {
  2469.       forwards: new Monocle.Controls.Panel(),
  2470.       backwards: new Monocle.Controls.Panel()
  2471.     }
  2472.  
  2473.     for (dir in p.panels) {
  2474.       flipper.properties.reader.addControl(p.panels[dir]);
  2475.       p.panels[dir].listenTo(evtCallbacks);
  2476.       p.panels[dir].properties.direction = flipper.constants[dir.toUpperCase()];
  2477.       var style = { "width": k.WIDTH };
  2478.       style[(dir == "forwards" ? "right" : "left")] = 0;
  2479.       p.panels[dir].properties.div.dom.setStyles(style);
  2480.     }
  2481.   }
  2482.  
  2483.  
  2484.   initialize();
  2485.  
  2486.   return API;
  2487. }
  2488.  
  2489. Monocle.Panels.TwoPane.WIDTH = "50%";
  2490.  
  2491. Monocle.pieceLoaded('panels/twopane');
  2492. Monocle.Dimensions.Vert = function (pageDiv) {
  2493.  
  2494.   var API = { constructor: Monocle.Dimensions.Vert }
  2495.   var k = API.constants = API.constructor;
  2496.   var p = API.properties = {
  2497.     page: pageDiv,
  2498.     reader: pageDiv.m.reader
  2499.   }
  2500.  
  2501.  
  2502.   function initialize() {
  2503.     p.reader.listen('monocle:componentchange', componentChanged);
  2504.   }
  2505.  
  2506.  
  2507.   function hasChanged() {
  2508.     return getBodyHeight() != p.bodyHeight || getPageHeight != p.pageHeight;
  2509.   }
  2510.  
  2511.  
  2512.   function measure() {
  2513.     p.bodyHeight = getBodyHeight();
  2514.     p.pageHeight = getPageHeight();
  2515.     p.length = Math.ceil(p.bodyHeight / p.pageHeight);
  2516.     return p.length;
  2517.   }
  2518.  
  2519.  
  2520.   function pages() {
  2521.     return p.length;
  2522.   }
  2523.  
  2524.  
  2525.   function getBodyHeight() {
  2526.     return p.page.m.activeFrame.contentDocument.body.scrollHeight;
  2527.   }
  2528.  
  2529.  
  2530.   function getPageHeight() {
  2531.     return p.page.m.activeFrame.offsetHeight - k.GUTTER;
  2532.   }
  2533.  
  2534.  
  2535.   function percentageThroughOfNode(target) {
  2536.     if (!target) {
  2537.       return 0;
  2538.     }
  2539.     var doc = p.page.m.activeFrame.contentDocument;
  2540.     var offset = 0;
  2541.     if (target.getBoundingClientRect) {
  2542.       offset = target.getBoundingClientRect().top;
  2543.       offset -= doc.body.getBoundingClientRect().top;
  2544.     } else {
  2545.       var oldScrollTop = doc.body.scrollTop;
  2546.       target.scrollIntoView();
  2547.       offset = doc.body.scrollTop;
  2548.       doc.body.scrollLeft = 0;
  2549.       doc.body.scrollTop = oldScrollTop;
  2550.     }
  2551.  
  2552.     var percent = offset / p.bodyHeight;
  2553.     return percent;
  2554.   }
  2555.  
  2556.  
  2557.   function componentChanged(evt) {
  2558.     if (evt.m['page'] != p.page) { return; }
  2559.     var sheaf = p.page.m.sheafDiv;
  2560.     var cmpt = p.page.m.activeFrame;
  2561.     sheaf.dom.setStyles(k.SHEAF_STYLES);
  2562.     cmpt.dom.setStyles(k.COMPONENT_STYLES);
  2563.     var doc = evt.m['document'];
  2564.     doc.documentElement.style.overflow = 'hidden';
  2565.     doc.body.style.marginRight = '10px !important';
  2566.     cmpt.contentWindow.scrollTo(0,0);
  2567.   }
  2568.  
  2569.  
  2570.   function locusToOffset(locus) {
  2571.     return p.pageHeight * (locus.page - 1);
  2572.   }
  2573.  
  2574.  
  2575.   API.hasChanged = hasChanged;
  2576.   API.measure = measure;
  2577.   API.pages = pages;
  2578.   API.percentageThroughOfNode = percentageThroughOfNode;
  2579.   API.locusToOffset = locusToOffset;
  2580.  
  2581.   initialize();
  2582.  
  2583.   return API;
  2584. }
  2585.  
  2586. Monocle.Dimensions.Vert.GUTTER = 10;
  2587. Monocle.Flippers.Legacy = function (reader) {
  2588.  
  2589.   var API = { constructor: Monocle.Flippers.Legacy }
  2590.   var k = API.constants = API.constructor;
  2591.   var p = API.properties = {
  2592.     pageCount: 1,
  2593.     divs: {}
  2594.   }
  2595.  
  2596.  
  2597.   function initialize() {
  2598.     p.reader = reader;
  2599.   }
  2600.  
  2601.  
  2602.   function addPage(pageDiv) {
  2603.     pageDiv.m.dimensions = new Monocle.Dimensions.Vert(pageDiv);
  2604.   }
  2605.  
  2606.  
  2607.   function getPlace() {
  2608.     return page().m.place;
  2609.   }
  2610.  
  2611.  
  2612.   function moveTo(locus, callback) {
  2613.     var fn = frameToLocus;
  2614.     if (typeof callback == "function") {
  2615.       fn = function (locus) { frameToLocus(locus); callback(locus); }
  2616.     }
  2617.     p.reader.getBook().setOrLoadPageAt(page(), locus, fn);
  2618.   }
  2619.  
  2620.  
  2621.   function listenForInteraction(panelClass) {
  2622.     if (typeof panelClass != "function") {
  2623.       panelClass = k.DEFAULT_PANELS_CLASS;
  2624.       if (!panelClass) {
  2625.         console.warn("Invalid panel class.")
  2626.       }
  2627.     }
  2628.     p.panels = new panelClass(API, { 'end': turn });
  2629.   }
  2630.  
  2631.  
  2632.   function page() {
  2633.     return p.reader.dom.find('page');
  2634.   }
  2635.  
  2636.  
  2637.   function turn(panel) {
  2638.     var dir = panel.properties.direction;
  2639.     var place = getPlace();
  2640.     if (
  2641.       (dir < 0 && place.onFirstPageOfBook()) ||
  2642.       (dir > 0 && place.onLastPageOfBook())
  2643.     ) { return; }
  2644.     moveTo({ page: getPlace().pageNumber() + dir });
  2645.   }
  2646.  
  2647.  
  2648.   function frameToLocus(locus) {
  2649.     var cmpt = p.reader.dom.find('component');
  2650.     var win = cmpt.contentWindow;
  2651.     var srcY = scrollPos(win);
  2652.     var dims = page().m.dimensions;
  2653.     var pageHeight = dims.properties.pageHeight;
  2654.     var destY = dims.locusToOffset(locus);
  2655.  
  2656.     if (Math.abs(destY - srcY) > pageHeight) {
  2657.       return win.scrollTo(0, destY);
  2658.     }
  2659.  
  2660.     showIndicator(win, srcY < destY ? srcY + pageHeight : srcY);
  2661.     Monocle.defer(
  2662.       function () { smoothScroll(win, srcY, destY, 300, scrollingFinished); },
  2663.       150
  2664.     );
  2665.   }
  2666.  
  2667.  
  2668.   function scrollPos(win) {
  2669.     if (win.pageYOffset) {
  2670.       return win.pageYOffset;
  2671.     }
  2672.     if (win.document.documentElement && win.document.documentElement.scrollTop) {
  2673.       return win.document.documentElement.scrollTop;
  2674.     }
  2675.     if (win.document.body.scrollTop) {
  2676.       return win.document.body.scrollTop;
  2677.     }
  2678.     return 0;
  2679.   }
  2680.  
  2681.  
  2682.   function smoothScroll(win, currY, finalY, duration, callback) {
  2683.     clearTimeout(win.smoothScrollInterval);
  2684.     var stamp = (new Date()).getTime();
  2685.     var frameRate = 40;
  2686.     var step = (finalY - currY) * (frameRate / duration);
  2687.     var stepFn = function () {
  2688.       var destY = currY + step;
  2689.       if (
  2690.         (new Date()).getTime() - stamp > duration ||
  2691.         Math.abs(currY - finalY) < Math.abs((currY + step) - finalY)
  2692.       ) {
  2693.         clearTimeout(win.smoothScrollInterval);
  2694.         win.scrollTo(0, finalY);
  2695.         if (callback) { callback(); }
  2696.       } else {
  2697.         win.scrollTo(0, destY);
  2698.         currY = destY;
  2699.       }
  2700.     }
  2701.     win.smoothScrollInterval = setInterval(stepFn, frameRate);
  2702.   }
  2703.  
  2704.  
  2705.   function scrollingFinished() {
  2706.     hideIndicator(page().m.activeFrame.contentWindow);
  2707.     p.reader.dispatchEvent('monocle:turn');
  2708.   }
  2709.  
  2710.  
  2711.   function showIndicator(win, pos) {
  2712.     if (p.hideTO) { clearTimeout(p.hideTO); }
  2713.  
  2714.     var doc = win.document;
  2715.     if (!doc.body.indicator) {
  2716.       doc.body.indicator = createIndicator(doc);
  2717.       doc.body.appendChild(doc.body.indicator);
  2718.     }
  2719.     doc.body.indicator.line.style.display = "block";
  2720.     doc.body.indicator.style.opacity = 1;
  2721.     positionIndicator(pos);
  2722.   }
  2723.  
  2724.  
  2725.   function hideIndicator(win) {
  2726.     var doc = win.document;
  2727.     p.hideTO = Monocle.defer(
  2728.       function () {
  2729.         if (!doc.body.indicator) {
  2730.           doc.body.indicator = createIndicator(doc);
  2731.           doc.body.appendChild(doc.body.indicator);
  2732.         }
  2733.         var dims = page().m.dimensions;
  2734.         positionIndicator(
  2735.           dims.locusToOffset(getPlace().getLocus()) + dims.properties.pageHeight
  2736.         )
  2737.         doc.body.indicator.line.style.display = "none";
  2738.         doc.body.indicator.style.opacity = 0.5;
  2739.       },
  2740.       600
  2741.     );
  2742.   }
  2743.  
  2744.  
  2745.   function createIndicator(doc) {
  2746.     var iBox = doc.createElement('div');
  2747.     doc.body.appendChild(iBox);
  2748.     Monocle.Styles.applyRules(iBox, k.STYLES.iBox);
  2749.  
  2750.     iBox.arrow = doc.createElement('div');
  2751.     iBox.appendChild(iBox.arrow);
  2752.     Monocle.Styles.applyRules(iBox.arrow, k.STYLES.arrow);
  2753.  
  2754.     iBox.line = doc.createElement('div');
  2755.     iBox.appendChild(iBox.line);
  2756.     Monocle.Styles.applyRules(iBox.line, k.STYLES.line);
  2757.  
  2758.     return iBox;
  2759.   }
  2760.  
  2761.  
  2762.   function positionIndicator(y) {
  2763.     var p = page();
  2764.     var doc = p.m.activeFrame.contentDocument;
  2765.     var maxHeight = p.m.dimensions.properties.bodyHeight;
  2766.     maxHeight -= doc.body.indicator.offsetHeight;
  2767.     if (y > maxHeight) {
  2768.       y = maxHeight;
  2769.     }
  2770.     doc.body.indicator.style.top = y + "px";
  2771.   }
  2772.  
  2773.  
  2774.   API.pageCount = p.pageCount;
  2775.   API.addPage = addPage;
  2776.   API.getPlace = getPlace;
  2777.   API.moveTo = moveTo;
  2778.   API.listenForInteraction = listenForInteraction;
  2779.  
  2780.   initialize();
  2781.  
  2782.   return API;
  2783. }
  2784.  
  2785. Monocle.Flippers.Legacy.FORWARDS = 1;
  2786. Monocle.Flippers.Legacy.BACKWARDS = -1;
  2787. Monocle.Flippers.Legacy.DEFAULT_PANELS_CLASS = Monocle.Panels.TwoPane;
  2788.  
  2789. Monocle.Flippers.Legacy.STYLES = {
  2790.   iBox: {
  2791.     'position': 'absolute',
  2792.     'right': 0,
  2793.     'left': 0,
  2794.     'height': '10px'
  2795.   },
  2796.   arrow: {
  2797.     'position': 'absolute',
  2798.     'right': 0,
  2799.     'height': '10px',
  2800.     'width': '10px',
  2801.     'background': '#333',
  2802.     'border-radius': '6px'
  2803.   },
  2804.   line: {
  2805.     'width': '100%',
  2806.     'border-top': '2px dotted #333',
  2807.     'margin-top': '5px'
  2808.   }
  2809. }
  2810.  
  2811. Monocle.pieceLoaded('flippers/legacy');
  2812. Monocle.Dimensions.Columns = function (pageDiv) {
  2813.  
  2814.   var API = { constructor: Monocle.Dimensions.Columns }
  2815.   var k = API.constants = API.constructor;
  2816.   var p = API.properties = {
  2817.     page: pageDiv,
  2818.     reader: pageDiv.m.reader,
  2819.     dirty: true
  2820.   }
  2821.  
  2822.  
  2823.   function initialize() {
  2824.     p.reader.listen('monocle:componentchange', componentChanged);
  2825.   }
  2826.  
  2827.  
  2828.   function hasChanged() {
  2829.     if (p.dirty) { return true; }
  2830.     var newMeasurements = rawMeasurements();
  2831.     return (
  2832.       (!p.measurements) ||
  2833.       (p.measurements.width != newMeasurements.width) ||
  2834.       (p.measurements.height != newMeasurements.height) ||
  2835.       (p.measurements.scrollWidth != newMeasurements.scrollWidth)
  2836.     );
  2837.   }
  2838.  
  2839.  
  2840.   function measure() {
  2841.     setColumnWidth();
  2842.     p.measurements = rawMeasurements();
  2843.  
  2844.     if (
  2845.       Monocle.Browser.has.iframeDoubleWidthBug &&
  2846.       p.measurements.scrollWidth == p.measurements.width * 2
  2847.     ) {
  2848.       var doc = p.page.m.activeFrame.contentDocument;
  2849.       var lc;
  2850.       for (var i = doc.body.childNodes.length - 1; i >= 0; --i) {
  2851.         lc = doc.body.childNodes[i];
  2852.         if (lc.getBoundingClientRect) { break; }
  2853.       }
  2854.       if (!lc || !lc.getBoundingClientRect) {
  2855.         console.warn('Empty document for page['+p.page.m.pageIndex+']');
  2856.         p.measurements.scrollWidth = p.measurements.width;
  2857.       } else {
  2858.         var bcr = lc.getBoundingClientRect();
  2859.         if (
  2860.           bcr.right > p.measurements.width ||
  2861.           bcr.bottom > p.measurements.height
  2862.         ) {
  2863.           p.measurements.scrollWidth = p.measurements.width * 2;
  2864.         } else {
  2865.           p.measurements.scrollWidth = p.measurements.width;
  2866.         }
  2867.       }
  2868.     }
  2869.  
  2870.     p.length = Math.ceil(p.measurements.scrollWidth / p.measurements.width);
  2871.     p.dirty = false;
  2872.     return p.length;
  2873.   }
  2874.  
  2875.  
  2876.   function pages() {
  2877.     if (p.dirty) {
  2878.       console.warn('Accessing pages() when dimensions are dirty.')
  2879.       return 0;
  2880.     }
  2881.     return p.length;
  2882.   }
  2883.  
  2884.  
  2885.   function percentageThroughOfNode(target) {
  2886.     if (!target) {
  2887.       return 0;
  2888.     }
  2889.     var doc = p.page.m.activeFrame.contentDocument;
  2890.     var offset = 0;
  2891.     if (target.getBoundingClientRect) {
  2892.       offset = target.getBoundingClientRect().left;
  2893.       offset -= doc.body.getBoundingClientRect().left;
  2894.     } else {
  2895.       var scroller = scrollerElement();
  2896.       var oldScrollLeft = scroller.scrollLeft;
  2897.       target.scrollIntoView();
  2898.       offset = scroller.scrollLeft;
  2899.       scroller.scrollTop = 0;
  2900.       scroller.scrollLeft = oldScrollLeft;
  2901.     }
  2902.  
  2903.     var percent = offset / p.measurements.scrollWidth;
  2904.     return percent;
  2905.   }
  2906.  
  2907.  
  2908.   function componentChanged(evt) {
  2909.     if (evt.m['page'] != p.page) { return; }
  2910.     var doc = evt.m['document'];
  2911.     if (Monocle.Browser.has.columnOverflowPaintBug) {
  2912.       var div = doc.createElement('div');
  2913.       Monocle.Styles.applyRules(div, k.BODY_STYLES);
  2914.       div.style.cssText += "overflow: scroll !important;";
  2915.       while (doc.body.childNodes.length) {
  2916.         div.appendChild(doc.body.firstChild);
  2917.       }
  2918.       doc.body.appendChild(div);
  2919.     } else {
  2920.       Monocle.Styles.applyRules(doc.body, k.BODY_STYLES);
  2921.  
  2922.       if (Monocle.Browser.is.WebKit) {
  2923.         doc.documentElement.style.overflow = 'hidden';
  2924.       }
  2925.     }
  2926.  
  2927.     p.dirty = true;
  2928.   }
  2929.  
  2930.  
  2931.   function setColumnWidth() {
  2932.     var cw = p.page.m.sheafDiv.clientWidth;
  2933.     if (currBodyStyleValue('column-width') != cw+"px") {
  2934.       Monocle.Styles.affix(columnedElement(), 'column-width', cw+"px");
  2935.       p.dirty = true;
  2936.     }
  2937.   }
  2938.  
  2939.  
  2940.   function rawMeasurements() {
  2941.     var sheaf = p.page.m.sheafDiv;
  2942.     return {
  2943.       width: sheaf.clientWidth,
  2944.       height: sheaf.clientHeight,
  2945.       scrollWidth: scrollerWidth()
  2946.     }
  2947.   }
  2948.  
  2949.  
  2950.   function scrollerElement() {
  2951.     if (Monocle.Browser.has.mustScrollSheaf) {
  2952.       return p.page.m.sheafDiv;
  2953.     } else {
  2954.       return columnedElement();
  2955.     }
  2956.   }
  2957.  
  2958.  
  2959.   function columnedElement() {
  2960.     var elem = p.page.m.activeFrame.contentDocument.body;
  2961.     return Monocle.Browser.has.columnOverflowPaintBug ? elem.firstChild : elem;
  2962.   }
  2963.  
  2964.  
  2965.   function scrollerWidth() {
  2966.     var bdy = p.page.m.activeFrame.contentDocument.body;
  2967.     if (Monocle.Browser.has.iframeDoubleWidthBug) {
  2968.       if (Monocle.Browser.on.Kindle3) {
  2969.         return scrollerElement().scrollWidth;
  2970.       } else if (Monocle.Browser.on.Android) {
  2971.         return bdy.scrollWidth;
  2972.       } else if (Monocle.Browser.iOSVersion < "4.1") {
  2973.         var hbw = bdy.scrollWidth / 2;
  2974.         var sew = scrollerElement().scrollWidth;
  2975.         return Math.max(sew, hbw);
  2976.       } else {
  2977.         bdy.scrollWidth; // Throw one away. Nuts.
  2978.         var hbw = bdy.scrollWidth / 2;
  2979.         return hbw;
  2980.       }
  2981.     } else if (bdy.getBoundingClientRect) {
  2982.       var elems = bdy.getElementsByTagName('*');
  2983.       var bdyRect = bdy.getBoundingClientRect();
  2984.       var l = bdyRect.left, r = bdyRect.right;
  2985.       for (var i = elems.length - 1; i >= 0; --i) {
  2986.         var rect = elems[i].getBoundingClientRect();
  2987.         l = Math.min(l, rect.left);
  2988.         r = Math.max(r, rect.right);
  2989.       }
  2990.       return Math.abs(l) + Math.abs(r);
  2991.     }
  2992.  
  2993.     return scrollerElement().scrollWidth;
  2994.   }
  2995.  
  2996.  
  2997.   function currBodyStyleValue(property) {
  2998.     var win = p.page.m.activeFrame.contentWindow;
  2999.     var doc = win.document;
  3000.     if (!doc.body) { return null; }
  3001.     var currStyle = win.getComputedStyle(doc.body, null);
  3002.     return currStyle.getPropertyValue(property);
  3003.   }
  3004.  
  3005.  
  3006.   function locusToOffset(locus) {
  3007.     return 0 - (p.measurements.width * (locus.page - 1));
  3008.   }
  3009.  
  3010.  
  3011.   function translateToLocus(locus) {
  3012.     var offset = locusToOffset(locus);
  3013.     p.page.m.offset = 0 - offset;
  3014.     if (k.SETX && !Monocle.Browser.has.columnOverflowPaintBug) {
  3015.       var bdy = p.page.m.activeFrame.contentDocument.body;
  3016.       Monocle.Styles.affix(bdy, "transform", "translateX("+offset+"px)");
  3017.     } else {
  3018.       var scrElem = scrollerElement();
  3019.       scrElem.scrollLeft = 0 - offset;
  3020.     }
  3021.     return offset;
  3022.   }
  3023.  
  3024.  
  3025.   API.hasChanged = hasChanged;
  3026.   API.measure = measure;
  3027.   API.pages = pages;
  3028.   API.percentageThroughOfNode = percentageThroughOfNode;
  3029.  
  3030.   API.locusToOffset = locusToOffset;
  3031.   API.translateToLocus = translateToLocus;
  3032.  
  3033.   initialize();
  3034.  
  3035.   return API;
  3036. }
  3037.  
  3038.  
  3039. Monocle.Dimensions.Columns.BODY_STYLES = {
  3040.   "position": "absolute",
  3041.   "height": "100%",
  3042.   "-webkit-column-gap": "0",
  3043.   "-webkit-column-fill": "auto",
  3044.   "-moz-column-gap": "0",
  3045.   "-moz-column-fill": "auto",
  3046.   "column-gap": "0",
  3047.   "column-fill": "auto"
  3048. }
  3049.  
  3050. Monocle.Dimensions.Columns.SETX = true; // Set to false for scrollLeft.
  3051.  
  3052. if (Monocle.Browser.has.iframeDoubleWidthBug) {
  3053.   Monocle.Dimensions.Columns.BODY_STYLES["min-width"] = "200%";
  3054. } else {
  3055.   Monocle.Dimensions.Columns.BODY_STYLES["width"] = "100%";
  3056. }
  3057. Monocle.Flippers.Slider = function (reader) {
  3058.   if (Monocle.Flippers == this) {
  3059.     return new Monocle.Flippers.Slider(reader);
  3060.   }
  3061.  
  3062.   var API = { constructor: Monocle.Flippers.Slider }
  3063.   var k = API.constants = API.constructor;
  3064.   var p = API.properties = {
  3065.     pageCount: 2,
  3066.     activeIndex: 1,
  3067.     turnData: {}
  3068.   }
  3069.  
  3070.  
  3071.   function initialize() {
  3072.     p.reader = reader;
  3073.   }
  3074.  
  3075.  
  3076.   function addPage(pageDiv) {
  3077.     pageDiv.m.dimensions = new Monocle.Dimensions.Columns(pageDiv);
  3078.  
  3079.     Monocle.Styles.setX(pageDiv, "0px");
  3080.   }
  3081.  
  3082.  
  3083.   function visiblePages() {
  3084.     return [upperPage()];
  3085.   }
  3086.  
  3087.  
  3088.   function listenForInteraction(panelClass) {
  3089.     interactiveMode(true);
  3090.     interactiveMode(false);
  3091.  
  3092.     if (typeof panelClass != "function") {
  3093.       panelClass = k.DEFAULT_PANELS_CLASS;
  3094.       if (!panelClass) {
  3095.         console.warn("Invalid panel class.")
  3096.       }
  3097.     }
  3098.     var q = function (action, panel, x) {
  3099.       var dir = panel.properties.direction;
  3100.       if (action == "lift") {
  3101.         lift(dir, x);
  3102.       } else if (action == "release") {
  3103.         release(dir, x);
  3104.       }
  3105.     }
  3106.     p.panels = new panelClass(
  3107.       API,
  3108.       {
  3109.         'start': function (panel, x) { q('lift', panel, x); },
  3110.         'move': function (panel, x) { turning(panel.properties.direction, x); },
  3111.         'end': function (panel, x) { q('release', panel, x); },
  3112.         'cancel': function (panel, x) { q('release', panel, x); }
  3113.       }
  3114.     );
  3115.   }
  3116.  
  3117.  
  3118.   function interactiveMode(bState) {
  3119.     p.reader.dispatchEvent('monocle:interactive:'+(bState ? 'on' : 'off'));
  3120.     if (!Monocle.Browser.has.selectThruBug) {
  3121.       return;
  3122.     }
  3123.     if (p.interactive = bState) {
  3124.       if (p.activeIndex != 0) {
  3125.         var place = getPlace();
  3126.         if (place) {
  3127.           setPage(
  3128.             p.reader.dom.find('page', 0),
  3129.             place.getLocus(),
  3130.             function () {
  3131.               flipPages();
  3132.               prepareNextPage();
  3133.             }
  3134.           );
  3135.         } else {
  3136.           flipPages();
  3137.         }
  3138.       }
  3139.     }
  3140.   }
  3141.  
  3142.  
  3143.   function getPlace(pageDiv) {
  3144.     pageDiv = pageDiv || upperPage();
  3145.     return pageDiv.m ? pageDiv.m.place : null;
  3146.   }
  3147.  
  3148.  
  3149.   function moveTo(locus, callback) {
  3150.     var fn = function () {
  3151.       prepareNextPage(function () {
  3152.         if (typeof callback == "function") { callback(); }
  3153.         announceTurn();
  3154.       });
  3155.     }
  3156.     setPage(upperPage(), locus, fn);
  3157.   }
  3158.  
  3159.  
  3160.   function setPage(pageDiv, locus, callback) {
  3161.     ensureWaitControl();
  3162.     p.reader.getBook().setOrLoadPageAt(
  3163.       pageDiv,
  3164.       locus,
  3165.       function (locus) {
  3166.         pageDiv.m.dimensions.translateToLocus(locus);
  3167.         if (callback) { callback(); }
  3168.       }
  3169.     );
  3170.   }
  3171.  
  3172.  
  3173.   function upperPage() {
  3174.     return p.reader.dom.find('page', p.activeIndex);
  3175.   }
  3176.  
  3177.  
  3178.   function lowerPage() {
  3179.     return p.reader.dom.find('page', (p.activeIndex + 1) % 2);
  3180.   }
  3181.  
  3182.  
  3183.   function flipPages() {
  3184.     upperPage().style.zIndex = 1;
  3185.     lowerPage().style.zIndex = 2;
  3186.     return p.activeIndex = (p.activeIndex + 1) % 2;
  3187.   }
  3188.  
  3189.  
  3190.   function lift(dir, boxPointX) {
  3191.     if (p.turnData.lifting || p.turnData.releasing) { return; }
  3192.  
  3193.     p.turnData.points = {
  3194.       start: boxPointX,
  3195.       min: boxPointX,
  3196.       max: boxPointX
  3197.     }
  3198.     p.turnData.lifting = true;
  3199.  
  3200.     if (dir == k.FORWARDS) {
  3201.       if (getPlace().onLastPageOfBook()) {
  3202.         p.reader.dispatchEvent(
  3203.           'monocle:boundaryend',
  3204.           {
  3205.             locus: getPlace().getLocus({ direction : dir }),
  3206.             page: upperPage()
  3207.           }
  3208.         );
  3209.         resetTurnData();
  3210.         return;
  3211.       }
  3212.       onGoingForward(boxPointX);
  3213.     } else if (dir == k.BACKWARDS) {
  3214.       if (getPlace().onFirstPageOfBook()) {
  3215.         p.reader.dispatchEvent(
  3216.           'monocle:boundarystart',
  3217.           {
  3218.             locus: getPlace().getLocus({ direction : dir }),
  3219.             page: upperPage()
  3220.           }
  3221.         );
  3222.         resetTurnData();
  3223.         return;
  3224.       }
  3225.       onGoingBackward(boxPointX);
  3226.     } else {
  3227.       console.warn("Invalid direction: " + dir);
  3228.     }
  3229.   }
  3230.  
  3231.  
  3232.   function turning(dir, boxPointX) {
  3233.     if (!p.turnData.points) { return; }
  3234.     if (p.turnData.lifting || p.turnData.releasing) { return; }
  3235.     checkPoint(boxPointX);
  3236.     slideToCursor(boxPointX, null, "0");
  3237.   }
  3238.  
  3239.  
  3240.   function release(dir, boxPointX) {
  3241.     if (!p.turnData.points) {
  3242.       return;
  3243.     }
  3244.     if (p.turnData.lifting) {
  3245.       p.turnData.releaseArgs = [dir, boxPointX];
  3246.       return;
  3247.     }
  3248.     if (p.turnData.releasing) {
  3249.       return;
  3250.     }
  3251.  
  3252.     checkPoint(boxPointX);
  3253.  
  3254.     p.turnData.releasing = true;
  3255.     showWaitControl(lowerPage());
  3256.  
  3257.     if (dir == k.FORWARDS) {
  3258.       if (
  3259.         p.turnData.points.tap ||
  3260.         p.turnData.points.start - boxPointX > 60 ||
  3261.         p.turnData.points.min >= boxPointX
  3262.       ) {
  3263.         slideOut(afterGoingForward);
  3264.       } else {
  3265.         slideIn(afterCancellingForward);
  3266.       }
  3267.     } else if (dir == k.BACKWARDS) {
  3268.       if (
  3269.         p.turnData.points.tap ||
  3270.         boxPointX - p.turnData.points.start > 60 ||
  3271.         p.turnData.points.max <= boxPointX
  3272.       ) {
  3273.         slideIn(afterGoingBackward);
  3274.       } else {
  3275.         slideOut(afterCancellingBackward);
  3276.       }
  3277.     } else {
  3278.       console.warn("Invalid direction: " + dir);
  3279.     }
  3280.   }
  3281.  
  3282.  
  3283.   function checkPoint(boxPointX) {
  3284.     p.turnData.points.min = Math.min(p.turnData.points.min, boxPointX);
  3285.     p.turnData.points.max = Math.max(p.turnData.points.max, boxPointX);
  3286.     p.turnData.points.tap = p.turnData.points.max - p.turnData.points.min < 10;
  3287.   }
  3288.  
  3289.  
  3290.   function onGoingForward(x) {
  3291.     lifted(x);
  3292.   }
  3293.  
  3294.  
  3295.   function onGoingBackward(x) {
  3296.     var lp = lowerPage(), up = upperPage();
  3297.     showWaitControl(up);
  3298.     jumpOut(lp, // move lower page off-screen
  3299.       function () {
  3300.         flipPages(); // flip lower to upper
  3301.         setPage( // set upper page to previous
  3302.           lp,
  3303.           getPlace(lowerPage()).getLocus({ direction: k.BACKWARDS }),
  3304.           function () {
  3305.             lifted(x);
  3306.             hideWaitControl(up);
  3307.           }
  3308.         );
  3309.       }
  3310.     );
  3311.   }
  3312.  
  3313.  
  3314.   function afterGoingForward() {
  3315.     var up = upperPage(), lp = lowerPage();
  3316.     if (p.interactive) {
  3317.       showWaitControl(up);
  3318.       showWaitControl(lp);
  3319.       setPage( // set upper (off screen) to current
  3320.         up,
  3321.         getPlace().getLocus({ direction: k.FORWARDS }),
  3322.         function () {
  3323.           jumpIn(up, function () { prepareNextPage(announceTurn); });
  3324.         }
  3325.       );
  3326.     } else {
  3327.       showWaitControl(lp);
  3328.       flipPages();
  3329.       jumpIn(up, function () { prepareNextPage(announceTurn); });
  3330.     }
  3331.   }
  3332.  
  3333.  
  3334.   function afterGoingBackward() {
  3335.     if (p.interactive) {
  3336.       setPage( // set lower page to current
  3337.         lowerPage(),
  3338.         getPlace().getLocus(),
  3339.         function () {
  3340.           flipPages(); // flip lower to upper
  3341.           prepareNextPage(announceTurn);
  3342.         }
  3343.       );
  3344.     } else {
  3345.       announceTurn();
  3346.     }
  3347.   }
  3348.  
  3349.  
  3350.   function afterCancellingForward() {
  3351.     resetTurnData();
  3352.   }
  3353.  
  3354.  
  3355.   function afterCancellingBackward() {
  3356.     flipPages(); // flip upper to lower
  3357.     jumpIn( // move lower back onto screen
  3358.       lowerPage(),
  3359.       function () { prepareNextPage(resetTurnData); }
  3360.     );
  3361.   }
  3362.  
  3363.  
  3364.   function prepareNextPage(callback) {
  3365.     setPage(
  3366.       lowerPage(),
  3367.       getPlace().getLocus({ direction: k.FORWARDS }),
  3368.       callback
  3369.     );
  3370.   }
  3371.  
  3372.  
  3373.   function lifted(x) {
  3374.     p.turnData.lifting = false;
  3375.     var releaseArgs = p.turnData.releaseArgs;
  3376.     if (releaseArgs) {
  3377.       p.turnData.releaseArgs = null;
  3378.       release(releaseArgs[0], releaseArgs[1]);
  3379.     } else if (x) {
  3380.       slideToCursor(x);
  3381.     }
  3382.   }
  3383.  
  3384.  
  3385.   function announceTurn() {
  3386.     p.reader.dispatchEvent('monocle:turn');
  3387.     resetTurnData();
  3388.   }
  3389.  
  3390.  
  3391.   function resetTurnData() {
  3392.     hideWaitControl(upperPage());
  3393.     hideWaitControl(lowerPage());
  3394.     p.turnData = {};
  3395.   }
  3396.  
  3397.  
  3398.   function setX(elem, x, options, callback) {
  3399.     var duration;
  3400.  
  3401.     if (!options.duration) {
  3402.       duration = 0;
  3403.     } else {
  3404.       duration = parseInt(options['duration']);
  3405.     }
  3406.  
  3407.     if (typeof(x) == "number") { x = x + "px"; }
  3408.  
  3409.     if (typeof WebKitTransitionEvent != "undefined") {
  3410.       if (duration) {
  3411.         transition = '-webkit-transform';
  3412.         transition += ' ' + duration + "ms";
  3413.         transition += ' ' + (options['timing'] || 'linear');
  3414.         transition += ' ' + (options['delay'] || 0) + 'ms';
  3415.       } else {
  3416.         transition = 'none';
  3417.       }
  3418.       elem.style.webkitTransition = transition;
  3419.       if (Monocle.Browser.has.transform3d) {
  3420.         elem.style.webkitTransform = "translate3d("+x+",0,0)";
  3421.       } else {
  3422.         elem.style.webkitTransform = "translateX("+x+")";
  3423.       }
  3424.  
  3425.     } else if (duration > 0) {
  3426.       clearTimeout(elem.setXTransitionInterval)
  3427.  
  3428.       var stamp = (new Date()).getTime();
  3429.       var frameRate = 40;
  3430.       var finalX = parseInt(x);
  3431.       var currX = getX(elem);
  3432.       var step = (finalX - currX) * (frameRate / duration);
  3433.       var stepFn = function () {
  3434.         var destX = currX + step;
  3435.         if (
  3436.           (new Date()).getTime() - stamp > duration ||
  3437.           Math.abs(currX - finalX) <= Math.abs((currX + step) - finalX)
  3438.         ) {
  3439.           clearTimeout(elem.setXTransitionInterval);
  3440.           Monocle.Styles.setX(elem, finalX);
  3441.           if (elem.setXTCB) {
  3442.             elem.setXTCB();
  3443.           }
  3444.         } else {
  3445.           Monocle.Styles.setX(elem, destX);
  3446.           currX = destX;
  3447.         }
  3448.       }
  3449.  
  3450.       elem.setXTransitionInterval = setInterval(stepFn, frameRate);
  3451.     } else {
  3452.       Monocle.Styles.setX(elem, x);
  3453.     }
  3454.  
  3455.     if (elem.setXTCB) {
  3456.       Monocle.Events.deafen(elem, 'webkitTransitionEnd', elem.setXTCB);
  3457.       elem.setXTCB = null;
  3458.     }
  3459.  
  3460.     elem.setXTCB = function () {
  3461.       if (callback) { callback(); }
  3462.     }
  3463.  
  3464.     var sX = getX(elem);
  3465.     if (!duration || sX == parseInt(x)) {
  3466.       elem.setXTCB();
  3467.     } else {
  3468.       Monocle.Events.listen(elem, 'webkitTransitionEnd', elem.setXTCB);
  3469.     }
  3470.   }
  3471.  
  3472.  
  3473.   /*
  3474.   function setX(elem, x, options, callback) {
  3475.     var duration, transition;
  3476.  
  3477.     if (!Monocle.Browser.has.transitions) {
  3478.       duration = 0;
  3479.     } else if (!options.duration) {
  3480.       duration = 0;
  3481.     } else {
  3482.       duration = parseInt(options['duration']);
  3483.     }
  3484.  
  3485.     if (typeof(x) == "number") { x = x + "px"; }
  3486.  
  3487.     if (duration) {
  3488.       transition = duration + "ms";
  3489.       transition += ' ' + (options['timing'] || 'linear');
  3490.       transition += ' ' + (options['delay'] || 0) + 'ms';
  3491.     } else {
  3492.       transition = "none";
  3493.     }
  3494.  
  3495.     if (elem.setXTCB) {
  3496.       Monocle.Events.deafen(elem, 'webkitTransitionEnd', elem.setXTCB);
  3497.       Monocle.Events.deafen(elem, 'transitionend', elem.setXTCB);
  3498.       elem.setXTCB = null;
  3499.     }
  3500.  
  3501.     elem.setXTCB = function () {
  3502.       if (callback) { callback(); }
  3503.     }
  3504.  
  3505.     elem.dom.setBetaStyle('transition', transition);
  3506.     if (Monocle.Browser.has.transform3d) {
  3507.       elem.dom.setBetaStyle('transform', 'translate3d('+x+',0,0)');
  3508.     } else {
  3509.       elem.dom.setBetaStyle('transform', 'translateX('+x+')');
  3510.     }
  3511.  
  3512.     if (!duration) {
  3513.       elem.setXTCB();
  3514.     } else {
  3515.       Monocle.Events.listen(elem, 'webkitTransitionEnd', elem.setXTCB);
  3516.       Monocle.Events.listen(elem, 'transitionend', elem.setXTCB);
  3517.     }
  3518.   }
  3519.   */
  3520.  
  3521.  
  3522.   function getX(elem) {
  3523.     if (typeof WebKitCSSMatrix == "object") {
  3524.       var matrix = window.getComputedStyle(elem).webkitTransform;
  3525.       matrix = new WebKitCSSMatrix(matrix);
  3526.       return matrix.m41;
  3527.     } else {
  3528.       var prop = elem.style.MozTransform;
  3529.       if (!prop || prop == "") { return 0; }
  3530.       return parseFloat((/translateX\((\-?.*)px\)/).exec(prop)[1]) || 0;
  3531.     }
  3532.   }
  3533.  
  3534.  
  3535.   function jumpIn(pageDiv, callback) {
  3536.     var dur = Monocle.Browser.has.jumpFlickerBug ? 1 : 0;
  3537.     Monocle.defer(function () {
  3538.       setX(pageDiv, 0, { duration: dur }, callback);
  3539.     });
  3540.   }
  3541.  
  3542.  
  3543.   function jumpOut(pageDiv, callback) {
  3544.     var dur = Monocle.Browser.has.jumpFlickerBug ? 1 : 0;
  3545.     Monocle.defer(function () {
  3546.       setX(pageDiv, 0 - pageDiv.offsetWidth, { duration: dur }, callback);
  3547.     });
  3548.   }
  3549.  
  3550.  
  3551.  
  3552.   function slideIn(callback) {
  3553.     var slideOpts = {
  3554.       duration: k.durations.SLIDE,
  3555.       timing: 'ease-in'
  3556.     };
  3557.     Monocle.defer(function () {
  3558.       setX(upperPage(), 0, slideOpts, callback);
  3559.     });
  3560.   }
  3561.  
  3562.  
  3563.   function slideOut(callback) {
  3564.     var slideOpts = {
  3565.       duration: k.durations.SLIDE,
  3566.       timing: 'ease-in'
  3567.     };
  3568.     Monocle.defer(function () {
  3569.       setX(upperPage(), 0 - upperPage().offsetWidth, slideOpts, callback);
  3570.     });
  3571.   }
  3572.  
  3573.  
  3574.   function slideToCursor(cursorX, callback, duration) {
  3575.     setX(
  3576.       upperPage(),
  3577.       Math.min(0, cursorX - upperPage().offsetWidth),
  3578.       { duration: duration || k.durations.FOLLOW_CURSOR },
  3579.       callback
  3580.     );
  3581.   }
  3582.  
  3583.  
  3584.   function ensureWaitControl() {
  3585.     if (p.waitControl) { return; }
  3586.     p.waitControl = {
  3587.       createControlElements: function (holder) {
  3588.         return holder.dom.make('div', 'flippers_slider_wait');
  3589.       }
  3590.     }
  3591.     p.reader.addControl(p.waitControl, 'page');
  3592.   }
  3593.  
  3594.  
  3595.   function showWaitControl(page) {
  3596.     var ctrl = p.reader.dom.find('flippers_slider_wait', page.m.pageIndex);
  3597.     ctrl.style.visibility = "visible";
  3598.   }
  3599.  
  3600.  
  3601.   function hideWaitControl(page) {
  3602.     var ctrl = p.reader.dom.find('flippers_slider_wait', page.m.pageIndex);
  3603.     ctrl.style.visibility = "hidden";
  3604.   }
  3605.  
  3606.   API.pageCount = p.pageCount;
  3607.   API.addPage = addPage;
  3608.   API.getPlace = getPlace;
  3609.   API.moveTo = moveTo;
  3610.   API.listenForInteraction = listenForInteraction;
  3611.  
  3612.   API.visiblePages = visiblePages;
  3613.   API.interactiveMode = interactiveMode;
  3614.  
  3615.   initialize();
  3616.  
  3617.   return API;
  3618. }
  3619.  
  3620.  
  3621. Monocle.Flippers.Slider.DEFAULT_PANELS_CLASS = Monocle.Panels.TwoPane;
  3622. Monocle.Flippers.Slider.FORWARDS = 1;
  3623. Monocle.Flippers.Slider.BACKWARDS = -1;
  3624. Monocle.Flippers.Slider.durations = {
  3625.   SLIDE: 220,
  3626.   FOLLOW_CURSOR: 100
  3627. }
  3628.  
  3629. Monocle.pieceLoaded('flippers/slider');
  3630.  
  3631. Monocle.pieceLoaded('monocle');
  3632.