From b94c7665a9ecbe6c5b5d81cd62d21787e6ff4d7e Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 29 Sep 2019 16:24:57 +0200 Subject: [PATCH] LibHTML: Add a way to get a Document's title You can now query Document::title() to get a String containing whatever is inside the document's tag. In support of this, this patch adds the <html>, <head> and <title> elements. --- Libraries/LibHTML/DOM/Document.cpp | 29 ++++++++++++++++++++++ Libraries/LibHTML/DOM/Document.h | 9 ++++++- Libraries/LibHTML/DOM/HTMLHeadElement.cpp | 10 ++++++++ Libraries/LibHTML/DOM/HTMLHeadElement.h | 9 +++++++ Libraries/LibHTML/DOM/HTMLHtmlElement.cpp | 10 ++++++++ Libraries/LibHTML/DOM/HTMLHtmlElement.h | 9 +++++++ Libraries/LibHTML/DOM/HTMLTitleElement.cpp | 10 ++++++++ Libraries/LibHTML/DOM/HTMLTitleElement.h | 9 +++++++ Libraries/LibHTML/DOM/Node.h | 9 +++++++ Libraries/LibHTML/HtmlView.h | 1 + Libraries/LibHTML/Makefile.shared | 3 +++ Libraries/LibHTML/Parser/HTMLParser.cpp | 9 +++++++ 12 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 Libraries/LibHTML/DOM/HTMLHeadElement.cpp create mode 100644 Libraries/LibHTML/DOM/HTMLHeadElement.h create mode 100644 Libraries/LibHTML/DOM/HTMLHtmlElement.cpp create mode 100644 Libraries/LibHTML/DOM/HTMLHtmlElement.h create mode 100644 Libraries/LibHTML/DOM/HTMLTitleElement.cpp create mode 100644 Libraries/LibHTML/DOM/HTMLTitleElement.h diff --git a/Libraries/LibHTML/DOM/Document.cpp b/Libraries/LibHTML/DOM/Document.cpp index 766be050ba0..22a9d0a9100 100644 --- a/Libraries/LibHTML/DOM/Document.cpp +++ b/Libraries/LibHTML/DOM/Document.cpp @@ -1,6 +1,9 @@ #include <LibHTML/CSS/StyleResolver.h> #include <LibHTML/DOM/Document.h> #include <LibHTML/DOM/Element.h> +#include <LibHTML/DOM/HTMLHeadElement.h> +#include <LibHTML/DOM/HTMLHtmlElement.h> +#include <LibHTML/DOM/HTMLTitleElement.h> #include <LibHTML/Layout/LayoutDocument.h> #include <stdio.h> @@ -34,3 +37,29 @@ void Document::normalize() this->donate_all_children_to(body); this->append_child(html); } + +const HTMLHtmlElement* Document::document_element() const +{ + return static_cast<const HTMLHtmlElement*>(first_child_with_tag_name("html")); +} + +const HTMLHeadElement* Document::head() const +{ + auto* html = document_element(); + if (!html) + return nullptr; + return static_cast<const HTMLHeadElement*>(html->first_child_with_tag_name("head")); +} + +String Document::title() const +{ + auto* head_element = head(); + if (!head_element) + return {}; + + auto* title_element = static_cast<const HTMLTitleElement*>(head_element->first_child_with_tag_name("title")); + if (!title_element) + return {}; + + return title_element->text_content(); +} diff --git a/Libraries/LibHTML/DOM/Document.h b/Libraries/LibHTML/DOM/Document.h index 1364cfb3c44..ce779e52f2a 100644 --- a/Libraries/LibHTML/DOM/Document.h +++ b/Libraries/LibHTML/DOM/Document.h @@ -1,12 +1,14 @@ #pragma once -#include <AK/String.h> #include <AK/NonnullRefPtrVector.h> #include <AK/OwnPtr.h> +#include <AK/String.h> #include <LibHTML/CSS/StyleResolver.h> #include <LibHTML/CSS/StyleSheet.h> #include <LibHTML/DOM/ParentNode.h> +class HTMLHtmlElement; +class HTMLHeadElement; class LayoutNode; class StyleResolver; class StyleSheet; @@ -29,6 +31,11 @@ public: Node* hovered_node() { return m_hovered_node; } const Node* hovered_node() const { return m_hovered_node; } + const HTMLHtmlElement* document_element() const; + const HTMLHeadElement* head() const; + + String title() const; + private: OwnPtr<StyleResolver> m_style_resolver; NonnullRefPtrVector<StyleSheet> m_sheets; diff --git a/Libraries/LibHTML/DOM/HTMLHeadElement.cpp b/Libraries/LibHTML/DOM/HTMLHeadElement.cpp new file mode 100644 index 00000000000..2bad3da75df --- /dev/null +++ b/Libraries/LibHTML/DOM/HTMLHeadElement.cpp @@ -0,0 +1,10 @@ +#include <LibHTML/DOM/HTMLHeadElement.h> + +HTMLHeadElement::HTMLHeadElement(Document& document, const String& tag_name) + : HTMLElement(document, tag_name) +{ +} + +HTMLHeadElement::~HTMLHeadElement() +{ +} diff --git a/Libraries/LibHTML/DOM/HTMLHeadElement.h b/Libraries/LibHTML/DOM/HTMLHeadElement.h new file mode 100644 index 00000000000..4586a26bf3e --- /dev/null +++ b/Libraries/LibHTML/DOM/HTMLHeadElement.h @@ -0,0 +1,9 @@ +#pragma once + +#include <LibHTML/DOM/HTMLElement.h> + +class HTMLHeadElement : public HTMLElement { +public: + HTMLHeadElement(Document&, const String& tag_name); + virtual ~HTMLHeadElement() override; +}; diff --git a/Libraries/LibHTML/DOM/HTMLHtmlElement.cpp b/Libraries/LibHTML/DOM/HTMLHtmlElement.cpp new file mode 100644 index 00000000000..cc12a426e8d --- /dev/null +++ b/Libraries/LibHTML/DOM/HTMLHtmlElement.cpp @@ -0,0 +1,10 @@ +#include <LibHTML/DOM/HTMLHtmlElement.h> + +HTMLHtmlElement::HTMLHtmlElement(Document& document, const String& tag_name) + : HTMLElement(document, tag_name) +{ +} + +HTMLHtmlElement::~HTMLHtmlElement() +{ +} diff --git a/Libraries/LibHTML/DOM/HTMLHtmlElement.h b/Libraries/LibHTML/DOM/HTMLHtmlElement.h new file mode 100644 index 00000000000..4ab5b78af63 --- /dev/null +++ b/Libraries/LibHTML/DOM/HTMLHtmlElement.h @@ -0,0 +1,9 @@ +#pragma once + +#include <LibHTML/DOM/HTMLElement.h> + +class HTMLHtmlElement : public HTMLElement { +public: + HTMLHtmlElement(Document&, const String& tag_name); + virtual ~HTMLHtmlElement() override; +}; diff --git a/Libraries/LibHTML/DOM/HTMLTitleElement.cpp b/Libraries/LibHTML/DOM/HTMLTitleElement.cpp new file mode 100644 index 00000000000..de4e6db20a0 --- /dev/null +++ b/Libraries/LibHTML/DOM/HTMLTitleElement.cpp @@ -0,0 +1,10 @@ +#include <LibHTML/DOM/HTMLTitleElement.h> + +HTMLTitleElement::HTMLTitleElement(Document& document, const String& tag_name) + : HTMLElement(document, tag_name) +{ +} + +HTMLTitleElement::~HTMLTitleElement() +{ +} diff --git a/Libraries/LibHTML/DOM/HTMLTitleElement.h b/Libraries/LibHTML/DOM/HTMLTitleElement.h new file mode 100644 index 00000000000..4b0edf803a4 --- /dev/null +++ b/Libraries/LibHTML/DOM/HTMLTitleElement.h @@ -0,0 +1,9 @@ +#pragma once + +#include <LibHTML/DOM/HTMLElement.h> + +class HTMLTitleElement : public HTMLElement { +public: + HTMLTitleElement(Document&, const String& tag_name); + virtual ~HTMLTitleElement() override; +}; diff --git a/Libraries/LibHTML/DOM/Node.h b/Libraries/LibHTML/DOM/Node.h index 25659e5a293..a49220d84c7 100644 --- a/Libraries/LibHTML/DOM/Node.h +++ b/Libraries/LibHTML/DOM/Node.h @@ -46,6 +46,15 @@ public: virtual bool is_html_element() const { return false; } + const Node* first_child_with_tag_name(const StringView& tag_name) const + { + for (auto* child = first_child(); child; child = child->next_sibling()) { + if (child->tag_name() == tag_name) + return child; + } + return nullptr; + } + protected: Node(Document&, NodeType); diff --git a/Libraries/LibHTML/HtmlView.h b/Libraries/LibHTML/HtmlView.h index 8f62c3d8a6e..ffa99578c28 100644 --- a/Libraries/LibHTML/HtmlView.h +++ b/Libraries/LibHTML/HtmlView.h @@ -13,6 +13,7 @@ public: void set_document(Document*); Function<void(const String&)> on_link_click; + Function<void(const String&)> on_title_change; protected: HtmlView(GWidget* parent = nullptr); diff --git a/Libraries/LibHTML/Makefile.shared b/Libraries/LibHTML/Makefile.shared index efa0f8ccd3d..76329a0299b 100644 --- a/Libraries/LibHTML/Makefile.shared +++ b/Libraries/LibHTML/Makefile.shared @@ -5,6 +5,9 @@ LIBHTML_OBJS = \ DOM/HTMLElement.o \ DOM/HTMLAnchorElement.o \ DOM/HTMLHeadingElement.o \ + DOM/HTMLHeadElement.o \ + DOM/HTMLHtmlElement.o \ + DOM/HTMLTitleElement.o \ DOM/Document.o \ DOM/Text.o \ CSS/Selector.o \ diff --git a/Libraries/LibHTML/Parser/HTMLParser.cpp b/Libraries/LibHTML/Parser/HTMLParser.cpp index d01df0c1dea..940726c5653 100644 --- a/Libraries/LibHTML/Parser/HTMLParser.cpp +++ b/Libraries/LibHTML/Parser/HTMLParser.cpp @@ -2,7 +2,10 @@ #include <AK/StringBuilder.h> #include <LibHTML/DOM/Element.h> #include <LibHTML/DOM/HTMLAnchorElement.h> +#include <LibHTML/DOM/HTMLHeadElement.h> #include <LibHTML/DOM/HTMLHeadingElement.h> +#include <LibHTML/DOM/HTMLHtmlElement.h> +#include <LibHTML/DOM/HTMLTitleElement.h> #include <LibHTML/DOM/Text.h> #include <LibHTML/Parser/HTMLParser.h> #include <ctype.h> @@ -13,6 +16,12 @@ static NonnullRefPtr<Element> create_element(Document& document, const String& t auto lowercase_tag_name = tag_name.to_lowercase(); if (lowercase_tag_name == "a") return adopt(*new HTMLAnchorElement(document, tag_name)); + if (lowercase_tag_name == "html") + return adopt(*new HTMLHtmlElement(document, tag_name)); + if (lowercase_tag_name == "head") + return adopt(*new HTMLHeadElement(document, tag_name)); + if (lowercase_tag_name == "title") + return adopt(*new HTMLTitleElement(document, tag_name)); if (lowercase_tag_name == "h1" || lowercase_tag_name == "h2" || lowercase_tag_name == "h3"