`).attr(\"data-page\", i).data(\"width\", pageinfo.width).data(\"height\", pageinfo.height).data(\"zoom\", this._zoom.current).addClass(this.settings.pageClass).width(pageinfo.width * this._zoom.current).height(pageinfo.height * this._zoom.current);\n\t\t\tlet $content = $(`
`).width(pageinfo.width).height(pageinfo.height);\n\t\t\tpageinfo.$div.append($content);\n\t\t\tthis._cleanPage(pageinfo.$div);\n\t\t\treturn pageinfo;\n\t\t}\n\t\t_placeSkeleton(pageinfo, i) {\n\t\t\tlet prevpage = i - 1;\n\t\t\tlet $prevpage = null;\n\t\t\twhile (prevpage > 0 && ($prevpage = this.$container.find(`.${this.settings.pageClass}[data-page=\"${prevpage}\"]`)).length === 0) {\n\t\t\t\tprevpage--;\n\t\t\t}\n\t\t\tif (prevpage === 0) {\n\t\t\t\tthis.$container.append(pageinfo.$div);\n\t\t\t} else {\n\t\t\t\t$prevpage.after(pageinfo.$div);\n\t\t\t}\n\t\t}\n\t\t_createSkeletons(pageinfo) {\n\t\t\tfor (let i = 1; i <= this.pageCount; i++) {\n\t\t\t\tif (this.pages[i] === undefined) {\n\t\t\t\t\tpageinfo = this._createSkeleton(pageinfo, i);\n\t\t\t\t\tthis.pages[i] = pageinfo;\n\t\t\t\t\tthis._placeSkeleton(pageinfo, i);\n\t\t\t\t\tif (typeof this.settings.onNewPage === \"function\") {\n\t\t\t\t\t\tthis.settings.onNewPage.call(this, pageinfo.$div.get(0), i);\n\t\t\t\t\t}\n\t\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"newpage\", {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tpageNumber: i,\n\t\t\t\t\t\t\tpage: pageinfo.$div.get(0)\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t_setActivePage(i) {\n\t\t\tif (this._activePage !== i) {\n\t\t\t\tthis._activePage = i;\n\t\t\t\tlet activePage = this.getActivePage();\n\t\t\t\tif (this._documentReady) {\n\t\t\t\t\tactivePage = activePage == null ? null : activePage.get(0);\n\t\t\t\t\tif (typeof this.settings.onActivePageChanged === \"function\") {\n\t\t\t\t\t\tthis.settings.onActivePageChanged.call(this, activePage, i);\n\t\t\t\t\t}\n\t\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"activepagechanged\", {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tactivePageNumber: i,\n\t\t\t\t\t\t\tactivePage: activePage\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t_areaOfPageVisible($page) {\n\t\t\tif ($page === undefined) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tlet c_offset = this.$container.offset();\n\t\t\tlet c_width = this.$container.width();\n\t\t\tlet c_height = this.$container.height();\n\t\t\tlet position = $page.offset();\n\t\t\tposition.top -= c_offset.top;\n\t\t\tposition.left -= c_offset.left;\n\t\t\tposition.bottom = position.top + $page.outerHeight();\n\t\t\tposition.right = position.left + $page.outerWidth();\n\t\t\tlet page_y0 = Math.min(Math.max(position.top, 0), c_height);\n\t\t\tlet page_y1 = Math.min(Math.max($page.outerHeight() + position.top, 0), c_height);\n\t\t\tlet page_x0 = Math.min(Math.max(position.left, 0), c_width);\n\t\t\tlet page_x1 = Math.min(Math.max($page.outerWidth() + position.left, 0), c_width);\n\t\t\tlet vis_x = page_x1 - page_x0;\n\t\t\tlet vis_y = page_y1 - page_y0;\n\t\t\treturn vis_x * vis_y;\n\t\t}\n\t\tisPageVisible(i) {\n\t\t\tif (this.pdf === null || i === undefined || i === null || i < 1 || i > this.pdf.numPages) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (typeof i === \"string\") {\n\t\t\t\ti = parseInt(i);\n\t\t\t}\n\t\t\tlet $page = i;\n\t\t\tif (typeof i === \"number\") {\n\t\t\t\tif (this.pages[i] === undefined) return false;\n\t\t\t\t$page = this.pages[i].$div;\n\t\t\t}\n\t\t\treturn this._areaOfPageVisible($page) > $page.outerWidth() * $page.outerHeight() * this.settings.visibleThreshold;\n\t\t}\n\t\t_visiblePages(forceRedraw = false) {\n\t\t\tlet max_area = 0;\n\t\t\tlet i_page = null;\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\tthis._visibles = [];\n\t\t\t\tthis._setActivePage(0);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet $visibles = this.pages.filter(function (pageinfo) {\n\t\t\t\tlet areaVisible = this._areaOfPageVisible(pageinfo.$div);\n\t\t\t\tif (areaVisible > max_area) {\n\t\t\t\t\tmax_area = areaVisible;\n\t\t\t\t\ti_page = pageinfo.$div.data(\"page\");\n\t\t\t\t}\n\t\t\t\treturn areaVisible > 0;\n\t\t\t}.bind(this)).map(x => x.$div);\n\t\t\tthis._setActivePage(i_page);\n\t\t\tlet visibles = $visibles.map(x => {\n\t\t\t\treturn parseInt($(x).data(\"page\"));\n\t\t\t});\n\t\t\tif (visibles.length > 0) {\n\t\t\t\tlet minVisible = Math.min(...visibles);\n\t\t\t\tlet maxVisible = Math.max(...visibles);\n\t\t\t\tfor (let i = Math.max(1, minVisible - this.settings.extraPagesToLoad); i < minVisible; i++) {\n\t\t\t\t\tif (!visibles.includes(i)) visibles.push(i);\n\t\t\t\t}\n\t\t\t\tfor (let i = maxVisible + 1; i <= Math.min(maxVisible + this.settings.extraPagesToLoad, this.pdf.numPages); i++) {\n\t\t\t\t\tif (!visibles.includes(i)) visibles.push(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet nowVisibles = visibles;\n\t\t\tif (!forceRedraw) {\n\t\t\t\tnowVisibles = visibles.filter(function (x) {\n\t\t\t\t\treturn !this._visibles.includes(x);\n\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tthis._visibles.filter(function (x) {\n\t\t\t\treturn !visibles.includes(x);\n\t\t\t}).forEach(function (i) {\n\t\t\t\tthis._cleanPage(this.pages[i].$div);\n\t\t\t}.bind(this));\n\t\t\tthis._visibles = visibles;\n\t\t\tthis.loadPages(...nowVisibles);\n\t\t}\n\t\tloadPages(...pages) {\n\t\t\tthis._pagesLoading.push(...pages);\n\t\t\tif (this._loading) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._loadingTask();\n\t\t}\n\t\t_loadingTask() {\n\t\t\tthis._loading = true;\n\t\t\tif (this._pagesLoading.length > 0) {\n\t\t\t\tlet pagei = this._pagesLoading.shift();\n\t\t\t\tthis.pdf.getPage(pagei).then(function (page) {\n\t\t\t\t\tthis._renderPage(page, pagei);\n\t\t\t\t}.bind(this)).then(function (pageinfo) {\n\t\t\t\t\tif (this._pagesLoading.length > 0) {\n\t\t\t\t\t\tthis._loadingTask();\n\t\t\t\t\t}\n\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tthis._loading = false;\n\t\t}\n\t\tscrollToPage(i) {\n\t\t\tif (this.pages.length === 0 || this.pages[i] === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet $page = this.pages[i].$div;\n\t\t\tif ($page.length === 0) {\n\t\t\t\tconsole.warn(`Page ${i} not found`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet position = $page.position();\n\t\t\tlet containerPosition = this.$container.position();\n\t\t\tif (position !== undefined) {\n\t\t\t\tthis.$container.get(0).scrollTop = this.$container.get(0).scrollTop + position.top - containerPosition.top;\n\t\t\t\tthis.$container.get(0).scrollLeft = this.$container.get(0).scrollLeft + position.left - containerPosition.left;\n\t\t\t}\n\t\t\tthis._setActivePage(i);\n\t\t}\n\t\t_renderPage(page, i) {\n\t\t\tlet pageinfo = this.pages[i];\n\t\t\tlet scale = this.settings.renderingScale;\n\t\t\tlet pixel_ratio = window.devicePixelRatio || 1;\n\t\t\tlet viewport = page.getViewport({\n\t\t\t\trotation: this._rotation,\n\t\t\t\tscale: this._zoom.current * scale\n\t\t\t});\n\t\t\tpageinfo.width = viewport.width / this._zoom.current / scale;\n\t\t\tpageinfo.height = viewport.height / this._zoom.current / scale;\n\t\t\tpageinfo.$div.data(\"width\", pageinfo.width);\n\t\t\tpageinfo.$div.data(\"height\", pageinfo.height);\n\t\t\tpageinfo.$div.width(pageinfo.width * this._zoom.current);\n\t\t\tpageinfo.$div.height(pageinfo.height * this._zoom.current);\n\t\t\tpageinfo.loaded = true;\n\t\t\tlet $canvas = $(\"
\");\n\t\t\tlet canvas = $canvas.get(0);\n\t\t\tlet context = canvas.getContext(\"2d\");\n\t\t\tcanvas.height = viewport.height * pixel_ratio;\n\t\t\tcanvas.width = viewport.width * pixel_ratio;\n\t\t\tcanvas.getContext(\"2d\");\n\t\t\tvar transform = pixel_ratio !== 1 ? [pixel_ratio, 0, 0, pixel_ratio, 0, 0] : null;\n\t\t\tvar renderContext = {\n\t\t\t\tcanvasContext: context,\n\t\t\t\tviewport: viewport,\n\t\t\t\ttransform: transform\n\t\t\t};\n\t\t\treturn page.render(renderContext).promise.then(function () {\n\t\t\t\tthis._setPageContent(pageinfo.$div, $canvas);\n\t\t\t\tif (this._documentReady) {\n\t\t\t\t\tif (typeof this.settings.onPageRender === \"function\") {\n\t\t\t\t\t\tthis.settings.onPageRender.call(this, pageinfo.$div.get(0), i);\n\t\t\t\t\t}\n\t\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"pagerender\", {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tpageNumber: i,\n\t\t\t\t\t\t\tpage: pageinfo.$div.get(0)\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\treturn pageinfo;\n\t\t\t}.bind(this));\n\t\t}\n\t\tgetActivePage() {\n\t\t\tif (this._activePage === null || this.pdf === null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (this._activePage < 1 || this._activePage > this.pdf.numPages) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn this.pages[this._activePage].$div;\n\t\t}\n\t\tgetPages() {\n\t\t\treturn this.pages;\n\t\t}\n\t\tgetPageCount() {\n\t\t\tif (this.pdf === null) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn this.pdf.numPages;\n\t\t}\n\t\tnext() {\n\t\t\tif (this._activePage < this.pdf.numPages) {\n\t\t\t\tthis.scrollToPage(this._activePage + 1);\n\t\t\t}\n\t\t}\n\t\tprev() {\n\t\t\tif (this._activePage > 1) {\n\t\t\t\tthis.scrollToPage(this._activePage - 1);\n\t\t\t}\n\t\t}\n\t\tfirst() {\n\t\t\tif (this._activePage !== 1) {\n\t\t\t\tthis.scrollToPage(1);\n\t\t\t}\n\t\t}\n\t\tlast() {\n\t\t\tif (this.pdf === null) return;\n\t\t\tif (this._activePage !== this.pdf.numPages) {\n\t\t\t\tthis.scrollToPage(this.pdf.numPages);\n\t\t\t}\n\t\t}\n\t\trotate(deg, accumulate = false) {\n\t\t\tif (accumulate) {\n\t\t\t\tdeg = deg + this._rotation;\n\t\t\t}\n\t\t\tthis._rotation = deg;\n\t\t\tlet container = this.$container.get(0);\n\t\t\tlet prevScroll = {\n\t\t\t\ttop: container.scrollTop,\n\t\t\t\tleft: container.scrollLeft,\n\t\t\t\theight: container.scrollHeight,\n\t\t\t\twidth: container.scrollWidth\n\t\t\t};\n\t\t\treturn this.forceViewerInitialization().then(function () {\n\t\t\t\tlet newScroll = {\n\t\t\t\t\ttop: container.scrollTop,\n\t\t\t\t\tleft: container.scrollLeft,\n\t\t\t\t\theight: container.scrollHeight,\n\t\t\t\t\twidth: container.scrollWidth\n\t\t\t\t};\n\t\t\t\tcontainer.scrollTop = prevScroll.top * (newScroll.height / prevScroll.height);\n\t\t\t\tcontainer.scrollLeft = prevScroll.left * (newScroll.width / prevScroll.width);\n\t\t\t}.bind(this));\n\t\t}\n\t\tforceViewerInitialization() {\n\t\t\tthis.pages = [];\n\t\t\tthis.$container.find(`.${this.settings.pageClass}`).remove();\n\t\t\tthis._pagesLoading = [];\n\t\t\tthis._loading = false;\n\t\t\tthis._visibles = [];\n\t\t\tthis._activePage = null;\n\t\t\treturn this.pdf.getPage(1).then(function (page) {\n\t\t\t\tthis._createSkeletons(page);\n\t\t\t\tthis._visiblePages();\n\t\t\t\tthis._setActivePage(1);\n\t\t\t}.bind(this));\n\t\t}\n\t\tasync loadDocument(document) {\n\t\t\tthis._documentReady = false;\n\t\t\tthis.pages = [];\n\t\t\tthis.$container.find(`.${this.settings.pageClass}`).remove();\n\t\t\tthis.pdf = null;\n\t\t\tlet loadingTask = pdfjsLib.getDocument(document);\n\t\t\treturn loadingTask.promise.then(function (pdf) {\n\t\t\t\tthis.pdf = pdf;\n\t\t\t\tthis.pageCount = pdf.numPages;\n\t\t\t\tthis._rotation = 0;\n\t\t\t\treturn this.forceViewerInitialization();\n\t\t\t}.bind(this)).then(function () {\n\t\t\t\tif (typeof this.settings.onDocumentReady === \"function\") {\n\t\t\t\t\tthis.settings.onDocumentReady.call(this);\n\t\t\t\t}\n\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"documentready\", {\n\t\t\t\t\tdetail: {\n\t\t\t\t\t\tdocument: this.pdf\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t\tthis._setActivePage(0);\n\t\t\t\tthis._documentReady = true;\n\t\t\t\tthis._setActivePage(1);\n\t\t\t}.bind(this));\n\t\t}\n\t}\n\n\tfunction recoverAttributes(target, attributeDefaults) {\n\t\tconst camelcaseToSnakecase = str => str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);\n\t\tlet $target = $(target);\n\t\tlet result = {};\n\t\tif ($target.length > 0) {\n\t\t\t$target = $($target[0]);\n\t\t\tfor (let originalAttributeName in attributeDefaults) {\n\t\t\t\tlet attributeName = camelcaseToSnakecase(originalAttributeName);\n\t\t\t\tlet attributeValue = $target.attr(attributeName);\n\t\t\t\tif (attributeValue != null) {\n\t\t\t\t\tswitch (typeof attributeDefaults[originalAttributeName]) {\n\t\t\t\t\tcase \"float\":\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tattributeValue = parseFloat(attributeValue);\n\t\t\t\t\t\t} catch (_) {}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"number\":\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tattributeValue = parseInt(attributeValue);\n\t\t\t\t\t\t} catch (_) {}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"function\":\n\t\t\t\t\t\tlet functionString = attributeValue;\n\t\t\t\t\t\tattributeValue = function () {\n\t\t\t\t\t\t\teval(functionString);\n\t\t\t\t\t\t}.bind(target[0]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tresult[originalAttributeName] = attributeValue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tfunction init(element) {\n\t\tlet options = recoverAttributes(element, Object.assign({\n\t\t\tpdfDocument: \"\",\n\t\t\tinitialZoom: \"\"\n\t\t}, defaults));\n\t\tif (options[\"pdfDocument\"] != null) {\n\t\t\tlet pdfViewer = new PDFjsViewer($(element), options);\n\t\t\tpdfViewer.loadDocument(options[\"pdfDocument\"]).then(function () {\n\t\t\t\tif (options[\"initialZoom\"] != null) {\n\t\t\t\t\tpdfViewer.setZoom(options[\"initialZoom\"]);\n\t\t\t\t}\n\t\t\t});\n\t\t\telement.get(0).pdfViewer = pdfViewer;\n\t\t}\n\t}\n\t$(function () {\n\t\t$(\".pdfjs-viewer\").each(function () {\n\t\t\tlet $viewer = $(this);\n\t\t\tinit($viewer);\n\t\t});\n\t});\n\texports.PDFjsViewer = PDFjsViewer;\n})(window, window._$ ?? window.jQuery ?? undefined);\n"],"names":["exports","$","undefined","console","error","let","defaults","visibleThreshold","extraPagesToLoad","pageClass","contentClass","onDocumentReady","onNewPage","page","i","onPageRender","zoomValues","onZoomChange","zoomlevel","onActivePageChanged","zoomFillArea","emptyContent","renderingScale","Zoomer","constructor","viewer","options","fillArea","this","current","settings","Object","assign","sort","get","zoom","parseFloat","$activepage","getActivePage","filter","x","length","Math","min","max","$container","width","data","height","zoomPages","getPages","forEach","$page","$div","c_width","c_height","find","bind","PDFjsViewer","version","_zoom","_pdfjsViewer","_setScrollListener","pages","pdf","_documentReady","setZoom","container","prevzoom","prevScroll","top","scrollTop","left","scrollLeft","_visiblePages","call","dispatchEvent","CustomEvent","detail","getZoom","_cleanPage","$emptyContent","html","append","_setPageContent","$content","refreshAll","scrollLock","scrollPos","__scrollHandler","e","abs","clientHeight","clientWidth","off","on","_createSkeleton","pageinfo","loaded","getViewport","viewport","rotation","_rotation","scale","assert","attr","addClass","_placeSkeleton","prevpage","$prevpage","after","_createSkeletons","pageCount","pageNumber","_setActivePage","_activePage","activePage","activePageNumber","_areaOfPageVisible","c_offset","offset","position","bottom","outerHeight","right","outerWidth","page_y0","page_y1","page_x0","page_x1","vis_x","vis_y","isPageVisible","numPages","parseInt","forceRedraw","max_area","i_page","_visibles","$visibles","areaVisible","map","visibles","minVisible","maxVisible","includes","push","nowVisibles","loadPages","_pagesLoading","_loading","_loadingTask","pagei","shift","getPage","then","_renderPage","scrollToPage","warn","containerPosition","pixel_ratio","window","devicePixelRatio","$canvas","canvas","context","getContext","transform","renderContext","canvasContext","render","promise","getPageCount","next","prev","first","last","rotate","deg","accumulate","scrollHeight","scrollWidth","forceViewerInitialization","newScroll","remove","loadDocument","document","loadingTask","pdfjsLib","getDocument","recoverAttributes","target","attributeDefaults","camelcaseToSnakecase","str","replace","letter","toLowerCase","$target","result","originalAttributeName","attributeName","attributeValue","_","functionString","eval","init","element","pdfDocument","initialZoom","pdfViewer","each","$viewer","_$","jQuery"],"mappings":"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"}
--------------------------------------------------------------------------------
/js/pdfjs-viewer.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2020 Carlos de Alfonso (https://github.com/dealfonso)
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | (function(exports, $) {
17 | 'use strict';
18 |
19 | if ($ === undefined) {
20 | console.error("jQuery-like library not available");
21 | return;
22 | }
23 |
24 | let defaults = {
25 | // Threshold to consider that a page is visible
26 | visibleThreshold: 0.5,
27 | // Number of extra pages to load (appart from the visible)
28 | extraPagesToLoad: 3,
29 | // The class used for each page (the div that wraps the content of the page)
30 | pageClass: "pdfpage",
31 | // Prefix of the id used for each page (the page id will be
-)
32 | pageIdPrefix: "page",
33 | // The class used for the content of each page (the div that contains the page)
34 | contentClass: "content-wrapper",
35 | // Function called when a document has been loaded and its structure has been created
36 | onDocumentReady: () => {},
37 | // Function called when a new page is created (it is bound to the object, and receives a html object as parameter, and the page number)
38 | onNewPage: (page, i) => {},
39 | // Function called when a page is rendered (it is bound to the object, and receives a html object as parameter, and the page number)
40 | onPageRender: (page, i) => {},
41 | // Posible zoom values to iterate over using "in" and "out"
42 | zoomValues: [ 0.25, 0.5, 0.75, 1, 1.25, 1.50, 2, 4, 8 ],
43 | // Function called when the zoom level changes (it receives the zoom level)
44 | onZoomChange: (zoomlevel) => {},
45 | // Function called whenever the active page is changed (the active page is the one that is shown in the viewer)
46 | onActivePageChanged: (page, i) => {},
47 | // Percentage of the container that will be filled with the page
48 | zoomFillArea: 0.95,
49 | // Function called to get the content of an empty page
50 | emptyContent: () => $(''),
51 | // The scale to which the pages are rendered (1.5 is the default value for the PDFjs viewer); a higher value will render the pages with a higher resolution
52 | // but it will consume more memory and CPU. A lower value will render the pages with a lower resolution, but they will be uglier.
53 | renderingScale: 1.5,
54 | }
55 |
56 | // Class used to help in zoom management; probably it can be moved to the main class, but it is used to group methods
57 | class Zoomer {
58 | /**
59 | * Construct the helper class
60 | * @param {PDFjsViewer} viewer - the viewer object
61 | * @param {*} options - the options object
62 | */
63 | constructor(viewer, options = {}) {
64 | let defaults = {
65 | // The possible zoom values to iterate through using "in" and "out"
66 | zoomValues: [ 0.25, 0.5, 0.75, 1, 1.25, 1.50, 2, 4, 8 ],
67 | // The area to fill the container with the zoomed pages
68 | fillArea: 0.9,
69 | }
70 |
71 | // The current zooom value
72 | this.current = 1;
73 | // The viewer instance whose pages may be zoomed
74 | this.viewer = viewer;
75 | // The settings
76 | this.settings = Object.assign({}, defaults, options);
77 |
78 | // Need having the zoom values in order
79 | this.settings.zoomValues = this.settings.zoomValues.sort();
80 | }
81 |
82 | /** Translates a zoom value into a float value; possible values:
83 | * - a float value
84 | * - a string with a keyword (e.g. "width", "height", "fit", "in", "out")
85 | * @param {number} zoom - the zoom value to be translated
86 | * @return {number} The zoom value
87 | */
88 | get(zoom = null) {
89 | // If no zoom is specified, return the current one
90 | if (zoom === null) {
91 | return this.current;
92 | }
93 | // If it is a number, return it
94 | if (parseFloat(zoom) == zoom) {
95 | return zoom;
96 | }
97 | let $activepage = this.viewer.getActivePage();
98 | let zoomValues = [];
99 | // If it is a keyword, return the corresponding value
100 | switch(zoom) {
101 | case "in":
102 | zoom = this.current;
103 | zoomValues = this.settings.zoomValues.filter((x) => x > zoom);
104 | if (zoomValues.length > 0) {
105 | zoom = Math.min(...zoomValues);
106 | }
107 | break;
108 | case "out":
109 | zoom = this.current;
110 | zoomValues = this.settings.zoomValues.filter((x) => x < zoom);
111 | if (zoomValues.length > 0) {
112 | zoom = Math.max(...zoomValues);
113 | }
114 | break;
115 | case "fit":
116 | zoom = Math.min(this.get("width"), this.get("height"));
117 | break;
118 | case "width":
119 | zoom = this.settings.fillArea * this.viewer.$container.width() / $activepage.data("width");
120 | break;
121 | case "height":
122 | zoom = this.settings.fillArea * this.viewer.$container.height() / $activepage.data("height");
123 | break;
124 | default:
125 | zoom = this.current;
126 | break;
127 | }
128 | return zoom;
129 | }
130 |
131 | /**
132 | * Sets the zoom value to each page (changes both the page and the content div); relies on the data-values for the page
133 | * @param {number} zoom - the zoom value to be set
134 | */
135 | zoomPages(zoom) {
136 | zoom = this.get(zoom);
137 | this.viewer.getPages().forEach(function(page) {
138 | let $page = page.$div;
139 | let c_width = $page.data("width");
140 | let c_height = $page.data("height");
141 |
142 | $page.width(c_width * zoom).height(c_height * zoom);
143 | $page.data('zoom', zoom);
144 | $page.find(`.${this.viewer.settings.contentClass}`).width(c_width * zoom).height(c_height * zoom);
145 | }.bind(this));
146 | this.current = zoom;
147 | }
148 | }
149 |
150 | class PDFjsViewer {
151 | // The version of the viewer
152 | version = "2.0.0";
153 |
154 | /**
155 | * Constructs the object, and initializes actions:
156 | * - add the scroll handler to the container
157 | * - set the first adjusting action when the page is loaded
158 | * - creates the zoom helper
159 | * @param {jQuery} $container the jQuery value that will hold the pages
160 | * @param {dictionary} options options for the viewer
161 | */
162 | constructor($container, options = {}) {
163 |
164 | this.settings = Object.assign({}, defaults, options);
165 |
166 | // Create the zoomer helper
167 | this._zoom = new Zoomer(this, {
168 | zoomValues: this.settings.zoomValues,
169 | fillArea: this.settings.zoomFillArea,
170 | });
171 |
172 | $container = $($container);
173 |
174 | // Store the container
175 | this.$container = $container;
176 |
177 | // Add a reference to this object to the container
178 | $container.get(0)._pdfjsViewer = this;
179 |
180 | // Add the event listeners
181 | this._setScrollListener();
182 |
183 | // Initialize some variables
184 | this.pages = [];
185 | this.pdf = null;
186 |
187 | // Whether the document is ready or not
188 | this._documentReady = false;
189 | }
190 |
191 | /**
192 | * Sets the current zoom level and applies it to all the pages
193 | * @param {number} zoom the desired zoom level, which will be a value (1 equals to 100%), or the keywords 'in', 'out', 'width', 'height' or 'fit'
194 | */
195 | setZoom(zoom) {
196 | let container = this.$container.get(0);
197 |
198 | // Get the previous zoom and scroll position
199 | let prevzoom = this._zoom.current;
200 | let prevScroll = {
201 | top: container.scrollTop,
202 | left: container.scrollLeft
203 | };
204 |
205 | // Now zoom the pages
206 | this._zoom.zoomPages(zoom);
207 |
208 | // Update the scroll position (to match the previous one), according to the new relationship of zoom
209 | container.scrollLeft = prevScroll.left * this._zoom.current / prevzoom;
210 | container.scrollTop = prevScroll.top * this._zoom.current / prevzoom;
211 |
212 | // Force to redraw the visible pages to upgrade the resolution
213 | this._visiblePages(true);
214 |
215 | // Call the callback (if provided)
216 | if (this._documentReady) {
217 | if (typeof this.settings.onZoomChange === "function")
218 | this.settings.onZoomChange.call(this, this._zoom.current);
219 | this.$container.get(0).dispatchEvent(new CustomEvent("zoomchange", { detail: { zoom: this._zoom.current } }));
220 | }
221 |
222 | return this._zoom.current;
223 | }
224 |
225 | /**
226 | * Obtain the current zoom level
227 | * @returns {number} the current zoom level
228 | */
229 | getZoom() {
230 | return this._zoom.current;
231 | }
232 |
233 | /**
234 | * Function that removes the content of a page and replaces it with the empty content (i.e. a content generated by function emptyContent)
235 | * such content will not be visible except for the time that the
236 | * @param {jQuery} $page the page to be emptied
237 | */
238 | _cleanPage($page) {
239 | let $emptyContent = this.settings.emptyContent();
240 | $page.find(`.${this.settings.contentClass}`).html("").append($emptyContent)
241 | }
242 |
243 | /**
244 | * Function that replaces the content with the empty class in a page with a new content
245 | * @param {*} $page the page to be modified
246 | * @param {*} $content the new content that will be set in the page
247 | */
248 | _setPageContent($page, $content) {
249 | $page.find(`.${this.settings.contentClass}`).html("").append($content)
250 | }
251 |
252 | /**
253 | * Recalculates which pages are now visible and forces redrawing them (moreover it cleans those not visible)
254 | */
255 | refreshAll() {
256 | this._visiblePages(true);
257 | }
258 |
259 | /** Function that creates a scroll handler to update the active page and to load more pages as the scroll position changes */
260 | _setScrollListener() {
261 | // Create a scroll handler that prevents reentrance if called multiple times and the loading of pages is not finished
262 | let scrollLock = false;
263 | let scrollPos = { top:0 , left:0 };
264 | this.__scrollHandler = function(e) {
265 | // Avoid re-entrance for the same event while loading pages
266 | if (scrollLock === true) {
267 | return;
268 | }
269 | scrollLock = true;
270 |
271 | let container = this.$container.get(0);
272 | if ((Math.abs(container.scrollTop - scrollPos.top) > (container.clientHeight * 0.2 * this._zoom.current)) ||
273 | (Math.abs(container.scrollLeft - scrollPos.left) > (container.clientWidth * 0.2 * this._zoom.current))) {
274 | scrollPos = {
275 | top: container.scrollTop,
276 | left: container.scrollLeft
277 | }
278 | this._visiblePages();
279 | }
280 |
281 | scrollLock = false;
282 | }.bind(this);
283 |
284 | // Set the scroll handler
285 | this.$container.off('scroll');
286 | this.$container.on('scroll', this.__scrollHandler);
287 | }
288 | /**
289 | * Function that creates the pageinfo structure for one page, along with the skeleton to host the page (i.e. )
290 | * If the page is a pageinfo, the new pageinfo structure will not rely on the size (it will copy it, but it won't be marked as loaded). If it is a page, the size will
291 | * be calculated from the viewport and it will be marked as loaded.
292 | * This is done in this way, because when creating the pages in the first time, they will be created assuming that they are of the same size than the first one. If they
293 | * are not, the size will be adjusted later, when the pages are loaded.
294 | *
295 | * @param {*} page - the pageinfo (or the page) from which to create the pageinfo structure
296 | * @param {*} i - the number of the page to be created
297 | * @returns pageinfo - the pageinfo structure for the page
298 | */
299 | _createSkeleton(page, i) {
300 | let pageinfo = {
301 | $div: null,
302 | width: 0,
303 | height: 0,
304 | loaded: false,
305 | };
306 |
307 | // If it is a page, the size will be obtained from the viewport; otherwise, it will be copied from the provided pageinfo
308 | if (page.getViewport !== undefined) {
309 | let viewport = page.getViewport({rotation:this._rotation,scale:1});
310 | pageinfo.width = viewport.width;
311 | pageinfo.height = viewport.height;
312 | pageinfo.loaded = true;
313 | } else {
314 | pageinfo.width = page.width;
315 | pageinfo.height = page.height;
316 | }
317 | console.assert(((pageinfo.width > 0) && (pageinfo.height > 0)), "Page width and height must be greater than 0");
318 |
319 | // Now create the skeleton for the divs
320 | pageinfo.$div = $(``)
321 | .attr('data-page', i)
322 | .data('width', pageinfo.width)
323 | .data('height', pageinfo.height)
324 | .data('zoom', this._zoom.current)
325 | .addClass(this.settings.pageClass)
326 | .width(pageinfo.width * this._zoom.current)
327 | .height(pageinfo.height * this._zoom.current);
328 |
329 | let $content = $(`
`)
330 | .width(pageinfo.width)
331 | .height(pageinfo.height);
332 |
333 | pageinfo.$div.append($content);
334 |
335 | // Clean the page (i.e. put the empty content, etc.)
336 | this._cleanPage(pageinfo.$div);
337 |
338 | return pageinfo;
339 | }
340 |
341 | /**
342 | * This function places the page.$div in the container, according to its page number (i.e. it searches for the previous page and puts this page after)
343 | * * in principle, this method sould not be needed because all the pages are put in order; but this is created just in case it is needed in further versions
344 | * @param {*} pageinfo - the pageinfo structure for the page (needs a valid $div)
345 | * @param {*} i - the number of the page
346 | */
347 | _placeSkeleton(pageinfo, i) {
348 | let prevpage = i - 1;
349 | let $prevpage = null;
350 | while ((prevpage>0) && (($prevpage = this.$container.find(`.${this.settings.pageClass}[data-page="${prevpage}"]`)).length === 0)) {
351 | prevpage--;
352 | }
353 | if (prevpage === 0) {
354 | this.$container.append(pageinfo.$div);
355 | }
356 | else {
357 | $prevpage.after(pageinfo.$div);
358 | }
359 | }
360 |
361 | /**
362 | * Creates the initial skeletons for all the pages, and places them into the container
363 | * @param {page/pageinfo} pageinfo - the initial pageinfo (or page) structure
364 | */
365 | _createSkeletons(pageinfo) {
366 | for (let i = 1; i <= this.pageCount; i++) {
367 | if (this.pages[i] === undefined) {
368 |
369 | // Create the pageinfo structure, store it and place it in the appropriate place (the next page will be created similar to the previous one)
370 | pageinfo = this._createSkeleton(pageinfo, i);
371 | this.pages[i] = pageinfo;
372 | this._placeSkeleton(pageinfo, i);
373 |
374 | // Call the callback function (if provided)
375 | if (typeof this.settings.onNewPage === "function") {
376 | this.settings.onNewPage.call(this, pageinfo.$div.get(0), i);
377 | }
378 | this.$container.get(0).dispatchEvent(new CustomEvent("newpage", { detail: { pageNumber: i, page: pageinfo.$div.get(0) } }));
379 | }
380 | }
381 | }
382 |
383 | /**
384 | * Function to set the active page, and calling the callback (if provided)
385 | * @param {*} i - the number of the page to set active
386 | */
387 | _setActivePage(i) {
388 | if (this._activePage !== i) {
389 | this._activePage = i;
390 | let activePage = this.getActivePage();
391 | if (this._documentReady) {
392 | activePage = activePage==null?null:activePage.get(0);
393 | if (typeof this.settings.onActivePageChanged === "function") {
394 | this.settings.onActivePageChanged.call(this, activePage, i);
395 | }
396 | this.$container.get(0).dispatchEvent(new CustomEvent("activepagechanged", { detail: { activePageNumber: i, activePage: activePage } }));
397 | }
398 | }
399 | }
400 |
401 | /**
402 | * Obtains the area of a div that falls in the viewer
403 | * @param {*} $page - div whose area is to be calculated
404 | * @returns the visible area
405 | */
406 | _areaOfPageVisible($page) {
407 | if ($page === undefined) {
408 | return 0;
409 | }
410 | let c_offset = this.$container.offset();
411 | let c_width = this.$container.width();
412 | let c_height = this.$container.height();
413 | let position = $page.offset();
414 | position.top -= c_offset.top;
415 | position.left -= c_offset.left;
416 | position.bottom = position.top + $page.outerHeight();
417 | position.right = position.left + $page.outerWidth();
418 | let page_y0 = Math.min(Math.max(position.top, 0), c_height);
419 | let page_y1 = Math.min(Math.max($page.outerHeight() + position.top, 0), c_height);
420 | let page_x0 = Math.min(Math.max(position.left, 0), c_width);
421 | let page_x1 = Math.min(Math.max($page.outerWidth() + position.left, 0), c_width);
422 | let vis_x = page_x1 - page_x0;
423 | let vis_y = page_y1 - page_y0;
424 | return (vis_x * vis_y);
425 | }
426 |
427 | /**
428 | * Function that returns true if the page is considered to be visible (the amount of visible area is greater than the threshold)
429 | * @param {*} i - the number of page to check
430 | * @returns true if the page is visible
431 | */
432 | isPageVisible(i) {
433 | if ((this.pdf === null) || (i === undefined) || (i === null) || (i < 1) || (i > this.pdf.numPages)) {
434 | return false;
435 | }
436 | if (typeof i === "string") {
437 | i = parseInt(i);
438 | }
439 | let $page = i;
440 | if (typeof i === "number") {
441 | if (this.pages[i] === undefined)
442 | return false;
443 | $page = this.pages[i].$div;
444 | }
445 | return this._areaOfPageVisible($page) > ($page.outerWidth() * $page.outerHeight() * this.settings.visibleThreshold);
446 | }
447 |
448 | /**
449 | * Function that calculates which pages are visible in the viewer, draws them (if not already drawn), and clears those not visible
450 | * @param {*} forceRedraw - if true, the visible pages will be redrawn regardless of whether they are already drawn (useful for zoom changes)
451 | */
452 | _visiblePages(forceRedraw = false) {
453 | // Will grab the page with the greater visible area to set it as active
454 | let max_area = 0;
455 | let i_page = null;
456 |
457 | // If there are no visible pages, return
458 | if (this.pages.length === 0) {
459 | this._visibles = [];
460 | this._setActivePage(0);
461 | return;
462 | }
463 |
464 | // Calculate the visible area for each page and consider it visible if the visible area is greater than 0
465 | let $visibles = this.pages.filter(function(pageinfo) {
466 | let areaVisible = this._areaOfPageVisible(pageinfo.$div);
467 | if (areaVisible > max_area) {
468 | max_area = areaVisible;
469 | i_page = pageinfo.$div.data('page');
470 | }
471 | return areaVisible > 0;
472 | }.bind(this)).map((x) => x.$div);
473 |
474 | // Set the active page
475 | this._setActivePage(i_page);
476 |
477 | // Now get the visible pages
478 | let visibles = $visibles.map((x) => {
479 | return parseInt($(x).data('page'))
480 | });
481 | if (visibles.length > 0) {
482 | // Now will add some extra pages (before and after) the visible ones, to have them prepared in case of scroll
483 | let minVisible = Math.min(...visibles);
484 | let maxVisible = Math.max(...visibles);
485 |
486 | for (let i = Math.max(1, minVisible - this.settings.extraPagesToLoad) ; i < minVisible ; i++) {
487 | if (!visibles.includes(i))
488 | visibles.push(i)
489 | }
490 | for (let i = maxVisible + 1; i <= Math.min(maxVisible + this.settings.extraPagesToLoad, this.pdf.numPages); i++) {
491 | if (!visibles.includes(i))
492 | visibles.push(i)
493 | }
494 | }
495 |
496 | // Now will draw the visible pages, but if not forcing, will only draw those that were not visible before
497 | let nowVisibles = visibles;
498 | if (! forceRedraw) {
499 | nowVisibles = visibles.filter(function (x) {
500 | return !this._visibles.includes(x)
501 | }.bind(this));
502 | }
503 |
504 | // Get the pages that were visible before, that are not visible now, and clear them
505 | this._visibles.filter(function (x) {
506 | return !visibles.includes(x)
507 | }).forEach(function (i) {
508 | this._cleanPage(this.pages[i].$div);
509 | }.bind(this))
510 |
511 | // Store the new visible pages
512 | this._visibles = visibles;
513 |
514 | // And now we'll queue the pages to load
515 | this.loadPages(...nowVisibles);
516 | }
517 |
518 | /**
519 | * Function queue a set of pages to be loaded; if not loading, the function starts the loading worker
520 | * @param {...pageinfo} pages - the pages to load
521 | */
522 | loadPages(...pages) {
523 | this._pagesLoading.push(...pages);
524 | if (this._loading) {
525 | return;
526 | }
527 | this._loadingTask();
528 | }
529 |
530 | /**
531 | * Function that gets the pages pending to load and renders them sequentially (to avoid multiple rendering promises)
532 | */
533 | _loadingTask() {
534 | this._loading = true;
535 | if (this._pagesLoading.length > 0) {
536 | let pagei = this._pagesLoading.shift();
537 | this.pdf.getPage(pagei).then(function(page) {
538 | // Render the page and update the information about the page with the loaded values
539 | this._renderPage(page, pagei);
540 | }.bind(this)).then(function(pageinfo) {
541 | // Once loaded, we are not loading anymore
542 | if (this._pagesLoading.length > 0) {
543 | this._loadingTask();
544 | }
545 | }.bind(this));
546 | }
547 | // Free the loading state
548 | this._loading = false;
549 | }
550 |
551 | /**
552 | * Function that sets the scroll position of the container to the specified page
553 | * @param {*} i - the number of the page to set the scroll position
554 | */
555 | scrollToPage(i) {
556 | if ((this.pages.length === 0) || (this.pages[i] === undefined)) {
557 | return;
558 | }
559 | let $page = this.pages[i].$div;
560 | if ($page.length === 0) {
561 | console.warn(`Page ${i} not found`);
562 | return;
563 | }
564 | let position = $page.position();
565 | let containerPosition = this.$container.position();
566 | if (position !== undefined) {
567 | this.$container.get(0).scrollTop = this.$container.get(0).scrollTop + position.top - containerPosition.top;
568 | this.$container.get(0).scrollLeft = this.$container.get(0).scrollLeft + position.left - containerPosition.left;
569 | }
570 | this._setActivePage(i);
571 | }
572 |
573 | /**
574 | * Function that renders the page in a canvas, and sets the canvas into the $div
575 | * @param {*} page - the page to be rendered
576 | * @param {*} i - the number of the page to be rendered
577 | * @returns a promise to render the page (the result of the promise will be the pageinfo)
578 | */
579 | _renderPage(page, i) {
580 | // Get the pageinfo structure
581 | let pageinfo = this.pages[i];
582 | let scale = this.settings.renderingScale;
583 |
584 | // Calculate the pixel ratio of the device (we'll use a minimum of 1)
585 | let pixel_ratio = window.devicePixelRatio || 1;
586 | // Update the information that we know about the page to the actually loaded page
587 | let viewport = page.getViewport({rotation: this._rotation, scale: this._zoom.current * scale});
588 | pageinfo.width = (viewport.width / this._zoom.current) / scale;
589 | pageinfo.height = (viewport.height / this._zoom.current) / scale;
590 | pageinfo.$div.data("width", pageinfo.width);
591 | pageinfo.$div.data("height", pageinfo.height);
592 | pageinfo.$div.width(pageinfo.width * this._zoom.current);
593 | pageinfo.$div.height(pageinfo.height * this._zoom.current);
594 | pageinfo.loaded = true;
595 |
596 | // Create the canvas and prepare the rendering context
597 | let $canvas = $('');
598 | let canvas = $canvas.get(0);
599 | let context = canvas.getContext('2d');
600 | canvas.height = viewport.height * pixel_ratio;
601 | canvas.width = viewport.width * pixel_ratio;
602 | canvas.getContext("2d")//.scale(pixel_ratio, pixel_ratio);
603 | var transform = pixel_ratio !== 1
604 | ? [pixel_ratio, 0, 0, pixel_ratio, 0, 0]
605 | : null;
606 | var renderContext = {
607 | canvasContext: context,
608 | viewport: viewport,
609 | transform: transform,
610 | };
611 |
612 | // Render the page and put the resulting rendered canvas into the page $div
613 | return page.render(renderContext).promise.then(function() {
614 | this._setPageContent(pageinfo.$div, $canvas);
615 |
616 | // Call the callback (if provided)
617 | if (this._documentReady) {
618 | if (typeof this.settings.onPageRender === "function") {
619 | this.settings.onPageRender.call(this, pageinfo.$div.get(0), i);
620 | }
621 | this.$container.get(0).dispatchEvent(new CustomEvent("pagerender", { detail: { pageNumber: i, page: pageinfo.$div.get(0) } }));
622 | }
623 | return pageinfo;
624 | }.bind(this));
625 | }
626 |
627 | /** Gets the div object corresponding to the active page */
628 | getActivePage() {
629 | if ((this._activePage === null) || (this.pdf === null)) {
630 | return null;
631 | }
632 | if ((this._activePage < 1) || (this._activePage > this.pdf.numPages)) {
633 | return null;
634 | }
635 | return this.pages[this._activePage].$div;
636 | }
637 |
638 | /** Gets all the pages of the document (the pageinfo structures) */
639 | getPages() {
640 | return this.pages;
641 | }
642 |
643 | /** Gets the number of pages of the document */
644 | getPageCount() {
645 | if (this.pdf === null) {
646 | return 0;
647 | }
648 | return this.pdf.numPages;
649 | }
650 |
651 | /** Scrolls to the next page (if any) */
652 | next() {
653 | if (this._activePage < this.pdf.numPages) {
654 | this.scrollToPage(this._activePage + 1);
655 | }
656 | }
657 |
658 | /** Scrolls to the previous page (if any) */
659 | prev() {
660 | if (this._activePage > 1) {
661 | this.scrollToPage(this._activePage - 1);
662 | }
663 | }
664 |
665 | first() {
666 | if (this._activePage !== 1) {
667 | this.scrollToPage(1);
668 | }
669 | }
670 |
671 | last() {
672 | if (this.pdf === null)
673 | return;
674 | if (this._activePage !== this.pdf.numPages) {
675 | this.scrollToPage(this.pdf.numPages);
676 | }
677 | }
678 | /**
679 | * Rotates the pages of the document
680 | * @param {*} deg - degrees to rotate the pages
681 | * @param {*} accumulate - whether the rotation is accumulated or not
682 | */
683 | rotate(deg, accumulate = false) {
684 | if (accumulate) {
685 | deg = deg + this._rotation;
686 | }
687 | this._rotation = deg;
688 |
689 | let container = this.$container.get(0);
690 | let prevScroll = {
691 | top: container.scrollTop,
692 | left: container.scrollLeft,
693 | height: container.scrollHeight,
694 | width: container.scrollWidth
695 | };
696 |
697 | return this.forceViewerInitialization().then(function() {
698 | let newScroll = {
699 | top: container.scrollTop,
700 | left: container.scrollLeft,
701 | height: container.scrollHeight,
702 | width: container.scrollWidth
703 | };
704 | container.scrollTop = prevScroll.top * (newScroll.height / prevScroll.height);
705 | container.scrollLeft = prevScroll.left * (newScroll.width / prevScroll.width);
706 | }.bind(this));
707 | }
708 | /**
709 | * This functions forces the creation of the whole content of the viewer (i.e. new divs, structures, etc.). It is usefull for full refresh of the viewer (e.g. when changes
710 | * the rotation of the pages)
711 | * @returns a promise that is resolved when the viewer is fully initialized
712 | */
713 | forceViewerInitialization() {
714 | // Store the pdf file
715 | // Now prepare a placeholder for the pages
716 | this.pages = [];
717 |
718 | // Remove all the pages
719 | this.$container.find(`.${this.settings.pageClass}`).remove();
720 |
721 | this._pagesLoading = [];
722 | this._loading = false;
723 | this._visibles = [];
724 | this._activePage = null;
725 | return this.pdf.getPage(1).then(function(page) {
726 | this._createSkeletons(page);
727 | this._visiblePages();
728 | this._setActivePage(1);
729 | }.bind(this));
730 | }
731 | /**
732 | * Loads the document and creates the pages
733 | * @param {string} document - the url of the document to load
734 | */
735 | async loadDocument(document) {
736 | // The document is not ready while loading
737 | this._documentReady = false;
738 |
739 | // Now prepare a placeholder for the pages
740 | this.pages = [];
741 |
742 | // Remove all the pages
743 | this.$container.find(`.${this.settings.pageClass}`).remove();
744 |
745 | // Let's free the pdf file (if there was one before), and rely on the garbage collector to free the memory
746 | this.pdf = null;
747 |
748 | // Load the task and return the promise to load the document
749 | let loadingTask = pdfjsLib.getDocument(document);
750 | return loadingTask.promise.then(function(pdf) {
751 | // Store the pdf file and get the
752 | this.pdf = pdf;
753 | this.pageCount = pdf.numPages;
754 | this._rotation = 0;
755 | return this.forceViewerInitialization();
756 | }.bind(this)).then(function() {
757 | if (typeof this.settings.onDocumentReady === "function") {
758 | this.settings.onDocumentReady.call(this);
759 | }
760 | this.$container.get(0).dispatchEvent(new CustomEvent("documentready", { detail: { document: this.pdf } }));
761 |
762 | // This is a trick to force active page changed event triggering after the document is ready
763 | this._setActivePage(0)
764 | this._documentReady = true;
765 | this._setActivePage(1)
766 | }.bind(this));
767 | }
768 | }
769 |
770 | function recoverAttributes(target, attributeDefaults) {
771 | const camelcaseToSnakecase = str => str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);
772 | let $target = $(target);
773 | let result = {};
774 | if ($target.length > 0) {
775 | $target = $($target[0]);
776 | for (let originalAttributeName in attributeDefaults) {
777 | let attributeName = camelcaseToSnakecase(originalAttributeName)
778 | let attributeValue = $target.attr(attributeName);
779 | if (attributeValue != null) {
780 | switch (typeof(attributeDefaults[originalAttributeName])) {
781 | case 'float':
782 | try {
783 | attributeValue = parseFloat(attributeValue);
784 | } catch (_) {
785 | }
786 | break;
787 | case 'number':
788 | try {
789 | attributeValue = parseInt(attributeValue);
790 | } catch (_) {
791 | }
792 | break;
793 | case 'function':
794 | let functionString = attributeValue;
795 | attributeValue = function() { eval(functionString); }.bind(target[0]); break;
796 | default:
797 | break;
798 | }
799 | result[originalAttributeName] = attributeValue;
800 | }
801 | };
802 | }
803 | return result;
804 | }
805 |
806 | function init(element) {
807 | let options = recoverAttributes(element, Object.assign({
808 | pdfDocument: "", initialZoom: ""
809 | }, defaults));
810 | if (options["pdfDocument"] != null) {
811 | let pdfViewer = new PDFjsViewer($(element), options);
812 | pdfViewer.loadDocument(options["pdfDocument"]).then(function() {
813 | if (options["initialZoom"] != null) {
814 | pdfViewer.setZoom(options["initialZoom"]);
815 | }
816 | })
817 | element.get(0).pdfViewer = pdfViewer;
818 | }
819 | }
820 |
821 | $(function() {
822 | $('.pdfjs-viewer').each(function() {
823 | let $viewer = $(this);
824 | init($viewer);
825 | })
826 | });
827 |
828 | exports.PDFjsViewer = PDFjsViewer;
829 | })(window, window._$??window.jQuery??undefined);
--------------------------------------------------------------------------------