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