From 4ad1695c78450d49a86c917815274f5b17b0bf3c Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Sat, 19 Nov 2022 12:30:16 +0000 Subject: [PATCH] WebContent: Add `$()` and `$$()` functions to browser console These are based on the ones in Firefox: `$(selector, element = document)`: Equivalent to `element.querySelector(selector)`. `$$(selector, element = document)`: Equivalent to `element.querySelectorAll(selector)`. --- .../WebContent/ConsoleGlobalObject.cpp | 59 +++++++++++++++++++ .../Services/WebContent/ConsoleGlobalObject.h | 4 ++ 2 files changed, 63 insertions(+) diff --git a/Userland/Services/WebContent/ConsoleGlobalObject.cpp b/Userland/Services/WebContent/ConsoleGlobalObject.cpp index 45e9dd8e5d..8082698fa7 100644 --- a/Userland/Services/WebContent/ConsoleGlobalObject.cpp +++ b/Userland/Services/WebContent/ConsoleGlobalObject.cpp @@ -5,8 +5,11 @@ */ #include "ConsoleGlobalObject.h" +#include #include +#include #include +#include #include namespace WebContent { @@ -23,6 +26,8 @@ void ConsoleGlobalObject::initialize(JS::Realm& realm) define_native_accessor(realm, "$0", $0_getter, nullptr, 0); define_native_accessor(realm, "$_", $__getter, nullptr, 0); + define_native_function(realm, "$", $_function, 2, JS::default_attributes); + define_native_function(realm, "$$", $$_function, 2, JS::default_attributes); } void ConsoleGlobalObject::visit_edges(Visitor& visitor) @@ -117,4 +122,58 @@ JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalObject::$__getter) return console_global_object->m_most_recent_result; } +JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalObject::$_function) +{ + auto* console_global_object = TRY(get_console(vm)); + auto& window = *console_global_object->m_window_object; + + auto selector = TRY(vm.argument(0).to_string(vm)); + + if (vm.argument_count() > 1) { + auto element_value = vm.argument(1); + if (!(element_value.is_object() && is(element_value.as_object()))) { + return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "Node"); + } + + auto& element = static_cast(element_value.as_object()); + return TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { + return element.query_selector(selector); + })); + } + + return TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { + return window.associated_document().query_selector(selector); + })); +} + +JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalObject::$$_function) +{ + auto* console_global_object = TRY(get_console(vm)); + auto& window = *console_global_object->m_window_object; + + auto selector = TRY(vm.argument(0).to_string(vm)); + + Web::DOM::ParentNode* element = &window.associated_document(); + + if (vm.argument_count() > 1) { + auto element_value = vm.argument(1); + if (!(element_value.is_object() && is(element_value.as_object()))) { + return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "Node"); + } + + element = static_cast(&element_value.as_object()); + } + + auto node_list = TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { + return element->query_selector_all(selector); + })); + + auto* array = TRY(JS::Array::create(*vm.current_realm(), node_list->length())); + for (auto i = 0u; i < node_list->length(); ++i) { + TRY(array->create_data_property_or_throw(i, node_list->item_value(i))); + } + + return array; +} + } diff --git a/Userland/Services/WebContent/ConsoleGlobalObject.h b/Userland/Services/WebContent/ConsoleGlobalObject.h index e4abdfc287..75d13ad4c5 100644 --- a/Userland/Services/WebContent/ConsoleGlobalObject.h +++ b/Userland/Services/WebContent/ConsoleGlobalObject.h @@ -42,6 +42,10 @@ private: JS_DECLARE_NATIVE_FUNCTION($0_getter); // $_, the value of the most recent expression entered into the console JS_DECLARE_NATIVE_FUNCTION($__getter); + // $(selector, element), equivalent to `(element || document).querySelector(selector)` + JS_DECLARE_NATIVE_FUNCTION($_function); + // $$(selector, element), equivalent to `(element || document).querySelectorAll(selector)` + JS_DECLARE_NATIVE_FUNCTION($$_function); Web::HTML::Window* m_window_object; JS::Value m_most_recent_result { JS::js_undefined() };