mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
feat: add Notification
Web API binding (#34842)
* feat: add Notification Web API binding Signed-off-by: Jason Tsai <git@pews.dev> * chore: update spec link Signed-off-by: Jason Tsai <git@pews.dev> * chore: fix clippy Signed-off-by: Jason Tsai <git@pews.dev> * fix: index overflow Signed-off-by: Jason Tsai <git@pews.dev> * test(tidy): add notification WebIDL standard URL Signed-off-by: Jason Tsai <git@pews.dev> * fix: allow crown::unrooted_must_root Signed-off-by: Jason Tsai <git@pews.dev> * implement GetPermission Signed-off-by: Jason Tsai <git@pews.dev> * fix silent type Signed-off-by: Jason Tsai <git@pews.dev> * add all properties Signed-off-by: Jason Tsai <git@pews.dev> * test: add Notification to global Signed-off-by: Jason Tsai <git@pews.dev> * chore: update wpt manifest and fix clippy Signed-off-by: Jason Tsai <git@pews.dev> * test: temp skip notifications Signed-off-by: Jason Tsai <git@pews.dev> * add vibration and apply suggestions Signed-off-by: Jason Tsai <git@pews.dev> * partially implement RequestPermission Signed-off-by: Jason Tsai <git@pews.dev> * call Permission request permission algorithm Signed-off-by: Jason Tsai <git@pews.dev> * chore: pub crate Notification Signed-off-by: Jason Tsai <git@pews.dev> * chore: fix clippy Signed-off-by: Jason Tsai <git@pews.dev> * chore: crown attribute Signed-off-by: Jason Tsai <git@pews.dev> * fix part of suggestions Signed-off-by: Jason Tsai <git@pews.dev> * fix: store private `Action` structure Signed-off-by: Jason Tsai <git@pews.dev> * chore: fix typo Signed-off-by: Jason Tsai <git@pews.dev> * fix: serialize images URL Signed-off-by: Jason Tsai <git@pews.dev> * fix: use globalscope as environment settings object Signed-off-by: Jason Tsai <git@pews.dev> * chore: add pref `dom_notification_enabled` and default to disabled Signed-off-by: Jason Tsai <git@pews.dev> * fix: use `descriptor_permission_state` Signed-off-by: Jason Tsai <git@pews.dev> * apply suggestions Signed-off-by: Jason Tsai <git@pews.dev> Co-authored-by: Josh Matthews <josh@joshmatthews.net> * test: remove passed meta Signed-off-by: Jason Tsai <git@pews.dev> * test: enable notification prefs in mozilla tests Signed-off-by: Jason Tsai <git@pews.dev> --------- Signed-off-by: Jason Tsai <git@pews.dev> Co-authored-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
14d591c462
commit
22c3a63737
21 changed files with 717 additions and 370 deletions
|
@ -89,6 +89,7 @@ pub struct Preferences {
|
||||||
pub dom_microdata_testing_enabled: bool,
|
pub dom_microdata_testing_enabled: bool,
|
||||||
pub dom_mouse_event_which_enabled: bool,
|
pub dom_mouse_event_which_enabled: bool,
|
||||||
pub dom_mutation_observer_enabled: bool,
|
pub dom_mutation_observer_enabled: bool,
|
||||||
|
pub dom_notification_enabled: bool,
|
||||||
pub dom_offscreen_canvas_enabled: bool,
|
pub dom_offscreen_canvas_enabled: bool,
|
||||||
pub dom_permissions_enabled: bool,
|
pub dom_permissions_enabled: bool,
|
||||||
pub dom_permissions_testing_allowed_in_nonsecure_contexts: bool,
|
pub dom_permissions_testing_allowed_in_nonsecure_contexts: bool,
|
||||||
|
@ -252,6 +253,7 @@ impl Preferences {
|
||||||
dom_microdata_testing_enabled: false,
|
dom_microdata_testing_enabled: false,
|
||||||
dom_mouse_event_which_enabled: false,
|
dom_mouse_event_which_enabled: false,
|
||||||
dom_mutation_observer_enabled: true,
|
dom_mutation_observer_enabled: true,
|
||||||
|
dom_notification_enabled: false,
|
||||||
dom_offscreen_canvas_enabled: false,
|
dom_offscreen_canvas_enabled: false,
|
||||||
dom_permissions_enabled: false,
|
dom_permissions_enabled: false,
|
||||||
dom_permissions_testing_allowed_in_nonsecure_contexts: false,
|
dom_permissions_testing_allowed_in_nonsecure_contexts: false,
|
||||||
|
|
|
@ -80,6 +80,7 @@ use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::{
|
||||||
ImageBitmapOptions, ImageBitmapSource,
|
ImageBitmapOptions, ImageBitmapSource,
|
||||||
};
|
};
|
||||||
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods;
|
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::NotificationBinding::NotificationPermissionCallback;
|
||||||
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::Performance_Binding::PerformanceMethods;
|
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::Performance_Binding::PerformanceMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::{
|
use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::{
|
||||||
PermissionName, PermissionState,
|
PermissionName, PermissionState,
|
||||||
|
@ -370,6 +371,10 @@ pub(crate) struct GlobalScope {
|
||||||
/// <https://streams.spec.whatwg.org/#count-queuing-strategy-size-function>
|
/// <https://streams.spec.whatwg.org/#count-queuing-strategy-size-function>
|
||||||
#[ignore_malloc_size_of = "Rc<T> is hard"]
|
#[ignore_malloc_size_of = "Rc<T> is hard"]
|
||||||
count_queuing_strategy_size_function: OnceCell<Rc<Function>>,
|
count_queuing_strategy_size_function: OnceCell<Rc<Function>>,
|
||||||
|
|
||||||
|
#[ignore_malloc_size_of = "Rc<T> is hard"]
|
||||||
|
notification_permission_request_callback_map:
|
||||||
|
DomRefCell<HashMap<String, Rc<NotificationPermissionCallback>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper for glue-code between the ipc router and the event-loop.
|
/// A wrapper for glue-code between the ipc router and the event-loop.
|
||||||
|
@ -763,6 +768,7 @@ impl GlobalScope {
|
||||||
unminified_js_dir: unminify_js.then(|| unminified_path("unminified-js")),
|
unminified_js_dir: unminify_js.then(|| unminified_path("unminified-js")),
|
||||||
byte_length_queuing_strategy_size_function: OnceCell::new(),
|
byte_length_queuing_strategy_size_function: OnceCell::new(),
|
||||||
count_queuing_strategy_size_function: OnceCell::new(),
|
count_queuing_strategy_size_function: OnceCell::new(),
|
||||||
|
notification_permission_request_callback_map: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3268,6 +3274,25 @@ impl GlobalScope {
|
||||||
pub(crate) fn get_count_queuing_strategy_size(&self) -> Option<Rc<Function>> {
|
pub(crate) fn get_count_queuing_strategy_size(&self) -> Option<Rc<Function>> {
|
||||||
self.count_queuing_strategy_size_function.get().cloned()
|
self.count_queuing_strategy_size_function.get().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_notification_permission_request_callback(
|
||||||
|
&self,
|
||||||
|
callback_id: String,
|
||||||
|
callback: Rc<NotificationPermissionCallback>,
|
||||||
|
) {
|
||||||
|
self.notification_permission_request_callback_map
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(callback_id, callback.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn remove_notification_permission_request_callback(
|
||||||
|
&self,
|
||||||
|
callback_id: String,
|
||||||
|
) -> Option<Rc<NotificationPermissionCallback>> {
|
||||||
|
self.notification_permission_request_callback_map
|
||||||
|
.borrow_mut()
|
||||||
|
.remove(&callback_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the Rust global scope from a JS global object.
|
/// Returns the Rust global scope from a JS global object.
|
||||||
|
|
|
@ -454,6 +454,7 @@ pub(crate) mod node;
|
||||||
pub(crate) mod nodeiterator;
|
pub(crate) mod nodeiterator;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) mod nodelist;
|
pub(crate) mod nodelist;
|
||||||
|
pub(crate) mod notification;
|
||||||
pub(crate) mod offlineaudiocompletionevent;
|
pub(crate) mod offlineaudiocompletionevent;
|
||||||
pub(crate) mod offlineaudiocontext;
|
pub(crate) mod offlineaudiocontext;
|
||||||
pub(crate) mod offscreencanvas;
|
pub(crate) mod offscreencanvas;
|
||||||
|
|
562
components/script/dom/notification.rs
Normal file
562
components/script/dom/notification.rs
Normal file
|
@ -0,0 +1,562 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
use dom_struct::dom_struct;
|
||||||
|
use js::jsapi::Heap;
|
||||||
|
use js::jsval::JSVal;
|
||||||
|
use js::rust::{HandleObject, MutableHandleValue};
|
||||||
|
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use super::bindings::refcounted::TrustedPromise;
|
||||||
|
use super::bindings::reflector::DomGlobal;
|
||||||
|
use super::permissionstatus::PermissionStatus;
|
||||||
|
use crate::dom::bindings::callback::ExceptionHandling;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::NotificationBinding::{
|
||||||
|
NotificationAction, NotificationDirection, NotificationMethods, NotificationOptions,
|
||||||
|
NotificationPermission, NotificationPermissionCallback,
|
||||||
|
};
|
||||||
|
use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionStatus_Binding::PermissionStatusMethods;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::{
|
||||||
|
PermissionDescriptor, PermissionName, PermissionState,
|
||||||
|
};
|
||||||
|
use crate::dom::bindings::codegen::UnionTypes::UnsignedLongOrUnsignedLongSequence;
|
||||||
|
use crate::dom::bindings::error::Error;
|
||||||
|
use crate::dom::bindings::import::module::{Fallible, Rc};
|
||||||
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
|
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||||
|
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||||
|
use crate::dom::bindings::str::{DOMString, USVString};
|
||||||
|
use crate::dom::bindings::trace::RootedTraceableBox;
|
||||||
|
use crate::dom::bindings::utils::to_frozen_array;
|
||||||
|
use crate::dom::eventtarget::EventTarget;
|
||||||
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::permissions::{descriptor_permission_state, PermissionAlgorithm, Permissions};
|
||||||
|
use crate::dom::promise::Promise;
|
||||||
|
use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
|
||||||
|
use crate::dom::serviceworkerregistration::ServiceWorkerRegistration;
|
||||||
|
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
|
||||||
|
|
||||||
|
// TODO: Service Worker API (persistent notification)
|
||||||
|
// https://notifications.spec.whatwg.org/#service-worker-api
|
||||||
|
|
||||||
|
/// <https://notifications.spec.whatwg.org/#notifications>
|
||||||
|
#[dom_struct]
|
||||||
|
pub(crate) struct Notification {
|
||||||
|
eventtarget: EventTarget,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#service-worker-registration>
|
||||||
|
serviceworker_registration: Option<Dom<ServiceWorkerRegistration>>,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#concept-title>
|
||||||
|
title: DOMString,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#body>
|
||||||
|
body: DOMString,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#data>
|
||||||
|
#[ignore_malloc_size_of = "mozjs"]
|
||||||
|
data: Heap<JSVal>,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#concept-direction>
|
||||||
|
dir: NotificationDirection,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#image-url>
|
||||||
|
image: Option<USVString>,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#icon-url>
|
||||||
|
icon: Option<USVString>,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#badge-url>
|
||||||
|
badge: Option<USVString>,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#concept-language>
|
||||||
|
lang: DOMString,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#silent-preference-flag>
|
||||||
|
silent: Option<bool>,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#tag>
|
||||||
|
tag: DOMString,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#concept-origin>
|
||||||
|
#[no_trace] // ImmutableOrigin is not traceable
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#vibration-pattern>
|
||||||
|
vibration_pattern: Vec<u32>,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#timestamp>
|
||||||
|
timestamp: u64,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#renotify-preference-flag>
|
||||||
|
renotify: bool,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#require-interaction-preference-flag>
|
||||||
|
require_interaction: bool,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#actions>
|
||||||
|
actions: Vec<Action>,
|
||||||
|
// TODO: image resource, icon resource, and badge resource
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Notification {
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub(crate) fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
|
title: DOMString,
|
||||||
|
options: RootedTraceableBox<NotificationOptions>,
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
base_url: ServoUrl,
|
||||||
|
fallback_timestamp: u64,
|
||||||
|
proto: Option<HandleObject>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> DomRoot<Self> {
|
||||||
|
let notification = reflect_dom_object_with_proto(
|
||||||
|
Box::new(Notification::new_inherited(
|
||||||
|
global,
|
||||||
|
title,
|
||||||
|
&options,
|
||||||
|
origin,
|
||||||
|
base_url,
|
||||||
|
fallback_timestamp,
|
||||||
|
)),
|
||||||
|
global,
|
||||||
|
proto,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
|
||||||
|
notification.data.set(options.data.get());
|
||||||
|
|
||||||
|
notification
|
||||||
|
}
|
||||||
|
|
||||||
|
/// partial implementation of <https://notifications.spec.whatwg.org/#create-a-notification>
|
||||||
|
fn new_inherited(
|
||||||
|
global: &GlobalScope,
|
||||||
|
title: DOMString,
|
||||||
|
options: &RootedTraceableBox<NotificationOptions>,
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
base_url: ServoUrl,
|
||||||
|
fallback_timestamp: u64,
|
||||||
|
) -> Self {
|
||||||
|
// TODO: missing call to https://html.spec.whatwg.org/multipage/#structuredserializeforstorage
|
||||||
|
// may be find in `dom/bindings/structuredclone.rs`
|
||||||
|
let data = Heap::default();
|
||||||
|
|
||||||
|
let title = title.clone();
|
||||||
|
let dir = options.dir;
|
||||||
|
let lang = options.lang.clone();
|
||||||
|
let body = options.body.clone();
|
||||||
|
let tag = options.tag.clone();
|
||||||
|
|
||||||
|
// If options["image"] exists, then parse it using baseURL, and if that does not return failure,
|
||||||
|
// set notification’s image URL to the return value. (Otherwise notification’s image URL is not set.)
|
||||||
|
let image = options.image.as_ref().and_then(|image_url| {
|
||||||
|
ServoUrl::parse_with_base(Some(&base_url), image_url.as_ref())
|
||||||
|
.map(|url| USVString::from(url.to_string()))
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
|
// If options["icon"] exists, then parse it using baseURL, and if that does not return failure,
|
||||||
|
// set notification’s icon URL to the return value. (Otherwise notification’s icon URL is not set.)
|
||||||
|
let icon = options.icon.as_ref().and_then(|icon_url| {
|
||||||
|
ServoUrl::parse_with_base(Some(&base_url), icon_url.as_ref())
|
||||||
|
.map(|url| USVString::from(url.to_string()))
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
|
// If options["badge"] exists, then parse it using baseURL, and if that does not return failure,
|
||||||
|
// set notification’s badge URL to the return value. (Otherwise notification’s badge URL is not set.)
|
||||||
|
let badge = options.badge.as_ref().and_then(|badge_url| {
|
||||||
|
ServoUrl::parse_with_base(Some(&base_url), badge_url.as_ref())
|
||||||
|
.map(|url| USVString::from(url.to_string()))
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
|
// If options["vibrate"] exists, then validate and normalize it and
|
||||||
|
// set notification’s vibration pattern to the return value.
|
||||||
|
let vibration_pattern = match &options.vibrate {
|
||||||
|
Some(pattern) => validate_and_normalize_vibration_pattern(pattern),
|
||||||
|
None => Vec::new(),
|
||||||
|
};
|
||||||
|
// If options["timestamp"] exists, then set notification’s timestamp to the value.
|
||||||
|
// Otherwise, set notification’s timestamp to fallbackTimestamp.
|
||||||
|
let timestamp = options.timestamp.unwrap_or(fallback_timestamp);
|
||||||
|
let renotify = options.renotify;
|
||||||
|
let silent = options.silent;
|
||||||
|
let require_interaction = options.requireInteraction;
|
||||||
|
|
||||||
|
// For each entry in options["actions"]
|
||||||
|
// up to the maximum number of actions supported (skip any excess entries):
|
||||||
|
let mut actions: Vec<Action> = Vec::new();
|
||||||
|
let max_actions = Notification::MaxActions(global);
|
||||||
|
for action in options.actions.iter().take(max_actions as usize) {
|
||||||
|
actions.push(Action {
|
||||||
|
name: action.action.clone(),
|
||||||
|
title: action.title.clone(),
|
||||||
|
// If entry["icon"] exists, then parse it using baseURL, and if that does not return failure
|
||||||
|
// set action’s icon URL to the return value. (Otherwise action’s icon URL remains null.)
|
||||||
|
icon_url: action.icon.as_ref().and_then(|icon_url| {
|
||||||
|
ServoUrl::parse_with_base(Some(&base_url), icon_url.as_ref())
|
||||||
|
.map(|url| USVString::from(url.to_string()))
|
||||||
|
.ok()
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
eventtarget: EventTarget::new_inherited(),
|
||||||
|
// A non-persistent notification is a notification whose service worker registration is null.
|
||||||
|
serviceworker_registration: None,
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
data,
|
||||||
|
dir,
|
||||||
|
image,
|
||||||
|
icon,
|
||||||
|
badge,
|
||||||
|
lang,
|
||||||
|
silent,
|
||||||
|
origin,
|
||||||
|
vibration_pattern,
|
||||||
|
timestamp,
|
||||||
|
renotify,
|
||||||
|
tag,
|
||||||
|
require_interaction,
|
||||||
|
actions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NotificationMethods<crate::DomTypeHolder> for Notification {
|
||||||
|
/// <https://notifications.spec.whatwg.org/#constructors>
|
||||||
|
fn Constructor(
|
||||||
|
global: &GlobalScope,
|
||||||
|
proto: Option<HandleObject>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
title: DOMString,
|
||||||
|
options: RootedTraceableBox<NotificationOptions>,
|
||||||
|
) -> Fallible<DomRoot<Notification>> {
|
||||||
|
// step 1: Check global is a ServiceWorkerGlobalScope
|
||||||
|
if global.is::<ServiceWorkerGlobalScope>() {
|
||||||
|
return Err(Error::Type(
|
||||||
|
"Notification constructor cannot be used in service worker.".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 2: Check options.actions must be empty
|
||||||
|
if !options.actions.is_empty() {
|
||||||
|
return Err(Error::Type(
|
||||||
|
"Actions are only supported for persistent notifications.".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 3: Create a notification with a settings object
|
||||||
|
let notification =
|
||||||
|
create_notification_with_settings_object(global, title, options, proto, can_gc)?;
|
||||||
|
|
||||||
|
// TODO: Run step 5.1, 5.2 in parallel
|
||||||
|
// step 5.1: If the result of getting the notifications permission state is not "granted",
|
||||||
|
// then queue a task to fire an event named error on this, and abort these steps.
|
||||||
|
let permission_state = get_notifications_permission_state(global);
|
||||||
|
if permission_state != NotificationPermission::Granted {
|
||||||
|
global
|
||||||
|
.task_manager()
|
||||||
|
.dom_manipulation_task_source()
|
||||||
|
.queue_simple_event(notification.upcast(), atom!("error"));
|
||||||
|
// TODO: abort steps
|
||||||
|
}
|
||||||
|
// TODO: step 5.2: Run the notification show steps for notification
|
||||||
|
// https://notifications.spec.whatwg.org/#notification-show-steps
|
||||||
|
|
||||||
|
Ok(notification)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-permission>
|
||||||
|
fn GetPermission(global: &GlobalScope) -> Fallible<NotificationPermission> {
|
||||||
|
Ok(get_notifications_permission_state(global))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-requestpermission>
|
||||||
|
fn RequestPermission(
|
||||||
|
global: &GlobalScope,
|
||||||
|
permission_callback: Option<Rc<NotificationPermissionCallback>>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> Rc<Promise> {
|
||||||
|
// Step 2: Let promise be a new promise in this’s relevant Realm.
|
||||||
|
let promise = Promise::new(global, can_gc);
|
||||||
|
|
||||||
|
// TODO: Step 3: Run these steps in parallel:
|
||||||
|
// Step 3.1: Let permissionState be the result of requesting permission to use "notifications".
|
||||||
|
let notification_permission = request_notification_permission(global);
|
||||||
|
|
||||||
|
// Step 3.2: Queue a global task on the DOM manipulation task source given global to run these steps:
|
||||||
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
||||||
|
let uuid = Uuid::new_v4().simple().to_string();
|
||||||
|
let uuid_ = uuid.clone();
|
||||||
|
|
||||||
|
if let Some(callback) = permission_callback {
|
||||||
|
global.add_notification_permission_request_callback(uuid.clone(), callback.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
global.task_manager().dom_manipulation_task_source().queue(
|
||||||
|
task!(request_permission: move || {
|
||||||
|
let promise = trusted_promise.root();
|
||||||
|
let global = promise.global();
|
||||||
|
|
||||||
|
// Step 3.2.1: If deprecatedCallback is given,
|
||||||
|
// then invoke deprecatedCallback with « permissionState » and "report".
|
||||||
|
if let Some(callback) = global.remove_notification_permission_request_callback(uuid_) {
|
||||||
|
let _ = callback.Call__(notification_permission, ExceptionHandling::Report);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3.2.2: Resolve promise with permissionState.
|
||||||
|
promise.resolve_native(¬ification_permission);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
promise
|
||||||
|
}
|
||||||
|
|
||||||
|
// <https://notifications.spec.whatwg.org/#dom-notification-onclick>
|
||||||
|
event_handler!(click, GetOnclick, SetOnclick);
|
||||||
|
// <https://notifications.spec.whatwg.org/#dom-notification-onshow>
|
||||||
|
event_handler!(show, GetOnshow, SetOnshow);
|
||||||
|
// <https://notifications.spec.whatwg.org/#dom-notification-onerror>
|
||||||
|
event_handler!(error, GetOnerror, SetOnerror);
|
||||||
|
// <https://notifications.spec.whatwg.org/#dom-notification-onclose>
|
||||||
|
event_handler!(close, GetOnclose, SetOnclose);
|
||||||
|
|
||||||
|
/// <https://notifications.spec.whatwg.org/#maximum-number-of-actions>
|
||||||
|
fn MaxActions(_global: &GlobalScope) -> u32 {
|
||||||
|
// TODO: determine the maximum number of actions
|
||||||
|
2
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-title>
|
||||||
|
fn Title(&self) -> DOMString {
|
||||||
|
self.title.clone()
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-dir>
|
||||||
|
fn Dir(&self) -> NotificationDirection {
|
||||||
|
self.dir
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-lang>
|
||||||
|
fn Lang(&self) -> DOMString {
|
||||||
|
self.lang.clone()
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-body>
|
||||||
|
fn Body(&self) -> DOMString {
|
||||||
|
self.body.clone()
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-tag>
|
||||||
|
fn Tag(&self) -> DOMString {
|
||||||
|
self.tag.clone()
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-image>
|
||||||
|
fn Image(&self) -> USVString {
|
||||||
|
// step 1: If there is no this’s notification’s image URL, then return the empty string.
|
||||||
|
// step 2: Return this’s notification’s image URL, serialized.
|
||||||
|
self.image.clone().unwrap_or_default()
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-icon>
|
||||||
|
fn Icon(&self) -> USVString {
|
||||||
|
// step 1: If there is no this’s notification’s icon URL, then return the empty string.
|
||||||
|
// step 2: Return this’s notification’s icon URL, serialized.
|
||||||
|
self.icon.clone().unwrap_or_default()
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-badge>
|
||||||
|
fn Badge(&self) -> USVString {
|
||||||
|
// step 1: If there is no this’s notification’s badge URL, then return the empty string.
|
||||||
|
// step 2: Return this’s notification’s badge URL, serialized.
|
||||||
|
self.badge.clone().unwrap_or_default()
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-renotify>
|
||||||
|
fn Renotify(&self) -> bool {
|
||||||
|
self.renotify
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-silent>
|
||||||
|
fn GetSilent(&self) -> Option<bool> {
|
||||||
|
self.silent
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-requireinteraction>
|
||||||
|
fn RequireInteraction(&self) -> bool {
|
||||||
|
self.require_interaction
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-data>
|
||||||
|
fn Data(&self, _cx: SafeJSContext, mut retval: MutableHandleValue) {
|
||||||
|
retval.set(self.data.get());
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-actions>
|
||||||
|
fn Actions(&self, cx: SafeJSContext, retval: MutableHandleValue) {
|
||||||
|
// step 1: Let frozenActions be an empty list of type NotificationAction.
|
||||||
|
let mut frozen_actions: Vec<NotificationAction> = Vec::new();
|
||||||
|
|
||||||
|
// step 2: For each entry of this’s notification’s actions
|
||||||
|
for action in self.actions.iter() {
|
||||||
|
let action = NotificationAction {
|
||||||
|
action: action.name.clone(),
|
||||||
|
title: action.title.clone(),
|
||||||
|
// If entry’s icon URL is non-null,
|
||||||
|
// then set action["icon"] to entry’s icon URL, icon_url, serialized.
|
||||||
|
icon: action.icon_url.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: step 2.5: Call Object.freeze on action, to prevent accidental mutation by scripts.
|
||||||
|
// step 2.6: Append action to frozenActions.
|
||||||
|
frozen_actions.push(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 3: Return the result of create a frozen array from frozenActions.
|
||||||
|
to_frozen_array(frozen_actions.as_slice(), cx, retval);
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-vibrate>
|
||||||
|
fn Vibrate(&self, cx: SafeJSContext, retval: MutableHandleValue) {
|
||||||
|
to_frozen_array(self.vibration_pattern.as_slice(), cx, retval);
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-timestamp>
|
||||||
|
fn Timestamp(&self) -> u64 {
|
||||||
|
self.timestamp
|
||||||
|
}
|
||||||
|
/// <https://notifications.spec.whatwg.org/#dom-notification-close>
|
||||||
|
fn Close(&self) {
|
||||||
|
// TODO: If notification is a persistent notification and notification was closed by the end user
|
||||||
|
// then fire a service worker notification event named "notificationclose" given notification.
|
||||||
|
|
||||||
|
// If notification is a non-persistent notification
|
||||||
|
// then queue a task to fire an event named close on the Notification object representing notification.
|
||||||
|
self.global()
|
||||||
|
.task_manager()
|
||||||
|
.dom_manipulation_task_source()
|
||||||
|
.queue_simple_event(self.upcast(), atom!("close"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://notifications.spec.whatwg.org/#actions>
|
||||||
|
#[derive(JSTraceable, MallocSizeOf)]
|
||||||
|
struct Action {
|
||||||
|
/// <https://notifications.spec.whatwg.org/#action-name>
|
||||||
|
name: DOMString,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#action-title>
|
||||||
|
title: DOMString,
|
||||||
|
/// <https://notifications.spec.whatwg.org/#action-icon-url>
|
||||||
|
icon_url: Option<USVString>,
|
||||||
|
// TODO: icon_resource <https://notifications.spec.whatwg.org/#action-icon-resource>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://notifications.spec.whatwg.org/#create-a-notification-with-a-settings-object>
|
||||||
|
fn create_notification_with_settings_object(
|
||||||
|
global: &GlobalScope,
|
||||||
|
title: DOMString,
|
||||||
|
options: RootedTraceableBox<NotificationOptions>,
|
||||||
|
proto: Option<HandleObject>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> Fallible<DomRoot<Notification>> {
|
||||||
|
// step 1: Let origin be settings’s origin.
|
||||||
|
let origin = global.origin().immutable().clone();
|
||||||
|
// step 2: Let baseURL be settings’s API base URL.
|
||||||
|
let base_url = global.api_base_url();
|
||||||
|
// step 3: Let fallbackTimestamp be the number of milliseconds from
|
||||||
|
// the Unix epoch to settings’s current wall time, rounded to the nearest integer.
|
||||||
|
let fallback_timestamp = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.as_millis() as u64;
|
||||||
|
// step 4: Return the result of creating a notification given title, options, origin,
|
||||||
|
// baseURL, and fallbackTimestamp.
|
||||||
|
create_notification(
|
||||||
|
global,
|
||||||
|
title,
|
||||||
|
options,
|
||||||
|
origin,
|
||||||
|
base_url,
|
||||||
|
fallback_timestamp,
|
||||||
|
proto,
|
||||||
|
can_gc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://notifications.spec.whatwg.org/#create-a-notification
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn create_notification(
|
||||||
|
global: &GlobalScope,
|
||||||
|
title: DOMString,
|
||||||
|
options: RootedTraceableBox<NotificationOptions>,
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
base_url: ServoUrl,
|
||||||
|
fallback_timestamp: u64,
|
||||||
|
proto: Option<HandleObject>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> Fallible<DomRoot<Notification>> {
|
||||||
|
// If options["silent"] is true and options["vibrate"] exists, then throw a TypeError.
|
||||||
|
if options.silent.is_some() && options.vibrate.is_some() {
|
||||||
|
return Err(Error::Type(
|
||||||
|
"Can't specify vibration patterns when setting notification to silent.".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// If options["renotify"] is true and options["tag"] is the empty string, then throw a TypeError.
|
||||||
|
if options.renotify && options.tag.is_empty() {
|
||||||
|
return Err(Error::Type(
|
||||||
|
"tag must be set to renotify as an existing notification.".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Notification::new(
|
||||||
|
global,
|
||||||
|
title,
|
||||||
|
options,
|
||||||
|
origin,
|
||||||
|
base_url,
|
||||||
|
fallback_timestamp,
|
||||||
|
proto,
|
||||||
|
can_gc,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://w3c.github.io/vibration/#dfn-validate-and-normalize>
|
||||||
|
fn validate_and_normalize_vibration_pattern(
|
||||||
|
pattern: &UnsignedLongOrUnsignedLongSequence,
|
||||||
|
) -> Vec<u32> {
|
||||||
|
// Step 1: If pattern is a list, proceed to the next step. Otherwise run the following substeps:
|
||||||
|
let mut pattern: Vec<u32> = match pattern {
|
||||||
|
UnsignedLongOrUnsignedLongSequence::UnsignedLong(value) => {
|
||||||
|
// Step 1.1: Let list be an initially empty list, and add pattern to list.
|
||||||
|
// Step 1.2: Set pattern to list.
|
||||||
|
vec![*value]
|
||||||
|
},
|
||||||
|
UnsignedLongOrUnsignedLongSequence::UnsignedLongSequence(values) => values.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 2: Let max length have the value 10.
|
||||||
|
// Step 3: If the length of pattern is greater than max length, truncate pattern,
|
||||||
|
// leaving only the first max length entries.
|
||||||
|
pattern.truncate(10);
|
||||||
|
|
||||||
|
// If the length of the pattern is even and not zero then the last entry in the pattern will
|
||||||
|
// have no effect so an implementation can remove it from the pattern at this point.
|
||||||
|
if pattern.len() % 2 == 0 && !pattern.is_empty() {
|
||||||
|
pattern.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Let max duration have the value 10000.
|
||||||
|
// Step 5: For each entry in pattern whose value is greater than max duration,
|
||||||
|
// set the entry's value to max duration.
|
||||||
|
pattern.iter_mut().for_each(|entry| {
|
||||||
|
*entry = 10000.min(*entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Step 6: Return pattern.
|
||||||
|
pattern
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://notifications.spec.whatwg.org/#get-the-notifications-permission-state>
|
||||||
|
fn get_notifications_permission_state(global: &GlobalScope) -> NotificationPermission {
|
||||||
|
let permission_state = descriptor_permission_state(PermissionName::Notifications, Some(global));
|
||||||
|
match permission_state {
|
||||||
|
PermissionState::Granted => NotificationPermission::Granted,
|
||||||
|
PermissionState::Denied => NotificationPermission::Denied,
|
||||||
|
PermissionState::Prompt => NotificationPermission::Default,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_notification_permission(global: &GlobalScope) -> NotificationPermission {
|
||||||
|
let cx = GlobalScope::get_cx();
|
||||||
|
let promise = &Promise::new(global, CanGc::note());
|
||||||
|
let descriptor = PermissionDescriptor {
|
||||||
|
name: PermissionName::Notifications,
|
||||||
|
};
|
||||||
|
let status = PermissionStatus::new(global, &descriptor);
|
||||||
|
|
||||||
|
// The implementation of `request_notification_permission` seemed to be synchronous
|
||||||
|
Permissions::permission_request(cx, promise, &descriptor, &status);
|
||||||
|
|
||||||
|
match status.State() {
|
||||||
|
PermissionState::Granted => NotificationPermission::Granted,
|
||||||
|
PermissionState::Denied => NotificationPermission::Denied,
|
||||||
|
// Should only receive "Granted" or "Denied" from the permission request
|
||||||
|
PermissionState::Prompt => NotificationPermission::Default,
|
||||||
|
}
|
||||||
|
}
|
|
@ -383,6 +383,10 @@ DOMInterfaces = {
|
||||||
'canGc': ['CloneNode', 'SetTextContent'],
|
'canGc': ['CloneNode', 'SetTextContent'],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'Notification': {
|
||||||
|
'canGc': ['RequestPermission'],
|
||||||
|
},
|
||||||
|
|
||||||
'OfflineAudioContext': {
|
'OfflineAudioContext': {
|
||||||
'inRealms': ['StartRendering'],
|
'inRealms': ['StartRendering'],
|
||||||
'canGc': ['StartRendering'],
|
'canGc': ['StartRendering'],
|
||||||
|
|
113
components/script_bindings/webidls/Notification.webidl
Normal file
113
components/script_bindings/webidls/Notification.webidl
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// https://notifications.spec.whatwg.org/#api
|
||||||
|
[Exposed=(Window,Worker), Pref="dom_notification_enabled"]
|
||||||
|
interface Notification : EventTarget {
|
||||||
|
[Throws]
|
||||||
|
constructor(DOMString title, optional NotificationOptions options = {});
|
||||||
|
|
||||||
|
[GetterThrows]
|
||||||
|
static readonly attribute NotificationPermission permission;
|
||||||
|
|
||||||
|
[Exposed=Window]
|
||||||
|
static Promise<NotificationPermission> requestPermission(optional NotificationPermissionCallback deprecatedCallback);
|
||||||
|
|
||||||
|
static readonly attribute unsigned long maxActions;
|
||||||
|
|
||||||
|
attribute EventHandler onclick;
|
||||||
|
attribute EventHandler onshow;
|
||||||
|
attribute EventHandler onerror;
|
||||||
|
attribute EventHandler onclose;
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
readonly attribute DOMString title;
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
readonly attribute NotificationDirection dir;
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
readonly attribute DOMString lang;
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
readonly attribute DOMString body;
|
||||||
|
|
||||||
|
[Constant]
|
||||||
|
readonly attribute DOMString tag;
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
readonly attribute USVString image;
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
readonly attribute USVString icon;
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
readonly attribute USVString badge;
|
||||||
|
|
||||||
|
readonly attribute boolean renotify;
|
||||||
|
|
||||||
|
[Constant]
|
||||||
|
readonly attribute boolean requireInteraction;
|
||||||
|
|
||||||
|
[Constant]
|
||||||
|
readonly attribute boolean? silent;
|
||||||
|
|
||||||
|
// [Cached, Frozen, Pure]
|
||||||
|
readonly attribute /*FrozenArray<<unsigned long>*/any vibrate;
|
||||||
|
|
||||||
|
readonly attribute EpochTimeStamp timestamp;
|
||||||
|
|
||||||
|
[Constant]
|
||||||
|
readonly attribute any data;
|
||||||
|
|
||||||
|
// [Cached, Frozen, Pure]
|
||||||
|
readonly attribute /*FrozenArray<NotificationAction>*/any actions;
|
||||||
|
|
||||||
|
undefined close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// <https://w3c.github.io/hr-time/#dom-epochtimestamp>
|
||||||
|
typedef unsigned long long EpochTimeStamp;
|
||||||
|
typedef (unsigned long or sequence<unsigned long>) VibratePattern;
|
||||||
|
|
||||||
|
dictionary NotificationOptions {
|
||||||
|
NotificationDirection dir = "auto";
|
||||||
|
DOMString lang = "";
|
||||||
|
DOMString body = "";
|
||||||
|
DOMString tag = "";
|
||||||
|
USVString image;
|
||||||
|
USVString icon;
|
||||||
|
USVString badge;
|
||||||
|
VibratePattern vibrate;
|
||||||
|
EpochTimeStamp timestamp;
|
||||||
|
boolean renotify = false;
|
||||||
|
boolean? silent = null;
|
||||||
|
boolean requireInteraction = false;
|
||||||
|
any data = null;
|
||||||
|
sequence<NotificationAction> actions = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary GetNotificationOptions {
|
||||||
|
DOMString tag = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NotificationPermission {
|
||||||
|
"default",
|
||||||
|
"denied",
|
||||||
|
"granted"
|
||||||
|
};
|
||||||
|
|
||||||
|
callback NotificationPermissionCallback = undefined (NotificationPermission permission);
|
||||||
|
|
||||||
|
enum NotificationDirection {
|
||||||
|
"auto",
|
||||||
|
"ltr",
|
||||||
|
"rtl"
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary NotificationAction {
|
||||||
|
required DOMString action;
|
||||||
|
required DOMString title;
|
||||||
|
USVString icon;
|
||||||
|
};
|
|
@ -101,6 +101,7 @@ WEBIDL_STANDARDS = [
|
||||||
b"//github.com/immersive-web/webxr-test-api/",
|
b"//github.com/immersive-web/webxr-test-api/",
|
||||||
b"//github.com/immersive-web/webxr-hands-input/",
|
b"//github.com/immersive-web/webxr-hands-input/",
|
||||||
b"//gpuweb.github.io",
|
b"//gpuweb.github.io",
|
||||||
|
b"//notifications.spec.whatwg.org",
|
||||||
# Not a URL
|
# Not a URL
|
||||||
b"// This interface is entirely internal to Servo, and should not be"
|
b"// This interface is entirely internal to Servo, and should not be"
|
||||||
+ b" accessible to\n// web pages."
|
+ b" accessible to\n// web pages."
|
||||||
|
|
2
tests/wpt/meta/__dir__.ini
vendored
2
tests/wpt/meta/__dir__.ini
vendored
|
@ -1 +1 @@
|
||||||
prefs: ["dom_imagebitmap_enabled:true", "dom_offscreen_canvas_enabled:true", "dom_shadowdom_enabled:true", "dom_xpath_enabled:true", "dom_intersection_observer_enabled:true", "dom_resize_observer_enabled:true"]
|
prefs: ["dom_imagebitmap_enabled:true", "dom_offscreen_canvas_enabled:true", "dom_shadowdom_enabled:true", "dom_xpath_enabled:true", "dom_intersection_observer_enabled:true", "dom_resize_observer_enabled:true", "dom_notification_enabled:true"]
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
[constructor-basic.https.html]
|
|
||||||
[Called the notification constructor with one argument.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Constructing a notification without a NotificationOptions defaults to null.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[constructing a notification with a NotificationOptions dictionary correctly sets and reflects the silent attribute.]
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[constructor-invalid.https.html]
|
|
||||||
[Called the notification constructor with no arguments.]
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[constructor-non-secure.html]
|
|
||||||
[new Notification calls onerror in non-secure contexts]
|
|
||||||
expected: FAIL
|
|
|
@ -1,8 +0,0 @@
|
||||||
[historical.any.worker.html]
|
|
||||||
[Notification.get is obsolete]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
||||||
[historical.any.html]
|
|
||||||
[Notification.get is obsolete]
|
|
||||||
expected: FAIL
|
|
|
@ -2,171 +2,6 @@
|
||||||
expected: ERROR
|
expected: ERROR
|
||||||
|
|
||||||
[idlharness.https.any.worker.html]
|
[idlharness.https.any.worker.html]
|
||||||
[idl_test setup]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: existence and properties of interface object]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface object length]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface object name]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: existence and properties of interface prototype object]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: existence and properties of interface prototype object's "constructor" property]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: existence and properties of interface prototype object's @@unscopables property]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute permission]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: member requestPermission]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute maxActions]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute onclick]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute onshow]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute onerror]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute onclose]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute title]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute dir]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute lang]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute body]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute tag]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute image]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute icon]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute badge]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute vibrate]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute timestamp]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute renotify]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute silent]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute requireInteraction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute data]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute actions]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: operation close()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification must be primary interface of notification]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Stringification of notification]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "permission" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must not have property "requestPermission"]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "maxActions" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "onclick" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "onshow" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "onerror" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "onclose" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "title" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "dir" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "lang" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "body" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "tag" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "image" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "icon" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "badge" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "vibrate" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "timestamp" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "renotify" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "silent" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "requireInteraction" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "data" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "actions" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "close()" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ServiceWorkerRegistration interface: operation showNotification(DOMString, optional NotificationOptions)]
|
[ServiceWorkerRegistration interface: operation showNotification(DOMString, optional NotificationOptions)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -175,174 +10,6 @@
|
||||||
|
|
||||||
|
|
||||||
[idlharness.https.any.html]
|
[idlharness.https.any.html]
|
||||||
[idl_test setup]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: existence and properties of interface object]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface object length]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface object name]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: existence and properties of interface prototype object]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: existence and properties of interface prototype object's "constructor" property]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: existence and properties of interface prototype object's @@unscopables property]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute permission]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: operation requestPermission(optional NotificationPermissionCallback)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute maxActions]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute onclick]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute onshow]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute onerror]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute onclose]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute title]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute dir]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute lang]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute body]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute tag]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute image]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute icon]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute badge]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute vibrate]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute timestamp]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute renotify]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute silent]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute requireInteraction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute data]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: attribute actions]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: operation close()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification must be primary interface of notification]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Stringification of notification]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "permission" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "requestPermission(optional NotificationPermissionCallback)" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: calling requestPermission(optional NotificationPermissionCallback) on notification with too few arguments must throw TypeError]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "maxActions" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "onclick" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "onshow" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "onerror" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "onclose" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "title" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "dir" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "lang" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "body" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "tag" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "image" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "icon" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "badge" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "vibrate" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "timestamp" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "renotify" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "silent" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "requireInteraction" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "data" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "actions" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification interface: notification must inherit property "close()" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ServiceWorkerRegistration interface: operation showNotification(DOMString, optional NotificationOptions)]
|
[ServiceWorkerRegistration interface: operation showNotification(DOMString, optional NotificationOptions)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[permission.html]
|
|
||||||
[Checked the Notification.permission property.]
|
|
||||||
expected: FAIL
|
|
|
@ -1,10 +1,4 @@
|
||||||
[permissions-non-secure.html]
|
[permissions-non-secure.html]
|
||||||
expected: ERROR
|
expected: ERROR
|
||||||
[Notification.requestPermission must be called from a secure context]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification.permission must be called from a secure context]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Notification.permission must be called from a secure worker]
|
[Notification.permission must be called from a secure worker]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
6
tests/wpt/mozilla/meta/MANIFEST.json
vendored
6
tests/wpt/mozilla/meta/MANIFEST.json
vendored
|
@ -10518,7 +10518,7 @@
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"interfaces.js": [
|
"interfaces.js": [
|
||||||
"e2c2de8556c7fa88f54a76a3c18e06be14722de9",
|
"fbfc396b62c55415c0493b7528bd5e2b959452e6",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"max-session-history-frame.html": [
|
"max-session-history-frame.html": [
|
||||||
|
@ -13506,14 +13506,14 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"interfaces.https.html": [
|
"interfaces.https.html": [
|
||||||
"501caf7410bba6533e11c0d83acb2729da48a289",
|
"4e9a583f82479e20dfa932459d3eff607e530d01",
|
||||||
[
|
[
|
||||||
null,
|
null,
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"interfaces.worker.js": [
|
"interfaces.worker.js": [
|
||||||
"5288c40b0fb6e67f2b903f82f074580faa4dca33",
|
"fc621bbafeec167942f802caae43b9f2ef23b29b",
|
||||||
[
|
[
|
||||||
"mozilla/interfaces.worker.html",
|
"mozilla/interfaces.worker.html",
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
prefs: [dom_webxr_test: false]
|
prefs: [dom_webxr_test: false, dom_notification_enabled: true]
|
||||||
|
|
1
tests/wpt/mozilla/meta/mozilla/interfaces.worker.js.ini
vendored
Normal file
1
tests/wpt/mozilla/meta/mozilla/interfaces.worker.js.ini
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
prefs: [dom_notification_enabled: true]
|
|
@ -210,6 +210,7 @@ test_interfaces([
|
||||||
"NodeFilter",
|
"NodeFilter",
|
||||||
"NodeIterator",
|
"NodeIterator",
|
||||||
"NodeList",
|
"NodeList",
|
||||||
|
"Notification",
|
||||||
"OfflineAudioCompletionEvent",
|
"OfflineAudioCompletionEvent",
|
||||||
"OfflineAudioContext",
|
"OfflineAudioContext",
|
||||||
"Option",
|
"Option",
|
||||||
|
|
|
@ -34,6 +34,7 @@ function test_interfaces(interfaceNamesInGlobalScope) {
|
||||||
"MessageChannel",
|
"MessageChannel",
|
||||||
"MessagePort",
|
"MessagePort",
|
||||||
"NaN",
|
"NaN",
|
||||||
|
"Notification",
|
||||||
"Number",
|
"Number",
|
||||||
"Object",
|
"Object",
|
||||||
"Promise",
|
"Promise",
|
||||||
|
|
|
@ -42,6 +42,7 @@ test_interfaces([
|
||||||
"MessageChannel",
|
"MessageChannel",
|
||||||
"MessageEvent",
|
"MessageEvent",
|
||||||
"MessagePort",
|
"MessagePort",
|
||||||
|
"Notification",
|
||||||
"Performance",
|
"Performance",
|
||||||
"PerformanceEntry",
|
"PerformanceEntry",
|
||||||
"PerformanceMark",
|
"PerformanceMark",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue