wickes-css2 2.113.0 → 2.117.0-develop.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +1 -1
- package/build/css/category-main.css +1 -1
- package/build/css/components/checkout-payment-details-v2.css +1 -1
- package/build/css/components/checkout-payment-repayment-terms.css +1 -1
- package/build/css/components/price-block-v2-critical.css +1 -1
- package/build/css/components/price-block-v2.css +1 -1
- package/build/css/kitchen-plp-main.css +1 -1
- package/build/css/main.css +1 -1
- package/build/css/my-account-main-v2.css +1 -1
- package/build/css/my-account-main.css +1 -1
- package/build/css/pages/checkout-new.css +1 -1
- package/build/css/pages/checkout.css +1 -1
- package/build/css/pages/page_checkout_delivery-new.css +1 -1
- package/build/css/pages/page_product-details-v2-critical.css +1 -1
- package/build/css/pages/page_product-details-v2.css +1 -1
- package/build/css/pages/page_product-details.css +1 -1
- package/build/css/pages/page_products-list-combined.css +1 -1
- package/build/css/pages/page_products-list_v2.css +1 -1
- package/build/css/pages/tradePro-signup.css +1 -1
- package/build/css/pdp-main-before-combine.css +1 -1
- package/build/css/pdp-main-critical.css +1 -1
- package/build/css/pdp-main-non-critical.css +1 -1
- package/build/css/pdp-main.css +1 -1
- package/build/css/plp-main.css +1 -1
- package/build/css/store-locator-main.css +1 -1
- package/build/img/file-pdf-solid-full.svg +3 -0
- package/build/img/lorem_ipsum.pdf +150 -0
- package/build/js/account-members.min.js +1 -1
- package/build/js/add-project-list-id.min.js +1 -1
- package/build/js/address-book.min.js +1 -1
- package/build/js/basket.min.js +2 -2
- package/build/js/bloomreach-widget.min.js +1 -1
- package/build/js/bundle.min.js +1 -1
- package/build/js/change-password.min.js +1 -1
- package/build/js/checkout.min.js +2 -2
- package/build/js/emulation.min.js +400 -192
- package/build/js/general.bundle.min.js +1 -1
- package/build/js/gift-cards.min.js +1 -1
- package/build/js/kitchen/kitchen-plp.min.js +1 -1
- package/build/js/merged-checkout.min.js +2 -2
- package/build/js/package-bulk-add.min.js +1 -0
- package/build/js/page/bloomreach-widget/bloomreach-recommendation-carousel-widget.js +7 -6
- package/build/js/page/bloomreach-widget/bloomreach-widget-core.js +47 -27
- package/build/js/page/bloomreach-widget/bloomreach-widget.js +5 -0
- package/build/js/page/bloomreach-widget/complete-your-project/view.js +11 -6
- package/build/js/page/bloomreach-widget/complete-your-project/widget.js +0 -1
- package/build/js/page/bloomreach-widget/similar-products-widget.js +17 -0
- package/build/js/page/plp-load-more.js +81 -66
- package/build/js/page/ripple/bulk-add.js +71 -0
- package/build/js/page/ripple/package-bulk-add.js +43 -0
- package/build/js/page/ripple/postcode-checker.js +83 -0
- package/build/js/page/ripple/thumb-gallery.js +236 -0
- package/build/js/page/utils/validation.js +1 -1
- package/build/js/pdf-preview.min.js +1 -0
- package/build/js/pdp.bundle.min.js +2 -2
- package/build/js/personal-details.min.js +1 -1
- package/build/js/plp.bundle.min.js +1 -1
- package/build/js/postcode-checker.min.js +1 -0
- package/build/js/project-list.min.js +2 -2
- package/build/js/quiz.min.js +1 -1
- package/build/js/track-my-order.min.js +1 -1
- package/package.json +1 -1
- package/src/badges-ripple.html +120 -0
- package/src/badges.html +9 -18
- package/src/components/bloomreach/complete-card.hbs +1 -1
- package/src/components/bloomreach/why-not-add-card.hbs +26 -7
- package/src/components/bloomreach/why-not-add.hbs +1 -1
- package/src/components/fulfilment-accordions.hbs +1 -1
- package/src/components/image-accordion.hbs +18 -0
- package/src/components/kitchen/price.hbs +49 -29
- package/src/components/kitchen/strip-stickers.hbs +9 -3
- package/src/components/modal-capture.hbs +1 -1
- package/src/components/modal-id-type.hbs +271 -0
- package/src/components/modal-pdf-preview.hbs +70 -0
- package/src/components/package-card.hbs +30 -0
- package/src/components/partner-signup-form.hbs +1 -231
- package/src/components/pdp-price-actions.hbs +17 -0
- package/src/components/postcode-checker.hbs +24 -0
- package/src/components/price-badges.hbs +12 -10
- package/src/components/price-block-v2.hbs +289 -199
- package/src/components/product-main-info-v2.hbs +2 -0
- package/src/components/suite-includes.hbs +66 -0
- package/src/components/suite-product-card.hbs +47 -0
- package/src/components/thumb-gallery.hbs +23 -0
- package/src/data/data_badges.json +143 -0
- package/src/data/data_bathroom-plp.json +814 -0
- package/src/data/data_suite-includes-products.json +134 -0
- package/src/img/file-pdf-solid-full.svg +3 -0
- package/src/img/lorem_ipsum.pdf +150 -0
- package/src/js/components/banner-placement-manager.js +25 -9
- package/src/js/components/general/image-accordion.js +54 -0
- package/src/js/components/general/switchVat.js +8 -1
- package/src/js/components/package-card.js +69 -0
- package/src/js/components/store-locator-cards.js +76 -0
- package/src/js/emulation/banner-placement-manager.js +219 -188
- package/src/js/emulation/bloomreach-widget-calculations.js +1 -1
- package/src/js/emulation/mock.js +66 -34
- package/src/js/emulation/plp-load-more.js +13 -4
- package/src/js/emulation/postcode-checker.js +11 -0
- package/src/js/emulation/similar-products-loading.js +22 -0
- package/src/js/emulation/tradepro-id-pdf.js +182 -0
- package/src/js/libs/pdf-preview.js +1177 -0
- package/src/js/page/bloomreach-widget/bloomreach-recommendation-carousel-widget.js +7 -6
- package/src/js/page/bloomreach-widget/bloomreach-widget-core.js +47 -27
- package/src/js/page/bloomreach-widget/bloomreach-widget.js +5 -0
- package/src/js/page/bloomreach-widget/complete-your-project/view.js +11 -6
- package/src/js/page/bloomreach-widget/complete-your-project/widget.js +0 -1
- package/src/js/page/bloomreach-widget/similar-products-widget.js +17 -0
- package/src/js/page/plp-load-more.js +81 -66
- package/src/js/page/ripple/bulk-add.js +71 -0
- package/src/js/page/ripple/package-bulk-add.js +43 -0
- package/src/js/page/ripple/postcode-checker.js +83 -0
- package/src/js/page/ripple/thumb-gallery.js +236 -0
- package/src/js/page/utils/validation.js +1 -1
- package/src/page_bathroom-plp-vat.html +81 -0
- package/src/page_bathroom-plp-without-load-more.html +83 -0
- package/src/page_bathroom-plp.html +98 -0
- package/src/page_checkout_confirmation-billie.html +5 -231
- package/src/page_checkout_confirmation-clearpay.html +5 -231
- package/src/page_checkout_confirmation-new-apple.html +5 -231
- package/src/page_checkout_confirmation-new-google.html +5 -231
- package/src/page_checkout_confirmation-new-klarna.html +5 -231
- package/src/page_checkout_confirmation-new-paypal.html +5 -231
- package/src/page_checkout_delivery-details-v2-calendar-not-loaded.html +167 -0
- package/src/page_checkout_payment-details-v2-asm.html +2 -3
- package/src/page_checkout_payment-details-v2.html +2 -3
- package/src/page_checkout_payment-details_with-card-loader.html +2 -3
- package/src/page_checkout_payment-details_with-klarna-loader.html +2 -3
- package/src/page_checkout_payment-details_with-loader-v2.html +2 -3
- package/src/page_klarna_payment-details_with-klarna.html +2 -3
- package/src/page_payment-details-billie-registered-only.html +2 -3
- package/src/page_payment-details-billie-unregistered-only.html +2 -3
- package/src/page_payment-details-with-billie.html +2 -3
- package/src/page_payment-details-with-clearpay.html +2 -3
- package/src/page_payment-details-with-gift-card.html +2 -3
- package/src/page_payment-details_with_apple-pay.html +0 -1
- package/src/page_payment-details_with_google-pay.html +2 -3
- package/src/page_pdf-preview-example.html +955 -0
- package/src/page_product-details-banner.html +1 -3
- package/src/page_product-details-big-wins-disabled-delivery.html +1 -3
- package/src/page_product-details-big-wins-non-registered.html +1 -3
- package/src/page_product-details-big-wins-out-nearest.html +1 -3
- package/src/page_product-details-big-wins-unhappy.html +1 -3
- package/src/page_product-details-big-wins.html +1 -3
- package/src/page_product-details-billie.html +1 -3
- package/src/page_product-details-calculator.html +1 -3
- package/src/page_product-details-cashback-v2.html +1 -3
- package/src/page_product-details-clearpay.html +1 -3
- package/src/page_product-details-cnc-error-notification.html +1 -3
- package/src/page_product-details-cnc-success-notification-vat.html +1 -4
- package/src/page_product-details-cnc-success-notification.html +1 -3
- package/src/page_product-details-default-store.html +1 -3
- package/src/page_product-details-energy-efficiency.html +1 -3
- package/src/page_product-details-flooring-with-pr-placeholder.html +1 -3
- package/src/page_product-details-flooring.html +1 -3
- package/src/page_product-details-gallery-actual.html +1 -3
- package/src/page_product-details-mfe-calculator.html +1 -3
- package/src/page_product-details-mtm-doors.html +1 -3
- package/src/page_product-details-only-clearpay.html +1 -3
- package/src/page_product-details-paint-mixing.html +1 -3
- package/src/page_product-details-ripple-gallery-1-image.html +120 -0
- package/src/page_product-details-ripple-gallery-missing-image.html +121 -0
- package/src/page_product-details-ripple-gallery.html +121 -0
- package/src/page_product-details-saved-pl.html +1 -3
- package/src/page_product-details-suite-includes-banners.html +139 -0
- package/src/page_product-details-suite-includes-billie.html +128 -0
- package/src/page_product-details-suite-includes-klarna.html +120 -0
- package/src/page_product-details-suite-includes-vat.html +126 -0
- package/src/page_product-details-suite-includes.html +122 -0
- package/src/page_product-details-tile-steps-klarna-widget-with-method-ids.html +1 -3
- package/src/page_product-details-tile-steps-logout.html +1 -3
- package/src/page_product-details-tile-steps-no-new-project-list.html +1 -3
- package/src/page_product-details-tile-steps-with-klarna.html +1 -3
- package/src/page_product-details-tile-steps.html +1 -3
- package/src/page_product-details-v2.html +1 -3
- package/src/page_product-details-vat.html +1 -3
- package/src/page_product-details-wisdom-mcfc-registered.html +1 -3
- package/src/page_product-details-wisdom-mcfc.html +1 -3
- package/src/page_product-details-wisdom-oos-registered.html +1 -3
- package/src/page_product-details-wisdom-oos.html +1 -3
- package/src/page_product-details-wisdom-registered.html +1 -3
- package/src/page_product-details-wisdom.html +1 -3
- package/src/page_product-details-with-favourite.html +1 -3
- package/src/page_product-details-with-global-search-v2.html +2 -3
- package/src/page_product-details-with-similar-products-widget.html +132 -0
- package/src/page_product-details-with-why-not-add-single.html +1 -0
- package/src/page_product-details_no-previous-default.html +1 -3
- package/src/page_tradePro-checkout-summary-klarna.html +4 -231
- package/src/page_tradePro-checkout-summary.html +4 -231
- package/src/page_tradePro-signup.html +5 -0
- package/src/scss/common/_loading-button.scss +3 -1
- package/src/scss/components/_date-selection-add-new-styles.scss +53 -3
- package/src/scss/components/_gift-cards.scss +1 -1
- package/src/scss/components/_id-type-modal.scss +39 -0
- package/src/scss/components/_image-accordion.scss +54 -0
- package/src/scss/components/_kitchen-card.scss +1 -0
- package/src/scss/components/_map.scss +38 -0
- package/src/scss/components/_package-card.scss +65 -0
- package/src/scss/components/_package-plp.scss +88 -0
- package/src/scss/components/_pdf-preview-modal.scss +122 -0
- package/src/scss/components/_postcode-checker.scss +115 -0
- package/src/scss/components/_price-badges-critical.scss +10 -0
- package/src/scss/components/_price-badges.scss +10 -0
- package/src/scss/components/_price-block-critical.scss +1 -0
- package/src/scss/components/_price-block.scss +1 -0
- package/src/scss/components/_suite-includes.scss +141 -0
- package/src/scss/components/_suite-product-card.scss +98 -0
- package/src/scss/components/_thumb-gallery-critical.scss +35 -0
- package/src/scss/components/_thumb-gallery.scss +200 -0
- package/src/scss/components/bloomreach/_why-not-add.scss +3 -1
- package/src/scss/components/checkout-payment-details-v2.scss +44 -20
- package/src/scss/components/checkout-payment-repayment-terms.scss +0 -1
- package/src/scss/components/kitchen/_price.scss +10 -0
- package/src/scss/components/kitchen/_strip-stickers.scss +46 -0
- package/src/scss/components/price-block-v2-critical.scss +62 -0
- package/src/scss/components/price-block-v2.scss +62 -0
- package/src/scss/pages/_checkout-tradepro.scss +1 -0
- package/src/scss/pages/_checkout_delivery-details.scss +16 -104
- package/src/scss/pages/page_checkout_delivery-new.scss +252 -164
- package/src/scss/pages/page_product-details-v2-critical.scss +216 -109
- package/src/scss/pages/page_product-details-v2.scss +168 -107
- package/src/scss/pages/page_product-details.scss +11 -0
- package/src/scss/pages/page_products-list-combined.scss +8 -6
- package/src/scss/pages/page_products-list_v2.scss +8 -6
- package/src/scss/pages/tradePro-signup.scss +1 -0
- package/src/scss/pdp-main-critical.scss +1 -0
- package/src/scss/pdp-main.scss +6 -0
- package/src/scss/plp-main.scss +5 -0
- package/src/sitemap.html +30 -6
- package/build/css/components/kitchen/strip-stickers.css +0 -1
- package/build/css/components/strip-stickers.css +0 -1
- package/src/scss/components/kitchen/strip-stickers.scss +0 -18
- package/src/scss/components/strip-stickers.scss +0 -18
|
@@ -0,0 +1,1177 @@
|
|
|
1
|
+
/* eslint-env amd */
|
|
2
|
+
/*!
|
|
3
|
+
* PdfPreview - a small, dependency-free PDF preview with pagination.
|
|
4
|
+
*
|
|
5
|
+
* Renders a PDF into a container as one canvas per page, and wires up optional
|
|
6
|
+
* navigation controls. Brings no styling of its own: the consumer supplies the
|
|
7
|
+
* markup, the classes, and the CSS.
|
|
8
|
+
*
|
|
9
|
+
* pdf.js is the only dependency and is fetched from a CDN on first use, unless
|
|
10
|
+
* an instance of it is passed in or already present on the page.
|
|
11
|
+
*
|
|
12
|
+
* Quick start
|
|
13
|
+
* -----------
|
|
14
|
+
* <div id="preview">
|
|
15
|
+
* <button data-pdf-preview-prev>Prev</button>
|
|
16
|
+
* <input data-pdf-preview-page>
|
|
17
|
+
* / <span data-pdf-preview-total></span>
|
|
18
|
+
* <button data-pdf-preview-next>Next</button>
|
|
19
|
+
* <div data-pdf-preview-pages></div>
|
|
20
|
+
* </div>
|
|
21
|
+
*
|
|
22
|
+
* var preview = new PdfPreview('#preview');
|
|
23
|
+
* preview.load(fileOrBlobOrUrl);
|
|
24
|
+
*
|
|
25
|
+
* Constructing against an element that already has an instance returns that
|
|
26
|
+
* instance, so this is safe to call repeatedly. Options are read on first
|
|
27
|
+
* construction only; call destroy() first to rebuild with different ones.
|
|
28
|
+
*
|
|
29
|
+
* Declarative usage
|
|
30
|
+
* -----------------
|
|
31
|
+
* <div data-pdf-preview data-pdf-preview-src="doc.pdf"> ... </div>
|
|
32
|
+
* PdfPreview.initAll();
|
|
33
|
+
*
|
|
34
|
+
* Thumbnails
|
|
35
|
+
* ----------
|
|
36
|
+
* One page drawn to an offscreen canvas and handed back as a data URL, for use
|
|
37
|
+
* as the src of an <img>. No root element and no preview needed.
|
|
38
|
+
*
|
|
39
|
+
* PdfPreview.thumbnail(fileOrBlobOrUrl, { width: 120 }).then(function (thumb) {
|
|
40
|
+
* img.src = thumb.dataUrl;
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* PdfPreview.thumbnailInto(img, fileOrBlobOrUrl, { width: 120 });
|
|
44
|
+
*
|
|
45
|
+
* <img data-pdf-thumbnail data-pdf-thumbnail-src="doc.pdf" alt="First page">
|
|
46
|
+
* PdfPreview.initThumbnails();
|
|
47
|
+
*
|
|
48
|
+
* A preview that already has a document open can make one from it, without
|
|
49
|
+
* reading and parsing the file a second time:
|
|
50
|
+
*
|
|
51
|
+
* preview.getThumbnail({ width: 120 }).then(...);
|
|
52
|
+
*
|
|
53
|
+
* Thumbnail options
|
|
54
|
+
* -----------------
|
|
55
|
+
* width number width to draw the page at in CSS px, default 160
|
|
56
|
+
* height number height to draw the page at in CSS px, default none.
|
|
57
|
+
* With both, the page is fitted inside the box and
|
|
58
|
+
* keeps its aspect ratio
|
|
59
|
+
* page number page to draw, default 1, clamped to the document
|
|
60
|
+
* maxPixelRatio number as above, default 2
|
|
61
|
+
* type string image format, default 'image/jpeg'
|
|
62
|
+
* quality number quality for lossy formats, 0 to 1, default 0.85
|
|
63
|
+
* background string colour drawn behind the page, default '#ffffff'
|
|
64
|
+
* pdfjsLib, pdfjsUrl, pdfjsWorkerUrl as above
|
|
65
|
+
*
|
|
66
|
+
* Thumbnail events (dispatched on the <img>, bubbling)
|
|
67
|
+
* ----------------------------------------------------
|
|
68
|
+
* pdfthumbnail:loaded detail: { dataUrl, width, height, page, pageCount }
|
|
69
|
+
* pdfthumbnail:error detail: { error }
|
|
70
|
+
*
|
|
71
|
+
* Out of the box it injects a handful of base styles so the pages stack inside a
|
|
72
|
+
* scrolling viewport. These go in at the top of <head>, so any stylesheet on the
|
|
73
|
+
* page overrides them, and `injectStyles: false` turns them off entirely.
|
|
74
|
+
*
|
|
75
|
+
* Options
|
|
76
|
+
* -------
|
|
77
|
+
* scale number page size relative to the PDF's own size, used when
|
|
78
|
+
* fitWidth is false (or the container has no width
|
|
79
|
+
* yet), default 1.5
|
|
80
|
+
* pageClass string extra class set on every page canvas, default ''
|
|
81
|
+
* src string URL loaded immediately
|
|
82
|
+
* fitWidth boolean size pages to the container width, default true
|
|
83
|
+
* maxPixelRatio number cap on the device pixel ratio pages are rendered
|
|
84
|
+
* at, to bound memory on dense screens, default 2
|
|
85
|
+
* height number|string max-height of the scrolling viewport, any
|
|
86
|
+
* CSS length, default '50vh'. 'none' removes
|
|
87
|
+
* the cap. Bare numbers are treated as px.
|
|
88
|
+
* spacing number|string gap between pages and inset around them,
|
|
89
|
+
* default 16px. Bare numbers are treated as px.
|
|
90
|
+
* injectStyles boolean add the base layout styles, default true
|
|
91
|
+
* pdfjsLib object existing pdf.js instance, skips the CDN fetch
|
|
92
|
+
* pdfjsUrl string pdf.js script URL
|
|
93
|
+
* pdfjsWorkerUrl string pdf.js worker URL
|
|
94
|
+
* selectors object overrides for the markup hooks below
|
|
95
|
+
*
|
|
96
|
+
* Events (dispatched on the root element, all bubbling)
|
|
97
|
+
* -----------------------------------------------------
|
|
98
|
+
* pdfpreview:loaded detail: { pageCount }
|
|
99
|
+
* pdfpreview:pagechange detail: { page }
|
|
100
|
+
* pdfpreview:error detail: { error }
|
|
101
|
+
*/
|
|
102
|
+
(function (root, factory) {
|
|
103
|
+
if (typeof define === 'function' && define.amd) {
|
|
104
|
+
define([], factory);
|
|
105
|
+
} else if (typeof module === 'object' && module.exports) {
|
|
106
|
+
module.exports = factory();
|
|
107
|
+
} else {
|
|
108
|
+
root.PdfPreview = factory();
|
|
109
|
+
}
|
|
110
|
+
})(typeof self !== 'undefined' ? self : this, function () {
|
|
111
|
+
'use strict';
|
|
112
|
+
|
|
113
|
+
var DEFAULTS = {
|
|
114
|
+
scale: 1.5,
|
|
115
|
+
pageClass: '',
|
|
116
|
+
src: null,
|
|
117
|
+
fitWidth: true,
|
|
118
|
+
maxPixelRatio: 2,
|
|
119
|
+
height: '50vh',
|
|
120
|
+
spacing: null,
|
|
121
|
+
injectStyles: true,
|
|
122
|
+
pdfjsLib: null,
|
|
123
|
+
pdfjsUrl: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js',
|
|
124
|
+
pdfjsWorkerUrl: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js',
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Thumbnails share the pdf.js plumbing with previews but nothing else, so
|
|
128
|
+
// they get their own defaults rather than overloading the ones above.
|
|
129
|
+
var THUMBNAIL_DEFAULTS = {
|
|
130
|
+
width: 160,
|
|
131
|
+
height: null,
|
|
132
|
+
page: 1,
|
|
133
|
+
maxPixelRatio: DEFAULTS.maxPixelRatio,
|
|
134
|
+
// JPEG keeps the data URL small, which matters when it lives in an
|
|
135
|
+
// attribute. PDF pages are opaque, so there is no transparency to lose.
|
|
136
|
+
type: 'image/jpeg',
|
|
137
|
+
quality: 0.85,
|
|
138
|
+
background: '#ffffff',
|
|
139
|
+
pdfjsLib: DEFAULTS.pdfjsLib,
|
|
140
|
+
pdfjsUrl: DEFAULTS.pdfjsUrl,
|
|
141
|
+
pdfjsWorkerUrl: DEFAULTS.pdfjsWorkerUrl,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
var SELECTORS = {
|
|
145
|
+
root: '[data-pdf-preview]',
|
|
146
|
+
pages: '[data-pdf-preview-pages]',
|
|
147
|
+
first: '[data-pdf-preview-first]',
|
|
148
|
+
prev: '[data-pdf-preview-prev]',
|
|
149
|
+
next: '[data-pdf-preview-next]',
|
|
150
|
+
last: '[data-pdf-preview-last]',
|
|
151
|
+
pageInput: '[data-pdf-preview-page]',
|
|
152
|
+
pageTotal: '[data-pdf-preview-total]',
|
|
153
|
+
thumbnail: '[data-pdf-thumbnail]',
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Classes the library puts on its own elements. Prefixed to stay clear of
|
|
157
|
+
// whatever the consumer names things.
|
|
158
|
+
var CLASSES = {
|
|
159
|
+
pages: 'pdfp-pages',
|
|
160
|
+
page: 'pdfp-page',
|
|
161
|
+
pageAuto: 'pdfp-page--auto',
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
var STYLE_ID = 'pdf-preview-base-styles';
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The minimum needed for a usable document view: a scrolling viewport with
|
|
168
|
+
* pages stacked inside it. Decoration is left to the consumer, so this is
|
|
169
|
+
* inserted at the top of <head> and any stylesheet on the page outranks it.
|
|
170
|
+
*/
|
|
171
|
+
var BASE_STYLES =
|
|
172
|
+
'.' +
|
|
173
|
+
CLASSES.pages +
|
|
174
|
+
'{overflow-y:auto;overflow-x:hidden;max-height:var(--pdfp-height);scrollbar-gutter:stable;' +
|
|
175
|
+
'padding:var(--pdfp-spacing,16px);-webkit-overflow-scrolling:touch}' +
|
|
176
|
+
'.' +
|
|
177
|
+
CLASSES.page +
|
|
178
|
+
'{display:block;width:100%;height:auto;margin:0 auto}' +
|
|
179
|
+
// Canvases are rendered at a multiple of their display size for sharp
|
|
180
|
+
// output on dense screens, so natural-size pages need their CSS width
|
|
181
|
+
// set explicitly. The library supplies it as --pdfp-page-width.
|
|
182
|
+
'.' +
|
|
183
|
+
CLASSES.pageAuto +
|
|
184
|
+
'{width:var(--pdfp-page-width,auto);max-width:100%}' +
|
|
185
|
+
'.' +
|
|
186
|
+
CLASSES.page +
|
|
187
|
+
'+.' +
|
|
188
|
+
CLASSES.page +
|
|
189
|
+
'{margin-top:var(--pdfp-spacing,16px)}';
|
|
190
|
+
|
|
191
|
+
// How long after the last scroll event a programmatic scroll is treated as
|
|
192
|
+
// finished, and the safety net for when it produces no scroll events at all.
|
|
193
|
+
var SETTLE_DELAY = 150;
|
|
194
|
+
var SETTLE_TIMEOUT = 700;
|
|
195
|
+
|
|
196
|
+
// Largest canvas iOS Safari will draw (4096 x 4096); bigger ones render blank.
|
|
197
|
+
var MAX_CANVAS_PIXELS = 16777216;
|
|
198
|
+
|
|
199
|
+
var INSTANCE_KEY = '__pdfPreview';
|
|
200
|
+
var THUMBNAIL_KEY = '__pdfThumbnail';
|
|
201
|
+
var pdfjsPromise = null;
|
|
202
|
+
var stylesInjected = false;
|
|
203
|
+
|
|
204
|
+
function noop() {
|
|
205
|
+
// Deliberately empty: used to mark a rejection as handled.
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function injectBaseStyles() {
|
|
209
|
+
if (stylesInjected || document.getElementById(STYLE_ID)) {
|
|
210
|
+
stylesInjected = true;
|
|
211
|
+
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
var style = document.createElement('style');
|
|
216
|
+
|
|
217
|
+
style.id = STYLE_ID;
|
|
218
|
+
style.appendChild(document.createTextNode(BASE_STYLES));
|
|
219
|
+
document.head.insertBefore(style, document.head.firstChild);
|
|
220
|
+
stylesInjected = true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function assign(target) {
|
|
224
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
225
|
+
var source = arguments[i];
|
|
226
|
+
|
|
227
|
+
if (!source) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
for (var key in source) {
|
|
232
|
+
if (
|
|
233
|
+
Object.prototype.hasOwnProperty.call(source, key) &&
|
|
234
|
+
source[key] !== undefined
|
|
235
|
+
) {
|
|
236
|
+
target[key] = source[key];
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return target;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function smoothScrollSupported() {
|
|
245
|
+
return 'scrollBehavior' in document.documentElement.style;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function emit(element, name, detail) {
|
|
249
|
+
var event;
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
event = new CustomEvent(name, { detail: detail, bubbles: true });
|
|
253
|
+
} catch (error) {
|
|
254
|
+
// IE11 and other engines without the CustomEvent constructor.
|
|
255
|
+
event = document.createEvent('CustomEvent');
|
|
256
|
+
event.initCustomEvent(name, true, false, detail);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
element.dispatchEvent(event);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Scale back a render that would need a canvas bigger than iOS Safari will
|
|
264
|
+
* draw. Shared by pages and thumbnails, so neither can render blank.
|
|
265
|
+
*/
|
|
266
|
+
function clampRenderScale(natural, renderScale) {
|
|
267
|
+
var area = natural.width * natural.height * renderScale * renderScale;
|
|
268
|
+
|
|
269
|
+
if (area > MAX_CANVAS_PIXELS) {
|
|
270
|
+
return renderScale * Math.sqrt(MAX_CANVAS_PIXELS / area);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return renderScale;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function toCssLength(value) {
|
|
277
|
+
if (value === null || value === undefined || value === '') {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return /^-?\d+(\.\d+)?$/.test(String(value)) ? value + 'px' : String(value);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function addClass(existing, name) {
|
|
285
|
+
var current = existing ? String(existing).split(/\s+/) : [];
|
|
286
|
+
|
|
287
|
+
for (var i = 0; i < current.length; i++) {
|
|
288
|
+
if (current[i] === name) {
|
|
289
|
+
return existing;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
current.push(name);
|
|
294
|
+
|
|
295
|
+
return current.join(' ').replace(/^\s+/, '');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function resolveElement(target) {
|
|
299
|
+
if (!target) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (typeof target === 'string') {
|
|
304
|
+
return document.querySelector(target);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Accept a jQuery-like or array-like wrapper.
|
|
308
|
+
if (target.nodeType !== 1 && typeof target.length === 'number') {
|
|
309
|
+
return target[0] || null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return target.nodeType === 1 ? target : null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function readDataOptions(element) {
|
|
316
|
+
var scale = parseFloat(element.getAttribute('data-pdf-preview-scale'));
|
|
317
|
+
var maxPixelRatio = parseFloat(element.getAttribute('data-pdf-preview-max-pixel-ratio'));
|
|
318
|
+
|
|
319
|
+
var fitWidth = element.getAttribute('data-pdf-preview-fit-width');
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
scale: isNaN(scale) ? undefined : scale,
|
|
323
|
+
maxPixelRatio: isNaN(maxPixelRatio) ? undefined : maxPixelRatio,
|
|
324
|
+
pageClass: element.getAttribute('data-pdf-preview-page-class') || undefined,
|
|
325
|
+
src: element.getAttribute('data-pdf-preview-src') || undefined,
|
|
326
|
+
height: element.getAttribute('data-pdf-preview-height') || undefined,
|
|
327
|
+
spacing: element.getAttribute('data-pdf-preview-spacing') || undefined,
|
|
328
|
+
fitWidth: fitWidth === null ? undefined : fitWidth !== 'false',
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function loadScript(url) {
|
|
333
|
+
return new Promise(function (resolve, reject) {
|
|
334
|
+
var script = document.createElement('script');
|
|
335
|
+
|
|
336
|
+
script.src = url;
|
|
337
|
+
script.onload = resolve;
|
|
338
|
+
script.onerror = function () {
|
|
339
|
+
reject(new Error('PdfPreview: failed to load ' + url));
|
|
340
|
+
};
|
|
341
|
+
document.head.appendChild(script);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function getPdfjs(options) {
|
|
346
|
+
if (options.pdfjsLib) {
|
|
347
|
+
return Promise.resolve(options.pdfjsLib);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (window.pdfjsLib) {
|
|
351
|
+
return Promise.resolve(window.pdfjsLib);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (!pdfjsPromise) {
|
|
355
|
+
pdfjsPromise = loadScript(options.pdfjsUrl).then(function () {
|
|
356
|
+
var lib = window.pdfjsLib || window['pdfjs-dist/build/pdf'];
|
|
357
|
+
|
|
358
|
+
if (!lib) {
|
|
359
|
+
throw new Error('PdfPreview: pdf.js did not register itself');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (options.pdfjsWorkerUrl && lib.GlobalWorkerOptions) {
|
|
363
|
+
lib.GlobalWorkerOptions.workerSrc = options.pdfjsWorkerUrl;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
window.pdfjsLib = lib;
|
|
367
|
+
|
|
368
|
+
return lib;
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return pdfjsPromise;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Scale that fits a page into the requested box. With a width and a height
|
|
377
|
+
* the smaller of the two wins, so the page is contained rather than
|
|
378
|
+
* stretched; the thumbnail then matches the page's own aspect ratio.
|
|
379
|
+
*/
|
|
380
|
+
function thumbnailDisplayScale(natural, options) {
|
|
381
|
+
var width = parseFloat(options.width);
|
|
382
|
+
var height = parseFloat(options.height);
|
|
383
|
+
var scale = Infinity;
|
|
384
|
+
|
|
385
|
+
if (width > 0) {
|
|
386
|
+
scale = Math.min(scale, width / natural.width);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (height > 0) {
|
|
390
|
+
scale = Math.min(scale, height / natural.height);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return scale === Infinity ? 1 : scale;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Draw one page to an offscreen canvas and hand it back as a data URL. The
|
|
398
|
+
* canvas is released straight away, so all that is kept is the string.
|
|
399
|
+
*/
|
|
400
|
+
function drawThumbnail(page, options) {
|
|
401
|
+
var natural = page.getViewport({ scale: 1 });
|
|
402
|
+
var displayScale = thumbnailDisplayScale(natural, options);
|
|
403
|
+
var pixelRatio = Math.min(window.devicePixelRatio || 1, options.maxPixelRatio);
|
|
404
|
+
var renderScale = clampRenderScale(natural, displayScale * pixelRatio);
|
|
405
|
+
var viewport = page.getViewport({ scale: renderScale });
|
|
406
|
+
var canvas = document.createElement('canvas');
|
|
407
|
+
|
|
408
|
+
canvas.width = Math.floor(viewport.width);
|
|
409
|
+
canvas.height = Math.floor(viewport.height);
|
|
410
|
+
|
|
411
|
+
return page
|
|
412
|
+
.render({
|
|
413
|
+
canvasContext: canvas.getContext('2d'),
|
|
414
|
+
viewport: viewport,
|
|
415
|
+
// pdf.js fills white by default, but a PDF page carries no
|
|
416
|
+
// background of its own, so say it explicitly rather than rely
|
|
417
|
+
// on the default of whichever pdf.js is in play.
|
|
418
|
+
background: options.background,
|
|
419
|
+
})
|
|
420
|
+
.promise.then(function () {
|
|
421
|
+
var dataUrl = canvas.toDataURL(options.type, options.quality);
|
|
422
|
+
|
|
423
|
+
// Zero-sized canvases free their backing store immediately,
|
|
424
|
+
// which matters on iOS where it is capped per page.
|
|
425
|
+
canvas.width = 0;
|
|
426
|
+
canvas.height = 0;
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
dataUrl: dataUrl,
|
|
430
|
+
width: Math.round(natural.width * displayScale),
|
|
431
|
+
height: Math.round(natural.height * displayScale),
|
|
432
|
+
};
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function thumbnailFromDocument(doc, options) {
|
|
437
|
+
var requested = parseInt(options.page, 10);
|
|
438
|
+
var pageNumber = Math.min(Math.max(isNaN(requested) ? 1 : requested, 1), doc.numPages);
|
|
439
|
+
|
|
440
|
+
return doc.getPage(pageNumber).then(function (page) {
|
|
441
|
+
return drawThumbnail(page, options).then(function (thumbnail) {
|
|
442
|
+
thumbnail.page = pageNumber;
|
|
443
|
+
thumbnail.pageCount = doc.numPages;
|
|
444
|
+
|
|
445
|
+
return thumbnail;
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function readThumbnailDataOptions(element) {
|
|
451
|
+
var width = parseFloat(element.getAttribute('data-pdf-thumbnail-width'));
|
|
452
|
+
var height = parseFloat(element.getAttribute('data-pdf-thumbnail-height'));
|
|
453
|
+
var page = parseInt(element.getAttribute('data-pdf-thumbnail-page'), 10);
|
|
454
|
+
var quality = parseFloat(element.getAttribute('data-pdf-thumbnail-quality'));
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
src: element.getAttribute('data-pdf-thumbnail-src') || undefined,
|
|
458
|
+
width: isNaN(width) ? undefined : width,
|
|
459
|
+
height: isNaN(height) ? undefined : height,
|
|
460
|
+
page: isNaN(page) ? undefined : page,
|
|
461
|
+
type: element.getAttribute('data-pdf-thumbnail-type') || undefined,
|
|
462
|
+
quality: isNaN(quality) ? undefined : quality,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function PdfPreview(target, options) {
|
|
467
|
+
var element = resolveElement(target);
|
|
468
|
+
|
|
469
|
+
if (!element) {
|
|
470
|
+
throw new Error('PdfPreview: root element not found');
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Calling on an already-initialised element returns the existing
|
|
474
|
+
// instance, so it is safe to call repeatedly for the same root.
|
|
475
|
+
if (element[INSTANCE_KEY]) {
|
|
476
|
+
return element[INSTANCE_KEY];
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Tolerate being called without `new`.
|
|
480
|
+
if (!(this instanceof PdfPreview)) {
|
|
481
|
+
return new PdfPreview(element, options);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
this.element = element;
|
|
485
|
+
this.options = assign({}, DEFAULTS, readDataOptions(element), options);
|
|
486
|
+
this.selectors = assign({}, SELECTORS, (options || {}).selectors);
|
|
487
|
+
this.pagesContainer = element.querySelector(this.selectors.pages) || element;
|
|
488
|
+
this.doc = null;
|
|
489
|
+
this.canvases = [];
|
|
490
|
+
this.objectUrl = null;
|
|
491
|
+
// Bumped by every load() and reset(), so async work started by an
|
|
492
|
+
// earlier load can tell it has been superseded and stop touching the DOM.
|
|
493
|
+
this._loadId = 0;
|
|
494
|
+
this._loadingTask = null;
|
|
495
|
+
|
|
496
|
+
element[INSTANCE_KEY] = this;
|
|
497
|
+
|
|
498
|
+
if (this.options.injectStyles) {
|
|
499
|
+
injectBaseStyles();
|
|
500
|
+
this.pagesContainer.className = addClass(this.pagesContainer.className, CLASSES.pages);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Sizing options are handed to the base styles as custom properties
|
|
504
|
+
// rather than set as inline max-height/padding/margin, so a consumer
|
|
505
|
+
// stylesheet can still override the real properties.
|
|
506
|
+
var height = toCssLength(this.options.height);
|
|
507
|
+
var spacing = toCssLength(this.options.spacing);
|
|
508
|
+
|
|
509
|
+
if (this.pagesContainer.style.setProperty) {
|
|
510
|
+
if (height) {
|
|
511
|
+
this.pagesContainer.style.setProperty('--pdfp-height', height);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (spacing) {
|
|
515
|
+
this.pagesContainer.style.setProperty('--pdfp-spacing', spacing);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
this._bind();
|
|
520
|
+
|
|
521
|
+
if (this.options.src) {
|
|
522
|
+
this.load(this.options.src);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
PdfPreview.prototype._find = function (selector) {
|
|
527
|
+
return selector ? this.element.querySelector(selector) : null;
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
PdfPreview.prototype._emit = function (name, detail) {
|
|
531
|
+
emit(this.element, name, detail);
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
PdfPreview.prototype._bind = function () {
|
|
535
|
+
var self = this;
|
|
536
|
+
|
|
537
|
+
this._onClick = function (event) {
|
|
538
|
+
var target = event.target;
|
|
539
|
+
|
|
540
|
+
function matches(selector) {
|
|
541
|
+
return selector && target.closest(selector);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (matches(self.selectors.first)) {
|
|
545
|
+
self.goToPage(1);
|
|
546
|
+
} else if (matches(self.selectors.prev)) {
|
|
547
|
+
self.goToPage(self.getCurrentPage() - 1);
|
|
548
|
+
} else if (matches(self.selectors.next)) {
|
|
549
|
+
self.goToPage(self.getCurrentPage() + 1);
|
|
550
|
+
} else if (matches(self.selectors.last)) {
|
|
551
|
+
self.goToPage(self.getPageCount());
|
|
552
|
+
} else {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
event.preventDefault();
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
this._onChange = function (event) {
|
|
560
|
+
if (!self.selectors.pageInput || !event.target.closest(self.selectors.pageInput)) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
var value = parseInt(event.target.value, 10);
|
|
565
|
+
|
|
566
|
+
if (!isNaN(value) && value >= 1 && value <= self.getPageCount()) {
|
|
567
|
+
self.goToPage(value);
|
|
568
|
+
} else {
|
|
569
|
+
self._setPageInput(self.getCurrentPage());
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
this._onScroll = function (event) {
|
|
574
|
+
var target = event.target;
|
|
575
|
+
|
|
576
|
+
// Listening in the capture phase on the document sees every scroll
|
|
577
|
+
// on the page, since scroll events do not bubble. Only the ones that
|
|
578
|
+
// move the pages matter: the pages container itself when it is the
|
|
579
|
+
// scrolling viewport, or an ancestor (the window, a modal) when the
|
|
580
|
+
// pages sit in normal flow.
|
|
581
|
+
if (target !== document && !(target.contains && target.contains(self.pagesContainer))) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (self._scrollLocked) {
|
|
586
|
+
// A programmatic scroll is running, so keep showing the
|
|
587
|
+
// destination page and wait for it to settle rather than
|
|
588
|
+
// reporting every page it travels past.
|
|
589
|
+
self._lockPageSync(SETTLE_DELAY);
|
|
590
|
+
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
if (self._scrollFrame) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
self._scrollFrame = requestAnimationFrame(function () {
|
|
599
|
+
self._scrollFrame = null;
|
|
600
|
+
self._setPageInput(self.getCurrentPage());
|
|
601
|
+
});
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
this.element.addEventListener('click', this._onClick);
|
|
605
|
+
this.element.addEventListener('change', this._onChange);
|
|
606
|
+
document.addEventListener('scroll', this._onScroll, true);
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
/** Whether the pages container is itself the scrolling viewport. */
|
|
610
|
+
PdfPreview.prototype._isScrollViewport = function () {
|
|
611
|
+
return this.pagesContainer.scrollHeight > this.pagesContainer.clientHeight;
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Stop scroll events from writing to the page input until things have
|
|
616
|
+
* settled. Called again on every scroll event so the lock lasts as long as
|
|
617
|
+
* the animation does. Once settled, the page asked for by goToPage() is kept
|
|
618
|
+
* even if it could not be scrolled fully into place (e.g. the second-to-last
|
|
619
|
+
* page when the last one is short); the next user scroll re-syncs.
|
|
620
|
+
*/
|
|
621
|
+
PdfPreview.prototype._lockPageSync = function (delay) {
|
|
622
|
+
var self = this;
|
|
623
|
+
|
|
624
|
+
this._scrollLocked = true;
|
|
625
|
+
clearTimeout(this._scrollTimer);
|
|
626
|
+
|
|
627
|
+
this._scrollTimer = setTimeout(function () {
|
|
628
|
+
self._scrollLocked = false;
|
|
629
|
+
self._setPageInput(self._targetPage || self.getCurrentPage());
|
|
630
|
+
self._targetPage = null;
|
|
631
|
+
}, delay);
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
PdfPreview.prototype._setPageInput = function (page) {
|
|
635
|
+
var input = this._find(this.selectors.pageInput);
|
|
636
|
+
|
|
637
|
+
if (input && String(input.value) !== String(page)) {
|
|
638
|
+
input.value = page;
|
|
639
|
+
this._emit('pdfpreview:pagechange', { page: page });
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
PdfPreview.prototype._setPageTotal = function (total) {
|
|
644
|
+
var element = this._find(this.selectors.pageTotal);
|
|
645
|
+
|
|
646
|
+
if (element) {
|
|
647
|
+
element.textContent = total;
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
PdfPreview.prototype._isCurrentLoad = function (token) {
|
|
652
|
+
return token === this._loadId;
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
/** Width available to a page inside the pages container, in CSS px. */
|
|
656
|
+
PdfPreview.prototype._contentWidth = function () {
|
|
657
|
+
var container = this.pagesContainer;
|
|
658
|
+
var style = window.getComputedStyle(container);
|
|
659
|
+
|
|
660
|
+
return (
|
|
661
|
+
container.clientWidth -
|
|
662
|
+
(parseFloat(style.paddingLeft) || 0) -
|
|
663
|
+
(parseFloat(style.paddingRight) || 0)
|
|
664
|
+
);
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Scale that gives a page its on-screen (CSS) size: the container width
|
|
669
|
+
* when fitting, otherwise the `scale` option. Also used when the container
|
|
670
|
+
* has no width yet, e.g. when loading into a hidden element.
|
|
671
|
+
*/
|
|
672
|
+
PdfPreview.prototype._displayScale = function (pageWidth) {
|
|
673
|
+
if (this.options.fitWidth && this._availableWidth > 0) {
|
|
674
|
+
return this._availableWidth / pageWidth;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
return this.options.scale;
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
PdfPreview.prototype._renderPage = function (num, token) {
|
|
681
|
+
var self = this;
|
|
682
|
+
|
|
683
|
+
return this.doc.getPage(num).then(function (page) {
|
|
684
|
+
if (!self._isCurrentLoad(token)) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Draw at display size x device pixel ratio, so the canvas has one
|
|
689
|
+
// backing pixel per screen pixel and stays sharp on dense screens,
|
|
690
|
+
// capped to keep memory in check.
|
|
691
|
+
var natural = page.getViewport({ scale: 1 });
|
|
692
|
+
var displayScale = self._displayScale(natural.width);
|
|
693
|
+
var pixelRatio = Math.min(window.devicePixelRatio || 1, self.options.maxPixelRatio);
|
|
694
|
+
var renderScale = clampRenderScale(natural, displayScale * pixelRatio);
|
|
695
|
+
var viewport = page.getViewport({ scale: renderScale });
|
|
696
|
+
var canvas = document.createElement('canvas');
|
|
697
|
+
|
|
698
|
+
canvas.width = Math.floor(viewport.width);
|
|
699
|
+
canvas.height = Math.floor(viewport.height);
|
|
700
|
+
canvas.setAttribute('data-page', num);
|
|
701
|
+
|
|
702
|
+
if (canvas.style.setProperty) {
|
|
703
|
+
canvas.style.setProperty(
|
|
704
|
+
'--pdfp-page-width',
|
|
705
|
+
Math.round(natural.width * displayScale) + 'px'
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
var className = '';
|
|
710
|
+
|
|
711
|
+
if (self.options.injectStyles) {
|
|
712
|
+
className = addClass(className, CLASSES.page);
|
|
713
|
+
|
|
714
|
+
if (!self.options.fitWidth) {
|
|
715
|
+
className = addClass(className, CLASSES.pageAuto);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (self.options.pageClass) {
|
|
720
|
+
className = addClass(className, self.options.pageClass);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (className) {
|
|
724
|
+
canvas.className = className;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
self.pagesContainer.appendChild(canvas);
|
|
728
|
+
self.canvases.push(canvas);
|
|
729
|
+
|
|
730
|
+
return page.render({
|
|
731
|
+
canvasContext: canvas.getContext('2d'),
|
|
732
|
+
viewport: viewport,
|
|
733
|
+
}).promise;
|
|
734
|
+
});
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
PdfPreview.prototype._renderFrom = function (num, token) {
|
|
738
|
+
var self = this;
|
|
739
|
+
|
|
740
|
+
if (!this._isCurrentLoad(token) || !this.doc || num > this.doc.numPages) {
|
|
741
|
+
return Promise.resolve();
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
return this._renderPage(num, token).then(function () {
|
|
745
|
+
return self._renderFrom(num + 1, token);
|
|
746
|
+
});
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Render a PDF. Accepts a File, a Blob, or a URL string.
|
|
751
|
+
* Returns a Promise resolving with the pdf.js document, or with undefined
|
|
752
|
+
* when the load is superseded by another load(), reset() or destroy()
|
|
753
|
+
* before it finishes.
|
|
754
|
+
*/
|
|
755
|
+
PdfPreview.prototype.load = function (source) {
|
|
756
|
+
var self = this;
|
|
757
|
+
|
|
758
|
+
if (!source) {
|
|
759
|
+
return Promise.reject(new Error('PdfPreview: no source given'));
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
this.reset();
|
|
763
|
+
|
|
764
|
+
var token = ++this._loadId;
|
|
765
|
+
|
|
766
|
+
return getPdfjs(this.options)
|
|
767
|
+
.then(function (pdfjsLib) {
|
|
768
|
+
if (!self._isCurrentLoad(token)) {
|
|
769
|
+
return null;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
var url = source;
|
|
773
|
+
|
|
774
|
+
if (typeof source !== 'string') {
|
|
775
|
+
self.objectUrl = URL.createObjectURL(source);
|
|
776
|
+
url = self.objectUrl;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// isEvalSupported: false stops pdf.js compiling font glyphs into
|
|
780
|
+
// code with new Function(), which a crafted PDF can abuse to run
|
|
781
|
+
// its own script (CVE-2024-4367, fixed in pdf.js 4.2.67). Glyphs
|
|
782
|
+
// are interpreted instead; slightly slower, but safe for any
|
|
783
|
+
// pdf.js version, including one passed in via `pdfjsLib`.
|
|
784
|
+
self._loadingTask = pdfjsLib.getDocument({ url: url, isEvalSupported: false });
|
|
785
|
+
|
|
786
|
+
return self._loadingTask.promise;
|
|
787
|
+
})
|
|
788
|
+
.then(function (doc) {
|
|
789
|
+
if (!doc) {
|
|
790
|
+
return undefined;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
if (!self._isCurrentLoad(token)) {
|
|
794
|
+
// Resolved after being superseded: free it and bail out.
|
|
795
|
+
doc.destroy();
|
|
796
|
+
|
|
797
|
+
return undefined;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
self.doc = doc;
|
|
801
|
+
self._setPageTotal(doc.numPages);
|
|
802
|
+
|
|
803
|
+
var input = self._find(self.selectors.pageInput);
|
|
804
|
+
|
|
805
|
+
if (input) {
|
|
806
|
+
input.setAttribute('max', doc.numPages);
|
|
807
|
+
input.value = 1;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
self._emit('pdfpreview:loaded', { pageCount: doc.numPages });
|
|
811
|
+
|
|
812
|
+
// Measured once per load, so every page is fitted to the same width.
|
|
813
|
+
self._availableWidth = self._contentWidth();
|
|
814
|
+
|
|
815
|
+
return self._renderFrom(1, token).then(function () {
|
|
816
|
+
return self._isCurrentLoad(token) ? doc : undefined;
|
|
817
|
+
});
|
|
818
|
+
})
|
|
819
|
+
.catch(function (error) {
|
|
820
|
+
// Cancelling a load makes pdf.js reject whatever was in flight
|
|
821
|
+
// (worker destroyed, rendering cancelled). That is expected, not
|
|
822
|
+
// an error worth reporting.
|
|
823
|
+
if (!self._isCurrentLoad(token)) {
|
|
824
|
+
return undefined;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
self._emit('pdfpreview:error', { error: error });
|
|
828
|
+
throw error;
|
|
829
|
+
});
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Remove all rendered pages, cancel any load in progress and release the
|
|
834
|
+
* current document.
|
|
835
|
+
*/
|
|
836
|
+
PdfPreview.prototype.reset = function () {
|
|
837
|
+
this._loadId++;
|
|
838
|
+
|
|
839
|
+
if (this._loadingTask) {
|
|
840
|
+
// Also destroys the document it produced, and aborts the fetch and
|
|
841
|
+
// parsing if it has not finished yet.
|
|
842
|
+
this._loadingTask.destroy();
|
|
843
|
+
this._loadingTask = null;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
while (this.pagesContainer.firstChild) {
|
|
847
|
+
this.pagesContainer.removeChild(this.pagesContainer.firstChild);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
this.canvases = [];
|
|
851
|
+
this.doc = null;
|
|
852
|
+
clearTimeout(this._scrollTimer);
|
|
853
|
+
cancelAnimationFrame(this._scrollFrame);
|
|
854
|
+
this._scrollFrame = null;
|
|
855
|
+
this._scrollLocked = false;
|
|
856
|
+
this._targetPage = null;
|
|
857
|
+
this._setPageTotal('');
|
|
858
|
+
|
|
859
|
+
var input = this._find(this.selectors.pageInput);
|
|
860
|
+
|
|
861
|
+
if (input) {
|
|
862
|
+
input.value = 1;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
if (this.objectUrl) {
|
|
866
|
+
URL.revokeObjectURL(this.objectUrl);
|
|
867
|
+
this.objectUrl = null;
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
|
|
871
|
+
PdfPreview.prototype.getPageCount = function () {
|
|
872
|
+
return this.doc ? this.doc.numPages : 0;
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* Thumbnail of the document this preview already has open, so the file is
|
|
877
|
+
* read and parsed once for both. Resolves with { dataUrl, width, height,
|
|
878
|
+
* page, pageCount }, or with undefined when a later load(), reset() or
|
|
879
|
+
* destroy() takes over while it is being drawn. Rejects when no document is
|
|
880
|
+
* open; use the static PdfPreview.thumbnail() for that case.
|
|
881
|
+
*/
|
|
882
|
+
PdfPreview.prototype.getThumbnail = function (options) {
|
|
883
|
+
var self = this;
|
|
884
|
+
|
|
885
|
+
if (!this.doc) {
|
|
886
|
+
return Promise.reject(new Error('PdfPreview: no document loaded'));
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
var settings = assign(
|
|
890
|
+
{},
|
|
891
|
+
THUMBNAIL_DEFAULTS,
|
|
892
|
+
{ maxPixelRatio: this.options.maxPixelRatio },
|
|
893
|
+
options
|
|
894
|
+
);
|
|
895
|
+
var token = this._loadId;
|
|
896
|
+
|
|
897
|
+
return thumbnailFromDocument(this.doc, settings).then(
|
|
898
|
+
function (thumbnail) {
|
|
899
|
+
return self._isCurrentLoad(token) ? thumbnail : undefined;
|
|
900
|
+
},
|
|
901
|
+
function (error) {
|
|
902
|
+
// Superseded loads destroy the document mid-render, which
|
|
903
|
+
// rejects. Expected, and not this thumbnail's problem.
|
|
904
|
+
if (!self._isCurrentLoad(token)) {
|
|
905
|
+
return undefined;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
throw error;
|
|
909
|
+
}
|
|
910
|
+
);
|
|
911
|
+
};
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* The page under, or nearest to, the middle of the visible area: the
|
|
915
|
+
* pages container when it scrolls, otherwise the browser window.
|
|
916
|
+
*/
|
|
917
|
+
PdfPreview.prototype.getCurrentPage = function () {
|
|
918
|
+
var count = this.canvases.length;
|
|
919
|
+
|
|
920
|
+
if (!count) {
|
|
921
|
+
return 1;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
var middle;
|
|
925
|
+
|
|
926
|
+
if (this._isScrollViewport()) {
|
|
927
|
+
var container = this.pagesContainer;
|
|
928
|
+
|
|
929
|
+
// A short last page can never reach the middle, so treat the very
|
|
930
|
+
// end of the scroll range as the last page (and the start as the first).
|
|
931
|
+
if (container.scrollTop + container.clientHeight >= container.scrollHeight - 1) {
|
|
932
|
+
return count;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
if (container.scrollTop <= 0) {
|
|
936
|
+
return 1;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
var bounds = container.getBoundingClientRect();
|
|
940
|
+
|
|
941
|
+
middle = bounds.top + bounds.height / 2;
|
|
942
|
+
} else {
|
|
943
|
+
middle = window.innerHeight / 2;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
var nearest = 1;
|
|
947
|
+
var nearestDistance = Infinity;
|
|
948
|
+
|
|
949
|
+
for (var i = 0; i < count; i++) {
|
|
950
|
+
var pageBounds = this.canvases[i].getBoundingClientRect();
|
|
951
|
+
|
|
952
|
+
if (pageBounds.top <= middle && pageBounds.bottom >= middle) {
|
|
953
|
+
return i + 1;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// The middle is in the gap between pages (or past either end):
|
|
957
|
+
// fall back to whichever page edge is closest to it.
|
|
958
|
+
var distance = Math.min(
|
|
959
|
+
Math.abs(pageBounds.top - middle),
|
|
960
|
+
Math.abs(pageBounds.bottom - middle)
|
|
961
|
+
);
|
|
962
|
+
|
|
963
|
+
if (distance < nearestDistance) {
|
|
964
|
+
nearestDistance = distance;
|
|
965
|
+
nearest = i + 1;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
return nearest;
|
|
970
|
+
};
|
|
971
|
+
|
|
972
|
+
PdfPreview.prototype.goToPage = function (page) {
|
|
973
|
+
var canvas = this.canvases[page - 1];
|
|
974
|
+
|
|
975
|
+
if (!canvas || page < 1 || page > this.getPageCount()) {
|
|
976
|
+
return this;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
var container = this.pagesContainer;
|
|
980
|
+
|
|
981
|
+
// Show the destination straight away and hold it there for the duration
|
|
982
|
+
// of the scroll, so the input does not count through every page on route.
|
|
983
|
+
this._setPageInput(page);
|
|
984
|
+
this._targetPage = page;
|
|
985
|
+
this._lockPageSync(SETTLE_TIMEOUT);
|
|
986
|
+
|
|
987
|
+
if (this._isScrollViewport()) {
|
|
988
|
+
// Scroll the viewport itself rather than using scrollIntoView, which
|
|
989
|
+
// would also scroll every ancestor and drag the page away from the
|
|
990
|
+
// navigation controls.
|
|
991
|
+
var offset = canvas.getBoundingClientRect().top - container.getBoundingClientRect().top;
|
|
992
|
+
var paddingTop = parseFloat(window.getComputedStyle(container).paddingTop) || 0;
|
|
993
|
+
var top = container.scrollTop + offset - paddingTop;
|
|
994
|
+
|
|
995
|
+
if (smoothScrollSupported() && container.scrollTo) {
|
|
996
|
+
container.scrollTo({ top: top, behavior: 'smooth' });
|
|
997
|
+
} else {
|
|
998
|
+
container.scrollTop = top;
|
|
999
|
+
}
|
|
1000
|
+
} else {
|
|
1001
|
+
// Not a scrolling viewport, so the pages sit in normal page flow and
|
|
1002
|
+
// moving the document is the only way to reach them.
|
|
1003
|
+
canvas.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
return this;
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
/** Unbind listeners, clear the container and forget the instance. */
|
|
1010
|
+
PdfPreview.prototype.destroy = function () {
|
|
1011
|
+
this.reset();
|
|
1012
|
+
clearTimeout(this._scrollTimer);
|
|
1013
|
+
this._scrollLocked = false;
|
|
1014
|
+
this.element.removeEventListener('click', this._onClick);
|
|
1015
|
+
this.element.removeEventListener('change', this._onChange);
|
|
1016
|
+
document.removeEventListener('scroll', this._onScroll, true);
|
|
1017
|
+
delete this.element[INSTANCE_KEY];
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Thumbnail of one page of a PDF, as a data URL for the src of an <img>.
|
|
1022
|
+
* Accepts a File, a Blob or a URL, and needs no preview and no element.
|
|
1023
|
+
* Resolves with { dataUrl, width, height, page, pageCount }, where width
|
|
1024
|
+
* and height are the CSS px the thumbnail is meant to be shown at.
|
|
1025
|
+
*
|
|
1026
|
+
* The document is closed and any object URL revoked before it resolves, so
|
|
1027
|
+
* nothing is held on to but the string.
|
|
1028
|
+
*/
|
|
1029
|
+
PdfPreview.thumbnail = function (source, options) {
|
|
1030
|
+
if (!source) {
|
|
1031
|
+
return Promise.reject(new Error('PdfPreview.thumbnail: no source given'));
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
var settings = assign({}, THUMBNAIL_DEFAULTS, options);
|
|
1035
|
+
var objectUrl = null;
|
|
1036
|
+
var loadingTask = null;
|
|
1037
|
+
|
|
1038
|
+
function release() {
|
|
1039
|
+
if (loadingTask) {
|
|
1040
|
+
// Destroys the document it produced along with it.
|
|
1041
|
+
loadingTask.destroy();
|
|
1042
|
+
loadingTask = null;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
if (objectUrl) {
|
|
1046
|
+
URL.revokeObjectURL(objectUrl);
|
|
1047
|
+
objectUrl = null;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
return getPdfjs(settings)
|
|
1052
|
+
.then(function (pdfjsLib) {
|
|
1053
|
+
var url = source;
|
|
1054
|
+
|
|
1055
|
+
if (typeof source !== 'string') {
|
|
1056
|
+
objectUrl = URL.createObjectURL(source);
|
|
1057
|
+
url = objectUrl;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// isEvalSupported: false for the same reason as in load().
|
|
1061
|
+
loadingTask = pdfjsLib.getDocument({ url: url, isEvalSupported: false });
|
|
1062
|
+
|
|
1063
|
+
return loadingTask.promise;
|
|
1064
|
+
})
|
|
1065
|
+
.then(function (doc) {
|
|
1066
|
+
return thumbnailFromDocument(doc, settings);
|
|
1067
|
+
})
|
|
1068
|
+
.then(
|
|
1069
|
+
function (thumbnail) {
|
|
1070
|
+
release();
|
|
1071
|
+
|
|
1072
|
+
return thumbnail;
|
|
1073
|
+
},
|
|
1074
|
+
function (error) {
|
|
1075
|
+
release();
|
|
1076
|
+
|
|
1077
|
+
throw error;
|
|
1078
|
+
}
|
|
1079
|
+
);
|
|
1080
|
+
};
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* Render a thumbnail straight into an <img>: sets its src, and its width
|
|
1084
|
+
* and height so the tile holds its space before the image arrives. Options
|
|
1085
|
+
* can come from data-pdf-thumbnail-* attributes on the element, with the
|
|
1086
|
+
* ones passed here winning. `source` may be omitted to use
|
|
1087
|
+
* data-pdf-thumbnail-src.
|
|
1088
|
+
*
|
|
1089
|
+
* Dispatches pdfthumbnail:loaded or pdfthumbnail:error on the element. On
|
|
1090
|
+
* failure the element is left untouched, so whatever it already shows (a
|
|
1091
|
+
* generic file icon, say) stays visible.
|
|
1092
|
+
*/
|
|
1093
|
+
PdfPreview.thumbnailInto = function (target, source, options) {
|
|
1094
|
+
var element = resolveElement(target);
|
|
1095
|
+
|
|
1096
|
+
if (!element) {
|
|
1097
|
+
return Promise.reject(new Error('PdfPreview.thumbnailInto: element not found'));
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
if (element.tagName !== 'IMG') {
|
|
1101
|
+
return Promise.reject(new Error('PdfPreview.thumbnailInto: expects an <img> element'));
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
var settings = assign({}, readThumbnailDataOptions(element), options);
|
|
1105
|
+
|
|
1106
|
+
return PdfPreview.thumbnail(source || settings.src, settings).then(
|
|
1107
|
+
function (thumbnail) {
|
|
1108
|
+
element.src = thumbnail.dataUrl;
|
|
1109
|
+
element.setAttribute('width', thumbnail.width);
|
|
1110
|
+
element.setAttribute('height', thumbnail.height);
|
|
1111
|
+
emit(element, 'pdfthumbnail:loaded', thumbnail);
|
|
1112
|
+
|
|
1113
|
+
return thumbnail;
|
|
1114
|
+
},
|
|
1115
|
+
function (error) {
|
|
1116
|
+
emit(element, 'pdfthumbnail:error', { error: error });
|
|
1117
|
+
|
|
1118
|
+
throw error;
|
|
1119
|
+
}
|
|
1120
|
+
);
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* Fill every [data-pdf-thumbnail] within an optional scope from its
|
|
1125
|
+
* data-pdf-thumbnail-src. Returns the promises, one per element, in
|
|
1126
|
+
* document order. Elements already handled are skipped, so this is safe to
|
|
1127
|
+
* call again after adding markup.
|
|
1128
|
+
*/
|
|
1129
|
+
PdfPreview.initThumbnails = function (scope, options) {
|
|
1130
|
+
var context = resolveElement(scope) || document;
|
|
1131
|
+
var elements = context.querySelectorAll(SELECTORS.thumbnail);
|
|
1132
|
+
var promises = [];
|
|
1133
|
+
|
|
1134
|
+
for (var i = 0; i < elements.length; i++) {
|
|
1135
|
+
var element = elements[i];
|
|
1136
|
+
|
|
1137
|
+
if (!element[THUMBNAIL_KEY]) {
|
|
1138
|
+
element[THUMBNAIL_KEY] = PdfPreview.thumbnailInto(element, null, options);
|
|
1139
|
+
// Failures are reported through pdfthumbnail:error and through
|
|
1140
|
+
// the returned promise. This stops a caller that watches the
|
|
1141
|
+
// events instead from logging an unhandled rejection.
|
|
1142
|
+
element[THUMBNAIL_KEY].catch(noop);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
promises.push(element[THUMBNAIL_KEY]);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
return promises;
|
|
1149
|
+
};
|
|
1150
|
+
|
|
1151
|
+
/** Existing instance for an element, or null. */
|
|
1152
|
+
PdfPreview.get = function (target) {
|
|
1153
|
+
var element = resolveElement(target);
|
|
1154
|
+
|
|
1155
|
+
return (element && element[INSTANCE_KEY]) || null;
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
/** Initialise every [data-pdf-preview] within an optional scope. */
|
|
1159
|
+
PdfPreview.initAll = function (scope, options) {
|
|
1160
|
+
var context = resolveElement(scope) || document;
|
|
1161
|
+
var elements = context.querySelectorAll(SELECTORS.root);
|
|
1162
|
+
var instances = [];
|
|
1163
|
+
|
|
1164
|
+
for (var i = 0; i < elements.length; i++) {
|
|
1165
|
+
instances.push(new PdfPreview(elements[i], options));
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
return instances;
|
|
1169
|
+
};
|
|
1170
|
+
|
|
1171
|
+
PdfPreview.defaults = DEFAULTS;
|
|
1172
|
+
PdfPreview.thumbnailDefaults = THUMBNAIL_DEFAULTS;
|
|
1173
|
+
PdfPreview.selectors = SELECTORS;
|
|
1174
|
+
PdfPreview.classes = CLASSES;
|
|
1175
|
+
|
|
1176
|
+
return PdfPreview;
|
|
1177
|
+
});
|