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,      ];    } | 
