Home | History | Annotate | Download | only in options
      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