From aeaf11ca43d5d4676a886214ed7354482c957425 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Sat, 25 Jan 2014 20:09:04 +0100 Subject: [PATCH 1/3] [CRX] Fall back to sender.tab.url if !tab.url sender.url is relatively new (Chromium 29) ( https://chromiumcodereview.appspot.com/14301016 ) --- extensions/chromium/extension-router.js | 5 +---- web/pdf_history.js | 4 +++- web/viewer.js | 4 +++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/extensions/chromium/extension-router.js b/extensions/chromium/extension-router.js index 8f53cc118..d3c7d52b1 100644 --- a/extensions/chromium/extension-router.js +++ b/extensions/chromium/extension-router.js @@ -96,10 +96,7 @@ limitations under the License. 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); - } + showPageAction(sender.tab.id, sender.tab.url); } }); diff --git a/web/pdf_history.js b/web/pdf_history.js index c63a109a0..79161da25 100644 --- a/web/pdf_history.js +++ b/web/pdf_history.js @@ -145,7 +145,9 @@ var PDFHistory = { // window.history.pushState(stateObj, ''); //#endif //#if CHROME -// chrome.runtime.sendMessage('showPageAction'); +// if (top === window) { +// chrome.runtime.sendMessage('showPageAction'); +// } //#endif } }, diff --git a/web/viewer.js b/web/viewer.js index ef3fc9a7b..9021ec02f 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -1573,7 +1573,9 @@ 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'); +// if (top === window) { +// chrome.runtime.sendMessage('showPageAction'); +// } // } //})(); //#endif From b0e18a07036c49f16584a5c5773ce5490a1ea152 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Sat, 25 Jan 2014 21:44:58 +0100 Subject: [PATCH 2/3] [CRX] Remove redundant location.origin check The PDF Viewer will always be rendered directly from the extension, so checking "origin == chrome-extension:/.." is not needed any more. ( since edd4bae903c36048b7d4d4bed393e4408d0198ba ) --- web/viewer.js | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index 9021ec02f..4cd233be5 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -1564,18 +1564,14 @@ var DocumentOutlineView = function documentOutlineView(outline) { //(function rewriteUrlClosure() { // // Run this code outside DOMContentLoaded to make sure that the URL // // is rewritten as soon as possible. -// if (location.origin + '/' !== chrome.extension.getURL('/')) { -// DEFAULT_URL = window.location.href.split('#')[0]; -// } else { -// var params = PDFView.parseQueryString(document.location.search.slice(1)); -// DEFAULT_URL = params.file || DEFAULT_URL; +// var params = PDFView.parseQueryString(document.location.search.slice(1)); +// DEFAULT_URL = params.file || DEFAULT_URL; // -// // Example: chrome-extension://.../http://example.com/file.pdf -// var humanReadableUrl = '/' + DEFAULT_URL + location.hash; -// history.replaceState(history.state, '', humanReadableUrl); -// if (top === window) { -// chrome.runtime.sendMessage('showPageAction'); -// } +// // Example: chrome-extension://.../http://example.com/file.pdf +// var humanReadableUrl = '/' + DEFAULT_URL + location.hash; +// history.replaceState(history.state, '', humanReadableUrl); +// if (top === window) { +// chrome.runtime.sendMessage('showPageAction'); // } //})(); //#endif @@ -1594,12 +1590,6 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) { //var file = DEFAULT_URL; //#endif -//#if CHROME -//if (location.protocol !== 'chrome-extension:') { -// file = location.href.split('#')[0]; -//} -//#endif - //#if !(FIREFOX || MOZCENTRAL || CHROME || B2G) var fileInput = document.createElement('input'); fileInput.id = 'fileInput'; From 60fb28caf08263941b827e746e903ace60396950 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Sat, 25 Jan 2014 22:29:33 +0100 Subject: [PATCH 3/3] Register as File browser handler in Chrome OS --- extensions/chromium/extension-router.js | 35 ++++++--- extensions/chromium/manifest.json | 12 +++- extensions/chromium/pdfHandler-vcros.js | 95 +++++++++++++++++++++++++ extensions/chromium/pdfHandler.html | 1 + web/viewer.js | 3 + 5 files changed, 135 insertions(+), 11 deletions(-) create mode 100644 extensions/chromium/pdfHandler-vcros.js diff --git a/extensions/chromium/extension-router.js b/extensions/chromium/extension-router.js index d3c7d52b1..e56c45fa0 100644 --- a/extensions/chromium/extension-router.js +++ b/extensions/chromium/extension-router.js @@ -22,16 +22,33 @@ limitations under the License. var VIEWER_URL = chrome.extension.getURL('content/web/viewer.html'); var CRX_BASE_URL = chrome.extension.getURL('/'); + var schemes = [ + 'http', + 'https', + 'ftp', + 'file', + 'chrome-extension', + // Chromium OS + 'filesystem', + // Chromium OS, shorthand for filesystem:/external/ + 'drive' + ]; + /** * @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) { + // Find the (url-encoded) colon and verify that the scheme is whitelisted. + var schemeIndex = url.search(/:|%3A/i); + if (schemeIndex === -1) { + return; + } + var scheme = url.slice(0, schemeIndex).toLowerCase(); + if (schemes.indexOf(scheme) >= 0) { url = url.split('#')[0]; - if (matchingUrl[1] === ':') { + if (url.charAt(schemeIndex) === ':') { url = encodeURIComponent(url); } return url; @@ -86,12 +103,10 @@ limitations under the License. } }, { types: ['main_frame', 'sub_frame'], - urls: [ - CRX_BASE_URL + 'http*', // and https - CRX_BASE_URL + 'file*', - CRX_BASE_URL + 'ftp*', - CRX_BASE_URL + 'chrome-extension*' - ] + urls: schemes.map(function(scheme) { + // Format: "chrome-extension://[EXTENSIONID]/*" + return CRX_BASE_URL + scheme + '*'; + }) }, ['blocking']); chrome.runtime.onMessage.addListener(function(message, sender) { @@ -104,7 +119,7 @@ limitations under the License. // webRequest event listener is attached (= page not found). // Reload these tabs. chrome.tabs.query({ - url: CRX_BASE_URL + '*://*' + url: CRX_BASE_URL + '*:*' }, function(tabsFromLastSession) { for (var i = 0; i < tabsFromLastSession.length; ++i) { chrome.tabs.reload(tabsFromLastSession[i].id); diff --git a/extensions/chromium/manifest.json b/extensions/chromium/manifest.json index cd760480b..a70994830 100644 --- a/extensions/chromium/manifest.json +++ b/extensions/chromium/manifest.json @@ -9,6 +9,7 @@ "16": "icon16.png" }, "permissions": [ + "fileBrowserHandler", "webRequest", "webRequestBlocking", "", "tabs", @@ -25,6 +26,13 @@ ], "js": ["nothing.js"] }], + "file_browser_handlers": [{ + "id": "open-as-pdf", + "default_title": "Open with PDF Viewer", + "file_filters": [ + "filesystem:*.pdf" + ] + }], "mime_types": [ "application/pdf" ], @@ -47,6 +55,8 @@ "https:/*", "ftp:/*", "file:/*", - "chrome-extension:/*" + "chrome-extension:/*", + "filesystem:/*", + "drive:*" ] } diff --git a/extensions/chromium/pdfHandler-vcros.js b/extensions/chromium/pdfHandler-vcros.js new file mode 100644 index 000000000..4fb7b3614 --- /dev/null +++ b/extensions/chromium/pdfHandler-vcros.js @@ -0,0 +1,95 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* +Copyright 2014 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 chrome, getViewerURL */ + +(function() { +'use strict'; + +if (!chrome.fileBrowserHandler) { + // Not on Chromium OS, bail out + return; +} +chrome.fileBrowserHandler.onExecute.addListener(onExecuteFileBrowserHandler); + +/** + * Invoked when "Open with PDF Viewer" is chosen in the File browser. + * + * @param {String} id File browser action ID as specified in manifest.json + * @param {Object} details Object of type FileHandlerExecuteEventDetails + */ +function onExecuteFileBrowserHandler(id, details) { + if (id !== 'open-as-pdf') { + return; + } + var fileEntries = details.entries; + // "tab_id" is the currently documented format, but it is inconsistent with + // the other Chrome APIs that use "tabId" (http://crbug.com/179767) + var tabId = details.tab_id || details.tabId; + if (tabId > 0) { + chrome.tabs.get(tabId, function(tab) { + openViewer(tab && tab.windowId, fileEntries); + }); + } else { + // Re-use existing window, if available. + chrome.windows.getLastFocused(function(chromeWindow) { + var windowId = chromeWindow && chromeWindow.id; + if (windowId) { + chrome.windows.update(windowId, { focused: true }); + } + openViewer(windowId, fileEntries); + }); + } +} + +/** + * Open the PDF Viewer for the given list of PDF files. + * + * @param {number} windowId + * @param {Array} fileEntries List of Entry objects (HTML5 FileSystem API) + */ +function openViewer(windowId, fileEntries) { + if (!fileEntries.length) { + return; + } + var fileEntry = fileEntries.shift(); + var url = fileEntry.toURL(); + // Use drive: alias to get shorter (more human-readable) URLs. + url = url.replace(/^filesystem:chrome-extension:\/\/[a-p]{32}\/external\//, + 'drive:'); + url = getViewerURL(url); + + if (windowId) { + chrome.tabs.create({ + windowId: windowId, + active: true, + url: url + }, function() { + openViewer(windowId, fileEntries); + }); + } else { + chrome.windows.create({ + type: 'normal', + focused: true, + url: url + }, function(chromeWindow) { + openViewer(chromeWindow.id, fileEntries); + }); + } +} + +})(); diff --git a/extensions/chromium/pdfHandler.html b/extensions/chromium/pdfHandler.html index df35754e0..ffb6c1ae6 100644 --- a/extensions/chromium/pdfHandler.html +++ b/extensions/chromium/pdfHandler.html @@ -18,3 +18,4 @@ limitations under the License. + diff --git a/web/viewer.js b/web/viewer.js index 4cd233be5..f85f3c5a0 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -1588,6 +1588,9 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) { //#endif //#if CHROME //var file = DEFAULT_URL; +//// XHR cannot get data from drive:-URLs, so expand to filesystem: (Chrome OS) +//file = file.replace(/^drive:/i, +// 'filesystem:' + location.origin + '/external/'); //#endif //#if !(FIREFOX || MOZCENTRAL || CHROME || B2G)