Introduce a new attemptCollapse function#7532
Conversation
75ce93e to
ea13475
Compare
| return this.attemptChangeHeight(0).then(() => { | ||
| this./*OK*/collapse(); | ||
| }, () => {}); | ||
| return this.attemptCollapse().then(() => {}, () => {}); |
There was a problem hiding this comment.
Just need a catch block.
src/base-element.js
Outdated
| * @public | ||
| */ | ||
| attemptCollapse() { | ||
| return this.element.getResources().attemptCollapse( |
There was a problem hiding this comment.
Why do we need to pass width and height?
There was a problem hiding this comment.
Fail to cleanup, will delete
src/service/resource.js
Outdated
| this.element.updateLayoutBox(box); | ||
| } | ||
| /** | ||
| * Collapse on changing height/width to 0 |
There was a problem hiding this comment.
My fault. Will clean up
| * @return {!Promise} | ||
| */ | ||
| attemptCollapse(element) { | ||
| return new Promise((resolve, reject) => { |
There was a problem hiding this comment.
Let's just call #attemptChangeSize:
attemptCollapse(element) {
this.attemptChangeSize(element, 0, undefined).then(() => {
const resource = Resource.forElement(element);
resource.completeCollapse();
});
}There was a problem hiding this comment.
That's the thing that I want to fix in this PR.
#attemptChangeSize success, resources manager does some calculation to adjust scrollTop, we then immediately collapse the element the previous measurement gives incorrect value which results in a page jump.
|
We need a really good test that will fail if anyone ever does #7532 (comment). |
ads/_ping_.js
Outdated
| } | ||
| } else { | ||
| global.context.noContentAvailable(); | ||
| window.setTimeout(() => { |
There was a problem hiding this comment.
does this work: global.setTimeout(global.context.noContentAvailable, 1000) ?
There was a problem hiding this comment.
yup, I changed to using global
|
@jridgewell You have any ideas on the test? |
|
I don't understand where the measure is coming from that is incorrect. But you could stub that, and make sure the element is |
|
@jridgewell that won't help me from preventing anyone from calling. As a call like this is still valid. And they would both trigger measurement. |
|
Sorry, I missed the second sentence in your comment. But, I was talking about prevent someone from doing the refactor I suggested. We need a test to make sure that doesn't happen. |
|
|
||
| /** | ||
| * Return a promise that request the runtime to collapse one element | ||
| * @return {!Promise} |
|
@jridgewell Finally add some test coverage. Ugly test though... |
|
👀 |
| // Functions | ||
| '\\.changeHeight\\(': bannedTermsHelpString, | ||
| '\\.changeSize\\(': bannedTermsHelpString, | ||
| '\\.attemptChangeHeight\\(0\\)': 'please consider using `attemptCollapse()`', |
There was a problem hiding this comment.
Why not use a dev().assert? We could catch both height = 0 and width = 0 changes then.
There was a problem hiding this comment.
That's good point. But it is possible that an iframe request leads runtime to call attemptChangeSize(newWidth=0, newHeight=0). It is perfectly valid without setting element display to none afterwards.
The thing I want avoid is us explicitly put 0 as the input. dev().assert is too strict, maybe I can switch to dev().warn. honestly i feel presubmit check should be sufficient.
There was a problem hiding this comment.
Or, let's forward to #attemptCollapse when we receive 0?
There was a problem hiding this comment.
That's what I was planning to do at first, just add a check inside #attemptChangeSize. Then we realize once an iframe send us request to resize to (0, 0), they will never be able to resize again because we don't remove the display:none for them.
| }); | ||
| }); | ||
|
|
||
| it('attemptCollapse should not call attemptChangeSize', () => { |
There was a problem hiding this comment.
We're targeting the scrollAdjSet path, right?
If so, we should be able to avoid the getScrollHeight stub, and just assert that resource1#completeCollapse has ben called before resource1#getLayoutBox.
There was a problem hiding this comment.
but #completeCollapse gets called after #getLayoutBox.
https://github.com/ampproject/amphtml/blob/master/src/service/resources-impl.js#L1029
Or should I reorder the call, as I feel the order doesn't matter here. It makes more sense to call #changeSize first and then measure layout box.
There was a problem hiding this comment.
Ah, I confused the sync and async paths. I think re-ordering the calls might be best.
There was a problem hiding this comment.
will go with re-ordering calls
There was a problem hiding this comment.
Sorry for going back and forth. But few things I found:
request.callback()can do something to affect elementlayoutBox. For example we are settingresource.isFixedto false when we call#completeCollapsein the callback. This won't be an issue for us because we will also manually update elementlayoutBoxin#completeCollapsecall.- So I can still go with re-ordering calls, and assert
#completeCollapsegets called before#getLayoutBox. However just like what I do with#getScrollHeight#getLayoutBoxgets called 2 times in the test path. here and here. I fell I will still need to stub#getLayoutBoxto assert on the second call. which makes no difference between my current test approach.
One other thing that's not related to this PR:
if we resize an fixed element, is it likely that it won't affect other elements layout on the page. Maybe we can add some optimization by not updating minTop here if element is position fixed.
* still need tests * need to fix test * fix lint * nit * add test coverage
when we try to collapse an element we do things like:
We do some measurements after height is set to 0, and before we call
element.collapse(); However with display:inline-block, it is still possible for layout to change from height = 0 to display: none. [Looks like a well know CSS issue] Then the previous measure will give wrong result. https://github.com/ampproject/amphtml/blob/master/src/service/resources-impl.js#L1036In this PR I am trying to introduce a new method call
attemptCollapse, and it will call resourcesscheduleChangeSize_with a callback function to set display none.Still need to work on adding test coverage.