From ce341c0230aa216bcbb2a81e75873d38d5d7a717 Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Mon, 1 Apr 2024 22:18:00 +0200 Subject: [PATCH] LibWeb: Add support for document.lastModified --- Userland/Libraries/LibWeb/DOM/Document.cpp | 34 ++++++++++++++++++++++ Userland/Libraries/LibWeb/DOM/Document.h | 7 ++++- Userland/Libraries/LibWeb/DOM/Document.idl | 1 + 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 257987d39d2..5a14f3ca9c6 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -301,6 +301,10 @@ WebIDL::ExceptionOr> Document::create_and_initialize( document->m_window = window; + // NOTE: Non-standard: Pull out the Last-Modified header for use in the lastModified property. + if (auto maybe_last_modified = MUST(navigation_params.response->header_list()->get("Last-Modified"sv.bytes())); maybe_last_modified.has_value()) + document->m_last_modified = Core::DateTime::parse("%a, %d %b %Y %H:%M:%S %Z"sv, maybe_last_modified.value()); + // 11. Set window's associated Document to document. window->set_associated_document(*document); @@ -2158,6 +2162,36 @@ void Document::update_readiness(HTML::DocumentReadyState readiness_value) } } +// https://html.spec.whatwg.org/multipage/dom.html#dom-document-lastmodified +String Document::last_modified() const +{ + // The lastModified attribute, on getting, must return the date and time of the Document's source file's + // last modification, in the user's local time zone, in the following format: + + // 1. The month component of the date. + // 2. A U+002F SOLIDUS character (/). + // 3. The day component of the date. + // 4. A U+002F SOLIDUS character (/). + // 5. The year component of the date. + // 6. A U+0020 SPACE character. + // 7. The hours component of the time. + // 8. A U+003A COLON character (:). + // 9. The minutes component of the time. + // 10. A U+003A COLON character (:). + // 11. The seconds component of the time. + + // The Document's source file's last modification date and time must be derived from relevant features + // of the networking protocols used, e.g. from the value of the HTTP `Last-Modified` header of the document, + // or from metadata in the file system for local files. If the last modification date and time are not known, + // the attribute must return the current date and time in the above format. + constexpr auto format_string = "%m/%d/%Y %H:%M:%S"sv; + + if (m_last_modified.has_value()) + return MUST(m_last_modified.value().to_string(format_string)); + + return MUST(Core::DateTime::now().to_string(format_string)); +} + Page& Document::page() { return m_page; diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index b16b315aec2..2c1436fdd16 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2018-2023, Andreas Kling * Copyright (c) 2021-2023, Linus Groh - * Copyright (c) 2023, Shannon Booth + * Copyright (c) 2023-2024, Shannon Booth * * SPDX-License-Identifier: BSD-2-Clause */ @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -323,6 +324,8 @@ public: HTML::DocumentReadyState readiness() const { return m_readiness; } void update_readiness(HTML::DocumentReadyState); + String last_modified() const; + [[nodiscard]] JS::GCPtr window() const { return m_window; } void set_window(HTML::Window&); @@ -872,6 +875,8 @@ private: Vector> m_shadow_roots; + Optional m_last_modified; + u64 m_dom_tree_version { 0 }; // https://drafts.csswg.org/css-position-4/#document-top-layer diff --git a/Userland/Libraries/LibWeb/DOM/Document.idl b/Userland/Libraries/LibWeb/DOM/Document.idl index d6247efec8d..584609ea87a 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.idl +++ b/Userland/Libraries/LibWeb/DOM/Document.idl @@ -103,6 +103,7 @@ interface Document : Node { readonly attribute HTMLHeadElement? head; readonly attribute HTMLScriptElement? currentScript; + readonly attribute DOMString lastModified; readonly attribute DOMString readyState; [CEReactions] attribute DOMString title;