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 // TODO(vitalyp): Inline the enums below into cr.ui definition function, remove | 7 // TODO(vitalyp): Inline the enums below into cr.ui definition function, remove |
8 // cr.exportPath() call and remove exportPath from exports in cr.js when this | 8 // cr.exportPath() call and remove exportPath from exports in cr.js when this |
9 // issue will be fixed: | 9 // issue will be fixed: |
10 // https://github.com/google/closure-compiler/issues/544 | 10 // https://github.com/google/closure-compiler/issues/544 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 * @type {Node} | 91 * @type {Node} |
92 * @private | 92 * @private |
93 */ | 93 */ |
94 anchorNode_: null, | 94 anchorNode_: null, |
95 | 95 |
96 /** | 96 /** |
97 * Initialization function for the cr.ui framework. | 97 * Initialization function for the cr.ui framework. |
98 */ | 98 */ |
99 decorate: function() { | 99 decorate: function() { |
100 this.className = 'bubble'; | 100 this.className = 'bubble'; |
101 this.innerHTML = | 101 this.innerHTML = '<div class="bubble-content"></div>' + |
dschuyler
2016/12/22 19:41:40
Could the rectangle rule apply here? It seems more
Dan Beam
2016/12/22 19:48:11
if this was made a multi-line string literal (i.e.
| |
102 '<div class="bubble-content"></div>' + | |
103 '<div class="bubble-shadow"></div>' + | 102 '<div class="bubble-shadow"></div>' + |
104 '<div class="bubble-arrow"></div>'; | 103 '<div class="bubble-arrow"></div>'; |
105 this.hidden = true; | 104 this.hidden = true; |
106 this.bubbleAlignment = cr.ui.BubbleAlignment.ENTIRELY_VISIBLE; | 105 this.bubbleAlignment = cr.ui.BubbleAlignment.ENTIRELY_VISIBLE; |
107 }, | 106 }, |
108 | 107 |
109 /** | 108 /** |
110 * Set the anchor node, i.e. the node that this bubble points at. Only | 109 * Set the anchor node, i.e. the node that this bubble points at. Only |
111 * available when the bubble is not being shown. | 110 * available when the bubble is not being shown. |
112 * @param {HTMLElement} node The new anchor node. | 111 * @param {HTMLElement} node The new anchor node. |
(...skipping 22 matching lines...) Expand all Loading... | |
135 /** | 134 /** |
136 * Set the arrow location. Only available when the bubble is not being | 135 * Set the arrow location. Only available when the bubble is not being |
137 * shown. | 136 * shown. |
138 * @param {cr.ui.ArrowLocation} location The new arrow location. | 137 * @param {cr.ui.ArrowLocation} location The new arrow location. |
139 */ | 138 */ |
140 set arrowLocation(location) { | 139 set arrowLocation(location) { |
141 if (!this.hidden) | 140 if (!this.hidden) |
142 return; | 141 return; |
143 | 142 |
144 this.arrowAtRight_ = location == cr.ui.ArrowLocation.TOP_END || | 143 this.arrowAtRight_ = location == cr.ui.ArrowLocation.TOP_END || |
145 location == cr.ui.ArrowLocation.BOTTOM_END; | 144 location == cr.ui.ArrowLocation.BOTTOM_END; |
146 if (document.documentElement.dir == 'rtl') | 145 if (document.documentElement.dir == 'rtl') |
147 this.arrowAtRight_ = !this.arrowAtRight_; | 146 this.arrowAtRight_ = !this.arrowAtRight_; |
148 this.arrowAtTop_ = location == cr.ui.ArrowLocation.TOP_START || | 147 this.arrowAtTop_ = location == cr.ui.ArrowLocation.TOP_START || |
149 location == cr.ui.ArrowLocation.TOP_END; | 148 location == cr.ui.ArrowLocation.TOP_END; |
150 }, | 149 }, |
151 | 150 |
152 /** | 151 /** |
153 * Set the bubble alignment. Only available when the bubble is not being | 152 * Set the bubble alignment. Only available when the bubble is not being |
154 * shown. | 153 * shown. |
155 * @param {cr.ui.BubbleAlignment} alignment The new bubble alignment. | 154 * @param {cr.ui.BubbleAlignment} alignment The new bubble alignment. |
156 */ | 155 */ |
157 set bubbleAlignment(alignment) { | 156 set bubbleAlignment(alignment) { |
158 if (!this.hidden) | 157 if (!this.hidden) |
159 return; | 158 return; |
(...skipping 14 matching lines...) Expand all Loading... | |
174 var bubble = this.getBoundingClientRect(); | 173 var bubble = this.getBoundingClientRect(); |
175 var arrow = this.querySelector('.bubble-arrow').getBoundingClientRect(); | 174 var arrow = this.querySelector('.bubble-arrow').getBoundingClientRect(); |
176 | 175 |
177 if (this.bubbleAlignment_ == cr.ui.BubbleAlignment.ENTIRELY_VISIBLE) { | 176 if (this.bubbleAlignment_ == cr.ui.BubbleAlignment.ENTIRELY_VISIBLE) { |
178 // Work out horizontal placement. The bubble is initially positioned so | 177 // Work out horizontal placement. The bubble is initially positioned so |
179 // that the arrow tip points toward the midpoint of the anchor and is | 178 // that the arrow tip points toward the midpoint of the anchor and is |
180 // BubbleBase.ARROW_OFFSET pixels from the reference edge and (as | 179 // BubbleBase.ARROW_OFFSET pixels from the reference edge and (as |
181 // specified by the arrow location). If the bubble is not entirely | 180 // specified by the arrow location). If the bubble is not entirely |
182 // within view, it is then shifted, preserving the arrow tip position. | 181 // within view, it is then shifted, preserving the arrow tip position. |
183 var left = this.arrowAtRight_ ? | 182 var left = this.arrowAtRight_ ? |
184 anchorMid + BubbleBase.ARROW_OFFSET - bubble.width : | 183 anchorMid + BubbleBase.ARROW_OFFSET - bubble.width : |
185 anchorMid - BubbleBase.ARROW_OFFSET; | 184 anchorMid - BubbleBase.ARROW_OFFSET; |
186 var max_left_pos = | 185 var max_left_pos = |
187 documentWidth - bubble.width - BubbleBase.MIN_VIEWPORT_EDGE_MARGIN; | 186 documentWidth - bubble.width - BubbleBase.MIN_VIEWPORT_EDGE_MARGIN; |
188 var min_left_pos = BubbleBase.MIN_VIEWPORT_EDGE_MARGIN; | 187 var min_left_pos = BubbleBase.MIN_VIEWPORT_EDGE_MARGIN; |
189 if (document.documentElement.dir == 'rtl') | 188 if (document.documentElement.dir == 'rtl') |
190 left = Math.min(Math.max(left, min_left_pos), max_left_pos); | 189 left = Math.min(Math.max(left, min_left_pos), max_left_pos); |
191 else | 190 else |
192 left = Math.max(Math.min(left, max_left_pos), min_left_pos); | 191 left = Math.max(Math.min(left, max_left_pos), min_left_pos); |
193 var arrowTip = Math.min( | 192 var arrowTip = Math.min( |
194 Math.max(arrow.width / 2, | 193 Math.max( |
195 this.arrowAtRight_ ? left + bubble.width - anchorMid : | 194 arrow.width / 2, this.arrowAtRight_ ? |
196 anchorMid - left), | 195 left + bubble.width - anchorMid : |
196 anchorMid - left), | |
197 bubble.width - arrow.width / 2); | 197 bubble.width - arrow.width / 2); |
198 | 198 |
199 // Work out the vertical placement, attempting to fit the bubble | 199 // Work out the vertical placement, attempting to fit the bubble |
200 // entirely into view. The following placements are considered in | 200 // entirely into view. The following placements are considered in |
201 // decreasing order of preference: | 201 // decreasing order of preference: |
202 // * Outside the anchor, arrow tip touching the anchor (arrow at | 202 // * Outside the anchor, arrow tip touching the anchor (arrow at |
203 // top/bottom as specified by the arrow location). | 203 // top/bottom as specified by the arrow location). |
204 // * Outside the anchor, arrow tip touching the anchor (arrow at | 204 // * Outside the anchor, arrow tip touching the anchor (arrow at |
205 // bottom/top, opposite the specified arrow location). | 205 // bottom/top, opposite the specified arrow location). |
206 // * Outside the anchor, arrow tip overlapping the anchor (arrow at | 206 // * Outside the anchor, arrow tip overlapping the anchor (arrow at |
207 // top/bottom as specified by the arrow location). | 207 // top/bottom as specified by the arrow location). |
208 // * Outside the anchor, arrow tip overlapping the anchor (arrow at | 208 // * Outside the anchor, arrow tip overlapping the anchor (arrow at |
209 // bottom/top, opposite the specified arrow location). | 209 // bottom/top, opposite the specified arrow location). |
210 // * Overlapping the anchor. | 210 // * Overlapping the anchor. |
211 var offsetTop = Math.min(documentHeight - anchor.bottom - bubble.height, | 211 var offsetTop = Math.min( |
212 arrow.height / 2); | 212 documentHeight - anchor.bottom - bubble.height, arrow.height / 2); |
213 var offsetBottom = Math.min(anchor.top - bubble.height, | 213 var offsetBottom = |
214 arrow.height / 2); | 214 Math.min(anchor.top - bubble.height, arrow.height / 2); |
215 if (offsetTop < 0 && offsetBottom < 0) { | 215 if (offsetTop < 0 && offsetBottom < 0) { |
216 var top = 0; | 216 var top = 0; |
217 this.updateArrowPosition_(false, false, arrowTip); | 217 this.updateArrowPosition_(false, false, arrowTip); |
218 } else if (offsetTop > offsetBottom || | 218 } else if ( |
219 offsetTop == offsetBottom && this.arrowAtTop_) { | 219 offsetTop > offsetBottom || |
220 offsetTop == offsetBottom && this.arrowAtTop_) { | |
220 var top = anchor.bottom + offsetTop; | 221 var top = anchor.bottom + offsetTop; |
221 this.updateArrowPosition_(true, true, arrowTip); | 222 this.updateArrowPosition_(true, true, arrowTip); |
222 } else { | 223 } else { |
223 var top = anchor.top - bubble.height - offsetBottom; | 224 var top = anchor.top - bubble.height - offsetBottom; |
224 this.updateArrowPosition_(true, false, arrowTip); | 225 this.updateArrowPosition_(true, false, arrowTip); |
225 } | 226 } |
226 } else { | 227 } else { |
227 if (this.bubbleAlignment_ == | 228 if (this.bubbleAlignment_ == |
228 cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE) { | 229 cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE) { |
229 var left = this.arrowAtRight_ ? anchor.right - bubble.width : | 230 var left = |
230 anchor.left; | 231 this.arrowAtRight_ ? anchor.right - bubble.width : anchor.left; |
231 } else { | 232 } else { |
232 var left = this.arrowAtRight_ ? | 233 var left = this.arrowAtRight_ ? |
233 anchorMid - this.clientWidth + BubbleBase.ARROW_OFFSET : | 234 anchorMid - this.clientWidth + BubbleBase.ARROW_OFFSET : |
234 anchorMid - BubbleBase.ARROW_OFFSET; | 235 anchorMid - BubbleBase.ARROW_OFFSET; |
235 } | 236 } |
236 var top = this.arrowAtTop_ ? anchor.bottom + arrow.height / 2 : | 237 var top = this.arrowAtTop_ ? |
238 anchor.bottom + arrow.height / 2 : | |
237 anchor.top - this.clientHeight - arrow.height / 2; | 239 anchor.top - this.clientHeight - arrow.height / 2; |
238 this.updateArrowPosition_(true, this.arrowAtTop_, | 240 this.updateArrowPosition_( |
239 BubbleBase.ARROW_OFFSET); | 241 true, this.arrowAtTop_, BubbleBase.ARROW_OFFSET); |
240 } | 242 } |
241 | 243 |
242 this.style.left = left + 'px'; | 244 this.style.left = left + 'px'; |
243 this.style.top = top + 'px'; | 245 this.style.top = top + 'px'; |
244 }, | 246 }, |
245 | 247 |
246 /** | 248 /** |
247 * Show the bubble. | 249 * Show the bubble. |
248 */ | 250 */ |
249 show: function() { | 251 show: function() { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
282 this.hide(); | 284 this.hide(); |
283 event.preventDefault(); | 285 event.preventDefault(); |
284 event.stopPropagation(); | 286 event.stopPropagation(); |
285 } | 287 } |
286 }, | 288 }, |
287 | 289 |
288 /** | 290 /** |
289 * Attach the bubble to the document's DOM. | 291 * Attach the bubble to the document's DOM. |
290 * @private | 292 * @private |
291 */ | 293 */ |
292 attachToDOM_: function() { | 294 attachToDOM_: function() { document.body.appendChild(this); }, |
293 document.body.appendChild(this); | |
294 }, | |
295 | 295 |
296 /** | 296 /** |
297 * Update the arrow so that it appears at the correct position. | 297 * Update the arrow so that it appears at the correct position. |
298 * @param {boolean} visible Whether the arrow should be visible. | 298 * @param {boolean} visible Whether the arrow should be visible. |
299 * @param {boolean} atTop Whether the arrow should be at the top of the | 299 * @param {boolean} atTop Whether the arrow should be at the top of the |
300 * bubble. | 300 * bubble. |
301 * @param {number} tipOffset The horizontal distance between the tip of the | 301 * @param {number} tipOffset The horizontal distance between the tip of the |
302 * arrow and the reference edge of the bubble (as specified by the arrow | 302 * arrow and the reference edge of the bubble (as specified by the arrow |
303 * location). | 303 * location). |
304 * @private | 304 * @private |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
400 * TODO(vitalyp): remove suppression when the extern | 400 * TODO(vitalyp): remove suppression when the extern |
401 * Node.prototype.contains() will be fixed. | 401 * Node.prototype.contains() will be fixed. |
402 */ | 402 */ |
403 handleEvent: function(event) { | 403 handleEvent: function(event) { |
404 BubbleBase.prototype.handleEvent.call(this, event); | 404 BubbleBase.prototype.handleEvent.call(this, event); |
405 | 405 |
406 if (event.type == 'mousedown') { | 406 if (event.type == 'mousedown') { |
407 // Dismiss the bubble when the user clicks on the close button. | 407 // Dismiss the bubble when the user clicks on the close button. |
408 if (event.target == this.querySelector('.bubble-close')) { | 408 if (event.target == this.querySelector('.bubble-close')) { |
409 this.handleCloseEvent_(); | 409 this.handleCloseEvent_(); |
410 // Dismiss the bubble when the user clicks outside it after the | 410 // Dismiss the bubble when the user clicks outside it after the |
411 // specified delay has passed. | 411 // specified delay has passed. |
412 } else if (!this.contains(event.target) && | 412 } else if ( |
413 !this.contains(event.target) && | |
413 Date.now() - this.showTime_ >= this.deactivateToDismissDelay_) { | 414 Date.now() - this.showTime_ >= this.deactivateToDismissDelay_) { |
414 this.hide(); | 415 this.hide(); |
415 } | 416 } |
416 } | 417 } |
417 }, | 418 }, |
418 }; | 419 }; |
419 | 420 |
420 /** | 421 /** |
421 * A bubble that closes automatically when the user clicks or moves the focus | 422 * A bubble that closes automatically when the user clicks or moves the focus |
422 * outside the bubble and its target element, scrolls the underlying document | 423 * outside the bubble and its target element, scrolls the underlying document |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
531 }, | 532 }, |
532 }; | 533 }; |
533 | 534 |
534 | 535 |
535 return { | 536 return { |
536 BubbleBase: BubbleBase, | 537 BubbleBase: BubbleBase, |
537 Bubble: Bubble, | 538 Bubble: Bubble, |
538 AutoCloseBubble: AutoCloseBubble | 539 AutoCloseBubble: AutoCloseBubble |
539 }; | 540 }; |
540 }); | 541 }); |
OLD | NEW |