Skip to content

Commit eb847a4

Browse files
authored
Merge branch 'master' into css-unit-value-inset
2 parents 6cf1d53 + 0db3973 commit eb847a4

File tree

4 files changed

+64
-31
lines changed

4 files changed

+64
-31
lines changed

src/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {
1818
} from "./scroll-timeline-base";
1919
import {
2020
animate,
21+
elementGetAnimations,
22+
documentGetAnimations,
2123
ProxyAnimation
2224
} from "./proxy-animation.js";
2325

@@ -61,6 +63,16 @@ function initPolyfill() {
6163
if (!Reflect.defineProperty(window, 'Animation', { value: ProxyAnimation })) {
6264
throw Error('Error installing Animation constructor.');
6365
}
66+
if (!Reflect.defineProperty(Element.prototype, "getAnimations", { value: elementGetAnimations })) {
67+
throw Error(
68+
"Error installing ScrollTimeline polyfill: could not attach WAAPI's getAnimations to DOM Element"
69+
);
70+
}
71+
if (!Reflect.defineProperty(document, "getAnimations", { value: documentGetAnimations })) {
72+
throw Error(
73+
"Error installing ScrollTimeline polyfill: could not attach WAAPI's getAnimations to document"
74+
);
75+
}
6476
}
6577

6678
initPolyfill();

src/proxy-animation.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
relativePosition
66
} from "./scroll-timeline-base";
77

8+
const nativeDocumentGetAnimations = document.getAnimations;
9+
const nativeElementGetAnimations = window.Element.prototype.getAnimations;
810
const nativeElementAnimate = window.Element.prototype.animate;
911
const nativeAnimation = window.Animation;
1012

@@ -829,6 +831,20 @@ function fractionalEndDelay(details) {
829831
return 1 - relativePosition(details.timeline, endTime.rangeName, endTime.offset);
830832
}
831833

834+
// Map from an instance of ProxyAnimation to internal details about that animation.
835+
// See ProxyAnimation constructor for details.
836+
let proxyAnimations = new WeakMap();
837+
838+
// Clear cache containing the ProxyAnimation instances when leaving the page.
839+
// See https://github.com/flackr/scroll-timeline/issues/146#issuecomment-1698159183
840+
// for details.
841+
window.addEventListener('pagehide', (e) => {
842+
proxyAnimations = new WeakMap();
843+
}, false);
844+
845+
// Map from the real underlying native animation to the ProxyAnimation proxy of it.
846+
let proxiedAnimations = new WeakMap();
847+
832848
/**
833849
* Procedure for calculating an auto-aligned start time.
834850
* https://drafts.csswg.org/web-animations-2/#animation-calculating-an-auto-aligned-start-time
@@ -886,15 +902,14 @@ function autoAlignStartTime(details) {
886902
// Create an alternate Animation class which proxies API requests.
887903
// TODO: Create a full-fledged proxy so missing methods are automatically
888904
// fetched from Animation.
889-
let proxyAnimations = new WeakMap();
890-
891905
export class ProxyAnimation {
892906
constructor(effect, timeline, animOptions={}) {
893907
const animation =
894908
(effect instanceof nativeAnimation) ?
895909
effect : new nativeAnimation(effect, animationTimeline);
896910
const isScrollAnimation = timeline instanceof ScrollTimeline;
897911
const animationTimeline = isScrollAnimation ? undefined : timeline;
912+
proxiedAnimations.set(animation, this);
898913
proxyAnimations.set(this, {
899914
animation: animation,
900915
timeline: isScrollAnimation ? timeline : undefined,
@@ -1817,4 +1832,24 @@ export function animate(keyframes, options) {
18171832
}
18181833

18191834
return proxyAnimation;
1820-
};
1835+
}
1836+
1837+
function replaceProxiedAnimations(animationsList) {
1838+
for (let i = 0; i < animationsList.length; ++i) {
1839+
let proxyAnimation = proxiedAnimations.get(animationsList[i]);
1840+
if (proxyAnimation) {
1841+
animationsList[i] = proxyAnimation;
1842+
}
1843+
}
1844+
return animationsList;
1845+
}
1846+
1847+
export function elementGetAnimations(options) {
1848+
let animations = nativeElementGetAnimations.apply(this, [options]);
1849+
return replaceProxiedAnimations(animations);
1850+
}
1851+
1852+
export function documentGetAnimations(options) {
1853+
let animations = nativeDocumentGetAnimations.apply(this, [options]);
1854+
return replaceProxiedAnimations(animations);
1855+
}

src/scroll-timeline-css.js

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -140,37 +140,23 @@ export function initCSSPolyfill() {
140140

141141
initMutationObserver();
142142

143-
// Cache all Proxy Animations
144-
let proxyAnimations = new WeakMap();
145-
146143
// We are not wrapping capturing 'animationstart' by a 'load' event,
147144
// because we may lose some of the 'animationstart' events by the time 'load' is completed.
148145
window.addEventListener('animationstart', (evt) => {
149146
evt.target.getAnimations().filter(anim => anim.animationName === evt.animationName).forEach(anim => {
150-
// Create a per-element cache
151-
if (!proxyAnimations.has(evt.target)) {
152-
proxyAnimations.set(evt.target, new Map());
153-
}
154-
const elementProxyAnimations = proxyAnimations.get(evt.target);
155-
156-
// Store Proxy Animation in the cache
157-
if (!elementProxyAnimations.has(anim.animationName)) {
158-
const result = createScrollTimeline(anim, anim.animationName, evt.target);
159-
if (result && result.timeline && anim.timeline != result.timeline) {
160-
elementProxyAnimations.set(anim.animationName, new ProxyAnimation(anim, result.timeline, result.animOptions));
147+
const result = createScrollTimeline(anim, anim.animationName, evt.target);
148+
if (result) {
149+
// If the CSS Animation refers to a scroll or view timeline we need to proxy the animation instance.
150+
if (result.timeline && !(anim instanceof ProxyAnimation)) {
151+
const proxyAnimation = new ProxyAnimation(anim, result.timeline, result.animOptions);
152+
anim.pause();
153+
proxyAnimation.play();
161154
} else {
162-
elementProxyAnimations.set(anim.animationName, null);
155+
// If the timeline was removed or the animation was already an instance of a proxy animation,
156+
// invoke the set the timeline procedure on the existing animation.
157+
anim.timeline = result.timeline;
163158
}
164159
}
165-
166-
// Get Proxy Animation from cache
167-
const proxyAnimation = elementProxyAnimations.get(anim.animationName);
168-
169-
// Swap the original animation with the proxied one
170-
if (proxyAnimation !== null) {
171-
anim.pause();
172-
proxyAnimation.play();
173-
}
174160
});
175161
});
176162

test/expected.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ FAIL /scroll-animations/css/animation-timeline-deferred.html Animation.timeline
7979
FAIL /scroll-animations/css/animation-timeline-deferred.html Animation.timeline returns null for inactive deferred timeline
8080
FAIL /scroll-animations/css/animation-timeline-deferred.html Animation.timeline returns null for inactive (overattached) deferred timeline
8181
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html Changing animation-timeline changes the timeline (sanity check)
82-
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (ScrollTimeline from JS)
82+
PASS /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (ScrollTimeline from JS)
8383
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (ScrollTimeline from CSS)
84-
PASS /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (document timeline)
85-
PASS /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (null)
84+
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (document timeline)
85+
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (null)
8686
FAIL /scroll-animations/css/animation-timeline-in-keyframe.html The animation-timeline property may not be used in keyframes
8787
PASS /scroll-animations/css/animation-timeline-multiple.html animation-timeline works with multiple timelines
8888
FAIL /scroll-animations/css/animation-timeline-none.html Animation with animation-timeline:none holds current time at zero
@@ -957,4 +957,4 @@ FAIL /scroll-animations/view-timelines/view-timeline-sticky-block.html View time
957957
FAIL /scroll-animations/view-timelines/view-timeline-sticky-inline.html View timeline with sticky target, block axis.
958958
FAIL /scroll-animations/view-timelines/view-timeline-subject-size-changes.html View timeline with subject size change after the creation of the animation
959959
FAIL /scroll-animations/view-timelines/zero-intrinsic-iteration-duration.tentative.html Intrinsic iteration duration is non-negative
960-
Passed 432 of 959 tests.
960+
Passed 431 of 959 tests.

0 commit comments

Comments
 (0)