/* * 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' + '