aboutsummaryrefslogtreecommitdiff
path: root/src/background
diff options
context:
space:
mode:
authorShin'ya Ueoka <ueokande@i-beam.org>2020-11-29 16:02:57 +0900
committerShin'ya Ueoka <ueokande@i-beam.org>2020-12-09 23:09:34 +0900
commitddf912804fc4cb26d388283eacca63a0aeddf779 (patch)
treec51faed020e9b4cfd0db40bccbe37843b15fa417 /src/background
parentdcb09f7c74ff3d396431e423b0be6572c3f98955 (diff)
Make background operations as a operator
Diffstat (limited to 'src/background')
-rw-r--r--src/background/controllers/OperationController.ts116
-rw-r--r--src/background/di.ts2
-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.ts62
-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.ts36
-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.ts64
-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.ts28
-rw-r--r--src/background/operators/impls/ResetZoomOperator.ts9
-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.ts22
-rw-r--r--src/background/operators/impls/SelectTabPrevOperator.ts22
-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.ts25
-rw-r--r--src/background/operators/impls/ZoomOutOperator.ts10
46 files changed, 892 insertions, 108 deletions
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..44bf427 100644
--- a/src/background/di.ts
+++ b/src/background/di.ts
@@ -11,6 +11,7 @@ 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";
container.register("LocalSettingRepository", {
useValue: LocalSettingRepository,
@@ -26,3 +27,4 @@ container.register("HistoryRepository", { useClass: HistoryRepositoryImpl });
container.register("BookmarkRepository", { useClass: BookmarkRepositoryImpl });
container.register("TabRepository", { useClass: TabRepositoryImpl });
container.register("TabPresenter", { useClass: TabPresenterImpl });
+container.register("OperatorFactory", { useClass: OperatorFactoryImpl });
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..7432153
--- /dev/null
+++ b/src/background/operators/impls/CommandOperatorFactoryChain.ts
@@ -0,0 +1,62 @@
+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,
+ 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..607dbfa
--- /dev/null
+++ b/src/background/operators/impls/InternalOperatorFactoryChain.ts
@@ -0,0 +1,36 @@
+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(
+ private readonly windowPresenter: WindowPresenter,
+ @inject("TabPresenter")
+ private readonly tabPresenter: TabPresenter,
+ 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..d9b1619
--- /dev/null
+++ b/src/background/operators/impls/NavigateOperatorFactoryChain.ts
@@ -0,0 +1,64 @@
+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,
+ private readonly navigateClient: NavigateClient,
+ 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..9d67b75
--- /dev/null
+++ b/src/background/operators/impls/RepeatOperatorFactoryChain.ts
@@ -0,0 +1,28 @@
+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(
+ 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..66cf245
--- /dev/null
+++ b/src/background/operators/impls/ResetZoomOperator.ts
@@ -0,0 +1,9 @@
+import Operator from "../Operator";
+import ZoomUseCase from "../../usecases/ZoomUseCase";
+
+export default class ResetZoomOperator implements Operator {
+ constructor(private readonly zoomUseCase: ZoomUseCase) {}
+ run(): Promise<void> {
+ return this.zoomUseCase.zoomNutoral();
+ }
+}
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..37482fe
--- /dev/null
+++ b/src/background/operators/impls/SelectTabNextOperator.ts
@@ -0,0 +1,22 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class SelectTabNextOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly count: number
+ ) {}
+
+ 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 + this.count) % 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..93a0d6d
--- /dev/null
+++ b/src/background/operators/impls/SelectTabPrevOperator.ts
@@ -0,0 +1,22 @@
+import Operator from "../Operator";
+import TabPresenter from "../../presenters/TabPresenter";
+
+export default class SelectTabPrevOperator implements Operator {
+ constructor(
+ private readonly tabPresenter: TabPresenter,
+ private readonly count: number
+ ) {}
+
+ 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 - this.count + 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..a1752eb
--- /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 = "addookmark ";
+ 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..b4cb401
--- /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 "./SelectTabPrevOperator";
+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, 1);
+ case operations.TAB_NEXT:
+ return new SelectTabNextOperator(this.tabPresenter, 1);
+ 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..0c44c6f
--- /dev/null
+++ b/src/background/operators/impls/ZoomInOperator.ts
@@ -0,0 +1,10 @@
+import Operator from "../Operator";
+import ZoomUseCase from "../../usecases/ZoomUseCase";
+
+export default class ZoomInOperator implements Operator {
+ constructor(private readonly zoomUseCase: ZoomUseCase) {}
+
+ run(): Promise<void> {
+ return this.zoomUseCase.zoomIn();
+ }
+}
diff --git a/src/background/operators/impls/ZoomOperatorFactoryChain.ts b/src/background/operators/impls/ZoomOperatorFactoryChain.ts
new file mode 100644
index 0000000..b8858ab
--- /dev/null
+++ b/src/background/operators/impls/ZoomOperatorFactoryChain.ts
@@ -0,0 +1,25 @@
+import { injectable } from "tsyringe";
+import Operator from "../Operator";
+import OperatorFactoryChain from "../OperatorFactoryChain";
+import ZoomInOperator from "./ZoomInOperator";
+import ZoomOutOperator from "./ZoomOutOperator";
+import ResetZoomOperator from "./ResetZoomOperator";
+import ZoomUseCase from "../../usecases/ZoomUseCase";
+import * as operations from "../../../shared/operations";
+
+@injectable()
+export default class ZoomOperatorFactoryChain implements OperatorFactoryChain {
+ constructor(private readonly zoomUseCase: ZoomUseCase) {}
+
+ create(op: operations.Operation): Operator | null {
+ switch (op.type) {
+ case operations.ZOOM_IN:
+ return new ZoomInOperator(this.zoomUseCase);
+ case operations.ZOOM_OUT:
+ return new ZoomOutOperator(this.zoomUseCase);
+ case operations.ZOOM_NEUTRAL:
+ return new ResetZoomOperator(this.zoomUseCase);
+ }
+ return null;
+ }
+}
diff --git a/src/background/operators/impls/ZoomOutOperator.ts b/src/background/operators/impls/ZoomOutOperator.ts
new file mode 100644
index 0000000..7f9cb6b
--- /dev/null
+++ b/src/background/operators/impls/ZoomOutOperator.ts
@@ -0,0 +1,10 @@
+import Operator from "../Operator";
+import ZoomUseCase from "../../usecases/ZoomUseCase";
+
+export default class ZoomOutOperator implements Operator {
+ constructor(private readonly zoomUseCase: ZoomUseCase) {}
+
+ run(): Promise<void> {
+ return this.zoomUseCase.zoomOut();
+ }
+}