From a72b0c29bb34ea87d52a0b85a6ba9301d45db565 Mon Sep 17 00:00:00 2001 From: Niccolo Antonelli Dziri Date: Wed, 17 Sep 2025 09:14:38 +0200 Subject: [PATCH] LibWeb: Add a simplified Notification constructor This allows the Notification object to be created in javascript without any additional functionalities. It passes two wpt tests which require a call to the notification constructor with no arguments. https://wpt.live/notifications/constructor-basic.https.html https://wpt.live/notifications/constructor-invalid.https.html --- Libraries/LibWeb/CMakeLists.txt | 1 + Libraries/LibWeb/Forward.h | 9 +++ .../LibWeb/NotificationsAPI/Notification.cpp | 39 ++++++++++ .../LibWeb/NotificationsAPI/Notification.h | 60 +++++++++++++++ .../LibWeb/NotificationsAPI/Notification.idl | 76 +++++++++++++++++++ Libraries/LibWeb/idl_files.cmake | 1 + .../BindingsGenerator/IDLGenerators.cpp | 1 + .../Text/expected/all-window-properties.txt | 1 + .../notifications/constructor-basic.https.txt | 9 +++ .../constructor-invalid.https.txt | 6 ++ .../constructor-basic.https.html | 46 +++++++++++ .../constructor-invalid.https.html | 14 ++++ 12 files changed, 263 insertions(+) create mode 100644 Libraries/LibWeb/NotificationsAPI/Notification.cpp create mode 100644 Libraries/LibWeb/NotificationsAPI/Notification.h create mode 100644 Libraries/LibWeb/NotificationsAPI/Notification.idl create mode 100644 Tests/LibWeb/Text/expected/wpt-import/notifications/constructor-basic.https.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/notifications/constructor-invalid.https.txt create mode 100644 Tests/LibWeb/Text/input/wpt-import/notifications/constructor-basic.https.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/notifications/constructor-invalid.https.html diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index bb6d47e094..123a69317c 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -759,6 +759,7 @@ set(SOURCES NavigationTiming/EntryNames.cpp NavigationTiming/PerformanceNavigation.cpp NavigationTiming/PerformanceTiming.cpp + NotificationsAPI/Notification.cpp Page/DragAndDropEventHandler.cpp Page/EventHandler.cpp Page/InputEvent.cpp diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index bad0d7f0fc..3d2506ab68 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -910,6 +910,15 @@ class PerformanceTiming; } +namespace Web::NotificationsAPI { + +struct NotificationAction; +struct NotificationOptions; + +class Notification; + +} + namespace Web::Painting { class AudioPaintable; diff --git a/Libraries/LibWeb/NotificationsAPI/Notification.cpp b/Libraries/LibWeb/NotificationsAPI/Notification.cpp new file mode 100644 index 0000000000..d18a586dff --- /dev/null +++ b/Libraries/LibWeb/NotificationsAPI/Notification.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, Niccolo Antonelli-Dziri + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Web::NotificationsAPI { + +GC_DEFINE_ALLOCATOR(Notification); + +Notification::Notification(JS::Realm& realm) + : DOM::EventTarget(realm) +{ +} + +// https://notifications.spec.whatwg.org/#constructors +WebIDL::ExceptionOr> Notification::construct_impl( + JS::Realm& realm, + String, // FIXME: title is unused + Optional) // FIXME: options is unused +{ + + // FIXME: all of the steps specified in the spec + + return realm.create(realm); +} + +void Notification::initialize(JS::Realm& realm) +{ + WEB_SET_PROTOTYPE_FOR_INTERFACE(Notification); + Base::initialize(realm); +} + +} diff --git a/Libraries/LibWeb/NotificationsAPI/Notification.h b/Libraries/LibWeb/NotificationsAPI/Notification.h new file mode 100644 index 0000000000..2f02e26430 --- /dev/null +++ b/Libraries/LibWeb/NotificationsAPI/Notification.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025, Niccolo Antonelli-Dziri + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Web::NotificationsAPI { + +struct NotificationAction { + String action; + String title; + Optional navigate; + Optional icon; +}; + +struct NotificationOptions { + Bindings::NotificationDirection dir = Bindings::NotificationDirection::Auto; + String lang = ""_string; + String body = ""_string; + Optional navigate; + String tag = ""_string; + Optional image; + Optional icon; + Optional badge; + // VibratePattern vibrate; // FIXME: properly implement vibrate pattern + Optional timestamp; + bool renotify = false; + Optional silent; + bool require_interaction = false; + JS::Value data; + Vector actions; +}; + +// https://notifications.spec.whatwg.org/#notifications +class WEB_API Notification final : public DOM::EventTarget { + WEB_PLATFORM_OBJECT(Notification, DOM::EventTarget); + GC_DECLARE_ALLOCATOR(Notification); + +public: + [[nodiscard]] static WebIDL::ExceptionOr> construct_impl( + JS::Realm& realm, + String title, + Optional options); + +private: + Notification(JS::Realm&); + + virtual void initialize(JS::Realm&) override; +}; + +} diff --git a/Libraries/LibWeb/NotificationsAPI/Notification.idl b/Libraries/LibWeb/NotificationsAPI/Notification.idl new file mode 100644 index 0000000000..566cb3b439 --- /dev/null +++ b/Libraries/LibWeb/NotificationsAPI/Notification.idl @@ -0,0 +1,76 @@ +#import +#import + +// https://notifications.spec.whatwg.org/#notification +[Exposed=(Window,Worker)] +interface Notification : EventTarget { + constructor(DOMString title, optional NotificationOptions options = {}); + + // FIXME: static readonly attribute NotificationPermission permission; + // FIXME: [Exposed=Window] static Promise requestPermission(optional NotificationPermissionCallback deprecatedCallback); + + // FIXME: static readonly attribute unsigned long maxActions; + + [FIXME] attribute EventHandler onclick; + [FIXME] attribute EventHandler onshow; + [FIXME] attribute EventHandler onerror; + [FIXME] attribute EventHandler onclose; + + [FIXME] readonly attribute DOMString title; + [FIXME] readonly attribute NotificationDirection dir; + [FIXME] readonly attribute DOMString lang; + [FIXME] readonly attribute DOMString body; + [FIXME] readonly attribute USVString navigate; + [FIXME] readonly attribute DOMString tag; + [FIXME] readonly attribute USVString image; + [FIXME] readonly attribute USVString icon; + [FIXME] readonly attribute USVString badge; + // FIXME: [SameObject] readonly attribute FrozenArray vibrate; + [FIXME] readonly attribute EpochTimeStamp timestamp; + [FIXME] readonly attribute boolean renotify; + [FIXME] readonly attribute boolean? silent; + [FIXME] readonly attribute boolean requireInteraction; + // FIXME: [SameObject] readonly attribute any data; + // FIXME: [SameObject] readonly attribute FrozenArray actions; + + [FIXME] undefined close(); +}; + +dictionary NotificationOptions { + NotificationDirection dir = "auto"; + DOMString lang = ""; + DOMString body = ""; + USVString navigate; + DOMString tag = ""; + USVString image; + USVString icon; + USVString badge; + // FIXME: VibratePattern vibrate; + EpochTimeStamp timestamp; + boolean renotify = false; + boolean? silent = null; + boolean requireInteraction = false; + any data = null; + sequence actions = []; +}; + +enum NotificationPermission { + "default", + "denied", + "granted" +}; + +enum NotificationDirection { + "auto", + "ltr", + "rtl" +}; + +dictionary NotificationAction { + required DOMString action; + required DOMString title; + USVString navigate; + USVString icon; +}; + +[FIXME] callback NotificationPermissionCallback = undefined (NotificationPermission permission); diff --git a/Libraries/LibWeb/idl_files.cmake b/Libraries/LibWeb/idl_files.cmake index 68da1e5f80..4bc0e24116 100644 --- a/Libraries/LibWeb/idl_files.cmake +++ b/Libraries/LibWeb/idl_files.cmake @@ -324,6 +324,7 @@ libweb_js_bindings(MediaSourceExtensions/SourceBuffer) libweb_js_bindings(MediaSourceExtensions/SourceBufferList) libweb_js_bindings(NavigationTiming/PerformanceNavigation) libweb_js_bindings(NavigationTiming/PerformanceTiming) +libweb_js_bindings(NotificationsAPI/Notification) libweb_js_bindings(PerformanceTimeline/PerformanceEntry) libweb_js_bindings(PerformanceTimeline/PerformanceObserver) libweb_js_bindings(PerformanceTimeline/PerformanceObserverEntryList) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index 2146c19b96..7047e0b723 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -4940,6 +4940,7 @@ using namespace Web::IntersectionObserver; using namespace Web::MediaCapabilitiesAPI; using namespace Web::MediaSourceExtensions; using namespace Web::NavigationTiming; +using namespace Web::NotificationsAPI; using namespace Web::PerformanceTimeline; using namespace Web::RequestIdleCallback; using namespace Web::ResizeObserver; diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt index 115d271615..a6d0439a5e 100644 --- a/Tests/LibWeb/Text/expected/all-window-properties.txt +++ b/Tests/LibWeb/Text/expected/all-window-properties.txt @@ -304,6 +304,7 @@ Node NodeFilter NodeIterator NodeList +Notification Number Object OfflineAudioContext diff --git a/Tests/LibWeb/Text/expected/wpt-import/notifications/constructor-basic.https.txt b/Tests/LibWeb/Text/expected/wpt-import/notifications/constructor-basic.https.txt new file mode 100644 index 0000000000..24756b9fc1 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/notifications/constructor-basic.https.txt @@ -0,0 +1,9 @@ +Harness status: OK + +Found 3 tests + +1 Pass +2 Fail +Pass Called the notification constructor with one argument. +Fail Constructing a notification without a NotificationOptions defaults to null. +Fail constructing a notification with a NotificationOptions dictionary correctly sets and reflects the silent attribute. \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/notifications/constructor-invalid.https.txt b/Tests/LibWeb/Text/expected/wpt-import/notifications/constructor-invalid.https.txt new file mode 100644 index 0000000000..3700d0cdda --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/notifications/constructor-invalid.https.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass Called the notification constructor with no arguments. \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/notifications/constructor-basic.https.html b/Tests/LibWeb/Text/input/wpt-import/notifications/constructor-basic.https.html new file mode 100644 index 0000000000..d23069ac2d --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/notifications/constructor-basic.https.html @@ -0,0 +1,46 @@ + + +Notification constructor (basic) + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/notifications/constructor-invalid.https.html b/Tests/LibWeb/Text/input/wpt-import/notifications/constructor-invalid.https.html new file mode 100644 index 0000000000..8deccad1d7 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/notifications/constructor-invalid.https.html @@ -0,0 +1,14 @@ + + +Notification constructor (invalid) + + + + +