From 1bd2494431d9ddc26ad27f9c32b1c8d711f3b263 Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Fri, 2 Jun 2017 00:39:29 +0800 Subject: [PATCH] Add support for GitHub Enterprise (#450) --- extension/background.js | 3 + extension/content.js | 10 +- extension/manifest.json | 20 +++- extension/options/index.css | 6 + extension/options/index.html | 12 ++ extension/options/index.js | 25 +++++ .../vendor/webext-dynamic-content-scripts.js | 105 ++++++++++++++++++ 7 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 extension/background.js create mode 100644 extension/options/index.css create mode 100644 extension/options/index.html create mode 100644 extension/options/index.js create mode 100644 extension/vendor/webext-dynamic-content-scripts.js diff --git a/extension/background.js b/extension/background.js new file mode 100644 index 0000000..5d9e433 --- /dev/null +++ b/extension/background.js @@ -0,0 +1,3 @@ +/* globals injectContentScripts */ + +injectContentScripts(); diff --git a/extension/content.js b/extension/content.js index d19b26a..f8d1191 100644 --- a/extension/content.js +++ b/extension/content.js @@ -467,7 +467,7 @@ $(document).on('pjax:end', () => { } }); -document.addEventListener('DOMContentLoaded', () => { +function init() { const username = getUsername(); markUnread.unreadIndicatorIcon(); @@ -601,8 +601,14 @@ document.addEventListener('DOMContentLoaded', () => { } }); } -}); +} if (!pageDetect.isGist()) { addTrendingMenuItem(); } + +if (document.readyState === 'complete') { + init(); +} else { + document.addEventListener('DOMContentLoaded', init); +} diff --git a/extension/manifest.json b/extension/manifest.json index 2a28d9d..b8778aa 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -8,9 +8,24 @@ "permissions": [ "storage" ], + "optional_permissions": [ + "http://*/*", + "https://*/*" + ], "icons": { "128": "icon.png" }, + "options_ui": { + "chrome_style": true, + "page": "options/index.html" + }, + "background": { + "scripts": [ + "vendor/webext-dynamic-content-scripts.js", + "background.js" + ], + "persistent": false + }, "content_scripts": [ { "run_at": "document_start", @@ -26,6 +41,7 @@ "vendor/jquery.slim.min.js", "vendor/element-ready.js", "vendor/gh-injection.js", + "vendor/webext-dynamic-content-scripts.js", "util.js", "page-detect.js", "icons.js", @@ -36,10 +52,10 @@ "copy-gist.js", "copy-on-y.js", "show-names.js", - "content.js", "mark-unread.js", "linkify-urls-in-code.js", - "upload-button.js" + "upload-button.js", + "content.js" ] } ] diff --git a/extension/options/index.css b/extension/options/index.css new file mode 100644 index 0000000..a15540c --- /dev/null +++ b/extension/options/index.css @@ -0,0 +1,6 @@ +html { + font-family: sans-serif; +} +input { + font: inherit; +} diff --git a/extension/options/index.html b/extension/options/index.html new file mode 100644 index 0000000..0f7a514 --- /dev/null +++ b/extension/options/index.html @@ -0,0 +1,12 @@ + + +Refined GitHub options + +
+

GitHub Enterprise support

+

+ + +

+
+ diff --git a/extension/options/index.js b/extension/options/index.js new file mode 100644 index 0000000..0b6f303 --- /dev/null +++ b/extension/options/index.js @@ -0,0 +1,25 @@ +const cdForm = document.querySelector('#custom-domain'); +const cdInput = document.querySelector('#custom-domain-origin'); + +if (!chrome.permissions) { + cdForm.disabled = true; + cdForm.querySelector('p').textContent = 'Your browser doesn’t support the required Permission API.'; +} + +cdForm.addEventListener('submit', event => { + event.preventDefault(); + + const origin = new URL(cdInput.value).origin; + + if (origin) { + chrome.permissions.request({ + origins: [ + `${origin}/*` + ] + }, granted => { + if (granted) { + cdForm.reset(); + } + }); + } +}); diff --git a/extension/vendor/webext-dynamic-content-scripts.js b/extension/vendor/webext-dynamic-content-scripts.js new file mode 100644 index 0000000..1133d78 --- /dev/null +++ b/extension/vendor/webext-dynamic-content-scripts.js @@ -0,0 +1,105 @@ +// https://github.com/bfred-it/webext-dynamic-content-scripts 2.0.0 + +var injectContentScripts = (function () { +'use strict'; + +function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; +} + +var webextContentScriptPing = createCommonjsModule(function (module, exports) { +// https://github.com/bfred-it/webext-content-script-ping + +function pingContentScript(tab) { + return new Promise((resolve, reject) => { + setTimeout(reject, 300); + chrome.tabs.sendMessage(tab.id || tab, chrome.runtime.id, { + // Only the main frame is necessary; + // if that isn't loaded, no other iframe is + frameId: 0 + }, response => { + if (response === chrome.runtime.id) { + resolve(); + } else { + reject(); + } + }); + }); +} + +if (!chrome.runtime.getBackground) { + // Respond to pings + chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request === chrome.runtime.id) { + sendResponse(chrome.runtime.id); + } + }); +} + +if (typeof exports === 'object') { + exports.pingContentScript = pingContentScript; +} +}); + +var pingContentScript = webextContentScriptPing.pingContentScript; + +function logRuntimeErrors() { + if (chrome.runtime.lastError) { + console.error(chrome.runtime.lastError); + } +} + +async function injectContentScript(script, tabId) { + const allFrames = script.all_frames; + const runAt = script.run_at; + script.css.forEach(file => chrome.tabs.insertCSS(tabId, {file, allFrames, runAt}, logRuntimeErrors)); + script.js.forEach(file => chrome.tabs.executeScript(tabId, {file, allFrames, runAt}, logRuntimeErrors)); +} + +async function injectContentScripts(tab) { + // Get the tab object if we don't have it already + if (!tab.id) { + tab = await new Promise(resolve => chrome.tabs.get(tab, resolve)); + logRuntimeErrors(); + } + + // If we don't have the URL, we definitely can't access it. + if (!tab.url) { + return; + } + + // We might just get the url because of the `tabs` permission, + // not necessarily because we have access to the origin. + // This will explicitly verify this permission. + const isPermitted = await new Promise(resolve => chrome.permissions.contains({ + origins: [new URL(tab.url).origin + '/'] + }, resolve)); + logRuntimeErrors(); + + if (!isPermitted) { + return; + } + + // Exit if already injected + try { + return await pingContentScript(tab.id || tab); + } catch (err) {} + + chrome.runtime.getManifest().content_scripts.forEach(s => injectContentScript(s, tab.id)); +} + +var index = function (tab = false) { + if (tab === false) { + chrome.tabs.onUpdated.addListener((tabId, {status}) => { + if (status === 'loading') { + injectContentScripts(tabId); + } + }); + } else { + injectContentScripts(tab); + } +}; + +return index; + +}());