Skip to content

Commit

Permalink
Merge branch 'master' into css-unit-value-inset
Browse files Browse the repository at this point in the history
  • Loading branch information
flackr authored Dec 21, 2023
2 parents 6cf1d53 + 0db3973 commit eb847a4
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 31 deletions.
12 changes: 12 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
} from "./scroll-timeline-base";
import {
animate,
elementGetAnimations,
documentGetAnimations,
ProxyAnimation
} from "./proxy-animation.js";

Expand Down Expand Up @@ -61,6 +63,16 @@ function initPolyfill() {
if (!Reflect.defineProperty(window, 'Animation', { value: ProxyAnimation })) {
throw Error('Error installing Animation constructor.');
}
if (!Reflect.defineProperty(Element.prototype, "getAnimations", { value: elementGetAnimations })) {
throw Error(
"Error installing ScrollTimeline polyfill: could not attach WAAPI's getAnimations to DOM Element"
);
}
if (!Reflect.defineProperty(document, "getAnimations", { value: documentGetAnimations })) {
throw Error(
"Error installing ScrollTimeline polyfill: could not attach WAAPI's getAnimations to document"
);
}
}

initPolyfill();
41 changes: 38 additions & 3 deletions src/proxy-animation.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
relativePosition
} from "./scroll-timeline-base";

const nativeDocumentGetAnimations = document.getAnimations;
const nativeElementGetAnimations = window.Element.prototype.getAnimations;
const nativeElementAnimate = window.Element.prototype.animate;
const nativeAnimation = window.Animation;

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

// Map from an instance of ProxyAnimation to internal details about that animation.
// See ProxyAnimation constructor for details.
let proxyAnimations = new WeakMap();

// Clear cache containing the ProxyAnimation instances when leaving the page.
// See https://github.com/flackr/scroll-timeline/issues/146#issuecomment-1698159183
// for details.
window.addEventListener('pagehide', (e) => {
proxyAnimations = new WeakMap();
}, false);

// Map from the real underlying native animation to the ProxyAnimation proxy of it.
let proxiedAnimations = new WeakMap();

/**
* Procedure for calculating an auto-aligned start time.
* https://drafts.csswg.org/web-animations-2/#animation-calculating-an-auto-aligned-start-time
Expand Down Expand Up @@ -886,15 +902,14 @@ function autoAlignStartTime(details) {
// Create an alternate Animation class which proxies API requests.
// TODO: Create a full-fledged proxy so missing methods are automatically
// fetched from Animation.
let proxyAnimations = new WeakMap();

export class ProxyAnimation {
constructor(effect, timeline, animOptions={}) {
const animation =
(effect instanceof nativeAnimation) ?
effect : new nativeAnimation(effect, animationTimeline);
const isScrollAnimation = timeline instanceof ScrollTimeline;
const animationTimeline = isScrollAnimation ? undefined : timeline;
proxiedAnimations.set(animation, this);
proxyAnimations.set(this, {
animation: animation,
timeline: isScrollAnimation ? timeline : undefined,
Expand Down Expand Up @@ -1817,4 +1832,24 @@ export function animate(keyframes, options) {
}

return proxyAnimation;
};
}

function replaceProxiedAnimations(animationsList) {
for (let i = 0; i < animationsList.length; ++i) {
let proxyAnimation = proxiedAnimations.get(animationsList[i]);
if (proxyAnimation) {
animationsList[i] = proxyAnimation;
}
}
return animationsList;
}

export function elementGetAnimations(options) {
let animations = nativeElementGetAnimations.apply(this, [options]);
return replaceProxiedAnimations(animations);
}

export function documentGetAnimations(options) {
let animations = nativeDocumentGetAnimations.apply(this, [options]);
return replaceProxiedAnimations(animations);
}
34 changes: 10 additions & 24 deletions src/scroll-timeline-css.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,37 +140,23 @@ export function initCSSPolyfill() {

initMutationObserver();

// Cache all Proxy Animations
let proxyAnimations = new WeakMap();

// We are not wrapping capturing 'animationstart' by a 'load' event,
// because we may lose some of the 'animationstart' events by the time 'load' is completed.
window.addEventListener('animationstart', (evt) => {
evt.target.getAnimations().filter(anim => anim.animationName === evt.animationName).forEach(anim => {
// Create a per-element cache
if (!proxyAnimations.has(evt.target)) {
proxyAnimations.set(evt.target, new Map());
}
const elementProxyAnimations = proxyAnimations.get(evt.target);

// Store Proxy Animation in the cache
if (!elementProxyAnimations.has(anim.animationName)) {
const result = createScrollTimeline(anim, anim.animationName, evt.target);
if (result && result.timeline && anim.timeline != result.timeline) {
elementProxyAnimations.set(anim.animationName, new ProxyAnimation(anim, result.timeline, result.animOptions));
const result = createScrollTimeline(anim, anim.animationName, evt.target);
if (result) {
// If the CSS Animation refers to a scroll or view timeline we need to proxy the animation instance.
if (result.timeline && !(anim instanceof ProxyAnimation)) {
const proxyAnimation = new ProxyAnimation(anim, result.timeline, result.animOptions);
anim.pause();
proxyAnimation.play();
} else {
elementProxyAnimations.set(anim.animationName, null);
// If the timeline was removed or the animation was already an instance of a proxy animation,
// invoke the set the timeline procedure on the existing animation.
anim.timeline = result.timeline;
}
}

// Get Proxy Animation from cache
const proxyAnimation = elementProxyAnimations.get(anim.animationName);

// Swap the original animation with the proxied one
if (proxyAnimation !== null) {
anim.pause();
proxyAnimation.play();
}
});
});

Expand Down
8 changes: 4 additions & 4 deletions test/expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ FAIL /scroll-animations/css/animation-timeline-deferred.html Animation.timeline
FAIL /scroll-animations/css/animation-timeline-deferred.html Animation.timeline returns null for inactive deferred timeline
FAIL /scroll-animations/css/animation-timeline-deferred.html Animation.timeline returns null for inactive (overattached) deferred timeline
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html Changing animation-timeline changes the timeline (sanity check)
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (ScrollTimeline from JS)
PASS /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (ScrollTimeline from JS)
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (ScrollTimeline from CSS)
PASS /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (document timeline)
PASS /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (null)
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (document timeline)
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html animation-timeline ignored after setting timeline with JS (null)
FAIL /scroll-animations/css/animation-timeline-in-keyframe.html The animation-timeline property may not be used in keyframes
PASS /scroll-animations/css/animation-timeline-multiple.html animation-timeline works with multiple timelines
FAIL /scroll-animations/css/animation-timeline-none.html Animation with animation-timeline:none holds current time at zero
Expand Down Expand Up @@ -957,4 +957,4 @@ FAIL /scroll-animations/view-timelines/view-timeline-sticky-block.html View time
FAIL /scroll-animations/view-timelines/view-timeline-sticky-inline.html View timeline with sticky target, block axis.
FAIL /scroll-animations/view-timelines/view-timeline-subject-size-changes.html View timeline with subject size change after the creation of the animation
FAIL /scroll-animations/view-timelines/zero-intrinsic-iteration-duration.tentative.html Intrinsic iteration duration is non-negative
Passed 432 of 959 tests.
Passed 431 of 959 tests.

0 comments on commit eb847a4

Please sign in to comment.