From a27d8fc44936e979e8d3a35ef2d286e13db33a0b Mon Sep 17 00:00:00 2001 From: Alexander Danilov Date: Tue, 9 Jul 2019 15:00:32 +0300 Subject: [PATCH] Fix multiple pinned ingress tabs * Fix multiple pinned ingress tabs #11 * Fix (only in Firefox) js errors by gen_dashboard_... #8 --- app/popup/popup.js | 6 +- manifest.json | 7 ++ scripts/background.js | 207 ++++++++++++------------------------------ scripts/defaults.js | 4 +- scripts/loader.js | 65 +++++++++++++ scripts/pre.js | 43 --------- scripts/updater.js | 4 +- 7 files changed, 136 insertions(+), 200 deletions(-) create mode 100644 scripts/loader.js delete mode 100644 scripts/pre.js diff --git a/app/popup/popup.js b/app/popup/popup.js index 03272fb..4552bc2 100644 --- a/app/popup/popup.js +++ b/app/popup/popup.js @@ -33,10 +33,8 @@ let app = new Vue({ return ((typeof obj !== 'object') || (Object.keys(obj).length === 0)) }, 'openIITC': function () { - chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { - chrome.runtime.sendMessage({'type': "requestOpenIntel", 'tab': tabs[0].id}); - window.close(); - }) + chrome.runtime.sendMessage({'type': "requestOpenIntel"}); + window.close(); }, 'toggleIITC': function () { let checkedValue = this.IITC_is_enabled; diff --git a/manifest.json b/manifest.json index dd870a1..69b12e2 100644 --- a/manifest.json +++ b/manifest.json @@ -32,6 +32,13 @@ ], "persistent": false }, + "content_scripts": [ + { + "matches" : ["https://intel.ingress.com/*"], + "run_at": "document_start", + "js": ["scripts/loader.js"] + } + ], "browser_action": { "browser_style": true, "default_popup": "app/popup/popup.html", diff --git a/scripts/background.js b/scripts/background.js index 62b26bb..0b590f3 100644 --- a/scripts/background.js +++ b/scripts/background.js @@ -1,18 +1,16 @@ -let activeIITCTab = null; +let lastIITCTab = null; const { - onActivated, onUpdated, onRemoved } = chrome.tabs; // tab -onActivated.addListener(onActivatedListener); onUpdated.addListener(onUpdatedListener); onRemoved.addListener(onRemovedListener); chrome.runtime.onMessage.addListener(function(request) { switch (request.type) { case "requestOpenIntel": - onRequestOpenIntel(request.tab).finally(); + onRequestOpenIntel().finally(); break; case "toggleIITC": onToggleIITC(request.value).finally(); @@ -29,61 +27,38 @@ chrome.webNavigation.onBeforeNavigate.addListener( {url: [{pathSuffix: ".user.js"}]} ); -async function onRequestOpenIntel(id) { - if (!id) return; - const { - active, - url - } = await getTabInfo(id); - if (activeIITCTab) { - let isActive = false; - try { - isActive = await getTabInfo(activeIITCTab); - } catch (e) { - console.warn('tab not found:', activeIITCTab); - } - - if (!!isActive) { - console.log('found activeIITCTab %s', activeIITCTab); - return setTabActive(activeIITCTab); - } else { - activeIITCTab = null; +async function onRequestOpenIntel() { + if (lastIITCTab) { + const tabInfo = await getTabInfo(lastIITCTab); + if (isIngressUrl(tabInfo.url)) { + console.log('detected ingress.com/intel page on tab %d', lastIITCTab); + return setTabActive(lastIITCTab); } } - if (active) { - if (isIngressUrl(url)) { - console.log('detected ingress.com/intel page on active tab %d', id); - return; - } - return chrome.tabs.create({ - url: 'https://intel.ingress.com/intel', - pinned: true - }, function(tab) { - activeIITCTab = tab.id; - }); - } + return chrome.tabs.create({ + url: 'https://intel.ingress.com/intel', + pinned: true + }, function(tab) { + lastIITCTab = tab.id; + }); } async function onToggleIITC(value) { chrome.storage.local.set({'IITC_is_enabled': value}, async function() { - if (activeIITCTab) { - let isActive = false; - try { - isActive = await getTabInfo(activeIITCTab); - } catch (e) { - console.warn('tab not found:', activeIITCTab); - } + // Fetch all completly loaded Ingress Intel tabs + chrome.tabs.query({ + "url": "https://intel.ingress.com/*", + "status": "complete" + }, function (tabs) { - if (!!isActive) { - console.log('found activeIITCTab %s', activeIITCTab); - return chrome.tabs.reload(activeIITCTab); - } else { - activeIITCTab = null; + for (let tab of Object.values(tabs)) { + chrome.tabs.reload(tab.id); } - } + + }); }); } @@ -92,66 +67,26 @@ async function onToggleIITC(value) { // tab listeners async function onUpdatedListener(tabId, status) { if (status.status) { - console.log(JSON.stringify(status)); - console.log(status.status, ':tab updated #', tabId); - - const { - active, - url - } = await getTabInfo(tabId); - if (tabId === activeIITCTab) { - console.log('remove activeIITCTab'); - if(status.status === 'loading' && status.url) { - console.info('navigate to %s', status.url); - } - } - console.log('tab is active: ', active); - if (status.status === 'complete') { - if (isIngressUrl(url)) { - loaded_plugins = []; - console.log('detected intel.ingress.com/intel page on active tab %d', tabId); + const tabInfo = await getTabInfo(tabId); + if (isIngressUrl(tabInfo.url)) { + console.log('detected intel.ingress.com/intel page on tab %d', tabId); console.log('requested iitc launch'); - console.log('initializing iitc'); - initialize(tabId); + initialize(); + lastIITCTab = tabId; } } - return false; } } function onRemovedListener(tabId) { - console.log(tabId + ': closing'); - if (activeIITCTab === tabId) { - activeIITCTab = null; - console.log('removed iitc flags') - } -} - -async function onActivatedListener({ - tabId, - url -}) { - if (!tabId) { - throw new Error('not tabId found') - } - const tabInfo = await getTabInfo(tabId); - if (tabInfo) { - const isIngressTab = isIngressUrl(tabInfo.url) - - if (isIngressTab) { - console.log('tab has Intel url #', tabId); - } + if (lastIITCTab === tabId) { + lastIITCTab = null; } - - const { - active - } = await getTabInfo(tabId); - //if (active) chrome.pageAction.show(tabId); } -function initialize(tabId) { +function initialize() { chrome.storage.local.get([ "IITC_is_enabled", @@ -169,21 +104,15 @@ function initialize(tabId) { let iitc_version = data[channel+'_iitc_version']; if ((status === undefined || status === true) && iitc_code !== undefined) { - chrome.tabs.executeScript(tabId, { - runAt: "document_end", - file: './scripts/pre.js' - }, () => { let inject_iitc_code = preparationUserScript({'version': iitc_version, 'code': iitc_code}); - loadJS(tabId, "document_end", "ingress-intel-total-conversion@jonatkins", inject_iitc_code, function () { - activeIITCTab = tabId; - }); + injectUserScript(inject_iitc_code); let plugins_local = data[channel+'_plugins_local']; if (plugins_local !== undefined) { Object.keys(plugins_local).forEach(function(id) { let plugin = plugins_local[id]; if (plugin['status'] === 'on') { - loadJS(tabId, "document_end", id, preparationUserScript(plugin, id)); + injectUserScript(preparationUserScript(plugin, id)); } }); } @@ -193,13 +122,12 @@ function initialize(tabId) { Object.keys(plugins_user).forEach(function(id) { let plugin = plugins_user[id]; if (plugin['status'] === 'on') { - loadJS(tabId, "document_end", id, preparationUserScript(plugin, id)); + injectUserScript(preparationUserScript(plugin, id)); } }); } - - }); + } }); @@ -207,27 +135,29 @@ function initialize(tabId) { } -function loadJS(tabId, runAt, id, code, callback) { - if (!tabId) { console.log('no tabId!'); return } - - if (loaded_plugins.includes(id)) { - console.info('Plugin %s is already loaded. Skip', id); - return - } else { - loaded_plugins.push(id); - } - - callback = (typeof callback == 'function' ? callback : false); - - chrome.tabs.executeScript(tabId, { - runAt: runAt, - code: code - }, () => { - if(chrome.runtime.lastError) { - console.log(chrome.runtime.lastError.message); +function injectUserScript(code) { + let inject = ` + document.dispatchEvent(new CustomEvent('IITCButtonInitJS', { + detail: `+JSON.stringify(code)+` + })); + ` + // Fetch all completly loaded Ingress Intel tabs + chrome.tabs.query({ + "url": "https://intel.ingress.com/*", + "status": "complete" + }, function (tabs) { + + for (let tab of Object.values(tabs)) { + console.log(tab); + chrome.tabs.executeScript(tab.id, { + code: inject + }, () => { + if (chrome.runtime.lastError) { + console.log(chrome.runtime.lastError.message); + } + }); } - console.info('plugin %s loaded', id); - if (callback) callback(); + }); } @@ -240,10 +170,9 @@ function setTabActive(tabId) { setWindowFocused(tab.windowId) } catch (e) { console.log(e); - activeIITCTab = null; + lastIITCTab = null; console.log('repeated click with updated params'); - let id = await getActiveTab(); - onRequestOpenIntel(id); + onRequestOpenIntel().finally(); } }); } @@ -256,24 +185,6 @@ function getTabInfo(tabId) { return new Promise(resolve => chrome.tabs.get(tabId, resolve)); } -async function getActiveTab() { - return new Promise(resolve => chrome.tabs.query({ active: true }, resolve)) - .then(function(current) { - if (current && current[0]) { - return current[0].id - } else { - throw new Error('current tab not found') - } - }); -} - -/* function togglePageAction(state, id) { - state = state ? 'show' : 'hide'; - - chrome.pageAction.setIcon({ tabId: id, path: state ? "assets/images/48/logo.png" : "assets/images/19/logo-ok.png" }); - chrome.pageAction.setTitle({ tabId: id, title: state ? "open IITC" : "Intel Ingress Enable is Activated" }); - chrome.pageAction[state](id); -} */ function isIngressUrl(url) { if (url) { return (/intel.ingress.com/.test(url)) diff --git a/scripts/defaults.js b/scripts/defaults.js index 14da62d..1113c87 100644 --- a/scripts/defaults.js +++ b/scripts/defaults.js @@ -3,6 +3,4 @@ let network_host = { 'release': "https://iitc.modos189.ru/build/release", 'test': "https://iitc.modos189.ru/build/test", 'local': "http://127.0.0.1:8000" -} - -let loaded_plugins = []; \ No newline at end of file +} \ No newline at end of file diff --git a/scripts/loader.js b/scripts/loader.js new file mode 100644 index 0000000..2f1e1c3 --- /dev/null +++ b/scripts/loader.js @@ -0,0 +1,65 @@ +let loaded_plugins = []; +let sandbox = 'window.plugin = {};window.plugin.missions = true;'; + +function getPlayerData() { + if (window.wrappedJSObject) { + window.PLAYER = window.wrappedJSObject.PLAYER; + } else { + + // Chrome does not provide access to WINDOW. + // Old IITC code is used to retrieve user data. + let scr = document.getElementsByTagName('script'); + let d; + for (let x in scr) { + let s = scr[x]; + if (s.src) continue; + if (s.type !== 'text/javascript') continue; + d = s.innerHTML.split('\n'); + break; + } + + if (!d) { + // page doesn’t have a script tag with player information. + if (document.getElementById('header_email')) { + // however, we are logged in. + // it used to be regularly common to get temporary 'account not enabled' messages from the intel site. + // however, this is no longer common. more common is users getting account suspended/banned - and this + // currently shows the 'not enabled' message. so it's safer to not repeatedly reload in this case + // setTimeout('location.reload();', 3*1000); + throw("Page doesn't have player data, but you are logged in."); + } + // FIXME: handle nia takedown in progress + throw("Couldn't retrieve player data. Are you logged in?"); + } + + for (let i = 0; i < d.length; i++) { + if (!d[i].match('var PLAYER = ')) continue; + sandbox += d[i]+'window.PLAYER = PLAYER;'; + break; + } + + } +} + +document.addEventListener("DOMContentLoaded", function() { + window.onload = function() {}; + document.body.onload = function() {}; + getPlayerData(); +}); + +document.addEventListener('IITCButtonInitJS', function (e) { + let code = e.detail; + + let GM_info_raw = code.substring(0, code.indexOf(";")); + let GM_info = new Function("GM_info", GM_info_raw+';return GM_info')(); + let id = GM_info.script.name; + + if (loaded_plugins.includes(id)) { + console.info('Plugin %s is already loaded. Skip', id); + } else { + loaded_plugins.push(id); + console.info('Plugin %s loaded', id); + new Function(sandbox+code)(); + } + +}); \ No newline at end of file diff --git a/scripts/pre.js b/scripts/pre.js deleted file mode 100644 index 0cdb85c..0000000 --- a/scripts/pre.js +++ /dev/null @@ -1,43 +0,0 @@ -// Fix for ingressmosaik plugin. -// This plugin uses Tampermonkey-specific feature to access site’s context -// instead of in the Greasemonkey/Extension/etc. context. -window.plugin = {}; -window.plugin.missions = true; - -// A simple solution for Firefox -if (window.wrappedJSObject) { - window.PLAYER = window.wrappedJSObject.PLAYER; -} else { - - // Chrome does not provide access to WINDOW. - // Old IITC code is used to retrieve user data. - var scr = document.getElementsByTagName('script'); - for (var x in scr) { - var s = scr[x]; - if (s.src) continue; - if (s.type !== 'text/javascript') continue; - var d = s.innerHTML.split('\n'); - break; - } - - if (!d) { - // page doesn’t have a script tag with player information. - if (document.getElementById('header_email')) { - // however, we are logged in. - // it used to be regularly common to get temporary 'account not enabled' messages from the intel site. - // however, this is no longer common. more common is users getting account suspended/banned - and this - // currently shows the 'not enabled' message. so it's safer to not repeatedly reload in this case - // setTimeout('location.reload();', 3*1000); - throw("Page doesn't have player data, but you are logged in."); - } - // FIXME: handle nia takedown in progress - throw("Couldn't retrieve player data. Are you logged in?"); - } - - for (var i = 0; i < d.length; i++) { - if (!d[i].match('var PLAYER = ')) continue; - eval(d[i]); - break; - } - -} \ No newline at end of file diff --git a/scripts/updater.js b/scripts/updater.js index 69dfbe3..58ed3bd 100644 --- a/scripts/updater.js +++ b/scripts/updater.js @@ -294,7 +294,7 @@ function managePlugin(id, category, action) { plugins_local[id]['status'] = 'on'; } - loadJS(activeIITCTab, "document_end", id, preparationUserScript(plugins[category]['plugins'][id], id)); + injectUserScript(preparationUserScript(plugins[category]['plugins'][id], id)); await save({ 'plugins': plugins, @@ -316,7 +316,7 @@ function managePlugin(id, category, action) { plugins_local[id]['status'] = 'on'; plugins_local[id]['code'] = response; - loadJS(activeIITCTab, "document_end", id, preparationUserScript(plugins_local[id], id)); + injectUserScript(preparationUserScript(plugins_local[id], id)); await save({ 'plugins': plugins,