* Performs fixed/sticky actions. * 1. Updates `top` styling if necessary. * 2. On iOS/Iframe moves elements between fixed layer and BODY depending on * whether they are currently visible and fixed * @return {!Promise}
()
| 394 | * @return {!Promise} |
| 395 | */ |
| 396 | update() { |
| 397 | // Some of the elements may no longer be in DOM. |
| 398 | /** @type {!Array<!ElementDef>} */ |
| 399 | const toRemove = this.elements_.filter( |
| 400 | (fe) => !this.ampdoc.contains(fe.element) |
| 401 | ); |
| 402 | toRemove.forEach((fe) => this.tearDownElement_(fe.element)); |
| 403 | |
| 404 | if (this.elements_.length == 0) { |
| 405 | return Promise.resolve(); |
| 406 | } |
| 407 | |
| 408 | // Clear out the update pass since we're doing the work now. |
| 409 | this.updatePass_.cancel(); |
| 410 | |
| 411 | // Next, the positioning-related properties will be measured. If a |
| 412 | // potentially fixed/sticky element turns out to be actually fixed/sticky, |
| 413 | // it will be decorated and possibly moved to a separate layer. |
| 414 | let hasTransferables = false; |
| 415 | return this.vsync_ |
| 416 | .runPromise( |
| 417 | { |
| 418 | measure: (state) => { |
| 419 | const elements = this.elements_; |
| 420 | const autoTops = []; |
| 421 | const {win} = this.ampdoc; |
| 422 | |
| 423 | // Notice that this code intentionally breaks vsync contract. |
| 424 | // Unfortunately, there's no way to reliably test whether or not |
| 425 | // `top` has been set to a non-auto value on all platforms. To work |
| 426 | // this around, this code compares `style.top` values with a new |
| 427 | // `style.bottom` value. |
| 428 | // 1. Unset top from previous mutates and set bottom to an extremely |
| 429 | // large value (to catch cases where sticky-tops are in a long way |
| 430 | // down inside a scroller). |
| 431 | for (let i = 0; i < elements.length; i++) { |
| 432 | setImportantStyles(elements[i].element, { |
| 433 | top: '', |
| 434 | bottom: '-9999vh', |
| 435 | transition: 'none', |
| 436 | }); |
| 437 | } |
| 438 | // 2. Capture the `style.top` with this new `style.bottom` value. If |
| 439 | // this element has a non-auto top, this value will remain constant |
| 440 | // regardless of bottom. |
| 441 | for (let i = 0; i < elements.length; i++) { |
| 442 | autoTops.push(computedStyle(win, elements[i].element).top); |
| 443 | } |
| 444 | // 3. Cleanup the `style.bottom`. |
| 445 | for (let i = 0; i < elements.length; i++) { |
| 446 | setStyle(elements[i].element, 'bottom', ''); |
| 447 | } |
| 448 | |
| 449 | for (let i = 0; i < elements.length; i++) { |
| 450 | const fe = elements[i]; |
| 451 | const {element, forceTransfer} = fe; |
| 452 | const style = computedStyle(win, element); |
| 453 |
no test coverage detected