@vaadin-component-factory/vcf-pdf-viewer 3.1.0 → 4.0.0
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 +2 -1
- package/package.json +56 -52
- package/pdfjs/dist/display_utils.js +609 -714
- package/pdfjs/dist/fetch_stream.js +239 -293
- package/pdfjs/dist/l10n_utils.js +113 -122
- package/pdfjs/dist/message_handler.js +451 -524
- package/pdfjs/dist/network.js +441 -552
- package/pdfjs/dist/network_utils.js +262 -309
- package/pdfjs/dist/node_stream.js +383 -481
- package/pdfjs/dist/pdf.js +9883 -11687
- package/pdfjs/dist/pdf_link_service.js +440 -534
- package/pdfjs/dist/pdf_rendering_queue.js +134 -154
- package/pdfjs/dist/pdf_thumbnail_viewer.js +620 -738
- package/pdfjs/dist/pdf_viewer.js +2667 -3207
- package/pdfjs/dist/ui_utils.js +762 -881
- package/pdfjs/dist/util.js +867 -991
- package/pdfjs/dist/worker.js +51434 -60846
- package/src/vcf-pdf-viewer.js +999 -886
- package/theme/base/vcf-pdf-viewer-styles.js +144 -0
- package/theme/base/vcf-pdf-viewer-toolbar-icons-styles.js +39 -0
- package/theme/base/vcf-pdf-viewer.js +3 -0
- package/vcf-pdf-viewer.js +1 -1
- package/theme/lumo/vcf-pdf-viewer-styles.js +0 -153
- package/theme/lumo/vcf-pdf-viewer-toolbar-icons-styles.js +0 -35
- package/theme/lumo/vcf-pdf-viewer.js +0 -3
- package/theme/material/baseline-keyboard_arrow_down-24px.svg +0 -1
- package/theme/material/baseline-keyboard_arrow_up-24px.svg +0 -1
- package/theme/material/vcf-pdf-viewer-styles.js +0 -123
- package/theme/material/vcf-pdf-viewer.js +0 -2
package/src/vcf-pdf-viewer.js
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
import * as
|
|
16
|
-
import * as
|
|
17
|
-
import * as
|
|
18
|
-
import * as
|
|
19
|
-
import
|
|
20
|
-
import * as
|
|
1
|
+
import { LitElement, html, css } from "lit";
|
|
2
|
+
import { ElementMixin } from "@vaadin/component-base/src/element-mixin";
|
|
3
|
+
import { ThemeDetectionMixin } from "@vaadin/vaadin-themable-mixin/vaadin-theme-detection-mixin";
|
|
4
|
+
import { ResizeMixin, SlotStylesMixin } from "@vaadin/component-base/";
|
|
5
|
+
import { ThemableMixin } from "@vaadin/vaadin-themable-mixin";
|
|
6
|
+
|
|
7
|
+
import "@vaadin/text-field";
|
|
8
|
+
import "@vaadin/select";
|
|
9
|
+
import "@vaadin/item";
|
|
10
|
+
import "@vaadin/button";
|
|
11
|
+
import "@vaadin/icon";
|
|
12
|
+
import "@vaadin/icons";
|
|
13
|
+
import "@vaadin/tooltip";
|
|
14
|
+
|
|
15
|
+
import * as pdfjsLib from "../pdfjs/dist/pdf";
|
|
16
|
+
import * as pdfjsViewer from "../pdfjs/dist/pdf_viewer";
|
|
17
|
+
import * as pdfUtils from "../pdfjs/dist/ui_utils";
|
|
18
|
+
import * as pdfjsLinkService from "../pdfjs/dist/pdf_link_service";
|
|
19
|
+
import * as pdfjsThumbnailViewer from "../pdfjs/dist/pdf_thumbnail_viewer";
|
|
20
|
+
import * as pdfjsRenderingQueue from "../pdfjs/dist/pdf_rendering_queue";
|
|
21
|
+
import { NullL10n } from "../pdfjs/dist/l10n_utils";
|
|
22
|
+
import * as pdfjsWorker from "../pdfjs/dist/worker";
|
|
23
|
+
|
|
21
24
|
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
|
22
25
|
|
|
23
26
|
/**
|
|
@@ -34,904 +37,1017 @@ pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
|
|
34
37
|
* @mixes Vaadin.ThemableMixin
|
|
35
38
|
* @demo demo/index.html
|
|
36
39
|
*/
|
|
37
|
-
class PdfViewerElement extends
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
border: 2px solid;
|
|
241
|
-
border-color: rgba(0, 0, 0, 0.5);
|
|
242
|
-
width: 40px;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
::slotted(#nextPage), ::slotted(#previousPage) {
|
|
246
|
-
width: 30px;
|
|
247
|
-
margin: 0;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
[part~="toolbar"].ready ::slotted(.toolbar-zoom.hide-zoom) {
|
|
251
|
-
display: none;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
</style>
|
|
255
|
-
|
|
256
|
-
<div id="outerContainer" part="outer-container" >
|
|
257
|
-
<div id="sidebarContainer" part="sidebar-container">
|
|
258
|
-
<div id="sidebarContent" part="sidebar-content">
|
|
259
|
-
<div id="thumbnailView" part="thumbnail-view"></div>
|
|
260
|
-
</div>
|
|
261
|
-
</div>
|
|
262
|
-
<div id="mainContainer" part="main-container">
|
|
263
|
-
<div id="toolbar" part="toolbar">
|
|
264
|
-
<slot name="sidebar-toggle-button-slot"></slot>
|
|
265
|
-
<span id="title" part="toolbar-text toolbar-title">{{__title}}</span>
|
|
266
|
-
<slot name="toolbar-zoom-slot"></slot>
|
|
267
|
-
<div part="toolbar-pages">
|
|
268
|
-
<slot name="toolbar-current-page-slot"></slot>
|
|
269
|
-
<span id="pageSeparator" part="toolbar-text toolbar-page-separator">/</span>
|
|
270
|
-
<span id="totalPages" part="toolbar-text toolbar-total-pages">{{__totalPages}}</span>
|
|
271
|
-
<slot name="previous-page-button-slot"></slot>
|
|
272
|
-
<slot name="next-page-button-slot"></slot>
|
|
273
|
-
</div>
|
|
274
|
-
<slot></slot>
|
|
275
|
-
</div>
|
|
276
|
-
|
|
277
|
-
<div id="viewerContainer" part="viewer-container" tabindex="0">
|
|
278
|
-
<div id="viewer" part="viewer"></div>
|
|
279
|
-
</div>
|
|
280
|
-
</div>
|
|
281
|
-
</div>
|
|
40
|
+
export class PdfViewerElement extends ResizeMixin(
|
|
41
|
+
SlotStylesMixin(ThemeDetectionMixin(ThemableMixin(ElementMixin(LitElement)))),
|
|
42
|
+
) {
|
|
43
|
+
static get styles() {
|
|
44
|
+
return css`
|
|
45
|
+
:host {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
width: 100%;
|
|
49
|
+
height: 500px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
:host([hidden]) {
|
|
53
|
+
display: none !important;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
[part~="toolbar"] #currentPage,
|
|
57
|
+
[part~="toolbar"] #pageSeparator,
|
|
58
|
+
[part~="toolbar"] #totalPages,
|
|
59
|
+
[part~="toolbar"] #previousPage,
|
|
60
|
+
[part~="toolbar"] #nextPage,
|
|
61
|
+
[part~="toolbar"] #zoom,
|
|
62
|
+
[part~="toolbar"] #sidebarToggle {
|
|
63
|
+
display: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
[part~="toolbar"].ready #currentPage,
|
|
67
|
+
[part~="toolbar"].ready #pageSeparator,
|
|
68
|
+
[part~="toolbar"].ready #totalPages,
|
|
69
|
+
[part~="toolbar"].ready #previousPage,
|
|
70
|
+
[part~="toolbar"].ready #nextPage,
|
|
71
|
+
[part~="toolbar"].ready #zoom,
|
|
72
|
+
[part~="toolbar"].ready #sidebarToggle {
|
|
73
|
+
display: inherit;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
[part~="outer-container"] {
|
|
77
|
+
width: 100%;
|
|
78
|
+
height: 100%;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
[part~="main-container"] {
|
|
82
|
+
position: absolute;
|
|
83
|
+
top: 0;
|
|
84
|
+
right: 0;
|
|
85
|
+
bottom: 0;
|
|
86
|
+
left: 0;
|
|
87
|
+
min-width: 320px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
[part~="viewer-container"] {
|
|
91
|
+
position: absolute;
|
|
92
|
+
flex: 1;
|
|
93
|
+
overflow: auto;
|
|
94
|
+
width: 100%;
|
|
95
|
+
height: -moz-calc(100% - 45px); /* Firefox */
|
|
96
|
+
height: -webkit-calc(100% - 45px); /* Chrome, Safari */
|
|
97
|
+
height: calc(100% - 45px); /*all other browsers */
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
[part~="sidebar-container"] {
|
|
101
|
+
position: absolute;
|
|
102
|
+
width: 200px;
|
|
103
|
+
top: 45px;
|
|
104
|
+
bottom: 0;
|
|
105
|
+
visibility: hidden;
|
|
106
|
+
height: -moz-calc(100% - 45px); /* Firefox */
|
|
107
|
+
height: -webkit-calc(100% - 45px); /* Chrome, Safari */
|
|
108
|
+
height: calc(100% - 45px); /*all other browsers */
|
|
109
|
+
z-index: 100;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
[part~="sidebar-content"] {
|
|
113
|
+
position: absolute;
|
|
114
|
+
top: 0;
|
|
115
|
+
bottom: 0;
|
|
116
|
+
overflow: auto;
|
|
117
|
+
width: 100%;
|
|
118
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
[part~="thumbnail-view"] {
|
|
122
|
+
position: absolute;
|
|
123
|
+
width: calc(100% - 60px);
|
|
124
|
+
top: 0;
|
|
125
|
+
bottom: 0;
|
|
126
|
+
padding: 10px 30px 0;
|
|
127
|
+
overflow: auto;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
[part~="toolbar"] {
|
|
131
|
+
height: 44px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.page {
|
|
135
|
+
position: relative;
|
|
136
|
+
margin: 0 auto;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.textLayer {
|
|
140
|
+
position: absolute;
|
|
141
|
+
left: 0;
|
|
142
|
+
top: 0;
|
|
143
|
+
right: 0;
|
|
144
|
+
bottom: 0;
|
|
145
|
+
overflow: hidden;
|
|
146
|
+
line-height: 1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.textLayer > span {
|
|
150
|
+
color: transparent;
|
|
151
|
+
position: absolute;
|
|
152
|
+
white-space: pre;
|
|
153
|
+
cursor: text;
|
|
154
|
+
-webkit-transform-origin: 0% 0%;
|
|
155
|
+
transform-origin: 0% 0%;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.textLayer .highlight {
|
|
159
|
+
margin: -1px;
|
|
160
|
+
padding: 1px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.textLayer .highlight.begin {
|
|
164
|
+
border-radius: 4px 0 0 4px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.textLayer .highlight.end {
|
|
168
|
+
border-radius: 0 4px 4px 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.textLayer .highlight.middle {
|
|
172
|
+
border-radius: 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.textLayer .endOfContent {
|
|
176
|
+
display: block;
|
|
177
|
+
position: absolute;
|
|
178
|
+
left: 0;
|
|
179
|
+
top: 100%;
|
|
180
|
+
right: 0;
|
|
181
|
+
bottom: 0;
|
|
182
|
+
z-index: -1;
|
|
183
|
+
cursor: default;
|
|
184
|
+
-webkit-user-select: none;
|
|
185
|
+
-moz-user-select: none;
|
|
186
|
+
-ms-user-select: none;
|
|
187
|
+
user-select: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.textLayer .endOfContent.active {
|
|
191
|
+
top: 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
#header {
|
|
195
|
+
display: flex;
|
|
196
|
+
flex-direction: row;
|
|
197
|
+
align-items: baseline;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
::slotted(#currentPage) {
|
|
201
|
+
align-self: baseline;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
#outerContainer.sidebarOpen #viewerContainer {
|
|
205
|
+
transition-property: left;
|
|
206
|
+
left: 200px;
|
|
207
|
+
width: -moz-calc(100% - 200px); /* Firefox */
|
|
208
|
+
width: -webkit-calc(100% - 200px); /* Chrome, Safari */
|
|
209
|
+
width: calc(100% - 200px); /*all other browsers */
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
#outerContainer.sidebarOpen #sidebarContainer {
|
|
213
|
+
visibility: visible;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.thumbnail {
|
|
217
|
+
margin: 0 10px 5px;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.thumbnailImage {
|
|
221
|
+
border: 1px solid rgba(0, 0, 0, 0);
|
|
222
|
+
box-shadow:
|
|
223
|
+
0 0 0 1px rgba(0, 0, 0, 0.5),
|
|
224
|
+
0 2px 8px rgba(0, 0, 0, 0.3);
|
|
225
|
+
opacity: 1;
|
|
226
|
+
z-index: 99;
|
|
227
|
+
background-color: rgba(255, 255, 255, 1);
|
|
228
|
+
background-clip: content-box;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.thumbnailSelectionRing {
|
|
232
|
+
border-radius: 2px;
|
|
233
|
+
padding: 7px;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.thumbnail.selected > .thumbnailSelectionRing {
|
|
237
|
+
background-color: rgba(0, 0, 0, 0.15);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
[part~="toolbar"].ready ::slotted(.toolbar-zoom.hide-zoom) {
|
|
241
|
+
display: none;
|
|
242
|
+
}
|
|
282
243
|
`;
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
static get is() {
|
|
286
|
-
return 'vcf-pdf-viewer';
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
static get version() {
|
|
290
|
-
return '3.1.0';
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
static get properties() {
|
|
294
|
-
return {
|
|
295
|
-
/**
|
|
296
|
-
* You can set a pdf file that you want to render with src. Note that regular cross
|
|
297
|
-
* site scripting (XSS) rules apply. This means that the file should be on the same
|
|
298
|
-
* server as where the component is run, or that the server where the file is on should
|
|
299
|
-
* be configured to allow loading files from other sites.
|
|
300
|
-
*/
|
|
301
|
-
src: {
|
|
302
|
-
type: String,
|
|
303
|
-
observer: '__srcChanged'
|
|
304
|
-
},
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* The viewer, which takes care of rendering content into a DOM element.
|
|
308
|
-
*/
|
|
309
|
-
__viewer: Object,
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* The viewer for thumbnails.
|
|
313
|
-
*/
|
|
314
|
-
__thumbnailViewer: Object,
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* The link service.
|
|
318
|
-
*/
|
|
319
|
-
__linkService: Object,
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* A represenentation of a document that has been read in.
|
|
323
|
-
*/
|
|
324
|
-
__document: Object,
|
|
325
|
-
/**
|
|
326
|
-
* The title for the PDF shown in the toolbar of component. It uses both the file name and
|
|
327
|
-
* the title in the PDF metadata if available.
|
|
328
|
-
*/
|
|
329
|
-
__title: {
|
|
330
|
-
type: String,
|
|
331
|
-
value: 'PDF'
|
|
332
|
-
},
|
|
333
|
-
/**
|
|
334
|
-
* Relative filename
|
|
335
|
-
*/
|
|
336
|
-
__filename: String,
|
|
337
|
-
/**
|
|
338
|
-
* The pdf metadata title
|
|
339
|
-
*/
|
|
340
|
-
__pdfTitle: String,
|
|
341
|
-
/**
|
|
342
|
-
* The level of zoom on the document.
|
|
343
|
-
* Allowed values are
|
|
344
|
-
* - Number, for zoom percentage. Eg. 1.5 means 150% zoom
|
|
345
|
-
* - 'auto', default value
|
|
346
|
-
* - 'page-fit', fit a full page into component
|
|
347
|
-
*/
|
|
348
|
-
zoom: {
|
|
349
|
-
type: String,
|
|
350
|
-
value: 'auto'
|
|
351
|
-
},
|
|
352
|
-
/**
|
|
353
|
-
* The current page visible viewed right now
|
|
354
|
-
*/
|
|
355
|
-
currentPage: {
|
|
356
|
-
type: String,
|
|
357
|
-
value: "1"
|
|
358
|
-
},
|
|
359
|
-
/**
|
|
360
|
-
* Total amount of pages in an opened document
|
|
361
|
-
*/
|
|
362
|
-
__totalPages: Number,
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Loading state
|
|
366
|
-
*/
|
|
367
|
-
__loading: {
|
|
368
|
-
type: Boolean,
|
|
369
|
-
value: true
|
|
370
|
-
},
|
|
244
|
+
}
|
|
371
245
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
__sidebarOpen: {
|
|
376
|
-
type: Boolean,
|
|
377
|
-
value: false
|
|
378
|
-
},
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Flag to indicate if toolbar should only show filename as title
|
|
382
|
-
*/
|
|
383
|
-
toolbarOnlyFilename: {
|
|
384
|
-
type: Boolean,
|
|
385
|
-
value: false
|
|
386
|
-
},
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Property to define auto zoom label
|
|
390
|
-
*/
|
|
391
|
-
autoZoomOptionLabel: {
|
|
392
|
-
type: String,
|
|
393
|
-
value: "Automatic zoom"
|
|
394
|
-
},
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Property to define page fit zoom label
|
|
398
|
-
*/
|
|
399
|
-
fitZoomOptionLabel: {
|
|
400
|
-
type: String,
|
|
401
|
-
value: "Page fit"
|
|
402
|
-
},
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Property to define a custom title for the viewer
|
|
406
|
-
*/
|
|
407
|
-
customTitle: {
|
|
408
|
-
type: String,
|
|
409
|
-
value: ""
|
|
410
|
-
},
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Renders interactive form elements in the annotation layer (html) if true,
|
|
414
|
-
* renders values of form elements directly onto the canvas if false
|
|
415
|
-
*/
|
|
416
|
-
renderInteractiveForms: {
|
|
417
|
-
type: Boolean,
|
|
418
|
-
value: true
|
|
419
|
-
},
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* Allows to hide the zoom dropdown. By default it's always shown.
|
|
423
|
-
*/
|
|
424
|
-
hideZoom: {
|
|
425
|
-
type: Boolean,
|
|
426
|
-
value: false
|
|
427
|
-
},
|
|
428
|
-
|
|
429
|
-
__zoomItems: {
|
|
430
|
-
computed: '__computeZoomItems(autoZoomOptionLabel, fitZoomOptionLabel)'
|
|
431
|
-
},
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* Property to define a custom tooltip for the sidebar toggle button
|
|
435
|
-
*/
|
|
436
|
-
sidebarToggleTooltip: {
|
|
437
|
-
type: String,
|
|
438
|
-
value: ""
|
|
439
|
-
},
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Property to define a custom tooltip for the previous page button
|
|
443
|
-
*/
|
|
444
|
-
previousPageTooltip: {
|
|
445
|
-
type: String,
|
|
446
|
-
value: ""
|
|
447
|
-
},
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* Property to define a custom tooltip for the next page button
|
|
451
|
-
*/
|
|
452
|
-
nextPageTooltip: {
|
|
453
|
-
type: String,
|
|
454
|
-
value: ""
|
|
455
|
-
},
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
__createToolbarButton() {
|
|
460
|
-
const icon = document.createElement('vaadin-icon');
|
|
461
|
-
icon.setAttribute('slot', 'prefix');
|
|
462
|
-
|
|
463
|
-
const tooltip = document.createElement('vaadin-tooltip');
|
|
464
|
-
tooltip.setAttribute('slot', 'tooltip');
|
|
465
|
-
|
|
466
|
-
const button = document.createElement('vaadin-button');
|
|
467
|
-
button.classList.add('toolbar-button');
|
|
468
|
-
button.setAttribute('theme', 'icon');
|
|
469
|
-
|
|
470
|
-
button.appendChild(icon);
|
|
471
|
-
button.appendChild(tooltip);
|
|
472
|
-
return button;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* Adds toggle button to the toolbar slot named "sidebar-toggle-button-slot".
|
|
477
|
-
*/
|
|
478
|
-
_createSideBarToggleButton() {
|
|
479
|
-
const button = this.__createToolbarButton();
|
|
480
|
-
const icon = button.querySelector('vaadin-icon');
|
|
481
|
-
icon.classList.add('toggle-button-icon')
|
|
482
|
-
button.querySelector('vaadin-tooltip').setAttribute('text', this.sidebarToggleTooltip);
|
|
483
|
-
button.setAttribute('slot', 'sidebar-toggle-button-slot');
|
|
484
|
-
button.setAttribute('id','sidebarToggle');
|
|
485
|
-
button.setAttribute('aria-label', 'Sidebar toggle');
|
|
486
|
-
button.addEventListener('click', () => {
|
|
487
|
-
this.__toogleSidebar();
|
|
488
|
-
if(this.$.outerContainer.classList.contains('sidebarOpen')) {
|
|
489
|
-
icon.classList.add('sidebarOpen');
|
|
490
|
-
} else {
|
|
491
|
-
icon.classList.remove('sidebarOpen');
|
|
492
|
-
}
|
|
493
|
-
});
|
|
494
|
-
this.appendChild(button);
|
|
495
|
-
}
|
|
246
|
+
get slotStyles() {
|
|
247
|
+
const tag = "vcf-pdf-viewer";
|
|
248
|
+
const lumo = '[data-application-theme="lumo"]';
|
|
496
249
|
|
|
497
250
|
/**
|
|
498
|
-
*
|
|
251
|
+
* These rules target a <vaadin-text-field> element with a child element
|
|
252
|
+
* having the 'toggle-button' class name. We can't use `::slotted()` as
|
|
253
|
+
* the toggle button is not a direct child of the month picker element.
|
|
254
|
+
* Also for `vaadin-popover` we can't use `::part()` after `::slotted()`.
|
|
499
255
|
*/
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
button.setAttribute('slot', 'previous-page-button-slot');
|
|
505
|
-
button.setAttribute('id', 'previousPage');
|
|
506
|
-
button.setAttribute('aria-label', 'Previous page');
|
|
507
|
-
button.addEventListener('click', () => this.__previousPage());
|
|
508
|
-
this.appendChild(button);
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
/**
|
|
512
|
-
* Adds next page button to the toolbar slot named "next-page-button-slot".
|
|
513
|
-
*/
|
|
514
|
-
_createNextPageButton() {
|
|
515
|
-
const button = this.__createToolbarButton();
|
|
516
|
-
button.querySelector('vaadin-icon').classList.add('next-page-button-icon')
|
|
517
|
-
button.querySelector('vaadin-tooltip').setAttribute('text', this.nextPageTooltip);
|
|
518
|
-
button.setAttribute('slot', 'next-page-button-slot');
|
|
519
|
-
button.setAttribute('id', 'nextPage');
|
|
520
|
-
button.setAttribute('aria-label', 'Next page');
|
|
521
|
-
button.addEventListener('click', () => this.__nextPage());
|
|
522
|
-
this.appendChild(button);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Adds current page text field to the toolbar slot named "toolbar-current-page-slot".
|
|
527
|
-
*/
|
|
528
|
-
_createCurrentPageTextField() {
|
|
529
|
-
const textField = document.createElement('vaadin-text-field');
|
|
530
|
-
textField.setAttribute('slot', 'toolbar-current-page-slot');
|
|
531
|
-
textField.setAttribute('id', 'currentPage');
|
|
532
|
-
textField.classList.add('toolbar-current-page');
|
|
533
|
-
textField.setAttribute('value', this.currentPage);
|
|
534
|
-
textField.addEventListener('change', () => this.__pageChange());
|
|
535
|
-
this.appendChild(textField);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
/**
|
|
539
|
-
* Adds zoom select to the toolbar slot named "toolbar-zoom-slot".
|
|
540
|
-
*/
|
|
541
|
-
_createZoomSelect() {
|
|
542
|
-
const select = document.createElement('vaadin-select');
|
|
543
|
-
select.setAttribute('slot', 'toolbar-zoom-slot');
|
|
544
|
-
select.setAttribute('id', 'zoom');
|
|
545
|
-
select.classList.add('toolbar-zoom');
|
|
546
|
-
select.setAttribute('value', this.zoom);
|
|
547
|
-
select.items = this.__zoomItems;
|
|
548
|
-
select.addEventListener('value-changed', (e) => this.__zoomChanged(e.detail.value));
|
|
549
|
-
if(this.hideZoom) {
|
|
550
|
-
select.classList.add('hide-zoom');
|
|
551
|
-
} else {
|
|
552
|
-
select.classList.remove('hide-zoom');
|
|
256
|
+
return [
|
|
257
|
+
`
|
|
258
|
+
${tag}:not(${lumo}) vaadin-button.toolbar-button vaadin-icon {
|
|
259
|
+
display: none;
|
|
553
260
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
{ label: '50%', value:'0.5' },
|
|
562
|
-
{ label: '75%', value:'0.75' },
|
|
563
|
-
{ label: '100%', value:'1.0' },
|
|
564
|
-
{ label: '125%', value:'1.25' },
|
|
565
|
-
{ label: '150%', value:'1.5' },
|
|
566
|
-
{ label: '200%', value:'2.0' },
|
|
567
|
-
{ label: '300%', value:'3.0' },
|
|
568
|
-
{ label: '400%', value:'4.0' }
|
|
569
|
-
]
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
static get observers() {
|
|
573
|
-
return [
|
|
574
|
-
'__setTitle(__pdfTitle, __filename)'
|
|
575
|
-
];
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
__setTitle(pdfTitle, filename) {
|
|
579
|
-
if(this.customTitle){
|
|
580
|
-
this.__title = this.customTitle;
|
|
581
|
-
} else if(this.__viewer && this.toolbarOnlyFilename && filename) {
|
|
582
|
-
this.__title = filename;
|
|
583
|
-
} else if (pdfTitle && filename) {
|
|
584
|
-
this.__title = pdfTitle + ' - ' + filename;
|
|
585
|
-
} else if (pdfTitle) {
|
|
586
|
-
this.__title = pdfTitle;
|
|
587
|
-
} else if (filename) {
|
|
588
|
-
this.__title = filename;
|
|
589
|
-
} else {
|
|
590
|
-
this.__title = 'PDF';
|
|
261
|
+
|
|
262
|
+
${tag}:not(${lumo}) vaadin-button.toolbar-button {
|
|
263
|
+
height: var(--vaadin-icon-size, 1.5lh);
|
|
264
|
+
width: var(--vaadin-icon-size, 1.5lh);
|
|
265
|
+
padding: 0;
|
|
266
|
+
justify-content: flex-start;
|
|
267
|
+
box-sizing: content-box;
|
|
591
268
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
this.$.viewerContainer.addEventListener('focus', e => this.__setFocused(true), true);
|
|
608
|
-
this.$.viewerContainer.addEventListener('blur', e => this.__setFocused(false), true);
|
|
609
|
-
this.$.viewerContainer.addEventListener('mousedown', e => {
|
|
610
|
-
this._mousedown = true;
|
|
611
|
-
const mouseUpListener = () => {
|
|
612
|
-
this._mousedown = false;
|
|
613
|
-
document.removeEventListener('mouseup', mouseUpListener);
|
|
614
|
-
};
|
|
615
|
-
document.addEventListener('mouseup', mouseUpListener);
|
|
616
|
-
});
|
|
617
|
-
|
|
618
|
-
// options
|
|
619
|
-
const eventBus = new pdfUtils.EventBus();
|
|
620
|
-
this.__linkService = new pdfjsLinkService.PDFLinkService({
|
|
621
|
-
eventBus,
|
|
622
|
-
});
|
|
623
|
-
var pdfRenderingQueue = new pdfjsRenderingQueue.PDFRenderingQueue();
|
|
624
|
-
var l10n = NullL10n;
|
|
625
|
-
|
|
626
|
-
// pdfViewer
|
|
627
|
-
this.__viewer = new pdfjsViewer.PDFViewer({
|
|
628
|
-
container: this.$.viewerContainer,
|
|
629
|
-
textLayerMode: 2,
|
|
630
|
-
viewer: this.$.viewer,
|
|
631
|
-
eventBus: eventBus,
|
|
632
|
-
linkService: this.__linkService,
|
|
633
|
-
renderingQueue: pdfRenderingQueue,
|
|
634
|
-
l10n: l10n,
|
|
635
|
-
renderInteractiveForms: this.renderInteractiveForms
|
|
636
|
-
});
|
|
637
|
-
|
|
638
|
-
this.__linkService.setViewer(this.__viewer);
|
|
639
|
-
pdfRenderingQueue.setViewer(this.__viewer);
|
|
640
|
-
|
|
641
|
-
// thumbnailViewer
|
|
642
|
-
this.__thumbnailViewer = new pdfjsThumbnailViewer.PDFThumbnailViewer({
|
|
643
|
-
container: this.$.thumbnailView,
|
|
644
|
-
eventBus: eventBus,
|
|
645
|
-
linkService: this.__linkService,
|
|
646
|
-
renderingQueue: pdfRenderingQueue,
|
|
647
|
-
l10n: l10n
|
|
648
|
-
})
|
|
649
|
-
|
|
650
|
-
pdfRenderingQueue.setThumbnailViewer(this.__thumbnailViewer);
|
|
651
|
-
|
|
652
|
-
// listeners
|
|
653
|
-
eventBus.on('pagesinit', () => {
|
|
654
|
-
this.__viewer.currentScaleValue = this.zoom;
|
|
655
|
-
this.__loading = false;
|
|
656
|
-
this.__updateThumbnailViewer();
|
|
657
|
-
if(this.__sidebarOpen){
|
|
658
|
-
this.__openSidebar();
|
|
659
|
-
} else {
|
|
660
|
-
this.__closeSidebar();
|
|
661
|
-
}
|
|
662
|
-
this.__viewer.currentPage = this.setCurrentPage();
|
|
663
|
-
});
|
|
664
|
-
eventBus.on('pagechanging', (event) => {
|
|
665
|
-
this.__updateCurrentPageValue(event.pageNumber);
|
|
666
|
-
this.__updatePageNumberStates();
|
|
667
|
-
if(this.__thumbnailViewer && this.__thumbnailViewer.renderingQueue.isThumbnailViewEnabled){
|
|
668
|
-
this.__thumbnailViewer.scrollThumbnailIntoView(this.currentPage);
|
|
669
|
-
}
|
|
670
|
-
this.querySelector('#currentPage').value = this.currentPage;
|
|
671
|
-
});
|
|
672
|
-
|
|
673
|
-
this.__resizeObserver = new ResizeObserver(() => {
|
|
674
|
-
requestAnimationFrame(() => this.__recalculateSizes());
|
|
675
|
-
});
|
|
676
|
-
|
|
677
|
-
this.__resizeObserver.observe(this);
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
connectedCallback() {
|
|
681
|
-
super.connectedCallback();
|
|
682
|
-
this.__recalculateSizes();
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
__updateCurrentPageValue(pageNumber){
|
|
686
|
-
this.currentPage = "" + pageNumber;
|
|
687
|
-
this.dispatchEvent(new CustomEvent('currentPage-changed'));
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
__recalculateSizes() {
|
|
691
|
-
if (this.offsetWidth < 600) {
|
|
692
|
-
this.classList.add('small-size');
|
|
693
|
-
this.$.toolbar.classList.add('small-size');
|
|
694
|
-
} else {
|
|
695
|
-
this.classList.remove('small-size');
|
|
696
|
-
this.$.toolbar.classList.remove('small-size');
|
|
269
|
+
|
|
270
|
+
${tag}:not(${lumo}) vaadin-button.toolbar-button::before {
|
|
271
|
+
content: '';
|
|
272
|
+
flex: none;
|
|
273
|
+
background: var(--vaadin-input-field-button-text-color, var(--vaadin-text-color-secondary));
|
|
274
|
+
cursor: var(--vaadin-clickable-cursor);
|
|
275
|
+
touch-action: manipulation;
|
|
276
|
+
-webkit-tap-highlight-color: transparent;
|
|
277
|
+
-webkit-user-select: none;
|
|
278
|
+
user-select: none;
|
|
279
|
+
height: var(--vaadin-icon-size, 1.5lh);
|
|
280
|
+
width: var(--vaadin-icon-size, 1.5lh);
|
|
281
|
+
mask-size: var(--vaadin-icon-visual-size, 100%);
|
|
282
|
+
mask-position: 50%;
|
|
283
|
+
mask-repeat: no-repeat;
|
|
697
284
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
this.$.viewerContainer.setAttribute('focused', '');
|
|
702
|
-
if (!this._mousedown) {
|
|
703
|
-
this.$.viewerContainer.setAttribute('focus-ring', '');
|
|
704
|
-
}
|
|
705
|
-
} else {
|
|
706
|
-
this.$.viewerContainer.removeAttribute('focused');
|
|
707
|
-
this.$.viewerContainer.removeAttribute('focus-ring');
|
|
285
|
+
|
|
286
|
+
${tag}:not(${lumo}) vaadin-button.toolbar-button#sidebarToggle::before {
|
|
287
|
+
mask-image: var(--pdf-viewer-toggle-button-icon-closed);
|
|
708
288
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
// Is there already a document loaded?
|
|
713
|
-
if (this.__document) {
|
|
714
|
-
// We need to close the current document
|
|
715
|
-
return this.__close().then(() => {
|
|
716
|
-
// and start over with opening the new one
|
|
717
|
-
return this.__open(src);
|
|
718
|
-
});
|
|
289
|
+
|
|
290
|
+
${tag}:not(${lumo}) vaadin-button.toolbar-button#sidebarToggle:has(vaadin-icon.sidebarOpen)::before {
|
|
291
|
+
mask-image: var(--pdf-viewer-toggle-button-icon-open);
|
|
719
292
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
293
|
+
|
|
294
|
+
${tag}:not(${lumo}) vaadin-button.toolbar-button#previousPage::before {
|
|
295
|
+
mask-image: var(--pdf-viewer-previous-page-button-icon);
|
|
723
296
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
// Document loaded, specifying document for the viewer.
|
|
728
|
-
this.__thumbnailViewer.setDocument(pdfDocument);
|
|
729
|
-
this.__viewer.setDocument(pdfDocument);
|
|
730
|
-
this.__linkService.setDocument(pdfDocument);
|
|
731
|
-
|
|
732
|
-
this.$.toolbar.classList.add('ready');
|
|
733
|
-
this.__totalPages = pdfDocument.numPages;
|
|
734
|
-
this.__updatePageNumberStates();
|
|
735
|
-
this.__setPdfTitleFromMetadata(pdfDocument).then(() => {
|
|
736
|
-
this.dispatchEvent(new CustomEvent('document-loaded', {
|
|
737
|
-
detail: {
|
|
738
|
-
document: pdfDocument
|
|
739
|
-
}
|
|
740
|
-
}));
|
|
741
|
-
});
|
|
742
|
-
}, function (exception) {
|
|
743
|
-
console.error(exception && exception.message);
|
|
744
|
-
});
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
__srcChanged(newSrc) {
|
|
748
|
-
this.__open(newSrc);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
/**
|
|
752
|
-
* Closes opened PDF document.
|
|
753
|
-
* @returns {Promise} - Returns the promise, which is resolved when all
|
|
754
|
-
* destruction is completed.
|
|
755
|
-
*/
|
|
756
|
-
__close() {
|
|
757
|
-
this.$.toolbar.classList.remove('ready');
|
|
758
|
-
this.__filename = 'PDF';
|
|
759
|
-
if (!this.__document) {
|
|
760
|
-
return Promise.resolve();
|
|
297
|
+
|
|
298
|
+
${tag}:not(${lumo}) vaadin-button.toolbar-button#nextPage::before {
|
|
299
|
+
mask-image: var(--pdf-viewer-next-page-button-icon);
|
|
761
300
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
this.__viewer.setDocument(null);
|
|
767
|
-
this.__thumbnailViewer.setDocument(null);
|
|
768
|
-
this.__linkService.setDocument(null);
|
|
301
|
+
|
|
302
|
+
${tag}${lumo} vaadin-button[theme~="icon"] {
|
|
303
|
+
padding-left: 6px;
|
|
304
|
+
padding-right: 6px;
|
|
769
305
|
}
|
|
770
|
-
|
|
306
|
+
|
|
307
|
+
${tag}${lumo} vaadin-button.toolbar-button#sidebarToggle {
|
|
308
|
+
border: 2px solid;
|
|
309
|
+
border-color: rgba(0, 0, 0, 0.5);
|
|
310
|
+
}
|
|
311
|
+
`,
|
|
312
|
+
];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
render() {
|
|
316
|
+
return html`
|
|
317
|
+
<div id="outerContainer" part="outer-container">
|
|
318
|
+
<div id="sidebarContainer" part="sidebar-container">
|
|
319
|
+
<div id="sidebarContent" part="sidebar-content">
|
|
320
|
+
<div id="thumbnailView" part="thumbnail-view"></div>
|
|
321
|
+
</div>
|
|
322
|
+
</div>
|
|
323
|
+
<div id="mainContainer" part="main-container">
|
|
324
|
+
<div id="toolbar" part="toolbar">
|
|
325
|
+
<slot name="sidebar-toggle-button-slot"></slot>
|
|
326
|
+
<span id="title" part="toolbar-text toolbar-title"
|
|
327
|
+
>${this.__title}</span
|
|
328
|
+
>
|
|
329
|
+
<slot name="toolbar-zoom-slot"></slot>
|
|
330
|
+
<div part="toolbar-pages">
|
|
331
|
+
<slot name="toolbar-current-page-slot"></slot>
|
|
332
|
+
<span
|
|
333
|
+
id="pageSeparator"
|
|
334
|
+
part="toolbar-text toolbar-page-separator"
|
|
335
|
+
>/</span
|
|
336
|
+
>
|
|
337
|
+
<span id="totalPages" part="toolbar-text toolbar-total-pages"
|
|
338
|
+
>${this.__totalPages}</span
|
|
339
|
+
>
|
|
340
|
+
<slot name="previous-page-button-slot"></slot>
|
|
341
|
+
<slot name="next-page-button-slot"></slot>
|
|
342
|
+
</div>
|
|
343
|
+
<slot></slot>
|
|
344
|
+
</div>
|
|
345
|
+
|
|
346
|
+
<div id="viewerContainer" part="viewer-container">
|
|
347
|
+
<div id="viewer" part="viewer"></div>
|
|
348
|
+
</div>
|
|
349
|
+
</div>
|
|
350
|
+
</div>
|
|
351
|
+
`;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
static get is() {
|
|
355
|
+
return "vcf-pdf-viewer";
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
static get version() {
|
|
359
|
+
return "4.0.0";
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
static get properties() {
|
|
363
|
+
return {
|
|
364
|
+
/**
|
|
365
|
+
* You can set a pdf file that you want to render with src. Note that regular cross
|
|
366
|
+
* site scripting (XSS) rules apply. This means that the file should be on the same
|
|
367
|
+
* server as where the component is run, or that the server where the file is on should
|
|
368
|
+
* be configured to allow loading files from other sites.
|
|
369
|
+
*/
|
|
370
|
+
src: { type: String },
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* The viewer, which takes care of rendering content into a DOM element.
|
|
374
|
+
*/
|
|
375
|
+
__viewer: Object,
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* The viewer for thumbnails.
|
|
379
|
+
*/
|
|
380
|
+
__thumbnailViewer: Object,
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* The link service.
|
|
384
|
+
*/
|
|
385
|
+
__linkService: Object,
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* A represenentation of a document that has been read in.
|
|
389
|
+
*/
|
|
390
|
+
__document: Object,
|
|
391
|
+
/**
|
|
392
|
+
* The title for the PDF shown in the toolbar of component. It uses both the file name and
|
|
393
|
+
* the title in the PDF metadata if available.
|
|
394
|
+
*/
|
|
395
|
+
__title: { type: String },
|
|
396
|
+
/**
|
|
397
|
+
* Relative filename
|
|
398
|
+
*/
|
|
399
|
+
__filename: String,
|
|
400
|
+
/**
|
|
401
|
+
* The pdf metadata title
|
|
402
|
+
*/
|
|
403
|
+
__pdfTitle: String,
|
|
404
|
+
/**
|
|
405
|
+
* The level of zoom on the document.
|
|
406
|
+
* Allowed values are
|
|
407
|
+
* - Number, for zoom percentage. Eg. 1.5 means 150% zoom
|
|
408
|
+
* - 'auto', default value
|
|
409
|
+
* - 'page-fit', fit a full page into component
|
|
410
|
+
*/
|
|
411
|
+
zoom: { type: String },
|
|
412
|
+
/**
|
|
413
|
+
* The current page visible viewed right now
|
|
414
|
+
*/
|
|
415
|
+
currentPage: { type: String },
|
|
416
|
+
/**
|
|
417
|
+
* Total amount of pages in an opened document
|
|
418
|
+
*/
|
|
419
|
+
__totalPages: Number,
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Loading state
|
|
423
|
+
*/
|
|
424
|
+
__loading: { type: Boolean },
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Whether sidebar is open after loading or not
|
|
428
|
+
*/
|
|
429
|
+
__sidebarOpen: { type: Boolean },
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Flag to indicate if toolbar should only show filename as title
|
|
433
|
+
*/
|
|
434
|
+
toolbarOnlyFilename: { type: Boolean },
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Property to define auto zoom label
|
|
438
|
+
*/
|
|
439
|
+
autoZoomOptionLabel: { type: String },
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Property to define page fit zoom label
|
|
443
|
+
*/
|
|
444
|
+
fitZoomOptionLabel: { type: String },
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Property to define a custom title for the viewer
|
|
448
|
+
*/
|
|
449
|
+
customTitle: { type: String },
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Renders interactive form elements in the annotation layer (html) if true,
|
|
453
|
+
* renders values of form elements directly onto the canvas if false
|
|
454
|
+
*/
|
|
455
|
+
renderInteractiveForms: { type: Boolean },
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Allows to hide the zoom dropdown. By default it's always shown.
|
|
459
|
+
*/
|
|
460
|
+
hideZoom: { type: Boolean },
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Property to define a custom tooltip for the sidebar toggle button
|
|
464
|
+
*/
|
|
465
|
+
sidebarToggleTooltip: { type: String },
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Property to define a custom tooltip for the previous page button
|
|
469
|
+
*/
|
|
470
|
+
previousPageTooltip: { type: String },
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Property to define a custom tooltip for the next page button
|
|
474
|
+
*/
|
|
475
|
+
nextPageTooltip: { type: String },
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
get __zoomItems() {
|
|
480
|
+
return this.__computeZoomItems(
|
|
481
|
+
this.autoZoomOptionLabel,
|
|
482
|
+
this.fitZoomOptionLabel,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
constructor() {
|
|
487
|
+
super();
|
|
488
|
+
this.__title = "PDF";
|
|
489
|
+
this.zoom = "auto";
|
|
490
|
+
this.currentPage = "1";
|
|
491
|
+
this.__loading = true;
|
|
492
|
+
this.__sidebarOpen = false;
|
|
493
|
+
this.toolbarOnlyFilename = false;
|
|
494
|
+
this.autoZoomOptionLabel = "Automatic zoom";
|
|
495
|
+
this.fitZoomOptionLabel = "Page fit";
|
|
496
|
+
this.customTitle = "";
|
|
497
|
+
this.renderInteractiveForms = true;
|
|
498
|
+
this.hideZoom = false;
|
|
499
|
+
this.sidebarToggleTooltip = "";
|
|
500
|
+
this.previousPageTooltip = "";
|
|
501
|
+
this.nextPageTooltip = "";
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
willUpdate(changedProperties) {
|
|
505
|
+
super.willUpdate(changedProperties);
|
|
506
|
+
|
|
507
|
+
// Compute filename if src changes
|
|
508
|
+
if (changedProperties.has("src")) {
|
|
509
|
+
this.__setFilename(this.src);
|
|
771
510
|
}
|
|
772
511
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
512
|
+
// Compute title before rendering to avoid setting reactive properties during update
|
|
513
|
+
if (
|
|
514
|
+
changedProperties.has("src") ||
|
|
515
|
+
changedProperties.has("customTitle") ||
|
|
516
|
+
changedProperties.has("toolbarOnlyFilename")
|
|
517
|
+
) {
|
|
518
|
+
this.__setTitle(this.__pdfTitle, this.__filename);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
updated(changedProperties) {
|
|
523
|
+
super.updated(changedProperties);
|
|
524
|
+
|
|
525
|
+
// Defer property synchronization to avoid "update during update" warning
|
|
526
|
+
// This ensures these calls happen after the current update cycle completes
|
|
527
|
+
Promise.resolve().then(() => {
|
|
528
|
+
if (changedProperties.has("src")) {
|
|
529
|
+
this.__srcChanged(this.src);
|
|
530
|
+
}
|
|
531
|
+
if (changedProperties.has("zoom")) {
|
|
532
|
+
const zoomSelect = this.querySelector("#zoom");
|
|
533
|
+
if (zoomSelect && zoomSelect.value !== this.zoom) {
|
|
534
|
+
zoomSelect.value = this.zoom;
|
|
780
535
|
}
|
|
781
|
-
this.
|
|
536
|
+
this.__zoomChanged(this.zoom);
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
__createToolbarButton() {
|
|
542
|
+
const icon = document.createElement("vaadin-icon");
|
|
543
|
+
icon.setAttribute("slot", "prefix");
|
|
544
|
+
|
|
545
|
+
const tooltip = document.createElement("vaadin-tooltip");
|
|
546
|
+
tooltip.setAttribute("slot", "tooltip");
|
|
547
|
+
|
|
548
|
+
const button = document.createElement("vaadin-button");
|
|
549
|
+
button.classList.add("toolbar-button");
|
|
550
|
+
button.setAttribute("theme", "icon tertiary contrast");
|
|
551
|
+
|
|
552
|
+
button.appendChild(icon);
|
|
553
|
+
button.appendChild(tooltip);
|
|
554
|
+
return button;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Adds toggle button to the toolbar slot named "sidebar-toggle-button-slot".
|
|
559
|
+
*/
|
|
560
|
+
_createSideBarToggleButton() {
|
|
561
|
+
const button = this.__createToolbarButton();
|
|
562
|
+
const icon = button.querySelector("vaadin-icon");
|
|
563
|
+
icon.classList.add("toggle-button-icon");
|
|
564
|
+
button
|
|
565
|
+
.querySelector("vaadin-tooltip")
|
|
566
|
+
.setAttribute("text", this.sidebarToggleTooltip);
|
|
567
|
+
button.setAttribute("slot", "sidebar-toggle-button-slot");
|
|
568
|
+
button.setAttribute("id", "sidebarToggle");
|
|
569
|
+
button.setAttribute("aria-label", "Sidebar toggle");
|
|
570
|
+
button.addEventListener("click", () => {
|
|
571
|
+
this.__toogleSidebar();
|
|
572
|
+
if (this._outerContainer.classList.contains("sidebarOpen")) {
|
|
573
|
+
icon.classList.add("sidebarOpen");
|
|
574
|
+
} else {
|
|
575
|
+
icon.classList.remove("sidebarOpen");
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
this.appendChild(button);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Adds previous page button to the toolbar slot named "previous-page-button-slot".
|
|
583
|
+
*/
|
|
584
|
+
_createPreviousPageButton() {
|
|
585
|
+
const button = this.__createToolbarButton();
|
|
586
|
+
button
|
|
587
|
+
.querySelector("vaadin-icon")
|
|
588
|
+
.classList.add("previous-page-button-icon");
|
|
589
|
+
button
|
|
590
|
+
.querySelector("vaadin-tooltip")
|
|
591
|
+
.setAttribute("text", this.previousPageTooltip);
|
|
592
|
+
button.setAttribute("slot", "previous-page-button-slot");
|
|
593
|
+
button.setAttribute("id", "previousPage");
|
|
594
|
+
button.setAttribute("aria-label", "Previous page");
|
|
595
|
+
button.addEventListener("click", () => this.__previousPage());
|
|
596
|
+
this.appendChild(button);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Adds next page button to the toolbar slot named "next-page-button-slot".
|
|
601
|
+
*/
|
|
602
|
+
_createNextPageButton() {
|
|
603
|
+
const button = this.__createToolbarButton();
|
|
604
|
+
button.querySelector("vaadin-icon").classList.add("next-page-button-icon");
|
|
605
|
+
button
|
|
606
|
+
.querySelector("vaadin-tooltip")
|
|
607
|
+
.setAttribute("text", this.nextPageTooltip);
|
|
608
|
+
button.setAttribute("slot", "next-page-button-slot");
|
|
609
|
+
button.setAttribute("id", "nextPage");
|
|
610
|
+
button.setAttribute("aria-label", "Next page");
|
|
611
|
+
button.addEventListener("click", () => this.__nextPage());
|
|
612
|
+
this.appendChild(button);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Adds current page text field to the toolbar slot named "toolbar-current-page-slot".
|
|
617
|
+
*/
|
|
618
|
+
_createCurrentPageTextField() {
|
|
619
|
+
const textField = document.createElement("vaadin-text-field");
|
|
620
|
+
textField.setAttribute("slot", "toolbar-current-page-slot");
|
|
621
|
+
textField.setAttribute("id", "currentPage");
|
|
622
|
+
textField.classList.add("toolbar-current-page");
|
|
623
|
+
textField.setAttribute("value", this.currentPage);
|
|
624
|
+
textField.addEventListener("change", () => this.__pageChange());
|
|
625
|
+
this.appendChild(textField);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Adds zoom select to the toolbar slot named "toolbar-zoom-slot".
|
|
630
|
+
*/
|
|
631
|
+
_createZoomSelect() {
|
|
632
|
+
const select = document.createElement("vaadin-select");
|
|
633
|
+
select.setAttribute("slot", "toolbar-zoom-slot");
|
|
634
|
+
select.setAttribute("id", "zoom");
|
|
635
|
+
select.classList.add("toolbar-zoom");
|
|
636
|
+
select.setAttribute("value", this.zoom);
|
|
637
|
+
select.items = this.__zoomItems;
|
|
638
|
+
select.addEventListener("value-changed", (e) => {
|
|
639
|
+
if (e.detail.value !== this.zoom) {
|
|
640
|
+
this.__zoomChanged(e.detail.value);
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
if (this.hideZoom) {
|
|
644
|
+
select.classList.add("hide-zoom");
|
|
645
|
+
} else {
|
|
646
|
+
select.classList.remove("hide-zoom");
|
|
782
647
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
648
|
+
this.appendChild(select);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
__computeZoomItems(autoZoomOptionLabel, fitZoomOptionLabel) {
|
|
652
|
+
return [
|
|
653
|
+
{ label: autoZoomOptionLabel, value: "auto" },
|
|
654
|
+
{ label: fitZoomOptionLabel, value: "page-fit" },
|
|
655
|
+
{ label: "50%", value: "0.5" },
|
|
656
|
+
{ label: "75%", value: "0.75" },
|
|
657
|
+
{ label: "100%", value: "1.0" },
|
|
658
|
+
{ label: "125%", value: "1.25" },
|
|
659
|
+
{ label: "150%", value: "1.5" },
|
|
660
|
+
{ label: "200%", value: "2.0" },
|
|
661
|
+
{ label: "300%", value: "3.0" },
|
|
662
|
+
{ label: "400%", value: "4.0" },
|
|
663
|
+
];
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
__setTitle(pdfTitle, filename) {
|
|
667
|
+
if (this.customTitle) {
|
|
668
|
+
this.__title = this.customTitle;
|
|
669
|
+
} else if (this.__viewer && this.toolbarOnlyFilename && filename) {
|
|
670
|
+
this.__title = filename;
|
|
671
|
+
} else if (pdfTitle && filename) {
|
|
672
|
+
this.__title = pdfTitle + " - " + filename;
|
|
673
|
+
} else if (pdfTitle) {
|
|
674
|
+
this.__title = pdfTitle;
|
|
675
|
+
} else if (filename) {
|
|
676
|
+
this.__title = filename;
|
|
677
|
+
} else {
|
|
678
|
+
this.__title = "PDF";
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
_addToolbarButtons() {
|
|
683
|
+
this._createSideBarToggleButton();
|
|
684
|
+
this._createZoomSelect();
|
|
685
|
+
this._createCurrentPageTextField();
|
|
686
|
+
this._createPreviousPageButton();
|
|
687
|
+
this._createNextPageButton();
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
firstUpdated() {
|
|
691
|
+
this._toolbar = this.shadowRoot.querySelector("#toolbar");
|
|
692
|
+
this._viewerContainer = this.shadowRoot.querySelector("#viewerContainer");
|
|
693
|
+
this._outerContainer = this.shadowRoot.querySelector("#outerContainer");
|
|
694
|
+
this._viewer = this.shadowRoot.querySelector("#viewer");
|
|
695
|
+
this._thumbnailView = this.shadowRoot.querySelector("#thumbnailView");
|
|
696
|
+
|
|
697
|
+
this._addToolbarButtons();
|
|
698
|
+
|
|
699
|
+
this._viewerContainer.addEventListener(
|
|
700
|
+
"focus",
|
|
701
|
+
(e) => this.__setFocused(true),
|
|
702
|
+
true,
|
|
703
|
+
);
|
|
704
|
+
this._viewerContainer.addEventListener(
|
|
705
|
+
"blur",
|
|
706
|
+
(e) => this.__setFocused(false),
|
|
707
|
+
true,
|
|
708
|
+
);
|
|
709
|
+
this._viewerContainer.addEventListener("mousedown", (e) => {
|
|
710
|
+
this._mousedown = true;
|
|
711
|
+
const mouseUpListener = () => {
|
|
712
|
+
this._mousedown = false;
|
|
713
|
+
document.removeEventListener("mouseup", mouseUpListener);
|
|
714
|
+
};
|
|
715
|
+
document.addEventListener("mouseup", mouseUpListener);
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// options
|
|
719
|
+
const eventBus = new pdfUtils.EventBus();
|
|
720
|
+
|
|
721
|
+
// Defer initialization of reactive controller properties to avoid immediate update request
|
|
722
|
+
// that triggers "update scheduled after update" warning.
|
|
723
|
+
Promise.resolve().then(() => {
|
|
724
|
+
this.__linkService = new pdfjsLinkService.PDFLinkService({
|
|
725
|
+
eventBus,
|
|
726
|
+
});
|
|
727
|
+
var pdfRenderingQueue = new pdfjsRenderingQueue.PDFRenderingQueue();
|
|
728
|
+
var l10n = NullL10n;
|
|
729
|
+
|
|
730
|
+
// pdfViewer
|
|
731
|
+
this.__viewer = new pdfjsViewer.PDFViewer({
|
|
732
|
+
container: this._viewerContainer,
|
|
733
|
+
textLayerMode: 2,
|
|
734
|
+
viewer: this._viewer,
|
|
735
|
+
eventBus: eventBus,
|
|
736
|
+
linkService: this.__linkService,
|
|
737
|
+
renderingQueue: pdfRenderingQueue,
|
|
738
|
+
l10n: l10n,
|
|
739
|
+
renderInteractiveForms: this.renderInteractiveForms,
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
this.__linkService.setViewer(this.__viewer);
|
|
743
|
+
pdfRenderingQueue.setViewer(this.__viewer);
|
|
744
|
+
|
|
745
|
+
// thumbnailViewer
|
|
746
|
+
this.__thumbnailViewer = new pdfjsThumbnailViewer.PDFThumbnailViewer({
|
|
747
|
+
container: this._thumbnailView,
|
|
748
|
+
eventBus: eventBus,
|
|
749
|
+
linkService: this.__linkService,
|
|
750
|
+
renderingQueue: pdfRenderingQueue,
|
|
751
|
+
l10n: l10n,
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
pdfRenderingQueue.setThumbnailViewer(this.__thumbnailViewer);
|
|
755
|
+
|
|
756
|
+
// Initialize listeners after viewer creation
|
|
757
|
+
this.__initListeners(eventBus);
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
__initListeners(eventBus) {
|
|
762
|
+
// listeners
|
|
763
|
+
eventBus.on("pagesinit", () => {
|
|
764
|
+
this.__viewer.currentScaleValue = this.zoom;
|
|
765
|
+
this.__loading = false;
|
|
766
|
+
this.__updateThumbnailViewer();
|
|
767
|
+
if (this.__sidebarOpen) {
|
|
768
|
+
this.__openSidebar();
|
|
769
|
+
} else {
|
|
770
|
+
this.__closeSidebar();
|
|
771
|
+
}
|
|
772
|
+
this.__viewer.currentPage = this.setCurrentPage();
|
|
773
|
+
});
|
|
774
|
+
eventBus.on("pagechanging", (event) => {
|
|
775
|
+
this.__updateCurrentPageValue(event.pageNumber);
|
|
776
|
+
this.__updatePageNumberStates();
|
|
777
|
+
if (
|
|
778
|
+
this.__thumbnailViewer &&
|
|
779
|
+
this.__thumbnailViewer.renderingQueue.isThumbnailViewEnabled
|
|
780
|
+
) {
|
|
781
|
+
this.__thumbnailViewer.scrollThumbnailIntoView(this.currentPage);
|
|
782
|
+
}
|
|
783
|
+
this.querySelector("#currentPage").value = this.currentPage;
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
__updateCurrentPageValue(pageNumber) {
|
|
788
|
+
this.currentPage = "" + pageNumber;
|
|
789
|
+
this.dispatchEvent(new CustomEvent("currentPage-changed"));
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
__setFocused(focused) {
|
|
793
|
+
if (focused) {
|
|
794
|
+
this._viewerContainer.setAttribute("focused", "");
|
|
795
|
+
if (!this._mousedown) {
|
|
796
|
+
this._viewerContainer.setAttribute("focus-ring", "");
|
|
797
|
+
}
|
|
798
|
+
} else {
|
|
799
|
+
this._viewerContainer.removeAttribute("focused");
|
|
800
|
+
this._viewerContainer.removeAttribute("focus-ring");
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
__open(src) {
|
|
805
|
+
// Is there already a document loaded?
|
|
806
|
+
if (this.__document) {
|
|
807
|
+
// We need to close the current document
|
|
808
|
+
return this.__close().then(() => {
|
|
809
|
+
// and start over with opening the new one
|
|
810
|
+
return this.__open(src);
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
if (!src) {
|
|
814
|
+
// No file given, show nothing.
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
this.__setFilename(src);
|
|
818
|
+
this.__document = pdfjsLib.getDocument(new URL(src, document.baseURI).href);
|
|
819
|
+
return this.__document.promise.then(
|
|
820
|
+
(pdfDocument) => {
|
|
821
|
+
// Document loaded, specifying document for the viewer.
|
|
822
|
+
this.__thumbnailViewer.setDocument(pdfDocument);
|
|
823
|
+
this.__viewer.setDocument(pdfDocument);
|
|
824
|
+
this.__linkService.setDocument(pdfDocument);
|
|
825
|
+
|
|
826
|
+
this._toolbar.classList.add("ready");
|
|
827
|
+
this.__totalPages = pdfDocument.numPages;
|
|
828
|
+
this.__updatePageNumberStates();
|
|
829
|
+
this.__setPdfTitleFromMetadata(pdfDocument).then(() => {
|
|
830
|
+
this.dispatchEvent(
|
|
831
|
+
new CustomEvent("document-loaded", {
|
|
832
|
+
detail: {
|
|
833
|
+
document: pdfDocument,
|
|
834
|
+
},
|
|
835
|
+
}),
|
|
836
|
+
);
|
|
802
837
|
});
|
|
838
|
+
},
|
|
839
|
+
function (exception) {
|
|
840
|
+
console.error(exception && exception.message);
|
|
841
|
+
},
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
__srcChanged(newSrc) {
|
|
846
|
+
this.__open(newSrc);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Closes opened PDF document.
|
|
851
|
+
* @returns {Promise} - Returns the promise, which is resolved when all
|
|
852
|
+
* destruction is completed.
|
|
853
|
+
*/
|
|
854
|
+
__close() {
|
|
855
|
+
this._toolbar.classList.remove("ready");
|
|
856
|
+
this.__filename = "PDF";
|
|
857
|
+
if (!this.__document) {
|
|
858
|
+
return Promise.resolve();
|
|
803
859
|
}
|
|
804
860
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
861
|
+
var promise = this.__document.destroy();
|
|
862
|
+
if (this.__document) {
|
|
863
|
+
this.__document = null;
|
|
864
|
+
this.__viewer.setDocument(null);
|
|
865
|
+
this.__thumbnailViewer.setDocument(null);
|
|
866
|
+
this.__linkService.setDocument(null);
|
|
808
867
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
// webcomponents/shadow dom messing with
|
|
820
|
-
// TODO: Fix the issue so that we get rid of the error in log
|
|
821
|
-
this.__viewer.currentScaleValue = value;
|
|
822
|
-
this.__viewer.forceRendering();
|
|
868
|
+
return promise;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
__setFilename(src) {
|
|
872
|
+
let filename = pdfjsLib.getFilenameFromUrl(src) || src;
|
|
873
|
+
try {
|
|
874
|
+
filename = decodeURIComponent(filename);
|
|
875
|
+
} catch (e) {
|
|
876
|
+
// decodeURIComponent may throw URIError,
|
|
877
|
+
// fall back to using the unprocessed url in that case
|
|
823
878
|
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
879
|
+
this.__filename = filename;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
__setPdfTitleFromMetadata(pdfDocument) {
|
|
883
|
+
return pdfDocument.getMetadata().then((data) => {
|
|
884
|
+
let pdfTitle;
|
|
885
|
+
const metadata = data.metadata;
|
|
886
|
+
if (metadata && metadata.has("dc:title")) {
|
|
887
|
+
const title = metadata.get("dc:title");
|
|
888
|
+
// Ghostscript sometimes returns 'Untitled', so prevent setting the
|
|
889
|
+
// title to 'Untitled'.
|
|
890
|
+
if (title !== "Untitled") {
|
|
891
|
+
pdfTitle = title;
|
|
834
892
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
const info = data.info;
|
|
896
|
+
if (!pdfTitle && info && info["Title"]) {
|
|
897
|
+
pdfTitle = info["Title"];
|
|
898
|
+
}
|
|
899
|
+
this.__pdfTitle = pdfTitle;
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
__updatePageNumberStates() {
|
|
904
|
+
this.querySelector("#previousPage").disabled = this.currentPage === "1";
|
|
905
|
+
this.querySelector("#nextPage").disabled =
|
|
906
|
+
this.currentPage === "" + this.__totalPages;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
__zoomChanged(value) {
|
|
910
|
+
if (!this.__viewer || this.__loading) {
|
|
911
|
+
return;
|
|
839
912
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
913
|
+
// This logs error 'TextLayerBuilder._bindEvents: `this.cancel()` should have
|
|
914
|
+
// been called when the page was reset, or rendering cancelled.'
|
|
915
|
+
//
|
|
916
|
+
// There is a problem deep inside pdfjs viewer that causes an console.error()
|
|
917
|
+
// to be logged, but the component still works. It seems to be due to
|
|
918
|
+
// webcomponents/shadow dom messing with
|
|
919
|
+
// TODO: Fix the issue so that we get rid of the error in log
|
|
920
|
+
this.__viewer.currentScaleValue = value;
|
|
921
|
+
this.__viewer.forceRendering();
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
__pageChange(event) {
|
|
925
|
+
const currentPageValue = this.querySelector("#currentPage").value;
|
|
926
|
+
let pageNumber = parseInt(currentPageValue, 10);
|
|
927
|
+
if (isNaN(pageNumber)) {
|
|
928
|
+
pageNumber = this.__viewer.currentPageNumber;
|
|
929
|
+
this.querySelector("#currentPage").value = "" + pageNumber;
|
|
846
930
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
return this.__viewer.currentPageNumber;
|
|
931
|
+
if (pageNumber < 1) {
|
|
932
|
+
pageNumber = 1;
|
|
850
933
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
this.__viewer.currentPageNumber--;
|
|
934
|
+
if (pageNumber > this.__totalPages) {
|
|
935
|
+
pageNumber = this.__totalPages;
|
|
854
936
|
}
|
|
937
|
+
this.__viewer.currentPageNumber = pageNumber;
|
|
938
|
+
}
|
|
855
939
|
|
|
856
|
-
|
|
857
|
-
|
|
940
|
+
setCurrentPage(value) {
|
|
941
|
+
if (value != undefined) {
|
|
942
|
+
this.querySelector("#currentPage").value = "" + value;
|
|
858
943
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
944
|
+
this.__pageChange();
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
_getPage() {
|
|
948
|
+
return this.__viewer.currentPageNumber;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
__previousPage() {
|
|
952
|
+
this.__viewer.currentPageNumber--;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
__nextPage() {
|
|
956
|
+
this.__viewer.currentPageNumber++;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
__toogleSidebar() {
|
|
960
|
+
if (this._outerContainer.classList.length == 0) {
|
|
961
|
+
this.__openSidebar();
|
|
962
|
+
} else {
|
|
963
|
+
this.__closeSidebar();
|
|
866
964
|
}
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
__openSidebar() {
|
|
968
|
+
if (!this.__thumbnailViewer || this.__loading) {
|
|
969
|
+
this.__sidebarOpen = true;
|
|
970
|
+
} else {
|
|
971
|
+
this.__thumbnailViewer.renderingQueue.isThumbnailViewEnabled = true;
|
|
972
|
+
this.__updateThumbnailViewer();
|
|
973
|
+
this._outerContainer.classList.add("sidebarOpen");
|
|
876
974
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
__closeSidebar() {
|
|
978
|
+
if (!this.__thumbnailViewer || this.__loading) {
|
|
979
|
+
this.__sidebarOpen = false;
|
|
980
|
+
} else {
|
|
981
|
+
this.__thumbnailViewer.renderingQueue.isThumbnailViewEnabled = false;
|
|
982
|
+
this._outerContainer.classList.remove("sidebarOpen");
|
|
885
983
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
const thumbnailView = this.__thumbnailViewer.getThumbnail(i);
|
|
901
|
-
thumbnailView.anchor.onclick = function () {
|
|
902
|
-
const id = thumbnailView.id;
|
|
903
|
-
thumbnailView.linkService.goToPage(id);
|
|
904
|
-
component.dispatchEvent(new CustomEvent('thumbnail-clicked', {
|
|
905
|
-
detail: {
|
|
906
|
-
source: component,
|
|
907
|
-
pageNumber: id
|
|
908
|
-
}
|
|
909
|
-
}));
|
|
910
|
-
return false;
|
|
911
|
-
};
|
|
912
|
-
}
|
|
913
|
-
if(this.__thumbnailViewer && this.__thumbnailViewer.renderingQueue.isThumbnailViewEnabled){
|
|
914
|
-
this.__thumbnailViewer.scrollThumbnailIntoView(this.currentPage);
|
|
915
|
-
}
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
__updateThumbnailViewer() {
|
|
987
|
+
const pagesCount = this.__totalPages;
|
|
988
|
+
for (let i = 0; i < pagesCount; i++) {
|
|
989
|
+
const pageView = this.__viewer.getPageView(i);
|
|
990
|
+
if (
|
|
991
|
+
pageView.renderingState === pdfjsRenderingQueue.RenderingStates.FINISHED
|
|
992
|
+
) {
|
|
993
|
+
const thumbnailView = this.__thumbnailViewer.getThumbnail(i);
|
|
994
|
+
thumbnailView.setImage(pageView);
|
|
995
|
+
} else {
|
|
996
|
+
this.__thumbnailViewer.renderingQueue.renderHighestPriority();
|
|
997
|
+
}
|
|
916
998
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
999
|
+
var component = this;
|
|
1000
|
+
for (let i = 0; i < this.__thumbnailViewer._thumbnails.length; i++) {
|
|
1001
|
+
const thumbnailView = this.__thumbnailViewer.getThumbnail(i);
|
|
1002
|
+
thumbnailView.anchor.onclick = function () {
|
|
1003
|
+
const id = thumbnailView.id;
|
|
1004
|
+
thumbnailView.linkService.goToPage(id);
|
|
1005
|
+
component.dispatchEvent(
|
|
1006
|
+
new CustomEvent("thumbnail-clicked", {
|
|
1007
|
+
detail: {
|
|
1008
|
+
source: component,
|
|
1009
|
+
pageNumber: id,
|
|
1010
|
+
},
|
|
1011
|
+
}),
|
|
1012
|
+
);
|
|
1013
|
+
return false;
|
|
1014
|
+
};
|
|
925
1015
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
let delta = -90;
|
|
932
|
-
this.__viewer.pagesRotation += delta;
|
|
933
|
-
this.__viewer.forceRendering();
|
|
1016
|
+
if (
|
|
1017
|
+
this.__thumbnailViewer &&
|
|
1018
|
+
this.__thumbnailViewer.renderingQueue.isThumbnailViewEnabled
|
|
1019
|
+
) {
|
|
1020
|
+
this.__thumbnailViewer.scrollThumbnailIntoView(this.currentPage);
|
|
934
1021
|
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
_onResize() {
|
|
1025
|
+
if (this.offsetWidth < 600) {
|
|
1026
|
+
this.classList.add("small-size");
|
|
1027
|
+
this._toolbar.classList.add("small-size");
|
|
1028
|
+
} else {
|
|
1029
|
+
this.classList.remove("small-size");
|
|
1030
|
+
this._toolbar.classList.remove("small-size");
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* Rotates document clockwise.
|
|
1036
|
+
*/
|
|
1037
|
+
rotateCw() {
|
|
1038
|
+
let delta = 90;
|
|
1039
|
+
this.__viewer.pagesRotation += delta;
|
|
1040
|
+
this.__viewer.forceRendering();
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* Rotates document counterclockwise.
|
|
1045
|
+
*/
|
|
1046
|
+
rotateCcw() {
|
|
1047
|
+
let delta = -90;
|
|
1048
|
+
this.__viewer.pagesRotation += delta;
|
|
1049
|
+
this.__viewer.forceRendering();
|
|
1050
|
+
}
|
|
935
1051
|
}
|
|
936
1052
|
|
|
937
1053
|
customElements.define(PdfViewerElement.is, PdfViewerElement);
|
|
@@ -940,6 +1056,3 @@ customElements.define(PdfViewerElement.is, PdfViewerElement);
|
|
|
940
1056
|
* @namespace Vaadin
|
|
941
1057
|
*/
|
|
942
1058
|
window.Vaadin.PdfViewerElement = PdfViewerElement;
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|