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 {HTMLSpanElement} 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 /* 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 this.controlledBy = 62 !this.value || String(event.value.value) == this.value ? 63 event.value.controlledBy : null; 64 } else if (event.value.recommendedValue != undefined) { 65 this.controlledBy = 66 !this.value || String(event.value.recommendedValue) == this.value ? 67 'hasRecommendation' : null; 68 } else { 69 this.controlledBy = null; 70 } 71 }, 72 73 /** 74 * Open or close a bubble with further information about the pref. 75 * @private 76 */ 77 toggleBubble_: function() { 78 if (this.showingBubble) { 79 OptionsPage.hideBubble(); 80 } else { 81 var self = this; 82 83 // Construct the bubble text. 84 if (this.hasAttribute('plural')) { 85 var defaultStrings = { 86 'policy': loadTimeData.getString('controlledSettingsPolicy'), 87 'extension': loadTimeData.getString('controlledSettingsExtension'), 88 }; 89 } else { 90 var defaultStrings = { 91 'policy': loadTimeData.getString('controlledSettingPolicy'), 92 'extension': loadTimeData.getString('controlledSettingExtension'), 93 'recommended': 94 loadTimeData.getString('controlledSettingRecommended'), 95 'hasRecommendation': 96 loadTimeData.getString('controlledSettingHasRecommendation'), 97 }; 98 } 99 100 // No controller, no bubble. 101 if (!this.controlledBy || !(this.controlledBy in defaultStrings)) 102 return; 103 104 var text = defaultStrings[this.controlledBy]; 105 106 // Apply text overrides. 107 if (this.hasAttribute('text' + this.controlledBy)) 108 text = this.getAttribute('text' + this.controlledBy); 109 110 // Create the DOM tree. 111 var content = document.createElement('div'); 112 content.className = 'controlled-setting-bubble-content'; 113 content.setAttribute('controlled-by', this.controlledBy); 114 content.textContent = text; 115 116 if (this.controlledBy == 'hasRecommendation' && this.resetHandler_ && 117 !this.readOnly) { 118 var container = document.createElement('div'); 119 var action = document.createElement('button'); 120 action.classList.add('link-button'); 121 action.classList.add('controlled-setting-bubble-action'); 122 action.textContent = 123 loadTimeData.getString('controlledSettingFollowRecommendation'); 124 action.addEventListener('click', function(event) { 125 self.resetHandler_(); 126 }); 127 container.appendChild(action); 128 content.appendChild(container); 129 } 130 131 OptionsPage.showBubble(content, this.image, this, this.location); 132 } 133 }, 134 }; 135 136 /** 137 * The name of the associated preference. 138 * @type {string} 139 */ 140 cr.defineProperty(ControlledSettingIndicator, 'pref', cr.PropertyKind.ATTR); 141 142 /** 143 * Whether this indicator is part of a dialog. If so, changes made to the 144 * associated preference take effect in the settings UI immediately but are 145 * only actually committed when the user confirms the dialog. If the user 146 * cancels the dialog instead, the changes are rolled back in the settings UI 147 * and never committed. 148 * @type {boolean} 149 */ 150 cr.defineProperty(ControlledSettingIndicator, 'dialogPref', 151 cr.PropertyKind.BOOL_ATTR); 152 153 /** 154 * The value of the associated preference that the indicator represents. If 155 * this is not set, the indicator will be visible whenever any value is 156 * enforced or recommended. If it is set, the indicator will be visible only 157 * when the enforced or recommended value matches the value it represents. 158 * This allows multiple indicators to be created for a set of radio buttons, 159 * ensuring that only one of them is visible at a time. 160 */ 161 cr.defineProperty(ControlledSettingIndicator, 'value', 162 cr.PropertyKind.ATTR); 163 164 /** 165 * The status of the associated preference: 166 * - 'policy': A specific value is enfoced by policy. 167 * - 'extension': A specific value is enforced by an extension. 168 * - 'recommended': A value is recommended by policy. The user could 169 * override this recommendation but has not done so. 170 * - 'hasRecommendation': A value is recommended by policy. The user has 171 * overridden this recommendation. 172 * - unset: The value is controlled by the user alone. 173 * @type {string} 174 */ 175 cr.defineProperty(ControlledSettingIndicator, 'controlledBy', 176 cr.PropertyKind.ATTR); 177 178 // Export. 179 return { 180 ControlledSettingIndicator: ControlledSettingIndicator 181 }; 182 }); 183