Bug 899585 - Add custom data support in the Notification constructor r=baku

This commit is contained in:
Robert Bindar 2014-08-20 17:56:12 -07:00
Родитель 10638101c5
Коммит 29ee85a120
26 изменённых файлов: 319 добавлений и 56 удалений

Просмотреть файл

@ -149,7 +149,8 @@ let AlertsHelper = {
dir: listener.dir,
id: listener.id,
tag: listener.tag,
timestamp: listener.timestamp
timestamp: listener.timestamp,
data: listener.dataObj
},
Services.io.newURI(listener.target, null, null),
Services.io.newURI(listener.manifestURL, null, null)
@ -199,8 +200,32 @@ let AlertsHelper = {
});
},
deserializeStructuredClone: function(dataString) {
if (!dataString) {
return null;
}
let scContainer = Cc["@mozilla.org/docshell/structured-clone-container;1"].
createInstance(Ci.nsIStructuredCloneContainer);
// The maximum supported structured-clone serialization format version
// as defined in "js/public/StructuredClone.h"
let JS_STRUCTURED_CLONE_VERSION = 4;
scContainer.initFromBase64(dataString, JS_STRUCTURED_CLONE_VERSION);
let dataObj = scContainer.deserializeToVariant();
// We have to check whether dataObj contains DOM objects (supported by
// nsIStructuredCloneContainer, but not by Cu.cloneInto), e.g. ImageData.
// After the structured clone callback systems will be unified, we'll not
// have to perform this check anymore.
try {
let data = Cu.cloneInto(dataObj, {});
} catch(e) { dataObj = null; }
return dataObj;
},
showNotification: function(imageURL, title, text, textClickable, cookie,
uid, bidi, lang, manifestURL, timestamp) {
uid, bidi, lang, dataObj, manifestURL, timestamp) {
function send(appName, appIcon) {
SystemAppProxy._sendCustomEvent(kMozChromeNotificationEvent, {
type: kDesktopNotification,
@ -213,7 +238,8 @@ let AlertsHelper = {
appName: appName,
appIcon: appIcon,
manifestURL: manifestURL,
timestamp: timestamp
timestamp: timestamp,
data: dataObj
});
}
@ -238,15 +264,17 @@ let AlertsHelper = {
currentListener.observer.observe(null, kTopicAlertFinished, currentListener.cookie);
}
let dataObj = this.deserializeStructuredClone(data.dataStr);
this.registerListener(data.name, data.cookie, data.alertListener);
this.showNotification(data.imageURL, data.title, data.text,
data.textClickable, data.cookie, data.name, data.bidi,
data.lang, null);
data.lang, dataObj, null);
},
showAppNotification: function(aMessage) {
let data = aMessage.data;
let details = data.details;
let dataObject = this.deserializeStructuredClone(details.data);
let listener = {
mm: aMessage.target,
title: data.title,
@ -257,12 +285,14 @@ let AlertsHelper = {
id: details.id || undefined,
dir: details.dir || undefined,
tag: details.tag || undefined,
timestamp: details.timestamp || undefined
timestamp: details.timestamp || undefined,
dataObj: dataObject || undefined
};
this.registerAppListener(data.uid, listener);
this.showNotification(data.imageURL, data.title, data.text,
details.textClickable, null, data.uid, details.dir,
details.lang, details.manifestURL, details.timestamp);
details.lang, dataObject, details.manifestURL,
details.timestamp);
},
closeAlert: function(name) {

Просмотреть файл

@ -69,7 +69,7 @@ AlertsService.prototype = {
// nsIAlertsService
showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable,
aCookie, aAlertListener, aName, aBidi,
aLang) {
aLang, aDataStr) {
cpmm.sendAsyncMessage(kMessageAlertNotificationSend, {
imageURL: aImageUrl,
title: aTitle,
@ -79,7 +79,8 @@ AlertsService.prototype = {
listener: aAlertListener,
id: aName,
dir: aBidi,
lang: aLang
lang: aLang,
dataStr: aDataStr
});
},
@ -95,6 +96,7 @@ AlertsService.prototype = {
let uid = (aDetails.id == "") ?
"app-notif-" + uuidGenerator.generateUUID() : aDetails.id;
let dataObj = this.deserializeStructuredClone(aDetails.data);
this._listeners[uid] = {
observer: aAlertListener,
title: aTitle,
@ -106,7 +108,8 @@ AlertsService.prototype = {
dbId: aDetails.dbId || undefined,
dir: aDetails.dir || undefined,
tag: aDetails.tag || undefined,
timestamp: aDetails.timestamp || undefined
timestamp: aDetails.timestamp || undefined,
dataObj: dataObj || undefined
};
cpmm.sendAsyncMessage(kMessageAppNotificationSend, {
@ -151,7 +154,8 @@ AlertsService.prototype = {
id: listener.id,
tag: listener.tag,
dbId: listener.dbId,
timestamp: listener.timestamp
timestamp: listener.timestamp,
data: listener.dataObj || undefined,
},
Services.io.newURI(data.target, null, null),
Services.io.newURI(listener.manifestURL, null, null)
@ -167,6 +171,30 @@ AlertsService.prototype = {
}
delete this._listeners[data.uid];
}
},
deserializeStructuredClone: function(dataString) {
if (!dataString) {
return null;
}
let scContainer = Cc["@mozilla.org/docshell/structured-clone-container;1"].
createInstance(Ci.nsIStructuredCloneContainer);
// The maximum supported structured-clone serialization format version
// as defined in "js/public/StructuredClone.h"
let JS_STRUCTURED_CLONE_VERSION = 4;
scContainer.initFromBase64(dataString, JS_STRUCTURED_CLONE_VERSION);
let dataObj = scContainer.deserializeToVariant();
// We have to check whether dataObj contains DOM objects (supported by
// nsIStructuredCloneContainer, but not by Cu.cloneInto), e.g. ImageData.
// After the structured clone callback systems will be unified, we'll not
// have to perform this check anymore.
try {
let data = Cu.cloneInto(dataObj, {});
} catch(e) { dataObj = null; }
return dataObj;
}
};

Просмотреть файл

@ -46,7 +46,7 @@ interface nsIStructuredCloneContainer : nsISupports
void initFromBase64(in AString aData,in unsigned long aFormatVersion);
/**
* Deserialize the object this conatiner holds, returning it wrapped as
* Deserialize the object this container holds, returning it wrapped as
* an nsIVariant.
*/
[implicit_jscontext]

Просмотреть файл

@ -4,7 +4,7 @@
#include "domstubs.idl"
[scriptable, uuid(fb089720-1c5c-11e3-b773-0800200c9a66)]
[scriptable, uuid(9b12f566-2c7f-48ef-990d-e5092a71d11e)]
interface nsINotificationStorageCallback : nsISupports
{
/**
@ -26,7 +26,8 @@ interface nsINotificationStorageCallback : nsISupports
in DOMString lang,
in DOMString body,
in DOMString tag,
in DOMString icon);
in DOMString icon,
in DOMString data);
/**
* Callback function used to notify C++ the we have returned
@ -39,7 +40,7 @@ interface nsINotificationStorageCallback : nsISupports
/**
* Interface for notification persistence layer.
*/
[scriptable, uuid(cc4656d7-2a2a-47f1-8016-55891e833d64)]
[scriptable, uuid(1be733d9-d614-43f2-9fd4-8f573a33b215)]
interface nsINotificationStorage : nsISupports
{
@ -68,7 +69,8 @@ interface nsINotificationStorage : nsISupports
in DOMString body,
in DOMString tag,
in DOMString icon,
in DOMString alertName);
in DOMString alertName,
in DOMString data);
/**
* Retrieve a list of notifications.

Просмотреть файл

@ -3361,6 +3361,7 @@ ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsStri
const nsString& aText, const bool& aTextClickable,
const nsString& aCookie, const nsString& aName,
const nsString& aBidi, const nsString& aLang,
const nsString& aData,
const IPC::Principal& aPrincipal)
{
#ifdef MOZ_CHILD_PERMISSIONS
@ -3374,7 +3375,8 @@ ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsStri
nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID));
if (sysAlerts) {
sysAlerts->ShowAlertNotification(aImageUrl, aTitle, aText, aTextClickable,
aCookie, this, aName, aBidi, aLang, aPrincipal);
aCookie, this, aName, aBidi, aLang,
aData, aPrincipal);
}
return true;
}

Просмотреть файл

@ -530,6 +530,7 @@ private:
const nsString& aText, const bool& aTextClickable,
const nsString& aCookie, const nsString& aName,
const nsString& aBidi, const nsString& aLang,
const nsString& aData,
const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
virtual bool RecvCloseAlert(const nsString& aName,

Просмотреть файл

@ -542,6 +542,7 @@ parent:
nsString name,
nsString bidi,
nsString lang,
nsString data,
Principal principal);
CloseAlert(nsString name, Principal principal);

Просмотреть файл

@ -60,7 +60,8 @@ ChromeNotifications.prototype = {
lang: notification.lang,
tag: notification.tag,
dbId: notification.id,
timestamp: notification.timestamp
timestamp: notification.timestamp,
data: notification.data
}
);
resentNotifications++;

Просмотреть файл

@ -111,6 +111,7 @@ DesktopNotification::PostDesktopNotification()
uniqueName,
NS_LITERAL_STRING("auto"),
EmptyString(),
EmptyString(),
principal);
}

Просмотреть файл

@ -4,6 +4,7 @@
#include "mozilla/dom/Notification.h"
#include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/OwningNonNull.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/Preferences.h"
@ -16,10 +17,12 @@
#include "nsIPermissionManager.h"
#include "nsIUUIDGenerator.h"
#include "nsServiceManagerUtils.h"
#include "nsStructuredCloneContainer.h"
#include "nsToolkitCompsCID.h"
#include "nsGlobalWindow.h"
#include "nsDOMJSUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsIXPConnect.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/Services.h"
#include "nsContentPermissionHelper.h"
@ -57,11 +60,12 @@ public:
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
JSContext* aCx)
{
MOZ_ASSERT(!aID.IsEmpty());
NotificationOptions options;
RootedDictionary<NotificationOptions> options(aCx);
options.mDir = Notification::StringToDirection(nsString(aDir));
options.mLang = aLang;
options.mBody = aBody;
@ -71,6 +75,12 @@ public:
aID,
aTitle,
options);
ErrorResult rv;
notification->InitFromBase64(aCx, aData, rv);
if (rv.Failed()) {
return rv.ErrorCode();
}
JSAutoCompartment ac(aCx, mGlobal);
JS::Rooted<JSObject*> element(aCx, notification->WrapObject(aCx));
NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
@ -371,7 +381,7 @@ NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
Notification::Notification(const nsAString& aID, const nsAString& aTitle, const nsAString& aBody,
NotificationDirection aDir, const nsAString& aLang,
const nsAString& aTag, const nsAString& aIconUrl,
nsPIDOMWindow* aWindow)
nsPIDOMWindow* aWindow)
: DOMEventTargetHelper(aWindow),
mID(aID), mTitle(aTitle), mBody(aBody), mDir(aDir), mLang(aLang),
mTag(aTag), mIconUrl(aIconUrl), mIsClosed(false)
@ -404,11 +414,19 @@ Notification::Constructor(const GlobalObject& aGlobal,
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
MOZ_ASSERT(window, "Window should not be null.");
nsRefPtr<Notification> notification = CreateInternal(window,
EmptyString(),
aTitle,
aOptions);
// Make a structured clone of the aOptions.mData object
JS::Rooted<JS::Value> data(aGlobal.Context(), aOptions.mData);
notification->InitFromJSVal(aGlobal.Context(), data, aRv);
if (aRv.Failed()) {
return nullptr;
}
// Queue a task to show the notification.
nsCOMPtr<nsIRunnable> showNotificationTask =
new NotificationTask(notification, NotificationTask::eShow);
@ -435,6 +453,13 @@ Notification::Constructor(const GlobalObject& aGlobal,
nsString alertName;
notification->GetAlertName(alertName);
nsString dataString;
nsCOMPtr<nsIStructuredCloneContainer> scContainer;
scContainer = notification->GetDataCloneContainer();
if (scContainer) {
scContainer->GetDataAsBase64(dataString);
}
aRv = notificationStorage->Put(origin,
id,
aTitle,
@ -443,7 +468,9 @@ Notification::Constructor(const GlobalObject& aGlobal,
aOptions.mBody,
aOptions.mTag,
aOptions.mIcon,
alertName);
alertName,
dataString);
if (aRv.Failed()) {
return nullptr;
}
@ -481,10 +508,29 @@ Notification::CreateInternal(nsPIDOMWindow* aWindow,
aOptions.mLang,
aOptions.mTag,
aOptions.mIcon,
aWindow);
aWindow);
return notification.forget();
}
Notification::~Notification() {}
NS_IMPL_CYCLE_COLLECTION_CLASS(Notification)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDataObjectContainer)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDataObjectContainer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(Notification, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(Notification, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Notification)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
nsIPrincipal*
Notification::GetPrincipal()
{
@ -531,6 +577,13 @@ Notification::ShowInternal()
nsCOMPtr<nsIObserver> observer = new NotificationObserver(this);
// mDataObjectContainer might be uninitialized here because the notification
// was constructed with an undefined data property.
nsString dataStr;
if (mDataObjectContainer) {
mDataObjectContainer->GetDataAsBase64(dataStr);
}
#ifdef MOZ_B2G
nsCOMPtr<nsIAppNotificationService> appNotifier =
do_GetService("@mozilla.org/system-alerts-service;1");
@ -553,6 +606,7 @@ Notification::ShowInternal()
ops.mDir = DirectionToString(mDir);
ops.mLang = mLang;
ops.mTag = mTag;
ops.mData = dataStr;
if (!ToJSValue(cx, ops, &val)) {
NS_WARNING("Converting dict to object failed!");
@ -574,7 +628,7 @@ Notification::ShowInternal()
alertService->ShowAlertNotification(absoluteUrl, mTitle, mBody, true,
uniqueCookie, observer, mAlertName,
DirectionToString(mDir), mLang,
GetPrincipal());
dataStr, GetPrincipal());
}
void
@ -780,6 +834,54 @@ Notification::GetOrigin(nsPIDOMWindow* aWindow, nsString& aOrigin)
return NS_OK;
}
nsIStructuredCloneContainer* Notification::GetDataCloneContainer()
{
return mDataObjectContainer;
}
void
Notification::GetData(JSContext* aCx,
JS::MutableHandle<JS::Value> aRetval)
{
if (!mData && mDataObjectContainer) {
nsresult rv;
rv = mDataObjectContainer->DeserializeToVariant(aCx, getter_AddRefs(mData));
if (NS_WARN_IF(NS_FAILED(rv))) {
aRetval.setNull();
return;
}
}
if (!mData) {
aRetval.setNull();
return;
}
VariantToJsval(aCx, mData, aRetval);
}
void
Notification::InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData,
ErrorResult& aRv)
{
if (mDataObjectContainer || aData.isNull()) {
return;
}
mDataObjectContainer = new nsStructuredCloneContainer();
aRv = mDataObjectContainer->InitFromJSVal(aData);
}
void Notification::InitFromBase64(JSContext* aCx, const nsAString& aData,
ErrorResult& aRv)
{
if (mDataObjectContainer || aData.IsEmpty()) {
return;
}
auto container = new nsStructuredCloneContainer();
aRv = container->InitFromBase64(aData, JS_STRUCTURED_CLONE_VERSION,
aCx);
mDataObjectContainer = container;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -13,6 +13,8 @@
#include "nsCycleCollectionParticipant.h"
class nsIPrincipal;
class nsIStructuredCloneContainer;
class nsIVariant;
namespace mozilla {
namespace dom {
@ -34,6 +36,9 @@ public:
IMPL_EVENT_HANDLER(error)
IMPL_EVENT_HANDLER(close)
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Notification, DOMEventTargetHelper)
static already_AddRefed<Notification> Constructor(const GlobalObject& aGlobal,
const nsAString& aTitle,
const NotificationOptions& aOption,
@ -72,6 +77,8 @@ public:
aRetval = mIconUrl;
}
nsIStructuredCloneContainer* GetDataCloneContainer();
static void RequestPermission(const GlobalObject& aGlobal,
const Optional<OwningNonNull<NotificationPermissionCallback> >& aCallback,
ErrorResult& aRv);
@ -91,11 +98,17 @@ public:
}
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
void InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData, ErrorResult& aRv);
void InitFromBase64(JSContext* aCx, const nsAString& aData, ErrorResult& aRv);
protected:
Notification(const nsAString& aID, const nsAString& aTitle, const nsAString& aBody,
NotificationDirection aDir, const nsAString& aLang,
const nsAString& aTag, const nsAString& aIconUrl,
nsPIDOMWindow* aWindow);
nsPIDOMWindow* aWindow);
static already_AddRefed<Notification> CreateInternal(nsPIDOMWindow* aWindow,
const nsAString& aID,
@ -145,6 +158,10 @@ protected:
nsString mLang;
nsString mTag;
nsString mIconUrl;
nsCOMPtr<nsIStructuredCloneContainer> mDataObjectContainer;
// It's null until GetData is first called
nsCOMPtr<nsIVariant> mData;
nsString mAlertName;
@ -153,6 +170,8 @@ protected:
static uint32_t sCount;
private:
virtual ~Notification();
nsIPrincipal* GetPrincipal();
};

Просмотреть файл

@ -71,7 +71,8 @@ NotificationStorage.prototype = {
}
},
put: function(origin, id, title, dir, lang, body, tag, icon, alertName) {
put: function(origin, id, title, dir, lang, body, tag, icon, alertName,
data) {
if (DEBUG) { debug("PUT: " + id + ": " + title); }
var notification = {
id: id,
@ -83,7 +84,8 @@ NotificationStorage.prototype = {
icon: icon,
alertName: alertName,
timestamp: new Date().getTime(),
origin: origin
origin: origin,
data: data
};
this._notifications[id] = notification;
@ -202,7 +204,8 @@ NotificationStorage.prototype = {
notification.lang,
notification.body,
notification.tag,
notification.icon);
notification.icon,
notification.data);
} catch (e) {
if (DEBUG) { debug("Error calling callback handle: " + e); }
}

Просмотреть файл

@ -48,7 +48,8 @@ var MockServices = (function () {
dbId: aDetails.dbId || undefined,
dir: aDetails.dir || undefined,
tag: aDetails.tag || undefined,
timestamp: aDetails.timestamp || undefined
timestamp: aDetails.timestamp || undefined,
data: aDetails.data || undefined
};
this.showAlertNotification(aImageUrl, aTitle, aText, true, "", listener, aDetails.id);
},

Просмотреть файл

@ -43,6 +43,34 @@ var NotificationTest = (function () {
})(tests);
}
var fakeCustomData = (function () {
var buffer = new ArrayBuffer(2);
var dv = new DataView(buffer).setInt16(0, 42, true);
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 100;
var context = canvas.getContext("2d");
var map = new Map();
var set = new Set();
map.set("test", 42);
set.add(4); set.add(2);
return {
primitives: {
a: 123,
b: "test",
c: true,
d: [1, 2, 3]
},
date: new Date(2013, 2, 1, 1, 10),
regexp: new RegExp("[^.]+"),
arrayBuffer: buffer,
imageData: context.createImageData(100, 100),
map: map,
set: set
};
})();
// NotificationTest API
return {
run: function (tests, callback) {
@ -68,6 +96,33 @@ var NotificationTest = (function () {
// TODO: how??
},
info: info
info: info,
customDataMatches: function(dataObj) {
var url = "http://www.domain.com";
try {
return (JSON.stringify(dataObj.primitives) ===
JSON.stringify(fakeCustomData.primitives)) &&
(dataObj.date.toDateString() ===
fakeCustomData.date.toDateString()) &&
(dataObj.regexp.exec(url)[0].substr(7) === "www") &&
(new Int16Array(dataObj.arrayBuffer)[0] === 42) &&
(JSON.stringify(dataObj.imageData.data) ===
JSON.stringify(fakeCustomData.imageData.data)) &&
(dataObj.map.get("test") == 42) &&
(dataObj.set.has(4) && dataObj.set.has(2));
} catch(e) {
return false;
}
},
payload: {
body: "Body",
tag: "fakeTag",
icon: "icon.jpg",
lang: "en-US",
dir: "ltr",
data: fakeCustomData
}
};
})();

Просмотреть файл

@ -9,7 +9,8 @@ var registrar = SpecialPowers.wrap(SpecialPowers.Components).manager.
var mockAlertsService = {
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name, bidi, lang) {
cookie, alertListener, name, bidi,
lang, data) {
// probably should do this async....
SpecialPowers.wrap(alertListener).observe(null, "alertshow", cookie);
@ -22,7 +23,8 @@ var mockAlertsService = {
showAppNotification: function(imageUrl, title, text, alertListener, details) {
this.showAlertNotification(imageUrl, title, text, details.textClickable, "",
alertListener, details.name, details.dir, details.lang);
alertListener, details.name, details.dir,
details.lang, details.data);
},
QueryInterface: function(aIID) {

Просмотреть файл

@ -24,7 +24,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=782211
var mockAlertsService = {
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name, dir, lang) {
cookie, alertListener, name, dir,
lang, data) {
notificationsCreated.push(name);
if (notificationsCreated.length == 3) {
checkNotifications();

Просмотреть файл

@ -24,7 +24,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=874090
var mockAlertsService = {
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name, dir, lang) {
cookie, alertListener, name, dir, lang, data) {
ok(true, "System principal was granted permission and is able to call showAlertNotification.");
unregisterMock();
SimpleTest.finish();

Просмотреть файл

@ -14,6 +14,7 @@
<script type="text/javascript">
var info = NotificationTest.info;
var options;
var steps = [
function () {
@ -62,13 +63,8 @@
function (done) {
info("Test create notification");
var options = {
dir: "auto",
lang: "",
body: "This is a notification body",
tag: "sometag",
icon: "icon.png"
};
options = NotificationTest.payload;
var notification = new Notification("This is a title", options);
ok(notification, "Notification exists");
@ -77,12 +73,15 @@
is(notification.onerror, null, "onerror() should be null");
is(notification.onclose, null, "onclose() should be null");
is(typeof notification.close, "function", "close() should exist");
is(typeof notification.data, "object", "data should be a JS object");
is(notification.dir, options.dir, "auto should get set");
is(notification.lang, options.lang, "lang should get set");
is(notification.body, options.body, "body should get set");
is(notification.tag, options.tag, "tag should get set");
is(notification.icon, options.icon, "icon should get set");
ok(NotificationTest.customDataMatches(notification.data),
"data should get set");
// store notification in test context
this.notification = notification;

Просмотреть файл

@ -94,13 +94,8 @@
done();
};
var payload = {
body: "Body",
tag: "fakeTag",
icon: "icon.jpg",
lang: "en-US",
dir: "ltr"
};
var payload = NotificationTest.payload;
var notif2 = new Notification("Title2", payload);
ok(notif2, "Notification object is valid");
notifications.push(notif2);
@ -156,6 +151,16 @@
is(notif.dir, "ltr", "Notification dir is valid: " + notif.dir);
is(notif.tag, "fakeTag", "Notification tag is valid: " + notif.tag);
ok((notif.timestamp >= now), "Notification timestamp is valid: (" + notif.timestamp + " >= " + now + ")");
var scContainer =
SpecialPowers.Cc["@mozilla.org/docshell/structured-clone-container;1"].
createInstance(SpecialPowers.Ci.nsIStructuredCloneContainer);
scContainer.initFromBase64(notif.data, 4);
var dataObj = scContainer.deserializeToVariant().SpecialPowers_wrappedObject;
ok(NotificationTest.customDataMatches(dataObj),
"Notification data is valid");
notif2.close();
});
}

Просмотреть файл

@ -45,13 +45,8 @@
function (done) {
info("Test adding a notification, and making sure get returns it");
NotificationTest.allowNotifications();
var options = {
dir: "auto",
lang: "",
body: "This is a notification body",
tag: "sometag",
icon: "icon.png"
};
var options = NotificationTest.payload;
var notification = new Notification("This is a title", options);
var promise = Notification.get();
promise.then(function (notifications) {
@ -61,6 +56,11 @@
if (notification.tag === options.tag) {
ok(true, "should contain newly created notification");
for (var key in options) {
if (key === "data") {
ok(NotificationTest.customDataMatches(notification.data),
"data property should match");
continue;
}
is(notification[key], options[key], key + " property should match");
}
notification.close();

Просмотреть файл

@ -14,4 +14,5 @@ dictionary AppNotificationServiceOptions {
DOMString dir = "";
DOMString lang = "";
DOMString tag = "";
DOMString data = "";
};

Просмотреть файл

@ -49,6 +49,9 @@ interface Notification : EventTarget {
[Pure]
readonly attribute DOMString? icon;
[Constant]
readonly attribute any data;
void close();
};
@ -58,6 +61,7 @@ dictionary NotificationOptions {
DOMString body = "";
DOMString tag = "";
DOMString icon = "";
any data = null;
};
dictionary GetNotificationOptions {

Просмотреть файл

@ -69,6 +69,7 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
const nsAString & aAlertName,
const nsAString & aBidi,
const nsAString & aLang,
const nsAString & aData,
nsIPrincipal * aPrincipal)
{
if (XRE_GetProcessType() == GeckoProcessType_Content) {
@ -85,6 +86,7 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
PromiseFlatString(aAlertName),
PromiseFlatString(aBidi),
PromiseFlatString(aLang),
PromiseFlatString(aData),
IPC::Principal(aPrincipal));
return NS_OK;
}
@ -100,7 +102,8 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
if (sysAlerts) {
return sysAlerts->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
aAlertCookie, aAlertListener, aAlertName,
aBidi, aLang, IPC::Principal(aPrincipal));
aBidi, aLang, aData,
IPC::Principal(aPrincipal));
}
if (!ShouldShowAlert()) {

Просмотреть файл

@ -9,7 +9,7 @@
interface nsIPrincipal;
[scriptable, uuid(160e87e1-d57d-456b-b6ea-17826f6ea7a8)]
[scriptable, uuid(d446bede-fcf7-403d-b6b6-5fd67b19ba58)]
interface nsIAlertsService : nsISupports
{
/**
@ -61,6 +61,7 @@ interface nsIAlertsService : nsISupports
[optional] in AString name,
[optional] in AString dir,
[optional] in AString lang,
[optional] in AString data,
[optional] in nsIPrincipal principal);
/**

Просмотреть файл

@ -2750,7 +2750,7 @@ nsDownload::SetState(DownloadState aState)
message, !removeWhenDone,
mPrivate ? NS_LITERAL_STRING("private") : NS_LITERAL_STRING("non-private"),
mDownloadManager, EmptyString(), NS_LITERAL_STRING("auto"),
EmptyString(), nullptr);
EmptyString(), EmptyString(), nullptr);
}
}
}

Просмотреть файл

@ -202,6 +202,7 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
const nsAString & aAlertName,
const nsAString & aBidi,
const nsAString & aLang,
const nsAString & aData,
nsIPrincipal * aPrincipal)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;