203 lines
6.6 KiB
JavaScript
203 lines
6.6 KiB
JavaScript
/* 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/. */
|
|
/* import-globals-from ../performance-controller.js */
|
|
/* import-globals-from ../performance-view.js */
|
|
/* globals document, window */
|
|
"use strict";
|
|
|
|
/**
|
|
* Functions handling the recordings UI.
|
|
*/
|
|
var RecordingsView = {
|
|
/**
|
|
* Initialization function, called when the tool is started.
|
|
*/
|
|
initialize: function () {
|
|
this._onSelect = this._onSelect.bind(this);
|
|
this._onRecordingStateChange = this._onRecordingStateChange.bind(this);
|
|
this._onNewRecording = this._onNewRecording.bind(this);
|
|
this._onSaveButtonClick = this._onSaveButtonClick.bind(this);
|
|
this._onRecordingDeleted = this._onRecordingDeleted.bind(this);
|
|
this._onRecordingExported = this._onRecordingExported.bind(this);
|
|
|
|
PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
|
|
PerformanceController.on(EVENTS.RECORDING_ADDED, this._onNewRecording);
|
|
PerformanceController.on(EVENTS.RECORDING_DELETED, this._onRecordingDeleted);
|
|
PerformanceController.on(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
|
|
|
|
// DE-XUL: Begin migrating the recording sidebar to React. Temporarily hold state
|
|
// here.
|
|
this._listState = {
|
|
recordings: [],
|
|
labels: new WeakMap(),
|
|
selected: null,
|
|
};
|
|
this._listMount = PerformanceUtils.createHtmlMount($("#recording-list-mount"));
|
|
this._renderList();
|
|
},
|
|
|
|
/**
|
|
* Get the index of the currently selected recording. Only used by tests.
|
|
* @return {integer} index
|
|
*/
|
|
getSelectedIndex() {
|
|
const { recordings, selected } = this._listState;
|
|
return recordings.indexOf(selected);
|
|
},
|
|
|
|
/**
|
|
* Set the currently selected recording via its index. Only used by tests.
|
|
* @param {integer} index
|
|
*/
|
|
setSelectedByIndex(index) {
|
|
this._onSelect(this._listState.recordings[index]);
|
|
this._renderList();
|
|
},
|
|
|
|
/**
|
|
* DE-XUL: During the migration, this getter will access the selected recording from
|
|
* the private _listState object so that tests will continue to pass.
|
|
*/
|
|
get selected() {
|
|
return this._listState.selected;
|
|
},
|
|
|
|
/**
|
|
* DE-XUL: During the migration, this getter will access the number of recordings.
|
|
*/
|
|
get itemCount() {
|
|
return this._listState.recordings.length;
|
|
},
|
|
|
|
/**
|
|
* DE-XUL: Render the recording list using React.
|
|
*/
|
|
_renderList: function () {
|
|
const {recordings, labels, selected} = this._listState;
|
|
|
|
const recordingList = RecordingList({
|
|
itemComponent: RecordingListItem,
|
|
items: recordings.map(recording => ({
|
|
onSelect: () => this._onSelect(recording),
|
|
onSave: () => this._onSaveButtonClick(recording),
|
|
isLoading: !recording.isRecording() && !recording.isCompleted(),
|
|
isRecording: recording.isRecording(),
|
|
isSelected: recording === selected,
|
|
duration: recording.getDuration().toFixed(0),
|
|
label: labels.get(recording),
|
|
}))
|
|
});
|
|
|
|
ReactDOM.render(recordingList, this._listMount);
|
|
},
|
|
|
|
/**
|
|
* Destruction function, called when the tool is closed.
|
|
*/
|
|
destroy: function () {
|
|
PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE,
|
|
this._onRecordingStateChange);
|
|
PerformanceController.off(EVENTS.RECORDING_ADDED, this._onNewRecording);
|
|
PerformanceController.off(EVENTS.RECORDING_DELETED, this._onRecordingDeleted);
|
|
PerformanceController.off(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
|
|
},
|
|
|
|
/**
|
|
* Called when a new recording is stored in the UI. This handles
|
|
* when recordings are lazily loaded (like a console.profile occurring
|
|
* before the tool is loaded) or imported. In normal manual recording cases,
|
|
* this will also be fired.
|
|
*/
|
|
_onNewRecording: function (_, recording) {
|
|
this._onRecordingStateChange(_, null, recording);
|
|
},
|
|
|
|
/**
|
|
* Signals that a recording has changed state.
|
|
*
|
|
* @param string state
|
|
* Can be "recording-started", "recording-stopped", "recording-stopping"
|
|
* @param RecordingModel recording
|
|
* Model of the recording that was started.
|
|
*/
|
|
_onRecordingStateChange: function (_, state, recording) {
|
|
const { recordings, labels } = this._listState;
|
|
|
|
if (!recordings.includes(recording)) {
|
|
recordings.push(recording);
|
|
labels.set(recording, recording.getLabel() ||
|
|
L10N.getFormatStr("recordingsList.itemLabel", recordings.length));
|
|
|
|
// If this is a manual recording, immediately select it, or
|
|
// select a console profile if its the only one
|
|
if (!recording.isConsole() || !this._listState.selected) {
|
|
this._onSelect(recording);
|
|
}
|
|
}
|
|
|
|
// Determine if the recording needs to be selected.
|
|
const isCompletedManualRecording = !recording.isConsole() && recording.isCompleted();
|
|
if (recording.isImported() || isCompletedManualRecording) {
|
|
this._onSelect(recording);
|
|
}
|
|
|
|
this._renderList();
|
|
},
|
|
|
|
/**
|
|
* Clears out all non-console recordings.
|
|
*/
|
|
_onRecordingDeleted: function (_, recording) {
|
|
const { recordings } = this._listState;
|
|
const index = recordings.indexOf(recording);
|
|
if (index === -1) {
|
|
throw new Error("Attempting to remove a recording that doesn't exist.");
|
|
}
|
|
recordings.splice(index, 1);
|
|
this._renderList();
|
|
},
|
|
|
|
/**
|
|
* The select listener for this container.
|
|
*/
|
|
_onSelect: Task.async(function* (recording) {
|
|
this._listState.selected = recording;
|
|
this.emit(EVENTS.UI_RECORDING_SELECTED, recording);
|
|
this._renderList();
|
|
}),
|
|
|
|
/**
|
|
* The click listener for the "save" button of each item in this container.
|
|
*/
|
|
_onSaveButtonClick: function (recording) {
|
|
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
|
fp.init(window, L10N.getStr("recordingsList.saveDialogTitle"),
|
|
Ci.nsIFilePicker.modeSave);
|
|
fp.appendFilter(L10N.getStr("recordingsList.saveDialogJSONFilter"), "*.json");
|
|
fp.appendFilter(L10N.getStr("recordingsList.saveDialogAllFilter"), "*.*");
|
|
fp.defaultString = "profile.json";
|
|
|
|
fp.open({ done: result => {
|
|
if (result == Ci.nsIFilePicker.returnCancel) {
|
|
return;
|
|
}
|
|
this.emit(EVENTS.UI_EXPORT_RECORDING, recording, fp.file);
|
|
}});
|
|
},
|
|
|
|
_onRecordingExported: function (_, recording, file) {
|
|
if (recording.isConsole()) {
|
|
return;
|
|
}
|
|
const name = file.leafName.replace(/\..+$/, "");
|
|
this._listState.labels.set(recording, name);
|
|
this._renderList();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Convenient way of emitting events from the RecordingsView.
|
|
*/
|
|
EventEmitter.decorate(RecordingsView);
|