| OLD | NEW |
| 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 // require: event_tracker.js | 5 // require: event_tracker.js |
| 6 | 6 |
| 7 cr.define('cr.ui', function() { | 7 cr.define('cr.ui', function() { |
| 8 'use strict'; | 8 'use strict'; |
| 9 | 9 |
| 10 /** | 10 /** |
| 11 * ExpandableBubble is a free-floating compact informational bubble with an | 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 | 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 | 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 | 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 | 15 * fixed width, but variable height. Currently the arrow is always positioned |
| 16 * at the bottom right and points down. | 16 * at the bottom right and points down. |
| 17 * @constructor | 17 * @constructor |
| 18 * @extends {HTMLDivElement} | 18 * @extends {HTMLDivElement} |
| 19 * @implements {EventListener} | 19 * @implements {EventListener} |
| 20 */ | 20 */ |
| 21 var ExpandableBubble = cr.ui.define('div'); | 21 var ExpandableBubble = cr.ui.define('div'); |
| 22 | 22 |
| 23 ExpandableBubble.prototype = { | 23 ExpandableBubble.prototype = { |
| 24 __proto__: HTMLDivElement.prototype, | 24 __proto__: HTMLDivElement.prototype, |
| 25 | 25 |
| 26 decorate: function() { | 26 decorate: function() { |
| 27 this.className = 'expandable-bubble'; | 27 this.className = 'expandable-bubble'; |
| 28 this.innerHTML = | 28 this.innerHTML = '<div class="expandable-bubble-contents">' + |
| 29 '<div class="expandable-bubble-contents">' + | 29 '<div class="expandable-bubble-title"></div>' + |
| 30 '<div class="expandable-bubble-title"></div>' + | 30 '<div class="expandable-bubble-main" hidden></div>' + |
| 31 '<div class="expandable-bubble-main" hidden></div>' + | |
| 32 '</div>' + | 31 '</div>' + |
| 33 '<div class="expandable-bubble-close" hidden></div>'; | 32 '<div class="expandable-bubble-close" hidden></div>'; |
| 34 | 33 |
| 35 this.hidden = true; | 34 this.hidden = true; |
| 36 this.bubbleSuppressed = false; | 35 this.bubbleSuppressed = false; |
| 37 this.handleCloseEvent = this.hide; | 36 this.handleCloseEvent = this.hide; |
| 38 }, | 37 }, |
| 39 | 38 |
| 40 /** | 39 /** |
| 41 * Sets the title of the bubble. The title is always visible when the | 40 * Sets the title of the bubble. The title is always visible when the |
| (...skipping 27 matching lines...) Expand all Loading... |
| 69 | 68 |
| 70 if (!this.hidden) | 69 if (!this.hidden) |
| 71 this.resizeAndReposition(); | 70 this.resizeAndReposition(); |
| 72 }, | 71 }, |
| 73 | 72 |
| 74 /** | 73 /** |
| 75 * Handles the close event which is triggered when the close button | 74 * Handles the close event which is triggered when the close button |
| 76 * is clicked. By default is set to this.hide. | 75 * is clicked. By default is set to this.hide. |
| 77 * @param {Function} func A function with no parameters. | 76 * @param {Function} func A function with no parameters. |
| 78 */ | 77 */ |
| 79 set handleCloseEvent(func) { | 78 set handleCloseEvent(func) { this.handleCloseEvent_ = func; }, |
| 80 this.handleCloseEvent_ = func; | |
| 81 }, | |
| 82 | 79 |
| 83 /** | 80 /** |
| 84 * Temporarily suppresses the bubble from view (and toggles it back). | 81 * Temporarily suppresses the bubble from view (and toggles it back). |
| 85 * 'Suppressed' and 'hidden' are two bubble states that both indicate that | 82 * 'Suppressed' and 'hidden' are two bubble states that both indicate that |
| 86 * the bubble should not be visible, but when you 'un-suppress' a bubble, | 83 * the bubble should not be visible, but when you 'un-suppress' a bubble, |
| 87 * only a suppressed bubble becomes visible. This can be handy, for example, | 84 * only a suppressed bubble becomes visible. This can be handy, for example, |
| 88 * if the user switches away from the app card (then we need to know which | 85 * if the user switches away from the app card (then we need to know which |
| 89 * bubbles to show (only the suppressed ones, not the hidden ones). Hiding | 86 * bubbles to show (only the suppressed ones, not the hidden ones). Hiding |
| 90 * and un-hiding a bubble overrides the suppressed state (a bubble cannot | 87 * and un-hiding a bubble overrides the suppressed state (a bubble cannot |
| 91 * be suppressed but not hidden). | 88 * be suppressed but not hidden). |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 | 187 |
| 191 /** | 188 /** |
| 192 * The onclick handler for the notification (expands the bubble). | 189 * The onclick handler for the notification (expands the bubble). |
| 193 * @param {Event} e The event. | 190 * @param {Event} e The event. |
| 194 * @private | 191 * @private |
| 195 * @suppress {checkTypes} | 192 * @suppress {checkTypes} |
| 196 * TODO(vitalyp): remove suppression when the extern | 193 * TODO(vitalyp): remove suppression when the extern |
| 197 * Node.prototype.contains() will be fixed. | 194 * Node.prototype.contains() will be fixed. |
| 198 */ | 195 */ |
| 199 onNotificationClick_: function(e) { | 196 onNotificationClick_: function(e) { |
| 200 if (!this.contains(/** @type {!Node} */(e.target))) | 197 if (!this.contains(/** @type {!Node} */ (e.target))) |
| 201 return; | 198 return; |
| 202 | 199 |
| 203 if (!this.expanded) { | 200 if (!this.expanded) { |
| 204 // Save the height of the unexpanded bubble, so we can make sure to | 201 // Save the height of the unexpanded bubble, so we can make sure to |
| 205 // position it correctly (arrow points in the same location) after | 202 // position it correctly (arrow points in the same location) after |
| 206 // we expand it. | 203 // we expand it. |
| 207 this.unexpandedHeight = this.offsetHeight; | 204 this.unexpandedHeight = this.offsetHeight; |
| 208 } | 205 } |
| 209 | 206 |
| 210 this.expandBubble_(); | 207 this.expandBubble_(); |
| 211 }, | 208 }, |
| 212 | 209 |
| 213 /** | 210 /** |
| 214 * Shows the bubble. The bubble will start collapsed and expand when | 211 * Shows the bubble. The bubble will start collapsed and expand when |
| 215 * clicked. | 212 * clicked. |
| 216 */ | 213 */ |
| 217 show: function() { | 214 show: function() { |
| 218 if (!this.hidden) | 215 if (!this.hidden) |
| 219 return; | 216 return; |
| 220 | 217 |
| 221 document.body.appendChild(this); | 218 document.body.appendChild(this); |
| 222 this.hidden = false; | 219 this.hidden = false; |
| 223 this.resizeAndReposition(); | 220 this.resizeAndReposition(); |
| 224 | 221 |
| 225 this.eventTracker_ = new EventTracker; | 222 this.eventTracker_ = new EventTracker; |
| 226 this.eventTracker_.add(window, | 223 this.eventTracker_.add( |
| 227 'load', this.resizeAndReposition.bind(this)); | 224 window, 'load', this.resizeAndReposition.bind(this)); |
| 228 this.eventTracker_.add(window, | 225 this.eventTracker_.add( |
| 229 'resize', this.resizeAndReposition.bind(this)); | 226 window, 'resize', this.resizeAndReposition.bind(this)); |
| 230 this.eventTracker_.add(this, 'click', this.onNotificationClick_); | 227 this.eventTracker_.add(this, 'click', this.onNotificationClick_); |
| 231 | 228 |
| 232 var doc = this.ownerDocument; | 229 var doc = this.ownerDocument; |
| 233 this.eventTracker_.add(assert(doc), 'keydown', this, true); | 230 this.eventTracker_.add(assert(doc), 'keydown', this, true); |
| 234 this.eventTracker_.add(assert(doc), 'mousedown', this, true); | 231 this.eventTracker_.add(assert(doc), 'mousedown', this, true); |
| 235 }, | 232 }, |
| 236 | 233 |
| 237 /** | 234 /** |
| 238 * Hides the bubble from view. | 235 * Hides the bubble from view. |
| 239 */ | 236 */ |
| (...skipping 22 matching lines...) Expand all Loading... |
| 262 this.collapseBubble_(); | 259 this.collapseBubble_(); |
| 263 handled = true; | 260 handled = true; |
| 264 } | 261 } |
| 265 } | 262 } |
| 266 break; | 263 break; |
| 267 | 264 |
| 268 case 'mousedown': | 265 case 'mousedown': |
| 269 if (e.target == this.querySelector('.expandable-bubble-close')) { | 266 if (e.target == this.querySelector('.expandable-bubble-close')) { |
| 270 this.handleCloseEvent_(); | 267 this.handleCloseEvent_(); |
| 271 handled = true; | 268 handled = true; |
| 272 } else if (!this.contains(/** @type {!Node} */(e.target))) { | 269 } else if (!this.contains(/** @type {!Node} */ (e.target))) { |
| 273 if (this.expanded) { | 270 if (this.expanded) { |
| 274 this.collapseBubble_(); | 271 this.collapseBubble_(); |
| 275 handled = true; | 272 handled = true; |
| 276 } | 273 } |
| 277 } | 274 } |
| 278 break; | 275 break; |
| 279 } | 276 } |
| 280 | 277 |
| 281 if (handled) { | 278 if (handled) { |
| 282 // The bubble emulates a focus grab when expanded, so when we've | 279 // The bubble emulates a focus grab when expanded, so when we've |
| (...skipping 11 matching lines...) Expand all Loading... |
| 294 cr.defineProperty(ExpandableBubble, 'expanded', cr.PropertyKind.BOOL_ATTR); | 291 cr.defineProperty(ExpandableBubble, 'expanded', cr.PropertyKind.BOOL_ATTR); |
| 295 | 292 |
| 296 /** | 293 /** |
| 297 * Whether the title needs to be masked out towards the right, which indicates | 294 * Whether the title needs to be masked out towards the right, which indicates |
| 298 * to the user that part of the text is clipped. This is only used when the | 295 * to the user that part of the text is clipped. This is only used when the |
| 299 * bubble is collapsed and the title doesn't fit because it is maxed out in | 296 * bubble is collapsed and the title doesn't fit because it is maxed out in |
| 300 * width within the anchored node. | 297 * width within the anchored node. |
| 301 */ | 298 */ |
| 302 cr.defineProperty(ExpandableBubble, 'masked', cr.PropertyKind.BOOL_ATTR); | 299 cr.defineProperty(ExpandableBubble, 'masked', cr.PropertyKind.BOOL_ATTR); |
| 303 | 300 |
| 304 return { | 301 return {ExpandableBubble: ExpandableBubble}; |
| 305 ExpandableBubble: ExpandableBubble | |
| 306 }; | |
| 307 }); | 302 }); |
| OLD | NEW |