Bug 1456828 - Part 2: Apply ProgressInspectionPanel to animations. r?gl
MozReview-Commit-ID: 7It2CibH3oa
--- a/devtools/client/inspector/animation/components/AnimationListContainer.js
+++ b/devtools/client/inspector/animation/components/AnimationListContainer.js
@@ -1,21 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { createFactory, PureComponent } =
require("devtools/client/shared/vendor/react");
+const { connect } = require("devtools/client/shared/vendor/react-redux");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
-const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const AnimationList = createFactory(require("./AnimationList"));
-const AnimationListHeader = createFactory(require("./AnimationListHeader"));
+const CurrentTimeScrubberController =
+ createFactory(require("./CurrentTimeScrubberController"));
+const ProgressInspectionPanel = createFactory(require("./ProgressInspectionPanel"));
+
+const { findOptimalTimeInterval } = require("../utils/utils");
+
+// The minimum spacing between 2 time graduation headers in the timeline (px).
+const TIME_GRADUATION_MIN_SPACING = 40;
class AnimationListContainer extends PureComponent {
static get propTypes() {
return {
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
animations: PropTypes.arrayOf(PropTypes.object).isRequired,
emitEventForTest: PropTypes.func.isRequired,
getAnimatedPropertyMap: PropTypes.func.isRequired,
@@ -27,16 +36,54 @@ class AnimationListContainer extends Pur
setAnimationsCurrentTime: PropTypes.func.isRequired,
setHighlightedNode: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired,
simulateAnimation: PropTypes.func.isRequired,
timeScale: PropTypes.object.isRequired,
};
}
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ // tick labels and lines on the progress inspection panel
+ ticks: [],
+ };
+ }
+
+ componentDidMount() {
+ this.updateState(this.props);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.updateState(nextProps);
+ }
+
+ updateState(props) {
+ const { timeScale } = props;
+ const tickLinesEl = ReactDOM.findDOMNode(this).querySelector(".tick-lines");
+ const width = tickLinesEl.offsetWidth;
+ const animationDuration = timeScale.getDuration();
+ const minTimeInterval = TIME_GRADUATION_MIN_SPACING * animationDuration / width;
+ const intervalLength = findOptimalTimeInterval(minTimeInterval);
+ const intervalWidth = intervalLength * width / animationDuration;
+ const tickCount = width / intervalWidth;
+
+ const ticks = [];
+
+ for (let i = 0; i <= tickCount; i++) {
+ const position = i * intervalWidth * 100 / width;
+ const label = timeScale.formatTime(timeScale.distanceToRelativeTime(position));
+ ticks.push({ position, label });
+ }
+
+ this.setState({ ticks });
+ }
+
render() {
const {
addAnimationsCurrentTimeListener,
animations,
emitEventForTest,
getAnimatedPropertyMap,
getNodeFromActor,
onHideBoxModelHighlighter,
@@ -44,41 +91,53 @@ class AnimationListContainer extends Pur
removeAnimationsCurrentTimeListener,
selectAnimation,
setAnimationsCurrentTime,
setHighlightedNode,
setSelectedNode,
simulateAnimation,
timeScale,
} = this.props;
+ const { ticks } = this.state;
return dom.div(
{
className: "animation-list-container"
},
- AnimationListHeader(
- {
- addAnimationsCurrentTimeListener,
- removeAnimationsCurrentTimeListener,
- setAnimationsCurrentTime,
- timeScale,
- }
- ),
- AnimationList(
+ ProgressInspectionPanel(
{
- animations,
- emitEventForTest,
- getAnimatedPropertyMap,
- getNodeFromActor,
- onHideBoxModelHighlighter,
- onShowBoxModelHighlighterForNode,
- selectAnimation,
- setHighlightedNode,
- setSelectedNode,
- simulateAnimation,
- timeScale,
+ indicator: CurrentTimeScrubberController(
+ {
+ addAnimationsCurrentTimeListener,
+ removeAnimationsCurrentTimeListener,
+ setAnimationsCurrentTime,
+ timeScale,
+ }
+ ),
+ list: AnimationList(
+ {
+ animations,
+ emitEventForTest,
+ getAnimatedPropertyMap,
+ getNodeFromActor,
+ onHideBoxModelHighlighter,
+ onShowBoxModelHighlighterForNode,
+ selectAnimation,
+ setHighlightedNode,
+ setSelectedNode,
+ simulateAnimation,
+ timeScale,
+ }
+ ),
+ ticks,
}
)
);
}
}
-module.exports = AnimationListContainer;
+const mapStateToProps = state => {
+ return {
+ sidebarWidth: state.animations.sidebarSize ? state.animations.sidebarSize.width : 0
+ };
+};
+
+module.exports = connect(mapStateToProps)(AnimationListContainer);
deleted file mode 100644
--- a/devtools/client/inspector/animation/components/AnimationListHeader.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const { createFactory, PureComponent } =
- require("devtools/client/shared/vendor/react");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
-const dom = require("devtools/client/shared/vendor/react-dom-factories");
-
-const AnimationTimelineTickList = createFactory(require("./AnimationTimelineTickList"));
-const CurrentTimeScrubberController =
- createFactory(require("./CurrentTimeScrubberController"));
-
-class AnimationListHeader extends PureComponent {
- static get propTypes() {
- return {
- addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
- removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
- setAnimationsCurrentTime: PropTypes.func.isRequired,
- timeScale: PropTypes.object.isRequired,
- };
- }
-
- render() {
- const {
- addAnimationsCurrentTimeListener,
- removeAnimationsCurrentTimeListener,
- setAnimationsCurrentTime,
- timeScale,
- } = this.props;
-
- return dom.div(
- {
- className: "animation-list-header"
- },
- dom.div(
- {
- className: "devtools-toolbar"
- }
- ),
- AnimationTimelineTickList(
- {
- timeScale
- }
- ),
- CurrentTimeScrubberController(
- {
- addAnimationsCurrentTimeListener,
- removeAnimationsCurrentTimeListener,
- setAnimationsCurrentTime,
- timeScale,
- }
- )
- );
- }
-}
-
-module.exports = AnimationListHeader;
deleted file mode 100644
--- a/devtools/client/inspector/animation/components/AnimationTimelineTickItem.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const { PureComponent } = require("devtools/client/shared/vendor/react");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
-const dom = require("devtools/client/shared/vendor/react-dom-factories");
-
-class AnimationTimeTickItem extends PureComponent {
- static get propTypes() {
- return {
- position: PropTypes.number.isRequired,
- timeTickLabel: PropTypes.string.isRequired,
- };
- }
-
- render() {
- const { position, timeTickLabel } = this.props;
-
- return dom.div(
- {
- className: "animation-timeline-tick-item",
- style: { left: `${ position }%` }
- },
- timeTickLabel
- );
- }
-}
-
-module.exports = AnimationTimeTickItem;
deleted file mode 100644
--- a/devtools/client/inspector/animation/components/AnimationTimelineTickList.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const { Component, createFactory } = require("devtools/client/shared/vendor/react");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
-const dom = require("devtools/client/shared/vendor/react-dom-factories");
-const { connect } = require("devtools/client/shared/vendor/react-redux");
-const ReactDOM = require("devtools/client/shared/vendor/react-dom");
-
-const AnimationTimelineTickItem = createFactory(require("./AnimationTimelineTickItem"));
-
-const { findOptimalTimeInterval } = require("../utils/utils");
-
-// The minimum spacing between 2 time graduation headers in the timeline (px).
-const TIME_GRADUATION_MIN_SPACING = 40;
-
-class AnimationTimelineTickList extends Component {
- static get propTypes() {
- return {
- sidebarWidth: PropTypes.number.isRequired,
- timeScale: PropTypes.object.isRequired,
- };
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- tickList: [],
- };
- }
-
- componentDidMount() {
- this.updateTickList(this.props);
- }
-
- componentWillReceiveProps(nextProps) {
- this.updateTickList(nextProps);
- }
-
- shouldComponentUpdate(nextProps, nextState) {
- if (this.state.tickList.length !== nextState.tickList.length) {
- return true;
- }
-
- for (let i = 0; i < this.state.tickList.length; i++) {
- const currentTickItem = this.state.tickList[i];
- const nextTickItem = nextState.tickList[i];
-
- if (currentTickItem.timeTickLabel !== nextTickItem.timeTickLabel) {
- return true;
- }
- }
-
- return false;
- }
-
- updateTickList(props) {
- const { timeScale } = props;
- const tickListEl = ReactDOM.findDOMNode(this);
- const width = tickListEl.offsetWidth;
- const animationDuration = timeScale.getDuration();
- const minTimeInterval = TIME_GRADUATION_MIN_SPACING * animationDuration / width;
- const intervalLength = findOptimalTimeInterval(minTimeInterval);
- const intervalWidth = intervalLength * width / animationDuration;
- const tickCount = width / intervalWidth;
- const intervalPositionPercentage = 100 * intervalWidth / width;
-
- const tickList = [];
- for (let i = 0; i <= tickCount; i++) {
- const position = i * intervalPositionPercentage;
- const timeTickLabel =
- timeScale.formatTime(timeScale.distanceToRelativeTime(position));
- tickList.push({ position, timeTickLabel });
- }
-
- this.setState({ tickList });
- }
-
- render() {
- const { tickList } = this.state;
-
- return dom.div(
- {
- className: "animation-timeline-tick-list"
- },
- tickList.map(tickItem => AnimationTimelineTickItem(tickItem))
- );
- }
-}
-
-const mapStateToProps = state => {
- return {
- sidebarWidth: state.animations.sidebarSize ? state.animations.sidebarSize.width : 0
- };
-};
-
-module.exports = connect(mapStateToProps)(AnimationTimelineTickList);
--- a/devtools/client/inspector/animation/components/moz.build
+++ b/devtools/client/inspector/animation/components/moz.build
@@ -13,20 +13,17 @@ DevToolsModules(
'AnimatedPropertyListContainer.js',
'AnimatedPropertyListHeader.js',
'AnimatedPropertyName.js',
'AnimationDetailContainer.js',
'AnimationDetailHeader.js',
'AnimationItem.js',
'AnimationList.js',
'AnimationListContainer.js',
- 'AnimationListHeader.js',
'AnimationTarget.js',
- 'AnimationTimelineTickItem.js',
- 'AnimationTimelineTickList.js',
'AnimationToolbar.js',
'App.js',
'CurrentTimeLabel.js',
'CurrentTimeScrubber.js',
'CurrentTimeScrubberController.js',
'KeyframesProgressBar.js',
'KeyframesProgressTickItem.js',
'KeyframesProgressTickList.js',
--- a/devtools/client/inspector/animation/test/browser_animation_animation-timeline-tick.js
+++ b/devtools/client/inspector/animation/test/browser_animation_animation-timeline-tick.js
@@ -1,17 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following timeline tick items.
// * animation list header elements existence
-// * timeline tick item elements existence
-// * count and label of timeline tick elements changing by the sidebar width
+// * tick labels elements existence
+// * count and text of tick label elements changing by the sidebar width
const TimeScale = require("devtools/client/inspector/animation/utils/timescale");
const { findOptimalTimeInterval } =
require("devtools/client/inspector/animation/utils/utils");
// Should be kept in sync with TIME_GRADUATION_MIN_SPACING in
// AnimationTimeTickList component.
const TIME_GRADUATION_MIN_SPACING = 40;
@@ -24,48 +24,44 @@ add_task(async function() {
const timeScale = new TimeScale(animationInspector.state.animations);
info("Checking animation list header element existence");
const listContainerEl = panel.querySelector(".animation-list-container");
const listHeaderEl = listContainerEl.querySelector(".devtools-toolbar");
ok(listHeaderEl, "The header element should be in animation list container element");
info("Checking time tick item elements existence");
- assertTimelineTickItems(timeScale, listContainerEl);
- const timelineTickItemLength =
- listContainerEl.querySelectorAll(".animation-timeline-tick-item").length;
+ assertTickLabels(timeScale, listContainerEl);
+ const timelineTickItemLength = listContainerEl.querySelectorAll(".tick-label").length;
info("Checking timeline tick item elements after enlarge sidebar width");
await setSidebarWidth("100%", inspector);
- assertTimelineTickItems(timeScale, listContainerEl);
- ok(timelineTickItemLength <
- listContainerEl.querySelectorAll(".animation-timeline-tick-item").length,
+ assertTickLabels(timeScale, listContainerEl);
+ ok(timelineTickItemLength < listContainerEl.querySelectorAll(".tick-label").length,
"The timeline tick item elements should increase");
});
/**
- * Assert timeline tick item's position and label.
+ * Assert tick label's position and label.
*
* @param {TimeScale} - timeScale
* @param {Element} - listContainerEl
*/
-function assertTimelineTickItems(timeScale, listContainerEl) {
- const timelineTickListEl =
- listContainerEl.querySelector(".animation-timeline-tick-list");
+function assertTickLabels(timeScale, listContainerEl) {
+ const timelineTickListEl = listContainerEl.querySelector(".tick-labels");
ok(timelineTickListEl,
"The animation timeline tick list element should be in header");
const width = timelineTickListEl.offsetWidth;
const animationDuration = timeScale.getDuration();
const minTimeInterval = TIME_GRADUATION_MIN_SPACING * animationDuration / width;
const interval = findOptimalTimeInterval(minTimeInterval);
const expectedTickItem = Math.ceil(animationDuration / interval);
- const timelineTickItemEls =
- timelineTickListEl.querySelectorAll(".animation-timeline-tick-item");
+ const timelineTickItemEls = timelineTickListEl.querySelectorAll(".tick-label");
is(timelineTickItemEls.length, expectedTickItem,
"The expected number of timeline ticks were found");
info("Make sure graduations are evenly distributed and show the right times");
for (const [index, tickEl] of timelineTickItemEls.entries()) {
const left = parseFloat(tickEl.style.left);
const expectedPos = index * interval * 100 / animationDuration;
is(Math.round(left), Math.round(expectedPos),
--- a/devtools/client/themes/animation.css
+++ b/devtools/client/themes/animation.css
@@ -7,16 +7,17 @@
:root {
--animation-even-background-color: rgba(0, 0, 0, 0.05);
--command-pick-image: url(chrome://devtools/skin/images/command-pick.svg);
--devtools-toolbar-height: 24px;
--fast-track-image: url("images/animation-fast-track.svg");
--fill-color-cssanimation: var(--theme-contrast-background);
--fill-color-csstransition: var(--theme-highlight-blue);
--fill-color-scriptanimation: var(--theme-graphs-green);
+ --graph-height: 30px;
--graph-right-offset: 10px;
--keyframe-marker-shadow-color: #c4c4c4;
--pause-image: url(chrome://devtools/skin/images/pause.svg);
--progress-bar-color: #909090;
--resume-image: url(chrome://devtools/skin/images/play.svg);
--rewind-image: url(chrome://devtools/skin/images/rewind.svg);
--scrubber-color: #dd00a9;
--sidebar-width: 200px;
@@ -83,72 +84,29 @@ select.playback-rate-selector.devtools-b
}
.rewind-button::before {
background-image: var(--rewind-image);
}
/* Animation List Container */
.animation-list-container {
- height: 100%;
- overflow-y: auto;
- overflow-x: hidden;
- position: relative;
+ overflow: hidden;
width: 100%;
-moz-user-select: none;
}
.animation-list-container.active-scrubber {
cursor: col-resize;
}
-/* Animation List Header */
-.animation-list-header {
- display: grid;
- grid-template-columns: var(--sidebar-width) calc(100% - var(--sidebar-width) - var(--graph-right-offset)) var(--graph-right-offset);
- line-height: var(--devtools-toolbar-height);
- min-height: 100%;
- padding: 0;
- pointer-events: none;
- position: sticky;
- top: 0;
- z-index: 2;
-}
-
-.animation-list-header .devtools-toolbar {
- position: absolute;
- width: 100%;
-}
-
-/* Animation Timeline Tick List */
-.animation-timeline-tick-list {
- grid-column: 2/3;
- height: 100%;
- position: relative;
-}
-
-.animation-timeline-tick-item {
- height: 100%;
- position: absolute;
-}
-
-.animation-timeline-tick-item::before {
- border-left: var(--tick-line-style);
- content: "";
- height: 100%;
- position: absolute;
-}
-
/* Current Time Scrubber */
.current-time-scrubber-controller {
grid-column: 2 / 3;
- height: 100%;
- padding: 0;
- position: absolute;
- width: 100%;
+ z-index: 2;
}
.current-time-scrubber-controller::before {
content: "";
cursor: col-resize;
height: var(--devtools-toolbar-height);
pointer-events: auto;
position: absolute;
@@ -158,17 +116,16 @@ select.playback-rate-selector.devtools-b
.current-time-scrubber {
cursor: col-resize;
height: 100%;
margin-left: -6px;
pointer-events: auto;
position: absolute;
width: 12px;
- z-index: 1;
}
.current-time-scrubber::before {
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid var(--scrubber-color);
content: "";
position: absolute;
@@ -181,32 +138,17 @@ select.playback-rate-selector.devtools-b
content: "";
height: 100%;
left: 5px;
position: absolute;
top: 0;
width: 0;
}
-/* Animation List */
-.animation-list {
- list-style-type: none;
- margin: 0;
- padding: 0;
- position: absolute;
- top: var(--devtools-toolbar-height);
- width: 100%;
-}
-
/* Animation Item */
-.animation-item {
- display: flex;
- height: 30px;
-}
-
.animation-item:nth-child(2n+1) {
background-color: var(--animation-even-background-color);
}
.animation-item.cssanimation {
--computed-timing-graph-color: var(--fill-color-cssanimation);
--effect-timing-graph-color: var(--stroke-color-cssanimation);
}
@@ -224,19 +166,19 @@ select.playback-rate-selector.devtools-b
.animation-item.selected {
background-color: var(--theme-selection-background-hover);
}
/* Animation Target */
.animation-target {
align-items: center;
display: flex;
- height: 100%;
+ grid-column: 1 / 2;
+ height: var(--graph-height);
padding-left: 4px;
- width: var(--sidebar-width);
}
/* Reps component */
.animation-target .objectBox {
display: flex;
max-width: 100%;
}
@@ -254,35 +196,34 @@ select.playback-rate-selector.devtools-b
.animation-target .objectBox .open-inspector:hover,
.animation-target.highlighting .objectBox .open-inspector {
background-color: var(--theme-highlight-blue);
}
/* Summary Graph */
.animation-summary-graph {
cursor: pointer;
- height: 100%;
+ grid-column: 2 / 3;
+ height: var(--graph-height);
padding-top: 5px;
position: relative;
- width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
}
.animation-summary-graph.compositor::after {
background-image: var(--fast-track-image);
background-repeat: no-repeat;
content: "";
display: block;
fill: var(--theme-content-color3);
height: 100%;
position: absolute;
right: 0;
top: 5px;
width: 15px;
-moz-context-properties: fill;
- z-index: 1;
}
.animation-summary-graph-path {
height: 100%;
width: 100%;
}
.animation-computed-timing-path path {
@@ -377,17 +318,17 @@ select.playback-rate-selector.devtools-b
/* Animation Detail */
.animation-detail-container {
background-color: var(--theme-body-background);
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
width: 100%;
- z-index: 1;
+ z-index: 2;
}
.animation-detail-header {
display: flex;
padding-inline-end: 0;
}
/* On OSX the cursor turns into a window-resizing cursor at the edges of the
@@ -522,17 +463,17 @@ select.playback-rate-selector.devtools-b
position: absolute;
top: var(--devtools-toolbar-height);
width: 100%;
}
/* Animated Property Item */
.animated-property-item {
display: flex;
- height: 30px;
+ height: var(--graph-height);
}
.animated-property-item:nth-child(2n+1) {
background-color: var(--animation-even-background-color);
}
.animated-property-item.unchanged {
opacity: 0.6;