# HG changeset patch # User Daisuke Akatsuka # Date 1521526235 -32400 # Node ID 5e7233f63d44a65391136d5c2d5c2af66cb21c75 # Parent 723feb3465f872f27430c770cc99106c5a06d3a1 Bug 1437730 - Part 2: Update animation inspector to reflect animation modification. r=gl MozReview-Commit-ID: 35hgVGujptl diff --git a/devtools/client/inspector/animation/animation.js b/devtools/client/inspector/animation/animation.js --- a/devtools/client/inspector/animation/animation.js +++ b/devtools/client/inspector/animation/animation.js @@ -45,16 +45,17 @@ class AnimationInspector { this.setAnimationsPlaybackRate = this.setAnimationsPlaybackRate.bind(this); this.setAnimationsPlayState = this.setAnimationsPlayState.bind(this); this.setDetailVisibility = this.setDetailVisibility.bind(this); this.simulateAnimation = this.simulateAnimation.bind(this); this.simulateAnimationForKeyframesProgressBar = this.simulateAnimationForKeyframesProgressBar.bind(this); this.toggleElementPicker = this.toggleElementPicker.bind(this); this.update = this.update.bind(this); + this.onAnimationStateChanged = this.onAnimationStateChanged.bind(this); this.onAnimationsCurrentTimeUpdated = this.onAnimationsCurrentTimeUpdated.bind(this); this.onAnimationsMutation = this.onAnimationsMutation.bind(this); this.onCurrentTimeTimerUpdated = this.onCurrentTimeTimerUpdated.bind(this); this.onElementPickerStarted = this.onElementPickerStarted.bind(this); this.onElementPickerStopped = this.onElementPickerStopped.bind(this); this.onSidebarResized = this.onSidebarResized.bind(this); this.onSidebarSelect = this.onSidebarSelect.bind(this); @@ -138,16 +139,17 @@ class AnimationInspector { this.inspector.toolbox.on("inspector-sidebar-resized", this.onSidebarResized); this.inspector.toolbox.on("picker-started", this.onElementPickerStarted); this.inspector.toolbox.on("picker-stopped", this.onElementPickerStopped); this.animationsFront.on("mutations", this.onAnimationsMutation); } destroy() { + this.setAnimationStateChangedListenerEnabled(false); this.inspector.selection.off("new-node-front", this.update); this.inspector.sidebar.off("newanimationinspector-selected", this.onSidebarSelect); this.inspector.toolbox.off("inspector-sidebar-resized", this.onSidebarResized); this.inspector.toolbox.off("picker-started", this.onElementPickerStarted); this.inspector.toolbox.off("picker-stopped", this.onElementPickerStopped); this.animationsFront.off("mutations", this.onAnimationsMutation); @@ -242,16 +244,21 @@ class AnimationInspector { } isPanelVisible() { return this.inspector && this.inspector.toolbox && this.inspector.sidebar && this.inspector.toolbox.currentToolId === "inspector" && this.inspector.sidebar.getCurrentTabID() === "newanimationinspector"; } + onAnimationStateChanged() { + // Simply update the animations since the state has already been updated. + this.updateState([...this.state.animations]); + } + /** * This method should call when the current time is changed. * Then, dispatches the current time to listeners that are registered * by addAnimationsCurrentTimeListener. * * @param {Number} currentTime */ onAnimationsCurrentTimeUpdated(currentTime) { @@ -350,25 +357,31 @@ class AnimationInspector { if (shouldRefresh) { this.updateState([...animations]); } } async setAnimationsPlaybackRate(playbackRate) { const animations = this.state.animations; + // "changed" event on each animation will fire respectively when the playback + // rate changed. Since for each occurrence of event, change of UI is urged. + // To avoid this, disable the listeners once in order to not capture the event. + this.setAnimationStateChangedListenerEnabled(false); try { await this.animationsFront.setPlaybackRates(animations, playbackRate); await this.updateAnimations(animations); } catch (e) { // Expected if we've already been destroyed or other node have been selected // in the meantime. console.error(e); return; + } finally { + this.setAnimationStateChangedListenerEnabled(true); } await this.updateState([...animations]); } async setAnimationsPlayState(doPlay) { try { if (doPlay) { @@ -383,16 +396,35 @@ class AnimationInspector { // in the meantime. console.error(e); return; } await this.updateState([...this.state.animations]); } + /** + * Enable/disable the animation state change listener. + * If set true, observe "changed" event on current animations. + * Otherwise, quit observing the "changed" event. + * + * @param {Bool} isEnabled + */ + setAnimationStateChangedListenerEnabled(isEnabled) { + if (isEnabled) { + for (const animation of this.state.animations) { + animation.on("changed", this.onAnimationStateChanged); + } + } else { + for (const animation of this.state.animations) { + animation.off("changed", this.onAnimationStateChanged); + } + } + } + setDetailVisibility(isVisible) { this.inspector.store.dispatch(updateDetailVisibility(isVisible)); } /** * Returns simulatable animation by given parameters. * The returned animation is implementing Animation interface of Web Animation API. * https://drafts.csswg.org/web-animations/#the-animation-interface @@ -523,15 +555,17 @@ class AnimationInspector { }); } updateState(animations) { this.stopAnimationsCurrentTimeTimer(); this.inspector.store.dispatch(updateAnimations(animations)); + this.setAnimationStateChangedListenerEnabled(true); + if (hasRunningAnimation(animations)) { this.startAnimationsCurrentTimeTimer(); } } } module.exports = AnimationInspector;