UNPKG

8.27 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.PDFDocumentProperties = void 0;
28
29var _pdf = require("../pdf");
30
31var _ui_utils = require("./ui_utils.js");
32
33const DEFAULT_FIELD_CONTENT = "-";
34const NON_METRIC_LOCALES = ["en-us", "en-lr", "my"];
35const US_PAGE_NAMES = {
36 "8.5x11": "Letter",
37 "8.5x14": "Legal"
38};
39const METRIC_PAGE_NAMES = {
40 "297x420": "A3",
41 "210x297": "A4"
42};
43
44function getPageName(size, isPortrait, pageNames) {
45 const width = isPortrait ? size.width : size.height;
46 const height = isPortrait ? size.height : size.width;
47 return pageNames[`${width}x${height}`];
48}
49
50class PDFDocumentProperties {
51 #fieldData = null;
52
53 constructor({
54 dialog,
55 fields,
56 closeButton
57 }, overlayManager, eventBus, l10n, fileNameLookup) {
58 this.dialog = dialog;
59 this.fields = fields;
60 this.overlayManager = overlayManager;
61 this.l10n = l10n;
62 this._fileNameLookup = fileNameLookup;
63 this.#reset();
64 closeButton.addEventListener("click", this.close.bind(this));
65 this.overlayManager.register(this.dialog);
66
67 eventBus._on("pagechanging", evt => {
68 this._currentPageNumber = evt.pageNumber;
69 });
70
71 eventBus._on("rotationchanging", evt => {
72 this._pagesRotation = evt.pagesRotation;
73 });
74
75 this._isNonMetricLocale = true;
76 l10n.getLanguage().then(locale => {
77 this._isNonMetricLocale = NON_METRIC_LOCALES.includes(locale);
78 });
79 }
80
81 async open() {
82 await Promise.all([this.overlayManager.open(this.dialog), this._dataAvailableCapability.promise]);
83 const currentPageNumber = this._currentPageNumber;
84 const pagesRotation = this._pagesRotation;
85
86 if (this.#fieldData && currentPageNumber === this.#fieldData._currentPageNumber && pagesRotation === this.#fieldData._pagesRotation) {
87 this.#updateUI();
88 return;
89 }
90
91 const {
92 info,
93 contentLength
94 } = await this.pdfDocument.getMetadata();
95 const [fileName, fileSize, creationDate, modificationDate, pageSize, isLinearized] = await Promise.all([this._fileNameLookup(), this.#parseFileSize(contentLength), this.#parseDate(info.CreationDate), this.#parseDate(info.ModDate), this.pdfDocument.getPage(currentPageNumber).then(pdfPage => {
96 return this.#parsePageSize((0, _ui_utils.getPageSizeInches)(pdfPage), pagesRotation);
97 }), this.#parseLinearization(info.IsLinearized)]);
98 this.#fieldData = Object.freeze({
99 fileName,
100 fileSize,
101 title: info.Title,
102 author: info.Author,
103 subject: info.Subject,
104 keywords: info.Keywords,
105 creationDate,
106 modificationDate,
107 creator: info.Creator,
108 producer: info.Producer,
109 version: info.PDFFormatVersion,
110 pageCount: this.pdfDocument.numPages,
111 pageSize,
112 linearized: isLinearized,
113 _currentPageNumber: currentPageNumber,
114 _pagesRotation: pagesRotation
115 });
116 this.#updateUI();
117 const {
118 length
119 } = await this.pdfDocument.getDownloadInfo();
120
121 if (contentLength === length) {
122 return;
123 }
124
125 const data = Object.assign(Object.create(null), this.#fieldData);
126 data.fileSize = await this.#parseFileSize(length);
127 this.#fieldData = Object.freeze(data);
128 this.#updateUI();
129 }
130
131 async close() {
132 this.overlayManager.close(this.dialog);
133 }
134
135 setDocument(pdfDocument) {
136 if (this.pdfDocument) {
137 this.#reset();
138 this.#updateUI(true);
139 }
140
141 if (!pdfDocument) {
142 return;
143 }
144
145 this.pdfDocument = pdfDocument;
146
147 this._dataAvailableCapability.resolve();
148 }
149
150 #reset() {
151 this.pdfDocument = null;
152 this.#fieldData = null;
153 this._dataAvailableCapability = (0, _pdf.createPromiseCapability)();
154 this._currentPageNumber = 1;
155 this._pagesRotation = 0;
156 }
157
158 #updateUI(reset = false) {
159 if (reset || !this.#fieldData) {
160 for (const id in this.fields) {
161 this.fields[id].textContent = DEFAULT_FIELD_CONTENT;
162 }
163
164 return;
165 }
166
167 if (this.overlayManager.active !== this.dialog) {
168 return;
169 }
170
171 for (const id in this.fields) {
172 const content = this.#fieldData[id];
173 this.fields[id].textContent = content || content === 0 ? content : DEFAULT_FIELD_CONTENT;
174 }
175 }
176
177 async #parseFileSize(fileSize = 0) {
178 const kb = fileSize / 1024,
179 mb = kb / 1024;
180
181 if (!kb) {
182 return undefined;
183 }
184
185 return this.l10n.get(`document_properties_${mb >= 1 ? "mb" : "kb"}`, {
186 size_mb: mb >= 1 && (+mb.toPrecision(3)).toLocaleString(),
187 size_kb: mb < 1 && (+kb.toPrecision(3)).toLocaleString(),
188 size_b: fileSize.toLocaleString()
189 });
190 }
191
192 async #parsePageSize(pageSizeInches, pagesRotation) {
193 if (!pageSizeInches) {
194 return undefined;
195 }
196
197 if (pagesRotation % 180 !== 0) {
198 pageSizeInches = {
199 width: pageSizeInches.height,
200 height: pageSizeInches.width
201 };
202 }
203
204 const isPortrait = (0, _ui_utils.isPortraitOrientation)(pageSizeInches);
205 let sizeInches = {
206 width: Math.round(pageSizeInches.width * 100) / 100,
207 height: Math.round(pageSizeInches.height * 100) / 100
208 };
209 let sizeMillimeters = {
210 width: Math.round(pageSizeInches.width * 25.4 * 10) / 10,
211 height: Math.round(pageSizeInches.height * 25.4 * 10) / 10
212 };
213 let rawName = getPageName(sizeInches, isPortrait, US_PAGE_NAMES) || getPageName(sizeMillimeters, isPortrait, METRIC_PAGE_NAMES);
214
215 if (!rawName && !(Number.isInteger(sizeMillimeters.width) && Number.isInteger(sizeMillimeters.height))) {
216 const exactMillimeters = {
217 width: pageSizeInches.width * 25.4,
218 height: pageSizeInches.height * 25.4
219 };
220 const intMillimeters = {
221 width: Math.round(sizeMillimeters.width),
222 height: Math.round(sizeMillimeters.height)
223 };
224
225 if (Math.abs(exactMillimeters.width - intMillimeters.width) < 0.1 && Math.abs(exactMillimeters.height - intMillimeters.height) < 0.1) {
226 rawName = getPageName(intMillimeters, isPortrait, METRIC_PAGE_NAMES);
227
228 if (rawName) {
229 sizeInches = {
230 width: Math.round(intMillimeters.width / 25.4 * 100) / 100,
231 height: Math.round(intMillimeters.height / 25.4 * 100) / 100
232 };
233 sizeMillimeters = intMillimeters;
234 }
235 }
236 }
237
238 const [{
239 width,
240 height
241 }, unit, name, orientation] = await Promise.all([this._isNonMetricLocale ? sizeInches : sizeMillimeters, this.l10n.get(`document_properties_page_size_unit_${this._isNonMetricLocale ? "inches" : "millimeters"}`), rawName && this.l10n.get(`document_properties_page_size_name_${rawName.toLowerCase()}`), this.l10n.get(`document_properties_page_size_orientation_${isPortrait ? "portrait" : "landscape"}`)]);
242 return this.l10n.get(`document_properties_page_size_dimension_${name ? "name_" : ""}string`, {
243 width: width.toLocaleString(),
244 height: height.toLocaleString(),
245 unit,
246 name,
247 orientation
248 });
249 }
250
251 async #parseDate(inputDate) {
252 const dateObject = _pdf.PDFDateString.toDateObject(inputDate);
253
254 if (!dateObject) {
255 return undefined;
256 }
257
258 return this.l10n.get("document_properties_date_string", {
259 date: dateObject.toLocaleDateString(),
260 time: dateObject.toLocaleTimeString()
261 });
262 }
263
264 #parseLinearization(isLinearized) {
265 return this.l10n.get(`document_properties_linearized_${isLinearized ? "yes" : "no"}`);
266 }
267
268}
269
270exports.PDFDocumentProperties = PDFDocumentProperties;
\No newline at end of file