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   var Preferences = options.Preferences;
      7 
      8   /**
      9    * A controlled setting indicator that can be placed on a setting as an
     10    * indicator that the value is controlled by some external entity such as
     11    * policy or an extension.
     12    * @constructor
     13    * @extends {cr.ui.BubbleButton}
     14    */
     15   var ControlledSettingIndicator = cr.ui.define('span');
     16 
     17   ControlledSettingIndicator.prototype = {
     18     __proto__: cr.ui.BubbleButton.prototype,
     19 
     20     /**
     21      * Decorates the base element to show the proper icon.
     22      */
     23     decorate: function() {
     24       cr.ui.BubbleButton.prototype.decorate.call(this);
     25       this.classList.add('controlled-setting-indicator');
     26 
     27       // If there is a pref, track its controlledBy and recommendedValue
     28       // properties in order to be able to bring up the correct bubble.
     29       if (this.pref) {
     30         Preferences.getInstance().addEventListener(
     31             this.pref, this.handlePrefChange.bind(this));
     32         this.resetHandler = this.clearAssociatedPref_;
     33       }
     34     },
     35 
     36     /**
     37      * The given handler will be called when the user clicks on the 'reset to
     38      * recommended value' link shown in the indicator bubble. The |this| object
     39      * will be the indicator itself.
     40      * @param {function()} handler The handler to be called.
     41      */
     42     set resetHandler(handler) {
     43       this.resetHandler_ = handler;
     44     },
     45 
     46     /**
     47      * Clears the preference associated with this indicator.
     48      * @private
     49      */
     50     clearAssociatedPref_: function() {
     51       Preferences.clearPref(this.pref, !this.dialogPref);
     52     },
     53 
     54     /**
     55      * Handle changes to the associated pref by hiding any currently visible
     56      * bubble and updating the controlledBy property.
     57      * @param {Event} event Pref change event.
     58      */
     59     handlePrefChange: function(event) {
     60       PageManager.hideBubble();
     61       if (event.value.controlledBy) {
     62         if (!this.value || String(event.value.value) == this.value) {
     63           this.controlledBy = event.value.controlledBy;
     64           if (event.value.extension) {
     65             this.extensionId = event.value.extension.id;
     66             this.extensionIcon = event.value.extension.icon;
     67             this.extensionName = event.value.extension.name;
     68           }
     69         } else {
     70           this.controlledBy = null;
     71         }
     72       } else if (event.value.recommendedValue != undefined) {
     73         this.controlledBy =
     74             !this.value || String(event.value.recommendedValue) == this.value ?
     75             'hasRecommendation' : null;
     76       } else {
     77         this.controlledBy = null;
     78       }
     79     },
     80 
     81     /**
     82      * Open or close a bubble with further information about the pref.
     83      * @override
     84      */
     85     toggleBubble: function() {
     86       if (this.showingBubble) {
     87         PageManager.hideBubble();
     88       } else {
     89         var self = this;
     90 
     91         // Construct the bubble text.
     92         if (this.hasAttribute('plural')) {
     93           var defaultStrings = {
     94             'policy': loadTimeData.getString('controlledSettingsPolicy'),
     95             'extension': loadTimeData.getString('controlledSettingsExtension'),
     96             'extensionWithName': loadTimeData.getString(
     97                 'controlledSettingsExtensionWithName'),
     98           };
     99           if (cr.isChromeOS) {
    100             defaultStrings.shared =
    101                 loadTimeData.getString('controlledSettingsShared');
    102           }
    103         } else {
    104           var defaultStrings = {
    105             'policy': loadTimeData.getString('controlledSettingPolicy'),
    106             'extension': loadTimeData.getString('controlledSettingExtension'),
    107             'extensionWithName': loadTimeData.getString(
    108                 'controlledSettingExtensionWithName'),
    109             'recommended':
    110                 loadTimeData.getString('controlledSettingRecommended'),
    111             'hasRecommendation':
    112                 loadTimeData.getString('controlledSettingHasRecommendation'),
    113           };
    114           if (cr.isChromeOS) {
    115             defaultStrings.owner =
    116                 loadTimeData.getString('controlledSettingOwner');
    117             defaultStrings.shared =
    118                 loadTimeData.getString('controlledSettingShared');
    119           }
    120         }
    121 
    122         // No controller, no bubble.
    123         if (!this.controlledBy || !(this.controlledBy in defaultStrings))
    124           return;
    125 
    126         var text = defaultStrings[this.controlledBy];
    127         if (this.controlledBy == 'extension' && this.extensionName)
    128           text = defaultStrings.extensionWithName;
    129 
    130         // Apply text overrides.
    131         if (this.hasAttribute('text' + this.controlledBy))
    132           text = this.getAttribute('text' + this.controlledBy);
    133 
    134         // Create the DOM tree.
    135         var content = document.createElement('div');
    136         content.classList.add('controlled-setting-bubble-header');
    137         content.textContent = text;
    138 
    139         if (this.controlledBy == 'hasRecommendation' && this.resetHandler_ &&
    140             !this.readOnly) {
    141           var container = document.createElement('div');
    142           var action = document.createElement('button');
    143           action.classList.add('link-button');
    144           action.classList.add('controlled-setting-bubble-action');
    145           action.textContent =
    146               loadTimeData.getString('controlledSettingFollowRecommendation');
    147           action.addEventListener('click', function(event) {
    148             self.resetHandler_();
    149           });
    150           container.appendChild(action);
    151           content.appendChild(container);
    152         } else if (this.controlledBy == 'extension' && this.extensionName) {
    153           var extensionContainer =
    154               $('extension-controlled-settings-bubble-template').
    155                   cloneNode(true);
    156           // No need for an id anymore, and thus remove to avoid id collision.
    157           extensionContainer.removeAttribute('id');
    158           extensionContainer.hidden = false;
    159 
    160           var extensionName = extensionContainer.querySelector(
    161               '.controlled-setting-bubble-extension-name');
    162           extensionName.textContent = this.extensionName;
    163           extensionName.style.backgroundImage =
    164               'url("' + this.extensionIcon + '")';
    165 
    166           var manageLink = extensionContainer.querySelector(
    167               '.controlled-setting-bubble-extension-manage-link');
    168           var extensionId = this.extensionId;
    169           manageLink.onclick = function() {
    170             uber.invokeMethodOnWindow(
    171                 window.top, 'showPage', {pageId: 'extensions',
    172                                          path: '?id=' + extensionId});
    173           };
    174 
    175           var disableButton = extensionContainer.querySelector(
    176               '.controlled-setting-bubble-extension-disable-button');
    177           disableButton.onclick = function() {
    178             chrome.send('disableExtension', [extensionId]);
    179           };
    180           content.appendChild(extensionContainer);
    181         }
    182 
    183         PageManager.showBubble(content, this.image, this, this.location);
    184       }
    185     },
    186   };
    187 
    188   /**
    189    * The name of the associated preference.
    190    */
    191   cr.defineProperty(ControlledSettingIndicator, 'pref', cr.PropertyKind.ATTR);
    192 
    193   /**
    194    * Whether this indicator is part of a dialog. If so, changes made to the
    195    * associated preference take effect in the settings UI immediately but are
    196    * only actually committed when the user confirms the dialog. If the user
    197    * cancels the dialog instead, the changes are rolled back in the settings UI
    198    * and never committed.
    199    */
    200   cr.defineProperty(ControlledSettingIndicator, 'dialogPref',
    201                     cr.PropertyKind.BOOL_ATTR);
    202 
    203   /**
    204    * The value of the associated preference that the indicator represents. If
    205    * this is not set, the indicator will be visible whenever any value is
    206    * enforced or recommended. If it is set, the indicator will be visible only
    207    * when the enforced or recommended value matches the value it represents.
    208    * This allows multiple indicators to be created for a set of radio buttons,
    209    * ensuring that only one of them is visible at a time.
    210    */
    211   cr.defineProperty(ControlledSettingIndicator, 'value',
    212                     cr.PropertyKind.ATTR);
    213 
    214   /**
    215    * The status of the associated preference:
    216    * - 'policy':            A specific value is enforced by policy.
    217    * - 'extension':         A specific value is enforced by an extension.
    218    * - 'recommended':       A value is recommended by policy. The user could
    219    *                        override this recommendation but has not done so.
    220    * - 'hasRecommendation': A value is recommended by policy. The user has
    221    *                        overridden this recommendation.
    222    * - 'owner':             A value is controlled by the owner of the device
    223    *                        (Chrome OS only).
    224    * - 'shared':            A value belongs to the primary user but can be
    225    *                        modified (Chrome OS only).
    226    * - unset:               The value is controlled by the user alone.
    227    */
    228   cr.defineProperty(ControlledSettingIndicator, 'controlledBy',
    229                     cr.PropertyKind.ATTR);
    230 
    231   // Export.
    232   return {
    233     ControlledSettingIndicator: ControlledSettingIndicator
    234   };
    235 });
    236