PageSourceSearch

https://www.cityofmoore.com/themes/addons/dflip/js/dflip.js?tlu9pl

js cityofmoore.com collected 2026-09-24 21:51:05 UTC 280,082 bytes, 8,241 lines download raw bytes

1/**
2 * @preserve
3 * Plugin Name: dflip
4 * Description: dflip - 3D & 2D FlipBook
5 *
6 * Author: Deepak Ghimire
7 * Author URI: http://codecanyon.net/user/deip?ref=deip
8 */
9
10'use strict';
11
12var DFLIP = DFLIP || {};
13
14// old fallback
15// use DFLIP instead of PRESENTATION as of v 1.1
16var PRESENTATION = DFLIP;
17
18(function dFlip(DFLIP, $) {
19
20  DFLIP.version = "1.5";
21
22  DFLIP.PAGE_MODE = {SINGLE: 1, DOUBLE: 2, AUTO: null};
23  DFLIP.SINGLE_PAGE_MODE = {ZOOM: 1, BOOKLET: 2, AUTO: null};
24  DFLIP.CONTROLSPOSITION = {HIDDEN: 'hide', TOP: 'top', BOTTOM: 'bottom'};
25  DFLIP.DIRECTION = {LTR: 1, RTL: 2};
26
27  DFLIP.CORNERS = {TL: "tl", TR: "tr", BL: "bl", BR: "br", L: "l", R: "r", NONE: null};
28
29  DFLIP.SOURCE_TYPE = {IMAGE: "image", PDF: "pdf", HTML: "html"};
30  DFLIP.DISPLAY_TYPE = {WEBGL: "3D", HTML: "2D"};
31  DFLIP.PAGE_SIZE = {AUTO: 0, SINGLE: 1, DOUBLEINTERNAL: 2};
32
33
34  //defaults settings
35  var defaults = DFLIP.defaults = {
36
37    //sets if to use 3d or not (true|false)
38    webgl: false,
39    //if you want to turn of shadow in 3d set it to false
40    webglShadow: false,
41
42    // if enable sound at start (true|false)
43    soundEnable: false,
44
45    // height of the container
46    // value(eg: 320) or percentage (eg: '50%')
47    // calculaton limit: minimum 320, max window height
48    height: '90%',
49
50    // set to true to show outline on open (true|false)
51    autoEnableOutline: false,
52
53    // set to true to show thumbnail on open (true|false)
54    autoEnableThumbnail: false,
55
56    // set to true if PDF inbuilt outline is to be removed (true|false)
57    overwritePDFOutline: false,
58
59    // enableDownload of PDF files (true|false)
60    enableDownload: true,
61
62    // duration of page turn in milliseconds
63    duration: 400,
64
65    //direction of flipbook
66    //DFLIP.DIRECTION.LTR or 1	for left to right(default),
67    //DFLIP.DIRECTION.RTL or 2	for right to left,
68    direction: DFLIP.DIRECTION.LTR,
69
70    //set as
71    //DFLIP.PAGE_MODE.AUTO	 				for auto-detect(default),
72    //DFLIP.PAGE_MODE.SINGLE or 1 			for singleview,
73    //DFLIP.PAGE_MODE.DOUBLE or 2 			for doubleview,
74    pageMode: DFLIP.PAGE_MODE.AUTO,
75
76    //set as
77    //DFLIP.SINGLE_PAGE_MODE.AUTO	 				for auto-detect(default),
78    //DFLIP.SINGLE_PAGE_MODE.ZOOM or 1 				for normal zoom single view,
79    //DFLIP.SINGLE_PAGE_MODE.BOOKLET or 2 			for Booklet mode,
80    singlePageMode: DFLIP.SINGLE_PAGE_MODE.AUTO,
81
82    //color value in hexadecimal
83    backgroundColor: "#ffffff",
84
85    forceFit: true, //very rare usage leave it as true unless page are not fitting wrong...
86    transparent: false, //true or false
87    hard: "none", //possible values are "hard", "none", "cover"
88    openPage: 1, //the pagenumber where the book should open
89
90    annotationClass: "",
91
92    autoPlay: false,
93    autoPlayDuration: 5000,
94    autoPlayStart: false,
95
96    // texture settings
97    maxTextureSize: 1600,	//max page size to be rendered. for pdf files only
98    minTextureSize: 256,	//min page size to be rendered. for pdf files only
99    rangeChunkSize: 524288,
100
101    // icons for the buttons
102    icons: {
103      'altnext': 'ti-angle-right',
104      'altprev': 'ti-angle-left',
105      'next': 'ti-angle-right',
106      'prev': 'ti-angle-left',
107      'end': 'ti-angle-double-right',
108      'start': 'ti-angle-double-left',
109      'share': 'ti-sharethis',
110      'help': 'ti-help-alt',
111      'more': 'ti-more-alt',
112      'download': 'ti-download',
113      'zoomin': 'ti-zoom-in',
114      'zoomout': 'ti-zoom-out',
115      'fullscreen': 'ti-fullscreen',
116      'fitscreen': 'ti-arrows-corner',
117      'thumbnail': 'ti-layout-grid2',
118      'outline': 'ti-menu-alt',
119      'close': 'ti-close',
120      'doublepage': 'ti-book',
121      'singlepage': 'ti-file',
122      'sound': 'ti-volume',
123      'facebook': 'ti-facebook',
124      'google': 'ti-google',
125      'twitter': 'ti-twitter-alt',
126      'mail': 'ti-email',
127      'play': 'ti-control-play',
128      'pause': 'ti-control-pause'
129    },
130
131    // TRANSLATION text to be displayed
132    text: {
133
134      toggleSound: "Turn on/off Sound",
135      toggleThumbnails: "Toggle Thumbnails",
136      toggleOutline: "Toggle Outline/Bookmark",
137      previousPage: "Previous Page",
138      nextPage: "Next Page",
139      toggleFullscreen: "Toggle Fullscreen",
140      zoomIn: "Zoom In",
141      zoomOut: "Zoom Out",
142      toggleHelp: "Toggle Help",
143
144      singlePageMode: "Single Page Mode",
145      doublePageMode: "Double Page Mode",
146      downloadPDFFile: "Download PDF File",
147      gotoFirstPage: "Goto First Page",
148      gotoLastPage: "Goto Last Page",
149      play: "Start AutoPlay",
150      pause: "Pause AutoPlay",
151
152      share: "Share"
153    },
154
155    //valid controlnames:
156    //altPrev,pageNumber,altNext,outline,thumbnail,zoomIn,zoomOut,fullScreen,share
157    //more,download,pageMode,startPage,endPage,sound
158    allControls: "altPrev,pageNumber,altNext,play,outline,thumbnail,zoomIn,zoomOut,fullScreen,share,download,more,pageMode,startPage,endPage,sound",
159    moreControls: "download,pageMode,startPage,endPage,sound",
160    hideControls: "outline,share",
161
162    controlsPosition: DFLIP.CONTROLSPOSITION.BOTTOM,
163    paddingTop: 30,
164    paddingLeft: 20,
165    paddingRight: 20,
166    paddingBottom: 30,
167
168    //set if the zoom changes on mouse scroll (true|false)
169    scrollWheel: true,
170
171    // callbacks
172    onCreate: function (flipBook) {
173      // after flip book is created is fired
174    },
175    onCreateUI: function (flipBook) {
176      // after ui created event is fired
177    },
178    onFlip: function (flipBook) {
179      // after flip event is fired
180    },
181    beforeFlip: function (flipBook) {
182      // before flip event is fired
183    },
184    onReady: function (flipBook) {
185      // after flip book is completely loaded
186    },
187
188    zoomRatio: 1.5,
189    pageSize: DFLIP.PAGE_SIZE.AUTO,
190
191    /**
192     * NON-OPTIONS AREA
193     * These options are not supposed to be sent from options variable
194     */
195    /**
196     * dependency URLS (NON-OPTION):
197     * Do not set them as options,
198     * Refer to advance-examples
199     */
200    //(NON-OPTION) source link for PDF.JS file
201    pdfjsSrc: "//www.cityofmoore.com/themes/addons/dflip/js/libs/pdf.min.js",
202    //(NON-OPTION) source link for PDFcompatibility.JS file
203    pdfjsCompatibilitySrc: "//www.cityofmoore.com/themes/addons/dflip/js/libs/compatibility.js",
204    //(NON-OPTION) source link for PDF.WORKER.JS file
205    pdfjsWorkerSrc: "//www.cityofmoore.com/themes/addons/dflip/js/libs/pdf.worker.min.js",
206    //(NON-OPTION) source link for THREE.JS file
207    threejsSrc: "//www.cityofmoore.com/themes/addons/dflip/js/libs/three.min.js",
208    //(NON-OPTION) source link for MOCKUP.JS file
209    mockupjsSrc: "//www.cityofmoore.com/themes/addons/dflip/js/libs/mockup.min.js",
210    //(NON-OPTION) File path to the trun sound
211    soundFile: "//www.cityofmoore.com/themes/addons/dflip/sound/turn2.mp3",
212    imagesLocation: "images",
213    imageResourcesPath: "images/pdfjs/",
214    cMapUrl: "cmaps/", //it's quite wierd how cmaps don't work properly with relative urls like others.. but is relative to pdf.min.js path
215
216    //(NON-OPTION) developer parameters
217    enableDebugLog: false,
218    canvasToBlob: false,//as of 1.2.9 canvas are better optimized and secure
219    enableAnnotation: true,
220    pdfRenderQuality: 0.75,
221
222
223    /**
224     * Let them be, change at your risk
225     */
226    // if texture fallback override is required
227    // note: if set to anything other than "blank" the first page is changed
228    // recommended : "blank"
229    textureLoadFallback: "blank", //"images/textures/white.jpg",
230    // controls the flexibility of the paper more value for more flexiblilty
231    stiffness: 3,
232    // minTopOffset: 30,
233    // link to the images file that you want as background.
234    // supported files are jpgs,png. smaller files are preffered for performance
235    backgroundImage: "",//"images/textures/el.jpg",
236    // or any number like 5, 500. recommended: "auto"
237
238    pageRatio: null, 		//equals to width/height
239
240    pixelRatio: window.devicePixelRatio || 1,
241    thumbElement: 'div',
242
243    /*3D settings*/
244    spotLightIntensity: 0,
245    ambientLightColor: "#fff",
246    ambientLightIntensity: 0,
247    shadowOpacity: 0
248  };
249
250  var has3d = 'WebKitCSSMatrix' in window
251      || (document.body && 'MozPerspective' in document.body.style),
252    hasMouse = 'onmousedown' in window,
253    hasTouch = 'ontouchstart' in window;
254
255  var userAgent = navigator.userAgent;
256
257  var utils = DFLIP.utils = {
258
259    drag: {
260      left: 0,
261      right: 1,
262      none: -1
263    },
264    mouseEvents: (hasMouse)
265      ? {type: "mouse", start: "mousedown", move: "mousemove", end: "mouseup"}
266      : {type: "touch", start: "touchstart", move: "touchmove", end: "touchend"},
267
268    html: {
269      div: "<div/>",
270      img: "<img/>",
271      a: "<a>",
272      input: "<input type='text'/>"
273    },
274    //functions or so
275    toRad: function (deg) {
276      return deg * Math.PI / 180;
277    },
278    isset: function (check, fallback) {
279      return check == null ? fallback : check;
280    },
281    isnull: function (variable) {
282      return variable == null || variable == null;
283    },
284    toDeg: function (rad) {
285      return rad * 180 / Math.PI;
286    },
287
288    transition: function (hasTransition, duration) {
289      return hasTransition ? duration / 1000 + "s ease-out" : "0s none";
290    },
291
292    display: function (hasDisplay) {
293      return hasDisplay ? "block" : "none";
294    },
295
296    resetTranslate: function () {
297      return translateStr(0, 0);
298    },
299
300    translateStr: function (x, y) {
301      return has3d ? ' translate3d(' + x + 'px,' + y + 'px, 0px) ' : ' translate(' + x + 'px, ' + y + 'px) ';
302    },
303    httpsCorrection: function (url) {
304      var location = window.location;
305      if (location.href.indexOf("https://") > -1 && url.indexOf(location.hostname) > -1) {
306        url = url.replace("http://", "https://");
307      }
308      return url;
309    },
310    resetBoxShadow: function () {
311      return "rgba(0, 0, 0, 0) 0px 0px 20px";
312    },
313
314    rotateStr: function (deg) {
315      return ' rotateZ(' + deg + 'deg) ';
316    },
317
318    bg: function (src) {
319      return '#fff' + bgImage(src);
320    },
321
322    bgImage: function (src) {
323      return (src == null || src == "blank" ? '' : ' url(' + src + ')');
324    },
325
326    src: function (src) {
327      return (src != null ? '' + src + '' : '');
328    },
329
330    limitAt: function (x, min, max) {
331      return x < min ? min : x > max ? max : x;
332    },
333
334    distOrigin: function (x, y) {
335      return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
336    },
337
338    distPoints: function (x1, y1, x2, y2) {
339      return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
340    },
341    calculateScale: function (startTouches, endTouches) {
342      var startDistance = distPoints(startTouches[0].x, startTouches[0].y, startTouches[1].x, startTouches[1].y),
343        endDistance = distPoints(endTouches[0].x, endTouches[0].y, endTouches[1].x, endTouches[1].y);
344      return endDistance / startDistance;
345    },
346    /**
347     * Calculates the average of multiple vectors (x, y values)
348     */
349    getVectorAvg: function (vectors) {
350      return {
351        x: vectors.map(function (v) {
352          return v.x;
353        }).reduce(utils.sum) / vectors.length,
354        y: vectors.map(function (v) {
355          return v.y;
356        }).reduce(utils.sum) / vectors.length
357      };
358    },
359    sum: function (a, b) {
360      return a + b;
361    },
362    /**
363     * Returns the touches of an event relative to the container offset
364     * @param event
365     * @return array touches
366     */
367    getTouches: function (event, position) {
368      position = position || {left: 0, top: 0};
369      return Array.prototype.slice.call(event.touches).map(function (touch) {
370        return {
371          x: touch.pageX - position.left,
372          y: touch.pageY - position.top
373        };
374      });
375    },
376
377    angleByDistance: function (distance, fullWidth) {
378      var h = fullWidth / 2;
379      var d = limitAt(distance, 0, fullWidth);
380
381      return d < h
382        ? toDeg(Math.asin(d / h))
383        : 90 + toDeg(Math.asin((d - h) / h));
384
385    },
386
387    log: function (args) {
388      if (defaults.enableDebugLog == true && window.console)
389        console.log(args);
390    },
391    lowerPowerOfTwo: function (value) {
392      return Math.pow(2, Math.floor(Math.log(value) / Math.LN2));
393    },
394    nearestPowerOfTwo: function (value, max) {
395      return Math.min(max || 2048, Math.pow(2, Math.ceil(Math.log(value) / Math.LN2)));
396    },
397    zoomStops: function (value, zoomRatio, ceil, min, max) {
398      if (min == null) min = 256;
399      if (max == null) max = 2048;
400      //Math.pow(2, Math.ceil(Math.log(value) / Math.LN2));
401
402      var factor = Math.log(value / min) / Math.log(zoomRatio);
403
404      return min * Math.pow(zoomRatio, ceil == null ? Math.round(factor) : (ceil == true ? Math.ceil(factor)
405          : Math.floor(factor)));
406    },
407
408    extendOptions: function (defaults, options) {
409      return $.extend(true, {}, defaults, options);
410    },
411    getFullscreenElement: function () {
412      return document.fullscreenElement
413        || document.mozFullScreenElement
414        || document.webkitFullscreenElement
415        || document.msFullscreenElement
416    },
417    hasFullscreenEnabled: function () {
418      return document.fullscreenEnabled
419        || document.mozFullScreenEnabled
420        || document.webkitFullscreenEnabled
421        || document.msFullscreenEnabled
422    },
423    getBasePage: function (pageNumber) {
424      return Math.floor(pageNumber / 2) * 2;
425    },
426
427    loadResources: function loadResources(resourceTag, src, callback) {
428      var doc = document,
429        element = doc.createElement(resourceTag),
430        refElement = doc.getElementsByTagName(resourceTag)[0];
431
432      element.async = true;
433      if (callback) {
434        element.addEventListener('load', function (e) {
435          callback(null, e);
436        }, false);
437      }
438
439      element.src = src;
440
441      refElement.parentNode.insertBefore(element, refElement);
442    },
443    getScript: function (source, callback, errorCallback) {
444      var script = document.createElement('script');
445      var prior = document.body.getElementsByTagName('script')[0];
446      script.async = 1;
447      script.setAttribute("data-cfasync", false);
448      if (prior != null) {
449        prior.parentNode.insertBefore(script, prior);
450        prior = null;
451      }
452      else { //sometimes if script are loaded in head and no scripts are present in body
453        document.body.appendChild(script);
454      }
455
456      function load(_, isAbort) {
457        if (script != null) { //IE 10 doesn't regard
458          if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
459            //console.log("aborted loading :" + source);
460            script.onload = script.onreadystatechange = null;
461            script = null;
462            script = null;
463            if (!isAbort) {
464              if (callback) callback();
465              callback = null;
466              errorCallback = null;
467            }
468
469          }
470        }
471      }
472
473      script.addEventListener("load", load, false);
474      script.addEventListener("readystatechange", load, false);
475      script.addEventListener("complete", load, false);
476
477      if (errorCallback) {
478        script.addEventListener("error", errorCallback, false);
479      }
480      //script.onload = script.onreadystatechange = load;
481
482      script.src = source + (prefix.dom == "MS" ? ("?" + Math.random(1)) : "");
483    },
484    isHardPage: function (config, pageNumber, pageCount, isBooklet) {
485      if (config != null) {
486
487        // var config = this.hardConfig;
488
489        if (config == "cover") {
490          return pageNumber == 0 || (isBooklet && pageNumber == 1)  //front cover is 0
491            || pageNumber == (Math.floor(pageCount / (isBooklet ? 1 : 2)) - (isBooklet ? 0 : 1)); //start with 0 so 1 minus
492        }
493        else if (config == "all") {
494          return true;
495        }
496        else {
497          var baseTest = ("," + config + ",").indexOf("," + (pageNumber * 2 + 1) + ",") > -1;
498          var nextTest = ("," + config + ",").indexOf("," + (pageNumber * 2 + 2) + ",") > -1;
499          return baseTest || nextTest;
500
501        }
502      }
503      return false;
504    },
505    fixMouseEvent: function (event) {
506
507
508      if (event) {
509        var originalEvent = event.originalEvent || event;
510
511        //noinspection JSUnresolvedVariable
512        if (originalEvent.changedTouches && originalEvent.changedTouches.length > 0) {
513          var _event = $.event.fix(event);
514          //noinspection JSUnresolvedVariable
515          var touch = originalEvent.changedTouches[0];
516          _event.clientX = touch.clientX;
517          _event.clientY = touch.clientY;
518          _event.pageX = touch.pageX;
519          _event.touches = originalEvent.touches;
520          _event.pageY = touch.pageY;
521          _event.movementX = touch.movementX;
522          _event.movementY = touch.movementY;
523          return _event;
524        }
525        else {
526          return event;
527        }
528      }
529      else {
530        return event;
531      }
532
533    },
534
535    //self Execution
536    hasWebgl: (function () {
537      try {
538        var canvas = document.createElement('canvas');
539        //noinspection JSUnresolvedVariable
540        return !!( window.WebGLRenderingContext && ( canvas.getContext('webgl') || canvas.getContext('experimental-webgl') ) );
541      } catch (e) {
542        return false;
543      }
544    })(),
545    isBookletMode: function (book) {
546      return book.pageMode == DFLIP.PAGE_MODE.SINGLE && book.singlePageMode == DFLIP.SINGLE_PAGE_MODE.BOOKLET
547    },
548    isRTLMode: function (book) {
549      return book.direction == DFLIP.DIRECTION.RTL
550    },
551    isMobile: (function () {
552      var check = false;
553      (function (a) {
554        if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true
555      })(userAgent || navigator.vendor || window.opera);
556      return check;
557    })(),
558    isIOS: /(iPad|iPhone|iPod)/g.test(userAgent),
559    isSafari: /constructor/i.test(window.HTMLElement) || (function (p) {
560      return p.toString() === "[object SafariRemoteNotification]";
561    })(!window['safari'] || safari.pushNotification),
562    prefix: (function () {
563      var styles = window.getComputedStyle(document.documentElement, ''),
564        pre = (Array.prototype.slice
565          .call(styles)
566          .join('')
567          .match(/-(moz|webkit|ms)-/))[1],
568        dom = ('WebKit|Moz|MS').match(new RegExp('(' + pre + ')', 'i'))[1];
569      return {
570        dom: dom,
571        lowercase: pre,
572        css: '-' + pre + '-',
573        js: pre[0].toUpperCase() + pre.substr(1)
574      };
575    })(),
576
577    __extends: function (child, parent) {
578      for (var key in parent)
579        if (parent.hasOwnProperty(key)) child[key] = parent[key];
580      function Ctor() {
581        this.constructor = child;
582      }
583
584      Ctor.prototype = parent.prototype;
585      child.prototype = new Ctor();
586      child.__super = parent.prototype;
587      return child;
588    }
589
590  };
591
592  //caching the utils
593
594  var SOURCE_TYPE = DFLIP.SOURCE_TYPE,
595    DISPLAY_TYPE = DFLIP.DISPLAY_TYPE,
596
597    drag = utils.drag,
598    mouseEvents = utils.mouseEvents,
599    html = utils.html,
600    isset = utils.isset,
601    isnull = utils.isnull,
602
603    toRad = utils.toRad,
604    toDeg = utils.toDeg,
605    transition = utils.transition,
606    translateStr = utils.translateStr,
607    resetBoxShadow = utils.resetBoxShadow,
608    rotateStr = utils.rotateStr,
609
610    bg = utils.bg,
611    bgImage = utils.bgImage,
612    src = utils.src,
613
614    limitAt = utils.limitAt,
615    distOrigin = utils.distOrigin,
616    distPoints = utils.distPoints,
617    angleByDistance = utils.angleByDistance,
618    log = utils.log,
619    nearestPowerOfTwo = utils.nearestPowerOfTwo,
620    extendOptions = utils.extendOptions,
621    getBasePage = utils.getBasePage,
622    getScript = utils.getScript,
623    fixMouseEvent = utils.fixMouseEvent,
624    prefix = utils.prefix,
625    isBookletMode = utils.isBookletMode,
626    isRTLMode = utils.isRTLMode,
627    isMobile = utils.isMobile,
628    hasWebgl = utils.hasWebgl,
629    isSafari = utils.isSafari,
630    isIOS = utils.isIOS,
631    __extends = utils.__extends;
632
633  // Support: IE<11, Chrome<21, Android<4.4, Safari<6
634  (function checkSetPresenceInImageData() {
635    // IE < 11 will use window.CanvasPixelArray which lacks set function.
636    if (window.CanvasPixelArray) {
637      if (typeof window.CanvasPixelArray.prototype.set !== 'function') {
638        window.CanvasPixelArray.prototype.set = function (arr) {
639          for (var i = 0, ii = this.length; i < ii; i++) {
640            this[i] = arr[i];
641          }
642        };
643      }
644    } else {
645      // Old Chrome and Android use an inaccessible CanvasPixelArray prototype.
646      // Because we cannot feature detect it, we rely on user agent parsing.
647      var polyfill = false, versionMatch;
648      if (isSafari) {
649        versionMatch = userAgent.match(/Version\/([0-9]+)\.([0-9]+)\.([0-9]+) Safari\//);
650        // Safari < 6 lacks the set function.
651        polyfill = versionMatch && parseInt(versionMatch[1]) < 6;
652      }
653
654      if (polyfill) {
655        var contextPrototype = window.CanvasRenderingContext2D.prototype;
656        var createImageData = contextPrototype.createImageData;
657        contextPrototype.createImageData = function (w, h) {
658          var imageData = createImageData.call(this, w, h);
659          imageData.data.set = function (arr) {
660            for (var i = 0, ii = this.length; i < ii; i++) {
661              this[i] = arr[i];
662            }
663          };
664          return imageData;
665        };
666        // this closure will be kept referenced, so clear its vars
667        contextPrototype = null;
668      }
669    }
670  })();
671
672  // Support: IE<10, Android<4.0, iOS
673  (function checkRequestAnimationFrame() {
674    function fakeRequestAnimationFrame(callback) {
675      window.setTimeout(callback, 20);
676    }
677
678    if ('requestAnimationFrame' in window) {
679      return;
680    }
681    window.requestAnimationFrame =
682      window.mozRequestAnimationFrame ||
683      window.webkitRequestAnimationFrame ||
684      fakeRequestAnimationFrame;
685  })();
686
687  // Checking if the typed arrays are supported
688  // Support: iOS<6.0 (subarray), IE<10, Android<4.0
689  (function checkTypedArrayCompatibility() {
690    if (typeof Uint8Array !== 'undefined') {
691      // Support: iOS<6.0
692      if (typeof Uint8Array.prototype.subarray === 'undefined') {
693        Uint8Array.prototype.subarray = function subarray(start, end) {
694          return new Uint8Array(this.slice(start, end));
695        };
696        Float32Array.prototype.subarray = function subarray(start, end) {
697          return new Float32Array(this.slice(start, end));
698        };
699      }
700
701      // Support: Android<4.1
702      if (typeof Float64Array === 'undefined') {
703        window.Float64Array = Float32Array;
704      }
705      return;
706    }
707
708    function subarray(start, end) {
709      return new TypedArray(this.slice(start, end));
710    }
711
712    function setArrayOffset(array, offset) {
713      if (arguments.length < 2) {
714        offset = 0;
715      }
716      for (var i = 0, n = array.length; i < n; ++i, ++offset) {
717        this[offset] = array[i] & 0xFF;
718      }
719    }
720
721    function TypedArray(arg1) {
722      var result, i, n;
723      if (typeof arg1 === 'number') {
724        result = [];
725        for (i = 0; i < arg1; ++i) {
726          result[i] = 0;
727        }
728      } else if ('slice' in arg1) {
729        result = arg1.slice(0);
730      } else {
731        result = [];
732        for (i = 0, n = arg1.length; i < n; ++i) {
733          result[i] = arg1[i];
734        }
735      }
736
737      result.subarray = subarray;
738      result.buffer = result;
739      result.byteLength = result.length;
740      result.set = setArrayOffset;
741
742      if (typeof arg1 === 'object' && arg1.buffer) {
743        result.buffer = arg1.buffer;
744      }
745      return result;
746    }
747
748    window.Uint8Array = TypedArray;
749    window.Int8Array = TypedArray;
750
751    // we don't need support for set, byteLength for 32-bit array
752    // so we can use the TypedArray as well
753    window.Uint32Array = TypedArray;
754    window.Int32Array = TypedArray;
755    window.Uint16Array = TypedArray;
756    window.Float32Array = TypedArray;
757    window.Float64Array = TypedArray;
758  })();
759
760  var extendDFlipOptions = function (options) {
761    return $.extend(true, {}, defaults, options);
762  };
763
764  //Creates ui for the flipbook
765  var createUI = function (container, object) {
766
767      var uiClass = "df-ui";
768      var wrapperClass = "df-ui-wrapper";
769      var buttonClass = uiClass + "-" + "btn";
770      var ui = object.ui = $(html.div, {'class': uiClass});
771      var options = object.options;
772
773      ui.dispose = function () {
774        container.find("." + buttonClass).each(function () {
775          $(this).off();
776        });
777        help.off();
778        next.off();
779        prev.off();
780        play.off();
781        zoom.off();
782        zoomIn.off();
783        zoomOut.off();
784        page.off();
785        sound.off();
786        more.off();
787        fullScreen.off();
788        fit.off();
789        share.off();
790        start.off();
791        end.off();
792        pageModeButton.off();
793        altPrev.off();
794        altNext.off();
795        thumbnail.off();
796        outline.off();
797
798        controls.remove();
799        sizeControls.remove();
800        prev.remove();
801        next.remove();
802        zoom.remove();
803        if (ui.shareBox) {
804          if (ui.shareBox.dispose)
805            ui.shareBox.dispose();
806          ui.shareBox = null;
807        }
808        document.removeEventListener('keyup', onKeyUp, false);
809        window.removeEventListener('click', closeMoreOptions, false);
810        ui.update = null;
811        object = null;
812      };
813
814      var validPage = function (pageNumber) {
815
816        if (isNaN(pageNumber)) pageNumber = object.target._activePage;
817        else if (pageNumber < 1) pageNumber = 1;
818        else if (pageNumber >
818 object.target.pageCount) pageNumber = object.target.pageCount;
819        return pageNumber;
820
821      };
822
823      var next = ui.next = $(html.div, {
824
825        class: buttonClass + " " + uiClass + "-next " + options.icons['next'],
826        title: options.text.nextPage,
827        html: "<span>" + options.text.nextPage + "</span>"
828
829      }).on("click", function () {
830        object.next();
831      });
832
833      var prev = ui.prev = $(html.div, {
834
835        class: buttonClass + " " + uiClass + "-prev " + options.icons['prev'],
836        title: options.text.previousPage,
837        html: "<span>" + options.text.previousPage + "</span>"
838
839      }).on("click", function () {
840
841        object.prev();
842
843      });
844      var play = $(html.div, {
845
846        class: buttonClass + " " + uiClass + "-play " + options.icons['play'],
847        title: options.text.play,
848        html: "<span>" + options.text.play + "</span>"
849
850      }).on("click", function () {
851        var el = $(this);
852        object.setAutoPlay(!el.hasClass(options.icons['pause']));
853
854      });
855      if (options.autoPlay == true) {
856        ui.play = play;
857        object.setAutoPlay(options.autoPlayStart);
858      }
859      var zoom = $(html.div, {
860        class: wrapperClass + " " + uiClass + "-zoom"
861      });
862
863      var zoomIn = ui.zoomIn = $(html.div, {
864
865        class: buttonClass + " " + uiClass + "-zoomin " + options.icons['zoomin'],
866        title: options.text.zoomIn,
867        html: "<span>" + options.text.zoomIn + "</span>"
868
869      }).on("click", function () {
870
871        object.zoom(1);
872        ui.update();
873        if (object.target.startPoint && object.target.pan)
874          object.target.pan(object.target.startPoint);
875
876      });
877
878      var zoomOut = ui.zoomOut = $(html.div, {
879
880        class: buttonClass + " " + uiClass + "-zoomout " + options.icons['zoomout'],
881        title: options.text.zoomOut,
882        html: "<span>" + options.text.zoomOut + "</span>"
883
884      }).on("click", function () {
885        object.zoom(-1);
886        ui.update();
887        if (object.target.startPoint && object.target.pan)
888          object.target.pan(object.target.startPoint);
889      });
890      zoom.append(zoomIn).append(zoomOut);
891
892      var page = ui.pageNumber = $(html.div, {
893
894        class: buttonClass + " " + uiClass + "-page",
895
896      }).on("change", function () {
897
898        var pageNumber = parseInt((ui.pageInput.val()), 10);
899
900        pageNumber = validPage(pageNumber);
901        object.gotoPage(pageNumber);
902
903      }).on("keyup", function (event) {
904
905        if (event.keyCode == 13) {
906          var pageNumber = parseInt((ui.pageInput.val()), 10);
907
908          pageNumber = validPage(pageNumber);
909          if (pageNumber !== validPage(object.target._activePage || object._activePage))
910            object.gotoPage(pageNumber);
911        }
912
913      });
914
915      ui.pageInput = $('<input id="df_book_page_number" type="text"/>').appendTo(page);
916      ui.pageLabel = $('<label for="df_book_page_number"/>').appendTo(page);
917
918      var sizeControls = $(html.div, {
919        class: wrapperClass + " " + uiClass + "-size"
920      });
921
922      var help = $(html.div, {
923        class: buttonClass + " " + uiClass + "-help " + options.icons['help'],
924        title: options.text.toggleHelp,
925        html: "<span>" + options.text.toggleHelp + "</span>"
926      }).on("click", function () {
927
928      });
929
930
931      //Sound Button
932      var sound = ui.sound = $(html.div, {
933
934        class: buttonClass + " " + uiClass + "-sound " + options.icons['sound'],
935        title: options.text.toggleSound,
936        html: "<span>" + options.text.toggleSound + "</span>"
937
938      }).on("click", function () {
939
940        options.soundEnable = !options.soundEnable;
941        ui.updateSound();
942
943      });
944
945      //Updates sound on click of sound button
946      ui.updateSound = function () {
947
948        if (options.soundEnable == false || options.soundEnable == 'false')
949          sound.addClass("disabled");
950        else
951          sound.removeClass("disabled");
952
953      };
954
955      //immediate check
956      ui.updateSound();
957
958
959      //More button
960      var more = ui.more = $(html.div, {
961
962        class: buttonClass + " " + uiClass + "-more " + options.icons['more']
963
964      }).on("click", function (event) {
965        if (!more.hasClass("df-active")) {
966          $(this).addClass("df-active");
967          event.stopPropagation();
968        }
969      });
970
971      //closes moreoptions container
972      function closeMoreOptions(event) {
973        more.removeClass("df-active");
974      }
975
976      //register a click event on window to close the moreoptions
977      window.addEventListener('click', closeMoreOptions, false);
978
979      //more container that holds the moreoptions
980      var moreContainer = $(html.div, {
981        class: "more-container"
982      });
983      more.append(moreContainer);
984
985      if (typeof options.source == 'string' && options.enableDownload == true) {
986        var downloadClass = buttonClass + " " + uiClass + "-download " + options.icons['download'];
987        var download = ui.download = $('<a download target="_blank" class="' + downloadClass + '"><span>' + options.text.downloadPDFFile + '</span></a>');
988        download.attr("href", options.source).attr("title", options.text.downloadPDFFile);
989        //moreContainer.append(download);
990      }
991
992      var fullscreenEnabled = utils.hasFullscreenEnabled();
993
994      if (!fullscreenEnabled) {
995        container.addClass("df-custom-fullscreen");
996      }
997
998      ui.switchFullscreen = function () {
999
1000        var fullscreenElement = utils.getFullscreenElement();
1001
1002        var container = object.container[0];
1003
1004        if (ui.isFullscreen != true) {
1005
1006          object.container.addClass("df-fullscreen");
1007          if (container.requestFullscreen) {
1008            container.requestFullscreen();
1009          } else if (container.msRequestFullscreen) {
1010            container.msRequestFullscreen();
1011          } else if (container.mozRequestFullScreen) {
1012            container.mozRequestFullScreen();
1013          } else if (container.webkitRequestFullscreen) {
1014            container.webkitRequestFullscreen();
1015          }
1016
1017          ui.isFullscreen = true
1018
1019        }
1020        else {
1021
1022          object.container.removeClass("df-fullscreen");
1023          ui.isFullscreen = false;
1024
1025          if (document.exitFullscreen) {
1026            document.exitFullscreen();
1027          } else if (document.msExitFullscreen) {
1028            document.msExitFullscreen();
1029          } else if (document.mozCancelFullScreen) {
1030            document.mozCancelFullScreen();
1031          } else if (document.webkitExitFullscreen) {
1032            document.webkitExitFullscreen();
1033          }
1034
1035        }
1036
1037        if (!utils.hasFullscreenEnabled()) {
1038          setTimeout(function () {
1039            object.resize();
1040          }, 50);
1041        }
1042      };
1043
1044      var fullScreen = ui.fullScreen = $(html.div, {
1045
1046        class: buttonClass + " " + uiClass + "-fullscreen " + options.icons['fullscreen'],
1047        title: options.text.toggleFullscreen,
1048        html: "<span>" + options.text.toggleFullscreen + "</span>"
1049
1050      }).on("click", ui.switchFullscreen);
1051
1052      var fit = ui.fit = $(html.div, {
1053
1054        class: buttonClass + " " + uiClass + "-fit " + options.icons['fitscreen']
1055
1056      }).on("click", function () {
1057
1058        $(this).toggleClass("df-button-fit-active");
1059
1060      });
1061      sizeControls.append(fullScreen);
1062
1063      var controls = $(html.div, {
1064        class: wrapperClass + " " + uiClass + "-controls"
1065      });
1066
1067      var shareBox = ui.shareBox = new DFLIP.Share(container, options);
1068
1069      var share = ui.share = $(html.div, {
1070
1071        class: buttonClass + " " + uiClass + "-share " + options.icons['share'],
1072        title: options.text.share,
1073        html: "<span>" + options.text.share + "</span>"
1074
1075      }).on("click", function (event) {
1076        if (ui.shareBox.isOpen == true)
1077          ui.shareBox.close();
1078        else {
1079          ui.shareBox.update(object.getURLHash());
1080          ui.shareBox.show();
1081        }
1082      });
1083
1084      var start = ui.startPage = $(html.div, {
1085
1086        class: buttonClass + " " + uiClass + "-start " + options.icons['start'],
1087        title: options.text.gotoFirstPage,
1088        html: "<span>" + options.text.gotoFirstPage + "</span>"
1089
1090      }).on("click", function () {
1091
1092        object.start();
1093
1094      });
1095
1096
1097      var end = ui.endPage = $(html.div, {
1098
1099        class: buttonClass + " " + uiClass + "-end " + options.icons['end'],
1100        title: options.text.gotoLastPage,
1101        html: "<span>" + options.text.gotoLastPage + "</span>"
1102
1103      }).on("click", function () {
1104
1105        object.end();
1106
1107      });
1108
1109      var pageModeButton = ui.pageMode = $(html.div, {
1110
1111        class: buttonClass + " " + uiClass + "-pagemode " + options.icons['singlepage'],
1112        html: "<span>" + options.text.singlePageMode + "</span>"
1113
1114      }).on("click", function () {
1115
1116        var el = $(this);
1117        object.setPageMode(!el.hasClass(options.icons['doublepage']));
1118
1119      });
1120
1121
1122      object.setPageMode(object.target.pageMode == DFLIP.PAGE_MODE.SINGLE)
1123      //moreContainer.append(pageModeButton).append(start).append(end).append(sound);
1124
1125      var altPrev = ui.altPrev = $(html.div, {
1126
1127        class: buttonClass + " " + uiClass + "-prev" + " " + uiClass + "-alt " + options.icons['prev'],
1128        title: options.text.previousPage,
1129        html: "<span>" + options.text.previousPage + "</span>"
1130
1131      }).on("click", function () {
1132        object.prev();
1133      });
1134
1135      var altNext = ui.altNext = $(html.div, {
1136
1137        class: buttonClass + " " + uiClass + "-next" + " " + uiClass + "-alt " + options.icons['next'],
1138        title: options.text.nextPage,
1139        html: "<span>" + options.text.nextPage + "</span>"
1140
1141      }).on("click", function () {
1142        object.next();
1143      });
1144
1145      var thumbnail = ui.thumbnail = $(html.div, {
1146
1147        class: buttonClass + " " + uiClass + "-thumbnail " + options.icons['thumbnail'],
1148        title: options.text.toggleThumbnails,
1149        html: "<span>" + options.text.toggleThumbnails + "</span>"
1150
1151      }).on("click", function () {
1152        var $this = $(this);
1153        if (object.target.thumbContainer) {
1154          var thumbContainer = object.target.thumbContainer;
1155          thumbContainer.toggleClass("df-sidemenu-visible");
1156          $this.toggleClass("df-active");
1157        }
1158        else {
1159          object.contentProvider.initThumbs();
1160          $this.toggleClass("df-active");
1161        }
1162        if ($this.hasClass("df-active")) {
1163          $this.siblings(".df-active").trigger("click");
1164        }
1165        ui.update(true);
1166      });
1167
1168      var outline = ui.outline = $(html.div, {
1169
1170        class: buttonClass + " " + uiClass + "-outline " + options.icons['outline'],
1171        title: options.text.toggleOutline,
1172        html: "<span>" + options.text.toggleOutline + "</span>"
1173
1174      }).on("click", function () {
1175        var $this = $(this);
1176        if (object.target.outlineContainer) {
1177          var outlineContainer = object.target.outlineContainer;
1178          $this.toggleClass("df-active");
1179          outlineContainer.toggleClass("df-sidemenu-visible");
1180          if ($this.hasClass("df-active")) {
1181            $this.siblings(".df-active").trigger("click");
1182          }
1183          ui.update(true);
1184        }
1185      });
1186
1187      /**
1188       * Controls position and pplace ment is determined by options.moreControls and options.hideControls
1189       */
1190      var allControls = options.allControls.replace(/ /g, '').split(','),
1191        moreControls = "," + options.moreControls.replace(/ /g, '') + ",",
1192        hideControls = "," + options.hideControls.replace(/ /g, '') + ",";
1193
1194      var moreControlsArray = moreControls.split(',');
1195
1196      for (var controlCount = 0; controlCount < allControls.length; controlCount++) {
1197        //if hidden skip
1198        var controlName = allControls[controlCount];
1199        if (hideControls.indexOf("," + controlName + ",") < 0) { //not found in hide list
1200          var control = ui[controlName];
1201          if (control != null) {
1202            if (moreControls.indexOf("," + controlName + ",") > -1 && controlName !== 'more' && controlName !== 'pageNumber') {//found in more controls
1203              moreContainer.append(control);
1204            }
1205            else {
1206              controls.append(control);
1207            }
1208          }
1209        }
1210      }
1211
1212      container.append(controls).append(prev).append(next).append(zoom);
1213
1214      var ctrlDown = false, shiftDown = false, altDown = false;
1215      var shiftKey = 16, ctrlKey = 17, altKey = 18, sKey = 83, vKey = 86, cKey = 67, eKey = 69, gKey = 71, nKey = 78,
1216        oKey = 79, deleteKey = 46, rightKey = 39, leftKey = 37, escKey = 27;
1217
1218      document.addEventListener('keyup', onKeyUp, false);
1219
1220      function onKeyUp(event) {
1221        switch (event.keyCode) {
1222          case escKey:
1223            if (ui.isFullscreen == true) ui.fullScreen.trigger("click");
1224            break;
1225          case shiftKey:
1226            shiftDown = false;
1227            break;
1228          case ctrlKey:
1229            ctrlDown = false;
1230            break;
1231          case altKey:
1232            altDown = false;
1233            break;
1234          case leftKey:
1235            object.prev();
1236            break;
1237          case rightKey:
1238            object.next();
1239            break;
1240          default:
1241            break;
1242        }
1243        //log(event.keyCode);
1244      }
1245
1246      ui.update = function (resize) {
1247        log("ui update");
1248        var target = object.target;
1249
1250        var pageNumber = validPage(target._activePage || object._activePage);
1251        var pageCount = target.pageCount || object.pageCount;
1252
1253        var isRTL = target.direction == DFLIP.DIRECTION.RTL,
1254          isStart = (pageNumber == 1 || pageNumber == 0),
1255          isEnd = pageNumber == pageCount;
1256
1257        ui.next.show();
1258        ui.prev.show();
1259        ui.altNext.removeClass("disabled");
1260        ui.altPrev.removeClass("disabled");
1261
1262        if ((isStart && !isRTL) || (isEnd && isRTL)) {
1263          ui.prev.hide();
1264          ui.altPrev.addClass("disabled");
1265        }
1266        if ((isEnd && !isRTL) || (isStart && isRTL)) {
1267          ui.next.hide();
1268          ui.altNext.addClass("disabled");
1269        }
1270
1271        ui.pageInput.val(pageNumber);
1272        ui.pageLabel.html((pageNumber) + "/" + pageCount);
1273
1274
1275        if (container.find(".df-sidemenu-visible").length > 0) {
1276          container.addClass("df-sidemenu-open");
1277        }
1278        else {
1279          container.removeClass("df-sidemenu-open");
1280        }
1281        if (resize == true)
1282          object.resize();
1283
1284        if (target.contentProvider.zoomScale == target.contentProvider.maxZoom) {
1285          ui.zoomIn.addClass("disabled");
1286        }
1287        else {
1288          ui.zoomIn.removeClass("disabled");
1289        }
1290
1291        if (target.contentProvider.zoomScale == 1) {
1292          ui.zoomOut.addClass("disabled");
1293        }
1294        else {
1295          ui.zoomOut.removeClass("disabled");
1296        }
1297
1298      };
1299
1300      if (object.target != null) {
1301        object.target.ui = ui;
1302      }
1303
1304      if (options.onCreateUI != null)
1305        options.onCreateUI(object);
1306    }
1307  ;
1308
1309  var PreviewStage = null;
1310  //later updated via RegisterMockupObjects in case 3d is requested
1311
1312  //Registers necessary mockup object when required
1313  function RegisterMockupObjects() {
1314
1315    PreviewStage = (function (_super) {
1316      __extends(PreviewStage, _super);
1317      function PreviewStage(parameters) {
1318        parameters = parameters || {};
1319        var _this = this;
1320        _super.call(this, parameters);
1321        _this.options = parameters;
1322        _this.canvas = $(_this.renderer.domElement).addClass("df-3dcanvas");
1323        _this.container = parameters.container;
1324        _this.container.append(_this.canvas);
1325        //_this.container.height(parameters.height);
1326        _this.type = "PreviewStage";
1327        _this.mouse = new THREE.Vector2();
1328        _this.raycaster = new THREE.Raycaster();
1329
1330        _this.camera.position.set(0, 20, 600);
1331        _this.camera.lookAt(new THREE.Vector3(0, 0, 0));
1332
1333        //shadows are zigzap due to shadow camera position
1334        _this.spotLight.position.set(-220, 330, 550);
1335
1336        _this.spotLight.castShadow = isMobile ? false : parameters.webglShadow;
1337        //_this.spotLight.shadowDarkness = 0.6;
1338        if (_this.spotLight.shadow) {
1339          _this.spotLight.shadow.bias = -0.0008;
1340        }
1341        _this.spotLight.intensity = isset(parameters.spotLightIntensity, defaults.spotLightIntensity);
1342        _this.ambientLight.color = new THREE.Color(isset(parameters.ambientLightColor, defaults.ambientLightColor));
1343        _this.ambientLight.intensity = isset(parameters.ambientLightIntensity, defaults.ambientLightIntensity);
1344
1345        var material = new THREE.ShadowMaterial();
1346        material.opacity = isset(parameters.shadowOpacity, defaults.shadowOpacity);
1347
1348        _this.ground.material = material;
1349        _this.ground.position.z = -2;
1350
1351        _this.orbitControl.maxAzimuthAngle = 0.4;
1352        _this.orbitControl.minAzimuthAngle = -0.4;
1353        _this.orbitControl.minPolarAngle = 1.4;
1354        _this.orbitControl.maxPolarAngle = 2.2;
1355
1356        //_this.orbitControl.maxPolarAngle = 10;
1357        _this.orbitControl.mouseButtons.ORBIT = THREE.MOUSE.RIGHT;
1358        _this.orbitControl.mouseButtons.PAN = -1;
1359        _this.orbitControl.maxDistance = 5000;
1360        _this.orbitControl.minDistance = 50;
1361        _this.orbitControl.noZoom = true;
1362
1363        _this.selectiveRendering = true;
1364
1365        _this.orbitControl.zoomSpeed = 5;
1366
1367        _this.orbitControl.keyPanSpeed = 0;
1368        _this.orbitControl.center.set(0, 0, 0);
1369        _this.orbitControl.update();
1370
1371        _this.swipe_threshold = isMobile ? 15 : 20;
1372
1373        var cssRenderer = _this.cssRenderer = new THREE.CSS3DRenderer();
1374        $(cssRenderer.domElement).css({
1375          position: "absolute",
1376          top: 0,
1377          pointerEvents: "none"
1378        }).addClass("df-3dcanvas df-csscanvas");
1379        _this.container[0].appendChild(cssRenderer.domElement);
1380
1381        var cssScene = _this.cssScene = new THREE.Scene();
1382
1383        var divLeftDOM = document.createElement("div");
1384        divLeftDOM.className = "df-page-content df-page-content-left";
1385
1386        var divRightDOM = document.createElement("div");
1387        divRightDOM.className = "df-page-content df-page-content-right";
1388
1389        var divLeft = cssScene.divLeft = new THREE.CSS3DObject(divLeftDOM);
1390        var divRight = cssScene.divRight = new THREE.CSS3DObject(divRightDOM);
1391        cssScene.add(divLeft);
1392        cssScene.add(divRight);
1393
1394        _this.resizeCallback = function () {
1395          cssRenderer.setSize(_this.canvas.width(), _this.canvas.height());
1396        };
1397
1398        function requestRender() {
1399          _this.renderRequestPending = true;
1400        }
1401
1402        window.addEventListener(mouseEvents.move, requestRender, false);
1403
1404        window.addEventListener('keyup', requestRender, false);
1405
1406
1407        _this.dispose = function () {
1408
1409          _this.clearChild();
1410          _this.render();
1411
1412          window.removeEventListener(mouseEvents.move, requestRender, false);
1413
1414          if (_this.options.scrollWheel == true) {
1415            _this.renderer.domElement.removeEventListener('mousewheel', onMouseWheel, false);
1416            _this.renderer.domElement.removeEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
1417          }
1418
1419          window.removeEventListener('keyup', requestRender, false);
1420
1421          _this.renderer.domElement.removeEventListener("mousemove", editor_mouseMove, false);
1422          _this.renderer.domElement.removeEventListener("touchmove", editor_mouseMove, false);
1423
1424          _this.renderer.domElement.removeEventListener("mousedown", editor_mouseDown, false);
1425          _this.renderer.domElement.removeEventListener("touchstart", editor_mouseDown, false);
1426          _this.renderer.domElement.removeEventListener("mouseup", editor_mouseUp, false);
1427          _this.renderer.domElement.removeEventListener("touchend", editor_mouseUp, false);
1428
1429
1430          _this.canvas.remove();
1431
1432          cssRenderer.domElement.parentNode.removeChild(cssRenderer.domElement);
1433
1434          cssRenderer = null;
1435
1436          _this.renderCallback = null;
1437          _this.renderCallback = null;
1438          _this.orbitControl.dispose();
1439          _this.orbitControl = null;
1440
1441
1442          _this.renderer.dispose();
1443
1444          _this.cancelRAF();
1445        };
1446
1447        _this.renderCallback = function () {
1448          if (TWEEN.getAll().length > 0)
1449            _this.renderRequestPending = true;
1450          TWEEN.update();
1451          cssRenderer.render(cssScene, _this.camera)
1452        };
1453
1454        var onMouseWheel = function (event) {
1455          var delta = 0;
1456
1457          if (event.wheelDelta != null) { // WebKit / Opera / Explorer 9
1458
1459            delta = event.wheelDelta;
1460
1461          } else if (event.detail != null) { // Firefox
1462
1463            delta = -event.detail;
1464
1465          }
1466          if (delta) {
1467            var currentZoom = _this.previewObject.contentProvider.zoomScale;
1468            if ((delta > 0 && currentZoom == 1)
1469              || (delta < 0 && currentZoom > 1)) {
1470              event.preventDefault();
1471            }
1472            _this.previewObject.zoom(delta > 0 ? 1 : -1);
1473          }
1474
1475          requestRender();
1476        };
1477
1478        var editor_mouseMove = function (event) {
1479
1480          _this.renderRequestPending = true;
1481          event = fixMouseEvent(event);
1482          if (_this.isMouseDown && event.movementX != 0 && event.movementY != 0) {
1483            _this.isMouseMoving = true;
1484          }
1485          if (event.touches != null && event.touches.length == 2 && _this.startTouches != null) {
1486            //return;
1487            // _this.startTouches = event.touches;
1488            _this.zoomDirty = true;
1489            var touchCenter = utils.getVectorAvg(utils.getTouches(event, _this.container.offset())),
1490              newScale = utils.calculateScale(_this.startTouches, utils.getTouches(event)),
1491              scale = newScale / _this.lastScale;
1492
1493            var zoom = _this.previewObject.contentProvider.zoomScale,
1494              x = touchCenter.x,
1495              y = touchCenter.y;
1496
1497            _this.camera.position.z = _this.originalZ / (newScale);
1498            _this.lastScale = newScale;
1499
1500            _this.lastZoomCenter = touchCenter;
1501            event.preventDefault();
1502            return;
1503          }
1504          if (_this.isMouseDown == true && _this.previewObject.contentProvider.zoomScale == 1) {
1505            //check if swipe has happened
1506
1507            var swipe_dist = event.pageX - _this.lastPos,
1508              swipe_time = performance.now() - _this.lastTime;
1509
1510            //$("body > p").html(swipe_dist);
1511
1512            if (Math.abs(swipe_dist) > _this.swipe_threshold) {
1513              //swipe has triggered
1514              //_this.dragPage.pendingPoint = point;
1515              if (swipe_dist < 0) {
1516                _this.target.next();
1517              }
1518              else {
1519                _this.target.prev();
1520              }
1521              event.preventDefault();
1522              _this.isMouseDown = false;
1523            }
1524            _this.lastPos = event.pageX;
1525            _this.lastTime = performance.now();
1526
1527          }
1528        };
1529
1530        var editor_mouseDown = function (event) {
1531          event = fixMouseEvent(event);
1532          if (event.touches != null && event.touches.length == 2 && _this.startTouches == null) {
1533            _this.startTouches = utils.getTouches(event);
1534            _this.lastScale = 1;
1535            _this.originalZ = _this.camera.position.z * 1;
1536          }
1537          document.activeElement.blur();
1538          _this.mouseValue = event.pageX + "," + event.pageY;
1539          _this.isMouseMoving = false;
1540          _this.isMouseDown = true;
1541          _this.lastPos = event.pageX;
1542          _this.lastTime = performance.now();
1543        };
1544
1545        var editor_click = function (event) {
1546          _this.isMouseDown = false;
1547          //bail out if it's not left click
1548          if (event.button !== 0) return this;
1549          var mouseValue = event.pageX + "," + event.pageY;
1550
1551          if (_this.isMouseMoving) {
1552
1553          }
1554          else if (mouseValue == _this.mouseValue) {
1555            event = event || window.event;
1556            event = $.event.fix(event);
1557
1558            var mouse = _this.mouse, raycaster = _this.raycaster;
1559            mouse.x = ( (event.offsetX) / _this.canvas.innerWidth() ) * 2 - 1;
1560            mouse.y = 1 - ( (event.offsetY ) / _this.canvas.innerHeight() ) * 2;
1561
1562            raycaster.setFromCamera(mouse, _this.camera);
1563
1564            var intersects = raycaster.intersectObjects(_this.target instanceof MOCKUP.Bundle
1565              ? _this.target.children : [_this.target], true);
1566
1567            if (intersects.length > 0) {
1568
1569              var object, objectCount = 0;
1570              do {
1571                object = intersects[objectCount] != null ? intersects[objectCount].object : null;
1572                //bookStage.clickFace = intersects[objectCount].face;
1573                objectCount++;
1574              } while ((object instanceof THREE.BoxHelper || !(object instanceof MOCKUP.Paper) || object.isFlipping == true) && objectCount < intersects.length);
1575
1576              //if (object.parent instanceof  MOCKUP.Bundle) {
1577              //    object = object.parent;
1578              //}
1579
1580              if (object.userData.object != null) {
1581
1582                // helper
1583
1584                //bookStage.selectObject(object.userData.object);
1585
1586              } else {
1587
1588                if (object.angles[1] > 90) {
1589                  if (object.isEdge != true) _this.target.next();
1590                }
1591                else {
1592                  if (object.isEdge != true) _this.target.prev();
1593                }
1594
1595              }
1596
1597            } else {
1598
1599              //bookStage.selectObject(null);
1600
1601            }
1602          }
1603          //bookStage.stage.render();
1604        };
1605
1606        var editor_mouseUp = function (event) {
1607          event = fixMouseEvent(event);
1608          if (event.touches != null && event.touches.length == 0) {
1609            var zoom = _this.previewObject.contentProvider.zoomScale;
1610            if (_this.zoomDirty == true) {
1611              _this.previewObject.contentProvider.zoomScale =
1612                utils.limitAt(_this.previewObject.contentProvider.zoomScale * _this.lastScale,
1613                  1, _this.previewObject.contentProvider.maxZoom);
1614              _this.previewObject.zoomValue = _this.previewObject.contentProvider.zoomScale * 1;
1615              //_this.previewObject.zoom(_this.lastScale < 1 ? -1 : 1);
1616              //console.log(_this.previewObject.contentProvider.zoomScale * _this.lastScale,_this.previewObject.contentProvider.maxZoom)
1617              //_this.previewObject.pendingZoom = true;
1618              _this.previewObject.resize();
1619              _this.zoomDirty = false;
1620            }
1621
1622            _this.lastScale = null;
1623            _this.startTouches = null;
1624          }
1625          if (event.touches != null && event.touches.length > 1) return;
1626          editor_click(event);
1627        };
1628        //if (MOCKUP.mode !== MOCKUP.MODE.PLUGIN) {
1629
1630        //_this.renderer.domElement.addEventListener('click', editor_click, false);
1631        //bookStage.renderer.domElement.addEventListener('dblclick', editor_dblclick, false);
1632        _this.renderer.domElement.addEventListener("mousemove", editor_mouseMove, false);
1633        _this.renderer.domElement.addEventListener("touchmove", editor_mouseMove, false);
1634
1635        _this.renderer.domElement.addEventListener("mousedown", editor_mouseDown, false);
1636        _this.renderer.domElement.addEventListener("touchstart", editor_mouseDown, false);
1637        _this.renderer.domElement.addEventListener("mouseup", editor_mouseUp, false);
1638        _this.renderer.domElement.addEventListener("touchend", editor_mouseUp, false);
1639        if (_this.options.scrollWheel == true) {
1640          _this.renderer.domElement.addEventListener('mousewheel', onMouseWheel, false);
1641          _this.renderer.domElement.addEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
1642        }
1643
1644        //}
1645
1646        $(_this.renderer.domElement).css({display: "block"});
1647
1648        $(window).trigger("resize");
1649
1650        return this;
1651      }
1652
1653      PreviewStage.prototype.width = function () {
1654        return this.container.width();
1655      };
1656
1657      PreviewStage.prototype.height = function () {
1658        return this.container.height();
1659      };
1660
1661      return PreviewStage;
1662
1663    })(MOCKUP.Stage);
1664    MOCKUP.PreviewStage = PreviewStage;
1665
1666    var BookPaper = (function (_super) {
1667      __extends(BookPaper, _super);
1668      function BookPaper(parameters, stage) {
1669        parameters = parameters || {};
1670        parameters.folds = 1;
1671        _super.call(this, parameters, stage);
1672        this.angle = 0;
1673        this.isFlipping = false;
1674        this.material.materials[5].transparent = true;
1675        this.material.materials[4].transparent = true;
1676        this.type = "BookPaper";
1677      }
1678
1679      BookPaper.prototype.tween = function (oldAngle, newAngle) {
1680        var page = this;
1681        var epsilon = 0.00001;
1682        page.originalStiff = page.stiffness;
1683        var oldTarget = page.newStiffness;
1684        var isBooklet = isBookletMode(page.parent);
1685        //console.log(page.stiffness);
1686        var diff = newAngle - oldAngle;//170 -5 == 165 :  5-170 = -165
1687
1688        var isRight = oldAngle > 90;
1689        var isRTL = page.parent.direction == DFLIP.DIRECTION.RTL;
1690        page.init = {
1691          angle: oldAngle,
1692          angle2: (oldAngle < 90 ? 0 : 180),
1693          stiff: page.originalStiff,
1694          index: (isRight && !isRTL) || (!isRight && isRTL) ? 1 : 0
1695        };
1696        page.first = {
1697          angle: oldAngle + diff / 4,
1698          angle2: (oldAngle < 90 ? 90 : 90),
1699          stiff: page.originalStiff,
1700          index: (isRight && !isRTL) || (!isRight && isRTL) ? 1 : 0.25
1701        };
1702        page.mid = {
1703          angle: oldAngle + diff * 2 / 4,
1704          angle2: (oldAngle < 90 ? 135 : 45),
1705          stiff: page.newStiffness,
1706          index: (isRight && !isRTL) || (!isRight && isRTL) ? 0.5 : 0.5
1707        };
1708        page.mid2 = {
1709          angle: oldAngle + diff * 3 / 4,
1710          angle2: (oldAngle < 90 ? 180 : 0),
1711          stiff: page.newStiffness,
1712          index: (isRight && !isRTL) || (!isRight && isRTL) ? 0.25 : 1
1713        };
1714        page.end = {
1715          angle: newAngle,
1716          angle2: (oldAngle < 90 ? 180 : 0),
1717          stiff: page.newStiffness,
1718          index: (isRight && !isRTL) || (!isRight && isRTL) ? 0 : 1
1719        };
1720
1721        //console.log(page.init, page.first, page.mid, page.end);
1722        page.isFlipping = true;
1723
1724        var update = function (tween, event) {
1725
1726          page.angles[1] = tween.angle;
1727          page.angles[4] = page.isHard ? tween.angle : tween.angle2;
1728          if (page.isHard == true) {
1729            page.stiffness = 0;
1730          } else {
1731            page.stiffness = tween.stiff / (oldTarget + epsilon) * (page.newStiffness + epsilon);
1732            page.stiffness = isNaN(page.stiffness) ? 0 : tween.stiff;
1733          }
1734          if (isBooklet) {
1735            page.material.materials[5].opacity = page.material.materials[4].opacity = tween.index;
1736            page.castShadow = (isRight && !isRTL) || (!isRight && isRTL) ? tween.index > 0.5 : tween.index > 0.5;
1737          }
1738          //check if any sibling is flipping and their stiff is more that this
1739
1740          page.updateAngle(true);
1741
1742        };
1743
1744        if (isBooklet && ((!isRight && !isRTL) || (isRight && isRTL))) {
1745          page.material.materials[5].opacity = page.material.materials[4].opacity = 0;
1746          page.castShadow = false;
1747        }
1748
1749        page.currentTween = new TWEEN.Tween(page.init)
1750          .to({
1751            angle: [page.first.angle, page.mid.angle, page.mid2.angle, page.end.angle],
1752            angle2: [page.first.angle2, page.mid.angle2, page.mid2.angle2, page.end.angle2],
1753            stiff: [page.first.stiff, page.mid.stiff, page.mid2.stiff, page.end.stiff],
1754            index: [page.first.index, page.mid.index, page.mid2.index, page.end.index]
1755          }, page.parent.duration)
1756          .onUpdate(function (event) {
1757            update(this, event);
1758          }).easing(TWEEN.Easing.Sinusoidal.Out)
1759          .onComplete(function (event) {
1760            page.stiffness = page.newStiffness;
1761            page.updateAngle();
1762            page.material.materials[5].opacity = page.material.materials[4].opacity = 1;
1763            page.castShadow = true;
1764            page.isFlipping = false;
1765            if (page.parent && page.parent.refresh)
1766              page.parent.refresh();
1767            //console.log(page.stiffness);
1768          }).start();
1769
1770      };
1771
1772      return BookPaper;
1773    })(MOCKUP.FlexBoxPaper);
1774    MOCKUP.BookPaper = BookPaper;
1775
1776    var Book = (function (_super) {
1777      __extends(Book, _super);
1778
1779      function Book(parameters, stage) {
1780
1781        parameters = parameters || {};
1782        parameters.segments = parameters.segments || 50;
1783        this.pageCount = parameters.pageCount;
1784
1785        this.height = parameters.height;
1786        this.width = parameters.width;
1787
1788        //correcting page count as multiple of 2
1789        this.pageCount = (this.pageCount == 1 ? this.pageCount : Math.ceil(this.pageCount / 2) * 2);
1790
1791        this.direction = parameters.direction || DFLIP.DIRECTION.LTR;
1792
1793        this.startPage = 1;
1794        this.endPage = this.pageCount;
1795
1796        this.stackCount = parameters.stackCount || 6;// = 15;
1797        this.materials = [];
1798
1799        _super.call(this, parameters, stage);
1800        this.angles = [0, 0, 0, 0, 0, 0];
1801        this.stiffness = parameters.stiffness == null ? 1.5 : parameters.stiffness; //so that 0 can be set
1802        this.hardConfig = parameters.hard; //hard is not that good in 3d
1803        this._activePage = parameters.openPage || this.startPage;
1804
1805        this.createStack(parameters);
1806        this.pageMode = parameters.pageMode || ((isMobile || this.pageCount <= 2) ? D
1806FLIP.PAGE_MODE.SINGLE
1807            : DFLIP.PAGE_MODE.DOUBLE);
1808
1809        this.singlePageMode = parameters.singlePageMode || (isMobile ? DFLIP.SINGLE_PAGE_MODE.BOOKLET
1810            : DFLIP.SINGLE_PAGE_MODE.ZOOM);
1811
1812
1813        this.type = "Book";
1814
1815      }
1816
1817      Book.prototype.getPageByNumber = function (pageNumber) {
1818        var relativePageNumber = isBookletMode(this) ? (isRTLMode(this) ? pageNumber + 1 : pageNumber)
1819          : Math.floor((pageNumber - 1) / 2);
1820        return this.getObjectByName(relativePageNumber.toString());
1821      };
1822
1823      Book.prototype.isPageHard = function (pageNumber) {
1824
1825        return utils.isHardPage(this.hardConfig, pageNumber, this.pageCount);
1826
1827      };
1828
1829      Book.prototype.activePage = function (pageNumber) {
1830        if (pageNumber == null) return this._activePage;
1831        this.gotoPage(pageNumber);
1832      };
1833
1834      Book.prototype.gotoPage = function (pageNumber) {
1835        pageNumber = parseInt(pageNumber, 10);
1836        this._activePage = pageNumber;
1837        if (this.autoPlay == true) {
1838          this.previewObject.setAutoPlay(this.autoPlay);
1839        }
1840        this.updatePage(pageNumber);
1841        if (this && this.thumblist && this.thumblist.review)
1842          this.thumblist.review();
1843      };
1844
1845
1846      Book.prototype.moveBy = function (step) {
1847        var nextPage = this._activePage + step;
1848        nextPage = limitAt(nextPage, this.startPage, this.endPage);
1849
1850        this.gotoPage(nextPage);
1851      };
1852
1853      Book.prototype.next = function (step) {
1854        if (step == null)
1855          step =
1856            (this.direction == DFLIP.DIRECTION.RTL)
1857              ? -this.pageMode : this.pageMode;
1858
1859        this.moveBy(step);
1860      };
1861
1862      Book.prototype.prev = function (step) {
1863        if (step == null)
1864          step =
1865            (this.direction == DFLIP.DIRECTION.RTL)
1866              ? this.pageMode : -this.pageMode;
1867
1868        this.moveBy(step);
1869      };
1870
1871      Book.prototype.updateAngle = function () {
1872
1873        var startAngle = this.angles[1];
1874        var endAngle = this.angles[4];
1875
1876        var spreadAngle = endAngle - startAngle;
1877        var stacks = this.stackCount;
1878
1879        for (var _stackCount = 0; _stackCount < stacks; _stackCount++) {
1880          var clone = this.children[_stackCount];
1881          //start from angle[1] and end at angles[4]
1882          clone.angles[1] = startAngle + _stackCount * spreadAngle / (stacks * 100);
1883          clone.stiffness = this.stiffness;//_stackCount/stacks;
1884          clone.updateAngle();
1885        }
1886
1887      };
1888
1889      Book.prototype.refresh = function () {
1890        this.updatePage(this._activePage);
1891        if (this.flipCallback != null) this.flipCallback();
1892      };
1893
1894
1895      Book.prototype.updatePage = function (pageNumber) {
1896        // this.contentProvider.setLoading(pageNumber, true);
1897        var isRTL = (this.direction == DFLIP.DIRECTION.RTL),
1898          isBooklet = isBookletMode(this),
1899          newBaseNumber = getBasePage(pageNumber);
1900
1901        var pageDivisor = isBooklet ? 1 : 2;
1902
1903        pageNumber = Math.floor((pageNumber / pageDivisor));
1904
1905        if (isRTL) pageNumber = this.pageCount / pageDivisor - pageNumber;
1906
1907        var oldBaseNumber = this.oldBaseNumber || 0;
1908        var pageCount = this.pageCount / pageDivisor;
1909        var stackCount = this.stackCount;
1910        var angleShift = 0.02;
1911        var depth = 0.4;
1912        var stiffFactor = isBooklet ? 0
1913          : (0.5 - Math.abs(pageCount / 2 - pageNumber) / pageCount) / this.stiffness;
1914        var positionFactor = 1;//(stiffFactor +width);
1915        // var centre = Math.floor(stackCount / 2);
1916        var midPoint = Math.floor(stackCount / 2);//pageNumber < centre ? pageNumber //starting center pages
1917        // : ((pageCount - pageNumber > centre) ? centre //other pages
1918        //: (pageNumber + centre - pageCount)) ;//remainig center page
1919        //console.log(midPoint);
1920
1921        //var targetIndex = midPoint;
1922        //if(midPoint == centre) {
1923        /*This sitaution is good when there is icrement or decrement by 1*/
1924        var isLeft = false;
1925        if (oldBaseNumber > pageNumber) {
1926          isLeft = true;
1927          this.children[stackCount - 1].skipFlip = true;
1928          this.children.unshift(this.children.pop());
1929
1930          // this.contentProvider.setLoading(pageNumber, true);
1931        }
1932        else if (oldBaseNumber < pageNumber) {
1933          this.children[0].skipFlip = true;
1934          this.children.push(this.children.shift());
1935
1936          // this.contentProvider.setLoading(pageNumber, true);
1937        }
1938
1939        var remainingPages = (pageCount - pageNumber);
1940        var stackDepth = (5) / pageCount;
1941        var leftDepth = stackDepth * pageNumber / 2;
1942        var rightDepth = stackDepth * remainingPages / 2;
1943        var maxDepth = (leftDepth < rightDepth ? rightDepth : leftDepth);
1944        //maxDepth = maxDepth > 5 ? 5: maxDepth;
1945        for (var _pageCount = 0; _pageCount < stackCount; _pageCount++) {
1946          var page = this.children[_pageCount];//this.getObjectByName("page"+_pageCount);//this.children[_pageCount];
1947
1948          var color = page.color;
1949          var oldAngle = page.angles[1];
1950          var newAngle;
1951          var relativePageNumber = pageNumber - midPoint + _pageCount;
1952          if (isRTL) relativePageNumber = isBooklet ? this.pageCount - relativePageNumber
1953            : Math.floor(this.pageCount / 2) - relativePageNumber - 1;
1954
1955          var isHard = page.isHard = this.isPageHard(relativePageNumber);
1956          var oldName = page.name;
1957
1958
1959          //Sizing
1960          page.isEdge = false; //true;
1961          if (_pageCount == 0) {
1962            page.depth = leftDepth < depth ? depth : leftDepth;
1963          }
1964          else if (_pageCount == stackCount - 1) {
1965            page.depth = rightDepth < depth ? depth : rightDepth;
1966          }
1967          else {
1968            page.depth = depth;
1969            page.isEdge = false;
1970          }
1971          if (page.isFlipping == true) {
1972            page.depth = depth;
1973          }
1974          page.position.x = 0;
1975
1976          var leftAngle = angleShift * _pageCount,
1977            rightAngle = 180 - angleShift * (_pageCount - midPoint) + angleShift * _pageCount;
1978
1979          if (_pageCount < midPoint) {
1980            page.newStiffness = isHard || this.stiffness == 0 ? 0 : stiffFactor / (pageNumber / pageCount) / 4;
1981            newAngle = leftAngle;
1982            page.position.z = maxDepth - ( -_pageCount + midPoint) * depth;//(pageNumber < pageCount / 2)
1983            if (isLeft == true) page.position.z -= depth;
1984
1985          }
1986          else {
1987            newAngle = rightAngle;
1988            page.newStiffness = isHard || this.stiffness == 0 ? 0
1989              : stiffFactor / (Math.abs(pageCount - pageNumber) / pageCount) / 4;
1990            page.position.z = (maxDepth - (-stackCount + _pageCount + midPoint + 1) * depth) - page.depth;//(pageNumber < pageCount / 2)
1991
1992          }
1993
1994          if (page.isFlipping == false) {
1995
1996            if (Math.abs(oldAngle - newAngle) > 20 && page.skipFlip == false) {
1997              page.depth = depth;
1998              //we need predicted stiffness so that there is no overlap issues
1999              var predicted = page.stiffness;
2000
2001              if (oldAngle > newAngle) {//left
2002                predicted = stiffFactor / (Math.abs(pageCount - pageNumber) / pageCount) / 4;
2003              }
2004              else {//right
2005                predicted = stiffFactor / (pageNumber / pageCount) / 4;
2006              }
2007              page.position.z += depth;//((_pageCount < midPoint) ? 0 : depth) * 2;/// 2;
2008
2009              page.stiffness = isNaN(predicted) ? page.stiffness : predicted;
2010              page.updateAngle(true);
2011              page.targetStiffness = isHard ? 0 : (_pageCount < pageNumber)
2012                ? stiffFactor / (Math.abs(pageCount - pageNumber) / pageCount) / 4
2013                : stiffFactor / (pageNumber / pageCount) / 4;
2014
2015              page.targetStiffness = isHard ? 0 : (isNaN(page.targetStiffness) ? page.stiffness : page.targetStiffness);
2016
2017              page.isFlipping = true;
2018
2019              page.tween(oldAngle, newAngle);
2020
2021              if (this.preFlipCallback != null)
2022                this.preFlipCallback();
2023            } else {
2024              page.skipFlip = false;
2025              page.newStiffness = isNaN(page.newStiffness) ? 0 : page.newStiffness;
2026              if (page.angles[1] != newAngle || page.stiffness != page.newStiffness || page.depth != page.oldDepth) {
2027                page.angles[1] = page.angles[4] = newAngle;
2028                page.stiffness = page.newStiffness;
2029                page.updateAngle(true);
2030              }
2031              else {
2032                //console.log("skipped");
2033              }
2034            }
2035          }
2036
2037          page.visible = isBooklet
2038            ? (isRTL
2039
2040              ? (_pageCount < midPoint || page.isFlipping)
2041              : (_pageCount >= midPoint || page.isFlipping))
2042
2043            : ((relativePageNumber >= 0 && relativePageNumber < pageCount) || (isBooklet && relativePageNumber == pageCount));
2044
2045
2046          if (this.requestPage != null) {
2047            page.name = relativePageNumber.toString();
2048            if (page.name != oldName) {
2049
2050              page.textureLoaded = false;
2051              page.frontImage(defaults.textureLoadFallback);
2052              page.frontPageStamp = "-1";
2053              page.frontTextureLoaded = false;
2054              page.thumbLoaded = false;
2055
2056              // if (!isBooklet) {
2057              page.backImage(defaults.textureLoadFallback);
2058              page.backPageStamp = "-1";
2059              page.backTextureLoaded = false;
2060              // }
2061              this.requestPage();
2062            }
2063          }
2064
2065          //if (isBooklet && _pageCount < midPoint && page.isFlipping == false)
2066          //	page.visible = false;
2067
2068          page.oldDepth = page.depth;
2069          var xPos = Math.abs(page.geometry.boundingBox.max.x) < Math.abs(page.geometry.boundingBox.min.x)
2070            ? page.geometry.boundingBox.max.x : page.geometry.boundingBox.min.x;
2071          page.position.x = (page.isEdge == true && page.isFlipping == false ) ? ((_pageCount < midPoint)
2072            ? xPos : -xPos) : 0;
2073        }
2074        //$(".quick-hint").html(pageNumber);
2075        //console.log("leftDepth:" + leftDepth, "rightDepth:" + rightDepth, "midPoint:" + midPoint, "oldBaseNumber:" + oldBaseNumber, "pageNumber:" + pageNumber);
2076        this.oldBaseNumber = pageNumber;
2077
2078        if (this.updatePageCallback != null)
2079          this.updatePageCallback();
2080
2081      };
2082      //if (window.flipBook != null)flipBook.book.refresh();
2083      //book.activePage(book.activePage());
2084      Book.prototype.createCover = function (parameters) {
2085        parameters.width = parameters.width * 2;
2086        this.cover = new MOCKUP.BiFold(parameters);
2087        this.add(this.cover);
2088      };
2089
2090      Book.prototype.createStack = function (parameters) {
2091
2092        var colors = "red,green,blue,yellow,orange,black".split(",");
2093
2094        for (var _stackCount = 0; _stackCount < this.stackCount; _stackCount++) {
2095          parameters.angles = [, this.stackCount - _stackCount];//[1] = (this.stackCount - _stackCount);
2096          parameters.stiffness = (this.stackCount - _stackCount) / 100;
2097
2098          var clone = new MOCKUP.BookPaper(parameters);
2099          clone.angles[1] = 180;
2100          //clone.name = "page" + _stackCount;
2101          clone.index = _stackCount;
2102          clone.updateAngle();
2103          clone.textureReady = false;
2104          clone.textureRequested = false;
2105          this.add(clone);
2106          clone.color = colors[_stackCount];
2107          //for (var _count = 0; _count < 4; _count++) {
2108          //    clone.material.materials[_count].color = new THREE.Color(THREE.ColorKeywords[colors[_stackCount]]);
2109          //}
2110          clone.position.z = -1 * _stackCount;// * (this.mainObject.depth * 1.05);
2111        }
2112      };
2113
2114
2115      Book.prototype.shininess = function (shininess) {
2116        if (shininess == null) {
2117          return this.mainObject.shininess();
2118        }
2119        else {
2120          this.mainObject.shininess(shininess);
2121        }
2122      };
2123
2124      Book.prototype.bumpScale = function (bumpScale) {
2125        if (bumpScale == null) {
2126          return this.mainObject.bumpScale();
2127        }
2128        else {
2129          this.mainObject.bumpScale(bumpScale);
2130        }
2131      };
2132
2133
2134      Book.prototype.frontImage = function (frontImage) {
2135        if (frontImage == null) {
2136          return this.mainObject.frontImage();
2137        }
2138        else {
2139          this.mainObject.frontImage(frontImage);
2140        }
2141      };
2142
2143
2144      Book.prototype.backImage = function (backImage) {
2145        if (backImage == null) {
2146          return this.mainObject.backImage();
2147        }
2148        else {
2149          this.mainObject.backImage(backImage);
2150        }
2151      };
2152
2153      return Book;
2154    })(MOCKUP.Bundle);
2155    MOCKUP.Book = Book;
2156
2157  }
2158
2159  //base object of flipbook or other trifold objects
2160  var PreviewObject = (function (_super) {
2161
2162    function PreviewObject(parameters) {
2163      parameters = parameters || {};
2164      //_super.call(this, parameters);
2165      this.type = "PreviewObject";
2166      var _this = this;
2167
2168      _this.zoomValue = 1;
2169      function resizeDelay() {
2170        setTimeout(function () {
2171          _this.resize()
2172        }, 50);
2173      }
2174
2175      window.addEventListener("resize", resizeDelay, false);
2176
2177      this.sound = document.createElement("audio");
2178      this.sound.setAttribute("src", parameters.soundFile + "?ver=" + DFLIP.version);
2179      this.sound.setAttribute("type", "audio/mpeg");
2180
2181      this.autoPlayFunction = function () {
2182        if (_this && _this.target.autoPlay) {
2183          if (_this.target.direction == DFLIP.DIRECTION.RTL)
2184            _this.target.prev();
2185          else
2186            _this.target.next();
2187        }
2188      };
2189      //this.pageMode = DFLIP.PAGE_MODE.DOUBLE;
2190      this.dispose = function () {
2191
2192        clearInterval(this.autoPlayTimer);
2193        this.autoPlayTimer = null;
2194        this.autoPlayFunction = null;
2195
2196        //complete any tweens left.
2197        if (this.target && this.target.children) {
2198          for (var count = 0; count < this.target.children.length; count++) {
2199            var page = this.target.children[count];
2200            if (page && page.currentTween) page.currentTween.stop();
2201          }
2202        }
2203        //first dispose internal objects
2204        if (this.zoomTween) {
2205          if (this.zoomTween.stop) this.zoomTween.stop();
2206          this.zoomTween = null;
2207        }
2208        if (this.container && this.container.info && this.container.info.remove)
2209          this.container.info.remove();
2210
2211        if (this.target && this.target.dispose)
2212          this.target.dispose();
2213        this.target = null;
2214
2215        if (this.stage && this.stage.dispose)
2216          this.stage.dispose();
2217        this.stage = null;
2218
2219        //if (this.target && this.target.outlineContainer) this.target.outlineContainer.remove();
2220
2221        if (this.ui && this.ui.dispose)
2222          this.ui.dispose();
2223        this.ui = null;
2224
2225        if (this.contentProvider && this.contentProvider.dispose)
2226          this.contentProvider.dispose();
2227        this.contentProvider = null;
2228
2229        window.removeEventListener("resize", resizeDelay);
2230
2231      };
2232    }
2233
2234    PreviewObject.prototype = {
2235
2236      start: function () {
2237
2238        this.target.gotoPage(this.target.startPage);
2239
2240      },
2241
2242      end: function () {
2243        this.target.gotoPage(this.target.endPage);
2244      },
2245
2246      next: function () {
2247
2248      },
2249
2250      prev: function () {
2251
2252      },
2253
2254      zoom: function (delta) {
2255
2256        this.pendingZoom = true;
2257        this.zoomDelta = delta;
2258
2259        this.resize();
2260        this.ui.update();
2261      },
2262
2263      resize: function () {
2264
2265        var _this = this;
2266
2267        if (_this.target == null ||
2268          _this.target.ui == null ||
2269          _this.target.contentProvider == null ||
2270          _this.target.contentProvider.viewport == null ||
2271          _this.target.stage == null)
2272          return;
2273
2274        if (this.ui && this.ui.isFullscreen == true && utils.hasFullscreenEnabled() == true && utils.getFullscreenElement() == null) {
2275          this.ui.switchFullscreen();
2276        }
2277
2278        //Variable Caches
2279        var target = _this.target,
2280          container = _this.container,
2281          options = _this.options,
2282          stage = target.stage,
2283          contentProvider = target.contentProvider,
2284          pageRatio = contentProvider.pageRatio,
2285          zoomViewport = contentProvider.zoomViewport,
2286          isRTL = isRTLMode(target),
2287          is3d = target.mode !== "css",
2288          isLandScape = contentProvider.pageRatio > 1,
2289          isWide, height, width, cameraZ, fov, zoom, maxZoom,
2290          sideShift = container.hasClass("df-sidemenu-open") ? 220 : 0,
2291          isSingle = this.target.pageMode == DFLIP.PAGE_MODE.SINGLE;
2292
2293        /*SIZE CALCULATION*/
2294        //checking if the container height is more than the window height
2295        container.height(options.height);
2296        var containerHeight = Math.min(container.height(), $(window).height());
2297        container.height(containerHeight);//setting twice for failsafe
2298
2299
2300        //checking if the responsive width according to container
2301        var containerWidth = container.width();
2302        if (containerWidth < 400) {//rather than responsive lets use
2303          _this.container.addClass("df-xs");
2304        } else {
2305          _this.container.removeClass("df-xs");
2306        }
2307
2308        var controlsHeight = container.find(".df-ui-controls").height();
2309        var paddingTop = options.paddingTop + (options.controlsPosition == DFLIP.CONTROLSPOSITION.TOP
2310              ? controlsHeight : 0),
2311          paddingRight = options.paddingRight,
2312          paddingBottom = options.paddingBottom + (options.controlsPosition == DFLIP.CONTROLSPOSITION.BOTTOM
2313              ? controlsHeight : 0),
2314          paddingLeft = options.paddingLeft;
2315
2316        paddingTop = isNaN(paddingTop) ? 0 : limitAt(paddingTop, 0, paddingTop),
2317          paddingBottom = isNaN(paddingBottom) ? 0 : limitAt(paddingBottom, 0, paddingBottom),
2318          paddingLeft = isNaN(paddingLeft) ? 0 : limitAt(paddingLeft, 0, paddingLeft),
2319          paddingRight = isNaN(paddingRight) ? 0 : limitAt(paddingRight, 0, paddingRight);
2320
2321        //containerHeight, containerWidth, controlsHeight above
2322        var stageWidth = containerWidth - sideShift, //if sideMenu for thumbnails is open?
2323          stageHeight = containerHeight;
2324        var paddingHeight = paddingTop + paddingBottom,
2325          paddingWidth = paddingLeft + paddingRight;
2326
2327        var stageInnerWidth = stageWidth - paddingWidth,
2328          stageInnerHeight = stageHeight - paddingHeight;
2329
2330        width = Math.floor(isSingle ? stageInnerWidth : stageInnerWidth / 2);
2331        height = Math.floor(width / pageRatio);
2332
2333        //check if book fits by width
2334        isWide = height > stageInnerHeight;
2335        if (isWide) {
2336          height = stageInnerHeight;
2337          width = height * pageRatio;
2338        }
2339
2340        /*ZOOM CALCULATION*/
2341        //update maxZoom for current Stage Dimension
2342        maxZoom = contentProvider.maxZoom = contentProvider.zoomViewport.height / height;
2343
2344        //set to 1 if unset initally
2345        if (_this.zoomValue == null) _this.zoomValue = 1;
2346        if (contentProvider.zoomScale == null) contentProvider.zoomScale = 1;
2347
2348        if (_this.pendingZoom == true && _this.zoomDelta != null) {
2349
2350          var delta = _this.zoomDelta, predictedIndex, currentMaxDimension = Math.max(height, width);
2351
2352          _this.zoomValue = _this.zoomDelta > 0 ? _this.zoomValue * _this.options.zoomRatio
2353            : _this.zoomValue / _this.options.zoomRatio;
2354          _this.zoomValue = limitAt(_this.zoomValue, 1, maxZoom);
2355
2356          if (_this.zoomValue == 1) {
2357            contentProvider.zoomScale = 1;
2358          } else {
2359            predictedIndex = height * _this.zoomValue;
2360            //zoomStops matches the contentProvider internal calcuation and prediction stops so that the texture size won't differ
2361            predictedIndex = utils.zoomStops(predictedIndex, _this.options.zoomRatio, _this.zoomDelta > 0, Math.max(width, height));
2362            contentProvider.zoomScale = limitAt(predictedIndex / currentMaxDimension, 1, maxZoom);
2363          }
2364
2365        }
2366
2367        zoom = contentProvider.zoomScale;
2368
2369        //Update Image CacheSize Index
2370        contentProvider.checkViewportSize(width, height, zoom);
2371
2372        if (contentProvider.contentSourceType == SOURCE_TYPE.PDF) {
2373          //recalculation is required for pixel shift issue only if the source is PDF
2374          width = contentProvider.imageViewport.width / zoom;
2375          height = contentProvider.imageViewport.height / zoom;
2376        }
2377
2378        if (contentProvider.zoomScale != 1) {
2379          this.target.container.addClass("df-zoom-enabled");
2380        }
2381
2382        var zoomWidth = target.zoomWidth = Math.floor(width * zoom),
2383          zoomHeight = target.zoomHeight = Math.floor(height * zoom);
2384        var zoomFullWidth = zoomWidth * 2;
2385
2386        if (is3d) {
2387
2388          //zoomHeight is equal to target.height (normally 300) so relative calculation is required
2389          var proportion = zoomHeight / target.height,
2390            aspect = stageWidth / stageHeight;
2391          var relativeHeight = zoom * (height + paddingHeight) / proportion,
2392            relativeWidth = zoom * (width * (isSingle ? 1 : 2) + paddingWidth) / proportion;
2393
2394          var focusSize = isWide ? relativeHeight : relativeWidth / aspect;
2395          stage.resizeCanvas(stageWidth, stageHeight);
2396
2397          cameraZ = 1 / ( 2 * Math.tan(Math.PI * stage.camera.fov * 0.5 / 180) / (focusSize / zoom)) + 2.2;
2398
2399          stage.camera.updateProjectionMatrix();
2400
2401          stage.renderRequestPending = true;
2402
2403          //pixel value to stage position value
2404
2405          var shift = (paddingTop - paddingBottom) * ( target.height / height) / zoom / 2;
2406
2407          //put a check if the existing gap is enough
2408          // _this.target.position.y = shift;
2409          // stage.cssScene.position.y = _this.target.position.y;
2410
2411          var _reset = contentProvider.zoomScale == 1;
2412          if (stage.camera.position.z !== cameraZ && _this.pendingZoom == true) { //avoid recreating the tween if the target is same as before
2413            if (_this.zoomTween != null)
2414              _this.zoomTween.stop();
2415            _this.zoomTween = new TWEEN.Tween({
2416              campos: stage.camera.position.z,
2417              otx: stage.orbitControl.target.x,
2418              oty: stage.orbitControl.target.y,
2419              otz: stage.orbitControl.target.z
2420            }).delay(0)
2421              .to({
2422                  campos: cameraZ,
2423                  otx: 0,
2424                  oty: shift,
2425                  otz: 0
2426                },
2427                100)
2428              .onUpdate(function () {
2429                stage.camera.position.z = this.campos;
2430                if (_reset) {
2431                  stage.camera.position.y = this.oty;
2432                  stage.orbitControl.target = new THREE.Vector3(this.otx, this.oty, this.otz);
2433                }
2434                stage.orbitControl.update();
2435              }).easing(TWEEN.Easing.Linear.None)
2436              .onComplete(function () {
2437                stage.camera.position.z = cameraZ;
2438                if (contentProvider.zoomScale == 1) {
2439                  stage.camera.position.set(0, shift, cameraZ);
2440                  stage.orbitControl.target = new THREE.Vector3(0, shift, 0);
2441                }
2442                stage.orbitControl.update();
2443              })
2444              .start();
2445          }
2446          else {
2447            if (contentProvider.zoomScale == 1) {
2448              stage.camera.position.set(0, shift, cameraZ);
2449              stage.orbitControl.target = new THREE.Vector3(0, shift, 0);
2450            }
2451            /*else {
2452              stage.camera.position.z = cameraZ;
2453            }*/
2454            stage.orbitControl.update();
2455          }
2456
2457          stage.orbitControl.update();
2458          stage.orbitControl.mouseButtons.ORBIT = zoom != 1 ? -1 : THREE.MOUSE.RIGHT;
2459          stage.orbitControl.mouseButtons.PAN = zoom != 1 ? THREE.MOUSE.LEFT : -1;
2460
2461        }
2462        else {
2463
2464          target.pageWidth = Math.round(width);
2465          target.fullWidth = target.pageWidth * 2;
2466          target.height = Math.round(height);
2467
2468          var shiftHeight = target.shiftHeight = Math.round(limitAt((zoomHeight - stageHeight + paddingHeight) / 2, 0, zoomHeight)),
2469            shiftWidth = target.shiftWidth = Math.round(limitAt((zoomFullWidth - stageWidth + paddingWidth ) / 2, 0, zoomFullWidth));
2470
2471          if (zoom == 1) {
2472            target.left = 0;
2473            target.top = 0;
2474          }
2475          target.stage.css({
2476            top: -shiftHeight,
2477            bottom: -shiftHeight,
2478            right: -shiftWidth + (isRTL ? sideShift : 0),
2479            left: -shiftWidth + (isRTL ? 0 : sideShift),
2480            paddingTop: paddingTop,
2481            paddingRight: paddingRight,
2482            paddingBottom: paddingBottom,
2483            paddingLeft: paddingLeft,
2484            transform: "translate3d(" + target.left + "px," + target.top + "px,0)"
2485          });
2486          target.stageHeight = stage.height();
2487
2488          target.wrapper.css({
2489            width: zoomFullWidth,
2490            height: zoomHeight,
2491            marginTop: (containerHeight - zoomHeight - paddingHeight ) > 0
2492              ? (containerHeight - paddingHeight - zoomHeight) / 2
2493              : 0
2494          });
2495
2496          var wrapperSize = Math.floor((distOrigin(width, height)) * zoom);
2497
2498          target.stage.find(".df-page-wrapper").width(wrapperSize).height(wrapperSize);
2499
2500          target.stage.find(".df-book-page, .df-page-front , .df-page-back, .df-page-fold-inner-shadow").height(zoomHeight).width(zoomWidth);
2501
2502        }
2503
2504        _this.checkCenter({type: "resize"});
2505
2506        if (contentProvider.zoomScale == 1) {
2507          this.target.container.removeClass("df-zoom-enabled");
2508        }
2509
2510        if (target.thumblist) {
2511          target.thumblist.reset($(target.thumblist.container).height());
2512        }
2513
2514        _this.pendingZoom = false;
2515
2516      },
2517
2518      playSound: function () {
2519        try {
2520          if (this.options && this.options.soundEnable == true) {
2521            this.sound.currentTime = 0;
2522            this.sound.play();
2523          }
2524        } catch (error) {
2525
2526        }
2527      },
2528
2529      setPageMode: function (isSingle) {
2530        if (isSingle == true) {
2531          this.ui.pageMode.addClass(this.options.icons['doublepage']);
2532          this.ui.pageMode.html("<span>" + this.options.text.doublePageMode + "</span>");
2533          this.ui.pageMode.attr("title", this.options.text.doublePageMode);
2534          this.target.pageMode = DFLIP.PAGE_MODE.SINGLE;
2535        }
2536        else {
2537          this.ui.pageMode.removeClass(this.options.icons['doublepage']);
2538          this.ui.pageMode.html("<span>" + this.options.text.singlePageMode + "</span>");
2539          this.ui.pageMode.attr("title", this.options.text.singlePageMode);
2540          this.target.pageMode = DFLIP.PAGE_MODE.DOUBLE;
2541        }
2542
2543        if (this.target && this.target.singlePageMode == DFLIP.SINGLE_PAGE_MODE.BOOKLET) {
2544          this.target.reset();
2545        }
2546
2547        this.resize();
2548      },
2549      setAutoPlay: function (isPlay) {
2550        if (this.options.autoPlay) {
2551          isPlay = isPlay == true;
2552          var text = isPlay ? this.options.text.pause : this.options.text.play;
2553          this.ui.play.toggleClass(this.options.icons['pause'], isPlay);
2554          this.ui.play.html("<span>
2554" + text + "</span>");
2555          this.ui.play.attr("title", text);
2556
2557          clearInterval(this.autoPlayTimer);
2558          if (isPlay) {
2559            this.autoPlayTimer = setInterval(this.autoPlayFunction, this.options.autoPlayDuration);
2560          }
2561
2562          this.target.autoPlay = isPlay;
2563        }
2564      },
2565      height: function (height) {
2566        if (height == null) {
2567          return this.container.height();
2568        } else {
2569          this.options.height = height;
2570          this.container.height(height);
2571          this.resize();
2572        }
2573      },
2574      /**
2575       *checks whether the book is closed and needs to be centered
2576       */
2577      checkCenter: function (options) {
2578
2579        options = options == null ? {} : options;
2580        this.centerType = this.centerType || "start";
2581        var target = this.target;
2582        var singleShift = 0, left = 0, right = 0;
2583        var basePage = utils.getBasePage(target._activePage);
2584        var isEven = target._activePage % 2 == 0;
2585        var isRTL = target.direction == DFLIP.DIRECTION.RTL;
2586        var isSingle = target.pageMode == DFLIP.PAGE_MODE.SINGLE,
2587          isBooklet = isSingle && target.singlePageMode == DFLIP.SINGLE_PAGE_MODE.BOOKLET;
2588        var stageWidth = target.stage.width(),
2589          width;
2590
2591        if (target.mode == 'css') {
2592          width = target.wrapper.width();
2593          //calculate the excess shift required for correction in case width is too small
2594          singleShift = Math.max((width - stageWidth) / 2, 0);
2595
2596          left = -width / 4;
2597          right = width / 4;
2598
2599          if (basePage == 0 || isBooklet) {
2600            target.wrapper.css({
2601              left: isSingle
2602                ? isRTL ? right - singleShift : left - singleShift
2603                : isRTL ? right : left
2604            });
2605            target.shadow.css({width: '50%', left: isRTL ? 0 : '50%', transitionDelay: ''});
2606          }
2607          else if (basePage == target.pageCount) {
2608            target.wrapper.css({
2609              left: isSingle
2610                ? isRTL ? left - singleShift : right - singleShift
2611                : isRTL ? left : right
2612            });
2613            target.shadow.css({width: '50%', left: isRTL ? '50%' : 0, transitionDelay: ''});
2614          }
2615          else {
2616            target.wrapper.css({
2617              left: isSingle
2618                ? isRTL
2619                      ? (isEven ? left - singleShift : right - singleShift )
2620                      : (isEven ? right - singleShift : left - singleShift )
2621                : 0
2622            });
2623            target.shadow.css({
2624              width: '100%',
2625              left: 0,
2626              transitionDelay: (parseInt(target.duration, 10) + 50) + 'ms'
2627            });
2628          }
2629
2630          target.wrapper.css({transition: options.type == "resize" ? "none" : ""});
2631
2632        }
2633        else if (target.stage != null) {
2634          var init = target.position.x, end;
2635          singleShift = target.width / 4;
2636          width = target.width;
2637          left = -width / 2;
2638          right = width / 2;
2639
2640          if (basePage == 0 || isBooklet) {
2641            end = isRTL ? right : left;
2642          }
2643          else if (basePage == target.pageCount) {
2644            end = isRTL ? left : right;
2645          }
2646          else {
2647            end = isSingle
2648              ? isRTL
2649                    ? (isEven ? left : right )
2650                    : (isEven ? right : left )
2651              : 0;
2652          }
2653          //create a centertween
2654          if (end !== this.centerEnd) { //avoid recreating the tween if the target is same as before
2655            this.centerTween = new TWEEN.Tween({x: init}).delay(0)
2656              .to({x: end}, target.duration)
2657              .onUpdate(function () {
2658                target.position.x = this.x;
2659                target.stage.cssScene.position.x = this.x;
2660              }).easing(target.ease)
2661              .start();
2662            this.centerEnd = end;
2663
2664          }
2665        }
2666        // log("checkcenter at : " + left);
2667      },
2668
2669      width: function (width) {
2670        if (width == null) {
2671          return this.container.width();
2672        } else {
2673          this.options.width = width;
2674          this.container.width(width);
2675          this.resize();
2676        }
2677      }
2678
2679    };
2680
2681    return PreviewObject;
2682
2683  })({});
2684
2685  DFLIP.PreviewObject = PreviewObject;
2686
2687  //contentprovider that handles the source of book
2688  var ContentProvider = (function (_super) {
2689    __extends(ContentProvider, _super);
2690
2691
2692    function ContentProvider(contentSource, callback, parameters, flipbook) {
2693
2694      parameters = parameters || {};
2695
2696      var _this = this;
2697
2698      _this.contentRawSource = contentSource || [defaults.textureLoadFallback];
2699      _this.contentSource = _this.contentRawSource;
2700      _this.contentSourceType = null;
2701      _this.minDimension = parameters.minTextureSize || 256;
2702      _this.maxDimension = parameters.maxTextureSize || 2048;
2703      _this.pdfRenderQuality = parameters.pdfRenderQuality || DFLIP.defaults.pdfRenderQuality;
2704      _this.flipbook = flipbook;
2705      _this.waitPeriod = 50;
2706      _this.maxLength = 297;
2707      _this.enableDebug = false;
2708      _this.zoomScale = 1;
2709      _this.maxZoom = 2;
2710      _this.options = parameters;
2711      _this.outline = parameters.outline;
2712      _this.links = parameters.links;
2713      _this.html = parameters.html;
2714      _this.isCrossOrigin = parameters.isCrossOrigin;
2715
2716      _this.normalViewport = {
2717        height: 297,
2718        width: 210,
2719        scale: 1
2720      };
2721      _this.viewport = {
2722        height: 297,
2723        width: 210,
2724        scale: 1
2725      };
2726      _this.imageViewport = {
2727        height: 297,
2728        width: 210,
2729        scale: 1
2730      };
2731      _this.bookSize = {
2732        height: 297,
2733        width: 210
2734      }
2735      _this.zoomViewport = {
2736        height: 297,
2737        width: 210
2738      };
2739
2740      _this.thumbsize = 128;
2741      _this.cacheIndex = 256; //index of bigger dimension height or width
2742      _this.cache = [];
2743
2744      _this.pageRatio = parameters.pageRatio || _this.viewport.width / _this.viewport.height;
2745
2746      //texture load control so that it wont delay the transition
2747      _this.textureLoadTimeOut = null;
2748
2749      _this.type = "TextureLibrary";
2750
2751      if (Array === _this.contentSource.constructor || Array.isArray(_this.contentSource) || _this.contentSource instanceof Array) {
2752
2753        //case of images and html content
2754        _this.contentSourceType = SOURCE_TYPE.IMAGE;
2755        _this.pageCount = _this.contentSource.length;
2756
2757        //_this.setLoading(1, true);
2758
2759        // Make in memory copy of image to avoid css issues
2760        $("<img/>")
2761          .attr("src", _this.contentSource[0])
2762          .on('load', (function () {
2763            _this.viewport.height = this.height;
2764            _this.viewport.width = this.width;
2765
2766            _this.pageRatio = _this.viewport.width / _this.viewport.height;
2767            _this.bookSize = {
2768              width: (_this.pageRatio > 1 ? 1 : _this.pageRatio) * _this.maxLength,
2769              height: _this.maxLength / (_this.pageRatio < 1 ? 1 : _this.pageRatio)
2770            };
2771            _this.zoomViewport = {
2772              width: (_this.pageRatio > 1 ? 1 : _this.pageRatio) * _this.maxDimension,
2773              height: _this.maxDimension / (_this.pageRatio < 1 ? 1 : _this.pageRatio)
2774            };
2775
2776            _this.linkService = new PDFLinkService();
2777
2778            $(this).off();
2779
2780            if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL) {
2781              _this.pageCount = _this.contentSource.length * 2 - 2;
2782              if (_this.options.webgl == true)
2783                _this.requiresImageTextureScaling = true;
2784            }
2785
2786            if (callback != null) {
2787              callback(_this);
2788              callback = null;
2789            }
2790            //_this.setLoading(1);
2791
2792            //console.log(_this.zoomViewport);
2793            log(this.height + ":" + this.width);
2794            //pic_real_width = this.width;   // Note: $(this).width() will not
2795            //pic_real_height = this.height; // work for in memory images.
2796            //moved to set target function
2797            //_this.
2798            // ();
2799
2800
2801          }));
2802
2803      }
2804      else if (typeof _this.contentSource == 'string' || _this.contentSource instanceof String) { //case of link to pdf file
2805
2806        var checkSource = function () {
2807          if (_this.contentSource.indexOf(".base64") > 1) {
2808            $.ajax({
2809              url: _this.contentSource,
2810              xhrFields: {
2811                onprogress: function (e) {
2812                  if (e.lengthComputable) {
2813                    var percentage = 100 * e.loaded / e.total;
2814                    _this.updateInfo("Loading PDF " + percentage.toString().split(".")[0] + "% ...");
2815                  }
2816                }
2817              },
2818              success: function (response) {
2819                _this.options.docParameters = {data: atob(response)};
2820                processSource();
2821              }
2822            });
2823          } else {
2824            processSource();
2825          }
2826        }
2827        var processSource = function () {
2828          if (_this) {
2829            //configurePDFJS(PDFJS);
2830            PDFJS.workerSrc = defaults.pdfjsWorkerSrc;
2831
2832            _this.contentSourceType = SOURCE_TYPE.PDF;
2833            //PDFJS.disableWorker = true;
2834            PDFJS.disableAutoFetch = true;
2835            PDFJS.disableStream = true;
2836            if (isSafari || isIOS || _this.options.disableFontFace == true) {
2837              PDFJS.disableFontFace = isSafari || isIOS || _this.options.disableFontFace == true;
2838            }
2839            PDFJS.imageResourcesPath = defaults.imageResourcesPath;
2840            PDFJS.cMapUrl = defaults.cMapUrl;
2841            PDFJS.cMapPacked = !0;
2842            PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK;
2843
2844            var loading = _this.loading = PDFJS.getDocument(_this.options.docParameters ? _this.options.docParameters
2845              : {
2846                url: utils.httpsCorrection(contentSource),
2847                rangeChunkSize: isNaN(DFLIP.defaults.rangeChunkSize) ? 524288 : DFLIP.defaults.rangeChunkSize
2848              });
2849
2850            loading.then(function sourceLoaded(pdf) {
2851
2852                _this.pdfDocument = pdf;
2853                pdf.getPage(1).then(function (page) {
2854                  _this.normalViewport = page.getViewport(1);
2855                  _this.viewport = page.getViewport(1);
2856                  _this.viewport.height = _this.viewport.height / 10;
2857                  _this.viewport.width = _this.viewport.width / 10;
2858
2859                  _this.pageRatio = _this.viewport.width / _this.viewport.height;
2860
2861                  _this.bookSize = {
2862                    width: (_this.pageRatio > 1 ? 1 : _this.pageRatio) * _this.maxLength,
2863                    height: _this.maxLength / (_this.pageRatio < 1 ? 1 : _this.pageRatio)
2864                  };
2865
2866                  _this.zoomViewport = {
2867                    width: (_this.pageRatio > 1 ? 1 : _this.pageRatio) * _this.maxDimension,
2868                    height: _this.maxDimension / (_this.pageRatio < 1 ? 1 : _this.pageRatio)
2869                  };
2870
2871                  _this.refPage = page;
2872
2873                  //console.log(_this.zoomViewport);
2874
2875                  //check if intenal pages are of double sizes.
2876                  if (pdf.numPages > 1) {
2877                    pdf.getPage(2).then(function (page) {
2878                      if (_this.options.pageSize == DFLIP.PAGE_SIZE.AUTO) {
2879                        var _viewport = page.getViewport(1);
2880                        //Update: doing width check gives false alarm if the internal pages are of different sizes yet follow same aspect ratio
2881                        //if (_viewport.width > _this.normalViewport.width * 1.5) {
2882                        var _pageRatio = _viewport.width / _viewport.height;
2883                        if (_pageRatio > _this.pageRatio * 1.5) {
2884                          _this.options.pageSize = DFLIP.PAGE_SIZE.DOUBLEINTERNAL;
2885                          _this.pageCount = pdf.numPages * 2 - 2;
2886                        }
2887                        else {
2888                          _this.options.pageSize = DFLIP.PAGE_SIZE.SINGLE;
2889                        }
2890                      }
2891                      if (callback != null) {
2892                        callback(_this);
2893                        callback = null;
2894                      }
2895                    });
2896                  } else {
2897                    if (callback != null) {
2898                      callback(_this);
2899                      callback = null;
2900                    }
2901                  }
2902
2903                });
2904                _this.linkService = new PDFLinkService();
2905                _this.linkService.setDocument(pdf, null);
2906
2907                //moved to set target function
2908                //_this.initThumbs();
2909                _this.pageCount = pdf.numPages;
2910                _this.contentSource = pdf;
2911
2912              },
2913              function loadingError(error) {
2914                if (_this) {
2915                  var cors = "", tmp = document.createElement('a');
2916                  tmp.href = _this.contentSource;
2917
2918                  if (tmp.hostname !== window.location.hostname)
2919                    cors = "CROSS ORIGIN!! ";
2920
2921                  _this.updateInfo(cors + "Cannot access file!  " + _this.contentSource);
2922                }
2923              });
2924
2925            loading.onProgress = function getDocumentProgress(progressData) {
2926              if (_this) {
2927                var percentage = 100 * progressData.loaded / progressData.total;
2928                if (isNaN(percentage)) {
2929                  if (progressData && progressData.loaded) {
2930                    _this.updateInfo("Loading PDF " + (Math.ceil(progressData.loaded / 10000) / 100).toString() + "MB ...");
2931                  } else {
2932                    _this.updateInfo("Loading PDF ...");
2933                  }
2934                } else {
2935                  _this.updateInfo("Loading PDF " + percentage.toString().split(".")[0] + "% ...");
2936                }
2937              }
2938            };
2939          }
2940        };
2941        var checkCORS = function () {
2942          if (_this) {
2943            defaults.pdfjsWorkerSrc += "?ver=" + DFLIP.version;
2944
2945            _this.updateInfo("Loading PDF Worker ...");
2946            var tmp = document.createElement('a');
2947            tmp.href = defaults.pdfjsWorkerSrc;
2948
2949            if (tmp.hostname !== window.location.hostname) {
2950              _this.updateInfo("Loading PDF Worker CORS ...");
2951              $.ajax({
2952                url: defaults.pdfjsWorkerSrc,
2953                cache: true,
2954                success: function (data) {
2955                  defaults.pdfjsWorkerSrc = DFLIP.createObjectURL(data, "text/javascript");
2956                  checkSource();
2957                }
2958              });
2959            }
2960            else {
2961              checkSource();
2962            }
2963          }
2964        };
2965        if (window.PDFJS == null) {
2966          if (_this) {
2967            _this.updateInfo("Loading PDF Service ...");
2968            //getScript(defaults.pdfjsCompatibilitySrc + "?ver=" + DFLIP.version, function () {
2969
2970            getScript(defaults.pdfjsSrc + "?ver=" + DFLIP.version, function () {
2971
2972              if (typeof define === 'function' && define.amd && window.requirejs) {
2973                _this.updateInfo("Loading PDF Service (require) ...");
2974                require.config({paths: {'pdfjs-dist/build/pdf.worker': defaults.pdfjsWorkerSrc.replace(".js", "")}});
2975                require(['pdfjs-dist/build/pdf'], function (pdf) {
2976                  checkCORS();
2977                });
2978              } else {
2979                checkCORS();
2980              }
2981            }, function () {
2982              _this.updateInfo("Unable to load PDF service..");
2983            });
2984            //});
2985          }
2986        }
2987        else {
2988
2989          checkSource();
2990        }
2991
2992      }
2993      else {
2994        console.error("Unknown source type. Please check documentation for help");
2995      }
2996
2997      this.dispose = function () {
2998        if (_this.loading && _this.loading.destroy) {
2999          _this.loading.destroy();
3000        }
3001        _this.loading = null;
3002        if (_this.textureLoadTimeOut) {
3003          clearTimeout(_this.textureLoadTimeOut);
3004          _this.textureLoadTimeOut = null;
3005        }
3006        if (this.targetObject) {
3007          if (this.targetObject.thumbContainer && this.targetObject.thumbContainer.remove)
3008            this.targetObject.thumbContainer.remove();
3009          if (this.targetObject.outlineContainer && this.targetObject.outlineContainer.remove)
3010            this.targetObject.outlineContainer.remove();
3011          if (this.targetObject.dispose) this.targetObject.dispose();
3012          this.targetObject.processPage = null;
3013          this.targetObject.requestPage = null;
3014          if (this.targetObject.container && this.targetObject.container.off)
3015            this.targetObject.container.off();
3016
3017        }
3018        if (this.pdfDocument && this.pdfDocument.destroy) this.pdfDocument.destroy();
3019        if (this.linkService && this.linkService.dispose) this.linkService.dispose();
3020        if (this.outlineViewer && this.outlineViewer.dispose) this.outlineViewer.dispose();
3021        if (this.thumblist && this.thumblist.dispose) {
3022          this.thumblist.review = null;
3023          this.thumblist.dispose();
3024        }
3025
3026        this.activeThumb = null;
3027        this.targetObject = null;
3028        this.pdfDocument = null;
3029        this.linkService = null;
3030        this.outlineViewer = null;
3031        this.thumblist = null;
3032        _this = null;
3033      };
3034      return this;
3035    }
3036
3037    ContentProvider.prototype.updateInfo = function (info) {
3038      if (this.flipbook && this.flipbook.updateInfo) {
3039        this.flipbook.updateInfo(info);
3040      }
3041    };
3042
3043    ContentProvider.prototype.initThumbs = function () {
3044
3045      var _this = this;
3046      if (_this.cache[_this.thumbsize] == null) _this.cache[_this.thumbsize] = [];
3047      var thumbLoadTimeOut;
3048      var review = function () {
3049        clearTimeout(thumbLoadTimeOut);
3050        thumbLoadTimeOut = setTimeout(function () {
3051
3052          thumbLoadTimeOut = setTimeout(reviewThumbs, _this.waitPeriod / 2);
3053
3054        }, _this.waitPeriod);
3055      };
3056
3057      var reviewThumbs = function () {
3058        var requestCount = 0;
3059        if (Date.now() - _this.thumblist.lastScrolled < 100) {
3060          requestCount = 1;
3061        } else {
3062          _this.targetObject.container.find(".df-thumb-container .df-vrow").each(function () {
3063            var thumb = $(this);
3064            if (!thumb.hasClass("df-thumb-loaded")) {
3065              requestCount++;
3066              var id = $(this).attr("id").replace("df-thumb", "");
3067              _this.getPage(id, review, true);
3068              thumb.addClass("df-thumb-loaded");
3069              return false;
3070            }
3071          });
3072          if (requestCount == 0) {
3073            clearTimeout(thumbLoadTimeOut);
3074          }
3075        }
3076
3077        if (requestCount > 0) {
3078          review();
3079        }
3080        //move to thumb if thumb is on
3081        if (_this.activeThumb != _this.targetObject._activePage) {
3082          var thumbVisible = _this.targetObject.thumbContainer != null && _this.targetObject.thumbContainer.hasClass("df-sidemenu-visible");
3083
3084          if (thumbVisible) {
3085            var wrapper = _this.thumblist.container;
3086            var cScroll = wrapper.scrollTop,
3087              cHeight = wrapper.getBoundingClientRect().height;
3088
3089            var thumb = _this.targetObject.thumbContainer.find("#df-thumb" + _this.targetObject._activePage);
3090            if (thumb.length > 0) {//TODO direct jumps won't work..
3091              _this.targetObject.thumbContainer.find(".df-selected").removeClass("df-selected");
3092              thumb.addClass("df-selected");
3093              //js calculation
3094              thumb = thumb[0];
3095
3096
3097              if (cScroll + cHeight < thumb.offsetTop + thumb.scrollHeight)
3098                thumb.scrollIntoView(false);
3099              else if (cScroll > thumb.offsetTop)
3100                thumb.scrollIntoView();
3101
3102              _this.activeThumb = _this.targetObject._activePage;
3103            }
3104            else {
3105              $(wrapper).scrollTop(_this.targetObject._activePage * 124);
3106              review();
3107            }
3108          }
3109        }
3110      };
3111
3112      _this.thumblist = _this.targetObject.thumblist = new ThumbList({
3113        //w: 128 * _this.viewport.width/_this.viewport.height,
3114        h: 500,
3115        addFn: function (row) {
3116
3117        },
3118        scrollFn: review,
3119        itemHeight: 128,
3120        totalRows: _this.pageCount,
3121        generatorFn: function (row) {
3122          var el = document.createElement("div");
3123          var pageNumber = row + 1;
3124          el.id = "df-thumb" + pageNumber;
3125          var elText = document.createElement("div");
3126          elText.innerHTML = pageNumber;
3127          el.appendChild(elText);
3128          //el.style.position = "absolute";
3129          //el.callback = function_this.getPage(pageNumber,null,true);
3130          return el;
3131        }
3132      });
3133
3134      _this.thumblist.lastScrolled = Date.now();
3135      _this.thumblist.review = review;
3136      review();
3137
3138      //_this.thumblist.container.classList.add('thumb-container');
3139      var thumbContainer = $('<div>').addClass("df-thumb-container df-sidemenu-visible df-sidemenu");
3140      thumbContainer.append($(_this.thumblist.container).addClass("df-thumb-wrapper"));
3141      _this.targetObject.thumbContainer = thumbContainer;
3142      _this.targetObject.container.append(thumbContainer);
3143
3144      var sideMenuClose = $(html.div, {
3145        class: "df-ui-btn df-ui-sidemenu-close ti-close"
3146      });
3147      thumbContainer.append(sideMenuClose);
3148      _this.thumblist.reset($(_this.thumblist.container).height());
3149      _this.targetObject.container.on('click', '.df-thumb-container .df-vrow', function (e) {
3150        e.stopPropagation();
3151        var id = $(this).attr("id").replace("df-thumb", "");
3152        _this.targetObject.gotoPage(parseInt(id, 10));
3153      });
3154    };
3155
3156    ContentProvider.prototype.initOutline = function () {
3157      var _this = this;
3158      var outlineContainer = $('<div>').addClass("df-outline-container df-sidemenu");
3159      var outlineWrapper = $('<div>').addClass("df-outline-wrapper");
3160
3161      var sideMenuClose = $(html.div, {
3162        class: "df-ui-btn df-ui-sidemenu-close ti-close"
3163      });
3164
3165      outlineContainer.append(sideMenuClose).append(outlineWrapper);
3166      _this.targetObject.container.append(outlineContainer);
3167      _this.targetObject.outlineContainer = outlineContainer;
3168
3169      _this.outlineViewer = new BookMarkViewer({
3170        container: outlineWrapper[0],
3171        linkService: _this.linkService,
3172        outlineItemClass: "df-outline-item",
3173        outlineToggleClass: "df-outline-toggle",
3174        outlineToggleHiddenClass: "df-outlines-hidden"
3175      });
3176
3177      function processOutline(outline) {
3178
3179        if (_this.options.overwritePDFOutline == true) {
3180          outline = [];
3181        }
3182        outline = outline || [];
3183
3184        if (_this.outline) {
3185          for (var count = 0; count < _this.outline.length; count++) {
3186            _this.outline[count].custom = true;
3187            if (outline) outline.push(_this.outline[count]);
3188          }
3189          /*                    _this.outline.forEach(function(v) {
3190           //v.custom = true;
3191           this.push(v);
3192           }, this);
3193           outline.push(_this.outline)*/
3194        }
3195
3196        _this.outlineViewer.render({outline: outline});
3197      }
3198
3199      if (_this.pdfDocument) {
3200        _this.pdfDocument.getOutline().then(function (outline) {
3201          processOutline(outline);
3202        });
3203      }
3204      else {
3205        processOutline([]);
3206      }
3207
3208      if (_this.options.autoEnableOutline == true) {
3209        _this.targetObject.ui.outline.trigger("click");
3210      }
3211
3212      if (_this.options.autoEnableThumbnail == true) {
3213        _this.targetObject.ui.thumbnail.trigger("click");
3214      }
3215
3216    };
3217
3218    ContentProvider.prototype.checkViewportSize = function (width, height, zoom) {
3219      var _this = this;
3220      var target = _this.targetObject;
3221      var zoomWidth = width * zoom,
3222        zoomHeight = height * zoom;
3223
3224      var oldCacheSize = _this.cacheIndex;
3225
3226      /*            var height = target.mode == "css"
3227       ? (target.container.height() - (target.stage.innerWidth() - target.stage.width()) )
3228       : target.stage.height();
3229
3230       var width = height * _this.normalViewport.width / _this.normalViewport.height;*/
3231
3232      //var zoom = _this.zoomScale != 1;
3233
3234      if (_this.contentSourceType == SOURCE_TYPE.PDF) {
3235
3236
3237        /*                _this.viewport.height = height;
3238         _this.viewport.width = width;*/
3239        _this.cacheIndex = Math.ceil(Math.max(zoomWidth, zoomHeight));
3240
3241        // if (zoom !== 1) {
3242
3243        _this.cacheIndex = Math.floor(Math.max(zoomWidth, zoomHeight));// * _this.zoomScale;//nearestPowerOfTwo(Math.max(_this.viewport.width,_this.viewport.height));
3244        // _this.cacheIndex = Math.floor(utils.zoomStops(Math.max(zoomWidth, zoomHeight), _this.options.zoomRatio, oldCacheSize < _this.cacheIndex, Math.max(width, height)));
3245
3246        // }
3247
3248        _this.cacheIndex = limitAt(_this.cacheIndex * defaults.pixelRatio, _this.minDimension, _this.maxDimension);
3249        //removed to force internal page size fit incase the internal pages are of different sizes.
3250        // _this.cacheScale = _this.cacheIndex / Math.max(_this.normalViewport.width, _this.normalViewport.height);
3251
3252        if (_this.cache[_this.cacheIndex] == null) _this.cache[_this.cacheIndex] = [];
3253
3254        if (oldCacheSize !== _this.cacheIndex) {
3255          for (var pageCount = 0; pageCount < target.children.length; pageCount++) {
3256            var page = target.children[pageCount];
3257            //page.name = '-2';
3258          }
3259          target.refresh();
3260        }
3261
3262        //if(zoom !==1){
3263        //	zoomHeight = height> width ? _this.cacheIndex : _this.cacheIndex * _this.pageRatio;
3264        //}
3265        _this.imageViewport = _this.refPage.getViewport(zoomHeight / _this.normalViewport.height);
3266        _this.viewport = (target.mode == "css") ? _this.imageViewport
3267          : _this.refPage.getViewport(_this.bookSize.height / _this.normalViewport.height);
3268
3269        log(_this.cacheIndex);
3270
3271        var div = target.container.find(".linkAnnotation"),
3272          viewportClone = _this.viewport.clone({dontFlip: true});
3273        div.css({
3274          transform: 'matrix(' + viewportClone.transform.join(',') + ')'
3275        });
3276        //_this.zoomScale = (zoom == true) ? _this.normalViewport.height * _this.viewport.scale / _this.viewport.height : 1;
3277
3278      }
3279      else {
3280        if (_this.cache[_this.cacheIndex] == null) _this.cache[_this.cacheIndex] = [];
3281        /*                _this.cacheIndex = _this.zoomScale == 1 ? limitAt(_this.cacheIndex, _this.minDimension, _this.maxDimension) : _this.maxDimension;*/
3282
3283        //_this.zoomScale = (zoom == true) ? _this.zoomViewport.height / height : 1;
3284      }
3285
3286      //_this.zoomScale = (zoom == true) ? _this.zoomViewport.height / height : 1;
3287    };
3288
3289    ContentProvider.prototype.getCache = function (index, isThumb) {
3290      return (isThumb == true)
3291        ? this.cache[this.thumbsize] == null ? null : this.cache[this.thumbsize][index]
3292        : this.cache[this.cacheIndex] == null ? null : this.cache[this.cacheIndex][index];
3293    };
3294
3295    ContentProvider.prototype.setCache = function (index, src, isThumb, cacheIndexSize) {
3296      if (isThumb == true) {
3297        if (this.cache[this.thumbsize] != null) this.cache[this.thumbsize][index] = src;
3298      }
3299      else {
3300        var cacheIndex = cacheIndexSize == null ? this.cacheIndex : cacheIndexSize;
3301        if (this.cache[cacheIndex] != null)
3302          this.cache[cacheIndex][index] = src;
3303      }
3304
3305    };
3306
3307    ContentProvider.prototype.setTarget = function (targetObject) {
3308      var _this = this;
3309      if (targetObject == null) {
3310        return this.targetObject;
3311      }
3312      else {
3313        this.targetObject = targetObject;
3314        targetObject.contentProvider = this;
3315
3316        targetObject.container.removeClass("df-loading df-init");
3317
3318        //_this.initThumbs();
3319
3320        if (_this.linkService != null) {
3321          _this.linkService.setViewer(targetObject);
3322
3323          _this.initOutline();
3324        }
3325
3326        targetObject.processPage = function (pageNumber, callback) {
3327          if (pageNumber > 0 && pageNumber <= _this.pageCount) {
3328            //log("Loading page :" + pageNumber);
3329            _this.getPage(pageNumber, callback);
3330          }
3331          else {
3332            _this.setPage(pageNumber, defaults.textureLoadFallback, callback);
3333            //log("Invalid PageNumber :" + pageNumber);
3334          }
3335        };
3336
3337        targetObject.requestPage = function () {
3338
3339          _this.review("Request");
3340
3341        };
3342
3343        if (targetObject.resize != null)
3344          targetObject.resize();
3345
3346      }
3347    };
3348
3349    ContentProvider.prototype.review = function (message) {
3350      var _this = this;
3351      message = message || "timer review";
3352      clearTimeout(_this.textureLoadTimeOut);
3353      _this.textureLoadTimeOut = setTimeout(function () {
3354
3355        _this.textureLoadTimeOut = setTimeout(_this.reviewPages, _this.waitPeriod / 2, _this, message);
3356
3357      }, _this.waitPeriod);
3358    };
3359
3360    ContentProvider.prototype.reviewPages = function (_this, message) {
3361      _this = _this || this;
3362      var target = _this.targetObject;
3363
3364      if (target == null) return;
3365
3366      var isBooklet = isBookletMode(target);
3367      if (message != null) log(message);
3368      var requiresRevisit = false;
3369      var pageCount, page;
3370
3371      for (pageCount = 0; pageCount < _this.targetObject.children.length; pageCount++) {
3372        page = target.children[pageCount];
3373        if (page.isFlipping == true) { //requires revisit
3374          requiresRevisit = true;
3375          break;
3376        }
3377      }
3378      if (requiresRevisit == false) {
3379
3380        var pageLength = target.children.length > 3 ? 3 : target.children.length;
3381        var midPoint = pageLength / 2;
3382
3383        var basePage = isBooklet ? target._activePage : getBasePage(target._activePage);
3384        _this.baseNumber = basePage;
3385
3386        if (_this.zoomScale > 1) {
3387          pageLength = 1;
3388        }
3389
3390        for (pageCount = 0; pageCount < pageLength; pageCount++) {
3391
3392          var dividend = Math.floor(pageCount / 2);
3393          var diff = pageCount % 2 == 0
3394            ? -dividend * (isBooklet ? 1 : 2)
3395            : (dividend == 0 ? 1 : dividend) * (isBooklet ? 1 : 2);
3396
3397          var frontPageNumber = basePage + diff,
3398            backPageNumber = basePage + diff + 1;
3399
3400          var page1 = target.getPageByNumber(frontPageNumber),
3401            page2 = target.getPageByNumber(backPageNumber),
3402            reqFrontPageStamp = frontPageNumber + "|" + _this.cacheIndex,
3403            reqBackPageStamp = backPageNumber + "|" + _this.cacheIndex;
3404
3405
3406          var requestCount = 0;
3407          if (page1 != null && page1.frontPageStamp != reqFrontPageStamp && page1.visible == true) {
3408            page1.frontTextureLoaded = false;
3409            target.processPage(frontPageNumber, function () {
3410              _this.review("Batch Call");
3411            });
3412            page1.frontPageStamp = reqFrontPageStamp;
3413            requestCount++;
3414          }
3415          if (page2 != null && page2.backPageStamp != reqBackPageStamp && page2.visible == true && !isBooklet) {
3416            page2.backTextureLoaded = false;
3417            target.processPage(backPageNumber, function () {
3418              _this.review("Batch Call");
3419            });
3420            page2.backPageStamp = reqBackPageStamp;
3421            requestCount++;
3422          }
3423
3424          //diff is 0 only at the open pages
3425          if (diff == 0 && _this.annotedPage !== basePage) {// && target.mode !== "css") {
3426            _this.getAnnotations(frontPageNumber);
3427            if (!isBooklet) _this.getAnnotations(backPageNumber);
3428            _this.annotedPage = basePage;
3429          }
3430
3431          if (requestCount > 0) {
3432            break;
3433          }
3434        }
3435        if (requestCount == 0) {
3436          if (target.mode !== "css") {
3437            _this.setLoading(basePage);
3438          }
3439          else {
3440            // _this.setLoading(basePage);
3441            // _this.setLoading(basePage + 1);
3442          }
3443        }
3444      }
3445      else {
3446        _this.review("Revisit request");
3447        if (_this.annotedPage != null && target.mode !== "css") {
3448          var baseActive = getBasePage(target._activePage);
3449          $(target.getContentLayer(baseActive)).html("");
3450          $(target.getContentLayer(baseActive + 1)).html("");
3451          _this.annotedPage = null;
3452        }
3453      }
3454
3455    };
3456
3457    ContentProvider.prototype.getPage = function (pageNumber, callbackFunction, isThumb) {
3458      var _this = this;
3459
3460      pageNumber = parseInt(pageNumber, 10);
3461      var _pageNumber = pageNumber;
3462      var source = _this.contentSource;
3463      if (pageNumber <= 0 && pageNumber >= _this.pageCount) {
3464        _this.setPage(pageNumber, defaults.textureLoadFallback, callbackFunction, isThumb);
3465      }
3466      else {
3467        if (_this.contentSourceType == SOURCE_TYPE.PDF) {
3468          if (_this.getCache(pageNumber, isThumb) != null) {
3469            _this.setPage(pageNumber, _this.getCache(pageNumber, isThumb), callbackFunction, isThumb);
3470            log("Page " + pageNumber + " loaded from cache");
3471          }
3472          else {
3473            if (isThumb !== true) _this.setLoading(pageNumber, true);
3474
3475            if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2) {
3476              _pageNumber = Math.ceil((pageNumber - 1) / 2) + 1;
3477            }
3478            source.getPage(_pageNumber, isThumb).then(function (page) {
3479              renderPage(page, pageNumber, callbackFunction, isThumb);
3480            });
3481          }
3482        }
3483        else if (_this.contentSourceType == SOURCE_TYPE.IMAGE || _this.contentSourceType == SOURCE_TYPE.HTML) {
3484          if (_this.getCache(pageNumber, isThumb) != null) {
3485            _this.setPage(pageNumber, _this.getCache(pageNumber, isThumb), callbackFunction, isThumb);
3486            log("Page " + pageNumber + " loaded from cache");
3487          }
3488          else {
3489            if (isThumb !== true) _this.setLoading(pageNumber, true);
3490
3491            if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2) {
3492              _pageNumber = Math.ceil((pageNumber - 1) / 2) + 1;
3493            }
3494
3495            //if (_this.isCrossOrigin == null) {
3496            //
3497            //	_this.setCache(pageNumber, source[_pageNumber - 1], isThumb, _this.cacheIndex);
3498            //	_this.setPage(pageNumber, source[_pageNumber - 1], callbackFunction, isThumb);
3499            //
3500            //	if (callbackFunction != null) callbackFunction();
3501            //
3502            //} else {
3503            loadImage(source[_pageNumber - 1], function (src) {
3504
3505              _this.setCache(pageNumber, src, isThumb, _this.cacheIndex);
3506              _this.setPage(pageNumber, src, callbackFunction, isThumb);
3507
3508              if (callbackFunction != null) callbackFunction();
3509
3510            }, _this.isCrossOrigin);
3511            //}
3512          }
3513
3514          //_this.setPage(pageNumber, source[pageNumber - 1], callbackFunction, isThumb);
3515        }
3516      }
3517
3518      function loadImage(src, callback, isCrossOrigin) {
3519
3520        var img = new Image;
3521
3522        img.crossOrigin = "Anonymous";
3523
3524        img.onload = function () {
3525
3526          if (isCrossOrigin == true) {
3527            var canvas = document.createElement("canvas"),
3528              ctx = canvas.getContext("2d");
3529            canvas.width = img.width;
3530            canvas.height = img.height;
3531            ctx.drawImage(img, 0, 0);
3532            //localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
3533
3534            if (defaults.canvasToBlob == true) {
3535              canvas.toBlob(function (blob) {
3536                var src = DFLIP.createObjectURL(blob, "image/jpeg");
3537
3538                if (callback != null) callback(src);
3539
3540              }, "image/jpeg", 0.85)
3541
3542
3543            }
3544            else {
3545              if (callback != null) callback(canvas);
3546            }
3547          }
3548          else {
3549            if (callback != null) callback(src);
3550          }
3551          //$(this).off();
3552          img.onload = null;
3553          img = null;
3554
3555        };
3556
3557        img.src = src;
3558
3559        // make sure the load event fires for cached images too
3560        if (img.complete || img.complete === undefined) {
3561          img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
3562          img.src = src;
3563        }
3564
3565      }
3566
3567      function renderPage(page, pageNumber, callbackFunction, isThumb) {
3568
3569
3570        var forceFit = _this.options.forceFit;
3571        var isDoublePage = _this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 1 && pageNumber < _this.pageCount;
3572        var widthFix = isDoublePage && forceFit ? 2 : 1;
3573
3574        /*                var heightScale = _this.pageRatio < 1
3575         ? _this.cacheScale
3576         : _this.cacheScale / _this.pageRatio;*/
3577        //_this.cacheScale = _this.cacheIndex / Math.max(_this.normalViewport.width, _this.normalViewport.height);
3578        //scales are calculated based on perpage in case per page fitting is required.
3579        var viewport = forceFit ? page.getViewport(1) : _this.normalViewport;
3580
3581        var scale = _this.cacheIndex / Math.max(viewport.width / widthFix, viewport.height);//heightScale /_this.normalViewport.height;
3582        if (_this.webgl == true) {
3583          scale = nearestPowerOfTwo(_this.cacheIndex) / (_this.pageRatio > 1
3584              ? viewport.width / widthFix : viewport.height);
3585        }
3586
3587        var canvas = document.createElement('canvas');
3588        var start = performance.now();
3589
3590        var requestedCacheSize = _this.cacheIndex;
3591
3592        var context = canvas.getContext('2d');
3593
3594        // scale = scale * defaults.pixelRatio;
3595
3596        if (isThumb == true) {
3597          scale = _this.thumbsize / _this.normalViewport.height;
3598        }
3599
3600        canvas.height = Math.round(viewport.height * scale); //causes fluctuation in value like 22.99999 as 22
3601        canvas.width = Math.round(viewport.width / widthFix * scale);
3602
3603        if (_this.targetObject.mode == 'css' && Math.abs(_this.targetObject.zoomHeight - canvas.height) < 2) {
3604          canvas.height = _this.targetObject.zoomHeight + 0; //causes fluctuation in value like 22.99999 as 22
3605          canvas.width = _this.targetObject.zoomWidth + 0;
3606        }
3607
3608        viewport = page.getViewport(scale);
3609        log("rendering " + pageNumber + " at " + canvas.width + "x" + canvas.height);
3610
3611        if (isDoublePage) {
3612          if (isRTLMode(_this.targetObject)) {
3613            if (pageNumber % 2 == 0) {
3614              viewport.transform[4] = -canvas.width;
3615            }
3616          } else {
3617            if (pageNumber % 2 == 1) {
3618              viewport.transform[4] = -canvas.width;
3619            }
3620          }
3621        }
3622        var renderContext = {
3623          canvasContext: context,
3624          viewport: viewport
3625        };
3626
3627        page.cleanupAfterRender = true;
3628        var pageRendering = page.render(renderContext);
3629
3630        pageRendering.promise.then(
3631          function () {
3632
3633            log(performance.now() - start);
3634            start = performance.now();
3635            if (isThumb == true || (_this.options.canvasToBlob == true && _this.webgl !== true)) {
3636              canvas.toBlob(function (blob) {
3637                var src = DFLIP.createObjectURL(blob, "image/jpeg");
3638                log(performance.now() - start);
3639                _this.setCache(pageNumber, src, isThumb, requestedCacheSize);
3640                _this.setPage(pageNumber, src, callbackFunction, isThumb);
3641
3642                //canvas.width = canvas.height = 1;
3643                //context.clearRect( 0, 0, canvas.width, canvas.height );
3644
3645                //page.cleanup();
3646              }, "image/jpeg", _this.pdfRenderQuality)
3647            }
3648            else {
3649              log("Setting Page " + pageNumber);
3650              _this.setPage(pageNumber, canvas, callbackFunction, isThumb);
3651            }
3652            renderContext = null;
3653          });
3654
3655      }
3656
3657    };
3658
3659    ContentProvider.prototype.getTargetPage = function (pageNumber) {
3660
3661    };
3662
3663    ContentProvider.prototype.setLoading = function (pageNumber, show) {
3664      if (this.targetObject != null) {
3665        if (this.webgl == true) {
3666          var container = this.targetObject.container;
3667          if (show == true) {
3668            if (container.isLoading !== true) {
3669              container.addClass("df-loading");
3670              container.isLoading = true;
3671              log("Loading icon at " + pageNumber + " as " + show);
3672            }
3673          }
3674          else {
3675            if (container.isLoading != null) {
3676              container.removeClass("df-loading");
3677              container.isLoading = null;
3678              log("Loading icon at " + pageNumber + " as " + show);
3679            }
3680          }
3681        } else {
3682          var contentLayer = $(this.targetObject.getContentLayer(pageNumber));
3683          if (contentLayer != null) {
3684            if (show == true) contentLayer.addClass("df-page-loading");
3685            else contentLayer.removeClass("df-page-loading");
3686            log("Loading icon at " + pageNumber + " as " + show);
3687          }
3688        }
3689      }
3690    };
3691
3692    ContentProvider.prototype.getAnnotations = function (pageNumber) {
3693      var _this = this;
3694
3695      if (_this.options.enableAnnotation == false) return;
3696
3697      var target = _this.targetObject;
3698
3699      pageNumber = parseInt(pageNumber, 10);
3700      var source = _this.contentSource;
3701      var contentLayer = $(target.getContentLayer(pageNumber));
3702      contentLayer.empty();
3703      if (pageNumber > 0 && pageNumber <= _this.pageCount) {
3704
3705
3706        if (_this.contentSourceType == SOURCE_TYPE.PDF) {
3707          var basePage = getBasePage(pageNumber);
3708
3709          var _pageNumber = pageNumber;
3710          if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2) {
3711            _pageNumber = Math.ceil((pageNumber - 1) / 2) + 1;
3712          }
3713
3714          source.getPage(_pageNumber).then(function (page) {
3715
3716            if (contentLayer != null && contentLayer.length > 0) {
3717              _this.setupAnnotations(page, _this.viewport, contentLayer, pageNumber);
3718
3719              /*                            //it's just resizing nothing to do with annotation fetch
3720               if (target.mode != "css") {
3721
3722               var page3d = target.getPageByNumber(pageNumber);
3723               if (page3d != null) {
3724               var isLeft = (pageNumber % 2 == 0);
3725               var width = Math.abs(page3d.geometry.boundingBox.max.x - page3d.geometry.boundingBox.min.x);
3726               var height = Math.abs(page3d.geometry.boundingBox.max.z - page3d.geometry.boundingBox.min.z);
3727
3728               var div3d = isLeft ? target.parent.cssScene.divLeft : target.parent.cssScene.divRight;
3729               if (div3d != null) {
3730               div3d.rotation.y = (isLeft ? -1 : 1 ) * Math.atan2(height, width) * 0.9;
3731               div3d.position.z = height * 0.8;
3732               div3d.position.x = (isLeft ? 1 : -1 ) * height / 2.5;
3733               $(div3d.element).css({
3734               width: width,
3735               left: isLeft ? -width / 2 : width / 2
3736               });
3737
3738               }
3739               }
3740               }*/
3741            }
3742          });
3743        }
3744
3745        //render any custom liks available for page.
3746
3747        if (_this.links != null && _this.links[pageNumber] != null) {
3748          var pageLinks = _this.links[pageNumber];
3749          for (var index = 0; index < pageLinks.length; index++) {
3750            var pageLink = pageLinks[index];
3751
3752            var annotation;
3753            if (pageLink.dest && pageLink.dest.indexOf && pageLink.dest.indexOf('[html]') == 0) {
3754              annotation = document.createElement('div');
3755              annotation.innerHTML = pageLink.dest.substr(6);
3756              annotation.className = "customHtmlAnnotation";
3757            } else {
3758              annotation = document.createElement('a');
3759              annotation.setAttribute("dest", pageLink.dest);
3760              annotation.className = "customLinkAnnotation";
3761              annotation.href = "#" + pageLink.dest;
3762              annotation.onclick = function () {
3763                var dest = this.getAttribute("dest");
3764                if (dest) {
3765                  _this.linkService.customNavigateTo(dest);
3766                }
3767                return false;
3768              };
3769
3770            }
3771            annotation.style.left = pageLink.x + "%";
3772            annotation.style.top = pageLink.y + "%";
3773
3774            annotation.style.width = pageLink.w + "%";
3775            annotation.style.height = pageLink.h + "%";
3776            contentLayer[0].appendChild(annotation);
3777          }
3778        }
3779
3780        //render any html available for page.
3781
3782        if (_this.html != null && _this.html[pageNumber] != null) {
3783          var pageHTML = _this.html[pageNumber];
3784          contentLayer.append($("<div class='customHTMLAnnotation'>").html(pageHTML));
3785        }
3786      }
3787    };
3788
3789    ContentProvider.prototype.setPage = function (pageNumber, textureSrc, callbackFunction, isThumb) {
3790      var _this = this;
3791      var target = _this.targetObject;
3792      var isRTL = isRTLMode(target);
3793      var isBooklet = isBookletMode(target);
3794      if (isThumb == true) {
3795        var page = _this.targetObject.container.find("#df-thumb" + pageNumber);
3796        //log("setting:" + pageNumber + " " + bgImage(textureSrc));
3797        page.css({
3798          backgroundImage: bgImage(textureSrc)
3799        });
3800      }
3801      else {
3802
3803        if (textureSrc == defaults.textureLoadFallback) {
3804          log("Fallback on " + pageNumber);
3805        }
3806
3807        var bookPage = target.getPageByNumber(pageNumber);
3808        if (bookPage != null) {
3809          if (
3810            (pageNumber % 2 != 0 && !isRTL) ||
3811            (pageNumber % 2 != 1 && isRTL && !isBooklet) || (isBooklet && !isRTL)
3812          ) {
3813            log(pageNumber + "rendered to back of " + bookPage.color);
3814            bookPage.backImage(textureSrc, function (object, texture) {
3815              bookPage.backTextureLoaded = true;
3816              _this.setLoading(pageNumber);
3817              if (_this.requiresImageTextureScaling && texture && pageNumber != 1 && pageNumber != _this.pageCount) {
3818                texture.repeat.x = 0.5;
3819                texture.offset.x = 0.5;
3820              }
3821              if (callbackFunction != null) callbackFunction();
3822            });
3823
3824          }
3825          else {
3826            log(pageNumber + "rendered to front of " + bookPage.color);
3827            bookPage.frontImage(textureSrc, function (object, texture) {
3828              bookPage.frontTextureLoaded = true;
3829              _this.setLoading(pageNumber);
3830              if (_this.requiresImageTextureScaling && texture && pageNumber != 1 && pageNumber != _this.pageCount) {
3831                texture.repeat.x = 0.5;
3832              }
3833              if (callbackFunction != null) callbackFunction();
3834            });
3835            //}
3836          }
3837        }
3838        else {
3839          log("Invalid set request on Page " + pageNumber);
3840        }
3841      }
3842    };
3843
3844    ContentProvider.prototype.setupAnnotations = function (page, viewport, pageDiv, pageNumber) {
3845      if (pageDiv == null || $(pageDiv).length == 0) return;
3846      var _this = this;
3847      return page.getAnnotations().then(function (annotationsData) {
3848        viewport = viewport.clone({
3849          dontFlip: true
3850        });
3851
3852        if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2 && pageNumber % 2 == 1) {
3853          //viewport.transform[4]= -viewport.scale * page.view[2]/2;
3854
3855        }
3856        else if (pageNumber == 1) {
3857
3858        }
3859        if (pageDiv == null) {
3860          return;
3861        }
3862        pageDiv = $(pageDiv);
3863        if (pageDiv.find(".annotationDiv").length == 0) {
3864          pageDiv.append($("<div class='annotationDiv'>"));
3865        }
3866        var div = pageDiv.find(".annotationDiv");
3867        div.empty();
3868        if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2 && pageNumber % 2 == 1) {
3869          //viewport.transform[4]= -viewport.scale * page.view[2]/2;
3870          div.css({left: '-100%'});
3871        }
3872        else if (pageNumber == 1) {
3873          div.css({left: ''});
3874        }
3875        /*                div.css({
3876         transform:'matrix(' + _this.viewport.transform.join(',') + ')'
3877         });*/
3878
3879        PDFJS.AnnotationLayer.render({
3880          annotations: annotationsData,
3881          div: div[0],
3882          page: page,
3883          viewport: viewport,
3884          linkService: _this.linkService
3885        });
3886
3887        if (_this.options.annotationClass && _this.options.annotationClass !== "") {
3888          div.find(" > section").addClass(_this.options.annotationClass);
3889        }
3890        // div.find(" > section").addClass("someclass");
3891        /*				page.getTextContent().then(function(textContent){
3892         console.log( textContent );
3893         var textLayer = new DFLIP.TextLayerBuilder({
3894         textLayerDiv :div[0],
3895         pageIndex : null,
3896         viewport : viewport.clone({
3897         dontFlip: false
3898         })
3899         });
3900
3901         textLayer.setTextContent(textContent);
3902         textLayer.render();
3903         });*/
3904
3905      });
3906
3907    };
3908
3909    return ContentProvider;
3910  })({});
3911
3912  var PageCSS = (function () {
3913    function PageCSS(parameters) {
3914      this.angles = parameters.angles || [0, 0, 0, 0, 0, 0];
3915      this.stiffness = parameters.angles || 0.1;
3916      this.segments = parameters.segments || 1;
3917      this.canvasMode = parameters.contentSourceType !== SOURCE_TYPE.IMAGE && parameters.canvasToBlob == false;
3918      this.initDOM();
3919    }
3920
3921    function createInternals(pageSide) {
3922      var contentLayer = pageSide.contentLayer = $(html.div, {
3923        class: "df-page-content"
3924      });
3925      pageSide.append(contentLayer);
3926    }
3927
3928    PageCSS.prototype = {
3929      initDOM: function () {
3930        var element = this.element = $(html.div, {
3931          class: "df-book-page"
3932        });
3933        var wrapper = this.wrapper = $(html.div, {
3934          class: "df-page-wrapper"
3935        });
3936        var front = this.front = $(html.div, {
3937          class: "df-page-front"
3938        });
3939        var back = this.back = $(html.div, {
3940          class: "df-page-back"
3941        });
3942        var foldInnerShadow = this.foldInnerShadow = $(html.div, {
3943          class: "df-page-fold-inner-shadow"
3944        });
3945        var foldOuterShadow = this.foldOuterShadow = $(html.div, {
3946          class: "df-page-fold-outer-shadow"
3947        });
3948        this.frontIMG = new Image();
3949        this.backIMG = new Image();
3950
3951        createInternals(front, this.segments, true);
3952        createInternals(back, this.segments, false);
3953        element.append(wrapper).append(foldOuterShadow);
3954        wrapper.append(front).append(back).append(foldInnerShadow);
3955
3956      },
3957
3958      updatePoint: function (point) {
3959
3960        if (point == null) return;
3961
3962        //detect the current page
3963        var page = this.parent.dragPage != null ? this.parent.dragPage
3964          : point.page != null ? point.page : this;
3965
3966        //get the pageWidth and pageHeight
3967        var pageWidth = page.element.width(),
3968          pageHeight = page.element.height();
3969
3970        //the corner where the drag started
3971        var corner = this.parent.corner != null ? this.parent.corner : point.corner,
3972          corners = DFLIP.CORNERS;
3973
3974        var
3975          isRight = page.side == drag.right,
3976          isBottom = (corner == corners.BL) || (corner == corners.BR);
3977
3978        point.rx = (isRight == true)
3979          ? pageWidth * 2 - point.x
3980          : point.x;
3981
3982        point.ry = (isBottom == true)
3983          ? pageHeight - point.y
3984          : point.y;
3985
3986        var radAngle = Math.atan2(point.ry, point.rx);
3987
3988        radAngle = Math.PI / 2 - limitAt(radAngle, 0, toRad(90));
3989
3990        var correctionX = isRight
3991            ? point.x / 2
3992            : pageWidth - point.x / 2,
3993
3994          correctionY = point.ry / 2,
3995
3996          refLength = Math.max(0,
3997            Math.sin(radAngle - Math.atan2(correctionY, correctionX)) * distOrigin(correctionX,
3998              correctionY)),
3999
4000          foldLength = 0.5 * distOrigin(point.rx, point.ry);
4001
4002        var x = Math.round(pageWidth - refLength * Math.sin(radAngle)),
4003          y = Math.round(refLength * Math.cos(radAngle)),
4004
4005          angle = toDeg(radAngle);
4006
4007        var angle1 = isBottom
4008          ? isRight ? 180 + ( 90 - angle) : 180 + angle
4009          : isRight ? angle : 90 - angle;
4010
4011        var angle2 = isBottom
4012            ? isRight ? 180 + ( 90 - angle) : angle
4013            : isRight ? angle + 180 : angle1,
4014          angleS = isBottom
4015            ? isRight ? 90 - angle : angle + 90
4016            : isRight ? angle1 - 90 : angle1 + 180,
4017          x1 = isRight ? pageWidth - x : x,
4018          y1 = isBottom ? pageHeight + y : -y,
4019          x2 = isRight ? -x : x - pageWidth,
4020          y2 = isBottom ? -pageHeight - y : y;
4021
4022        var opacity = limitAt(point.distance * 0.5 / pageWidth, 0, 0.5);
4023        var foldOpacity = limitAt((pageWidth * 2 - point.rx) * 0.5 / pageWidth, 0.05, 0.3);
4024
4025        page.element.addClass("df-folding");
4026
4027        var front = isRight ? page.back : page.front;
4028        var back = isRight ? page.front : page.back;
4029        var outerShadow = page.foldOuterShadow;
4030        var innerShadow = page.foldInnerShadow;
4031        page.wrapper.css({
4032          transform: translateStr(x1, y1) + rotateStr(angle1)
4033        });
4034
4035        front.css({
4036          transform: rotateStr(-angle1) + translateStr(-x1, -y1)
4037        });
4038
4039        back.css({
4040          transform: rotateStr(angle2) + translateStr(x2, y2),
4041          boxShadow: "rgba(0, 0, 0, " + opacity + ") 0px 0px 20px"
4042        });
4043
4044        innerShadow.css({
4045          transform: rotateStr(angle2) + translateStr(x2, y2),
4046          opacity: foldOpacity / 2,
4047          backgroundImage: prefix.css + "linear-gradient( " + angleS + "deg, rgba(0, 0, 0, 0.25) , rgb(0, 0, 0) " + foldLength * 0.7 + "px, rgb(255, 255, 255) " + foldLength + "px)"
4048        });
4049
4050        outerShadow.css({
4051          //transform: rotateStr(angle - (isRight ? -180 : 0)) + translateStr(isRight ? -x : x - pageWidth, y),
4052          opacity: foldOpacity / 2,
4053          left: isRight ? "auto" : 0,
4054          right: isRight ? 0 : "auto",
4055          backgroundImage: prefix.css + "linear-gradient( " + (-angleS + 180) + "deg, rgba(0, 0, 0,0) " + foldLength / 3 + "px, rgb(0, 0, 0) " + foldLength + "px)"
4056        });
4057
4058        //$("body > p").html(JSON.stringify({
4059        //	x: Math.round(point.rx),
4060        //	y: Math.round(point.ry),
4061        //	a: Math.round(angle),
4062        //	a1: Math.round(angle1),
4063        //	cx: Math.round(correctionX),
4064        //	cy: Math.round(correctionY),
4065        //	dx: Math.round(x),
4066        //	dy: Math.round(y),
4067        //	ref: Math.round(refLength),
4068        //	dis: Math.round(distOrigin(point.x, point.y))
4069        //}));
4070      },
4071
4072      updateAngle: function (angle, isRight) {
4073
4074        var width = this.element.width() * 5;
4075
4076        //if(prefix.dom!=='MS') {
4077        this.wrapper.css({
4078          perspective: width,
4079          perspectiveOrigin: isRight == true ? "0% 50%" : "100% 50%"
4080        });
4081        //}
4082
4083        this.front.css({
4084          display: (isRight == true ? (angle <= -90 ? 'block' : 'none') : (angle < 90 ? 'block' : 'none')),
4085          transform: (prefix.dom !== 'MfS' ? "" : "perspective(" + width + "px) ")
4086          + (isRight == true ? "translateX(-100%) " : "" )
4087          + "rotateY(" + ((isRight == true ? 180 : 0 ) + angle) + "deg)"
4088        });
4089        this.back.css({
4090          display: (isRight == true ? (angle > -90 ? 'block' : 'none') : (angle >= 90 ? 'block' : 'none')),
4091          transform: (prefix.dom !== 'MSd' ? "" : "perspective(" + width + "px) ")
4092          + (isRight == false ? "translateX(100%) " : "" )
4093          + "rotateY(" + ((isRight == false ? -180 : 0 ) + angle) + "deg)"
4094        });
4095        //$("body > p").html(JSON.stringify({
4096        //	a: Math.round(angle)
4097        //}));
4098        return;
4099        /*if(this.angles[1] != null) {
4100         var segsb = this.back.segments;
4101         var segsf = this.front.segments;
4102         var width = this.element.width();
4103         var angle1 = this.angles[1];
4104         var angle2 = this.angles[4]/segsb.length;
4105         var step = Math.floor(width/segsb.length);
4106
4107         for (var count = 0; count < segsb.length; count++) {
4108         var segb = segsb[count];
4109         var segf = segsf[count];
4110         segb.css({
4111         transform: "rotate3d(0,1,0," + (count == 0 ? angle1 : angle2) + "deg)",
4112         //backgroundPositionX: -step * count,
4113         //backgroundSize: width + "px 100%"
4114         });
4115
4116         segf.css({
4117         transform: "rotate3d(0,1,0," + (count == 0 ? 180 + angle1 : angle2) + "deg)",
4118         //backgroundPositionX: step * (count + 1),
4119         //backgroundSize: width + "px 100%"
4120         });
4121         }
4122         }
4123         else{
4124         this.element.find(".bg-segment").css({
4125         transform: "translate3d(0px,0,0) rotate3d(0,1,0,0deg)"
4126         });
4127         }*/
4128
4129      },
4130
4131      tween: function (point) {
4132        var page = this;
4133        if (page == null || page.parent == null) return;
4134        var isBooklet = isBookletMode(page.parent);
4135        var isRight = page.side == drag.right;
4136        var isRTL = page.parent.direction == DFLIP.DIRECTION.RTL;
4137        var isBottom = page.parent.corner == DFLIP.CORNERS.BL || page.parent.corner == DFLIP.CORNERS.BR;
4138        var isMagnetic = page.magnetic == true;
4139        var travelY = isBottom ? page.parent.height : 0;
4140
4141        var init, first, mid, angle = 0;
4142
4143        var end = page.end = (page && page.animateToReset == true)
4144          ? {x: isRight ? page.parent.fullWidth : 0, y: travelY}
4145          : {x: isRight ? 0 : page.parent.fullWidth, y: travelY};
4146
4147        page.ease = page.isHard ? TWEEN.Easing.Quadratic.InOut : TWEEN.Easing.Linear.None;
4148
4149        var tempDuration = page.parent.duration;
4150
4151        if (page.isHard == true) {
4152
4153          if (point != null) {
4154            angle = angleByDistance(point.distance, point.fullWidth);
4155          }
4156
4157          init = page.init = {angle: angle * (isRight ? -1 : 1)};
4158          end = page.end = (page && page.animateToReset == true)
4159            ? {angle: isRight ? 0 : -0}
4160            : {angle: isRight ? -180 : 180};
4161
4162        } else {
4163
4164          if (point == null) {
4165
4166            init = page.init = (page && page.animateToReset == true)
4167              ? {x: isRight ? 0 : page.parent.fullWidth, y: 0}
4168              : {x: isRight ? page.parent.fullWidth : 0, y: 0};
4169
4170            first = page.first = {
4171              x: (isRight ? 3 : 1 ) * page.parent.fullWidth / 4,
4172              y: 0
4173            };
4174
4175            mid = page.mid = {x: (isRight ? 1 : 3 ) * page.parent.fullWidth / 4, y: 0};
4176
4177          }
4178          else {
4179
4180            init = page.init = {x: point.x, y: point.y, opacity: 1};
4181            first = page.first = {x: point.x * 3 / 4, y: point.y * 3 / 4, opacity: 1};
4182            mid = page.mid = {x: point.x / 4, y: point.y / 4, opacity: 1};
4183
4184            tempDuration = page.parent.duration * distPoints(init.x, init.y, end.x, end.y) / page.parent.fullWidth;
4185
4186            tempDuration = limitAt(tempDuration, page.parent.duration / 3, page.parent.duration);
4187
4188          }
4189        }
4190        init.index = 0;
4191        // first.index = 0;
4192        // mid.index = 0;
4193        end.index = 1;
4194        page.isFlipping = true;
4195
4196        var update = function (tween) {
4197
4198          if (page.isHard == true) {
4199            page.updateAngle(tween.angle, isRight);
4200            page.angle = tween.angle;
4201          } else {
4202            page.updatePoint({
4203              x: tween.x,
4204              y: tween.y
4205            });
4206            page.x = tween.x;
4207            page.y = tween.y;
4208          }
4209          if (isBooklet && !isMagnetic)
4210            page.element[0].style.opacity = (isRight && !isRTL) || (!isRight && isRTL)
4211              ? tween.index > 0.5 ? 2 * (1 - tween.index) : 1
4212              : tween.index < 0.5 ? 2 * tween.index : 1;
4213
4214        };
4215
4216        if (isBooklet && ((!isRight && !isRTL) || (isRight && isRTL)))
4217          page.element[0].style.opacity = 0;
4218
4219        var completeTween = page.completeTween = page.completeTween || function (skipRefresh) {
4220            page.isFlipping = false;
4221
4222            if (page.isHard == true) {
4223
4224              page.updateAngle(page.end.angle);
4225              page.back.css({display: "block"});
4226              page.front.css({display: "block"});
4227
4228            }
4229            else {
4230
4231              page.updatePoint({
4232                x: page.end.x,
4233                y: page.end.y
4234              });
4235
4236            }
4237
4238            page.element[0].style.opacity = 1;
4239
4240            if (page.animateToReset !== true) {
4241              page.side = page.side == drag.right ? drag.left : drag.right;
4242            }
4243            else
4244              page.animateToReset = null;
4245
4246            page.currentTween = null;
4247            page.pendingPoint = null;
4248            page.magnetic = false;
4249            page.parent.dragPage = null;
4250            page.parent.corner = DFLIP.CORNERS.NONE;
4251
4252            if (skipRefresh != true)
4253              page.parent.refresh();
4254
4255
4256            //log("Tween Completed");
4257          };
4258        if (page.isHard == true) {
4259          page.currentTween = new TWEEN.Tween(init).delay(0)
4260            .to(end, page.parent.duration)
4261            .onUpdate(function () {
4262              update(this);
4263            }).easing(page.ease)
4264            .onComplete(page.completeTween)
4265            .start();
4266        } else {
4267          if (point == null) {
4268            page.currentTween = new TWEEN.Tween(init).delay(0)
4269              .to(end, page.parent.duration)
4270              .onUpdate(function () {
4271                update(this);
4272              }).easing(TWEEN.Easing.Sinusoidal.Out)
4273              .onComplete(page.completeTween)
4274              .start();
4275          }
4276          else {
4277            page.currentTween = new TWEEN.Tween(init).delay(0)
4278              .to(end, tempDuration)
4279              .onUpdate(function () {
4280                update(this);
4281              }).easing(TWEEN.Easing.Sinusoidal.Out)
4282              .onComplete(page.completeTween);
4283            page.currentTween.start();
4284          }
4285        }
4286        //page.currentTween.parent= page;
4287
4288      },
4289      frontImage: function (texture, callback) {
4290        var _this = this;
4291
4292        function completed() {
4293          _this.front.css({
4294            backgroundImage: bgImage(texture)
4295          });
4296          if (callback != null) callback();
4297        }
4298
4299        if (_this.canvasMode == true) {
4300          _this.front.find(">canvas").remove();
4301          if (texture !== defaults.textureLoadFallback) {
4302            _this.front.append($(texture));
4303          }
4304          if (callback != null) callback();
4305        }
4306        else {
4307          if (texture == defaults.textureLoadFallback) {
4308            completed();
4309          } else {
4310            _this.frontIMG.onload = completed;
4311            _this.frontIMG.src = texture;
4312          }
4313        }
4314      },
4315      backImage: function (texture, callback) {
4316        var _this = this;
4317
4318        function completed() {
4319          _this.back.css({
4320            backgroundImage: bgImage(texture)
4321          });
4322          if (callback != null) callback();
4323        }
4324
4325        if (_this.canvasMode == true) {
4326          _this.back.find(">canvas").remove();
4327          if (texture !== defaults.textureLoadFallback) {
4328            _this.back.append($(texture));
4329          }
4330          if (callback != null) callback();
4331        }
4332        else {
4333          if (texture == defaults.textureLoadFallback) {
4334            completed();
4335          } else {
4336            _this.backIMG.onload = completed;
4337            _this.backIMG.src = texture;
4338          }
4339        }
4340
4341      },
4342      updateCSS: function (css) {
4343        this.element.css(css);
4344      },
4345      resetCSS: function () {
4346        this.wrapper.css({
4347          transform: ''
4348        });
4349
4350        this.front.css({
4351          transform: '',
4352          boxShadow: ''
4353        });
4354
4355        this.back.css({
4356          transform: '',
4357          boxShadow: ''
4358        });
4359      },
4360      clearTween: function (skipRefresh) {
4361        this.currentTween.stop();
4362        this.completeTween(skipRefresh == true);
4363        this.resetCSS();
4364      }
4365
4366    };
4367
4368    return PageCSS;
4369  })();
4370
4371  var BookCSS = (function (_super) {
4372    __extends(BookCSS, _super);
4373
4374    function updateFolding(dragPage) {
4375      dragPage.parent.container.find(".df-folding").removeClass("df-folding");
4376      dragPage.element.addClass("df-folding");
4377    }
4378
4379    function hasFlipping(book) {
4380      var hasFlipping = false;
4381      for (var pageCount = 0; pageCount < book.pages.length; pageCount++) {
4382        var page = book.pages[pageCount];
4383        if (page.isFlipping == true) {
4384          hasFlipping = true;
4385          break;
4386        }
4387      }
4388      return hasFlipping;
4389    }
4390
4391    function BookCSS(parameters, container) {
4392      //parameters = extendOptions(parameters);
4393
4394      //_super.call(this, parameters, stage);
4395      var _this = this;
4396      _this.type = "BookCSS";
4397      _this.images = parameters.images || [];
4398      _this.pageCount = parameters.pageCount || 2;
4399      //_this.segments = parameters.segments = 5;
4400
4401      _this.foldSense = 50;
4402
4403      _this.stackCount = 4;
4404      _this.mode = "css";
4405      _this.pages = [];
4406      _this.duration = parameters.duration;
4407
4408      _this.container = $(container);
4409      _this.options = parameters;
4410      _this.drag = drag.none;
4411      _this.pageCount = (_this.pageCount == 1 ? _this.pageCount : Math.ceil(_this.pageCount / 2) * 2);
4412      _this.pageMode = parameters.pageMode || ((isMobile || _this.pageCount <= 2) ? DFLIP.PAGE_MODE.SINGLE
4413          : DFLIP.PAGE_MODE.DOUBLE);
4414
4415      _this.singlePageMode = parameters.singlePageMode || (isMobile ? DFLIP.SINGLE_PAGE_MODE.BOOKLET
4416          : DFLIP.SINGLE_PAGE_MODE.ZOOM);
4417
4418      _this.swipe_threshold = isMobile ? 15 : 50;
4419
4420      _this.direction = parameters.direction || DFLIP.DIRECTION.LTR;
4421
4422      _this.startPage = 1;
4423      _this.endPage = _this.pageCount;
4424
4425      _this._activePage = parameters.openPage || _this.startPage;
4426
4427      _this.hardConfig = parameters.hard;
4428      //var foldTime = null;
4429      has3d = 'WebKitCSSMatrix' in window || (document.body && 'MozPerspective' in document.body.style);
4430
4431      _this.animateF = function () {
4432        if (TWEEN.getAll().length > 0)
4433          TWEEN.update();
4434        else
4435          clearInterval(_this.animate);
4436      };
4437
4438      _this.init(parameters);
4439
4440      _this.skipDrag = false;
4441
4442      function checkPage(point) {
4443        if (_this.dragPage != point.page && point.page.visible == true) {
4444          _this.dragPage.clearTween(true);
4445          _this.dragPage = point.page;
4446          _this.corner = point.corner;
4447          _this.dragPage.pendingPoint = point;
4448        }
4449      }
4450
4451      var mouseMove = function (event) {
4452          //event.preventDefault();
4453          var point = _this.eventToPoint(event);
4454          if (event.touches != null && event.touches.length == 2 && _this.startTouches != null) {
4455            //return;
4456            // _this.startTouches = event.touches;
4457            _this.zoomDirty = true;
4458            var touchCenter = utils.getVectorAvg(utils.getTouches(event, _this.container.offset())),
4459              newScale = utils.calculateScale(_this.startTouches, utils.getTouches(event)),
4460              scale = newScale / _this.lastScale;
4461
4462            var zoom = _this.contentProvider.zoomScale,
4463              x = touchCenter.x,
4464              y = touchCenter.y;
4465
4466            _this.stage.css({
4467              transform: "translate3d(" + _this.left + "px," + _this.top + "px,0) scale3d(" + newScale + "," + newScale + ",1)"
4468            });
4469
4470            _this.lastScale = newScale;
4471
4472            _this.lastZoomCenter = touchCenter;
4473            event.preventDefault();
4474          }
4475
4476          if ((event.touches != null && event.touches.length > 1) || _this.startPoint == null || _this.startTouches != null) return;
4477
4478          var targetPage = _this.dragPage || point.page;
4479
4480          if (_this.contentProvider.zoomScale !== 1) {
4481            if ((event.touches != null || _this.isPanning == true)) {
4482              _this.pan(point);
4483              event.preventDefault();
4484            }
4485          }
4486          else {
4487            if (_this.skipDrag !== true) {
4488              //if (_this.cancelMouse != true) {
4489
4490              var distance = point.distance;//_this.getDistance(event);//point.x < _this.pageWidth ? point.x : _this.fullWidth - point.x;
4491
4492              if (!hasFlipping(_this)) {
4493
4494
4495                if ((_this.dragPage != null ) || (point.isInside == true)) {
4496                  //$(".quick-hint").html(distance);
4497                  if (_this.dragPage != null) {
4498                    log("set mouse down move");
4499                  }
4500                  else {
4501                    point.y = limitAt(point.y, 1, _this.height - 1);
4502                    point.x = limitAt(point.x, 1, point.fullWidth - 1);
4503                  }
4504
4505                  var corner = _this.corner || point.corner;
4506                  if (targetPage.isHard) {
4507                    var isRight = corner == DFLIP.CORNERS.BR || corner == DFLIP.CORNERS.TR;
4508
4509                    var angle = angleByDistance(point.distance, point.fullWidth);
4510
4511                    targetPage.updateAngle(angle * (isRight ? -1 : 1), isRight);
4512
4513                  }
4514                  else {
4515                    targetPage.updatePoint(point, _this);
4516                  }
4517
4518                  targetPage.magnetic = true;
4519                  targetPage.magneticCorner = point.corner;
4520                  event.preventDefault();
4521                  //point.page.updatePoint(point);
4522                }
4523
4524                if (_this.dragPage == null && targetPage != null && point.isInside == false && targetPage.magnetic == true) {
4525                  targetPage.pendingPoint = point;
4526                  targetPage.animateToReset = true;
4527                  _this.corner = targetPage.magneticCorner;
4528                  _this.animatePage(targetPage);
4529                  targetPage.pendingPoint = null;
4530                  targetPage.magnetic = false;
4531                  targetPage.magneticCorner = null;
4532                }
4533
4534                if (_this.isPanning == true && _this.dragPage == null && _this.contentProvider.zoomScale == 1) {
4535                  //check if swipe has happened
4536                  //console.log(_this.lastPos - point.x,performance.now()-_this.lastTime);
4537                  var swipe_dist = point.x - _this.lastPos,
4538                    swipe_time = performance.now() - _this.lastTime;
4539                  if (Math.abs(swipe_dist) > _this.swipe_threshold) {
4540                    //swipe has triggered
4541                    //_this.dragPage.pendingPoint = point;
4542                    if (swipe_dist < 0) {
4543                      _this.next();
4544                    }
4545                    else {
4546                      _this.prev();
4547                    }
4548                    _this.drag = drag.none;
4549                    _this.isPanning = false;
4550                    event.preventDefault();
4551                  }
4552                  _this.lastPos = point.x;
4553                  _this.lastTime = performance.now();
4554
4555                }
4556              }
4557            }
4558          }
4559
4560        },
4561        mouseUp = function (event) {
4562          if (event.touches != null && event.touches.length == 0) {
4563            var zoom = _this.contentProvider.zoomScale;
4564            if (_this.zoomDirty == true) {
4565              _this.previewObject.contentProvider.zoomScale =
4566                utils.limitAt(_this.previewObject.contentProvider.zoomScale * _this.lastScale,
4567                  1, _this.previewObject.contentProvider.maxZoom);
4568              _this.previewObject.zoomValue = _this.previewObject.contentProvider.zoomScale * 1;
4569              //_this.previewObject.zoom(_this.lastScale < 1 ? -1 : 1);
4570              //console.log(_this.previewObject.contentProvider.zoomScale * _this.lastScale,_this.previewObject.contentProvider.maxZoom)
4571              //_this.previewObject.pendingZoom = true;
4572              _this.previewObject.resize();
4573              _this.zoomDirty = false;
4574            }
4575            _this.wrapper.css({
4576              transform: ""
4577            });
4578            _this.lastScale = null;
4579            _this.startTouches = null;
4580          }
4581          _this.isPanning = false;
4582          if (event.touches != null && event.touches.length > 1) return;
4583          if (_this.skipDrag !== true) {
4584            //completeFold();
4585            var point = _this.eventToPoint(event);
4586            if (_this.dragPage) {
4587              event.preventDefault();
4588
4589              /*							if (_this.animate != null) {
4590               clearInterval(_this.animate);
4591               }
4592
4593               _this.animate = setInterval(_this.animateF, 30);
4594
4595               _this.dragPage.tween(point);*/
4596
4597              //use something like pending point
4598              // detect the next page anbd call the updatepage
4599              //will be better
4600
4601              _this.dragPage.pendingPoint = point;
4602              if (point.x == _this.startPoint.x && point.y == _this.startPoint.y && point.isInside == true) {
4603
4604                if (_this.corner == DFLIP.CORNERS.BR || _this.corner == DFLIP.CORNERS.TR) {
4605                  checkPage(point);
4606                  if (_this.dragPage.isFlipping !== true)
4607                    _this.next();
4608                }
4609                else if (_this.corner == DFLIP.CORNERS.BL || _this.corner == DFLIP.CORNERS.TL) {
4610                  checkPage(point);
4611                  if (_this.dragPage.isFlipping !== true)
4612                    _this.prev();
4613                }
4614              }
4615              else if (_this.dragPage.isFlipping !== true) {
4616                if (point.distance > point.fullWidth / 2) {
4617                  if (point.x > point.fullWidth / 2)
4618                    _this.prev();
4619                  else
4620                    _this.next();
4621                }
4622                else {
4623                  _this.dragPage.animateToReset = true;
4624                  _this.animatePage(_this.dragPage);
4625                }
4626              }
4627              //_this.dragPage.animateToReset = true;
4628              if (_this.dragPage) {
4629                _this.dragPage.pendingPoint = null;
4630                _this.dragPage.magnetic = false;
4631              }
4632            } else {
4633              //detect click
4634              /*if(_this.wrapper[0].contains(event.target) && _this.contentProvider.zoomScale == 1 && point.x == _this.startPoint.x && point.y == _this.startPoint.y && point.isInsidePage && _this.startPoint.page == point.page && !point.page.isFlipping && event.srcElement.nodeName!=="A"){
4635               if(_this.startPoint.page.side ==0){
4636               _this.prev();
4637               _this.startPoint.page = null;
4638               }
4639               else{
4640               _this.next();
4641               _this.startPoint.page = null;
4642               }
4643               }*/
4644            }
4645
4646            _this.drag = drag.none;
4647
4648            //_this.dragPage = null;
4649            //_this.corner = DFLIP.CORNERS.NONE;
4650            //log("set mouse up");
4651          }
4652
4653        },
4654        mouseClick = function (event) {
4655
4656          var point = _this.eventToPoint(event);
4657
4658          var element = event.srcElement || event.originalTarget;
4659
4660          if (_this.dragPage && _this.dragPage.magnetic) return;
4661
4662          if (_this.wrapper[0].contains(event.target) && _this.contentProvider.zoomScale == 1 && point.x == _this.startPoint.x && point.y == _this.startPoint.y && point.isInsidePage && _this.startPoint.page == point.page && !point.page.isFlipping && element.nodeName !== "A") {
4663
4664            if (_this.startPoint.page.side == 0) {
4665              _this.corner = DFLIP.CORNERS.TL;
4666              _this.prev();
4667              _this.startPoint.page = null;
4668            }
4669            else {
4670              _this.corner = DFLIP.CORNERS.TR;
4671              _this.next();
4672              _this.startPoint.page = null;
4673            }
4674            _this.isPanning = false;
4675          }
4676
4677        },
4678        mouseDown = function (event) {
4679          if (event.touches != null && event.touches.length == 2 && _this.startTouches == null) {
4680            _this.startTouches = utils.getTouches(event);
4681            _this.lastScale = 1;
4682          }
4683          if ((event.touches != null && event.touches.length > 1) || (event.touches == null && event.button !== 0)) return;
4684          var point = _this.eventToPoint(event);
4685          _this.startPoint = point;
4686          _this.left = _this.left || 0;
4687          _this.top = _this.top || 0;
4688          _this.isPanning = true;
4689          _this.lastPos = point.x;
4690          _this.lastTime = performance.now();
4691
4692          if (_this.skipDrag !== true) {
4693
4694            if (point.isInside == true && !hasFlipping(_this)) {
4695              _this.startPoint = point;
4696              _this.drag = point.drag;
4697              _this.dragPage = point.page;
4698
4699              _this.corner = point.corner;
4700
4701              log(_this.corner);
4702
4703              updateFolding(_this.dragPage);
4704              //log("set mouse down");
4705              if (point.page.isHard) {
4706
4707              }
4708              else {
4709                point.page.updatePoint(point, _this);
4710              }
4711              if (point.page.name == "0") {
4712                _this.shadow.css({
4713                  width: '50%',
4714                  left: _this.direction == DFLIP.DIRECTION.RTL ? 0 : '50%',
4715                  transitionDelay: ''
4716                });
4717              } else if (point.page.name == Math.ceil(_this.pageCount / 2) - 1) {
4718                _this.shadow.css({
4719                  width: '50%',
4720                  left: _this.direction == DFLIP.DIRECTION.RTL ? '50%' : 0,
4721                  transitionDelay: ''
4722                });
4723              }
4724            }
4725          }
4726        },
4727        onMouseWheel = function (event) {
4728          var delta = 0;
4729
4730          //var zoom = _this.contentProvider.zoomScale > 1;
4731          if (event.wheelDelta != null) { // WebKit / Opera / Explorer 9
4732
4733            delta = event.wheelDelta / 120;
4734
4735          } else if (event.detail != null) { // Firefox
4736
4737            delta = -event.detail / 3;
4738
4739          }
4740
4741          var zoom1 = _this.contentProvider.zoomScale,
4742            maxZoom = _this.contentProvider.maxZoom;
4743
4744          if (delta) {
4745
4746            if ((delta > 0 && zoom1 < maxZoom) || (delta < 0 && zoom1 > 1)) {
4747
4748              event.stopPropagation();
4749              event.preventDefault();
4750
4751              var pointOld = _this.eventToPoint(event);
4752              var pointNew = _this.eventToPoint(event);
4753
4754              var origin = {x: _this.container.width() / 2, y: -23 + _this.container.height() / 2};
4755
4756              _this.previewObject.zoom(delta);
4757
4758              var zoom2 = _this.contentProvider.zoomScale;
4759              if (zoom1 !== zoom2) {
4760                var dz = (zoom2 / zoom1);
4761
4762                //fix zoom to previous center
4763                if (zoom2 == 1) {
4764                  _this.left = 0;
4765                  _this.top = 0;
4766                } else {
4767                  _this.left *= dz;
4768                  _this.top *= dz;
4769                }
4770
4771                //fix zoom to previous pointer
4772                var dx = (pointOld.raw.x - origin.x ) * dz,
4773                  dy = (pointOld.raw.y - origin.y ) * dz;
4774
4775                pointNew.raw.x = origin.x + dx;// origin.x + dz * (point.x-origin.x);
4776                pointNew.raw.y = origin.y + dy;// origin.y + dz * (point.y-origin.y);
4777
4778                _this.startPoint = pointNew;
4779                //console.log(pointOld.raw.x - origin.x,dx,pointOld.raw.y - origin.y,dy,pointNew.raw,_this.startPoint.raw);
4780                _this.pan(pointOld);
4781
4782                var targetPage = _this.dragPage || pointOld.page;
4783                if (_this.dragPage == null && targetPage != null && pointOld.isInside == true && targetPage.magnetic == true) {
4784                  targetPage.pendingPoint = pointOld;
4785                  targetPage.animateToReset = true;
4786                  _this.corner = targetPage.magneticCorner;
4787                  _this.animatePage(targetPage);
4788                  targetPage.pendingPoint = null;
4789                  targetPage.magnetic = false;
4790                  targetPage.magneticCorner = null;
4791                }
4792              }
4793
4794            }
4795          }
4796
4797        };
4798
4799      var containerDom = _this.container[0];
4800      var stageDom = _this.stage[0];
4801      if (containerDom) {
4802        stageDom.addEventListener("mousemove", mouseMove, false);
4803        stageDom.addEventListener("touchmove", mouseMove, false);
4804
4805        stageDom.addEventListener("mousedown", mouseDown, false);
4806        stageDom.addEventListener("click", mouseClick, false);
4807        stageDom.addEventListener("mouseup", mouseUp, false);
4808        stageDom.addEventListener("touchend", mouseUp, false);
4809        stageDom.addEventListener("touchstart", mouseDown, false);
4810
4811        if (_this.options.scrollWheel == true) {
4812          //lets not trigger scroll when in outline or another
4813          stageDom.addEventListener('mousewheel', onMouseWheel, false);
4814          stageDom.addEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
4815        }
4816      }
4817
4818      this.dispose = function () {
4819        stageDom.removeEventListener("mousemove", mouseMove, false);
4820        stageDom.removeEventListener("touchmove", mouseMove, false);
4821
4822        stageDom.removeEventListener("mousedown", mouseDown, false);
4823        stageDom.removeEventListener("click", mouseClick, false);
4824        stageDom.removeEventListener("mouseup", mouseUp, false);
4825        stageDom.removeEventListener("touchend", mouseUp, false);
4826        stageDom.removeEventListener("touchstart", mouseDown, false);
4827
4828        if (_this.options.scrollWheel == true) {
4829          stageDom.removeEventListener('mousewheel', onMouseWheel, false);
4830          stageDom.removeEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
4831        }
4832        _this.updatePageCallback = null;
4833        _this.flipCallback = null;
4834        _this.animateF = null;
4835        _this.stage.remove();
4836
4837      };
4838    }
4839
4840    BookCSS.prototype = {
4841      add: function (object) {
4842        if (object instanceof PageCSS)
4843          this.container.append($(object.element));
4844        else
4845          this.container.append($(object));
4846      },
4847      pan: function (point) {
4848        var origin = this.startPoint;
4849        var scale = this.contentProvider.zoomScale;
4850
4851        var left = (this.left + (point.raw.x - origin.raw.x)),
4852          top = (this.top + (point.raw.y - origin.raw.y));
4853
4854        //round removes blur due to decimal value in transform.
4855        this.left = Math.round(limitAt(left, -this.shiftWidth, this.shiftWidth));
4856        this.top = Math.round(limitAt(top, -this.shiftHeight, this.shiftHeight));
4857
4858        if (scale == 1) {
4859          this.left = 0;
4860          this.top = 0;
4861        }
4862
4863        this.startPoint = point;
4864
4865        //console.log(point, origin);
4866        this.stage.css({
4867          transform: "translate3d(" + this.left + "px," + this.top + "px,0)"
4868        });
4869
4870        //var a = book.wrapper.height();
4871      },
4872      getPageByNumber: function (pageNumber) {
4873        var relativePageNumber = isBookletMode(this) ? (isRTLMode(this) ? pageNumber + 1 : pageNumber)
4874          : Math.floor((pageNumber - 1) / 2);
4875        var page;
4876        for (var count = 0; count < this.pages.length; count++) {
4877          if (relativePageNumber == parseInt(this.pages[count].name, 10))
4878            page = this.pages[count];
4879        }
4880        return page;
4881      },
4882      getPageSide: function (pageNumber) {
4883
4884        var isRTL = this.direction == DFLIP.DIRECTION.RTL;
4885
4886        var page = this.getPageByNumber(pageNumber);
4887        if (page == null) return;
4888        if (isBookletMode(this)) return isRTL ? page.front : page.back;
4889        if (pageNumber % 2 == 0)
4890          return isRTL ? page.back : page.front;
4891        else
4892          return isRTL ? page.front : page.back;
4893      },
4894      getContentLayer: function (pageNumber) {
4895        var pageSide = this.getPageSide(pageNumber);
4896        return pageSide == null ? null : pageSide.contentLayer;
4897      }
4898    };
4899
4900    BookCSS.prototype.init = function (parameters) {
4901      var _this = this;
4902      _this.stage = $(html.div, {
4903        class: "df-book-stage"
4904      });
4905      _this.wrapper = $(html.div, {
4906        class: "df-book-wrapper"
4907      });
4908      _this.shadow = $(html.div, {
4909        class: "df-book-shadow"
4910      });
4911      //_this.resize();
4912      _this.container.append(_this.stage);
4913      _this.stage.append(_this.wrapper);
4914      _this.wrapper.append(_this.shadow);
4915      /*			_this.nextButton = $(html.div, {
4916       class: "df-book-next-button df-book-side-buttons " + parameters.icons['altnext']
4917       }).appendTo(_this.wrapper).on("click", function () {
4918       _this.next();
4919       });
4920       _this.prevButton = $(html.div, {
4921       class: "df-book-prev-button df-book-side-buttons " + parameters.icons['altprev']
4922       }).appendTo(_this.wrapper).on("click", function () {
4923       _this.prev();
4924       });*/
4925
4926
4927      //_this.container.height(parameters.height);
4928
4929      _this.createStack(parameters);
4930    };
4931
4932    BookCSS.prototype.createStack = function (parameters) {
4933
4934      var colors = "red,green,blue,yellow,orange,black".split(",");
4935
4936      for (var _stackCount = 0; _stackCount < this.stackCount; _stackCount++) {
4937        parameters.angles = [, this.stackCount - _stackCount];//[1] = (this.stackCount - _stackCount);
4938        parameters.stiffness = (this.stackCount - _stackCount) / 100;
4939
4940        var clone = new PageCSS(parameters);
4941        clone.angles[1] = 180;
4942        clone.index = _stackCount;
4943        clone.parent = this;
4944        clone.textureReady = false;
4945        clone.textureRequested = false;
4946        this.wrapper.append(clone.element);
4947        clone.isFlipping = false;
4948        this.pages.push(clone);
4949        clone.color = colors[_stackCount];
4950        //for (var _count = 0; _count < 4; _count++) {
4951        //    clone.element.css({
4952        //        backgroundColor : colors[_stackCount]
4953        //    });
4954        //}
4955      }
4956
4957      this.children = this.pages;
4958    };
4959
4960    BookCSS.prototype.isPageHard = function (pageNumber) {
4961
4962      return utils.isHardPage(this.hardConfig, pageNumber, this.pageCount, isBookletMode(this));
4963
4964    };
4965
4966    BookCSS.prototype.setDuration = function (_duration) {
4967      this.duration = _duration;
4968    };
4969
4970    BookCSS.prototype.moveBy = function (step) {
4971      var nextPage = this._activePage + step;
4972
4973      nextPage = limitAt(nextPage, this.startPage, this.endPage);
4974
4975      this.gotoPage(nextPage);
4976    };
4977
4978    BookCSS.prototype.next = function (step) {
4979      if (step == null)
4980        step =
4981          (this.direction == DFLIP.DIRECTION.RTL)
4982            ? -this.pageMode : this.pageMode;
4983
4984      this.moveBy(step);
4985    };
4986
4987    BookCSS.prototype.prev = function (step) {
4988      if (step == null)
4989        step =
4990          (this.direction == DFLIP.DIRECTION.RTL)
4991            ? this.pageMode : -this.pageMode;
4992
4993      this.moveBy(step);
4994    };
4995    BookCSS.prototype.eventToPoint = function (event) {
4996
4997      event = fixMouseEvent(event);
4998
4999      var wrapper = this.wrapper,
5000        pages = this.pages,
5001        pageWidth = this.pageWidth,
5002        fullWidth = this.fullWidth,
5003        height = this.height,
5004        win = $(window),
5005        point = {x: event.clientX, y: event.clientY};
5006
5007      var left = point.x - wrapper[0].getBoundingClientRect().left;// + win['scrollLeft']();
5008
5009      var top = point.y - wrapper[0].getBoundingClientRect().top;// + win['scrollTop']();
5010
5011      point.x = point.x - this.container[0].getBoundingClientRect().left;
5012      point.y = point.y - this.container[0].getBoundingClientRect().top;
5013
5014      var distance = (this.drag == drag.none)
5015        ? left < pageWidth ? left : fullWidth - left
5016        : this.drag == drag.left ? left : fullWidth - left;
5017
5018      var page = //((left >= 0 && left <= fullWidth)?
5019        (left < pageWidth ? pages[this.stackCount / 2 - 1] : pages[this.stackCount / 2]);
5020
5021      var pageDrag = left < this.foldSense ? drag.left
5022        : (left > fullWidth - this.foldSense) ? drag.right : drag.none;
5023
5024      //determine the corner
5025      var x = left,
5026        y = top,
5027        h = height,
5028        w = fullWidth,
5029        delta = this.foldSense,
5030        corners = DFLIP.CORNERS,
5031        corner;
5032
5033      if (x >= 0 && x < delta) {
5034        if (y >= 0 && y <= delta)
5035          corner = corners.TL;
5036        else if (y >= h - delta && y <= h)
5037          corner = corners.BL;
5038        else if (y > delta && y < h - delta)
5039          corner = corners.L;
5040        else
5041          corner = corners.NONE;
5042      }
5043      else if (x >= w - delta && x <= w) {
5044        if (y >= 0 && y <= delta)
5045          corner = corners.TR;
5046        else if (y >= h - delta && y <= h)
5047          corner = corners.BR;
5048        else if (y > delta && y < h - delta)
5049          corner = corners.R;
5050        else
5051          corner = corners.NONE;
5052      }
5053      else
5054        corner = corners.NONE;
5055
5056      return {
5057        isInsidePage: x >= 0 && x <= w && y >= 0 && y <= h,
5058        isInside: corner !== corners.NONE && corner !== corners.L && corner !== corners.R,
5059        x: left,
5060        y: top,
5061        fullWidth: fullWidth,
5062        rawDistance: fullWidth - left,
5063        distance: distance,
5064        page: page,
5065        drag: pageDrag,
5066        foldSense: this.foldSense,
5067        event: event,
5068        raw: point,
5069        corner: corner
5070      };
5071    };
5072
5073    BookCSS.prototype.gotoPage = function (pageNumber) {
5074      pageNumber = parseInt(pageNumber, 10);
5075      this._activePage = pageNumber;
5076
5077      if (this.autoPlay == true) {
5078        this.previewObject.setAutoPlay(this.autoPlay);
5079      }
5080      this.updatePage(pageNumber);
5081      if (this && this.thumblist && this.thumblist.review)
5082        this.thumblist.review();
5083    };
5084
5085    BookCSS.prototype.refresh = function () {
5086      this.updatePage(this._activePage);
5087      if (this.flipCallback != null) this.flipCallback();
5088    };
5089
5090    BookCSS.prototype.updatePage = function (pageNumber) {
5091
5092      var isRTL = (this.direction == DFLIP.DIRECTION.RTL),
5093        isBooklet = isBookletMode(this),
5094        newBaseNumber = getBasePage(pageNumber);
5095
5096      var pageDivisor = isBooklet ? 1 : 2;
5097
5098      pageNumber = Math.floor((pageNumber / pageDivisor));
5099
5100      if (isRTL) pageNumber = this.pageCount / pageDivisor - pageNumber;
5101
5102      var oldBaseNumber = this.oldBaseNumber || 0;
5103      var pageCount = this.pageCount / pageDivisor;
5104      var stackCount = this.stackCount;
5105
5106      var midPoint = Math.floor(stackCount / 2);
5107
5108      if (oldBaseNumber > pageNumber) {
5109        this.children[stackCount - 1].skipFlip = true;
5110        this.children.unshift(this.children.pop());
5111      }
5112      else if (oldBaseNumber < pageNumber) {
5113        this.children[0].skipFlip = true;
5114        this.children.push(this.children.shift());
5115      }
5116
5117      for (var _pageCount = 0; _pageCount < stackCount; _pageCount++) {
5118        var page = this.children[_pageCount];
5119
5120        if (oldBaseNumber !== pageNumber) {
5121          if (page.currentTween != null) {
5122            page.clearTween(true);
5123            //page.currentTween.stop();
5124            //page.completeTween(true);
5125            //page.resetCSS();
5126            //page.currentTween = null;
5127          }
5128        }
5129
5130        var oldSide = page.side;
5131        var newSide;
5132        var relativePageNumber = pageNumber - midPoint + _pageCount;
5133        if (isRTL) relativePageNumber = isBooklet ? this.pageCount - relativePageNumber
5134          : Math.floor(this.pageCount / 2) - relativePageNumber - 1;
5135
5136        var oldName = page.name;
5137
5138        page.isHard = this.isPageHard(relativePageNumber);
5139        if (page.isHard) {
5140          page.element.addClass("df-hard-page");
5141        } else {
5142          page.element.removeClass("df-hard-page");
5143          page.front.css({display: "block"});
5144          page.back.css({display: "block"});
5145        }
5146        if (relativePageNumber == 0 || relativePageNumber == pageCount) {
5147          page.element.addClass("df-cover-page");
5148        } else {
5149          page.element.removeClass("df-cover-page");
5150        }
5151
5152        var oldPageNumber = $(page.element).attr("pageNumber");
5153        if (oldPageNumber != relativePageNumber) {
5154          page.front.contentLayer.empty();
5155          page.back.contentLayer.empty();
5156        }
5157        $(page.element).attr("pageNumber", relativePageNumber);
5158
5159
5160        //Sizing
5161        page.isEdge = false; //true;
5162        if (_pageCount == 0) {
5163
5164        }
5165        else if (_pageCount == stackCount - 1) {
5166
5167        }
5168        else {
5169
5170          page.isEdge = false;
5171        }
5172
5173
5174        if (_pageCount < midPoint) {
5175          newSide = drag.left;
5176        }
5177        else {
5178          newSide = drag.right;
5179        }
5180
5181
5182        if (page.isFlipping == false) {
5183
5184          if (newSide !== oldSide && page.skipFlip == false) {
5185
5186            this.animatePage(page);
5187
5188            if (this.preFlipCallback != null)
5189              this.preFlipCallback();
5190
5191          } else {
5192            page.skipFlip = false;
5193            page.element.removeClass("df-flipping df-quick-turn df-folding df-left-side df-right-side");
5194            page.element.addClass((_pageCount < midPoint) ? "df-left-side" : "df-right-side");
5195            page.side = newSide;
5196          }
5197        }
5198
5199        page.visible = isBooklet
5200          ? (isRTL
5201
5202            ? (_pageCount < midPoint || page.isFlipping)
5203            : (_pageCount >= midPoint || page.isFlipping))
5204
5205          : ((relativePageNumber >= 0 && relativePageNumber < pageCount) || (isBooklet && relativePageNumber == pageCount));
5206
5207        if (this.requestPage != null && page.visible == true) {
5208
5209          page.name = relativePageNumber.toString();
5210          if (page.name != oldName) {
5211
5212            page.backTextureLoaded = false;
5213            page.frontTextureLoaded = false;
5214            page.backPageStamp = "-1";
5215            page.frontPageStamp = "-1";
5216            page.thumbLoaded = false;
5217            page.front.contentLayer.html("");
5218            page.back.contentLayer.html("");
5219            //if (oldName !== '-2') {
5220            //canvas clearing
5221            page.frontImage(defaults.textureLoadFallback);
5222            page.backImage(defaults.textureLoadFallback);
5223            //}
5224            this.requestPage();
5225
5226          }
5227        }
5228
5229        page.oldDepth = page.depth;
5230        page.updateCSS({
5231          display: page.visible == true ? "block" : "none",
5232          zIndex: 6 + (_pageCount < midPoint ? (_pageCount - midPoint) : (midPoint - _pageCount)),
5233          transform: ''
5234        });
5235
5236        if (page.pendingPoint == null && page.isFlipping == false) {
5237          page.resetCSS();
5238        }
5239      }
5240
5241      if (TWEEN.getAll().length == 0) {
5242        clearInterval(this.animate);
5243      }
5244      $(".quick-hint").html(pageNumber);
5245
5246      this.oldBaseNumber = pageNumber;
5247
5248      if (this.updatePageCallback)
5249        this.updatePageCallback();
5250
5251    };
5252
5253    BookCSS.prototype.animatePage = function (page) {
5254      page.element.addClass("df-flipping");
5255      page.isFlipping = true;
5256
5257      if (this.animate != null) {
5258        clearInterval(this.animate);
5259      }
5260
5261      this.animate = setInterval(this.animateF, 30);
5262
5263      page.tween(page.pendingPoint);
5264    };
5265
5266    return BookCSS;
5267  })
5268  ({});
5269
5270  var FlipBook = (function (_super) {
5271
5272    __extends(FlipBook, _super);
5273
5274    function FlipBook(container, source, parameters) {
5275      _super.call(this, parameters);
5276      var _this = this;
5277
5278      _this.type = "FlipBook";
5279      _this.container = container;
5280      _this.options = parameters;
5281      _this.options.source = source;
5282      _this.contentSource = source;
5283
5284      if (parameters.height != null && parameters.height.toString().indexOf('%') < 0) {
5285        _this.container.height(Math.min(parameters.height, $(window).height()));
5286      } else {
5287        _this.container.height(parameters.height);
5288      }
5289
5290      if (_this.options.isLightBox) {
5291        window.dfLightBox.closeButton.addClass(_this.options.icons['close']);
5292      }
5293      if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL) {
5294        //currently booklet version cannot handle double sized image pages
5295        if (Array === _this.contentSource.constructor || Array.isArray(_this.contentSource) || _this.contentSource instanceof Array) {
5296          _this.options.singlePageMode = DFLIP.SINGLE_PAGE_MODE.ZOOM;
5297        }
5298        _this.container.addClass("df-double-internal");
5299      }
5300      if (!_this.options.isLightBox && _this.container.attr("id") != null) {
5301        _this.options.id = _this.container.attr("id");
5302      }
5303
5304      if (_this.options.parsed !== true && _this.options.links != null) {
5305        DFLIP.parseLinks(_this.options.links);
5306      }
5307      var webgl = _this.webgl = parameters.webgl == true && hasWebgl == true;
5308
5309      container.addClass("df-container df-loading df-init df-floating" + " df-controls-" + _this.options.controlsPosition);
5310
5311      if (_this.options.transparent == true) {
5312        container.addClass("df-transparent");
5313      }
5314      if (_this.options.direction == DFLIP.DIRECTION.RTL) {
5315        container.addClass("df-rtl");
5316      }
5317      _this.container.info = $(html.div, {
5318        class: "loading-info"
5319      }).appendTo(_this.container).html("Loading...");
5320
5321      if (userAgent.indexOf('MSIE') !== -1
5322        || navigator.appVersion.indexOf('Trident/') > 0 || (isSafari && !isIOS)) {
5323        _this.options.webgl = false; //IE 11
5324      }
5325
5326      if (!!userAgent.match(/msie\s[5-9]/i)) {
5327        _this.container.info.html("Your browser (Internet Explorer) is out of date to run DFlip Flipbook Plugin. <br><a href='http://browsehappy.com/'>Upgrade to a new one</a>").addClass("df-old-browser");
5328        container.removeClass("df-loading");
5329        return _this;
5330      }
5331
5332      var backgroundImage = parameters.backgroundImage == null || parameters.backgroundImage == '' ? ''
5333        : "url('" + parameters.backgroundImage + "')";
5334
5335      _this.container.css({
5336        position: "relative",
5337        overflow: "hidden",
5338        backgroundColor: parameters.backgroundColor,
5339        backgroundImage: backgroundImage
5340      });
5341
5342      _this.init(webgl, source);
5343
5344      if (_this.options.onCreate != null)
5345        _this.options.onCreate(_this);
5346
5347      return _this;
5348
5349    }
5350
5351    FlipBook.prototype.init = function (webgl) {
5352      var _this = this;
5353      var book = _this.target;
5354
5355      var options = _this.options;
5356
5357      if (webgl == true) {
5358
5359        var updateMockupJs = function (callback) {
5360
5361            var process3d = function () {
5362              MOCKUP.defaults.anisotropy = 0;
5363              MOCKUP.defaults.groundTexture = "blank";
5364              THREE.skipPowerOfTwo = true;
5365
5366              RegisterMockupObjects();
5367
5368              if (callback != null) callback();
5369            };
5370
5371            if (window.MOCKUP == null) {
5372              _this.updateInfo("Loading WEBGL 3D ...");
5373
5374              if (typeof define === 'function' && define.amd && window.requirejs) {
5375                requirejs.config({
5376                  "paths": {
5377                    "three": defaults.threejsSrc.replace(".js", "")
5378                  },
5379                  shim: {
5380                    'three': {
5381                      exports: 'THREE'
5382                    }
5383                  }
5384                });
5385                require(['three'], function (THREE) {
5386                  window.THREE = THREE;
5387                  getScript(defaults.mockupjsSrc + "?ver=" + DFLIP.version, function () {
5388                    process3d();
5389                  });
5390                  return THREE;
5391                });
5392              }
5393              else if (typeof define === 'function' && define.amd) {
5394                require(["three", defaults.threejsSrc.replace(".js", "")], function (ready, fx) {
5395                  ready(function () {
5396
5397                  });
5398                });
5399              }
5400              else {
5401                getScript(defaults.threejsSrc + "?ver=" + DFLIP.version, function () {
5402                  //_this.updateInfo("Loading 3D Pages ..."); this was retainnng _this and not releasing memory
5403                  getScript(defaults.mockupjsSrc + "?ver=" + DFLIP.version, function () {
5404                    process3d();
5405                  });
5406                });
5407              }
5408            }
5409            else {
5410              process3d();
5411            }
5412          }
5413        ;
5414
5415        updateMockupJs(function () {
5416
5417          //Todo: ability to use anisotropy
5418
5419          _this.container.css({
5420            minHeight: 300,
5421            minWidth: 300
5422          });
5423
5424          _this.stage = new PreviewStage(extendOptions(_this.options, {container: _this.container}));
5425          _this.stage.previewObject = _this;
5426
5427          _this.contentProvider = new ContentProvider(_this.contentSource, function (contentProvider) {
5428            // _this.pageCount = contentProvider.pageCount = utils.limitAt(contentProvider.pageCount, 1, 2 * 5);
5429            var options = {
5430              pageCount: contentProvider.pageCount,//Math.ceil(contentProvider.pageCount / 2) * 2,
5431              stackCount: 6,
5432              segments: 20,
5433              width: contentProvider.bookSize.width,
5434              height: contentProvider.bookSize.height
5435            };
5436
5437            _this.checkOpenPage();
5438            _this.target = book = _this.stage.target = new MOCKUP.Book(extendOptions(_this.options, options), _this.stage);
5439            _this.extendtarget();
5440            createUI(_this.container, _this);
5441
5442            //bookStage.setTarget(_this.target);
5443            book.ui = _this.ui;
5444            book.container = _this.container;
5445            contentProvider.webgl = webgl;
5446            contentProvider.setTarget(_this.target);
5447
5448            book.getContentLayer = function (pageNumber) {
5449
5450              var isRTL = book.direction == DFLIP.DIRECTION.RTL,
5451                left = _this.stage.cssScene.divLeft.element,
5452                right = _this.stage.cssScene.divRight.element;
5453
5454              var baseActive = getBasePage(book._activePage);
5455
5456              //if(isRTL){
5457              //	if(pageNumber == 0 || pageNumber == 1) return right;
5458              //	if(pageNumber == book.pageCount) return left;
5459              //}
5460
5461              if (isBookletMode(book)) return isRTL ? left : right;
5462
5463              if (pageNumber % 2 == 0)
5464                return isRTL ? right : left;
5465              else
5466                return isRTL ? left : right;
5467              //else
5468              //	return null;
5469            };
5470            book.stage = _this.stage;
5471
5472            book.flipCallback = function () {
5473              if (_this.contentProvider) {
5474                _this.contentProvider.review("flipCallback");
5475
5476                var baseActive = getBasePage(book._activePage);
5477
5478                var width, height;
5479                var pageLeft = book.getPageByNumber(baseActive),
5480                  pageRight = book.getPageByNumber(baseActive + 1);
5481                //if (page3d != null) {
5482                //    var isLeft = (pageNumber % 2 == 0);
5483                var divLeft = book.parent.cssScene.divLeft,
5484                  divRight = book.parent.cssScene.divRight;
5485
5486                var isSingle = book.pageMode == DFLIP.PAGE_MODE.SINGLE;
5487                var isRTL = book.direction == DFLIP.DIRECTION.RTL;
5488
5489                if (pageLeft != null && divLeft != null) {
5490                  width = Math.abs(pageLeft.geometry.boundingBox.max.x - pageLeft.geometry.boundingBox.min.x);
5491                  height = Math.abs(pageLeft.geometry.boundingBox.max.z - pageLeft.geometry.boundingBox.min.z);
5492
5493                  divLeft.rotation.y = -Math.atan2(height, width) * 0.9;
5494                  divLeft.position.z = height * 0.8;
5495                  divLeft.position.x = height / 2.5;
5496                  $(divLeft.element).css({
5497                    width: width,
5498                    left: -width / 2//baseActive == 0 && isRTL == true? width
5499                    //: baseActive == book.pageCount && isRTL == true ? 0 : -width / 2
5500                  });
5501
5502                }
5503
5504                if (pageRight != null && divRight != null) {
5505                  width = Math.abs(pageRight.geometry.boundingBox.max.x - pageRight.geometry.boundingBox.min.x);
5506                  height = Math.abs(pageRight.geometry.boundingBox.max.z - pageRight.geometry.boundingBox.min.z);
5507
5508                  divRight.rotation.y = Math.atan2(height, width) * 0.9;
5509                  divRight.position.z = height * 0.8;
5510                  divRight.position.x = -height / 2.5;
5511                  $(divRight.element).css({
5512                    width: width,
5513                    left: width / 2// == 0 && isRTL == true ? 0
5514                    //: baseActive == book.pageCount && isRTL == true ? -width : width / 2
5515                  });
5516
5517                }
5518
5519                if (_this.options.onFlip != null)
5520                  _this.options.onFlip(_this);
5521              }
5522            };
5523
5524            book.resize = function () {
5525              _this.resize();
5526            }();
5527
5528            book.updatePageCallback = function () {
5529              _this.ui.update();
5530              _this.checkCenter();
5531              _this.stage.renderRequestPending = true;
5532            };
5533
5534            var divLeft = $(_this.stage.cssScene.divLeft.element);
5535            var divRight = $(_this.stage.cssScene.divRight.element);
5536
5537            book.preFlipCallback = function () {
5538              divLeft.empty();
5539              divRight.empty();
5540              if (_this.options.beforeFlip != null)
5541                _this.options.beforeFlip(_this);
5542
5543              _this.playSound();
5544            };
5545
5546            $(window).trigger("resize");
5547
5548            divLeft.css({
5549              width: contentProvider.bookSize.width,
5550              height: contentProvider.bookSize.height,
5551              left: -contentProvider.bookSize.width / 2
5552            });
5553
5554            divRight.css({
5555              width: contentProvider.bookSize.width,
5556              height: contentProvider.bookSize.height,
5557              left: contentProvider.bookSize.width / 2
5558            });
5559
5560            book.ease = TWEEN.Easing.Cubic.InOut;
5561            //book.ease = TWEEN.Easing.Quadratic.InOut;
5562            book.contentProvider = contentProvider;
5563            book.duration = _this.options.duration;
5564            book.gotoPage(book._activePage);
5565            book.flipCallback();
5566
5567            if (_this.options.onReady != null)
5568              _this.options.onReady(_this);
5569
5570          }, options, _this);
5571        });
5572      }
5573      else {
5574
5575        _this.contentProvider = new ContentProvider(_this.contentSource, function (contentProvider) {
5576          // _this.pageCount = contentProvider.pageCount = utils.limitAt(contentProvider.pageCount, 1, 2 * 5);
5577          var options = {
5578            pageCount: contentProvider.pageCount,//Math.ceil(contentProvider.pageCount / 2) * 2,
5579            contentSourceType: contentProvider.contentSourceType
5580          };
5581
5582          _this.checkOpenPage();
5583          _this.target = book = new BookCSS(extendOptions(_this.options, options), _this.container);
5584          _this.target.previewObject = _this;
5585          _this.extendtarget();
5586          createUI(_this.container, _this);
5587          contentProvider.webgl = webgl;
5588          contentProvider.setTarget(_this.target);
5589          contentProvider.waitPeriod = 2;
5590          book.ease = TWEEN.Easing.Quadratic.InOut;
5591          book.duration = _this.options.duration;
5592
5593          /*					_this.ui.prev.hide();
5594           _this.ui.next.hide();
5595
5596           _this.ui.prev = book.prevButton;
5597           _this.ui.next = book.nextButton;*/
5598
5599          book.container = _this.container;
5600          book.updatePageCallback = function () {
5601            _this.ui.update();
5602            _this.checkCenter();
5603          };
5604
5605          book.resize = function () {
5606            _this.resize();
5607          }();
5608
5609          $(window).trigger("resize");
5610
5611          book.flipCallback = function () {
5612            if (_this.contentProvider) {
5613              _this.contentProvider.review("flipCallback");
5614
5615              if (_this.options.onFlip != null)
5616                _this.options.onFlip(_this);
5617            }
5618          };
5619
5620          book.preFlipCallback = function () {
5621            if (_this.options.beforeFlip != null)
5622              _this.options.beforeFlip(_this);
5623
5624            _this.playSound();
5625          };
5626          book.gotoPage(book._activePage);
5627          book.flipCallback();
5628
5629          if (_this.options.onReady != null)
5630            _this.options.onReady(_this);
5631
5632        }, options, _this);
5633
5634      }
5635
5636
5637    }
5638    ;
5639
5640    FlipBook.prototype.extendtarget = function () {
5641      var _this = this;
5642      _this.target.previewObject = _this;
5643      _this.target.reset = function () {
5644        for (var pageCount = 0; pageCount < _this.target.children.length; pageCount++) {
5645          var page = _this.target.children[pageCount];
5646          page.skipFlip = true;
5647          page.name = '-2';
5648        }
5649        _this.contentProvider.annotedPage = '-2';
5650        _this.target.refresh();
5651
5652      }
5653    };
5654
5655    FlipBook.prototype.getURLHash = function () {
5656      if (this.options.id != null) {
5657        var hash = "dflip-" + (this.options.slug != null ? this.options.slug : this.options.id) + "/";
5658        if (this.target != null && this.target._activePage != null) {
5659          hash += this.target._activePage + "/";
5660        }
5661        window.location.hash = hash;
5662      }
5663      return window.location.href;
5664    };
5665
5666    FlipBook.prototype.checkOpenPage = function () {
5667      //options value is overridden by attribute
5668      if (this.options.id != null) {
5669        var book = $("#" + this.options.id);
5670        if (book.length > 0 && book.data("page") != null) {
5671          var pageNumber = parseInt(book.data("page"), 10);
5672          if (!isNaN(pageNumber))
5673            this.options.openPage = pageNumber;
5674        }
5675      }
5676    };
5677
5678    FlipBook.prototype.end = function () {
5679
5680      this.target.gotoPage(this.target.endPage);
5681
5682    };
5683
5684    FlipBook.prototype.gotoPage = function (pageNumber) {
5685
5686      this.target.gotoPage(pageNumber);
5687      if (this.ui != null) this.ui.update();
5688    };
5689
5690    FlipBook.prototype.prev = function () {
5691
5692      this.target.prev();
5693
5694    };
5695
5696    FlipBook.prototype.next = function () {
5697
5698      this.target.next();
5699
5700    };
5701
5702    FlipBook.prototype.updateInfo = function (info) {
5703      if (this.container && this.container.info && this.container.info.html)
5704        this.container.info.html(info);
5705    }
5706    return FlipBook;
5707
5708  })(PreviewObject);
5709
5710  $.fn.extend({
5711
5712    shelf: function () {
5713
5714    },
5715    flipBook: function (source, options) {
5716      return new FlipBook($(this), source, extendDFlipOptions(options));
5717    }
5718  });
5719
5720})
5721(DFLIP, jQuery);
5722
5723
5724//Polyfills
5725
5726/**
5727 * Blob.js Polyfill
5728 * A Blob implementation.
5729 * 2014-07-24
5730 *
5731 * By Eli Grey, http://eligrey.com
5732 * By Devin Samarin, https://github.com/dsamarin
5733 * License: X11/MIT
5734 */
5735(function (view) {
5736  "use strict";
5737
5738  view.URL = view.URL || view.webkitURL;
5739
5740  if (view.Blob && view.URL) {
5741    try {
5742      new Blob;
5743      return;
5744    } catch (e) {
5745    }
5746  }
5747
5748  // Internally we use a BlobBuilder implementation to base Blob off of
5749  // in order to support older browsers that only have BlobBuilder
5750  var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function (view) {
5751      var
5752        get_class = function (object) {
5753          return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
5754        }, FakeBlobBuilder = function BlobBuilder() {
5755          this.data = [];
5756        }, FakeBlob = function Blob(data, type, encoding) {
5757          this.data = data;
5758          this.size = data.length;
5759          this.type = type;
5760          this.encoding = encoding;
5761        }, FBB_proto = FakeBlobBuilder.prototype, FB_proto = FakeBlob.prototype, FileReaderSync = view.FileReaderSync,
5762        FileException = function (type) {
5763          this.code = this[this.name = type];
5764        }, file_ex_codes = (
5765          "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
vendor: 6,148 bytes, lines 5766-5930
5766          + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
5767        ).split(" "), file_ex_code = file_ex_codes.length, real_URL = view.URL || view.webkitURL || view,
5768        real_create_object_URL = real_URL.createObjectURL, real_revoke_object_URL = real_URL.revokeObjectURL,
5769        URL = real_URL, btoa = view.btoa, atob = view.atob, ArrayBuffer = view.ArrayBuffer,
5770        Uint8Array = view.Uint8Array, origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/
5771      ;
5772      FakeBlob.fake = FB_proto.fake = true;
5773      while (file_ex_code--) {
5774        FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
5775      }
5776      // Polyfill URL
5777      if (!real_URL.createObjectURL) {
5778        URL = view.URL = function (uri) {
5779          var
5780            uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a"), uri_origin
5781          ;
5782          uri_info.href = uri;
5783          if (!("origin" in uri_info)) {
5784            if (uri_info.protocol.toLowerCase() === "data:") {
5785              uri_info.origin = null;
5786            } else {
5787              uri_origin = uri.match(origin);
5788              uri_info.origin = uri_origin && uri_origin[1];
5789            }
5790          }
5791          return uri_info;
5792        };
5793      }
5794      URL.createObjectURL = function (blob) {
5795        var
5796          type = blob.type, data_URI_header
5797        ;
5798        if (type === null) {
5799          type = "application/octet-stream";
5800        }
5801        if (blob instanceof FakeBlob) {
5802          data_URI_header = "data:" + type;
5803          if (blob.encoding === "base64") {
5804            return data_URI_header + ";base64," + blob.data;
5805          } else if (blob.encoding === "URI") {
5806            return data_URI_header + "," + decodeURIComponent(blob.data);
5807          }
5808          if (btoa) {
5809            return data_URI_header + ";base64," + btoa(blob.data);
5810          } else {
5811            return data_URI_header + "," + encodeURIComponent(blob.data);
5812          }
5813        } else if (real_create_object_URL) {
5814          return real_create_object_URL.call(real_URL, blob);
5815        }
5816      };
5817      URL.revokeObjectURL = function (object_URL) {
5818        if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
5819          real_revoke_object_URL.call(real_URL, object_URL);
5820        }
5821      };
5822      FBB_proto.append = function (data/*, endings*/) {
5823        var bb = this.data;
5824        // decode data to a binary string
5825        if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
5826          var
5827            str = "", buf = new Uint8Array(data), i = 0, buf_len = buf.length
5828          ;
5829          for (; i < buf_len; i++) {
5830            str += String.fromCharCode(buf[i]);
5831          }
5832          bb.push(str);
5833        } else if (get_class(data) === "Blob" || get_class(data) === "File") {
5834          if (FileReaderSync) {
5835            var fr = new FileReaderSync;
5836            bb.push(fr.readAsBinaryString(data));
5837          } else {
5838            // async FileReader won't work as BlobBuilder is sync
5839            throw new FileException("NOT_READABLE_ERR");
5840          }
5841        } else if (data instanceof FakeBlob) {
5842          if (data.encoding === "base64" && atob) {
5843            bb.push(atob(data.data));
5844          } else if (data.encoding === "URI") {
5845            bb.push(decodeURIComponent(data.data));
5846          } else if (data.encoding === "raw") {
5847            bb.push(data.data);
5848          }
5849        } else {
5850          if (typeof data !== "string") {
5851            data += ""; // convert unsupported types to strings
5852          }
5853          // decode UTF-16 to binary string
5854          bb.push(unescape(encodeURIComponent(data)));
5855        }
5856      };
5857      FBB_proto.getBlob = function (type) {
5858        if (!arguments.length) {
5859          type = null;
5860        }
5861        return new FakeBlob(this.data.join(""), type, "raw");
5862      };
5863      FBB_proto.toString = function () {
5864        return "[object BlobBuilder]";
5865      };
5866      FB_proto.slice = function (start, end, type) {
5867        var args = arguments.length;
5868        if (args < 3) {
5869          type = null;
5870        }
5871        return new FakeBlob(
5872          this.data.slice(start, args > 1 ? end : this.data.length), type, this.encoding
5873        );
5874      };
5875      FB_proto.toString = function () {
5876        return "[object Blob]";
5877      };
5878      FB_proto.close = function () {
5879        this.size = 0;
5880        delete this.data;
5881      };
5882      return FakeBlobBuilder;
5883    }(view));
5884
5885  view.Blob = function (blobParts, options) {
5886    var type = options ? (options.type || "") : "";
5887    var builder = new BlobBuilder();
5888    if (blobParts) {
5889      for (var i = 0, len = blobParts.length; i < len; i++) {
5890        if (Uint8Array && blobParts[i] instanceof Uint8Array) {
5891          builder.append(blobParts[i].buffer);
5892        }
5893        else {
5894          builder.append(blobParts[i]);
5895        }
5896      }
5897    }
5898    var blob = builder.getBlob(type);
5899    if (!blob.slice && blob.webkitSlice) {
5900      blob.slice = blob.webkitSlice;
5901    }
5902    return blob;
5903  };
5904
5905  var getPrototypeOf = Object.getPrototypeOf || function (object) {
5906      return object.__proto__;
5907    };
5908  view.Blob.prototype = getPrototypeOf(new view.Blob());
5909}(window));
5910
5911/**
5912 * canvas-toBlob.js Polyfill
5913 * A canvas.toBlob() implementation.
5914 * 2013-12-27
5915 *
5916 * By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr
5917 * License: X11/MIT
5918 *   See https://github.com/eligrey/canvas-toBlob.js/blob/master/LICENSE.md
5919 */
5920(function (view) {
5921  "use strict";
5922  var
5923    Uint8Array = view.Uint8Array, HTMLCanvasElement = view.HTMLCanvasElement,
5924    canvas_proto = HTMLCanvasElement && HTMLCanvasElement.prototype, is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i,
5925    to_data_url = "toDataURL", base64_ranks, decode_base64 = function (base64) {
5926      var
5927        len = base64.length, buffer = new Uint8Array(len / 4 * 3 | 0), i = 0, outptr = 0, last = [0, 0], state = 0,
5928        save = 0, rank, code;
5929      while (len--) {
5930        code = base64.charCodeAt(i++);
5931        rank = base64_ranks[code - 43];
5932        if (rank !== 255 && rank != null) {
5933          last[1] = last[0];
5934          last[0] = code;
5935          save = (save << 6) | rank;
5936          state++;
5937          if (state === 4) {
5938            buffer[outptr++] = save >>> 16;
5939            if (last[1] !== 61 /* padding character */) {
5940              buffer[outptr++] = save >>> 8;
5941            }
5942            if (last[0] !== 61 /* padding character */) {
5943              buffer[outptr++] = save;
5944            }
5945            state = 0;
5946          }
5947        }
5948      }
5949      // 2/3 chance there's going to be some null bytes at the end, but that
5950      // doesn't really matter with most image formats.
5951      // If it somehow matters for you, truncate the buffer up outptr.
5952      return buffer;
5953    }
5954  ;
5955  if (Uint8Array) {
5956    base64_ranks = new Uint8Array([
5957      62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
5958    ]);
5959  }
5960  if (HTMLCanvasElement && !canvas_proto.toBlob) {
5961    canvas_proto.toBlob = function (callback, type /*, ...args*/) {
5962      if (!type) {
5963        type = "image/png";
5964      }
5965      if (this.mozGetAsFile) {
5966        callback(this.mozGetAsFile("canvas", type));
5967        return;
5968      }
5969      if (this.msToBlob && /^\s*image\/png\s*(?:$|;)/i.test(type)) {
5970        callback(this.msToBlob());
5971        return;
5972      }
5973
5974      var
5975        args = Array.prototype.slice.call(arguments, 1),
5976        dataURI = this[to_data_url].apply(this, args),
5977        header_end = dataURI.indexOf(","),
5978        data = dataURI.substring(header_end + 1),
5979        is_base64 = is_base64_regex.test(dataURI.substring(0, header_end)),
5980        blob
5981      ;
5982      if (Blob.fake) {
5983        // no reason to decode a data: URI that's just going to become a data URI again
5984        blob = new Blob;
5985        if (is_base64) {
5986          blob.encoding = "base64";
5987        } else {
5988          blob.encoding = "URI";
5989        }
5990        blob.data = data;
5991        blob.size = data.length;
5992      } else if (Uint8Array) {
5993        if (is_base64) {
5994          blob = new Blob([decode_base64(data)], {type: type});
5995        } else {
5996          blob = new Blob([decodeURIComponent(data)], {type: type});
5997        }
5998      }
5999      callback(blob);
6000    };
6001
6002    if (canvas_proto.toDataURLHD) {
6003      canvas_proto.toBlobHD = function () {
6004        to_data_url = "toDataURLHD";
6005        var blob = this.toBlob();
6006        to_data_url = "toDataURL";
6007        return blob;
6008      }
6009    } else {
6010      canvas_proto.toBlobHD = canvas_proto.toBlob;
6011    }
6012  }
6013}(window));
6014
6015/**
6016 * performance.now polyfill
6017 **/
6018(function PerformanceNowPolyfill() {
6019
6020  if ('performance' in window === false) {
6021    window.performance = {};
6022  }
6023
6024  // IE 8
6025  Date.now = (Date.now || function () {
6026    return new Date().getTime();
6027  });
6028
6029  if ('now' in window.performance === false) {
6030    var offset = window.performance.timing && window.performance.timing.navigationStart
6031      ? window.performance.timing.navigationStart
6032      : Date.now();
6033
6034    window.performance.now = function () {
6035      return Date.now() - offset;
6036    };
6037  }
6038
6039})();
6040
6041/**
6042 * Tween.js - Licensed under the MIT license
6043 * https://github.com/tweenjs/tween.js
6044 */
6045(function TweenJs() {
6046  var TWEEN = TWEEN || (function () {
6047
6048      var _tweens = [];
6049
6050      return {
6051
6052        getAll: function () {
6053
6054          return _tweens;
6055
6056        },
6057
6058        removeAll: function () {
6059
6060          _tweens = [];
6061
6062        },
6063
6064        add: function (tween) {
6065
6066          _tweens.push(tween);
6067
6068        },
6069
6070        remove: function (tween) {
6071
6072          var i = _tweens.indexOf(tween);
6073
6074          if (i !== -1) {
6075            _tweens.splice(i, 1);
6076          }
6077
6078        },
6079
6080        update: function (time) {
6081
6082          if (_tweens.length === 0) {
6083            return false;
6084          }
6085
6086          var i = 0;
6087
6088          time = time != null ? time : window.performance.now();
6089
6090          while (i < _tweens.length) {
6091
6092            if (_tweens[i].update(time)) {
6093              i++;
6094            } else {
6095              _tweens.splice(i, 1);
6096            }
6097
6098          }
6099
6100          return true;
6101
6102        }
6103      };
6104
6105    })();
6106
6107  TWEEN.Tween = function (object) {
6108
6109    var _object = object;
6110    var _valuesStart = {};
6111    var _valuesEnd = {};
6112    var _valuesStartRepeat = {};
6113    var _duration = 1000;
6114    var _repeat = 0;
6115    var _yoyo = false;
6116    var _isPlaying = false;
6117    var _reversed = false;
6118    var _delayTime = 0;
6119    var _startTime = null;
6120    var _easingFunction = TWEEN.Easing.Linear.None;
6121    var _interpolationFunction = TWEEN.Interpolation.Linear;
6122    var _chainedTweens = [];
6123    var _onStartCallback = null;
6124    var _onStartCallbackFired = false;
6125    var _onUpdateCallback = null;
6126    var _onCompleteCallback = null;
6127    var _onStopCallback = null;
6128
6129    // Set all starting values present on the target object
6130    for (var field in object) {
6131      _valuesStart[field] = parseFloat(object[field], 10);
6132    }
6133
6134    this.to = function (properties, duration) {
6135
6136      if (duration != null) {
6137        _duration = duration;
6138      }
6139
6140      _valuesEnd = properties;
6141
6142      return this;
6143
6144    };
6145
6146    this.start = function (time) {
6147
6148      TWEEN.add(this);
6149
6150      _isPlaying = true;
6151
6152      _onStartCallbackFired = false;
6153
6154      _startTime = time != null ? time : window.performance.now();
6155      _startTime += _delayTime;
6156
6157      for (var property in _valuesEnd) {
6158
6159        // Check if an Array was provided as property value
6160        if (_valuesEnd[property] instanceof Array) {
6161
6162          if (_valuesEnd[property].length === 0) {
6163            continue;
6164          }
6165
6166          // Create a local copy of the Array with the start value at the front
6167          _valuesEnd[property] = [_object[property]].concat(_valuesEnd[property]);
6168
6169        }
6170
6171        // If `to()` specifies a property that doesn't exist in the source object,
6172        // we should not set that property in the object
6173        if (_valuesStart[property] === null) {
6174          continue;
6175        }
6176
6177        _valuesStart[property] = _object[property];
6178
6179        if ((_valuesStart[property] instanceof Array) === false) {
6180          _valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings
6181        }
6182
6183        _valuesStartRepeat[property] = _valuesStart[property] || 0;
6184
6185      }
6186
6187      return this;
6188
6189    };
6190
6191    this.stop = function () {
6192
6193      if (!_isPlaying) {
6194        return this;
6195      }
6196
6197      TWEEN.remove(this);
6198      _isPlaying = false;
6199
6200      if (_onStopCallback !== null) {
6201        _onStopCallback.call(_object);
6202      }
6203
6204      this.stopChainedTweens();
6205      return this;
6206
6207    };
6208
6209    this.stopChainedTweens = function () {
6210
6211      for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) {
6212        _chainedTweens[i].stop();
6213      }
6214
6215    };
6216
6217    this.complete = function () {
6218      if (!_isPlaying) {
6219        return this;
6220      }
6221
6222      TWEEN.remove(this);
6223      _isPlaying = false;
6224
6225      if (_onCompleteCallback !== null) {
6226        _onCompleteCallback.call(_object);
6227      }
6228
6229      this.completeChainedTweens();
6230      return this;
6231    };
6232
6233    this.completeChainedTweens = function () {
6234
6235      for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) {
6236        _chainedTweens[i].complete();
6237      }
6238
6239    };
6240
6241    this.delay = function (amount) {
6242
6243      _delayTime = amount;
6244      return this;
6245
6246    };
6247
6248    this.repeat = function (times) {
6249
6250      _repeat = times;
6251      return this;
6252
6253    };
6254
6255    this.yoyo = function (yoyo) {
6256
6257      _yoyo = yoyo;
6258      return this;
6259
6260    };
6261
6262
6263    this.easing = function (easing) {
6264
6265      _easingFunction = easing == null ? _easingFunction : easing;
6266      return this;
6267
6268    };
6269
6270    this.interpolation = function (interpolation) {
6271
6272      _interpolationFunction = interpolation;
6273      return this;
6274
6275    };
6276
6277    this.chain = function () {
6278
6279      _chainedTweens = arguments;
6280      return this;
6281
6282    };
6283
6284    this.onStart = function (callback) {
6285
6286      _onStartCallback = callback;
6287      return this;
6288
6289    };
6290
6291    this.onUpdate = function (callback) {
6292
6293      _onUpdateCallback = callback;
6294      return this;
6295
6296    };
6297
6298    this.onComplete = function (callback) {
6299
6300      _onCompleteCallback = callback;
6301      return this;
6302
6303    };
6304
6305    this.onStop = function (callback) {
6306
6307      _onStopCallback = callback;
6308      return this;
6309
6310    };
6311
6312    this.update = function (time) {
6313
6314      var property;
6315      var elapsed;
6316      var value;
6317
6318      if (time < _startTime) {
6319        return true;
6320      }
6321
6322      if (_onStartCallbackFired === false) {
6323
6324        if (_onStartCallback !== null) {
6325          _onStartCallback.call(_object);
6326        }
6327
6328        _onStartCallbackFired = true;
6329
6330      }
6331
6332      elapsed = (time - _startTime) / _duration;
6333      elapsed = elapsed > 1 ? 1 : elapsed;
6334
6335      value = _easingFunction(elapsed);
6336
6337      for (property in _valuesEnd) {
6338
6339        // Don't update properties that do not exist in the source object
6340        if (_valuesStart[property] === null) {
6341          continue;
6342        }
6343
6344        var start = _valuesStart[property] || 0;
6345        var end = _valuesEnd[property];
6346
6347        if (end instanceof Array) {
6348
6349          _object[property] = _interpolationFunction(end, value);
6350
6351        } else {
6352
6353          // Parses relative end values with start as base (e.g.: +10, -3)
6354          if (typeof (end) === 'string') {
6355
6356            if (end.startsWith('+') || end.startsWith('-')) {
6357              end = start + parseFloat(end, 10);
6358            } else {
6359              end = parseFloat(end, 10);
6360            }
6361          }
6362
6363          // Protect against non numeric properties.
6364          if (typeof (end) === 'number') {
6365            _object[property] = start + (end - start) * value;
6366          }
6367
6368        }
6369
6370      }
6371
6372      if (_onUpdateCallback !== null) {
6373        _onUpdateCallback.call(_object, value);
6374      }
6375
6376      if (elapsed === 1) {
6377
6378        if (_repeat > 0) {
6379
6380          if (isFinite(_repeat)) {
6381            _repeat--;
6382          }
6383
6384          // Reassign starting values, restart by making startTime = now
6385          for (property in _valuesStartRepeat) {
6386
6387            if (typeof (_valuesEnd[property]) === 'string') {
6388              _valuesStartRepeat[property] = _valuesStartRepeat[property] + parseFloat(_valuesEnd[property], 10);
6389            }
6390
6391            if (_yoyo) {
6392              var tmp = _valuesStartRepeat[property];
6393
6394              _valuesStartRepeat[property] = _valuesEnd[property];
6395              _valuesEnd[property] = tmp;
6396            }
6397
6398            _valuesStart[property] = _valuesStartRepeat[property];
6399
6400          }
6401
6402          if (_yoyo) {
6403            _reversed = !_reversed;
6404          }
6405
6406          _startTime = time + _delayTime;
6407
6408          return true;
6409
6410        } else {
6411
6412          if (_onCompleteCallback !== null) {
6413            _onCompleteCallback.call(_object);
6414          }
6415
6416          for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) {
6417            // Make the chained tweens start exactly at the time they should,
6418            // even if the `update()` method was called way past the duration of the tween
6419            _chainedTweens[i].start(_startTime + _duration);
6420          }
6421
6422          return false;
6423
6424        }
6425
6426      }
6427
6428      return true;
6429
6430    };
6431
6432  };
6433
6434  TWEEN.Easing = {
6435
6436    Linear: {
6437
6438      None: function (k) {
6439
6440        return k;
6441
6442      }
6443
6444    },
6445
6446    Quadratic: {
6447
6448      In: function (k) {
6449
6450        return k * k;
6451
6452      },
6453
6454      Out: function (k) {
6455
6456        return k * (2 - k);
6457
6458      },
6459
6460      InOut: function (k) {
6461
6462        if ((k *= 2) < 1) {
6463          return 0.5 * k * k;
6464        }
6465
6466        return -0.5 * (--k * (k - 2) - 1);
6467
6468      }
6469
6470    },
6471    Quartic: {
6472
6473      In: function (k) {
6474
6475        return k * k * k * k;
6476
6477      },
6478
6479      Out: function (k) {
6480
6481        return 1 - (--k * k * k * k);
6482
6483      },
6484
6485      InOut: function (k) {
6486
6487        if ((k *= 2) < 1) {
6488          return 0.5 * k * k * k * k;
6489        }
6490
6491        return -0.5 * ((k -= 2) * k * k * k - 2);
6492
6493      }
6494
6495    },
6496    Sinusoidal: {
6497
6498      In: function (k) {
6499
6500        return 1 - Math.cos(k * Math.PI / 2);
6501
6502      },
6503
6504      Out: function (k) {
6505
6506        return Math.sin(k * Math.PI / 2);
6507
6508      },
6509
6510      InOut: function (k) {
6511
6512        return 0.5 * (1 - Math.cos(Math.PI * k));
6513
6514      }
6515
6516    },
6517    Cubic: {
6518
6519      In: function (k) {
6520
6521        return k * k * k;
6522
6523      },
6524
6525      Out: function (k) {
6526
6527        return --k * k * k + 1;
6528
6529      },
6530
6531      InOut: function (k) {
6532
6533        if ((k *= 2) < 1) {
6534          return 0.5 * k * k * k;
6535        }
6536
6537        return 0.5 * ((k -= 2) * k * k + 2);
6538
6539      }
6540
6541    }
6542
6543  };
6544
6545  TWEEN.Interpolation = {
6546
6547    Linear: function (v, k) {
6548
6549      var m = v.length - 1;
6550      var f = m * k;
6551      var i = Math.floor(f);
6552      var fn = TWEEN.Interpolation.Utils.Linear;
6553
6554      if (k < 0) {
6555        return fn(v[0], v[1], f);
6556      }
6557
6558      if (k > 1) {
6559        return fn(v[m], v[m - 1], m - f);
6560      }
6561
6562      return fn(v[i], v[i + 1 > m ? m : i + 1], f - i);
6563
6564    },
6565
6566    Bezier: function (v, k) {
6567
6568      var b = 0;
6569      var n = v.length - 1;
6570      var pw = Math.pow;
6571      var bn = TWEEN.Interpolation.Utils.Bernstein;
6572
6573      for (var i = 0; i <= n; i++) {
6574        b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i);
6575      }
6576
6577      return b;
6578
6579    },
6580
6581    Utils: {
6582
6583      Linear: function (p0, p1, t) {
6584
6585        return (p1 - p0) * t + p0;
6586
6587      },
6588
6589      Bernstein: function (n, i) {
6590
6591        var fc = TWEEN.Interpolation.Utils.Factorial;
6592
6593        return fc(n) / fc(i) / fc(n - i);
6594
6595      },
6596
6597      Factorial: (function () {
6598
6599        var a = [1];
6600
6601        return function (n) {
6602
6603          var s = 1;
6604
6605          if (a[n]) {
6606            return a[n];
6607          }
6608
6609          for (var i = n; i > 1; i--) {
6610            s *= i;
6611          }
6612
6613          a[n] = s;
6614          return s;
6615
6616        };
6617
6618      })(),
6619
6620      CatmullRom: function (p0, p1, p2, p3, t) {
6621
6622        var v0 = (p2 - p0) * 0.5;
6623        var v1 = (p3 - p1) * 0.5;
6624        var t2 = t * t;
6625        var t3 = t * t2;
6626
6627        return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
6628
6629      }
6630
6631    }
6632  };
6633
6634  window.TWEEN = TWEEN;
6635})();
6636
6637DFLIP.createBlob = function createBlob(data, contentType) {
6638  if (typeof Blob !== 'undefined') {
6639    return new Blob([data], {type: contentType});
6640  }
6641  // Blob builder is deprecated in FF14 and removed in FF18.
6642  var bb = new MozBlobBuilder();
6643  bb.append(data);
6644  return bb.getBlob(contentType);
6645};
6646
6647DFLIP.createObjectURL = (function createObjectURLClosure() {
6648  // Blob/createObjectURL is not available, falling back to data schema.
6649  var digits =
6650    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
6651
6652  return function createObjectURL(data, contentType) {
6653    if (typeof URL !== 'undefined' && URL.createObjectURL) {
6654      var blob = DFLIP.createBlob(data, contentType);
6655      return URL.createObjectURL(blob);
6656    }
6657
6658    var buffer = 'data:' + contentType + ';base64,';
6659    for (var i = 0, ii = data.length; i < ii; i += 3) {
6660      var b1 = data[i] & 0xFF;
6661      var b2 = data[i + 1] & 0xFF;
6662      var b3 = data[i + 2] & 0xFF;
6663      var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
6664      var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
6665      var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
6666      buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
6667    }
6668    return buffer;
6669  };
6670})();
6671
6672var ThumbList = (function ThumbListClosure() {
6673  function ThumbList(config) {
6674    var width = (config && config.w + 'px') || '100%';
6675    var height = (config && config.h + 'px') || '100%';
6676    var itemHeight = this.itemHeight = config.itemHeight;
6677
6678    this.items = config.items;
6679    this.generatorFn = config.generatorFn;
6680    this.totalRows = config.totalRows || (config.items && config.items.length);
6681
6682    this.addFn = config.addFn;
6683    this.scrollFn = config.scrollFn;
6684
6685    var scroller = ThumbList.createScroller(itemHeight * this.totalRows);
6686    this.container = ThumbList.createContainer(width, height);
6687    this.container.appendChild(scroller);
6688
6689    this.screenItemsLen = Math.ceil(config.h / itemHeight);
6690    this.offsetItems = this.screenItemsLen;
6691    // Cache 4 times the number of items that fit in the container viewport
6692    this.cachedItemsLen = this.screenItemsLen + this.offsetItems * 2;
6693    this._renderChunk(this.container, 0);
6694
6695    var self = this;
6696    self.lastRepaintY = 0;
6697    var maxBuffer = this.screenItemsLen * itemHeight;
6698    var lastScrolled = 0;
6699
6700    var requestInterval;
6701
6702    function onScroll(e) {
6703      var scrollTop = e.target.scrollTop; // Triggers reflow
6704      if (!self.lastRepaintY || Math.abs(scrollTop - self.lastRepaintY) >= (self.offsetItems * self.itemHeight)) {
6705        var first = parseInt(scrollTop / itemHeight, 10) - self.offsetItems;
6706        self._renderChunk(self.container, first < 0 ? 0 : first);
6707        self.lastRepaintY = scrollTop;
6708      }
6709
6710      self.lastScrolled = lastScrolled = Date.now();
6711
6712      if (self.scrollFn != null) {
6713        self.scrollFn();
6714      }
6715
6716      e.preventDefault && e.preventDefault();
6717    }
6718
6719    self.dispose = function () {
6720      if (self.container) {
6721        if (self.container.parentNode) {
6722          self.container.parentNode.removeChild(self.container);
6723        }
6724      }
6725
6726      self.container.removeEventListener('scroll', onScroll);
6727    };
6728
6729    self.container.addEventListener('scroll', onScroll);
6730  }
6731
6732  ThumbList.prototype.reset = function (height) {
6733
6734    //container.find(".df-vrow").remove();
6735    this.screenItemsLen = Math.ceil(height / this.itemHeight);
6736    this.cachedItemsLen = this.screenItemsLen + this.offsetItems * 2;
6737    var first = parseInt(this.lastRepaintY / this.itemHeight, 10) - this.offsetItems;
6738    //this.lastRepaintY = 0;
6739    this.needReset = true;
6740    this._renderChunk(this.container, Math.max(first, 0));
6741  };
6742
6743  ThumbList.prototype.createRow = function (i) {
6744    var item;
6745    if (this.generatorFn) {
6746      item = this.generatorFn(i);
6747      item.classList.add('df-vrow');
6748      item.style.position = 'absolute';
6749      item.style.top = (i * this.itemHeight) + 'px';
6750      item.setAttribute("index", i);
6751    }
6752    return item;
6753  };
6754
6755  /**
6756   * Renders a particular, consecutive chunk of the total rows in the list. To
6757   * keep acceleration while scrolling, we mark the nodes that are candidate for
6758   * deletion instead of deleting them right away, which would suddenly stop the
6759   * acceleration. We delete them once scrolling has finished.
6760   *
6761   * @param {Node} node Parent node where we want to append the children chunk.
6762   * @param {Number} from Starting position, i.e. first children index.
6763   * @return {void}
6764   */
6765  ThumbList.prototype._renderChunk = function (node, from) {
6766    var isEmpty = this.range == null;
6767    this.range = this.range || {min: 0, max: this.cachedItemsLen};
6768    var range = this.range;
6769
6770    var min = range.min, max = range.max;
6771
6772    var isAdd = isEmpty ? true : from >= min;
6773
6774    if (!isEmpty && from == min && this.needReset == false) return;
6775
6776    var countVar;
6777
6778    var start = isEmpty ? min : isAdd ? max : from;// - this.cachedItemsLen/3;
6779
6780    start = start > this.totalRows ? this.totalRows
6781      : start < 0 ? 0 : start;
6782
6783    var end = from + this.cachedItemsLen;//this.cachedItemsLen/3);
6784
6785    end = end > this.totalRows ? this.totalRows : end;
6786
6787    for (countVar = start; countVar < end; countVar++) {
6788      if (isAdd)
6789        node.appendChild(this.createRow(countVar));
6790      else
6791        node.insertBefore(this.createRow(countVar), node.childNodes[1 + countVar - start]);
6792      if (this.addFn != null) {
6793        this.addFn(countVar);
6794      }
6795    }
6796    var difference = Math.abs(from - min);
6797    this.needReset = false;
6798    if (!isEmpty && node.childNodes.length > (this.cachedItemsLen + 1)) {
6799      // Hide and mark obsolete nodes for deletion.
6800      var delStart = isAdd ? 1 : 1 + this.cachedItemsLen,
6801        delEnd = delStart + (end - start);
6802
6803      for (var j = delEnd; j > delStart; j--) {
6804        if (node.childNodes[delStart])
6805          this.container.removeChild(node.childNodes[delStart]);
6806      }
6807    }
6808    this.range.min = from;
6809    this.range.max = end;
6810  };
6811
6812  ThumbList.createContainer = function (w, h) {
6813    var c = document.createElement('div');
6814    c.style.width = w;
6815    c.style.height = h;
6816    c.style.overflow = 'auto';
6817    c.style.position = 'relative';
6818    c.style.padding = 0;
6819    //c.style.border = '1px solid black';
6820    return c;
6821  };
6822
6823  ThumbList.createScroller = function (h) {
6824    var scroller = document.createElement('div');
6825    scroller.style.opacity = 0;
6826    scroller.style.position = 'absolute';
6827    scroller.style.top = 0;
6828    scroller.style.left = 0;
6829    scroller.style.width = '1px';
6830    scroller.style.height = h + 'px';
6831    return scroller;
6832  };
6833  return ThumbList;
6834})();
6835
6836
6837/**
6838 * @typedef {Object} BookMarkViewerOptions
6839 * @property {HTMLDivElement} container - The viewer element.
6840 * @property {IPDFLinkService} linkService - The navigation/linking service.
6841 */
6842
6843/**
6844 * @typedef {Object} BookMarkViewerRenderParameters
6845 * @property {Array|null} outline - An array of outline objects.
6846 */
6847
6848/**
6849 * @class
6850 */
6851var BookMarkViewer = (function BookMarkViewerClosure() {
6852  /**
6853   * @constructs BookMarkViewer
6854   * @param {BookMarkViewerOptions} options
6855   */
6856  function BookMarkViewer(options) {
6857    this.outline = null;
6858    this.lastToggleIsShow = true;
6859    this.container = options.container;
6860    this.linkService = options.linkService;
6861    this.outlineItemClass = options.outlineItemClass || "outlineItem";
6862    this.outlineToggleClass = options.outlineToggleClass || "outlineItemToggler";
6863    this.outlineToggleHiddenClass = options.outlineToggleHiddenClass || "outlineItemsHidden";
6864  }
6865
6866  BookMarkViewer.prototype = {
6867
6868    dispose: function () {
6869      if (this.container) {
6870        if (this.container.parentNode) {
6871          this.container.parentNode.removeChild(this.container);
6872        }
6873      }
6874      this.linkService = null;
6875
6876    },
6877    reset: function BookMarkViewer_reset() {
6878      this.outline = null;
6879      this.lastToggleIsShow = true;
6880
6881      var container = this.container;
6882      while (container.firstChild) {
6883        container.removeChild(container.firstChild);
6884      }
6885    },
6886
6887    /**
6888     * @private
6889     */
6890    _dispatchEvent: function BookMarkViewer_dispatchEvent(outlineCount) {
6891      var event = document.createEvent('CustomEvent');
6892      event.initCustomEvent('outlineloaded', true, true, {
6893        outlineCount: outlineCount
6894      });
6895      this.container.dispatchEvent(event);
6896    },
6897
6898    /**
6899     * @private
6900     */
6901    _bindLink: function BookMarkViewer_bindLink(element, item) {
6902      var linkService = this.linkService;
6903      if (item.custom == true) {
6904        element.href = linkService.getCustomDestinationHash(item.dest);
6905        element.onclick = function goToDestination(e) {
6906          linkService.customNavigateTo(item.dest);
6907          return false;
6908        };
6909      }
6910      else {
6911        if (item.url) {
6912          PDFJS.addLinkAttributes(element, {url: item.url});
6913          return;
6914        }
6915
6916        element.href = linkService.getDestinationHash(item.dest);
6917        element.onclick = function goToDestination(e) {
6918          linkService.navigateTo(item.dest);
6919          return false;
6920        };
6921      }
6922    },
6923
6924    /**
6925     * Prepend a button before an outline item which allows the user to toggle
6926     * the visibility of all outline items at that level.
6927     *
6928     * @private
6929     */
6930    _addToggleButton: function BookMarkViewer_addToggleButton(div) {
6931      var toggler = document.createElement('div');
6932      toggler.className = this.outlineToggleClass + " " + this.outlineToggleHiddenClass;
6933      toggler.onclick = function (event) {
6934        event.stopPropagation();
6935        toggler.classList.toggle(this.outlineToggleHiddenClass);
6936
6937        if (event.shiftKey) {
6938          var shouldShowAll = !toggler.classList.contains(this.outlineToggleHiddenClass);
6939          this._toggleOutlineItem(div, shouldShowAll);
6940        }
6941      }.bind(this);
6942      div.insertBefore(toggler, div.firstChild);
6943    },
6944
6945    /**
6946     * Toggle the visibility of the subtree of an outline item.
6947     *
6948     * @param {Element} root - the root of the outline (sub)tree.
6949     * @param {boolean} show - whether to show the outline (sub)tree. If false,
6950     *   the outline subtree rooted at |root| will be collapsed.
6951     *
6952     * @private
6953     */
6954    _toggleOutlineItem: function BookMarkViewer_toggleOutlineItem(root, show) {
6955      this.lastToggleIsShow = show;
6956      var togglers = root.querySelectorAll('.' + this.outlineToggleClass);
6957      for (var i = 0, ii = togglers.length; i < ii; ++i) {
6958        togglers[i].classList[show ? 'remove' : 'add'](this.outlineToggleHiddenClass);
6959      }
6960    },
6961
6962    /**
6963     * Collapse or expand all subtrees of the outline.
6964     */
6965    toggleOutlineTree: function BookMarkViewer_toggleOutlineTree() {
6966      if (!this.outline) {
6967        return;
6968      }
6969      this._toggleOutlineItem(this.container, !this.lastToggleIsShow);
6970    },
6971
6972    /**
6973     * @param {BookMarkViewerRenderParameters} params
6974     */
6975    render: function BookMarkViewer_render(params) {
6976      var outline = (params && params.outline) || null;
6977      var outlineCount = 0;
6978
6979      if (this.outline) {
6980        this.reset();
6981      }
6982      this.outline = outline;
6983
6984      if (!outline) {
6985        //this._dispatchEvent(outlineCount);
6986        return;
6987      }
6988
6989      var fragment = document.createDocumentFragment();
6990      var queue = [{parent: fragment, items: this.outline}];
6991      var hasAnyNesting = false;
6992      while (queue.length > 0) {
6993        var levelData = queue.shift();
6994        var isCustom = levelData.custom;
6995        for (var i = 0, len = levelData.items.length; i < len; i++) {
6996          var item = levelData.items[i];
6997
6998          var div = document.createElement('div');
6999          div.className = this.outlineItemClass;
7000
7001          var element = document.createElement('a');
7002          if (item.custom == null && isCustom != null)
7003            item.custom = isCustom;
7004
7005          this._bindLink(element, item);
7006          //element.
7007          element.textContent = item.title.replace(/\x00/g, '');
7008          //PDFJS.removeNullCharacters(item.title) || "Untitled Bookmark";
7009
7010          div.appendChild(element);
7011
7012          if (item.items && item.items.length > 0) {
7013            hasAnyNesting = true;
7014            this._addToggleButton(div);
7015
7016            var itemsDiv = document.createElement('div');
7017            itemsDiv.className = this.outlineItemClass + "s";
7018            div.appendChild(itemsDiv);
7019            queue.push({parent: itemsDiv, custom: item.custom, items: item.items});
7020          }
7021
7022          levelData.parent.appendChild(div);
7023          outlineCount++;
7024        }
7025      }
7026      if (hasAnyNesting) {
7027        if (this.container.classList != null) {
7028          this.container.classList.add(this.outlineItemClass + "s");
7029        }
7030        else if (this.container.className != null) {
7031          this.container.className += " picWindow";
7032        }
7033      }
7034
7035      this.container.appendChild(fragment);
7036
7037      this._dispatchEvent(outlineCount);
7038    }
7039
7040  };
7041
7042  return BookMarkViewer;
7043})();
7044//PDFJS.PDFOutlineViewer = PDFOutlineViewer;
7045
7046var DFLightBox = (function DFLightBoxClosure($) {
7047  /**
7048   * @constructs DFLightBox
7049   * @param closeCallback callBack function required to dispose object properly when lighbox is closed
7050   */
7051  function DFLightBox(closeCallback, options) {
7052
7053    this.duration = 300;
7054
7055    //cache this
7056    var _this = this;
7057    //lightbox wrapper div
7058    _this.lightboxWrapper = $("<div>").addClass("df-lightbox-wrapper");
7059
7060    //lightbox container
7061    _this.container = $("<div>").addClass("df-container").appendTo(_this.lightboxWrapper);
7062    //lightbox controls
7063    _this.controls = $("<div>").addClass("df-lightbox-controls").appendTo(_this.lightboxWrapper);
7064
7065    //lightbox close button
7066    _this.closeButton = $("<div>").addClass("df-lightbox-close df-ui-btn")
7067      .on("click", function () {
7068        _this.close(closeCallback);
7069      })
7070      .appendTo(_this.controls);
7071
7072    _this.lightboxWrapper.append(_this.container);
7073
7074    return _this;
7075  }
7076
7077  DFLightBox.prototype.show = function (callback) {
7078
7079    if (this.lightboxWrapper.parent().length == 0)
7080      $("body").append(this.lightboxWrapper);
7081
7082    this.lightboxWrapper.fadeIn(this.duration, callback);
7083
7084    return this;
7085  };
7086
7087  DFLightBox.prototype.close = function (callback) {
7088
7089    this.lightboxWrapper.fadeOut(this.duration);
7090    setTimeout(callback, this.duration);
7091
7092    return this;
7093  };
7094
7095  return DFLightBox;
7096})(jQuery);
7097
7098DFLIP.Share = (function ShareClosure($) {
7099
7100  function Share(container, options) {
7101    var _this = this;
7102    var htmlDiv = '<div>';
7103    var shareButtonClass = "df-share-button";
7104    var windowParameters = "width=500,height=400";
7105    _this.isOpen = false;
7106    _this.shareUrl = "";
7107    _this.wrapper = $('<div class="df-share-wrapper" style="display: none;">')
7108      .on("click", function (e) {
7109        _this.close();
7110      });
7111    _this.box = $('<div class="df-share-box">')
7112      .on("click", function (e) {
7113        e.preventDefault();
7114        e.stopPropagation();
7115      }).appendTo(_this.wrapper).html('<span class="df-share-title">' + options.text.share + '</span>');
7116    _this.urlInput = $('<textarea class="df-share-url">').on("click", function () {
7117      $(this).select();
7118    });
7119
7120    _this.facebook = $(htmlDiv, {
7121      class: shareButtonClass + " df-share-facebook " + options.icons['facebook']
7122    }).on("click", function (e) {
7123      window.open('https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(_this.shareUrl), "Sharer", windowParameters);
7124    });
7125    _this.google = $(htmlDiv, {
7126      class: shareButtonClass + " df-share-google " + options.icons['google']
7127    }).on("click", function (e) {
7128      window.open('https://plus.google.com/share?url=' + encodeURIComponent(_this.shareUrl), "Sharer", windowParameters);
7129    });
7130    _this.twitter = $(htmlDiv, {
7131      class: shareButtonClass + " df-share-twitter " + options.icons['twitter']
7132    }).on("click", function (e) {
7133      window.open('http://twitter.com/share?url=' + encodeURIComponent(_this.shareUrl), "Sharer", windowParameters);
7134    });
7135    _this.mail = $('<a>', {
7136      class: shareButtonClass + " df-share-mail " + options.icons['mail'],
7137      href: 'mailto:?subject=I wanted you to see this FlipBook&body=Check out this site ' + encodeURIComponent(_this.shareUrl),
7138      target: '_blank'
7139    }).on("click", function (e) {
7140      $(this).attr('href', 'mailto:?subject=I wanted you to see this FlipBook&body=Check out this site ' + encodeURIComponent(_this.shareUrl));
7141      e.stopPropagation();//so the default event is not cancelled by parent element
7142    });
7143
7144    _this.box.append(_this.urlInput).append(_this.facebook).append(_this.google).append(_this.twitter).append(_this.mail);
7145    $(container).append(_this.wrapper);
7146
7147  }
7148
7149  Share.prototype.show = function () {
7150    this.wrapper.fadeIn(300);
7151    this.urlInput.val(this.shareUrl);
7152    this.urlInput.trigger("click");
7153    this.isOpen = true;
7154  }
7155
7156  Share.prototype.dispose = function () {
7157    var _this = this;
7158    _this.box.off();
7159    _this.google.off();
7160    _this.twitter.off();
7161    _this.facebook.off();
7162    _this.mail.off();
7163    _this.urlInput.off();
7164    _this.wrapper.off().remove();
7165  }
7166
7167  Share.prototype.close = function () {
7168    this.wrapper.fadeOut(300);
7169    this.isOpen = false;
7170  }
7171
7172  Share.prototype.update = function (url) {
7173    this.shareUrl = url;
7174  }
7175
7176  return Share;
7177})(jQuery);
7178DFLIP.Popup = (function PopupClosure($) {
7179
7180  function Popup(container, options) {
7181    var _this = this;
7182    var htmlDiv = '<div>';
7183    var windowParameters = "width=500,height=400";
7184    _this.isOpen = false;
7185    _this.wrapper = $('<div class="df-popup-wrapper" style="display: none;">')
7186      .on("click", function (e) {
7187        _this.close();
7188      });
7189    _this.box = $('<div class="df-popup-box">')
7190      .on("click", function (e) {
7191        e.preventDefault();
7192        e.stopPropagation();
7193      }).appendTo(_this.wrapper);
7194
7195    $(container).append(_this.wrapper);
7196
7197  }
7198
7199  Popup.prototype.show = function () {
7200    this.wrapper.fadeIn(300);
7201    this.isOpen = true;
7202  }
7203
7204  Popup.prototype.dispose = function () {
7205    var _this = this;
7206    _this.box.off();
7207    _this.wrapper.off().remove();
7208  }
7209
7210  Popup.prototype.close = function () {
7211    this.wrapper.fadeOut(300);
7212    this.isOpen = false;
7213  }
7214
7215  return Popup;
7216})(jQuery);
7217
7218/**
7219 * Performs navigation functions inside PDF, such as opening specified page,
7220 * or destination.
7221 * @class
7222 * @implements {IPDFLinkService}
7223 */
7224var PDFLinkService = (function () {
7225  /**
7226   * @constructs PDFLinkService
7227   */
7228  function PDFLinkService() {
7229    this.baseUrl = null;
7230    this.pdfDocument = null;
7231    this.pdfViewer = null;
7232    this.pdfHistory = null;
7233
7234    this._pagesRefCache = null;
7235  }
7236
7237  PDFLinkService.prototype = {
7238    dispose: function () {
7239      this.baseUrl = null;
7240      this.pdfDocument = null;
7241      this.pdfViewer = null;
7242      this.pdfHistory = null;
7243
7244      this._pagesRefCache = null;
7245    },
7246    setDocument: function PDFLinkService_setDocument(pdfDocument, baseUrl) {
7247      this.baseUrl = baseUrl;
7248      this.pdfDocument = pdfDocument;
7249      this._pagesRefCache = Object.create(null);
7250    },
7251
7252    setViewer: function PDFLinkService_setViewer(pdfViewer) {
7253      this.pdfViewer = pdfViewer;
7254    },
7255
7256    setHistory: function PDFLinkService_setHistory(pdfHistory) {
7257      this.pdfHistory = pdfHistory;
7258    },
7259
7260    /**
7261     * @returns {number}
7262     */
7263    get pagesCount() {
7264      return this.pdfDocument.numPages;
7265    },
7266
7267    /**
7268     * @returns {number}
7269     */
7270    get page() {
7271      return this.pdfViewer.currentPageNumber;
7272    },
7273
7274    /**
7275     * @param {number} value
7276     */
7277    set page(value) {
7278      this.pdfViewer.currentPageNumber = value;
7279    },
7280
7281    /**
7282     * @param dest - The PDF destination object.
7283     */
7284    navigateTo: function PDFLinkService_navigateTo(dest) {
7285      var destString = '';
7286      var self = this;
7287
7288      var goToDestination = function (destRef) {
7289        // dest array looks like that: <page-ref> </XYZ|FitXXX> <args..>
7290        var pageNumber = destRef instanceof Object ? self._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R']
7291          : (destRef + 1);
7292        if (pageNumber) {
7293          //case double internal
7294          if (self.pdfViewer.contentProvider.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2) {
7295            pageNumber = pageNumber * 2 - 1;
7296          }
7297
7298          if (pageNumber >
7298 self.pdfViewer.pageCount) {
7299            pageNumber = self.pdfViewer.pageCount;
7300          }
7301          self.pdfViewer.gotoPage(pageNumber);
7302          // self.pdfViewer.scrollPageIntoView(pageNumber, dest);
7303
7304          if (self.pdfHistory) {
7305            // Update the browsing history.
7306            self.pdfHistory.push({
7307              dest: dest,
7308              hash: destString,
7309              page: pageNumber
7310            });
7311          }
7312        } else {
7313          self.pdfDocument.getPageIndex(destRef).then(function (pageIndex) {
7314            var pageNum = pageIndex + 1;
7315            var cacheKey = destRef.num + ' ' + destRef.gen + ' R';
7316            self._pagesRefCache[cacheKey] = pageNum;
7317            goToDestination(destRef);
7318          });
7319        }
7320      };
7321
7322      var destinationPromise;
7323      if (typeof dest === 'string') {
7324        destString = dest;
7325        destinationPromise = this.pdfDocument.getDestination(dest);
7326      } else {
7327        destinationPromise = Promise.resolve(dest);
7328      }
7329      destinationPromise.then(function (destination) {
7330        dest = destination;
7331        if (!(destination instanceof Array)) {
7332          return; // invalid destination
7333        }
7334        goToDestination(destination[0]);
7335      });
7336    },
7337
7338
7339    /**
7340     * @param dest - The PDF destination object.
7341     */
7342    customNavigateTo: function PDFLinkService_navigateTo(dest) {
7343      if (dest == '' || dest == null || dest == 'null') return;
7344      var pageNumber = null;
7345      if (!isNaN(Math.round(dest))) {
7346        pageNumber = dest;
7347      }
7348      else if (typeof dest === 'string') {
7349        pageNumber = parseInt(dest.replace("#", ""), 10);
7350        if (isNaN(pageNumber)) {
7351          window.open(dest);
7352          return;
7353        }
7354      }
7355
7356      if (pageNumber != null)
7357        this.pdfViewer.gotoPage(pageNumber);
7358
7359    },
7360
7361    /**
7362     * @param dest - The PDF destination object.
7363     * @returns {string} The hyperlink to the PDF object.
7364     */
7365    getDestinationHash: function PDFLinkService_getDestinationHash(dest) {
7366      if (typeof dest === 'string') {
7367        return this.getAnchorUrl('#' + escape(dest));
7368      }
7369      if (dest instanceof Array) {
7370        var destRef = dest[0]; // see navigateTo method for dest format
7371        var pageNumber = destRef instanceof Object ? this._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R']
7372          : (destRef + 1);
7373        if (pageNumber) {
7374          var pdfOpenParams = this.getAnchorUrl('#page=' + pageNumber);
7375          var destKind = dest[1];
7376          if (typeof destKind === 'object' && 'name' in destKind &&
7377            destKind.name === 'XYZ') {
7378            var scale = (dest[4] || this.pdfViewer.currentScaleValue);
7379            var scaleNumber = parseFloat(scale);
7380            if (scaleNumber) {
7381              scale = scaleNumber * 100;
7382            }
7383            pdfOpenParams += '&zoom=' + scale;
7384            if (dest[2] || dest[3]) {
7385              pdfOpenParams += ',' + (dest[2] || 0) + ',' + (dest[3] || 0);
7386            }
7387          }
7388          return pdfOpenParams;
7389        }
7390      }
7391      return this.getAnchorUrl('');
7392    },
7393
7394    /**
7395     * @param dest - The PDF destination object.
7396     * @returns {string} The hyperlink to the PDF object.
7397     */
7398    getCustomDestinationHash: function PDFLinkService_getCustomDestinationHash(dest) {
7399      //if (typeof dest === 'string') {
7400      return '#' + escape(dest);
7401      //}
7402      //return this.getAnchorUrl('');
7403    },
7404
7405
7406    /**
7407     * Prefix the full url on anchor links to make sure that links are resolved
7408     * relative to the current URL instead of the one defined in <base href>.
7409     * @param {String} anchor The anchor hash, including the #.
7410     * @returns {string} The hyperlink to the PDF object.
7411     */
7412    getAnchorUrl: function PDFLinkService_getAnchorUrl(anchor) {
7413      return (this.baseUrl || '') + anchor;
7414    },
7415
7416    /**
7417     * @param {string} hash
7418     */
7419    setHash: function PDFLinkService_setHash(hash) {
7420      if (hash.indexOf('=') >= 0) {
7421        var params = parseQueryString(hash);
7422        // borrowing syntax from "Parameters for Opening PDF Files"
7423        if ('nameddest' in params) {
7424          if (this.pdfHistory) {
7425            this.pdfHistory.updateNextHashParam(params.nameddest);
7426          }
7427          this.navigateTo(params.nameddest);
7428          return;
7429        }
7430        var pageNumber, dest;
7431        if ('page' in params) {
7432          pageNumber = (params.page | 0) || 1;
7433        }
7434        if ('zoom' in params) {
7435          // Build the destination array.
7436          var zoomArgs = params.zoom.split(','); // scale,left,top
7437          var zoomArg = zoomArgs[0];
7438          var zoomArgNumber = parseFloat(zoomArg);
7439
7440          if (zoomArg.indexOf('Fit') === -1) {
7441            // If the zoomArg is a number, it has to get divided by 100. If it's
7442            // a string, it should stay as it is.
7443            dest = [null, {name: 'XYZ'},
7444              zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null,
7445              zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null,
7446              (zoomArgNumber ? zoomArgNumber / 100 : zoomArg)];
7447          } else {
7448            if (zoomArg === 'Fit' || zoomArg === 'FitB') {
7449              dest = [null, {name: zoomArg}];
7450            } else if ((zoomArg === 'FitH' || zoomArg === 'FitBH') ||
7451              (zoomArg === 'FitV' || zoomArg === 'FitBV')) {
7452              dest = [null, {name: zoomArg},
7453                zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null];
7454            } else if (zoomArg === 'FitR') {
7455              if (zoomArgs.length !== 5) {
7456                console.error('PDFLinkService_setHash: ' +
7457                  'Not enough parameters for \'FitR\'.');
7458              } else {
7459                dest = [null, {name: zoomArg},
7460                  (zoomArgs[1] | 0), (zoomArgs[2] | 0),
7461                  (zoomArgs[3] | 0), (zoomArgs[4] | 0)];
7462              }
7463            } else {
7464              console.error('PDFLinkService_setHash: \'' + zoomArg +
7465                '\' is not a valid zoom value.');
7466            }
7467          }
7468        }
7469        if (dest) {
7470          this.pdfViewer.scrollPageIntoView(pageNumber || this.page, dest);
7471        } else if (pageNumber) {
7472          this.page = pageNumber; // simple page
7473        }
7474        if ('pagemode' in params) {
7475          var event = document.createEvent('CustomEvent');
7476          event.initCustomEvent('pagemode', true, true, {
7477            mode: params.pagemode
7478          });
7479          this.pdfViewer.container.dispatchEvent(event);
7480        }
7481      } else if (/^\d+$/.test(hash)) { // page number
7482        this.page = hash;
7483      } else { // named destination
7484        if (this.pdfHistory) {
7485          this.pdfHistory.updateNextHashParam(unescape(hash));
7486        }
7487        this.navigateTo(unescape(hash));
7488      }
7489    },
7490
7491    /**
7492     * @param {string} action
7493     */
7494    executeNamedAction: function PDFLinkService_executeNamedAction(action) {
7495      // See PDF reference, table 8.45 - Named action
7496      switch (action) {
7497        case 'GoBack':
7498          if (this.pdfHistory) {
7499            this.pdfHistory.back();
7500          }
7501          break;
7502
7503        case 'GoForward':
7504          if (this.pdfHistory) {
7505            this.pdfHistory.forward();
7506          }
7507          break;
7508
7509        case 'NextPage':
7510          this.page++;
7511          break;
7512
7513        case 'PrevPage':
7514          this.page--;
7515          break;
7516
7517        case 'LastPage':
7518          this.page = this.pagesCount;
7519          break;
7520
7521        case 'FirstPage':
7522          this.page = 1;
7523          break;
7524
7525        default:
7526          break; // No action according to spec
7527      }
7528
7529      var event = document.createEvent('CustomEvent');
7530      event.initCustomEvent('namedaction', true, true, {
7531        action: action
7532      });
7533      this.pdfViewer.container.dispatchEvent(event);
7534    },
7535
7536    /**
7537     * @param {number} pageNum - page number.
7538     * @param {Object} pageRef - reference to the page.
7539     */
7540    cachePageRef: function PDFLinkService_cachePageRef(pageNum, pageRef) {
7541      var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
7542      this._pagesRefCache[refStr] = pageNum;
7543    }
7544  };
7545
7546  return PDFLinkService;
7547})();
7548//PDFJS.PDFLinkService = PDFLinkService;
7549
7550/**
7551 * @typedef {Object} TextLayerBuilderOptions
7552 * @property {HTMLDivElement} textLayerDiv - The text layer container.
7553 * @property {EventBus} eventBus - The application event bus.
7554 * @property {number} pageIndex - The page index.
7555 * @property {PageViewport} viewport - The viewport of the text layer.
7556 * @property {PDFFindController} findController
7557 * @property {boolean} enhanceTextSelection - Option to turn on improved
7558 *   text selection.
7559 */
7560
7561/**
7562 * TextLayerBuilder provides text-selection functionality for the PDF.
7563 * It does this by creating overlay divs over the PDF text. These divs
7564 * contain text that matches the PDF text they are overlaying. This object
7565 * also provides a way to highlight text that is being searched for.
7566 * @class
7567 */
7568DFLIP.TextLayerBuilder = (function TextLayerBuilderClosure() {
7569  function TextLayerBuilder(options) {
7570    this.textLayerDiv = options.textLayerDiv;
7571    this.renderingDone = false;
7572    this.divContentDone = false;
7573    this.pageIdx = options.pageIndex;
7574    this.pageNumber = this.pageIdx + 1;
7575    this.matches = [];
7576    this.viewport = options.viewport;
7577    this.textDivs = [];
7578    this.findController = options.findController || null;
7579    this.textLayerRenderTask = null;
7580    this.enhanceTextSelection = options.enhanceTextSelection;
7581    this._bindMouse();
7582  }
7583
7584  TextLayerBuilder.prototype = {
7585    _finishRendering: function TextLayerBuilder_finishRendering() {
7586      this.renderingDone = true;
7587
7588      if (!this.enhanceTextSelection) {
7589        var endOfContent = document.createElement('div');
7590        endOfContent.className = 'endOfContent';
7591        this.textLayerDiv.appendChild(endOfContent);
7592      }
7593
7594      /*			this.eventBus.dispatch('textlayerrendered', {
7595       source: this,
7596       pageNumber: this.pageNumber
7597       });*/
7598    },
7599
7600    /**
7601     * Renders the text layer.
7602     * @param {number} timeout (optional) if specified, the rendering waits
7603     *   for specified amount of ms.
7604     */
7605    render: function TextLayerBuilder_render(timeout) {
7606      if (!this.divContentDone || this.renderingDone) {
7607        return;
7608      }
7609
7610      if (this.textLayerRenderTask) {
7611        this.textLayerRenderTask.cancel();
7612        this.textLayerRenderTask = null;
7613      }
7614
7615      this.textDivs = [];
7616      var textLayerFrag = document.createDocumentFragment();
7617      this.textLayerRenderTask = PDFJS.renderTextLayer({
7618        textContent: this.textContent,
7619        container: textLayerFrag,
7620        viewport: this.viewport,
7621        textDivs: this.textDivs,
7622        timeout: timeout,
7623        enhanceTextSelection: this.enhanceTextSelection,
7624      });
7625      this.textLayerRenderTask.promise.then(function () {
7626        this.textLayerDiv.appendChild(textLayerFrag);
7627        this._finishRendering();
7628        this.updateMatches();
7629      }.bind(this), function (reason) {
7630        // canceled or failed to render text layer -- skipping errors
7631      });
7632    },
7633
7634    setTextContent: function TextLayerBuilder_setTextContent(textContent) {
7635      if (this.textLayerRenderTask) {
7636        this.textLayerRenderTask.cancel();
7637        this.textLayerRenderTask = null;
7638      }
7639      this.textContent = textContent;
7640      this.divContentDone = true;
7641    },
7642
7643    convertMatches: function TextLayerBuilder_convertMatches(matches,
7644                                                             matchesLength) {
7645      var i = 0;
7646      var iIndex = 0;
7647      var bidiTexts = this.textContent.items;
7648      var end = bidiTexts.length - 1;
7649      var queryLen = (this.findController === null ? 0 : this.findController.state.query.length);
7650      var ret = [];
7651      if (!matches) {
7652        return ret;
7653      }
7654      for (var m = 0, len = matches.length; m < len; m++) {
7655        // Calculate the start position.
7656        var matchIdx = matches[m];
7657
7658        // Loop over the divIdxs.
7659        while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
7660          iIndex += bidiTexts[i].str.length;
7661          i++;
7662        }
7663
7664        if (i === bidiTexts.length) {
7665          console.error('Could not find a matching mapping');
7666        }
7667
7668        var match = {
7669          begin: {
7670            divIdx: i,
7671            offset: matchIdx - iIndex
7672          }
7673        };
7674
7675        // Calculate the end position.
7676        if (matchesLength) { // multiterm search
7677          matchIdx += matchesLength[m];
7678        } else { // phrase search
7679          matchIdx += queryLen;
7680        }
7681
7682        // Somewhat the same array as above, but use > instead of >= to get
7683        // the end position right.
7684        while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
7685          iIndex += bidiTexts[i].str.length;
7686          i++;
7687        }
7688
7689        match.end = {
7690          divIdx: i,
7691          offset: matchIdx - iIndex
7692        };
7693        ret.push(match);
7694      }
7695
7696      return ret;
7697    },
7698
7699    renderMatches: function TextLayerBuilder_renderMatches(matches) {
7700      // Early exit if there is nothing to render.
7701      if (matches.length === 0) {
7702        return;
7703      }
7704
7705      var bidiTexts = this.textContent.items;
7706      var textDivs = this.textDivs;
7707      var prevEnd = null;
7708      var pageIdx = this.pageIdx;
7709      var isSelectedPage = (this.findController === null ? false : (pageIdx === this.findController.selected.pageIdx));
7710      var selectedMatchIdx = (this.findController === null ? -1 : this.findController.selected.matchIdx);
7711      var highlightAll = (this.findController === null ? false : this.findController.state.highlightAll);
7712      var infinity = {
7713        divIdx: -1,
7714        offset: undefined
7715      };
7716
7717      function beginText(begin, className) {
7718        var divIdx = begin.divIdx;
7719        textDivs[divIdx].textContent = '';
7720        appendTextToDiv(divIdx, 0, begin.offset, className);
7721      }
7722
7723      function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
7724        var div = textDivs[divIdx];
7725        var content = bidiTexts[divIdx].str.substring(fromOffset, toOffset);
7726        var node = document.createTextNode(content);
7727        if (className) {
7728          var span = document.createElement('span');
7729          span.className = className;
7730          span.appendChild(node);
7731          div.appendChild(span);
7732          return;
7733        }
7734        div.appendChild(node);
7735      }
7736
7737      var i0 = selectedMatchIdx, i1 = i0 + 1;
7738      if (highlightAll) {
7739        i0 = 0;
7740        i1 = matches.length;
7741      } else if (!isSelectedPage) {
7742        // Not highlighting all and this isn't the selected page, so do nothing.
7743        return;
7744      }
7745
7746      for (var i = i0; i < i1; i++) {
7747        var match = matches[i];
7748        var begin = match.begin;
7749        var end = match.end;
7750        var isSelected = (isSelectedPage && i === selectedMatchIdx);
7751        var highlightSuffix = (isSelected ? ' selected' : '');
7752
7753        if (this.findController) {
7754          this.findController.updateMatchPosition(pageIdx, i, textDivs,
7755            begin.divIdx);
7756        }
7757
7758        // Match inside new div.
7759        if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
7760          // If there was a previous div, then add the text at the end.
7761          if (prevEnd !== null) {
7762            appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
7763          }
7764          // Clear the divs and set the content until the starting point.
7765          beginText(begin);
7766        } else {
7767          appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);
7768        }
7769
7770        if (begin.divIdx === end.divIdx) {
7771          appendTextToDiv(begin.divIdx, begin.offset, end.offset,
7772            'highlight' + highlightSuffix);
7773        } else {
7774          appendTextToDiv(begin.divIdx, begin.offset, infinity.offset,
7775            'highlight begin' + highlightSuffix);
7776          for (var n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) {
7777            textDivs[n0].className = 'highlight middle' + highlightSuffix;
7778          }
7779          beginText(end, 'highlight end' + highlightSuffix);
7780        }
7781        prevEnd = end;
7782      }
7783
7784      if (prevEnd) {
7785        appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
7786      }
7787    },
7788
7789    updateMatches: function TextLayerBuilder_updateMatches() {
7790      // Only show matches when all rendering is done.
7791      if (!this.renderingDone) {
7792        return;
7793      }
7794
7795      // Clear all matches.
7796      var matches = this.matches;
7797      var textDivs = this.textDivs;
7798      var bidiTexts = this.textContent.items;
7799      var clearedUntilDivIdx = -1;
7800
7801      // Clear all current matches.
7802      for (var i = 0, len = matches.length; i < len; i++) {
7803        var match = matches[i];
7804        var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
7805        for (var n = begin, end = match.end.divIdx; n <= end; n++) {
7806          var div = textDivs[n];
7807          div.textContent = bidiTexts[n].str;
7808          div.className = '';
7809        }
7810        clearedUntilDivIdx = match.end.divIdx + 1;
7811      }
7812
7813      if (this.findController === null || !this.findController.active) {
7814        return;
7815      }
7816
7817      // Convert the matches on the page controller into the match format
7818      // used for the textLayer.
7819      var pageMatches, pageMatchesLength;
7820      if (this.findController !== null) {
7821        pageMatches = this.findController.pageMatches[this.pageIdx] || null;
7822        pageMatchesLength = (this.findController.pageMatchesLength)
7823          ? this.findController.pageMatchesLength[this.pageIdx] || null : null;
7824      }
7825
7826      this.matches = this.convertMatches(pageMatches, pageMatchesLength);
7827      this.renderMatches(this.matches);
7828    },
7829
7830    /**
7831     * Fixes text selection: adds additional div where mouse was clicked.
7832     * This reduces flickering of the content if mouse slowly dragged down/up.
7833     * @private
7834     */
7835    _bindMouse: function TextLayerBuilder_bindMouse() {
7836      var div = this.textLayerDiv;
7837      var self = this;
7838      div.addEventListener('mousedown', function (e) {
7839        if (self.enhanceTextSelection && self.textLayerRenderTask) {
7840          self.textLayerRenderTask.expandTextDivs(true);
7841          return;
7842        }
7843        var end = div.querySelector('.endOfContent');
7844        if (!end) {
7845          return;
7846        }
7847        // On non-Firefox browsers, the selection will feel better if the height
7848        // of the endOfContent div will be adjusted to start at mouse click
7849        // location -- this will avoid flickering when selections moves up.
7850        // However it does not work when selection started on empty space.
7851        var adjustTop = e.target !== div;
7852        adjustTop = adjustTop && window.getComputedStyle(end).getPropertyValue('-moz-user-select') !== 'none';
7853        if (adjustTop) {
7854          var divBounds = div.getBoundingClientRect();
7855          var r = Math.max(0, (e.pageY - divBounds.top) / divBounds.height);
7856          end.style.top = (r * 100).toFixed(2) + '%';
7857        }
7858        end.classList.add('active');
7859      });
7860      div.addEventListener('mouseup', function (e) {
7861        if (self.enhanceTextSelection && self.textLayerRenderTask) {
7862          self.textLayerRenderTask.expandTextDivs(false);
7863          return;
7864        }
7865        var end = div.querySelector('.endOfContent');
7866        if (!end) {
7867          return;
7868        }
7869        end.style.top = '';
7870        end.classList.remove('active');
7871      });
7872    },
7873  };
7874  return TextLayerBuilder;
7875})();
7876
7877DFLIP.ConvertPageLinks = function () {
7878
7879  var w = arguments[0] / 100, h = arguments[1] / 100;
7880
7881  var toPercent = function (_x, _y, _w, _h, _dest) {
7882    return {
7883      x: _x / w,
7884      y: _y / h,
7885      w: _w / w,
7886      h: _h / h,
7887      dest: _dest
7888    };
7889  };
7890
7891  var percents = [];
7892  var input;
7893
7894  for (var index = 2; index < arguments.length; index++) {
7895    input = arguments[index];
7896    percents[index - 2] = toPercent.apply(this, input);
7897  }
7898
7899  return percents;
7900};
7901
7902DFLIP.parseLinks = function (links) {
7903  var _links;
7904  if (links != null && links.length > 0) {
7905    for (var index = 0; index < links.length; index++) {
7906      _links = links[index];
7907
7908      if (_links != null && _links[0] != null && _links[0].dest == null) {
7909
7910        _links = DFLIP.ConvertPageLinks.apply(this, _links);
7911        links[index] = _links;
7912      }
7913    }
7914  }
7915  return links;
7916};
7917
7918/**
7919 * DFLIP.parseBooks
7920 */
7921(function ($) {
7922
7923  //php and javascript interpret booleans differently so we use string checks
7924  function isTrue(val) {
7925    return val == "true" || val == true;
7926  }
7927
7928  function checkValues(options) {
7929
7930    //boolean values
7931    if (options.webgl != null) options.webgl = isTrue(options.webgl);
7932    if (options.enableDownload != null) options.enableDownload = isTrue(options.enableDownload);
7933    if (options.scrollWheel != null) options.scrollWheel = isTrue(options.scrollWheel);
7934    if (options.autoEnableOutline != null) options.autoEnableOutline = isTrue(options.autoEnableOutline);
7935    if (options.autoEnableThumbnail != null) options.autoEnableThumbnail = isTrue(options.autoEnableThumbnail);
7936    if (options.transparent != null) options.transparent = isTrue(options.transparent);
7937    if (options.overwritePDFOutline != null) options.overwritePDFOutline = isTrue(options.overwritePDFOutline);
7938    if (options.soundEnable != null) options.soundEnable = isTrue(options.soundEnable);
7939    if (options.forceFit != null) options.forceFit = isTrue(options.forceFit);
7940    if (options.enableAnnotation != null) options.enableAnnotation = isTrue(options.enableAnnotation);
7941    if (options.webglShadow != null) options.webglShadow = isTrue(options.webglShadow);
7942    if (options.autoPlay != null) options.autoPlay = isTrue(options.autoPlay);
7943    if (options.autoPlayStart != null) options.autoPlayStart = isTrue(options.autoPlayStart);
7944
7945    //integer value
7946    if (options.paddingTop != null) options.paddingTop = parseInt(options.paddingTop, 10);
7947    if (options.paddingRight != null) options.paddingRight = parseInt(options.paddingRight, 10);
7948    if (options.paddingBottom != null) options.paddingBottom = parseInt(options.paddingBottom, 10);
7949    if (options.paddingLeft != null) options.paddingLeft = parseInt(options.paddingLeft, 10);
7950    if (options.zoomRatio != null) options.zoomRatio = parseFloat(options.zoomRatio, 10);
7951    if (options.stiffness != null) options.stiffness = parseFloat(options.stiffness, 10);
7952    if (options.autoPlayDuration != null) options.autoPlayDuration = parseInt(options.autoPlayDuration, 10);
7953
7954    if (options.pageMode == 0 || options.pageMode == "0")
7955      options.pageMode = null;
7956    if (options.singlePageMode == 0 || options.singlePageMode == "0")
7957      options.singlePageMode = null;
7958  }
7959
7960  function parseOptions(options) {
7961
7962    //bail out if already parsed or failed
7963    if (options.parsed == true) return;
7964
7965    options.parsed = true;
7966    //options.links are in json format
7967    //{"1":[]}
7968    //convert them to array format
7969    var links = [];
7970    checkValues(options);
7971
7972    if (typeof dFlipWPGlobal !== 'undefined' && options.wpOptions == 'true') {
7973
7974      try {
7975        for (var key in options.links) {
7976          var _pagelinks = options.links[key];
7977          var pagelink = [100, 100];
7978          for (var l = 0; l < _pagelinks.length; l++) {
7979            var _link = _pagelinks[l];
7980            var _values = _link.substr(1).slice(0, -1).split(",");
7981            var _linkarr = [];
7982            for (var v = 0; v < 5; v++) {
7983              _linkarr[v] = _values[v];
7984            }
7985            pagelink.push(_linkarr);
7986          }
7987          links[parseInt(key, 10) + 1] = pagelink;
7988        }
7989      }
7990      catch (error) {
7991        console.error(error.stack);
7992      }
7993      options.links = DFLIP.parseLinks(links);
7994
7995    } else {
7996      options.links = DFLIP.parseLinks(options.links);
7997    }
7998
7999  }
8000
8001  DFLIP.getOptions = function (book) {
8002
8003    book = $(book);
8004
8005    var book_id = book.attr("id");
8006
8007    var options = "option_" + book_id,
8008      source = book.attr("source") || book.attr("df-source");
8009
8010    //verify and optimize the values
8011    options = options == null || options == "" || window[options] == null ? {} : window[options];
8012
8013    options.source = source == null || source == "" ? options.source : source;
8014
8015    /*As of 1.2.6 attribute values are also considered as options in some cases*/
8016    var attrOptions = {
8017      webgl: book.attr("webgl"),
8018      height: book.attr("height"),
8019      soundEnable: book.attr("sound"),
8020      transparent: book.attr("transparent"),
8021      enableDownload: book.attr("download"),
8022      duration: book.attr("duration"),
8023      hard: book.attr("hard"),
8024      pageMode: book.attr("pagemode"),
8025      direction: book.attr("direction"),
8026      backgroundColor: book.attr("backgroundcolor"),
8027      scrollWheel: book.attr("scrollwheel"),
8028      backgroundImage: book.attr("backgroundimage"),
8029      paddingTop: book.attr("paddingtop"),
8030      paddingRight: book.attr("paddingright"),
8031      paddingBottom: book.attr("paddingbottom"),
8032      paddingLeft: book.attr("paddingleft"),
8033      wpOptions: book.attr("wpoptions")
8034    };
8035
8036    options = $.extend(true, {}, options, attrOptions);
8037
8038    parseOptions(options);
8039
8040    return options;
8041  }
8042
8043  DFLIP.parseBooks = function () {
8044
8045    $('._df_button, ._df_thumb, ._df_custom, ._df_book').each(function () {
8046
8047      var book = $(this);
8048
8049      //fetch any existing values
8050      var parsed = book.attr("parsed") || book.attr("df-parsed");
8051
8052      //skip if already parsed or failed
8053      if (parsed !== "true") {
8054        book.attr("df-parsed", "true")
8055
8056        if (book.hasClass("_df_book")) {
8057
8058          var book_id = book.attr("id"),
8059            slug = book.attr("slug");
8060          var options = DFLIP.getOptions(book);
8061          options.id = book_id;
8062          if (slug != null)
8063            options.slug = slug;
8064          if (book_id) {
8065            window[book_id.toString()] = $(book).flipBook(options.source, options);
8066          }
8067          else {
8068            $(book).flipBook(options.source, options);
8069          }
8070
8071        }
8072        else {
8073
8074          if (book.hasClass("_df_thumb")) {
8075            var wrapper = $("<div class='_df_book-cover'>");
8076
8077            var text = book.html().trim();
8078            book.html("");
8079            var title = $("<span class='_df_book-title'>").html(text).appendTo(wrapper);
8080
8081            var thumb = book.attr("thumb") || book.attr("df-thumb"),
8082              thumbType = book.attr("thumbtype") || DFLIP.defaults.thumbElement || "div",
8083              tags = book.attr("tags") || book.attr("df-tags");
8084
8085            if (tags) {
8086              tags = tags.split(",");
8087
8088              if (tags.length > 0) {
8089                for (var tagcount = 0; tagcount < tags.length; tagcount++) {
8090                  book.append("<span class='_df_book-tag'>" + tags[tagcount] + "</span>");
8091                }
8092              }
8093            }
8094
8095            if (thumb != null && thumb.toString().trim() != '') {
8096              if (thumbType == 'img') {
8097                wrapper.append('<img src="' + thumb + '" alt="' + text + '"/>');
8098                book.attr("thumb-type", "img");
8099              } else {
8100                wrapper.css({
8101                  backgroundImage: "url(" + thumb + ")"
8102                });
8103              }
8104            } else {
8105              wrapper.addClass("_df_thumb-not-found");
8106            }
8107
8108            book.append(wrapper);
8109          }
8110
8111        }
8112
8113      }
8114    });
8115
8116  };
8117
8118  $(document).ready(function () {
8119
8120    //Autodetection if the folder structure is copied properly
8121    if (typeof dFlipLocation == 'undefined' && DFLIP.autoDetectLocation != false) {
8122      $("script").each(function () {
8123        var src = $(this)[0].src;
8124        if ((src.indexOf("/dflip.js") > -1 || src.indexOf("/dflip.min.js") > -1 )
8125          && (src.indexOf("https://") > -1 || src.indexOf("http://") > -1 ) && src.indexOf("js/dflip.") > -1) {
8126          var splits = src.split("/");
8127          window.dFlipLocation = splits.slice(0, -2).join("/");
8128        }
8129      });
8130    }
8131
8132    if (typeof dFlipLocation !== 'undefined') {
8133
8134      //add ending forward slash trail for safety
8135      if (dFlipLocation.length > 2 && dFlipLocation.slice(-1) !== "/") {
8136        window.dFlipLocation += "/";
8137      }
8138
8139      //PRESENTATION.defaults.backgroundImage = "blank"; "images/textures/white.jpg";
8140      //PRESENTATION.defaults.textureLoadFallback = dFlipLocation + "images/textures/white.jpg";
8141      DFLIP.defaults.mockupjsSrc = dFlipLocation + "js/libs/mockup.min.js";
8142      DFLIP.defaults.pdfjsSrc = dFlipLocation + "js/libs/pdf.min.js";
8143      DFLIP.defaults.pdfjsCompatibilitySrc = dFlipLocation + "js/libs/compatibility.js";
8144      DFLIP.defaults.threejsSrc = dFlipLocation + "js/libs/three.min.js";
8145      DFLIP.defaults.pdfjsWorkerSrc = dFlipLocation + "js/libs/pdf.worker.min.js";
8146      DFLIP.defaults.soundFile = dFlipLocation + "sound/turn2.mp3";
8147      DFLIP.defaults.imagesLocation = dFlipLocation + "images";
8148      DFLIP.defaults.imageResourcesPath = dFlipLocation + "images/pdfjs/";
8149      DFLIP.defaults.cMapUrl = dFlipLocation + "js/libs/cmaps/";
8150
8151      if (typeof dFlipWPGlobal !== 'undefined') {
8152
8153        checkValues(dFlipWPGlobal);
8154
8155        $.extend(DFLIP.defaults, dFlipWPGlobal);
8156      }
8157    }
8158
8159    DFLIP.preParseHash = window.location.hash;
8160    DFLIP.parseBooks();
8161
8162    $('body').on('click', '._df_button, ._df_thumb, ._df_custom', function () {
8163
8164      //cache the book element
8165      var book = $(this);
8166
8167      if (!window.dfLightBox) {
8168        window.dfLightBox = new DFLightBox(function () {
8169
8170          if (window.location.hash.indexOf("#dflip-") == 0)
8171            window.location.hash = "#_";
8172          window.dfActiveLightBoxBook.dispose();
8173          window.dfActiveLightBoxBook = null;
8174        });
8175      }
8176
8177      window.dfLightBox.duration = 500;
8178
8179      if (window.dfActiveLightBoxBook && window.dfActiveLightBoxBook.dispose) {
8180        window.dfActiveLightBoxBook.dispose();
8181
8182      } else {
8183        window.dfLightBox.show(
8184          function () {
8185            //                            $("body").addClass("df-no-scroll");
8186            var options = DFLIP.getOptions(book);
8187            options.transparent = false;
8188            options.id = book.attr("id");
8189            var slug = book.attr("slug");
8190            if (slug != null)
8191              options.slug = slug;
8192            options.isLightBox = true;
8193            window.dfActiveLightBoxBook = $(window.dfLightBox.container).flipBook(options.source, options);
8194          }
8195        );
8196      }
8197
8198
8199    });
8200
8201    if (DFLIP.utils.isSafari || DFLIP.utils.isIOS) {
8202      $('body').addClass("df-webkit");
8203    }
8204    //parse hash and check if any exists
8205    if (DFLIP.preParseHash && DFLIP.preParseHash.indexOf('dflip-') >= 0) {
8206      var id = DFLIP.preParseHash.split('dflip-')[1].split('/')[0];
8207      var page = DFLIP.preParseHash.split('dflip-')[1].split('/')[1];
8208      if (page != null) {
8209        page = page.split('/')[0];
8210      }
8211      var book;
8212      //first check for slug pattern
8213      book = $("[slug=" + id + "]");
8214      //then id pattern
8215      if (book.length == 0) book = $('#' + id);
8216
8217      if (book.length > 0) {
8218
8219        //var oldHash = window.location.hash;
8220        //window.location.hash = id;
8221        //window.location.hash = DFLIP.preParseHash;
8222
8223        if (page != null) {
8224          book.data("page", page)
8225        }
8226
8227        if (book.is('._df_button, ._df_thumb, ._df_custom')) {
8228          book.trigger("click");
8229        }
8230      }
8231    }
8232
8233    $('body').on('click', '.df-ui-sidemenu-close', function () {
8234      var $this = $(this);
8235      $this.closest(".df-container").find(".df-ui-outline.df-active , .df-ui-thumbn
8235ail.df-active").trigger("click");
8236    });
8237
8238
8239  });
8240
8241})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.