|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 module.metadata = { |
|
8 "stability": "unstable" |
|
9 }; |
|
10 |
|
11 // The minimum and maximum integers that can be set as preferences. |
|
12 // The range of valid values is narrower than the range of valid JS values |
|
13 // because the native preferences code treats integers as NSPR PRInt32s, |
|
14 // which are 32-bit signed integers on all platforms. |
|
15 const MAX_INT = 0x7FFFFFFF; |
|
16 const MIN_INT = -0x80000000; |
|
17 |
|
18 const {Cc,Ci,Cr} = require("chrome"); |
|
19 |
|
20 const prefService = Cc["@mozilla.org/preferences-service;1"]. |
|
21 getService(Ci.nsIPrefService); |
|
22 const prefSvc = prefService.getBranch(null); |
|
23 const defaultBranch = prefService.getDefaultBranch(null); |
|
24 |
|
25 function Branch(branchName) { |
|
26 function getPrefKeys() { |
|
27 return keys(branchName).map(function(key) { |
|
28 return key.replace(branchName, ""); |
|
29 }); |
|
30 } |
|
31 |
|
32 return Proxy.create({ |
|
33 get: function(receiver, pref) { |
|
34 return get(branchName + pref); |
|
35 }, |
|
36 set: function(receiver, pref, val) { |
|
37 set(branchName + pref, val); |
|
38 }, |
|
39 delete: function(pref) { |
|
40 reset(branchName + pref); |
|
41 return true; |
|
42 }, |
|
43 has: function hasPrefKey(pref) { |
|
44 return has(branchName + pref) |
|
45 }, |
|
46 getPropertyDescriptor: function(name) { |
|
47 return { |
|
48 value: get(branchName + name) |
|
49 }; |
|
50 }, |
|
51 enumerate: getPrefKeys, |
|
52 keys: getPrefKeys |
|
53 }, Branch.prototype); |
|
54 } |
|
55 |
|
56 function get(name, defaultValue) { |
|
57 switch (prefSvc.getPrefType(name)) { |
|
58 case Ci.nsIPrefBranch.PREF_STRING: |
|
59 return prefSvc.getComplexValue(name, Ci.nsISupportsString).data; |
|
60 |
|
61 case Ci.nsIPrefBranch.PREF_INT: |
|
62 return prefSvc.getIntPref(name); |
|
63 |
|
64 case Ci.nsIPrefBranch.PREF_BOOL: |
|
65 return prefSvc.getBoolPref(name); |
|
66 |
|
67 case Ci.nsIPrefBranch.PREF_INVALID: |
|
68 return defaultValue; |
|
69 |
|
70 default: |
|
71 // This should never happen. |
|
72 throw new Error("Error getting pref " + name + |
|
73 "; its value's type is " + |
|
74 prefSvc.getPrefType(name) + |
|
75 ", which I don't know " + |
|
76 "how to handle."); |
|
77 } |
|
78 } |
|
79 exports.get = get; |
|
80 |
|
81 function set(name, value) { |
|
82 var prefType; |
|
83 if (typeof value != "undefined" && value != null) |
|
84 prefType = value.constructor.name; |
|
85 |
|
86 switch (prefType) { |
|
87 case "String": |
|
88 { |
|
89 var string = Cc["@mozilla.org/supports-string;1"]. |
|
90 createInstance(Ci.nsISupportsString); |
|
91 string.data = value; |
|
92 prefSvc.setComplexValue(name, Ci.nsISupportsString, string); |
|
93 } |
|
94 break; |
|
95 |
|
96 case "Number": |
|
97 // We throw if the number is outside the range or not an integer, since |
|
98 // the result will not be what the consumer wanted to store. |
|
99 if (value > MAX_INT || value < MIN_INT) |
|
100 throw new Error("you cannot set the " + name + |
|
101 " pref to the number " + value + |
|
102 ", as number pref values must be in the signed " + |
|
103 "32-bit integer range -(2^31) to 2^31-1. " + |
|
104 "To store numbers outside that range, store " + |
|
105 "them as strings."); |
|
106 if (value % 1 != 0) |
|
107 throw new Error("cannot store non-integer number: " + value); |
|
108 prefSvc.setIntPref(name, value); |
|
109 break; |
|
110 |
|
111 case "Boolean": |
|
112 prefSvc.setBoolPref(name, value); |
|
113 break; |
|
114 |
|
115 default: |
|
116 throw new Error("can't set pref " + name + " to value '" + value + |
|
117 "'; it isn't a string, integer, or boolean"); |
|
118 } |
|
119 } |
|
120 exports.set = set; |
|
121 |
|
122 function has(name) { |
|
123 return (prefSvc.getPrefType(name) != Ci.nsIPrefBranch.PREF_INVALID); |
|
124 } |
|
125 exports.has = has; |
|
126 |
|
127 function keys(root) { |
|
128 return prefSvc.getChildList(root); |
|
129 } |
|
130 exports.keys = keys; |
|
131 |
|
132 function isSet(name) { |
|
133 return (has(name) && prefSvc.prefHasUserValue(name)); |
|
134 } |
|
135 exports.isSet = isSet; |
|
136 |
|
137 function reset(name) { |
|
138 try { |
|
139 prefSvc.clearUserPref(name); |
|
140 } |
|
141 catch (e) { |
|
142 // The pref service throws NS_ERROR_UNEXPECTED when the caller tries |
|
143 // to reset a pref that doesn't exist or is already set to its default |
|
144 // value. This interface fails silently in those cases, so callers |
|
145 // can unconditionally reset a pref without having to check if it needs |
|
146 // resetting first or trap exceptions after the fact. It passes through |
|
147 // other exceptions, however, so callers know about them, since we don't |
|
148 // know what other exceptions might be thrown and what they might mean. |
|
149 if (e.result != Cr.NS_ERROR_UNEXPECTED) { |
|
150 throw e; |
|
151 } |
|
152 } |
|
153 } |
|
154 exports.reset = reset; |
|
155 |
|
156 function getLocalized(name, defaultValue) { |
|
157 let value = null; |
|
158 try { |
|
159 value = prefSvc.getComplexValue(name, Ci.nsIPrefLocalizedString).data; |
|
160 } |
|
161 finally { |
|
162 return value || defaultValue; |
|
163 } |
|
164 } |
|
165 exports.getLocalized = getLocalized; |
|
166 |
|
167 function setLocalized(name, value) { |
|
168 // We can't use `prefs.set` here as we have to use `getDefaultBranch` |
|
169 // (instead of `getBranch`) in order to have `mIsDefault` set to true, here: |
|
170 // http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/nsPrefBranch.cpp#233 |
|
171 // Otherwise, we do not enter into this expected condition: |
|
172 // http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/nsPrefBranch.cpp#244 |
|
173 defaultBranch.setCharPref(name, value); |
|
174 } |
|
175 exports.setLocalized = setLocalized; |
|
176 |
|
177 exports.Branch = Branch; |
|
178 |