Skip to content

Commit

Permalink
LibWeb: Rerun find in page query when navigating between URLs
Browse files Browse the repository at this point in the history
Previously, the find next match and fond previous match actions simply
updated the match index of the last query to be performed. This led to
incorrect results if the page had been modified after the last query
had been run.

`Page::find_in_page_next_match()` and
`Page::find_in_page_previous_match()` both now rerun the last query to
ensure the results are up to date before updating the match index.

The match index is also reset if the URL of the active document has
changed since the last query. The current match index is maintained if
only the URL fragment changes.
  • Loading branch information
tcl3 committed Jun 14, 2024
1 parent 484bcd3 commit 1cc5a91
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 27 deletions.
63 changes: 38 additions & 25 deletions Userland/Libraries/LibWeb/Page/Page.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,26 +563,29 @@ void Page::clear_selection()
}
}

Page::FindInPageResult Page::find_in_page(String const& query, CaseSensitivity case_sensitivity)
Page::FindInPageResult Page::perform_find_in_page_query(FindInPageQuery const& query)
{
m_find_in_page_match_index = 0;

if (query.is_empty()) {
m_find_in_page_matches = {};
update_find_in_page_selection();
return {};
}
VERIFY(top_level_traversable_is_initialized());

Vector<JS::Handle<DOM::Range>> all_matches;
for (auto const& document : documents_in_active_window()) {
auto matches = document->find_matching_text(query, case_sensitivity);
auto matches = document->find_matching_text(query.string, query.case_sensitivity);
all_matches.extend(move(matches));
}

m_find_in_page_matches.clear_with_capacity();
for (auto& match : all_matches)
m_find_in_page_matches.append(*match);

if (auto active_document = top_level_traversable()->active_document()) {
if (m_last_find_in_page_url.serialize(URL::ExcludeFragment::Yes) != active_document->url().serialize(URL::ExcludeFragment::Yes)) {
m_last_find_in_page_url = top_level_traversable()->active_document()->url();
m_find_in_page_match_index = 0;
}
} else if (m_find_in_page_match_index >= m_find_in_page_matches.size()) {
m_find_in_page_match_index = 0;
}

update_find_in_page_selection();

return Page::FindInPageResult {
Expand All @@ -591,42 +594,52 @@ Page::FindInPageResult Page::find_in_page(String const& query, CaseSensitivity c
};
}

Page::FindInPageResult Page::find_in_page(FindInPageQuery const& query)
{
if (!top_level_traversable_is_initialized())
return {};

m_find_in_page_match_index = 0;
m_last_find_in_page_query = query;
m_last_find_in_page_url = top_level_traversable()->active_document()->url();

if (query.string.is_empty()) {
m_last_find_in_page_query = {};
update_find_in_page_selection();
return {};
}

return perform_find_in_page_query(query);
}

Page::FindInPageResult Page::find_in_page_next_match()
{
if (m_find_in_page_matches.is_empty())
if (!(m_last_find_in_page_query.has_value() && top_level_traversable_is_initialized()))
return {};

if (m_find_in_page_match_index == m_find_in_page_matches.size() - 1) {
auto result = perform_find_in_page_query(*m_last_find_in_page_query);
if (m_find_in_page_match_index == *result.total_match_count - 1) {
m_find_in_page_match_index = 0;
} else {
m_find_in_page_match_index++;
}

update_find_in_page_selection();

return Page::FindInPageResult {
.current_match_index = m_find_in_page_match_index,
.total_match_count = m_find_in_page_matches.size(),
};
return result;
}

Page::FindInPageResult Page::find_in_page_previous_match()
{
if (m_find_in_page_matches.is_empty())
if (!(m_last_find_in_page_query.has_value() && top_level_traversable_is_initialized()))
return {};

auto result = perform_find_in_page_query(*m_last_find_in_page_query);
if (m_find_in_page_match_index == 0) {
m_find_in_page_match_index = m_find_in_page_matches.size() - 1;
m_find_in_page_match_index = *result.total_match_count - 1;
} else {
m_find_in_page_match_index--;
}

update_find_in_page_selection();

return Page::FindInPageResult {
.current_match_index = m_find_in_page_match_index,
.total_match_count = m_find_in_page_matches.size(),
};
return result;
}

void Page::update_find_in_page_selection()
Expand Down
9 changes: 8 additions & 1 deletion Userland/Libraries/LibWeb/Page/Page.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,15 @@ class Page final : public JS::Cell {

void clear_selection();

struct FindInPageQuery {
String string {};
CaseSensitivity case_sensitivity { CaseSensitivity::CaseInsensitive };
};
struct FindInPageResult {
size_t current_match_index { 0 };
Optional<size_t> total_match_count {};
};
FindInPageResult find_in_page(String const& query, CaseSensitivity);
FindInPageResult find_in_page(FindInPageQuery const&);
FindInPageResult find_in_page_next_match();
FindInPageResult find_in_page_previous_match();

Expand All @@ -203,6 +207,7 @@ class Page final : public JS::Cell {

Vector<JS::Handle<DOM::Document>> documents_in_active_window() const;

FindInPageResult perform_find_in_page_query(FindInPageQuery const&);
void update_find_in_page_selection();

JS::NonnullGCPtr<PageClient> m_client;
Expand Down Expand Up @@ -248,6 +253,8 @@ class Page final : public JS::Cell {
bool m_pdf_viewer_supported { false };
size_t m_find_in_page_match_index { 0 };
Vector<JS::NonnullGCPtr<DOM::Range>> m_find_in_page_matches;
Optional<FindInPageQuery> m_last_find_in_page_query;
URL::URL m_last_find_in_page_url;
};

struct PaintOptions {
Expand Down
2 changes: 1 addition & 1 deletion Userland/Services/WebContent/ConnectionFromClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ void ConnectionFromClient::find_in_page(u64 page_id, String const& query, CaseSe
if (!page.has_value())
return;

auto result = page->page().find_in_page(query, case_sensitivity);
auto result = page->page().find_in_page({ .string = query, .case_sensitivity = case_sensitivity });
async_did_find_in_page(page_id, result.current_match_index, result.total_match_count);
}

Expand Down

0 comments on commit 1cc5a91

Please sign in to comment.