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

Side by Side Diff: chrome/browser/resources/shared/js/cr/ui/expandable_bubble.js

Issue 8208014: Update the notification bubble. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 2 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
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 // require: event_tracker.js
6
7 cr.define('cr.ui', function() {
8 'use strict';
9
10 /**
11 * ExpandableBubble is a free-floating compact informational bubble with an
12 * arrow that points at a place of interest on the page. When clicked, the
13 * bubble expands to show more of its content. Width of the bubble is the
14 * width of the node it is overlapping when unexpanded. Expanded, it is of a
15 * fixed width, but variable height. Currently the arrow is always positioned
16 * at the bottom right and points down.
17 * @constructor
18 * @extends {cr.ui.div}
19 */
20 var ExpandableBubble = cr.ui.define('div');
21
22 ExpandableBubble.prototype = {
23 __proto__: HTMLDivElement.prototype,
24
25 /** @inheritDoc */
26 decorate: function() {
27 this.className = 'ex-bubble';
28 this.innerHTML =
29 '<div class=\"ex-bubble-contents\">' +
arv (Not doing code reviews) 2011/10/14 22:20:55 Replace \" with "
30 '<div class=\"ex-bubble-title\"></div>' +
31 '<div class=\"ex-bubble-main\" hidden=\"true\"></div>' +
arv (Not doing code reviews) 2011/10/14 22:20:55 It is hidden, not hidden="..." '<div class="ex-bu
32 '</div>' +
33 '<div class=\"ex-bubble-close\" hidden=\"true\"></div>' +
34 '<div class=\"ex-bubble-shadow\"></div>' +
35 '<div class=\"ex-bubble-arrow\"></div>';
36
37 this.hidden = true;
38 this.handleCloseEvent = this.hide;
39 this.dismissOnBlur_ = true;
Evan Stade 2011/10/14 18:22:59 this is always false, right? for now I wouldn't ma
arv (Not doing code reviews) 2011/10/14 22:20:55 This can be moved to the prototype.
40 },
41
42 /**
43 * Sets the title of the bubble. The title is always visible when the
44 * bubble is visible.
45 * @param {node} An HTML element.
arv (Not doing code reviews) 2011/10/14 22:20:55 @param {Node} node An HTML element. or @type {N
46 */
47 set contentTitle(node) {
48 var bubbleTitle = this.querySelector('.ex-bubble-title');
49 bubbleTitle.innerHTML = '';
arv (Not doing code reviews) 2011/10/14 22:20:55 textContent = '' But it doesn't really matter
50 bubbleTitle.appendChild(node);
51 },
52
53 /**
54 * Sets the content node of the bubble. The content node is only visible
55 * when the bubble is expanded.
56 * @param {node} An HTML element.
57 */
58 set content(node) {
59 var bubbleMain = this.querySelector('.ex-bubble-main');
60 bubbleMain.innerHTML = '';
61 bubbleMain.appendChild(node);
62 },
63
64 /**
65 * Sets the anchor node, i.e. the node that this bubble points at and
66 * partially overlaps.
67 * @param {HTMLElement} node The new anchor node.
68 */
69 set anchorNode(node) {
70 this.anchorNode_ = node;
71
72 if (!this.hidden)
73 this.resizeAndReposition();
74 },
75
76 /**
77 * Sets whether the bubble will dismiss on blur. By default, it does.
arv (Not doing code reviews) 2011/10/14 22:20:55 Please fix formatting of the comment
78 * @param {boolean} value Whether to dismiss on blur.
79 **/
80 set dismissOnBlur(value) {
arv (Not doing code reviews) 2011/10/14 22:20:55 This does not need a setter. since it has no side
81 this.dismissOnBlur_ = value;
82 },
83
84 /**
85 * Handles the close event which is triggered when the close button
86 * is clicked. By default is set to this.hide.
87 * @param {function} A function with no parameters
88 */
89 set handleCloseEvent(func) {
arv (Not doing code reviews) 2011/10/14 22:20:55 no need for setter
90 this.handleCloseEvent_ = func;
91 },
92
93 /**
94 * Updates the position of the bubble.
95 * @private
96 */
97 reposition: function() {
98 var clientRect = this.anchorNode_.getBoundingClientRect();
99 this.style.left = this.style.right = clientRect.left + 'px';
100
101 if (this.classList.contains('.ex-bubble-contents-expanded')) {
102 this.style.top = (clientRect.top - this.offsetHeight +
arv (Not doing code reviews) 2011/10/14 22:20:55 Maybe a variable for top to reduce the code size
103 this.unexpandedHeight - 1) + 'px';
104 } else {
105 this.style.top = (clientRect.top - 1) + 'px';
106 }
107 },
108
109 /**
110 * Resizes the bubble and then repositions it.
111 * @private
112 */
113 resizeAndReposition: function() {
arv (Not doing code reviews) 2011/10/14 22:20:55 This should have a trailing underscore since it is
114 var clientRect = this.anchorNode_.getBoundingClientRect();
115 var width = clientRect.width;
116 if (this.classList.contains('.ex-bubble-contents-expanded')) {
117 var expandedWidth = 250;
118 this.style.marginLeft = (width - expandedWidth) + 'px';
119 width = expandedWidth;
120 } else {
121 this.style.marginLeft = '0';
122 }
123
124 // Width is dynamic (when not expanded) based on the width of the anchor
125 // node, and the title and shadow need to follow suit.
126 this.style.width = width + 'px';
127 var bubbleTitle = this.querySelector('.ex-bubble-title');
128 bubbleTitle.style.width = (width - 2) + 'px';
arv (Not doing code reviews) 2011/10/14 22:20:55 I feel like the parentheses on expression like the
Evan Stade 2011/10/17 23:15:14 I believe he got this style from copying my code.
129 var bubbleContent = this.querySelector('.ex-bubble-main');
130 bubbleContent.style.width = (width - 12) + 'px';
131 var bubbleShadow = this.querySelector('.ex-bubble-shadow');
132 bubbleShadow.style.width = (width + 2) + 'px';
133
134 // Also reposition the bubble -- dimensions have potentially changed.
135 this.reposition();
136 },
137
138 /*
139 * Expand the bubble (bringing the full content into view).
140 * @private
141 */
142 expandBubble_: function() {
143 this.querySelector('.ex-bubble-main').hidden = false;
144 this.querySelector('.ex-bubble-close').hidden = false;
145 var title = this.querySelector('.ex-bubble-title');
146 title.classList.add('ex-bubble-title-bubble-expanded');
arv (Not doing code reviews) 2011/10/14 22:20:55 This could probably be done by adding and removing
Finnur 2011/10/18 12:39:10 Indeed. And I like it a lot more, actually. Done.
147 this.classList.add('.ex-bubble-contents-expanded');
148 this.resizeAndReposition();
149 },
150
151 /**
152 * Collapse the bubble, hiding the main content and the close button.
153 * This is automatically called when the window is resized.
154 * @private
155 */
156 collapseBubble_: function() {
157 this.querySelector('.ex-bubble-main').hidden = true;
158 this.querySelector('.ex-bubble-close').hidden = true;
159 var title = this.querySelector('.ex-bubble-title');
160 title.classList.remove('ex-bubble-title-bubble-expanded');
161 this.classList.remove('.ex-bubble-contents-expanded');
162 this.resizeAndReposition();
163 },
164
165 /**
166 * The onclick handler for the notification (expands the bubble).
167 * @param {Event} e The event.
168 * @private
169 */
170 onNotificationClick_ : function(e) {
171 if (!this.contains(e.target))
172 return;
173
174 if (!this.classList.contains('.ex-bubble-contents-expanded')) {
175 // Save the height of the unexpanded bubble, so we can make sure to
176 // position it correctly (arrow points in the same location) after
177 // we expand it.
178 this.unexpandedHeight = this.offsetHeight;
179 }
180
181 this.expandBubble_();
182 },
183
184 /**
185 * Starts showing the bubble. The bubble will grab input and show until the
186 * user clicks away.
187 */
188 show: function() {
189 if (!this.hidden)
190 return;
191
192 document.body.appendChild(this);
193 this.hidden = false;
194 this.resizeAndReposition();
195
196 this.eventTracker_ = new EventTracker;
197 this.eventTracker_.add(window,
198 'load', this.resizeAndReposition.bind(this));
199 this.eventTracker_.add(window,
200 'resize', this.collapseBubble_.bind(this));
201 this.eventTracker_.add(window,
202 'click', this.onNotificationClick_.bind(this));
203
204 var doc = this.ownerDocument;
205 this.eventTracker_.add(doc, 'keydown', this, true);
206 this.eventTracker_.add(doc, 'mousedown', this, true);
207 },
208
209 /**
210 * Hides the bubble from view.
211 */
212 hide: function() {
213 this.hidden = true;
214 this.eventTracker_.removeAll();
215 this.parentNode.removeChild(this);
216 },
217
218 /**
219 * Handles keydown and mousedown events, dismissing the bubble if
220 * necessary.
221 * @param {Event} e The event.
222 * @private
223 */
224 handleEvent: function(e) {
225 switch (e.type) {
226 case 'keydown':
227 if (e.keyCode == 27) // Esc.
228 this.hide();
229 break;
230
231 case 'mousedown':
232 if (e.target == this.querySelector('.ex-bubble-close')) {
233 this.handleCloseEvent_();
234 } else if (!this.contains(e.target)) {
235 // A click outside the bubble dismisses the bubble, unless that has
236 // been disabled. If dismissOnBlur has been disabled, it should
237 // collapse if expanded.
238 if (this.dismissOnBlur_)
239 this.hide();
240 else if (this.classList.contains('.ex-bubble-contents-expanded'))
241 this.collapseBubble_();
242 }
243 break;
244 }
245
246 e.stopPropagation();
arv (Not doing code reviews) 2011/10/14 22:20:55 Please add comments about both of these to explain
Finnur 2011/10/18 12:39:10 I don't know if they are needed. This is from the
Evan Stade 2011/10/18 16:34:15 yea they are needed, this is a hacked up way of im
247 e.preventDefault();
248 return;
249 },
250 };
251
252 return {
253 ExpandableBubble: ExpandableBubble
254 };
255 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698