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

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

Issue 10907148: Implement popup bubbles for the controlled setting indicator (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comment 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
(Empty)
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
3 // found in the LICENSE file.
4
5 cr.define('options', function() {
6 var BubbleBase = cr.ui.BubbleBase;
7
8 var Bubble = cr.ui.define('div');
9
10 Bubble.prototype = {
Evan Stade 2012/09/21 12:12:11 even though they are in different namespaces, I th
bartfab (slow) 2012/09/24 17:15:55 Renamed to OptionsBubble.
11 // Set up the prototype chain.
12 __proto__: BubbleBase.prototype,
13
14 /**
15 * Initialization function for the cr.ui framework.
16 */
17 decorate: function() {
18 BubbleBase.prototype.decorate.call(this);
19 this.classList.add('options-bubble');
20 },
21
22 /**
23 * Show the bubble.
24 */
25 show: function() {
26 if (!this.hidden)
27 return;
28
29 BubbleBase.prototype.show.call(this);
30 this.position_();
31
32 var doc = this.ownerDocument;
33 this.eventTracker_.add(doc, 'mousewheel', this, true);
34 this.eventTracker_.add(doc, 'scroll', this, true);
35 this.eventTracker_.add(doc, 'elementFocused', this, true);
36 this.eventTracker_.add(window, 'resize', this);
37 },
38
39 /**
40 * Position the bubble so that it is entirely within view and does not
41 * obstruct the anchor element, if possible.
Evan Stade 2012/09/21 12:12:11 this seems pretty useful for bubbles in general. W
Evan Stade 2012/09/21 12:12:11 nit: @private
bartfab (slow) 2012/09/24 17:15:55 I moved this to BubbleBase as a third alignment al
42 */
43 position_: function() {
44 var documentWidth = document.documentElement.clientWidth;
45 var documentHeight = document.documentElement.clientHeight;
46 var anchor = this.anchorNode_.getBoundingClientRect();
47 var anchorMid = (anchor.left + anchor.right) / 2.;
Evan Stade 2012/09/21 12:12:11 don't need decimal point
bartfab (slow) 2012/09/24 17:15:55 Done.
48 var bubble = this.getBoundingClientRect();
49 var arrow = this.querySelector('.bubble-arrow').getBoundingClientRect();
50
51 // Work out horizontal placement. The bubble is initially positioned so
52 // that the arrow tip points toward the midpoint of the anchor and is
53 // BubbleBase.ARROW_OFFSET pixels from the reference edge and (as
54 // specified by the arrow location). If the bubble is not entirely within
55 // view, it is then shifted, preserving the arrow tip position.
56 if (this.arrowAtRight_) {
57 var right = Math.min(Math.max(anchorMid + BubbleBase.ARROW_OFFSET,
58 bubble.width), documentWidth);
59 var left = right - bubble.width;
60 var arrowTip = right - anchorMid;
61 } else {
62 var left = Math.max(Math.min(anchorMid - BubbleBase.ARROW_OFFSET,
63 documentWidth - bubble.width), 0);
64 var arrowTip = anchorMid - left;
65 }
66 arrowTip = Math.min(Math.max(arrowTip, arrow.width / 2),
67 bubble.width - arrow.width / 2);
68
69 // Work out the vertical placement, attempting to fit the bubble entirely
70 // into view. The following placements are considered in decreasing order
71 // of preference:
72 // * Outside the anchor, arrow tip touching the anchor (arrow at
73 // top/bottom as specified by the arrow location).
74 // * Outside the anchor, arrow tip touching the anchor (arrow at
75 // bottom/top, opposite the specified arrow location).
76 // * Outside the anchor, arrow tip overlapping the anchor (arrow at
77 // top/bottom as specified by the arrow location).
78 // * Outside the anchor, arrow tip overlapping the anchor (arrow at
79 // bottom/top, opposite the specified arrow location).
80 // * Overlapping the anchor.
81 var offsetTop = Math.min(documentHeight - anchor.bottom - bubble.height,
82 arrow.height / 2);
83 var offsetBottom = Math.min(anchor.top - bubble.height, arrow.height / 2);
84 if (offsetTop < 0 && offsetBottom < 0) {
85 var top = 0;
86 this.updateArrowPosition_(false, false, arrowTip);
87 } else if (offsetTop > offsetBottom ||
88 offsetTop == offsetBottom && this.arrowAtTop_) {
89 var top = anchor.bottom + offsetTop;
90 this.updateArrowPosition_(true, true, arrowTip);
91 } else {
92 var top = anchor.top - bubble.height - offsetBottom;
93 this.updateArrowPosition_(true, false, arrowTip);
94 }
95
96 this.style.left = left + 'px';
97 this.style.top = top + 'px';
98 },
99
100 /**
101 * Handle events, closing the bubble when the user clicks or moves the focus
102 * outside the bubble and its anchor elements, scrolls the underlying
103 * document or resizes the window.
104 * @param {Event} event The event.
105 */
106 handleEvent: function(event) {
107 BubbleBase.prototype.handleEvent.call(this, event);
108
109 switch (event.type) {
110 // Close the bubble when the user clicks outside it, except if it is a
111 // left-click on the anchor element (allowing the anchor to handle the
112 // event and close the bubble itself).
113 case 'mousedown':
114 if (event.button == 0 && this.anchorNode_.contains(event.target))
115 break;
116 // Close the bubble when the underlying document is scrolled.
117 case 'mousewheel':
118 case 'scroll':
119 if (this.contains(event.target))
120 break;
121 // Close the bubble when the window is resized.
122 case 'resize':
123 this.hide();
124 break;
125 // Close the bubble when the focus moves to an element that is not the
126 // anchor and is not inside the bubble.
127 case 'elementFocused':
128 if (!this.anchorNode_.contains(event.target) &&
129 !this.contains(event.target)) {
130 this.hide();
131 }
132 break;
133 }
134 },
135
136 /**
137 * Attach the bubble to the document's DOM, making it a sibling of the
138 * anchor element so that focusable elements inside the bubble follow the
139 * anchor in the document's tab order.
140 * @private
141 */
142 attachToDOM_: function() {
143 var parent = this.anchorNode_.parentNode;
144 parent.insertBefore(this, this.anchorNode_.nextSibling);
145 },
146 };
147
148 return {
149 Bubble: Bubble
150 };
151 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698