Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: chrome/browser/resources/options/controlled_setting.js

Issue 10907148: Implement popup bubbles for the controlled setting indicator (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: All comments addressed. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 cr.define('options', function() { 5 cr.define('options', function() {
6 var Preferences = options.Preferences; 6 var Preferences = options.Preferences;
7 7
8 /** 8 /**
9 * A controlled setting indicator that can be placed on a setting as an 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 10 * indicator that the value is controlled by some external entity such as
11 * policy or an extension. 11 * policy or an extension.
12 * @constructor 12 * @constructor
13 * @extends {HTMLSpanElement} 13 * @extends {HTMLSpanElement}
14 */ 14 */
15 var ControlledSettingIndicator = cr.ui.define('span'); 15 var ControlledSettingIndicator = cr.ui.define('span');
16 16
17 ControlledSettingIndicator.prototype = { 17 ControlledSettingIndicator.prototype = {
18 __proto__: HTMLSpanElement.prototype, 18 __proto__: HTMLSpanElement.prototype,
19 19
20 /** 20 /**
21 * Decorates the base element to show the proper icon. 21 * Decorates the base element to show the proper icon.
22 */ 22 */
23 decorate: function() { 23 decorate: function() {
24 var self = this; 24 var self = this;
25 var doc = self.ownerDocument;
26
27 // Create the details and summary elements.
28 var detailsContainer = doc.createElement('details');
29 detailsContainer.appendChild(doc.createElement('summary'));
30
31 // This should really create a div element, but that breaks :hover. See
32 // https://bugs.webkit.org/show_bug.cgi?id=72957
33 var bubbleContainer = doc.createElement('p');
34 bubbleContainer.className = 'controlled-setting-bubble';
35 detailsContainer.appendChild(bubbleContainer);
36
37 self.appendChild(detailsContainer);
38 self.addEventListener('click', self.show_);
39 25
40 // If there is a pref, track its controlledBy property in order to be able 26 // If there is a pref, track its controlledBy property in order to be able
41 // to bring up the correct bubble. 27 // to bring up the correct bubble.
42 if (this.hasAttribute('pref')) { 28 if (this.pref) {
43 Preferences.getInstance().addEventListener( 29 Preferences.getInstance().addEventListener(this.pref,
44 this.getAttribute('pref'),
45 function(event) { 30 function(event) {
46 if (event.value) { 31 var controlledBy = event.value.controlledBy;
47 var controlledBy = event.value.controlledBy; 32 self.controlledBy = controlledBy ? controlledBy : null;
48 self.controlledBy = controlledBy ? controlledBy : null; 33 OptionsPage.hideBubble();
49 }
50 }); 34 });
35 this.resetHandler = this.clearAssociatedPref_;
36 }
51 37
52 self.resetHandler(self.clearAssociatedPref_); 38 this.tabIndex = 0;
53 } 39 this.setAttribute('role', 'button');
54 }, 40 this.addEventListener('click', this);
55 41 this.addEventListener('keydown', this);
56 42 this.addEventListener('mousedown', this);
57 /**
58 * Closes the bubble.
59 */
60 close: function() {
61 this.querySelector('details').removeAttribute('open');
62 this.ownerDocument.removeEventListener('click', this.closeHandler_, true);
63 }, 43 },
64 44
65 /** 45 /**
66 * The given handler will be called when the user clicks on the 'reset to 46 * The given handler will be called when the user clicks on the 'reset to
67 * recommended value' link shown in the indicator bubble. 47 * recommended value' link shown in the indicator bubble.
68 * @param {function()} handler The handler to be called. 48 * @param {function()} handler The handler to be called.
69 */ 49 */
70 set resetHandler(handler) { 50 set resetHandler(handler) {
71 this.resetHandler_ = handler; 51 this.resetHandler_ = handler;
72 }, 52 },
73 53
74 /** 54 /**
55 * Whether the indicator is currently showing a bubble.
56 * @type {boolean}
57 */
58 get showingBubble() {
59 return !!this.showingBubble_;
60 },
61 set showingBubble(showing) {
62 if (showing)
63 this.classList.add('showing-bubble');
64 else
65 this.classList.remove('showing-bubble');
66 this.showingBubble_ = showing;
67 },
68
69 /**
75 * Clears the preference associated with this indicator. 70 * Clears the preference associated with this indicator.
76 * @private 71 * @private
77 */ 72 */
78 clearAssociatedPref_: function() { 73 clearAssociatedPref_: function() {
79 Preferences.clearPref(this.getAttribute('pref'), this.dialogPref); 74 Preferences.clearPref(this.pref, this.dialogPref);
80 }, 75 },
81 76
82 /** 77 /**
83 * Constructs the bubble DOM tree and shows it. 78 * Handle mouse and keyboard events, allowing the user to open and close a
79 * bubble with further information.
80 * @param {Event} event Mouse or keyboard event.
81 */
82 handleEvent: function(event) {
83 switch (event.type) {
84 // Toggle the bubble on left click. Let any other clicks propagate.
85 case 'click':
86 if (event.button != 0)
87 return;
88 break;
89 // Toggle the bubble when <Return> or <Space> is pressed. Let any other
90 // key presses propagate.
91 case 'keydown':
92 switch (event.keyCode) {
93 case 13: // Return.
94 case 32: // Space.
95 break;
96 default:
97 return;
98 }
99 break;
100 // Blur focus when a mouse button is pressed, matching the behavior of
101 // other Web UI elements.
102 case 'mousedown':
103 if (document.activeElement)
104 document.activeElement.blur();
105 event.preventDefault();
106 return;
107 }
108 this.toggleBubble_();
109 event.preventDefault();
110 event.stopPropagation();
111 },
112
113 /**
114 * Open or close a bubble with further information about the pref.
84 * @private 115 * @private
85 */ 116 */
86 show_: function() { 117 toggleBubble_: function() {
87 var self = this; 118 if (this.showingBubble) {
88 var doc = self.ownerDocument; 119 OptionsPage.hideBubble();
120 } else {
121 var self = this;
89 122
90 // Clear out the old bubble contents. 123 // Work out the popup text.
91 var bubbleContainer = this.querySelector('.controlled-setting-bubble'); 124 defaultStrings = {
92 if (bubbleContainer) { 125 'policy': loadTimeData.getString('controlledSettingPolicy'),
93 while (bubbleContainer.hasChildNodes()) 126 'extension': loadTimeData.getString('controlledSettingExtension'),
94 bubbleContainer.removeChild(bubbleContainer.lastChild); 127 'recommended': loadTimeData.getString('controlledSettingRecommended'),
128 };
129
130 // No controller, no popup.
131 if (!this.controlledBy || !(this.controlledBy in defaultStrings))
132 return;
133
134 var text = defaultStrings[this.controlledBy];
135
136 // Apply text overrides.
137 if (this.hasAttribute('text' + this.controlledBy))
138 text = this.getAttribute('text' + this.controlledBy);
139
140 // Create the DOM tree.
141 var content = document.createElement('div');
142 content.className = 'controlled-setting-bubble-content';
143 content.setAttribute('controlled-by', this.controlledBy);
144 content.textContent = text;
145
146 if (this.controlledBy == 'recommended' && this.resetHandler_) {
147 var container = document.createElement('div');
148 var action = document.createElement('button');
149 action.classList.add('link-button');
150 action.classList.add('controlled-setting-bubble-action');
151 action.textContent =
152 loadTimeData.getString('controlledSettingApplyRecommendation');
153 action.addEventListener('click', function(event) {
154 self.resetHandler_();
155 });
156 container.appendChild(action);
157 content.appendChild(container);
158 }
159
160 OptionsPage.showBubble(content, this);
95 } 161 }
96 162 },
97 // Work out the bubble text.
98 defaultStrings = {
99 policy: loadTimeData.getString('controlledSettingPolicy'),
100 extension: loadTimeData.getString('controlledSettingExtension'),
101 recommended: loadTimeData.getString('controlledSettingRecommended'),
102 };
103
104 // No controller, no bubble.
105 if (!self.controlledBy || !self.controlledBy in defaultStrings)
106 return;
107
108 var text = defaultStrings[self.controlledBy];
109
110 // Apply text overrides.
111 if (self.hasAttribute('text' + self.controlledBy))
112 text = self.getAttribute('text' + self.controlledBy);
113
114 // Create the DOM tree.
115 var bubbleText = doc.createElement('p');
116 bubbleText.className = 'controlled-setting-bubble-text';
117 bubbleText.textContent = text;
118
119 if (self.controlledBy == 'recommended' && self.resetHandler_) {
120 var container = doc.createElement('div');
121 var action = doc.createElement('button');
122 action.classList.add('link-button');
123 action.classList.add('controlled-setting-bubble-action');
124 action.textContent =
125 loadTimeData.getString('controlledSettingApplyRecommendation');
126 action.addEventListener(
127 'click',
128 function(event) { self.resetHandler_(); });
129 container.appendChild(action);
130 bubbleText.appendChild(container);
131 }
132
133 bubbleContainer.appendChild(bubbleText);
134
135 // One-time bubble-closing event handler.
136 self.closeHandler_ = this.close.bind(this);
137 doc.addEventListener('click', self.closeHandler_, true);
138 }
139 }; 163 };
140 164
141 /** 165 /**
142 * The controlling entity of the setting. Can take the values "policy", 166 * The name of the associated preference.
143 * "extension", "recommended" or be unset. 167 * @type {string}
144 */ 168 */
145 cr.defineProperty(ControlledSettingIndicator, 'controlledBy', 169 cr.defineProperty(ControlledSettingIndicator, 'pref', cr.PropertyKind.ATTR);
146 cr.PropertyKind.ATTR,
147 ControlledSettingIndicator.prototype.close);
148 170
149 /** 171 /**
150 * A special preference type specific to dialogs. Changes take effect in the 172 * Whether this indicator is part of a dialog. If so, changes made to the
151 * settings UI immediately but are only actually committed when the user 173 * associated preference take effect in the settings UI immediately but are
152 * confirms the dialog. If the user cancels the dialog instead, the changes 174 * only actually committed when the user confirms the dialog. If the user
153 * are rolled back in the settings UI and never committed. 175 * cancels the dialog instead, the changes are rolled back in the settings UI
176 * and never committed.
154 * @type {boolean} 177 * @type {boolean}
155 */ 178 */
156 cr.defineProperty(ControlledSettingIndicator, 'dialogPref', 179 cr.defineProperty(ControlledSettingIndicator, 'dialogPref',
157 cr.PropertyKind.BOOL_ATTR); 180 cr.PropertyKind.BOOL_ATTR);
158 181
182 /**
183 * Whether the associated preference is controlled by a source other than the
184 * user's setting (can be 'policy', 'extension', 'recommended' or unset).
185 * @type {string}
186 */
187 cr.defineProperty(ControlledSettingIndicator, 'controlledBy',
188 cr.PropertyKind.ATTR);
189
159 // Export. 190 // Export.
160 return { 191 return {
161 ControlledSettingIndicator: ControlledSettingIndicator 192 ControlledSettingIndicator: ControlledSettingIndicator
162 }; 193 };
163 }); 194 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/options/chromeos/network_list.js ('k') | chrome/browser/resources/options/options.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698