In a following patch, all DevTools moz.build files will use DevToolsModules to install JS modules at a path that corresponds directly to their source tree location. Here we rewrite all require and import calls to match the new location that these files are installed to.
223 lines
7.2 KiB
JavaScript
223 lines
7.2 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
|
/* 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/. */
|
|
/* globals AnimationsController, document, performance, promise,
|
|
gToolbox, gInspector, requestAnimationFrame, cancelAnimationFrame, L10N */
|
|
|
|
"use strict";
|
|
|
|
const {AnimationsTimeline} = require("devtools/client/animationinspector/components");
|
|
|
|
/**
|
|
* The main animations panel UI.
|
|
*/
|
|
var AnimationsPanel = {
|
|
UI_UPDATED_EVENT: "ui-updated",
|
|
PANEL_INITIALIZED: "panel-initialized",
|
|
|
|
initialize: Task.async(function*() {
|
|
if (AnimationsController.destroyed) {
|
|
console.warn("Could not initialize the animation-panel, controller " +
|
|
"was destroyed");
|
|
return;
|
|
}
|
|
if (this.initialized) {
|
|
yield this.initialized.promise;
|
|
return;
|
|
}
|
|
this.initialized = promise.defer();
|
|
|
|
this.playersEl = document.querySelector("#players");
|
|
this.errorMessageEl = document.querySelector("#error-message");
|
|
this.pickerButtonEl = document.querySelector("#element-picker");
|
|
this.toggleAllButtonEl = document.querySelector("#toggle-all");
|
|
this.playTimelineButtonEl = document.querySelector("#pause-resume-timeline");
|
|
|
|
// If the server doesn't support toggling all animations at once, hide the
|
|
// whole global toolbar.
|
|
if (!AnimationsController.traits.hasToggleAll) {
|
|
document.querySelector("#global-toolbar").style.display = "none";
|
|
}
|
|
|
|
// Binding functions that need to be called in scope.
|
|
for (let functionName of ["onPickerStarted", "onPickerStopped",
|
|
"refreshAnimations", "toggleAll", "onTabNavigated",
|
|
"onTimelineDataChanged", "playPauseTimeline"]) {
|
|
this[functionName] = this[functionName].bind(this);
|
|
}
|
|
let hUtils = gToolbox.highlighterUtils;
|
|
this.togglePicker = hUtils.togglePicker.bind(hUtils);
|
|
|
|
this.animationsTimelineComponent = new AnimationsTimeline(gInspector);
|
|
this.animationsTimelineComponent.init(this.playersEl);
|
|
|
|
this.startListeners();
|
|
|
|
yield this.refreshAnimations();
|
|
|
|
this.initialized.resolve();
|
|
|
|
this.emit(this.PANEL_INITIALIZED);
|
|
}),
|
|
|
|
destroy: Task.async(function*() {
|
|
if (!this.initialized) {
|
|
return;
|
|
}
|
|
|
|
if (this.destroyed) {
|
|
yield this.destroyed.promise;
|
|
return;
|
|
}
|
|
this.destroyed = promise.defer();
|
|
|
|
this.stopListeners();
|
|
|
|
this.animationsTimelineComponent.destroy();
|
|
this.animationsTimelineComponent = null;
|
|
|
|
yield this.destroyPlayerWidgets();
|
|
|
|
this.playersEl = this.errorMessageEl = null;
|
|
this.toggleAllButtonEl = this.pickerButtonEl = null;
|
|
this.playTimelineButtonEl = null;
|
|
|
|
this.destroyed.resolve();
|
|
}),
|
|
|
|
startListeners: function() {
|
|
AnimationsController.on(AnimationsController.PLAYERS_UPDATED_EVENT,
|
|
this.refreshAnimations);
|
|
|
|
this.pickerButtonEl.addEventListener("click", this.togglePicker);
|
|
gToolbox.on("picker-started", this.onPickerStarted);
|
|
gToolbox.on("picker-stopped", this.onPickerStopped);
|
|
|
|
this.toggleAllButtonEl.addEventListener("click", this.toggleAll);
|
|
this.playTimelineButtonEl.addEventListener("click", this.playPauseTimeline);
|
|
gToolbox.target.on("navigate", this.onTabNavigated);
|
|
|
|
this.animationsTimelineComponent.on("timeline-data-changed",
|
|
this.onTimelineDataChanged);
|
|
},
|
|
|
|
stopListeners: function() {
|
|
AnimationsController.off(AnimationsController.PLAYERS_UPDATED_EVENT,
|
|
this.refreshAnimations);
|
|
|
|
this.pickerButtonEl.removeEventListener("click", this.togglePicker);
|
|
gToolbox.off("picker-started", this.onPickerStarted);
|
|
gToolbox.off("picker-stopped", this.onPickerStopped);
|
|
|
|
this.toggleAllButtonEl.removeEventListener("click", this.toggleAll);
|
|
this.playTimelineButtonEl.removeEventListener("click", this.playPauseTimeline);
|
|
gToolbox.target.off("navigate", this.onTabNavigated);
|
|
|
|
this.animationsTimelineComponent.off("timeline-data-changed",
|
|
this.onTimelineDataChanged);
|
|
},
|
|
|
|
togglePlayers: function(isVisible) {
|
|
if (isVisible) {
|
|
document.body.removeAttribute("empty");
|
|
document.body.setAttribute("timeline", "true");
|
|
} else {
|
|
document.body.setAttribute("empty", "true");
|
|
document.body.removeAttribute("timeline");
|
|
}
|
|
},
|
|
|
|
onPickerStarted: function() {
|
|
this.pickerButtonEl.setAttribute("checked", "true");
|
|
},
|
|
|
|
onPickerStopped: function() {
|
|
this.pickerButtonEl.removeAttribute("checked");
|
|
},
|
|
|
|
toggleAll: Task.async(function*() {
|
|
this.toggleAllButtonEl.classList.toggle("paused");
|
|
yield AnimationsController.toggleAll();
|
|
}),
|
|
|
|
/**
|
|
* Depending on the state of the timeline either pause or play the animations
|
|
* displayed in it.
|
|
* If the animations are finished, this will play them from the start again.
|
|
* If the animations are playing, this will pause them.
|
|
* If the animations are paused, this will resume them.
|
|
*/
|
|
playPauseTimeline: Task.async(function*() {
|
|
yield AnimationsController.toggleCurrentAnimations(this.timelineData.isMoving);
|
|
|
|
// Now that the playState have been changed make sure the player (the
|
|
// fronts) are up to date, and then refresh the UI.
|
|
for (let player of AnimationsController.animationPlayers) {
|
|
yield player.refreshState();
|
|
}
|
|
yield this.refreshAnimations();
|
|
}),
|
|
|
|
onTabNavigated: function() {
|
|
this.toggleAllButtonEl.classList.remove("paused");
|
|
},
|
|
|
|
onTimelineDataChanged: function(e, data) {
|
|
this.timelineData = data;
|
|
let {isPaused, isMoving, time} = data;
|
|
|
|
this.playTimelineButtonEl.classList.toggle("paused", !isMoving);
|
|
|
|
// Pause all animations and set their currentTimes (but only do this after
|
|
// the previous currentTime setting is done, as this gets called many times
|
|
// when users drag the scrubber with the mouse, and we want the server-side
|
|
// requests to be sequenced).
|
|
if (isPaused && !this.setCurrentTimeAllPromise) {
|
|
this.setCurrentTimeAllPromise =
|
|
AnimationsController.setCurrentTimeAll(time, true)
|
|
.catch(error => console.error(error))
|
|
.then(() => this.setCurrentTimeAllPromise = null);
|
|
}
|
|
},
|
|
|
|
refreshAnimations: Task.async(function*() {
|
|
let done = gInspector.updating("animationspanel");
|
|
|
|
// Empty the whole panel first.
|
|
this.togglePlayers(true);
|
|
yield this.destroyPlayerWidgets();
|
|
|
|
// Re-render the timeline component.
|
|
this.animationsTimelineComponent.render(
|
|
AnimationsController.animationPlayers,
|
|
AnimationsController.documentCurrentTime);
|
|
|
|
// If there are no players to show, show the error message instead and
|
|
// return.
|
|
if (!AnimationsController.animationPlayers.length) {
|
|
this.togglePlayers(false);
|
|
this.emit(this.UI_UPDATED_EVENT);
|
|
done();
|
|
return;
|
|
}
|
|
|
|
this.emit(this.UI_UPDATED_EVENT);
|
|
done();
|
|
}),
|
|
|
|
destroyPlayerWidgets: Task.async(function*() {
|
|
if (!this.playerWidgets) {
|
|
return;
|
|
}
|
|
|
|
let destroyers = this.playerWidgets.map(widget => widget.destroy());
|
|
yield promise.all(destroyers);
|
|
this.playerWidgets = null;
|
|
this.playersEl.innerHTML = "";
|
|
})
|
|
};
|
|
|
|
EventEmitter.decorate(AnimationsPanel);
|