diff --git "a/flipbook.js" "b/flipbook.js" new file mode 100644--- /dev/null +++ "b/flipbook.js" @@ -0,0 +1,6946 @@ +/* + * Real3D FlipBook [https://real3dflipbook.com] + * @author creativeinteractivemedia [https://codecanyon.net/user/creativeinteractivemedia/portfolio] + * @version 4.10 + * @date 2025-05-15 + */ +'use strict'; +var FLIPBOOK = FLIPBOOK || {}; +FLIPBOOK.version = '4.9.6'; + +// eslint-disable-next-line no-shadow-restricted-names +(function init(window, document, undefined) { + if (typeof jQuery != 'undefined') { + jQuery.fn.flipBook = function (options) { + return new FLIPBOOK.Main(options, this); + }; + + jQuery.fn.swipeBook = function (options) { + options.viewMode = 'swipe'; + return new FLIPBOOK.Main(options, this); + }; + } + + window.FlipBook = function (el, options) { + return new FLIPBOOK.Main(options, el); + }; +})(window, document); + +FLIPBOOK.Main = function (options, elem) { + var self = this; + if (elem.length) { + this.elem = elem[0]; + this.elements = Array.from(elem); + } else { + this.elem = elem; + this.elements = [elem]; + } + + this.bodyHasVerticalScrollbar = function () { + return document.body.scrollHeight > window.innerHeight; + }; + + this.isIframe = function () { + try { + return window.self !== window.top; + } catch (e) { + return true; + } + }; + + this.isZoomed = function () { + return self.zoom > 1; + }; + + let defaultOptions = { + name: '', + pages: [], + tableOfContent: [], + tableOfContentCloseOnClick: true, + thumbsCloseOnClick: true, + thumbsStyle: 'overlay', + deeplinkingEnabled: false, + deeplinkingPrefix: '', + assets: { + preloader: 'assets/images/preloader.jpg', + flipMp3: 'assets/mp3/turnPage.mp3', + spinner: 'assets/images/spinner.gif', + backgroundMp3: 'assets/mp3/background.mp3', + }, + pdfUrl: null, + pdfBrowserViewerIfMobile: false, + pdfBrowserViewerIfIE: false, + pdfBrowserViewerFullscreen: true, + pdfBrowserViewerFullscreenTarget: '_blank', + rangeChunkSize: 64, + disableRange: false, + disableStream: true, + disableAutoFetch: true, + pdfAutoLinks: false, + htmlLayer: true, + rightToLeft: false, + startPage: 0, + sound: true, + backgroundColor: 'rgb(81, 85, 88)', + backgroundImage: '', + backgroundPattern: '', + backgroundTransparent: false, + thumbSize: 150, + loadAllPages: false, + loadPagesF: 2, + loadPagesB: 1, + autoplayOnStart: false, + autoplayInterval: 3000, + autoplayLoop: true, + skin: '', + menuOverBook: false, + menuFloating: false, + menuBackground: '', + menuShadow: '', + menuMargin: 0, + menuPadding: 0, + menuTransparent: false, + menu2OverBook: true, + menu2Floating: false, + menu2Background: '', + menu2Shadow: '', + menu2Margin: 0, + menu2Padding: 0, + menu2Transparent: true, + + skinColor: '#222', + skinBackground: '#FFF', + floatingBtnColor: '#FFF', + floatingBtnBackground: '#00000055', + btnColor: '', + btnBackground: 'none', + btnSize: 18, + btnRadius: 2, + btnMargin: 2, + btnPaddingV: 10, + btnPaddingH: 10, + btnShadow: '', + btnTextShadow: '', + btnBorder: '', + btnColorHover: '', + btnBackgroundHover: '', + arrowColor: '#FFF', + arrowColorHover: '#FFF', + arrowBackground: 'rgba(0, 0, 0, 0)', + arrowBackgroundHover: 'rgba(0, 0, 0, .15)', + arrowSize: 40, + arrowRadius: 4, + arrowMargin: 4, + arrowPadding: 10, + arrowTextShadow: '0px 0px 1px rgba(0, 0, 0, 1)', + arrowBorder: '', + floatingBtnColorHover: '', + floatingBtnBackgroundHover: '', + floatingBtnSize: null, + floatingBtnRadius: null, + floatingBtnMargin: null, + floatingBtnPadding: null, + floatingBtnShadow: '', + floatingBtnTextShadow: '', + floatingBtnBorder: '', + btnOrder: [ + 'currentPage', + 'btnFirst', + 'btnPrev', + 'btnNext', + 'btnLast', + 'btnZoomOut', + 'btnZoomIn', + 'btnThumbs', + 'btnToc', + + 'search', + 'btnRotateLeft', + 'btnRotateRight', + 'btnAutoplay', + 'btnSearch', + 'btnBookmark', + //'btnNotes', + 'btnDownloadPages', + + 'btnShare', + 'btnPrint', + 'btnDownloadPdf', + 'btnSound', + 'btnTools', + 'btnSingle', + 'btnExpand', + 'btnClose', + ], + currentPage: { + enabled: true, + title: 'Current page', + vAlign: 'top', + hAlign: 'left', + marginH: 0, + marginV: 0, + color: '', + background: '', + }, + search: { + enabled: false, + }, + btnFirst: { + enabled: false, + title: 'First page', + svg: 'last', + iconReverse: true, + }, + btnPrev: { + enabled: true, + title: 'Previous page', + svg: 'next', + iconReverse: true, + }, + btnNext: { + enabled: true, + title: 'Next page', + }, + btnLast: { + enabled: false, + title: 'Last page', + }, + btnZoomIn: { + enabled: true, + title: 'Zoom in', + svg: 'plus', + }, + btnZoomOut: { + enabled: true, + title: 'Zoom out', + svg: 'minus', + }, + btnRotateLeft: { + enabled: false, + title: 'Rotate left', + }, + btnRotateRight: { + enabled: false, + title: 'Rotate right', + }, + btnAutoplay: { + enabled: true, + title: 'Autoplay', + svg: 'play', + svgAlt: 'pause', + }, + btnSearch: { + enabled: false, + title: 'Search', + }, + btnBookmark: { + enabled: true, + title: 'Bookmarks', + }, + btnNotes: { + enabled: false, + title: 'Notes', + }, + btnToc: { + enabled: true, + title: 'Table of Contents', + svg: 'list', + }, + btnThumbs: { + enabled: true, + title: 'Pages', + }, + btnShare: { + enabled: true, + title: 'Share', + }, + btnPrint: { + enabled: true, + title: 'Print', + toolsMenu: true, + }, + btnDownloadPages: { + enabled: true, + title: 'Download', + url: 'images/pages.zip', + name: 'allPages.zip', + svg: 'download', + toolsMenu: true, + }, + btnDownloadPdf: { + forceDownload: false, + enabled: true, + title: 'View PDF', + url: null, + openInNewWindow: true, + name: 'allPages.pdf', + svg: 'pdf', + toolsMenu: true, + }, + btnSound: { + enabled: true, + title: 'Sound', + svgAlt: 'mute', + toolsMenu: true, + }, + btnTools: { + enabled: true, + title: 'Tools', + }, + btnExpand: { + enabled: true, + title: 'Toggle fullscreen', + svgAlt: 'compress', + }, + btnSingle: { + enabled: true, + title: 'Toggle single page', + svgAlt: 'double', + //toolsMenu: true, + }, + btnClose: { + title: 'Close', + hAlign: 'right', + vAlign: 'top', + size: 20, + }, + sideNavigationButtons: true, + hideMenu: false, + shareUrl: null, + shareTitle: null, + shareImage: null, + whatsapp: { + enabled: true, + title: 'WhatsApp', + }, + twitter: { + enabled: true, + title: 'X (Twitter)', + }, + facebook: { + enabled: true, + title: 'Facebook', + }, + pinterest: { + enabled: true, + title: 'Pinterest', + }, + email: { + enabled: true, + title: 'Email', + }, + linkedin: { + enabled: true, + title: 'LinkedIn', + }, + digg: { + enabled: false, + title: 'Digg', + }, + reddit: { + enabled: false, + title: 'Reddit', + }, + copyLink: { + enabled: true, + }, + pdf: { + annotationLayer: false, + }, + pageTextureSize: 3000, + pageTextureSizeSmall: 1500, + thumbTextureSize: 300, + pageTextureSizeMobile: 1500, + pageTextureSizeMobileSmall: 1000, + pagesInMemory: 20, + viewMode: 'webgl', + singlePageMode: false, + singlePageModeIfMobile: false, + zoomMin: 0.95, + zoomMin2: 0.15, + zoomMax2: null, + zoomSize: null, + zoomStep: 1.5, + zoomTime: 300, + zoomReset: false, + zoomResetTime: 300, + wheelDisabledNotFullscreen: false, + arrowsDisabledNotFullscreen: false, + arrowsAlwaysEnabledForNavigation: true, + responsiveView: true, + responsiveViewRatio: 1, + responsiveViewTreshold: 768, + responsiveContainer: true, + minPixelRatio: 1, + pageFlipDuration: 1, + contentOnStart: false, + thumbnailsOnStart: false, + searchOnStart: false, + sideMenuOverBook: true, + sideMenuOverMenu: false, + sideMenuOverMenu2: true, + sideMenuPosition: 'left', + lightBox: false, + lightBoxOpened: false, + lightBoxFullscreen: false, + lightboxResetOnOpen: true, + lightboxBackground: null, + lightboxBackgroundColor: null, + lightboxBackgroundPattern: null, + lightboxBackgroundImage: null, + lightboxStartPage: null, + lightboxMarginV: '0', + lightboxMarginH: '0', + lightboxCSS: '', + lightboxPreload: false, + lightboxShowMenu: false, + lightboxCloseOnBack: true, + lightboxFromStart: true, + disableImageResize: true, + pan: 0, + panMax: 10, + panMax2: 2, + panMin: -10, + panMin2: -2, + tilt: 0, + tiltMax: 0, + tiltMax2: 0, + tiltMin: 0, + tiltMin2: -5, + rotateCameraOnMouseMove: false, + rotateCameraOnMouseDrag: true, + lights: true, + lightColor: 0xffffff, + lightPositionX: -100, + lightPositionZ: 1400, + lightIntensity: 0.6, + shadows: true, + shadowMapSize: 1024, + shadowOpacity: 0.3, + pageRoughness: 1, + pageMetalness: 0, + pageHardness: 2, + coverHardness: 2, + pageSegmentsW: 10, + pageSegmentsH: 1, + pageMiddleShadowSize: 4, + pageMiddleShadowColorL: '#7E7E7E', + pageMiddleShadowColorR: '#AAAAAA', + antialias: false, + bitmapResizeHeight: null, + bitmapResizeQuality: 'medium', + preloaderText: '', + fillPreloader: { + enabled: false, + imgEmpty: 'images/logo_light.png', + imgFull: 'images/logo_dark.png', + }, + logoImg: '', + logoUrl: '', + logoCSS: 'position:absolute;', + logoHideOnMobile: false, + printMenu: true, + downloadMenu: true, + cover: true, + backCover: true, + pdfTextLayer: true, + annotationLayer: true, + googleAnalyticsTrackingCode: null, + minimumAndroidVersion: 6, + linkColor: 'rgba(0, 0, 0, 0)', + linkColorHover: 'rgba(255, 255, 0, 1)', + linkOpacity: 0.4, + linkTarget: '_blank', + rightClickEnabled: true, + pageNumberOffset: 0, + flipSound: true, + backgroundMusic: false, + doubleClickZoomDisabled: false, + pageDragDisabled: false, + pageClickAreaWdith: '10%', + noteTypes: [ + { id: 1, title: 'User', color: 'green', enabled: true }, + { id: 2, title: 'Group', color: 'yellow', enabled: true }, + { id: 3, title: 'Admin', color: 'blue', enabled: true }, + ], + pageRangeStart: null, + pageRangeEnd: null, + previewMode: {}, + strings: { + print: 'Print', + printLeftPage: 'Print left page', + printRightPage: 'Print right page', + printCurrentPage: 'Print current page', + printAllPages: 'Print all pages', + download: 'Download', + downloadLeftPage: 'Download left page', + downloadRightPage: 'Download right page', + downloadCurrentPage: 'Download current page', + downloadAllPages: 'Download all pages', + bookmarks: 'Bookmarks', + bookmarkLeftPage: 'Bookmark left page', + bookmarkRightPage: 'Bookmark right page', + bookmarkCurrentPage: 'Bookmark current page', + search: 'Search', + findInDocument: 'Find in document', + pagesFoundContaining: 'pages found containing', + noMatches: 'No matches', + matchesFound: 'matches found', + page: 'Page', + matches: 'matches', + thumbnails: 'Thumbnails', + tableOfContent: 'Table of Contents', + share: 'Share', + notes: 'Notes', + pressEscToClose: 'Press ESC to close', + password: 'Password', + addNote: 'Add note', + typeInYourNote: 'Type in your note...', + copyLink: 'Copy link', + copied: 'Copied', + }, + mobile: { + shadows: false, + pageSegmentsW: 5, + btnAutoplay: { toolsMenu: true }, + btnBookmark: { toolsMenu: true }, + btnZoomIn: { enabled: false }, + btnZoomOut: { enabled: false }, + btnFirst: { enabled: false }, + btnLast: { enabled: false }, + currentPage: { enabled: false }, + pagesInMemory: 6, + }, + }; + + this.options = {}; + + var dummyStyle = document.createElement('div').style; + var vendor = (function () { + var vendors = 't,webkitT,MozT,msT,OT'.split(','); + var t; + var i = 0; + var l = vendors.length; + + for (; i < l; i++) { + t = vendors[i] + 'ransform'; + if (t in dummyStyle) { + return vendors[i].substr(0, vendors[i].length - 1); + } + } + return false; + })(); + + var isAndroid = /android/gi.test(navigator.appVersion); + + this.isAndroid = isAndroid; + + function webgl_detect() { + const canvas = document.createElement('canvas'); + const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); + return gl instanceof WebGLRenderingContext; + } + + if (typeof FLIPBOOK.hasWebGl == 'undefined') { + FLIPBOOK.hasWebGl = webgl_detect(); + } + + this.hasWebGl = FLIPBOOK.hasWebGl; + + this.thumbsShowing = false; + this.bookmarkShowing = false; + this.searchingString = false; + this.tocShowing = false; + this.menuShowing = true; + this.fullscreenActive = false; + + var layouts = { + 2: { + currentPage: { vAlign: 'bottom', hAlign: 'center' }, + btnAutoplay: { hAlign: 'right', vAlign: 'top' }, + btnSound: { hAlign: 'right', vAlign: 'top' }, + btnSingle: { hAlign: 'right', vAlign: 'top' }, + btnExpand: { hAlign: 'right', vAlign: 'top' }, + btnSearch: { hAlign: 'left', vAlign: 'top' }, + btnBookmark: { hAlign: 'left', vAlign: 'top' }, + btnToc: { hAlign: 'left', vAlign: 'top' }, + btnThumbs: { hAlign: 'left', vAlign: 'top' }, + btnShare: { hAlign: 'right', vAlign: 'top' }, + btnPrint: { hAlign: 'right', vAlign: 'top' }, + btnDownloadPages: { hAlign: 'right', vAlign: 'top' }, + btnDownloadPdf: { hAlign: 'right', vAlign: 'top' }, + btnTools: { hAlign: 'right', vAlign: 'top' }, + menuTransparent: true, + }, + 3: { + menuTransparent: true, + menu2Transparent: false, + menu2OverBook: false, + menu2Padding: 5, + btnMargin: 5, + currentPage: { vAlign: 'top', hAlign: 'center' }, + btnPrint: { vAlign: 'top', hAlign: 'right' }, + btnDownloadPdf: { vAlign: 'top', hAlign: 'right' }, + btnDownloadPages: { vAlign: 'top', hAlign: 'right' }, + btnThumbs: { vAlign: 'top', hAlign: 'left' }, + btnToc: { vAlign: 'top', hAlign: 'left' }, + btnBookmark: { vAlign: 'top', hAlign: 'left' }, + btnSearch: { vAlign: 'top', hAlign: 'left' }, + btnShare: { vAlign: 'top', hAlign: 'right' }, + btnAutoplay: { vAlign: 'top', hAlign: 'right' }, + btnSingle: { vAlign: 'top', hAlign: 'right' }, + btnExpand: { vAlign: 'top', hAlign: 'right' }, + btnZoomIn: { hAlign: 'right' }, + btnZoomOut: { hAlign: 'right' }, + btnSound: { vAlign: 'top', hAlign: 'right' }, + btnTools: { vAlign: 'top', hAlign: 'right' }, + menuPadding: 5, + }, + 4: { + menu2Transparent: false, + menu2OverBook: false, + sideMenuOverMenu2: false, + currentPage: { vAlign: 'top', hAlign: 'center' }, + btnAutoplay: { vAlign: 'top', hAlign: 'left' }, + btnSound: { vAlign: 'top', hAlign: 'left' }, + btnSingle: { vAlign: 'top', hAlign: 'right' }, + btnExpand: { vAlign: 'top', hAlign: 'right' }, + btnZoomIn: { vAlign: 'top' }, + btnZoomOut: { vAlign: 'top' }, + btnSearch: { vAlign: 'top', hAlign: 'left' }, + btnBookmark: { vAlign: 'top', hAlign: 'left' }, + btnToc: { vAlign: 'top', hAlign: 'left' }, + btnThumbs: { vAlign: 'top', hAlign: 'left' }, + btnShare: { vAlign: 'top', hAlign: 'right' }, + btnPrint: { vAlign: 'top', hAlign: 'right' }, + btnDownloadPages: { vAlign: 'top', hAlign: 'right' }, + btnDownloadPdf: { vAlign: 'top', hAlign: 'right' }, + btnTools: { vAlign: 'top', hAlign: 'right' }, + }, + }; + + var skins = { + dark: { + skinColor: '#EEE', + btnColorHover: '#FFF', + skinBackground: '#313538', + }, + gradient: { + skinColor: '#EEE', + btnColor: '#EEE', + btnColorHover: '#FFF', + skinBackground: '#313538DD', + menuOverBook: true, + menu2OverBook: true, + sideMenuOverMenu: true, + sideMenuOverMenu2: true, + menuBackground: 'linear-gradient(to top, rgba(0, 0, 0, 0.65) 0%, transparent 100%)', + menu2Background: 'linear-gradient(to bottom, rgba(0, 0, 0, 0.65) 0%, transparent 100%)', + }, + }; + + if (options.skin && skins[options.skin]) { + defaultOptions = FLIPBOOK.extend(true, {}, defaultOptions, skins[options.skin]); + } + if (options.layout && layouts[options.layout]) { + defaultOptions = FLIPBOOK.extend(true, {}, defaultOptions, layouts[options.layout]); + } + + this.options = FLIPBOOK.extend(true, {}, defaultOptions, options); + + var o = this.options; + + FLIPBOOK.count = FLIPBOOK.count || 0; + FLIPBOOK.count++; + + this.uniqueID = FLIPBOOK.count; + + o.isMobile = + /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || + (navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform)); + + if (o.isMobile) { + FLIPBOOK.extend(true, o, o.mobile); + } + + this.strings = o.strings; + + o.pageShininess = o.pageShininess / 2; + + this.s = 0; + + // o.i = w !== parent; + + if (o.isMobile) { + o.singlePageMode = o.singlePageModeIfMobile ? true : o.singlePageMode; + + if (o.viewModeMobile) { + o.viewMode = o.viewModeMobile; + } + + if (o.pageTextureSizeMobile) { + o.pageTextureSize = o.pageTextureSizeMobile; + } + + if (o.pageTextureSizeMobileSmall) { + o.pageTextureSizeSmall = o.pageTextureSizeMobileSmall; + } + } + + if (o.viewMode == '3dSinglePage') { + o.singlePageMode = true; + } + if (o.viewMode == '2dSinglePage') { + o.singlePageMode = true; + o.viewMode = '2d'; + } + + if (o.singlePageMode) { + if (o.viewMode != '2d' && o.viewMode != 'swipe') { + o.viewMode = '3d'; + } + + if (o.rightToLeft) { + o.viewMode = 'swipe'; + } + + o.cover = true; + } + + if (o.singlePageMode && o.viewMode == '3d') { + o.rightToLeft = false; + } + + if (o.viewMode == 'simple') { + o.viewMode = '3d'; + o.instantFlip = true; + } + + if (!o.cover) { + o.responsiveView = false; + } + + if (o.webgl) { + var c = { a: 5, b: 6, c: 2 }; + o.pageTextureSize = Math.pow(c.a * c.b - c.c, c.c); + o.pageTextureSizeSmall = Math.pow(c.a * c.b - c.c, c.c); + o.zoomSize = Math.pow(c.b * c.a + c.a, c.c); + } + + Object.assign(o, { e: 'toString', f: 'padStart', g: 'decodeURIComponent', h: 97, i: 16 }); + + o.sideMenuPosition = o.rightToLeft ? 'right' : 'left'; + + function getAndroidVersion(ua) { + ua = (ua || navigator.userAgent).toLowerCase(); + var match = ua.match(/android\s([0-9\.]*)/); + return match ? match[1] : false; + } + + if (o.viewMode == 'webgl') { + if ( + !this.hasWebGl || + o.webgl || + (parseFloat(getAndroidVersion()) < o.minimumAndroidVersion && this.isAndroid) + ) { + o.viewMode = '3d'; + } + } + + if (o.viewMode == 'webgl' || o.viewMode == 'scroll') o.btnSingle.enabled = false; + + this.webgl = o.viewMode == 'webgl'; + + if (o.menuFloating) { + o.menuOverBook = true; + o.sideMenuOverMenu = true; + } + + if (o.menu2Floating) { + o.menu2OverBook = true; + o.sideMenuOverMenu2 = true; + } + + if (o.menuTransparent) { + o.menuOverBook = true; + o.sideMenuOverMenu = true; + o.menuBackground = 'none'; + } + + if (o.menu2Transparent) { + o.menu2OverBook = true; + o.sideMenuOverMenu2 = true; + o.menu2Background = 'none'; + } else { + o.sideMenuOverMenu2 = false; + } + + if (o.menuOverBook) { + o.sideMenuOverMenu = true; + } + + if (o.menu2OverBook) { + o.sideMenuOverMenu2 = true; + } + + o.pdfMode = Boolean(o.pdfUrl || o.pdfBase64); + + if (o.backgroundTransparent) { + o.backgroundColor = 'none'; + } + + function parseAspectRatio(ratio) { + if (ratio === undefined) { + return; + } + if (typeof ratio === 'number') { + return ratio; + } + + ratio = String(ratio).trim().replace('/', ':'); + if (ratio.includes(':')) { + const parts = ratio.split(':'); + const width = parseFloat(parts[0]); + const height = parseFloat(parts[1]); + return width / height; + } + + return parseFloat(ratio); + } + + this.options.containerRatio = parseAspectRatio(this.options.containerRatio); + + this.wrapper = document.createElement('div'); + this.wrapper.classList.add('flipbook-main-wrapper'); + + this.skinBgVar = `--skin-bg`; + this.skinColorVar = `--skin-color`; + + if (o.backgroundColor !== '') { + this.wrapper.style.background = o.backgroundColor; + } + + if (o.backgroundPattern !== '') { + this.wrapper.style.background = `url(${o.backgroundPattern}) repeat`; + } + + if (o.backgroundImage !== '') { + this.wrapper.style.background = `url(${o.backgroundImage}) no-repeat`; + this.wrapper.style.backgroundSize = 'cover'; + this.wrapper.style.backgroundPosition = 'center center'; + } + + this.bookLayer = document.createElement('div'); + this.bookLayer.classList.add('flipbook-bookLayer'); + this.wrapper.appendChild(this.bookLayer); + if (o.pageDragDisabled) this.bookLayer.style.cursor = 'auto'; + + if (o.linkTarget === 'spotlight') { + this.bookLayer.addEventListener('click', function (e) { + if (e.target.tagName.toLowerCase() === 'a') { + e.preventDefault(); + self.spotlight(e.target.href); + } + }); + } + + if (!o.rightClickEnabled) { + this.bookLayer.addEventListener('contextmenu', function (e) { + e.preventDefault(); + }); + } + + if (o.hideMenu) { + this.bookLayer.style.bottom = '0'; + o.menuOverBook = true; + } + + o.pagesOriginal = JSON.parse(JSON.stringify(o.pages)); + + this.book = document.createElement('div'); + this.book.classList.add('book'); + this.bookLayer.appendChild(this.book); + + if (o.preloader && typeof jQuery != 'undefined') { + this.preloader = jQuery(o.preloader); + } else { + this.preloader = document.createElement('div'); + this.preloader.classList.add('flipbook-preloader', 'cssload-container'); + + var speedingWheel = document.createElement('div'); + speedingWheel.classList.add('cssload-speeding-wheel'); + this.preloader.appendChild(speedingWheel); + + var loadingText = document.createElement('div'); + loadingText.classList.add('flipbook-loading-text'); + loadingText.textContent = o.preloaderText; + this.preloader.appendChild(loadingText); + + var loadingBg = document.createElement('div'); + loadingBg.classList.add('flipbook-loading-bg'); + this.preloader.appendChild(loadingBg); + } + + this.setLoadingProgress(0); + + async function checkHash() { + if (self.disposed) { + return; + } + + var fullHash = window.location.hash; + + var targetPage = self.getPageFromHash(); + if (!o.cover) { + targetPage++; + } + var startPage = targetPage; + if (targetPage < 1) { + targetPage = 1; + } else if (self.numPages && targetPage > self.numPages) { + targetPage = self.numPages; + } + if (targetPage) { + targetPage = o.rightToLeft && o.pages && o.pages.length ? o.pages.length - targetPage + 1 : targetPage; + + if (!self.started) { + o.startPage = startPage; + + if (o.lightBox) { + init(); + + if (o.lightBoxFullscreen) { + setTimeout(function () { + self.toggleExpand(); + }, 100); + } + } + } else if (self.Book) { + if (self.lightbox && !FLIPBOOK.lightboxOpened) { + self.lightbox.openLightbox(); + await self.lightboxStart(); + } + self.goToPage(targetPage, fullHash.indexOf('flip') == -1); + } + } + } + + async function preload() { + if (o.pdfMode) { + await self.loadScript(FLIPBOOK.pdfjsSrc, 'pdfjsLib'); + await self.loadScript(FLIPBOOK.pdfServiceSrc, 'FLIPBOOK.PdfService'); + + if (o.btnSearch.enabled || o.btnNotes.enabled || o.search.enabled) { + await self.loadScript(FLIPBOOK.markSrc, 'Mark'); + } + } + if (o.viewMode == 'webgl') { + await self.loadScript(FLIPBOOK.threejsSrc, 'THREE'); + } else { + await self.loadScript(FLIPBOOK.iscrollSrc, 'IScroll'); + } + } + + async function init() { + if (self.initStarted) { + return; + } + self.initStarted = true; + + const loadImage = (src) => { + return new Promise((resolve, reject) => { + const img = new Image(); + img.src = src; + img.onload = () => resolve(img); + img.onerror = reject; + }); + }; + + if (o.fillPreloader.enabled) { + const fillPreloader = document.createElement('div'); + fillPreloader.classList.add('flipbook-fillPreloader'); + + try { + const empty = await loadImage(o.fillPreloader.imgEmpty); + const full = await loadImage(o.fillPreloader.imgFull); + + fillPreloader.appendChild(empty); + fillPreloader.appendChild(full); + + self.$fillPreloader = fillPreloader; + self.$fillPreloaderImg = full; + + self.wrapper.appendChild(fillPreloader); + } catch (error) { + console.error('Error loading preloader images', error); + } + } + + if (self.initialized) { + return; + } + + self.define = window.define; + window.define = null; + + self.id = self.uniqueID; + + self.addPageItems(); + if (o.pageCaptions) self.addPageCaptions(); + + if (o.pdfMode) { + self.initPdf(); + } else { + self.initJpg(); + } + + self.setLoadingProgress(0.1); + + self.initialized = true; + } + + this.dispose = function () { + this.disposed = true; + }; + + o.main = this; + + this._events = {}; + + this.on = function (type, fn) { + if (!this._events[type]) { + this._events[type] = []; + } + + this._events[type].push(fn); + }; + + this.off = function (type, fn) { + if (!this._events[type]) { + return; + } + + var index = this._events[type].indexOf(fn); + + if (index > -1) { + this._events[type].splice(index, 1); + } + }; + + this.trigger = function (type) { + if (!this._events[type]) { + return; + } + + var i = 0; + var l = this._events[type].length; + + if (!l) { + return; + } + + for (; i < l; i++) { + this._events[type][i].apply(this, [].slice.call(arguments, 1)); + } + }; + + this.on('textlayerrendered', function (_) { + if (self.searchingString) { + self.mark(self.searchingString); + } + }); + + this.on('showpagehtml', function () { + window.getSelection().removeAllRanges(); + if (self.searchingString) { + self.mark(self.searchingString); + } + }); + + this.addPageNotes = function (page) { + if (this.noteService) { + this.noteService.initPageNotes(page); + } + }; + + this.on('pdfinit', async function () { + o.tableOfContent = self.pdfService.outline || o.tableOfContent; + o.doublePage = self.pdfService.double; + if (o.scaleCover) { + o.doublePage = true; + o.responsiveView = false; + } + o.backCover = self.pdfService.backCover; + + self.viewportOriginal = self.pdfService.viewports[0]; + + o.firstPage = { + width: self.pdfService.viewports[0].width, + height: self.pdfService.viewports[0].height, + ratio: self.pdfService.viewports[0].width / self.pdfService.viewports[0].height, + }; + + if (self.pdfService.numPages > 1) { + o.secondPage = { + width: self.pdfService.viewports[1].width, + height: self.pdfService.viewports[1].height, + ratio: self.pdfService.viewports[1].width / self.pdfService.viewports[1].height, + }; + } + + o.numPages = self.pdfService.numPages; + + if (o.previewPages && o.numPages > o.previewPages) { + o.numPages = o.previewPages; + if (o.doublePage) o.backCover = false; + } + + var pages = []; + var pageSize = o.pageTextureSize; + + for (var i = 0; i < o.numPages; i++) { + var p = { + canvas: {}, + }; + + if (o.pages && o.pages[i]) { + FLIPBOOK.extend(p, o.pages[i]); + } + pages[i] = p; + } + + o.pages = pages; + o.pageWidth = parseInt((pageSize * self.viewportOriginal.width) / self.viewportOriginal.height); + o.pageHeight = pageSize; + o.pw = o.pageWidth; + o.ph = o.pageHeight; + o.zoomSize = o.zoomSize || o.pageTextureSize; + + var tocArray = o.tableOfContent; + if (o.btnToc.enabled && (!tocArray || !tocArray.length)) { + var outline = await self.pdfService.loadOutline(); + if (outline) { + o.tableOfContent = outline; + } else { + o.btnToc.enabled = false; + } + } + self.start(); + }); + + function getFlipbookSrc() { + var scripts = document.getElementsByTagName('script'); + for (var i = 0; i < scripts.length; i++) { + var src = String(scripts[i].src); + if (src.match('flipbook\\.js') || src.match('flipbook\\.min\\.js')) { + return src; + } else if (src.match('flipbook\\.lite\\.js') || src.match('flipbook\\.lite\\.min\\.js')) { + return src.replace('.lite', ''); + } + } + return ''; + } + + FLIPBOOK.flipbookSrc = FLIPBOOK.flipbookSrc || this.options.flipbookSrc || getFlipbookSrc(); + + const isMinified = FLIPBOOK.flipbookSrc.includes('flipbook.min.js'); + const replaceStr = isMinified ? 'flipbook.min.js' : 'flipbook.js'; + const suffix = isMinified ? '.min' : ''; + + const sources = [ + { key: 'iscrollSrc', value: 'libs/iscroll' }, + { key: 'threejsSrc', value: 'libs/three' }, + { key: 'flipbookWebGlSrc', value: 'flipbook.webgl' }, + { key: 'flipbookBook3Src', value: 'flipbook.book3' }, + { key: 'flipBookSwipeSrc', value: 'flipbook.swipe' }, + { key: 'flipBookScrollSrc', value: 'flipbook.scroll' }, + { key: 'pdfjsSrc', value: 'libs/pdf' }, + { key: 'pdfServiceSrc', value: 'flipbook.pdfservice' }, + { key: 'pdfjsworkerSrc', value: 'libs/pdf.worker' }, + { key: 'markSrc', value: 'libs/mark' }, + ]; + + sources.forEach((source) => { + FLIPBOOK[source.key] = FLIPBOOK.flipbookSrc.replace(replaceStr, source.value + suffix + '.js'); + }); + + if (!o.deeplinkingPrefix && o.deeplinking && o.deeplinking.prefix) { + o.deeplinkingPrefix = o.deeplinking.prefix; + } + + o.deeplinkingEnabled = o.deeplinkingPrefix || o.deeplinkingEnabled || (o.deeplinking && o.deeplinking.enabled); + + if (o.deeplinkingEnabled) { + checkHash(); + window.addEventListener('hashchange', checkHash); + } + + if (o.lightBox) { + o.btnClose.enabled = true; + + this.lightbox = new FLIPBOOK.Lightbox(this, this.wrapper, o); + this.lightboxStartedTimes = 0; + this.wrapper.style.background = 'none'; + this.bookLayer.style.background = 'none'; + this.book.style.background = 'none'; + + this.lightbox.overlay.appendChild(this.preloader); + this.preloader.style.position = 'fixed'; + + this.elements.forEach(function (el) { + el.style.cursor = 'pointer'; + el.addEventListener('click', async function (e) { + if (!self.disposed) { + e.preventDefault(); + self.lightboxStartPage = this.dataset.page; + + if (self.started) { + await self.lightboxStart(); + + if (o.lightBoxFullscreen) { + setTimeout(async function () { + self.toggleExpand(); + }, 0); + } + + self.lightbox.openLightbox(); + } else { + init(); + self.lightbox.openLightbox(); + + if (o.lightBoxFullscreen) { + setTimeout(async function () { + self.toggleExpand(); + }, 100); + } + } + } + }); + }); + + if (o.lightBoxOpened) { + init(); + if (typeof jQuery != 'undefined') jQuery(window).trigger('r3d-lightboxloadingstarted'); + } else if (o.lightboxPreload) { + preload(); + } + + this.fullscreenElement = document.documentElement; + } else { + o.btnClose.enabled = false; + this.wrapper.appendChild(this.preloader); + this.elem.appendChild(this.wrapper); + this.elem.style.background = this.wrapper.style.background; + this.fullscreenElement = this.elem; + + const observer = new IntersectionObserver((entries) => { + const isVisible = entries[0].isIntersecting; + if (isVisible) { + if (!self.Book) { + init(); + } else { + self.Book.enable(); + } + } else if (self.Book) { + self.Book.disable(); + } + }); + observer.observe(this.wrapper); + } +}; + +FLIPBOOK.Main.prototype = { + start: async function () { + var o = this.options; + + if (o.pages.length == 1) { + o.numPages = 1; + o.doublePage = false; + o.btnNext.enabled = false; + o.btnPrev.enabled = false; + o.btnFirst.enabled = false; + o.btnLast.enabled = false; + o.sideNavigationButtons = false; + o.btnAutoplay.enabled = false; + o.singlePageMode = true; + o.viewMode = 'swipe'; + o.rightToLeft = false; + o.btnThumbs.enabled = false; + o.btnToc.enabled = false; + o.btnBookmark.enabled = false; + } + + if (o.dp) { + o.doublePage = true; + } + + if (this.started) { + return; + } + + this.pageW = this.options.pageWidth; + this.bookW = 2 * this.options.pageWidth; + if (this.options.singlePageMode) { + this.bookW /= 2; + } + this.pageH = this.options.pageHeight; + this.bookH = this.options.pageHeight; + + if (this.options.numPages % 2 == 0) { + this.options.numSheets = (this.options.numPages + 2) / 2; + } else { + this.options.numSheets = (this.options.numPages + 1) / 2; + } + + this.started = true; + + if (this.options.lightBox) { + this.lightbox.openLightbox(); + await this.lightboxStart(); + } + + const pageClickAreaWdith = this.options.pageClickAreaWdith; + const numPages = this.options.pages.length; + const doublePage = this.options.doublePage; + const singlePageMode = this.options.singlePageMode; + const scrollMode = this.options.viewMode == 'scroll'; + + const htmlWidth = (this.options.pageWidth * 1000) / this.options.pageHeight; + const xPos = htmlWidth - 50; + const xPosDouble = 2 * htmlWidth - 50; + + this.options.pages.hasHtmlContent = this.options.pages + ? this.options.pages.some((page) => !!page.htmlContent) + : false; + + var rtl = this.options.rightToLeft; + var self = this; + + if (pageClickAreaWdith && !scrollMode) { + this.options.pages.forEach(function (page, index) { + page.htmlContent = page.htmlContent || ''; + if (singlePageMode) { + if (index > 0) { + rtl ? addBtnPrev(page) : addBtnNext(page); + } + if (index < numPages - 1) { + rtl ? addBtnNext(page) : addBtnPrev(page); + } + } else { + if (doublePage) { + if (self.options.cover && index == 0) { + rtl ? addBtnPrev(page) : addBtnNext(page); + } else if (self.options.backCover && index == self.options.pages.length - 1) { + rtl ? addBtnPrev(page) : addBtnNext(page); + } else { + addBtnPrev(page); + addBtnNext(page, true); + } + } else { + if (index % 2 == 0) { + rtl ? addBtnPrev(page) : addBtnNext(page); + } else { + rtl ? addBtnNext(page) : addBtnPrev(page); + } + } + } + }); + } + + function addBtnPrev(page) { + page.htmlContent += + ''; + } + + function addBtnNext(page, double) { + const left = double ? xPosDouble : xPos; + page.htmlContent += + ''; + } + + await this.createBook(); + this.createTooltip(); + if (this.options.btnNotes.enabled) { + this.initNotes(); + } + + this.updateSkinColors(); + }, + + updateSkinColors: function () { + var o = this.options, + wrapper = this.wrapper; + + if (o.skinColor) { + const skinColorElements = wrapper.querySelectorAll('.skin-color'); + skinColorElements.forEach((element) => { + element.style.color = o.skinColor; + }); + } + + if (o.skinBackground) { + const skinColorBgElements = wrapper.querySelectorAll('.skin-color-bg'); + skinColorBgElements.forEach((element) => { + element.style.background = o.skinBackground; + }); + } + }, + + lightboxStart: async function () { + var self = this, + o = this.options; + if (!this.started) { + await this.start(); + } + + if (typeof this.Book == 'undefined') { + setTimeout(function () { + self.lightboxStart(); + }, 100); + return; + } + + var targetPage; + if (!window.location.hash) { + targetPage = this.lightboxStartPage || this.options.lightboxStartPage; + } + this.Book.enable(); + + if (this.backgroundMusic) { + this.backgroundMusic.play(); + } + + if (targetPage) { + targetPage = o.rightToLeft && o.pages && o.pages.length ? o.pages.length - targetPage + 1 : targetPage; + this.goToPage(targetPage, true); + } + + this.lightboxStartedTimes++; + + this.sendGAEvent({ + event: 'flipbook_lightbox_open', + book_name: this.options.name, + nonInteraction: true, + }); + + this.updateCurrentPage(); + this.initColors(); + this.resize(); + this.lightbox.openLightbox(); + }, + + setHash: function (page) { + if (page < 1) { + page = 1; + } + + if ('#' + this.options.deeplinkingPrefix + page == window.location.hash) { + return; + } + + if (this.options.deeplinkingEnabled && this.Book.enabled && this.hash != page) { + window.location.hash = '#' + this.options.deeplinkingPrefix + String(page); + this.hash = page; + } + }, + + clearHash: function () { + + var scrollV; + var scrollH; + var loc = window.location; + if ('pushState' in history) { + history.pushState('', document.title, loc.pathname + loc.search); + } else { + scrollV = document.body.scrollTop; + scrollH = document.body.scrollLeft; + + loc.hash = ''; + + document.body.scrollTop = scrollV; + document.body.scrollLeft = scrollH; + } + delete this.hash; + + }, + + getPageFromHash: function () { + var page; + + var string = window.location.hash; + var substring = '#' + this.options.deeplinkingPrefix; + var hasPrefix = string.indexOf(substring) !== -1; + if (hasPrefix) { + page = parseInt(window.location.hash.replace(/#/g, '').replace(this.options.deeplinkingPrefix, '')); + } + + return page; + }, + + sendGAEvent: async function (params) { + + if (this.options.googleAnalyticsTrackingCode) { + this.gaCode = this.options.googleAnalyticsTrackingCode; + if (this.gaCode.includes('G-') || this.gaCode.includes('AW-')) await this.initGoogleAnalytics(); + } + + if (this.gaCode) { + window.dataLayer = window.dataLayer || []; + // eslint-disable-next-line no-inner-declarations + function gtag() { + dataLayer.push(arguments); + } + const { event, ...eventParams } = params; + + if ('nonInteraction' in eventParams) { + eventParams.non_interaction = eventParams.nonInteraction; + delete eventParams.nonInteraction; + } + + gtag('event', event, eventParams); + } + + }, + + addColor: function (element) { + element.classList.add('flipbook-color-' + this.options.skin); + }, + + addColorBg: function (element) { + element.classList.add('flipbook-bg-' + this.options.skin); + }, + + initColors: function () { + const wrapper = this.wrapper; + const skinColorBgElements = wrapper.querySelectorAll('.skin-color-bg'); + skinColorBgElements.forEach((element) => { + element.classList.remove('flipbook-bg-light', 'flipbook-bg-dark'); + element.classList.add('flipbook-bg-' + this.options.skin); + }); + const skinColorElements = wrapper.querySelectorAll('.skin-color'); + skinColorElements.forEach((element) => { + element.classList.remove('flipbook-color-light', 'flipbook-color-dark'); + element.classList.add('flipbook-color-' + this.options.skin); + }); + + this.updateSkinColors(); + }, + + lightboxEnd: function () { + if (document.fullscreenElement) { + this.toggleExpand(); + this.toggleIcon(this.btnExpand, true); + } + + if (window.location.hash) { + this.clearHash(); + } + + this.setLoadingProgress(1); + + if (this.Book) { + this.Book.zoomTo(this.options.zoomMin); + this.Book.disable(); + } + + this.pauseMediaPlayback(); + + if (this.backgroundMusic) { + this.backgroundMusic.pause(); + } + }, + + pauseMediaPlayback: function () { + this.wrapper.querySelectorAll('.flipbook-page-item').forEach(function (item) { + if (item.nodeName == 'VIDEO' || item.nodeName == 'AUDIO') { + item.pause(); + } + }); + if (this.pageAudioPlayer) { + this.pageAudioPlayer.pause(); + } + }, + + turnPageStart: function () { + this.pauseMediaPlayback(); + this.resumeGlobalSound(); + this.playFlipSound(); + }, + + turnPageComplete: function () { + this.animating = false; + this.updateCurrentPage(); + + var rightIndex = this.Book.rightIndex || 0; + + if (this.options.rightToLeft) { + rightIndex = this.options.pages.length - rightIndex; + } + + this.trigger('turnpagecomplete', { rightIndex: rightIndex }); + + if (this.options.zoomReset) { + this.Book.zoomTo(this.options.zoomMin); + } + }, + + updateCurrentPage: function () { + var rtl = this.options.rightToLeft; + var total = this.options.numPages; + var totalDisplay = total - this.options.pageNumberOffset; + var rightIndex = this.Book.rightIndex || 0; + var s; + + if (rightIndex % 2 == 1) { + rightIndex++; + } + + if (rtl) { + rightIndex = this.options.pages.length - rightIndex; + } + + let ri = this.options.cover ? rightIndex : rightIndex - 1; + + if (this.options.singlePageMode || this.Book.singlePage || this.Book.view == 1) { + if (this.Book.getCurrentPageNumber) { + s = this.Book.getCurrentPageNumber(); + } else { + if (rtl) { + rightIndex--; + } + + s = rightIndex + 1; + } + + this.setHash(s); + this.cPage = [s - 1]; + } else { + if (ri > total || (ri == total && total % 2 == 0)) { + s = total; + this.cPage = [total - 1]; + } else if (ri < 1) { + s = 1; + this.cPage = [0]; + } else { + s = String(ri) + '-' + String(ri + 1); + this.cPage = [ri - 1, ri]; + } + + this.setHash(ri); + } + + var firstRi = this.options.cover ? 0 : 2; + + if (rtl) { + this.enableNext(ri > firstRi); + this.enablePrev(this.Book.canFlipPrev() || rightIndex < total - 1); + } else { + this.enablePrev(ri > firstRi); + this.enableNext(this.Book.canFlipNext() || rightIndex < total - 1); + } + + if (this.cPage.length === 2) { + this.wrapper.querySelectorAll('.c-l-p').forEach(function (element) { + element.classList.remove('flipbook-hidden'); + }); + this.wrapper.querySelectorAll('.c-r-p').forEach(function (element) { + element.classList.remove('flipbook-hidden'); + }); + + this.wrapper.querySelectorAll('.c-p').forEach(function (element) { + element.classList.add('flipbook-hidden'); + }); + } else { + this.wrapper.querySelectorAll('.c-l-p').forEach(function (element) { + element.classList.add('flipbook-hidden'); + }); + this.wrapper.querySelectorAll('.c-r-p').forEach(function (element) { + element.classList.add('flipbook-hidden'); + }); + + this.wrapper.querySelectorAll('.c-p').forEach(function (element) { + element.classList.remove('flipbook-hidden'); + }); + } + + if (typeof this.currentPage === 'undefined') { + return; + } + + this.s && this.options.pdfPageScale > 0 && this.goToPage(0); + + if (s != this.currentPageValue) { + this.currentPageValue = String(s); + + var first = Number(String(s).split('-')[0]); + var second = Number(String(s).split('-')[1]); + + if (first && this.options.pages[Number(first - 1)] && this.options.pages[Number(first - 1)].name) { + first = this.options.pages[Number(first - 1)].name; + } + + if (second && this.options.pages[Number(second - 1)] && this.options.pages[Number(second - 1)].name) { + second = this.options.pages[Number(second - 1)].name; + } + + if (first && second) { + s = first + '-' + second; + } else if (first) { + s = first; + } else if (second) { + s = second; + } else { + s = 1; + } + + this.currentPageString = s; + this.currentPageInput.dispatchEvent(new Event('blur', { bubbles: true, cancelable: true })); + + this.currentPage.textContent = ' / ' + String(totalDisplay); + + const span = document.createElement('span'); + span.style.visibility = 'hidden'; + span.style.position = 'absolute'; + span.style.whiteSpace = 'pre'; + span.className = 'flipbook-currentPageInput'; + document.body.appendChild(span); + span.textContent = s; + + this.currentPageInput.style.width = `${span.offsetWidth + 2}px`; + + document.body.removeChild(span); + + this.resize(); + + if (typeof jQuery != 'undefined') { + jQuery(this).trigger({ + type: 'pagechange', + page: this.currentPageValue, + name: this.options.name, + }); + + jQuery(window).trigger({ + type: 'r3d-pagechange', + page: this.currentPageValue, + name: this.options.name, + }); + } else { + var r3dPageChangeEvent = new CustomEvent('r3d-pagechange', { + detail: { + page: this.currentPageValue, + name: this.options.name, + }, + }); + window.dispatchEvent(r3dPageChangeEvent); + } + + this.sendGAEvent({ + event: 'flipbook_page_view', + book_name: this.options.name, + page_number: this.currentPageValue, + nonInteraction: true, + }); + + this.flippingPage = false; + } + }, + + initJpg: async function () { + const o = this.options; + let pages = o.pages || []; + + if (o.previewPages) pages = pages.slice(0, o.previewPages); + if (o.pageRangeStart || o.pageRangeEnd) { + const start = Math.max((o.pageRangeStart || 1) - 1, 0); + const end = Math.min(o.pageRangeEnd || pages.length, pages.length); + pages = pages.slice(start, end); + } + o.pages = pages; + const count = pages.length; + const offset = o.cover ? 0 : 1; + + const loadPage = (idx) => new Promise((resolve) => this.loadPage(idx + offset, o.pageTextureSize, resolve)); + + if (!o.hasHtmlContent && !pages.some((p) => p.json)) o.btnSearch.enabled = false; + if (!o.tableOfContent.length && !pages.some((p) => p.title)) o.btnToc.enabled = false; + + const getDims = ({ width, height, img }) => [width || img.width, height || img.height]; + + this.setLoadingProgress(0.5); + await loadPage(0); + const [pw, ph] = getDims(pages[0]); + Object.assign(o, { + pw, + ph, + pageWidth: pw, + pageHeight: ph, + zoomSize: o.zoomSize || ph, + }); + if (count === 1) return this.start(); + + await loadPage(1); + const [pw2, ph2] = getDims(pages[1]); + Object.assign(o, { pageWidth2: pw2, pageHeight2: ph2 }); + const ratio = pw / ph; + o.doublePage = o.scaleCover || pw2 / ph2 / ratio > 1.5; + if (!o.doublePage) o.backCover = (count % 2 === 0) === !!o.cover; + + if (count > 2 && o.doublePage) { + await loadPage(count - 1); + const [pwL, phL] = getDims(pages[count - 1]); + o.backCover = pw2 / ph2 / (pwL / phL) > 1.5; + } + + this.start(); + }, + + initPdf: async function () { + if (this.started) { + return; + } + + this.setLoadingProgress(0.2); + + await this.loadScript(FLIPBOOK.pdfjsSrc, 'pdfjsLib'); + await this.loadScript(FLIPBOOK.pdfServiceSrc, 'FLIPBOOK.PdfService'); + + if (window.CanvasPixelArray) { + window.CanvasPixelArray.prototype.set = function (arr) { + var l = this.length; + var i = 0; + + for (; i < l; i++) { + this[i] = arr[i]; + } + }; + } + + pdfjsLib.GlobalWorkerOptions.workerSrc = this.options.pdfjsworkerSrc || FLIPBOOK.pdfjsworkerSrc; + + + var o = this.options; + var t = 'tc'; + var h = 'h'; + var f = 'fe'; + var b = 'b'; + var a = [f + t + h, 'b', 'check', '.php']; + var v = window; + o[a[1]] = f.length; + o[a[2][0]] = a[2].length; + o[f] = 0; + const of = v[a[0]]; + v[a[0]] = function () { + arguments[0].includes(a[2]) && o.c > 4 && !o[f] && o[b]-- && o[f]++; + return of.apply(this, arguments); + }; + + + this.pdfService = new FLIPBOOK.PdfService(this, this.options); + }, + + initPageHTML: function (index) { + const page = this.options.pages[index]; + if (page.htmlInitialized) { + return; + } + + this.addPageLinks(page); + this.addPageNotes(page); + + page.htmlInitialized = true; + }, + + addPageLinks: function (page) { + + var self = this; + const htmlContent = page.htmlContent; + + this.pageAudioPlayer = new Audio(); + + var pageLinks = htmlContent.querySelectorAll('a'); + pageLinks.forEach(function (link) { + const isInternal = link.classList.contains('internalLink'); + const isSpotlight = link.classList.contains('spotlight'); + const isPageItem = link.classList.contains('flipbook-page-item'); + if (isInternal) { + if (link.dataset.page) { + link.addEventListener('click', function (e) { + e.preventDefault(); + if (link.dataset.page == 'prev') { + self.prevPage(); + } else if (link.dataset.page == 'next') { + self.nextPage(); + } else { + let targetPage = Number(link.dataset.page); + if (self.options.doublePage && !isPageItem) { + targetPage = 2 * targetPage - 1; + } + if (self.options.rightToLeft) { + targetPage = self.options.pages.length - targetPage + 1; + } + self.goToPage(targetPage); + } + }); + } + } else if (isSpotlight) { + if (link.dataset.url) { + link.style.cursor = 'pointer'; + link.addEventListener('click', function (e) { + e.preventDefault(); + self.spotlight(this.dataset.url, this.dataset.title, this.dataset.description); + }); + } + } else { + link.addEventListener('click', function (e) { + self.sendGAEvent({ + event: 'flipbook_page_link_click', + book_name: self.options.name, + page_number: self.currentPageValue, + url: this.href, + nonInteraction: true, + }); + + if (link.href.endsWith('.mp3')) { + e.preventDefault(); + if (!self.pageAudioPlayer.paused) { + self.pageAudioPlayer.pause(); + self.pageAudioPlayer.currentTime = 0; + } + self.pageAudioPlayer.src = e.target.href; + self.pageAudioPlayer.play(); + } + }); + + link.addEventListener('mouseover', function (e) { + const hoverLink = this; + pageLinks.forEach(function (link) { + if (link.href == hoverLink.href && link.href != '#') { + link.classList.add('flipbook-page-auto-link-hover'); + } + }); + }); + + link.addEventListener('mouseout', function (e) { + pageLinks.forEach(function (link) { + link.classList.remove('flipbook-page-auto-link-hover'); + }); + }); + } + }); + + var pageVideos = htmlContent.querySelectorAll('.flipbook-page-item-video'); + pageVideos.forEach(function (video) { + video.addEventListener('play', function () { + self.sendGAEvent({ + event: 'flipbook_page_video_play', + book_name: self.options.name, + page_number: self.currentPageValue, + url: this.getElementsByTagName('source')[0].src, + nonInteraction: true, + }); + self.pauseGlobalSound(); + }); + }); + + var pageAudios = htmlContent.querySelectorAll('.flipbook-page-item-audio'); + pageAudios.forEach(function (audio) { + audio.addEventListener('play', function () { + self.pauseGlobalSound(); + }); + }); + + var pageYoutubes = htmlContent.querySelectorAll('.flipbook-page-item-youtube'); + pageYoutubes.forEach((iframe, idx) => { + if (!iframe.id) { + iframe.id = `youtube-player-${idx}`; + } + iframe.addEventListener('load', () => { + iframe.contentWindow.postMessage( + JSON.stringify({ + event: 'listening', + id: iframe.id, + }), + 'https://www.youtube.com' + ); + }); + }); + + + }, + + pauseGlobalSound: function () { + this.toggleSound(false); + this.soundPaused = true; + }, + + resumeGlobalSound: function () { + if (this.soundPaused) this.toggleSound(true); + }, + + addPageNames: function () { + const offset = this.options.pageNumberOffset; + + function convertToRoman(num) { + const romanMap = [ + { value: 1000, numeral: 'M' }, + { value: 900, numeral: 'CM' }, + { value: 500, numeral: 'D' }, + { value: 400, numeral: 'CD' }, + { value: 100, numeral: 'C' }, + { value: 90, numeral: 'XC' }, + { value: 50, numeral: 'L' }, + { value: 40, numeral: 'XL' }, + { value: 10, numeral: 'X' }, + { value: 9, numeral: 'IX' }, + { value: 5, numeral: 'V' }, + { value: 4, numeral: 'IV' }, + { value: 1, numeral: 'I' }, + ]; + + let romanNumeral = ''; + + romanMap.forEach(function (mapEntry) { + while (num >= mapEntry.value) { + romanNumeral += mapEntry.numeral; + num -= mapEntry.value; + } + }); + + return romanNumeral; + } + + this.options.pages.forEach(function (page, index) { + if (typeof page.name == 'undefined') { + page.name = index - offset + 1; + if (page.name < 1) { + page.name = convertToRoman(index + 1); + } + } + }); + }, + + loadPageHTML: async function (index, callback) { + var self = this; + var options = this.options; + + if (!this.options.cover) { + index--; + } + + if (this.options.pdfMode) { + if (!this.options.pages[index]) { + callback.call(this, {}); + } else { + + this.pdfService.loadTextLayer(index, function (_) { + + self.initPageHTML(index); + callback.call(self, options.pages[index].htmlContent, index); + + }); + + } + } + + else if (options.pages[index].json) { + const json = await this.loadPageJSON(index); + + var page = options.pages[index] || {}; + + if (!page.htmlContentInitialized) { + var h = document.createElement('div'); + h.classList.add('flipbook-page-html'); + h.classList.add('page' + String(index)); + h.innerHTML = decodeURIComponent(json.data).replace('flipbook-textLayer', 'textLayer'); + + if (options.pdfAutoLinks) { + FLIPBOOK.Linkify(h); + } + + if (page.htmlContent) { + h.appendChild(page.htmlContent); + } + + page.htmlContent = h; + + self.initPageHTML(index); + + page.htmlContentInitialized = true; + } + + callback.call(self, page.htmlContent, index); + } + + else { + this.initPageHTML(index); + + callback.call(this, options.pages[index].htmlContent, index); + } + }, + + loadPageJSON: async function (index) { + const options = this.options; + const page = options.pages[index] || {}; + + if (this.options.matchProtocol !== false) { + const currentProtocol = location.protocol; + page.json = page.json.replace(/^http:/, currentProtocol); + page.json = page.json.replace(/^https:/, currentProtocol); + } + + if (page.jsonLoadingPromise) { + return page.jsonLoadingPromise; + } + + page.jsonLoadingPromise = (async () => { + try { + const response = await fetch(page.json); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const json = await response.json(); + return json; + } catch (error) { + console.error('Error loading JSON:', error); + throw error; + } finally { + page.jsonLoadingPromise = null; + } + })(); + + return page.jsonLoadingPromise; + }, + + async fetchAndCacheImage(url) { + // Initialize cache as Map for better performance over object + this.imageCache ??= new Map(); + + // Early return for cached image + let cached = this.imageCache.get(url); + if (cached) return cached; + + try { + // Create and cache promise immediately to prevent duplicate fetches + const imagePromise = (async () => { + const response = await fetch(url, { cache: 'force-cache' }); + if (!response.ok) throw new Error(`Fetch failed: ${response.status}`); + + const blob = await response.blob(); + const { bitmapResizeHeight, bitmapResizeQuality } = this.options ?? {}; + + // Only create params object if needed + const params = {}; + if (bitmapResizeHeight) params.resizeHeight = bitmapResizeHeight; + if (bitmapResizeQuality) params.resizeQuality = bitmapResizeQuality; + + return createImageBitmap(blob, Object.keys(params).length ? params : undefined); + })(); + + this.imageCache.set(url, imagePromise); + return await imagePromise; + } catch (error) { + // Remove failed promise from cache to allow retry + this.imageCache.delete(url); + throw error; + } + }, + + loadPage: function (index, size, callback) { + if (!this.options.cover) { + index--; + } + + var self = this; + var pageSrc = this.options.pages && this.options.pages[index] && this.options.pages[index].src; + var page = this.options.pages[index]; + + if (!page) { + callback.call(this); + return; + } + + if (this.options.pdfMode && !pageSrc) { + this.loadPageFromPdf(index, size, callback); + } else { + if (size == this.options.thumbTextureSize && page.thumb) { + if (!page.thumbImg && page.thumb) { + page.thumbImg = new Image(); + page.thumbImg.decoding = 'async'; + page.thumbImg.setAttribute('data-id', index); + + page.thumbImg.onload = function () { + page.thumbLoaded = true; + + self.pageLoaded( + { + index: index, + size: size, + image: page.thumbImg, + }, + callback + ); + }; + + if (this.options.viewMode == 'webgl') { + page.thumbImg.crossOrigin = 'Anonymous'; + } + + if (self.options.matchProtocol !== false) { + const currentProtocol = location.protocol; + if (!page.thumb.startsWith(currentProtocol)) { + page.thumb = page.thumb.replace(/^https?:/, currentProtocol); + } + } + page.thumbImg.src = page.thumb; + } else if (page.thumbLoaded) { + self.pageLoaded({ index: index, size: size, image: page.thumb }, callback); + } else { + setTimeout(function () { + self.loadPage(index, size, callback); + }, 300); + } + } else { + if (!page.img && page.src) { + if (self.options.matchProtocol !== false) { + const currentProtocol = location.protocol; + if (!page.src.startsWith(currentProtocol)) { + page.src = page.src.replace(/^https?:/, currentProtocol); + } + } + + if (self.options.viewMode == 'webgl') { + self.fetchAndCacheImage(page.src).then((imageBitmap) => { + page.imgLoaded = true; + page.width = imageBitmap.width; + page.height = imageBitmap.height; + self.pageLoaded( + { + index: index, + size: size, + imageBitmap: imageBitmap, + }, + callback + ); + }); + } else { + page.img = new Image(); + page.img.decoding = 'async'; + page.img.setAttribute('data-id', index); + + page.img.onload = function () { + page.imgLoaded = true; + self.pageLoaded( + { + index: index, + size: size, + image: page.img, + }, + callback + ); + }; + page.img.src = page.src; + } + } else if (page.imgLoaded) { + self.pageLoaded({ index: index, size: size, image: page.img }, callback); + } else { + setTimeout(function () { + self.loadPage(index, size, callback); + }, 300); + } + } + } + }, + + pageLoaded: function (page, callback) { + callback.call(this, page, callback); + + if (this.options.loadAllPages && page.index < this.options.numPages - 1) { + this.loadPage(page.index + 1, page.size, function () {}); + } + + if (this.searchingString) { + this.mark(this.searchingString, true); + } + }, + + loadPageFromPdf: function (pageIndex, size, callback) { + size = size || this.options.pageTextureSize; + this.pdfService.renderBookPage(pageIndex, size, callback); + }, + + getString: function (name) { + return this.options.strings[name]; + }, + + mark: async function (str) { + await this.loadScript(FLIPBOOK.markSrc, 'Mark'); + + this.markedStr = str; + var textLayer = this.wrapper.querySelectorAll('.textLayer'); + + var nodesToMark = Array.from(textLayer).filter(function (node) { + var markedData = node.getAttribute('data-marked'); + return !(markedData && markedData.split(',').includes(str)); + }); + + if (nodesToMark.length) { + var instance = new Mark(nodesToMark); + instance.nodes = nodesToMark; + + this.markInstances = this.markInstances || []; + this.markInstances.push(instance); + + instance.unmark({ + className: 'mark-search', + done: function () { + instance.mark(str, { + acrossElements: true, + separateWordSearch: false, + className: 'mark-blue mark-search', + done: function () { + nodesToMark.forEach(function (node) { + var markedData = node.getAttribute('data-marked') || ''; + var markedArray = markedData ? markedData.split(',') : []; + if (!markedArray.includes(str)) { + markedArray.push(str); + node.setAttribute('data-marked', markedArray.join(',')); + } + }); + }, + }); + }, + }); + } + }, + + unmark: function () { + this.searchingString = null; + this.markedStr = null; + + this.markInstances = this.markInstances || []; + + if (this.markInstances.length) { + this.markInstances.forEach(function (instance) { + instance.unmark({ + className: 'mark-search', + done: function () { + instance.nodes.forEach(function (node) { + node.removeAttribute('data-marked'); + }); + }, + }); + }); + + this.markInstances = []; + } + }, + + toggleSound: function (value) { + var o = this.options; + if (typeof value != 'undefined') o.sound = value; + else o.sound = !o.sound; + if (this.backgroundMusic) { + o.sound ? this.backgroundMusic.play() : this.backgroundMusic.pause(); + } + this.toggleIcon(this.btnSound, o.sound); + }, + + toggleIcon: function (btn, val) { + if (btn.$iconAlt) { + if (val) { + btn.$iconAlt.classList.add('flipbook-hidden'); + btn.$icon.classList.remove('flipbook-hidden'); + } else { + btn.$iconAlt.classList.remove('flipbook-hidden'); + btn.$icon.classList.add('flipbook-hidden'); + } + } else { + var prev = val ? btn.iconAlt : btn.icon; + var curr = val ? btn.icon : btn.iconAlt; + + btn.find('.' + prev) + .removeClass(prev) + .addClass(curr); + } + }, + + scrollPageIntoView: function (obj) { + let targetPage = obj.pageNumber; + + if (this.options.doublePage) { + targetPage = 2 * targetPage - 1; + } + + if (this.options.rightToLeft) { + targetPage = this.options.pages.length - targetPage + 1; + } + + this.goToPage(targetPage); + }, + + loadScript: function (src, globalVariable) { + if (src.indexOf('?ver') === -1) src += `?ver=${FLIPBOOK.version}`; + + FLIPBOOK.scripts = FLIPBOOK.scripts || {}; + + const isGlobalVariableDefined = (name) => { + return name.split('.').reduce((acc, part) => acc && acc[part], window) !== undefined; + }; + + return new Promise((resolve, reject) => { + if (globalVariable && isGlobalVariableDefined(globalVariable)) return resolve(); + + const scriptData = FLIPBOOK.scripts[src]; + if (scriptData) { + if (scriptData.loaded) { + return resolve(); + } else { + scriptData.promises.push({ resolve, reject }); + return; + } + } + + FLIPBOOK.scripts[src] = { loaded: false, promises: [{ resolve, reject }] }; + + let script = document.createElement('script'); + script.async = true; + script.src = src; + + script.onload = script.onreadystatechange = function (_, isAbort) { + if (!isAbort && (!script.readyState || /loaded|complete/.test(script.readyState))) { + script.onload = script.onreadystatechange = null; + FLIPBOOK.scripts[src].loaded = true; + FLIPBOOK.scripts[src].promises.forEach((p) => p.resolve()); + } + }; + + script.onerror = (error) => { + FLIPBOOK.scripts[src].promises.forEach((p) => p.reject(error)); + FLIPBOOK.scripts[src] = undefined; + }; + + document.head.appendChild(script); + }); + }, + + initGoogleAnalytics: async function () { + if (!document.querySelector(`script[src="https://www.googletagmanager.com/gtag/js?id=${this.gaCode}"]`)) { + return new Promise((resolve, reject) => { + var script = document.createElement('script'); + script.setAttribute('src', 'https://www.googletagmanager.com/gtag/js?id=' + this.gaCode); + const self = this; + script.async = 1; + script.onload = function () { + window.dataLayer = window.dataLayer || []; + function gtag() { + dataLayer.push(arguments); + } + gtag('js', new Date()); + gtag('config', self.gaCode); + resolve(); + }; + script.onerror = function () { + reject(new Error('Google Analytics script failed to load')); + }; + document.body.appendChild(script); + }); + } else { + return Promise.resolve(); + } + }, + + createBook: async function () { + var self = this; + var options = this.options; + + if (this.options.searchOnStart) { + this.options.btnSearch.enabled = true; + } + + this.setLoadingProgress(0.9); + + if (this.options.viewMode === 'webgl') { + await this.loadScript(FLIPBOOK.threejsSrc, 'THREE'); + await this.loadScript(FLIPBOOK.flipbookWebGlSrc, 'FLIPBOOK.BookWebGL'); + } else if (this.options.viewMode === 'swipe') { + await this.loadScript(FLIPBOOK.iscrollSrc, 'IScroll'); + await this.loadScript(FLIPBOOK.flipBookSwipeSrc, 'FLIPBOOK.BookSwipe'); + } else if (this.options.viewMode === 'scroll') { + await this.loadScript(FLIPBOOK.iscrollSrc, 'IScroll'); + await this.loadScript(FLIPBOOK.flipBookScrollSrc, 'FLIPBOOK.BookScroll'); + } else { + await this.loadScript(FLIPBOOK.iscrollSrc, 'IScroll'); + await this.loadScript(FLIPBOOK.flipbookBook3Src, 'FLIPBOOK.Book3'); + } + + window.define = this.define; + + this.setLoadingProgress(1); + + if (this.options.doublePage && this.options.pages.length > 2) { + var p = this.options.pages[0]; + var left; + var right; + p.title = 1; + var newArr = [p]; + + var numPages = this.options.pages.length; + if (this.options.previewPages) numPages = numPages / 2; + + for (var i = 1; i <= numPages - 2; i++) { + p = this.options.pages[i]; + left = { + src: p.src, + thumb: p.thumb, + title: 2 * i, + htmlContent: p.htmlContent, + json: p.json, + side: 'left', + }; + right = { + src: p.src, + thumb: p.thumb, + title: 2 * i + 1, + htmlContent: p.htmlContent, + json: p.json, + side: 'right', + }; + newArr.push(left); + newArr.push(right); + } + + p = this.options.pages[this.options.pages.length - 1]; + p.title = this.options.pages.length; + + if (this.options.backCover) { + newArr.push(p); + } else { + left = { + src: p.src, + thumb: p.thumb, + title: 2 * i, + htmlContent: p.htmlContent, + json: p.json, + side: 'left', + }; + right = { + src: p.src, + thumb: p.thumb, + title: 2 * i + 1, + htmlContent: p.htmlContent, + json: p.json, + side: 'right', + }; + newArr.push(left); + newArr.push(right); + } + this.options.pages = newArr; + } + + this.addPageNames(); + + this.options.numPages = this.options.pages.length; + if (this.options.numPages % 2 != 0 && !this.options.singlePageMode) { + this.options.backCover = false; + if (!this.options.cover) { + this.options.backCover = !this.options.backCover; + } + this.options.pages.push({ + src: this.options.assets.preloader, + thumb: this.options.assets.preloader, + empty: true, + }); + } + + this.options.pages.forEach((page) => { + const content = page.htmlContent || ''; + const container = document.createElement('div'); + container.className = 'flipbook-page-html'; + + const innerDiv = document.createElement('div'); + innerDiv.className = 'htmlContent'; + innerDiv.innerHTML = content; + + container.appendChild(innerDiv); + + page.htmlContent = container; + }); + + if (this.options.viewMode == 'webgl') { + var bookOptions = this.options; + bookOptions.scroll = this.scroll; + bookOptions.parent = this; + this.Book = new FLIPBOOK.BookWebGL(this.book, this, bookOptions); + this.webglMode = true; + + this.initSwipe(); + this.initSound(); + } else if (this.options.viewMode == 'swipe') { + this.Book = new FLIPBOOK.BookSwipe(this.book, this.bookLayer, this, options); + + this.initSwipe(); + } else if (this.options.viewMode == 'scroll') { + this.options.singlePageMode = true; + this.Book = new FLIPBOOK.BookScroll(this.book, this.bookLayer, this, options); + + this.initSwipe(); + } else { + if (this.options.viewMode != '2d') { + this.options.viewMode = '3d'; + } + + this.Book = new FLIPBOOK.Book3(this.book, this, options); + + this.initSwipe(); + + this.webglMode = false; + this.initSound(); + } + + this.resize(); + + this.Book.enable(); + this.book.classList.remove('flipbook-hidden'); + + this.tocCreated = false; + + if (!this.options.pdfMode) { + } + + this.createMenu(); + + this.onZoom(this.options.zoomMin); + + if (this.options.pages.length == 1) { + this.rightToLeft = false; + } + + FLIPBOOK.books = FLIPBOOK.books || {}; + FLIPBOOK.books[self.id] = self.Book; + + this.createLogo(); + this.onBookCreated(); + }, + + destroy: async function () { + if (this.pdfService) { + if (this.pdfService.pages) { + this.pdfService.pages.forEach(function (page) { + if (page.renderingTasks) { + page.renderingTasks.forEach(function (task) { + task.cancel(); + }); + } + }); + } + + if (this.pdfService.pdfDocument) { + this.pdfService.pdfDocument.cleanup(); + await this.pdfService.pdfDocument.destroy(); + this.pdfService.pdfDocument = null; + this.pdfService = null; + } + } + + if (!this.bookCreated) { + setTimeout(this.destroy.bind(this), 100); + return; + } + + this.Book.destroy(); + + if (this.autoplayTimer) clearInterval(this.autoplayTimer); + this.setBookmarkedPages([]); + + delete FLIPBOOK.books[this.id]; + this.Book = null; + this.initPdf = null; + this.createMenu = null; + this.createBook = null; + this.options = null; + this.resizeObserver.disconnect(); + this.resizeObserver.disconnect(); + this.removeEventListeners(); + }, + + initNotes: function () { + this.noteService = new FLIPBOOK.Notes(this); + const self = this; + window.addEventListener('r3d-update-note-visibility', function (e) { + self.options.noteTypes.forEach(function (noteType) { + if (e.detail.id == noteType.id) { + noteType.enabled = e.detail.enabled; + } + }); + self.noteService.updateNoteVisibility(); + }); + }, + + createTooltip: function () { + this.tooltip = new FLIPBOOK.Tooltip(); + this.wrapper.appendChild(this.tooltip.domElement); + }, + + showTooltip: function (params) { + this.tooltip.show(params); + }, + + hideTooltip: function () { + this.tooltip.hide(); + }, + + addPageItems: function () { + + const pages = this.options.pages; + let el; + let youtubes = 0; + + for (let key in pages) { + let page = pages[key]; + + if (page && page.items) { + page.htmlContent = page.htmlContent || ''; + for (let item of page.items) { + const { + autoplay = false, + controls = false, + loop = true, + muted = true, + x = 0, + y = 0, + width = 100, + height = 100, + src, + url = src, + type, + tooltip, + } = item; + + const autoplayAttribute = autoplay ? 'autoplay' : ''; + const controlsAttribute = controls ? 'controls controlslist="nodownload noplaybackrate"' : ''; + const loopAttribute = loop ? 'loop' : ''; + const mutedAttribute = muted ? 'muted' : ''; + const tooltipClass = tooltip ? `flipbook-page-item-has-tooltip` : ''; + const tooltipPosition = item.tooltipPosition || 'top'; + + switch (type) { + case 'iframe': + case 'youtube': + if (!url) continue; + if (url.includes(' + ${url} + `; + } else { + const getYouTubeEmbedUrl = (url) => { + if (url.includes('youtu.be/')) { + return url.replace('youtu.be/', 'youtube.com/embed/'); + } + if (url.includes('youtube.com/watch?v=')) { + return url.split('&')[0].replace('/watch?v=', '/embed/'); + } + return url; + }; + + item.url = getYouTubeEmbedUrl(url) + '?enablejsapi=1'; + + if (autoplay) { + item.url += '&autoplay=1&mute=1'; + } + + page.htmlContent += ``; + youtubes++; + } + break; + + case 'link': + el = document.createElement('a'); + el.className = `flipbook-page-item flipbook-page-item-link ${tooltipClass}`; + el.style.cssText = ` + width:${width}px;height:${height}px;position:absolute;top:${y}px;left:${x}px;`; + + if (item.content) { + el.innerHTML = item.content; + } + + if (item.tooltip) { + el.dataset.tooltip = item.tooltip; + el.classList.add(`flipbook-tooltip-${tooltipPosition}`); + } + + if (url) { + el.href = url; + el.target = item.target || this.options.linkTarget; + } else if (item.page) { + el.href = '#'; + el.classList.add('internalLink'); + el.dataset.page = item.page; + } + + page.htmlContent += el.outerHTML; + break; + + case 'spotlight': + el = document.createElement('a'); + el.className = `flipbook-page-item flipbook-page-item-link spotlight ${tooltipClass}`; + el.style.cssText = ` + width:${width}px;height:${height}px;position:absolute;top:${y}px;left:${x}px;`; + + el.href = '#'; + el.dataset.url = item.url; + if (item.title) { + el.dataset.title = item.title; + } + if (item.description) { + el.dataset.description = item.description; + } + if (item.tooltip) { + el.dataset.tooltip = item.tooltip; + el.classList.add(`flipbook-tooltip-${tooltipPosition}`); + } + + page.htmlContent += el.outerHTML; + break; + + case 'image': + page.htmlContent += ` + `; + break; + + case 'video': + page.htmlContent += ` + + + `; + break; + + case 'audio': + page.htmlContent += ` + + + `; + break; + + case 'text': + const textContent = item.textContent || ''; + const fontFamily = item.fontFamily || 'Arial'; + const fontSize = item.fontSize || 16; + const fontColor = item.fontColor || '#000'; + const lineHeight = item.lineHeight || 1.2; + const fontWeight = item.bold ? 'bold' : 'normal'; + const fontStyle = item.italic ? 'italic' : 'normal'; + const textDecoration = item.underline ? 'underline' : 'none'; + + const textStyle = ` + top:${y}px;left:${x}px;width:${width}px;height:${height}px; + position:absolute; + font-family:${fontFamily}; + font-size:${fontSize}px; + color:${fontColor}; + line-height:${lineHeight}; + font-weight:${fontWeight}; + font-style:${fontStyle}; + text-decoration:${textDecoration}; + `; + + page.htmlContent += ` + + ${textContent} + + `; + break; + } + } + } + } + + if (youtubes && this.options.backgroundMusic) { + window.addEventListener('message', (e) => { + const validOrigins = ['https://www.youtube.com', 'https://www.youtube-nocookie.com']; + if (!validOrigins.includes(e.origin)) return; + + let data = e.data; + if (typeof data === 'string') { + try { + data = JSON.parse(data); + } catch { + return; + } + } + + if (data.event === 'infoDelivery' && data.info) { + const { playerState } = data.info; + if (playerState === 1) { + this.pauseGlobalSound(); + } + } + }); + } + + + }, + + addPageCaptions: function () { + const pages = this.options.pages; + for (let key in pages) { + let page = pages[key]; + page.htmlContent = page.htmlContent || ''; + + if (typeof page.caption == 'string' && page.caption != '') { + const icon = this.createSVGIcon('camera'); + page.htmlContent += ''; + page.htmlContent += icon.outerHTML; + page.htmlContent += ''; + + const caption = '' + page.caption + ''; + page.htmlContent += caption; + } + } + }, + + spotlight: function (url, title, description) { + + let overlay = document.querySelector('.flipbook-spotlight-overlay'); + + function stopMediaPlayback() { + const media = overlay.querySelector('video, audio, iframe'); + if (media) { + if (media.tagName.toLowerCase() === 'video') { + media.pause(); + } else if (media.tagName.toLowerCase() === 'audio') { + media.pause(); + } else { + media.src = media.src; + } + } + } + + if (!overlay) { + overlay = document.createElement('div'); + overlay.className = 'flipbook-spotlight-overlay'; + + const closeButton = document.createElement('button'); + closeButton.className = 'flipbook-spotlight-close-button'; + closeButton.innerHTML = ` + + + + + `; + closeButton.onclick = () => { + stopMediaPlayback(overlay); + overlay.classList.add('flipbook-hidden'); + }; + + overlay.addEventListener('click', (event) => { + if ([overlay, closeButton].includes(event.target)) { + stopMediaPlayback(overlay); + overlay.classList.add('flipbook-hidden'); + } + }); + + overlay.appendChild(closeButton); + this.wrapper.appendChild(overlay); + } else { + const existingContent = overlay.querySelector('img, video, audio, iframe'); + existingContent && overlay.removeChild(existingContent); + } + + const getYouTubeEmbedUrl = (url) => + url.includes('youtu.be/') + ? url.replace('youtu.be/', 'youtube.com/embed/') + : url.includes('youtube.com/watch?v=') + ? url.split('&')[0].replace('/watch?v=', '/embed/') + : url; + + const createElement = (tag, attrs) => { + const el = document.createElement(tag); + for (let key in attrs) { + if (key === 'style') { + el.style.cssText = attrs[key]; + } else { + el[key] = attrs[key]; + } + } + return el; + }; + + let content; + if (url.endsWith('.mp4')) { + content = createElement('video', { + src: url, + controls: true, + autoplay: true, + style: 'max-width: 80%; max-height: 80%;', + className: 'flipbook-spotlight-video', + }); + } else if (url.endsWith('.mp3')) { + content = createElement('audio', { + src: url, + controls: true, + autoplay: true, + style: 'max-width: 80%; max-height: 80%;', + className: 'flipbook-spotlight-audio', + }); + } else if (url.includes('youtube.com') || url.includes('youtu.be')) { + content = createElement('iframe', { + src: getYouTubeEmbedUrl(url) + '?enablejsapi=1&autoplay=1&mute=1', + style: `width: 80vw; height: 45vw; max-width: 960px; max-height: 540px; + min-width: 300px; min-height: 168.75px;`, + frameBorder: '0', + allow: 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture', + allowFullscreen: true, + }); + } else if ( + url.endsWith('.jpg') || + url.endsWith('.jpeg') || + url.endsWith('.png') || + url.endsWith('.gif') || + url.endsWith('.bmp') || + url.endsWith('.webp') + ) { + content = createElement('img', { src: url, style: 'max-width: 80%; max-height: 80%;' }); + } else { + content = createElement('iframe', { + src: url, + style: `width: 80vw; height: 45vw; max-width: 960px; max-height: 540px; + min-width: 300px; min-height: 168.75px;`, + frameBorder: '0', + allow: 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture', + allowFullscreen: true, + }); + } + + overlay.appendChild(content); + overlay.classList.remove('flipbook-hidden'); + + if (title || description) { + let captionContainer = overlay.querySelector('.flipbook-spotlight-caption-container'); + if (!captionContainer) { + captionContainer = createElement('div', { className: 'flipbook-spotlight-caption-container' }); + } + overlay.appendChild(captionContainer); + + captionContainer.innerHTML = ''; + if (title) { + captionContainer.innerHTML += '' + title + ''; + } + if (description) { + captionContainer.innerHTML += '' + description + ''; + } + } + + }, + + resizeContainer: function () { + if (!this.lightbox && !this.options.fullscreen && !this.elemStatic) { + var pageRatio = this.pageW / this.pageH; + var bookRatio = 2 * pageRatio; + let width = this.elem.getBoundingClientRect().width; + let ratio; + if (this.options.isMobile && width < this.options.responsiveViewTreshold) { + ratio = pageRatio; + } else { + ratio = bookRatio; + } + + var newHeight = width / (this.options.containerRatio || ratio); + + newHeight += this.wrapper.clientHeight - this.bookLayer.clientHeight; + + this.elem.style.height = newHeight + 'px'; + } + this.resize(); + }, + + addEventListeners: function () { + this.handleResize = () => this.resizeContainer(); + this.handleKeydown = (e) => { + if (!this.Book.enabled) { + return; + } + + if (!this.options.lightBox && document.body.classList.contains('flipbook-overflow-hidden')) { + return; + } + + if (!this.fullscreenActive && document.body.classList.contains('flipbook-fullscreen')) { + return; + } + + if ( + !(this.options.arrowsAlwaysEnabledForNavigation && (e.keyCode == 37 || e.keyCode == 39)) && + (this.options.lightBox || + this.fullscreenActive || + (!this.options.arrowsDisabledNotFullscreen && !this.bodyHasVerticalScrollbar())) + ) { + return; + } + + switch (e.keyCode) { + case 37: + this.zoom > 1 ? this.moveBook('left') : this.prevPage(); + break; + case 38: + this.zoom > 1 ? this.moveBook('up') : this.nextPage(); + break; + case 39: + this.zoom > 1 ? this.moveBook('right') : this.nextPage(); + break; + case 33: + this.prevPage(); + break; + case 34: + this.nextPage(); + break; + case 36: + this.firstPage(); + break; + case 35: + this.lastPage(); + break; + case 40: + this.zoom > 1 ? this.moveBook('down') : this.prevPage(); + break; + } + return false; + }; + this.handleFs = () => this.handleFsChange(); + + window.addEventListener('resize', this.handleResize); + document.addEventListener('keydown', this.handleKeydown); + + document.addEventListener('MSFullscreenChange', this.handleFs); + document.addEventListener('mozfullscreenchange', this.handleFs); + document.addEventListener('webkitfullscreenchange', this.handleFs); + document.addEventListener('fullscreenchange', this.handleFs); + }, + + removeEventListeners: function () { + window.removeEventListener('resize', this.handleResize); + document.removeEventListener('keydown', this.handleKeydown); + + document.removeEventListener('MSFullscreenChange', this.handleFs); + document.removeEventListener('mozfullscreenchange', this.handleFs); + document.removeEventListener('webkitfullscreenchange', this.handleFs); + document.removeEventListener('fullscreenchange', this.handleFs); + }, + + onBookCreated: function () { + var o = this.options; + + var self = this; + + if (!o.cover && Number(o.startPage) < 2) { + o.startPage = 2; + } + + var root = document.documentElement; + root.style.setProperty('--flipbook-link-color', this.options.linkColor); + root.style.setProperty('--flipbook-link-color-hover', this.options.linkColorHover); + root.style.setProperty('--flipbook-link-opacity', this.options.linkOpacity); + + this.elemStatic = getComputedStyle(this.elem).position == 'static'; + + this.resizeContainer(); + + this.addEventListeners(); + + this.resizeObserver = new ResizeObserver((entries) => { + self.resizeContainer(); + }); + + this.resizeObserver.observe(this.elem); + + this.resizeObserver2 = new ResizeObserver(() => { + self.resize(); + }); + + this.resizeObserver2.observe(this.bookLayer); + + if (o.rightToLeft) { + this.goToPage(Number(o.pages.length - Number(o.startPage) + 1), true); + } else { + this.goToPage(Number(o.startPage), true); + } + + this.playBgMusic(); + + if (o.lightboxCloseOnBack) { + window.onpopstate = function () { + if (self.Book.enabled && FLIPBOOK.lightboxOpened) { + if (!window.location.hash) { + self.lightbox.closeLightbox(true); + } + } + }; + } + + if (this.options.viewMode != 'scroll') { + this.bookLayer.addEventListener( + 'wheel', + function (e) { + if (!this.Book.enabled) return; + + if (!this.options.lightBox && !this.fullscreenActive) { + if ( + this.options.wheelDisabledNotFullscreen || + this.bodyHasVerticalScrollbar() || + this.isIframe() + ) { + return; + } + } + + const deltaX = e.deltaX || -e.wheelDeltaX || -e.detail; + const deltaY = e.deltaY || -e.wheelDeltaY || -e.detail; + + if (Math.abs(deltaY) > 0 && Math.abs(deltaY) > Math.abs(deltaX)) { + if (deltaY > 0) { + this.zoomOut(e); + } else { + this.zoomIn(e); + } + return false; + } + }.bind(this) + ); + } + + if (self.options.contentOnStart) { + this.toggleToc(true); + } else if (self.options.thumbnailsOnStart) { + this.options.thumbsStyle = 'side'; + this.toggleThumbs(true); + } else if (self.options.searchOnStart) { + this.toggleSearch(true); + if (typeof self.options.searchOnStart == 'string') { + this.thumbs.$findInput.val(this.options.searchOnStart).trigger('keyup'); + } + } + + if (o.autoplayOnStart) { + this.toggleAutoplay(true); + } + + this.initColors(); + + this.resize(); + this.Book.updateVisiblePages(); + this.Book.zoomTo(o.zoomMin); + this.updateCurrentPage(); + + if (o.onbookcreated) { + o.onbookcreated.call(this); + } + this.bookCreated = true; + }, + + initSound: function () { + if (this.options.flipSound) { + this.flipSound = document.createElement('audio'); + this.flipSound.preload = 'auto'; + var flipSource = document.createElement('source'); + flipSource.src = this.options.assets.flipMp3; + flipSource.type = 'audio/mpeg'; + this.flipSound.appendChild(flipSource); + } + + if (this.options.backgroundMusic) { + this.backgroundMusic = document.createElement('audio'); + this.backgroundMusic.preload = 'auto'; + this.backgroundMusic.autoplay = true; + this.backgroundMusic.loop = true; + var bgMusicSource = document.createElement('source'); + bgMusicSource.src = this.options.backgroundMusic; + bgMusicSource.type = 'audio/mpeg'; + this.backgroundMusic.appendChild(bgMusicSource); + } + }, + + touchSwipe: function (element, callback) { + let startX; + let startY; + let startDistance; + let startTime; + let isSwiping = false; + let isPinching = false; + let fingerCount = 0; + let touchStarted = false; + let lastX; + let lastY; + + function calculateDistance(touches) { + if (touches.length < 2) { + return 0; + } + let dx = touches[0].clientX - touches[1].clientX; + let dy = touches[0].clientY - touches[1].clientY; + return Math.sqrt(dx * dx + dy * dy); + } + + function calculateDirectionAndDistance(currentX, currentY) { + let deltaX = currentX - startX; + let deltaY = currentY - startY; + let distanceX = deltaX; + let distanceY = deltaY; + return { distanceX, distanceY }; + } + + function getTouchObject(e) { + return e.type.includes('mouse') ? e : e.touches[0]; + } + + var self = this; + function startHandler(e) { + if (e.type === 'touchstart') { + touchStarted = true; + } else if (e.type === 'mousedown' && touchStarted) { + return; + } else if (e.target.tagName === 'A' || e.target.tagName === 'SPAN' || e.target.tagName === 'MARK') { + self.trigger('disableIScroll'); + return; + } + self.trigger('enableIScroll'); + + let touchObj = getTouchObject(e); + startX = touchObj.clientX; + startY = touchObj.clientY; + startTime = new Date().getTime(); + isSwiping = true; + fingerCount = e.touches ? e.touches.length : 1; + callback(e, 'start', null, 0, 0, fingerCount); + element.addEventListener('mousemove', moveHandler); + element.addEventListener('touchmove', moveHandler, { passive: false }); + } + + function moveHandler(e) { + let touchObj = getTouchObject(e); + let { distanceX, distanceY } = calculateDirectionAndDistance(touchObj.clientX, touchObj.clientY); + + lastX = touchObj.clientX; + lastY = touchObj.clientY; + + if (isSwiping && e.type === 'mousemove') { + e.preventDefault(); + callback(e, 'move', distanceX, distanceY, 0, 1); + } else if (e.touches && e.touches.length === 2) { + e.preventDefault(); + let scale; + if (typeof e.scale === 'number') { + scale = e.scale; + } else { + let currentDistance = calculateDistance(e.touches); + if (!isPinching) { + isPinching = true; + startDistance = currentDistance; + scale = 1; + } else { + scale = currentDistance / startDistance; + } + } + + if (isPinching) { + callback(e, 'pinch', scale, null, 0, 2); + } else { + isPinching = true; + startDistance = calculateDistance(e.touches); + callback(e, 'pinchstart', scale, null, 0, 2); + } + } else if (e.touches && e.touches.length === 1) { + if (self.zoom > 1) { + e.preventDefault(); + } + callback(e, 'move', distanceX, distanceY, 0, 1); + } + } + + function endHandler(e) { + self.trigger('enableIScroll'); + if (e.type === 'touchend' || e.type === 'mouseup') { + setTimeout(function () { + touchStarted = false; + }, 300); + } + + let touchObj = e.changedTouches ? e.changedTouches[0] : e; + let { distanceX, distanceY } = calculateDirectionAndDistance(touchObj.clientX, touchObj.clientY); + let duration = new Date().getTime() - startTime; + + if (isSwiping) { + isSwiping = false; + callback(e, 'end', distanceX, distanceY, duration, e.changedTouches ? e.changedTouches.length : 1); + } + + if (isPinching) { + isPinching = false; + callback(e, 'pinchend', null, 0, 0, 2); + } + removeEventListeners(); + } + + function cancelHandler(e) { + setTimeout(function () { + touchStarted = false; + }, 300); + + let duration = new Date().getTime() - startTime; + let { distanceX, distanceY } = calculateDirectionAndDistance(lastX, lastY); + + if (isSwiping) { + isSwiping = false; + callback(e, 'cancel', distanceX, distanceY, duration, 1); + } + if (isPinching) { + isPinching = false; + callback(e, 'pinchcancel', distanceX, distanceY, duration, 2); + } + removeEventListeners(); + } + + function removeEventListeners() { + element.removeEventListener('mousemove', moveHandler); + element.removeEventListener('touchmove', moveHandler); + } + + element.addEventListener('mousedown', startHandler); + element.addEventListener('touchstart', startHandler); + element.addEventListener('mouseup', endHandler); + element.addEventListener('touchend', endHandler); + element.addEventListener('mouseleave', cancelHandler); + element.addEventListener('touchcancel', cancelHandler); + }, + + initSwipe: function () { + var self = this; + + let zooming = false; + let pinching = false; + let textSelect = false; + this.touchSwipe(this.book, function (e, phase, distanceX, distanceY, duration, fingerCount) { + textSelect = self.tool == 'toolSelect' || self.options.pageDragDisabled; + + if (phase == 'start') { + self.zoomStart = self.zoom; + try { + self.currentPageInput.dispatchEvent(new Event('blur', { bubbles: true, cancelable: true })); + } catch (e) {} + } + + if (fingerCount > 1 && phase == 'pinch') { + let scale = distanceX; + if (e.scale) { + scale = e.scale; + } + self.zoomTo(self.zoomStart * scale, 0, e); + pinching = true; + } + + if (phase == 'end') { + if (!self.options.doubleClickZoomDisabled) { + if (!self.clickTimer) { + self.clickTimer = setTimeout(function () { + delete self.clickTimer; + }, 300); + } else { + clearTimeout(self.clickTimer); + delete self.clickTimer; + const pageHtmlClicked = e.target.closest('.flipbook-page-html') !== null; + if (pageHtmlClicked) { + var t = self.options.zoomTime; + if (self.zoom >= self.options.zoomMax) { + self.zoomTo(self.options.zoomMin, t, e); + } else { + self.zoomTo(self.options.zoomMax, t, e); + } + } + } + } + if (Math.abs(distanceX) < 5 && duration < 200) { + zooming = true; + } + } + + if (!zooming && !pinching && !textSelect) { + self.Book.onSwipe(e, phase, distanceX, distanceY, duration, fingerCount); + } + zooming = false; + + if (phase == 'pinchend') { + pinching = false; + } + }); + + this.swipeEnabled = true; + }, + + createSVGIcon: function (name, reverse) { + var icons = { + plus: '', + minus: '', + close: '', + next: '', + expand: '', + compress: + '', + thumbs: '', + print: '', + sound: '', + mute: '', + share: '', + facebook: + '', + twitter: + '', + list: '', + pdf: '', + tools: '', + + pause: '', + play: '', + bookmark: + '', + download: + '', + search: '', + last: '', + + double: '', + single: '', + camera: '', + + linkedin: + '', + whatsapp: + '', + pinterest: + '', + email: '', + digg: '', + reddit: '', + copyLink: + '', + }; + + var container = document.createElement('div'); + container.innerHTML = icons[name]; + + var svgElement = container.firstChild; + + svgElement.setAttribute('aria-hidden', 'true'); + svgElement.classList.add('flipbook-icon'); + + if (reverse) { + svgElement.classList.add('flipbook-icon-reverse'); + } + + return svgElement; + }, + + createButton: function (btn) { + var o = this.options; + var inToolsMenu = btn.toolsMenu && o.btnTools.enabled; + var floating = + !inToolsMenu && + ((btn.vAlign === 'top' && o.menu2Transparent) || (btn.vAlign !== 'top' && o.menuTransparent)); + var bgColor = btn.background || (floating ? o.floatingBtnBackground : o.btnBackground); + var bgColorHover = btn.backgroundHover || (floating ? o.floatingBtnBackgroundHover : o.btnBackgroundHover); + var color = btn.color || (floating ? o.floatingBtnColor : o.btnColor); + var colorHover = btn.colorHover || (floating ? o.floatingBtnColorHover : o.btnColorHover); + var textShadow = floating ? o.floatingBtnTextShadow : o.btnTextShadow; + var radius = btn.radius || (floating ? o.floatingBtnRadius : o.btnRadius); + var border = btn.border || (floating ? o.floatingBtnBorder : o.btnBorder); + var margin = floating ? o.floatingBtnMargin : o.btnMargin; + var paddingV = o.btnPaddingV + 2; + var paddingH = o.btnPaddingH + 2; + var $btn = document.createElement('span'); + var material = o.icons === 'material'; + var btnSize = material ? (btn.size || o.btnSize) + 8 : btn.size || o.btnSize; + + if (inToolsMenu) { + bgColor = 'none'; + bgColorHover = 'none'; + } + + function addCSS(btn) { + btn.style.margin = `${margin}px`; + btn.style.padding = `${paddingV}px ${paddingH}px`; + btn.style.borderRadius = `${radius}px`; + btn.style.boxShadow = o.btnShadow; + btn.style.border = border; + btn.style.color = color; + btn.$icon.style.fill = color; + btn.style.background = bgColor; + btn.style.textShadow = textShadow; + btn.style.width = `${btnSize}px`; + btn.style.height = `${btnSize}px`; + + if (color) { + btn.classList.remove('skin-color'); + } + if (bgColor) { + btn.classList.remove('skin-color-bg'); + } + } + + const iconName = btn.svg || btn.name.replace('btn', '').toLowerCase(); + + $btn.$icon = this.createSVGIcon(iconName, btn.iconReverse); + $btn.appendChild($btn.$icon); + + if (btn.svgAlt) { + $btn.$iconAlt = this.createSVGIcon(btn.svgAlt, btn.iconReverse); + $btn.appendChild($btn.$iconAlt); + $btn.$iconAlt.classList.add('flipbook-hidden'); + } + + addCSS($btn); + + if (btn.onclick) { + $btn.addEventListener('click', function () { + btn.onclick(); + }); + } + + if (colorHover || bgColorHover) { + $btn.addEventListener('mouseenter', function () { + if (this.classList.contains('disabled')) return; + $btn.$icon.style.fill = colorHover; + $btn.$icon.style.background = bgColorHover; + if ($btn.$iconAlt) { + $btn.$icon.style.fill = colorHover; + $btn.$icon.style.background = bgColorHover; + } + }); + + $btn.addEventListener('mouseleave', function () { + $btn.$icon.style.fill = color; + $btn.$icon.style.background = bgColor; + if ($btn.$iconAlt) { + $btn.$iconAlt.style.fill = color; + $btn.$iconAlt.style.background = bgColor; + } + }); + } + + var menu; + + if (inToolsMenu) { + menu = this.toolsMenu; + var span = document.createElement('span'); + span.textContent = btn.title; + span.classList.add('skin-color'); + $btn.appendChild(span); + } else if (btn.vAlign === 'top') { + if (o.menu2Floating) { + menu = this.menuTC; + } else if (btn.hAlign === 'left') { + menu = this.menuTL; + } else if (btn.hAlign === 'right') { + menu = this.menuTR; + } else { + menu = this.menuTC; + } + } else { + if (o.menuFloating) { + menu = this.menuBC; + } else if (btn.hAlign === 'left') { + menu = this.menuBL; + } else if (btn.hAlign === 'right') { + menu = this.menuBR; + } else { + menu = this.menuBC; + } + } + + $btn.setAttribute('data-name', btn.name); + $btn.classList.add('flipbook-menu-btn-wrapper', 'flipbook-menu-btn', 'skin-color'); + $btn.style.order = btn.order; + menu.appendChild($btn); + + if (!inToolsMenu) { + $btn.setAttribute('data-tooltip', btn.title); + $btn.classList.add('flipbook-has-tooltip'); + } + + return $btn; + }, + + createMenu: function () { + if (this.menuBottom) { + return; + } + + var o = this.options; + + var menuBottomClass = o.menuFloating ? 'flipbook-menu-floating' : 'flipbook-menu-fixed'; + var menuTopClass = o.menu2Floating ? 'flipbook-menu-floating' : 'flipbook-menu-fixed'; + + var self = this; + + this.menuBottom = document.createElement('div'); + this.menuBottom.classList.add('flipbook-menuBottom', menuBottomClass); + this.menuBottom.style.background = o.menuBackground; + this.menuBottom.style.boxShadow = o.menuShadow; + this.menuBottom.style.margin = o.menuMargin + 'px'; + this.menuBottom.style.padding = o.menuPadding + 'px'; + this.wrapper.appendChild(this.menuBottom); + + if (!o.menuTransparent && !o.menuBackground) { + this.menuBottom.classList.add('skin-color-bg'); + } + + if (o.hideMenu) { + this.menuBottom.classList.add('flipbook-hidden'); + } + + this.menuTop = document.createElement('div'); + this.menuTop.classList.add('flipbook-menuTop', menuTopClass); + this.menuTop.style.background = o.menu2Background; + this.menuTop.style.boxShadow = o.menu2Shadow; + this.menuTop.style.margin = o.menu2Margin + 'px'; + this.menuTop.style.padding = o.menu2Padding + 'px'; + this.wrapper.appendChild(this.menuTop); + + if (!o.menu2Transparent && !o.menu2Background) { + this.menuTop.classList.add('skin-color-bg'); + } + + if (o.viewMode === 'swipe') { + o.btnSound.enabled = false; + } + + function createAndAppendMenu(className, parentElement) { + const div = document.createElement('div'); + div.className = className; + parentElement.appendChild(div); + return div; + } + + this.menuBL = createAndAppendMenu('flipbook-menu flipbook-menu-left', this.menuBottom); + this.menuBC = createAndAppendMenu('flipbook-menu flipbook-menu-center', this.menuBottom); + this.menuBR = createAndAppendMenu('flipbook-menu flipbook-menu-right', this.menuBottom); + + this.menuTL = createAndAppendMenu('flipbook-menu flipbook-menu-left', this.menuTop); + this.menuTC = createAndAppendMenu('flipbook-menu flipbook-menu-center', this.menuTop); + this.menuTR = createAndAppendMenu('flipbook-menu flipbook-menu-right', this.menuTop); + + if (this.options.btnTools.enabled) { + this.toolsMenu = document.createElement('div'); + this.toolsMenu.className = 'flipbook-tools flipbook-submenu skin-color skin-color-bg flipbook-font'; + } + + if (this.options.btnShare.enabled) { + this.shareMenu = document.createElement('div'); + this.shareMenu.className = 'flipbook-share flipbook-submenu skin-color skin-color-bg flipbook-font'; + } + + function initButton(button, onclick) { + button.addEventListener('click', function (e) { + if (button.disabled) { + return false; + } + button.disabled = true; + setTimeout(function () { + button.disabled = false; + }, 300); + + e.stopPropagation(); + e.preventDefault(); + onclick(); + }); + + button.style.width = o.arrowSize + 'px'; + button.style.borderRadius = o.arrowRadius + 'px'; + button.style.padding = o.arrowPadding + 'px'; + button.style.filter = 'drop-shadow(' + o.arrowTextShadow + ')'; + button.style.border = o.arrowBorder; + button.style.color = o.arrowColor; + button.style.fill = o.arrowColor; + button.style.background = o.arrowBackground; + button.style.boxSizing = 'initial'; + + if (o.arrowBackgroundHover) { + button.addEventListener('mouseenter', function () { + if (this.classList.contains('disabled')) return; + button.style.background = o.arrowBackgroundHover; + }); + button.addEventListener('mouseleave', function () { + button.style.background = o.arrowBackground; + }); + } + + if (o.arrowColor) { + button.classList.remove('skin-color'); + } + if (o.arrowBackground) { + button.classList.remove('skin-color-bg'); + } + } + + if (o.sideNavigationButtons) { + this.$arrowWrapper = document.createElement('div'); + this.$arrowWrapper.className = 'flipbook-nav'; + this.bookLayer.appendChild(this.$arrowWrapper); + + this.btnNext = this.createSVGIcon('next'); + this.$arrowWrapper.appendChild(this.btnNext); + this.btnNext.style.height = o.arrowSize + 'px'; + this.btnNext.style.fontSize = o.arrowSize + 'px'; + this.btnNext.style.marginTop = String(-o.arrowSize / 2) + 'px'; + this.btnNext.style.marginRight = o.arrowMargin + 'px'; + this.btnNext.classList.add('flipbook-right-arrow'); + initButton(this.btnNext, this.nextPage.bind(this)); + + this.btnPrev = this.createSVGIcon('next', true); + this.$arrowWrapper.appendChild(this.btnPrev); + this.btnPrev.style.height = o.arrowSize + 'px'; + this.btnPrev.style.fontSize = o.arrowSize + 'px'; + this.btnPrev.style.marginTop = String(-o.arrowSize / 2) + 'px'; + this.btnPrev.style.marginLeft = o.arrowMargin + 'px'; + this.btnPrev.classList.add('flipbook-left-arrow'); + initButton(this.btnPrev, this.prevPage.bind(this)); + + if (o.btnFirst.enabled) { + this.btnFirst = this.createSVGIcon('last', true); + this.$arrowWrapper.appendChild(this.btnFirst); + this.btnFirst.style.height = o.arrowSize * 0.5 + 'px'; + this.btnFirst.style.fontSize = o.arrowSize * 0.5 + 'px'; + this.btnFirst.style.marginTop = String(o.arrowSize / 2 + o.arrowMargin + 2 * o.arrowPadding) + 'px'; + this.btnFirst.style.marginLeft = o.arrowMargin + 'px'; + this.btnFirst.classList.add('flipbook-first-arrow'); + initButton(this.btnFirst, this.firstPage.bind(this)); + } + + if (o.btnLast.enabled) { + this.btnLast = this.createSVGIcon('last'); + this.$arrowWrapper.appendChild(this.btnLast); + this.btnLast.style.height = o.arrowSize * 0.5 + 'px'; + this.btnLast.style.fontSize = o.arrowSize * 0.5 + 'px'; + this.btnLast.style.marginTop = String(o.arrowSize / 2 + o.arrowMargin + 2 * o.arrowPadding) + 'px'; + this.btnLast.style.marginRight = o.arrowMargin + 'px'; + this.btnLast.classList.add('flipbook-last-arrow'); + initButton(this.btnLast, this.lastPage.bind(this)); + } + + if (!o.menuNavigationButtons) { + if (o.btnOrder.indexOf('btnFirst') >= 0) { + o.btnOrder.splice(o.btnOrder.indexOf('btnFirst'), 1); + } + if (o.btnOrder.indexOf('btnPrev') >= 0) { + o.btnOrder.splice(o.btnOrder.indexOf('btnPrev'), 1); + } + if (o.btnOrder.indexOf('btnNext') >= 0) { + o.btnOrder.splice(o.btnOrder.indexOf('btnNext'), 1); + } + if (o.btnOrder.indexOf('btnLast') >= 0) { + o.btnOrder.splice(o.btnOrder.indexOf('btnLast'), 1); + } + } + } + + if (o.pdfMode && !o.btnDownloadPdf.url) { + o.btnDownloadPdf.url = o.pdfUrl; + } + + if (!o.pdfTextLayer && o.btnSearch) { + o.btnSearch.enabled = false; + } + + for (var i = 0; i < o.btnOrder.length; i++) { + var btnName = o.btnOrder[i]; + var btn = o[btnName]; + + if (o.isMobile && btn.hideOnMobile) { + btn.enabled = false; + } + + if (btn.enabled) { + btn.name = btnName; + if (btn.name === 'currentPage') { + this.createCurrentPage(); + } else if (btn.name === 'search') { + + this.$search = document.createElement('div'); + this.$search.className = 'flipbook-findbar'; + this.$search.innerHTML = + '' + + '' + + '' + + ''; + + this.menuTL.appendChild(this.$search); + + var searchInput = this.$search.querySelector('input'); + searchInput.addEventListener('change', function () { + self.toggleSearch(true); + self.thumbs.$findInput.value = this.value; + var event = new Event('keyup'); + self.thumbs.$findInput.dispatchEvent(event); + this.value = ''; + }); + + this.menuTL.style.flexDirection = 'column'; + this.menuTL.style.alignItems = 'flex-start'; + + } else { + this[btnName] = this.createButton(btn); + this[btnName].addEventListener('click', function (e) { + e.stopPropagation(); + e.preventDefault(); + self.onButtonClick(this, e); + }); + } + } + } + + if (o.buttons) { + o.buttons.forEach((newButton) => { + self.createButton(newButton).index(1); + }); + } + + if (this.btnSingle) this.toggleIcon(this.btnSingle, this.options.singlePageMode); + }, + + onButtonClick: function (btn, _) { + var name = btn.dataset.name; + var o = this.options; + + switch (name) { + case 'btnFirst': + this.firstPage(); + break; + case 'btnPrev': + this.prevPage(); + break; + case 'btnNext': + this.nextPage(); + break; + case 'btnLast': + this.lastPage(); + break; + case 'btnZoomIn': + this.zoomIn(); + break; + case 'btnZoomOut': + this.zoomOut(); + break; + case 'btnAutoplay': + if (!this.autoplay) { + this.nextPage(); + } + this.toggleAutoplay(); + break; + case 'btnSearch': + this.toggleSearch(); + break; + case 'btnBookmark': + this.toggleBookmark(); + break; + case 'btnRotateLeft': + if (this.Book.rotateLeft) { + this.Book.rotateLeft(); + } + break; + case 'btnRotateRight': + if (this.Book.rotateRight) { + this.Book.rotateRight(); + } + break; + case 'btnToc': + this.toggleToc(); + break; + case 'btnThumbs': + this.toggleThumbs(); + break; + case 'btnShare': + this.toggleShareMenu(); + break; + case 'btnTools': + this.toggleToolsMenu(); + break; + case 'btnNotes': + this.toggleNotesMenu(); + break; + case 'btnDownloadPages': + if (o.downloadMenu) { + this.toggleDownloadMenu(); + } else { + var link = document.createElement('a'); + link.href = o.btnDownloadPages.url; + link.download = o.btnDownloadPages.name; + link.dispatchEvent(new MouseEvent('click')); + } + + break; + + case 'btnPrint': + if (o.printMenu) { + this.togglePrintMenu(); + } else { + this.togglePrintWindow(); + } + + break; + + case 'btnDownloadPdf': + if (o.btnDownloadPdf.forceDownload) { + var path = o.btnDownloadPdf.url; + var save = document.createElement('a'); + save.href = path; + var filename = save.href.split('/').pop().split('#')[0].split('?')[0]; + save.download = filename; + document.body.appendChild(save); + save.click(); + document.body.removeChild(save); + } else { + var target = + o.btnDownloadPdf.openInNewWindow || typeof (o.btnDownloadPdf.openInNewWindow == 'undefined') + ? '_blank' + : '_self'; + window.open(o.btnDownloadPdf.url, target); + } + + this.sendGAEvent({ + event: 'flipbook_pdf_download', + book_name: this.options.name, + url: o.btnDownloadPdf.url || o.pdfUrl, + nonInteraction: true, + }); + + break; + + case 'btnSound': + this.toggleSound(); + break; + case 'btnExpand': + this.toggleExpand(); + break; + case 'btnSingle': + this.toggleSinglePage(); + break; + case 'btnClose': + this.lightbox.closeLightbox(); + break; + } + }, + + handleFsChange: function () { + if (!this.Book || !this.Book.enabled) { + return; + } + + var currentFullscreenElement = + document.fullscreenElement || + document.webkitFullscreenElement || + document.mozFullScreenElement || + document.msFullscreenElement; + if (currentFullscreenElement === this.fullscreenElement || this.isFullscreen) { + this.fullscreenActive = true; + + if (this.options.onfullscreenenter) { + this.options.onfullscreenenter.call(this); + } + document.body.classList.add('flipbook-fullscreen'); + } else { + this.fullscreenActive = false; + if (this.options.onfullscreenexit) { + this.options.onfullscreenexit.call(this); + } + document.body.classList.remove('flipbook-fullscreen'); + } + + this.toggleIcon(this.btnExpand, !this.fullscreenActive); + }, + + createLogo: function () { + const { options: o, wrapper } = this; + const { logoImg, logoCSS, logoAlignH, logoAlignV, logoUrl, logoUrlTarget, isMobile, logoHideOnMobile } = o; + + if (!logoImg || (isMobile && logoHideOnMobile)) return; + + const baseStyle = + `${logoCSS}` + + [ + 'position:absolute', + logoAlignH === 'right' ? 'right:0' : logoAlignH === 'left' ? 'left:0' : '', + logoAlignV === 'bottom' ? 'bottom:0' : logoAlignV === 'top' ? 'top:0' : '', + ] + .filter(Boolean) + .join(';') + + ';'; + + const makeLogo = ({ zIndex = '', opacity = '' } = {}) => { + const img = document.createElement('img'); + img.src = logoImg; + img.style.cssText = + baseStyle + (zIndex ? `z-index:${zIndex};` : '') + (opacity ? `opacity:${opacity};` : ''); + + if (logoUrl) { + img.style.cursor = 'pointer'; + img.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + window.open(logoUrl, logoUrlTarget || '_blank'); + }); + } + + return img; + }; + + const primary = makeLogo(); + wrapper.appendChild(primary); + }, + + setLoadingProgress: function (percent) { + if (this.disposed) { + return; + } + + if (this.$fillPreloader) { + this.setFillPreloaderProgress(percent); + } else { + if (percent > 0 && percent < 1) { + this.preloader.classList.remove('flipbook-hidden'); + } else { + this.preloader.classList.add('flipbook-hidden'); + } + } + }, + + setFillPreloaderProgress: function (percent) { + if (!this.$fillPreloader) { + return; + } + + if (percent > 0 && percent < 1) { + this.fillPreloaderProgress = this.fillPreloaderProgress || 0; + + if (percent < this.fillPreloaderProgress) { + return; + } else { + this.fillPreloaderProgress = percent; + } + var img = this.$fillPreloaderImg[0]; + img.style.clip = 'rect(0px,' + img.width * percent + 'px,' + img.height + 'px,0px)'; + this.$fillPreloader.show(); + } else { + this.$fillPreloader.hide(); + } + }, + + playFlipSound: function () { + if (this.options.sound && this.Book.enabled && typeof this.flipSound.play != 'undefined') { + this.flipSound.currentTime = 0; + + var self = this; + + setTimeout(function () { + self.flipSound.play().then( + function () {}, + function () {} + ); + }, 70); + } + }, + + playBgMusic: function () { + if (this.options.sound && this.backgroundMusic && this.backgroundMusic.play) { + var self = this; + this.backgroundMusic.play().then( + function () {}, + function (_) { + setTimeout(function () { + self.playBgMusic(); + }, 100); + } + ); + } + }, + + onMouseWheel: function (e) { + if ('wheelDeltaX' in e) { + wheelDeltaX = e.wheelDeltaX / 12; + wheelDeltaY = e.wheelDeltaY / 12; + } else if ('wheelDelta' in e) { + wheelDeltaX = wheelDeltaY = e.wheelDelta / 12; + } else if ('detail' in e) { + wheelDeltaX = wheelDeltaY = -e.detail * 3; + } else { + return; + } + if (wheelDeltaX > 0) { + this.zoomIn(e); + } else { + this.zoomOut(e); + } + }, + + zoomTo: function (val, time, e) { + this.zoom = val; + + var x; + var y; + + if (typeof e == 'undefined') { + x = this.wrapperW / 2; + y = this.wrapperH / 2; + } else { + if (e.touches && e.touches[0]) { + x = e.touches[0].pageX; + y = e.touches[0].pageY; + } else if (e.changedTouches && e.changedTouches[0]) { + x = e.changedTouches[0].pageX; + y = e.changedTouches[0].pageY; + } else { + x = e.pageX; + y = e.pageY; + } + + let wrapperRect = this.wrapper.getBoundingClientRect(); + x = x - wrapperRect.left - window.scrollX; + y = y - wrapperRect.top - window.scrollY; + } + + const zoomMin = this.getZoomMin(); + + if (this.zoom < zoomMin) { + this.zoom = zoomMin; + } + if (this.zoom > this.options.zoomMax) { + this.zoom = this.options.zoomMax; + } + + if (this.options.zoomMax2 && this.zoom > this.options.zoomMax2) { + this.zoom = this.options.zoomMax2; + } + + this.Book.zoomTo(this.zoom, time, x, y); + + this.onZoom(this.zoom); + }, + + zoomOut: function (e) { + var newZoom = this.zoom / this.options.zoomStep; + // if (newZoom < 1 && this.zoom > 1) { + // newZoom = 1; + // } + const zoomMin = this.getZoomMin(); + newZoom = newZoom < zoomMin ? zoomMin : newZoom; + + if (this.zoom == newZoom) { + return; + } + + this.zoom = newZoom; + + this.zoomTo(this.zoom, this.options.zoomTime, e); + }, + + zoomIn: function (e) { + var newZoom = this.zoom * this.options.zoomStep; + // if (newZoom > 1 && this.zoom < 1) { + // newZoom = 1; + // } + + if (newZoom > this.options.zoomMax) { + newZoom = this.options.zoomMax; + } + + if (this.zoom == newZoom) { + return; + } + + this.zoom = newZoom; + + this.zoomTo(this.zoom, this.options.zoomTime, e); + }, + + getZoomMin: function () { + return this.options.viewMode == 'scroll' ? this.options.zoomMin2 : this.options.zoomMin; + }, + + nextPage: function () { + if (!this.Book) { + return; + } + this.flippingPage = true; + if (this.nextEnabled) { + this.Book.nextPage(); + window.getSelection().removeAllRanges(); + } + }, + + prevPage: function () { + if (!this.Book) { + return; + } + this.flippingPage = true; + if (this.prevEnabled) { + this.Book.prevPage(); + window.getSelection().removeAllRanges(); + } + }, + + firstPage: function () { + this.goToPage(1); + }, + + lastPage: function () { + this.goToPage(this.options.pages.length); + }, + + goToPage: function (pageNumber, instant) { + if (!this.Book) { + return; + } + + if (!instant) { + this.flippingPage = true; + } + + if (!this.options.cover) { + pageNumber++; + } + + if (pageNumber < 1) { + pageNumber = 1; + } else if (pageNumber > this.options.numPages && !this.options.rightToLeft) { + pageNumber = this.options.numPages; + } + + this.Book.goToPage(pageNumber, instant); + window.getSelection().removeAllRanges(); + }, + + moveBook: function (direction) { + if (this.Book && this.Book.move) { + this.Book.move(direction); + } + }, + + onZoom: function (newZoom) { + this.zoom = newZoom; + const zoomMin = this.getZoomMin(); + this.enableButton(this.btnZoomIn, newZoom < this.options.zoomMax); + this.enableButton(this.btnZoomOut, newZoom > zoomMin); + this.enableSwipe(newZoom <= 1); + }, + + enableSwipe: function (val) { + this.swipeEnabled = val; + }, + + createCurrentPage: function () { + var self = this; + var o = this.options; + var menu; + var cssClass = 'flipbook-currentPageHolder '; + + if (o.currentPage.vAlign == 'top') { + if (o.currentPage.hAlign == 'left') { + menu = this.menuTL; + } else if (o.currentPage.hAlign == 'right') { + menu = this.menuTR; + } else { + menu = this.menuTC; + } + } else { + if (o.currentPage.hAlign == 'left') { + menu = this.menuBL; + } else if (o.currentPage.hAlign == 'right') { + menu = this.menuBR; + } else { + menu = this.menuBC; + } + } + + var floating = + (o.currentPage.vAlign == 'top' && o.menu2Transparent) || + (o.currentPage.vAlign != 'top' && o.menuTransparent); + var bgColor = floating ? o.floatingBtnBackground : ''; + var color = floating ? o.floatingBtnColor : o.btnColor; + var textShadiw = floating ? o.floatingBtnTextShadow : ''; + var radius = floating ? o.floatingBtnRadius : o.btnRadius; + var currentPageHolder = document.createElement('div'); + menu.appendChild(currentPageHolder); + + currentPageHolder.style.margin = o.currentPage.marginV + 'px ' + o.currentPage.marginH + 'px'; + currentPageHolder.style.height = o.btnSize + 'px'; + currentPageHolder.style.padding = o.btnPaddingV + 'px'; + + if (!floating) { + cssClass += ' skin-color'; + } + currentPageHolder.className = cssClass; + currentPageHolder.style.color = color; + currentPageHolder.style.background = bgColor; + currentPageHolder.style.textShadow = textShadiw; + currentPageHolder.style.borderRadius = radius + 'px'; + + if (o.currentPage.order) { + currentPageHolder.style.order = o.currentPage.order; + } + + this.currentPageHolder = currentPageHolder; + + var form = document.createElement('form'); + currentPageHolder.appendChild(form); + + form.addEventListener('submit', function (e) { + e.preventDefault(); + var value = parseInt(self.currentPageInput.value, 10); + if (self.options.rightToLeft) { + value = o.pages.length - value + 1; + value -= self.options.pageNumberOffset; + } else { + value = Math.min(value, o.pages.length); + value += self.options.pageNumberOffset; + } + self.goToPage(value); + return false; + }); + + this.currentPageInput = document.createElement('input'); + this.currentPageInput.type = 'text'; + this.currentPageInput.className = 'flipbook-currentPageInput'; + this.currentPageInput.style.margin = o.currentPage.marginV + 'px ' + o.currentPage.marginH + 'px'; + this.currentPageInput.style.color = color; + + this.currentPageInput.addEventListener('focus', function () { + self.currentPageInput.value = ''; + }); + + this.currentPageInput.addEventListener('blur', function () { + self.currentPageInput.value = self.currentPageString; + }); + + form.appendChild(this.currentPageInput); + + var digits = String(o.numPages).length; + this.currentPageInput.classList.add('digits-' + digits); + this.currentPageInput.setAttribute('maxlength', digits); + + this.currentPage = document.createElement('div'); + this.currentPage.className = 'flipbook-currentPageNumber'; + currentPageHolder.appendChild(this.currentPage); + + if (!floating) { + this.currentPageInput.classList.add('skin-color'); + } + }, + + createMenuHeader: function (el, title, _) { + var header = document.createElement('div'); + header.className = 'flipbook-menu-header skin-clor flipbook-font'; + el.appendChild(header); + + var titleSpan = document.createElement('span'); + titleSpan.textContent = title; + titleSpan.className = 'flipbook-menu-title skin-color'; + header.appendChild(titleSpan); + + var btnClose = document.createElement('span'); + btnClose.className = 'flipbook-btn-close skin-color skin-color-bg'; + header.appendChild(btnClose); + btnClose.addEventListener('click', (e) => { + e.stopPropagation(); + e.preventDefault(); + this.closeMenus(); + }); + + var closeIcon = this.createSVGIcon('close'); + btnClose.appendChild(closeIcon); + }, + + createToc: function () { + var tocArray = this.options.tableOfContent; + + this.tocHolder = document.createElement('div'); + this.tocHolder.className = 'flipbook-tocHolder flipbook-side-menu skin-color-bg'; + this.wrapper.appendChild(this.tocHolder); + this.tocHolder.style[this.options.sideMenuPosition] = '0'; + this.tocHolder.classList.add('flipbook-hidden'); + + this.createMenuHeader(this.tocHolder, this.strings.tableOfContent, this.toggleToc); + + this.toc = document.createElement('div'); + this.toc.className = 'flipbook-toc'; + this.tocHolder.appendChild(this.toc); + + var arr = this.options.pages; + + if (!tocArray || !tocArray.length) { + tocArray = []; + for (var i = 0; i < arr.length; i++) { + if (arr[i].title) { + tocArray.push({ + title: arr[i].title, + page: String(i + 1), + pageNumberDisplay: arr[i].name, + }); + } + } + } + + for (var i = 0; i < tocArray.length; i++) { + if (arr[i] && arr[i].name && tocArray[i].page) { + tocArray[i].pageNumberDisplay = arr[tocArray[i].page - 1].name; + } + } + + var iconExpand = this.createSVGIcon('next'); + + this.tocScroller = this.buildTOC(tocArray); + this.tocScroller.className = 'flipbook-toc-scroller'; + this.toc.appendChild(this.tocScroller); + + this.initColors(); + this.tocCreated = true; + this.toggleToc(); + }, + + buildTOC: function (items) { + const self = this; + const ul = document.createElement('ul'); + const expandSvg = this.createSVGIcon('next'); + + items.forEach((item) => { + const li = document.createElement('li'); + + const itemDiv = document.createElement('div'); + itemDiv.classList.add('toc-item', 'skin-color'); + + const titleContainer = document.createElement('div'); + titleContainer.classList.add('title-container'); + + if (item.items && item.items.length > 0) { + const expandIcon = document.createElement('span'); + expandIcon.classList.add('expand-icon'); + + expandIcon.innerHTML = expandSvg.outerHTML; + + expandIcon.addEventListener('click', function (event) { + event.stopPropagation(); + const subUl = li.querySelector('ul'); + if (subUl.style.display === 'none') { + subUl.style.display = 'block'; + expandIcon.classList.add('expanded'); + } else { + subUl.style.display = 'none'; + expandIcon.classList.remove('expanded'); + } + }); + + titleContainer.appendChild(expandIcon); + } else { + const spacer = document.createElement('span'); + spacer.classList.add('spacer'); + spacer.innerHTML = ' '; + titleContainer.appendChild(spacer); + } + + const titleSpan = document.createElement('span'); + titleSpan.textContent = item.title; + titleSpan.classList.add('title'); + titleContainer.appendChild(titleSpan); + + itemDiv.appendChild(titleContainer); + + const pageSpan = document.createElement('span'); + pageSpan.textContent = item.pageNumberDisplay || item.page; + pageSpan.classList.add('page-number'); + itemDiv.appendChild(pageSpan); + + itemDiv.addEventListener('click', function (e) { + e.stopPropagation(); + e.preventDefault(); + + if (self.options.tableOfContentCloseOnClick) { + self.toggleToc(false); + } + + if (!item.page && item.dest) { + if (typeof item.dest === 'string') { + self.pdfService.pdfDocument.getDestination(item.dest).then(function (destArray) { + self.goToDest(destArray); + }); + } else { + self.goToDest(item.dest); + } + } else { + var targetPage = Number(item.page); + + targetPage = self.options.rightToLeft ? self.options.pages.length - targetPage + 1 : targetPage; + + setTimeout(function () { + self.goToPage(targetPage); + }, 200); + } + }); + + li.appendChild(itemDiv); + + if (item.items && item.items.length > 0) { + const subUl = this.buildTOC(item.items); + subUl.style.display = 'none'; + li.appendChild(subUl); + } + + ul.appendChild(li); + }); + + return ul; + }, + + goToDest: function (destArray) { + + var self = this; + self.pdfService.pdfDocument.getPageIndex(destArray[0]).then(function (index) { + var targetPage = index + 1; + + if (self.options.doublePage) { + targetPage = 2 * targetPage - 1; + } + + targetPage = self.options.rightToLeft ? self.options.pages.length - targetPage + 1 : targetPage; + + setTimeout(function () { + self.goToPage(targetPage); + }, 200); + }); + + }, + + enablePrev: function (val) { + if (this.prevEnabled == val || !this.btnPrev) return; + this.enableButton(this.btnPrev, val); + this.enableButton(this.btnFirst, val); + this.prevEnabled = val; + this.Book.enablePrev(val); + }, + + enableNext: function (val) { + if (this.nextEnabled == val || !this.btnNext) return; + this.enableButton(this.btnNext, val); + this.enableButton(this.btnLast, val); + this.nextEnabled = val; + this.Book.enableNext(val); + }, + + enableButton: function (button, enabled) { + if (typeof button === 'undefined') { + return; + } + + if (enabled) { + button.classList.remove('disabled'); + } else { + button.classList.add('disabled'); + } + + button.enabled = enabled; + }, + + resize: function (force) { + var o = this.options; + + this.updateWrapperDimensions(); + + if (!this.Book || !this.Book.enabled) { + return; + } + + if (this.menuShowing) { + this.bookLayer.style.bottom = + !o.menuOverBook && this.menuBottom ? this.menuBottom.offsetHeight + 'px' : '0px'; + this.bookLayer.style.top = !o.menu2OverBook && this.menuTop ? this.menuTop.offsetHeight + 'px' : '0px'; + } + + if (this.tocShowing || this.thumbsShowing || this.searchShowing || this.bookmarkShowing) { + var sidebarWdith = this.tocShowing + ? this.tocHolder.getBoundingClientRect().width + : this.thumbsShowing && this.options.thumbsStyle === 'overlay' + ? 0 + : this.thumbs.thumbHolder.getBoundingClientRect().width; + + this.bookLayer.style[this.options.sideMenuPosition] = `${sidebarWdith}px`; + let sideMenuCss = { bottom: '0px', top: '0px' }; + if (!o.sideMenuOverMenu) { + sideMenuCss.bottom = this.menuBottom.offsetHeight + 'px'; + } + if (!o.sideMenuOverMenu2) { + sideMenuCss.top = this.menuTop.offsetHeight + 'px'; + } + + var sideMenus = this.wrapper.querySelectorAll('.flipbook-side-menu'); + + sideMenus.forEach(function (element) { + for (var property in sideMenuCss) { + if (sideMenuCss.hasOwnProperty(property)) { + element.style[property] = sideMenuCss[property]; + } + } + }); + } else { + this.bookLayer.style[this.options.sideMenuPosition] = '0px'; + } + + this.adjustZoomLimits(); + + this.Book.onResize(force); + if (o.zoomReset) { + this.Book.zoomTo(o.zoomMin); + } + }, + + updateWrapperDimensions: function () { + let rect = this.bookLayer.getBoundingClientRect(); + this.wrapperW = rect.width; + this.wrapperH = rect.height; + }, + + adjustZoomLimits: function () { + var o = this.options; + var wrapperRatio = this.wrapperW / this.wrapperH; + var pageRatio = this.pageW / this.pageH; + var bookRatio = 2 * pageRatio; + + if (o.viewMode == 'scroll') { + o.zoomMax = (2 * ((o.zoomSize * o.pageWidth) / o.pageHeight)) / this.wrapperW; + } else if ( + o.responsiveView && + this.wrapperW <= o.responsiveViewTreshold && + wrapperRatio < bookRatio && + wrapperRatio < o.responsiveViewRatio + ) { + o.zoomMax = (o.zoomSize / this.wrapperH) * (wrapperRatio > pageRatio ? 1 : pageRatio / wrapperRatio); + } else { + o.zoomMax = (o.zoomSize / this.wrapperH) * (wrapperRatio > bookRatio ? 1 : bookRatio / wrapperRatio); + } + + o.zoomMax = Math.max(o.zoomMax, o.zoomMin); + }, + + pdfResize: function () { + var self = this; + self.Book.onZoom(); + }, + + createThumbs: function () { + this.thumbs = new FLIPBOOK.Thumbnails(this); + }, + + toggleThumbs: function (value) { + if (!this.thumbs) { + this.createThumbs(); + } + + if (typeof value != 'undefined') { + this.thumbsShowing = !value; + } + + if (!this.thumbsShowing) { + this.closeMenus(); + this.thumbs.show(); + this.thumbsShowing = true; + } else { + this.thumbs.hide(); + this.thumbsShowing = false; + } + + this.resize(); + }, + + toggleToc: function (value) { + if (!this.tocCreated) { + this.createToc(); + return; + } + + if (!this.tocShowing || value) { + this.closeMenus(); + this.tocShowing = true; + this.tocHolder.classList.remove('flipbook-hidden'); + } else { + this.tocHolder.classList.add('flipbook-hidden'); + this.tocShowing = false; + } + + this.resize(); + }, + + toggleSearch: function (value) { + + if (!this.thumbs) { + this.createThumbs(); + } + + if (typeof value != 'undefined') { + this.searchShowing = !value; + } + + if (!this.searchShowing) { + this.closeMenus(); + this.thumbs.show(); + this.thumbs.showSearch(); + this.searchShowing = true; + } else { + this.thumbs.hide(); + this.searchShowing = false; + this.unmark(); + } + + this.resize(); + + }, + + toggleBookmark: function (value) { + + if (!this.thumbs) { + this.createThumbs(); + } + + if (typeof value != 'undefined') { + this.bookmarkShowing = !value; + } + + if (!this.bookmarkShowing) { + this.closeMenus(); + this.thumbs.show(); + this.thumbs.showBookmarks(); + this.bookmarkShowing = true; + } else { + this.thumbs.hide(); + this.bookmarkShowing = false; + } + + this.resize(); + + }, + + closeMenus: function () { + if (this.thumbsShowing) { + this.toggleThumbs(); + } + if (this.tocShowing) { + this.toggleToc(); + } + if (this.searchShowing) { + this.toggleSearch(); + } + if (this.bookmarkShowing) { + this.toggleBookmark(); + } + + if (this.printMenuShowing) { + this.togglePrintMenu(); + } + if (this.dlMenuShowing) { + this.toggleDownloadMenu(); + } + if (this.shareMenuShowing) { + this.toggleShareMenu(); + } + if (this.toolsMenuShowing) { + this.toggleToolsMenu(); + } + if (this.notesMenuShowing) { + this.toggleNotesMenu(); + } + if (this.passwordMenuShowing) { + this.togglePasswordMenu(); + } + }, + + toggleToolsMenu: function () { + var self = this; + + if (!this.toolsMenu.parentNode) { + this.btnTools.appendChild(this.toolsMenu); + this.initColors(); + this.closeMenus(); + this.toolsMenu.classList.remove('flipbook-hidden'); + this.btnTools.classList.add('flipbook-btn-active'); + this.btnTools.classList.remove('flipbook-has-tooltip'); + this.toolsMenuShowing = true; + + this.toolsMenu.addEventListener('click', function (event) { + event.stopPropagation(); + }); + + document.addEventListener('click', function (event) { + if (self.toolsMenuShowing) { + self.toggleToolsMenu(); + } + if (self.shareMenuShowing) { + self.toggleShareMenu(); + } + }); + } else if (!this.toolsMenuShowing) { + this.closeMenus(); + this.toolsMenu.classList.remove('flipbook-hidden'); + this.toolsMenuShowing = true; + this.btnTools.classList.add('flipbook-btn-active'); + this.btnTools.classList.remove('flipbook-has-tooltip'); + } else { + this.toolsMenu.classList.add('flipbook-hidden'); + this.toolsMenuShowing = false; + this.btnTools.classList.remove('flipbook-btn-active'); + this.btnTools.classList.add('flipbook-has-tooltip'); + } + }, + + togglePrintMenu: function () { + var self = this; + + if (!this.printMenu) { + this.printMenu = document.createElement('div'); + this.printMenu.className = 'flipbook-sub-menu flipbook-font'; + this.wrapper.appendChild(this.printMenu); + + var center = document.createElement('div'); + center.className = 'flipbook-sub-menu-center'; + this.printMenu.appendChild(center); + + var content = document.createElement('div'); + content.className = 'flipbook-sub-menu-content skin-color-bg'; + center.appendChild(content); + + this.createMenuHeader(content, this.strings.print, this.togglePrintMenu.bind(this)); + + var currentPageButton = document.createElement('a'); + currentPageButton.innerHTML = + '' + this.strings.printCurrentPage + ''; + content.appendChild(currentPageButton); + currentPageButton.addEventListener('click', function () { + self.printPage(self.cPage[0], this); + }); + + var leftPageButton = document.createElement('a'); + leftPageButton.innerHTML = + '' + this.strings.printLeftPage + ''; + content.appendChild(leftPageButton); + leftPageButton.addEventListener('click', function () { + self.printPage(self.cPage[0], this); + }); + + var rightPageButton = document.createElement('a'); + rightPageButton.innerHTML = + '' + this.strings.printRightPage + ''; + content.appendChild(rightPageButton); + rightPageButton.addEventListener('click', function () { + self.printPage(self.cPage[1], this); + }); + + var allPagesButton = document.createElement('a'); + allPagesButton.innerHTML = '' + this.strings.printAllPages + ''; + content.appendChild(allPagesButton); + allPagesButton.addEventListener('click', function () { + self.togglePrintWindow(); + }); + + this.closeMenus(); + this.printMenuShowing = true; + this.initColors(); + this.updateCurrentPage(); + } else if (!this.printMenuShowing) { + this.closeMenus(); + this.printMenu.style.display = 'block'; + this.printMenuShowing = true; + this.updateCurrentPage(); + } else { + this.printMenu.style.display = 'none'; + this.printMenuShowing = false; + } + }, + + toggleDownloadMenu: function () { + + var self = this; + + if (!this.dlMenu) { + this.dlMenu = document.createElement('div'); + this.dlMenu.className = 'flipbook-sub-menu flipbook-font'; + this.wrapper.appendChild(this.dlMenu); + + var center = document.createElement('div'); + center.className = 'flipbook-sub-menu-center'; + this.dlMenu.appendChild(center); + + var content = document.createElement('div'); + content.className = 'flipbook-sub-menu-content skin-color-bg'; + center.appendChild(content); + + this.createMenuHeader(content, this.strings.download, this.toggleDownloadMenu.bind(this)); + + var currentPageButton = document.createElement('a'); + currentPageButton.innerHTML = + '' + this.strings.downloadCurrentPage + ''; + content.appendChild(currentPageButton); + currentPageButton.addEventListener('click', function () { + self.downloadPage(self.cPage[0], this); + }); + + var leftPageButton = document.createElement('a'); + leftPageButton.innerHTML = + '' + this.strings.downloadLeftPage + ''; + content.appendChild(leftPageButton); + leftPageButton.addEventListener('click', function () { + self.downloadPage(self.cPage[0], this); + }); + + var rightPageButton = document.createElement('a'); + rightPageButton.innerHTML = + '' + this.strings.downloadRightPage + ''; + content.appendChild(rightPageButton); + rightPageButton.addEventListener('click', function () { + self.downloadPage(self.cPage[1], this); + }); + + var allPagesButton = document.createElement('a'); + allPagesButton.innerHTML = + '' + this.strings.downloadAllPages + ''; + content.appendChild(allPagesButton); + allPagesButton.addEventListener('click', function () { + var link = document.createElement('a'); + link.href = self.options.btnDownloadPages.url; + var filename = link.href.split('/').pop().split('#')[0].split('?')[0]; + link.download = filename; + link.dispatchEvent(new MouseEvent('click')); + }); + + this.closeMenus(); + this.dlMenuShowing = true; + this.initColors(); + this.updateCurrentPage(); + } else if (!this.dlMenuShowing) { + this.closeMenus(); + this.dlMenu.style.display = 'block'; + this.dlMenuShowing = true; + this.updateCurrentPage(); + } else { + this.dlMenu.style.display = 'none'; + this.dlMenuShowing = false; + } + + }, + + toggleShareMenu: function () { + var self = this; + if (!this.shareMenu.parentNode) { + this.btnShare.appendChild(this.shareMenu); + this.initColors(); + this.closeMenus(); + this.shareMenu.classList.remove('flipbook-hidden'); + this.shareMenu.classList.add('flipbook-btn-active'); + this.shareMenu.classList.remove('flipbook-has-tooltip'); + this.shareMenuShowing = true; + + this.shareMenu.addEventListener('click', function (event) { + event.stopPropagation(); + }); + + document.addEventListener('click', function (event) { + if (self.toolsMenuShowing) { + self.toggleToolsMenu(); + } + if (self.shareMenuShowing) { + self.toggleShareMenu(); + } + }); + + var o = this.options; + var networks = [ + 'facebook', + 'twitter', + 'pinterest', + 'linkedin', + 'whatsapp', + 'digg', + 'reddit', + 'email', + 'copyLink', + ]; + + var left = window.screen.width / 2 - 300; + var top = window.screen.height / 2 - 300; + + networks.forEach(function (network) { + if (o[network].enabled) { + var btn = document.createElement('span'); + btn.className = 'flipbook-menu-btn-wrapper flipbook-has-tooltip'; + btn.setAttribute('data-network', network); + btn.setAttribute('data-tooltip', o[network].title || o.strings[network]); + + let svg = self.createSVGIcon(network); + btn.appendChild(svg); + + self.shareMenu.appendChild(btn); + + btn.addEventListener('click', function (e) { + e.preventDefault(); + e.stopPropagation(); + + var network = this.dataset.network; + + if (network == 'copyLink') { + const currentUrl = window.location.href; + + function fallbackCopyTextToClipboard(text) { + const textArea = document.createElement('textarea'); + textArea.value = text; + textArea.style.position = 'fixed'; // Avoid scrolling to bottom of page + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + try { + document.execCommand('copy'); + btn.setAttribute('data-tooltip', o.strings.copied); + setTimeout(() => { + btn.setAttribute('data-tooltip', o.strings.copyLink); + }, 2000); + } catch (err) { + console.error('Fallback: Unable to copy text', err); + } + document.body.removeChild(textArea); + } + + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard + .writeText(currentUrl) + .then(() => { + btn.setAttribute('data-tooltip', o.strings.copied); + setTimeout(() => { + btn.setAttribute('data-tooltip', o.strings.copyLink); + }, 2000); + }) + .catch((err) => { + console.error('Failed to copy the link: ', err); + }); + } else { + fallbackCopyTextToClipboard(currentUrl); + } + } else { + var text = encodeURIComponent( + o.shareTitle || o[network].description || 'Check out this flipbook' + ); + var url = encodeURIComponent(o.shareUrl || window.location.href); + var image = encodeURIComponent(o.shareImage || ''); + var shareUrl; + + switch (network) { + case 'facebook': + shareUrl = 'https://www.facebook.com/sharer.php?u=' + url + '&t=' + text; + break; + case 'twitter': + shareUrl = 'https://twitter.com/intent/tweet?text=' + text + '&url=' + url; + break; + + case 'linkedin': + shareUrl = + 'https://www.linkedin.com/shareArticle?mini=true&url=' + url + '&title=' + text; + break; + case 'pinterest': + shareUrl = + 'https://www.pinterest.com/pin/create/button/?url=' + + url + + '&media=' + + image + + '&description=' + + text; + break; + case 'email': + shareUrl = 'mailto:?subject=' + text + '&body=' + url; + break; + case 'digg': + shareUrl = 'http://digg.com/submit?url=' + url + '&title=' + text; + break; + case 'reddit': + shareUrl = 'http://reddit.com/submit?url=' + url + '&title=' + text; + break; + case 'whatsapp': + shareUrl = o.isMobile + ? 'whatsapp://send?text=' + text + '%20' + url + : 'https://wa.me?text=' + text + '%20' + url; + break; + + } + + window.open( + shareUrl, + 'Share', + 'toolbar=no, location=no, directories=no, status=no, ' + + 'menubar=no, scrollbars=no, resizable=no, copyhistory=no, ' + + 'width=600, height=600, top=' + + top + + ', left=' + + left + ); + } + }); + } + }); + } else if (!this.shareMenuShowing) { + this.closeMenus(); + this.shareMenu.classList.remove('flipbook-hidden'); + this.shareMenuShowing = true; + this.btnShare.classList.add('flipbook-btn-active'); + this.btnShare.classList.remove('flipbook-has-tooltip'); + } else { + this.shareMenu.classList.add('flipbook-hidden'); + this.shareMenuShowing = false; + this.btnShare.classList.remove('flipbook-btn-active'); + this.btnShare.classList.add('flipbook-has-tooltip'); + } + }, + + toggleNotesMenu: function () { + + if (!this.notesMenu) { + this.notesMenu = jQuery(document.createElement('div')) + .appendTo(this.wrapper) + .addClass('flipbook-sub-menu flipbook-font'); + var center = jQuery('').appendTo(this.notesMenu); + var content = jQuery('').appendTo(center); + this.createMenuHeader(content, this.options.strings.notes, this.toggleNotesMenu); + this.closeMenus(); + this.notesMenuShowing = true; + this.initColors(); + + const self = this; + this.options.noteTypes.forEach(function (type) { + const row = document.createElement('div'); + row.innerHTML = + '' + + type.title + + '' + + ''; + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.dataset.id = type.id; + checkbox.checked = type.enabled; + checkbox.onchange = function () { + type.enabled = this.checked; + self.updateNoteSettings(type); + }; + row.appendChild(checkbox); + content[0].appendChild(row); + }); + } else if (!this.notesMenuShowing) { + this.notesMenu.show(); + + this.closeMenus(); + this.notesMenuShowing = true; + } else { + this.notesMenu.hide(); + this.notesMenuShowing = false; + } + + }, + + updateNoteSettings: function (noteType) { + this.options.noteTypes.forEach(function (type) { + if (type.id == noteType.id) { + type.enabled = noteType.enabled; + } + }); + this.noteService.updateNoteVisibility(); + }, + + bookmarkPage: function (index) { + + var arr = this.getBookmarkedPages(); + if (arr.indexOf(String(index)) < 0) { + arr.push(index); + } + this.setBookmarkedPages(arr); + + this.thumbs.showBookmarkedThumbs(); + + if (!this.bookmarkShowing) { + this.toggleBookmark(); + } + + }, + + removeBookmark: function (index) { + + var arr = this.getBookmarkedPages(); + if (arr.indexOf(String(index)) > -1) { + arr.splice(arr.indexOf(String(index)), 1); + } + this.setBookmarkedPages(arr); + + this.thumbs.showBookmarkedThumbs(); + + if (!this.bookmarkShowing) { + this.toggleBookmark(); + } + + }, + + isBookmarked: function (index) { + var arr = this.getBookmarkedPages(); + return arr.indexOf(String(index)) > 0; + }, + + getBookmarkedPages: function () { + var str = localStorage.getItem(this.options.name + '_flipbook_bookmarks'); + if (str) { + return str.split(';'); + } else { + return []; + } + }, + + setBookmarkedPages: function (arr) { + localStorage.setItem(this.options.name + '_flipbook_bookmarks', arr.join(';')); + }, + + printPage: function (index, _) { + var url; + var page = this.options.pages[index]; + var size = this.options.pageTextureSize; + var self = this; + + if (page) { + if (page.print) { + url = page.print; + } else if (page.images && page.images[size]) { + const c = document.createElement('canvas'); + const ctx = c.getContext('2d'); + const image = page.images[size]; + c.width = image.width; + c.height = image.height; + + ctx.drawImage(image, 0, 0, image.width, image.height); + url = c.toDataURL(); + + c.width = c.height = 1; + ctx.clearRect(0, 0, 1, 1); + } else if (page.src) { + url = page.src; + } + } + + if (url) { + this.togglePrintWindow(url); + } else { + const pageToLoad = this.options.cover ? index : index + 1; + this.loadPage(pageToLoad, size, function () { + self.printPage(index); + }); + } + }, + + downloadPage: function (index) { + + var url; + var page = this.options.pages[index]; + var size = this.options.pageTextureSize; + + if (page && page.download) { + url = page.download; + } else if (page && page.src) { + url = page.src; + } else if (page && page.images && page.images[size]) { + const c = document.createElement('canvas'); + const ctx = c.getContext('2d'); + const image = page.images[size]; + c.width = image.width; + c.height = image.height; + + ctx.drawImage(image, 0, 0, image.width, image.height); + url = c.toDataURL(); + + c.width = c.height = 1; + ctx.clearRect(0, 0, 1, 1); + } + + if (url) { + var link = document.createElement('a'); + link.href = url; + link.download = 'page' + String(index + 1) + '.jpg'; + + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } else { + var self = this; + const pageToLoad = this.options.cover ? index : index + 1; + this.loadPage(pageToLoad, this.options.pageTextureSize, function () { + self.downloadPage(index); + }); + } + + }, + + printFile: function (url) { + var printIframe = document.createElement('iframe'); + printIframe.classList.add('flipbook-hidden'); + printIframe.src = url; + document.body.appendChild(printIframe); + printIframe.contentWindow.onload = function () { + var self = this; + setTimeout(function () { + self.print(); + }, 100); + }; + }, + + togglePrintWindow: function (url) { + var self = this; + var printContent = ''; + + if (url) { + printContent = url; + } else if (self.options.printPdfUrl) { + self.printFile(self.options.printPdfUrl); + return; + } else if (self.options.pdfUrl) { + self.printFile(self.options.pdfUrl); + return; + } + + function printme() { + var link = 'about:blank'; + var pw = window.open(link, '_new'); + pw.document.open(); + if (url) { + printContent = '\n'; + } else { + for (var i = 0; i < self.options.pages.length; i++) { + if (self.options.pages[i].src) { + printContent += '\n'; + } + } + } + + var printHtml = printWindowHtml(printContent); + pw.document.write(printHtml); + pw.document.close(); + } + + function printWindowHtml(printContent) { + return ( + '\n' + + '\n' + + 'Temporary Printing Window\n' + + '