Index: chrome/browser/resources/shared/js/cr/ui/bubble.js |
diff --git a/chrome/browser/resources/shared/js/cr/ui/bubble.js b/chrome/browser/resources/shared/js/cr/ui/bubble.js |
index 998b4584a1bba1c28bd0bb230e93c229aa937100..e938c7af1b069f31a1d263140b8b0452bc48405d 100644 |
--- a/chrome/browser/resources/shared/js/cr/ui/bubble.js |
+++ b/chrome/browser/resources/shared/js/cr/ui/bubble.js |
@@ -314,7 +314,7 @@ cr.define('cr.ui', function() { |
var Bubble = cr.ui.define('div'); |
Bubble.prototype = { |
- // Set up the prototype chain |
+ // Set up the prototype chain. |
__proto__: BubbleBase.prototype, |
/** |
@@ -397,10 +397,118 @@ cr.define('cr.ui', function() { |
}, |
}; |
+ /** |
+ * A bubble that closes automatically when the user clicks or moves the focus |
+ * outside the bubble and its target element, scrolls the underlying document |
+ * or resizes the window. |
+ */ |
+ var AutoCloseBubble = cr.ui.define('div'); |
+ |
+ AutoCloseBubble.prototype = { |
+ // Set up the prototype chain. |
+ __proto__: BubbleBase.prototype, |
+ |
+ /** |
+ * Initialization function for the cr.ui framework. |
+ */ |
+ decorate: function() { |
+ BubbleBase.prototype.decorate.call(this); |
+ this.classList.add('auto-close-bubble'); |
+ }, |
+ |
+ /** |
+ * Set the DOM sibling node, i.e. the node as whose sibling the bubble |
+ * should join the DOM to ensure that focusable elements inside the bubble |
+ * follow the target element in the document's tab order. Only available |
+ * when the bubble is not being shown. |
+ * @param {HTMLElement} node The new DOM sibling node. |
+ */ |
+ set domSibling(node) { |
+ if (!this.hidden) |
+ return; |
+ |
+ this.domSibling_ = node; |
+ }, |
+ |
+ /** |
+ * Show the bubble. |
+ */ |
+ show: function() { |
+ if (!this.hidden) |
+ return; |
+ |
+ BubbleBase.prototype.show.call(this); |
+ this.domSibling_.showingBubble = true; |
+ |
+ var doc = this.ownerDocument; |
+ this.eventTracker_.add(doc, 'mousewheel', this, true); |
+ this.eventTracker_.add(doc, 'scroll', this, true); |
+ this.eventTracker_.add(doc, 'elementFocused', this, true); |
+ this.eventTracker_.add(window, 'resize', this); |
+ }, |
+ |
+ /** |
+ * Hide the bubble. |
+ */ |
+ hide: function() { |
+ BubbleBase.prototype.hide.call(this); |
+ this.domSibling_.showingBubble = false; |
+ }, |
+ |
+ /** |
+ * Handle events, closing the bubble when the user clicks or moves the focus |
+ * outside the bubble and its target element, scrolls the underlying |
+ * document or resizes the window. |
+ * @param {Event} event The event. |
+ */ |
+ handleEvent: function(event) { |
+ BubbleBase.prototype.handleEvent.call(this, event); |
+ |
+ switch (event.type) { |
+ // Close the bubble when the user clicks outside it, except if it is a |
+ // left-click on the bubble's target element (allowing the target to |
+ // handle the event and close the bubble itself). |
+ case 'mousedown': |
+ if (event.button == 0 && this.anchorNode_.contains(event.target)) |
+ break; |
+ // Close the bubble when the underlying document is scrolled. |
+ case 'mousewheel': |
+ case 'scroll': |
+ if (this.contains(event.target)) |
+ break; |
+ // Close the bubble when the window is resized. |
+ case 'resize': |
+ this.hide(); |
+ break; |
+ // Close the bubble when the focus moves to an element that is not the |
+ // bubble target and is not inside the bubble. |
+ case 'elementFocused': |
+ if (!this.anchorNode_.contains(event.target) && |
+ !this.contains(event.target)) { |
+ this.hide(); |
+ } |
+ break; |
+ } |
+ }, |
+ |
+ /** |
+ * Attach the bubble to the document's DOM, making it a sibling of the |
+ * |domSibling_| so that focusable elements inside the bubble follow the |
+ * target element in the document's tab order. |
+ * @private |
+ */ |
+ attachToDOM_: function() { |
+ var parent = this.domSibling_.parentNode; |
+ parent.insertBefore(this, this.domSibling_.nextSibling); |
+ }, |
+ }; |
+ |
+ |
return { |
ArrowLocation: ArrowLocation, |
BubbleAlignment: BubbleAlignment, |
BubbleBase: BubbleBase, |
- Bubble: Bubble |
+ Bubble: Bubble, |
+ AutoCloseBubble: AutoCloseBubble |
}; |
}); |