Bug 1210796 - Part 4: Add animated property header. r=pbro
MozReview-Commit-ID: F2KpzTvlyOj
--- a/devtools/client/animationinspector/components/animation-details.js
+++ b/devtools/client/animationinspector/components/animation-details.js
@@ -3,19 +3,23 @@
/* 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 {Task} = require("devtools/shared/task");
const EventEmitter = require("devtools/shared/event-emitter");
-const {createNode, TimeScale} = require("devtools/client/animationinspector/utils");
+const {createNode} = require("devtools/client/animationinspector/utils");
const {Keyframes} = require("devtools/client/animationinspector/components/keyframes");
+const { LocalizationHelper } = require("devtools/shared/l10n");
+const L10N =
+ new LocalizationHelper("devtools/client/locales/animationinspector.properties");
+
/**
* UI component responsible for displaying detailed information for a given
* animation.
* This includes information about timing, easing, keyframes, animated
* properties.
*
* @param {Object} serverTraits The list of server-side capabilities.
*/
@@ -177,23 +181,70 @@ AnimationDetails.prototype = {
}
// Build an element for each animated property track.
this.tracks = yield this.getTracks(animation, this.serverTraits);
// Get animation type for each CSS properties.
const animationTypes = yield this.getAnimationTypes(Object.keys(this.tracks));
+ // Render animated properties header.
+ this.renderAnimatedPropertiesHeader();
+ // Render animated properties body.
+ this.renderAnimatedPropertiesBody(animationTypes);
+
+ // Useful for tests to know when rendering of all animation detail UIs
+ // have been completed.
+ this.emit("animation-detail-rendering-completed");
+ }),
+
+ onFrameSelected: function (e, args) {
+ // Relay the event up, it's needed in parents too.
+ this.emit(e, args);
+ },
+
+ renderAnimatedPropertiesHeader: function () {
+ // Add animated property header.
+ const headerEl = createNode({
+ parent: this.containerEl,
+ attributes: { "class": "animated-properties-header property" }
+ });
+
+ // Add label container.
+ const headerLabelContainerEl = createNode({
+ parent: headerEl,
+ attributes: { "class": "track-container" }
+ });
+
+ // Add labels
+ for (let label of [L10N.getFormatStr("detail.propertiesHeader.percentage", 0),
+ L10N.getFormatStr("detail.propertiesHeader.percentage", 50),
+ L10N.getFormatStr("detail.propertiesHeader.percentage", 100)]) {
+ createNode({
+ parent: headerLabelContainerEl,
+ nodeType: "label",
+ attributes: { "class": "header-item" },
+ textContent: label
+ });
+ }
+ },
+
+ renderAnimatedPropertiesBody: function (animationTypes) {
+ // Add animated property body.
+ const bodyEl = createNode({
+ parent: this.containerEl,
+ attributes: { "class": "animated-properties-body" }
+ });
for (let propertyName in this.tracks) {
let line = createNode({
- parent: this.containerEl,
+ parent: bodyEl,
attributes: {"class": "property"}
});
let {warning, className} =
- this.getPerfDataForProperty(animation, propertyName);
+ this.getPerfDataForProperty(this.animation, propertyName);
createNode({
// text-overflow doesn't work in flex items, so we need a second level
// of container to actually have an ellipsis on the name.
// See bug 972664.
parent: createNode({
parent: line,
attributes: {"class": "name"}
}),
@@ -213,31 +264,22 @@ AnimationDetails.prototype = {
attributes: {"class": "frames"}
});
let keyframesComponent = new Keyframes();
keyframesComponent.init(framesEl);
keyframesComponent.render({
keyframes: this.tracks[propertyName],
propertyName: propertyName,
- animation: animation,
+ animation: this.animation,
animationType: animationTypes[propertyName]
});
keyframesComponent.on("frame-selected", this.onFrameSelected);
this.keyframeComponents.push(keyframesComponent);
}
-
- // Useful for tests to know when rendering of all animation detail UIs
- // have been completed.
- this.emit("animation-detail-rendering-completed");
- }),
-
- onFrameSelected: function (e, args) {
- // Relay the event up, it's needed in parents too.
- this.emit(e, args);
}
};
/**
* Turn propertyName into property-name.
* @param {String} jsPropertyName A camelcased CSS property name. Typically
* something that comes out of computed styles. E.g. borderBottomColor
* @return {String} The corresponding CSS property name: border-bottom-color
--- a/devtools/client/locales/en-US/animationinspector.properties
+++ b/devtools/client/locales/en-US/animationinspector.properties
@@ -167,8 +167,14 @@ timeline.scriptanimation.nameLabel=%S -
timeline.scriptanimation.unnamedLabel=Script Animation
# LOCALIZATION NOTE (timeline.unknown.nameLabel):
# This string is displayed in a tooltip of the animation panel that is shown
# when hovering over the name of an unknown animation type in the timeline UI.
# This can happen if devtools couldn't figure out the type of the animation.
# %S will be replaced by the name of the transition at run-time.
timeline.unknown.nameLabel=%S
+
+# LOCALIZATION NOTE (detail.propertiesHeader.percentage):
+# This string is displayed on header label in .animated-properties-header.
+# %S represents the value in percentage with two decimal points, localized.
+# there are two "%" after %S to escape and display "%"
+detail.propertiesHeader.percentage=%S%%
--- a/devtools/client/themes/animationinspector.css
+++ b/devtools/client/themes/animationinspector.css
@@ -294,16 +294,17 @@ body {
}
.animation-timeline .time-header {
min-height: var(--timeline-animation-height);
cursor: col-resize;
-moz-user-select: none;
}
+.animated-properties-header .header-item,
.animation-timeline .time-header .header-item {
position: absolute;
height: 100%;
padding-top: 3px;
border-left: 0.5px solid var(--time-graduation-border-color);
}
.animation-timeline .header-wrapper {
@@ -521,22 +522,16 @@ body {
.animation-timeline .animated-properties:not(.selected) {
display: none;
}
.animation-timeline .animated-properties {
background-color: var(--theme-selection-background-semitransparent);
}
-.animation-timeline .animated-properties ul {
- margin: 0;
- padding: 0;
- list-style-type: none;
-}
-
.animation-timeline .animated-properties .property {
height: var(--timeline-animation-height);
position: relative;
}
.animation-timeline .animated-properties .property:nth-child(2n) {
background-color: var(--even-animation-timeline-background-color);
}
@@ -670,8 +665,23 @@ body {
.keyframes svg path.transform {
fill: var(--transform-background-color);
stroke: var(--transform-border-color);
}
.keyframes svg path.color {
stroke: none;
}
+
+.animated-properties-header {
+ min-height: var(--timeline-animation-height);
+ -moz-user-select: none;
+}
+
+.animated-properties-header .header-item:nth-child(2) {
+ left: 50%;
+}
+
+.animated-properties-header .header-item:nth-child(3) {
+ right: 0;
+ border-left: none;
+ border-right: 0.5px solid var(--time-graduation-border-color);
+}