Bug 678695 - Settings API. r=sicking, fabrice, smaug

This commit is contained in:
Gregor Wagner 2012-03-26 14:49:38 -07:00
Родитель b15d42f7a5
Коммит 3fb0e20633
23 изменённых файлов: 1208 добавлений и 1 удалений

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

@ -438,6 +438,9 @@ pref("dom.sms.whitelist", "file://,http://homescreen.gaiamobile.org,http://sms.g
pref("dom.mozContacts.enabled", true);
pref("dom.mozContacts.whitelist", "http://dialer.gaiamobile.org,http://sms.gaiamobile.org");
// WebSettings
pref("dom.mozSettings.enabled", true);
// Ignore X-Frame-Options headers.
pref("b2g.ignoreXFrameOptions", true);

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

@ -46,6 +46,7 @@ XPCOMUtils.defineLazyServiceGetter(Services, 'fm', function() {
function addPermissions(urls) {
let permissions = [
'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app',
'websettings-read', 'websettings-readwrite',
'content-camera', 'webcontacts-manage', 'wifi-manage', 'desktop-notification',
'geolocation'
];

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

@ -169,6 +169,7 @@
@BINPATH@/components/dom_json.xpt
@BINPATH@/components/dom_power.xpt
@BINPATH@/components/dom_range.xpt
@BINPATH@/components/dom_settings.xpt
@BINPATH@/components/dom_sidebar.xpt
@BINPATH@/components/dom_sms.xpt
@BINPATH@/components/dom_storage.xpt

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

@ -173,6 +173,7 @@
@BINPATH@/components/dom_json.xpt
@BINPATH@/components/dom_power.xpt
@BINPATH@/components/dom_range.xpt
@BINPATH@/components/dom_settings.xpt
@BINPATH@/components/dom_sidebar.xpt
@BINPATH@/components/dom_sms.xpt
@BINPATH@/components/dom_storage.xpt
@ -419,6 +420,8 @@
@BINPATH@/components/TelemetryPing.manifest
@BINPATH@/components/messageWakeupService.js
@BINPATH@/components/messageWakeupService.manifest
@BINPATH@/components/SettingsManager.js
@BINPATH@/components/SettingsManager.manifest
@BINPATH@/components/Webapps.js
@BINPATH@/components/Webapps.manifest

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

@ -147,6 +147,8 @@ NS_NewDOMCustomEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresConte
nsresult
NS_NewDOMSmsEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
nsresult
NS_NewDOMMozSettingsEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
nsresult
NS_NewDOMPopStateEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
nsresult
NS_NewDOMHashChangeEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);

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

@ -94,6 +94,7 @@ CPPSRCS = \
nsDOMPopStateEvent.cpp \
nsDOMHashChangeEvent.cpp \
nsDOMCloseEvent.cpp \
nsDOMSettingsEvent.cpp \
nsDOMTouchEvent.cpp \
nsDOMCustomEvent.cpp \
nsDOMCompositionEvent.cpp \
@ -113,6 +114,7 @@ LOCAL_INCLUDES += \
-I$(srcdir)/../../xul/content/src \
-I$(srcdir)/../../xml/content/src \
-I$(srcdir)/../../../dom/base \
-I$(srcdir)/../../../dom/settings \
-I$(srcdir)/../../../dom/src/storage \
-I$(srcdir)/../../../layout/generic \
-I$(srcdir)/../../../layout/xul/base/src \

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

@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 http://mozilla.org/MPL/2.0/. */
#include "nsDOMSettingsEvent.h"
#include "nsContentUtils.h"
#include "DictionaryHelpers.h"
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMozSettingsEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMozSettingsEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSettingValue)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMozSettingsEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSettingValue)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
DOMCI_DATA(MozSettingsEvent, nsDOMMozSettingsEvent)
NS_INTERFACE_MAP_BEGIN(nsDOMMozSettingsEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozSettingsEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSettingsEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMPL_ADDREF_INHERITED(nsDOMMozSettingsEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMMozSettingsEvent, nsDOMEvent)
NS_IMETHODIMP
nsDOMMozSettingsEvent::GetSettingName(nsAString & aSettingName)
{
aSettingName = mSettingName;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMozSettingsEvent::GetSettingValue(nsIVariant** aSettingValue)
{
NS_IF_ADDREF(*aSettingValue = mSettingValue);
return NS_OK;
}
NS_IMETHODIMP
nsDOMMozSettingsEvent::InitMozSettingsEvent(const nsAString& aType,
bool aCanBubble,
bool aCancelable,
const nsAString &aSettingName,
nsIVariant *aSettingValue)
{
nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
NS_ENSURE_SUCCESS(rv, rv);
mSettingName = aSettingName;
mSettingValue = aSettingValue;
return NS_OK;
}
nsresult
nsDOMMozSettingsEvent::InitFromCtor(const nsAString& aType,
JSContext* aCx, jsval* aVal)
{
mozilla::dom::MozSettingsEventInit d;
nsresult rv = d.Init(aCx, aVal);
NS_ENSURE_SUCCESS(rv, rv);
return InitMozSettingsEvent(aType, d.bubbles, d.cancelable, d.settingName, d.settingValue);
}
nsresult
NS_NewDOMMozSettingsEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsEvent* aEvent)
{
nsDOMMozSettingsEvent* e = new nsDOMMozSettingsEvent(aPresContext, aEvent);
return CallQueryInterface(e, aInstancePtrResult);
}

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

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 http://mozilla.org/MPL/2.0/. */
#ifndef nsDOMSettingsEvent_h__
#define nsDOMSettingsEvent_h__
#include "nsIDOMSettingsManager.h"
#include "nsDOMEvent.h"
class nsDOMMozSettingsEvent : public nsDOMEvent,
public nsIDOMMozSettingsEvent
{
public:
nsDOMMozSettingsEvent(nsPresContext* aPresContext, nsEvent* aEvent)
: nsDOMEvent(aPresContext, aEvent) {}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMMozSettingsEvent, nsDOMEvent)
// Forward to base class
NS_FORWARD_TO_NSDOMEVENT
NS_DECL_NSIDOMMOZSETTINGSEVENT
virtual nsresult InitFromCtor(const nsAString& aType,
JSContext* aCx, jsval* aVal);
private:
nsString mSettingName;
nsCOMPtr<nsIVariant> mSettingValue;
};
#endif // nsDOMSettingsEvent_h__

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

@ -51,6 +51,7 @@ DIRS = \
interfaces/core \
interfaces/html \
interfaces/events \
interfaces/settings \
interfaces/stylesheets \
interfaces/sidebar \
interfaces/css \
@ -78,6 +79,7 @@ DIRS += \
battery \
contacts \
power \
settings \
sms \
src \
locales \

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

@ -208,6 +208,7 @@
#include "nsWebSocket.h"
#include "nsIDOMCloseEvent.h"
#include "nsEventSource.h"
#include "nsIDOMSettingsManager.h"
// includes needed for the prototype chain interfaces
#include "nsIDOMNavigator.h"
@ -1617,6 +1618,9 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(CustomEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MozSettingsEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
#ifdef MOZ_B2G_RIL
NS_DEFINE_CLASSINFO_DATA(Telephony, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
@ -1680,6 +1684,7 @@ NS_DEFINE_EVENT_CTOR(PopStateEvent)
NS_DEFINE_EVENT_CTOR(HashChangeEvent)
NS_DEFINE_EVENT_CTOR(PageTransitionEvent)
NS_DEFINE_EVENT_CTOR(CloseEvent)
NS_DEFINE_EVENT_CTOR(MozSettingsEvent)
NS_DEFINE_EVENT_CTOR(UIEvent)
NS_DEFINE_EVENT_CTOR(MouseEvent)
nsresult
@ -1712,6 +1717,7 @@ static const nsConstructorFuncMapData kConstructorFuncMap[] =
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(HashChangeEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PageTransitionEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CloseEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozSettingsEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(StorageEvent)
@ -4364,6 +4370,11 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(MozSettingsEvent, nsIDOMMozSettingsEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSettingsEvent)
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
#ifdef MOZ_B2G_RIL
DOM_CLASSINFO_MAP_BEGIN(Telephony, nsIDOMTelephony)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMTelephony)

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

@ -532,6 +532,7 @@ DOMCI_CLASS(MozCSSKeyframesRule)
DOMCI_CLASS(MediaQueryList)
DOMCI_CLASS(CustomEvent)
DOMCI_CLASS(MozSettingsEvent)
#ifdef MOZ_B2G_RIL
DOMCI_CLASS(Telephony)

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

@ -3,6 +3,7 @@ DOM_SRCDIRS = \
dom/battery \
dom/power \
dom/network/src \
dom/settings \
dom/sms/src \
dom/contacts \
dom/src/events \

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

@ -0,0 +1,20 @@
# 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 http://mozilla.org/MPL/2.0/.
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = dom
XPIDL_MODULE = dom_settings
GRE_MODULE = 1
XPIDLSRCS = \
nsIDOMSettingsManager.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,49 @@
/* 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 http://mozilla.org/MPL/2.0/. */
#include "domstubs.idl"
#include "nsIDOMEventTarget.idl"
#include "nsIDOMEvent.idl"
interface nsIDOMDOMRequest;
interface nsIVariant;
[scriptable, uuid(ef95ddd0-6308-11e1-b86c-0800200c9a66)]
interface nsIDOMSettingsLock : nsISupports
{
// Contains a JSON object with name/value pairs to be set.
nsIDOMDOMRequest set(in nsIVariant settings);
// result contains the value of the setting.
nsIDOMDOMRequest get(in jsval name);
nsIDOMDOMRequest clear();
};
[scriptable, uuid(5609d0a0-52a9-11e1-b86c-0800200c9a66)]
interface nsIDOMSettingsManager : nsISupports
{
nsIDOMSettingsLock getLock();
attribute nsIDOMEventListener onsettingchange;
};
[scriptable, uuid(5ce02690-52a9-11e1-b86c-0800200c9a66)]
interface nsIDOMMozSettingsEvent : nsIDOMEvent
{
readonly attribute DOMString settingName;
readonly attribute nsIVariant settingValue;
[noscript] void initMozSettingsEvent(in DOMString aType,
in boolean aCanBubble,
in boolean aCancelable,
in DOMString aSettingName,
in nsIVariant aSettingValue);
};
dictionary MozSettingsEventInit : EventInit
{
DOMString settingName;
nsIVariant settingValue;
};

35
dom/settings/Makefile.in Normal file
Просмотреть файл

@ -0,0 +1,35 @@
# 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 http://mozilla.org/MPL/2.0/.
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = \
$(srcdir) \
$(NULL)
include $(DEPTH)/config/autoconf.mk
MODULE = dom
LIBRARY_NAME = jsdomsettings_s
LIBXUL_LIBRARY = 1
EXTRA_COMPONENTS = \
SettingsManager.js \
SettingsManager.manifest \
$(NULL)
ifdef ENABLE_TESTS
DIRS += tests
endif
# Add VPATH to LOCAL_INCLUDES so we are going to include the correct backend
# subdirectory (and the ipc one).
# LOCAL_INCLUDES += $(VPATH:%=-I%)
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
include $(topsrcdir)/config/rules.mk
DEFINES += -D_IMPL_NS_LAYOUT

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

@ -0,0 +1,361 @@
/* 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 http://mozilla.org/MPL/2.0/. */
"use strict"
/* static functions */
let DEBUG = 0;
if (DEBUG)
debug = function (s) { dump("-*- SettingsManager: " + s + "\n"); }
else
debug = function (s) {}
function Queue() {
this._queue = [];
this._index = 0;
}
Queue.prototype = {
getLength: function() { return (this._queue.length - this._index); },
isEmpty: function() { return (this._queue.length == 0); },
enqueue: function(item) { this._queue.push(item); },
dequeue: function() {
if(this.isEmpty())
return undefined;
var item = this._queue[this._index];
if (++this._index * 2 >= this._queue.length){
this._queue = this._queue.slice(this._index);
this._index = 0;
}
return item;
}
}
const DB_NAME = "settings";
const DB_VERSION = 1;
const STORE_NAME = "settings";
function SettingsDB() {}
SettingsDB.prototype = {
db: null,
close: function close() {
if (this.db)
this.db.close();
},
/**
* Prepare the database. This may include opening the database and upgrading
* it to the latest schema version.
*
* @return (via callback) a database ready for use.
*/
ensureDB: function ensureDB(aSuccessCb, aFailureCb, aGlobal) {
if (this.db) {
debug("ensureDB: already have a database, returning early.");
return;
}
let self = this;
debug("try to open database:" + DB_NAME + " " + DB_VERSION + " " + this._indexedDB);
let req = aGlobal.mozIndexedDB.open(DB_NAME, DB_VERSION);
req.onsuccess = function (event) {
debug("Opened database:", DB_NAME, DB_VERSION);
self.db = event.target.result;
self.db.onversionchange = function(event) {
debug("WARNING: DB modified from a different window.");
}
aSuccessCb();
};
req.onupgradeneeded = function (aEvent) {
debug("Database needs upgrade:" + DB_NAME + aEvent.oldVersion + aEvent.newVersion);
debug("Correct new database version:" + aEvent.newVersion == DB_VERSION);
let db = aEvent.target.result;
switch (aEvent.oldVersion) {
case 0:
debug("New database");
self.createSchema(db);
break;
default:
debug("No idea what to do with old database version:" + aEvent.oldVersion);
aFailureCb(aEvent.target.errorMessage);
break;
}
};
req.onerror = function (aEvent) {
debug("Failed to open database:", DB_NAME);
aFailureCb(aEvent.target.errorMessage);
};
req.onblocked = function (aEvent) {
debug("Opening database request is blocked.");
};
},
createSchema: function createSchema(aDb) {
let objectStore = aDb.createObjectStore(STORE_NAME, {keyPath: "settingName"});
objectStore.createIndex("settingValue", "settingValue", { unique: false });
debug("Created object stores and indexes");
}
}
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(Services, "DOMRequest", function() {
return Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci.nsIDOMRequestService);
});
const nsIClassInfo = Ci.nsIClassInfo;
const SETTINGSLOCK_CONTRACTID = "@mozilla.org/settingsLock;1";
const SETTINGSLOCK_CID = Components.ID("{ef95ddd0-6308-11e1-b86c-0800200c9a66}");
const nsIDOMSettingsLock = Ci.nsIDOMSettingsLock;
function SettingsLock(aSettingsManager)
{
this._open = true;
this._requests = new Queue();
this._settingsManager = aSettingsManager;
this._transaction = null;
}
SettingsLock.prototype = {
process: function process() {
let lock = this;
lock._open = false;
let store = lock._transaction.objectStore(STORE_NAME);
while (!lock._requests.isEmpty()) {
let info = lock._requests.dequeue();
debug("info:" + info.intent);
let request = info.request;
switch (info.intent) {
case "clear":
let req = store.clear();
req.onsuccess = function() { this._open = true;
Services.DOMRequest.fireSuccess(request, 0);
this._open = false; }.bind(lock);
req.onerror = function() { Services.DOMRequest.fireError(request, 0) };
break;
case "set":
for (var key in info.settings) {
debug("key: " + key + ", val: " + JSON.stringify(info.settings[key]) + "type: " + typeof(info.settings[key]));
if(typeof(info.settings[key]) != 'object') {
req = store.put({settingName: key, settingValue: info.settings[key]});
} else {
//Workaround for cloning issues
let obj = JSON.parse(JSON.stringify(info.settings[key]));
req = store.put({settingName: key, settingValue: obj});
}
req.onsuccess = function() { this._open = true;
if (this._settingsManager._onsettingchange) {
let event = new this._settingsManager._window.MozSettingsEvent("settingchanged", {settingName: key, settingValue: info.settings[key]});
this._settingsManager._onsettingchange.handleEvent(event);
}
Services.obs.notifyObservers(this, "mozsettings-changed-"+key, JSON.stringify(info.settings[key]));
Services.DOMRequest.fireSuccess(request, 0);
this._open = false; }.bind(lock);
req.onerror = function() { Services.DOMRequest.fireError(request, 0) };
}
break;
case "get":
if (info.name == "*") {
req = store.getAll();
} else {
req = store.getAll(info.name);
}
req.onsuccess = function(event) {
debug("Request successful. Record count:" + event.target.result.length);
debug("result: " + JSON.stringify(event.target.result));
var result = {};
for (var i in event.target.result)
result[event.target.result[i].settingName] = event.target.result[i].settingValue;
this._open = true;
Services.DOMRequest.fireSuccess(request, result);
this._open = false;
}.bind(lock);
req.onerror = function() { Services.DOMRequest.fireError(request, 0)};
break;
}
}
if (!lock._requests.isEmpty())
throw Components.results.NS_ERROR_ABORT;
lock._open = true;
},
createTransactionAndProcess: function() {
if (this._settingsManager._settingsDB.db) {
var lock;
while (lock = this._settingsManager._locks.dequeue()) {
if (!lock._transaction) {
lock._transaction = lock._settingsManager._settingsDB.db.transaction(STORE_NAME, "readwrite");
}
lock.process();
}
if (!this._requests.isEmpty())
this.process();
}
},
get: function get(aName) {
if (!this._open)
throw Components.results.NS_ERROR_ABORT;
if (this._settingsManager.hasReadPrivileges || this._settingsManager.hasReadWritePrivileges) {
let req = Services.DOMRequest.createRequest(this._settingsManager._window);
this._requests.enqueue({ request: req, intent:"get", name: aName });
this.createTransactionAndProcess();
return req;
} else {
debug("get not allowed");
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
}
},
set: function set(aSettings) {
if (!this._open)
throw Components.results.NS_ERROR_ABORT;
if (this._settingsManager.hasReadWritePrivileges) {
let req = Services.DOMRequest.createRequest(this._settingsManager._window);
debug("send: " + JSON.stringify(aSettings));
this._requests.enqueue({request: req, intent: "set", settings: aSettings});
this.createTransactionAndProcess();
return req;
} else {
debug("set not allowed");
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
}
},
clear: function clear() {
if (!this._open)
throw Components.results.NS_ERROR_ABORT;
if (this._settingsManager.hasReadWritePrivileges) {
let req = Services.DOMRequest.createRequest(this._settingsManager._window);
this._requests.enqueue({ request: req, intent: "clear"});
this.createTransactionAndProcess();
return req;
} else {
debug("clear not allowed");
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
}
},
classID : SETTINGSLOCK_CID,
QueryInterface : XPCOMUtils.generateQI([nsIDOMSettingsLock]),
classInfo : XPCOMUtils.generateCI({classID: SETTINGSLOCK_CID,
contractID: SETTINGSLOCK_CONTRACTID,
classDescription: "SettingsLock",
interfaces: [nsIDOMSettingsLock],
flags: nsIClassInfo.DOM_OBJECT})
};
const SETTINGSMANAGER_CONTRACTID = "@mozilla.org/settingsManager;1";
const SETTINGSMANAGER_CID = Components.ID("{5609d0a0-52a9-11e1-b86c-0800200c9a66}");
const nsIDOMSettingsManager = Ci.nsIDOMSettingsManager;
let myGlobal = this;
function SettingsManager()
{
this._locks = new Queue();
var idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
idbManager.initWindowless(myGlobal);
this._settingsDB = new SettingsDB();
}
SettingsManager.prototype = {
_onsettingchange: null,
nextTick: function nextTick(aCallback, thisObj) {
if (thisObj)
aCallback = aCallback.bind(thisObj);
Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
},
set onsettingchange(aCallback) {
if (this.hasReadPrivileges || this.hasReadWritePrivileges)
this._onsettingchange = aCallback;
else
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
get onsettingchange() {
return this._onsettingchange;
},
getLock: function() {
debug("get lock!");
var lock = new SettingsLock(this);
this._locks.enqueue(lock);
this._settingsDB.ensureDB(
function() { lock.createTransactionAndProcess(); },
function() { dump("ensureDB error cb!\n"); },
myGlobal );
this.nextTick(function() { this._open = false; }, lock);
return lock;
},
init: function(aWindow) {
// Set navigator.mozSettings to null.
if (!Services.prefs.getBoolPref("dom.mozSettings.enabled"))
return null;
this._window = aWindow;
Services.obs.addObserver(this, "inner-window-destroyed", false);
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
this.innerWindowID = util.currentInnerWindowID;
let principal = aWindow.document.nodePrincipal;
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
let readPerm = principal == secMan.getSystemPrincipal() ? Ci.nsIPermissionManager.ALLOW_ACTION : Services.perms.testExactPermission(principal.URI, "websettings-read");
let readwritePerm = principal == secMan.getSystemPrincipal() ? Ci.nsIPermissionManager.ALLOW_ACTION : Services.perms.testExactPermission(principal.URI, "websettings-readwrite");
this.hasReadPrivileges = readPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
this.hasReadWritePrivileges = readwritePerm == Ci.nsIPermissionManager.ALLOW_ACTION;
debug("has read privileges :" + this.hasReadPrivileges + ", has read-write privileges: " + this.hasReadWritePrivileges);
},
observe: function(aSubject, aTopic, aData) {
debug("Topic: " + aTopic);
if (aTopic == "inner-window-destroyed") {
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
if (wId == this.innerWindowID) {
Services.obs.removeObserver(this, "inner-window-destroyed");
this._requests = null;
this._window = null;
this._innerWindowID = null;
this._onsettingchange = null;
this._settingsDB.close();
}
}
},
classID : SETTINGSMANAGER_CID,
QueryInterface : XPCOMUtils.generateQI([nsIDOMSettingsManager, Ci.nsIDOMGlobalPropertyInitializer]),
classInfo : XPCOMUtils.generateCI({classID: SETTINGSMANAGER_CID,
contractID: SETTINGSMANAGER_CONTRACTID,
classDescription: "SettingsManager",
interfaces: [nsIDOMSettingsManager],
flags: nsIClassInfo.DOM_OBJECT})
}
const NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsManager, SettingsLock])

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

@ -0,0 +1,6 @@
component {5609d0a0-52a9-11e1-b86c-0800200c9a66} SettingsManager.js
contract @mozilla.org/settingsManager;1 {5609d0a0-52a9-11e1-b86c-0800200c9a66}
category JavaScript-navigator-property mozSettings @mozilla.org/settingsManager;1
component {ef95ddd0-6308-11e1-b86c-0800200c9a66} SettingsManager.js
contract @mozilla.org/settingsLock;1 {ef95ddd0-6308-11e1-b86c-0800200c9a66}

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

@ -0,0 +1,28 @@
# 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 http://mozilla.org/MPL/2.0/.
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/settings/tests
include $(DEPTH)/config/autoconf.mk
DIRS = \
$(NULL)
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
test_settings_basics.html \
test_settings_events.html \
$(NULL)
_CHROME_TEST_FILES = \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

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

@ -0,0 +1,526 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id={678695}
-->
<head>
<title>Test for Bug {678695} Settings API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={678695}">Mozilla Bug {678695}</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
"use strict"
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager)
.add(SpecialPowers.getDocumentURIObject(window.document),
"websettings-read",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager)
.add(SpecialPowers.getDocumentURIObject(window.document),
"websettings-readwrite",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
function onUnwantedSuccess() {
ok(false, "onUnwantedSuccess: shouldn't get here");
}
function onFailure() {
ok(false, "in on Failure!");
}
var wifi = {"net3g.apn": "internet.mnc012.mcc345.gprs"};
var wifi2 = {"net3g.apn": "internet.mnc012.mcc345.test"};
var wifiEnabled = {"wifi.enabled": true};
var wifiDisabled = {"wifi.enabled": false};
var screenBright = {"screen.brightness": 0.7};
var wifiNetworks0 = { "wifi.networks[0]": { ssid: "myfreenetwork", mac: "01:23:45:67:89:ab", passwd: "secret"}};
var wifiNetworks1 = { "wifi.networks[1]": { ssid: "myfreenetwork2", mac: "01:23:45:67:89:ab", passwd: "secret2"}};
function equals(o1, o2) {
var k1 = Object.keys(o1).sort();
var k2 = Object.keys(o2).sort();
if (k1.length != k2.length) return false;
return k1.zip(k2, function(keyPair) {
if(typeof o1[keyPair[0]] == typeof o2[keyPair[1]] == "object"){
return equals(o1[keyPair[0]], o2[keyPair[1]])
} else {
return o1[keyPair[0]] == o2[keyPair[1]];
}
}).all();
};
function check(o1, o2) {
is(JSON.stringify(o1), JSON.stringify(o2), "same");
}
var req, req2, req3, req4, req5, req6;
var index = 0;
var mozSettings = window.navigator.mozSettings;
var steps = [
function () {
ok(true, "Deleting database");
var lock = mozSettings.getLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
};
req.onerror = onFailure;
req2 = lock.set(screenBright);
req2.onsuccess = function () {
ok(true, "set done");
next();
}
req2.onerror = onFailure;
},
function() {
ok(true, "adding Event Listener2");
navigator.mozSettings.onsettingchange = function(event) {
is(event.settingName, "screen.brightness", "Same settingName");
is(event.settingValue, "0.7", "Same settingvalue");
}
var lock = mozSettings.getLock();
req2 = lock.get("screen.brightness");
req2.onsuccess = function() {
next();
};
req2.onerror = onFailure;
},
function() {
ok(true, "adding Event Listener");
var lock = mozSettings.getLock();
req = lock.set(screenBright);
req.onsuccess = function () {
ok(true, "set done");
navigator.mozSettings.onsettingchange = null;
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Nested test");
var lock = mozSettings.getLock();
req = lock.get("screen.brightness");
req.onsuccess = function () {
req3 = lock.set({"screen.brightness": req.result["screen.brightness"] + 1})
req3.onsuccess = function () {
req4 = lock.get("screen.brightness");
req4.onsuccess = function() {
is(req4.result["screen.brightness"], 1.7, "same Value");
}
req4.onerror = onFailure;
}
req3.onerror = onFailure;
};
req.onerror = onFailure;
req2 = lock.get("screen.brightness");
req2.onsuccess = function () {
is(req2.result["screen.brightness"], 0.7, "same Value");
}
req2.onerror = onFailure;
var lock2 = mozSettings.getLock();
req5 = lock2.get("screen.brightness");
req5.onsuccess = function () {
is(req5.result["screen.brightness"], 1.7, "same Value");
next();
}
req5.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
var lock = mozSettings.getLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
};
req.onerror = onFailure;
req2 = lock.set(wifi);
req2.onsuccess = function () {
ok(true, "set done");
}
req2.onerror = onFailure;
ok(true, "Get all settings");
var lock2 = mozSettings.getLock();
req = lock2.get("*");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifi, req.result);
ok(true, JSON.stringify(req.result));
ok(true, "Get all settings Done");
};
req.onerror = onFailure;
req2 = lock2.get("net3g.apn");
req2.onsuccess = function () {
is(Object.keys(req2.result).length, 1, "length 1");
check(wifi, req2.result);
ok(true, "Get net3g.apn Done");
next();
};
req2.onerror = onFailure;
},
function () {
ok(true, "Change wifi");
var lock = mozSettings.getLock();
req = lock.set(wifi2);
req.onsuccess = function () {
ok(true, "Set Done");
};
req.onerror = onFailure;
ok(true, "Get changed net3g.apn");
req2 = lock.get("net3g.apn");
req2.onsuccess = function () {
is(Object.keys(req2.result).length, 1, "length 1");
check(wifi2, req2.result);
ok(true, "Get net3g.apn Done");
next();
};
req2.onerror = onFailure;
},
function () {
ok(true, "Test locking");
var lock = mozSettings.getLock();
var lock2 = mozSettings.getLock();
req = lock.set(wifiEnabled);
req.onsuccess = function () {
ok(true, "Test Locking Done");
};
req.onerror = onFailure;
req2 = lock2.set(wifiDisabled);
req2.onsuccess = function () {
ok(true, "Set Done");
next();
};
req2.onerror = onFailure;
},
function () {
ok(true, "Test locking result");
var lock = mozSettings.getLock();
req = lock.get("wifi.enabled");
req.onsuccess = function() {
check(req.result, wifiDisabled);
ok(true, "Test1 locking result done");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Test locking heavy");
for (var i=0; i<30; i++) {
// only new locks!
var lock = mozSettings.getLock();
var obj = {};
obj["wifi.enabled" + i] = true;
req = lock.set( obj );
req.onsuccess = function () {
ok(true, "Set1 Done");
};
req.onerror = onFailure;
};
{
var lock2 = mozSettings.getLock();
req = lock2.get("*");
req.onsuccess = function () {
is(Object.keys(req.result).length, 32, "length 12");
ok(true, JSON.stringify(req.result));
ok(true, "Get all settings Done");
};
req.onerror = onFailure;
}
var lock2 = mozSettings.getLock();
var obj = {};
obj["wifi.enabled" + 30] = true;
req2 = lock2.set( obj );
req2.onsuccess = function () {
ok(true, "Set12 Done");
};
req2.onerror = onFailure;
var lock3 = mozSettings.getLock();
// with one lock
for (var i = 0; i < 30; i++) {
req3 = lock3.get("wifi.enabled" + i);
var testObj = {};
testObj["wifi.enabled" + i] = true;
req3.onsuccess = function () {
check(this.request.result, this.testObj);
ok(true, "Get1 Done");
}.bind({testObj: testObj, request: req3});
req3.onerror = onFailure;
}
ok(true, "start next2!");
var lock4 = mozSettings.getLock();
for (var i=0; i<30; i++) {
var obj = {};
obj["wifi.enabled" + i] = false;
req4 = lock4.set( obj );
req4.onsuccess = function () {
ok(true, "Set2 Done");
};
req4.onerror = onFailure;
}
var lock5 = mozSettings.getLock();
for (var i=0; i<30; i++) {
req5 = lock5.get("wifi.enabled" + i);
var testObj = {};
testObj["wifi.enabled" + i] = false;
req5.onsuccess = function () {
check(this.request.result, this.testObj);
ok(true, "Get2 Done");
}.bind({testObj: testObj, request: req5});
req5.onerror = onFailure;
}
var lock5 = mozSettings.getLock();
req6 = lock5.clear();
req6.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req6.onerror = onFailure;
},
function () {
ok(true, "reverse Test locking");
var lock2 = mozSettings.getLock();
var lock = mozSettings.getLock();
req = lock.set(wifiEnabled);
req.onsuccess = function () {
ok(true, "Test Locking Done");
next();
};
req.onerror = onFailure;
req2 = lock2.set(wifiDisabled);
req2.onsuccess = function () {
ok(true, "Set Done");
};
req2.onerror = onFailure;
},
function () {
ok(true, "Test locking result");
var lock = mozSettings.getLock();
req = lock.get("wifi.enabled");
req.onsuccess = function() {
check(req.result, wifiEnabled);
ok(true, "Test2 locking result done");
}
req.onerror = onFailure;
req2 = lock.clear();
req2.onsuccess = function () {
ok(true, "Deleted the database");
};
req2.onerror = onFailure;
req3 = lock.set(wifi);
req3.onsuccess = function () {
ok(true, "set done");
next();
}
req3.onerror = onFailure;
},
function () {
ok(true, "Get all settings");
var lock = mozSettings.getLock();
req = lock.get("*");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifi, req.result);
ok(true, "Get all settings Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Get net3g.apn");
var lock = mozSettings.getLock();
req = lock.get("net3g.apn");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifi, req.result);
ok(true, "Get net3g.apn Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Change wifi");
var lock = mozSettings.getLock();
req = lock.set(wifi2);
req.onsuccess = function () {
ok(true, "Set Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Get net3g.apn");
var lock = mozSettings.getLock();
req = lock.get("net3g.apn");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifi2, req.result);
ok(true, "Get net3g.apn Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Add wifi.enabled");
var lock = mozSettings.getLock();
req = lock.set(wifiEnabled);
req.onsuccess = function () {
ok(true, "Set Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Get Wifi Enabled");
var lock = mozSettings.getLock();
req = lock.get("wifi.enabled");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifiEnabled, req.result);
ok(true, "Get wifi.enabledDone");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Get all");
var lock = mozSettings.getLock();
req = lock.get("*");
req.onsuccess = function () {
is(Object.keys(req.result).length, 2, "length 2");
check(wifiEnabled["wifi.enabled"], req.result["wifi.enabled"]);
check(wifi2["net3g.apn"], req.result["net3g.apn"]);
ok(true, "Get all Done");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Add wifiNetworks");
var lock = mozSettings.getLock();
req = lock.set(wifiNetworks0);
req.onsuccess = function () {
ok(true, "Set Done");
};
req.onerror = onFailure;
req2 = lock.set(wifiNetworks1);
req2.onsuccess = function () {
ok(true, "Set Done");
next();
};
req2.onerror = onFailure;
},
function () {
ok(true, "Get Wifi Networks");
var lock = mozSettings.getLock();
req = lock.get("wifi.networks[0]");
req.onsuccess = function () {
is(Object.keys(req.result).length, 1, "length 1");
check(wifiNetworks0, req.result);
ok(true, "Get wifi.networks[0]");
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Clear DB, multiple locks");
var lock4 = mozSettings.getLock();
var lock3 = mozSettings.getLock();
var lock2 = mozSettings.getLock();
var lock = mozSettings.getLock();
var lock6 = mozSettings.getLock();
var lock7 = mozSettings.getLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Add wifiNetworks");
var lock = mozSettings.getLock();
req = lock.set(wifiNetworks0);
req.onsuccess = function () {
ok(true, "Set Done");
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Clear DB");
var lock = mozSettings.getLock();
req = lock.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "all done!\n");
SimpleTest.finish();
}
];
function next() {
ok(true, "Begin!");
if (index >= steps.length) {
ok(false, "Shouldn't get here!");
return;
}
try {
steps[index]();
} catch(ex) {
ok(false, "Caught exception", ex);
}
index += 1;
}
function permissionTest() {
if (gSettingsEnabled) {
next();
} else {
is(mozSettings, null, "mozSettings is null when not enabled.");
SimpleTest.finish();
}
}
var gSettingsEnabled = SpecialPowers.getBoolPref("dom.mozSettings.enabled");
SimpleTest.waitForExplicitFinish();
addLoadEvent(permissionTest);
ok(true, "test passed");
</script>
</pre>
</body>
</html>

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

@ -0,0 +1,39 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=678695
-->
<head>
<title>Test for Bug 678695</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=678695">Mozilla Bug 678695</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 678695 **/
var e = new MozSettingsEvent("settingchanged", {settingName: "a", settingValue: 1});
ok(e, "Should have settings event!");
is(e.settingName, "a", "Name should be a.");
is(e.settingValue, 1, "Value should be 1.");
e = new MozSettingsEvent("settingchanged", {settingName: "test", settingValue: {test: "test"}});
is(e.settingName, "test", "Name should be 'test'.");
is(e.settingValue.test, "test", "Name should be 'test'.");
e = new MozSettingsEvent("settingchanged", {settingName: "a", settingValue: true});
is(e.settingName, "a", "Name should be a.");
is(e.settingValue, true, "Value should be true.");
</script>
</pre>
</body>
</html>

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

@ -11,7 +11,8 @@ dictionaries = [
[ 'IDBObjectStoreParameters', 'nsIIDBDatabase.idl' ],
[ 'IDBIndexParameters', 'nsIIDBObjectStore.idl' ],
[ 'StorageEventInit', 'nsIDOMStorageEvent.idl' ],
[ 'BlobPropertyBag', 'nsIDOMFile.idl' ]
[ 'BlobPropertyBag', 'nsIDOMFile.idl' ],
[ 'SettingsEventInit', 'nsIDOMSettingsManager.idl' ]
]
# include file names

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

@ -95,6 +95,7 @@ SHARED_LIBRARY_LIBS = \
$(DEPTH)/dom/battery/$(LIB_PREFIX)dom_battery_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/contacts/$(LIB_PREFIX)jsdomcontacts_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/power/$(LIB_PREFIX)dom_power_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/settings/$(LIB_PREFIX)jsdomsettings_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/network/src/$(LIB_PREFIX)dom_network_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/sms/src/$(LIB_PREFIX)dom_sms_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/src/events/$(LIB_PREFIX)jsdomevents_s.$(LIB_SUFFIX) \
@ -260,6 +261,7 @@ LOCAL_INCLUDES += -I$(srcdir)/../base \
-I$(topsrcdir)/dom/src/offline \
-I$(topsrcdir)/dom/src/geolocation \
-I$(topsrcdir)/dom/contacts \
-I$(topsrcdir)/dom/settings \
-I$(topsrcdir)/dom/telephony \
-I. \
-I$(topsrcdir)/editor/libeditor/base \

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

@ -3512,6 +3512,9 @@ pref("dom.sms.whitelist", "");
pref("dom.mozContacts.enabled", false);
pref("dom.mozContacts.whitelist", "");
// WebSettings
pref("dom.mozSettings.enabled", false);
// enable JS dump() function.
pref("browser.dom.window.dump.enabled", false);