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

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: Reimplemented on top of newly refactored BubbleBase class. 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 /**
75 * Clears the preference associated with this indicator. 55 * Clears the preference associated with this indicator.
76 * @private 56 * @private
77 */ 57 */
78 clearAssociatedPref_: function() { 58 clearAssociatedPref_: function() {
79 Preferences.clearPref(this.getAttribute('pref'), this.dialogPref); 59 Preferences.clearPref(this.pref, this.dialogPref);
80 }, 60 },
81 61
82 /** 62 /**
83 * Constructs the bubble DOM tree and shows it. 63 * Handle mouse and keyboard events, allowing the user to open and close a
64 * bubble with further information.
65 * @param {Event} event Mouse or keyboard event.
66 */
67 handleEvent: function(event) {
68 switch (event.type) {
69 // Toggle the bubble on left click. Let any other clicks propagate.
70 case 'click':
71 if (event.button != 0)
72 return;
73 break;
74 // Toggle the bubble when <Return> or <Space> is pressed. Let any other
75 // key presses propagate.
76 case 'keydown':
77 switch (event.keyCode) {
78 case 13: // Return.
79 case 32: // Space.
80 break;
81 default:
82 return;
83 }
84 break;
85 // Blur focus when a mouse button is pressed, matching the behavior of
86 // other Web UI elements.
87 case 'mousedown':
88 if (document.activeElement)
89 document.activeElement.blur();
90 event.preventDefault();
91 return;
92 }
93 this.toggleBubble_();
94 event.preventDefault();
95 event.stopPropagation();
96 },
97
98 /**
99 * Open or close a bubble with further information about the pref.
84 * @private 100 * @private
85 */ 101 */
86 show_: function() { 102 toggleBubble_: function() {
87 var self = this; 103 if (this.isShowingBubble) {
88 var doc = self.ownerDocument; 104 OptionsPage.hideBubble();
105 } else {
106 var self = this;
89 107
90 // Clear out the old bubble contents. 108 // Work out the popup text.
91 var bubbleContainer = this.querySelector('.controlled-setting-bubble'); 109 defaultStrings = {
92 if (bubbleContainer) { 110 policy: loadTimeData.getString('controlledSettingPolicy'),
93 while (bubbleContainer.hasChildNodes()) 111 extension: loadTimeData.getString('controlledSettingExtension'),
94 bubbleContainer.removeChild(bubbleContainer.lastChild); 112 recommended: loadTimeData.getString('controlledSettingRecommended'),
113 };
114
115 // No controller, no popup.
116 if (!this.controlledBy || !this.controlledBy in defaultStrings)
117 return;
118
119 var text = defaultStrings[this.controlledBy];
120
121 // Apply text overrides.
122 if (this.hasAttribute('text' + this.controlledBy))
123 text = this.getAttribute('text' + this.controlledBy);
124
125 // Create the DOM tree.
126 var content = document.createElement('div');
127 content.className = 'controlled-setting-bubble-content';
128 content.setAttribute('controlled-by', this.controlledBy);
129 content.textContent = text;
130
131 var action = null;
132 if (this.controlledBy == 'recommended' && this.resetHandler_) {
133 var container = document.createElement('div');
134 action = document.createElement('button');
135 action.classList.add('link-button');
136 action.classList.add('controlled-setting-bubble-action');
137 action.textContent =
138 loadTimeData.getString('controlledSettingApplyRecommendation');
139 action.addEventListener('click', function(event) {
140 self.resetHandler_();
141 });
142 container.appendChild(action);
143 content.appendChild(container);
144 }
145
146 OptionsPage.showBubble(content, this);
95 } 147 }
96 148 },
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 }; 149 };
140 150
141 /** 151 /**
142 * The controlling entity of the setting. Can take the values "policy", 152 * The name of the associated preference.
143 * "extension", "recommended" or be unset. 153 * @type {string}
144 */ 154 */
145 cr.defineProperty(ControlledSettingIndicator, 'controlledBy', 155 cr.defineProperty(ControlledSettingIndicator, 'pref', cr.PropertyKind.ATTR);
146 cr.PropertyKind.ATTR,
147 ControlledSettingIndicator.prototype.close);
148 156
149 /** 157 /**
150 * A special preference type specific to dialogs. Changes take effect in the 158 * 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 159 * associated preference take effect in the settings UI immediately but are
152 * confirms the dialog. If the user cancels the dialog instead, the changes 160 * only actually committed when the user confirms the dialog. If the user
153 * are rolled back in the settings UI and never committed. 161 * cancels the dialog instead, the changes are rolled back in the settings UI
162 * and never committed.
154 * @type {boolean} 163 * @type {boolean}
155 */ 164 */
156 cr.defineProperty(ControlledSettingIndicator, 'dialogPref', 165 cr.defineProperty(ControlledSettingIndicator, 'dialogPref',
157 cr.PropertyKind.BOOL_ATTR); 166 cr.PropertyKind.BOOL_ATTR);
158 167
168 /**
169 * Whether the associated preference is controlled by a source other than the
170 * user's setting (can be 'policy', 'extension', 'recommended' or unset).
171 * @type {string}
172 */
173 cr.defineProperty(ControlledSettingIndicator, 'controlledBy',
174 cr.PropertyKind.ATTR);
175
176 /**
177 * Whether the indicator is currently showing a bubble.
178 */
179 cr.defineProperty(ControlledSettingIndicator, 'isShowingBubble',
180 cr.PropertyKind.BOOL_ATTR);
181
159 // Export. 182 // Export.
160 return { 183 return {
161 ControlledSettingIndicator: ControlledSettingIndicator 184 ControlledSettingIndicator: ControlledSettingIndicator
162 }; 185 };
163 }); 186 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698