One Hat Cyber Team
  • Dir : ~/www/wwwroot/ef.electronharmony.com/1/T10/src/js/
  • Edit File: flipbook.js
    ' + ''; this.notePopup.onmouseup = function (e) { e.stopPropagation(); }; this.noteDelete = this.notePopup.getElementsByClassName('note-delete-button')[0]; this.noteDelete.onclick = function () { self.deleteNote(); }; this.noteInput = this.notePopup.querySelectorAll('textarea')[0]; this.noteInput.onchange = function () { const noteId = this.dataset.note; const noteText = this.value; self.getNoteById(noteId).text = noteText; self.main.trigger('r3d-update-note', { note: self.getNoteById(noteId), }); }; this.updateNoteVisibility(); } initPageNotes(page) { const self = this; this.notes.forEach(function (note) { if (note.page == page.index + 1) { self.addPageNote(note, page); } }); this.addPageNoteListeners(page); } getNodeColor(note) { let result = 'green'; this.main.options.noteTypes.forEach(function (type) { if (type.id == note.type) { result = type.color; } }); return result; } updateNoteVisibility() { let root = document.documentElement; this.main.options.noteTypes.forEach(function (type) { root.style.setProperty(`--note-${type.id}-opacity`, type.enabled ? '1' : '0'); root.style.setProperty(`--note-${type.id}-pointer-events`, type.enabled ? 'auto' : 'none'); }); } addPageNote(note) { const pageNumber = note.page; const page = this.main.options.pages[pageNumber - 1]; const color = this.getNodeColor(note) || 'yellow'; if (note.selectedText && page.htmlContentInitialized) { if (!note.id) { note.id = Date.now() + Math.floor(Math.random() * 1000); } const $htmlContent = jQuery(page.htmlContent); const $textLayer = $htmlContent.find('.textLayer'); const uniqueClass = `flipbook-page-note note-id-${note.id} note-page-${pageNumber} note-type-${note.type} mark-${color} flipbook-note-${note.id}`; $textLayer.mark(note.selectedText, { acrossElements: true, separateWordSearch: false, className: 'mark-note ' + uniqueClass, }); const self = this; $textLayer.find(`.note-id-${note.id}`).each(function (index, el) { el.dataset.note = note.id; el.onclick = function () { self.showNote(this, page, this.dataset.note); self.hideButton(); }; el.style.opacity = 'var(--note-' + note.type + '-opacity)'; el.style.pointerEvents = 'var(--note-' + note.type + '-pointer-events)'; }); } } showButton() { this.noteButton.classList.remove('flipbook-hidden'); } hideButton() { this.noteButton.classList.add('flipbook-hidden'); } showNote(target, page, id) { const pageRect = page.htmlContent.getBoundingClientRect(); const targetRect = target.getBoundingClientRect(); const note = this.getNoteById(id); const $htmlContent = jQuery(page.htmlContent); $htmlContent[0].appendChild(this.notePopup); const main = this.main; const scale = (main.Book.sc * main.wrapperH) / 1000; const noteTop = (targetRect.y / main.zoom - pageRect.y / main.zoom) / scale; if (noteTop < 150) { this.notePopup.style.top = noteTop + 40 + 'px'; } else { this.notePopup.style.top = noteTop - 140 + 'px'; } this.notePopup.style.left = (targetRect.x / main.zoom + (0.5 * targetRect.width) / main.zoom - pageRect.x / main.zoom) / scale + 'px'; this.noteInput.value = note.text || ''; this.noteInput.dataset.note = note.id; this.activeNote = note; if (note.readonly) { this.disableNoteEdit(); } else { this.enableNoteEdit(); } } enableNoteEdit() { this.noteDelete.classList.remove('flipbook-hidden'); this.noteInput.readOnly = false; } disableNoteEdit() { this.noteDelete.classList.add('flipbook-hidden'); this.noteInput.readOnly = true; } hideNote() { if (this.notePopup.parentNode) { this.notePopup.parentNode.removeChild(this.notePopup); } this.activeNote = null; } createNote() { this.textSelectionRect.appendChild(this.notePopup); this.notePopup.style.left = '50%'; if (this.textSelectionRect.offsetTop < 150) { this.notePopup.style.top = '40px'; } else { this.notePopup.style.top = '-140px'; } this.noteInput.value = ''; this.noteInput.focus(); const note = { selectedText: this.selectedTextString, page: this.selectedTextPageNumber, type: 1, }; this.notes.push(note); this.addPageNote(note); this.noteInput.dataset.note = note.id; this.addPageNoteListeners(this.main.options.pages[note.page - 1]); this.activeNote = note; this.enableNoteEdit(); this.main.trigger('r3d-update-note', { note: note }); } deleteNote() { const page = this.main.options.pages[this.activeNote.page - 1]; const $htmlContent = jQuery(page.htmlContent); const $textLayer = $htmlContent.find('.textLayer'); $textLayer.unmark({ className: `flipbook-note-${this.activeNote.id}`, }); const index = this.notes.indexOf(this.activeNote); if (index > -1) { this.notes.splice(index, 1); } this.hideNote(); this.main.trigger('r3d-delete-note', { note: this.activeNote, }); } getNoteById(id) { let toReturn = null; this.notes.forEach(function (note) { if (Number(note.id) == Number(id)) { toReturn = note; } }); return toReturn; } removeTextRect() { if (this.textSelectionRect.parentNode) { this.textSelectionRect.parentNode.removeChild(this.textSelectionRect); } } addPageNoteListeners(page) { const self = this; if (!page.textLayerDiv || page.notesInitialized) { return; } page.textLayerDiv.addEventListener('mouseup', function (e) { if (e.target.classList.contains('add-note-btn')) { return; } self.hideNote(); self.showButton(); self.selectedText = window.getSelection(); if (self.selectedText.toString()) { self.selectedTextString = self.selectedText.toString(); self.selectedTextPageNumber = Number(this.dataset.pageNumber); self.selectedTextRange = self.selectedText.getRangeAt(0); const rect = self.selectedTextRange.getBoundingClientRect(); const pageRect = this.getBoundingClientRect(); const main = self.main; let scale = (main.Book.sc * main.wrapperH) / 1000; self.textSelectionRect.style.top = (rect.y / main.zoom - pageRect.y / main.zoom) / scale + 'px'; self.textSelectionRect.style.left = (rect.x / main.zoom - pageRect.x / main.zoom) / scale + 'px'; self.textSelectionRect.style.width = rect.width / main.zoom / scale + 'px'; self.textSelectionRect.style.height = rect.height / main.zoom / scale + 'px'; this.appendChild(self.textSelectionRect); } else { self.removeTextRect(); } }); page.textLayerDiv.addEventListener('mousemove', function (e) { if (self.selectedTextRange && self.selectedText.toString()) { const textSelectionRect = self.textSelectionRect.getBoundingClientRect(); const btnRect = self.textSelectionRect.firstChild.getBoundingClientRect(); if ( e.clientX >= textSelectionRect.left && e.clientX <= textSelectionRect.right && e.clientY >= btnRect.top && e.clientY <= textSelectionRect.bottom ) { self.showButton(); } else { self.hideButton(); } } }); page.notesInitialized = true; } }; FLIPBOOK.Tooltip = class { constructor() { this.domElement = document.createElement('div'); this.domElement.className = 'flipbook-tooltip flipbook-noselect'; this.domElement.classList.add('flipbook-hidden'); const self = this; this.currentPosition = { x: 0, y: 0 }; document.addEventListener('scroll', function () { self.position(); }); } show(params) { if (!this.showing) { this.domElement.classList.remove('flipbook-hidden'); this.showing = true; if (params.text) { this.domElement.innerText = params.text; } if (params.parent) { params.parent.appendChild(this.domElement); } if (params.onClick) { this.domElement.style.cursor = 'pointer'; this.domElement.onclick = params.onClick; } else { this.domElement.style.cursor = 'auto'; this.domElement.removeAttribute('onclick'); } this.currentPosition = params.position; this.position(); } } hide() { if (this.showing) { this.domElement.classList.add('flipbook-hidden'); this.showing = false; } } position() { const wrapperRect = this.domElement.parentNode.getBoundingClientRect(); this.domElement.style.top = this.currentPosition.y - wrapperRect.top - scrollY + 'px'; this.domElement.style.left = this.currentPosition.x - wrapperRect.left - scrollX + 'px'; } }; FLIPBOOK.ProgressBar = class { constructor(options = {}) { this.value = options.value || 0; // 0..100 this.min = options.min || 0; this.max = options.max || 100; this.onChange = options.onChange || function (val) {}; this.colors = options.colors || {}; this.wrapper = options.wrapper || document.body; this.el = null; this._dragging = false; this._render(); this.setValue(this.value); this._bindEvents(); } _render() { // Create the structure const bar = document.createElement('div'); bar.className = 'flipbook-progress-bar'; bar.tabIndex = 0; // Theming via CSS variables if (this.colors.bg) bar.style.setProperty('--progress-bg', this.colors.bg); if (this.colors.fill) bar.style.setProperty('--progress-fill', this.colors.fill); if (this.colors.thumb) bar.style.setProperty('--progress-thumb', this.colors.thumb); if (this.colors.thumbBorder) bar.style.setProperty('--progress-thumb-border', this.colors.thumbBorder); bar.innerHTML = `
    `; this.wrapper.appendChild(bar); // Save refs this.el = bar; this.track = bar.querySelector('.progress-track'); this.filled = bar.querySelector('.progress-filled'); this.thumb = bar.querySelector('.progress-thumb'); } _bindEvents() { // Mouse/touch events for dragging this.thumb.addEventListener('mousedown', this._startDrag.bind(this)); this.el.addEventListener('mousedown', this._startDrag.bind(this)); window.addEventListener('mousemove', this._onDrag.bind(this)); window.addEventListener('mouseup', this._endDrag.bind(this)); this.thumb.addEventListener('touchstart', this._startDrag.bind(this), { passive: false }); this.el.addEventListener('touchstart', this._startDrag.bind(this), { passive: false }); window.addEventListener('touchmove', this._onDrag.bind(this), { passive: false }); window.addEventListener('touchend', this._endDrag.bind(this)); // Keyboard accessibility this.thumb.addEventListener('keydown', (e) => { let step = (this.max - this.min) / 100 || 1; if (e.key === 'ArrowRight' || e.key === 'ArrowUp') { this.setValue(this.value + step); e.preventDefault(); } if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') { this.setValue(this.value - step); e.preventDefault(); } }); } _startDrag(e) { if (e.type === 'mousedown' && e.button !== 0) return; this._dragging = true; document.body.style.userSelect = 'none'; this._onDrag(e); } _onDrag(e) { if (!this._dragging) return; let clientX; if (e.touches) { clientX = e.touches[0].clientX; } else { clientX = e.clientX; } const rect = this.el.getBoundingClientRect(); let percent = ((clientX - rect.left) / rect.width) * 100; let val = this.min + (this.max - this.min) * (percent / 100); this.setValue(val); } _endDrag() { if (!this._dragging) return; this._dragging = false; document.body.style.userSelect = ''; } setValue(val) { val = Math.max(this.min, Math.min(this.max, val)); this.value = val; let percent = ((val - this.min) / (this.max - this.min)) * 100; this.filled.style.width = percent + '%'; this.thumb.style.left = percent + '%'; this.thumb.setAttribute('aria-valuenow', Math.round(val)); this.onChange(val); } getValue() { return this.value; } }; FLIPBOOK.Thumbnails = class { constructor(main) { var self = this; var options = main.options; var wrapper = main.wrapper; this.main = main; this.options = options; this.wrapper = wrapper; this.active = null; this.thumbHolder = document.createElement('div'); this.thumbHolder.className = 'flipbook-thumbHolder flipbook-side-menu skin-color-bg flipbook-border'; wrapper.appendChild(this.thumbHolder); this.thumbHolder.style[options.sideMenuPosition] = '0'; this.thumbHolder.classList.add('flipbook-hidden'); main.createMenuHeader(this.thumbHolder, main.strings.thumbnails, main.toggleThumbs); this.bookmark = document.createElement('div'); this.bookmark.className = 'flipbook-font'; this.thumbHolder.appendChild(this.bookmark); this.bookmark.classList.add('flipbook-hidden'); var currentBookmark = document.createElement('a'); currentBookmark.innerHTML = '
    ' + options.strings.bookmarkCurrentPage + '
    '; this.bookmark.appendChild(currentBookmark); currentBookmark.addEventListener('click', function (e) { main.bookmarkPage(main.cPage[0], this); e.preventDefault(); e.stopPropagation(); }); var leftBookmark = document.createElement('a'); leftBookmark.innerHTML = '
    ' + options.strings.bookmarkLeftPage + '
    '; this.bookmark.appendChild(leftBookmark); leftBookmark.addEventListener('click', function (e) { main.bookmarkPage(main.cPage[0], this); e.preventDefault(); e.stopPropagation(); }); var rightBookmark = document.createElement('a'); rightBookmark.innerHTML = '
    ' + options.strings.bookmarkRightPage + '
    '; this.bookmark.appendChild(rightBookmark); rightBookmark.addEventListener('click', function (e) { main.bookmarkPage(main.cPage[1], this); e.preventDefault(); e.stopPropagation(); }); this.search = document.createElement('div'); this.search.className = 'flipbook-search'; this.thumbHolder.appendChild(this.search); this.search.classList.add('flipbook-hidden'); this.searchBar = document.createElement('div'); this.searchBar.className = 'flipbook-findbar'; this.search.appendChild(this.searchBar); this.findInputCotainer = document.createElement('div'); this.findInputCotainer.id = 'findbarInputContainer'; this.searchBar.appendChild(this.findInputCotainer); this.findInput = document.createElement('input'); this.findInput.className = 'toolbarField skin-color skin-color-bg'; this.findInput.title = 'Find'; this.findInput.autocapitalize = 'none'; this.findInput.placeholder = `${options.strings.findInDocument}...`; this.findInputCotainer.appendChild(this.findInput); this.clearInput = document.createElement('span'); this.clearInput.className = 'flipbook-search-clear flipbook-hidden skin-color skin-color-bg'; var closeIcon = main.createSVGIcon('close'); this.clearInput.appendChild(closeIcon); this.clearInput.addEventListener('click', function () { self.findInput.value = ''; self.hideAllThumbs(); self.clearSearchResults(); main.unmark(); main.searchingString = ''; self.clearInput.classList.add('flipbook-hidden'); self.findInput.focus(); }); this.findInputCotainer.appendChild(this.clearInput); this.thumbsWrapper = document.createElement('div'); this.thumbsWrapper.className = 'flipbook-thumbsWrapper'; this.thumbHolder.appendChild(this.thumbsWrapper); this.closeGrid = document.createElement('div'); this.closeGrid.className = 'flipbook-thumbs-grid-close skin-color flipbook-menu-btn'; this.thumbsWrapper.appendChild(this.closeGrid); this.closeGrid.addEventListener('click', function (e) { e.stopPropagation(); e.preventDefault(); self.main.closeMenus(); }); var closeIcon = this.main.createSVGIcon('close'); this.closeGrid.appendChild(closeIcon); this.thumbsScroller = document.createElement('div'); this.thumbsScroller.className = 'flipbook-thumbsScroller skin-color'; this.thumbsWrapper.appendChild(this.thumbsScroller); var searchTimeout = 0; this.findInput.addEventListener('keyup', function () { var str = this.value; if (str) { self.clearInput.classList.remove('flipbook-hidden'); } else { self.clearInput.classList.add('flipbook-hidden'); } clearTimeout(searchTimeout); searchTimeout = setTimeout(function () { var main = self.main; var pdfService = main.pdfService; if (str !== '') { var options = main.options; var matchesFound = 0; self.hideAllThumbs(); self.clearSearchResults(); self.pagesFound = 0; main.unmark(); main.searchingString = str; if (pdfService) { for (var i = 0; i < pdfService.info.numPages; i++) { pdfService.findInPage(str, i, function (matches, htmlContent, index, pageText) { if (matches.length > 0) { self.pagesFound++; matchesFound += matches.length; main.mark(str); if (options.searchResultsThumbs) self.showThumb(index); else self.showSearchResults(matches, index, pageText); } }); } } else { options.pagesOriginal.forEach((_, index) => { if (!options.cover) { index++; } var pi = index; if (options.doublePage) { pi *= 2; } if (options.doublePage && pi === options.pagesOriginal.length * 2 - 2) { pi--; } main.loadPageHTML(pi, function (htmlContent, index) { var matches = htmlContent.innerText .toUpperCase() .search(main.searchingString.toUpperCase()); if (matches > -1) { if (options.doublePage) { index /= 2; } self.showThumb(index); self.pagesFound++; main.mark(str); } }); }); } } else { self.hideAllThumbs(); self.clearSearchResults(); main.unmark(); main.searchingString = str; self.clearInput.classList.add('flipbook-hidden'); } }, 700); }); this.thumbs = []; var arr2 = options.pages; var arr = []; if (options.doublePage) { for (var i = 0; i < arr2.length; i++) { if (i === 0 || i % 2 !== 0) { arr.push(arr2[i]); } } } else { arr = arr2; } if (options.pdfMode) { this.loadThumbsFromPdf(arr); } var h = options.thumbSize; var w = (options.thumbSize * options.pageWidth) / options.pageHeight; arr.forEach((item, i) => { if (item.empty) return; var thumb = document.createElement('div'); thumb.className = 'flipbook-thumb'; thumb.setAttribute('data-thumb-index', i); thumb.style.width = w + 'px'; thumb.style.height = h + 'px'; self.thumbsScroller.appendChild(thumb); var btnClose = document.createElement('span'); btnClose.className = 'thumb-btn-close skin-color skin-color-bg'; thumb.appendChild(btnClose); btnClose.addEventListener('click', function (e) { e.stopPropagation(); e.preventDefault(); main.removeBookmark(thumb.getAttribute('data-thumb-index')); }); var iconClose = main.createSVGIcon('close'); btnClose.appendChild(iconClose); this.thumbs.push(thumb); var thumbImg; if (item.thumbCanvas) { thumbImg = item.thumbCanvas; } else if (item.thumb) { thumbImg = document.createElement('img'); thumbImg.src = item.thumb; } else { return; } thumb.appendChild(thumbImg); thumbImg.style.height = h + 'px'; var hasBackCover = options.doublePage && options.pages.length % 2 === 0; var isBackCover = hasBackCover && i === arr.length - 1; var isCover = options.doublePage && i === 0; var isDouble = options.doublePage && !isCover && !isBackCover; if (isBackCover) { thumbImg.setAttribute('page-title', 2 * i); var span = document.createElement('span'); span.textContent = String(2 * i); span.className = 'skin-color flipbook-thumb-num'; thumb.appendChild(span); } else if (isDouble) { thumb.style.width = 2 * w + 'px'; thumbImg.setAttribute('page-title', 2 * i + 1); var span = document.createElement('span'); span.textContent = String(2 * i) + '-' + String(2 * i + 1); span.className = 'skin-color flipbook-thumb-num'; thumb.appendChild(span); } else { thumbImg.setAttribute('page-title', i + 1); var title = String(i + 1); if (this.options.pages[i] && this.options.pages[i].name) { title = this.options.pages[i].name; } var span = document.createElement('span'); span.textContent = title; span.className = 'skin-color flipbook-thumb-num'; thumb.appendChild(span); } if (options.thumbsStyle === 'overlay') { options.thumbsCloseOnClick = true; } thumbImg.addEventListener('click', function (e) { e.stopPropagation(); e.preventDefault(); var clickedPage = Number(thumbImg.getAttribute('page-title')); if (options.rightToLeft) { clickedPage = options.pages.length - clickedPage + 1; } main.goToPage(clickedPage); if (self.active !== 'search' && options.thumbsCloseOnClick) { main.toggleThumbs(false); } }); }); } loadThumbsFromPdf(arr) { var numPages = this.main.pdfService.info.numPages; for (var i = 0; i < numPages; i++) { var c = document.createElement('canvas'); if (arr[i]) arr[i].thumbCanvas = c; } this.loadThumbFromPdf(0, arr); } loadVisibleThumbs() {} loadThumbFromPdf(i, arr) { var self = this; this.main.pdfService.pdfDocument.getPage(i + 1).then(function (page) { var v = page.getViewport({ scale: 1 }); var scale = self.options.thumbSize / v.height; var viewport = page.getViewport({ scale: scale }); var c = arr[page._pageIndex].thumbCanvas; var context = c.getContext('2d'); c.height = viewport.height; c.width = viewport.width; var renderContext = { canvasContext: context, viewport: viewport, }; page.cleanupAfterRender = true; var renderTask = page.render(renderContext); renderTask.promise.then(function () { page.cleanup(); if (page._pageIndex + 1 < self.main.pdfService.info.numPages) { self.loadThumbFromPdf(page._pageIndex + 1, arr); } }); }); } showAllThumbs() { document.querySelectorAll('.flipbook-thumb').forEach((thumb) => thumb.classList.remove('flipbook-hidden')); this.clearSearchResults(); } hideAllThumbs() { document.querySelectorAll('.flipbook-thumb').forEach((thumb) => thumb.classList.add('flipbook-hidden')); } clearSearchResults() { document.querySelectorAll('.flipbook-search-match').forEach((match) => match.remove()); } showSearchResults(matches, pageIndex, str) { var self = this; var o = this.main.options; var num = matches.length; var pageNumber = Number(pageIndex + 1); var searchMatch = document.createElement('div'); searchMatch.className = 'flipbook-search-match'; searchMatch.setAttribute('data-page', pageNumber); searchMatch.style.order = pageIndex; searchMatch.innerHTML = `
    ${o.strings.page} ${pageNumber} ${num} ${o.strings.matches}
    ${str}
    `; self.thumbsScroller.appendChild(searchMatch); searchMatch.addEventListener('click', function (e) { e.stopPropagation(); e.preventDefault(); var targetPage = Number(this.dataset.page); targetPage = o.rightToLeft && o.pages && o.pages.length ? o.pages.length - targetPage + 1 : targetPage; self.main.goToPage(targetPage); }); } showThumb(index) { if (this.thumbs[index]) { this.thumbs[index].classList.remove('flipbook-hidden'); } } hideThumb(index) { this.thumbs[index].classList.add('flipbook-hidden'); } showBookmarks() { document.querySelectorAll('.thumb-btn-close').forEach((btn) => btn.classList.remove('flipbook-hidden')); this.showBookmarkedThumbs(); this.clearSearchResults(); this.bookmark.classList.remove('flipbook-hidden'); this.setTitle(this.options.strings.bookmarks); this.main.updateCurrentPage(); this.active = 'bookmarks'; this.thumbHolder.classList.remove('flipbook-thumbs-grid'); } showSearch() { this.clearSearchResults(); this.hideAllThumbs(); this.search.classList.remove('flipbook-hidden'); document.querySelectorAll('.thumb-btn-close').forEach((btn) => btn.classList.add('flipbook-hidden')); this.setTitle(this.options.strings.search); this.findInput.value = ''; this.clearInput.classList.add('flipbook-hidden'); this.findInput.focus(); this.active = 'search'; this.thumbHolder.classList.remove('flipbook-thumbs-grid'); } showBookmarkedThumbs() { var arr = this.main.getBookmarkedPages(); this.hideAllThumbs(); for (var i = 0; i < arr.length; i++) { var index = arr[i]; if (index) { this.showThumb(index); } } } show() { this.setTitle(this.options.strings.thumbnails); this.bookmark.classList.add('flipbook-hidden'); this.search.classList.add('flipbook-hidden'); this.thumbHolder.classList.remove('flipbook-hidden'); this.main.thumbsVertical(); this.showAllThumbs(); document.querySelectorAll('.thumb-btn-close').forEach((btn) => btn.classList.add('flipbook-hidden')); this.loadVisibleThumbs(); this.main.resize(); this.active = 'thumbs'; if (this.main.options.thumbsStyle === 'overlay') { this.thumbHolder.classList.add('flipbook-thumbs-grid'); } } hide() { this.thumbHolder.classList.add('flipbook-hidden'); this.main.resize(); this.active = null; } setTitle(str) { this.thumbHolder.querySelector('.flipbook-menu-title').textContent = str; } }; FLIPBOOK.Lightbox = class { constructor(context, content, options) { var self = this; this.context = context; this.options = options; this.$document = document; this.$body = document.body; this.$html = document.documentElement; this.$window = window; self.overlay = document.createElement('div'); self.overlay.className = 'flipbook-overlay'; self.overlay.classList.add('flipbook-hidden'); self.overlay.style.top = self.options.lightboxMarginV; self.overlay.style.bottom = self.options.lightboxMarginV; self.overlay.style.left = self.options.lightboxMarginH; self.overlay.style.right = self.options.lightboxMarginH; Object.assign(self.overlay.style, options.lightboxCSS); document.body.appendChild(self.overlay); if (options.lightboxBackground) { self.overlay.style.background = options.lightboxBackground; } if (options.lightboxBackgroundColor) { self.overlay.style.background = options.lightboxBackgroundColor; } if (options.lightboxBackgroundPattern) { self.overlay.style.background = 'url(' + options.lightboxBackgroundPattern + ') repeat'; } if (options.lightboxBackgroundImage) { self.overlay.style.background = 'url(' + options.lightboxBackgroundImage + ') no-repeat'; self.overlay.style.backgroundSize = 'cover'; self.overlay.style.backgroundPosition = 'center center'; } document.addEventListener('keydown', function (e) { if (e.key === 'Escape') { self.closeLightbox(); } }); self.wrapper = document.createElement('div'); self.wrapper.style.height = 'auto'; self.wrapper.className = 'flipbook-wrapper-transparent'; self.wrapper.style.margin = '0px auto'; self.wrapper.style.padding = '0px'; self.wrapper.style.height = '100%'; self.wrapper.style.width = '100%'; self.overlay.appendChild(self.wrapper); self.wrapper.appendChild(content); var toolbar = document.createElement('div'); toolbar.className = 'flipbook-lightbox-toolbar'; self.wrapper.appendChild(toolbar); } openLightbox() { if (FLIPBOOK.lightboxOpened) { return; } FLIPBOOK.lightboxOpened = true; this.showOverlay(); const lightboxOpenEvent = new Event('r3d-lightboxopen'); window.dispatchEvent(lightboxOpenEvent); if (!this.options.deeplinkingEnabled) { window.history.pushState(null, '', window.location.href); this.context.historyStateChange(); } if (this.context.options.password && !this.context.pdfinitStarted && this.context.initialized) { this.context.initPdf(); } } showOverlay() { if (!this.overlay || !this.$html) return; const element = this.overlay; element.classList.remove('flipbook-hidden'); element.classList.add('flipbook-overlay-visible'); this.context.saveScrollPosition(); document.body.classList.add('flipbook-overflow-hidden'); this.$html.classList.add('flipbook-overflow-hidden'); } hideOverlay() { if (!this.overlay || !this.$html) return; const element = this.overlay; element.classList.remove('flipbook-overlay-visible'); element.addEventListener( 'transitionend', () => { element.classList.add('flipbook-hidden'); }, { once: true } ); document.body.classList.remove('flipbook-overflow-hidden'); this.$html.classList.remove('flipbook-overflow-hidden'); this.context.restoreScrollPosition(); } closeLightbox(popState) { if (!FLIPBOOK.lightboxOpened /*|| !this.context.Book || !this.context.Book.enabled*/) { return; } FLIPBOOK.lightboxOpened = false; this.hideOverlay(); const lightboxCloseEvent = new Event('r3d-lightboxclose'); window.dispatchEvent(lightboxCloseEvent); this.context.trigger('lightboxclose'); this.context.fullscreenElement.classList.remove('flipbook-browser-fullscreen'); this.context.lightboxEnd(); if (!popState && !this.options.deeplinkingEnabled) { history.back(); } } disposeLightbox() { FLIPBOOK.lightboxOpened = false; this.hideOverlay(); const lightboxCloseEvent = new Event('r3d-lightboxclose'); window.dispatchEvent(lightboxCloseEvent); this.context.trigger('lightboxclose'); this.context.fullscreenElement.classList.remove('flipbook-browser-fullscreen'); this.context.lightboxEnd(); this.context.disposed = true; } }; FLIPBOOK.onPageLinkClick = function (link) { var id = link.dataset.bookid; var page = link.dataset.page; if (page) { FLIPBOOK.books[id].goToPage(Number(page)); } var _url = link.dataset.url; if (_url) { window.open(_url, '_blank'); } }; FLIPBOOK.easings = { linear: function (t) { return t; }, easeInQuad: function (t) { return t * t; }, easeOutQuad: function (t) { return t * (2 - t); }, easeInOutQuad: function (t) { return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; }, easeInCubic: function (t) { return t * t * t; }, easeOutCubic: function (t) { return --t * t * t + 1; }, easeInOutCubic: function (t) { return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; }, easeInQuart: function (t) { return t * t * t * t; }, easeOutQuart: function (t) { return 1 - --t * t * t * t; }, easeInOutQuart: function (t) { return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t; }, easeInQuint: function (t) { return t * t * t * t * t; }, easeOutQuint: function (t) { return 1 + --t * t * t * t * t; }, easeInOutQuint: function (t) { return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t; }, easeInSine: function (t) { return 1 - Math.cos((t * Math.PI) / 2); }, easeOutSine: function (t) { return Math.sin((t * Math.PI) / 2); }, easeInOutSine: function (t) { return 0.5 * (1 - Math.cos(Math.PI * t)); }, }; FLIPBOOK.animate = function (params) { let start = performance.now(); let from = params.from; let to = params.to; let duration = params.duration; let change = to - from; let easing = FLIPBOOK.easings[params.easing] || FLIPBOOK.easings.linear; let rafId = null; let pausedAt = null; let repeatCount = params.repeat || 1; let yoyo = params.yoyo || false; let currentIteration = 0; let reversed = false; let delay = params.delay || 0; function animate() { let now = performance.now(); let timeElapsed = pausedAt !== null ? pausedAt - start : now - start; if (timeElapsed < delay) { rafId = requestAnimationFrame(animate); return; } timeElapsed -= delay; // Adjust timeElapsed after delay let progress = Math.min(timeElapsed / duration, 1); let value; if (reversed) { value = from + change * easing(1 - progress); } else { value = from + change * easing(progress); } if (params.step) { params.step(value); } if (progress < 1) { rafId = requestAnimationFrame(animate); } else { currentIteration++; if (currentIteration < repeatCount) { if (yoyo) { reversed = !reversed; } start = performance.now(); rafId = requestAnimationFrame(animate); } else { if (params.step) { params.step(to); } if (params.complete) { params.complete(); } } } } function pause() { if (rafId) { cancelAnimationFrame(rafId); pausedAt = performance.now(); } } function resume() { if (pausedAt) { start += performance.now() - pausedAt; pausedAt = null; rafId = requestAnimationFrame(animate); } } function stop() { if (rafId) { cancelAnimationFrame(rafId); } } if (delay > 0) { setTimeout(() => { start = performance.now(); // Reset start time after delay rafId = requestAnimationFrame(animate); }, delay); } else { rafId = requestAnimationFrame(animate); } return { pause, resume, stop, }; }; FLIPBOOK.Linkify = function (element, linkTarget = '_blank') { // Regexes for URLs (including bare domains) and emails const urlRegex = /\b(?:https?:\/\/|ftp:\/\/|www\.|[A-Za-z0-9.-]+\.[A-Za-z]{2,6})(?:\/[^\s<>"']*)?/gi; const emailRegex = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b/gi; const skipTags = new Set(['a', 'script', 'style', 'textarea', 'code']); const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, { acceptNode(node) { const parentTag = node.parentNode.tagName?.toLowerCase(); return skipTags.has(parentTag) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT; }, }); const textNodes = []; while (walker.nextNode()) { textNodes.push(walker.currentNode); } textNodes.forEach((node) => { const frag = document.createDocumentFragment(); const text = node.nodeValue; let lastIndex = 0; // Combined regex to find either URL or email const combined = new RegExp(`${urlRegex.source}|${emailRegex.source}`, 'ig'); let match; while ((match = combined.exec(text))) { if (match.index > lastIndex) { frag.appendChild(document.createTextNode(text.slice(lastIndex, match.index))); } const token = match[0]; let href; if (emailRegex.test(token)) { href = `mailto:${token}`; } else { // If it doesn’t already start with a scheme, prepend http:// href = /^(?:https?:\/\/|ftp:\/\/)/i.test(token) ? token : token.startsWith('www.') ? `http://${token}` : `http://${token}`; } const a = document.createElement('a'); a.href = href; a.target = linkTarget; a.className = 'flipbook-page-auto-link'; a.textContent = token; frag.appendChild(a); lastIndex = combined.lastIndex; } if (lastIndex < text.length) { frag.appendChild(document.createTextNode(text.slice(lastIndex))); } node.parentNode.replaceChild(frag, node); }); }; FLIPBOOK.extend = function () { function isPlainObject(obj) { return Object.prototype.toString.call(obj) === '[object Object]'; } var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if (typeof target === 'boolean') { deep = target; target = arguments[1] || {}; // Skip the boolean and the target i = 2; } // Handle case when target is a string or something (possible in deep copy) if (typeof target !== 'object' && typeof target !== 'function') { target = {}; } // Extend the target object if only one argument is passed if (length === i) { target = this; --i; } for (; i < length; i++) { // Only deal with non-null/undefined values if ((options = arguments[i]) != null) { // Extend the base object for (name in options) { if (Object.prototype.hasOwnProperty.call(options, name)) { src = target[name]; copy = options[name]; // Prevent never-ending loop if (target === copy) { continue; } // Recurse if we're merging plain objects or arrays if (deep && copy && (isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { if (copyIsArray) { copyIsArray = false; clone = src && Array.isArray(src) ? src : []; } else { clone = src && isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[name] = FLIPBOOK.extend(deep, clone, copy); // Don't bring in undefined values } else if (copy !== undefined) { target[name] = copy; } } } } } // Return the modified object return target; }; FLIPBOOK.Tooltip2 = class { constructor(wrapper) { this.wrapper = wrapper; this.tooltipEl = null; this.init(); } init() { this.tooltipEl = document.createElement('span'); this.tooltipEl.className = 'flipbook-tooltip-element skin-color skin-color-bg'; this.tooltipEl.setAttribute('role', 'tooltip'); this.tooltipEl.id = 'flipbook-tooltip'; this.wrapper.appendChild(this.tooltipEl); this.wrapper.addEventListener('mouseover', this.handleMouseOver.bind(this)); this.wrapper.addEventListener('mouseout', this.handleMouseOut.bind(this)); this.wrapper.addEventListener('focusin', this.handleFocusIn.bind(this)); this.wrapper.addEventListener('focusout', this.handleMouseOut.bind(this)); this.wrapper.addEventListener('touchstart', this.handleTouchStart.bind(this), { passive: true }); } handleMouseOver(e) { const target = e.target.closest('.flipbook-has-tooltip'); if (target && !target.classList.contains('disabled')) { this.showTooltip(target); } } handleFocusIn(e) { const target = e.target.closest('.flipbook-has-tooltip'); if (target && !target.classList.contains('disabled')) { target.setAttribute('aria-describedby', 'flipbook-tooltip'); this.showTooltip(target); } } handleTouchStart(e) { const target = e.target.closest('.flipbook-has-tooltip'); if (target && !target.classList.contains('disabled')) { // e.preventDefault(); this.showTooltip(target); setTimeout(() => { this.hideTooltip(); }, 2000); } } handleMouseOut() { this.hideTooltip(); } showTooltip(target) { this.tooltipEl.innerText = target.dataset.tooltip; this.tooltipEl.style.opacity = 0; this.tooltipEl.style.display = 'block'; const targetRect = target.getBoundingClientRect(); const tooltipRect = this.tooltipEl.getBoundingClientRect(); const wrapperRect = this.wrapper.getBoundingClientRect(); let top = targetRect.top - wrapperRect.top - tooltipRect.height - 10; let left = targetRect.left - wrapperRect.left + (targetRect.width - tooltipRect.width) / 2; let isBelow = false; // Calculate arrow position (center of target relative to tooltip) let arrowLeft = targetRect.left - wrapperRect.left + targetRect.width / 2 - left; arrowLeft = Math.max(6, Math.min(tooltipRect.width - 6, arrowLeft)); // WRAPPER boundary checks instead of viewport // If tooltip goes above wrapper if (top < 0) { top = targetRect.bottom - wrapperRect.top + 10; isBelow = true; } // If tooltip goes below wrapper if (top + tooltipRect.height > wrapperRect.height) { top = wrapperRect.height - tooltipRect.height - 5; } // If tooltip goes left of wrapper if (left < 0) { left = 5; arrowLeft = targetRect.left - wrapperRect.left + targetRect.width / 2 - left; arrowLeft = Math.max(6, Math.min(tooltipRect.width - 6, arrowLeft)); } // If tooltip goes right of wrapper if (left + tooltipRect.width > wrapperRect.width) { left = wrapperRect.width - tooltipRect.width - 5; arrowLeft = targetRect.left - wrapperRect.left + targetRect.width / 2 - left; arrowLeft = Math.max(6, Math.min(tooltipRect.width - 6, arrowLeft)); } top += this.wrapper.scrollTop; left += this.wrapper.scrollLeft; this.tooltipEl.style.top = `${top}px`; this.tooltipEl.style.left = `${left}px`; this.tooltipEl.style.setProperty('--arrow-left', `${arrowLeft}px`); this.tooltipEl.style.opacity = 1; this.tooltipEl.classList.toggle('below', isBelow); } hideTooltip() { this.tooltipEl.style.opacity = 0; this.tooltipEl.style.display = 'none'; this.tooltipEl.removeAttribute('aria-describedby'); } };