1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 cr.define('options', function() { 6 7 ///////////////////////////////////////////////////////////////////////////// 8 // Preferences class: 9 10 /** 11 * Preferences class manages access to Chrome profile preferences. 12 * @constructor 13 * @extends {cr.EventTarget} 14 */ 15 function Preferences() { 16 // Map of registered preferences. 17 this.registeredPreferences_ = {}; 18 } 19 20 cr.addSingletonGetter(Preferences); 21 22 /** 23 * Sets a Boolean preference and signals its new value. 24 * @param {string} name Preference name. 25 * @param {boolean} value New preference value. 26 * @param {boolean} commit Whether to commit the change to Chrome. 27 * @param {string=} opt_metric User metrics identifier. 28 */ 29 Preferences.setBooleanPref = function(name, value, commit, opt_metric) { 30 if (!commit) { 31 Preferences.getInstance().setPrefNoCommit_(name, 'bool', Boolean(value)); 32 return; 33 } 34 35 var argumentList = [name, Boolean(value)]; 36 if (opt_metric != undefined) argumentList.push(opt_metric); 37 chrome.send('setBooleanPref', argumentList); 38 }; 39 40 /** 41 * Sets an integer preference and signals its new value. 42 * @param {string} name Preference name. 43 * @param {number} value New preference value. 44 * @param {boolean} commit Whether to commit the change to Chrome. 45 * @param {string} metric User metrics identifier. 46 */ 47 Preferences.setIntegerPref = function(name, value, commit, metric) { 48 if (!commit) { 49 Preferences.getInstance().setPrefNoCommit_(name, 'int', Number(value)); 50 return; 51 } 52 53 var argumentList = [name, Number(value)]; 54 if (metric != undefined) argumentList.push(metric); 55 chrome.send('setIntegerPref', argumentList); 56 }; 57 58 /** 59 * Sets a double-valued preference and signals its new value. 60 * @param {string} name Preference name. 61 * @param {number} value New preference value. 62 * @param {boolean} commit Whether to commit the change to Chrome. 63 * @param {string} metric User metrics identifier. 64 */ 65 Preferences.setDoublePref = function(name, value, commit, metric) { 66 if (!commit) { 67 Preferences.getInstance().setPrefNoCommit_(name, 'double', Number(value)); 68 return; 69 } 70 71 var argumentList = [name, Number(value)]; 72 if (metric != undefined) argumentList.push(metric); 73 chrome.send('setDoublePref', argumentList); 74 }; 75 76 /** 77 * Sets a string preference and signals its new value. 78 * @param {string} name Preference name. 79 * @param {string} value New preference value. 80 * @param {boolean} commit Whether to commit the change to Chrome. 81 * @param {string} metric User metrics identifier. 82 */ 83 Preferences.setStringPref = function(name, value, commit, metric) { 84 if (!commit) { 85 Preferences.getInstance().setPrefNoCommit_(name, 'string', String(value)); 86 return; 87 } 88 89 var argumentList = [name, String(value)]; 90 if (metric != undefined) argumentList.push(metric); 91 chrome.send('setStringPref', argumentList); 92 }; 93 94 /** 95 * Sets a string preference that represents a URL and signals its new value. 96 * The value will be fixed to be a valid URL when it gets committed to Chrome. 97 * @param {string} name Preference name. 98 * @param {string} value New preference value. 99 * @param {boolean} commit Whether to commit the change to Chrome. 100 * @param {string} metric User metrics identifier. 101 */ 102 Preferences.setURLPref = function(name, value, commit, metric) { 103 if (!commit) { 104 Preferences.getInstance().setPrefNoCommit_(name, 'url', String(value)); 105 return; 106 } 107 108 var argumentList = [name, String(value)]; 109 if (metric != undefined) argumentList.push(metric); 110 chrome.send('setURLPref', argumentList); 111 }; 112 113 /** 114 * Sets a JSON list preference and signals its new value. 115 * @param {string} name Preference name. 116 * @param {Array} value New preference value. 117 * @param {boolean} commit Whether to commit the change to Chrome. 118 * @param {string} metric User metrics identifier. 119 */ 120 Preferences.setListPref = function(name, value, commit, metric) { 121 if (!commit) { 122 Preferences.getInstance().setPrefNoCommit_(name, 'list', value); 123 return; 124 } 125 126 var argumentList = [name, JSON.stringify(value)]; 127 if (metric != undefined) argumentList.push(metric); 128 chrome.send('setListPref', argumentList); 129 }; 130 131 /** 132 * Clears the user setting for a preference and signals its new effective 133 * value. 134 * @param {string} name Preference name. 135 * @param {boolean} commit Whether to commit the change to Chrome. 136 * @param {string=} opt_metric User metrics identifier. 137 */ 138 Preferences.clearPref = function(name, commit, opt_metric) { 139 if (!commit) { 140 Preferences.getInstance().clearPrefNoCommit_(name); 141 return; 142 } 143 144 var argumentList = [name]; 145 if (opt_metric != undefined) argumentList.push(opt_metric); 146 chrome.send('clearPref', argumentList); 147 }; 148 149 Preferences.prototype = { 150 __proto__: cr.EventTarget.prototype, 151 152 /** 153 * Adds an event listener to the target. 154 * @param {string} type The name of the event. 155 * @param {!Function|{handleEvent:Function}} handler The handler for the 156 * event. This is called when the event is dispatched. 157 */ 158 addEventListener: function(type, handler) { 159 cr.EventTarget.prototype.addEventListener.call(this, type, handler); 160 if (!(type in this.registeredPreferences_)) 161 this.registeredPreferences_[type] = {}; 162 }, 163 164 /** 165 * Initializes preference reading and change notifications. 166 */ 167 initialize: function() { 168 var params1 = ['Preferences.prefsFetchedCallback']; 169 var params2 = ['Preferences.prefsChangedCallback']; 170 for (var prefName in this.registeredPreferences_) { 171 params1.push(prefName); 172 params2.push(prefName); 173 } 174 chrome.send('fetchPrefs', params1); 175 chrome.send('observePrefs', params2); 176 }, 177 178 /** 179 * Helper function for flattening of dictionary passed via fetchPrefs 180 * callback. 181 * @param {string} prefix Preference name prefix. 182 * @param {Object} dict Map with preference values. 183 * @private 184 */ 185 flattenMapAndDispatchEvent_: function(prefix, dict) { 186 for (var prefName in dict) { 187 var value = dict[prefName]; 188 if (typeof value == 'object' && 189 !this.registeredPreferences_[prefix + prefName]) { 190 this.flattenMapAndDispatchEvent_(prefix + prefName + '.', value); 191 } else if (value) { 192 var event = new Event(prefix + prefName); 193 this.registeredPreferences_[prefix + prefName].orig = value; 194 event.value = value; 195 this.dispatchEvent(event); 196 } 197 } 198 }, 199 200 /** 201 * Sets a preference and signals its new value. The change is propagated 202 * throughout the UI code but is not committed to Chrome yet. The new value 203 * and its data type are stored so that commitPref() can later be used to 204 * invoke the appropriate set*Pref() method and actually commit the change. 205 * @param {string} name Preference name. 206 * @param {string} type Preference data type. 207 * @param {*} value New preference value. 208 * @private 209 */ 210 setPrefNoCommit_: function(name, type, value) { 211 var pref = this.registeredPreferences_[name]; 212 pref.action = 'set'; 213 pref.type = type; 214 pref.value = value; 215 216 var event = new Event(name); 217 // Decorate pref value as CoreOptionsHandler::CreateValueForPref() does. 218 event.value = {value: value, uncommitted: true}; 219 if (pref.orig) { 220 event.value.recommendedValue = pref.orig.recommendedValue; 221 event.value.disabled = pref.orig.disabled; 222 } 223 this.dispatchEvent(event); 224 }, 225 226 /** 227 * Clears a preference and signals its new value. The change is propagated 228 * throughout the UI code but is not committed to Chrome yet. 229 * @param {string} name Preference name. 230 * @private 231 */ 232 clearPrefNoCommit_: function(name) { 233 var pref = this.registeredPreferences_[name]; 234 pref.action = 'clear'; 235 delete pref.type; 236 delete pref.value; 237 238 var event = new Event(name); 239 // Decorate pref value as CoreOptionsHandler::CreateValueForPref() does. 240 event.value = {controlledBy: 'recommended', uncommitted: true}; 241 if (pref.orig) { 242 event.value.value = pref.orig.recommendedValue; 243 event.value.recommendedValue = pref.orig.recommendedValue; 244 event.value.disabled = pref.orig.disabled; 245 } 246 this.dispatchEvent(event); 247 }, 248 249 /** 250 * Commits a preference change to Chrome and signals the new preference 251 * value. Does nothing if there is no uncommitted change. 252 * @param {string} name Preference name. 253 * @param {string} metric User metrics identifier. 254 */ 255 commitPref: function(name, metric) { 256 var pref = this.registeredPreferences_[name]; 257 switch (pref.action) { 258 case 'set': 259 switch (pref.type) { 260 case 'bool': 261 Preferences.setBooleanPref(name, pref.value, true, metric); 262 break; 263 case 'int': 264 Preferences.setIntegerPref(name, pref.value, true, metric); 265 break; 266 case 'double': 267 Preferences.setDoublePref(name, pref.value, true, metric); 268 break; 269 case 'string': 270 Preferences.setStringPref(name, pref.value, true, metric); 271 break; 272 case 'url': 273 Preferences.setURLPref(name, pref.value, true, metric); 274 break; 275 case 'list': 276 Preferences.setListPref(name, pref.value, true, metric); 277 break; 278 } 279 break; 280 case 'clear': 281 Preferences.clearPref(name, true, metric); 282 break; 283 } 284 delete pref.action; 285 delete pref.type; 286 delete pref.value; 287 }, 288 289 /** 290 * Rolls back a preference change and signals the original preference value. 291 * Does nothing if there is no uncommitted change. 292 * @param {string} name Preference name. 293 */ 294 rollbackPref: function(name) { 295 var pref = this.registeredPreferences_[name]; 296 if (!pref.action) 297 return; 298 299 delete pref.action; 300 delete pref.type; 301 delete pref.value; 302 303 var event = new Event(name); 304 event.value = pref.orig || {}; 305 event.value.uncommitted = true; 306 this.dispatchEvent(event); 307 } 308 }; 309 310 /** 311 * Callback for fetchPrefs method. 312 * @param {Object} dict Map of fetched property values. 313 */ 314 Preferences.prefsFetchedCallback = function(dict) { 315 Preferences.getInstance().flattenMapAndDispatchEvent_('', dict); 316 }; 317 318 /** 319 * Callback for observePrefs method. 320 * @param {Array} notification An array defining changed preference values. 321 * notification[0] contains name of the change preference while its new 322 * value is stored in notification[1]. 323 */ 324 Preferences.prefsChangedCallback = function(notification) { 325 var event = new Event(notification[0]); 326 event.value = notification[1]; 327 var prefs = Preferences.getInstance(); 328 prefs.registeredPreferences_[notification[0]] = {orig: notification[1]}; 329 if (event.value) 330 prefs.dispatchEvent(event); 331 }; 332 333 // Export 334 return { 335 Preferences: Preferences 336 }; 337 338 }); 339