Chromium Code Reviews| Index: ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js |
| diff --git a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js |
| index 854a812d00a94af6babd12cf556b80d0f8735000..36c742341a56fc2b56a739908f07dcc38fdaa87e 100644 |
| --- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js |
| +++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js |
| @@ -6,14 +6,14 @@ |
| * @typedef {{ |
| * top: number, |
| * left: number, |
| - * width: (number| undefined), |
| - * height: (number| undefined), |
| - * anchorAlignmentX: (number| undefined), |
| - * anchorAlignmentY: (number| undefined), |
| - * minX: (number| undefined), |
| - * minY: (number| undefined), |
| - * maxX: (number| undefined), |
| - * maxY: (number| undefined), |
| + * width: (number|undefined), |
| + * height: (number|undefined), |
| + * anchorAlignmentX: (number|undefined), |
| + * anchorAlignmentY: (number|undefined), |
| + * minX: (number|undefined), |
| + * minY: (number|undefined), |
| + * maxX: (number|undefined), |
| + * maxY: (number|undefined), |
| * }} |
| */ |
| var ShowConfig; |
| @@ -73,7 +73,6 @@ function getStartPointWithAnchor( |
| return startPoint; |
| } |
| - |
| /** |
| * @private |
| * @return {!ShowConfig} |
| @@ -86,10 +85,10 @@ function getDefaultShowConfig() { |
| width: 0, |
| anchorAlignmentX: AnchorAlignment.AFTER_START, |
| anchorAlignmentY: AnchorAlignment.AFTER_START, |
| - minX: 0, |
| - minY: 0, |
| - maxX: window.innerWidth, |
| - maxY: window.innerHeight, |
| + minX: document.body.scrollLeft, |
| + minY: document.body.scrollTop, |
| + maxX: document.body.scrollLeft + window.innerWidth, |
| + maxY: document.body.scrollTop + window.innerHeight, |
| }; |
| } |
| @@ -252,19 +251,48 @@ Polymer({ |
| /** |
| * Shows the menu anchored to the given element. |
| * @param {!Element} anchorElement |
| + * @param {ShowConfig=} opt_config |
| */ |
| - showAt: function(anchorElement) { |
| + showAt: function(anchorElement, opt_config) { |
| this.anchorElement_ = anchorElement; |
| + // Scroll the anchor element into view so that the bounding rect will be |
| + // accurate for where the menu should be shown. |
| this.anchorElement_.scrollIntoViewIfNeeded(); |
| + |
| + // Save the scroll position that ensures the anchor element is onscreen. |
| + var scrollLeft = document.body.scrollLeft; |
| + var scrollTop = document.body.scrollTop; |
| + |
| + // Reset position so that layout isn't affected by the previous position, |
| + // and so that the dialog is positioned at the top-start corner of the |
| + // document. |
| + this.resetStyle_(); |
|
dpapad
2017/06/22 21:18:37
After patching this CL locally I discovered an und
calamity
2017/06/28 04:00:47
Changed to use document.scrollingElement instead o
|
| + |
| + // Show the dialog which will focus the top-start of the body. This makes |
| + // the client rect calculation relative to the top-start of the body. |
| + this.showModal(); |
| + |
| var rect = this.anchorElement_.getBoundingClientRect(); |
| - this.showAtPosition({ |
| - top: rect.top, |
| - left: rect.left, |
| - height: rect.height, |
| - width: rect.width, |
| - // Default to anchoring towards the left. |
| - anchorAlignmentX: AnchorAlignment.BEFORE_END, |
| - }); |
| + this.positionDialog_(/** @type {ShowConfig} */ (Object.assign( |
| + { |
| + top: rect.top, |
| + left: rect.left, |
| + height: rect.height, |
| + width: rect.width, |
| + // Default to anchoring towards the left. |
| + anchorAlignmentX: AnchorAlignment.BEFORE_END, |
| + minX: scrollLeft, |
| + minY: scrollTop, |
| + maxX: scrollLeft + window.innerWidth, |
| + maxY: scrollTop + window.innerHeight, |
| + }, |
| + opt_config))); |
| + |
| + // Restore the scroll position. |
| + document.body.scrollTop = scrollTop; |
| + document.body.scrollLeft = scrollLeft; |
| + |
| + this.addCloseListeners_(); |
| }, |
| /** |
| @@ -294,6 +322,24 @@ Polymer({ |
| * @param {!ShowConfig} config |
| */ |
| showAtPosition: function(config) { |
| + this.resetStyle_(); |
| + this.showModal(); |
| + this.positionDialog_(config); |
| + this.addCloseListeners_(); |
| + }, |
| + |
| + /** @private */ |
| + resetStyle_: function() { |
| + this.style.left = ''; |
| + this.style.right = ''; |
| + this.style.top = '0'; |
| + }, |
| + |
| + /** |
| + * @param {!ShowConfig} config |
| + * @private |
| + */ |
| + positionDialog_: function(config) { |
| var c = Object.assign(getDefaultShowConfig(), config); |
| var top = c.top; |
| @@ -301,20 +347,6 @@ Polymer({ |
| var bottom = top + c.height; |
| var right = left + c.width; |
| - this.boundClose_ = this.boundClose_ || function() { |
| - if (this.open) |
| - this.close(); |
| - }.bind(this); |
| - window.addEventListener('resize', this.boundClose_); |
| - window.addEventListener('popstate', this.boundClose_); |
| - |
| - // Reset position to prevent previous values from affecting layout. |
| - this.style.left = ''; |
| - this.style.right = ''; |
| - this.style.top = ''; |
| - |
| - this.showModal(); |
| - |
| // Flip the X anchor in RTL. |
| var rtl = getComputedStyle(this).direction == 'rtl'; |
| if (rtl) |
| @@ -324,7 +356,7 @@ Polymer({ |
| left, right, this.offsetWidth, c.anchorAlignmentX, c.minX, c.maxX); |
| if (rtl) { |
| - var menuRight = window.innerWidth - menuLeft - this.offsetWidth; |
| + var menuRight = document.body.scrollWidth - menuLeft - this.offsetWidth; |
| this.style.right = menuRight + 'px'; |
| } else { |
| this.style.left = menuLeft + 'px'; |
| @@ -334,5 +366,17 @@ Polymer({ |
| top, bottom, this.offsetHeight, c.anchorAlignmentY, c.minY, c.maxY); |
| this.style.top = menuTop + 'px'; |
| }, |
| + |
| + /** |
| + * @private |
| + */ |
| + addCloseListeners_: function() { |
| + this.boundClose_ = this.boundClose_ || function() { |
| + if (this.open) |
| + this.close(); |
| + }.bind(this); |
| + window.addEventListener('resize', this.boundClose_); |
| + window.addEventListener('popstate', this.boundClose_); |
| + }, |
| }); |
| })(); |