diff options
Diffstat (limited to 'src/background/operators')
4 files changed, 235 insertions, 0 deletions
diff --git a/src/background/operators/impls/FindNextOperator.ts b/src/background/operators/impls/FindNextOperator.ts new file mode 100644 index 0000000..99f1759 --- /dev/null +++ b/src/background/operators/impls/FindNextOperator.ts @@ -0,0 +1,91 @@ +import Operator from "../Operator"; +import TabPresenter from "../../presenters/TabPresenter"; +import FindRepository from "../../repositories/FindRepository"; +import FindClient from "../../clients/FindClient"; +import ConsoleClient from "../../infrastructures/ConsoleClient"; +import ReadyFrameRepository from "../../repositories/ReadyFrameRepository"; + +export default class FindNextOperator implements Operator { + constructor( + private readonly tabPresenter: TabPresenter, + private readonly findRepository: FindRepository, + private readonly findClient: FindClient, + private readonly consoleClient: ConsoleClient, + private readonly frameRepository: ReadyFrameRepository + ) {} + + async run(): Promise<void> { + const tab = await this.tabPresenter.getCurrent(); + const tabId = tab?.id; + if (tabId == null) { + return; + } + + const frameIds = await this.frameRepository.getFrameIds(tabId); + if (typeof frameIds === "undefined") { + // No frames are ready + return; + } + + const state = await this.findRepository.getLocalState(tabId); + if (state) { + const framePos = frameIds.indexOf(state.frameId); + if (framePos !== -1) { + // Start to find the keyword from the current frame which last found on, + // and concat it to end of frame ids to perform a wrap-search + // + // ,- keyword should be in this frame + // | + // [100, 101, 0, 100] + // | + // `- continue from frame id 100 + // + const targetFrameIds = frameIds + .slice(framePos) + .concat(frameIds.slice(0, framePos), frameIds[framePos]); + + for (const frameId of targetFrameIds) { + const found = await this.findClient.findNext( + tabId, + frameId, + state.keyword + ); + if (found) { + this.findRepository.setLocalState(tabId, { + keyword: state.keyword, + frameId, + }); + return; + } + this.findClient.clearSelection(tabId, frameId); + } + + // The keyword is gone. + this.consoleClient.showError( + tabId, + "Pattern not found: " + state.keyword + ); + return; + } + } + + const keyword = await this.findRepository.getGlobalKeyword(); + if (keyword) { + for (const frameId of frameIds) { + await this.findClient.clearSelection(tabId, frameId); + } + + for (const frameId of frameIds) { + const found = await this.findClient.findNext(tabId, frameId, keyword); + if (found) { + await this.findRepository.setLocalState(tabId, { frameId, keyword }); + await this.consoleClient.showInfo(tabId, "Pattern found: " + keyword); + return; + } + } + this.consoleClient.showError(tabId, "Pattern not found: " + keyword); + return; + } + await this.consoleClient.showError(tabId, "No previous search keywords"); + } +} diff --git a/src/background/operators/impls/FindOperatorFactoryChain.ts b/src/background/operators/impls/FindOperatorFactoryChain.ts new file mode 100644 index 0000000..cc169dd --- /dev/null +++ b/src/background/operators/impls/FindOperatorFactoryChain.ts @@ -0,0 +1,49 @@ +import { inject, injectable } from "tsyringe"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import TabPresenter from "../../presenters/TabPresenter"; +import * as operations from "../../../shared/operations"; +import FindNextOperator from "./FindNextOperator"; +import FindPrevOperator from "./FindPrevOperator"; +import FindRepository from "../../repositories/FindRepository"; +import FindClient from "../../clients/FindClient"; +import ConsoleClient from "../../infrastructures/ConsoleClient"; +import ReadyFrameRepository from "../../repositories/ReadyFrameRepository"; + +@injectable() +export default class FindOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("TabPresenter") + private readonly tabPresenter: TabPresenter, + @inject("FindRepository") + private readonly findRepository: FindRepository, + @inject("FindClient") + private readonly findClient: FindClient, + @inject("ConsoleClient") + private readonly consoleClient: ConsoleClient, + @inject("ReadyFrameRepository") + private readonly frameRepository: ReadyFrameRepository + ) {} + + create(op: operations.Operation): Operator | null { + switch (op.type) { + case operations.FIND_NEXT: + return new FindNextOperator( + this.tabPresenter, + this.findRepository, + this.findClient, + this.consoleClient, + this.frameRepository + ); + case operations.FIND_PREV: + return new FindPrevOperator( + this.tabPresenter, + this.findRepository, + this.findClient, + this.consoleClient, + this.frameRepository + ); + } + return null; + } +} diff --git a/src/background/operators/impls/FindPrevOperator.ts b/src/background/operators/impls/FindPrevOperator.ts new file mode 100644 index 0000000..f8506b9 --- /dev/null +++ b/src/background/operators/impls/FindPrevOperator.ts @@ -0,0 +1,92 @@ +import Operator from "../Operator"; +import TabPresenter from "../../presenters/TabPresenter"; +import FindRepository from "../../repositories/FindRepository"; +import FindClient from "../../clients/FindClient"; +import ConsoleClient from "../../infrastructures/ConsoleClient"; +import ReadyFrameRepository from "../../repositories/ReadyFrameRepository"; + +export default class FindPrevOperator implements Operator { + constructor( + private readonly tabPresenter: TabPresenter, + private readonly findRepository: FindRepository, + private readonly findClient: FindClient, + private readonly consoleClient: ConsoleClient, + private readonly frameRepository: ReadyFrameRepository + ) {} + + async run(): Promise<void> { + const tab = await this.tabPresenter.getCurrent(); + const tabId = tab?.id; + if (tabId == null) { + return; + } + + let frameIds = await this.frameRepository.getFrameIds(tabId); + if (typeof frameIds === "undefined") { + // No frames are ready + return; + } + frameIds = frameIds.slice(0).reverse(); + + const state = await this.findRepository.getLocalState(tabId); + if (state) { + const framePos = frameIds.indexOf(state.frameId); + if (framePos !== -1) { + // Start to find the keyword from the current frame which last found on, + // and concat it to end of frame ids to perform a wrap-search + // + // ,- keyword should be in this frame + // | + // [100, 101, 0, 100] + // | + // `- continue from frame id 100 + // + const targetFrameIds = frameIds + .slice(framePos) + .concat(frameIds.slice(0, framePos), frameIds[framePos]); + + for (const frameId of targetFrameIds) { + const found = await this.findClient.findPrev( + tabId, + frameId, + state.keyword + ); + if (found) { + this.findRepository.setLocalState(tabId, { + keyword: state.keyword, + frameId, + }); + return; + } + this.findClient.clearSelection(tabId, frameId); + } + + // The keyword is gone. + this.consoleClient.showError( + tabId, + "Pattern not found: " + state.keyword + ); + return; + } + } + + const keyword = await this.findRepository.getGlobalKeyword(); + if (keyword) { + for (const frameId of frameIds) { + await this.findClient.clearSelection(tabId, frameId); + } + + for (const frameId of frameIds) { + const found = await this.findClient.findPrev(tabId, frameId, keyword); + if (found) { + await this.findRepository.setLocalState(tabId, { frameId, keyword }); + await this.consoleClient.showInfo(tabId, "Pattern found: " + keyword); + return; + } + } + this.consoleClient.showError(tabId, "Pattern not found: " + keyword); + return; + } + await this.consoleClient.showError(tabId, "No previous search keywords"); + } +} diff --git a/src/background/operators/impls/OperatorFactoryImpl.ts b/src/background/operators/impls/OperatorFactoryImpl.ts index 34e7bb5..ce87491 100644 --- a/src/background/operators/impls/OperatorFactoryImpl.ts +++ b/src/background/operators/impls/OperatorFactoryImpl.ts @@ -8,6 +8,7 @@ import NavigateOperatorFactoryChain from "./NavigateOperatorFactoryChain"; import RepeatOperatorFactoryChain from "./RepeatOperatorFactoryChain"; import TabOperatorFactoryChain from "./TabOperatorFactoryChain"; import ZoomOperatorFactoryChain from "./ZoomOperatorFactoryChain"; +import FindOperatorFactoryChain from "./FindOperatorFactoryChain"; import * as operations from "../../../shared/operations"; @injectable() @@ -20,6 +21,7 @@ export class OperatorFactoryImpl implements OperatorFactory { navigateOperatorFactoryChain: NavigateOperatorFactoryChain, tabOperatorFactoryChain: TabOperatorFactoryChain, zoomOperatorFactoryChain: ZoomOperatorFactoryChain, + findOperatorFactoryChain: FindOperatorFactoryChain, @inject(delay(() => RepeatOperatorFactoryChain)) repeatOperatorFactoryChain: RepeatOperatorFactoryChain ) { @@ -30,6 +32,7 @@ export class OperatorFactoryImpl implements OperatorFactory { repeatOperatorFactoryChain, tabOperatorFactoryChain, zoomOperatorFactoryChain, + findOperatorFactoryChain, ]; } |