mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:47:34 +00:00
LibWeb: Add document.querySelector()
This commit is contained in:
parent
6e505b853e
commit
67b742bf32
8 changed files with 46 additions and 5 deletions
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
function drawSomeCurves() {
|
function drawSomeCurves() {
|
||||||
|
|
||||||
var canvas = document.querySelectorAll("canvas")[0];
|
var canvas = document.querySelector("canvas");
|
||||||
var ctx = canvas.getContext("2d");
|
var ctx = canvas.getContext("2d");
|
||||||
var x = 150;
|
var x = 150;
|
||||||
var y = 150;
|
var y = 150;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
function drawHouse() {
|
function drawHouse() {
|
||||||
|
|
||||||
var ctx = document.querySelectorAll("canvas")[0].getContext("2d");
|
var ctx = document.querySelector("canvas").getContext("2d");
|
||||||
ctx.fillStyle = 'black';
|
ctx.fillStyle = 'black';
|
||||||
ctx.fillRect(0, 0, 300, 300);
|
ctx.fillRect(0, 0, 300, 300);
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
img = document.querySelectorAll("img")[0];
|
img = document.querySelector("img");
|
||||||
|
|
||||||
img.addEventListener("load", function() {
|
img.addEventListener("load", function() {
|
||||||
var ctx = document.querySelectorAll("canvas")[0].getContext("2d");
|
var ctx = document.querySelector("canvas").getContext("2d");
|
||||||
ctx.fillStyle = '#666';
|
ctx.fillStyle = '#666';
|
||||||
ctx.fillRect(0, 0, 400, 400);
|
ctx.fillRect(0, 0, 400, 400);
|
||||||
ctx.scale(2, 2);
|
ctx.scale(2, 2);
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<div id="set_href">Click me to set location.href!</div>
|
<div id="set_href">Click me to set location.href!</div>
|
||||||
<div id="reload">Click me to call location.reload()!</div>
|
<div id="reload">Click me to call location.reload()!</div>
|
||||||
<script>
|
<script>
|
||||||
var pre = document.querySelectorAll("pre")[0];
|
var pre = document.querySelector("pre");
|
||||||
pre.innerHTML += "href: " + location.href + '\n';
|
pre.innerHTML += "href: " + location.href + '\n';
|
||||||
pre.innerHTML += "protocol: " + location.protocol + '\n';
|
pre.innerHTML += "protocol: " + location.protocol + '\n';
|
||||||
pre.innerHTML += "host: " + location.host + '\n';
|
pre.innerHTML += "host: " + location.host + '\n';
|
||||||
|
|
|
@ -41,6 +41,7 @@ DocumentWrapper::DocumentWrapper(Document& document)
|
||||||
: NodeWrapper(document)
|
: NodeWrapper(document)
|
||||||
{
|
{
|
||||||
put_native_function("getElementById", get_element_by_id, 1);
|
put_native_function("getElementById", get_element_by_id, 1);
|
||||||
|
put_native_function("querySelector", query_selector, 1);
|
||||||
put_native_function("querySelectorAll", query_selector_all, 1);
|
put_native_function("querySelectorAll", query_selector_all, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +87,23 @@ JS::Value DocumentWrapper::get_element_by_id(JS::Interpreter& interpreter)
|
||||||
return wrap(interpreter.heap(), const_cast<Element&>(*element));
|
return wrap(interpreter.heap(), const_cast<Element&>(*element));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS::Value DocumentWrapper::query_selector(JS::Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
auto* document = document_from(interpreter);
|
||||||
|
if (!document)
|
||||||
|
return {};
|
||||||
|
if (!interpreter.argument_count())
|
||||||
|
return interpreter.throw_exception<JS::TypeError>("querySelector() needs one argument");
|
||||||
|
auto selector = interpreter.argument(0).to_string(interpreter);
|
||||||
|
if (interpreter.exception())
|
||||||
|
return {};
|
||||||
|
// FIXME: Throw if selector is invalid
|
||||||
|
auto element = document->query_selector(selector);
|
||||||
|
if (!element)
|
||||||
|
return JS::js_null();
|
||||||
|
return wrap(interpreter.heap(), *element);
|
||||||
|
}
|
||||||
|
|
||||||
JS::Value DocumentWrapper::query_selector_all(JS::Interpreter& interpreter)
|
JS::Value DocumentWrapper::query_selector_all(JS::Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
auto* document = document_from(interpreter);
|
auto* document = document_from(interpreter);
|
||||||
|
@ -96,6 +114,7 @@ JS::Value DocumentWrapper::query_selector_all(JS::Interpreter& interpreter)
|
||||||
auto selector = interpreter.argument(0).to_string(interpreter);
|
auto selector = interpreter.argument(0).to_string(interpreter);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
|
// FIXME: Throw if selector is invalid
|
||||||
auto elements = document->query_selector_all(selector);
|
auto elements = document->query_selector_all(selector);
|
||||||
// FIXME: This should be a static NodeList, not a plain JS::Array.
|
// FIXME: This should be a static NodeList, not a plain JS::Array.
|
||||||
auto* node_list = JS::Array::create(interpreter.global_object());
|
auto* node_list = JS::Array::create(interpreter.global_object());
|
||||||
|
|
|
@ -43,6 +43,7 @@ private:
|
||||||
virtual const char* class_name() const override { return "DocumentWrapper"; }
|
virtual const char* class_name() const override { return "DocumentWrapper"; }
|
||||||
|
|
||||||
static JS::Value get_element_by_id(JS::Interpreter&);
|
static JS::Value get_element_by_id(JS::Interpreter&);
|
||||||
|
static JS::Value query_selector(JS::Interpreter&);
|
||||||
static JS::Value query_selector_all(JS::Interpreter&);
|
static JS::Value query_selector_all(JS::Interpreter&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -321,6 +321,26 @@ Vector<const Element*> Document::get_elements_by_name(const String& name) const
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<Element> Document::query_selector(const StringView& selector_text)
|
||||||
|
{
|
||||||
|
auto selector = parse_selector(selector_text);
|
||||||
|
if (!selector.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
dump_selector(selector.value());
|
||||||
|
|
||||||
|
RefPtr<Element> result;
|
||||||
|
for_each_in_subtree_of_type<Element>([&](auto& element) {
|
||||||
|
if (SelectorEngine::matches(selector.value(), element)) {
|
||||||
|
result = element;
|
||||||
|
return IterationDecision::Break;
|
||||||
|
}
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtrVector<Element> Document::query_selector_all(const StringView& selector_text)
|
NonnullRefPtrVector<Element> Document::query_selector_all(const StringView& selector_text)
|
||||||
{
|
{
|
||||||
auto selector = parse_selector(selector_text);
|
auto selector = parse_selector(selector_text);
|
||||||
|
|
|
@ -116,6 +116,7 @@ public:
|
||||||
void schedule_style_update();
|
void schedule_style_update();
|
||||||
|
|
||||||
Vector<const Element*> get_elements_by_name(const String&) const;
|
Vector<const Element*> get_elements_by_name(const String&) const;
|
||||||
|
RefPtr<Element> query_selector(const StringView&);
|
||||||
NonnullRefPtrVector<Element> query_selector_all(const StringView&);
|
NonnullRefPtrVector<Element> query_selector_all(const StringView&);
|
||||||
|
|
||||||
const String& source() const { return m_source; }
|
const String& source() const { return m_source; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue