From 3c1c1df08dededf17dadfac308acef79ddb95d40 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Sun, 12 Nov 2017 23:53:04 +0100 Subject: [PATCH] Replace custom "Open With" with default "Open With" Remove the registry of external applications, and change the option to use Firefox's default "Open With" dialog (if any). --- extension/background.js | 6 +- extension/dialog.html | 4 +- extension/dialog.js | 34 +------ extension/external-viewers.js | 15 --- extension/i18n.js | 4 + extension/manifest.json | 2 - extension/open-with.js | 85 ----------------- extension/options.html | 7 -- extension/options.js | 39 +------- extension/prefs.js | 8 +- gen-i18n.js | 10 +- gen-viewer-info.js | 172 ---------------------------------- viewers/.template.json | 17 ---- viewers/google_docs.json | 9 -- 14 files changed, 23 insertions(+), 389 deletions(-) delete mode 100644 extension/external-viewers.js delete mode 100644 extension/open-with.js delete mode 100755 gen-viewer-info.js delete mode 100644 viewers/.template.json delete mode 100644 viewers/google_docs.json diff --git a/extension/background.js b/extension/background.js index 9e6c14d..ff5b0c4 100644 --- a/extension/background.js +++ b/extension/background.js @@ -1,7 +1,7 @@ /** * (c) 2013 Rob Wu (https://robwu.nl) */ -/* globals Prefs, MimeActions, mime_fromFilename, ModalDialog, OpenWith, ContentHandlers */ +/* globals Prefs, MimeActions, mime_fromFilename, ModalDialog, ContentHandlers */ 'use strict'; var dialogURL = chrome.extension.getURL('dialog.html'); @@ -73,7 +73,6 @@ chrome.webRequest.onHeadersReceived.addListener(async function(details) { guessedMimeType: guessedMimeType, mimeType: mimeType, isSniffingMimeType: isSniffingMimeType, - openWithOptions: OpenWith.getAvailableViewers([mimeType, guessedMimeType]) }; var dialog = new ModalDialog({ url: dialogURL + '#' + encodeURIComponent(JSON.stringify(dialogArguments)), @@ -98,7 +97,8 @@ chrome.webRequest.onHeadersReceived.addListener(async function(details) { Prefs.setMimeAction(guessedMimeType, isSniffingMimeType, desiredAction); } if (desiredAction.action === MimeActions.OPENWITH) { - return OpenWith.openWith(desiredAction.openWith, details); + // Don't modify the response headers and let the browser handle the request. + return; } return { responseHeaders: details.responseHeaders diff --git a/extension/dialog.html b/extension/dialog.html index 2f370f8..6ef1eed 100644 --- a/extension/dialog.html +++ b/extension/dialog.html @@ -28,9 +28,7 @@ What should brandShortName do with this file?
-

"Open with" viewers

-External viewers allows you to display many other files directly in the browser.
- -
-
- - diff --git a/extension/options.js b/extension/options.js index eed1b99..e4dadbc 100644 --- a/extension/options.js +++ b/extension/options.js @@ -1,4 +1,4 @@ -/* globals Prefs, MimeActions, EXTERNAL_VIEWERS */ +/* globals Prefs, MimeActions */ 'use strict'; Prefs.init(); var $ = document.getElementById.bind(document); @@ -67,7 +67,8 @@ function renderMimeMappingsCommon(mimeMappings, table, isSniffingMimeType) { } else if (mimeAction.action === MimeActions.OIB_SERVER_SNIFF) { actionMessage = 'Open in browser with sniffed MIME'; } else if (mimeAction.action === MimeActions.OPENWITH) { - actionMessage = 'Open with ' + EXTERNAL_VIEWERS[mimeAction.openWith].name; + // TODO: i18n. + actionMessage = 'Open with browser (Choose other Application)'; } else if (mimeAction.action === MimeActions.DOWNLOAD) { actionMessage = 'Save file'; } @@ -90,38 +91,6 @@ function renderMimeMappingsCommon(mimeMappings, table, isSniffingMimeType) { table.hidden = false; } -function renderViewerPreferences(externalViewersPref) { - var prefItems = document.createDocumentFragment(); - - var labelBase = document.createElement('label'); - labelBase.className = 'pref'; - - var checkboxBase = document.createElement('input'); - checkboxBase.type = 'checkbox'; - - Object.keys(EXTERNAL_VIEWERS).forEach(function(identifier) { - var viewer = EXTERNAL_VIEWERS[identifier]; - var pref = externalViewersPref[identifier]; - var isEnabled = !pref || pref.enabled; - var label = labelBase.cloneNode(); - var checkbox = checkboxBase.cloneNode(); - - checkbox.checked = isEnabled; - checkbox.onchange = function toggleViewer() { - if (!pref) pref = externalViewersPref[identifier] = {}; - pref.enabled = this.checked; - Prefs.set('external-viewers', externalViewersPref); - }; - - var labelText = viewer.name; - - label.appendChild(checkbox); - label.appendChild(document.createTextNode(labelText)); - prefItems.appendChild(label); - }); - $('external-viewers').appendChild(prefItems); -} - bindBooleanPref('text-nosniff'); bindBooleanPref('octet-sniff-mime'); @@ -130,5 +99,3 @@ Prefs.setPrefHandler('mime-mappings', renderMimeMappings); Prefs.setPrefHandler('sniffed-mime-mappings', renderSniffedMimeMappings); -Prefs.setPrefHandler('external-viewers', renderViewerPreferences); - diff --git a/extension/prefs.js b/extension/prefs.js index ec5226d..fb82fac 100644 --- a/extension/prefs.js +++ b/extension/prefs.js @@ -25,11 +25,6 @@ var prefs = { 'mime-mappings': {}, // Similar to mime-mappings; used if MIME-sniffing is enabled. 'sniffed-mime-mappings': {}, - 'external-viewers': { - // Formats: (see open-with.js) - // 'google_docs': { "enabled": true }, - // 'pdfjs': { "enabled": true, "extensionid": ''...' }, - }, // Whether to add the "X-Content-Type-Options: nosniff" header to text/plain requests 'text-nosniff': true, // Whether to use the file extension for detecting type when mime=application/octet-stream @@ -134,7 +129,6 @@ function getMimeAction(mimeType, isSniffingMimeType, serverSentMimeType) { case MimeActions.OPENWITH: return { action: actionType, - openWith: actionArgs }; case MimeActions.DOWNLOAD: return { @@ -156,7 +150,7 @@ function setMimeAction(mimeType, isSniffingMimeType, desiredAction) { var actionType = desiredAction.action; // The following assumes that the desiredAction object is always clean, // i.e. it doesn't contain any significant properties of a different action. - var actionArgs = desiredAction.openWith || desiredAction.mime || ''; + var actionArgs = desiredAction.mime || ''; if (actionType === MimeActions.OIB_SERVER_SENT || actionType === MimeActions.OIB_SERVER_SNIFF) { // For these actions the MIME is inferred from the request. diff --git a/gen-i18n.js b/gen-i18n.js index 7dd3205..66f4ee8 100755 --- a/gen-i18n.js +++ b/gen-i18n.js @@ -89,7 +89,7 @@ var SOURCES = [{ 'intro2', 'from', 'actionQuestion', - //'openWith', // Future update + 'openWith', 'other', 'saveFile', 'rememberChoice', @@ -122,6 +122,14 @@ var SOURCES = [{ aliases: { 'preferencesDefaultTitleMac.title': 'preferences' } +}, { + source: '/chrome/mozapps/handling/handling.dtd', + properties: [ + 'chooseOtherApp' + ], + aliases: { + 'ChooseOtherApp.description': 'chooseOtherApp', + }, }]; /** diff --git a/gen-viewer-info.js b/gen-viewer-info.js deleted file mode 100755 index 0419daa..0000000 --- a/gen-viewer-info.js +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env node -/** - * (c) 2013 Rob Wu (https://robwu.nl) - * - * Parses all .json files in viewers/ and outputs to extensions/external-viewers.json - * This information is used by the "Open With" feature of the extension. - * - * See parseSourceDefinitionObject for the format definition - * Unrecognized keys are reported, unless it's prefixed with _. - * - * See also viewers/.template.json - */ - -/* eslint-env node */ -'use strict'; - -var fs = require('fs'); -var path = require('path'); - -var extensionRoot = path.resolve(__dirname, 'extension'); -var inputDirectory = path.resolve(__dirname, 'viewers'); -var outputFileName = path.join(extensionRoot, 'external-viewers.js'); - -var inputFiles = fs.readdirSync(inputDirectory).filter(function(filename) { - if (filename.charAt(0) === '.') return; - if (filename.match(/\.json$/)) return true; - console.warn('Not a JSON file: ' + filename); -}).sort(); // Sorting names just to make the output file consistent across git commits - -process.nextTick(function() { - var outputObject = {}; - var successCount = 0; - inputFiles.forEach(function(fileName) { - if (importSourceDefinition(outputObject, fileName)) { - successCount++; - } - }); - if (successCount !== inputFiles.length) { - var errorCount = inputFiles.length - successCount; - console.warn(errorCount + ' input files were ignored because of errors.'); - } else { - console.log('All input files were successfully processed.'); - } - var outputJson = JSON.stringify(outputObject, null, '\t'); - var r_mime_types = /^(\s*)"mime_types":(\s*)\[\s*"([\S\s]+?)"\s*\]/mg; - var EXTERNAL_VIEWERS = outputJson.replace(r_mime_types, mimeToRegExp); - var outputData = `/* AUTOGENERATED - DO NOT EDIT */ -'use strict'; -/* exported EXTERNAL_VIEWERS */ - -var EXTERNAL_VIEWERS = ${EXTERNAL_VIEWERS}; -`; - - fs.writeFileSync(outputFileName, outputData); - console.log('Written to ' + outputFileName); -}); - -// Used by outputJson.replace to expand the mime_types array to a regex. -function mimeToRegExp(full_match, leadingWhitespace, separatorWhitespace, mimeTypes) { - mimeTypes = mimeTypes.replace(/[[^$.|?+(){}\\/]/g, '\\$&'); // Escape special characters - mimeTypes = mimeTypes.replace(/\*/g, '.+'); - mimeTypes = mimeTypes.replace(/",\s*"/g, ')|(?:'); - mimeTypes = '(?:' + mimeTypes + ')'; - mimeTypes = '"r_mime_types":' + separatorWhitespace + '/^' + mimeTypes + '$/i'; - return full_match + ',\n' + leadingWhitespace + mimeTypes; -} - - - -function importSourceDefinition(/*object*/output, /*string*/fileName) { - console.log('Processing source: ' + fileName); - - var identifier = fileName.slice(0, -5); // Remove trailing .json - // - // File name constraint because of chrome.i18n - if (/\W/.test(identifier)) { - console.error('Invalid character in file name. Allowed characters: A-Z a-z 0-9 _'); - return; - } - var filePath = path.join(inputDirectory, fileName); - - var json = fs.readFileSync(filePath, {encoding: 'utf-8'}); - // Remove //-comments. May only contain leading space; - // "k":"v", // comment is NOT OK (contains something before //) - // // comment is OK (only leading whitespace) - json = json.replace(/^\s+\/\/.*/m); - - // Note: Might generate an error because of failure - // This error is not caught, because incorrect JSON needs to be fixed urgently. - var orig = JSON.parse(json); - - var parsed; - try { - parsed = parseSourceDefinitionObject(orig); - } catch (e) { - console.error(e); - } - if (parsed) { - output[identifier] = parsed; - console.log('Successfully added ' + identifier); - return true; - } else { - console.log('Did not add ' + identifier + ' because of previous errors.'); - } -} - -function parseSourceDefinitionObject(/*object*/orig) { - var assertionFailed = false; - function assert(assertion, errorMessage) { - if (!assertion) { - console.error('E: ' + errorMessage); - assertionFailed = true; - } - } - var parsed = {}; - - // type - var types = ['web', 'extension']; - assert(types.indexOf(orig.type) !== -1, - '"type" must be one of ' + types + '. Found "' + orig.type + '"'); - parsed.type = orig.type; - - // name - assert(typeof orig.name === 'string', '"name" is a required string.'); - parsed.name = orig.name; - - // url - assert(typeof orig.url === 'string', '"url" is a required string.'); - var validVariables = ['url', 'rawurl']; - if (parsed.type === 'extension') { - validVariables.push('extensionid'); - } - var variables = orig.url.match(/\$\{([^}]*)\}/g) || []; - variables.forEach(function(variable) { - assert(validVariables.indexOf(variable) === -1, - 'url variable must be one of ' + validVariables + '. Found "' + variable + '"'); - }); - parsed.url = orig.url; - - // extensionids - if (parsed.type === 'extension') { - assert(Array.isArray(orig.extensionids), '"extensionids" is a required array.'); - assert(orig.extensionids.length > 0, '"extensionids" requires at least one element.'); - orig.extensionids.forEach(function(extensionid) { - assert(/^[a-p]{32}$/.test(extensionid), - 'Invalid Chromium extension ID, got "' + extensionid + '".'); - }); - parsed.extensionids = orig.extensionids; - } else { - assert(!('extensionids' in orig), '"extensionids" is only valid for type="extension"'); - } - - // mime_types - assert(Array.isArray(orig.mime_types), '"mime_types" is a required array.'); - assert(orig.mime_types.length > 0, '"mime_types" requires at least one element.'); - orig.mime_types.forEach(function(mimeType) { - // RFC 2045, section 5.1 (definition of token) - // RFC 3023, section A.12 (practical list of allowed characters) - var r_mime_token = "[A-Za-z0-9.*\\-_%'`#&~!$^+{}|]+"; - var r_mime = new RegExp('^' + r_mime_token + '/' + r_mime_token + '$', 'i'); - assert(r_mime.test(mimeType), 'Invalid MIME-type. Expected a valid MIME-type ' + - '(or wildcards such as */*), got "' + mimeType + '"'); - }); - parsed.mime_types = orig.mime_types; - - Object.keys(orig).forEach(function(key) { - if (key.charAt(0) !== '_' && !parsed.hasOwnProperty(key)) { - console.warn('Unrecognized key: "' + key + '"'); - } - }); - return assertionFailed ? null : parsed; -} diff --git a/viewers/.template.json b/viewers/.template.json deleted file mode 100644 index 6b3182c..0000000 --- a/viewers/.template.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - // One of "web", "extension" - "type": "", - // Friendly (English) name of viewer - "name": "", - // Absolute URL to viewer - // ${url} is replaced with urlencoded document URL - // ${rawurl} is replaced with the original document URL - // ${extensionid} is replaced with the extensionID of viewer, if type="extension" - "url": "", - // List of extension IDs (Chrome / Opera). Must contain at least one element if type="extension" - "extensionids": [], - // List of MIME-types that the viewer recognizes (wildcards permitted) - "mime_types": [ - "" - ] -} diff --git a/viewers/google_docs.json b/viewers/google_docs.json deleted file mode 100644 index e0b458c..0000000 --- a/viewers/google_docs.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "web", - "name": "Google Docs Viewer", - "url": "https://docs.google.com/viewer?url=${url}", - "mime_types": [ - "*/*" - ], - "_comment": "See also: https://support.google.com/drive/answer/2423485" -}