Serenity Operating System
at master 123 lines 4.3 kB view raw
1/* 2 * Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org> 3 * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include "ConsoleGlobalEnvironmentExtensions.h" 9#include <LibJS/Runtime/Array.h> 10#include <LibJS/Runtime/Completion.h> 11#include <LibWeb/Bindings/ExceptionOrUtils.h> 12#include <LibWeb/DOM/Document.h> 13#include <LibWeb/DOM/NodeList.h> 14#include <LibWeb/HTML/Window.h> 15 16namespace WebContent { 17 18ConsoleGlobalEnvironmentExtensions::ConsoleGlobalEnvironmentExtensions(JS::Realm& realm, Web::HTML::Window& window) 19 : Object(realm, nullptr) 20 , m_window_object(window) 21{ 22} 23 24JS::ThrowCompletionOr<void> ConsoleGlobalEnvironmentExtensions::initialize(JS::Realm& realm) 25{ 26 MUST_OR_THROW_OOM(Base::initialize(realm)); 27 28 define_native_accessor(realm, "$0", $0_getter, nullptr, 0); 29 define_native_accessor(realm, "$_", $__getter, nullptr, 0); 30 define_native_function(realm, "$", $_function, 2, JS::default_attributes); 31 define_native_function(realm, "$$", $$_function, 2, JS::default_attributes); 32 33 return {}; 34} 35 36void ConsoleGlobalEnvironmentExtensions::visit_edges(Visitor& visitor) 37{ 38 Base::visit_edges(visitor); 39 visitor.visit(m_window_object); 40} 41 42static JS::ThrowCompletionOr<ConsoleGlobalEnvironmentExtensions*> get_console(JS::VM& vm) 43{ 44 auto this_value = vm.this_value(); 45 if (!this_value.is_object() || !is<ConsoleGlobalEnvironmentExtensions>(this_value.as_object())) 46 return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "ConsoleGlobalEnvironmentExtensions"); 47 48 return &static_cast<ConsoleGlobalEnvironmentExtensions&>(this_value.as_object()); 49} 50 51JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalEnvironmentExtensions::$0_getter) 52{ 53 auto* console_global_object = TRY(get_console(vm)); 54 auto& window = *console_global_object->m_window_object; 55 auto* inspected_node = window.associated_document().inspected_node(); 56 if (!inspected_node) 57 return JS::js_undefined(); 58 59 return inspected_node; 60} 61 62JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalEnvironmentExtensions::$__getter) 63{ 64 auto* console_global_object = TRY(get_console(vm)); 65 return console_global_object->m_most_recent_result; 66} 67 68JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalEnvironmentExtensions::$_function) 69{ 70 auto* console_global_object = TRY(get_console(vm)); 71 auto& window = *console_global_object->m_window_object; 72 73 auto selector = TRY(vm.argument(0).to_deprecated_string(vm)); 74 75 if (vm.argument_count() > 1) { 76 auto element_value = vm.argument(1); 77 if (!(element_value.is_object() && is<Web::DOM::ParentNode>(element_value.as_object()))) { 78 return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Node"); 79 } 80 81 auto& element = static_cast<Web::DOM::ParentNode&>(element_value.as_object()); 82 return TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { 83 return element.query_selector(selector); 84 })); 85 } 86 87 return TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { 88 return window.associated_document().query_selector(selector); 89 })); 90} 91 92JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalEnvironmentExtensions::$$_function) 93{ 94 auto* console_global_object = TRY(get_console(vm)); 95 auto& window = *console_global_object->m_window_object; 96 97 auto selector = TRY(vm.argument(0).to_deprecated_string(vm)); 98 99 Web::DOM::ParentNode* element = &window.associated_document(); 100 101 if (vm.argument_count() > 1) { 102 auto element_value = vm.argument(1); 103 if (!(element_value.is_object() && is<Web::DOM::ParentNode>(element_value.as_object()))) { 104 return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Node"); 105 } 106 107 element = static_cast<Web::DOM::ParentNode*>(&element_value.as_object()); 108 } 109 110 auto node_list = TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { 111 return element->query_selector_all(selector); 112 })); 113 114 auto array = TRY(JS::Array::create(*vm.current_realm(), node_list->length())); 115 for (auto i = 0u; i < node_list->length(); ++i) { 116 // NOTE: NodeList::item_value cannot fail. 117 TRY(array->create_data_property_or_throw(i, MUST(node_list->item_value(i)))); 118 } 119 120 return array; 121} 122 123}