diff --git a/l10n/da/viewer.properties b/l10n/da/viewer.properties index 6d208db70..f9d77da1b 100644 --- a/l10n/da/viewer.properties +++ b/l10n/da/viewer.properties @@ -17,7 +17,7 @@ page_scale_width=Sidebredde page_scale_fit=Helside page_scale_auto=Automatisk zoom page_scale_actual=Faktisk størrelse -toggle_slider.title=Skift Slider +toggle_slider.title=Skift slider thumbs.title=Vis thumbnails outline.title=Vis dokumentoversigt loading=Indlæser... {{percent}}% @@ -29,3 +29,17 @@ page_of=af {{pageCount}} no_outline=Ingen dokumentoversigt tilgængelig open_file.title=Åbn fil text_annotation_type=[{{type}} Kommentar] +toggle_slider_label=Skift slider +thumbs_label=Thumbnails +outline_label=Dokumentoversigt +bookmark_label=Aktuel visning +previous_label=Forrige +next_label=Næste +print_label=Udskriv +download_label=Hent +zoom_out_label=Zoom ud +zoom_in_label=Zoom ind +zoom.title=Zoom +thumb_page_title=Side {{page}} +thumb_page_canvas=Thumbnail af side {{page}} +request_password=PDF filen er beskyttet med et kodeord: diff --git a/l10n/en-US/viewer.properties b/l10n/en-US/viewer.properties index 1cc46eedf..c8b061d49 100644 --- a/l10n/en-US/viewer.properties +++ b/l10n/en-US/viewer.properties @@ -42,5 +42,7 @@ zoom_in_label=Zoom In zoom.title=Zoom thumb_page_title=Page {{page}} thumb_page_canvas=Thumbnail of Page {{page}} +request_password=PDF is protected by a password: search.title=Search Document search_label=Search + diff --git a/l10n/fr/metadata.inc b/l10n/fr/metadata.inc new file mode 100644 index 000000000..874e93a18 --- /dev/null +++ b/l10n/fr/metadata.inc @@ -0,0 +1,7 @@ + + + fr + PDF Viewer + Utilise HTML5 pour afficher les documents PDF directement dans Firefox. + + diff --git a/l10n/fr/viewer.properties b/l10n/fr/viewer.properties new file mode 100644 index 000000000..c93df3681 --- /dev/null +++ b/l10n/fr/viewer.properties @@ -0,0 +1,45 @@ +bookmark.title=Vue courante (copier ou ouvrir dans une nouvelle fenêtre) +previous.title=Précédente +next.title=Suivante +print.title=Imprimer +download.title=Télécharger +zoom_out.title=Zoom arrière +zoom_in.title=Zoom avant +error_more_info=Plus d'informations +error_less_info=Moins d'informations +error_close=Fermer +error_build=Version de PDF.JS : {{build}} +error_message=Message : {{message}} +error_stack=Pile : {{stack}} +error_file=Fichier : {{file}} +error_line=Ligne : {{line}} +page_scale_width=Largeur de la page +page_scale_fit=Ajuster à la page +page_scale_auto=Zoom automatique +page_scale_actual=Taille réelle +toggle_slider.title=Afficher/Masquer la barre latérale +thumbs.title=Afficher/masquer les vignettes +outline.title=Afficher/masquer la structure +loading=Chargement… {{percent}}% +loading_error_indicator=Erreur +loading_error=Une erreur est survenue lors du chargement du PDF. +rendering_error=Une erreur est survenue lors de l'affichage de la page. +page_label=Page : +page_of=sur {{pageCount}} +no_outline=Pas de structure disponible +open_file.title=Ouvrir un fichier +text_annotation_type=[Annotation {{type}}] +toggle_slider_label=Afficher/Masquer la barre latérale +thumbs_label=Vignettes +outline_label=Structure du document +bookmark_label=Vue courante +previous_label=Précédente +next_label=Suivante +print_label=Imprimer +download_label=Télécharger +zoom_out_label=Zoom arrière +zoom_in_label=Zoom avant +zoom.title=Zoom +thumb_page_title=Page {{page}} +thumb_page_canvas=Aperçu de la page {{page}} +request_password=Ce PDF est protégé par un mot de passe : diff --git a/l10n/ja/metadata.inc b/l10n/ja/metadata.inc new file mode 100644 index 000000000..7ca474685 --- /dev/null +++ b/l10n/ja/metadata.inc @@ -0,0 +1,8 @@ + + + ja + PDF Viewer + HTML5を使用して、Firefoxで直接PDFファイルを表示します。 + + + diff --git a/l10n/ja/viewer.properties b/l10n/ja/viewer.properties new file mode 100644 index 000000000..4bbe8c48b --- /dev/null +++ b/l10n/ja/viewer.properties @@ -0,0 +1,45 @@ +bookmark.title=現在のビュー (コピーまたは新しいウインドウで開く) +previous.title=前のページ +next.title=次のページ +print.title=印刷 +download.title=ダウンロード +zoom_out.title=縮小 +zoom_in.title=拡大 +error_more_info=詳細情報 +error_less_info=詳細情報の非表示 +error_close=閉じる +error_build=PDF.JS Build: {{build}} +error_message=メッセージ: {{message}} +error_stack=スタック: {{stack}} +error_file=ファイル: {{file}} +error_line=ライン: {{line}} +page_scale_width=幅に合わせる +page_scale_fit=ページのサイズに合わせる +page_scale_auto=自動ズーム +page_scale_actual=実際のサイズ +toggle_slider.title=サイドバーの切り替え +thumbs.title=縮小版を表示 +outline.title=文書の目次を表示 +loading=読み込み中... {{percent}}% +loading_error_indicator=エラー +loading_error=PDFの読み込み中にエラーが発生しました +rendering_error=ページのレンダリング中にエラーが発生しました +page_label=ページ: +page_of=of {{pageCount}} +no_outline=利用可能な目次はありません +open_file.title=ファイルを開く +text_annotation_type=[{{type}} 注釈] +toggle_slider_label=サイドバーの切り替え +thumbs_label=縮小版 +outline_label=文書の目次 +bookmark_label=現在のビュー +previous_label=前へ +next_label=次へ +print_label=印刷 +download_label=ダウンロード +zoom_out_label=縮小 +zoom_in_label=拡大 +zoom.title=ズーム +thumb_page_title=ページ {{page}} +thumb_page_canvas=ページの縮小版 {{page}} +request_password=PDFはパスワードによって保護されています diff --git a/l10n/ru/viewer.properties b/l10n/ru/viewer.properties index a946cde98..796add2af 100644 --- a/l10n/ru/viewer.properties +++ b/l10n/ru/viewer.properties @@ -40,3 +40,6 @@ download_label=Загрузить zoom_out_label=Уменьшить zoom_in_label=Увеличить zoom.title=Масштаб +thumb_page_title=Страница {{page}} +thumb_page_canvas=Уменьшенное изображение страницы {{page}} +request_password=PDF защищён паролем: diff --git a/l10n/sv/metadata.inc b/l10n/sv/metadata.inc new file mode 100644 index 000000000..6753d83e9 --- /dev/null +++ b/l10n/sv/metadata.inc @@ -0,0 +1,8 @@ + + + sv + PDF Läsare + Använder HTML5 för att visa PDF filer direkt i Firefox. + + + diff --git a/l10n/sv/viewer.properties b/l10n/sv/viewer.properties new file mode 100644 index 000000000..3aadfd44f --- /dev/null +++ b/l10n/sv/viewer.properties @@ -0,0 +1,45 @@ +bookmark.title=Aktuell vy (visa eller öppna i nytt fönster) +previous.title=Föregående sida +next.title=Nästa sida +print.title=Skriv ut +download.title=Ladda ner +zoom_out.title=Zooma ut +zoom_in.title=Zooma in +error_more_info=Mer information +error_less_info=Mindre information +error_close=Stäng +error_build=PDF.JS bygge: {{build}} +error_message=Meddelande: {{message}} +error_stack=Stack: {{stack}} +error_file=Fil: {{file}} +error_line=Rad: {{line}} +page_scale_width=Sidbredd +page_scale_fit=Passa sida +page_scale_auto=Automatisk zoom +page_scale_actual=Faktisk storlek +toggle_slider.title=Visa/Dölj panel +thumbs.title=Visa miniatyrer +outline.title=Visa dokumentdisposition +loading=Laddar... {{percent}}% +loading_error_indicator=Fel +loading_error=Ett fel inträffade när PDF dokumentet laddades. +rendering_error=Ett fel inträffade när PDF dokumentet renderades. +page_label=Sida: +page_of=av {{pageCount}} +no_outline=Ingen dokumentdisposition tillgänglig +open_file.title=Öppna fil +text_annotation_type=[{{type}} Annotering] +toggle_slider_label=Visa/Dölj panel +thumbs_label=Miniatyrer +outline_label=Disposition +bookmark_label=Aktuell vy +previous_label=Föregående +next_label=Nästa +print_label=Skriv ut +download_label=Ladda ner +zoom_out_label=Zooma ut +zoom_in_label=Zooma in +zoom.title=Zooma +thumb_page_title=Sida {{page}} +thumb_page_canvas=Miniatyr av sida {{page}} +request_password=PDF dokumentet är skyddat av ett lösenord: \ No newline at end of file diff --git a/l10n/zh-CN/metadata.inc b/l10n/zh-CN/metadata.inc new file mode 100644 index 000000000..04be27c78 --- /dev/null +++ b/l10n/zh-CN/metadata.inc @@ -0,0 +1,8 @@ + + + zh-CN + PDF 查看器 + 使用 HTML5 来支持在 Firefox 中直接显示 PDF 文件。 + + + diff --git a/l10n/zh-CN/viewer.properties b/l10n/zh-CN/viewer.properties new file mode 100644 index 000000000..8b670fe12 --- /dev/null +++ b/l10n/zh-CN/viewer.properties @@ -0,0 +1,45 @@ +bookmark.title=当前视图(复制或在新窗口中打开) +previous.title=上一页 +next.title=下一页 +print.title=打印 +download.title=下载 +zoom_out.title=缩小 +zoom_in.title=放大 +error_more_info=更多信息 +error_less_info=更少信息 +error_close=关闭 +error_build=PDF.JS Build: {{build}} +error_message=Message: {{message}} +error_stack=Stack: {{stack}} +error_file=File: {{file}} +error_line=Line: {{line}} +page_scale_width=适合页宽 +page_scale_fit=适合页面 +page_scale_auto=自动缩放 +page_scale_actual=实际大小 +toggle_slider.title=切换侧栏 +thumbs.title=显示缩略图 +outline.title=显示文档大纲 +loading=正在载入... {{percent}}% +loading_error_indicator=错误 +loading_error=载入PDF时发生错误。 +rendering_error=呈现页面时发生错误。 +page_label=页: +page_of=/ {{pageCount}} +no_outline=无可用大纲 +open_file.title=打开文件 +text_annotation_type=[{{type}} 注解] +toggle_slider_label=切换侧栏 +thumbs_label=缩略图 +outline_label=文档大纲 +bookmark_label=当前视图 +previous_label=向上 +next_label=向下 +print_label=打印 +download_label=下载 +zoom_out_label=缩小 +zoom_in_label=放大 +zoom.title=缩放 +thumb_page_title=页码 {{page}} +thumb_page_canvas=页面 {{page}} 的缩略图 +request_password=PDF 被密码保护: diff --git a/l10n/zh-TW/metadata.inc b/l10n/zh-TW/metadata.inc new file mode 100644 index 000000000..6ef722be8 --- /dev/null +++ b/l10n/zh-TW/metadata.inc @@ -0,0 +1,8 @@ + + + zh-TW + PDF 瀏覽器 + 利用 HTML5 技術在 Firefox 中直接顯示 PDF 格式檔案。 + + + diff --git a/l10n/zh-TW/viewer.properties b/l10n/zh-TW/viewer.properties new file mode 100644 index 000000000..0f2182594 --- /dev/null +++ b/l10n/zh-TW/viewer.properties @@ -0,0 +1,45 @@ +bookmark.title=目前檢視(複製或在新視窗中開啟) +previous.title=上一頁 +next.title=下一頁 +print.title=列印 +download.title=下載 +zoom_out.title=縮小 +zoom_in.title=放大 +error_more_info=更多資訊 +error_less_info=更少資訊 +error_close=關閉 +error_build=PDF.JS 版本號: {{build}} +error_message=錯誤信息: {{message}} +error_stack=堆疊: {{stack}} +error_file=檔案: {{file}} +error_line=行數: {{line}} +page_scale_width=符合頁寬 +page_scale_fit=符合頁面 +page_scale_auto=自動縮放 +page_scale_actual=實際大小 +toggle_slider.title=切換側邊欄 +thumbs.title=顯示縮圖 +outline.title=顯示文件綱要 +loading=正在載入... {{percent}}% +loading_error_indicator=錯誤 +loading_error=載入PDF檔案時發生錯誤。 +rendering_error=渲染頁面時發生錯誤。 +page_label=頁次: +page_of=, 共 {{pageCount}} 頁 +no_outline=無可用的綱要 +open_file.title=開啟檔案 +text_annotation_type=[{{type}} 註解] +toggle_slider_label=切換側邊欄 +thumbs_label=縮圖 +outline_label=文件綱要 +bookmark_label=目前檢視 +previous_label=上一頁 +next_label=下一頁 +print_label=列印 +download_label=下載 +zoom_out_label=縮小 +zoom_in_label=放大 +zoom.title=縮放 +thumb_page_title=第 {{page}} 頁 +thumb_page_canvas=第 {{page}} 頁的縮圖 +request_password=PDF 檔案受密碼保護: diff --git a/src/api.js b/src/api.js index 976faf898..48d017c6d 100644 --- a/src/api.js +++ b/src/api.js @@ -7,20 +7,46 @@ * is used, which means it must follow the same origin rules that any XHR does * e.g. No cross domain requests without CORS. * - * @param {string|TypedAray} source Either a url to a PDF is located or a - * typed array (Uint8Array) already populated with data. - * @param {Object} headers An object containing the http headers like this: - * { Authorization: "BASIC XXX" }. + * @param {string|TypedAray|object} source Can be an url to where a PDF is + * located, a typed array (Uint8Array) already populated with data or + * and parameter object with the following possible fields: + * - url - The URL of the PDF. + * - data - A typed array with PDF data. + * - httpHeaders - Basic authentication headers. + * - password - For decrypting password-protected PDFs. + * * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object. */ -PDFJS.getDocument = function getDocument(source, headers) { +PDFJS.getDocument = function getDocument(source) { + var url, data, headers, password, parameters = {}; + if (typeof source === 'string') { + url = source; + } else if (isArrayBuffer(source)) { + data = source; + } else if (typeof source === 'object') { + url = source.url; + data = source.data; + headers = source.httpHeaders; + password = source.password; + parameters.password = password || null; + + if (!url && !data) + error('Invalid parameter array, need either .data or .url'); + } else { + error('Invalid parameter in getDocument, need either Uint8Array, ' + + 'string or a parameter object'); + } + var promise = new PDFJS.Promise(); var transport = new WorkerTransport(promise); - if (typeof source === 'string') { + if (data) { + // assuming the data is array, instantiating directly from it + transport.sendData(data, parameters); + } else if (url) { // fetch url PDFJS.getPdf( { - url: source, + url: url, progress: function getPDFProgress(evt) { if (evt.lengthComputable) promise.progress({ @@ -35,12 +61,10 @@ PDFJS.getDocument = function getDocument(source, headers) { headers: headers }, function getPDFLoad(data) { - transport.sendData(data); + transport.sendData(data, parameters); }); - } else { - // assuming the source is array, instantiating directly from it - transport.sendData(source); } + return promise; }; @@ -122,6 +146,11 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() { }); return promise; }, + isEncrypted: function PDFDocumentProxy_isEncrypted() { + var promise = new PDFJS.Promise(); + promise.resolve(this.pdfInfo.encrypted); + return promise; + }, destroy: function PDFDocumentProxy_destroy() { this.transport.destroy(); } @@ -473,6 +502,14 @@ var WorkerTransport = (function WorkerTransportClosure() { this.workerReadyPromise.resolve(pdfDocument); }, this); + messageHandler.on('NeedPassword', function transportPassword(data) { + this.workerReadyPromise.reject(data.exception.message, data.exception); + }, this); + + messageHandler.on('IncorrectPassword', function transportBadPass(data) { + this.workerReadyPromise.reject(data.exception.message, data.exception); + }, this); + messageHandler.on('GetPage', function transportPage(data) { var pageInfo = data.pageInfo; var page = new PDFPageProxy(pageInfo, this); @@ -575,8 +612,8 @@ var WorkerTransport = (function WorkerTransportClosure() { }); }, - sendData: function WorkerTransport_sendData(data) { - this.messageHandler.send('GetDocRequest', data); + sendData: function WorkerTransport_sendData(data, params) { + this.messageHandler.send('GetDocRequest', {data: data, params: params}); }, getPage: function WorkerTransport_getPage(pageNumber, promise) { diff --git a/src/core.js b/src/core.js index e1a9476a3..4af055bfe 100644 --- a/src/core.js +++ b/src/core.js @@ -362,19 +362,19 @@ var Page = (function PageClosure() { * `PDFDocument` objects on the main thread created. */ var PDFDocument = (function PDFDocumentClosure() { - function PDFDocument(arg, callback) { + function PDFDocument(arg, password) { if (isStream(arg)) - init.call(this, arg); + init.call(this, arg, password); else if (isArrayBuffer(arg)) - init.call(this, new Stream(arg)); + init.call(this, new Stream(arg), password); else error('PDFDocument: Unknown argument type'); } - function init(stream) { + function init(stream, password) { assertWellFormed(stream.length > 0, 'stream must have data'); this.stream = stream; - this.setup(); + this.setup(password); this.acroForm = this.catalog.catDict.get('AcroForm'); } @@ -465,11 +465,12 @@ var PDFDocument = (function PDFDocumentClosure() { } // May not be a PDF file, continue anyway. }, - setup: function PDFDocument_setup(ownerPassword, userPassword) { + setup: function PDFDocument_setup(password) { this.checkHeader(); var xref = new XRef(this.stream, this.startXRef, - this.mainXRefEntriesOffset); + this.mainXRefEntriesOffset, + password); this.xref = xref; this.catalog = new Catalog(xref); }, diff --git a/src/crypto.js b/src/crypto.js index dcd820554..c86551f36 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -556,7 +556,9 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata); - if (!encryptionKey && password) { + if (!encryptionKey && !password) { + throw new PasswordException('No password given', 'needpassword'); + } else if (!encryptionKey && password) { // Attempting use the password as an owner password var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword, revision, keyLength); @@ -566,7 +568,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { } if (!encryptionKey) - error('incorrect password or encryption data'); + throw new PasswordException('Incorrect Password', 'incorrectpassword'); this.encryptionKey = encryptionKey; diff --git a/src/obj.js b/src/obj.js index 9b99eb8f7..3432ac68d 100644 --- a/src/obj.js +++ b/src/obj.js @@ -298,7 +298,7 @@ var Catalog = (function CatalogClosure() { })(); var XRef = (function XRefClosure() { - function XRef(stream, startXRef, mainXRefEntriesOffset) { + function XRef(stream, startXRef, mainXRefEntriesOffset, password) { this.stream = stream; this.entries = []; this.xrefstms = {}; @@ -311,8 +311,7 @@ var XRef = (function XRefClosure() { var encrypt = trailerDict.get('Encrypt'); if (encrypt) { var fileId = trailerDict.get('ID'); - this.encrypt = new CipherTransformFactory(encrypt, - fileId[0] /*, password */); + this.encrypt = new CipherTransformFactory(encrypt, fileId[0], password); } // get the root dictionary (catalog) object diff --git a/src/util.js b/src/util.js index 140b18cf1..90e6cee5d 100644 --- a/src/util.js +++ b/src/util.js @@ -58,6 +58,19 @@ function shadow(obj, prop, value) { return value; } +var PasswordException = (function PasswordExceptionClosure() { + function PasswordException(msg, code) { + this.name = 'PasswordException'; + this.message = msg; + this.code = code; + } + + PasswordException.prototype = new Error(); + PasswordException.constructor = PasswordException; + + return PasswordException; +})(); + function bytesToString(bytes) { var str = ''; var length = bytes.length; @@ -456,7 +469,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() { } this.isResolved = true; - this.data = data || null; + this.data = (typeof data !== 'undefined') ? data : null; var callbacks = this.callbacks; for (var i = 0, ii = callbacks.length; i < ii; i++) { @@ -471,7 +484,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() { } }, - reject: function Promise_reject(reason) { + reject: function Promise_reject(reason, exception) { if (this.isRejected) { error('A Promise can be rejected only once ' + this.name); } @@ -484,7 +497,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() { var errbacks = this.errbacks; for (var i = 0, ii = errbacks.length; i < ii; i++) { - errbacks[i].call(null, reason); + errbacks[i].call(null, reason, exception); } }, diff --git a/src/worker.js b/src/worker.js index b3ba7671e..253232768 100644 --- a/src/worker.js +++ b/src/worker.js @@ -88,14 +88,35 @@ var WorkerMessageHandler = { handler.on('GetDocRequest', function wphSetupDoc(data) { // Create only the model of the PDFDoc, which is enough for // processing the content of the pdf. - pdfModel = new PDFDocument(new Stream(data)); + var pdfData = data.data; + var pdfPassword = data.params.password; + try { + pdfModel = new PDFDocument(new Stream(pdfData), pdfPassword); + } catch (e) { + if (e instanceof PasswordException) { + if (e.code === 'needpassword') { + handler.send('NeedPassword', { + exception: e + }); + } else if (e.code === 'incorrectpassword') { + handler.send('IncorrectPassword', { + exception: e + }); + } + + return; + } else { + throw e; + } + } var doc = { numPages: pdfModel.numPages, fingerprint: pdfModel.getFingerprint(), destinations: pdfModel.catalog.destinations, outline: pdfModel.catalog.documentOutline, info: pdfModel.getDocumentInfo(), - metadata: pdfModel.catalog.metadata + metadata: pdfModel.catalog.metadata, + encrypted: !!pdfModel.xref.encrypt }; handler.send('GetDoc', {pdfInfo: doc}); }); diff --git a/web/compatibility.js b/web/compatibility.js index 5c192c9a9..528841bb6 100644 --- a/web/compatibility.js +++ b/web/compatibility.js @@ -120,6 +120,9 @@ return new Uint8Array(new VBArray(this.responseBody).toArray()); } }); + Object.defineProperty(xhrPrototype, 'overrideMimeType', { + value: function xmlHttpRequestOverrideMimeType(mimeType) {} + }); return; } @@ -217,15 +220,84 @@ var div = document.createElement('div'); if ('dataset' in div) return; // dataset property exists - var oldCreateElement = document.createElement; - document.createElement = function newCreateElement() { - var result = oldCreateElement.apply(document, arguments); - if (arguments[0] === 'div') { - // creating dataset property for the div elements - result.dataset = {}; + + Object.defineProperty(HTMLElement.prototype, 'dataset', { + get: function() { + if (this._dataset) + return this._dataset; + + var dataset = {}; + for (var j = 0, jj = this.attributes.length; j < jj; j++) { + var attribute = this.attributes[j]; + if (attribute.name.substring(0, 5) != 'data-') + continue; + var key = attribute.name.substring(5).replace(/\-([a-z])/g, + function(all, ch) { return ch.toUpperCase(); }); + dataset[key] = attribute.value; + } + + Object.defineProperty(this, '_dataset', { + value: dataset, + writable: false, + enumerable: false + }); + return dataset; + }, + enumerable: true + }); +})(); + +// HTMLElement classList property +(function checkClassListProperty() { + var div = document.createElement('div'); + if ('classList' in div) + return; // classList property exists + + function changeList(element, itemName, add, remove) { + var s = element.className || ''; + var list = s.split(/\s+/g); + if (list[0] == '') list.shift(); + var index = list.indexOf(itemName); + if (index < 0 && add) + list.push(itemName); + if (index >= 0 && remove) + list.splice(index, 1); + element.className = list.join(' '); + } + + var classListPrototype = { + add: function(name) { + changeList(this.element, name, true, false); + }, + remove: function(name) { + changeList(this.element, name, false, true); + }, + toggle: function(name) { + changeList(this.element, name, true, true); } - return result; }; + + Object.defineProperty(HTMLElement.prototype, 'classList', { + get: function() { + if (this._classList) + return this._classList; + + var classList = Object.create(classListPrototype, { + element: { + value: this, + writable: false, + enumerable: true + } + }); + Object.defineProperty(this, '_classList', { + value: classList, + writable: false, + enumerable: false + }); + return classList; + }, + enumerable: true + }); })(); // Check console compatability @@ -252,3 +324,17 @@ document.addEventListener('click', ignoreIfTargetDisabled, true); } })(); + +// Checks if navigator.language is supported +(function checkNavigatorLanguage() { + if ('language' in navigator) + return; + Object.defineProperty(navigator, 'language', { + get: function navigatorLanguage() { + var language = navigator.userLanguage || 'en-US'; + return language.substring(0, 2).toLowerCase() + + language.substring(2).toUpperCase(); + }, + enumerable: true + }); +})(); diff --git a/web/viewer.css b/web/viewer.css index 3446c1627..cb6a7b474 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -428,6 +428,10 @@ html[dir='rtl'] .dropdownToolbarButton { background: transparent; } +.dropdownToolbarButton > select > option { + background: hsl(0,0%,24%); +} + #customScaleOption { display: none; } @@ -984,3 +988,47 @@ canvas { #PDFBug table { font-size: 10px; } + +@media all and (max-width: 770px) { + #scaleSelectContainer, #fileInput, #pageNumberLabel { + display: none; + } + + #sidebarContainer { + top: 33px; + z-index: 100; + } + #sidebarContent { + top: 33px; + background-color: hsla(0,0%,0%,.7); + } + #thumbnailView, #outlineView { + top: 66px; + } + + html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer { + left: 0px; + } + html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer { + right: 0px; + } + + #pageNumber { + width: 30px; + } +} + +@media all and (max-width: 500px) { + #viewBookmark { + display: none; + } + + html[dir='ltr'] .outerCenter { + float: left; + left: 180px; + } + html[dir='rtl'] .outerCenter { + float: right; + right: 180px; + } +} diff --git a/web/viewer.html b/web/viewer.html index 17688ef0c..b2d1a9243 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -89,7 +89,7 @@ Next - + @@ -127,7 +127,7 @@ Zoom In - +