mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 04:27:45 +00:00
Libraries: Move to Userland/Libraries/
This commit is contained in:
parent
dc28c07fa5
commit
13d7c09125
1857 changed files with 266 additions and 274 deletions
51
Userland/Libraries/LibWeb/DOM/Attribute.h
Normal file
51
Userland/Libraries/LibWeb/DOM/Attribute.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class Attribute {
|
||||
public:
|
||||
Attribute(const FlyString& name, const String& value)
|
||||
: m_name(name)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
const FlyString& name() const { return m_name; }
|
||||
const String& value() const { return m_value; }
|
||||
|
||||
void set_value(const String& value) { m_value = value; }
|
||||
|
||||
private:
|
||||
FlyString m_name;
|
||||
String m_value;
|
||||
};
|
||||
|
||||
}
|
41
Userland/Libraries/LibWeb/DOM/CharacterData.cpp
Normal file
41
Userland/Libraries/LibWeb/DOM/CharacterData.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/CharacterData.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
CharacterData::CharacterData(Document& document, NodeType type, const String& data)
|
||||
: Node(document, type)
|
||||
, m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
CharacterData::~CharacterData()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
57
Userland/Libraries/LibWeb/DOM/CharacterData.h
Normal file
57
Userland/Libraries/LibWeb/DOM/CharacterData.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/DOM/NonDocumentTypeChildNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class CharacterData
|
||||
: public Node
|
||||
, public NonDocumentTypeChildNode<CharacterData> {
|
||||
public:
|
||||
using WrapperType = Bindings::CharacterDataWrapper;
|
||||
|
||||
virtual ~CharacterData() override;
|
||||
|
||||
const String& data() const { return m_data; }
|
||||
void set_data(const String& data) { m_data = data; }
|
||||
|
||||
unsigned length() const { return m_data.length(); }
|
||||
|
||||
virtual String text_content() const override { return m_data; }
|
||||
|
||||
protected:
|
||||
explicit CharacterData(Document&, NodeType, const String&);
|
||||
|
||||
private:
|
||||
String m_data;
|
||||
};
|
||||
|
||||
}
|
9
Userland/Libraries/LibWeb/DOM/CharacterData.idl
Normal file
9
Userland/Libraries/LibWeb/DOM/CharacterData.idl
Normal file
|
@ -0,0 +1,9 @@
|
|||
interface CharacterData : Node {
|
||||
|
||||
attribute DOMString data;
|
||||
readonly attribute unsigned long length;
|
||||
|
||||
readonly attribute Element? nextElementSibling;
|
||||
readonly attribute Element? previousElementSibling;
|
||||
|
||||
};
|
41
Userland/Libraries/LibWeb/DOM/Comment.cpp
Normal file
41
Userland/Libraries/LibWeb/DOM/Comment.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Comment.h>
|
||||
#include <LibWeb/Layout/TextNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
Comment::Comment(Document& document, const String& data)
|
||||
: CharacterData(document, NodeType::COMMENT_NODE, data)
|
||||
{
|
||||
}
|
||||
|
||||
Comment::~Comment()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
44
Userland/Libraries/LibWeb/DOM/Comment.h
Normal file
44
Userland/Libraries/LibWeb/DOM/Comment.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibWeb/DOM/CharacterData.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Comment final : public CharacterData {
|
||||
public:
|
||||
using WrapperType = Bindings::CommentWrapper;
|
||||
|
||||
explicit Comment(Document&, const String&);
|
||||
virtual ~Comment() override;
|
||||
|
||||
virtual FlyString node_name() const override { return "#comment"; }
|
||||
};
|
||||
|
||||
}
|
3
Userland/Libraries/LibWeb/DOM/Comment.idl
Normal file
3
Userland/Libraries/LibWeb/DOM/Comment.idl
Normal file
|
@ -0,0 +1,3 @@
|
|||
interface Comment : CharacterData {
|
||||
|
||||
};
|
75
Userland/Libraries/LibWeb/DOM/DOMImplementation.cpp
Normal file
75
Userland/Libraries/LibWeb/DOM/DOMImplementation.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/DOMImplementation.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/DocumentType.h>
|
||||
#include <LibWeb/DOM/ElementFactory.h>
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/Namespace.h>
|
||||
#include <LibWeb/Origin.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
DOMImplementation::DOMImplementation(Document& document)
|
||||
: m_document(document)
|
||||
{
|
||||
}
|
||||
|
||||
const NonnullRefPtr<Document> DOMImplementation::create_htmldocument(const String& title) const
|
||||
{
|
||||
auto html_document = Document::create();
|
||||
|
||||
html_document->set_content_type("text/html");
|
||||
html_document->set_ready_for_post_load_tasks(true);
|
||||
|
||||
auto doctype = adopt(*new DocumentType(html_document));
|
||||
doctype->set_name("html");
|
||||
html_document->append_child(doctype);
|
||||
|
||||
auto html_element = create_element(html_document, HTML::TagNames::html, Namespace::HTML);
|
||||
html_document->append_child(html_element);
|
||||
|
||||
auto head_element = create_element(html_document, HTML::TagNames::head, Namespace::HTML);
|
||||
html_element->append_child(head_element);
|
||||
|
||||
if (!title.is_null()) {
|
||||
auto title_element = create_element(html_document, HTML::TagNames::title, Namespace::HTML);
|
||||
head_element->append_child(title_element);
|
||||
|
||||
auto text_node = adopt(*new Text(html_document, title));
|
||||
title_element->append_child(text_node);
|
||||
}
|
||||
|
||||
auto body_element = create_element(html_document, HTML::TagNames::body, Namespace::HTML);
|
||||
html_element->append_child(body_element);
|
||||
|
||||
html_document->set_origin(m_document.origin());
|
||||
|
||||
return html_document;
|
||||
}
|
||||
|
||||
}
|
60
Userland/Libraries/LibWeb/DOM/DOMImplementation.h
Normal file
60
Userland/Libraries/LibWeb/DOM/DOMImplementation.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class DOMImplementation final
|
||||
: public RefCounted<DOMImplementation>
|
||||
, public Weakable<DOMImplementation>
|
||||
, public Bindings::Wrappable {
|
||||
public:
|
||||
using WrapperType = Bindings::DOMImplementationWrapper;
|
||||
|
||||
static NonnullRefPtr<DOMImplementation> create(Document& document)
|
||||
{
|
||||
return adopt(*new DOMImplementation(document));
|
||||
}
|
||||
|
||||
// FIXME: snake_case in WrapperGenerator turns "createHTMLDocument" into "create_htmldocument"
|
||||
const NonnullRefPtr<Document> create_htmldocument(const String& title) const;
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
|
||||
bool has_feature() const { return true; }
|
||||
|
||||
private:
|
||||
explicit DOMImplementation(Document&);
|
||||
|
||||
Document& m_document;
|
||||
};
|
||||
|
||||
}
|
7
Userland/Libraries/LibWeb/DOM/DOMImplementation.idl
Normal file
7
Userland/Libraries/LibWeb/DOM/DOMImplementation.idl
Normal file
|
@ -0,0 +1,7 @@
|
|||
interface DOMImplementation {
|
||||
|
||||
Document createHTMLDocument(optional DOMString title);
|
||||
|
||||
boolean hasFeature();
|
||||
|
||||
};
|
690
Userland/Libraries/LibWeb/DOM/Document.cpp
Normal file
690
Userland/Libraries/LibWeb/DOM/Document.cpp
Normal file
|
@ -0,0 +1,690 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibCore/Timer.h>
|
||||
#include <LibGUI/Application.h>
|
||||
#include <LibGUI/DisplayLink.h>
|
||||
#include <LibGUI/MessageBox.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Parser.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibWeb/Bindings/DocumentWrapper.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/CSS/StyleResolver.h>
|
||||
#include <LibWeb/DOM/Comment.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/DocumentFragment.h>
|
||||
#include <LibWeb/DOM/DocumentType.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/ElementFactory.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/DOM/Window.h>
|
||||
#include <LibWeb/Dump.h>
|
||||
#include <LibWeb/HTML/AttributeNames.h>
|
||||
#include <LibWeb/HTML/EventNames.h>
|
||||
#include <LibWeb/HTML/HTMLBodyElement.h>
|
||||
#include <LibWeb/HTML/HTMLFrameSetElement.h>
|
||||
#include <LibWeb/HTML/HTMLHeadElement.h>
|
||||
#include <LibWeb/HTML/HTMLHtmlElement.h>
|
||||
#include <LibWeb/HTML/HTMLScriptElement.h>
|
||||
#include <LibWeb/HTML/HTMLTitleElement.h>
|
||||
#include <LibWeb/InProcessWebView.h>
|
||||
#include <LibWeb/Layout/BlockFormattingContext.h>
|
||||
#include <LibWeb/Layout/InitialContainingBlockBox.h>
|
||||
#include <LibWeb/Layout/TreeBuilder.h>
|
||||
#include <LibWeb/Namespace.h>
|
||||
#include <LibWeb/Origin.h>
|
||||
#include <LibWeb/Page/Frame.h>
|
||||
#include <LibWeb/SVG/TagNames.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
Document::Document(const URL& url)
|
||||
: ParentNode(*this, NodeType::DOCUMENT_NODE)
|
||||
, m_style_resolver(make<CSS::StyleResolver>(*this))
|
||||
, m_style_sheets(CSS::StyleSheetList::create(*this))
|
||||
, m_url(url)
|
||||
, m_window(Window::create_with_document(*this))
|
||||
, m_implementation(DOMImplementation::create(*this))
|
||||
{
|
||||
m_style_update_timer = Core::Timer::create_single_shot(0, [this] {
|
||||
update_style();
|
||||
});
|
||||
|
||||
m_forced_layout_timer = Core::Timer::create_single_shot(0, [this] {
|
||||
force_layout();
|
||||
});
|
||||
}
|
||||
|
||||
Document::~Document()
|
||||
{
|
||||
}
|
||||
|
||||
void Document::removed_last_ref()
|
||||
{
|
||||
ASSERT(!ref_count());
|
||||
ASSERT(!m_deletion_has_begun);
|
||||
|
||||
if (m_referencing_node_count) {
|
||||
// The document has reached ref_count==0 but still has nodes keeping it alive.
|
||||
// At this point, sever all the node links we control.
|
||||
// If nodes remain elsewhere (e.g JS wrappers), they will keep the document alive.
|
||||
|
||||
// NOTE: This makes sure we stay alive across for the duration of the cleanup below.
|
||||
increment_referencing_node_count();
|
||||
|
||||
m_focused_element = nullptr;
|
||||
m_hovered_node = nullptr;
|
||||
m_pending_parsing_blocking_script = nullptr;
|
||||
m_inspected_node = nullptr;
|
||||
m_scripts_to_execute_when_parsing_has_finished.clear();
|
||||
m_scripts_to_execute_as_soon_as_possible.clear();
|
||||
m_associated_inert_template_document = nullptr;
|
||||
|
||||
m_interpreter = nullptr;
|
||||
|
||||
{
|
||||
// Gather up all the descendants of this document and prune them from the tree.
|
||||
// FIXME: This could definitely be more elegant.
|
||||
NonnullRefPtrVector<Node> descendants;
|
||||
for_each_in_subtree([&](auto& node) {
|
||||
if (&node != this)
|
||||
descendants.append(node);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
for (auto& node : descendants) {
|
||||
ASSERT(&node.document() == this);
|
||||
ASSERT(!node.is_document());
|
||||
if (node.parent())
|
||||
node.parent()->remove_child(node);
|
||||
}
|
||||
}
|
||||
|
||||
m_in_removed_last_ref = false;
|
||||
decrement_referencing_node_count();
|
||||
return;
|
||||
}
|
||||
|
||||
m_in_removed_last_ref = false;
|
||||
m_deletion_has_begun = true;
|
||||
delete this;
|
||||
}
|
||||
|
||||
Origin Document::origin() const
|
||||
{
|
||||
if (!m_url.is_valid())
|
||||
return {};
|
||||
return { m_url.protocol(), m_url.host(), m_url.port() };
|
||||
}
|
||||
|
||||
void Document::set_origin(const Origin& origin)
|
||||
{
|
||||
m_url.set_protocol(origin.protocol());
|
||||
m_url.set_host(origin.host());
|
||||
m_url.set_port(origin.port());
|
||||
}
|
||||
|
||||
void Document::schedule_style_update()
|
||||
{
|
||||
if (m_style_update_timer->is_active())
|
||||
return;
|
||||
m_style_update_timer->start();
|
||||
}
|
||||
|
||||
void Document::schedule_forced_layout()
|
||||
{
|
||||
if (m_forced_layout_timer->is_active())
|
||||
return;
|
||||
m_forced_layout_timer->start();
|
||||
}
|
||||
|
||||
bool Document::is_child_allowed(const Node& node) const
|
||||
{
|
||||
switch (node.type()) {
|
||||
case NodeType::DOCUMENT_NODE:
|
||||
case NodeType::TEXT_NODE:
|
||||
return false;
|
||||
case NodeType::COMMENT_NODE:
|
||||
return true;
|
||||
case NodeType::DOCUMENT_TYPE_NODE:
|
||||
return !first_child_of_type<DocumentType>();
|
||||
case NodeType::ELEMENT_NODE:
|
||||
return !first_child_of_type<Element>();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const Element* Document::document_element() const
|
||||
{
|
||||
return first_child_of_type<Element>();
|
||||
}
|
||||
|
||||
const HTML::HTMLHtmlElement* Document::html_element() const
|
||||
{
|
||||
auto* html = document_element();
|
||||
if (is<HTML::HTMLHtmlElement>(html))
|
||||
return downcast<HTML::HTMLHtmlElement>(html);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const HTML::HTMLHeadElement* Document::head() const
|
||||
{
|
||||
auto* html = html_element();
|
||||
if (!html)
|
||||
return nullptr;
|
||||
return html->first_child_of_type<HTML::HTMLHeadElement>();
|
||||
}
|
||||
|
||||
const HTML::HTMLElement* Document::body() const
|
||||
{
|
||||
auto* html = html_element();
|
||||
if (!html)
|
||||
return nullptr;
|
||||
auto* first_body = html->first_child_of_type<HTML::HTMLBodyElement>();
|
||||
if (first_body)
|
||||
return first_body;
|
||||
auto* first_frameset = html->first_child_of_type<HTML::HTMLFrameSetElement>();
|
||||
if (first_frameset)
|
||||
return first_frameset;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Document::set_body(HTML::HTMLElement& new_body)
|
||||
{
|
||||
if (!is<HTML::HTMLBodyElement>(new_body) && !is<HTML::HTMLFrameSetElement>(new_body)) {
|
||||
// FIXME: throw a "HierarchyRequestError" DOMException.
|
||||
return;
|
||||
}
|
||||
|
||||
auto* existing_body = body();
|
||||
if (existing_body) {
|
||||
TODO();
|
||||
return;
|
||||
}
|
||||
|
||||
auto* html = document_element();
|
||||
if (!html) {
|
||||
// FIXME: throw a "HierarchyRequestError" DOMException.
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Implement this once there's a non-const first_child_of_type:
|
||||
// "Otherwise, the body element is null, but there's a document element. Append the new value to the document element."
|
||||
TODO();
|
||||
}
|
||||
|
||||
String Document::title() const
|
||||
{
|
||||
auto* head_element = head();
|
||||
if (!head_element)
|
||||
return {};
|
||||
|
||||
auto* title_element = head_element->first_child_of_type<HTML::HTMLTitleElement>();
|
||||
if (!title_element)
|
||||
return {};
|
||||
|
||||
auto raw_title = title_element->text_content();
|
||||
|
||||
StringBuilder builder;
|
||||
bool last_was_space = false;
|
||||
for (auto code_point : Utf8View(raw_title)) {
|
||||
if (isspace(code_point)) {
|
||||
last_was_space = true;
|
||||
} else {
|
||||
if (last_was_space && !builder.is_empty())
|
||||
builder.append(' ');
|
||||
builder.append_code_point(code_point);
|
||||
last_was_space = false;
|
||||
}
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
void Document::set_title(const String& title)
|
||||
{
|
||||
auto* head_element = const_cast<HTML::HTMLHeadElement*>(head());
|
||||
if (!head_element)
|
||||
return;
|
||||
|
||||
RefPtr<HTML::HTMLTitleElement> title_element = head_element->first_child_of_type<HTML::HTMLTitleElement>();
|
||||
if (!title_element) {
|
||||
title_element = static_ptr_cast<HTML::HTMLTitleElement>(create_element(HTML::TagNames::title));
|
||||
head_element->append_child(*title_element);
|
||||
}
|
||||
|
||||
while (RefPtr<Node> child = title_element->first_child())
|
||||
title_element->remove_child(child.release_nonnull());
|
||||
|
||||
title_element->append_child(adopt(*new Text(*this, title)));
|
||||
|
||||
if (auto* page = this->page())
|
||||
page->client().page_did_change_title(title);
|
||||
}
|
||||
|
||||
void Document::attach_to_frame(Badge<Frame>, Frame& frame)
|
||||
{
|
||||
m_frame = frame;
|
||||
update_layout();
|
||||
}
|
||||
|
||||
void Document::detach_from_frame(Badge<Frame>, Frame& frame)
|
||||
{
|
||||
ASSERT(&frame == m_frame);
|
||||
tear_down_layout_tree();
|
||||
m_frame = nullptr;
|
||||
}
|
||||
|
||||
void Document::tear_down_layout_tree()
|
||||
{
|
||||
if (!m_layout_root)
|
||||
return;
|
||||
|
||||
// Gather up all the layout nodes in a vector and detach them from parents
|
||||
// while the vector keeps them alive.
|
||||
|
||||
NonnullRefPtrVector<Layout::Node> layout_nodes;
|
||||
|
||||
m_layout_root->for_each_in_subtree([&](auto& layout_node) {
|
||||
layout_nodes.append(layout_node);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
for (auto& layout_node : layout_nodes) {
|
||||
if (layout_node.parent())
|
||||
layout_node.parent()->remove_child(layout_node);
|
||||
}
|
||||
|
||||
m_layout_root = nullptr;
|
||||
}
|
||||
|
||||
Color Document::background_color(const Palette& palette) const
|
||||
{
|
||||
auto default_color = palette.base();
|
||||
auto* body_element = body();
|
||||
if (!body_element)
|
||||
return default_color;
|
||||
|
||||
auto* body_layout_node = body_element->layout_node();
|
||||
if (!body_layout_node)
|
||||
return default_color;
|
||||
|
||||
auto color = body_layout_node->computed_values().background_color();
|
||||
if (!color.alpha())
|
||||
return default_color;
|
||||
return color;
|
||||
}
|
||||
|
||||
RefPtr<Gfx::Bitmap> Document::background_image() const
|
||||
{
|
||||
auto* body_element = body();
|
||||
if (!body_element)
|
||||
return {};
|
||||
|
||||
auto* body_layout_node = body_element->layout_node();
|
||||
if (!body_layout_node)
|
||||
return {};
|
||||
|
||||
auto background_image = body_layout_node->background_image();
|
||||
if (!background_image)
|
||||
return {};
|
||||
return background_image->bitmap();
|
||||
}
|
||||
|
||||
URL Document::complete_url(const String& string) const
|
||||
{
|
||||
return m_url.complete_url(string);
|
||||
}
|
||||
|
||||
void Document::invalidate_layout()
|
||||
{
|
||||
tear_down_layout_tree();
|
||||
}
|
||||
|
||||
void Document::force_layout()
|
||||
{
|
||||
invalidate_layout();
|
||||
update_layout();
|
||||
}
|
||||
|
||||
void Document::update_layout()
|
||||
{
|
||||
if (!frame())
|
||||
return;
|
||||
|
||||
if (!m_layout_root) {
|
||||
Layout::TreeBuilder tree_builder;
|
||||
m_layout_root = static_ptr_cast<Layout::InitialContainingBlockBox>(tree_builder.build(*this));
|
||||
}
|
||||
|
||||
Layout::BlockFormattingContext root_formatting_context(*m_layout_root, nullptr);
|
||||
root_formatting_context.run(*m_layout_root, Layout::LayoutMode::Default);
|
||||
|
||||
m_layout_root->set_needs_display();
|
||||
|
||||
if (frame()->is_main_frame()) {
|
||||
if (auto* page = this->page())
|
||||
page->client().page_did_layout();
|
||||
}
|
||||
}
|
||||
|
||||
static void update_style_recursively(DOM::Node& node)
|
||||
{
|
||||
node.for_each_child([&](auto& child) {
|
||||
if (child.needs_style_update()) {
|
||||
if (is<Element>(child))
|
||||
downcast<Element>(child).recompute_style();
|
||||
child.set_needs_style_update(false);
|
||||
}
|
||||
if (child.child_needs_style_update()) {
|
||||
update_style_recursively(child);
|
||||
child.set_child_needs_style_update(false);
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
void Document::update_style()
|
||||
{
|
||||
update_style_recursively(*this);
|
||||
update_layout();
|
||||
}
|
||||
|
||||
RefPtr<Layout::Node> Document::create_layout_node()
|
||||
{
|
||||
return adopt(*new Layout::InitialContainingBlockBox(*this, CSS::StyleProperties::create()));
|
||||
}
|
||||
|
||||
void Document::set_link_color(Color color)
|
||||
{
|
||||
m_link_color = color;
|
||||
}
|
||||
|
||||
void Document::set_active_link_color(Color color)
|
||||
{
|
||||
m_active_link_color = color;
|
||||
}
|
||||
|
||||
void Document::set_visited_link_color(Color color)
|
||||
{
|
||||
m_visited_link_color = color;
|
||||
}
|
||||
|
||||
const Layout::InitialContainingBlockBox* Document::layout_node() const
|
||||
{
|
||||
return static_cast<const Layout::InitialContainingBlockBox*>(Node::layout_node());
|
||||
}
|
||||
|
||||
Layout::InitialContainingBlockBox* Document::layout_node()
|
||||
{
|
||||
return static_cast<Layout::InitialContainingBlockBox*>(Node::layout_node());
|
||||
}
|
||||
|
||||
void Document::set_inspected_node(Node* node)
|
||||
{
|
||||
if (m_inspected_node == node)
|
||||
return;
|
||||
|
||||
if (m_inspected_node && m_inspected_node->layout_node())
|
||||
m_inspected_node->layout_node()->set_needs_display();
|
||||
|
||||
m_inspected_node = node;
|
||||
|
||||
if (m_inspected_node && m_inspected_node->layout_node())
|
||||
m_inspected_node->layout_node()->set_needs_display();
|
||||
}
|
||||
|
||||
void Document::set_hovered_node(Node* node)
|
||||
{
|
||||
if (m_hovered_node == node)
|
||||
return;
|
||||
|
||||
RefPtr<Node> old_hovered_node = move(m_hovered_node);
|
||||
m_hovered_node = node;
|
||||
|
||||
invalidate_style();
|
||||
}
|
||||
|
||||
NonnullRefPtrVector<Element> Document::get_elements_by_name(const String& name) const
|
||||
{
|
||||
NonnullRefPtrVector<Element> elements;
|
||||
for_each_in_subtree_of_type<Element>([&](auto& element) {
|
||||
if (element.attribute(HTML::AttributeNames::name) == name)
|
||||
elements.append(element);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return elements;
|
||||
}
|
||||
|
||||
NonnullRefPtrVector<Element> Document::get_elements_by_tag_name(const FlyString& tag_name) const
|
||||
{
|
||||
NonnullRefPtrVector<Element> elements;
|
||||
for_each_in_subtree_of_type<Element>([&](auto& element) {
|
||||
if (element.local_name() == tag_name)
|
||||
elements.append(element);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return elements;
|
||||
}
|
||||
|
||||
NonnullRefPtrVector<Element> Document::get_elements_by_class_name(const FlyString& class_name) const
|
||||
{
|
||||
NonnullRefPtrVector<Element> elements;
|
||||
for_each_in_subtree_of_type<Element>([&](auto& element) {
|
||||
if (element.has_class(class_name))
|
||||
elements.append(element);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return elements;
|
||||
}
|
||||
|
||||
Color Document::link_color() const
|
||||
{
|
||||
if (m_link_color.has_value())
|
||||
return m_link_color.value();
|
||||
if (!page())
|
||||
return Color::Blue;
|
||||
return page()->palette().link();
|
||||
}
|
||||
|
||||
Color Document::active_link_color() const
|
||||
{
|
||||
if (m_active_link_color.has_value())
|
||||
return m_active_link_color.value();
|
||||
if (!page())
|
||||
return Color::Red;
|
||||
return page()->palette().active_link();
|
||||
}
|
||||
|
||||
Color Document::visited_link_color() const
|
||||
{
|
||||
if (m_visited_link_color.has_value())
|
||||
return m_visited_link_color.value();
|
||||
if (!page())
|
||||
return Color::Magenta;
|
||||
return page()->palette().visited_link();
|
||||
}
|
||||
|
||||
static JS::VM& main_thread_vm()
|
||||
{
|
||||
static RefPtr<JS::VM> vm;
|
||||
if (!vm) {
|
||||
vm = JS::VM::create();
|
||||
vm->set_should_log_exceptions(true);
|
||||
}
|
||||
return *vm;
|
||||
}
|
||||
|
||||
JS::Interpreter& Document::interpreter()
|
||||
{
|
||||
if (!m_interpreter)
|
||||
m_interpreter = JS::Interpreter::create<Bindings::WindowObject>(main_thread_vm(), *m_window);
|
||||
return *m_interpreter;
|
||||
}
|
||||
|
||||
JS::Value Document::run_javascript(const StringView& source)
|
||||
{
|
||||
auto parser = JS::Parser(JS::Lexer(source));
|
||||
auto program = parser.parse_program();
|
||||
if (parser.has_errors()) {
|
||||
parser.print_errors();
|
||||
return JS::js_undefined();
|
||||
}
|
||||
auto& interpreter = document().interpreter();
|
||||
auto result = interpreter.run(interpreter.global_object(), *program);
|
||||
if (interpreter.exception())
|
||||
interpreter.vm().clear_exception();
|
||||
return result;
|
||||
}
|
||||
|
||||
NonnullRefPtr<Element> Document::create_element(const String& tag_name)
|
||||
{
|
||||
// FIXME: Let namespace be the HTML namespace, if this is an HTML document or this’s content type is "application/xhtml+xml", and null otherwise.
|
||||
return DOM::create_element(*this, tag_name, Namespace::HTML);
|
||||
}
|
||||
|
||||
NonnullRefPtr<DocumentFragment> Document::create_document_fragment()
|
||||
{
|
||||
return adopt(*new DocumentFragment(*this));
|
||||
}
|
||||
|
||||
NonnullRefPtr<Text> Document::create_text_node(const String& data)
|
||||
{
|
||||
return adopt(*new Text(*this, data));
|
||||
}
|
||||
|
||||
NonnullRefPtr<Comment> Document::create_comment(const String& data)
|
||||
{
|
||||
return adopt(*new Comment(*this, data));
|
||||
}
|
||||
|
||||
void Document::set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement* script)
|
||||
{
|
||||
m_pending_parsing_blocking_script = script;
|
||||
}
|
||||
|
||||
NonnullRefPtr<HTML::HTMLScriptElement> Document::take_pending_parsing_blocking_script(Badge<HTML::HTMLDocumentParser>)
|
||||
{
|
||||
return m_pending_parsing_blocking_script.release_nonnull();
|
||||
}
|
||||
|
||||
void Document::add_script_to_execute_when_parsing_has_finished(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement& script)
|
||||
{
|
||||
m_scripts_to_execute_when_parsing_has_finished.append(script);
|
||||
}
|
||||
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> Document::take_scripts_to_execute_when_parsing_has_finished(Badge<HTML::HTMLDocumentParser>)
|
||||
{
|
||||
return move(m_scripts_to_execute_when_parsing_has_finished);
|
||||
}
|
||||
|
||||
void Document::add_script_to_execute_as_soon_as_possible(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement& script)
|
||||
{
|
||||
m_scripts_to_execute_as_soon_as_possible.append(script);
|
||||
}
|
||||
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> Document::take_scripts_to_execute_as_soon_as_possible(Badge<HTML::HTMLDocumentParser>)
|
||||
{
|
||||
return move(m_scripts_to_execute_as_soon_as_possible);
|
||||
}
|
||||
|
||||
void Document::adopt_node(Node& subtree_root)
|
||||
{
|
||||
subtree_root.for_each_in_subtree([&](auto& node) {
|
||||
node.set_document({}, *this);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
const DocumentType* Document::doctype() const
|
||||
{
|
||||
return first_child_of_type<DocumentType>();
|
||||
}
|
||||
|
||||
const String& Document::compat_mode() const
|
||||
{
|
||||
static String back_compat = "BackCompat";
|
||||
static String css1_compat = "CSS1Compat";
|
||||
|
||||
if (m_quirks_mode == QuirksMode::Yes)
|
||||
return back_compat;
|
||||
|
||||
return css1_compat;
|
||||
}
|
||||
|
||||
bool Document::is_editable() const
|
||||
{
|
||||
return m_editable;
|
||||
}
|
||||
|
||||
void Document::set_focused_element(Element* element)
|
||||
{
|
||||
if (m_focused_element == element)
|
||||
return;
|
||||
|
||||
m_focused_element = element;
|
||||
|
||||
if (m_layout_root)
|
||||
m_layout_root->set_needs_display();
|
||||
}
|
||||
|
||||
void Document::set_ready_state(const String& ready_state)
|
||||
{
|
||||
m_ready_state = ready_state;
|
||||
dispatch_event(Event::create(HTML::EventNames::readystatechange));
|
||||
}
|
||||
|
||||
Page* Document::page()
|
||||
{
|
||||
return m_frame ? m_frame->page() : nullptr;
|
||||
}
|
||||
|
||||
const Page* Document::page() const
|
||||
{
|
||||
return m_frame ? m_frame->page() : nullptr;
|
||||
}
|
||||
|
||||
EventTarget* Document::get_parent(const Event& event)
|
||||
{
|
||||
if (event.type() == HTML::EventNames::load)
|
||||
return nullptr;
|
||||
|
||||
return &window();
|
||||
}
|
||||
|
||||
void Document::completely_finish_loading()
|
||||
{
|
||||
// FIXME: This needs to handle iframes.
|
||||
dispatch_event(DOM::Event::create(HTML::EventNames::load));
|
||||
}
|
||||
|
||||
}
|
295
Userland/Libraries/LibWeb/DOM/Document.h
Normal file
295
Userland/Libraries/LibWeb/DOM/Document.h
Normal file
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/NonnullRefPtrVector.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/URL.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <LibCore/Forward.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibWeb/Bindings/ScriptExecutionContext.h>
|
||||
#include <LibWeb/CSS/StyleResolver.h>
|
||||
#include <LibWeb/CSS/StyleSheet.h>
|
||||
#include <LibWeb/CSS/StyleSheetList.h>
|
||||
#include <LibWeb/DOM/DOMImplementation.h>
|
||||
#include <LibWeb/DOM/NonElementParentNode.h>
|
||||
#include <LibWeb/DOM/ParentNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
enum class QuirksMode {
|
||||
No,
|
||||
Limited,
|
||||
Yes
|
||||
};
|
||||
|
||||
class Document
|
||||
: public ParentNode
|
||||
, public NonElementParentNode<Document>
|
||||
, public Bindings::ScriptExecutionContext {
|
||||
public:
|
||||
using WrapperType = Bindings::DocumentWrapper;
|
||||
|
||||
static NonnullRefPtr<Document> create(const URL& url = "about:blank") { return adopt(*new Document(url)); }
|
||||
virtual ~Document() override;
|
||||
|
||||
bool should_invalidate_styles_on_attribute_changes() const { return m_should_invalidate_styles_on_attribute_changes; }
|
||||
void set_should_invalidate_styles_on_attribute_changes(bool b) { m_should_invalidate_styles_on_attribute_changes = b; }
|
||||
|
||||
void set_url(const URL& url) { m_url = url; }
|
||||
URL url() const { return m_url; }
|
||||
|
||||
Origin origin() const;
|
||||
void set_origin(const Origin& origin);
|
||||
|
||||
bool is_scripting_enabled() const { return true; }
|
||||
|
||||
URL complete_url(const String&) const;
|
||||
|
||||
CSS::StyleResolver& style_resolver() { return *m_style_resolver; }
|
||||
const CSS::StyleResolver& style_resolver() const { return *m_style_resolver; }
|
||||
|
||||
CSS::StyleSheetList& style_sheets() { return *m_style_sheets; }
|
||||
const CSS::StyleSheetList& style_sheets() const { return *m_style_sheets; }
|
||||
|
||||
virtual FlyString node_name() const override { return "#document"; }
|
||||
|
||||
void set_hovered_node(Node*);
|
||||
Node* hovered_node() { return m_hovered_node; }
|
||||
const Node* hovered_node() const { return m_hovered_node; }
|
||||
|
||||
void set_inspected_node(Node*);
|
||||
Node* inspected_node() { return m_inspected_node; }
|
||||
const Node* inspected_node() const { return m_inspected_node; }
|
||||
|
||||
const Element* document_element() const;
|
||||
const HTML::HTMLHtmlElement* html_element() const;
|
||||
const HTML::HTMLHeadElement* head() const;
|
||||
const HTML::HTMLElement* body() const;
|
||||
void set_body(HTML::HTMLElement& new_body);
|
||||
|
||||
String title() const;
|
||||
void set_title(const String&);
|
||||
|
||||
void attach_to_frame(Badge<Frame>, Frame&);
|
||||
void detach_from_frame(Badge<Frame>, Frame&);
|
||||
|
||||
Frame* frame() { return m_frame.ptr(); }
|
||||
const Frame* frame() const { return m_frame.ptr(); }
|
||||
|
||||
Page* page();
|
||||
const Page* page() const;
|
||||
|
||||
Color background_color(const Gfx::Palette&) const;
|
||||
RefPtr<Gfx::Bitmap> background_image() const;
|
||||
|
||||
Color link_color() const;
|
||||
void set_link_color(Color);
|
||||
|
||||
Color active_link_color() const;
|
||||
void set_active_link_color(Color);
|
||||
|
||||
Color visited_link_color() const;
|
||||
void set_visited_link_color(Color);
|
||||
|
||||
void force_layout();
|
||||
void invalidate_layout();
|
||||
|
||||
void update_style();
|
||||
void update_layout();
|
||||
|
||||
virtual bool is_child_allowed(const Node&) const override;
|
||||
|
||||
const Layout::InitialContainingBlockBox* layout_node() const;
|
||||
Layout::InitialContainingBlockBox* layout_node();
|
||||
|
||||
void schedule_style_update();
|
||||
void schedule_forced_layout();
|
||||
|
||||
NonnullRefPtrVector<Element> get_elements_by_name(const String&) const;
|
||||
NonnullRefPtrVector<Element> get_elements_by_tag_name(const FlyString&) const;
|
||||
NonnullRefPtrVector<Element> get_elements_by_class_name(const FlyString&) const;
|
||||
|
||||
const String& source() const { return m_source; }
|
||||
void set_source(const String& source) { m_source = source; }
|
||||
|
||||
virtual JS::Interpreter& interpreter() override;
|
||||
|
||||
JS::Value run_javascript(const StringView&);
|
||||
|
||||
NonnullRefPtr<Element> create_element(const String& tag_name);
|
||||
NonnullRefPtr<DocumentFragment> create_document_fragment();
|
||||
NonnullRefPtr<Text> create_text_node(const String& data);
|
||||
NonnullRefPtr<Comment> create_comment(const String& data);
|
||||
|
||||
void set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement*);
|
||||
HTML::HTMLScriptElement* pending_parsing_blocking_script() { return m_pending_parsing_blocking_script; }
|
||||
NonnullRefPtr<HTML::HTMLScriptElement> take_pending_parsing_blocking_script(Badge<HTML::HTMLDocumentParser>);
|
||||
|
||||
void add_script_to_execute_when_parsing_has_finished(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement&);
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> take_scripts_to_execute_when_parsing_has_finished(Badge<HTML::HTMLDocumentParser>);
|
||||
|
||||
void add_script_to_execute_as_soon_as_possible(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement&);
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> take_scripts_to_execute_as_soon_as_possible(Badge<HTML::HTMLDocumentParser>);
|
||||
|
||||
QuirksMode mode() const { return m_quirks_mode; }
|
||||
bool in_quirks_mode() const { return m_quirks_mode == QuirksMode::Yes; }
|
||||
void set_quirks_mode(QuirksMode mode) { m_quirks_mode = mode; }
|
||||
|
||||
void adopt_node(Node&);
|
||||
|
||||
const DocumentType* doctype() const;
|
||||
const String& compat_mode() const;
|
||||
|
||||
void set_editable(bool editable) { m_editable = editable; }
|
||||
virtual bool is_editable() const final;
|
||||
|
||||
Element* focused_element() { return m_focused_element; }
|
||||
const Element* focused_element() const { return m_focused_element; }
|
||||
|
||||
void set_focused_element(Element*);
|
||||
|
||||
bool created_for_appropriate_template_contents() const { return m_created_for_appropriate_template_contents; }
|
||||
void set_created_for_appropriate_template_contents(bool value) { m_created_for_appropriate_template_contents = value; }
|
||||
|
||||
Document* associated_inert_template_document() { return m_associated_inert_template_document; }
|
||||
const Document* associated_inert_template_document() const { return m_associated_inert_template_document; }
|
||||
void set_associated_inert_template_document(Document& document) { m_associated_inert_template_document = document; }
|
||||
|
||||
const String& ready_state() const { return m_ready_state; }
|
||||
void set_ready_state(const String&);
|
||||
|
||||
void ref_from_node(Badge<Node>)
|
||||
{
|
||||
increment_referencing_node_count();
|
||||
}
|
||||
|
||||
void unref_from_node(Badge<Node>)
|
||||
{
|
||||
decrement_referencing_node_count();
|
||||
}
|
||||
|
||||
void removed_last_ref();
|
||||
|
||||
Window& window() { return *m_window; }
|
||||
|
||||
const String& content_type() const { return m_content_type; }
|
||||
void set_content_type(const String& content_type) { m_content_type = content_type; }
|
||||
|
||||
const String& encoding() const { return m_encoding; }
|
||||
void set_encoding(const String& encoding) { m_encoding = encoding; }
|
||||
|
||||
// NOTE: These are intended for the JS bindings
|
||||
const String& character_set() const { return encoding(); }
|
||||
const String& charset() const { return encoding(); }
|
||||
const String& input_encoding() const { return encoding(); }
|
||||
|
||||
bool ready_for_post_load_tasks() const { return m_ready_for_post_load_tasks; }
|
||||
void set_ready_for_post_load_tasks(bool ready) { m_ready_for_post_load_tasks = ready; }
|
||||
|
||||
void completely_finish_loading();
|
||||
|
||||
const NonnullRefPtr<DOMImplementation> implementation() const { return m_implementation; }
|
||||
|
||||
virtual EventTarget* get_parent(const Event&) override;
|
||||
|
||||
private:
|
||||
explicit Document(const URL&);
|
||||
|
||||
virtual RefPtr<Layout::Node> create_layout_node() override;
|
||||
|
||||
void tear_down_layout_tree();
|
||||
|
||||
void increment_referencing_node_count()
|
||||
{
|
||||
ASSERT(!m_deletion_has_begun);
|
||||
++m_referencing_node_count;
|
||||
}
|
||||
|
||||
void decrement_referencing_node_count()
|
||||
{
|
||||
ASSERT(!m_deletion_has_begun);
|
||||
ASSERT(m_referencing_node_count);
|
||||
--m_referencing_node_count;
|
||||
if (!m_referencing_node_count && !ref_count()) {
|
||||
m_deletion_has_begun = true;
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned m_referencing_node_count { 0 };
|
||||
|
||||
OwnPtr<CSS::StyleResolver> m_style_resolver;
|
||||
RefPtr<CSS::StyleSheetList> m_style_sheets;
|
||||
RefPtr<Node> m_hovered_node;
|
||||
RefPtr<Node> m_inspected_node;
|
||||
WeakPtr<Frame> m_frame;
|
||||
URL m_url;
|
||||
|
||||
RefPtr<Window> m_window;
|
||||
|
||||
RefPtr<Layout::InitialContainingBlockBox> m_layout_root;
|
||||
|
||||
Optional<Color> m_link_color;
|
||||
Optional<Color> m_active_link_color;
|
||||
Optional<Color> m_visited_link_color;
|
||||
|
||||
RefPtr<Core::Timer> m_style_update_timer;
|
||||
RefPtr<Core::Timer> m_forced_layout_timer;
|
||||
|
||||
String m_source;
|
||||
|
||||
OwnPtr<JS::Interpreter> m_interpreter;
|
||||
|
||||
RefPtr<HTML::HTMLScriptElement> m_pending_parsing_blocking_script;
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> m_scripts_to_execute_when_parsing_has_finished;
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> m_scripts_to_execute_as_soon_as_possible;
|
||||
|
||||
QuirksMode m_quirks_mode { QuirksMode::No };
|
||||
bool m_editable { false };
|
||||
|
||||
WeakPtr<Element> m_focused_element;
|
||||
|
||||
bool m_created_for_appropriate_template_contents { false };
|
||||
RefPtr<Document> m_associated_inert_template_document;
|
||||
|
||||
String m_ready_state { "loading" };
|
||||
String m_content_type { "application/xml" };
|
||||
String m_encoding { "UTF-8" };
|
||||
|
||||
bool m_ready_for_post_load_tasks { false };
|
||||
|
||||
NonnullRefPtr<DOMImplementation> m_implementation;
|
||||
|
||||
bool m_should_invalidate_styles_on_attribute_changes { true };
|
||||
};
|
||||
|
||||
}
|
37
Userland/Libraries/LibWeb/DOM/Document.idl
Normal file
37
Userland/Libraries/LibWeb/DOM/Document.idl
Normal file
|
@ -0,0 +1,37 @@
|
|||
interface Document : Node {
|
||||
|
||||
readonly attribute DOMImplementation implementation;
|
||||
|
||||
readonly attribute DOMString characterSet;
|
||||
readonly attribute DOMString charset;
|
||||
readonly attribute DOMString inputEncoding;
|
||||
readonly attribute DOMString contentType;
|
||||
|
||||
Element? getElementById(DOMString id);
|
||||
ArrayFromVector getElementsByName(DOMString name);
|
||||
ArrayFromVector getElementsByTagName(DOMString tagName);
|
||||
ArrayFromVector getElementsByClassName(DOMString className);
|
||||
|
||||
readonly attribute Element? firstElementChild;
|
||||
readonly attribute Element? lastElementChild;
|
||||
|
||||
Element? querySelector(DOMString selectors);
|
||||
ArrayFromVector querySelectorAll(DOMString selectors);
|
||||
|
||||
Element createElement(DOMString tagName);
|
||||
DocumentFragment createDocumentFragment();
|
||||
Text createTextNode(DOMString data);
|
||||
Comment createComment(DOMString data);
|
||||
|
||||
readonly attribute DOMString compatMode;
|
||||
readonly attribute DocumentType? doctype;
|
||||
|
||||
readonly attribute Element? documentElement;
|
||||
attribute HTMLElement? body;
|
||||
readonly attribute HTMLHeadElement? head;
|
||||
|
||||
readonly attribute DOMString readyState;
|
||||
|
||||
attribute DOMString title;
|
||||
|
||||
};
|
40
Userland/Libraries/LibWeb/DOM/DocumentFragment.cpp
Normal file
40
Userland/Libraries/LibWeb/DOM/DocumentFragment.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Luke Wilde <luke.wilde@live.co.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/DocumentFragment.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
DocumentFragment::DocumentFragment(Document& document)
|
||||
: ParentNode(document, NodeType::DOCUMENT_FRAGMENT_NODE)
|
||||
{
|
||||
}
|
||||
|
||||
DocumentFragment::~DocumentFragment()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
56
Userland/Libraries/LibWeb/DOM/DocumentFragment.h
Normal file
56
Userland/Libraries/LibWeb/DOM/DocumentFragment.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/NonElementParentNode.h>
|
||||
#include <LibWeb/DOM/ParentNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class DocumentFragment
|
||||
: public ParentNode
|
||||
, public NonElementParentNode<DocumentFragment> {
|
||||
public:
|
||||
using WrapperType = Bindings::DocumentFragmentWrapper;
|
||||
|
||||
explicit DocumentFragment(Document& document);
|
||||
virtual ~DocumentFragment() override;
|
||||
|
||||
virtual FlyString node_name() const override { return "#document-fragment"; }
|
||||
|
||||
RefPtr<Element> host() { return m_host; }
|
||||
const RefPtr<Element> host() const { return m_host; }
|
||||
|
||||
void set_host(Element& host) { m_host = host; }
|
||||
|
||||
private:
|
||||
RefPtr<Element> m_host;
|
||||
};
|
||||
|
||||
}
|
11
Userland/Libraries/LibWeb/DOM/DocumentFragment.idl
Normal file
11
Userland/Libraries/LibWeb/DOM/DocumentFragment.idl
Normal file
|
@ -0,0 +1,11 @@
|
|||
interface DocumentFragment : Node {
|
||||
|
||||
Element? getElementById(DOMString id);
|
||||
|
||||
readonly attribute Element? firstElementChild;
|
||||
readonly attribute Element? lastElementChild;
|
||||
|
||||
Element? querySelector(DOMString selectors);
|
||||
ArrayFromVector querySelectorAll(DOMString selectors);
|
||||
|
||||
};
|
40
Userland/Libraries/LibWeb/DOM/DocumentType.cpp
Normal file
40
Userland/Libraries/LibWeb/DOM/DocumentType.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/DocumentType.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
DocumentType::DocumentType(Document& document)
|
||||
: Node(document, NodeType::DOCUMENT_TYPE_NODE)
|
||||
{
|
||||
}
|
||||
|
||||
DocumentType::~DocumentType()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
58
Userland/Libraries/LibWeb/DOM/DocumentType.h
Normal file
58
Userland/Libraries/LibWeb/DOM/DocumentType.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class DocumentType final : public Node {
|
||||
public:
|
||||
using WrapperType = Bindings::DocumentTypeWrapper;
|
||||
|
||||
explicit DocumentType(Document&);
|
||||
virtual ~DocumentType() override;
|
||||
|
||||
virtual FlyString node_name() const override { return "#doctype"; }
|
||||
|
||||
const String& name() const { return m_name; }
|
||||
void set_name(const String& name) { m_name = name; }
|
||||
|
||||
const String& public_id() const { return m_public_id; }
|
||||
void set_public_id(const String& public_id) { m_public_id = public_id; }
|
||||
|
||||
const String& system_id() const { return m_system_id; }
|
||||
void set_system_id(const String& system_id) { m_system_id = system_id; }
|
||||
|
||||
private:
|
||||
String m_name;
|
||||
String m_public_id;
|
||||
String m_system_id;
|
||||
};
|
||||
|
||||
}
|
7
Userland/Libraries/LibWeb/DOM/DocumentType.idl
Normal file
7
Userland/Libraries/LibWeb/DOM/DocumentType.idl
Normal file
|
@ -0,0 +1,7 @@
|
|||
interface DocumentType : Node {
|
||||
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute DOMString publicId;
|
||||
readonly attribute DOMString systemId;
|
||||
|
||||
};
|
335
Userland/Libraries/LibWeb/DOM/Element.cpp
Normal file
335
Userland/Libraries/LibWeb/DOM/Element.cpp
Normal file
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibWeb/CSS/Length.h>
|
||||
#include <LibWeb/CSS/Parser/CSSParser.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
#include <LibWeb/CSS/StyleInvalidator.h>
|
||||
#include <LibWeb/CSS/StyleResolver.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/DocumentFragment.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/Dump.h>
|
||||
#include <LibWeb/HTML/Parser/HTMLDocumentParser.h>
|
||||
#include <LibWeb/Layout/BlockBox.h>
|
||||
#include <LibWeb/Layout/InlineNode.h>
|
||||
#include <LibWeb/Layout/ListItemBox.h>
|
||||
#include <LibWeb/Layout/TableBox.h>
|
||||
#include <LibWeb/Layout/TableCellBox.h>
|
||||
#include <LibWeb/Layout/TableRowBox.h>
|
||||
#include <LibWeb/Layout/TableRowGroupBox.h>
|
||||
#include <LibWeb/Layout/TreeBuilder.h>
|
||||
#include <LibWeb/Layout/WidgetBox.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
Element::Element(Document& document, const QualifiedName& qualified_name)
|
||||
: ParentNode(document, NodeType::ELEMENT_NODE)
|
||||
, m_qualified_name(qualified_name)
|
||||
{
|
||||
}
|
||||
|
||||
Element::~Element()
|
||||
{
|
||||
}
|
||||
|
||||
Attribute* Element::find_attribute(const FlyString& name)
|
||||
{
|
||||
for (auto& attribute : m_attributes) {
|
||||
if (attribute.name() == name)
|
||||
return &attribute;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Attribute* Element::find_attribute(const FlyString& name) const
|
||||
{
|
||||
for (auto& attribute : m_attributes) {
|
||||
if (attribute.name() == name)
|
||||
return &attribute;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
String Element::attribute(const FlyString& name) const
|
||||
{
|
||||
if (auto* attribute = find_attribute(name))
|
||||
return attribute->value();
|
||||
return {};
|
||||
}
|
||||
|
||||
void Element::set_attribute(const FlyString& name, const String& value)
|
||||
{
|
||||
CSS::StyleInvalidator style_invalidator(document());
|
||||
|
||||
if (auto* attribute = find_attribute(name))
|
||||
attribute->set_value(value);
|
||||
else
|
||||
m_attributes.empend(name, value);
|
||||
|
||||
parse_attribute(name, value);
|
||||
}
|
||||
|
||||
void Element::remove_attribute(const FlyString& name)
|
||||
{
|
||||
CSS::StyleInvalidator style_invalidator(document());
|
||||
|
||||
m_attributes.remove_first_matching([&](auto& attribute) { return attribute.name() == name; });
|
||||
}
|
||||
|
||||
bool Element::has_class(const FlyString& class_name) const
|
||||
{
|
||||
for (auto& class_ : m_classes) {
|
||||
if (class_ == class_name)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<Layout::Node> Element::create_layout_node()
|
||||
{
|
||||
auto style = document().style_resolver().resolve_style(*this);
|
||||
const_cast<Element&>(*this).m_specified_css_values = style;
|
||||
auto display = style->display();
|
||||
|
||||
if (display == CSS::Display::None)
|
||||
return nullptr;
|
||||
|
||||
if (local_name() == "noscript" && document().is_scripting_enabled())
|
||||
return nullptr;
|
||||
|
||||
if (display == CSS::Display::Block)
|
||||
return adopt(*new Layout::BlockBox(document(), this, move(style)));
|
||||
|
||||
if (display == CSS::Display::Inline) {
|
||||
if (style->float_().value_or(CSS::Float::None) != CSS::Float::None)
|
||||
return adopt(*new Layout::BlockBox(document(), this, move(style)));
|
||||
return adopt(*new Layout::InlineNode(document(), *this, move(style)));
|
||||
}
|
||||
|
||||
if (display == CSS::Display::ListItem)
|
||||
return adopt(*new Layout::ListItemBox(document(), *this, move(style)));
|
||||
if (display == CSS::Display::Table)
|
||||
return adopt(*new Layout::TableBox(document(), this, move(style)));
|
||||
if (display == CSS::Display::TableRow)
|
||||
return adopt(*new Layout::TableRowBox(document(), this, move(style)));
|
||||
if (display == CSS::Display::TableCell)
|
||||
return adopt(*new Layout::TableCellBox(document(), this, move(style)));
|
||||
if (display == CSS::Display::TableRowGroup || display == CSS::Display::TableHeaderGroup || display == CSS::Display::TableFooterGroup)
|
||||
return adopt(*new Layout::TableRowGroupBox(document(), *this, move(style)));
|
||||
if (display == CSS::Display::InlineBlock) {
|
||||
auto inline_block = adopt(*new Layout::BlockBox(document(), this, move(style)));
|
||||
inline_block->set_inline(true);
|
||||
return inline_block;
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Element::parse_attribute(const FlyString& name, const String& value)
|
||||
{
|
||||
if (name == HTML::AttributeNames::class_) {
|
||||
auto new_classes = value.split_view(' ');
|
||||
m_classes.clear();
|
||||
m_classes.ensure_capacity(new_classes.size());
|
||||
for (auto& new_class : new_classes) {
|
||||
m_classes.unchecked_append(new_class);
|
||||
}
|
||||
} else if (name == HTML::AttributeNames::style) {
|
||||
m_inline_style = parse_css_declaration(CSS::ParsingContext(document()), value);
|
||||
set_needs_style_update(true);
|
||||
}
|
||||
}
|
||||
|
||||
enum class StyleDifference {
|
||||
None,
|
||||
NeedsRepaint,
|
||||
NeedsRelayout,
|
||||
};
|
||||
|
||||
static StyleDifference compute_style_difference(const CSS::StyleProperties& old_style, const CSS::StyleProperties& new_style, const Document& document)
|
||||
{
|
||||
if (old_style == new_style)
|
||||
return StyleDifference::None;
|
||||
|
||||
bool needs_repaint = false;
|
||||
bool needs_relayout = false;
|
||||
|
||||
if (new_style.display() != old_style.display())
|
||||
needs_relayout = true;
|
||||
|
||||
if (new_style.color_or_fallback(CSS::PropertyID::Color, document, Color::Black) != old_style.color_or_fallback(CSS::PropertyID::Color, document, Color::Black))
|
||||
needs_repaint = true;
|
||||
else if (new_style.color_or_fallback(CSS::PropertyID::BackgroundColor, document, Color::Black) != old_style.color_or_fallback(CSS::PropertyID::BackgroundColor, document, Color::Black))
|
||||
needs_repaint = true;
|
||||
|
||||
if (needs_relayout)
|
||||
return StyleDifference::NeedsRelayout;
|
||||
if (needs_repaint)
|
||||
return StyleDifference::NeedsRepaint;
|
||||
return StyleDifference::None;
|
||||
}
|
||||
|
||||
void Element::recompute_style()
|
||||
{
|
||||
set_needs_style_update(false);
|
||||
ASSERT(parent());
|
||||
auto old_specified_css_values = m_specified_css_values;
|
||||
auto new_specified_css_values = document().style_resolver().resolve_style(*this);
|
||||
m_specified_css_values = new_specified_css_values;
|
||||
if (!layout_node()) {
|
||||
if (new_specified_css_values->display() == CSS::Display::None)
|
||||
return;
|
||||
// We need a new layout tree here!
|
||||
Layout::TreeBuilder tree_builder;
|
||||
tree_builder.build(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't bother with style on widgets. NATIVE LOOK & FEEL BABY!
|
||||
if (is<Layout::WidgetBox>(layout_node()))
|
||||
return;
|
||||
|
||||
auto diff = StyleDifference::NeedsRelayout;
|
||||
if (old_specified_css_values)
|
||||
diff = compute_style_difference(*old_specified_css_values, *new_specified_css_values, document());
|
||||
if (diff == StyleDifference::None)
|
||||
return;
|
||||
layout_node()->apply_style(*new_specified_css_values);
|
||||
if (diff == StyleDifference::NeedsRelayout) {
|
||||
document().schedule_forced_layout();
|
||||
return;
|
||||
}
|
||||
if (diff == StyleDifference::NeedsRepaint) {
|
||||
layout_node()->set_needs_display();
|
||||
}
|
||||
}
|
||||
|
||||
NonnullRefPtr<CSS::StyleProperties> Element::computed_style()
|
||||
{
|
||||
// FIXME: This implementation is not doing anything it's supposed to.
|
||||
auto properties = m_specified_css_values->clone();
|
||||
if (layout_node() && layout_node()->has_style()) {
|
||||
CSS::PropertyID box_model_metrics[] = {
|
||||
CSS::PropertyID::MarginTop,
|
||||
CSS::PropertyID::MarginBottom,
|
||||
CSS::PropertyID::MarginLeft,
|
||||
CSS::PropertyID::MarginRight,
|
||||
CSS::PropertyID::PaddingTop,
|
||||
CSS::PropertyID::PaddingBottom,
|
||||
CSS::PropertyID::PaddingLeft,
|
||||
CSS::PropertyID::PaddingRight,
|
||||
CSS::PropertyID::BorderTopWidth,
|
||||
CSS::PropertyID::BorderBottomWidth,
|
||||
CSS::PropertyID::BorderLeftWidth,
|
||||
CSS::PropertyID::BorderRightWidth,
|
||||
};
|
||||
for (CSS::PropertyID id : box_model_metrics) {
|
||||
auto prop = m_specified_css_values->property(id);
|
||||
if (prop.has_value())
|
||||
properties->set_property(id, prop.value());
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
void Element::set_inner_html(StringView markup)
|
||||
{
|
||||
auto new_children = HTML::HTMLDocumentParser::parse_html_fragment(*this, markup);
|
||||
remove_all_children();
|
||||
while (!new_children.is_empty()) {
|
||||
append_child(new_children.take_first());
|
||||
}
|
||||
|
||||
set_needs_style_update(true);
|
||||
document().invalidate_layout();
|
||||
}
|
||||
|
||||
String Element::inner_html() const
|
||||
{
|
||||
auto escape_string = [](const StringView& string, bool attribute_mode) -> String {
|
||||
// https://html.spec.whatwg.org/multipage/parsing.html#escapingString
|
||||
StringBuilder builder;
|
||||
for (auto& ch : string) {
|
||||
if (ch == '&')
|
||||
builder.append("&");
|
||||
// FIXME: also replace U+00A0 NO-BREAK SPACE with
|
||||
else if (ch == '"' && attribute_mode)
|
||||
builder.append(""");
|
||||
else if (ch == '<' && !attribute_mode)
|
||||
builder.append("<");
|
||||
else if (ch == '>' && !attribute_mode)
|
||||
builder.append(">");
|
||||
else
|
||||
builder.append(ch);
|
||||
}
|
||||
return builder.to_string();
|
||||
};
|
||||
|
||||
StringBuilder builder;
|
||||
|
||||
Function<void(const Node&)> recurse = [&](auto& node) {
|
||||
for (auto* child = node.first_child(); child; child = child->next_sibling()) {
|
||||
if (child->is_element()) {
|
||||
auto& element = downcast<Element>(*child);
|
||||
builder.append('<');
|
||||
builder.append(element.local_name());
|
||||
element.for_each_attribute([&](auto& name, auto& value) {
|
||||
builder.append(' ');
|
||||
builder.append(name);
|
||||
builder.append('=');
|
||||
builder.append('"');
|
||||
builder.append(escape_string(value, true));
|
||||
builder.append('"');
|
||||
});
|
||||
builder.append('>');
|
||||
|
||||
recurse(*child);
|
||||
|
||||
// FIXME: This should be skipped for void elements
|
||||
builder.append("</");
|
||||
builder.append(element.local_name());
|
||||
builder.append('>');
|
||||
}
|
||||
if (child->is_text()) {
|
||||
auto& text = downcast<Text>(*child);
|
||||
builder.append(escape_string(text.data(), false));
|
||||
}
|
||||
// FIXME: Also handle Comment, ProcessingInstruction, DocumentType
|
||||
}
|
||||
};
|
||||
recurse(*this);
|
||||
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
bool Element::is_focused() const
|
||||
{
|
||||
return document().focused_element() == this;
|
||||
}
|
||||
|
||||
}
|
127
Userland/Libraries/LibWeb/DOM/Element.h
Normal file
127
Userland/Libraries/LibWeb/DOM/Element.h
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/DOM/Attribute.h>
|
||||
#include <LibWeb/DOM/NonDocumentTypeChildNode.h>
|
||||
#include <LibWeb/DOM/ParentNode.h>
|
||||
#include <LibWeb/HTML/AttributeNames.h>
|
||||
#include <LibWeb/HTML/TagNames.h>
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
#include <LibWeb/QualifiedName.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Element
|
||||
: public ParentNode
|
||||
, public NonDocumentTypeChildNode<Element> {
|
||||
|
||||
public:
|
||||
using WrapperType = Bindings::ElementWrapper;
|
||||
|
||||
Element(Document&, const QualifiedName& qualified_name);
|
||||
virtual ~Element() override;
|
||||
|
||||
virtual FlyString node_name() const final { return m_qualified_name.local_name(); }
|
||||
const FlyString& local_name() const { return m_qualified_name.local_name(); }
|
||||
|
||||
// NOTE: This is for the JS bindings
|
||||
const FlyString& tag_name() const { return local_name(); }
|
||||
|
||||
const FlyString& namespace_() const { return m_qualified_name.namespace_(); }
|
||||
|
||||
// NOTE: This is for the JS bindings
|
||||
const FlyString& namespace_uri() const { return namespace_(); }
|
||||
|
||||
bool has_attribute(const FlyString& name) const { return !attribute(name).is_null(); }
|
||||
bool has_attributes() const { return !m_attributes.is_empty(); }
|
||||
String attribute(const FlyString& name) const;
|
||||
String get_attribute(const FlyString& name) const { return attribute(name); }
|
||||
void set_attribute(const FlyString& name, const String& value);
|
||||
void remove_attribute(const FlyString& name);
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_attribute(Callback callback) const
|
||||
{
|
||||
for (auto& attribute : m_attributes)
|
||||
callback(attribute.name(), attribute.value());
|
||||
}
|
||||
|
||||
bool has_class(const FlyString&) const;
|
||||
const Vector<FlyString>& class_names() const { return m_classes; }
|
||||
|
||||
virtual void apply_presentational_hints(CSS::StyleProperties&) const { }
|
||||
virtual void parse_attribute(const FlyString& name, const String& value);
|
||||
|
||||
void recompute_style();
|
||||
|
||||
Layout::NodeWithStyle* layout_node() { return static_cast<Layout::NodeWithStyle*>(Node::layout_node()); }
|
||||
const Layout::NodeWithStyle* layout_node() const { return static_cast<const Layout::NodeWithStyle*>(Node::layout_node()); }
|
||||
|
||||
String name() const { return attribute(HTML::AttributeNames::name); }
|
||||
|
||||
const CSS::StyleProperties* specified_css_values() const { return m_specified_css_values.ptr(); }
|
||||
NonnullRefPtr<CSS::StyleProperties> computed_style();
|
||||
|
||||
const CSS::StyleDeclaration* inline_style() const { return m_inline_style; }
|
||||
|
||||
// FIXME: innerHTML also appears on shadow roots. https://w3c.github.io/DOM-Parsing/#dom-innerhtml
|
||||
String inner_html() const;
|
||||
void set_inner_html(StringView);
|
||||
|
||||
bool is_focused() const;
|
||||
virtual bool is_focusable() const { return false; }
|
||||
|
||||
protected:
|
||||
RefPtr<Layout::Node> create_layout_node() override;
|
||||
|
||||
private:
|
||||
Attribute* find_attribute(const FlyString& name);
|
||||
const Attribute* find_attribute(const FlyString& name) const;
|
||||
|
||||
QualifiedName m_qualified_name;
|
||||
Vector<Attribute> m_attributes;
|
||||
|
||||
RefPtr<CSS::StyleDeclaration> m_inline_style;
|
||||
|
||||
RefPtr<CSS::StyleProperties> m_specified_css_values;
|
||||
|
||||
Vector<FlyString> m_classes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace AK {
|
||||
template<>
|
||||
inline bool is<Web::DOM::Element>(const Web::DOM::Node& input)
|
||||
{
|
||||
return input.is_element();
|
||||
}
|
||||
|
||||
}
|
23
Userland/Libraries/LibWeb/DOM/Element.idl
Normal file
23
Userland/Libraries/LibWeb/DOM/Element.idl
Normal file
|
@ -0,0 +1,23 @@
|
|||
interface Element : Node {
|
||||
readonly attribute DOMString? namespaceURI;
|
||||
readonly attribute DOMString tagName;
|
||||
|
||||
DOMString? getAttribute(DOMString qualifiedName);
|
||||
undefined setAttribute(DOMString qualifiedName, DOMString value);
|
||||
undefined removeAttribute(DOMString qualifiedName);
|
||||
boolean hasAttribute(DOMString qualifiedName);
|
||||
boolean hasAttributes();
|
||||
|
||||
readonly attribute Element? firstElementChild;
|
||||
readonly attribute Element? lastElementChild;
|
||||
|
||||
Element? querySelector(DOMString selectors);
|
||||
ArrayFromVector querySelectorAll(DOMString selectors);
|
||||
|
||||
[LegacyNullToEmptyString] attribute DOMString innerHTML;
|
||||
[Reflect] attribute DOMString id;
|
||||
[Reflect=class] attribute DOMString className;
|
||||
|
||||
readonly attribute Element? nextElementSibling;
|
||||
readonly attribute Element? previousElementSibling;
|
||||
};
|
264
Userland/Libraries/LibWeb/DOM/ElementFactory.cpp
Normal file
264
Userland/Libraries/LibWeb/DOM/ElementFactory.cpp
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020, Luke Wilde <luke.wilde@live.co.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/ElementFactory.h>
|
||||
#include <LibWeb/HTML/HTMLAnchorElement.h>
|
||||
#include <LibWeb/HTML/HTMLAreaElement.h>
|
||||
#include <LibWeb/HTML/HTMLAudioElement.h>
|
||||
#include <LibWeb/HTML/HTMLBRElement.h>
|
||||
#include <LibWeb/HTML/HTMLBaseElement.h>
|
||||
#include <LibWeb/HTML/HTMLBlinkElement.h>
|
||||
#include <LibWeb/HTML/HTMLBodyElement.h>
|
||||
#include <LibWeb/HTML/HTMLButtonElement.h>
|
||||
#include <LibWeb/HTML/HTMLCanvasElement.h>
|
||||
#include <LibWeb/HTML/HTMLDListElement.h>
|
||||
#include <LibWeb/HTML/HTMLDataElement.h>
|
||||
#include <LibWeb/HTML/HTMLDataListElement.h>
|
||||
#include <LibWeb/HTML/HTMLDetailsElement.h>
|
||||
#include <LibWeb/HTML/HTMLDialogElement.h>
|
||||
#include <LibWeb/HTML/HTMLDirectoryElement.h>
|
||||
#include <LibWeb/HTML/HTMLDivElement.h>
|
||||
#include <LibWeb/HTML/HTMLEmbedElement.h>
|
||||
#include <LibWeb/HTML/HTMLFieldSetElement.h>
|
||||
#include <LibWeb/HTML/HTMLFontElement.h>
|
||||
#include <LibWeb/HTML/HTMLFormElement.h>
|
||||
#include <LibWeb/HTML/HTMLFrameElement.h>
|
||||
#include <LibWeb/HTML/HTMLFrameSetElement.h>
|
||||
#include <LibWeb/HTML/HTMLHRElement.h>
|
||||
#include <LibWeb/HTML/HTMLHeadElement.h>
|
||||
#include <LibWeb/HTML/HTMLHeadingElement.h>
|
||||
#include <LibWeb/HTML/HTMLHtmlElement.h>
|
||||
#include <LibWeb/HTML/HTMLIFrameElement.h>
|
||||
#include <LibWeb/HTML/HTMLImageElement.h>
|
||||
#include <LibWeb/HTML/HTMLInputElement.h>
|
||||
#include <LibWeb/HTML/HTMLLIElement.h>
|
||||
#include <LibWeb/HTML/HTMLLabelElement.h>
|
||||
#include <LibWeb/HTML/HTMLLegendElement.h>
|
||||
#include <LibWeb/HTML/HTMLLinkElement.h>
|
||||
#include <LibWeb/HTML/HTMLMapElement.h>
|
||||
#include <LibWeb/HTML/HTMLMarqueeElement.h>
|
||||
#include <LibWeb/HTML/HTMLMenuElement.h>
|
||||
#include <LibWeb/HTML/HTMLMetaElement.h>
|
||||
#include <LibWeb/HTML/HTMLMeterElement.h>
|
||||
#include <LibWeb/HTML/HTMLModElement.h>
|
||||
#include <LibWeb/HTML/HTMLOListElement.h>
|
||||
#include <LibWeb/HTML/HTMLObjectElement.h>
|
||||
#include <LibWeb/HTML/HTMLOptGroupElement.h>
|
||||
#include <LibWeb/HTML/HTMLOptionElement.h>
|
||||
#include <LibWeb/HTML/HTMLOutputElement.h>
|
||||
#include <LibWeb/HTML/HTMLParagraphElement.h>
|
||||
#include <LibWeb/HTML/HTMLParamElement.h>
|
||||
#include <LibWeb/HTML/HTMLPictureElement.h>
|
||||
#include <LibWeb/HTML/HTMLPreElement.h>
|
||||
#include <LibWeb/HTML/HTMLProgressElement.h>
|
||||
#include <LibWeb/HTML/HTMLQuoteElement.h>
|
||||
#include <LibWeb/HTML/HTMLScriptElement.h>
|
||||
#include <LibWeb/HTML/HTMLSelectElement.h>
|
||||
#include <LibWeb/HTML/HTMLSlotElement.h>
|
||||
#include <LibWeb/HTML/HTMLSourceElement.h>
|
||||
#include <LibWeb/HTML/HTMLSpanElement.h>
|
||||
#include <LibWeb/HTML/HTMLStyleElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableCaptionElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableCellElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableColElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableRowElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableSectionElement.h>
|
||||
#include <LibWeb/HTML/HTMLTemplateElement.h>
|
||||
#include <LibWeb/HTML/HTMLTextAreaElement.h>
|
||||
#include <LibWeb/HTML/HTMLTimeElement.h>
|
||||
#include <LibWeb/HTML/HTMLTitleElement.h>
|
||||
#include <LibWeb/HTML/HTMLTrackElement.h>
|
||||
#include <LibWeb/HTML/HTMLUListElement.h>
|
||||
#include <LibWeb/HTML/HTMLUnknownElement.h>
|
||||
#include <LibWeb/HTML/HTMLVideoElement.h>
|
||||
#include <LibWeb/SVG/SVGPathElement.h>
|
||||
#include <LibWeb/SVG/SVGSVGElement.h>
|
||||
#include <LibWeb/SVG/TagNames.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
NonnullRefPtr<Element> create_element(Document& document, const FlyString& tag_name, const FlyString& namespace_)
|
||||
{
|
||||
auto lowercase_tag_name = tag_name.to_lowercase();
|
||||
// FIXME: Add prefix when we support it.
|
||||
auto qualified_name = QualifiedName(tag_name, {}, namespace_);
|
||||
if (lowercase_tag_name == HTML::TagNames::a)
|
||||
return adopt(*new HTML::HTMLAnchorElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::area)
|
||||
return adopt(*new HTML::HTMLAreaElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::audio)
|
||||
return adopt(*new HTML::HTMLAudioElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::base)
|
||||
return adopt(*new HTML::HTMLBaseElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::blink)
|
||||
return adopt(*new HTML::HTMLBlinkElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::body)
|
||||
return adopt(*new HTML::HTMLBodyElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::br)
|
||||
return adopt(*new HTML::HTMLBRElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::button)
|
||||
return adopt(*new HTML::HTMLButtonElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::canvas)
|
||||
return adopt(*new HTML::HTMLCanvasElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::data)
|
||||
return adopt(*new HTML::HTMLDataElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::datalist)
|
||||
return adopt(*new HTML::HTMLDataListElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::details)
|
||||
return adopt(*new HTML::HTMLDetailsElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::dialog)
|
||||
return adopt(*new HTML::HTMLDialogElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::dir)
|
||||
return adopt(*new HTML::HTMLDirectoryElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::div)
|
||||
return adopt(*new HTML::HTMLDivElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::dl)
|
||||
return adopt(*new HTML::HTMLDListElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::embed)
|
||||
return adopt(*new HTML::HTMLEmbedElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::fieldset)
|
||||
return adopt(*new HTML::HTMLFieldSetElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::font)
|
||||
return adopt(*new HTML::HTMLFontElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::form)
|
||||
return adopt(*new HTML::HTMLFormElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::frame)
|
||||
return adopt(*new HTML::HTMLFrameElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::frameset)
|
||||
return adopt(*new HTML::HTMLFrameSetElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::head)
|
||||
return adopt(*new HTML::HTMLHeadElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::h1, HTML::TagNames::h2, HTML::TagNames::h3, HTML::TagNames::h4, HTML::TagNames::h5, HTML::TagNames::h6))
|
||||
return adopt(*new HTML::HTMLHeadingElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::hr)
|
||||
return adopt(*new HTML::HTMLHRElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::html)
|
||||
return adopt(*new HTML::HTMLHtmlElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::iframe)
|
||||
return adopt(*new HTML::HTMLIFrameElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::img)
|
||||
return adopt(*new HTML::HTMLImageElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::input)
|
||||
return adopt(*new HTML::HTMLInputElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::label)
|
||||
return adopt(*new HTML::HTMLLabelElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::legend)
|
||||
return adopt(*new HTML::HTMLLegendElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::li)
|
||||
return adopt(*new HTML::HTMLLIElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::link)
|
||||
return adopt(*new HTML::HTMLLinkElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::map)
|
||||
return adopt(*new HTML::HTMLMapElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::marquee)
|
||||
return adopt(*new HTML::HTMLMarqueeElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::menu)
|
||||
return adopt(*new HTML::HTMLMenuElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::meta)
|
||||
return adopt(*new HTML::HTMLMetaElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::meter)
|
||||
return adopt(*new HTML::HTMLMeterElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::ins, HTML::TagNames::del))
|
||||
return adopt(*new HTML::HTMLModElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::object)
|
||||
return adopt(*new HTML::HTMLObjectElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::ol)
|
||||
return adopt(*new HTML::HTMLOListElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::optgroup)
|
||||
return adopt(*new HTML::HTMLOptGroupElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::option)
|
||||
return adopt(*new HTML::HTMLOptionElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::output)
|
||||
return adopt(*new HTML::HTMLOutputElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::p)
|
||||
return adopt(*new HTML::HTMLParagraphElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::param)
|
||||
return adopt(*new HTML::HTMLParamElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::picture)
|
||||
return adopt(*new HTML::HTMLPictureElement(document, qualified_name));
|
||||
// NOTE: The obsolete elements "listing" and "xmp" are explicitly mapped to HTMLPreElement in the specification.
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::pre, HTML::TagNames::listing, HTML::TagNames::xmp))
|
||||
return adopt(*new HTML::HTMLPreElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::progress)
|
||||
return adopt(*new HTML::HTMLProgressElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::blockquote, HTML::TagNames::q))
|
||||
return adopt(*new HTML::HTMLQuoteElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::script)
|
||||
return adopt(*new HTML::HTMLScriptElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::select)
|
||||
return adopt(*new HTML::HTMLSelectElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::slot)
|
||||
return adopt(*new HTML::HTMLSlotElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::source)
|
||||
return adopt(*new HTML::HTMLSourceElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::span)
|
||||
return adopt(*new HTML::HTMLSpanElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::style)
|
||||
return adopt(*new HTML::HTMLStyleElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::caption)
|
||||
return adopt(*new HTML::HTMLTableCaptionElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(Web::HTML::TagNames::td, Web::HTML::TagNames::th))
|
||||
return adopt(*new HTML::HTMLTableCellElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::colgroup, HTML::TagNames::col))
|
||||
return adopt(*new HTML::HTMLTableColElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::table)
|
||||
return adopt(*new HTML::HTMLTableElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::tr)
|
||||
return adopt(*new HTML::HTMLTableRowElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::tbody, HTML::TagNames::thead, HTML::TagNames::tfoot))
|
||||
return adopt(*new HTML::HTMLTableSectionElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::template_)
|
||||
return adopt(*new HTML::HTMLTemplateElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::textarea)
|
||||
return adopt(*new HTML::HTMLTextAreaElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::time)
|
||||
return adopt(*new HTML::HTMLTimeElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::title)
|
||||
return adopt(*new HTML::HTMLTitleElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::track)
|
||||
return adopt(*new HTML::HTMLTrackElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::ul)
|
||||
return adopt(*new HTML::HTMLUListElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::video)
|
||||
return adopt(*new HTML::HTMLVideoElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(
|
||||
HTML::TagNames::article, HTML::TagNames::section, HTML::TagNames::nav, HTML::TagNames::aside, HTML::TagNames::hgroup, HTML::TagNames::header, HTML::TagNames::footer, HTML::TagNames::address, HTML::TagNames::dt, HTML::TagNames::dd, HTML::TagNames::figure, HTML::TagNames::figcaption, HTML::TagNames::main, HTML::TagNames::em, HTML::TagNames::strong, HTML::TagNames::small, HTML::TagNames::s, HTML::TagNames::cite, HTML::TagNames::dfn, HTML::TagNames::abbr, HTML::TagNames::ruby, HTML::TagNames::rt, HTML::TagNames::rp, HTML::TagNames::code, HTML::TagNames::var, HTML::TagNames::samp, HTML::TagNames::kbd, HTML::TagNames::sub, HTML::TagNames::sup, HTML::TagNames::i, HTML::TagNames::b, HTML::TagNames::u, HTML::TagNames::mark, HTML::TagNames::bdi, HTML::TagNames::bdo, HTML::TagNames::wbr, HTML::TagNames::summary, HTML::TagNames::noscript,
|
||||
// Obsolete
|
||||
HTML::TagNames::acronym, HTML::TagNames::basefont, HTML::TagNames::big, HTML::TagNames::center, HTML::TagNames::nobr, HTML::TagNames::noembed, HTML::TagNames::noframes, HTML::TagNames::plaintext, HTML::TagNames::rb, HTML::TagNames::rtc, HTML::TagNames::strike, HTML::TagNames::tt))
|
||||
return adopt(*new HTML::HTMLElement(document, qualified_name));
|
||||
if (lowercase_tag_name == SVG::TagNames::svg)
|
||||
return adopt(*new SVG::SVGSVGElement(document, qualified_name));
|
||||
if (lowercase_tag_name == SVG::TagNames::path)
|
||||
return adopt(*new SVG::SVGPathElement(document, qualified_name));
|
||||
|
||||
// FIXME: If name is a valid custom element name, then return HTMLElement.
|
||||
|
||||
return adopt(*new HTML::HTMLUnknownElement(document, qualified_name));
|
||||
}
|
||||
|
||||
}
|
35
Userland/Libraries/LibWeb/DOM/ElementFactory.h
Normal file
35
Userland/Libraries/LibWeb/DOM/ElementFactory.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
NonnullRefPtr<Element> create_element(Document&, const FlyString& tag_name, const FlyString& namespace_);
|
||||
|
||||
}
|
59
Userland/Libraries/LibWeb/DOM/Event.cpp
Normal file
59
Userland/Libraries/LibWeb/DOM/Event.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/DOM/ShadowRoot.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
void Event::append_to_path(EventTarget& invocation_target, RefPtr<EventTarget> shadow_adjusted_target, RefPtr<EventTarget> related_target, TouchTargetList& touch_targets, bool slot_in_closed_tree)
|
||||
{
|
||||
bool invocation_target_in_shadow_tree = false;
|
||||
bool root_of_closed_tree = false;
|
||||
|
||||
if (is<Node>(invocation_target)) {
|
||||
auto& invocation_target_node = downcast<Node>(invocation_target);
|
||||
if (is<ShadowRoot>(invocation_target_node.root()))
|
||||
invocation_target_in_shadow_tree = true;
|
||||
if (is<ShadowRoot>(invocation_target_node)) {
|
||||
auto& invocation_target_shadow_root = downcast<ShadowRoot>(invocation_target_node);
|
||||
root_of_closed_tree = invocation_target_shadow_root.closed();
|
||||
}
|
||||
}
|
||||
|
||||
m_path.append({ invocation_target, invocation_target_in_shadow_tree, shadow_adjusted_target, related_target, touch_targets, root_of_closed_tree, slot_in_closed_tree, m_path.size() });
|
||||
}
|
||||
|
||||
void Event::set_cancelled_flag()
|
||||
{
|
||||
if (m_cancelable && !m_in_passive_listener)
|
||||
m_cancelled = true;
|
||||
}
|
||||
|
||||
}
|
186
Userland/Libraries/LibWeb/DOM/Event.h
Normal file
186
Userland/Libraries/LibWeb/DOM/Event.h
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Event
|
||||
: public RefCounted<Event>
|
||||
, public Bindings::Wrappable {
|
||||
public:
|
||||
using WrapperType = Bindings::EventWrapper;
|
||||
|
||||
enum Phase : u16 {
|
||||
None = 0,
|
||||
CapturingPhase = 1,
|
||||
AtTarget = 2,
|
||||
BubblingPhase = 3,
|
||||
};
|
||||
|
||||
using TouchTargetList = Vector<RefPtr<EventTarget>>;
|
||||
|
||||
struct PathEntry {
|
||||
RefPtr<EventTarget> invocation_target;
|
||||
bool invocation_target_in_shadow_tree { false };
|
||||
RefPtr<EventTarget> shadow_adjusted_target;
|
||||
RefPtr<EventTarget> related_target;
|
||||
TouchTargetList touch_target_list;
|
||||
bool root_of_closed_tree { false };
|
||||
bool slot_in_closed_tree { false };
|
||||
size_t index;
|
||||
};
|
||||
|
||||
using Path = Vector<PathEntry>;
|
||||
|
||||
static NonnullRefPtr<Event> create(const FlyString& event_name)
|
||||
{
|
||||
return adopt(*new Event(event_name));
|
||||
}
|
||||
|
||||
virtual ~Event() { }
|
||||
|
||||
const FlyString& type() const { return m_type; }
|
||||
void set_type(const StringView& type) { m_type = type; }
|
||||
|
||||
RefPtr<EventTarget> target() const { return m_target; }
|
||||
void set_target(EventTarget* target) { m_target = target; }
|
||||
|
||||
// NOTE: This is intended for the JS bindings.
|
||||
RefPtr<EventTarget> src_target() const { return target(); }
|
||||
|
||||
RefPtr<EventTarget> related_target() const { return m_related_target; }
|
||||
void set_related_target(EventTarget* related_target) { m_related_target = related_target; }
|
||||
|
||||
bool should_stop_propagation() const { return m_stop_propagation; }
|
||||
void set_stop_propagation(bool stop_propagation) { m_stop_propagation = stop_propagation; }
|
||||
|
||||
bool should_stop_immediate_propagation() const { return m_stop_immediate_propagation; }
|
||||
void set_stop_immediate_propagation(bool stop_immediate_propagation) { m_stop_immediate_propagation = stop_immediate_propagation; }
|
||||
|
||||
bool cancelled() const { return m_cancelled; }
|
||||
void set_cancelled(bool cancelled) { m_cancelled = cancelled; }
|
||||
|
||||
bool in_passive_listener() const { return m_in_passive_listener; }
|
||||
void set_in_passive_listener(bool in_passive_listener) { m_in_passive_listener = in_passive_listener; }
|
||||
|
||||
bool composed() const { return m_composed; }
|
||||
void set_composed(bool composed) { m_composed = composed; }
|
||||
|
||||
bool initialized() const { return m_initialized; }
|
||||
void set_initialized(bool initialized) { m_initialized = initialized; }
|
||||
|
||||
bool dispatched() const { return m_dispatch; }
|
||||
void set_dispatched(bool dispatched) { m_dispatch = dispatched; }
|
||||
|
||||
void prevent_default() { set_cancelled_flag(); }
|
||||
bool default_prevented() const { return cancelled(); }
|
||||
|
||||
u16 event_phase() const { return m_phase; }
|
||||
void set_phase(Phase phase) { m_phase = phase; }
|
||||
|
||||
RefPtr<EventTarget> current_target() const { return m_current_target; }
|
||||
void set_current_target(EventTarget* current_target) { m_current_target = current_target; }
|
||||
|
||||
bool return_value() const { return !m_cancelled; }
|
||||
void set_return_value(bool return_value)
|
||||
{
|
||||
if (!return_value)
|
||||
set_cancelled_flag();
|
||||
}
|
||||
|
||||
void append_to_path(EventTarget&, RefPtr<EventTarget>, RefPtr<EventTarget>, TouchTargetList&, bool);
|
||||
Path& path() { return m_path; }
|
||||
const Path& path() const { return m_path; }
|
||||
void clear_path() { m_path.clear(); }
|
||||
|
||||
void set_touch_target_list(TouchTargetList& touch_target_list) { m_touch_target_list = touch_target_list; }
|
||||
TouchTargetList& touch_target_list() { return m_touch_target_list; };
|
||||
void clear_touch_target_list() { m_touch_target_list.clear(); }
|
||||
|
||||
bool bubbles() const { return m_bubbles; }
|
||||
void set_bubbles(bool bubbles) { m_bubbles = bubbles; }
|
||||
|
||||
bool cancelable() const { return m_cancelable; }
|
||||
void set_cancelable(bool cancelable) { m_cancelable = cancelable; }
|
||||
|
||||
bool is_trusted() const { return m_is_trusted; }
|
||||
void set_is_trusted(bool is_trusted) { m_is_trusted = is_trusted; }
|
||||
|
||||
void stop_propagation() { m_stop_propagation = true; }
|
||||
|
||||
bool cancel_bubble() const { return m_stop_propagation; }
|
||||
void set_cancel_bubble(bool cancel_bubble)
|
||||
{
|
||||
if (cancel_bubble)
|
||||
m_stop_propagation = true;
|
||||
}
|
||||
|
||||
void stop_immediate_propagation()
|
||||
{
|
||||
m_stop_propagation = true;
|
||||
m_stop_immediate_propagation = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit Event(const FlyString& type)
|
||||
: m_type(type)
|
||||
, m_initialized(true)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
FlyString m_type;
|
||||
RefPtr<EventTarget> m_target;
|
||||
RefPtr<EventTarget> m_related_target;
|
||||
RefPtr<EventTarget> m_current_target;
|
||||
|
||||
Phase m_phase { None };
|
||||
|
||||
bool m_bubbles { false };
|
||||
bool m_cancelable { false };
|
||||
|
||||
bool m_stop_propagation { false };
|
||||
bool m_stop_immediate_propagation { false };
|
||||
bool m_cancelled { false };
|
||||
bool m_in_passive_listener { false };
|
||||
bool m_composed { false };
|
||||
bool m_initialized { false };
|
||||
bool m_dispatch { false };
|
||||
|
||||
bool m_is_trusted { true };
|
||||
|
||||
Path m_path;
|
||||
TouchTargetList m_touch_target_list;
|
||||
|
||||
void set_cancelled_flag();
|
||||
};
|
||||
|
||||
}
|
23
Userland/Libraries/LibWeb/DOM/Event.idl
Normal file
23
Userland/Libraries/LibWeb/DOM/Event.idl
Normal file
|
@ -0,0 +1,23 @@
|
|||
interface Event {
|
||||
|
||||
readonly attribute DOMString type;
|
||||
readonly attribute EventTarget? target;
|
||||
readonly attribute EventTarget? srcTarget;
|
||||
readonly attribute EventTarget? currentTarget;
|
||||
|
||||
readonly attribute unsigned short eventPhase;
|
||||
|
||||
undefined stopPropagation();
|
||||
attribute boolean cancelBubble;
|
||||
undefined stopImmediatePropagation();
|
||||
|
||||
readonly attribute boolean bubbles;
|
||||
readonly attribute boolean cancelable;
|
||||
attribute boolean returnValue;
|
||||
undefined preventDefault();
|
||||
readonly attribute boolean defaultPrevented;
|
||||
readonly attribute boolean composed;
|
||||
|
||||
readonly attribute boolean isTrusted;
|
||||
|
||||
};
|
332
Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp
Normal file
332
Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp
Normal file
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibWeb/Bindings/EventTargetWrapper.h>
|
||||
#include <LibWeb/Bindings/EventTargetWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/EventWrapper.h>
|
||||
#include <LibWeb/Bindings/EventWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/ScriptExecutionContext.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/EventDispatcher.h>
|
||||
#include <LibWeb/DOM/EventListener.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/DOM/ShadowRoot.h>
|
||||
#include <LibWeb/DOM/Window.h>
|
||||
#include <LibWeb/HTML/EventNames.h>
|
||||
#include <LibWeb/UIEvents/MouseEvent.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
// FIXME: This shouldn't be here, as retargeting is not only used by the event dispatcher.
|
||||
// When moving this function, it needs to be generalized. https://dom.spec.whatwg.org/#retarget
|
||||
static EventTarget* retarget(EventTarget* left, [[maybe_unused]] EventTarget* right)
|
||||
{
|
||||
// FIXME
|
||||
for (;;) {
|
||||
if (!is<Node>(left))
|
||||
return left;
|
||||
|
||||
auto* left_node = downcast<Node>(left);
|
||||
auto* left_root = left_node->root();
|
||||
if (!is<ShadowRoot>(left_root))
|
||||
return left;
|
||||
|
||||
// FIXME: If right is a node and left’s root is a shadow-including inclusive ancestor of right, return left.
|
||||
|
||||
auto* left_shadow_root = downcast<ShadowRoot>(left_root);
|
||||
left = left_shadow_root->host();
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke
|
||||
bool EventDispatcher::inner_invoke(Event& event, Vector<EventTarget::EventListenerRegistration>& listeners, Event::Phase phase, bool invocation_target_in_shadow_tree)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
for (auto& listener : listeners) {
|
||||
if (listener.listener->removed())
|
||||
continue;
|
||||
|
||||
if (event.type() != listener.listener->type())
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
|
||||
if (phase == Event::Phase::CapturingPhase && !listener.listener->capture())
|
||||
continue;
|
||||
|
||||
if (phase == Event::Phase::BubblingPhase && listener.listener->capture())
|
||||
continue;
|
||||
|
||||
if (listener.listener->once())
|
||||
event.current_target()->remove_from_event_listener_list(listener.listener);
|
||||
|
||||
auto& function = listener.listener->function();
|
||||
auto& global = function.global_object();
|
||||
|
||||
RefPtr<Event> current_event;
|
||||
|
||||
if (is<Bindings::WindowObject>(global)) {
|
||||
auto& bindings_window_global = downcast<Bindings::WindowObject>(global);
|
||||
auto& window_impl = bindings_window_global.impl();
|
||||
current_event = window_impl.current_event();
|
||||
if (!invocation_target_in_shadow_tree)
|
||||
window_impl.set_current_event(&event);
|
||||
}
|
||||
|
||||
if (listener.listener->passive())
|
||||
event.set_in_passive_listener(true);
|
||||
|
||||
auto* this_value = Bindings::wrap(global, *event.current_target());
|
||||
auto* wrapped_event = Bindings::wrap(global, event);
|
||||
auto& vm = global.vm();
|
||||
[[maybe_unused]] auto rc = vm.call(listener.listener->function(), this_value, wrapped_event);
|
||||
if (vm.exception()) {
|
||||
vm.clear_exception();
|
||||
// FIXME: Set legacyOutputDidListenersThrowFlag if given. (Only used by IndexedDB currently)
|
||||
}
|
||||
|
||||
event.set_in_passive_listener(false);
|
||||
if (is<Bindings::WindowObject>(global)) {
|
||||
auto& bindings_window_global = downcast<Bindings::WindowObject>(global);
|
||||
auto& window_impl = bindings_window_global.impl();
|
||||
window_impl.set_current_event(current_event);
|
||||
}
|
||||
|
||||
if (event.should_stop_immediate_propagation())
|
||||
return found;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-event-listener-invoke
|
||||
void EventDispatcher::invoke(Event::PathEntry& struct_, Event& event, Event::Phase phase)
|
||||
{
|
||||
auto last_valid_shadow_adjusted_target = event.path().last_matching([&struct_](auto& entry) {
|
||||
return entry.index <= struct_.index && !entry.shadow_adjusted_target.is_null();
|
||||
});
|
||||
|
||||
ASSERT(last_valid_shadow_adjusted_target.has_value());
|
||||
|
||||
event.set_target(last_valid_shadow_adjusted_target.value().shadow_adjusted_target);
|
||||
event.set_related_target(struct_.related_target);
|
||||
event.set_touch_target_list(struct_.touch_target_list);
|
||||
|
||||
if (event.should_stop_propagation())
|
||||
return;
|
||||
|
||||
event.set_current_target(struct_.invocation_target);
|
||||
|
||||
// NOTE: This is an intentional copy. Any event listeners added after this point will not be invoked.
|
||||
auto listeners = event.current_target()->listeners();
|
||||
bool invocation_target_in_shadow_tree = struct_.invocation_target_in_shadow_tree;
|
||||
|
||||
bool found = inner_invoke(event, listeners, phase, invocation_target_in_shadow_tree);
|
||||
|
||||
if (!found && event.is_trusted()) {
|
||||
auto original_event_type = event.type();
|
||||
|
||||
if (event.type() == "animationend")
|
||||
event.set_type("webkitAnimationEnd");
|
||||
else if (event.type() == "animationiteration")
|
||||
event.set_type("webkitAnimationIteration");
|
||||
else if (event.type() == "animationstart")
|
||||
event.set_type("webkitAnimationStart");
|
||||
else if (event.type() == "transitionend")
|
||||
event.set_type("webkitTransitionEnd");
|
||||
else
|
||||
return;
|
||||
|
||||
inner_invoke(event, listeners, phase, invocation_target_in_shadow_tree);
|
||||
event.set_type(original_event_type);
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-event-dispatch
|
||||
bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<Event> event, bool legacy_target_override)
|
||||
{
|
||||
event->set_dispatched(true);
|
||||
RefPtr<EventTarget> target_override;
|
||||
|
||||
if (!legacy_target_override) {
|
||||
target_override = target;
|
||||
} else {
|
||||
// NOTE: This can be done because legacy_target_override is only set for events targeted at Window.
|
||||
target_override = downcast<Window>(*target).document();
|
||||
}
|
||||
|
||||
RefPtr<EventTarget> activation_target;
|
||||
RefPtr<EventTarget> related_target = retarget(event->related_target(), target);
|
||||
|
||||
bool clear_targets = false;
|
||||
|
||||
if (related_target != target || event->related_target() == target) {
|
||||
Event::TouchTargetList touch_targets;
|
||||
|
||||
for (auto& touch_target : event->touch_target_list()) {
|
||||
touch_targets.append(retarget(touch_target, target));
|
||||
}
|
||||
|
||||
event->append_to_path(*target, target_override, related_target, touch_targets, false);
|
||||
|
||||
bool is_activation_event = is<UIEvents::MouseEvent>(*event) && event->type() == HTML::EventNames::click;
|
||||
|
||||
if (is_activation_event && target->activation_behaviour)
|
||||
activation_target = target;
|
||||
|
||||
// FIXME: Let slottable be target, if target is a slottable and is assigned, and null otherwise.
|
||||
|
||||
bool slot_in_closed_tree = false;
|
||||
auto* parent = target->get_parent(event);
|
||||
|
||||
while (parent) {
|
||||
// FIXME: If slottable is non-null:
|
||||
|
||||
// FIXME: If parent is a slottable and is assigned, then set slottable to parent.
|
||||
|
||||
related_target = retarget(event->related_target(), parent);
|
||||
touch_targets.clear();
|
||||
|
||||
for (auto& touch_target : event->touch_target_list()) {
|
||||
touch_targets.append(retarget(touch_target, parent));
|
||||
}
|
||||
|
||||
// FIXME: or parent is a node and target’s root is a shadow-including inclusive ancestor of parent, then:
|
||||
if (is<Window>(parent)) {
|
||||
if (is_activation_event && event->bubbles() && !activation_target && parent->activation_behaviour)
|
||||
activation_target = parent;
|
||||
|
||||
event->append_to_path(*parent, nullptr, related_target, touch_targets, slot_in_closed_tree);
|
||||
} else if (related_target == parent) {
|
||||
parent = nullptr;
|
||||
} else {
|
||||
target = *parent;
|
||||
|
||||
if (is_activation_event && !activation_target && target->activation_behaviour)
|
||||
activation_target = target;
|
||||
|
||||
event->append_to_path(*parent, target, related_target, touch_targets, slot_in_closed_tree);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent = parent->get_parent(event);
|
||||
}
|
||||
|
||||
slot_in_closed_tree = false;
|
||||
}
|
||||
|
||||
auto clear_targets_struct = event->path().last_matching([](auto& entry) {
|
||||
return !entry.shadow_adjusted_target.is_null();
|
||||
});
|
||||
|
||||
ASSERT(clear_targets_struct.has_value());
|
||||
|
||||
if (is<Node>(clear_targets_struct.value().shadow_adjusted_target.ptr())) {
|
||||
auto& shadow_adjusted_target_node = downcast<Node>(*clear_targets_struct.value().shadow_adjusted_target);
|
||||
if (is<ShadowRoot>(shadow_adjusted_target_node.root()))
|
||||
clear_targets = true;
|
||||
}
|
||||
|
||||
if (!clear_targets && is<Node>(clear_targets_struct.value().related_target.ptr())) {
|
||||
auto& related_target_node = downcast<Node>(*clear_targets_struct.value().related_target);
|
||||
if (is<ShadowRoot>(related_target_node.root()))
|
||||
clear_targets = true;
|
||||
}
|
||||
|
||||
if (!clear_targets) {
|
||||
for (auto touch_target : clear_targets_struct.value().touch_target_list) {
|
||||
if (is<Node>(*touch_target.ptr())) {
|
||||
auto& touch_target_node = downcast<Node>(*touch_target.ptr());
|
||||
if (is<ShadowRoot>(touch_target_node.root())) {
|
||||
clear_targets = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activation_target && activation_target->legacy_pre_activation_behaviour)
|
||||
activation_target->legacy_pre_activation_behaviour();
|
||||
|
||||
for (ssize_t i = event->path().size() - 1; i >= 0; --i) {
|
||||
auto& entry = event->path().at(i);
|
||||
|
||||
if (entry.shadow_adjusted_target)
|
||||
event->set_phase(Event::Phase::AtTarget);
|
||||
else
|
||||
event->set_phase(Event::Phase::CapturingPhase);
|
||||
|
||||
invoke(entry, event, Event::Phase::CapturingPhase);
|
||||
}
|
||||
|
||||
for (auto& entry : event->path()) {
|
||||
if (entry.shadow_adjusted_target) {
|
||||
event->set_phase(Event::Phase::AtTarget);
|
||||
} else {
|
||||
if (!event->bubbles())
|
||||
continue;
|
||||
|
||||
event->set_phase(Event::Phase::BubblingPhase);
|
||||
}
|
||||
|
||||
invoke(entry, event, Event::Phase::BubblingPhase);
|
||||
}
|
||||
}
|
||||
|
||||
event->set_phase(Event::Phase::None);
|
||||
event->set_current_target(nullptr);
|
||||
event->clear_path();
|
||||
event->set_dispatched(false);
|
||||
event->set_stop_propagation(false);
|
||||
event->set_stop_immediate_propagation(false);
|
||||
|
||||
if (clear_targets) {
|
||||
event->set_target(nullptr);
|
||||
event->set_related_target(nullptr);
|
||||
event->clear_touch_target_list();
|
||||
}
|
||||
|
||||
if (activation_target) {
|
||||
if (!event->cancelled()) {
|
||||
// NOTE: Since activation_target is set, it will have activation behaviour.
|
||||
activation_target->activation_behaviour(event);
|
||||
} else {
|
||||
if (activation_target->legacy_cancelled_activation_behaviour)
|
||||
activation_target->legacy_cancelled_activation_behaviour();
|
||||
}
|
||||
}
|
||||
|
||||
return !event->cancelled();
|
||||
}
|
||||
|
||||
}
|
43
Userland/Libraries/LibWeb/DOM/EventDispatcher.h
Normal file
43
Userland/Libraries/LibWeb/DOM/EventDispatcher.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class EventDispatcher {
|
||||
public:
|
||||
static bool dispatch(NonnullRefPtr<EventTarget>, NonnullRefPtr<Event>, bool legacy_target_override = false);
|
||||
|
||||
private:
|
||||
static void invoke(Event::PathEntry&, Event&, Event::Phase);
|
||||
static bool inner_invoke(Event&, Vector<EventTarget::EventListenerRegistration>&, Event::Phase, bool);
|
||||
};
|
||||
|
||||
}
|
38
Userland/Libraries/LibWeb/DOM/EventListener.cpp
Normal file
38
Userland/Libraries/LibWeb/DOM/EventListener.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibWeb/DOM/EventListener.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
JS::Function& EventListener::function()
|
||||
{
|
||||
ASSERT(m_function.cell());
|
||||
return *m_function.cell();
|
||||
}
|
||||
|
||||
}
|
72
Userland/Libraries/LibWeb/DOM/EventListener.h
Normal file
72
Userland/Libraries/LibWeb/DOM/EventListener.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/RefCounted.h>
|
||||
#include <LibJS/Heap/Handle.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class EventListener
|
||||
: public RefCounted<EventListener>
|
||||
, public Bindings::Wrappable {
|
||||
public:
|
||||
using WrapperType = Bindings::EventListenerWrapper;
|
||||
|
||||
explicit EventListener(JS::Handle<JS::Function> function)
|
||||
: m_function(move(function))
|
||||
{
|
||||
}
|
||||
|
||||
JS::Function& function();
|
||||
|
||||
const FlyString& type() const { return m_type; }
|
||||
void set_type(const FlyString& type) { m_type = type; }
|
||||
|
||||
bool capture() const { return m_capture; }
|
||||
void set_capture(bool capture) { m_capture = capture; }
|
||||
|
||||
bool passive() const { return m_passive; }
|
||||
void set_passive(bool passive) { m_capture = passive; }
|
||||
|
||||
bool once() const { return m_once; }
|
||||
void set_once(bool once) { m_once = once; }
|
||||
|
||||
bool removed() const { return m_removed; }
|
||||
void set_removed(bool removed) { m_removed = removed; }
|
||||
|
||||
private:
|
||||
FlyString m_type;
|
||||
JS::Handle<JS::Function> m_function;
|
||||
bool m_capture { false };
|
||||
bool m_passive { false };
|
||||
bool m_once { false };
|
||||
bool m_removed { false };
|
||||
};
|
||||
|
||||
}
|
70
Userland/Libraries/LibWeb/DOM/EventTarget.cpp
Normal file
70
Userland/Libraries/LibWeb/DOM/EventTarget.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/Bindings/ScriptExecutionContext.h>
|
||||
#include <LibWeb/DOM/EventListener.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
EventTarget::EventTarget(Bindings::ScriptExecutionContext& script_execution_context)
|
||||
: m_script_execution_context(&script_execution_context)
|
||||
{
|
||||
}
|
||||
|
||||
EventTarget::~EventTarget()
|
||||
{
|
||||
}
|
||||
|
||||
void EventTarget::add_event_listener(const FlyString& event_name, NonnullRefPtr<EventListener> listener)
|
||||
{
|
||||
auto existing_listener = m_listeners.first_matching([&](auto& entry) {
|
||||
return entry.listener->type() == event_name && &entry.listener->function() == &listener->function() && entry.listener->capture() == listener->capture();
|
||||
});
|
||||
if (existing_listener.has_value())
|
||||
return;
|
||||
listener->set_type(event_name);
|
||||
m_listeners.append({ event_name, move(listener) });
|
||||
}
|
||||
|
||||
void EventTarget::remove_event_listener(const FlyString& event_name, NonnullRefPtr<EventListener> listener)
|
||||
{
|
||||
m_listeners.remove_first_matching([&](auto& entry) {
|
||||
auto matches = entry.event_name == event_name && &entry.listener->function() == &listener->function() && entry.listener->capture() == listener->capture();
|
||||
if (matches)
|
||||
entry.listener->set_removed(true);
|
||||
return matches;
|
||||
});
|
||||
}
|
||||
|
||||
void EventTarget::remove_from_event_listener_list(NonnullRefPtr<EventListener> listener)
|
||||
{
|
||||
m_listeners.remove_first_matching([&](auto& entry) {
|
||||
return entry.listener->type() == listener->type() && &entry.listener->function() == &listener->function() && entry.listener->capture() == listener->capture();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
85
Userland/Libraries/LibWeb/DOM/EventTarget.h
Normal file
85
Userland/Libraries/LibWeb/DOM/EventTarget.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/Noncopyable.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class EventTarget {
|
||||
AK_MAKE_NONCOPYABLE(EventTarget);
|
||||
AK_MAKE_NONMOVABLE(EventTarget);
|
||||
|
||||
public:
|
||||
virtual ~EventTarget();
|
||||
|
||||
void ref() { ref_event_target(); }
|
||||
void unref() { unref_event_target(); }
|
||||
|
||||
void add_event_listener(const FlyString& event_name, NonnullRefPtr<EventListener>);
|
||||
void remove_event_listener(const FlyString& event_name, NonnullRefPtr<EventListener>);
|
||||
|
||||
void remove_from_event_listener_list(NonnullRefPtr<EventListener>);
|
||||
|
||||
virtual bool dispatch_event(NonnullRefPtr<Event>) = 0;
|
||||
virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) = 0;
|
||||
Bindings::ScriptExecutionContext* script_execution_context() { return m_script_execution_context; }
|
||||
|
||||
virtual EventTarget* get_parent(const Event&) { return nullptr; }
|
||||
|
||||
struct EventListenerRegistration {
|
||||
FlyString event_name;
|
||||
NonnullRefPtr<EventListener> listener;
|
||||
};
|
||||
|
||||
const Vector<EventListenerRegistration>& listeners() const { return m_listeners; }
|
||||
|
||||
Function<void(const Event&)> activation_behaviour;
|
||||
|
||||
// NOTE: These only exist for checkbox and radio input elements.
|
||||
Function<void()> legacy_pre_activation_behaviour;
|
||||
Function<void()> legacy_cancelled_activation_behaviour;
|
||||
|
||||
protected:
|
||||
explicit EventTarget(Bindings::ScriptExecutionContext&);
|
||||
|
||||
virtual void ref_event_target() = 0;
|
||||
virtual void unref_event_target() = 0;
|
||||
|
||||
private:
|
||||
// FIXME: This should not be a raw pointer.
|
||||
Bindings::ScriptExecutionContext* m_script_execution_context { nullptr };
|
||||
|
||||
Vector<EventListenerRegistration> m_listeners;
|
||||
};
|
||||
|
||||
}
|
6
Userland/Libraries/LibWeb/DOM/EventTarget.idl
Normal file
6
Userland/Libraries/LibWeb/DOM/EventTarget.idl
Normal file
|
@ -0,0 +1,6 @@
|
|||
interface EventTarget {
|
||||
|
||||
undefined addEventListener(DOMString type, EventListener? callback);
|
||||
undefined removeEventListener(DOMString type, EventListener? callback);
|
||||
|
||||
};
|
263
Userland/Libraries/LibWeb/DOM/Node.cpp
Normal file
263
Userland/Libraries/LibWeb/DOM/Node.cpp
Normal file
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibJS/Runtime/ScriptFunction.h>
|
||||
#include <LibWeb/Bindings/EventWrapper.h>
|
||||
#include <LibWeb/Bindings/EventWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/NodeWrapper.h>
|
||||
#include <LibWeb/Bindings/NodeWrapperFactory.h>
|
||||
#include <LibWeb/CSS/StyleResolver.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/EventDispatcher.h>
|
||||
#include <LibWeb/DOM/EventListener.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/DOM/ShadowRoot.h>
|
||||
#include <LibWeb/HTML/HTMLAnchorElement.h>
|
||||
#include <LibWeb/Layout/BlockBox.h>
|
||||
#include <LibWeb/Layout/InitialContainingBlockBox.h>
|
||||
#include <LibWeb/Layout/InlineNode.h>
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
#include <LibWeb/Layout/TextNode.h>
|
||||
|
||||
//#define EVENT_DEBUG
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
Node::Node(Document& document, NodeType type)
|
||||
: EventTarget(static_cast<Bindings::ScriptExecutionContext&>(document))
|
||||
, m_document(&document)
|
||||
, m_type(type)
|
||||
{
|
||||
if (!is_document())
|
||||
m_document->ref_from_node({});
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
ASSERT(m_deletion_has_begun);
|
||||
if (layout_node() && layout_node()->parent())
|
||||
layout_node()->parent()->remove_child(*layout_node());
|
||||
|
||||
if (!is_document())
|
||||
m_document->unref_from_node({});
|
||||
}
|
||||
|
||||
const HTML::HTMLAnchorElement* Node::enclosing_link_element() const
|
||||
{
|
||||
for (auto* node = this; node; node = node->parent()) {
|
||||
if (is<HTML::HTMLAnchorElement>(*node) && downcast<HTML::HTMLAnchorElement>(*node).has_attribute(HTML::AttributeNames::href))
|
||||
return downcast<HTML::HTMLAnchorElement>(node);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const HTML::HTMLElement* Node::enclosing_html_element() const
|
||||
{
|
||||
return first_ancestor_of_type<HTML::HTMLElement>();
|
||||
}
|
||||
|
||||
String Node::text_content() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
||||
builder.append(child->text_content());
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
void Node::set_text_content(const String& content)
|
||||
{
|
||||
if (is_text()) {
|
||||
downcast<Text>(this)->set_data(content);
|
||||
} else {
|
||||
remove_all_children();
|
||||
append_child(document().create_text_node(content));
|
||||
}
|
||||
|
||||
set_needs_style_update(true);
|
||||
document().invalidate_layout();
|
||||
}
|
||||
|
||||
RefPtr<Layout::Node> Node::create_layout_node()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Node::invalidate_style()
|
||||
{
|
||||
for_each_in_subtree_of_type<Element>([&](auto& element) {
|
||||
element.set_needs_style_update(true);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
document().schedule_style_update();
|
||||
}
|
||||
|
||||
bool Node::is_link() const
|
||||
{
|
||||
return enclosing_link_element();
|
||||
}
|
||||
|
||||
bool Node::dispatch_event(NonnullRefPtr<Event> event)
|
||||
{
|
||||
return EventDispatcher::dispatch(*this, event);
|
||||
}
|
||||
|
||||
String Node::child_text_content() const
|
||||
{
|
||||
if (!is<ParentNode>(*this))
|
||||
return String::empty();
|
||||
|
||||
StringBuilder builder;
|
||||
downcast<ParentNode>(*this).for_each_child([&](auto& child) {
|
||||
if (is<Text>(child))
|
||||
builder.append(downcast<Text>(child).text_content());
|
||||
});
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
Node* Node::root()
|
||||
{
|
||||
Node* root = this;
|
||||
while (root->parent())
|
||||
root = root->parent();
|
||||
return root;
|
||||
}
|
||||
|
||||
Node* Node::shadow_including_root()
|
||||
{
|
||||
auto node_root = root();
|
||||
if (is<ShadowRoot>(node_root))
|
||||
return downcast<ShadowRoot>(node_root)->host()->shadow_including_root();
|
||||
return node_root;
|
||||
}
|
||||
|
||||
bool Node::is_connected() const
|
||||
{
|
||||
return shadow_including_root() && shadow_including_root()->is_document();
|
||||
}
|
||||
|
||||
Element* Node::parent_element()
|
||||
{
|
||||
if (!parent() || !is<Element>(parent()))
|
||||
return nullptr;
|
||||
return downcast<Element>(parent());
|
||||
}
|
||||
|
||||
const Element* Node::parent_element() const
|
||||
{
|
||||
if (!parent() || !is<Element>(parent()))
|
||||
return nullptr;
|
||||
return downcast<Element>(parent());
|
||||
}
|
||||
|
||||
RefPtr<Node> Node::append_child(NonnullRefPtr<Node> node, bool notify)
|
||||
{
|
||||
if (&node->document() != &document())
|
||||
document().adopt_node(node);
|
||||
TreeNode<Node>::append_child(node, notify);
|
||||
return node;
|
||||
}
|
||||
|
||||
RefPtr<Node> Node::insert_before(NonnullRefPtr<Node> node, RefPtr<Node> child, bool notify)
|
||||
{
|
||||
if (!child)
|
||||
return append_child(move(node), notify);
|
||||
if (child->parent_node() != this) {
|
||||
dbgln("FIXME: Trying to insert_before() a bogus child");
|
||||
return nullptr;
|
||||
}
|
||||
if (&node->document() != &document())
|
||||
document().adopt_node(node);
|
||||
TreeNode<Node>::insert_before(node, child, notify);
|
||||
return node;
|
||||
}
|
||||
|
||||
void Node::set_document(Badge<Document>, Document& document)
|
||||
{
|
||||
if (m_document == &document)
|
||||
return;
|
||||
document.ref_from_node({});
|
||||
m_document->unref_from_node({});
|
||||
m_document = &document;
|
||||
}
|
||||
|
||||
bool Node::is_editable() const
|
||||
{
|
||||
return parent() && parent()->is_editable();
|
||||
}
|
||||
|
||||
Bindings::EventTargetWrapper* Node::create_wrapper(JS::GlobalObject& global_object)
|
||||
{
|
||||
return wrap(global_object, *this);
|
||||
}
|
||||
|
||||
void Node::removed_last_ref()
|
||||
{
|
||||
if (is<Document>(*this)) {
|
||||
downcast<Document>(*this).removed_last_ref();
|
||||
return;
|
||||
}
|
||||
m_deletion_has_begun = true;
|
||||
delete this;
|
||||
}
|
||||
|
||||
void Node::set_layout_node(Badge<Layout::Node>, Layout::Node* layout_node) const
|
||||
{
|
||||
if (layout_node)
|
||||
m_layout_node = layout_node->make_weak_ptr();
|
||||
else
|
||||
m_layout_node = nullptr;
|
||||
}
|
||||
|
||||
EventTarget* Node::get_parent(const Event&)
|
||||
{
|
||||
// FIXME: returns the node’s assigned slot, if node is assigned, and node’s parent otherwise.
|
||||
return parent();
|
||||
}
|
||||
|
||||
void Node::set_needs_style_update(bool value)
|
||||
{
|
||||
if (m_needs_style_update == value)
|
||||
return;
|
||||
m_needs_style_update = value;
|
||||
|
||||
if (m_needs_style_update) {
|
||||
for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent())
|
||||
ancestor->m_child_needs_style_update = true;
|
||||
document().schedule_style_update();
|
||||
}
|
||||
}
|
||||
|
||||
void Node::inserted_into(Node&)
|
||||
{
|
||||
set_needs_style_update(true);
|
||||
}
|
||||
|
||||
}
|
156
Userland/Libraries/LibWeb/DOM/Node.h
Normal file
156
Userland/Libraries/LibWeb/DOM/Node.h
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
#include <LibWeb/TreeNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
enum class NodeType : unsigned {
|
||||
INVALID = 0,
|
||||
ELEMENT_NODE = 1,
|
||||
TEXT_NODE = 3,
|
||||
COMMENT_NODE = 8,
|
||||
DOCUMENT_NODE = 9,
|
||||
DOCUMENT_TYPE_NODE = 10,
|
||||
DOCUMENT_FRAGMENT_NODE = 11,
|
||||
};
|
||||
|
||||
class Node
|
||||
: public TreeNode<Node>
|
||||
, public EventTarget
|
||||
, public Bindings::Wrappable {
|
||||
public:
|
||||
using WrapperType = Bindings::NodeWrapper;
|
||||
|
||||
using TreeNode<Node>::ref;
|
||||
using TreeNode<Node>::unref;
|
||||
|
||||
// ^EventTarget
|
||||
virtual void ref_event_target() final { ref(); }
|
||||
virtual void unref_event_target() final { unref(); }
|
||||
virtual bool dispatch_event(NonnullRefPtr<Event>) final;
|
||||
virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) override;
|
||||
|
||||
virtual ~Node();
|
||||
|
||||
void removed_last_ref();
|
||||
|
||||
NodeType type() const { return m_type; }
|
||||
bool is_element() const { return type() == NodeType::ELEMENT_NODE; }
|
||||
bool is_text() const { return type() == NodeType::TEXT_NODE; }
|
||||
bool is_document() const { return type() == NodeType::DOCUMENT_NODE; }
|
||||
bool is_document_type() const { return type() == NodeType::DOCUMENT_TYPE_NODE; }
|
||||
bool is_comment() const { return type() == NodeType::COMMENT_NODE; }
|
||||
bool is_character_data() const { return type() == NodeType::TEXT_NODE || type() == NodeType::COMMENT_NODE; }
|
||||
bool is_document_fragment() const { return type() == NodeType::DOCUMENT_FRAGMENT_NODE; }
|
||||
bool is_parent_node() const { return is_element() || is_document() || is_document_fragment(); }
|
||||
bool is_slottable() const { return is_element() || is_text(); }
|
||||
|
||||
virtual bool is_editable() const;
|
||||
|
||||
RefPtr<Node> append_child(NonnullRefPtr<Node>, bool notify = true);
|
||||
RefPtr<Node> insert_before(NonnullRefPtr<Node> node, RefPtr<Node> child, bool notify = true);
|
||||
|
||||
virtual RefPtr<Layout::Node> create_layout_node();
|
||||
|
||||
virtual FlyString node_name() const = 0;
|
||||
|
||||
virtual String text_content() const;
|
||||
void set_text_content(const String&);
|
||||
|
||||
Document& document() { return *m_document; }
|
||||
const Document& document() const { return *m_document; }
|
||||
|
||||
const HTML::HTMLAnchorElement* enclosing_link_element() const;
|
||||
const HTML::HTMLElement* enclosing_html_element() const;
|
||||
|
||||
String child_text_content() const;
|
||||
|
||||
Node* root();
|
||||
const Node* root() const
|
||||
{
|
||||
return const_cast<Node*>(this)->root();
|
||||
}
|
||||
|
||||
Node* shadow_including_root();
|
||||
const Node* shadow_including_root() const
|
||||
{
|
||||
return const_cast<Node*>(this)->shadow_including_root();
|
||||
}
|
||||
|
||||
bool is_connected() const;
|
||||
|
||||
Node* parent_node() { return parent(); }
|
||||
const Node* parent_node() const { return parent(); }
|
||||
|
||||
Element* parent_element();
|
||||
const Element* parent_element() const;
|
||||
|
||||
virtual void inserted_into(Node&);
|
||||
virtual void removed_from(Node&) { }
|
||||
virtual void children_changed() { }
|
||||
|
||||
const Layout::Node* layout_node() const { return m_layout_node; }
|
||||
Layout::Node* layout_node() { return m_layout_node; }
|
||||
|
||||
void set_layout_node(Badge<Layout::Node>, Layout::Node*) const;
|
||||
|
||||
virtual bool is_child_allowed(const Node&) const { return true; }
|
||||
|
||||
bool needs_style_update() const { return m_needs_style_update; }
|
||||
void set_needs_style_update(bool);
|
||||
|
||||
bool child_needs_style_update() const { return m_child_needs_style_update; }
|
||||
void set_child_needs_style_update(bool b) { m_child_needs_style_update = b; }
|
||||
|
||||
void invalidate_style();
|
||||
|
||||
bool is_link() const;
|
||||
|
||||
void set_document(Badge<Document>, Document&);
|
||||
|
||||
virtual EventTarget* get_parent(const Event&) override;
|
||||
|
||||
protected:
|
||||
Node(Document&, NodeType);
|
||||
|
||||
Document* m_document { nullptr };
|
||||
mutable WeakPtr<Layout::Node> m_layout_node;
|
||||
NodeType m_type { NodeType::INVALID };
|
||||
bool m_needs_style_update { false };
|
||||
bool m_child_needs_style_update { false };
|
||||
};
|
||||
|
||||
}
|
16
Userland/Libraries/LibWeb/DOM/Node.idl
Normal file
16
Userland/Libraries/LibWeb/DOM/Node.idl
Normal file
|
@ -0,0 +1,16 @@
|
|||
interface Node : EventTarget {
|
||||
|
||||
readonly attribute DOMString nodeName;
|
||||
readonly attribute Node? firstChild;
|
||||
readonly attribute Node? lastChild;
|
||||
readonly attribute Node? previousSibling;
|
||||
readonly attribute Node? nextSibling;
|
||||
readonly attribute Node? parentNode;
|
||||
readonly attribute Element? parentElement;
|
||||
attribute DOMString textContent;
|
||||
|
||||
Node appendChild(Node node);
|
||||
Node insertBefore(Node node, Node? child);
|
||||
|
||||
};
|
||||
|
73
Userland/Libraries/LibWeb/DOM/NonDocumentTypeChildNode.h
Normal file
73
Userland/Libraries/LibWeb/DOM/NonDocumentTypeChildNode.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/TreeNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
template<typename NodeType>
|
||||
class NonDocumentTypeChildNode {
|
||||
public:
|
||||
Element* previous_element_sibling()
|
||||
{
|
||||
for (auto* sibling = static_cast<NodeType*>(this)->previous_sibling(); sibling; sibling = sibling->previous_sibling()) {
|
||||
if (is<Element>(*sibling))
|
||||
return downcast<Element>(sibling);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element* next_element_sibling()
|
||||
{
|
||||
for (auto* sibling = static_cast<NodeType*>(this)->next_sibling(); sibling; sibling = sibling->next_sibling()) {
|
||||
if (is<Element>(*sibling))
|
||||
return downcast<Element>(sibling);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element* next_element_in_pre_order()
|
||||
{
|
||||
for (auto* node = static_cast<NodeType*>(this)->next_in_pre_order(); node; node = node->next_in_pre_order()) {
|
||||
if (is<Element>(*node))
|
||||
return downcast<Element>(node);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Element* previous_element_sibling() const { return const_cast<NonDocumentTypeChildNode*>(this)->previous_element_sibling(); }
|
||||
const Element* next_element_sibling() const { return const_cast<NonDocumentTypeChildNode*>(this)->next_element_sibling(); }
|
||||
const Element* next_element_in_pre_order() const { return const_cast<NonDocumentTypeChildNode*>(this)->next_element_in_pre_order(); }
|
||||
|
||||
protected:
|
||||
NonDocumentTypeChildNode() { }
|
||||
};
|
||||
|
||||
}
|
60
Userland/Libraries/LibWeb/DOM/NonElementParentNode.h
Normal file
60
Userland/Libraries/LibWeb/DOM/NonElementParentNode.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/HTML/AttributeNames.h>
|
||||
#include <LibWeb/TreeNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
template<typename NodeType>
|
||||
class NonElementParentNode {
|
||||
public:
|
||||
RefPtr<Element> get_element_by_id(const FlyString& id) const
|
||||
{
|
||||
RefPtr<Element> found_element;
|
||||
static_cast<const NodeType*>(this)->template for_each_in_subtree_of_type<Element>([&](auto& element) {
|
||||
if (element.attribute(HTML::AttributeNames::id) == id) {
|
||||
found_element = &element;
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return found_element;
|
||||
}
|
||||
RefPtr<Element> get_element_by_id(const FlyString& id)
|
||||
{
|
||||
return const_cast<const NonElementParentNode*>(this)->get_element_by_id(id);
|
||||
}
|
||||
|
||||
protected:
|
||||
NonElementParentNode() { }
|
||||
};
|
||||
|
||||
}
|
83
Userland/Libraries/LibWeb/DOM/ParentNode.cpp
Normal file
83
Userland/Libraries/LibWeb/DOM/ParentNode.cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Luke Wilde <luke.wilde@live.co.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/CSS/Parser/CSSParser.h>
|
||||
#include <LibWeb/CSS/SelectorEngine.h>
|
||||
#include <LibWeb/DOM/ParentNode.h>
|
||||
#include <LibWeb/Dump.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
RefPtr<Element> ParentNode::query_selector(const StringView& selector_text)
|
||||
{
|
||||
auto selector = parse_selector(CSS::ParsingContext(*this), 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> ParentNode::query_selector_all(const StringView& selector_text)
|
||||
{
|
||||
auto selector = parse_selector(CSS::ParsingContext(*this), selector_text);
|
||||
if (!selector.has_value())
|
||||
return {};
|
||||
|
||||
dump_selector(selector.value());
|
||||
|
||||
NonnullRefPtrVector<Element> elements;
|
||||
for_each_in_subtree_of_type<Element>([&](auto& element) {
|
||||
if (SelectorEngine::matches(selector.value(), element)) {
|
||||
elements.append(element);
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
RefPtr<Element> ParentNode::first_element_child()
|
||||
{
|
||||
return first_child_of_type<Element>();
|
||||
}
|
||||
|
||||
RefPtr<Element> ParentNode::last_element_child()
|
||||
{
|
||||
return last_child_of_type<Element>();
|
||||
}
|
||||
|
||||
}
|
68
Userland/Libraries/LibWeb/DOM/ParentNode.h
Normal file
68
Userland/Libraries/LibWeb/DOM/ParentNode.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtrVector.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class ParentNode : public Node {
|
||||
public:
|
||||
template<typename F>
|
||||
void for_each_child(F) const;
|
||||
template<typename F>
|
||||
void for_each_child(F);
|
||||
|
||||
RefPtr<Element> first_element_child();
|
||||
RefPtr<Element> last_element_child();
|
||||
|
||||
RefPtr<Element> query_selector(const StringView&);
|
||||
NonnullRefPtrVector<Element> query_selector_all(const StringView&);
|
||||
|
||||
protected:
|
||||
ParentNode(Document& document, NodeType type)
|
||||
: Node(document, type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Callback>
|
||||
inline void ParentNode::for_each_child(Callback callback) const
|
||||
{
|
||||
for (auto* node = first_child(); node; node = node->next_sibling())
|
||||
callback(*node);
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
inline void ParentNode::for_each_child(Callback callback)
|
||||
{
|
||||
for (auto* node = first_child(); node; node = node->next_sibling())
|
||||
callback(*node);
|
||||
}
|
||||
|
||||
}
|
49
Userland/Libraries/LibWeb/DOM/Position.cpp
Normal file
49
Userland/Libraries/LibWeb/DOM/Position.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/DOM/Position.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
Position::Position(Node& node, unsigned offset)
|
||||
: m_node(node)
|
||||
, m_offset(offset)
|
||||
{
|
||||
}
|
||||
|
||||
Position::~Position()
|
||||
{
|
||||
}
|
||||
|
||||
String Position::to_string() const
|
||||
{
|
||||
if (!node())
|
||||
return String::formatted("DOM::Position(nullptr, {})", offset());
|
||||
return String::formatted("DOM::Position({} ({})), {})", node()->node_name(), node(), offset());
|
||||
}
|
||||
|
||||
}
|
78
Userland/Libraries/LibWeb/DOM/Position.h
Normal file
78
Userland/Libraries/LibWeb/DOM/Position.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/RefPtr.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Position {
|
||||
public:
|
||||
Position() { }
|
||||
Position(Node&, unsigned offset);
|
||||
|
||||
~Position();
|
||||
|
||||
bool is_valid() const { return m_node; }
|
||||
|
||||
Node* node() { return m_node; }
|
||||
const Node* node() const { return m_node; }
|
||||
|
||||
unsigned offset() const { return m_offset; }
|
||||
void set_offset(unsigned value) { m_offset = value; }
|
||||
|
||||
bool operator==(const Position& other) const
|
||||
{
|
||||
return m_node == other.m_node && m_offset == other.m_offset;
|
||||
}
|
||||
|
||||
bool operator!=(const Position& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
RefPtr<Node> m_node;
|
||||
unsigned m_offset { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace AK {
|
||||
template<>
|
||||
struct Formatter<Web::DOM::Position> : Formatter<StringView> {
|
||||
void format(FormatBuilder& builder, const Web::DOM::Position& value)
|
||||
{
|
||||
Formatter<StringView>::format(builder, value.to_string());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
75
Userland/Libraries/LibWeb/DOM/Range.cpp
Normal file
75
Userland/Libraries/LibWeb/DOM/Range.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/DOM/Range.h>
|
||||
#include <LibWeb/DOM/Window.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
Range::Range(Window& window)
|
||||
: m_start_container(window.document())
|
||||
, m_start_offset(0)
|
||||
, m_end_container(window.document())
|
||||
, m_end_offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
Range::Range(Node& start_container, size_t start_offset, Node& end_container, size_t end_offset)
|
||||
: m_start_container(start_container)
|
||||
, m_start_offset(start_offset)
|
||||
, m_end_container(end_container)
|
||||
, m_end_offset(end_offset)
|
||||
{
|
||||
}
|
||||
|
||||
NonnullRefPtr<Range> Range::clone_range() const
|
||||
{
|
||||
return adopt(*new Range(const_cast<Node&>(*m_start_container), m_start_offset, const_cast<Node&>(*m_end_container), m_end_offset));
|
||||
}
|
||||
|
||||
NonnullRefPtr<Range> Range::inverted() const
|
||||
{
|
||||
return adopt(*new Range(const_cast<Node&>(*m_end_container), m_end_offset, const_cast<Node&>(*m_start_container), m_start_offset));
|
||||
}
|
||||
|
||||
NonnullRefPtr<Range> Range::normalized() const
|
||||
{
|
||||
if (m_start_container.ptr() == m_end_container.ptr()) {
|
||||
if (m_start_offset <= m_end_offset)
|
||||
return clone_range();
|
||||
|
||||
return inverted();
|
||||
}
|
||||
|
||||
if (m_start_container->is_before(m_end_container))
|
||||
return clone_range();
|
||||
|
||||
return inverted();
|
||||
}
|
||||
|
||||
}
|
90
Userland/Libraries/LibWeb/DOM/Range.h
Normal file
90
Userland/Libraries/LibWeb/DOM/Range.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/RefCounted.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Range final
|
||||
: public RefCounted<Range>
|
||||
, public Bindings::Wrappable {
|
||||
public:
|
||||
using WrapperType = Bindings::RangeWrapper;
|
||||
|
||||
static NonnullRefPtr<Range> create(Window& window)
|
||||
{
|
||||
return adopt(*new Range(window));
|
||||
}
|
||||
static NonnullRefPtr<Range> create(Node& start_container, size_t start_offset, Node& end_container, size_t end_offset)
|
||||
{
|
||||
return adopt(*new Range(start_container, start_offset, end_container, end_offset));
|
||||
}
|
||||
|
||||
// FIXME: There are a ton of methods missing here.
|
||||
|
||||
Node* start_container() { return m_start_container; }
|
||||
unsigned start_offset() { return m_start_offset; }
|
||||
|
||||
Node* end_container() { return m_end_container; }
|
||||
unsigned end_offset() { return m_end_offset; }
|
||||
|
||||
bool collapsed()
|
||||
{
|
||||
return start_container() == end_container() && start_offset() == end_offset();
|
||||
}
|
||||
|
||||
void set_start(Node& container, unsigned offset)
|
||||
{
|
||||
m_start_container = container;
|
||||
m_start_offset = offset;
|
||||
}
|
||||
|
||||
void set_end(Node& container, unsigned offset)
|
||||
{
|
||||
m_end_container = container;
|
||||
m_end_offset = offset;
|
||||
}
|
||||
|
||||
NonnullRefPtr<Range> inverted() const;
|
||||
NonnullRefPtr<Range> normalized() const;
|
||||
NonnullRefPtr<Range> clone_range() const;
|
||||
|
||||
private:
|
||||
explicit Range(Window&);
|
||||
Range(Node& start_container, size_t start_offset, Node& end_container, size_t end_offset);
|
||||
|
||||
NonnullRefPtr<Node> m_start_container;
|
||||
unsigned m_start_offset;
|
||||
|
||||
NonnullRefPtr<Node> m_end_container;
|
||||
unsigned m_end_offset;
|
||||
};
|
||||
|
||||
}
|
49
Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp
Normal file
49
Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/ShadowRoot.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
ShadowRoot::ShadowRoot(Document& document, Element& host)
|
||||
: DocumentFragment(document)
|
||||
{
|
||||
set_host(host);
|
||||
}
|
||||
|
||||
EventTarget* ShadowRoot::get_parent(const Event& event)
|
||||
{
|
||||
if (!event.composed()) {
|
||||
auto& events_first_invocation_target = downcast<Node>(*event.path().first().invocation_target);
|
||||
if (events_first_invocation_target.root() == this)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return host();
|
||||
}
|
||||
|
||||
}
|
58
Userland/Libraries/LibWeb/DOM/ShadowRoot.h
Normal file
58
Userland/Libraries/LibWeb/DOM/ShadowRoot.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/DOM/DocumentFragment.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class ShadowRoot final : public DocumentFragment {
|
||||
public:
|
||||
ShadowRoot(Document&, Element&);
|
||||
|
||||
bool closed() const { return m_closed; }
|
||||
|
||||
bool delegates_focus() const { return m_delegates_focus; }
|
||||
void set_delegates_focus(bool delegates_focus) { m_delegates_focus = delegates_focus; }
|
||||
|
||||
bool available_to_element_internals() const { return m_available_to_element_internals; }
|
||||
void set_available_to_element_internals(bool available_to_element_internals) { m_available_to_element_internals = available_to_element_internals; }
|
||||
|
||||
// ^EventTarget
|
||||
virtual EventTarget* get_parent(const Event&) override;
|
||||
|
||||
// NOTE: This is intended for the JS bindings.
|
||||
String mode() const { return m_closed ? "closed" : "open"; }
|
||||
|
||||
private:
|
||||
// NOTE: The specification doesn't seem to specify a default value for closed. Assuming false for now.
|
||||
bool m_closed { false };
|
||||
bool m_delegates_focus { false };
|
||||
bool m_available_to_element_internals { false };
|
||||
};
|
||||
|
||||
}
|
6
Userland/Libraries/LibWeb/DOM/ShadowRoot.idl
Normal file
6
Userland/Libraries/LibWeb/DOM/ShadowRoot.idl
Normal file
|
@ -0,0 +1,6 @@
|
|||
interface ShadowRoot : DocumentFragment {
|
||||
|
||||
readonly attribute DOMString mode;
|
||||
readonly attribute Element host;
|
||||
|
||||
};
|
46
Userland/Libraries/LibWeb/DOM/Text.cpp
Normal file
46
Userland/Libraries/LibWeb/DOM/Text.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/Layout/TextNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
Text::Text(Document& document, const String& data)
|
||||
: CharacterData(document, NodeType::TEXT_NODE, data)
|
||||
{
|
||||
}
|
||||
|
||||
Text::~Text()
|
||||
{
|
||||
}
|
||||
|
||||
RefPtr<Layout::Node> Text::create_layout_node()
|
||||
{
|
||||
return adopt(*new Layout::TextNode(document(), *this));
|
||||
}
|
||||
|
||||
}
|
48
Userland/Libraries/LibWeb/DOM/Text.h
Normal file
48
Userland/Libraries/LibWeb/DOM/Text.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/DOM/CharacterData.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Text final : public CharacterData {
|
||||
public:
|
||||
using WrapperType = Bindings::TextWrapper;
|
||||
|
||||
explicit Text(Document&, const String&);
|
||||
virtual ~Text() override;
|
||||
|
||||
virtual FlyString node_name() const override { return "#text"; }
|
||||
|
||||
private:
|
||||
virtual RefPtr<Layout::Node> create_layout_node() override;
|
||||
};
|
||||
|
||||
}
|
3
Userland/Libraries/LibWeb/DOM/Text.idl
Normal file
3
Userland/Libraries/LibWeb/DOM/Text.idl
Normal file
|
@ -0,0 +1,3 @@
|
|||
interface Text : CharacterData {
|
||||
|
||||
};
|
60
Userland/Libraries/LibWeb/DOM/Timer.cpp
Normal file
60
Userland/Libraries/LibWeb/DOM/Timer.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibCore/Timer.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibWeb/DOM/Timer.h>
|
||||
#include <LibWeb/DOM/Window.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
NonnullRefPtr<Timer> Timer::create_interval(Window& window, int milliseconds, JS::Function& callback)
|
||||
{
|
||||
return adopt(*new Timer(window, Type::Interval, milliseconds, callback));
|
||||
}
|
||||
|
||||
NonnullRefPtr<Timer> Timer::create_timeout(Window& window, int milliseconds, JS::Function& callback)
|
||||
{
|
||||
return adopt(*new Timer(window, Type::Timeout, milliseconds, callback));
|
||||
}
|
||||
|
||||
Timer::Timer(Window& window, Type type, int milliseconds, JS::Function& callback)
|
||||
: m_window(window)
|
||||
, m_type(type)
|
||||
, m_callback(JS::make_handle(&callback))
|
||||
{
|
||||
m_id = window.allocate_timer_id({});
|
||||
m_timer = Core::Timer::construct(milliseconds, [this] { m_window.timer_did_fire({}, *this); });
|
||||
if (m_type == Type::Timeout)
|
||||
m_timer->set_single_shot(true);
|
||||
}
|
||||
|
||||
Timer::~Timer()
|
||||
{
|
||||
m_window.deallocate_timer_id({}, m_id);
|
||||
}
|
||||
|
||||
}
|
63
Userland/Libraries/LibWeb/DOM/Timer.h
Normal file
63
Userland/Libraries/LibWeb/DOM/Timer.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <LibCore/Forward.h>
|
||||
#include <LibJS/Heap/Handle.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Timer final : public RefCounted<Timer> {
|
||||
public:
|
||||
enum class Type {
|
||||
Interval,
|
||||
Timeout,
|
||||
};
|
||||
|
||||
static NonnullRefPtr<Timer> create_interval(Window&, int milliseconds, JS::Function&);
|
||||
static NonnullRefPtr<Timer> create_timeout(Window&, int milliseconds, JS::Function&);
|
||||
|
||||
~Timer();
|
||||
|
||||
i32 id() const { return m_id; }
|
||||
Type type() const { return m_type; }
|
||||
|
||||
JS::Function& callback() { return *m_callback.cell(); }
|
||||
|
||||
private:
|
||||
Timer(Window&, Type, int ms, JS::Function&);
|
||||
|
||||
Window& m_window;
|
||||
RefPtr<Core::Timer> m_timer;
|
||||
Type m_type;
|
||||
int m_id { 0 };
|
||||
JS::Handle<JS::Function> m_callback;
|
||||
};
|
||||
|
||||
}
|
177
Userland/Libraries/LibWeb/DOM/Window.cpp
Normal file
177
Userland/Libraries/LibWeb/DOM/Window.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibGUI/DisplayLink.h>
|
||||
#include <LibGUI/MessageBox.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/EventDispatcher.h>
|
||||
#include <LibWeb/DOM/Timer.h>
|
||||
#include <LibWeb/DOM/Window.h>
|
||||
#include <LibWeb/HighResolutionTime/Performance.h>
|
||||
#include <LibWeb/InProcessWebView.h>
|
||||
#include <LibWeb/Page/Frame.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
NonnullRefPtr<Window> Window::create_with_document(Document& document)
|
||||
{
|
||||
return adopt(*new Window(document));
|
||||
}
|
||||
|
||||
Window::Window(Document& document)
|
||||
: EventTarget(static_cast<Bindings::ScriptExecutionContext&>(document))
|
||||
, m_document(document)
|
||||
, m_performance(make<HighResolutionTime::Performance>(*this))
|
||||
{
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
}
|
||||
|
||||
void Window::set_wrapper(Badge<Bindings::WindowObject>, Bindings::WindowObject& wrapper)
|
||||
{
|
||||
m_wrapper = wrapper.make_weak_ptr();
|
||||
}
|
||||
|
||||
void Window::alert(const String& message)
|
||||
{
|
||||
if (auto* page = m_document.page())
|
||||
page->client().page_did_request_alert(message);
|
||||
}
|
||||
|
||||
bool Window::confirm(const String& message)
|
||||
{
|
||||
auto confirm_result = GUI::MessageBox::show(nullptr, message, "Confirm", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::OKCancel);
|
||||
return confirm_result == GUI::Dialog::ExecResult::ExecOK;
|
||||
}
|
||||
|
||||
i32 Window::set_interval(JS::Function& callback, i32 interval)
|
||||
{
|
||||
auto timer = Timer::create_interval(*this, interval, callback);
|
||||
m_timers.set(timer->id(), timer);
|
||||
return timer->id();
|
||||
}
|
||||
|
||||
i32 Window::set_timeout(JS::Function& callback, i32 interval)
|
||||
{
|
||||
auto timer = Timer::create_timeout(*this, interval, callback);
|
||||
m_timers.set(timer->id(), timer);
|
||||
return timer->id();
|
||||
}
|
||||
|
||||
void Window::timer_did_fire(Badge<Timer>, Timer& timer)
|
||||
{
|
||||
// We should not be here if there's no JS wrapper for the Window object.
|
||||
ASSERT(wrapper());
|
||||
auto& vm = wrapper()->vm();
|
||||
|
||||
// NOTE: This protector pointer keeps the timer alive until the end of this function no matter what.
|
||||
NonnullRefPtr protector(timer);
|
||||
|
||||
if (timer.type() == Timer::Type::Timeout) {
|
||||
m_timers.remove(timer.id());
|
||||
}
|
||||
|
||||
[[maybe_unused]] auto rc = vm.call(timer.callback(), wrapper());
|
||||
if (vm.exception())
|
||||
vm.clear_exception();
|
||||
}
|
||||
|
||||
i32 Window::allocate_timer_id(Badge<Timer>)
|
||||
{
|
||||
return m_timer_id_allocator.allocate();
|
||||
}
|
||||
|
||||
void Window::deallocate_timer_id(Badge<Timer>, i32 id)
|
||||
{
|
||||
m_timer_id_allocator.deallocate(id);
|
||||
}
|
||||
|
||||
void Window::clear_timeout(i32 timer_id)
|
||||
{
|
||||
m_timers.remove(timer_id);
|
||||
}
|
||||
|
||||
void Window::clear_interval(i32 timer_id)
|
||||
{
|
||||
m_timers.remove(timer_id);
|
||||
}
|
||||
|
||||
i32 Window::request_animation_frame(JS::Function& callback)
|
||||
{
|
||||
// FIXME: This is extremely fake!
|
||||
static double fake_timestamp = 0;
|
||||
|
||||
i32 link_id = GUI::DisplayLink::register_callback([handle = make_handle(&callback)](i32 link_id) {
|
||||
auto& function = const_cast<JS::Function&>(static_cast<const JS::Function&>(*handle.cell()));
|
||||
auto& vm = function.vm();
|
||||
fake_timestamp += 10;
|
||||
[[maybe_unused]] auto rc = vm.call(function, {}, JS::Value(fake_timestamp));
|
||||
if (vm.exception())
|
||||
vm.clear_exception();
|
||||
GUI::DisplayLink::unregister_callback(link_id);
|
||||
});
|
||||
|
||||
// FIXME: Don't hand out raw DisplayLink ID's to JavaScript!
|
||||
return link_id;
|
||||
}
|
||||
|
||||
void Window::cancel_animation_frame(i32 id)
|
||||
{
|
||||
// FIXME: We should not be passing untrusted numbers to DisplayLink::unregister_callback()!
|
||||
GUI::DisplayLink::unregister_callback(id);
|
||||
}
|
||||
|
||||
void Window::did_set_location_href(Badge<Bindings::LocationObject>, const URL& new_href)
|
||||
{
|
||||
auto* frame = document().frame();
|
||||
if (!frame)
|
||||
return;
|
||||
frame->loader().load(new_href, FrameLoader::Type::Navigation);
|
||||
}
|
||||
|
||||
void Window::did_call_location_reload(Badge<Bindings::LocationObject>)
|
||||
{
|
||||
auto* frame = document().frame();
|
||||
if (!frame)
|
||||
return;
|
||||
frame->loader().load(document().url(), FrameLoader::Type::Reload);
|
||||
}
|
||||
|
||||
bool Window::dispatch_event(NonnullRefPtr<Event> event)
|
||||
{
|
||||
return EventDispatcher::dispatch(*this, event, true);
|
||||
}
|
||||
|
||||
Bindings::EventTargetWrapper* Window::create_wrapper(JS::GlobalObject&)
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
98
Userland/Libraries/LibWeb/DOM/Window.h
Normal file
98
Userland/Libraries/LibWeb/DOM/Window.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/IDAllocator.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Window final
|
||||
: public RefCounted<Window>
|
||||
, public EventTarget {
|
||||
public:
|
||||
static NonnullRefPtr<Window> create_with_document(Document&);
|
||||
~Window();
|
||||
|
||||
using RefCounted::ref;
|
||||
using RefCounted::unref;
|
||||
|
||||
virtual void ref_event_target() override { RefCounted::ref(); }
|
||||
virtual void unref_event_target() override { RefCounted::unref(); }
|
||||
virtual bool dispatch_event(NonnullRefPtr<Event>) override;
|
||||
virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) override;
|
||||
|
||||
const Document& document() const { return m_document; }
|
||||
Document& document() { return m_document; }
|
||||
|
||||
void alert(const String&);
|
||||
bool confirm(const String&);
|
||||
i32 request_animation_frame(JS::Function&);
|
||||
void cancel_animation_frame(i32);
|
||||
|
||||
i32 set_timeout(JS::Function&, i32);
|
||||
i32 set_interval(JS::Function&, i32);
|
||||
void clear_timeout(i32);
|
||||
void clear_interval(i32);
|
||||
|
||||
void did_set_location_href(Badge<Bindings::LocationObject>, const URL& new_href);
|
||||
void did_call_location_reload(Badge<Bindings::LocationObject>);
|
||||
|
||||
Bindings::WindowObject* wrapper() { return m_wrapper; }
|
||||
const Bindings::WindowObject* wrapper() const { return m_wrapper; }
|
||||
|
||||
void set_wrapper(Badge<Bindings::WindowObject>, Bindings::WindowObject&);
|
||||
|
||||
i32 allocate_timer_id(Badge<Timer>);
|
||||
void deallocate_timer_id(Badge<Timer>, i32);
|
||||
void timer_did_fire(Badge<Timer>, Timer&);
|
||||
|
||||
HighResolutionTime::Performance& performance() { return *m_performance; }
|
||||
|
||||
const Event* current_event() const { return m_current_event; }
|
||||
void set_current_event(Event* event) { m_current_event = event; }
|
||||
|
||||
private:
|
||||
explicit Window(Document&);
|
||||
|
||||
Document& m_document;
|
||||
WeakPtr<Bindings::WindowObject> m_wrapper;
|
||||
|
||||
IDAllocator m_timer_id_allocator;
|
||||
HashMap<int, NonnullRefPtr<Timer>> m_timers;
|
||||
|
||||
NonnullOwnPtr<HighResolutionTime::Performance> m_performance;
|
||||
RefPtr<Event> m_current_event;
|
||||
};
|
||||
|
||||
}
|
121
Userland/Libraries/LibWeb/DOM/XMLHttpRequest.cpp
Normal file
121
Userland/Libraries/LibWeb/DOM/XMLHttpRequest.cpp
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibWeb/Bindings/EventWrapper.h>
|
||||
#include <LibWeb/Bindings/EventWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/XMLHttpRequestWrapper.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/EventDispatcher.h>
|
||||
#include <LibWeb/DOM/EventListener.h>
|
||||
#include <LibWeb/DOM/Window.h>
|
||||
#include <LibWeb/DOM/XMLHttpRequest.h>
|
||||
#include <LibWeb/HTML/EventNames.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
#include <LibWeb/Origin.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
XMLHttpRequest::XMLHttpRequest(DOM::Window& window)
|
||||
: EventTarget(static_cast<Bindings::ScriptExecutionContext&>(window.document()))
|
||||
, m_window(window)
|
||||
{
|
||||
}
|
||||
|
||||
XMLHttpRequest::~XMLHttpRequest()
|
||||
{
|
||||
}
|
||||
|
||||
void XMLHttpRequest::set_ready_state(ReadyState ready_state)
|
||||
{
|
||||
// FIXME: call onreadystatechange once we have that
|
||||
m_ready_state = ready_state;
|
||||
}
|
||||
|
||||
String XMLHttpRequest::response_text() const
|
||||
{
|
||||
if (m_response.is_null())
|
||||
return {};
|
||||
return String::copy(m_response);
|
||||
}
|
||||
|
||||
void XMLHttpRequest::open(const String& method, const String& url)
|
||||
{
|
||||
m_method = method;
|
||||
m_url = url;
|
||||
set_ready_state(ReadyState::Opened);
|
||||
}
|
||||
|
||||
void XMLHttpRequest::send()
|
||||
{
|
||||
URL request_url = m_window->document().complete_url(m_url);
|
||||
dbg() << "XHR send from " << m_window->document().url() << " to " << request_url;
|
||||
|
||||
// TODO: Add support for preflight requests to support CORS requests
|
||||
Origin request_url_origin = Origin(request_url.protocol(), request_url.host(), request_url.port());
|
||||
|
||||
if (!m_window->document().origin().is_same(request_url_origin)) {
|
||||
dbg() << "XHR failed to load: Same-Origin Policy violation: " << m_window->document().url() << " may not load " << request_url;
|
||||
auto weak_this = make_weak_ptr();
|
||||
if (!weak_this)
|
||||
return;
|
||||
const_cast<XMLHttpRequest&>(*weak_this).set_ready_state(ReadyState::Done);
|
||||
const_cast<XMLHttpRequest&>(*weak_this).dispatch_event(DOM::Event::create(HTML::EventNames::error));
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: in order to properly set ReadyState::HeadersReceived and ReadyState::Loading,
|
||||
// we need to make ResourceLoader give us more detailed updates than just "done" and "error".
|
||||
ResourceLoader::the().load(
|
||||
m_window->document().complete_url(m_url),
|
||||
[weak_this = make_weak_ptr()](auto data, auto&) {
|
||||
if (!weak_this)
|
||||
return;
|
||||
const_cast<XMLHttpRequest&>(*weak_this).m_response = ByteBuffer::copy(data);
|
||||
const_cast<XMLHttpRequest&>(*weak_this).set_ready_state(ReadyState::Done);
|
||||
const_cast<XMLHttpRequest&>(*weak_this).dispatch_event(DOM::Event::create(HTML::EventNames::load));
|
||||
},
|
||||
[weak_this = make_weak_ptr()](auto& error) {
|
||||
if (!weak_this)
|
||||
return;
|
||||
dbg() << "XHR failed to load: " << error;
|
||||
const_cast<XMLHttpRequest&>(*weak_this).set_ready_state(ReadyState::Done);
|
||||
const_cast<XMLHttpRequest&>(*weak_this).dispatch_event(DOM::Event::create(HTML::EventNames::error));
|
||||
});
|
||||
}
|
||||
|
||||
bool XMLHttpRequest::dispatch_event(NonnullRefPtr<DOM::Event> event)
|
||||
{
|
||||
return DOM::EventDispatcher::dispatch(*this, move(event));
|
||||
}
|
||||
|
||||
Bindings::EventTargetWrapper* XMLHttpRequest::create_wrapper(JS::GlobalObject& global_object)
|
||||
{
|
||||
return wrap(global_object, *this);
|
||||
}
|
||||
|
||||
}
|
85
Userland/Libraries/LibWeb/DOM/XMLHttpRequest.h
Normal file
85
Userland/Libraries/LibWeb/DOM/XMLHttpRequest.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class XMLHttpRequest final
|
||||
: public RefCounted<XMLHttpRequest>
|
||||
, public Weakable<XMLHttpRequest>
|
||||
, public DOM::EventTarget
|
||||
, public Bindings::Wrappable {
|
||||
public:
|
||||
enum class ReadyState {
|
||||
Unsent,
|
||||
Opened,
|
||||
HeadersReceived,
|
||||
Loading,
|
||||
Done,
|
||||
};
|
||||
|
||||
using WrapperType = Bindings::XMLHttpRequestWrapper;
|
||||
|
||||
static NonnullRefPtr<XMLHttpRequest> create(DOM::Window& window) { return adopt(*new XMLHttpRequest(window)); }
|
||||
|
||||
virtual ~XMLHttpRequest() override;
|
||||
|
||||
using RefCounted::ref;
|
||||
using RefCounted::unref;
|
||||
|
||||
ReadyState ready_state() const { return m_ready_state; };
|
||||
String response_text() const;
|
||||
void open(const String& method, const String& url);
|
||||
void send();
|
||||
|
||||
private:
|
||||
virtual void ref_event_target() override { ref(); }
|
||||
virtual void unref_event_target() override { unref(); }
|
||||
virtual bool dispatch_event(NonnullRefPtr<DOM::Event>) override;
|
||||
virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) override;
|
||||
|
||||
void set_ready_state(ReadyState);
|
||||
|
||||
explicit XMLHttpRequest(DOM::Window&);
|
||||
|
||||
NonnullRefPtr<DOM::Window> m_window;
|
||||
|
||||
ReadyState m_ready_state { ReadyState::Unsent };
|
||||
|
||||
String m_method;
|
||||
String m_url;
|
||||
|
||||
ByteBuffer m_response;
|
||||
};
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue