summaryrefslogtreecommitdiffstats
path: root/toolkit/components/url-classifier/content/moz/preferences.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/url-classifier/content/moz/preferences.js')
-rw-r--r--toolkit/components/url-classifier/content/moz/preferences.js276
1 files changed, 276 insertions, 0 deletions
diff --git a/toolkit/components/url-classifier/content/moz/preferences.js b/toolkit/components/url-classifier/content/moz/preferences.js
new file mode 100644
index 000000000..30105ab34
--- /dev/null
+++ b/toolkit/components/url-classifier/content/moz/preferences.js
@@ -0,0 +1,276 @@
+# 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/.
+
+
+// Class for manipulating preferences. Aside from wrapping the pref
+// service, useful functionality includes:
+//
+// - abstracting prefobserving so that you can observe preferences
+// without implementing nsIObserver
+//
+// - getters that return a default value when the pref doesn't exist
+// (instead of throwing)
+//
+// - get-and-set getters
+//
+// Example:
+//
+// var p = new PROT_Preferences();
+// dump(p.getPref("some-true-pref")); // shows true
+// dump(p.getPref("no-such-pref", true)); // shows true
+// dump(p.getPref("no-such-pref", null)); // shows null
+//
+// function observe(prefThatChanged) {
+// dump("Pref changed: " + prefThatChanged);
+// };
+//
+// p.addObserver("somepref", observe);
+// p.setPref("somepref", true); // dumps
+// p.removeObserver("somepref", observe);
+//
+// TODO: should probably have the prefobserver pass in the new and old
+// values
+
+// TODO(tc): Maybe remove this class and just call natively since we're no
+// longer an extension.
+
+/**
+ * A class that wraps the preferences service.
+ *
+ * @param opt_startPoint A starting point on the prefs tree to resolve
+ * names passed to setPref and getPref.
+ *
+ * @param opt_useDefaultPranch Set to true to work against the default
+ * preferences tree instead of the profile one.
+ *
+ * @constructor
+ */
+this.G_Preferences =
+function G_Preferences(opt_startPoint, opt_getDefaultBranch) {
+ this.debugZone = "prefs";
+ this.observers_ = {};
+ this.getDefaultBranch_ = !!opt_getDefaultBranch;
+
+ this.startPoint_ = opt_startPoint || null;
+}
+
+G_Preferences.setterMap_ = { "string": "setCharPref",
+ "boolean": "setBoolPref",
+ "number": "setIntPref" };
+
+G_Preferences.getterMap_ = {};
+G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_STRING] = "getCharPref";
+G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_BOOL] = "getBoolPref";
+G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_INT] = "getIntPref";
+
+G_Preferences.prototype.__defineGetter__('prefs_', function() {
+ var prefs;
+ var prefSvc = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService);
+
+ if (this.getDefaultBranch_) {
+ prefs = prefSvc.getDefaultBranch(this.startPoint_);
+ } else {
+ prefs = prefSvc.getBranch(this.startPoint_);
+ }
+
+ // QI to prefs in case we want to add observers
+ prefs.QueryInterface(Ci.nsIPrefBranchInternal);
+ return prefs;
+});
+
+/**
+ * Stores a key/value in a user preference. Valid types for val are string,
+ * boolean, and number. Complex values are not yet supported (but feel free to
+ * add them!).
+ */
+G_Preferences.prototype.setPref = function(key, val) {
+ var datatype = typeof(val);
+
+ if (datatype == "number" && (val % 1 != 0)) {
+ throw new Error("Cannot store non-integer numbers in preferences.");
+ }
+
+ var meth = G_Preferences.setterMap_[datatype];
+
+ if (!meth) {
+ throw new Error("Pref datatype {" + datatype + "} not supported.");
+ }
+
+ return this.prefs_[meth](key, val);
+}
+
+/**
+ * Retrieves a user preference. Valid types for the value are the same as for
+ * setPref. If the preference is not found, opt_default will be returned
+ * instead.
+ */
+G_Preferences.prototype.getPref = function(key, opt_default) {
+ var type = this.prefs_.getPrefType(key);
+
+ // zero means that the specified pref didn't exist
+ if (type == Ci.nsIPrefBranch.PREF_INVALID) {
+ return opt_default;
+ }
+
+ var meth = G_Preferences.getterMap_[type];
+
+ if (!meth) {
+ throw new Error("Pref datatype {" + type + "} not supported.");
+ }
+
+ // If a pref has been cleared, it will have a valid type but won't
+ // be gettable, so this will throw.
+ try {
+ return this.prefs_[meth](key);
+ } catch(e) {
+ return opt_default;
+ }
+}
+
+/**
+ * Delete a preference.
+ *
+ * @param which Name of preference to obliterate
+ */
+G_Preferences.prototype.clearPref = function(which) {
+ try {
+ // This throws if the pref doesn't exist, which is fine because a
+ // nonexistent pref is cleared
+ this.prefs_.clearUserPref(which);
+ } catch(e) {}
+}
+
+/**
+ * Add an observer for a given pref.
+ *
+ * @param which String containing the pref to listen to
+ * @param callback Function to be called when the pref changes. This
+ * function will receive a single argument, a string
+ * holding the preference name that changed
+ */
+G_Preferences.prototype.addObserver = function(which, callback) {
+ // Need to store the observer we create so we can eventually unregister it
+ if (!this.observers_[which])
+ this.observers_[which] = { callbacks: [], observers: [] };
+
+ /* only add an observer if the callback hasn't been registered yet */
+ if (this.observers_[which].callbacks.indexOf(callback) == -1) {
+ var observer = new G_PreferenceObserver(callback);
+ this.observers_[which].callbacks.push(callback);
+ this.observers_[which].observers.push(observer);
+ this.prefs_.addObserver(which, observer, false /* strong reference */);
+ }
+}
+
+/**
+ * Remove an observer for a given pref.
+ *
+ * @param which String containing the pref to stop listening to
+ * @param callback Function to remove as an observer
+ */
+G_Preferences.prototype.removeObserver = function(which, callback) {
+ var ix = this.observers_[which].callbacks.indexOf(callback);
+ G_Assert(this, ix != -1, "Tried to unregister a nonexistent observer");
+ this.observers_[which].callbacks.splice(ix, 1);
+ var observer = this.observers_[which].observers.splice(ix, 1)[0];
+ this.prefs_.removeObserver(which, observer);
+}
+
+/**
+ * Remove all preference observers registered through this object.
+ */
+G_Preferences.prototype.removeAllObservers = function() {
+ for (var which in this.observers_) {
+ for (var observer of this.observers_[which].observers) {
+ this.prefs_.removeObserver(which, observer);
+ }
+ }
+ this.observers_ = {};
+}
+
+/**
+ * Helper class that knows how to observe preference changes and
+ * invoke a callback when they do
+ *
+ * @constructor
+ * @param callback Function to call when the preference changes
+ */
+this.G_PreferenceObserver =
+function G_PreferenceObserver(callback) {
+ this.debugZone = "prefobserver";
+ this.callback_ = callback;
+}
+
+/**
+ * Invoked by the pref system when a preference changes. Passes the
+ * message along to the callback.
+ *
+ * @param subject The nsIPrefBranch that changed
+ * @param topic String "nsPref:changed" (aka
+ * NS_PREFBRANCH_PREFCHANGE_OBSERVER_ID -- but where does it
+ * live???)
+ * @param data Name of the pref that changed
+ */
+G_PreferenceObserver.prototype.observe = function(subject, topic, data) {
+ G_Debug(this, "Observed pref change: " + data);
+ this.callback_(data);
+}
+
+/**
+ * XPCOM cruft
+ *
+ * @param iid Interface id of the interface the caller wants
+ */
+G_PreferenceObserver.prototype.QueryInterface = function(iid) {
+ if (iid.equals(Ci.nsISupports) ||
+ iid.equals(Ci.nsIObserver) ||
+ iid.equals(Ci.nsISupportsWeakReference))
+ return this;
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+}
+
+#ifdef DEBUG
+// UNITTESTS
+this.TEST_G_Preferences = function TEST_G_Preferences() {
+ if (G_GDEBUG) {
+ var z = "preferences UNITTEST";
+ G_debugService.enableZone(z);
+ G_Debug(z, "Starting");
+
+ var p = new G_Preferences();
+
+ var testPref = "test-preferences-unittest";
+ var noSuchPref = "test-preferences-unittest-aypabtu";
+
+ // Used to test observing
+ var observeCount = 0;
+ let observe = function (prefChanged) {
+ G_Assert(z, prefChanged == testPref, "observer broken");
+ observeCount++;
+ };
+
+ // Test setting, getting, and observing
+ p.addObserver(testPref, observe);
+ p.setPref(testPref, true);
+ G_Assert(z, p.getPref(testPref), "get or set broken");
+ G_Assert(z, observeCount == 1, "observer adding not working");
+
+ p.removeObserver(testPref, observe);
+
+ p.setPref(testPref, false);
+ G_Assert(z, observeCount == 1, "observer removal not working");
+ G_Assert(z, !p.getPref(testPref), "get broken");
+
+ // Remember to clean up the prefs we've set, and test removing prefs
+ // while we're at it
+ p.clearPref(noSuchPref);
+ G_Assert(z, !p.getPref(noSuchPref, false), "clear broken");
+
+ p.clearPref(testPref);
+
+ G_Debug(z, "PASSED");
+ }
+}
+#endif