UNPKG

9.84 kBJavaScriptView Raw
1/**
2 * @licstart The following is the entire license notice for the
3 * JavaScript code in this page
4 *
5 * Copyright 2022 Mozilla Foundation
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * @licend The above is the entire license notice for the
20 * JavaScript code in this page
21 */
22"use strict";
23
24Object.defineProperty(exports, "__esModule", {
25 value: true
26});
27exports.Toolbar = void 0;
28
29var _ui_utils = require("./ui_utils.js");
30
31var _pdf = require("../pdf");
32
33const PAGE_NUMBER_LOADING_INDICATOR = "visiblePageIsLoading";
34
35class Toolbar {
36 constructor(options, eventBus, l10n) {
37 this.toolbar = options.container;
38 this.eventBus = eventBus;
39 this.l10n = l10n;
40 this.buttons = [{
41 element: options.previous,
42 eventName: "previouspage"
43 }, {
44 element: options.next,
45 eventName: "nextpage"
46 }, {
47 element: options.zoomIn,
48 eventName: "zoomin"
49 }, {
50 element: options.zoomOut,
51 eventName: "zoomout"
52 }, {
53 element: options.print,
54 eventName: "print"
55 }, {
56 element: options.presentationModeButton,
57 eventName: "presentationmode"
58 }, {
59 element: options.download,
60 eventName: "download"
61 }, {
62 element: options.viewBookmark,
63 eventName: null
64 }, {
65 element: options.editorNoneButton,
66 eventName: "switchannotationeditormode",
67 eventDetails: {
68 mode: _pdf.AnnotationEditorType.NONE
69 }
70 }, {
71 element: options.editorFreeTextButton,
72 eventName: "switchannotationeditormode",
73 eventDetails: {
74 mode: _pdf.AnnotationEditorType.FREETEXT
75 }
76 }, {
77 element: options.editorInkButton,
78 eventName: "switchannotationeditormode",
79 eventDetails: {
80 mode: _pdf.AnnotationEditorType.INK
81 }
82 }];
83 this.buttons.push({
84 element: options.openFile,
85 eventName: "openfile"
86 });
87 this.items = {
88 numPages: options.numPages,
89 pageNumber: options.pageNumber,
90 scaleSelect: options.scaleSelect,
91 customScaleOption: options.customScaleOption,
92 previous: options.previous,
93 next: options.next,
94 zoomIn: options.zoomIn,
95 zoomOut: options.zoomOut,
96 editorNoneButton: options.editorNoneButton,
97 editorFreeTextButton: options.editorFreeTextButton,
98 editorFreeTextParamsToolbar: options.editorFreeTextParamsToolbar,
99 editorInkButton: options.editorInkButton,
100 editorInkParamsToolbar: options.editorInkParamsToolbar
101 };
102 this._wasLocalized = false;
103 this.reset();
104
105 this._bindListeners(options);
106 }
107
108 setPageNumber(pageNumber, pageLabel) {
109 this.pageNumber = pageNumber;
110 this.pageLabel = pageLabel;
111
112 this._updateUIState(false);
113 }
114
115 setPagesCount(pagesCount, hasPageLabels) {
116 this.pagesCount = pagesCount;
117 this.hasPageLabels = hasPageLabels;
118
119 this._updateUIState(true);
120 }
121
122 setPageScale(pageScaleValue, pageScale) {
123 this.pageScaleValue = (pageScaleValue || pageScale).toString();
124 this.pageScale = pageScale;
125
126 this._updateUIState(false);
127 }
128
129 reset() {
130 this.pageNumber = 0;
131 this.pageLabel = null;
132 this.hasPageLabels = false;
133 this.pagesCount = 0;
134 this.pageScaleValue = _ui_utils.DEFAULT_SCALE_VALUE;
135 this.pageScale = _ui_utils.DEFAULT_SCALE;
136
137 this._updateUIState(true);
138
139 this.updateLoadingIndicatorState();
140 this.eventBus.dispatch("toolbarreset", {
141 source: this
142 });
143 }
144
145 _bindListeners(options) {
146 const {
147 pageNumber,
148 scaleSelect
149 } = this.items;
150 const self = this;
151
152 for (const {
153 element,
154 eventName,
155 eventDetails
156 } of this.buttons) {
157 element.addEventListener("click", evt => {
158 if (eventName !== null) {
159 const details = {
160 source: this
161 };
162
163 if (eventDetails) {
164 for (const property in eventDetails) {
165 details[property] = eventDetails[property];
166 }
167 }
168
169 this.eventBus.dispatch(eventName, details);
170 }
171 });
172 }
173
174 pageNumber.addEventListener("click", function () {
175 this.select();
176 });
177 pageNumber.addEventListener("change", function () {
178 self.eventBus.dispatch("pagenumberchanged", {
179 source: self,
180 value: this.value
181 });
182 });
183 scaleSelect.addEventListener("change", function () {
184 if (this.value === "custom") {
185 return;
186 }
187
188 self.eventBus.dispatch("scalechanged", {
189 source: self,
190 value: this.value
191 });
192 });
193 scaleSelect.addEventListener("click", function (evt) {
194 const target = evt.target;
195
196 if (this.value === self.pageScaleValue && target.tagName.toUpperCase() === "OPTION") {
197 this.blur();
198 }
199 });
200 scaleSelect.oncontextmenu = _ui_utils.noContextMenuHandler;
201
202 this.eventBus._on("localized", () => {
203 this._wasLocalized = true;
204 this.#adjustScaleWidth();
205
206 this._updateUIState(true);
207 });
208
209 this.#bindEditorToolsListener(options);
210 }
211
212 #bindEditorToolsListener({
213 editorNoneButton,
214 editorFreeTextButton,
215 editorFreeTextParamsToolbar,
216 editorInkButton,
217 editorInkParamsToolbar
218 }) {
219 const editorModeChanged = (evt, disableButtons = false) => {
220 const editorButtons = [{
221 mode: _pdf.AnnotationEditorType.NONE,
222 button: editorNoneButton
223 }, {
224 mode: _pdf.AnnotationEditorType.FREETEXT,
225 button: editorFreeTextButton,
226 toolbar: editorFreeTextParamsToolbar
227 }, {
228 mode: _pdf.AnnotationEditorType.INK,
229 button: editorInkButton,
230 toolbar: editorInkParamsToolbar
231 }];
232
233 for (const {
234 mode,
235 button,
236 toolbar
237 } of editorButtons) {
238 const checked = mode === evt.mode;
239 button.classList.toggle("toggled", checked);
240 button.setAttribute("aria-checked", checked);
241 button.disabled = disableButtons;
242
243 if (toolbar) {
244 toolbar.classList.toggle("hidden", !checked);
245 }
246 }
247 };
248
249 this.eventBus._on("annotationeditormodechanged", editorModeChanged);
250
251 this.eventBus._on("toolbarreset", evt => {
252 if (evt.source === this) {
253 editorModeChanged({
254 mode: _pdf.AnnotationEditorType.NONE
255 }, true);
256 }
257 });
258 }
259
260 _updateUIState(resetNumPages = false) {
261 if (!this._wasLocalized) {
262 return;
263 }
264
265 const {
266 pageNumber,
267 pagesCount,
268 pageScaleValue,
269 pageScale,
270 items
271 } = this;
272
273 if (resetNumPages) {
274 if (this.hasPageLabels) {
275 items.pageNumber.type = "text";
276 } else {
277 items.pageNumber.type = "number";
278 this.l10n.get("of_pages", {
279 pagesCount
280 }).then(msg => {
281 items.numPages.textContent = msg;
282 });
283 }
284
285 items.pageNumber.max = pagesCount;
286 }
287
288 if (this.hasPageLabels) {
289 items.pageNumber.value = this.pageLabel;
290 this.l10n.get("page_of_pages", {
291 pageNumber,
292 pagesCount
293 }).then(msg => {
294 items.numPages.textContent = msg;
295 });
296 } else {
297 items.pageNumber.value = pageNumber;
298 }
299
300 items.previous.disabled = pageNumber <= 1;
301 items.next.disabled = pageNumber >= pagesCount;
302 items.zoomOut.disabled = pageScale <= _ui_utils.MIN_SCALE;
303 items.zoomIn.disabled = pageScale >= _ui_utils.MAX_SCALE;
304 this.l10n.get("page_scale_percent", {
305 scale: Math.round(pageScale * 10000) / 100
306 }).then(msg => {
307 let predefinedValueFound = false;
308
309 for (const option of items.scaleSelect.options) {
310 if (option.value !== pageScaleValue) {
311 option.selected = false;
312 continue;
313 }
314
315 option.selected = true;
316 predefinedValueFound = true;
317 }
318
319 if (!predefinedValueFound) {
320 items.customScaleOption.textContent = msg;
321 items.customScaleOption.selected = true;
322 }
323 });
324 }
325
326 updateLoadingIndicatorState(loading = false) {
327 const {
328 pageNumber
329 } = this.items;
330 pageNumber.classList.toggle(PAGE_NUMBER_LOADING_INDICATOR, loading);
331 }
332
333 async #adjustScaleWidth() {
334 const {
335 items,
336 l10n
337 } = this;
338 const predefinedValuesPromise = Promise.all([l10n.get("page_scale_auto"), l10n.get("page_scale_actual"), l10n.get("page_scale_fit"), l10n.get("page_scale_width")]);
339 await _ui_utils.animationStarted;
340 const style = getComputedStyle(items.scaleSelect),
341 scaleSelectContainerWidth = parseInt(style.getPropertyValue("--scale-select-container-width"), 10),
342 scaleSelectOverflow = parseInt(style.getPropertyValue("--scale-select-overflow"), 10);
343 const canvas = document.createElement("canvas");
344 const ctx = canvas.getContext("2d", {
345 alpha: false
346 });
347 ctx.font = `${style.fontSize} ${style.fontFamily}`;
348 let maxWidth = 0;
349
350 for (const predefinedValue of await predefinedValuesPromise) {
351 const {
352 width
353 } = ctx.measureText(predefinedValue);
354
355 if (width > maxWidth) {
356 maxWidth = width;
357 }
358 }
359
360 maxWidth += 2 * scaleSelectOverflow;
361
362 if (maxWidth > scaleSelectContainerWidth) {
363 _ui_utils.docStyle.setProperty("--scale-select-container-width", `${maxWidth}px`);
364 }
365
366 canvas.width = 0;
367 canvas.height = 0;
368 }
369
370}
371
372exports.Toolbar = Toolbar;
\No newline at end of file