diff options
-rw-r--r-- | src/background/clients/FindClient.ts | 15 | ||||
-rw-r--r-- | src/background/operators/impls/FindPrevOperator.ts | 86 |
2 files changed, 95 insertions, 6 deletions
diff --git a/src/background/clients/FindClient.ts b/src/background/clients/FindClient.ts index 863c5ad..b46b964 100644 --- a/src/background/clients/FindClient.ts +++ b/src/background/clients/FindClient.ts @@ -3,6 +3,8 @@ import * as messages from "../../shared/messages"; export default interface FindClient { findNext(tabId: number, frameId: number, keyword: string): Promise<boolean>; + findPrev(tabId: number, frameId: number, keyword: string): Promise<boolean>; + clearSelection(tabId: number, frameId: number): Promise<void>; } @@ -20,6 +22,19 @@ export class FindClientImpl implements FindClient { return found; } + async findPrev( + tabId: number, + frameId: number, + keyword: string + ): Promise<boolean> { + const found = (await browser.tabs.sendMessage( + tabId, + { type: messages.FIND_PREV, keyword }, + { frameId } + )) as boolean; + return found; + } + clearSelection(tabId: number, frameId: number): Promise<void> { return browser.tabs.sendMessage( tabId, diff --git a/src/background/operators/impls/FindPrevOperator.ts b/src/background/operators/impls/FindPrevOperator.ts index 28238f6..822c386 100644 --- a/src/background/operators/impls/FindPrevOperator.ts +++ b/src/background/operators/impls/FindPrevOperator.ts @@ -7,14 +7,88 @@ import FramePresenter from "../../presenters/FramePresenter"; export default class FindPrevOperator implements Operator { constructor( - _tabPresenter: TabPresenter, - _findRepository: FindRepository, - _findClient: FindClient, - _consoleClient: ConsoleClient, - _framePresenter: FramePresenter + private readonly tabPresenter: TabPresenter, + private readonly findRepository: FindRepository, + private readonly findClient: FindClient, + private readonly consoleClient: ConsoleClient, + private readonly framePresenter: FramePresenter ) {} async run(): Promise<void> { - throw new Error("not implemented"); + const tab = await this.tabPresenter.getCurrent(); + const tabId = tab?.id; + if (tabId == null) { + return; + } + + const state = await this.findRepository.getLocalState(tabId); + if (state) { + // 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 = state.frameIds + .slice(state.framePos) + .concat( + state.frameIds.slice(0, state.framePos), + state.frameIds[state.framePos] + ); + + for (let i = targetFrameIds.length - 1; i >= 0; --i) { + const found = await this.findClient.findPrev( + tabId, + targetFrameIds[i], + state.keyword + ); + if (found) { + this.findRepository.setLocalState(tabId, { + ...state, + framePos: (i + state.framePos) % state.frameIds.length, // save current frame position or first + }); + return; + } + this.findClient.clearSelection(tabId, targetFrameIds[i]); + } + + // The keyword is gone. + this.consoleClient.showError( + tabId, + "Pattern not found: " + state.keyword + ); + return; + } + + const keyword = await this.findRepository.getGlobalKeyword(); + if (keyword) { + const frameIds = await this.framePresenter.getAllFrameIds(tabId); + for (const frameId of frameIds) { + await this.findClient.clearSelection(tabId, frameId); + } + + for (let framePos = frameIds.length - 1; framePos >= 0; --framePos) { + const found = await this.findClient.findPrev( + tabId, + frameIds[framePos], + keyword + ); + if (found) { + await this.findRepository.setLocalState(tabId, { + frameIds, + framePos, + 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"); } } |