From 5f7ded4ff65b08ed771bf79e7a0285734556c5a3 Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Wed, 22 Jan 2014 00:07:07 +0100 Subject: [PATCH] Document properties --- l10n/en-US/viewer.properties | 20 ++ l10n/nl/viewer.properties | 20 ++ src/display/api.js | 4 + web/document_properties.js | 179 ++++++++++++++++++ ...ondaryToolbarButton-documentProperties.png | Bin 0 -> 1246 bytes web/password_prompt.js | 2 + web/secondary_toolbar.js | 17 +- web/viewer.css | 75 +++++++- web/viewer.html | 62 +++++- web/viewer.js | 24 ++- 10 files changed, 385 insertions(+), 18 deletions(-) create mode 100644 web/document_properties.js create mode 100644 web/images/secondaryToolbarButton-documentProperties.png diff --git a/l10n/en-US/viewer.properties b/l10n/en-US/viewer.properties index 2c893a4a3..97e2a9401 100644 --- a/l10n/en-US/viewer.properties +++ b/l10n/en-US/viewer.properties @@ -62,6 +62,26 @@ hand_tool_enable_label=Enable hand tool hand_tool_disable.title=Disable hand tool hand_tool_disable_label=Disable hand tool +# Document properties dialog box +document_properties.title=Document Properties +document_properties_label=Document Properties +document_properties_file_name=File name: +document_properties_file_size=File size: +document_properties_kb={{size_kb}} KB +document_properties_mb={{size_mb}} MB +document_properties_title=Title: +document_properties_author=Author: +document_properties_subject=Subject: +document_properties_keywords=Keywords: +document_properties_creation_date=Creation Date: +document_properties_modification_date=Modification Date: +document_properties_date_string={{date}}, {{time}} +document_properties_creator=Creator: +document_properties_producer=PDF Producer: +document_properties_version=PDF Version: +document_properties_page_count=Page Count: +document_properties_close=Close + # Tooltips and alt text for side panel toolbar buttons # (the _label strings are alt text for the buttons, the .title strings are # tooltips) diff --git a/l10n/nl/viewer.properties b/l10n/nl/viewer.properties index 38f266d5f..44f6b4420 100644 --- a/l10n/nl/viewer.properties +++ b/l10n/nl/viewer.properties @@ -62,6 +62,26 @@ hand_tool_enable_label=Handcursor inschakelen hand_tool_disable.title=Handcursor uitschakelen hand_tool_disable_label=Handcursor uitschakelen +# Document properties dialog box +document_properties.title=Documenteigenschappen +document_properties_label=Documenteigenschappen +document_properties_file_name=Bestandsnaam: +document_properties_file_size=Bestandsgrootte: +document_properties_kb={{size_kb}} KB +document_properties_mb={{size_mb}} MB +document_properties_title=Titel: +document_properties_author=Auteur: +document_properties_subject=Onderwerp: +document_properties_keywords=Trefwoorden: +document_properties_creation_date=Aanmaakdatum: +document_properties_modification_date=Wijzigingsdatum: +document_properties_date_string={{date}}, {{time}} +document_properties_creator=Toepassing: +document_properties_producer=PDF-producent: +document_properties_version=PDF-versie: +document_properties_page_count=Aantal pagina's: +document_properties_close=Sluiten + # Tooltips and alt text for side panel toolbar buttons # (the _label strings are alt text for the buttons, the .title strings are # tooltips) diff --git a/src/display/api.js b/src/display/api.js index 0b948c1e6..390d2d44b 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -925,10 +925,14 @@ var WorkerTransport = (function WorkerTransportClosure() { }, dataLoaded: function WorkerTransport_dataLoaded() { + if (this.dataLoadedPromise) { + return this.dataLoadedPromise; + } var promise = new PDFJS.LegacyPromise(); this.messageHandler.send('DataLoaded', null, function(args) { promise.resolve(args); }); + this.dataLoadedPromise = promise; return promise; }, diff --git a/web/document_properties.js b/web/document_properties.js new file mode 100644 index 000000000..1fea86759 --- /dev/null +++ b/web/document_properties.js @@ -0,0 +1,179 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* globals PDFView, mozL10n */ + +'use strict'; + +var DocumentProperties = { + overlayContainer: null, + fileSize: '', + visible: false, + + // Document property fields (in the viewer). + fileNameField: null, + fileSizeField: null, + titleField: null, + authorField: null, + subjectField: null, + keywordsField: null, + creationDateField: null, + modificationDateField: null, + creatorField: null, + producerField: null, + versionField: null, + pageCountField: null, + + initialize: function documentPropertiesInitialize(options) { + this.overlayContainer = options.overlayContainer; + + // Set the document property fields. + this.fileNameField = options.fileNameField; + this.fileSizeField = options.fileSizeField; + this.titleField = options.titleField; + this.authorField = options.authorField; + this.subjectField = options.subjectField; + this.keywordsField = options.keywordsField; + this.creationDateField = options.creationDateField; + this.modificationDateField = options.modificationDateField; + this.creatorField = options.creatorField; + this.producerField = options.producerField; + this.versionField = options.versionField; + this.pageCountField = options.pageCountField; + + // Bind the event listener for the Close button. + if (options.closeButton) { + options.closeButton.addEventListener('click', this.hide.bind(this)); + } + }, + + getProperties: function documentPropertiesGetProperties() { + var self = this; + + // Get the file size. + PDFView.pdfDocument.dataLoaded().then(function(data) { + self.setFileSize(data.length); + }); + + // Get the other document properties. + PDFView.pdfDocument.getMetadata().then(function(data) { + var fields = [ + { field: self.fileNameField, content: PDFView.url }, + { field: self.fileSizeField, content: self.fileSize }, + { field: self.titleField, content: data.info.Title }, + { field: self.authorField, content: data.info.Author }, + { field: self.subjectField, content: data.info.Subject }, + { field: self.keywordsField, content: data.info.Keywords }, + { field: self.creationDateField, + content: self.parseDate(data.info.CreationDate) }, + { field: self.modificationDateField, + content: self.parseDate(data.info.ModDate) }, + { field: self.creatorField, content: data.info.Creator }, + { field: self.producerField, content: data.info.Producer }, + { field: self.versionField, content: data.info.PDFFormatVersion }, + { field: self.pageCountField, content: PDFView.pdfDocument.numPages } + ]; + + // Show the properties in the dialog. + for (var item in fields) { + var element = fields[item]; + if (element.field && element.content !== undefined && + element.content !== '') { + element.field.textContent = element.content; + } + } + }); + }, + + setFileSize: function documentPropertiesSetFileSize(fileSize) { + var kb = Math.round(fileSize / 1024); + if (kb < 1024) { + this.fileSize = mozL10n.get('document_properties_kb', + {size_kb: kb}, '{{size_kb}} KB'); + } else { + var mb = Math.round((kb / 1024) * 100) / 100; + this.fileSize = mozL10n.get('document_properties_mb', + {size_mb: mb}, '{{size_mb}} MB'); + } + }, + + show: function documentPropertiesShow() { + if (this.visible) { + return; + } + this.visible = true; + this.overlayContainer.classList.remove('hidden'); + this.overlayContainer.lastElementChild.classList.remove('hidden'); + this.getProperties(); + }, + + hide: function documentPropertiesClose() { + if (!this.visible) { + return; + } + this.visible = false; + this.overlayContainer.classList.add('hidden'); + this.overlayContainer.lastElementChild.classList.add('hidden'); + }, + + parseDate: function documentPropertiesParseDate(inputDate) { + // This is implemented according to the PDF specification (see + // http://www.gnupdf.org/Date for an overview), but note that + // Adobe Reader doesn't handle changing the date to universal time + // and doesn't use the user's time zone (they're effectively ignoring + // the HH' and mm' parts of the date string). + var dateToParse = inputDate; + if (dateToParse === undefined) { + return ''; + } + + // Remove the D: prefix if it is available. + if (dateToParse.substring(0,2) === 'D:') { + dateToParse = dateToParse.substring(2); + } + + // Get all elements from the PDF date string. + // JavaScript's Date object expects the month to be between + // 0 and 11 instead of 1 and 12, so we're correcting for this. + var year = parseInt(dateToParse.substring(0,4), 10); + var month = parseInt(dateToParse.substring(4,6), 10) - 1; + var day = parseInt(dateToParse.substring(6,8), 10); + var hours = parseInt(dateToParse.substring(8,10), 10); + var minutes = parseInt(dateToParse.substring(10,12), 10); + var seconds = parseInt(dateToParse.substring(12,14), 10); + var utRel = dateToParse.substring(14,15); + var offsetHours = parseInt(dateToParse.substring(15,17), 10); + var offsetMinutes = parseInt(dateToParse.substring(18,20), 10); + + // As per spec, utRel = 'Z' means equal to universal time. + // The other cases ('-' and '+') have to be handled here. + if (utRel == '-') { + hours += offsetHours; + minutes += offsetMinutes; + } else if (utRel == '+') { + hours -= offsetHours; + minutes += offsetMinutes; + } + + // Return the new date format from the user's locale. + var date = new Date(Date.UTC(year, month, day, hours, minutes, seconds)); + var dateString = date.toLocaleDateString(); + var timeString = date.toLocaleTimeString(); + return mozL10n.get('document_properties_date_string', + {date: dateString, time: timeString}, + '{{date}}, {{time}}'); + } +}; diff --git a/web/images/secondaryToolbarButton-documentProperties.png b/web/images/secondaryToolbarButton-documentProperties.png new file mode 100644 index 0000000000000000000000000000000000000000..a9e82db331e9dfc6e3a0d660423bbca5f31d3dcd GIT binary patch literal 1246 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`f(~1RD^r68eAMwS&*t9 zlvv ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`=xSnV;^by#VQ6A(Xy|He>FVs_Y-ny~=;-ER zVru9J)9aF-T$-DjR|3v4~Pj*wm=R%;iu*SQ+p9GSy!A&`OLt;806{V7*cU- z&gJvkE`cHkK7OBG_3KT8@>Iu?9sLUd*9hU-&1|xR^MlmN`V`H+Qqh>b9*0)vah&t zP*c59QrP0S;JSe08k=q$Vm0$|%6OX~%Y5SX?Hc7?rML}B!V~p$7RXy_@01PYeRpjq ze{b&5NtzeBGj*);vmK|4owCT@blQ;Tl=+O~l39KMp_7+hnEc#Aea2+jk_A^D?8%OB zU7r3|!dG)|r?tO>G1sp>z3J(H8RG*lR9sp6d{+A3+cii0_wL)@XJ_fO .toolbarButton { .splitToolbarButton > .toolbarButton:hover, .splitToolbarButton > .toolbarButton:focus, .dropdownToolbarButton:hover, -.promptButton:hover, +.overlayButton:hover, .toolbarButton.textButton:hover, .toolbarButton.textButton:focus { background-color: hsla(0,0%,0%,.2); @@ -642,7 +642,7 @@ html[dir='rtl'] .splitToolbarButtonSeparator { .toolbarButton, .dropdownToolbarButton, -.promptButton, +.overlayButton, .secondaryToolbarButton { min-width: 16px; padding: 2px 6px 0; @@ -665,12 +665,12 @@ html[dir='rtl'] .splitToolbarButtonSeparator { } html[dir='ltr'] .toolbarButton, -html[dir='ltr'] .promptButton, +html[dir='ltr'] .overlayButton, html[dir='ltr'] .dropdownToolbarButton { margin: 3px 2px 4px 0; } html[dir='rtl'] .toolbarButton, -html[dir='rtl'] .promptButton, +html[dir='rtl'] .overlayButton, html[dir='rtl'] .dropdownToolbarButton { margin: 3px 0 4px 2px; } @@ -678,7 +678,7 @@ html[dir='rtl'] .dropdownToolbarButton { .toolbarButton:hover, .toolbarButton:focus, .dropdownToolbarButton, -.promptButton, +.overlayButton, .secondaryToolbarButton:hover, .secondaryToolbarButton:focus { background-color: hsla(0,0%,0%,.12); @@ -692,7 +692,7 @@ html[dir='rtl'] .dropdownToolbarButton { } .toolbarButton:hover:active, -.promptButton:hover:active, +.overlayButton:hover:active, .dropdownToolbarButton:hover:active, .secondaryToolbarButton:hover:active { background-color: hsla(0,0%,0%,.2); @@ -766,7 +766,7 @@ html[dir='rtl'] .dropdownToolbarButton { background: hsl(0,0%,24%); } -.promptButton { +.overlayButton { margin: 3px 2px 4px 5px !important; line-height: 16px; padding: 2px 6px 3px 6px; @@ -1004,6 +1004,10 @@ html[dir="rtl"] .secondaryToolbarButton > span { content: url(images/secondaryToolbarButton-handTool.png); } +.secondaryToolbarButton.documentProperties::before { + content: url(images/secondaryToolbarButton-documentProperties.png); +} + .verticalToolbarSeparator { display: block; padding: 8px 0; @@ -1431,6 +1435,63 @@ canvas { border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42); } +#documentPropertiesContainer { + display: table-cell; + vertical-align: middle; + text-align: center; +} + +#documentPropertiesContainer > * { + display: inline-block; + padding: 15px; + border-spacing: 4px; + max-width: 350px; + max-height: 350px; + color: hsl(0,0%,85%); + font-size: 12px; + line-height: 14px; + text-align: left; + cursor: default; + background-color: #474747; /* fallback */ + background-image: url(images/texture.png), + linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95)); + box-shadow: inset 1px 0 0 hsla(0,0%,100%,.08), + inset 0 1px 1px hsla(0,0%,0%,.15), + inset 0 -1px 0 hsla(0,0%,100%,.05), + 0 1px 0 hsla(0,0%,0%,.15), + 0 1px 1px hsla(0,0%,0%,.1); +} + +#documentPropertiesContainer .separator { + display: block; + margin: 4px 0 4px 0; + height: 1px; + width: 100%; + background-color: hsla(0,0%,0%,.5); + box-shadow: 0 0 0 1px hsla(0,0%,100%,.08); +} + +#documentPropertiesContainer .row { + display: table-row; +} + +html[dir='ltr'] #documentPropertiesContainer .row > * { + display: table-cell; + min-width: 100px; +} + +html[dir='rtl'] #documentPropertiesContainer .row > * { + display: table-cell; + min-width: 100px; + text-align: right; +} + +#documentPropertiesContainer .buttonRow { + margin-top: 10px; + text-align: center; + vertical-align: middle; +} + .clearBoth { clear: both; } diff --git a/web/viewer.html b/web/viewer.html index 5c9e8a81b..1bff71f1a 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -77,6 +77,7 @@ limitations under the License. + @@ -171,6 +172,12 @@ limitations under the License. + +
+ + @@ -299,7 +306,7 @@ limitations under the License.