Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / resources / options / controlled_setting.js
blobbbf1de8fe945636401800ceaaf6ce4f3ed889665
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.
5 cr.define('options', function() {
6   var Preferences = options.Preferences;
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 {HTMLSpanElement}
14    */
15   var ControlledSettingIndicator = cr.ui.define('span');
17   ControlledSettingIndicator.prototype = {
18     __proto__: cr.ui.BubbleButton.prototype,
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');
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     },
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     },
46     /**
47      * Clears the preference associated with this indicator.
48      * @private
49      */
50     clearAssociatedPref_: function() {
51       Preferences.clearPref(this.pref, !this.dialogPref);
52     },
54     /* Handle changes to the associated pref by hiding any currently visible
55      * bubble and updating the controlledBy property.
56      * @param {Event} event Pref change event.
57      */
58     handlePrefChange: function(event) {
59       OptionsPage.hideBubble();
60       if (event.value.controlledBy) {
61         if (!this.value || String(event.value.value) == this.value) {
62           this.controlledBy = event.value.controlledBy;
63           if (event.value.extension) {
64             if (this.pref == 'session.restore_on_startup' ||
65                 this.pref == 'homepage_is_newtabpage') {
66               // Special case for the restore on startup, which is implied
67               // by the startup pages settings being controlled by an
68               // extension, and same for the home page as NTP, so we don't want
69               // to show two buttons in these cases.
70               // TODO(mad): Find a better way to handle this.
71               this.controlledBy = null;
72             } else {
73               this.extensionId = event.value.extension.id;
74               this.extensionIcon = event.value.extension.icon;
75               this.extensionName = event.value.extension.name;
76             }
77           }
78         } else {
79           this.controlledBy = null;
80         }
81       } else if (event.value.recommendedValue != undefined) {
82         this.controlledBy =
83             !this.value || String(event.value.recommendedValue) == this.value ?
84             'hasRecommendation' : null;
85       } else {
86         this.controlledBy = null;
87       }
88     },
90     /**
91      * Open or close a bubble with further information about the pref.
92      * @private
93      */
94     toggleBubble_: function() {
95       if (this.showingBubble) {
96         OptionsPage.hideBubble();
97       } else {
98         var self = this;
100         // Construct the bubble text.
101         if (this.hasAttribute('plural')) {
102           var defaultStrings = {
103             'policy': loadTimeData.getString('controlledSettingsPolicy'),
104             'extension': loadTimeData.getString('controlledSettingsExtension'),
105             'extensionWithName': loadTimeData.getString(
106                 'controlledSettingsExtensionWithName'),
107           };
108         } else {
109           var defaultStrings = {
110             'policy': loadTimeData.getString('controlledSettingPolicy'),
111             'extension': loadTimeData.getString('controlledSettingExtension'),
112             'extensionWithName': loadTimeData.getString(
113                 'controlledSettingExtensionWithName'),
114             'recommended':
115                 loadTimeData.getString('controlledSettingRecommended'),
116             'hasRecommendation':
117                 loadTimeData.getString('controlledSettingHasRecommendation'),
118           };
119           if (cr.isChromeOS) {
120             defaultStrings.owner =
121                 loadTimeData.getString('controlledSettingOwner');
122           }
123         }
125         // No controller, no bubble.
126         if (!this.controlledBy || !(this.controlledBy in defaultStrings))
127           return;
129         var text = defaultStrings[this.controlledBy];
130         if (this.controlledBy == 'extension' && this.extensionName)
131           text = defaultStrings.extensionWithName;
133         // Apply text overrides.
134         if (this.hasAttribute('text' + this.controlledBy))
135           text = this.getAttribute('text' + this.controlledBy);
137         // Create the DOM tree.
138         var content = document.createElement('div');
139         content.textContent = text;
141         if (this.controlledBy == 'hasRecommendation' && this.resetHandler_ &&
142             !this.readOnly) {
143           var container = document.createElement('div');
144           var action = document.createElement('button');
145           action.classList.add('link-button');
146           action.classList.add('controlled-setting-bubble-action');
147           action.textContent =
148               loadTimeData.getString('controlledSettingFollowRecommendation');
149           action.addEventListener('click', function(event) {
150             self.resetHandler_();
151           });
152           container.appendChild(action);
153           content.appendChild(container);
154         } else if (this.controlledBy == 'extension' && this.extensionName) {
155           var extensionContainer =
156               $('extension-controlled-settings-bubble-template').
157                   cloneNode(true);
158           // No need for an id anymore, and thus remove to avoid id collision.
159           extensionContainer.removeAttribute('id');
160           extensionContainer.hidden = false;
162           var extensionName = extensionContainer.querySelector(
163               '.controlled-setting-bubble-extension-name');
164           extensionName.textContent = this.extensionName;
165           extensionName.style.backgroundImage =
166               'url("' + this.extensionIcon + '")';
168           var manageLink = extensionContainer.querySelector(
169               '.controlled-setting-bubble-extension-manage-link');
170           manageLink.onclick = function() {
171             uber.invokeMethodOnWindow(
172                 window.top, 'showPage', {pageId: 'extensions'});
173           };
175           var disableButton = extensionContainer.querySelector('button');
176           var extensionId = this.extensionId;
177           disableButton.onclick = function() {
178             chrome.send('disableExtension', [extensionId]);
179           };
180           content.appendChild(extensionContainer);
181         }
183         OptionsPage.showBubble(content, this.image, this, this.location);
184       }
185     },
186   };
188   /**
189    * The name of the associated preference.
190    * @type {string}
191    */
192   cr.defineProperty(ControlledSettingIndicator, 'pref', cr.PropertyKind.ATTR);
194   /**
195    * Whether this indicator is part of a dialog. If so, changes made to the
196    * associated preference take effect in the settings UI immediately but are
197    * only actually committed when the user confirms the dialog. If the user
198    * cancels the dialog instead, the changes are rolled back in the settings UI
199    * and never committed.
200    * @type {boolean}
201    */
202   cr.defineProperty(ControlledSettingIndicator, 'dialogPref',
203                     cr.PropertyKind.BOOL_ATTR);
205   /**
206    * The value of the associated preference that the indicator represents. If
207    * this is not set, the indicator will be visible whenever any value is
208    * enforced or recommended. If it is set, the indicator will be visible only
209    * when the enforced or recommended value matches the value it represents.
210    * This allows multiple indicators to be created for a set of radio buttons,
211    * ensuring that only one of them is visible at a time.
212    */
213   cr.defineProperty(ControlledSettingIndicator, 'value',
214                     cr.PropertyKind.ATTR);
216   /**
217    * The status of the associated preference:
218    * - 'policy':            A specific value is enfoced by policy.
219    * - 'extension':         A specific value is enforced by an extension.
220    * - 'recommended':       A value is recommended by policy. The user could
221    *                        override this recommendation but has not done so.
222    * - 'hasRecommendation': A value is recommended by policy. The user has
223    *                        overridden this recommendation.
224    * - unset:               The value is controlled by the user alone.
225    * @type {string}
226    */
227   cr.defineProperty(ControlledSettingIndicator, 'controlledBy',
228                     cr.PropertyKind.ATTR);
230   // Export.
231   return {
232     ControlledSettingIndicator: ControlledSettingIndicator
233   };