From c5c08783d2b8454336b6cff2134c8636e889e1c3 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 6 May 2018 11:12:52 +0900 Subject: [PATCH 1/7] OperationComponent --- src/background/actions/operation.js | 92 ------------------- src/background/components/background.js | 5 -- src/background/components/operation.js | 113 ++++++++++++++++++++++++ src/background/index.js | 3 + 4 files changed, 116 insertions(+), 97 deletions(-) delete mode 100644 src/background/actions/operation.js create mode 100644 src/background/components/operation.js diff --git a/src/background/actions/operation.js b/src/background/actions/operation.js deleted file mode 100644 index 10c366f..0000000 --- a/src/background/actions/operation.js +++ /dev/null @@ -1,92 +0,0 @@ -import operations from 'shared/operations'; -import messages from 'shared/messages'; -import * as tabs from 'background/tabs'; -import * as zooms from 'background/zooms'; - -const sendConsoleShowCommand = (tab, command) => { - return browser.tabs.sendMessage(tab.id, { - type: messages.CONSOLE_SHOW_COMMAND, - command, - }); -}; - -// This switch statement is only gonna get longer as more -// features are added, so disable complexity check -/* eslint-disable complexity */ -const exec = (operation, tab) => { - switch (operation.type) { - case operations.TAB_CLOSE: - return tabs.closeTab(tab.id); - case operations.TAB_CLOSE_FORCE: - return tabs.closeTabForce(tab.id); - case operations.TAB_REOPEN: - return tabs.reopenTab(); - case operations.TAB_PREV: - return tabs.selectPrevTab(tab.index, operation.count); - case operations.TAB_NEXT: - return tabs.selectNextTab(tab.index, operation.count); - case operations.TAB_FIRST: - return tabs.selectFirstTab(); - case operations.TAB_LAST: - return tabs.selectLastTab(); - case operations.TAB_PREV_SEL: - return tabs.selectPrevSelTab(); - case operations.TAB_RELOAD: - return tabs.reload(tab, operation.cache); - case operations.TAB_PIN: - return tabs.updateTabPinned(tab, true); - case operations.TAB_UNPIN: - return tabs.updateTabPinned(tab, false); - case operations.TAB_TOGGLE_PINNED: - return tabs.toggleTabPinned(tab); - case operations.TAB_DUPLICATE: - return tabs.duplicate(tab.id); - case operations.ZOOM_IN: - return zooms.zoomIn(); - case operations.ZOOM_OUT: - return zooms.zoomOut(); - case operations.ZOOM_NEUTRAL: - return zooms.neutral(); - case operations.COMMAND_SHOW: - return sendConsoleShowCommand(tab, ''); - case operations.COMMAND_SHOW_OPEN: - if (operation.alter) { - // alter url - return sendConsoleShowCommand(tab, 'open ' + tab.url); - } - return sendConsoleShowCommand(tab, 'open '); - case operations.COMMAND_SHOW_TABOPEN: - if (operation.alter) { - // alter url - return sendConsoleShowCommand(tab, 'tabopen ' + tab.url); - } - return sendConsoleShowCommand(tab, 'tabopen '); - case operations.COMMAND_SHOW_WINOPEN: - if (operation.alter) { - // alter url - return sendConsoleShowCommand(tab, 'winopen ' + tab.url); - } - return sendConsoleShowCommand(tab, 'winopen '); - case operations.COMMAND_SHOW_BUFFER: - return sendConsoleShowCommand(tab, 'buffer '); - case operations.FIND_START: - return browser.tabs.sendMessage(tab.id, { - type: messages.CONSOLE_SHOW_FIND - }); - case operations.CANCEL: - return browser.tabs.sendMessage(tab.id, { - type: messages.CONSOLE_HIDE, - }); - case operations.PAGE_SOURCE: - return browser.tabs.create({ - url: 'view-source:' + tab.url, - index: tab.index + 1, - openerTabId: tab.id, - }); - default: - return Promise.resolve(); - } -}; -/* eslint-enable complexity */ - -export { exec }; diff --git a/src/background/components/background.js b/src/background/components/background.js index fae3fbb..81d815b 100644 --- a/src/background/components/background.js +++ b/src/background/components/background.js @@ -1,5 +1,4 @@ import messages from 'shared/messages'; -import * as operationActions from 'background/actions/operation'; import * as commandActions from 'background/actions/command'; import * as settingActions from 'background/actions/setting'; import * as findActions from 'background/actions/find'; @@ -27,10 +26,6 @@ export default class BackgroundComponent { let find = this.store.getState().find; switch (message.type) { - case messages.BACKGROUND_OPERATION: - return this.store.dispatch( - operationActions.exec(message.operation, sender.tab), - sender); case messages.OPEN_URL: if (message.newTab) { let action = tabActions.openNewTab( diff --git a/src/background/components/operation.js b/src/background/components/operation.js new file mode 100644 index 0000000..e1094c5 --- /dev/null +++ b/src/background/components/operation.js @@ -0,0 +1,113 @@ +import messages from 'shared/messages'; +import operations from 'shared/operations'; +import * as tabs from 'background/tabs'; +import * as zooms from 'background/zooms'; + +export default class BackgroundComponent { + constructor(store) { + this.store = store; + + browser.runtime.onMessage.addListener((message, sender) => { + try { + return this.onMessage(message, sender); + } catch (e) { + return browser.tabs.sendMessage(sender.tab.id, { + type: messages.CONSOLE_SHOW_ERROR, + text: e.message, + }); + } + }); + } + + onMessage(message, sender) { + switch (message.type) { + case messages.BACKGROUND_OPERATION: + return this.store.dispatch( + this.exec(message.operation, sender.tab), + sender); + } + } + + // eslint-disable-next-line complexity + exec(operation, tab) { + switch (operation.type) { + case operations.TAB_CLOSE: + return tabs.closeTab(tab.id); + case operations.TAB_CLOSE_FORCE: + return tabs.closeTabForce(tab.id); + case operations.TAB_REOPEN: + return tabs.reopenTab(); + case operations.TAB_PREV: + return tabs.selectPrevTab(tab.index, operation.count); + case operations.TAB_NEXT: + return tabs.selectNextTab(tab.index, operation.count); + case operations.TAB_FIRST: + return tabs.selectFirstTab(); + case operations.TAB_LAST: + return tabs.selectLastTab(); + case operations.TAB_PREV_SEL: + return tabs.selectPrevSelTab(); + case operations.TAB_RELOAD: + return tabs.reload(tab, operation.cache); + case operations.TAB_PIN: + return tabs.updateTabPinned(tab, true); + case operations.TAB_UNPIN: + return tabs.updateTabPinned(tab, false); + case operations.TAB_TOGGLE_PINNED: + return tabs.toggleTabPinned(tab); + case operations.TAB_DUPLICATE: + return tabs.duplicate(tab.id); + case operations.ZOOM_IN: + return zooms.zoomIn(); + case operations.ZOOM_OUT: + return zooms.zoomOut(); + case operations.ZOOM_NEUTRAL: + return zooms.neutral(); + case operations.COMMAND_SHOW: + return this.sendConsoleShowCommand(tab, ''); + case operations.COMMAND_SHOW_OPEN: + if (operation.alter) { + // alter url + return this.sendConsoleShowCommand(tab, 'open ' + tab.url); + } + return this.sendConsoleShowCommand(tab, 'open '); + case operations.COMMAND_SHOW_TABOPEN: + if (operation.alter) { + // alter url + return this.sendConsoleShowCommand(tab, 'tabopen ' + tab.url); + } + return this.sendConsoleShowCommand(tab, 'tabopen '); + case operations.COMMAND_SHOW_WINOPEN: + if (operation.alter) { + // alter url + return this.sendConsoleShowCommand(tab, 'winopen ' + tab.url); + } + return this.sendConsoleShowCommand(tab, 'winopen '); + case operations.COMMAND_SHOW_BUFFER: + return this.sendConsoleShowCommand(tab, 'buffer '); + case operations.FIND_START: + return browser.tabs.sendMessage(tab.id, { + type: messages.CONSOLE_SHOW_FIND + }); + case operations.CANCEL: + return browser.tabs.sendMessage(tab.id, { + type: messages.CONSOLE_HIDE, + }); + case operations.PAGE_SOURCE: + return browser.tabs.create({ + url: 'view-source:' + tab.url, + index: tab.index + 1, + openerTabId: tab.id, + }); + default: + return Promise.resolve(); + } + } + + sendConsoleShowCommand(tab, command) { + return browser.tabs.sendMessage(tab.id, { + type: messages.CONSOLE_SHOW_COMMAND, + command, + }); + } +} diff --git a/src/background/index.js b/src/background/index.js index ff27796..4f6b23f 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -1,6 +1,7 @@ import * as settingActions from 'background/actions/setting'; import messages from 'shared/messages'; import BackgroundComponent from 'background/components/background'; +import OperationComponent from 'background/components/operation'; import reducers from 'background/reducers'; import { createStore } from 'shared/store'; import * as versions from 'shared/versions'; @@ -16,6 +17,8 @@ const store = createStore(reducers, (e, sender) => { }); // eslint-disable-next-line no-unused-vars const backgroundComponent = new BackgroundComponent(store); +// eslint-disable-next-line no-unused-vars +const operationComponent = new OperationComponent(store); store.dispatch(settingActions.load()); From 98bc2326eeeb5d915706dee9aadc2ac3e9af1789 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 6 May 2018 11:45:07 +0900 Subject: [PATCH 2/7] Refactor background directories --- src/background/actions/command.js | 2 +- src/background/components/background.js | 4 ++-- src/background/components/operation.js | 4 ++-- src/background/{ => shared/completions}/histories.js | 0 .../shared/completions/index.js} | 6 +++--- src/background/shared/completions/tabs.js | 10 ++++++++++ src/background/{ => shared}/tabs.js | 11 +---------- src/background/{ => shared}/zooms.js | 0 src/shared/commands/index.js | 3 --- 9 files changed, 19 insertions(+), 21 deletions(-) rename src/background/{ => shared/completions}/histories.js (100%) rename src/{shared/commands/complete.js => background/shared/completions/index.js} (94%) create mode 100644 src/background/shared/completions/tabs.js rename src/background/{ => shared}/tabs.js (91%) rename src/background/{ => shared}/zooms.js (100%) delete mode 100644 src/shared/commands/index.js diff --git a/src/background/actions/command.js b/src/background/actions/command.js index 4c52bca..2f7305a 100644 --- a/src/background/actions/command.js +++ b/src/background/actions/command.js @@ -1,5 +1,5 @@ import actions from '../actions'; -import * as tabs from 'background/tabs'; +import * as tabs from '../shared/tabs'; import * as parsers from 'shared/commands/parsers'; import * as properties from 'shared/settings/properties'; diff --git a/src/background/components/background.js b/src/background/components/background.js index 81d815b..e13424b 100644 --- a/src/background/components/background.js +++ b/src/background/components/background.js @@ -3,7 +3,7 @@ import * as commandActions from 'background/actions/command'; import * as settingActions from 'background/actions/setting'; import * as findActions from 'background/actions/find'; import * as tabActions from 'background/actions/tab'; -import * as commands from 'shared/commands'; +import * as completions from '../shared/completions'; export default class BackgroundComponent { constructor(store) { @@ -44,7 +44,7 @@ export default class BackgroundComponent { case messages.SETTINGS_QUERY: return Promise.resolve(this.store.getState().setting.value); case messages.CONSOLE_QUERY_COMPLETIONS: - return commands.complete(message.text, settings.value); + return completions.complete(message.text, settings.value); case messages.SETTINGS_RELOAD: this.store.dispatch(settingActions.load()); return this.broadcastSettingsChanged(); diff --git a/src/background/components/operation.js b/src/background/components/operation.js index e1094c5..b9581c9 100644 --- a/src/background/components/operation.js +++ b/src/background/components/operation.js @@ -1,7 +1,7 @@ import messages from 'shared/messages'; import operations from 'shared/operations'; -import * as tabs from 'background/tabs'; -import * as zooms from 'background/zooms'; +import * as tabs from '../shared//tabs'; +import * as zooms from '../shared/zooms'; export default class BackgroundComponent { constructor(store) { diff --git a/src/background/histories.js b/src/background/shared/completions/histories.js similarity index 100% rename from src/background/histories.js rename to src/background/shared/completions/histories.js diff --git a/src/shared/commands/complete.js b/src/background/shared/completions/index.js similarity index 94% rename from src/shared/commands/complete.js rename to src/background/shared/completions/index.js index 0bdbab8..73b7b27 100644 --- a/src/shared/commands/complete.js +++ b/src/background/shared/completions/index.js @@ -1,5 +1,5 @@ -import * as tabs from 'background/tabs'; -import * as histories from 'background/histories'; +import * as tabs from './tabs'; +import * as histories from './histories'; const getOpenCompletions = (command, keywords, searchConfig) => { return histories.getCompletions(keywords).then((pages) => { @@ -81,4 +81,4 @@ const complete = (line, settings) => { return getCompletions(line, settings); }; -export default complete; +export { complete }; diff --git a/src/background/shared/completions/tabs.js b/src/background/shared/completions/tabs.js new file mode 100644 index 0000000..5edddca --- /dev/null +++ b/src/background/shared/completions/tabs.js @@ -0,0 +1,10 @@ +const getCompletions = (keyword) => { + return browser.tabs.query({ currentWindow: true }).then((tabs) => { + let matched = tabs.filter((t) => { + return t.url.includes(keyword) || t.title && t.title.includes(keyword); + }); + return matched; + }); +}; + +export { getCompletions }; diff --git a/src/background/tabs.js b/src/background/shared/tabs.js similarity index 91% rename from src/background/tabs.js rename to src/background/shared/tabs.js index e939870..277afb2 100644 --- a/src/background/tabs.js +++ b/src/background/shared/tabs.js @@ -66,15 +66,6 @@ const selectByKeyword = (current, keyword) => { }); }; -const getCompletions = (keyword) => { - return browser.tabs.query({ currentWindow: true }).then((tabs) => { - let matched = tabs.filter((t) => { - return t.url.includes(keyword) || t.title && t.title.includes(keyword); - }); - return matched; - }); -}; - const selectPrevTab = (current, count) => { return browser.tabs.query({ currentWindow: true }).then((tabs) => { if (tabs.length < 2) { @@ -139,7 +130,7 @@ const duplicate = (id) => { export { closeTab, closeTabForce, reopenTab, selectAt, selectByKeyword, - getCompletions, selectPrevTab, selectNextTab, selectFirstTab, + selectPrevTab, selectNextTab, selectFirstTab, selectLastTab, selectPrevSelTab, reload, updateTabPinned, toggleTabPinned, duplicate }; diff --git a/src/background/zooms.js b/src/background/shared/zooms.js similarity index 100% rename from src/background/zooms.js rename to src/background/shared/zooms.js diff --git a/src/shared/commands/index.js b/src/shared/commands/index.js deleted file mode 100644 index 78cb4df..0000000 --- a/src/shared/commands/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import complete from './complete'; - -export { complete }; From 2c366ac3b1d7114869567845c955238e96056565 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 6 May 2018 16:11:40 +0900 Subject: [PATCH 3/7] Previous selected tab as redux --- src/background/actions/index.js | 3 +++ src/background/actions/tab.js | 11 ++++++++++- src/background/components/operation.js | 7 ++++++- src/background/components/tab.js | 17 +++++++++++++++++ src/background/index.js | 3 +++ src/background/reducers/index.js | 3 +++ src/background/reducers/tab.js | 19 +++++++++++++++++++ src/background/shared/tabs.js | 16 +++------------- 8 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 src/background/components/tab.js create mode 100644 src/background/reducers/tab.js diff --git a/src/background/actions/index.js b/src/background/actions/index.js index 2bdaaf2..3833389 100644 --- a/src/background/actions/index.js +++ b/src/background/actions/index.js @@ -5,4 +5,7 @@ export default { // Find FIND_SET_KEYWORD: 'find.set.keyword', + + // Tab + TAB_SELECTED: 'tab.selected', }; diff --git a/src/background/actions/tab.js b/src/background/actions/tab.js index 3c642fd..0d439fd 100644 --- a/src/background/actions/tab.js +++ b/src/background/actions/tab.js @@ -1,3 +1,5 @@ +import actions from './index'; + const openNewTab = (url, openerTabId, background = false, adjacent = false) => { if (adjacent) { return browser.tabs.query({ @@ -18,4 +20,11 @@ const openToTab = (url, tab) => { return browser.tabs.update(tab.id, { url: url }); }; -export { openNewTab, openToTab }; +const selected = (tabId) => { + return { + type: actions.TAB_SELECTED, + tabId, + }; +}; + +export { openNewTab, openToTab, selected }; diff --git a/src/background/components/operation.js b/src/background/components/operation.js index b9581c9..9a0b4e1 100644 --- a/src/background/components/operation.js +++ b/src/background/components/operation.js @@ -30,6 +30,8 @@ export default class BackgroundComponent { // eslint-disable-next-line complexity exec(operation, tab) { + let tabState = this.store.getState().tab; + switch (operation.type) { case operations.TAB_CLOSE: return tabs.closeTab(tab.id); @@ -46,7 +48,10 @@ export default class BackgroundComponent { case operations.TAB_LAST: return tabs.selectLastTab(); case operations.TAB_PREV_SEL: - return tabs.selectPrevSelTab(); + if (tabState.previousSelected > 0) { + return tabs.selectTab(tabState.previousSelected); + } + break; case operations.TAB_RELOAD: return tabs.reload(tab, operation.cache); case operations.TAB_PIN: diff --git a/src/background/components/tab.js b/src/background/components/tab.js new file mode 100644 index 0000000..b273546 --- /dev/null +++ b/src/background/components/tab.js @@ -0,0 +1,17 @@ +import * as tabActions from '../actions/tab'; + +export default class TabComponent { + constructor(store) { + this.store = store; + + browser.tabs.onActivated.addListener((info) => { + return browser.tabs.query({ currentWindow: true }).then(() => { + return this.onTabActivated(info); + }); + }); + } + + onTabActivated(info) { + return this.store.dispatch(tabActions.selected(info.tabId)); + } +} diff --git a/src/background/index.js b/src/background/index.js index 4f6b23f..be042ce 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -2,6 +2,7 @@ import * as settingActions from 'background/actions/setting'; import messages from 'shared/messages'; import BackgroundComponent from 'background/components/background'; import OperationComponent from 'background/components/operation'; +import TabComponent from 'background/components/tab'; import reducers from 'background/reducers'; import { createStore } from 'shared/store'; import * as versions from 'shared/versions'; @@ -19,6 +20,8 @@ const store = createStore(reducers, (e, sender) => { const backgroundComponent = new BackgroundComponent(store); // eslint-disable-next-line no-unused-vars const operationComponent = new OperationComponent(store); +// eslint-disable-next-line no-unused-vars +const tabComponent = new TabComponent(store); store.dispatch(settingActions.load()); diff --git a/src/background/reducers/index.js b/src/background/reducers/index.js index 63ff0f8..5729f0a 100644 --- a/src/background/reducers/index.js +++ b/src/background/reducers/index.js @@ -1,15 +1,18 @@ import settingReducer from './setting'; import findReducer from './find'; +import tabReducer from './tab'; // Make setting reducer instead of re-use const defaultState = { setting: settingReducer(undefined, {}), find: findReducer(undefined, {}), + tab: tabReducer(undefined, {}), }; export default function reducer(state = defaultState, action = {}) { return Object.assign({}, state, { setting: settingReducer(state.setting, action), find: findReducer(state.find, action), + tab: tabReducer(state.tab, action), }); } diff --git a/src/background/reducers/tab.js b/src/background/reducers/tab.js new file mode 100644 index 0000000..e0cdf32 --- /dev/null +++ b/src/background/reducers/tab.js @@ -0,0 +1,19 @@ +import actions from 'background/actions'; + +const defaultState = { + previousSelected: -1, + currentSelected: -1, +}; + +export default function reducer(state = defaultState, action = {}) { + switch (action.type) { + case actions.TAB_SELECTED: + return { + previousSelected: state.currentSelected, + currentSelected: action.tabId, + }; + default: + return state; + } +} + diff --git a/src/background/shared/tabs.js b/src/background/shared/tabs.js index 277afb2..f1dcc73 100644 --- a/src/background/shared/tabs.js +++ b/src/background/shared/tabs.js @@ -1,13 +1,3 @@ -let prevSelTab = 1; -let currSelTab = 1; - -browser.tabs.onActivated.addListener((activeInfo) => { - return browser.tabs.query({ currentWindow: true }).then(() => { - prevSelTab = currSelTab; - currSelTab = activeInfo.tabId; - }); -}); - const closeTab = (id) => { return browser.tabs.get(id).then((tab) => { if (!tab.pinned) { @@ -102,8 +92,8 @@ const selectLastTab = () => { }); }; -const selectPrevSelTab = () => { - return browser.tabs.update(prevSelTab, { active: true }); +const selectTab = (id) => { + return browser.tabs.update(id, { active: true }); }; const reload = (current, cache) => { @@ -131,6 +121,6 @@ const duplicate = (id) => { export { closeTab, closeTabForce, reopenTab, selectAt, selectByKeyword, selectPrevTab, selectNextTab, selectFirstTab, - selectLastTab, selectPrevSelTab, reload, updateTabPinned, + selectLastTab, selectTab, reload, updateTabPinned, toggleTabPinned, duplicate }; From 129aae38df1a17a5850898d5832bb8112ead3cbb Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 6 May 2018 22:30:04 +0900 Subject: [PATCH 4/7] Indicator shows the add-on enabled --- manifest.json | 6 ++++ resources/disabled_32x32.png | Bin 0 -> 1426 bytes resources/enabled_32x32.png | Bin 0 -> 1504 bytes src/background/components/indicator.js | 38 ++++++++++++++++++++ src/background/index.js | 8 +++-- src/background/shared/indicators.js | 13 +++++++ src/content/components/common/index.js | 14 ++++++++ src/content/components/top-content/index.js | 7 ++++ src/shared/messages.js | 3 ++ 9 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 resources/disabled_32x32.png create mode 100644 resources/enabled_32x32.png create mode 100644 src/background/components/indicator.js create mode 100644 src/background/shared/indicators.js diff --git a/manifest.json b/manifest.json index 4c43b64..39d14f4 100644 --- a/manifest.json +++ b/manifest.json @@ -40,5 +40,11 @@ ], "options_ui": { "page": "build/settings.html" + }, + "browser_action": { + "default_icon": { + "32": "resources/enabled_32x32.png" + }, + "default_title": "Vim Vixen" } } diff --git a/resources/disabled_32x32.png b/resources/disabled_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..d3b88db809fc3fde05057fe81245afabff11cd1b GIT binary patch literal 1426 zcmV;D1#S9?P)_2000McNliru;spf_Ckex+_W1w+1s_R7 zK~z}7wUPIuinwwy*$=|`j{X)H$|!1PiCRis+3siIzyN<%qN zaX?6D4;+vX2N1b&qoPs}k$M0jfl4W~Avm^5P%4^B;*i93Y|ByYwX@0E!vWj1-Pn!W zG_h#RWDFArAUUOexUuYinyS34*W~2n1f;OUFK+&oDMNc5`!c^V4`d?qrNP$~pr8P)cIp%gbh~)%ug)?|*ZTqUK#L*SxOluRM70fRv`UY5*8xaR3Ye^7%YgR#vFpZol@d z5W!%O7X;xx$8krZ(P*`5y#`=rW<~>$C{LzRDP%GkBFpkOfk0sNY17X0{9k6Xxo2r< z35>C7^}jU$CHbe?A{vc?Qflbz?40uZ{hn3<91h3rj*gBa@pv4ns@CWjWA~p3plKSC z$s~+MBemIVw*rBHtA*5mZL`@%ip3&gvDi)~j{`8qBK1~lYij@iK@bE{6z`rrd$#>a z&d;4Y_mLz?7XTocOk!(mtKMWW6bhxw1FlLjQ*Wth8Xi7;2(#G?Q50>uu7?2}86O`X z0Wd@e=_$c40f@xoahD`X3L*a=_CzA_7$9Tp&+2gnAeYPi-QM1=0;q{Hkx0O7HUj`U zIy#=ebm>xt5F%FFlpWgbc1B8rd_MnJ?Mt?QRF5kqn4h07>{NzyI*mf1@MwX-AT~;W z**O4YGMPqZGdlt_DuX0Rpp>@!8A_6b?(XjT>1|5s-G%^!klWQ`x7!W3+x=8ch!BGA z?(UlPjIr?a^mM)<0AuWD02%-|ole;8_GfOzcDo%;r?Wi#p5V6j-5?kWfZ1VI4L^EiC?FuJ z78e%_xm=DCLe2xYPD+RG+KCeV!Z literal 0 HcmV?d00001 diff --git a/resources/enabled_32x32.png b/resources/enabled_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..eaf286262f6b2121c694eb22d81e4ad5563c1ff3 GIT binary patch literal 1504 zcmV<61t0o}P))y)j-W5wk@D7Z8mmA~HnBHV8q7D1*U(u`jlD zr5|tKs>=bX3a92J1q$epv!aigea<&!z%T`*V%i>}sF4r{a-Wb*@91zi-X4NI0~+`})OV z9a)r2jR2U01`rL0xYpj9o0mWD$D;QG&&-B*XU4V#-YZ0DU8yNL*L6WPW|dsKbS5PuZ>0l#Oa$mo2K&1^7#{2u4wv`q zqCJ(H|Cf6m%AJCOv)OqCzN`PXBBh>^6j##$M%0$t|JtRqsH#D6IE%k?eXuexQ~&vn zwT-rXcS+BUON4@b=}DanQvyW7LHfF{U@*>6?RL-cqCEl6bj`hctG>!}%&U^R&dtuh z#;J&n10ZS1EbF>@0gz;wv&}i#_A`aMms_VYFW$TAU3;N#J3w#uWnz(VW=T7r(VuJ> zQWC#sRz|`>h6ZktV=KgxW4CKsw7CmP$`3qSr7L>50zLp8E-Sjy($&@Gam@AB2{H1q z_ugzDODOpxwK)pV9XrQd<1mmm%f7BFF&30G|>Bjyno{6c(4 zgaGA>FTAd(>g-QH2?47v#*D9K#74CI%jc}BL2CyJ?iWBpy-|baJ73!ngp?IfjIoy| zHJ4yHt7Ez@CoC~_N-Ssf(IawvIkMvF3wM1179QP@C8XFnSuaDM#M-K3ZP6#Jv9{<~ zTXhWmlM_fO-duQeLlz|Ng4_Yy6B1mLb<*sDV6}>7pSUKtTEWl@=v&vrlGd@ZEaW;LT&{Pi^RuwaFcy?$0q0M9RkrIgg7asypmXO!{)c|i* zR#v_@opGmq=*7JN literal 0 HcmV?d00001 diff --git a/src/background/components/indicator.js b/src/background/components/indicator.js new file mode 100644 index 0000000..ccdcc74 --- /dev/null +++ b/src/background/components/indicator.js @@ -0,0 +1,38 @@ +import * as indicators from '../shared/indicators'; +import messages from 'shared/messages'; + +export default class IndicatorComponent { + constructor(store) { + this.store = store; + + messages.onMessage(this.onMessage.bind(this)); + + browser.tabs.onActivated.addListener((info) => { + return browser.tabs.query({ currentWindow: true }).then(() => { + return this.onTabActivated(info); + }); + }); + } + + onTabActivated(info) { + return browser.tabs.sendMessage(info.tabId, { + type: messages.ADDON_ENABLED_QUERY, + }).then((resp) => { + return this.updateIndicator(resp.enabled); + }); + } + + onMessage(message) { + switch (message.type) { + case messages.ADDON_ENABLED_RESPONSE: + return this.updateIndicator(message.enabled); + } + } + + updateIndicator(enabled) { + if (enabled) { + return indicators.enable(); + } + return indicators.disable(); + } +} diff --git a/src/background/index.js b/src/background/index.js index be042ce..3f1013c 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -3,6 +3,7 @@ import messages from 'shared/messages'; import BackgroundComponent from 'background/components/background'; import OperationComponent from 'background/components/operation'; import TabComponent from 'background/components/tab'; +import IndicatorComponent from 'background/components/indicator'; import reducers from 'background/reducers'; import { createStore } from 'shared/store'; import * as versions from 'shared/versions'; @@ -16,12 +17,13 @@ const store = createStore(reducers, (e, sender) => { }); } }); -// eslint-disable-next-line no-unused-vars + +/* eslint-disable no-unused-vars */ const backgroundComponent = new BackgroundComponent(store); -// eslint-disable-next-line no-unused-vars const operationComponent = new OperationComponent(store); -// eslint-disable-next-line no-unused-vars const tabComponent = new TabComponent(store); +const indicatorComponent = new IndicatorComponent(store); +/* eslint-enable no-unused-vars */ store.dispatch(settingActions.load()); diff --git a/src/background/shared/indicators.js b/src/background/shared/indicators.js new file mode 100644 index 0000000..74002c4 --- /dev/null +++ b/src/background/shared/indicators.js @@ -0,0 +1,13 @@ +const enable = () => { + return browser.browserAction.setIcon({ + path: 'resources/enabled_32x32.png', + }); +}; + +const disable = () => { + return browser.browserAction.setIcon({ + path: 'resources/disabled_32x32.png', + }); +}; + +export { enable, disable }; diff --git a/src/content/components/common/index.js b/src/content/components/common/index.js index 565632c..c5d1df7 100644 --- a/src/content/components/common/index.js +++ b/src/content/components/common/index.js @@ -14,10 +14,12 @@ export default class Common { input.onKey(key => keymapper.key(key)); this.store = store; + this.prevEnabled = this.store.getState().addon.enabled; this.reloadSettings(); messages.onMessage(this.onMessage.bind(this)); + store.subscribe(() => this.update()); } onMessage(message) { @@ -27,6 +29,18 @@ export default class Common { } } + update() { + let enabled = this.store.getState().addon.enabled; + if (enabled !== this.prevEnabled) { + this.prevEnabled = enabled; + + browser.runtime.sendMessage({ + type: messages.ADDON_ENABLED_RESPONSE, + enabled, + }); + } + } + reloadSettings() { browser.runtime.sendMessage({ type: messages.SETTINGS_QUERY, diff --git a/src/content/components/top-content/index.js b/src/content/components/top-content/index.js index cf21ec4..cb9e160 100644 --- a/src/content/components/top-content/index.js +++ b/src/content/components/top-content/index.js @@ -48,11 +48,18 @@ export default class TopContent { } onMessage(message) { + let addonState = this.store.getState().addon; + switch (message.type) { case messages.CONSOLE_UNFOCUS: this.win.focus(); consoleFrames.blur(window.document); return Promise.resolve(); + case messages.ADDON_ENABLED_QUERY: + return Promise.resolve({ + type: messages.ADDON_ENABLED_RESPONSE, + enabled: addonState.enabled, + }); } } } diff --git a/src/shared/messages.js b/src/shared/messages.js index a404658..2a286bf 100644 --- a/src/shared/messages.js +++ b/src/shared/messages.js @@ -48,6 +48,9 @@ export default { FIND_GET_KEYWORD: 'find.get.keyword', FIND_SET_KEYWORD: 'find.set.keyword', + ADDON_ENABLED_QUERY: 'addon.enabled.query', + ADDON_ENABLED_RESPONSE: 'addon.enabled.response', + OPEN_URL: 'open.url', SETTINGS_RELOAD: 'settings.reload', From 6d057a974bb42406259b6f0b0a8c0b1e22335073 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 6 May 2018 22:47:58 +0900 Subject: [PATCH 5/7] Toggle add-on enabled by clicking indicator --- src/background/components/indicator.js | 7 +++++++ src/content/components/common/index.js | 5 ++++- src/shared/messages.js | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/background/components/indicator.js b/src/background/components/indicator.js index ccdcc74..cceb119 100644 --- a/src/background/components/indicator.js +++ b/src/background/components/indicator.js @@ -7,6 +7,7 @@ export default class IndicatorComponent { messages.onMessage(this.onMessage.bind(this)); + browser.browserAction.onClicked.addListener(this.onClicked); browser.tabs.onActivated.addListener((info) => { return browser.tabs.query({ currentWindow: true }).then(() => { return this.onTabActivated(info); @@ -22,6 +23,12 @@ export default class IndicatorComponent { }); } + onClicked(tab) { + browser.tabs.sendMessage(tab.id, { + type: messages.ADDON_TOGGLE_ENABLED, + }); + } + onMessage(message) { switch (message.type) { case messages.ADDON_ENABLED_RESPONSE: diff --git a/src/content/components/common/index.js b/src/content/components/common/index.js index c5d1df7..c76a7d9 100644 --- a/src/content/components/common/index.js +++ b/src/content/components/common/index.js @@ -3,6 +3,7 @@ import KeymapperComponent from './keymapper'; import FollowComponent from './follow'; import * as settingActions from 'content/actions/setting'; import messages from 'shared/messages'; +import * as addonActions from '../../actions/addon'; export default class Common { constructor(win, store) { @@ -25,7 +26,9 @@ export default class Common { onMessage(message) { switch (message.type) { case messages.SETTINGS_CHANGED: - this.reloadSettings(); + return this.reloadSettings(); + case messages.ADDON_TOGGLE_ENABLED: + return this.store.dispatch(addonActions.toggleEnabled()); } } diff --git a/src/shared/messages.js b/src/shared/messages.js index 2a286bf..1f9c816 100644 --- a/src/shared/messages.js +++ b/src/shared/messages.js @@ -50,6 +50,7 @@ export default { ADDON_ENABLED_QUERY: 'addon.enabled.query', ADDON_ENABLED_RESPONSE: 'addon.enabled.response', + ADDON_TOGGLE_ENABLED: 'addon.toggle.enabled', OPEN_URL: 'open.url', From 1f51f3260d90914fba89720f63813a3f41f5e5f1 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 6 May 2018 21:11:26 +0900 Subject: [PATCH 6/7] add tests --- test/background/actions/tab.test.js | 13 +++++++++++++ test/background/reducers/tab.test.js | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 test/background/actions/tab.test.js create mode 100644 test/background/reducers/tab.test.js diff --git a/test/background/actions/tab.test.js b/test/background/actions/tab.test.js new file mode 100644 index 0000000..ab57374 --- /dev/null +++ b/test/background/actions/tab.test.js @@ -0,0 +1,13 @@ +import actions from 'background/actions'; +import * as tabActions from 'background/actions/tab'; + +describe("tab actions", () => { + describe("selected", () => { + it('create TAB_SELECTED action', () => { + let action = tabActions.selected(123); + expect(action.type).to.equal(actions.TAB_SELECTED); + expect(action.tabId).to.equal(123); + }); + }); +}); + diff --git a/test/background/reducers/tab.test.js b/test/background/reducers/tab.test.js new file mode 100644 index 0000000..09fa8a7 --- /dev/null +++ b/test/background/reducers/tab.test.js @@ -0,0 +1,22 @@ +import actions from 'background/actions'; +import tabReducer from 'background/reducers/tab'; + +describe("tab reducer", () => { + it('return the initial state', () => { + let state = tabReducer(undefined, {}); + expect(state.previousSelected).to.equal(-1); + expect(state.currentSelected).to.equal(-1); + }); + + it('return next state for TAB_SELECTED', () => { + let state = undefined; + + state = tabReducer(state, { type: actions.TAB_SELECTED, tabId: 123 }); + expect(state.previousSelected).to.equal(-1); + expect(state.currentSelected).to.equal(123); + + state = tabReducer(state, { type: actions.TAB_SELECTED, tabId: 456 }); + expect(state.previousSelected).to.equal(123); + expect(state.currentSelected).to.equal(456); + }); +}); From cf30ef0cd503b3b9dee882202d64ba9db9922ee3 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 6 May 2018 21:35:11 +0900 Subject: [PATCH 7/7] update indicator on loaded --- src/content/components/common/index.js | 2 +- src/content/components/top-content/index.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/content/components/common/index.js b/src/content/components/common/index.js index c76a7d9..9b7b083 100644 --- a/src/content/components/common/index.js +++ b/src/content/components/common/index.js @@ -15,7 +15,7 @@ export default class Common { input.onKey(key => keymapper.key(key)); this.store = store; - this.prevEnabled = this.store.getState().addon.enabled; + this.prevEnabled = undefined; this.reloadSettings(); diff --git a/src/content/components/top-content/index.js b/src/content/components/top-content/index.js index cb9e160..a0d0480 100644 --- a/src/content/components/top-content/index.js +++ b/src/content/components/top-content/index.js @@ -44,6 +44,8 @@ export default class TopContent { .some(regex => regex.test(partial)); if (matched) { this.store.dispatch(addonActions.disable()); + } else { + this.store.dispatch(addonActions.enable()); } }