diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2021-06-14 23:14:51 +0900 |
---|---|---|
committer | Shin'ya Ueoka <ueokande@i-beam.org> | 2021-07-05 21:32:43 +0900 |
commit | 65cf6f0842d8d5933dc13b3767b1baf398d68cd5 (patch) | |
tree | df9a8b139fd98adb79f075ba655d1303bdf3fd1d /src | |
parent | caced372415a944c4297157397d0027ba629fff0 (diff) |
Implement FindNextOperator
Diffstat (limited to 'src')
20 files changed, 475 insertions, 12 deletions
diff --git a/src/background/Application.ts b/src/background/Application.ts index 69fe4a4..2006965 100644 --- a/src/background/Application.ts +++ b/src/background/Application.ts @@ -3,6 +3,7 @@ import ContentMessageListener from "./infrastructures/ContentMessageListener"; import SettingController from "./controllers/SettingController"; import VersionController from "./controllers/VersionController"; import SettingRepository from "./repositories/SettingRepository"; +import FindRepositoryImpl from "./repositories/FindRepository"; @injectable() export default class Application { @@ -11,12 +12,19 @@ export default class Application { private settingController: SettingController, private versionController: VersionController, @inject("SyncSettingRepository") - private syncSettingRepository: SettingRepository + private syncSettingRepository: SettingRepository, + @inject("FindRepository") + private readonly findRepository: FindRepositoryImpl ) {} run() { this.settingController.reload(); + browser.tabs.onUpdated.addListener((tabId: number, info) => { + if (info.status == "loading") { + this.findRepository.deleteLocalState(tabId); + } + }); browser.runtime.onInstalled.addListener((details) => { if (details.reason !== "install" && details.reason !== "update") { return; diff --git a/src/background/clients/FindClient.ts b/src/background/clients/FindClient.ts new file mode 100644 index 0000000..863c5ad --- /dev/null +++ b/src/background/clients/FindClient.ts @@ -0,0 +1,30 @@ +import * as messages from "../../shared/messages"; + +export default interface FindClient { + findNext(tabId: number, frameId: number, keyword: string): Promise<boolean>; + + clearSelection(tabId: number, frameId: number): Promise<void>; +} + +export class FindClientImpl implements FindClient { + async findNext( + tabId: number, + frameId: number, + keyword: string + ): Promise<boolean> { + const found = (await browser.tabs.sendMessage( + tabId, + { type: messages.FIND_NEXT, keyword }, + { frameId } + )) as boolean; + return found; + } + + clearSelection(tabId: number, frameId: number): Promise<void> { + return browser.tabs.sendMessage( + tabId, + { type: messages.FIND_CLEAR_SELECTION }, + { frameId } + ); + } +} diff --git a/src/background/controllers/FindController.ts b/src/background/controllers/FindController.ts new file mode 100644 index 0000000..0772866 --- /dev/null +++ b/src/background/controllers/FindController.ts @@ -0,0 +1,11 @@ +import { injectable } from "tsyringe"; +import StartFindUseCase from "../usecases/StartFindUseCase"; + +@injectable() +export default class FindController { + constructor(private startFindUseCase: StartFindUseCase) {} + + startFind(tabId: number, keyword?: string): Promise<void> { + return this.startFindUseCase.startFind(tabId, keyword); + } +} diff --git a/src/background/di.ts b/src/background/di.ts index a571c7d..e97c4a8 100644 --- a/src/background/di.ts +++ b/src/background/di.ts @@ -18,7 +18,10 @@ import { BrowserSettingRepositoryImpl } from "./repositories/BrowserSettingRepos import { RepeatRepositoryImpl } from "./repositories/RepeatRepository"; import { ZoomPresenterImpl } from "./presenters/ZoomPresenter"; import { WindowPresenterImpl } from "./presenters/WindowPresenter"; +import { FramePresenterImpl } from "./presenters/FramePresenter"; +import { FindClientImpl } from "./clients/FindClient"; import { ConsoleFrameClientImpl } from "./clients/ConsoleFrameClient"; +import { FindRepositoryImpl } from "./repositories/FindRepository"; container.register("LocalSettingRepository", { useClass: LocalSettingRepository, @@ -40,6 +43,9 @@ container.register("TabRepository", { useClass: TabRepositoryImpl }); container.register("ZoomPresenter", { useClass: ZoomPresenterImpl }); container.register("TabPresenter", { useClass: TabPresenterImpl }); container.register("WindowPresenter", { useClass: WindowPresenterImpl }); +container.register("FramePresenter", { useClass: FramePresenterImpl }); +container.register("FindRepository", { useClass: FindRepositoryImpl }); +container.register("FindClient", { useClass: FindClientImpl }); container.register("NavigateClient", { useClass: NavigateClientImpl }); container.register("ConsoleClient", { useClass: ConsoleClientImpl }); container.register("ConsoleFrameClient", { useClass: ConsoleFrameClientImpl }); diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts index 6189e7c..ce7ff09 100644 --- a/src/background/infrastructures/ContentMessageListener.ts +++ b/src/background/infrastructures/ContentMessageListener.ts @@ -9,6 +9,7 @@ import OperationController from "../controllers/OperationController"; import MarkController from "../controllers/MarkController"; import CompletionController from "../controllers/CompletionController"; import ConsoleController from "../controllers/ConsoleController"; +import FindController from "../controllers/FindController"; @injectable() export default class ContentMessageListener { @@ -22,7 +23,8 @@ export default class ContentMessageListener { private readonly linkController: LinkController, private readonly operationController: OperationController, private readonly markController: MarkController, - private readonly consoleController: ConsoleController + private readonly consoleController: ConsoleController, + private readonly findController: FindController ) {} run(): void { @@ -80,6 +82,8 @@ export default class ContentMessageListener { return this.completionController.getProperties(); case messages.CONSOLE_ENTER_COMMAND: return this.onConsoleEnterCommand(message.text); + case messages.CONSOLE_ENTER_FIND: + return this.findController.startFind(senderTab.id!, message.keyword); case messages.CONSOLE_RESIZE: return this.onConsoleResize( senderTab.id!, diff --git a/src/background/operators/impls/FindNextOperator.ts b/src/background/operators/impls/FindNextOperator.ts new file mode 100644 index 0000000..241f71d --- /dev/null +++ b/src/background/operators/impls/FindNextOperator.ts @@ -0,0 +1,94 @@ +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 FramePresenter from "../../presenters/FramePresenter"; + +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 framePresenter: FramePresenter + ) {} + + async run(): Promise<void> { + 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 = 0; i < targetFrameIds.length; ++i) { + const found = await this.findClient.findNext( + 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 = 0; framePos < frameIds.length; ++framePos) { + const found = await this.findClient.findNext( + 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"); + } +} diff --git a/src/background/operators/impls/FindOperatorFactoryChain.ts b/src/background/operators/impls/FindOperatorFactoryChain.ts new file mode 100644 index 0000000..b71f032 --- /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 FramePresenter from "../../presenters/FramePresenter"; +import ConsoleClient from "../../infrastructures/ConsoleClient"; + +@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("FramePresenter") + private readonly framePresenter: FramePresenter + ) {} + + 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.framePresenter + ); + case operations.FIND_PREV: + return new FindPrevOperator( + this.tabPresenter, + this.findRepository, + this.findClient, + this.consoleClient, + this.framePresenter + ); + } + return null; + } +} diff --git a/src/background/operators/impls/FindPrevOperator.ts b/src/background/operators/impls/FindPrevOperator.ts new file mode 100644 index 0000000..28238f6 --- /dev/null +++ b/src/background/operators/impls/FindPrevOperator.ts @@ -0,0 +1,20 @@ +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 FramePresenter from "../../presenters/FramePresenter"; + +export default class FindPrevOperator implements Operator { + constructor( + _tabPresenter: TabPresenter, + _findRepository: FindRepository, + _findClient: FindClient, + _consoleClient: ConsoleClient, + _framePresenter: FramePresenter + ) {} + + async run(): Promise<void> { + throw new Error("not implemented"); + } +} 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, ]; } diff --git a/src/background/presenters/FramePresenter.ts b/src/background/presenters/FramePresenter.ts new file mode 100644 index 0000000..c94f8dd --- /dev/null +++ b/src/background/presenters/FramePresenter.ts @@ -0,0 +1,12 @@ +export default interface FramePresenter { + getAllFrameIds(tabId: number): Promise<Array<number>>; +} + +export class FramePresenterImpl implements FramePresenter { + async getAllFrameIds(tabId: number): Promise<Array<number>> { + const frames = await browser.webNavigation.getAllFrames({ tabId: tabId }); + return frames + .filter((f) => !f.url.startsWith("moz-extension://")) + .map((f) => f.frameId); + } +} diff --git a/src/background/repositories/FindRepository.ts b/src/background/repositories/FindRepository.ts new file mode 100644 index 0000000..46ee390 --- /dev/null +++ b/src/background/repositories/FindRepository.ts @@ -0,0 +1,69 @@ +import { injectable } from "tsyringe"; +import MemoryStorage from "../infrastructures/MemoryStorage"; + +const FIND_GLOBAL_KEYWORD_KEY = "find-global-keyword"; +const FIND_LOCAL_KEYWORD_KEY = "find-local-keyword"; + +export type FindState = { + keyword: string; + framePos: number; + frameIds: number[]; +}; + +export default interface FindRepository { + getGlobalKeyword(): Promise<string | undefined>; + + setGlobalKeyword(keyword: string): Promise<void>; + + getLocalState(tabId: number): Promise<undefined | FindState>; + + setLocalState(tabId: number, state: FindState): Promise<void>; + + deleteLocalState(tabId: number): Promise<void>; +} + +@injectable() +export class FindRepositoryImpl implements FindRepository { + private cache: MemoryStorage; + + constructor() { + this.cache = new MemoryStorage(); + } + + getGlobalKeyword(): Promise<string | undefined> { + return Promise.resolve(this.cache.get(FIND_GLOBAL_KEYWORD_KEY)); + } + + setGlobalKeyword(keyword: string): Promise<void> { + this.cache.set(FIND_GLOBAL_KEYWORD_KEY, keyword); + return Promise.resolve(); + } + + getLocalState(tabId: number): Promise<FindState | undefined> { + let states = this.cache.get(FIND_LOCAL_KEYWORD_KEY); + if (typeof states === "undefined") { + states = {}; + } + return Promise.resolve(states[tabId]); + } + + setLocalState(tabId: number, state: FindState): Promise<void> { + let states = this.cache.get(FIND_LOCAL_KEYWORD_KEY); + if (typeof states === "undefined") { + states = {}; + } + states[tabId] = state; + this.cache.set(FIND_LOCAL_KEYWORD_KEY, states); + return Promise.resolve(); + } + + deleteLocalState(tabId: number): Promise<void> { + const states = this.cache.get(FIND_LOCAL_KEYWORD_KEY); + if (typeof states === "undefined") { + return Promise.resolve(); + } + delete states[tabId]; + this.cache.set(FIND_LOCAL_KEYWORD_KEY, states); + return Promise.resolve(); + } +} diff --git a/src/background/usecases/StartFindUseCase.ts b/src/background/usecases/StartFindUseCase.ts new file mode 100644 index 0000000..066d930 --- /dev/null +++ b/src/background/usecases/StartFindUseCase.ts @@ -0,0 +1,57 @@ +import { inject, injectable } from "tsyringe"; +import ConsoleClient from "../infrastructures/ConsoleClient"; +import FindRepositoryImpl from "../repositories/FindRepository"; +import FindClient from "../clients/FindClient"; +import FramePresenter from "../presenters/FramePresenter"; + +@injectable() +export default class StartFindUseCase { + constructor( + @inject("FindClient") + private readonly findClient: FindClient, + @inject("FindRepository") + private readonly findRepository: FindRepositoryImpl, + @inject("ConsoleClient") + private readonly consoleClient: ConsoleClient, + @inject("FramePresenter") + private readonly framePresenter: FramePresenter + ) {} + + async startFind(tabId: number, keyword?: string): Promise<void> { + if (typeof keyword === "undefined") { + keyword = (await this.findRepository.getLocalState(tabId))?.keyword; + } + if (typeof keyword === "undefined") { + keyword = await this.findRepository.getGlobalKeyword(); + } + if (typeof keyword === "undefined") { + await this.consoleClient.showError(tabId, "No previous search keywords"); + return; + } + + this.findRepository.setGlobalKeyword(keyword); + + const frameIds = await this.framePresenter.getAllFrameIds(tabId); + for (const frameId of frameIds) { + await this.findClient.clearSelection(tabId, frameId); + } + + for (let framePos = 0; framePos < frameIds.length; ++framePos) { + const found = await this.findClient.findNext( + 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); + } +} diff --git a/src/console/app/hooks.ts b/src/console/app/hooks.ts index eefdea3..00ac05c 100644 --- a/src/console/app/hooks.ts +++ b/src/console/app/hooks.ts @@ -103,13 +103,10 @@ export const useExecCommand = () => { export const useExecFind = () => { const execFind = React.useCallback((text?: string) => { - window.top.postMessage( - JSON.stringify({ - type: messages.CONSOLE_ENTER_FIND, - text, - }), - "*" - ); + browser.runtime.sendMessage({ + type: messages.CONSOLE_ENTER_FIND, + keyword: text, + }); }, []); return execFind; }; diff --git a/src/content/Application.ts b/src/content/Application.ts index 9ea047c..a12c3c6 100644 --- a/src/content/Application.ts +++ b/src/content/Application.ts @@ -13,6 +13,7 @@ import SettingController from "./controllers/SettingController"; import ConsoleFrameController from "./controllers/ConsoleFrameController"; import NavigateController from "./controllers/NavigateController"; import * as messages from "../shared/messages"; +import FindController from "./controllers/FindController"; type Message = messages.Message; @@ -31,7 +32,8 @@ export default class Application { private addonEnabledController: AddonEnabledController, private settingController: SettingController, private consoleFrameController: ConsoleFrameController, - private navigateController: NavigateController + private navigateController: NavigateController, + private findController: FindController ) {} init(): Promise<void> { @@ -91,6 +93,12 @@ export default class Application { return this.navigateController.openLinkPrev(msg); case messages.CONSOLE_RESIZE: return this.consoleFrameController.resize(msg); + case messages.FIND_NEXT: + return this.findController.findNext(msg.keyword); + case messages.FIND_PREV: + return this.findController.findPrev(msg.keyword); + case messages.FIND_CLEAR_SELECTION: + return this.findController.clearSelection(); } if (window.self === window.top) { diff --git a/src/content/MessageListener.ts b/src/content/MessageListener.ts index ec6940b..31cc1ae 100644 --- a/src/content/MessageListener.ts +++ b/src/content/MessageListener.ts @@ -27,7 +27,12 @@ export default class MessageListener { ) { browser.runtime.onMessage.addListener( (msg: any, sender: WebExtMessageSender) => { - return Promise.resolve(listener(valueOf(msg), sender)); + try { + return Promise.resolve(listener(valueOf(msg), sender)); + } catch (e) { + console.warn(e); + return; + } } ); } diff --git a/src/content/controllers/FindController.ts b/src/content/controllers/FindController.ts new file mode 100644 index 0000000..adcdb0d --- /dev/null +++ b/src/content/controllers/FindController.ts @@ -0,0 +1,19 @@ +import { injectable } from "tsyringe"; +import FindUseCase from "../usecases/FindUseCase"; + +@injectable() +export default class FindController { + constructor(private findUseCase: FindUseCase) {} + + findNext(keyword: string): boolean { + return this.findUseCase.findNext(keyword); + } + + findPrev(keyword: string): boolean { + return this.findUseCase.findPrev(keyword); + } + + clearSelection() { + return this.findUseCase.clearSelection(); + } +} diff --git a/src/content/di.ts b/src/content/di.ts index 7a7fb08..4c85e76 100644 --- a/src/content/di.ts +++ b/src/content/di.ts @@ -27,6 +27,7 @@ import { TabsClientImpl } from "./client/TabsClient"; import { container } from "tsyringe"; import OperatorFactoryImpl from "./operators/impls/OperatorFactoryImpl"; import { URLRepositoryImpl } from "./operators/impls/URLRepository"; +import { FindPresenterImpl } from "./presenters/FindPresenter"; container.register("FollowMasterClient", { useValue: new FollowMasterClientImpl(window.top), @@ -71,6 +72,7 @@ container.register("NavigationPresenter", { }); container.register("OperationClient", { useClass: OperationClientImpl }); container.register("ScrollPresenter", { useClass: ScrollPresenterImpl }); +container.register("FindPresenter", { useClass: FindPresenterImpl }); container.register("SettingClient", { useClass: SettingClientImpl }); container.register("SettingRepository", { useClass: SettingRepositoryImpl }); container.register("URLRepository", { useClass: URLRepositoryImpl }); diff --git a/src/content/presenters/FindPresenter.ts b/src/content/presenters/FindPresenter.ts new file mode 100644 index 0000000..569f161 --- /dev/null +++ b/src/content/presenters/FindPresenter.ts @@ -0,0 +1,23 @@ +export default interface FindPresenter { + find(keyword: string, backwards: boolean): boolean; + + clearSelection(): void; +} + +export class FindPresenterImpl implements FindPresenter { + find(keyword: string, backwards: boolean): boolean { + const caseSensitive = false; + const wrapScan = false; + + // NOTE: aWholeWord dows not implemented, and aSearchInFrames does not work + // because of same origin policy + return window.find(keyword, caseSensitive, backwards, wrapScan); + } + + clearSelection(): void { + const sel = window.getSelection(); + if (sel) { + sel.removeAllRanges(); + } + } +} diff --git a/src/content/usecases/FindUseCase.ts b/src/content/usecases/FindUseCase.ts new file mode 100644 index 0000000..9e77124 --- /dev/null +++ b/src/content/usecases/FindUseCase.ts @@ -0,0 +1,22 @@ +import { inject, injectable } from "tsyringe"; +import FindPresenter from "../presenters/FindPresenter"; + +@injectable() +export default class FindUseCase { + constructor( + @inject("FindPresenter") + private readonly findPresenter: FindPresenter + ) {} + + findNext(keyword: string): boolean { + return this.findPresenter.find(keyword, false); + } + + findPrev(keyword: string): boolean { + return this.findPresenter.find(keyword, true); + } + + clearSelection() { + this.findPresenter.clearSelection(); + } +} diff --git a/src/shared/messages.ts b/src/shared/messages.ts index 2ad3b48..8b9e598 100644 --- a/src/shared/messages.ts +++ b/src/shared/messages.ts @@ -35,6 +35,10 @@ export const MARK_JUMP_GLOBAL = "mark.jump.global"; export const TAB_SCROLL_TO = "tab.scroll.to"; +export const FIND_NEXT = "find.next"; +export const FIND_PREV = "find.prev"; +export const FIND_CLEAR_SELECTION = "find.clear.selection"; + export const ADDON_ENABLED_QUERY = "addon.enabled.query"; export const ADDON_ENABLED_RESPONSE = "addon.enabled.response"; export const ADDON_TOGGLE_ENABLED = "addon.toggle.enabled"; @@ -68,7 +72,7 @@ export interface ConsoleEnterCommandMessage { export interface ConsoleEnterFindMessage { type: typeof CONSOLE_ENTER_FIND; - text?: string; + keyword?: string; } export interface ConsoleShowCommandMessage { @@ -222,6 +226,20 @@ export interface TabScrollToMessage { y: number; } +export interface FindNextMessage { + type: typeof FIND_NEXT; + keyword: string; +} + +export interface FindPrevMessage { + type: typeof FIND_PREV; + keyword: string; +} + +export interface FindClearSelection { + type: typeof FIND_CLEAR_SELECTION; +} + export interface AddonEnabledQueryMessage { type: typeof ADDON_ENABLED_QUERY; } @@ -299,6 +317,9 @@ export type Message = | MarkSetGlobalMessage | MarkJumpGlobalMessage | TabScrollToMessage + | FindNextMessage + | FindPrevMessage + | FindClearSelection | AddonEnabledQueryMessage | AddonEnabledResponseMessage | AddonToggleEnabledMessage @@ -333,6 +354,9 @@ export const valueOf = (o: any): Message => { case MARK_SET_GLOBAL: case MARK_JUMP_GLOBAL: case TAB_SCROLL_TO: + case FIND_NEXT: + case FIND_PREV: + case FIND_CLEAR_SELECTION: case ADDON_ENABLED_QUERY: case ADDON_ENABLED_RESPONSE: case ADDON_TOGGLE_ENABLED: |