Chromium Code Reviews| 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>' + |
| 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; |
|
dpapad
2016/12/22 00:56:29
+dschuyler
This change is a surprise to me. Per th
Dan Beam
2016/12/22 01:05:13
I think the style guide is intentionally ambiguous
dschuyler
2016/12/22 01:24:25
In my reading, both the new and old were valid pri
| |
| 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 |