aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/content/actions/index.js7
-rw-r--r--src/content/actions/input.js9
-rw-r--r--src/content/actions/setting.js10
-rw-r--r--src/content/components/common/index.js4
-rw-r--r--src/content/components/common/keymapper.js15
-rw-r--r--src/content/components/top-content/index.js26
-rw-r--r--src/content/reducers/index.js3
-rw-r--r--src/content/reducers/input.js7
-rw-r--r--src/content/reducers/setting.js13
-rw-r--r--src/shared/utils/re.js6
-rw-r--r--src/shared/validators/setting.js2
-rw-r--r--test/content/actions/setting.test.js13
-rw-r--r--test/content/reducers/setting.test.js18
-rw-r--r--test/shared/util/re.test.js20
14 files changed, 126 insertions, 27 deletions
diff --git a/src/content/actions/index.js b/src/content/actions/index.js
index 085d510..83fa7cf 100644
--- a/src/content/actions/index.js
+++ b/src/content/actions/index.js
@@ -1,12 +1,15 @@
export default {
- // User input
+ // Enable/disable
ADDON_ENABLE: 'addon.enable',
ADDON_DISABLE: 'addon.disable',
ADDON_TOGGLE_ENABLED: 'addon.toggle.enabled',
+ // Settings
+ SETTING_SET: 'setting.set',
+
+ // User input
INPUT_KEY_PRESS: 'input.key,press',
INPUT_CLEAR_KEYS: 'input.clear.keys',
- INPUT_SET_KEYMAPS: 'input.set.keymaps',
// Completion
COMPLETION_SET_ITEMS: 'completion.set.items',
diff --git a/src/content/actions/input.js b/src/content/actions/input.js
index 31cfee3..465a486 100644
--- a/src/content/actions/input.js
+++ b/src/content/actions/input.js
@@ -13,11 +13,4 @@ const clearKeys = () => {
};
};
-const setKeymaps = (keymaps) => {
- return {
- type: actions.INPUT_SET_KEYMAPS,
- keymaps,
- };
-};
-
-export { keyPress, clearKeys, setKeymaps };
+export { keyPress, clearKeys };
diff --git a/src/content/actions/setting.js b/src/content/actions/setting.js
new file mode 100644
index 0000000..c874294
--- /dev/null
+++ b/src/content/actions/setting.js
@@ -0,0 +1,10 @@
+import actions from 'content/actions';
+
+const set = (value) => {
+ return {
+ type: actions.SETTING_SET,
+ value,
+ };
+};
+
+export { set };
diff --git a/src/content/components/common/index.js b/src/content/components/common/index.js
index db0ac43..5f5531b 100644
--- a/src/content/components/common/index.js
+++ b/src/content/components/common/index.js
@@ -1,7 +1,7 @@
import InputComponent from './input';
import KeymapperComponent from './keymapper';
import FollowComponent from './follow';
-import * as inputActions from 'content/actions/input';
+import * as settingActions from 'content/actions/setting';
import messages from 'shared/messages';
export default class Common {
@@ -40,7 +40,7 @@ export default class Common {
browser.runtime.sendMessage({
type: messages.SETTINGS_QUERY,
}).then((settings) => {
- this.store.dispatch(inputActions.setKeymaps(settings.keymaps));
+ this.store.dispatch(settingActions.set(settings));
});
}
}
diff --git a/src/content/components/common/keymapper.js b/src/content/components/common/keymapper.js
index 5070cd8..44d8212 100644
--- a/src/content/components/common/keymapper.js
+++ b/src/content/components/common/keymapper.js
@@ -11,19 +11,20 @@ export default class KeymapperComponent {
}
key(key) {
- let enabled = this.store.getState().addon.enabled;
-
this.store.dispatch(inputActions.keyPress(key));
- let input = this.store.getState().input;
- let matched = Object.keys(input.keymaps).filter((keyStr) => {
+ let state = this.store.getState();
+ let input = state.input;
+ let keymaps = state.setting.keymaps;
+
+ let matched = Object.keys(keymaps).filter((keyStr) => {
return keyStr.startsWith(input.keys);
});
- if (!enabled) {
+ if (!state.addon.enabled) {
// available keymaps are only ADDON_ENABLE and ADDON_TOGGLE_ENABLED if
// the addon disabled
matched = matched.filter((keys) => {
- let type = input.keymaps[keys].type;
+ let type = keymaps[keys].type;
return type === operations.ADDON_ENABLE ||
type === operations.ADDON_TOGGLE_ENABLED;
});
@@ -35,7 +36,7 @@ export default class KeymapperComponent {
matched.length === 1 && input.keys !== matched[0]) {
return true;
}
- let operation = input.keymaps[matched];
+ let operation = keymaps[matched];
this.store.dispatch(operationActions.exec(operation));
this.store.dispatch(inputActions.clearKeys());
return true;
diff --git a/src/content/components/top-content/index.js b/src/content/components/top-content/index.js
index c318901..c4a8461 100644
--- a/src/content/components/top-content/index.js
+++ b/src/content/components/top-content/index.js
@@ -1,7 +1,9 @@
import CommonComponent from '../common';
import FollowController from './follow-controller';
import * as consoleFrames from '../../console-frames';
+import * as addonActions from '../../actions/addon';
import messages from 'shared/messages';
+import * as re from 'shared/utils/re';
export default class TopContent {
@@ -11,17 +13,39 @@ export default class TopContent {
new CommonComponent(win, store),
new FollowController(win, store),
];
+ this.store = store;
+ this.prevBlacklist = undefined;
// TODO make component
- consoleFrames.initialize(window.document);
+ consoleFrames.initialize(this.win.document);
messages.onMessage(this.onMessage.bind(this));
}
update() {
+ let blacklist = this.store.getState().setting.blacklist;
+ if (JSON.stringify(this.prevBlacklist) !== JSON.stringify(blacklist)) {
+ this.disableIfBlack(blacklist);
+ this.prevBlacklist = blacklist;
+ }
+
this.children.forEach(c => c.update());
}
+ disableIfBlack(blacklist) {
+ let loc = this.win.location;
+ let partial = loc.host + loc.pathname;
+ let matched = blacklist
+ .map((item) => {
+ let pattern = item.includes('/') ? item : item + '/*';
+ return re.fromWildcard(pattern);
+ })
+ .some(regex => regex.test(partial));
+ if (matched) {
+ this.store.dispatch(addonActions.disable());
+ }
+ }
+
onMessage(message) {
switch (message.type) {
case messages.CONSOLE_HIDE_COMMAND:
diff --git a/src/content/reducers/index.js b/src/content/reducers/index.js
index 7cf318e..ae4a845 100644
--- a/src/content/reducers/index.js
+++ b/src/content/reducers/index.js
@@ -1,10 +1,12 @@
import addonReducer from './addon';
+import settingReducer from './setting';
import inputReducer from './input';
import followReducer from './follow';
// Make setting reducer instead of re-use
const defaultState = {
addon: addonReducer(undefined, {}),
+ setting: settingReducer(undefined, {}),
input: inputReducer(undefined, {}),
follow: followReducer(undefined, {}),
};
@@ -12,6 +14,7 @@ const defaultState = {
export default function reducer(state = defaultState, action = {}) {
return Object.assign({}, state, {
addon: addonReducer(state.addon, action),
+ setting: settingReducer(state.setting, action),
input: inputReducer(state.input, action),
follow: followReducer(state.follow, action),
});
diff --git a/src/content/reducers/input.js b/src/content/reducers/input.js
index c79b206..9457604 100644
--- a/src/content/reducers/input.js
+++ b/src/content/reducers/input.js
@@ -1,8 +1,7 @@
import actions from 'content/actions';
const defaultState = {
- keys: '',
- keymaps: {},
+ keys: ''
};
export default function reducer(state = defaultState, action = {}) {
@@ -15,10 +14,6 @@ export default function reducer(state = defaultState, action = {}) {
return Object.assign({}, state, {
keys: '',
});
- case actions.INPUT_SET_KEYMAPS:
- return Object.assign({}, state, {
- keymaps: action.keymaps,
- });
default:
return state;
}
diff --git a/src/content/reducers/setting.js b/src/content/reducers/setting.js
new file mode 100644
index 0000000..22fac6f
--- /dev/null
+++ b/src/content/reducers/setting.js
@@ -0,0 +1,13 @@
+import actions from 'content/actions';
+
+const defaultState = {};
+
+export default function reducer(state = defaultState, action = {}) {
+ switch (action.type) {
+ case actions.SETTING_SET:
+ return Object.assign({}, action.value);
+ default:
+ return state;
+ }
+}
+
diff --git a/src/shared/utils/re.js b/src/shared/utils/re.js
new file mode 100644
index 0000000..7db9091
--- /dev/null
+++ b/src/shared/utils/re.js
@@ -0,0 +1,6 @@
+const fromWildcard = (pattern) => {
+ let regexStr = '^' + pattern.replace(/\*/g, '.*') + '$';
+ return new RegExp(regexStr);
+};
+
+export { fromWildcard };
diff --git a/src/shared/validators/setting.js b/src/shared/validators/setting.js
index 5039ec2..949ab29 100644
--- a/src/shared/validators/setting.js
+++ b/src/shared/validators/setting.js
@@ -1,6 +1,6 @@
import operations from 'shared/operations';
-const VALID_TOP_KEYS = ['keymaps', 'search'];
+const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist'];
const VALID_OPERATION_VALUES = Object.keys(operations).map((key) => {
return operations[key];
});
diff --git a/test/content/actions/setting.test.js b/test/content/actions/setting.test.js
new file mode 100644
index 0000000..8855f04
--- /dev/null
+++ b/test/content/actions/setting.test.js
@@ -0,0 +1,13 @@
+import { expect } from "chai";
+import actions from 'content/actions';
+import * as settingActions from 'content/actions/setting';
+
+describe("setting actions", () => {
+ describe("set", () => {
+ it('create SETTING_SET action', () => {
+ let action = settingActions.set({ red: 'apple', yellow: 'banana' });
+ expect(action.type).to.equal(actions.SETTING_SET);
+ expect(action.value).to.deep.equal({ red: 'apple', yellow: 'banana' });
+ });
+ });
+});
diff --git a/test/content/reducers/setting.test.js b/test/content/reducers/setting.test.js
new file mode 100644
index 0000000..50d1cf0
--- /dev/null
+++ b/test/content/reducers/setting.test.js
@@ -0,0 +1,18 @@
+import { expect } from "chai";
+import actions from 'content/actions';
+import settingReducer from 'content/reducers/setting';
+
+describe("content setting reducer", () => {
+ it('return the initial state', () => {
+ let state = settingReducer(undefined, {});
+ expect(state).to.deep.equal({});
+ });
+
+ it('return next state for SETTING_SET', () => {
+ let newSettings = { red: 'apple', yellow: 'banana' };
+ let action = { type: actions.SETTING_SET, value: newSettings };
+ let state = settingReducer(undefined, action);
+ expect(state).to.deep.equal(newSettings);
+ expect(state).not.to.equal(newSettings); // assert deep copy
+ });
+});
diff --git a/test/shared/util/re.test.js b/test/shared/util/re.test.js
new file mode 100644
index 0000000..9ed6521
--- /dev/null
+++ b/test/shared/util/re.test.js
@@ -0,0 +1,20 @@
+import { expect } from 'chai';
+import * as re from 'shared/utils/re';
+
+describe("re util", () => {
+ it('matches by pattern', () => {
+ let regex = re.fromWildcard('*.example.com/*');
+ expect('foo.example.com/bar').to.match(regex);
+ expect('foo.example.com').not.to.match(regex);
+ expect('example.com/bar').not.to.match(regex);
+
+ regex = re.fromWildcard('example.com/*')
+ expect('example.com/foo').to.match(regex);
+ expect('example.com/').to.match(regex);
+
+ regex = re.fromWildcard('example.com/*bar')
+ expect('example.com/foobar').to.match(regex);
+ expect('example.com/bar').to.match(regex);
+ expect('example.com/foobarfoo').not.to.match(regex);
+ })
+});