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;
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.
13 * @extends {HTMLSpanElement}
15 var ControlledSettingIndicator = cr.ui.define('span');
17 ControlledSettingIndicator.prototype = {
18 __proto__: cr.ui.BubbleButton.prototype,
21 * Decorates the base element to show the proper icon.
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.
30 Preferences.getInstance().addEventListener(
31 this.pref, this.handlePrefChange.bind(this));
32 this.resetHandler = this.clearAssociatedPref_;
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.
42 set resetHandler(handler) {
43 this.resetHandler_ = handler;
47 * Clears the preference associated with this indicator.
50 clearAssociatedPref_: function() {
51 Preferences.clearPref(this.pref, !this.dialogPref);
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.
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;
73 this.extensionId = event.value.extension.id;
74 this.extensionIcon = event.value.extension.icon;
75 this.extensionName = event.value.extension.name;
79 this.controlledBy = null;
81 } else if (event.value.recommendedValue != undefined) {
83 !this.value || String(event.value.recommendedValue) == this.value ?
84 'hasRecommendation' : null;
86 this.controlledBy = null;
91 * Open or close a bubble with further information about the pref.
94 toggleBubble_: function() {
95 if (this.showingBubble) {
96 OptionsPage.hideBubble();
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'),
109 var defaultStrings = {
110 'policy': loadTimeData.getString('controlledSettingPolicy'),
111 'extension': loadTimeData.getString('controlledSettingExtension'),
112 'extensionWithName': loadTimeData.getString(
113 'controlledSettingExtensionWithName'),
115 loadTimeData.getString('controlledSettingRecommended'),
117 loadTimeData.getString('controlledSettingHasRecommendation'),
120 defaultStrings.owner =
121 loadTimeData.getString('controlledSettingOwner');
125 // No controller, no bubble.
126 if (!this.controlledBy || !(this.controlledBy in defaultStrings))
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_ &&
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');
148 loadTimeData.getString('controlledSettingFollowRecommendation');
149 action.addEventListener('click', function(event) {
150 self.resetHandler_();
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').
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'});
175 var disableButton = extensionContainer.querySelector('button');
176 var extensionId = this.extensionId;
177 disableButton.onclick = function() {
178 chrome.send('disableExtension', [extensionId]);
180 content.appendChild(extensionContainer);
183 OptionsPage.showBubble(content, this.image, this, this.location);
189 * The name of the associated preference.
192 cr.defineProperty(ControlledSettingIndicator, 'pref', cr.PropertyKind.ATTR);
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.
202 cr.defineProperty(ControlledSettingIndicator, 'dialogPref',
203 cr.PropertyKind.BOOL_ATTR);
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.
213 cr.defineProperty(ControlledSettingIndicator, 'value',
214 cr.PropertyKind.ATTR);
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.
227 cr.defineProperty(ControlledSettingIndicator, 'controlledBy',
228 cr.PropertyKind.ATTR);
232 ControlledSettingIndicator: ControlledSettingIndicator