aboutsummaryrefslogtreecommitdiff
path: root/src/content
diff options
context:
space:
mode:
Diffstat (limited to 'src/content')
-rw-r--r--src/content/controllers/KeymapController.ts88
-rw-r--r--src/content/di.ts8
-rw-r--r--src/content/hint-key-producer.ts37
-rw-r--r--src/content/operators/Operator.ts5
-rw-r--r--src/content/operators/OperatorFactory.ts6
-rw-r--r--src/content/operators/OperatorFactoryChain.ts6
-rw-r--r--src/content/operators/impls/AbstractScrollOperator.ts10
-rw-r--r--src/content/operators/impls/AddonOperatorFactoryChain.ts40
-rw-r--r--src/content/operators/impls/BackgroundOperationOperator.ts15
-rw-r--r--src/content/operators/impls/ClipboardOperatorFactoryChain.ts47
-rw-r--r--src/content/operators/impls/DisableAddonOperator.ts15
-rw-r--r--src/content/operators/impls/EnableAddonOperator.ts15
-rw-r--r--src/content/operators/impls/EnableJumpMarkOperator.ts10
-rw-r--r--src/content/operators/impls/EnableSetMarkOperator.ts10
-rw-r--r--src/content/operators/impls/FindNextOperator.ts15
-rw-r--r--src/content/operators/impls/FindOperatorFactoryChain.ts25
-rw-r--r--src/content/operators/impls/FindPrevOperator.ts15
-rw-r--r--src/content/operators/impls/FocusOperator.ts10
-rw-r--r--src/content/operators/impls/FocusOperatorFactoryChain.ts22
-rw-r--r--src/content/operators/impls/FollowOperatorFactoryChain.ts27
-rw-r--r--src/content/operators/impls/HorizontalScrollOperator.ts21
-rw-r--r--src/content/operators/impls/MarkOperatorFactoryChain.ts25
-rw-r--r--src/content/operators/impls/OperatorFactoryImpl.ts51
-rw-r--r--src/content/operators/impls/PageScrollOperator.ts21
-rw-r--r--src/content/operators/impls/PasteOperator.ts25
-rw-r--r--src/content/operators/impls/ScrollOperatorFactoryChain.ts68
-rw-r--r--src/content/operators/impls/ScrollToBottomOperator.ts20
-rw-r--r--src/content/operators/impls/ScrollToEndOperator.ts20
-rw-r--r--src/content/operators/impls/ScrollToHomeOperator.ts20
-rw-r--r--src/content/operators/impls/ScrollToTopOperator.ts20
-rw-r--r--src/content/operators/impls/StartFollowOperator.ts14
-rw-r--r--src/content/operators/impls/ToggleAddonOperator.ts16
-rw-r--r--src/content/operators/impls/URLRepository.ts9
-rw-r--r--src/content/operators/impls/VerticalScrollOperator.ts21
-rw-r--r--src/content/operators/impls/YankURLOperator.ts18
-rw-r--r--src/content/presenters/ScrollPresenter.ts2
-rw-r--r--src/content/repositories/HintKeyRepository.ts49
-rw-r--r--src/content/usecases/ClipboardUseCase.ts34
-rw-r--r--src/content/usecases/FindSlaveUseCase.ts17
-rw-r--r--src/content/usecases/FocusUseCase.ts11
-rw-r--r--src/content/usecases/FollowMasterUseCase.ts18
-rw-r--r--src/content/usecases/HintKeyProducer.ts37
-rw-r--r--src/content/usecases/MarkKeyUseCase.ts8
-rw-r--r--src/content/usecases/ScrollUseCase.ts51
44 files changed, 738 insertions, 284 deletions
diff --git a/src/content/controllers/KeymapController.ts b/src/content/controllers/KeymapController.ts
index 092e55c..01ac8b5 100644
--- a/src/content/controllers/KeymapController.ts
+++ b/src/content/controllers/KeymapController.ts
@@ -1,32 +1,15 @@
import { injectable, inject } from "tsyringe";
-import * as operations from "../../shared/operations";
import KeymapUseCase from "../usecases/KeymapUseCase";
-import AddonEnabledUseCase from "../usecases/AddonEnabledUseCase";
-import FindSlaveUseCase from "../usecases/FindSlaveUseCase";
-import ScrollUseCase from "../usecases/ScrollUseCase";
-import FocusUseCase from "../usecases/FocusUseCase";
-import ClipboardUseCase from "../usecases/ClipboardUseCase";
-import OperationClient from "../client/OperationClient";
-import MarkKeyyUseCase from "../usecases/MarkKeyUseCase";
-import FollowMasterClient from "../client/FollowMasterClient";
import Key from "../../shared/settings/Key";
+import OperatorFactory from "../operators/OperatorFactory";
@injectable()
export default class KeymapController {
constructor(
private keymapUseCase: KeymapUseCase,
- private addonEnabledUseCase: AddonEnabledUseCase,
- private findSlaveUseCase: FindSlaveUseCase,
- private scrollUseCase: ScrollUseCase,
- private focusUseCase: FocusUseCase,
- private clipbaordUseCase: ClipboardUseCase,
- private markKeyUseCase: MarkKeyyUseCase,
- @inject("OperationClient")
- private operationClient: OperationClient,
-
- @inject("FollowMasterClient")
- private followMasterClient: FollowMasterClient
+ @inject("OperatorFactory")
+ private readonly operatorFactory: OperatorFactory
) {}
// eslint-disable-next-line complexity, max-lines-per-function
@@ -36,65 +19,14 @@ export default class KeymapController {
return false;
}
- if (!operations.isNRepeatable(nextOp.op.type)) {
- nextOp.repeat = 1;
- }
-
- const doFunc = ((op: operations.Operation) => {
- switch (op.type) {
- case operations.ADDON_ENABLE:
- return () => this.addonEnabledUseCase.enable();
- case operations.ADDON_DISABLE:
- return () => this.addonEnabledUseCase.disable();
- case operations.ADDON_TOGGLE_ENABLED:
- return () => this.addonEnabledUseCase.toggle();
- case operations.FIND_NEXT:
- return () => this.findSlaveUseCase.findNext();
- case operations.FIND_PREV:
- return () => this.findSlaveUseCase.findPrev();
- case operations.SCROLL_VERTICALLY:
- return () => this.scrollUseCase.scrollVertically(op.count);
- case operations.SCROLL_HORIZONALLY:
- return () => this.scrollUseCase.scrollHorizonally(op.count);
- case operations.SCROLL_PAGES:
- return () => this.scrollUseCase.scrollPages(op.count);
- case operations.SCROLL_TOP:
- return () => this.scrollUseCase.scrollToTop();
- case operations.SCROLL_BOTTOM:
- return () => this.scrollUseCase.scrollToBottom();
- case operations.SCROLL_HOME:
- return () => this.scrollUseCase.scrollToHome();
- case operations.SCROLL_END:
- return () => this.scrollUseCase.scrollToEnd();
- case operations.FOLLOW_START:
- return () =>
- this.followMasterClient.startFollow(op.newTab, op.background);
- case operations.MARK_SET_PREFIX:
- return () => this.markKeyUseCase.enableSetMode();
- case operations.MARK_JUMP_PREFIX:
- return () => this.markKeyUseCase.enableJumpMode();
- case operations.FOCUS_INPUT:
- return () => this.focusUseCase.focusFirstInput();
- case operations.URLS_YANK:
- return () => this.clipbaordUseCase.yankCurrentURL();
- case operations.URLS_PASTE:
- return () =>
- this.clipbaordUseCase.openOrSearch(op.newTab ? op.newTab : false);
- default:
- return null;
- }
- })(nextOp.op);
+ // Do not await asynchronous methods to return a boolean immidiately. The
+ // caller requires the synchronous response from the callback to identify
+ // to continue of abandon the event propagation.
+ this.operatorFactory
+ .create(nextOp.op, nextOp.repeat)
+ .run()
+ .catch(console.error);
- if (doFunc === null) {
- // Do not await asynchronous methods to return a boolean immidiately. The
- // caller requires the synchronous response from the callback to identify
- // to continue of abandon the event propagations.
- this.operationClient.execBackgroundOp(nextOp.repeat, nextOp.op);
- } else {
- for (let i = 0; i < nextOp.repeat; ++i) {
- doFunc();
- }
- }
return true;
}
diff --git a/src/content/di.ts b/src/content/di.ts
index cc10c78..e74d7ac 100644
--- a/src/content/di.ts
+++ b/src/content/di.ts
@@ -17,6 +17,7 @@ import { FollowMasterRepositoryImpl } from "./repositories/FollowMasterRepositor
import { FollowPresenterImpl } from "./presenters/FollowPresenter";
import { FollowSlaveClientFactoryImpl } from "./client/FollowSlaveClientFactory";
import { FollowSlaveRepositoryImpl } from "./repositories/FollowSlaveRepository";
+import { HintKeyRepositoryImpl } from "./repositories/HintKeyRepository";
import { KeymapRepositoryImpl } from "./repositories/KeymapRepository";
import { MarkClientImpl } from "./client/MarkClient";
import { MarkKeyRepositoryImpl } from "./repositories/MarkKeyRepository";
@@ -28,6 +29,8 @@ import { SettingClientImpl } from "./client/SettingClient";
import { SettingRepositoryImpl } from "./repositories/SettingRepository";
import { TabsClientImpl } from "./client/TabsClient";
import { container } from "tsyringe";
+import OperatorFactoryImpl from "./operators/impls/OperatorFactoryImpl";
+import { URLRepositoryImpl } from "./operators/impls/URLRepository";
container.register("FollowMasterClient", {
useValue: new FollowMasterClientImpl(window.top),
@@ -64,6 +67,9 @@ container.register("FollowSlaveClientFactory", {
container.register("FollowSlaveRepository", {
useClass: FollowSlaveRepositoryImpl,
});
+container.register("HintKeyRepository", {
+ useClass: HintKeyRepositoryImpl,
+});
container.register("KeymapRepository", { useClass: KeymapRepositoryImpl });
container.register("MarkClient", { useClass: MarkClientImpl });
container.register("MarkKeyRepository", { useClass: MarkKeyRepositoryImpl });
@@ -75,4 +81,6 @@ container.register("OperationClient", { useClass: OperationClientImpl });
container.register("ScrollPresenter", { useClass: ScrollPresenterImpl });
container.register("SettingClient", { useClass: SettingClientImpl });
container.register("SettingRepository", { useClass: SettingRepositoryImpl });
+container.register("URLRepository", { useClass: URLRepositoryImpl });
container.register("TabsClient", { useClass: TabsClientImpl });
+container.register("OperatorFactory", { useClass: OperatorFactoryImpl });
diff --git a/src/content/hint-key-producer.ts b/src/content/hint-key-producer.ts
deleted file mode 100644
index a5e2877..0000000
--- a/src/content/hint-key-producer.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-export default class HintKeyProducer {
- private charset: string;
-
- private counter: number[];
-
- constructor(charset: string) {
- if (charset.length === 0) {
- throw new TypeError("charset is empty");
- }
-
- this.charset = charset;
- this.counter = [];
- }
-
- produce(): string {
- this.increment();
-
- return this.counter.map((x) => this.charset[x]).join("");
- }
-
- private increment(): void {
- const max = this.charset.length - 1;
- if (this.counter.every((x) => x === max)) {
- this.counter = new Array(this.counter.length + 1).fill(0);
- return;
- }
-
- this.counter.reverse();
- const len = this.charset.length;
- let num = this.counter.reduce((x, y, index) => x + y * len ** index) + 1;
- for (let i = 0; i < this.counter.length; ++i) {
- this.counter[i] = num % len;
- num = ~~(num / len);
- }
- this.counter.reverse();
- }
-}
diff --git a/src/content/operators/Operator.ts b/src/content/operators/Operator.ts
new file mode 100644
index 0000000..3b1fe03
--- /dev/null
+++ b/src/content/operators/Operator.ts
@@ -0,0 +1,5 @@
+interface Operator {
+ run(): Promise<void>;
+}
+
+export default Operator;
diff --git a/src/content/operators/OperatorFactory.ts b/src/content/operators/OperatorFactory.ts
new file mode 100644
index 0000000..f45973b
--- /dev/null
+++ b/src/content/operators/OperatorFactory.ts
@@ -0,0 +1,6 @@
+import * as operations from "../../shared/operations";
+import Operator from "./Operator";
+
+export default interface OperatorFactory {
+ create(op: operations.Operation, repeat: number): Operator;
+}
diff --git a/src/content/operators/OperatorFactoryChain.ts b/src/content/operators/OperatorFactoryChain.ts
new file mode 100644
index 0000000..98dedb5
--- /dev/null
+++ b/src/content/operators/OperatorFactoryChain.ts
@@ -0,0 +1,6 @@
+import * as operations from "../../shared/operations";
+import Operator from "./Operator";
+
+export default interface OperatorFactoryChain {
+ create(op: operations.Operation, repeat: number): Operator | null;
+}
diff --git a/src/content/operators/impls/AbstractScrollOperator.ts b/src/content/operators/impls/AbstractScrollOperator.ts
new file mode 100644
index 0000000..f8d9f70
--- /dev/null
+++ b/src/content/operators/impls/AbstractScrollOperator.ts
@@ -0,0 +1,10 @@
+import SettingRepository from "../../repositories/SettingRepository";
+
+export default class AbstractScrollOperator {
+ constructor(private readonly settingRepository: SettingRepository) {}
+
+ protected getSmoothScroll(): boolean {
+ const settings = this.settingRepository.get();
+ return settings.properties.smoothscroll;
+ }
+}
diff --git a/src/content/operators/impls/AddonOperatorFactoryChain.ts b/src/content/operators/impls/AddonOperatorFactoryChain.ts
new file mode 100644
index 0000000..54880c4
--- /dev/null
+++ b/src/content/operators/impls/AddonOperatorFactoryChain.ts
@@ -0,0 +1,40 @@
+import { inject, injectable } from "tsyringe";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import AddonIndicatorClient from "../../client/AddonIndicatorClient";
+import AddonEnabledRepository from "../../repositories/AddonEnabledRepository";
+import * as operations from "../../../shared/operations";
+import Operator from "../Operator";
+import EnableAddonOperator from "./EnableAddonOperator";
+import DisableAddonOperator from "./DisableAddonOperator";
+import ToggleAddonOperator from "./ToggleAddonOperator";
+
+@injectable()
+export default class AddonOperatorFactoryChain implements OperatorFactoryChain {
+ constructor(
+ @inject("AddonIndicatorClient")
+ private readonly addonIndicatorClient: AddonIndicatorClient,
+ @inject("AddonEnabledRepository")
+ private readonly addonEnabledRepository: AddonEnabledRepository
+ ) {}
+
+ create(op: operations.Operation, _repeat: number): Operator | null {
+ switch (op.type) {
+ case operations.ADDON_ENABLE:
+ return new EnableAddonOperator(
+ this.addonIndicatorClient,
+ this.addonEnabledRepository
+ );
+ case operations.ADDON_DISABLE:
+ return new DisableAddonOperator(
+ this.addonIndicatorClient,
+ this.addonEnabledRepository
+ );
+ case operations.ADDON_TOGGLE_ENABLED:
+ return new ToggleAddonOperator(
+ this.addonIndicatorClient,
+ this.addonEnabledRepository
+ );
+ }
+ return null;
+ }
+}
diff --git a/src/content/operators/impls/BackgroundOperationOperator.ts b/src/content/operators/impls/BackgroundOperationOperator.ts
new file mode 100644
index 0000000..dd86559
--- /dev/null
+++ b/src/content/operators/impls/BackgroundOperationOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import OperationClient from "../../client/OperationClient";
+import * as operations from "../../../shared/operations";
+
+export default class BackgroundOperationOperator implements Operator {
+ constructor(
+ private readonly operationClient: OperationClient,
+ private readonly repeat: number,
+ private readonly op: operations.Operation
+ ) {}
+
+ async run(): Promise<void> {
+ await this.operationClient.execBackgroundOp(this.repeat, this.op);
+ }
+}
diff --git a/src/content/operators/impls/ClipboardOperatorFactoryChain.ts b/src/content/operators/impls/ClipboardOperatorFactoryChain.ts
new file mode 100644
index 0000000..454aea1
--- /dev/null
+++ b/src/content/operators/impls/ClipboardOperatorFactoryChain.ts
@@ -0,0 +1,47 @@
+import { inject, injectable } from "tsyringe";
+import YankURLOperator from "./YankURLOperator";
+import PasteOperator from "./PasteOperator";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import ClipboardRepository from "../../repositories/ClipboardRepository";
+import ConsoleClient from "../../client/ConsoleClient";
+import OperationClient from "../../client/OperationClient";
+import SettingRepository from "../../repositories/SettingRepository";
+import * as operations from "../../../shared/operations";
+import URLRepository from "./URLRepository";
+
+@injectable()
+export default class ClipboardOperatorFactoryChain
+ implements OperatorFactoryChain {
+ constructor(
+ @inject("ClipboardRepository")
+ private readonly clipboardRepository: ClipboardRepository,
+ @inject("ConsoleClient")
+ private readonly consoleClient: ConsoleClient,
+ @inject("OperationClient")
+ private readonly operationClinet: OperationClient,
+ @inject("SettingRepository")
+ private readonly settingRepository: SettingRepository,
+ @inject("URLRepository")
+ private readonly urlRepository: URLRepository
+ ) {}
+
+ create(op: operations.Operation, _repeat: number): Operator | null {
+ switch (op.type) {
+ case operations.URLS_YANK:
+ return new YankURLOperator(
+ this.clipboardRepository,
+ this.consoleClient,
+ this.urlRepository
+ );
+ case operations.URLS_PASTE:
+ return new PasteOperator(
+ this.clipboardRepository,
+ this.settingRepository,
+ this.operationClinet,
+ op.newTab
+ );
+ }
+ return null;
+ }
+}
diff --git a/src/content/operators/impls/DisableAddonOperator.ts b/src/content/operators/impls/DisableAddonOperator.ts
new file mode 100644
index 0000000..28811fe
--- /dev/null
+++ b/src/content/operators/impls/DisableAddonOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import AddonIndicatorClient from "../../client/AddonIndicatorClient";
+import AddonEnabledRepository from "../../repositories/AddonEnabledRepository";
+
+export default class DisableAddonOperator implements Operator {
+ constructor(
+ private readonly indicator: AddonIndicatorClient,
+ private readonly repository: AddonEnabledRepository
+ ) {}
+
+ async run(): Promise<void> {
+ this.repository.set(false);
+ await this.indicator.setEnabled(false);
+ }
+}
diff --git a/src/content/operators/impls/EnableAddonOperator.ts b/src/content/operators/impls/EnableAddonOperator.ts
new file mode 100644
index 0000000..b5b1d79
--- /dev/null
+++ b/src/content/operators/impls/EnableAddonOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import AddonIndicatorClient from "../../client/AddonIndicatorClient";
+import AddonEnabledRepository from "../../repositories/AddonEnabledRepository";
+
+export default class EnableAddonOperator implements Operator {
+ constructor(
+ private readonly indicator: AddonIndicatorClient,
+ private readonly repository: AddonEnabledRepository
+ ) {}
+
+ async run(): Promise<void> {
+ this.repository.set(true);
+ await this.indicator.setEnabled(true);
+ }
+}
diff --git a/src/content/operators/impls/EnableJumpMarkOperator.ts b/src/content/operators/impls/EnableJumpMarkOperator.ts
new file mode 100644
index 0000000..42ca8ee
--- /dev/null
+++ b/src/content/operators/impls/EnableJumpMarkOperator.ts
@@ -0,0 +1,10 @@
+import Operator from "../Operator";
+import MarkKeyRepository from "../../repositories/MarkKeyRepository";
+
+export default class EnableJumpMarkOperator implements Operator {
+ constructor(private readonly repository: MarkKeyRepository) {}
+
+ async run(): Promise<void> {
+ this.repository.enableJumpMode();
+ }
+}
diff --git a/src/content/operators/impls/EnableSetMarkOperator.ts b/src/content/operators/impls/EnableSetMarkOperator.ts
new file mode 100644
index 0000000..3d0daf4
--- /dev/null
+++ b/src/content/operators/impls/EnableSetMarkOperator.ts
@@ -0,0 +1,10 @@
+import Operator from "../Operator";
+import MarkKeyRepository from "../../repositories/MarkKeyRepository";
+
+export default class EnableSetMarkOperator implements Operator {
+ constructor(private readonly repository: MarkKeyRepository) {}
+
+ async run(): Promise<void> {
+ this.repository.enableSetMode();
+ }
+}
diff --git a/src/content/operators/impls/FindNextOperator.ts b/src/content/operators/impls/FindNextOperator.ts
new file mode 100644
index 0000000..c67f6d9
--- /dev/null
+++ b/src/content/operators/impls/FindNextOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import FindMasterClient from "../../client/FindMasterClient";
+
+export default class FindNextOperator implements Operator {
+ constructor(
+ private readonly findMasterClient: FindMasterClient,
+ private readonly repeat: number
+ ) {}
+
+ async run(): Promise<void> {
+ for (let i = 0; i < this.repeat; ++i) {
+ this.findMasterClient.findNext();
+ }
+ }
+}
diff --git a/src/content/operators/impls/FindOperatorFactoryChain.ts b/src/content/operators/impls/FindOperatorFactoryChain.ts
new file mode 100644
index 0000000..b3524c1
--- /dev/null
+++ b/src/content/operators/impls/FindOperatorFactoryChain.ts
@@ -0,0 +1,25 @@
+import { inject, injectable } from "tsyringe";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import FindNextOperator from "./FindNextOperator";
+import FindPrevOperator from "./FindPrevOperator";
+import FindMasterClient from "../../client/FindMasterClient";
+import * as operations from "../../../shared/operations";
+
+@injectable()
+export default class FindOperatorFactoryChain implements OperatorFactoryChain {
+ constructor(
+ @inject("FindMasterClient")
+ private readonly findMasterClient: FindMasterClient
+ ) {}
+
+ create(op: operations.Operation, repeat: number): Operator | null {
+ switch (op.type) {
+ case operations.FIND_NEXT:
+ return new FindNextOperator(this.findMasterClient, repeat);
+ case operations.FIND_PREV:
+ return new FindPrevOperator(this.findMasterClient, repeat);
+ }
+ return null;
+ }
+}
diff --git a/src/content/operators/impls/FindPrevOperator.ts b/src/content/operators/impls/FindPrevOperator.ts
new file mode 100644
index 0000000..f73e605
--- /dev/null
+++ b/src/content/operators/impls/FindPrevOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import FindMasterClient from "../../client/FindMasterClient";
+
+export default class FindPrevOperator implements Operator {
+ constructor(
+ private readonly findMasterClient: FindMasterClient,
+ private readonly repeat: number
+ ) {}
+
+ async run(): Promise<void> {
+ for (let i = 0; i < this.repeat; ++i) {
+ this.findMasterClient.findPrev();
+ }
+ }
+}
diff --git a/src/content/operators/impls/FocusOperator.ts b/src/content/operators/impls/FocusOperator.ts
new file mode 100644
index 0000000..51d6fec
--- /dev/null
+++ b/src/content/operators/impls/FocusOperator.ts
@@ -0,0 +1,10 @@
+import Operator from "../Operator";
+import FocusPresenter from "../../presenters/FocusPresenter";
+
+export default class FocusOperator implements Operator {
+ constructor(private readonly presenter: FocusPresenter) {}
+
+ async run(): Promise<void> {
+ this.presenter.focusFirstElement();
+ }
+}
diff --git a/src/content/operators/impls/FocusOperatorFactoryChain.ts b/src/content/operators/impls/FocusOperatorFactoryChain.ts
new file mode 100644
index 0000000..c89c1e5
--- /dev/null
+++ b/src/content/operators/impls/FocusOperatorFactoryChain.ts
@@ -0,0 +1,22 @@
+import { inject, injectable } from "tsyringe";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import Operator from "../Operator";
+import FocusOperator from "./FocusOperator";
+import FocusPresenter from "../../presenters/FocusPresenter";
+import * as operations from "../../../shared/operations";
+
+@injectable()
+export default class FocusOperatorFactoryChain implements OperatorFactoryChain {
+ constructor(
+ @inject("FocusPresenter")
+ private readonly focusPresenter: FocusPresenter
+ ) {}
+
+ create(op: operations.Operation, _repeat: number): Operator | null {
+ switch (op.type) {
+ case operations.FOCUS_INPUT:
+ return new FocusOperator(this.focusPresenter);
+ }
+ return null;
+ }
+}
diff --git a/src/content/operators/impls/FollowOperatorFactoryChain.ts b/src/content/operators/impls/FollowOperatorFactoryChain.ts
new file mode 100644
index 0000000..588e1a4
--- /dev/null
+++ b/src/content/operators/impls/FollowOperatorFactoryChain.ts
@@ -0,0 +1,27 @@
+import { inject, injectable } from "tsyringe";
+import StartFollowOperator from "./StartFollowOperator";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import FollowMasterClient from "../../client/FollowMasterClient";
+import * as operations from "../../../shared/operations";
+
+@injectable()
+export default class FollowOperatorFactoryChain
+ implements OperatorFactoryChain {
+ constructor(
+ @inject("FollowMasterClient")
+ private followMasterClient: FollowMasterClient
+ ) {}
+
+ create(op: operations.Operation, _repeat: number): Operator | null {
+ switch (op.type) {
+ case operations.FOLLOW_START:
+ return new StartFollowOperator(
+ this.followMasterClient,
+ op.newTab,
+ op.background
+ );
+ }
+ return null;
+ }
+}
diff --git a/src/content/operators/impls/HorizontalScrollOperator.ts b/src/content/operators/impls/HorizontalScrollOperator.ts
new file mode 100644
index 0000000..f813f85
--- /dev/null
+++ b/src/content/operators/impls/HorizontalScrollOperator.ts
@@ -0,0 +1,21 @@
+import AbstractScrollOperator from "./AbstractScrollOperator";
+import Operator from "../Operator";
+import ScrollPresenter from "../../presenters/ScrollPresenter";
+import SettingRepository from "../../repositories/SettingRepository";
+
+export default class HorizontalScrollOperator
+ extends AbstractScrollOperator
+ implements Operator {
+ constructor(
+ private readonly presenter: ScrollPresenter,
+ settingRepository: SettingRepository,
+ private readonly count: number
+ ) {
+ super(settingRepository);
+ }
+
+ async run(): Promise<void> {
+ const smooth = this.getSmoothScroll();
+ this.presenter.scrollHorizonally(this.count, smooth);
+ }
+}
diff --git a/src/content/operators/impls/MarkOperatorFactoryChain.ts b/src/content/operators/impls/MarkOperatorFactoryChain.ts
new file mode 100644
index 0000000..7e6c513
--- /dev/null
+++ b/src/content/operators/impls/MarkOperatorFactoryChain.ts
@@ -0,0 +1,25 @@
+import { inject, injectable } from "tsyringe";
+import EnableSetMarkOperator from "./EnableSetMarkOperator";
+import EnableJumpMarkOperator from "./EnableJumpMarkOperator";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import MarkKeyRepository from "../../repositories/MarkKeyRepository";
+import * as operations from "../../../shared/operations";
+
+@injectable()
+export default class MarkOperatorFactoryChain implements OperatorFactoryChain {
+ constructor(
+ @inject("MarkKeyRepository")
+ private readonly markKeyRepository: MarkKeyRepository
+ ) {}
+
+ create(op: operations.Operation, _repeat: number): Operator | null {
+ switch (op.type) {
+ case operations.MARK_SET_PREFIX:
+ return new EnableSetMarkOperator(this.markKeyRepository);
+ case operations.MARK_JUMP_PREFIX:
+ return new EnableJumpMarkOperator(this.markKeyRepository);
+ }
+ return null;
+ }
+}
diff --git a/src/content/operators/impls/OperatorFactoryImpl.ts b/src/content/operators/impls/OperatorFactoryImpl.ts
new file mode 100644
index 0000000..22b35c8
--- /dev/null
+++ b/src/content/operators/impls/OperatorFactoryImpl.ts
@@ -0,0 +1,51 @@
+import { inject, injectable } from "tsyringe";
+import OperatorFactory from "../OperatorFactory";
+import BackgroundOperationOperator from "./BackgroundOperationOperator";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import { Operation } from "../../../shared/operations";
+import OperationClient from "../../client/OperationClient";
+import AddonOperatorFactoryChain from "./AddonOperatorFactoryChain";
+import ClipboardOperatorFactoryChain from "./ClipboardOperatorFactoryChain";
+import FindOperatorFactoryChain from "./FindOperatorFactoryChain";
+import FocusOperatorFactoryChain from "./FocusOperatorFactoryChain";
+import FollowOperatorFactoryChain from "./FollowOperatorFactoryChain";
+import MarkOperatorFactoryChain from "./MarkOperatorFactoryChain";
+import ScrollOperatorFactoryChain from "./ScrollOperatorFactoryChain";
+
+@injectable()
+export default class OperatorFactoryImpl implements OperatorFactory {
+ private readonly factoryChains: OperatorFactoryChain[];
+
+ constructor(
+ addonOperatorFactoryChain: AddonOperatorFactoryChain,
+ clipboardOperatorFactoryChain: ClipboardOperatorFactoryChain,
+ findOperatorFactoryChain: FindOperatorFactoryChain,
+ focusOperatorFactoryChain: FocusOperatorFactoryChain,
+ followOperatorFactoryChain: FollowOperatorFactoryChain,
+ markOperatorFactoryChain: MarkOperatorFactoryChain,
+ scrollOperatorFactoryChain: ScrollOperatorFactoryChain,
+ @inject("OperationClient")
+ private readonly operationClient: OperationClient
+ ) {
+ this.factoryChains = [
+ addonOperatorFactoryChain,
+ clipboardOperatorFactoryChain,
+ findOperatorFactoryChain,
+ focusOperatorFactoryChain,
+ followOperatorFactoryChain,
+ markOperatorFactoryChain,
+ scrollOperatorFactoryChain,
+ ];
+ }
+
+ create(op: Operation, repeat: number): Operator {
+ for (const chain of this.factoryChains) {
+ const operator = chain.create(op, repeat);
+ if (operator != null) {
+ return operator;
+ }
+ }
+ return new BackgroundOperationOperator(this.operationClient, repeat, op);
+ }
+}
diff --git a/src/content/operators/impls/PageScrollOperator.ts b/src/content/operators/impls/PageScrollOperator.ts
new file mode 100644
index 0000000..377bf92
--- /dev/null
+++ b/src/content/operators/impls/PageScrollOperator.ts
@@ -0,0 +1,21 @@
+import AbstractScrollOperator from "./AbstractScrollOperator";
+import Operator from "../Operator";
+import ScrollPresenter from "../../presenters/ScrollPresenter";
+import SettingRepository from "../../repositories/SettingRepository";
+
+export default class PageScrollOperator
+ extends AbstractScrollOperator
+ implements Operator {
+ constructor(
+ private readonly presenter: ScrollPresenter,
+ settingRepository: SettingRepository,
+ private readonly count: number
+ ) {
+ super(settingRepository);
+ }
+
+ async run(): Promise<void> {
+ const smooth = this.getSmoothScroll();
+ this.presenter.scrollPages(this.count, smooth);
+ }
+}
diff --git a/src/content/operators/impls/PasteOperator.ts b/src/content/operators/impls/PasteOperator.ts
new file mode 100644
index 0000000..592da66
--- /dev/null
+++ b/src/content/operators/impls/PasteOperator.ts
@@ -0,0 +1,25 @@
+import Operator from "../Operator";
+import ClipboardRepository from "../../repositories/ClipboardRepository";
+import SettingRepository from "../../repositories/SettingRepository";
+import OperationClient from "../../client/OperationClient";
+import * as urls from "../../../shared/urls";
+
+export default class PasteOperator implements Operator {
+ constructor(
+ private readonly repository: ClipboardRepository,
+ private readonly settingRepository: SettingRepository,
+ private readonly operationClient: OperationClient,
+ private readonly newTab: boolean
+ ) {}
+
+ async run(): Promise<void> {
+ const search = this.settingRepository.get().search;
+ const text = this.repository.read();
+ const url = urls.searchUrl(text, search);
+
+ // NOTE: Repeat pasting from clipboard instead of opening a certain url.
+ // 'Repeat last' command is implemented in the background script and cannot
+ // access to clipboard until Firefox 63.
+ await this.operationClient.internalOpenUrl(url, this.newTab);
+ }
+}
diff --git a/src/content/operators/impls/ScrollOperatorFactoryChain.ts b/src/content/operators/impls/ScrollOperatorFactoryChain.ts
new file mode 100644
index 0000000..6847aea
--- /dev/null
+++ b/src/content/operators/impls/ScrollOperatorFactoryChain.ts
@@ -0,0 +1,68 @@
+import { inject, injectable } from "tsyringe";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import ScrollPresenter from "../../presenters/ScrollPresenter";
+import SettingRepository from "../../repositories/SettingRepository";
+import * as operations from "../../../shared/operations";
+import Operator from "../Operator";
+import VerticalScrollOperator from "./VerticalScrollOperator";
+import HorizontalScrollOperator from "./HorizontalScrollOperator";
+import PageScrollOperator from "./PageScrollOperator";
+import ScrollToTopOperator from "./ScrollToTopOperator";
+import ScrollToBottomOperator from "./ScrollToBottomOperator";
+import ScrollToHomeOperator from "./ScrollToHomeOperator";
+import ScrollToEndOperator from "./ScrollToEndOperator";
+
+@injectable()
+export default class ScrollOperatorFactoryChain
+ implements OperatorFactoryChain {
+ constructor(
+ @inject("ScrollPresenter")
+ private readonly scrollPresenter: ScrollPresenter,
+ @inject("SettingRepository")
+ private readonly settingRepository: SettingRepository
+ ) {}
+
+ create(op: operations.Operation, repeat: number): Operator | null {
+ switch (op.type) {
+ case operations.SCROLL_VERTICALLY:
+ return new VerticalScrollOperator(
+ this.scrollPresenter,
+ this.settingRepository,
+ op.count * repeat
+ );
+ case operations.SCROLL_HORIZONALLY:
+ return new HorizontalScrollOperator(
+ this.scrollPresenter,
+ this.settingRepository,
+ op.count * repeat
+ );
+ case operations.SCROLL_PAGES:
+ return new PageScrollOperator(
+ this.scrollPresenter,
+ this.settingRepository,
+ op.count * repeat
+ );
+ case operations.SCROLL_TOP:
+ return new ScrollToTopOperator(
+ this.scrollPresenter,
+ this.settingRepository
+ );
+ case operations.SCROLL_BOTTOM:
+ return new ScrollToBottomOperator(
+ this.scrollPresenter,
+ this.settingRepository
+ );
+ case operations.SCROLL_HOME:
+ return new ScrollToHomeOperator(
+ this.scrollPresenter,
+ this.settingRepository
+ );
+ case operations.SCROLL_END:
+ return new ScrollToEndOperator(
+ this.scrollPresenter,
+ this.settingRepository
+ );
+ }
+ return null;
+ }
+}
diff --git a/src/content/operators/impls/ScrollToBottomOperator.ts b/src/content/operators/impls/ScrollToBottomOperator.ts
new file mode 100644
index 0000000..4db521b
--- /dev/null
+++ b/src/content/operators/impls/ScrollToBottomOperator.ts
@@ -0,0 +1,20 @@
+import AbstractScrollOperator from "./AbstractScrollOperator";
+import Operator from "../Operator";
+import ScrollPresenter from "../../presenters/ScrollPresenter";
+import SettingRepository from "../../repositories/SettingRepository";
+
+export default class ScrollToBottomOperator
+ extends AbstractScrollOperator
+ implements Operator {
+ constructor(
+ private readonly presenter: ScrollPresenter,
+ settingRepository: SettingRepository
+ ) {
+ super(settingRepository);
+ }
+
+ async run(): Promise<void> {
+ const smooth = this.getSmoothScroll();
+ this.presenter.scrollToBottom(smooth);
+ }
+}
diff --git a/src/content/operators/impls/ScrollToEndOperator.ts b/src/content/operators/impls/ScrollToEndOperator.ts
new file mode 100644
index 0000000..8217e15
--- /dev/null
+++ b/src/content/operators/impls/ScrollToEndOperator.ts
@@ -0,0 +1,20 @@
+import AbstractScrollOperator from "./AbstractScrollOperator";
+import Operator from "../Operator";
+import ScrollPresenter from "../../presenters/ScrollPresenter";
+import SettingRepository from "../../repositories/SettingRepository";
+
+export default class ScrollToEndOperator
+ extends AbstractScrollOperator
+ implements Operator {
+ constructor(
+ private readonly presenter: ScrollPresenter,
+ settingRepository: SettingRepository
+ ) {
+ super(settingRepository);
+ }
+
+ async run(): Promise<void> {
+ const smooth = this.getSmoothScroll();
+ this.presenter.scrollToEnd(smooth);
+ }
+}
diff --git a/src/content/operators/impls/ScrollToHomeOperator.ts b/src/content/operators/impls/ScrollToHomeOperator.ts
new file mode 100644
index 0000000..a0d7701
--- /dev/null
+++ b/src/content/operators/impls/ScrollToHomeOperator.ts
@@ -0,0 +1,20 @@
+import AbstractScrollOperator from "./AbstractScrollOperator";
+import Operator from "../Operator";
+import ScrollPresenter from "../../presenters/ScrollPresenter";
+import SettingRepository from "../../repositories/SettingRepository";
+
+export default class ScrollToHomeOperator
+ extends AbstractScrollOperator
+ implements Operator {
+ constructor(
+ private readonly presenter: ScrollPresenter,
+ settingRepository: SettingRepository
+ ) {
+ super(settingRepository);
+ }
+
+ async run(): Promise<void> {
+ const smooth = this.getSmoothScroll();
+ this.presenter.scrollToHome(smooth);
+ }
+}
diff --git a/src/content/operators/impls/ScrollToTopOperator.ts b/src/content/operators/impls/ScrollToTopOperator.ts
new file mode 100644
index 0000000..6075758
--- /dev/null
+++ b/src/content/operators/impls/ScrollToTopOperator.ts
@@ -0,0 +1,20 @@
+import AbstractScrollOperator from "./AbstractScrollOperator";
+import Operator from "../Operator";
+import ScrollPresenter from "../../presenters/ScrollPresenter";
+import SettingRepository from "../../repositories/SettingRepository";
+
+export default class ScrollToTopOperator
+ extends AbstractScrollOperator
+ implements Operator {
+ constructor(
+ private readonly presenter: ScrollPresenter,
+ settingRepository: SettingRepository
+ ) {
+ super(settingRepository);
+ }
+
+ async run(): Promise<void> {
+ const smooth = this.getSmoothScroll();
+ this.presenter.scrollToTop(smooth);
+ }
+}
diff --git a/src/content/operators/impls/StartFollowOperator.ts b/src/content/operators/impls/StartFollowOperator.ts
new file mode 100644
index 0000000..6f30058
--- /dev/null
+++ b/src/content/operators/impls/StartFollowOperator.ts
@@ -0,0 +1,14 @@
+import Operator from "../Operator";
+import FollowMasterClient from "../../client/FollowMasterClient";
+
+export default class StartFollowOperator implements Operator {
+ constructor(
+ private readonly followMasterClient: FollowMasterClient,
+ private readonly newTab: boolean,
+ private readonly background: boolean
+ ) {}
+
+ async run(): Promise<void> {
+ this.followMasterClient.startFollow(this.newTab, this.background);
+ }
+}
diff --git a/src/content/operators/impls/ToggleAddonOperator.ts b/src/content/operators/impls/ToggleAddonOperator.ts
new file mode 100644
index 0000000..2a249d6
--- /dev/null
+++ b/src/content/operators/impls/ToggleAddonOperator.ts
@@ -0,0 +1,16 @@
+import Operator from "../Operator";
+import AddonIndicatorClient from "../../client/AddonIndicatorClient";
+import AddonEnabledRepository from "../../repositories/AddonEnabledRepository";
+
+export default class ToggleAddonOperator implements Operator {
+ constructor(
+ private readonly indicator: AddonIndicatorClient,
+ private readonly repository: AddonEnabledRepository
+ ) {}
+
+ async run(): Promise<void> {
+ const current = this.repository.get();
+ this.repository.set(!current);
+ await this.indicator.setEnabled(!current);
+ }
+}
diff --git a/src/content/operators/impls/URLRepository.ts b/src/content/operators/impls/URLRepository.ts
new file mode 100644
index 0000000..a1efc2e
--- /dev/null
+++ b/src/content/operators/impls/URLRepository.ts
@@ -0,0 +1,9 @@
+export default interface URLRepository {
+ getCurrentURL(): string;
+}
+
+export class URLRepositoryImpl implements URLRepository {
+ getCurrentURL(): string {
+ return window.location.href;
+ }
+}
diff --git a/src/content/operators/impls/VerticalScrollOperator.ts b/src/content/operators/impls/VerticalScrollOperator.ts
new file mode 100644
index 0000000..4ab336c
--- /dev/null
+++ b/src/content/operators/impls/VerticalScrollOperator.ts
@@ -0,0 +1,21 @@
+import AbstractScrollOperator from "./AbstractScrollOperator";
+import Operator from "../Operator";
+import ScrollPresenter from "../../presenters/ScrollPresenter";
+import SettingRepository from "../../repositories/SettingRepository";
+
+export default class VerticalScrollOperator
+ extends AbstractScrollOperator
+ implements Operator {
+ constructor(
+ private readonly presenter: ScrollPresenter,
+ settingRepository: SettingRepository,
+ private readonly count: number
+ ) {
+ super(settingRepository);
+ }
+
+ async run(): Promise<void> {
+ const smooth = this.getSmoothScroll();
+ this.presenter.scrollVertically(this.count, smooth);
+ }
+}
diff --git a/src/content/operators/impls/YankURLOperator.ts b/src/content/operators/impls/YankURLOperator.ts
new file mode 100644
index 0000000..2e774eb
--- /dev/null
+++ b/src/content/operators/impls/YankURLOperator.ts
@@ -0,0 +1,18 @@
+import Operator from "../Operator";
+import ClipboardRepository from "../../repositories/ClipboardRepository";
+import ConsoleClient from "../../client/ConsoleClient";
+import URLRepository from "./URLRepository";
+
+export default class YankURLOperator implements Operator {
+ constructor(
+ private readonly repository: ClipboardRepository,
+ private readonly consoleClient: ConsoleClient,
+ private readonly urlRepository: URLRepository
+ ) {}
+
+ async run(): Promise<void> {
+ const url = this.urlRepository.getCurrentURL();
+ this.repository.write(url);
+ await this.consoleClient.info("Yanked " + url);
+ }
+}
diff --git a/src/content/presenters/ScrollPresenter.ts b/src/content/presenters/ScrollPresenter.ts
index a8b2034..508532c 100644
--- a/src/content/presenters/ScrollPresenter.ts
+++ b/src/content/presenters/ScrollPresenter.ts
@@ -31,7 +31,7 @@ const isScrollableStyle = (element: Element): boolean => {
return canBeScrolled(element);
};
-// Find a visiable and scrollable element by depth-first search. Currently
+// Find a visible and scrollable element by depth-first search. Currently
// this method is called by each scrolling, and the returned value of this
// method is not cached. That does not cause performance issue because in the
// most pages, the window is root element i,e, documentElement.
diff --git a/src/content/repositories/HintKeyRepository.ts b/src/content/repositories/HintKeyRepository.ts
new file mode 100644
index 0000000..342b003
--- /dev/null
+++ b/src/content/repositories/HintKeyRepository.ts
@@ -0,0 +1,49 @@
+export default interface HintKeyRepository {
+ reset(charset: string): void;
+
+ produce(): string;
+}
+
+const current: {
+ charset: string;
+ counter: number[];
+} = {
+ charset: "",
+ counter: [],
+};
+
+export class HintKeyRepositoryImpl implements HintKeyRepository {
+ reset(charset: string): void {
+ if (charset.length === 0) {
+ throw new TypeError("charset is empty");
+ }
+ current.charset = charset;
+ current.counter = [];
+ }
+
+ produce(): string {
+ if (current.charset === "") {
+ throw new Error("charset is not set");
+ }
+ this.increment();
+
+ return current.counter.map((x) => current.charset[x]).join("");
+ }
+
+ private increment(): void {
+ const max = current.charset.length - 1;
+ if (current.counter.every((x) => x === max)) {
+ current.counter = new Array(current.counter.length + 1).fill(0);
+ return;
+ }
+
+ current.counter.reverse();
+ const len = current.charset.length;
+ let num = current.counter.reduce((x, y, index) => x + y * len ** index) + 1;
+ for (let i = 0; i < current.counter.length; ++i) {
+ current.counter[i] = num % len;
+ num = ~~(num / len);
+ }
+ current.counter.reverse();
+ }
+}
diff --git a/src/content/usecases/ClipboardUseCase.ts b/src/content/usecases/ClipboardUseCase.ts
deleted file mode 100644
index 875fc11..0000000
--- a/src/content/usecases/ClipboardUseCase.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { injectable, inject } from "tsyringe";
-import * as urls from "../../shared/urls";
-import ClipboardRepository from "../repositories/ClipboardRepository";
-import SettingRepository from "../repositories/SettingRepository";
-import ConsoleClient from "../client/ConsoleClient";
-import OperationClient from "../client/OperationClient";
-
-@injectable()
-export default class ClipboardUseCase {
- constructor(
- @inject("ClipboardRepository") private repository: ClipboardRepository,
- @inject("SettingRepository") private settingRepository: SettingRepository,
- @inject("ConsoleClient") private consoleClient: ConsoleClient,
- @inject("OperationClient") private operationClinet: OperationClient
- ) {}
-
- async yankCurrentURL(): Promise<string> {
- const url = window.location.href;
- this.repository.write(url);
- await this.consoleClient.info("Yanked " + url);
- return Promise.resolve(url);
- }
-
- async openOrSearch(newTab: boolean): Promise<void> {
- const search = this.settingRepository.get().search;
- const text = this.repository.read();
- const url = urls.searchUrl(text, search);
-
- // TODO: Repeat pasting from clipboard instead of opening a certain url.
- // 'Repeat last' command is implemented in the background script and cannot
- // access to clipboard until Firefox 63.
- await this.operationClinet.internalOpenUrl(url, newTab);
- }
-}
diff --git a/src/content/usecases/FindSlaveUseCase.ts b/src/content/usecases/FindSlaveUseCase.ts
deleted file mode 100644
index 3b8c4b4..0000000
--- a/src/content/usecases/FindSlaveUseCase.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { injectable, inject } from "tsyringe";
-import FindMasterClient from "../client/FindMasterClient";
-
-@injectable()
-export default class FindSlaveUseCase {
- constructor(
- @inject("FindMasterClient") private findMasterClient: FindMasterClient
- ) {}
-
- findNext() {
- this.findMasterClient.findNext();
- }
-
- findPrev() {
- this.findMasterClient.findPrev();
- }
-}
diff --git a/src/content/usecases/FocusUseCase.ts b/src/content/usecases/FocusUseCase.ts
deleted file mode 100644
index 8c62003..0000000
--- a/src/content/usecases/FocusUseCase.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { injectable, inject } from "tsyringe";
-import FocusPresenter from "../presenters/FocusPresenter";
-
-@injectable()
-export default class FocusUseCases {
- constructor(@inject("FocusPresenter") private presenter: FocusPresenter) {}
-
- focusFirstInput() {
- this.presenter.focusFirstElement();
- }
-}
diff --git a/src/content/usecases/FollowMasterUseCase.ts b/src/content/usecases/FollowMasterUseCase.ts
index 88c682e..f4705e1 100644
--- a/src/content/usecases/FollowMasterUseCase.ts
+++ b/src/content/usecases/FollowMasterUseCase.ts
@@ -4,13 +4,10 @@ import FollowMasterRepository from "../repositories/FollowMasterRepository";
import FollowSlaveClient from "../client/FollowSlaveClient";
import FollowSlaveClientFactory from "../client/FollowSlaveClientFactory";
import SettingRepository from "../repositories/SettingRepository";
-import HintKeyProducer from "./HintKeyProducer";
+import HintKeyRepository from "../repositories/HintKeyRepository";
@injectable()
export default class FollowMasterUseCase {
- // TODO Make repository
- private producer: HintKeyProducer | null;
-
constructor(
@inject("FollowKeyRepository")
private followKeyRepository: FollowKeyRepository,
@@ -22,14 +19,15 @@ export default class FollowMasterUseCase {
private settingRepository: SettingRepository,
@inject("FollowSlaveClientFactory")
- private followSlaveClientFactory: FollowSlaveClientFactory
- ) {
- this.producer = null;
- }
+ private followSlaveClientFactory: FollowSlaveClientFactory,
+
+ @inject("HintKeyRepository")
+ private hintKeyRepository: HintKeyRepository
+ ) {}
startFollow(newTab: boolean, background: boolean): void {
const hintchars = this.settingRepository.get().properties.hintchars;
- this.producer = new HintKeyProducer(hintchars);
+ this.hintKeyRepository.reset(hintchars);
this.followKeyRepository.clearKeys();
this.followMasterRepository.setCurrentFollowMode(newTab, background);
@@ -59,7 +57,7 @@ export default class FollowMasterUseCase {
createSlaveHints(count: number, sender: Window): void {
const produced = [];
for (let i = 0; i < count; ++i) {
- const tag = this.producer!.produce();
+ const tag = this.hintKeyRepository.produce();
produced.push(tag);
this.followMasterRepository.addTag(tag);
}
diff --git a/src/content/usecases/HintKeyProducer.ts b/src/content/usecases/HintKeyProducer.ts
deleted file mode 100644
index a5e2877..0000000
--- a/src/content/usecases/HintKeyProducer.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-export default class HintKeyProducer {
- private charset: string;
-
- private counter: number[];
-
- constructor(charset: string) {
- if (charset.length === 0) {
- throw new TypeError("charset is empty");
- }
-
- this.charset = charset;
- this.counter = [];
- }
-
- produce(): string {
- this.increment();
-
- return this.counter.map((x) => this.charset[x]).join("");
- }
-
- private increment(): void {
- const max = this.charset.length - 1;
- if (this.counter.every((x) => x === max)) {
- this.counter = new Array(this.counter.length + 1).fill(0);
- return;
- }
-
- this.counter.reverse();
- const len = this.charset.length;
- let num = this.counter.reduce((x, y, index) => x + y * len ** index) + 1;
- for (let i = 0; i < this.counter.length; ++i) {
- this.counter[i] = num % len;
- num = ~~(num / len);
- }
- this.counter.reverse();
- }
-}
diff --git a/src/content/usecases/MarkKeyUseCase.ts b/src/content/usecases/MarkKeyUseCase.ts
index b807c74..61ed135 100644
--- a/src/content/usecases/MarkKeyUseCase.ts
+++ b/src/content/usecases/MarkKeyUseCase.ts
@@ -15,18 +15,10 @@ export default class MarkKeyUseCase {
return this.repository.isJumpMode();
}
- enableSetMode(): void {
- this.repository.enableSetMode();
- }
-
disableSetMode(): void {
this.repository.disabeSetMode();
}
- enableJumpMode(): void {
- this.repository.enableJumpMode();
- }
-
disableJumpMode(): void {
this.repository.disabeJumpMode();
}
diff --git a/src/content/usecases/ScrollUseCase.ts b/src/content/usecases/ScrollUseCase.ts
deleted file mode 100644
index 319c8b4..0000000
--- a/src/content/usecases/ScrollUseCase.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { injectable, inject } from "tsyringe";
-import ScrollPresenter from "../presenters/ScrollPresenter";
-import SettingRepository from "../repositories/SettingRepository";
-
-@injectable()
-export default class ScrollUseCase {
- constructor(
- @inject("ScrollPresenter") private presenter: ScrollPresenter,
- @inject("SettingRepository") private settingRepository: SettingRepository
- ) {}
-
- scrollVertically(count: number): void {
- const smooth = this.getSmoothScroll();
- this.presenter.scrollVertically(count, smooth);
- }
-
- scrollHorizonally(count: number): void {
- const smooth = this.getSmoothScroll();
- this.presenter.scrollHorizonally(count, smooth);
- }
-
- scrollPages(count: number): void {
- const smooth = this.getSmoothScroll();
- this.presenter.scrollPages(count, smooth);
- }
-
- scrollToTop(): void {
- const smooth = this.getSmoothScroll();
- this.presenter.scrollToTop(smooth);
- }
-
- scrollToBottom(): void {
- const smooth = this.getSmoothScroll();
- this.presenter.scrollToBottom(smooth);
- }
-
- scrollToHome(): void {
- const smooth = this.getSmoothScroll();
- this.presenter.scrollToHome(smooth);
- }
-
- scrollToEnd(): void {
- const smooth = this.getSmoothScroll();
- this.presenter.scrollToEnd(smooth);
- }
-
- private getSmoothScroll(): boolean {
- const settings = this.settingRepository.get();
- return settings.properties.smoothscroll;
- }
-}