aboutsummaryrefslogtreecommitdiff
path: root/src/content
diff options
context:
space:
mode:
authorShin'ya Ueoka <ueokande@i-beam.org>2019-05-11 08:04:01 +0900
committerShin'ya Ueoka <ueokande@i-beam.org>2019-05-11 08:04:01 +0900
commitbacf83a32083c5a4c4a45c061288081423bbf18a (patch)
treef5a73e2b989428ca3f3466b6e4a4cc744e24f4b7 /src/content
parente76ca380f733b515c31297a285d8bea44e074a1b (diff)
Make settings as a clean architecture
Diffstat (limited to 'src/content')
-rw-r--r--src/content/actions/index.ts11
-rw-r--r--src/content/actions/operation.ts7
-rw-r--r--src/content/actions/setting.ts28
-rw-r--r--src/content/client/SettingClient.ts17
-rw-r--r--src/content/components/common/index.ts36
-rw-r--r--src/content/components/common/keymapper.ts39
-rw-r--r--src/content/components/common/mark.ts8
-rw-r--r--src/content/components/top-content/follow-controller.ts8
-rw-r--r--src/content/reducers/index.ts4
-rw-r--r--src/content/reducers/setting.ts40
-rw-r--r--src/content/repositories/SettingRepository.ts22
-rw-r--r--src/content/usecases/SettingUseCase.ts24
12 files changed, 122 insertions, 122 deletions
diff --git a/src/content/actions/index.ts b/src/content/actions/index.ts
index 74353fb..4e395c5 100644
--- a/src/content/actions/index.ts
+++ b/src/content/actions/index.ts
@@ -1,13 +1,9 @@
import Redux from 'redux';
-import Settings from '../../shared/Settings';
import * as keyUtils from '../../shared/utils/keys';
// Find
export const FIND_SET_KEYWORD = 'find.set.keyword';
-// Settings
-export const SETTING_SET = 'setting.set';
-
// User input
export const INPUT_KEY_PRESS = 'input.key.press';
export const INPUT_CLEAR_KEYS = 'input.clear.keys';
@@ -37,11 +33,6 @@ export interface FindSetKeywordAction extends Redux.Action {
found: boolean;
}
-export interface SettingSetAction extends Redux.Action {
- type: typeof SETTING_SET;
- settings: Settings,
-}
-
export interface InputKeyPressAction extends Redux.Action {
type: typeof INPUT_KEY_PRESS;
key: keyUtils.Key;
@@ -94,7 +85,6 @@ export interface NoopAction extends Redux.Action {
}
export type FindAction = FindSetKeywordAction | NoopAction;
-export type SettingAction = SettingSetAction;
export type InputAction = InputKeyPressAction | InputClearKeysAction;
export type FollowAction =
FollowControllerEnableAction | FollowControllerDisableAction |
@@ -105,7 +95,6 @@ export type MarkAction =
export type Action =
FindAction |
- SettingAction |
InputAction |
FollowAction |
MarkAction |
diff --git a/src/content/actions/operation.ts b/src/content/actions/operation.ts
index 949f69f..f65d0bd 100644
--- a/src/content/actions/operation.ts
+++ b/src/content/actions/operation.ts
@@ -9,14 +9,16 @@ import * as consoleFrames from '../console-frames';
import * as markActions from './mark';
import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase';
+import { SettingRepositoryImpl } from '../repositories/SettingRepository';
let addonEnabledUseCase = new AddonEnabledUseCase();
+let settingRepository = new SettingRepositoryImpl();
// eslint-disable-next-line complexity, max-lines-per-function
const exec = async(
operation: operations.Operation,
- settings: any,
): Promise<actions.Action> => {
+ let settings = settingRepository.get();
let smoothscroll = settings.properties.smoothscroll;
switch (operation.type) {
case operations.ADDON_ENABLE:
@@ -97,7 +99,8 @@ const exec = async(
break;
case operations.URLS_PASTE:
urls.paste(
- window, operation.newTab ? operation.newTab : false, settings.search
+ window, operation.newTab ? operation.newTab : false,
+ settings.search,
);
break;
default:
diff --git a/src/content/actions/setting.ts b/src/content/actions/setting.ts
deleted file mode 100644
index 92f8559..0000000
--- a/src/content/actions/setting.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as actions from './index';
-import * as operations from '../../shared/operations';
-import * as messages from '../../shared/messages';
-import Settings, { Keymaps } from '../../shared/Settings';
-
-const reservedKeymaps: Keymaps = {
- '<Esc>': { type: operations.CANCEL },
- '<C-[>': { type: operations.CANCEL },
-};
-
-const set = (settings: Settings): actions.SettingAction => {
- return {
- type: actions.SETTING_SET,
- settings: {
- ...settings,
- keymaps: { ...settings.keymaps, ...reservedKeymaps },
- }
- };
-};
-
-const load = async(): Promise<actions.SettingAction> => {
- let settings = await browser.runtime.sendMessage({
- type: messages.SETTINGS_QUERY,
- });
- return set(settings);
-};
-
-export { set, load };
diff --git a/src/content/client/SettingClient.ts b/src/content/client/SettingClient.ts
new file mode 100644
index 0000000..c67f544
--- /dev/null
+++ b/src/content/client/SettingClient.ts
@@ -0,0 +1,17 @@
+import Settings from '../../shared/Settings';
+import * as messages from '../../shared/messages';
+
+export default interface SettingClient {
+ load(): Promise<Settings>;
+
+ // eslint-disable-next-line semi
+}
+
+export class SettingClientImpl {
+ async load(): Promise<Settings> {
+ let settings = await browser.runtime.sendMessage({
+ type: messages.SETTINGS_QUERY,
+ });
+ return settings as Settings;
+ }
+}
diff --git a/src/content/components/common/index.ts b/src/content/components/common/index.ts
index be77812..899953d 100644
--- a/src/content/components/common/index.ts
+++ b/src/content/components/common/index.ts
@@ -2,22 +2,18 @@ import InputComponent from './input';
import FollowComponent from './follow';
import MarkComponent from './mark';
import KeymapperComponent from './keymapper';
-import * as settingActions from '../../actions/setting';
import * as messages from '../../../shared/messages';
import MessageListener from '../../MessageListener';
import * as blacklists from '../../../shared/blacklists';
import * as keys from '../../../shared/utils/keys';
-import * as actions from '../../actions';
import AddonEnabledUseCase from '../../usecases/AddonEnabledUseCase';
+import SettingUseCase from '../../usecases/SettingUseCase';
let addonEnabledUseCase = new AddonEnabledUseCase();
+let settingUseCase = new SettingUseCase();
export default class Common {
- private win: Window;
-
- private store: any;
-
constructor(win: Window, store: any) {
const input = new InputComponent(win.document.body);
const follow = new FollowComponent(win);
@@ -28,9 +24,6 @@ export default class Common {
input.onKey((key: keys.Key) => mark.key(key));
input.onKey((key: keys.Key) => keymapper.key(key));
- this.win = win;
- this.store = store;
-
this.reloadSettings();
new MessageListener().onBackgroundMessage(this.onMessage.bind(this));
@@ -41,23 +34,22 @@ export default class Common {
case messages.SETTINGS_CHANGED:
return this.reloadSettings();
case messages.ADDON_TOGGLE_ENABLED:
- addonEnabledUseCase.toggle();
+ return addonEnabledUseCase.toggle();
}
+ return undefined;
}
- reloadSettings() {
+ async reloadSettings() {
try {
- this.store.dispatch(settingActions.load())
- .then((action: actions.SettingAction) => {
- let enabled = !blacklists.includes(
- action.settings.blacklist, this.win.location.href
- );
- if (enabled) {
- addonEnabledUseCase.enable();
- } else {
- addonEnabledUseCase.disable();
- }
- });
+ let current = await settingUseCase.reload();
+ let disabled = blacklists.includes(
+ current.blacklist, window.location.href,
+ );
+ if (disabled) {
+ addonEnabledUseCase.disable();
+ } else {
+ addonEnabledUseCase.enable();
+ }
} catch (e) {
// Sometime sendMessage fails when background script is not ready.
console.warn(e);
diff --git a/src/content/components/common/keymapper.ts b/src/content/components/common/keymapper.ts
index 02579ec..c901ffe 100644
--- a/src/content/components/common/keymapper.ts
+++ b/src/content/components/common/keymapper.ts
@@ -4,8 +4,18 @@ import * as operations from '../../../shared/operations';
import * as keyUtils from '../../../shared/utils/keys';
import AddonEnabledUseCase from '../../usecases/AddonEnabledUseCase';
+import { SettingRepositoryImpl } from '../../repositories/SettingRepository';
+import { Keymaps } from '../../../shared/Settings';
+
+type KeymapEntityMap = Map<keyUtils.Key[], operations.Operation>;
let addonEnabledUseCase = new AddonEnabledUseCase();
+let settingRepository = new SettingRepositoryImpl();
+
+const reservedKeymaps: Keymaps = {
+ '<Esc>': { type: operations.CANCEL },
+ '<C-[>': { type: operations.CANCEL },
+};
const mapStartsWith = (
mapping: keyUtils.Key[],
@@ -29,18 +39,11 @@ export default class KeymapperComponent {
this.store = store;
}
- // eslint-disable-next-line max-statements
key(key: keyUtils.Key): boolean {
this.store.dispatch(inputActions.keyPress(key));
- let state = this.store.getState();
- let input = state.input;
- let keymaps = new Map<keyUtils.Key[], operations.Operation>(
- state.setting.keymaps.map(
- (e: {key: keyUtils.Key[], op: operations.Operation}) => [e.key, e.op],
- )
- );
-
+ let input = this.store.getState().input;
+ let keymaps = this.keymapEntityMap();
let matched = Array.from(keymaps.keys()).filter(
(mapping: keyUtils.Key[]) => {
return mapStartsWith(mapping, input.keys);
@@ -62,11 +65,23 @@ export default class KeymapperComponent {
return true;
}
let operation = keymaps.get(matched[0]) as operations.Operation;
- let act = operationActions.exec(
- operation, state.setting,
- );
+ let act = operationActions.exec(operation);
this.store.dispatch(act);
this.store.dispatch(inputActions.clearKeys());
return true;
}
+
+ private keymapEntityMap(): KeymapEntityMap {
+ let keymaps = {
+ ...settingRepository.get().keymaps,
+ ...reservedKeymaps,
+ };
+ let entries = Object.entries(keymaps).map((entry) => {
+ return [
+ keyUtils.fromMapKeys(entry[0]),
+ entry[1],
+ ];
+ }) as [keyUtils.Key[], operations.Operation][];
+ return new Map<keyUtils.Key[], operations.Operation>(entries);
+ }
}
diff --git a/src/content/components/common/mark.ts b/src/content/components/common/mark.ts
index 1237385..77aa15d 100644
--- a/src/content/components/common/mark.ts
+++ b/src/content/components/common/mark.ts
@@ -4,6 +4,10 @@ import * as consoleFrames from '../..//console-frames';
import * as keyUtils from '../../../shared/utils/keys';
import Mark from '../../Mark';
+import { SettingRepositoryImpl } from '../../repositories/SettingRepository';
+
+let settingRepository = new SettingRepositoryImpl();
+
const cancelKey = (key: keyUtils.Key): boolean => {
return key.key === 'Esc' || key.key === '[' && Boolean(key.ctrlKey);
};
@@ -21,8 +25,8 @@ export default class MarkComponent {
// eslint-disable-next-line max-statements
key(key: keyUtils.Key) {
- let { mark: markState, setting } = this.store.getState();
- let smoothscroll = setting.properties.smoothscroll;
+ let smoothscroll = settingRepository.get().properties.smoothscroll;
+ let { mark: markState } = this.store.getState();
if (!markState.setMode && !markState.jumpMode) {
return false;
diff --git a/src/content/components/top-content/follow-controller.ts b/src/content/components/top-content/follow-controller.ts
index d49b22a..2fcf365 100644
--- a/src/content/components/top-content/follow-controller.ts
+++ b/src/content/components/top-content/follow-controller.ts
@@ -3,6 +3,10 @@ import * as messages from '../../../shared/messages';
import MessageListener, { WebMessageSender } from '../../MessageListener';
import HintKeyProducer from '../../hint-key-producer';
+import { SettingRepositoryImpl } from '../../repositories/SettingRepository';
+
+let settingRepository = new SettingRepositoryImpl();
+
const broadcastMessage = (win: Window, message: messages.Message): void => {
let json = JSON.stringify(message);
let frames = [win.self].concat(Array.from(win.frames as any));
@@ -160,7 +164,7 @@ export default class FollowController {
});
}
- hintchars() {
- return this.store.getState().setting.properties.hintchars;
+ private hintchars() {
+ return settingRepository.get().properties.hintchars;
}
}
diff --git a/src/content/reducers/index.ts b/src/content/reducers/index.ts
index 6f11512..21e8918 100644
--- a/src/content/reducers/index.ts
+++ b/src/content/reducers/index.ts
@@ -1,6 +1,5 @@
import { combineReducers } from 'redux';
import find, { State as FindState } from './find';
-import setting, { State as SettingState } from './setting';
import input, { State as InputState } from './input';
import followController, { State as FollowControllerState }
from './follow-controller';
@@ -8,12 +7,11 @@ import mark, { State as MarkState } from './mark';
export interface State {
find: FindState;
- setting: SettingState;
input: InputState;
followController: FollowControllerState;
mark: MarkState;
}
export default combineReducers({
- find, setting, input, followController, mark,
+ find, input, followController, mark,
});
diff --git a/src/content/reducers/setting.ts b/src/content/reducers/setting.ts
deleted file mode 100644
index 9ca1380..0000000
--- a/src/content/reducers/setting.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import * as actions from '../actions';
-import * as keyUtils from '../../shared/utils/keys';
-import * as operations from '../../shared/operations';
-import { Search, Properties, DefaultSetting } from '../../shared/Settings';
-
-export interface State {
- keymaps: { key: keyUtils.Key[], op: operations.Operation }[];
- search: Search;
- properties: Properties;
-}
-
-// defaultState does not refer due to the state is load from
-// background on load.
-const defaultState: State = {
- keymaps: [],
- search: DefaultSetting.search,
- properties: DefaultSetting.properties,
-};
-
-export default function reducer(
- state: State = defaultState,
- action: actions.SettingAction,
-): State {
- switch (action.type) {
- case actions.SETTING_SET:
- return {
- keymaps: Object.entries(action.settings.keymaps).map((entry) => {
- return {
- key: keyUtils.fromMapKeys(entry[0]),
- op: entry[1],
- };
- }),
- properties: action.settings.properties,
- search: action.settings.search,
- };
- default:
- return state;
- }
-}
-
diff --git a/src/content/repositories/SettingRepository.ts b/src/content/repositories/SettingRepository.ts
new file mode 100644
index 0000000..ce13c25
--- /dev/null
+++ b/src/content/repositories/SettingRepository.ts
@@ -0,0 +1,22 @@
+import Settings, { DefaultSetting } from '../../shared/Settings';
+
+let current: Settings = DefaultSetting;
+
+export default interface SettingRepository {
+ set(setting: Settings): void;
+
+ get(): Settings;
+
+ // eslint-disable-next-line semi
+}
+
+export class SettingRepositoryImpl implements SettingRepository {
+ set(setting: Settings): void {
+ current = setting;
+ }
+
+ get(): Settings {
+ return current;
+ }
+
+}
diff --git a/src/content/usecases/SettingUseCase.ts b/src/content/usecases/SettingUseCase.ts
new file mode 100644
index 0000000..765cb45
--- /dev/null
+++ b/src/content/usecases/SettingUseCase.ts
@@ -0,0 +1,24 @@
+import SettingRepository, { SettingRepositoryImpl }
+ from '../repositories/SettingRepository';
+import SettingClient, { SettingClientImpl } from '../client/SettingClient';
+import Settings from '../../shared/Settings';
+
+export default class SettingUseCase {
+ private repository: SettingRepository;
+
+ private client: SettingClient;
+
+ constructor({
+ repository = new SettingRepositoryImpl(),
+ client = new SettingClientImpl(),
+ } = {}) {
+ this.repository = repository;
+ this.client = client;
+ }
+
+ async reload(): Promise<Settings> {
+ let settings = await this.client.load();
+ this.repository.set(settings);
+ return settings;
+ }
+}