From 632a3ad12c479a00082f3ba8d4bd79f387d3001d Mon Sep 17 00:00:00 2001 From: Jonathan Date: Thu, 18 Jan 2024 17:49:12 -0500 Subject: [PATCH] Add `Rml::Element::Matches` function (#573) --- Include/RmlUi/Core/Element.h | 3 +++ Source/Core/Element.cpp | 22 +++++++++++++++++++ Source/Lua/Element.cpp | 8 +++++++ Source/Lua/Element.h | 1 + Tests/Source/UnitTests/Selectors.cpp | 33 ++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+) diff --git a/Include/RmlUi/Core/Element.h b/Include/RmlUi/Core/Element.h index 04b537588..bb76f3ac0 100644 --- a/Include/RmlUi/Core/Element.h +++ b/Include/RmlUi/Core/Element.h @@ -561,6 +561,9 @@ class RMLUICORE_API Element : public ScriptInterface, public EnableObserverPtrIsApplicable(this)) + { + return true; + } + } + + return false; +} + EventDispatcher* Element::GetEventDispatcher() const { return &meta->event_dispatcher; diff --git a/Source/Lua/Element.cpp b/Source/Lua/Element.cpp index 8b17847d0..d67217596 100644 --- a/Source/Lua/Element.cpp +++ b/Source/Lua/Element.cpp @@ -211,6 +211,13 @@ int ElementQuerySelectorAll(lua_State* L, Element* obj) return 1; } +int ElementMatches(lua_State* L, Element* obj) +{ + const char* tag = luaL_checkstring(L, 1); + lua_pushboolean(L, obj->Matches(tag)); + return 1; +} + int ElementHasAttribute(lua_State* L, Element* obj) { const char* name = luaL_checkstring(L, 1); @@ -594,6 +601,7 @@ RegType ElementMethods[] = { RMLUI_LUAMETHOD(Element, GetElementsByTagName), RMLUI_LUAMETHOD(Element, QuerySelector), RMLUI_LUAMETHOD(Element, QuerySelectorAll), + RMLUI_LUAMETHOD(Element, Matches), RMLUI_LUAMETHOD(Element, HasAttribute), RMLUI_LUAMETHOD(Element, HasChildNodes), RMLUI_LUAMETHOD(Element, InsertBefore), diff --git a/Source/Lua/Element.h b/Source/Lua/Element.h index 7c2746eaa..120835a30 100644 --- a/Source/Lua/Element.h +++ b/Source/Lua/Element.h @@ -51,6 +51,7 @@ int ElementGetElementById(lua_State* L, Element* obj); int ElementGetElementsByTagName(lua_State* L, Element* obj); int ElementQuerySelector(lua_State* L, Element* obj); int ElementQuerySelectorAll(lua_State* L, Element* obj); +int ElementMatches(lua_State* L, Element* obj); int ElementHasAttribute(lua_State* L, Element* obj); int ElementHasChildNodes(lua_State* L, Element* obj); int ElementInsertBefore(lua_State* L, Element* obj); diff --git a/Tests/Source/UnitTests/Selectors.cpp b/Tests/Source/UnitTests/Selectors.cpp index 591c5e2b7..3eb7532c7 100644 --- a/Tests/Source/UnitTests/Selectors.cpp +++ b/Tests/Source/UnitTests/Selectors.cpp @@ -242,6 +242,22 @@ static const Vector closest_selectors = { "D1", ":nth-child(4)", "D" }, { "D1", "div:nth-child(4)", "P" }, }; + +struct MatchesSelector { + String id; + String selector; + bool expected_result; +}; +static const Vector matches_selectors = +{ + { "X", ".world", false }, + { "X", ".hello", true }, + { "X", ".hello, .world", true }, + { "E", "h3", true }, + { "G", "p#G[class]", true }, + { "G", "p#G[missing]", false }, + { "B", "[unit='m']", true } +}; // clang-format on // Recursively iterate through 'element' and all of its descendants to find all @@ -423,5 +439,22 @@ TEST_CASE("Selectors") context->UnloadDocument(document); } + SUBCASE("Matches") + { + const String document_string = doc_begin + doc_end; + ElementDocument* document = context->LoadDocumentFromMemory(document_string); + REQUIRE(document); + + for (const MatchesSelector& selector : matches_selectors) + { + Element* start = document->GetElementById(selector.id); + REQUIRE(start); + + bool matches = start->Matches(selector.selector); + CHECK_MESSAGE(matches == selector.expected_result, "Matches() selector '" << selector.selector << "' from " << selector.id); + } + context->UnloadDocument(document); + } + TestsShell::ShutdownShell(); }