From 8526d3c60089d9e492af4767fed621af58596065 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Sat, 7 Dec 2013 12:32:08 +0100 Subject: [PATCH] [CRX] Add a pageAction to omnibox showing PDF URL In Chromium extensions, the viewer's URL looks like this: chrome-extension://oemmndcbldboiebfnladdacbdfmadadm/http://example.com/file.pdf Furthermore, the PDF Viewer itself can also add something to the reference fragment: chrome-extension://oemmndcbldboiebfnladdacbdfmadadm/http://example.com/file.pdf#page=2 Consequently, it is difficult to copy a clean URL (e.g. for sharing over mail) without having to tidy-up the URL manually. This commit solves this issue by adding a button to the omnibox, which shows the clean PDF URL on click. --- extensions/chromium/extension-router.js | 68 ++++++++++++++++++++--- extensions/chromium/icon19.png | Bin 0 -> 787 bytes extensions/chromium/icon38.png | Bin 0 -> 1419 bytes extensions/chromium/manifest.json | 8 +++ extensions/chromium/pageActionPopup.html | 43 ++++++++++++++ extensions/chromium/pageActionPopup.js | 22 ++++++++ web/pdf_history.js | 3 + web/viewer.js | 1 + 8 files changed, 137 insertions(+), 8 deletions(-) create mode 100644 extensions/chromium/icon19.png create mode 100644 extensions/chromium/icon38.png create mode 100644 extensions/chromium/pageActionPopup.html create mode 100644 extensions/chromium/pageActionPopup.js diff --git a/extensions/chromium/extension-router.js b/extensions/chromium/extension-router.js index 07cac9b69..8f53cc118 100644 --- a/extensions/chromium/extension-router.js +++ b/extensions/chromium/extension-router.js @@ -22,6 +22,55 @@ limitations under the License. var VIEWER_URL = chrome.extension.getURL('content/web/viewer.html'); var CRX_BASE_URL = chrome.extension.getURL('/'); + /** + * @param {string} url The URL prefixed with chrome-extension://.../ + * @return {string|undefined} The percent-encoded URL of the (PDF) file. + */ + function parseExtensionURL(url) { + url = url.substring(CRX_BASE_URL.length); + var matchingUrl = /^(?:https?|file|ftp|chrome-extension)(:|%3A)/i.exec(url); + if (matchingUrl) { + url = url.split('#')[0]; + if (matchingUrl[1] === ':') { + url = encodeURIComponent(url); + } + return url; + } + } + + /** + * @param {string} url URL of PDF Viewer. + * @return {string|undefined} The percent-encoded URL of the (PDF) file. + */ + function parseViewerURL(url) { + if (url.lastIndexOf(VIEWER_URL, 0) !== 0) { + // Does not even start with the correct URL. Bye! + return; + } + url = url.match(/[&?]file=([^&#]+)/); + if (url) { + url = url[1]; + return url; + } + } + + /** + * @param {number} tabId ID of tab where the page action will be shown + * @param {string} url URL to be displayed in page action + */ + function showPageAction(tabId, displayUrl) { + var url = parseExtensionURL(displayUrl) || parseViewerURL(displayUrl); + if (url) { + chrome.pageAction.setPopup({ + tabId: tabId, + popup: 'pageActionPopup.html?file=' + url + }); + chrome.pageAction.show(tabId); + } else { + console.log('Unable to get PDF url from ' + displayUrl); + } + } + // TODO(rob): Use declarativeWebRequest once declared URL-encoding is // supported, see http://crbug.com/273589 // (or rewrite the query string parser in viewer.js to get it to @@ -29,14 +78,8 @@ limitations under the License. chrome.webRequest.onBeforeRequest.addListener(function(details) { // This listener converts chrome-extension://.../http://...pdf to // chrome-extension://.../content/web/viewer.html?file=http%3A%2F%2F...pdf - var url = details.url.substring(CRX_BASE_URL.length); - var matchingUrl = /^(?:https?|file|ftp|chrome-extension)(:|%3A)/.exec(url); - if (matchingUrl) { - // location.hash is restored when "#" is missing from URL. - url = url.split('#')[0]; - if (matchingUrl[1] === ':') { - url = encodeURIComponent(url); - } + var url = parseExtensionURL(details.url); + if (url) { url = VIEWER_URL + '?file=' + url; console.log('Redirecting ' + details.url + ' to ' + url); return { redirectUrl: url }; @@ -51,6 +94,15 @@ limitations under the License. ] }, ['blocking']); + chrome.runtime.onMessage.addListener(function(message, sender) { + if (message === 'showPageAction' && sender.tab) { + if (sender.tab.url === sender.url) { + // Only respond to messages from the top-level frame + showPageAction(sender.tab.id, sender.url); + } + } + }); + // When session restore is used, viewer pages may be loaded before the // webRequest event listener is attached (= page not found). // Reload these tabs. diff --git a/extensions/chromium/icon19.png b/extensions/chromium/icon19.png new file mode 100644 index 0000000000000000000000000000000000000000..55f4628a64d695707ccc8ca541fe31daf7f99fd2 GIT binary patch literal 787 zcmV+u1MK{XP)19NPu#UYmKdUaC*APKBM_1JqHi zt!BVb22>p&?YB%AiWk|@@=XkJFs0r&@N>VB~1+;?(34iZ9QX_X|Blr76EY RU#9>7002ovPDHLkV1gjbXU6~l literal 0 HcmV?d00001 diff --git a/extensions/chromium/icon38.png b/extensions/chromium/icon38.png new file mode 100644 index 0000000000000000000000000000000000000000..86afc6a1b6aa68df914deb9314a088d5b849203e GIT binary patch literal 1419 zcmV;61$6p}P)R!KHZy4bDzd=pe1QP<4Gg9g2=$WJ=TA9Z?onB` z2W&P;60O$10DM*uga$Z&9J&o!p#yL$wAmsE^{_b&+sp7_lVmyIbh*Opn`3D4eEtBL zOs1Xlz~JQB9-lv{b<|UD{{Z=eA@X>=iEgKJK$2vS)n+q^qO}eG{x^KTf;P9K+u85w z@haSxZHoDYKLrfcg}|yjJw35v4wg$Uw)<Nv~g8#+sE$`ZMuc%k=42FE&D0$ zWBp1(kX*h00@1gJiFUx>fvxIy)`=#fnl)O#4t+3(kUQQZ12DLE{yexOqS{S)@BfrO z*x4`CKKlWs#B%LAE|dt?A0*oO7*XpP)o@p}`gyrkZSQEq0*Pe6zB;0|zg$%utf^N0 zZ2OU@0i$U8y$mpKw;JH&v0Sj9zERtMIh6}m|Ek)qsT8nNpUm%56fEQ=+Om%5+{x0w zc)Iz|eECsvu*RCJNo;~>IE2~psv}qS8XF4}J->13z}|q(&nHwU*32|)r4qryLqv!6 zs(PZ5X!Dw-o66k}=C(V{L_WF9HKs`e(_8#{V1Jy(5h6j} zt|b7=e%x|#urtSVZN^85_Ef3sEBpDkwFEFuunl#&feIy9POe&leP+G>R36`(Nv6EM zxb3Y+Gi_ftBf+j+01R6aoSu)?J{&V*OG{lO)pXW?dl+)&KKU2GG{V}5u3Q8 zsAsVt?v^-N9LeXH2Zl45Xatyc7V`&!WU*NG6bG}~I*kB}#niJH-^ja6rl*U7;fVXU z5nz0`WE;1qCyI;E1I58avCRlDzH_n->KMZSTU!(i3-N*xU}KT-w2j^22m$Qo62OG- zd;9vA9gIr_>5Hx`d-ECez&__Q_)>!p=wn6%aCDySdznb$S55RbH!a Z*8gC=t&1N);_Uzc002ovPDHLkV1m6*vFHE* literal 0 HcmV?d00001 diff --git a/extensions/chromium/manifest.json b/extensions/chromium/manifest.json index b30aa40d5..b709b780d 100644 --- a/extensions/chromium/manifest.json +++ b/extensions/chromium/manifest.json @@ -21,6 +21,14 @@ "background": { "page": "pdfHandler.html" }, + "page_action": { + "default_icon": { + "19": "icon19.png", + "38": "icon38.png" + }, + "default_title": "Show PDF URL", + "default_popup": "pageActionPopup.html" + }, "incognito": "split", "web_accessible_resources": [ "getFrameId", diff --git a/extensions/chromium/pageActionPopup.html b/extensions/chromium/pageActionPopup.html new file mode 100644 index 000000000..93baed80a --- /dev/null +++ b/extensions/chromium/pageActionPopup.html @@ -0,0 +1,43 @@ + + + + + + + + + + + diff --git a/extensions/chromium/pageActionPopup.js b/extensions/chromium/pageActionPopup.js new file mode 100644 index 000000000..0c3c18459 --- /dev/null +++ b/extensions/chromium/pageActionPopup.js @@ -0,0 +1,22 @@ +/* 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. + */ +var url = location.search.match(/[&?]file=([^&]+)/i); +if (url) { + url = decodeURIComponent(url[1]); + document.body.textContent = url; + // Set cursor to end of the content-editable section. + getSelection().selectAllChildren(document.body); + getSelection().collapseToEnd(); +} diff --git a/web/pdf_history.js b/web/pdf_history.js index e1a32f43b..c63a109a0 100644 --- a/web/pdf_history.js +++ b/web/pdf_history.js @@ -143,6 +143,9 @@ var PDFHistory = { window.history.pushState(stateObj, '', document.URL); //#else // window.history.pushState(stateObj, ''); +//#endif +//#if CHROME +// chrome.runtime.sendMessage('showPageAction'); //#endif } }, diff --git a/web/viewer.js b/web/viewer.js index 9ea0388d3..8e591bc09 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -1530,6 +1530,7 @@ var DocumentOutlineView = function documentOutlineView(outline) { // // Example: chrome-extension://.../http://example.com/file.pdf // var humanReadableUrl = '/' + DEFAULT_URL + location.hash; // history.replaceState(history.state, '', humanReadableUrl); +// chrome.runtime.sendMessage('showPageAction'); // } //})(); //#endif