From 613f4f2b9013cb25464fc9dee0fb71cc3a300a3b Mon Sep 17 00:00:00 2001 From: Xavier Fung Date: Wed, 30 May 2012 02:47:00 +0800 Subject: [PATCH 1/5] Update translation --- l10n/zh-TW/chrome.properties | 2 ++ l10n/zh-TW/viewer.properties | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 l10n/zh-TW/chrome.properties diff --git a/l10n/zh-TW/chrome.properties b/l10n/zh-TW/chrome.properties new file mode 100644 index 000000000..92bb92dfe --- /dev/null +++ b/l10n/zh-TW/chrome.properties @@ -0,0 +1,2 @@ +unsupported_feature=本 PDF 文件可能無法正常顯示。 +open_with_different_viewer=使用其他檢視器打開文件 diff --git a/l10n/zh-TW/viewer.properties b/l10n/zh-TW/viewer.properties index 0f2182594..8a34b65a5 100644 --- a/l10n/zh-TW/viewer.properties +++ b/l10n/zh-TW/viewer.properties @@ -24,8 +24,8 @@ loading=正在載入... {{percent}}% loading_error_indicator=錯誤 loading_error=載入PDF檔案時發生錯誤。 rendering_error=渲染頁面時發生錯誤。 -page_label=頁次: -page_of=, 共 {{pageCount}} 頁 +page_label=第 +page_of=頁, 共 {{pageCount}} 頁 no_outline=無可用的綱要 open_file.title=開啟檔案 text_annotation_type=[{{type}} 註解] @@ -43,3 +43,7 @@ zoom.title=縮放 thumb_page_title=第 {{page}} 頁 thumb_page_canvas=第 {{page}} 頁的縮圖 request_password=PDF 檔案受密碼保護: +open_file_label=開啟 +search.title=搜索文件 +search_label=搜索 +search_button=尋找 From fd8588236638eef0856c25d849dda388bf505efb Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Thu, 31 May 2012 15:56:38 -0500 Subject: [PATCH 2/5] Addressing the bug 742099 review --- l10n/en-US/chrome.properties | 1 + l10n/en-US/viewer.properties | 77 ++++++++++++++++++++++-------------- web/viewer.html | 2 +- web/viewer.js | 3 +- 4 files changed, 51 insertions(+), 32 deletions(-) diff --git a/l10n/en-US/chrome.properties b/l10n/en-US/chrome.properties index 467d5920b..1885e6036 100644 --- a/l10n/en-US/chrome.properties +++ b/l10n/en-US/chrome.properties @@ -1,2 +1,3 @@ +# Chrome notification bar messages and buttons unsupported_feature=This PDF document might not be displayed correctly. open_with_different_viewer=Open With Different Viewer diff --git a/l10n/en-US/viewer.properties b/l10n/en-US/viewer.properties index 4ac776da2..007446075 100644 --- a/l10n/en-US/viewer.properties +++ b/l10n/en-US/viewer.properties @@ -1,10 +1,46 @@ -bookmark.title=Current view (copy or open in new window) +# Main toolbar buttons (tooltips and alt text for images) previous.title=Previous Page +previous_label=Previous next.title=Next Page -print.title=Print -download.title=Download +next_label=Next +page_label=Page: +page_of=of {{pageCount}} zoom_out.title=Zoom Out +zoom_out_label=Zoom Out zoom_in.title=Zoom In +zoom_in_label=Zoom In +zoom.title=Zoom +print.title=Print +print_label=Print +open_file.title=Open File +open_file_label=Open +download.title=Download +download_label=Download +bookmark.title=Current view (copy or open in new window) +bookmark_label=Current View + +# Side panel toolbar buttons (tooltips and alt text for images) +toggle_slider.title=Toggle Slider +toggle_slider_label=Toggle Slider +outline.title=Show Document Outline +outline_label=Document Outline +thumbs.title=Show Thumbnails +thumbs_label=Thumbnails +search.title=Search Document +search_label=Search + +# Document outline messages +no_outline=No Outline Available + +# Thumbnails panel item (tooltip and alt text for images) +thumb_page_title=Page {{page}} +thumb_page_canvas=Thumbnail of Page {{page}} + +# Search panel button title and messages +search=Find +search_terms_not_found=(Not found) + +# Error panel labels error_more_info=More Information error_less_info=Less Information error_close=Close @@ -13,38 +49,19 @@ error_message=Message: {{message}} error_stack=Stack: {{stack}} error_file=File: {{file}} error_line=Line: {{line}} +rendering_error=An error occurred while rendering the page. + +# Predefined zoom values page_scale_width=Page Width page_scale_fit=Page Fit page_scale_auto=Automatic Zoom page_scale_actual=Actual Size -toggle_slider.title=Toggle Slider -thumbs.title=Show Thumbnails -outline.title=Show Document Outline + +# Loading indicator messages loading=Loading... {{percent}}% loading_error_indicator=Error loading_error=An error occurred while loading the PDF. -rendering_error=An error occurred while rendering the page. -page_label=Page: -page_of=of {{pageCount}} -no_outline=No Outline Available -open_file.title=Open File -text_annotation_type=[{{type}} Annotation] -toggle_slider_label=Toggle Slider -thumbs_label=Thumbnails -outline_label=Document Outline -bookmark_label=Current View -previous_label=Previous -next_label=Next -print_label=Print -download_label=Download -zoom_out_label=Zoom Out -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: -open_file_label=Open -search.title=Search Document -search_label=Search -search_button=Find +# Misc labels and messages +text_annotation_type=[{{type}} Annotation] +request_password=PDF is protected by a password: diff --git a/web/viewer.html b/web/viewer.html index 087fb7af3..8b189a1f0 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -63,7 +63,7 @@ diff --git a/web/viewer.js b/web/viewer.js index e6d1b6766..0b43fd2c6 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -720,7 +720,8 @@ var PDFView = { pageFound = true; } if (!pageFound) { - searchResults.textContent = '(Not found)'; + searchResults.textContent = mozL10n.get('search_terms_not_found', null, + '(Not found)'; } }, From 5371dc671bc0612ceb2a3ad12e56b67f2f0249ca Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Thu, 31 May 2012 16:01:54 -0500 Subject: [PATCH 3/5] Missing parent --- web/viewer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/viewer.js b/web/viewer.js index 0b43fd2c6..21a50e96b 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -721,7 +721,7 @@ var PDFView = { } if (!pageFound) { searchResults.textContent = mozL10n.get('search_terms_not_found', null, - '(Not found)'; + '(Not found)'); } }, From e2011a42444b91fcb11649c53423d08ad887b6bb Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Thu, 31 May 2012 16:13:27 -0500 Subject: [PATCH 4/5] Fixing search button; removing xx culture --- l10n/en-US/viewer.properties | 4 ++-- l10n/xx/viewer.properties | 44 ------------------------------------ web/viewer.html | 4 ++-- 3 files changed, 4 insertions(+), 48 deletions(-) delete mode 100644 l10n/xx/viewer.properties diff --git a/l10n/en-US/viewer.properties b/l10n/en-US/viewer.properties index 007446075..25abd9275 100644 --- a/l10n/en-US/viewer.properties +++ b/l10n/en-US/viewer.properties @@ -26,8 +26,8 @@ outline.title=Show Document Outline outline_label=Document Outline thumbs.title=Show Thumbnails thumbs_label=Thumbnails -search.title=Search Document -search_label=Search +search_panel.title=Search Document +search_panel_label=Search # Document outline messages no_outline=No Outline Available diff --git a/l10n/xx/viewer.properties b/l10n/xx/viewer.properties deleted file mode 100644 index e26f79422..000000000 --- a/l10n/xx/viewer.properties +++ /dev/null @@ -1,44 +0,0 @@ -bookmark.title=<<<_¢ȗггεпţ ṿiεẂ (¢OÞӳ Oг OÞεп iп пεẂ ẂiпÐOẂ)_>>> -previous.title=<<<_ÞгεṿiOȗ§ Þãģε_>>> -next.title=<<<_пεӾţ Þãģε_>>> -print.title=<<<_Þгiпţ_>>> -download.title=<<<_ÐOẂпḻOãÐ_>>> -zoom_out.title=<<<_ƩOOм Oȗţ_>>> -zoom_in.title=<<<_ƩOOм iп_>>> -error_more_info=<<<_мOгε iп£OгмãţiOп_>>> -error_less_info=<<<_ḻ姧 iп£OгмãţiOп_>>> -error_close=<<<_¢ḻO§ε_>>> -error_build=<<<_ÞУ.ʃ§ ьȗiḻÐ: {{build}}_>>> -error_message=<<<_м姧ãģε: {{message}}_>>> -error_stack=<<<_§ţã¢қ: {{stack}}_>>> -error_file=<<<_£iḻε: {{file}}_>>> -error_line=<<<_ḻiпε: {{line}}_>>> -page_scale_width=<<<_Þãģε ẂiÐţН_>>> -page_scale_fit=<<<_Þãģε £iţ_>>> -page_scale_auto=<<<_ãȗţOмãţi¢ ƩOOм_>>> -page_scale_actual=<<<_ã¢ţȗãḻ §iƩε_>>> -toggle_slider.title=<<<_ţOģģḻε §ḻiÐεг_>>> -thumbs.title=<<<_§НOẂ ţНȗмьпãiḻ§_>>> -outline.title=<<<_§НOẂ ÐO¢ȗмεпţ Oȗţḻiпε_>>> -loading=<<<_ḻOãÐiпģ... {{percent}}%_>>> -loading_error_indicator=<<<_εггOг_>>> -loading_error=<<<_ãп εггOг O¢¢ȗггεÐ ẂНiḻε ḻOãÐiпģ ţНε ÞУ._>>> -rendering_error=<<<_ãп εггOг O¢¢ȗггεÐ ẂНiḻε гεпÐεгiпģ ţНε Þãģε._>>> -page_label=Þãģε: -page_of=<<<_O£ {{pageCount}}_>>> -no_outline=<<<_пO Oȗţḻiпε ãṿãiḻãьḻε_>>> -open_file.title=<<<_OÞεп £iḻε_>>> -text_annotation_type=<<<_[{{type}} ãппOţãţiOп]_>>> -toggle_slider_label=<<<_ţOģģḻε §ḻiÐεг_>>> -thumbs_label=<<<_ţНȗмьпãiḻ§_>>> -outline_label=<<<_ÐO¢ȗмεпţ Oȗţḻiпε_>>> -bookmark_label=<<<_¢ȗггεпţ ṿiεẂ_>>> -previous_label=<<<_ÞгεṿiOȗ§_>>> -next_label=<<<_пεӾţ_>>> -print_label=<<<_Þгiпţ_>>> -download_label=<<<_ÐOẂпḻOãÐ_>>> -zoom_out_label=<<<_ƩOOм Oȗţ_>>> -zoom_in_label=<<<_ƩOOм iп_>>> -zoom.title=<<<_ƩOOм_>>> -thumb_page_title=<<<_Þãģε {{page}}_>>> -thumb_page_canvas=<<<_ţНȗмьпãiḻ O£ Þãģε {{page}}_>>> diff --git a/web/viewer.html b/web/viewer.html index 8b189a1f0..56522478e 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -51,8 +51,8 @@ -
From 6175e4b526541aeacac267f07402c761ef6ab319 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Fri, 1 Jun 2012 14:17:09 -0700 Subject: [PATCH 5/5] Use already downloaded data for the open with/save as dialog. --- .../firefox/components/PdfStreamConverter.js | 95 ++++++++++++++----- extensions/firefox/tools/l10n.js | 4 +- src/api.js | 15 +++ src/worker.js | 4 + web/viewer.js | 82 ++++++++++++++-- 5 files changed, 166 insertions(+), 34 deletions(-) diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 62d22162b..ff63ab52a 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -104,11 +104,18 @@ function ChromeActions(domWindow) { } ChromeActions.prototype = { - download: function(data) { + download: function(data, sendResponse) { + var originalUrl = data.originalUrl; + // The data may not be downloaded so we need just retry getting the pdf with + // the original url. + var blobUrl = data.blobUrl || originalUrl; + + var originalUri = NetUtil.newURI(originalUrl); + var blobUri = NetUtil.newURI(blobUrl); + let mimeService = Cc['@mozilla.org/mime;1'].getService(Ci.nsIMIMEService); var handlerInfo = mimeService. getFromTypeAndExtension('application/pdf', 'pdf'); - var uri = NetUtil.newURI(data); var extHelperAppSvc = Cc['@mozilla.org/uriloader/external-helper-app-service;1']. @@ -116,26 +123,46 @@ ChromeActions.prototype = { var frontWindow = Cc['@mozilla.org/embedcomp/window-watcher;1']. getService(Ci.nsIWindowWatcher).activeWindow; var ioService = Services.io; - var channel = ioService.newChannel(data, null, null); - var listener = { - extListener: null, - onStartRequest: function(aRequest, aContext) { - this.extListener = extHelperAppSvc.doContent('application/pdf', - aRequest, frontWindow, false); - this.extListener.onStartRequest(aRequest, aContext); - }, - onStopRequest: function(aRequest, aContext, aStatusCode) { - if (this.extListener) - this.extListener.onStopRequest(aRequest, aContext, aStatusCode); - }, - onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, - aCount) { - this.extListener.onDataAvailable(aRequest, aContext, aInputStream, - aOffset, aCount); - } - }; + var channel = ioService.newChannel(originalUrl, null, null); - channel.asyncOpen(listener, null); + + NetUtil.asyncFetch(blobUri, function(aInputStream, aResult) { + if (!Components.isSuccessCode(aResult)) { + if (sendResponse) + sendResponse(true); + return; + } + // Create a nsIInputStreamChannel so we can set the url on the channel + // so the filename will be correct. + let channel = Cc['@mozilla.org/network/input-stream-channel;1']. + createInstance(Ci.nsIInputStreamChannel); + channel.setURI(originalUri); + channel.contentStream = aInputStream; + channel.QueryInterface(Ci.nsIChannel); + + var listener = { + extListener: null, + onStartRequest: function(aRequest, aContext) { + this.extListener = extHelperAppSvc.doContent('application/pdf', + aRequest, frontWindow, false); + this.extListener.onStartRequest(aRequest, aContext); + }, + onStopRequest: function(aRequest, aContext, aStatusCode) { + if (this.extListener) + this.extListener.onStopRequest(aRequest, aContext, aStatusCode); + // Notify the content code we're done downloading. + if (sendResponse) + sendResponse(false); + }, + onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, + aCount) { + this.extListener.onDataAvailable(aRequest, aContext, aInputStream, + aOffset, aCount); + } + }; + + channel.asyncOpen(listener, null); + }); }, setDatabase: function(data) { if (inPrivateBrowsing) @@ -199,20 +226,38 @@ ChromeActions.prototype = { function RequestListener(actions) { this.actions = actions; } -// Receive an event and synchronously responds. +// Receive an event and synchronously or asynchronously responds. RequestListener.prototype.receive = function(event) { var message = event.target; + var doc = message.ownerDocument; var action = message.getUserData('action'); var data = message.getUserData('data'); + var sync = message.getUserData('sync'); var actions = this.actions; if (!(action in actions)) { log('Unknown action: ' + action); return; } - var response = actions[action].call(this.actions, data); - message.setUserData('response', response, null); -}; + if (sync) { + var response = actions[action].call(this.actions, data); + message.setUserData('response', response, null); + } else { + var response; + if (!message.getUserData('callback')) { + doc.documentElement.removeChild(message); + response = null; + } else { + response = function sendResponse(response) { + message.setUserData('response', response, null); + var listener = doc.createEvent('HTMLEvents'); + listener.initEvent('pdf.js.response', true, false); + return message.dispatchEvent(listener); + } + } + actions[action].call(this.actions, data, response); + } +}; function PdfStreamConverter() { } diff --git a/extensions/firefox/tools/l10n.js b/extensions/firefox/tools/l10n.js index b16636e31..df20ff577 100644 --- a/extensions/firefox/tools/l10n.js +++ b/extensions/firefox/tools/l10n.js @@ -9,7 +9,7 @@ // fetch an l10n objects function getL10nData(key) { - var response = FirefoxCom.request('getStrings', key); + var response = FirefoxCom.requestSync('getStrings', key); var data = JSON.parse(response); if (!data) console.warn('[l10n] #' + key + ' missing for [' + gLanguage + ']'); @@ -78,7 +78,7 @@ } window.addEventListener('DOMContentLoaded', function() { - gLanguage = FirefoxCom.request('getLocale', null); + gLanguage = FirefoxCom.requestSync('getLocale', null); translateFragment(); diff --git a/src/api.js b/src/api.js index 59f9661bf..7d65f96b4 100644 --- a/src/api.js +++ b/src/api.js @@ -151,6 +151,15 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() { promise.resolve(this.pdfInfo.encrypted); return promise; }, + /** + * @return {Promise} A promise that is resolved with a TypedArray that has + * the raw data from the PDF. + */ + getData: function PDFDocumentProxy_getData() { + var promise = new PDFJS.Promise(); + this.transport.getData(promise); + return promise; + }, destroy: function PDFDocumentProxy_destroy() { this.transport.destroy(); } @@ -616,6 +625,12 @@ var WorkerTransport = (function WorkerTransportClosure() { this.messageHandler.send('GetDocRequest', {data: data, params: params}); }, + getData: function WorkerTransport_sendData(promise) { + this.messageHandler.send('GetData', null, function(data) { + promise.resolve(data); + }); + }, + getPage: function WorkerTransport_getPage(pageNumber, promise) { var pageIndex = pageNumber - 1; if (pageIndex in this.pagePromises) diff --git a/src/worker.js b/src/worker.js index a93c36e95..c1dfa79af 100644 --- a/src/worker.js +++ b/src/worker.js @@ -136,6 +136,10 @@ var WorkerMessageHandler = { handler.send('GetPage', {pageInfo: page}); }); + handler.on('GetData', function wphSetupGetData(data, promise) { + promise.resolve(pdfModel.stream.bytes); + }); + handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) { var pdfPage = pdfModel.getPage(data.pageIndex + 1); handler.send('GetAnnotations', { diff --git a/web/viewer.js b/web/viewer.js index 21a50e96b..f8837ba89 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -116,16 +116,19 @@ var RenderingQueue = (function RenderingQueueClosure() { var FirefoxCom = (function FirefoxComClosure() { return { /** - * Creates an event that hopefully the extension is listening for and will + * Creates an event that the extension is listening for and will * synchronously respond to. + * NOTE: It is reccomended to use request() instead since one day we may not + * be able to synchronously reply. * @param {String} action The action to trigger. * @param {String} data Optional data to send. * @return {*} The response. */ - request: function(action, data) { + requestSync: function(action, data) { var request = document.createTextNode(''); request.setUserData('action', action, null); request.setUserData('data', data, null); + request.setUserData('sync', true, null); document.documentElement.appendChild(request); var sender = document.createEvent('Events'); @@ -134,6 +137,39 @@ var FirefoxCom = (function FirefoxComClosure() { var response = request.getUserData('response'); document.documentElement.removeChild(request); return response; + }, + /** + * Creates an event that the extension is listening for and will + * asynchronously respond by calling the callback. + * @param {String} action The action to trigger. + * @param {String} data Optional data to send. + * @param {Function} callback Optional response callback that will be called + * with one data argument. + */ + request: function(action, data, callback) { + var request = document.createTextNode(''); + request.setUserData('action', action, null); + request.setUserData('data', data, null); + request.setUserData('sync', false, null); + if (callback) { + request.setUserData('callback', callback, null); + + document.addEventListener('pdf.js.response', function listener(event) { + var node = event.target, + callback = node.getUserData('callback'), + response = node.getUserData('response'); + + document.documentElement.removeChild(node); + + document.removeEventListener('pdf.js.response', listener, false); + return callback(response); + }, false); + } + document.documentElement.appendChild(request); + + var sender = document.createEvent('HTMLEvents'); + sender.initEvent('pdf.js.message', true, false); + return request.dispatchEvent(sender); } }; })(); @@ -160,7 +196,7 @@ var Settings = (function SettingsClosure() { var database = null; var index; if (isFirefoxExtension) - database = FirefoxCom.request('getDatabase', null) || '{}'; + database = FirefoxCom.requestSync('getDatabase', null) || '{}'; else if (isLocalStorageEnabled) database = localStorage.getItem('database') || '{}'; else @@ -193,7 +229,7 @@ var Settings = (function SettingsClosure() { file[name] = val; var database = JSON.stringify(this.database); if (isFirefoxExtension) - FirefoxCom.request('setDatabase', database); + FirefoxCom.requestSync('setDatabase', database); else if (isLocalStorageEnabled) localStorage.setItem('database', database); }, @@ -224,6 +260,7 @@ var PDFView = { container: null, initialized: false, fellback: false, + pdfDocument: null, // called once when the document is loaded initialize: function pdfViewInitialize() { this.container = document.getElementById('viewerContainer'); @@ -348,6 +385,7 @@ var PDFView = { PDFView.loadingBar = new ProgressBar('#loadingBar', {}); } + this.pdfDocument = null; var self = this; self.loading = true; PDFJS.getDocument(parameters).then( @@ -384,9 +422,37 @@ var PDFView = { }, download: function pdfViewDownload() { + function noData() { + FirefoxCom.request('download', { originalUrl: url }); + } + var url = this.url.split('#')[0]; if (PDFJS.isFirefoxExtension) { - FirefoxCom.request('download', url); + // Document isn't ready just try to download with the url. + if (!this.pdfDocument) { + noData(); + return; + } + this.pdfDocument.getData().then( + function getDataSuccess(data) { + var bb = new MozBlobBuilder(); + bb.append(data.buffer); + var blobUrl = window.URL.createObjectURL( + bb.getBlob('application/pdf')); + + FirefoxCom.request('download', { blobUrl: blobUrl, originalUrl: url }, + function response(err) { + if (err) { + // This error won't really be helpful because it's likely the + // fallback won't work either (or is already open). + PDFView.error('PDF failed to download.'); + } + window.URL.revokeObjectURL(blobUrl); + } + ); + }, + noData // Error ocurred try downloading with just the url. + ); } else { url += '#pdfjs.action=download', '_parent'; window.open(url, '_parent'); @@ -544,6 +610,8 @@ var PDFView = { }; } + this.pdfDocument = pdfDocument; + var errorWrapper = document.getElementById('errorWrapper'); errorWrapper.setAttribute('hidden', 'true'); @@ -1520,7 +1588,7 @@ window.addEventListener('load', function webViewerLoad(evt) { PDFJS.disableTextLayer = (hashParams['disableTextLayer'] === 'true'); if ('pdfBug' in hashParams && - (!PDFJS.isFirefoxExtension || FirefoxCom.request('pdfBugEnabled'))) { + (!PDFJS.isFirefoxExtension || FirefoxCom.requestSync('pdfBugEnabled'))) { PDFJS.pdfBug = true; var pdfBug = hashParams['pdfBug']; var enabled = pdfBug.split(','); @@ -1529,7 +1597,7 @@ window.addEventListener('load', function webViewerLoad(evt) { } if (!PDFJS.isFirefoxExtension || - (PDFJS.isFirefoxExtension && FirefoxCom.request('searchEnabled'))) { + (PDFJS.isFirefoxExtension && FirefoxCom.requestSync('searchEnabled'))) { document.querySelector('#viewSearch').classList.remove('hidden'); }