diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2020-11-29 16:02:57 +0900 |
---|---|---|
committer | Shin'ya Ueoka <ueokande@i-beam.org> | 2020-12-09 23:09:34 +0900 |
commit | ddf912804fc4cb26d388283eacca63a0aeddf779 (patch) | |
tree | c51faed020e9b4cfd0db40bccbe37843b15fa417 /src/background | |
parent | dcb09f7c74ff3d396431e423b0be6572c3f98955 (diff) |
Make background operations as a operator
Diffstat (limited to 'src/background')
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(); + } +} |