aboutsummaryrefslogtreecommitdiff
path: root/src/background
diff options
context:
space:
mode:
Diffstat (limited to 'src/background')
-rw-r--r--src/background/clients/NavigateClient.ts14
-rw-r--r--src/background/controllers/OperationController.ts116
-rw-r--r--src/background/di.ts16
-rw-r--r--src/background/infrastructures/ConsoleClient.ts14
-rw-r--r--src/background/operators/Operator.ts5
-rw-r--r--src/background/operators/OperatorFactory.ts6
-rw-r--r--src/background/operators/OperatorFactoryChain.ts6
-rw-r--r--src/background/operators/impls/CancelOperator.ts15
-rw-r--r--src/background/operators/impls/CloseTabOperator.ts22
-rw-r--r--src/background/operators/impls/CloseTabRightOperator.ts21
-rw-r--r--src/background/operators/impls/CommandOperatorFactoryChain.ts63
-rw-r--r--src/background/operators/impls/DuplicateTabOperator.ts11
-rw-r--r--src/background/operators/impls/InternalOpenURLOperator.ts24
-rw-r--r--src/background/operators/impls/InternalOperatorFactoryChain.ts38
-rw-r--r--src/background/operators/impls/NavigateHistoryNextOperator.ts15
-rw-r--r--src/background/operators/impls/NavigateHistoryPrevOperator.ts15
-rw-r--r--src/background/operators/impls/NavigateLinkNextOperator.ts15
-rw-r--r--src/background/operators/impls/NavigateLinkPrevOperator.ts15
-rw-r--r--src/background/operators/impls/NavigateOperatorFactoryChain.ts66
-rw-r--r--src/background/operators/impls/NavigateParentOperator.ts25
-rw-r--r--src/background/operators/impls/NavigateRootOperator.ts12
-rw-r--r--src/background/operators/impls/OpenHomeOperator.ts29
-rw-r--r--src/background/operators/impls/OpenSourceOperator.ts12
-rw-r--r--src/background/operators/impls/OperatorFactoryImpl.ts45
-rw-r--r--src/background/operators/impls/PinTabOperator.ts11
-rw-r--r--src/background/operators/impls/ReloadTabOperator.ts14
-rw-r--r--src/background/operators/impls/ReopenTabOperator.ts10
-rw-r--r--src/background/operators/impls/RepeatLastOperator.ts18
-rw-r--r--src/background/operators/impls/RepeatOperatorFactoryChain.ts29
-rw-r--r--src/background/operators/impls/ResetZoomOperator.ts10
-rw-r--r--src/background/operators/impls/SelectFirstTabOperator.ts11
-rw-r--r--src/background/operators/impls/SelectLastTabOperator.ts11
-rw-r--r--src/background/operators/impls/SelectPreviousSelectedTabOperator.ts14
-rw-r--r--src/background/operators/impls/SelectTabNextOperator.ts19
-rw-r--r--src/background/operators/impls/SelectTabPrevOperator.ts19
-rw-r--r--src/background/operators/impls/ShowAddBookmarkOperator.ts20
-rw-r--r--src/background/operators/impls/ShowBufferCommandOperator.ts16
-rw-r--r--src/background/operators/impls/ShowCommandOperator.ts15
-rw-r--r--src/background/operators/impls/ShowOpenCommandOperator.ts20
-rw-r--r--src/background/operators/impls/ShowTabOpenCommandOperator.ts20
-rw-r--r--src/background/operators/impls/ShowWinOpenCommandOperator.ts20
-rw-r--r--src/background/operators/impls/StartFindOperator.ts15
-rw-r--r--src/background/operators/impls/TabOperatorFactoryChain.ts64
-rw-r--r--src/background/operators/impls/TogglePinnedTabOperator.ts11
-rw-r--r--src/background/operators/impls/UnpinTabOperator.ts11
-rw-r--r--src/background/operators/impls/ZoomInOperator.ts10
-rw-r--r--src/background/operators/impls/ZoomOperatorFactoryChain.ts28
-rw-r--r--src/background/operators/impls/ZoomOutOperator.ts10
-rw-r--r--src/background/presenters/WindowPresenter.ts11
-rw-r--r--src/background/presenters/ZoomPresenter.ts60
-rw-r--r--src/background/repositories/BrowserSettingRepository.ts6
-rw-r--r--src/background/repositories/RepeatRepository.ts8
-rw-r--r--src/background/usecases/AddonEnabledUseCase.ts2
-rw-r--r--src/background/usecases/CommandUseCase.ts23
-rw-r--r--src/background/usecases/ConsoleUseCase.ts63
-rw-r--r--src/background/usecases/FindUseCase.ts15
-rw-r--r--src/background/usecases/MarkUseCase.ts12
-rw-r--r--src/background/usecases/NavigateUseCase.ts56
-rw-r--r--src/background/usecases/RepeatUseCase.ts7
-rw-r--r--src/background/usecases/TabSelectUseCase.ts51
-rw-r--r--src/background/usecases/TabUseCase.ts102
-rw-r--r--src/background/usecases/ZoomUseCase.ts51
62 files changed, 1040 insertions, 473 deletions
diff --git a/src/background/clients/NavigateClient.ts b/src/background/clients/NavigateClient.ts
index 40ceb45..af8688e 100644
--- a/src/background/clients/NavigateClient.ts
+++ b/src/background/clients/NavigateClient.ts
@@ -1,8 +1,16 @@
-import { injectable } from "tsyringe";
import * as messages from "../../shared/messages";
-@injectable()
-export default class NavigateClient {
+export default interface NavigateClient {
+ historyNext(tabId: number): Promise<void>;
+
+ historyPrev(tabId: number): Promise<void>;
+
+ linkNext(tabId: number): Promise<void>;
+
+ linkPrev(tabId: number): Promise<void>;
+}
+
+export class NavigateClientImpl implements NavigateClient {
async historyNext(tabId: number): Promise<void> {
await browser.tabs.sendMessage(tabId, {
type: messages.NAVIGATE_HISTORY_NEXT,
diff --git a/src/background/controllers/OperationController.ts b/src/background/controllers/OperationController.ts
index 5a7047d..d606ac0 100644
--- a/src/background/controllers/OperationController.ts
+++ b/src/background/controllers/OperationController.ts
@@ -1,23 +1,14 @@
-import { injectable } from "tsyringe";
+import { inject, injectable } from "tsyringe";
import * as operations from "../../shared/operations";
-import FindUseCase from "../usecases/FindUseCase";
-import ConsoleUseCase from "../usecases/ConsoleUseCase";
-import TabUseCase from "../usecases/TabUseCase";
-import TabSelectUseCase from "../usecases/TabSelectUseCase";
-import ZoomUseCase from "../usecases/ZoomUseCase";
-import NavigateUseCase from "../usecases/NavigateUseCase";
+import OperatorFactory from "../operators/OperatorFactory";
import RepeatUseCase from "../usecases/RepeatUseCase";
@injectable()
export default class OperationController {
constructor(
- private findUseCase: FindUseCase,
- private consoleUseCase: ConsoleUseCase,
- private tabUseCase: TabUseCase,
- private tabSelectUseCase: TabSelectUseCase,
- private zoomUseCase: ZoomUseCase,
- private navigateUseCase: NavigateUseCase,
- private repeatUseCase: RepeatUseCase
+ private readonly repeatUseCase: RepeatUseCase,
+ @inject("OperatorFactory")
+ private readonly operatorFactory: OperatorFactory
) {}
async exec(repeat: number, op: operations.Operation): Promise<any> {
@@ -27,105 +18,14 @@ export default class OperationController {
}
}
- // eslint-disable-next-line complexity, max-lines-per-function
- async doOperation(
+ private async doOperation(
repeat: number,
operation: operations.Operation
): Promise<any> {
- // eslint-disable-next-line complexity, max-lines-per-function
- const opFunc = (() => {
- switch (operation.type) {
- case operations.TAB_CLOSE:
- return () =>
- this.tabUseCase.close(false, operation.select === "left");
- case operations.TAB_CLOSE_RIGHT:
- return () => this.tabUseCase.closeRight();
- case operations.TAB_CLOSE_FORCE:
- return () => this.tabUseCase.close(true);
- case operations.TAB_REOPEN:
- return () => this.tabUseCase.reopen();
- case operations.TAB_PREV:
- return () => this.tabSelectUseCase.selectPrev(1);
- case operations.TAB_NEXT:
- return () => this.tabSelectUseCase.selectNext(1);
- case operations.TAB_FIRST:
- return () => this.tabSelectUseCase.selectFirst();
- case operations.TAB_LAST:
- return () => this.tabSelectUseCase.selectLast();
- case operations.TAB_PREV_SEL:
- return () => this.tabSelectUseCase.selectPrevSelected();
- case operations.TAB_RELOAD:
- return () => this.tabUseCase.reload(operation.cache);
- case operations.TAB_PIN:
- return () => this.tabUseCase.setPinned(true);
- case operations.TAB_UNPIN:
- return () => this.tabUseCase.setPinned(false);
- case operations.TAB_TOGGLE_PINNED:
- return () => this.tabUseCase.togglePinned();
- case operations.TAB_DUPLICATE:
- return () => this.tabUseCase.duplicate();
- case operations.PAGE_SOURCE:
- return () => this.tabUseCase.openPageSource();
- case operations.PAGE_HOME:
- return () => this.tabUseCase.openHome(operation.newTab);
- case operations.ZOOM_IN:
- return () => this.zoomUseCase.zoomIn();
- case operations.ZOOM_OUT:
- return () => this.zoomUseCase.zoomOut();
- case operations.ZOOM_NEUTRAL:
- return () => this.zoomUseCase.zoomNutoral();
- case operations.COMMAND_SHOW:
- return () => this.consoleUseCase.showCommand();
- case operations.COMMAND_SHOW_OPEN:
- return () => this.consoleUseCase.showOpenCommand(operation.alter);
- case operations.COMMAND_SHOW_TABOPEN:
- return () => this.consoleUseCase.showTabopenCommand(operation.alter);
- case operations.COMMAND_SHOW_WINOPEN:
- return () => this.consoleUseCase.showWinopenCommand(operation.alter);
- case operations.COMMAND_SHOW_BUFFER:
- return () => this.consoleUseCase.showBufferCommand();
- case operations.COMMAND_SHOW_ADDBOOKMARK:
- return () =>
- this.consoleUseCase.showAddbookmarkCommand(operation.alter);
- case operations.FIND_START:
- return () => this.findUseCase.findStart();
- case operations.CANCEL:
- return () => this.consoleUseCase.hideConsole();
- case operations.NAVIGATE_HISTORY_PREV:
- return () => this.navigateUseCase.openHistoryPrev();
- case operations.NAVIGATE_HISTORY_NEXT:
- return () => this.navigateUseCase.openHistoryNext();
- case operations.NAVIGATE_LINK_PREV:
- return () => this.navigateUseCase.openLinkPrev();
- case operations.NAVIGATE_LINK_NEXT:
- return () => this.navigateUseCase.openLinkNext();
- case operations.NAVIGATE_PARENT:
- return () => this.navigateUseCase.openParent();
- case operations.NAVIGATE_ROOT:
- return () => this.navigateUseCase.openRoot();
- case operations.REPEAT_LAST:
- return () => {
- const last = this.repeatUseCase.getLastOperation();
- if (typeof last !== "undefined") {
- return this.doOperation(1, last);
- }
- return Promise.resolve();
- };
- case operations.INTERNAL_OPEN_URL:
- return () =>
- this.tabUseCase.openURL(
- operation.url,
- operation.newTab,
- operation.newWindow
- );
- default:
- throw new Error("unknown operation: " + operation.type);
- }
- })();
-
+ const operator = this.operatorFactory.create(operation);
for (let i = 0; i < repeat; ++i) {
// eslint-disable-next-line no-await-in-loop
- await opFunc();
+ await operator.run();
}
}
}
diff --git a/src/background/di.ts b/src/background/di.ts
index 5e6ad03..efdf363 100644
--- a/src/background/di.ts
+++ b/src/background/di.ts
@@ -11,6 +11,13 @@ import HistoryRepositoryImpl from "./completion/impl/HistoryRepositoryImpl";
import BookmarkRepositoryImpl from "./completion/impl/BookmarkRepositoryImpl";
import TabRepositoryImpl from "./completion/impl/TabRepositoryImpl";
import { TabPresenterImpl } from "./presenters/TabPresenter";
+import { OperatorFactoryImpl } from "./operators/impls/OperatorFactoryImpl";
+import { NavigateClientImpl } from "./clients/NavigateClient";
+import { ConsoleClientImpl } from "./infrastructures/ConsoleClient";
+import { BrowserSettingRepositoryImpl } from "./repositories/BrowserSettingRepository";
+import { RepeatRepositoryImpl } from "./repositories/RepeatRepository";
+import { ZoomPresenterImpl } from "./presenters/ZoomPresenter";
+import { WindowPresenterImpl } from "./presenters/WindowPresenter";
container.register("LocalSettingRepository", {
useValue: LocalSettingRepository,
@@ -24,5 +31,14 @@ container.register("CachedSettingRepository", {
container.register("Notifier", { useClass: NotifierImpl });
container.register("HistoryRepository", { useClass: HistoryRepositoryImpl });
container.register("BookmarkRepository", { useClass: BookmarkRepositoryImpl });
+container.register("BrowserSettingRepository", {
+ useClass: BrowserSettingRepositoryImpl,
+});
+container.register("RepeatRepository", { useClass: RepeatRepositoryImpl });
container.register("TabRepository", { useClass: TabRepositoryImpl });
+container.register("ZoomPresenter", { useClass: ZoomPresenterImpl });
container.register("TabPresenter", { useClass: TabPresenterImpl });
+container.register("WindowPresenter", { useClass: WindowPresenterImpl });
+container.register("NavigateClient", { useClass: NavigateClientImpl });
+container.register("ConsoleClient", { useClass: ConsoleClientImpl });
+container.register("OperatorFactory", { useClass: OperatorFactoryImpl });
diff --git a/src/background/infrastructures/ConsoleClient.ts b/src/background/infrastructures/ConsoleClient.ts
index 8d0af89..2a1df5b 100644
--- a/src/background/infrastructures/ConsoleClient.ts
+++ b/src/background/infrastructures/ConsoleClient.ts
@@ -1,8 +1,20 @@
import { injectable } from "tsyringe";
import * as messages from "../../shared/messages";
+export default interface ConsoleClient {
+ showCommand(tabId: number, command: string): Promise<any>;
+
+ showFind(tabId: number): Promise<any>;
+
+ showInfo(tabId: number, message: string): Promise<any>;
+
+ showError(tabId: number, message: string): Promise<any>;
+
+ hide(tabId: number): Promise<any>;
+}
+
@injectable()
-export default class ConsoleClient {
+export class ConsoleClientImpl implements ConsoleClient {
showCommand(tabId: number, command: string): Promise<any> {
return browser.tabs.sendMessage(tabId, {
type: messages.CONSOLE_SHOW_COMMAND,
diff --git a/src/background/operators/Operator.ts b/src/background/operators/Operator.ts
new file mode 100644
index 0000000..3b1fe03
--- /dev/null
+++ b/src/background/operators/Operator.ts
@@ -0,0 +1,5 @@
+interface Operator {
+ run(): Promise<void>;
+}
+
+export default Operator;
diff --git a/src/background/operators/OperatorFactory.ts b/src/background/operators/OperatorFactory.ts
new file mode 100644
index 0000000..9a5234c
--- /dev/null
+++ b/src/background/operators/OperatorFactory.ts
@@ -0,0 +1,6 @@
+import Operator from "./Operator";
+import { Operation } from "../../shared/operations";
+
+export default interface OperatorFactory {
+ create(op: Operation): Operator;
+}
diff --git a/src/background/operators/OperatorFactoryChain.ts b/src/background/operators/OperatorFactoryChain.ts
new file mode 100644
index 0000000..046ed42
--- /dev/null
+++ b/src/background/operators/OperatorFactoryChain.ts
@@ -0,0 +1,6 @@
+import Operator from "./Operator";
+import { Operation } from "../../shared/operations";
+
+export default interface OperatorFactoryChain {
+ create(op: Operation): Operator | null;
+}
diff --git a/src/background/operators/impls/CancelOperator.ts b/src/background/operators/impls/CancelOperator.ts
new file mode 100644
index 0000000..7ab09fb
--- /dev/null
+++ b/src/background/operators/impls/CancelOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import ConsoleClient from "../../infrastructures/ConsoleClient";
+
+export default class CancelOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly consoleClient: ConsoleClient
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ return this.consoleClient.hide(tab.id as number);
+ }
+}
diff --git a/src/background/operators/impls/CloseTabOperator.ts b/src/background/operators/impls/CloseTabOperator.ts
new file mode 100644
index 0000000..5d8e80b
--- /dev/null
+++ b/src/background/operators/impls/CloseTabOperator.ts
@@ -0,0 +1,22 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class CloseTabOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly force: boolean = false,
+ private readonly selectLeft: boolean = false
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ if (!this.force && tab.pinned) {
+ return Promise.resolve();
+ }
+ if (this.selectLeft && tab.index > 0) {
+ const tabs = await this.tabPresenter.getAll();
+ await this.tabPresenter.select(tabs[tab.index - 1].id as number);
+ }
+ return this.tabPresenter.remove([tab.id as number]);
+ }
+}
diff --git a/src/background/operators/impls/CloseTabRightOperator.ts b/src/background/operators/impls/CloseTabRightOperator.ts
new file mode 100644
index 0000000..f36930e
--- /dev/null
+++ b/src/background/operators/impls/CloseTabRightOperator.ts
@@ -0,0 +1,21 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class CloseTabRightOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tabs = await this.tabPresenter.getAll();
+ tabs.sort((t1, t2) => t1.index - t2.index);
+ const index = tabs.findIndex((t) => t.active);
+ if (index < 0) {
+ return;
+ }
+ for (let i = index + 1; i < tabs.length; ++i) {
+ const tab = tabs[i];
+ if (!tab.pinned) {
+ await this.tabPresenter.remove([tab.id as number]);
+ }
+ }
+ }
+}
diff --git a/src/background/operators/impls/CommandOperatorFactoryChain.ts b/src/background/operators/impls/CommandOperatorFactoryChain.ts
new file mode 100644
index 0000000..680a384
--- /dev/null
+++ b/src/background/operators/impls/CommandOperatorFactoryChain.ts
@@ -0,0 +1,63 @@
+import { inject, injectable } from "tsyringe";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import ShowCommandOperator from "./ShowCommandOperator";
+import ShowOpenCommandOperator from "./ShowOpenCommandOperator";
+import ShowTabOpenCommandOperator from "./ShowTabOpenCommandOperator";
+import ShowWinOpenCommandOperator from "./ShowWinOpenCommandOperator";
+import ShowBufferCommandOperator from "./ShowBufferCommandOperator";
+import ShowAddBookmarkOperator from "./ShowAddBookmarkOperator";
+import TabPresenter from "../../presenters/TabPresenter";
+import ConsoleClient from "../../infrastructures/ConsoleClient";
+import * as operations from "../../../shared/operations";
+import StartFindOperator from "./StartFindOperator";
+
+@injectable()
+export default class CommandOperatorFactoryChain
+ implements OperatorFactoryChain {
+ constructor(
+ @inject("TabPresenter")
+ private readonly tabPresenter: TabPresenter,
+ @inject("ConsoleClient")
+ private readonly consoleClient: ConsoleClient
+ ) {}
+
+ create(op: operations.Operation): Operator | null {
+ switch (op.type) {
+ case operations.COMMAND_SHOW:
+ return new ShowCommandOperator(this.tabPresenter, this.consoleClient);
+ case operations.COMMAND_SHOW_OPEN:
+ return new ShowOpenCommandOperator(
+ this.tabPresenter,
+ this.consoleClient,
+ op.alter
+ );
+ case operations.COMMAND_SHOW_TABOPEN:
+ return new ShowTabOpenCommandOperator(
+ this.tabPresenter,
+ this.consoleClient,
+ op.alter
+ );
+ case operations.COMMAND_SHOW_WINOPEN:
+ return new ShowWinOpenCommandOperator(
+ this.tabPresenter,
+ this.consoleClient,
+ op.alter
+ );
+ case operations.COMMAND_SHOW_BUFFER:
+ return new ShowBufferCommandOperator(
+ this.tabPresenter,
+ this.consoleClient
+ );
+ case operations.COMMAND_SHOW_ADDBOOKMARK:
+ return new ShowAddBookmarkOperator(
+ this.tabPresenter,
+ this.consoleClient,
+ op.alter
+ );
+ case operations.FIND_START:
+ return new StartFindOperator(this.tabPresenter, this.consoleClient);
+ }
+ return null;
+ }
+}
diff --git a/src/background/operators/impls/DuplicateTabOperator.ts b/src/background/operators/impls/DuplicateTabOperator.ts
new file mode 100644
index 0000000..7737cfa
--- /dev/null
+++ b/src/background/operators/impls/DuplicateTabOperator.ts
@@ -0,0 +1,11 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class DuplicateTabOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ await this.tabPresenter.duplicate(tab.id as number);
+ }
+}
diff --git a/src/background/operators/impls/InternalOpenURLOperator.ts b/src/background/operators/impls/InternalOpenURLOperator.ts
new file mode 100644
index 0000000..6bf513b
--- /dev/null
+++ b/src/background/operators/impls/InternalOpenURLOperator.ts
@@ -0,0 +1,24 @@
+import Operator from "../Operator";
+import WindowPresenter from "../../presenters/WindowPresenter";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class InternalOpenURLOperator implements Operator {
+ constructor(
+ private readonly windowPresenter: WindowPresenter,
+ private readonly tabPresenter: TabPresenter,
+ private readonly url: string,
+ private readonly newTab?: boolean,
+ private readonly newWindow?: boolean
+ ) {}
+
+ async run(): Promise<void> {
+ if (this.newWindow) {
+ await this.windowPresenter.create(this.url);
+ } else if (this.newTab) {
+ await this.tabPresenter.create(this.url);
+ } else {
+ const tab = await this.tabPresenter.getCurrent();
+ await this.tabPresenter.open(this.url, tab.id);
+ }
+ }
+}
diff --git a/src/background/operators/impls/InternalOperatorFactoryChain.ts b/src/background/operators/impls/InternalOperatorFactoryChain.ts
new file mode 100644
index 0000000..05615f6
--- /dev/null
+++ b/src/background/operators/impls/InternalOperatorFactoryChain.ts
@@ -0,0 +1,38 @@
+import { inject, injectable } from "tsyringe";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import CancelOperator from "./CancelOperator";
+import InternalOpenURLOperator from "./InternalOpenURLOperator";
+import TabPresenter from "../../presenters/TabPresenter";
+import ConsoleClient from "../../infrastructures/ConsoleClient";
+import WindowPresenter from "../../presenters/WindowPresenter";
+import * as operations from "../../../shared/operations";
+
+@injectable()
+export default class InternalOperatorFactoryChain
+ implements OperatorFactoryChain {
+ constructor(
+ @inject("WindowPresenter")
+ private readonly windowPresenter: WindowPresenter,
+ @inject("TabPresenter")
+ private readonly tabPresenter: TabPresenter,
+ @inject("ConsoleClient")
+ private readonly consoleClient: ConsoleClient
+ ) {}
+
+ create(op: operations.Operation): Operator | null {
+ switch (op.type) {
+ case operations.CANCEL:
+ return new CancelOperator(this.tabPresenter, this.consoleClient);
+ case operations.INTERNAL_OPEN_URL:
+ return new InternalOpenURLOperator(
+ this.windowPresenter,
+ this.tabPresenter,
+ op.url,
+ op.newTab,
+ op.newWindow
+ );
+ }
+ return null;
+ }
+}
diff --git a/src/background/operators/impls/NavigateHistoryNextOperator.ts b/src/background/operators/impls/NavigateHistoryNextOperator.ts
new file mode 100644
index 0000000..b092c48
--- /dev/null
+++ b/src/background/operators/impls/NavigateHistoryNextOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import NavigateClient from "../../clients/NavigateClient";
+
+export default class NavigateHistoryNextOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly navigateClient: NavigateClient
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ await this.navigateClient.historyNext(tab.id!);
+ }
+}
diff --git a/src/background/operators/impls/NavigateHistoryPrevOperator.ts b/src/background/operators/impls/NavigateHistoryPrevOperator.ts
new file mode 100644
index 0000000..27d4ee9
--- /dev/null
+++ b/src/background/operators/impls/NavigateHistoryPrevOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import NavigateClient from "../../clients/NavigateClient";
+
+export default class NavigateHistoryPrevOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly navigateClient: NavigateClient
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ await this.navigateClient.historyPrev(tab.id!);
+ }
+}
diff --git a/src/background/operators/impls/NavigateLinkNextOperator.ts b/src/background/operators/impls/NavigateLinkNextOperator.ts
new file mode 100644
index 0000000..dbbcc45
--- /dev/null
+++ b/src/background/operators/impls/NavigateLinkNextOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import NavigateClient from "../../clients/NavigateClient";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class NavigateLinkNextOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly navigateClient: NavigateClient
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ await this.navigateClient.linkNext(tab.id!);
+ }
+}
diff --git a/src/background/operators/impls/NavigateLinkPrevOperator.ts b/src/background/operators/impls/NavigateLinkPrevOperator.ts
new file mode 100644
index 0000000..fe41ee6
--- /dev/null
+++ b/src/background/operators/impls/NavigateLinkPrevOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import NavigateClient from "../../clients/NavigateClient";
+
+export default class NavigateLinkPrevOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly navigateClient: NavigateClient
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ await this.navigateClient.linkPrev(tab.id!);
+ }
+}
diff --git a/src/background/operators/impls/NavigateOperatorFactoryChain.ts b/src/background/operators/impls/NavigateOperatorFactoryChain.ts
new file mode 100644
index 0000000..618db45
--- /dev/null
+++ b/src/background/operators/impls/NavigateOperatorFactoryChain.ts
@@ -0,0 +1,66 @@
+import { inject, injectable } from "tsyringe";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import NavigateHistoryPrevOperator from "./NavigateHistoryPrevOperator";
+import NavigateHistoryNextOperator from "./NavigateHistoryNextOperator";
+import NavigateLinkPrevOperator from "./NavigateLinkPrevOperator";
+import NavigateLinkNextOperator from "./NavigateLinkNextOperator";
+import NavigateParentOperator from "./NavigateParentOperator";
+import NavigateRootOperator from "./NavigateRootOperator";
+import OpenSourceOperator from "./OpenSourceOperator";
+import OpenHomeOperator from "./OpenHomeOperator";
+import TabPresenter from "../../presenters/TabPresenter";
+import NavigateClient from "../../clients/NavigateClient";
+import BrowserSettingRepository from "../../repositories/BrowserSettingRepository";
+import * as operations from "../../../shared/operations";
+
+@injectable()
+export default class NavigateOperatorFactoryChain
+ implements OperatorFactoryChain {
+ constructor(
+ @inject("TabPresenter")
+ private readonly tabPresenter: TabPresenter,
+ @inject("NavigateClient")
+ private readonly navigateClient: NavigateClient,
+ @inject("BrowserSettingRepository")
+ private readonly browserSettingRepository: BrowserSettingRepository
+ ) {}
+
+ create(op: operations.Operation): Operator | null {
+ switch (op.type) {
+ case operations.NAVIGATE_HISTORY_PREV:
+ return new NavigateHistoryPrevOperator(
+ this.tabPresenter,
+ this.navigateClient
+ );
+ case operations.NAVIGATE_HISTORY_NEXT:
+ return new NavigateHistoryNextOperator(
+ this.tabPresenter,
+ this.navigateClient
+ );
+ case operations.NAVIGATE_LINK_PREV:
+ return new NavigateLinkPrevOperator(
+ this.tabPresenter,
+ this.navigateClient
+ );
+ case operations.NAVIGATE_LINK_NEXT:
+ return new NavigateLinkNextOperator(
+ this.tabPresenter,
+ this.navigateClient
+ );
+ case operations.NAVIGATE_PARENT:
+ return new NavigateParentOperator(this.tabPresenter);
+ case operations.NAVIGATE_ROOT:
+ return new NavigateRootOperator(this.tabPresenter);
+ case operations.PAGE_SOURCE:
+ return new OpenSourceOperator(this.tabPresenter);
+ case operations.PAGE_HOME:
+ return new OpenHomeOperator(
+ this.tabPresenter,
+ this.browserSettingRepository,
+ op.newTab
+ );
+ }
+ return null;
+ }
+}
diff --git a/src/background/operators/impls/NavigateParentOperator.ts b/src/background/operators/impls/NavigateParentOperator.ts
new file mode 100644
index 0000000..652cfb8
--- /dev/null
+++ b/src/background/operators/impls/NavigateParentOperator.ts
@@ -0,0 +1,25 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class NavigateParentOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ const url = new URL(tab.url!);
+ if (url.hash.length > 0) {
+ url.hash = "";
+ } else if (url.search.length > 0) {
+ url.search = "";
+ } else {
+ const basenamePattern = /\/[^/]+$/;
+ const lastDirPattern = /\/[^/]+\/$/;
+ if (basenamePattern.test(url.pathname)) {
+ url.pathname = url.pathname.replace(basenamePattern, "/");
+ } else if (lastDirPattern.test(url.pathname)) {
+ url.pathname = url.pathname.replace(lastDirPattern, "/");
+ }
+ }
+ await this.tabPresenter.open(url.href);
+ }
+}
diff --git a/src/background/operators/impls/NavigateRootOperator.ts b/src/background/operators/impls/NavigateRootOperator.ts
new file mode 100644
index 0000000..b140156
--- /dev/null
+++ b/src/background/operators/impls/NavigateRootOperator.ts
@@ -0,0 +1,12 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class NavigateRootOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ const url = new URL(tab.url!);
+ await this.tabPresenter.open(url.origin);
+ }
+}
diff --git a/src/background/operators/impls/OpenHomeOperator.ts b/src/background/operators/impls/OpenHomeOperator.ts
new file mode 100644
index 0000000..4773be6
--- /dev/null
+++ b/src/background/operators/impls/OpenHomeOperator.ts
@@ -0,0 +1,29 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import BrowserSettingRepository from "../../repositories/BrowserSettingRepository";
+
+export default class OpenHomeOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly browserSettingRepository: BrowserSettingRepository,
+ private readonly newTab: boolean
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ const urls = await this.browserSettingRepository.getHomepageUrls();
+ if (urls.length === 1 && urls[0] === "about:home") {
+ // eslint-disable-next-line max-len
+ throw new Error(
+ "Cannot open Firefox Home (about:home) by WebExtensions, set your custom URLs"
+ );
+ }
+ if (urls.length === 1 && !this.newTab) {
+ await this.tabPresenter.open(urls[0], tab.id);
+ return;
+ }
+ for (const url of urls) {
+ await this.tabPresenter.create(url);
+ }
+ }
+}
diff --git a/src/background/operators/impls/OpenSourceOperator.ts b/src/background/operators/impls/OpenSourceOperator.ts
new file mode 100644
index 0000000..9185ba5
--- /dev/null
+++ b/src/background/operators/impls/OpenSourceOperator.ts
@@ -0,0 +1,12 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class OpenSourceOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ const url = "view-source:" + tab.url;
+ await this.tabPresenter.create(url);
+ }
+}
diff --git a/src/background/operators/impls/OperatorFactoryImpl.ts b/src/background/operators/impls/OperatorFactoryImpl.ts
new file mode 100644
index 0000000..34e7bb5
--- /dev/null
+++ b/src/background/operators/impls/OperatorFactoryImpl.ts
@@ -0,0 +1,45 @@
+import { inject, delay, injectable } from "tsyringe";
+import Operator from "../Operator";
+import OperatorFactory from "../OperatorFactory";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import CommandOperatorFactoryChain from "./CommandOperatorFactoryChain";
+import InternalOperatorFactoryChain from "./InternalOperatorFactoryChain";
+import NavigateOperatorFactoryChain from "./NavigateOperatorFactoryChain";
+import RepeatOperatorFactoryChain from "./RepeatOperatorFactoryChain";
+import TabOperatorFactoryChain from "./TabOperatorFactoryChain";
+import ZoomOperatorFactoryChain from "./ZoomOperatorFactoryChain";
+import * as operations from "../../../shared/operations";
+
+@injectable()
+export class OperatorFactoryImpl implements OperatorFactory {
+ private readonly factoryChains: OperatorFactoryChain[];
+
+ constructor(
+ commandOperatorFactoryChain: CommandOperatorFactoryChain,
+ internalOperatorFactoryChain: InternalOperatorFactoryChain,
+ navigateOperatorFactoryChain: NavigateOperatorFactoryChain,
+ tabOperatorFactoryChain: TabOperatorFactoryChain,
+ zoomOperatorFactoryChain: ZoomOperatorFactoryChain,
+ @inject(delay(() => RepeatOperatorFactoryChain))
+ repeatOperatorFactoryChain: RepeatOperatorFactoryChain
+ ) {
+ this.factoryChains = [
+ commandOperatorFactoryChain,
+ internalOperatorFactoryChain,
+ navigateOperatorFactoryChain,
+ repeatOperatorFactoryChain,
+ tabOperatorFactoryChain,
+ zoomOperatorFactoryChain,
+ ];
+ }
+
+ create(op: operations.Operation): Operator {
+ for (const chain of this.factoryChains) {
+ const operator = chain.create(op);
+ if (operator !== null) {
+ return operator;
+ }
+ }
+ throw new Error("unknown operation: " + op.type);
+ }
+}
diff --git a/src/background/operators/impls/PinTabOperator.ts b/src/background/operators/impls/PinTabOperator.ts
new file mode 100644
index 0000000..8121725
--- /dev/null
+++ b/src/background/operators/impls/PinTabOperator.ts
@@ -0,0 +1,11 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class PinTabOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ return this.tabPresenter.setPinned(tab.id as number, true);
+ }
+}
diff --git a/src/background/operators/impls/ReloadTabOperator.ts b/src/background/operators/impls/ReloadTabOperator.ts
new file mode 100644
index 0000000..db3389e
--- /dev/null
+++ b/src/background/operators/impls/ReloadTabOperator.ts
@@ -0,0 +1,14 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class ReloadTabOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly cache: boolean
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ return this.tabPresenter.reload(tab.id as number, this.cache);
+ }
+}
diff --git a/src/background/operators/impls/ReopenTabOperator.ts b/src/background/operators/impls/ReopenTabOperator.ts
new file mode 100644
index 0000000..507b4a8
--- /dev/null
+++ b/src/background/operators/impls/ReopenTabOperator.ts
@@ -0,0 +1,10 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class ReopenTabOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ run(): Promise<void> {
+ return this.tabPresenter.reopen();
+ }
+}
diff --git a/src/background/operators/impls/RepeatLastOperator.ts b/src/background/operators/impls/RepeatLastOperator.ts
new file mode 100644
index 0000000..d46daab
--- /dev/null
+++ b/src/background/operators/impls/RepeatLastOperator.ts
@@ -0,0 +1,18 @@
+import Operator from "../Operator";
+import RepeatRepository from "../../repositories/RepeatRepository";
+import OperatorFactory from "../OperatorFactory";
+
+export default class RepeatLastOperator implements Operator {
+ constructor(
+ private readonly repeatRepository: RepeatRepository,
+ private readonly operatorFactory: OperatorFactory
+ ) {}
+
+ run(): Promise<void> {
+ const op = this.repeatRepository.getLastOperation();
+ if (typeof op === "undefined") {
+ return Promise.resolve();
+ }
+ return this.operatorFactory.create(op).run();
+ }
+}
diff --git a/src/background/operators/impls/RepeatOperatorFactoryChain.ts b/src/background/operators/impls/RepeatOperatorFactoryChain.ts
new file mode 100644
index 0000000..5038d48
--- /dev/null
+++ b/src/background/operators/impls/RepeatOperatorFactoryChain.ts
@@ -0,0 +1,29 @@
+import { inject, injectable } from "tsyringe";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import RepeatLastOperator from "./RepeatLastOperator";
+import RepeatRepository from "../../repositories/RepeatRepository";
+import OperatorFactory from "../OperatorFactory";
+import * as operations from "../../../shared/operations";
+
+@injectable()
+export default class RepeatOperatorFactoryChain
+ implements OperatorFactoryChain {
+ constructor(
+ @inject("RepeatRepository")
+ private readonly repeatRepository: RepeatRepository,
+ @inject("OperatorFactory")
+ private readonly operatorFactory: OperatorFactory
+ ) {}
+
+ create(op: operations.Operation): Operator | null {
+ switch (op.type) {
+ case operations.REPEAT_LAST:
+ return new RepeatLastOperator(
+ this.repeatRepository,
+ this.operatorFactory
+ );
+ }
+ return null;
+ }
+}
diff --git a/src/background/operators/impls/ResetZoomOperator.ts b/src/background/operators/impls/ResetZoomOperator.ts
new file mode 100644
index 0000000..96af733
--- /dev/null
+++ b/src/background/operators/impls/ResetZoomOperator.ts
@@ -0,0 +1,10 @@
+import Operator from "../Operator";
+import ZoomPresenter from "../../presenters/ZoomPresenter";
+
+export default class ResetZoomOperator implements Operator {
+ constructor(private readonly zoomPresenter: ZoomPresenter) {}
+
+ run(): Promise<void> {
+ return this.zoomPresenter.resetZoom();
+ }
+}
diff --git a/src/background/operators/impls/SelectFirstTabOperator.ts b/src/background/operators/impls/SelectFirstTabOperator.ts
new file mode 100644
index 0000000..c04b8a9
--- /dev/null
+++ b/src/background/operators/impls/SelectFirstTabOperator.ts
@@ -0,0 +1,11 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class SelectFirstTabOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tabs = await this.tabPresenter.getAll();
+ return this.tabPresenter.select(tabs[0].id as number);
+ }
+}
diff --git a/src/background/operators/impls/SelectLastTabOperator.ts b/src/background/operators/impls/SelectLastTabOperator.ts
new file mode 100644
index 0000000..e16d406
--- /dev/null
+++ b/src/background/operators/impls/SelectLastTabOperator.ts
@@ -0,0 +1,11 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class SelectLastTabOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tabs = await this.tabPresenter.getAll();
+ return this.tabPresenter.select(tabs[tabs.length - 1].id as number);
+ }
+}
diff --git a/src/background/operators/impls/SelectPreviousSelectedTabOperator.ts b/src/background/operators/impls/SelectPreviousSelectedTabOperator.ts
new file mode 100644
index 0000000..03a778d
--- /dev/null
+++ b/src/background/operators/impls/SelectPreviousSelectedTabOperator.ts
@@ -0,0 +1,14 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class SelectPreviousSelectedTabOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tabId = await this.tabPresenter.getLastSelectedId();
+ if (tabId === null || typeof tabId === "undefined") {
+ return Promise.resolve();
+ }
+ return this.tabPresenter.select(tabId);
+ }
+}
diff --git a/src/background/operators/impls/SelectTabNextOperator.ts b/src/background/operators/impls/SelectTabNextOperator.ts
new file mode 100644
index 0000000..34d37ff
--- /dev/null
+++ b/src/background/operators/impls/SelectTabNextOperator.ts
@@ -0,0 +1,19 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class SelectTabNextOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tabs = await this.tabPresenter.getAll();
+ if (tabs.length < 2) {
+ return;
+ }
+ const tab = tabs.find((t) => t.active);
+ if (!tab) {
+ return;
+ }
+ const select = (tab.index + 1) % tabs.length;
+ return this.tabPresenter.select(tabs[select].id as number);
+ }
+}
diff --git a/src/background/operators/impls/SelectTabPrevOperator.ts b/src/background/operators/impls/SelectTabPrevOperator.ts
new file mode 100644
index 0000000..3776c1a
--- /dev/null
+++ b/src/background/operators/impls/SelectTabPrevOperator.ts
@@ -0,0 +1,19 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class SelectTabPrevOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tabs = await this.tabPresenter.getAll();
+ if (tabs.length < 2) {
+ return;
+ }
+ const tab = tabs.find((t) => t.active);
+ if (!tab) {
+ return;
+ }
+ const select = (tab.index - 1 + tabs.length) % tabs.length;
+ return this.tabPresenter.select(tabs[select].id as number);
+ }
+}
diff --git a/src/background/operators/impls/ShowAddBookmarkOperator.ts b/src/background/operators/impls/ShowAddBookmarkOperator.ts
new file mode 100644
index 0000000..cce4879
--- /dev/null
+++ b/src/background/operators/impls/ShowAddBookmarkOperator.ts
@@ -0,0 +1,20 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import ConsoleClient from "../../infrastructures/ConsoleClient";
+
+export default class ShowAddBookmarkOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly consoleClient: ConsoleClient,
+ private readonly alter: boolean
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ let command = "addbookmark ";
+ if (this.alter) {
+ command += tab.title || "";
+ }
+ return this.consoleClient.showCommand(tab.id as number, command);
+ }
+}
diff --git a/src/background/operators/impls/ShowBufferCommandOperator.ts b/src/background/operators/impls/ShowBufferCommandOperator.ts
new file mode 100644
index 0000000..e1246e4
--- /dev/null
+++ b/src/background/operators/impls/ShowBufferCommandOperator.ts
@@ -0,0 +1,16 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import ConsoleClient from "../../infrastructures/ConsoleClient";
+
+export default class ShowBufferCommandOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly consoleClient: ConsoleClient
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ const command = "buffer ";
+ return this.consoleClient.showCommand(tab.id as number, command);
+ }
+}
diff --git a/src/background/operators/impls/ShowCommandOperator.ts b/src/background/operators/impls/ShowCommandOperator.ts
new file mode 100644
index 0000000..a5e1765
--- /dev/null
+++ b/src/background/operators/impls/ShowCommandOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import ConsoleClient from "../../infrastructures/ConsoleClient";
+
+export default class ShowCommandOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly consoleClient: ConsoleClient
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ return this.consoleClient.showCommand(tab.id as number, "");
+ }
+}
diff --git a/src/background/operators/impls/ShowOpenCommandOperator.ts b/src/background/operators/impls/ShowOpenCommandOperator.ts
new file mode 100644
index 0000000..1e78e5f
--- /dev/null
+++ b/src/background/operators/impls/ShowOpenCommandOperator.ts
@@ -0,0 +1,20 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import ConsoleClient from "../../infrastructures/ConsoleClient";
+
+export default class ShowOpenCommandOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly consoleClient: ConsoleClient,
+ private readonly alter: boolean
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ let command = "open ";
+ if (this.alter) {
+ command += tab.url || "";
+ }
+ return this.consoleClient.showCommand(tab.id as number, command);
+ }
+}
diff --git a/src/background/operators/impls/ShowTabOpenCommandOperator.ts b/src/background/operators/impls/ShowTabOpenCommandOperator.ts
new file mode 100644
index 0000000..d734da1
--- /dev/null
+++ b/src/background/operators/impls/ShowTabOpenCommandOperator.ts
@@ -0,0 +1,20 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import ConsoleClient from "../../infrastructures/ConsoleClient";
+
+export default class ShowTabOpenCommandOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly consoleClient: ConsoleClient,
+ private readonly alter: boolean
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ let command = "tabopen ";
+ if (this.alter) {
+ command += tab.url || "";
+ }
+ return this.consoleClient.showCommand(tab.id as number, command);
+ }
+}
diff --git a/src/background/operators/impls/ShowWinOpenCommandOperator.ts b/src/background/operators/impls/ShowWinOpenCommandOperator.ts
new file mode 100644
index 0000000..3c5e639
--- /dev/null
+++ b/src/background/operators/impls/ShowWinOpenCommandOperator.ts
@@ -0,0 +1,20 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import ConsoleClient from "../../infrastructures/ConsoleClient";
+
+export default class ShowWinOpenCommandOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly consoleClient: ConsoleClient,
+ private readonly alter: boolean
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ let command = "winopen ";
+ if (this.alter) {
+ command += tab.url || "";
+ }
+ return this.consoleClient.showCommand(tab.id as number, command);
+ }
+}
diff --git a/src/background/operators/impls/StartFindOperator.ts b/src/background/operators/impls/StartFindOperator.ts
new file mode 100644
index 0000000..284ac9b
--- /dev/null
+++ b/src/background/operators/impls/StartFindOperator.ts
@@ -0,0 +1,15 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import ConsoleClient from "../../infrastructures/ConsoleClient";
+
+export default class StartFindOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly consoleClient: ConsoleClient
+ ) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ return this.consoleClient.showFind(tab.id as number);
+ }
+}
diff --git a/src/background/operators/impls/TabOperatorFactoryChain.ts b/src/background/operators/impls/TabOperatorFactoryChain.ts
new file mode 100644
index 0000000..edd3eaf
--- /dev/null
+++ b/src/background/operators/impls/TabOperatorFactoryChain.ts
@@ -0,0 +1,64 @@
+import { inject, injectable } from "tsyringe";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import * as operations from "../../../shared/operations";
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+import CloseTabOperator from "./CloseTabOperator";
+import CloseTabRightOperator from "./CloseTabRightOperator";
+import ReopenTabOperator from "./ReopenTabOperator";
+import SelectTabPrevOperator from "./SelectTabPrevOperator";
+import SelectTabNextOperator from "./SelectTabNextOperator";
+import SelectFirstTabOperator from "./SelectFirstTabOperator";
+import SelectLastTabOperator from "./SelectLastTabOperator";
+import SelectPreviousSelectedTabOperator from "./SelectPreviousSelectedTabOperator";
+import ReloadTabOperator from "./ReloadTabOperator";
+import PinTabOperator from "./PinTabOperator";
+import UnpinTabOperator from "./UnpinTabOperator";
+import TogglePinnedTabOperator from "./TogglePinnedTabOperator";
+import DuplicateTabOperator from "./DuplicateTabOperator";
+
+@injectable()
+export default class TabOperatorFactoryChain implements OperatorFactoryChain {
+ constructor(
+ @inject("TabPresenter")
+ private readonly tabPresenter: TabPresenter
+ ) {}
+
+ create(op: operations.Operation): Operator | null {
+ switch (op.type) {
+ case operations.TAB_CLOSE:
+ return new CloseTabOperator(
+ this.tabPresenter,
+ false,
+ op.select === "left"
+ );
+ case operations.TAB_CLOSE_RIGHT:
+ return new CloseTabRightOperator(this.tabPresenter);
+ case operations.TAB_CLOSE_FORCE:
+ return new CloseTabOperator(this.tabPresenter, true, false);
+ case operations.TAB_REOPEN:
+ return new ReopenTabOperator(this.tabPresenter);
+ case operations.TAB_PREV:
+ return new SelectTabPrevOperator(this.tabPresenter);
+ case operations.TAB_NEXT:
+ return new SelectTabNextOperator(this.tabPresenter);
+ case operations.TAB_FIRST:
+ return new SelectFirstTabOperator(this.tabPresenter);
+ case operations.TAB_LAST:
+ return new SelectLastTabOperator(this.tabPresenter);
+ case operations.TAB_PREV_SEL:
+ return new SelectPreviousSelectedTabOperator(this.tabPresenter);
+ case operations.TAB_RELOAD:
+ return new ReloadTabOperator(this.tabPresenter, op.cache);
+ case operations.TAB_PIN:
+ return new PinTabOperator(this.tabPresenter);
+ case operations.TAB_UNPIN:
+ return new UnpinTabOperator(this.tabPresenter);
+ case operations.TAB_TOGGLE_PINNED:
+ return new TogglePinnedTabOperator(this.tabPresenter);
+ case operations.TAB_DUPLICATE:
+ return new DuplicateTabOperator(this.tabPresenter);
+ }
+ return null;
+ }
+}
diff --git a/src/background/operators/impls/TogglePinnedTabOperator.ts b/src/background/operators/impls/TogglePinnedTabOperator.ts
new file mode 100644
index 0000000..c4fd4ba
--- /dev/null
+++ b/src/background/operators/impls/TogglePinnedTabOperator.ts
@@ -0,0 +1,11 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class TogglePinnedTabOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ return this.tabPresenter.setPinned(tab.id as number, !tab.pinned);
+ }
+}
diff --git a/src/background/operators/impls/UnpinTabOperator.ts b/src/background/operators/impls/UnpinTabOperator.ts
new file mode 100644
index 0000000..fa50145
--- /dev/null
+++ b/src/background/operators/impls/UnpinTabOperator.ts
@@ -0,0 +1,11 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class UnpinTabOperator implements Operator {
+ constructor(private readonly tabPresenter: TabPresenter) {}
+
+ async run(): Promise<void> {
+ const tab = await this.tabPresenter.getCurrent();
+ return this.tabPresenter.setPinned(tab.id as number, false);
+ }
+}
diff --git a/src/background/operators/impls/ZoomInOperator.ts b/src/background/operators/impls/ZoomInOperator.ts
new file mode 100644
index 0000000..e900f0d
--- /dev/null
+++ b/src/background/operators/impls/ZoomInOperator.ts
@@ -0,0 +1,10 @@
+import Operator from "../Operator";
+import ZoomPresenter from "../../presenters/ZoomPresenter";
+
+export default class ZoomInOperator implements Operator {
+ constructor(private readonly zoomPresenter: ZoomPresenter) {}
+
+ run(): Promise<void> {
+ return this.zoomPresenter.zoomIn();
+ }
+}
diff --git a/src/background/operators/impls/ZoomOperatorFactoryChain.ts b/src/background/operators/impls/ZoomOperatorFactoryChain.ts
new file mode 100644
index 0000000..bf930a7
--- /dev/null
+++ b/src/background/operators/impls/ZoomOperatorFactoryChain.ts
@@ -0,0 +1,28 @@
+import { inject, injectable } from "tsyringe";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import ZoomInOperator from "./ZoomInOperator";
+import ZoomOutOperator from "./ZoomOutOperator";
+import ResetZoomOperator from "./ResetZoomOperator";
+import ZoomPresenter from "../../presenters/ZoomPresenter";
+import * as operations from "../../../shared/operations";
+
+@injectable()
+export default class ZoomOperatorFactoryChain implements OperatorFactoryChain {
+ constructor(
+ @inject("ZoomPresenter")
+ private readonly zoomPresenter: ZoomPresenter
+ ) {}
+
+ create(op: operations.Operation): Operator | null {
+ switch (op.type) {
+ case operations.ZOOM_IN:
+ return new ZoomInOperator(this.zoomPresenter);
+ case operations.ZOOM_OUT:
+ return new ZoomOutOperator(this.zoomPresenter);
+ case operations.ZOOM_NEUTRAL:
+ return new ResetZoomOperator(this.zoomPresenter);
+ }
+ return null;
+ }
+}
diff --git a/src/background/operators/impls/ZoomOutOperator.ts b/src/background/operators/impls/ZoomOutOperator.ts
new file mode 100644
index 0000000..0c0389e
--- /dev/null
+++ b/src/background/operators/impls/ZoomOutOperator.ts
@@ -0,0 +1,10 @@
+import Operator from "../Operator";
+import ZoomPresenter from "../../presenters/ZoomPresenter";
+
+export default class ZoomOutOperator implements Operator {
+ constructor(private readonly zoomPresenter: ZoomPresenter) {}
+
+ run(): Promise<void> {
+ return this.zoomPresenter.zoomOut();
+ }
+}
diff --git a/src/background/presenters/WindowPresenter.ts b/src/background/presenters/WindowPresenter.ts
index 4f37f5d..5eb0f22 100644
--- a/src/background/presenters/WindowPresenter.ts
+++ b/src/background/presenters/WindowPresenter.ts
@@ -1,8 +1,9 @@
-import { injectable } from "tsyringe";
+export default interface WindowPresenter {
+ create(url: string): Promise<void>;
+}
-@injectable()
-export default class WindowPresenter {
- create(url: string): Promise<browser.windows.Window> {
- return browser.windows.create({ url });
+export class WindowPresenterImpl implements WindowPresenter {
+ async create(url: string): Promise<void> {
+ await browser.windows.create({ url });
}
}
diff --git a/src/background/presenters/ZoomPresenter.ts b/src/background/presenters/ZoomPresenter.ts
new file mode 100644
index 0000000..5a3c64d
--- /dev/null
+++ b/src/background/presenters/ZoomPresenter.ts
@@ -0,0 +1,60 @@
+const ZOOM_SETTINGS = [
+ 0.33,
+ 0.5,
+ 0.66,
+ 0.75,
+ 0.8,
+ 0.9,
+ 1.0,
+ 1.1,
+ 1.25,
+ 1.5,
+ 1.75,
+ 2.0,
+ 2.5,
+ 3.0,
+] as const;
+
+export default interface ZoomPresenter {
+ zoomIn(): Promise<void>;
+ zoomOut(): Promise<void>;
+ resetZoom(): Promise<void>;
+}
+
+export class ZoomPresenterImpl implements ZoomPresenter {
+ async zoomIn(): Promise<void> {
+ const tab = await browser.tabs.query({
+ active: true,
+ currentWindow: true,
+ });
+ const tabId = tab[0].id as number;
+ const current = await browser.tabs.getZoom(tabId);
+ const factor = ZOOM_SETTINGS.find((f) => f > current);
+ if (factor) {
+ return browser.tabs.setZoom(tabId, factor);
+ }
+ }
+
+ async zoomOut(): Promise<void> {
+ const tab = await browser.tabs.query({
+ active: true,
+ currentWindow: true,
+ });
+ const tabId = tab[0].id as number;
+ const current = await browser.tabs.getZoom(tabId);
+ const factor = ZOOM_SETTINGS.slice(0)
+ .reverse()
+ .find((f) => f < current);
+ if (factor) {
+ return browser.tabs.setZoom(tabId, factor);
+ }
+ }
+
+ async resetZoom(): Promise<void> {
+ const tab = await browser.tabs.query({
+ active: true,
+ currentWindow: true,
+ });
+ return browser.tabs.setZoom(tab[0].id, 1);
+ }
+}
diff --git a/src/background/repositories/BrowserSettingRepository.ts b/src/background/repositories/BrowserSettingRepository.ts
index e24874b..1dde190 100644
--- a/src/background/repositories/BrowserSettingRepository.ts
+++ b/src/background/repositories/BrowserSettingRepository.ts
@@ -1,8 +1,12 @@
import { injectable } from "tsyringe";
import * as urls from "../../shared/urls";
+export default interface BrowserSettingRepository {
+ getHomepageUrls(): Promise<string[]>;
+}
+
@injectable()
-export default class BrowserSettingRepository {
+export class BrowserSettingRepositoryImpl implements BrowserSettingRepository {
async getHomepageUrls(): Promise<string[]> {
const { value } = await browser.browserSettings.homepageOverride.get({});
return value.split("|").map(urls.normalizeUrl);
diff --git a/src/background/repositories/RepeatRepository.ts b/src/background/repositories/RepeatRepository.ts
index e3ab43d..00098d3 100644
--- a/src/background/repositories/RepeatRepository.ts
+++ b/src/background/repositories/RepeatRepository.ts
@@ -4,8 +4,14 @@ import MemoryStorage from "../infrastructures/MemoryStorage";
const REPEAT_KEY = "repeat";
+export default interface RepeatRepository {
+ getLastOperation(): Operation | undefined;
+
+ setLastOperation(op: Operation): void;
+}
+
@injectable()
-export default class RepeatRepository {
+export class RepeatRepositoryImpl implements RepeatRepository {
private cache: MemoryStorage;
constructor() {
diff --git a/src/background/usecases/AddonEnabledUseCase.ts b/src/background/usecases/AddonEnabledUseCase.ts
index f563ab0..f9bafde 100644
--- a/src/background/usecases/AddonEnabledUseCase.ts
+++ b/src/background/usecases/AddonEnabledUseCase.ts
@@ -22,7 +22,7 @@ export default class AddonEnabledUseCase {
return this.indicatorPresentor.indicate(enabled);
}
- onIndicatorClick(tabId: number): Promise<void> {
+ private onIndicatorClick(tabId: number): Promise<void> {
return this.contentMessageClient.toggleAddonEnabled(tabId);
}
diff --git a/src/background/usecases/CommandUseCase.ts b/src/background/usecases/CommandUseCase.ts
index 811ec77..18ddd4d 100644
--- a/src/background/usecases/CommandUseCase.ts
+++ b/src/background/usecases/CommandUseCase.ts
@@ -12,17 +12,20 @@ import ContentMessageClient from "../infrastructures/ContentMessageClient";
import RepeatUseCase from "../usecases/RepeatUseCase";
@injectable()
-export default class CommandIndicator {
+export default class CommandUseCase {
constructor(
- @inject("TabPresenter") private tabPresenter: TabPresenter,
- private windowPresenter: WindowPresenter,
- private helpPresenter: HelpPresenter,
+ @inject("TabPresenter")
+ private readonly tabPresenter: TabPresenter,
+ @inject("WindowPresenter")
+ private readonly windowPresenter: WindowPresenter,
+ private readonly helpPresenter: HelpPresenter,
@inject("CachedSettingRepository")
- private cachedSettingRepository: CachedSettingRepository,
- private bookmarkRepository: BookmarkRepository,
- private consoleClient: ConsoleClient,
- private contentMessageClient: ContentMessageClient,
- private repeatUseCase: RepeatUseCase
+ private readonly cachedSettingRepository: CachedSettingRepository,
+ private readonly bookmarkRepository: BookmarkRepository,
+ @inject("ConsoleClient")
+ private readonly consoleClient: ConsoleClient,
+ private readonly contentMessageClient: ContentMessageClient,
+ private readonly repeatUseCase: RepeatUseCase
) {}
async open(keywords: string): Promise<browser.tabs.Tab> {
@@ -44,7 +47,7 @@ export default class CommandIndicator {
return this.tabPresenter.create(url);
}
- async winopen(keywords: string): Promise<browser.windows.Window> {
+ async winopen(keywords: string): Promise<void> {
const url = await this.urlOrSearch(keywords);
this.repeatUseCase.storeLastOperation({
type: operations.INTERNAL_OPEN_URL,
diff --git a/src/background/usecases/ConsoleUseCase.ts b/src/background/usecases/ConsoleUseCase.ts
deleted file mode 100644
index 195c70f..0000000
--- a/src/background/usecases/ConsoleUseCase.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { inject, injectable } from "tsyringe";
-import TabPresenter from "../presenters/TabPresenter";
-import ConsoleClient from "../infrastructures/ConsoleClient";
-
-@injectable()
-export default class ConsoleUseCase {
- constructor(
- @inject("TabPresenter") private tabPresenter: TabPresenter,
- private consoleClient: ConsoleClient
- ) {}
-
- async showCommand(): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- return this.consoleClient.showCommand(tab.id as number, "");
- }
-
- async showOpenCommand(alter: boolean): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- let command = "open ";
- if (alter) {
- command += tab.url || "";
- }
- return this.consoleClient.showCommand(tab.id as number, command);
- }
-
- async showTabopenCommand(alter: boolean): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- let command = "tabopen ";
- if (alter) {
- command += tab.url || "";
- }
- return this.consoleClient.showCommand(tab.id as number, command);
- }
-
- async showWinopenCommand(alter: boolean): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- let command = "winopen ";
- if (alter) {
- command += tab.url || "";
- }
- return this.consoleClient.showCommand(tab.id as number, command);
- }
-
- async showBufferCommand(): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- const command = "buffer ";
- return this.consoleClient.showCommand(tab.id as number, command);
- }
-
- async showAddbookmarkCommand(alter: boolean): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- let command = "addbookmark ";
- if (alter) {
- command += tab.title || "";
- }
- return this.consoleClient.showCommand(tab.id as number, command);
- }
-
- async hideConsole(): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- return this.consoleClient.hide(tab.id as number);
- }
-}
diff --git a/src/background/usecases/FindUseCase.ts b/src/background/usecases/FindUseCase.ts
index facc461..ce96e03 100644
--- a/src/background/usecases/FindUseCase.ts
+++ b/src/background/usecases/FindUseCase.ts
@@ -1,15 +1,9 @@
-import { inject, injectable } from "tsyringe";
+import { injectable } from "tsyringe";
import FindRepository from "../repositories/FindRepository";
-import TabPresenter from "../presenters/TabPresenter";
-import ConsoleClient from "../infrastructures/ConsoleClient";
@injectable()
export default class FindUseCase {
- constructor(
- @inject("TabPresenter") private tabPresenter: TabPresenter,
- private findRepository: FindRepository,
- private consoleClient: ConsoleClient
- ) {}
+ constructor(private readonly findRepository: FindRepository) {}
getKeyword(): Promise<string> {
return this.findRepository.getKeyword();
@@ -18,9 +12,4 @@ export default class FindUseCase {
setKeyword(keyword: string): Promise<any> {
return this.findRepository.setKeyword(keyword);
}
-
- async findStart(): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- return this.consoleClient.showFind(tab.id as number);
- }
}
diff --git a/src/background/usecases/MarkUseCase.ts b/src/background/usecases/MarkUseCase.ts
index 9da9a21..57e04b4 100644
--- a/src/background/usecases/MarkUseCase.ts
+++ b/src/background/usecases/MarkUseCase.ts
@@ -1,16 +1,18 @@
import { inject, injectable } from "tsyringe";
import TabPresenter from "../presenters/TabPresenter";
import MarkRepository from "../repositories/MarkRepository";
-import ConsoleClient from "../infrastructures/ConsoleClient";
import ContentMessageClient from "../infrastructures/ContentMessageClient";
+import ConsoleClient from "../infrastructures/ConsoleClient";
@injectable()
export default class MarkUseCase {
constructor(
- @inject("TabPresenter") private tabPresenter: TabPresenter,
- private markRepository: MarkRepository,
- private consoleClient: ConsoleClient,
- private contentMessageClient: ContentMessageClient
+ @inject("TabPresenter")
+ private readonly tabPresenter: TabPresenter,
+ private readonly markRepository: MarkRepository,
+ @inject("ConsoleClient")
+ private readonly consoleClient: ConsoleClient,
+ private readonly contentMessageClient: ContentMessageClient
) {}
async setGlobal(key: string, x: number, y: number): Promise<any> {
diff --git a/src/background/usecases/NavigateUseCase.ts b/src/background/usecases/NavigateUseCase.ts
deleted file mode 100644
index 974606c..0000000
--- a/src/background/usecases/NavigateUseCase.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { inject, injectable } from "tsyringe";
-import NavigateClient from "../clients/NavigateClient";
-import TabPresenter from "../presenters/TabPresenter";
-
-@injectable()
-export default class NavigateUseCase {
- constructor(
- @inject("TabPresenter") private tabPresenter: TabPresenter,
- private navigateClient: NavigateClient
- ) {}
-
- async openHistoryNext(): Promise<void> {
- const tab = await this.tabPresenter.getCurrent();
- await this.navigateClient.historyNext(tab.id!);
- }
-
- async openHistoryPrev(): Promise<void> {
- const tab = await this.tabPresenter.getCurrent();
- await this.navigateClient.historyPrev(tab.id!);
- }
-
- async openLinkNext(): Promise<void> {
- const tab = await this.tabPresenter.getCurrent();
- await this.navigateClient.linkNext(tab.id!);
- }
-
- async openLinkPrev(): Promise<void> {
- const tab = await this.tabPresenter.getCurrent();
- await this.navigateClient.linkPrev(tab.id!);
- }
-
- async openParent(): Promise<void> {
- const tab = await this.tabPresenter.getCurrent();
- const url = new URL(tab.url!);
- if (url.hash.length > 0) {
- url.hash = "";
- } else if (url.search.length > 0) {
- url.search = "";
- } else {
- const basenamePattern = /\/[^/]+$/;
- const lastDirPattern = /\/[^/]+\/$/;
- if (basenamePattern.test(url.pathname)) {
- url.pathname = url.pathname.replace(basenamePattern, "/");
- } else if (lastDirPattern.test(url.pathname)) {
- url.pathname = url.pathname.replace(lastDirPattern, "/");
- }
- }
- await this.tabPresenter.open(url.href);
- }
-
- async openRoot(): Promise<void> {
- const tab = await this.tabPresenter.getCurrent();
- const url = new URL(tab.url!);
- await this.tabPresenter.open(url.origin);
- }
-}
diff --git a/src/background/usecases/RepeatUseCase.ts b/src/background/usecases/RepeatUseCase.ts
index d7235ee..992e76b 100644
--- a/src/background/usecases/RepeatUseCase.ts
+++ b/src/background/usecases/RepeatUseCase.ts
@@ -1,4 +1,4 @@
-import { injectable } from "tsyringe";
+import { inject, injectable } from "tsyringe";
import * as operations from "../../shared/operations";
import RepeatRepository from "../repositories/RepeatRepository";
@@ -6,7 +6,10 @@ type Operation = operations.Operation;
@injectable()
export default class RepeatUseCase {
- constructor(private repeatRepository: RepeatRepository) {}
+ constructor(
+ @inject("RepeatRepository")
+ private readonly repeatRepository: RepeatRepository
+ ) {}
storeLastOperation(op: Operation): void {
this.repeatRepository.setLastOperation(op);
diff --git a/src/background/usecases/TabSelectUseCase.ts b/src/background/usecases/TabSelectUseCase.ts
deleted file mode 100644
index 663ceb8..0000000
--- a/src/background/usecases/TabSelectUseCase.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { inject, injectable } from "tsyringe";
-import TabPresenter from "../presenters/TabPresenter";
-
-@injectable()
-export default class TabSelectUseCase {
- constructor(@inject("TabPresenter") private tabPresenter: TabPresenter) {}
-
- async selectPrev(count: number): Promise<any> {
- const tabs = await this.tabPresenter.getAll();
- if (tabs.length < 2) {
- return;
- }
- const tab = tabs.find((t) => t.active);
- if (!tab) {
- return;
- }
- const select = (tab.index - count + tabs.length) % tabs.length;
- return this.tabPresenter.select(tabs[select].id as number);
- }
-
- async selectNext(count: number): Promise<any> {
- const tabs = await this.tabPresenter.getAll();
- if (tabs.length < 2) {
- return;
- }
- const tab = tabs.find((t) => t.active);
- if (!tab) {
- return;
- }
- const select = (tab.index + count) % tabs.length;
- return this.tabPresenter.select(tabs[select].id as number);
- }
-
- async selectFirst(): Promise<any> {
- const tabs = await this.tabPresenter.getAll();
- return this.tabPresenter.select(tabs[0].id as number);
- }
-
- async selectLast(): Promise<any> {
- const tabs = await this.tabPresenter.getAll();
- return this.tabPresenter.select(tabs[tabs.length - 1].id as number);
- }
-
- async selectPrevSelected(): Promise<any> {
- const tabId = await this.tabPresenter.getLastSelectedId();
- if (tabId === null || typeof tabId === "undefined") {
- return Promise.resolve();
- }
- return this.tabPresenter.select(tabId);
- }
-}
diff --git a/src/background/usecases/TabUseCase.ts b/src/background/usecases/TabUseCase.ts
deleted file mode 100644
index 1439107..0000000
--- a/src/background/usecases/TabUseCase.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-import { inject, injectable } from "tsyringe";
-import TabPresenter from "../presenters/TabPresenter";
-import WindowPresenter from "../presenters/WindowPresenter";
-import BrowserSettingRepository from "../repositories/BrowserSettingRepository";
-
-@injectable()
-export default class TabUseCase {
- constructor(
- @inject("TabPresenter") private tabPresenter: TabPresenter,
- private windowPresenter: WindowPresenter,
- private browserSettingRepository: BrowserSettingRepository
- ) {}
-
- async close(force: boolean, selectLeft = false): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- if (!force && tab.pinned) {
- return Promise.resolve();
- }
- if (selectLeft && tab.index > 0) {
- const tabs = await this.tabPresenter.getAll();
- await this.tabPresenter.select(tabs[tab.index - 1].id as number);
- }
- return this.tabPresenter.remove([tab.id as number]);
- }
-
- async closeRight(): Promise<any> {
- const tabs = await this.tabPresenter.getAll();
- tabs.sort((t1, t2) => t1.index - t2.index);
- const index = tabs.findIndex((t) => t.active);
- if (index < 0) {
- return;
- }
- for (let i = index + 1; i < tabs.length; ++i) {
- const tab = tabs[i];
- if (!tab.pinned) {
- this.tabPresenter.remove([tab.id as number]);
- }
- }
- }
-
- reopen(): Promise<any> {
- return this.tabPresenter.reopen();
- }
-
- async reload(cache: boolean): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- return this.tabPresenter.reload(tab.id as number, cache);
- }
-
- async setPinned(pinned: boolean): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- return this.tabPresenter.setPinned(tab.id as number, pinned);
- }
-
- async togglePinned(): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- return this.tabPresenter.setPinned(tab.id as number, !tab.pinned);
- }
-
- async duplicate(): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- return this.tabPresenter.duplicate(tab.id as number);
- }
-
- async openPageSource(): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- const url = "view-source:" + tab.url;
- return this.tabPresenter.create(url);
- }
-
- async openHome(newTab: boolean): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- const urls = await this.browserSettingRepository.getHomepageUrls();
- if (urls.length === 1 && urls[0] === "about:home") {
- // eslint-disable-next-line max-len
- throw new Error(
- "Cannot open Firefox Home (about:home) by WebExtensions, set your custom URLs"
- );
- }
- if (urls.length === 1 && !newTab) {
- return this.tabPresenter.open(urls[0], tab.id);
- }
- for (const url of urls) {
- this.tabPresenter.create(url);
- }
- }
-
- async openURL(
- url: string,
- newTab?: boolean,
- newWindow?: boolean
- ): Promise<void> {
- if (newWindow) {
- await this.windowPresenter.create(url);
- } else if (newTab) {
- await this.tabPresenter.create(url);
- } else {
- const tab = await this.tabPresenter.getCurrent();
- await this.tabPresenter.open(url, tab.id);
- }
- }
-}
diff --git a/src/background/usecases/ZoomUseCase.ts b/src/background/usecases/ZoomUseCase.ts
deleted file mode 100644
index 173e4d7..0000000
--- a/src/background/usecases/ZoomUseCase.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { inject, injectable } from "tsyringe";
-import TabPresenter from "../presenters/TabPresenter";
-
-const ZOOM_SETTINGS: number[] = [
- 0.33,
- 0.5,
- 0.66,
- 0.75,
- 0.8,
- 0.9,
- 1.0,
- 1.1,
- 1.25,
- 1.5,
- 1.75,
- 2.0,
- 2.5,
- 3.0,
-];
-
-@injectable()
-export default class ZoomUseCase {
- constructor(@inject("TabPresenter") private tabPresenter: TabPresenter) {}
-
- async zoomIn(): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- const tabId = tab.id as number;
- const current = await this.tabPresenter.getZoom(tabId);
- const factor = ZOOM_SETTINGS.find((f) => f > current);
- if (factor) {
- return this.tabPresenter.setZoom(tabId as number, factor);
- }
- }
-
- async zoomOut(): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- const tabId = tab.id as number;
- const current = await this.tabPresenter.getZoom(tabId);
- const factor = ZOOM_SETTINGS.slice(0)
- .reverse()
- .find((f) => f < current);
- if (factor) {
- return this.tabPresenter.setZoom(tabId as number, factor);
- }
- }
-
- async zoomNutoral(): Promise<any> {
- const tab = await this.tabPresenter.getCurrent();
- return this.tabPresenter.setZoom(tab.id as number, 1);
- }
-}