aboutsummaryrefslogtreecommitdiff
path: root/src/background/operators/impls/FindPrevOperator.ts
blob: f8506b90d64db45d5f1564dda79df486895b67e8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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");
  }
}