/* 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 . */
const {
LocalizationProvider,
Localized,
} = require("devtools/client/shared/vendor/fluent-react");
import React, { PureComponent } from "react";
import PropTypes from "prop-types";
import { connect } from "../../utils/connect";
import AccessibleImage from "../shared/AccessibleImage";
import actions from "../../actions";
import Reps from "devtools/client/shared/components/reps/index";
const {
REPS: { Rep },
MODE,
} = Reps;
import { getPauseReason } from "../../utils/pause";
import {
getCurrentThread,
getPaneCollapse,
getPauseReason as getWhy,
} from "../../selectors";
import "./WhyPaused.css";
class WhyPaused extends PureComponent {
constructor(props) {
super(props);
this.state = { hideWhyPaused: "" };
}
static get propTypes() {
return {
delay: PropTypes.number.isRequired,
endPanelCollapsed: PropTypes.bool.isRequired,
highlightDomElement: PropTypes.func.isRequired,
openElementInInspector: PropTypes.func.isRequired,
unHighlightDomElement: PropTypes.func.isRequired,
why: PropTypes.object,
};
}
componentDidUpdate() {
const { delay } = this.props;
if (delay) {
setTimeout(() => {
this.setState({ hideWhyPaused: "" });
}, delay);
} else {
this.setState({ hideWhyPaused: "pane why-paused" });
}
}
renderExceptionSummary(exception) {
if (typeof exception === "string") {
return exception;
}
const { preview } = exception;
if (!preview || !preview.name || !preview.message) {
return null;
}
return `${preview.name}: ${preview.message}`;
}
renderMessage(why) {
const { type, exception, message } = why;
if (type == "exception" && exception) {
// Our types for 'Why' are too general because 'type' can be 'string'.
// $FlowFixMe - We should have a proper discriminating union of reasons.
const summary = this.renderExceptionSummary(exception);
return
{summary}
;
}
if (type === "mutationBreakpoint" && why.nodeGrip) {
const { nodeGrip, ancestorGrip, action } = why;
const {
openElementInInspector,
highlightDomElement,
unHighlightDomElement,
} = this.props;
const targetRep = Rep({
object: nodeGrip,
mode: MODE.TINY,
onDOMNodeClick: () => openElementInInspector(nodeGrip),
onInspectIconClick: () => openElementInInspector(nodeGrip),
onDOMNodeMouseOver: () => highlightDomElement(nodeGrip),
onDOMNodeMouseOut: () => unHighlightDomElement(),
});
const ancestorRep = ancestorGrip
? Rep({
object: ancestorGrip,
mode: MODE.TINY,
onDOMNodeClick: () => openElementInInspector(ancestorGrip),
onInspectIconClick: () => openElementInInspector(ancestorGrip),
onDOMNodeMouseOver: () => highlightDomElement(ancestorGrip),
onDOMNodeMouseOut: () => unHighlightDomElement(),
})
: null;
return (
{why.message}
{ancestorRep}
{ancestorGrip ? (
{targetRep}
) : (
targetRep
)}
);
}
if (typeof message == "string") {
return {message}
;
}
return null;
}
render() {
const { endPanelCollapsed, why } = this.props;
const { fluentBundles } = this.context;
const reason = getPauseReason(why);
if (!why || !reason || endPanelCollapsed) {
return ;
}
return (
// We're rendering the LocalizationProvider component from here and not in an upper
// component because it does set a new context, overriding the context that we set
// in the first place in , which breaks some components.
// This should be fixed in Bug 1743155.
{this.renderMessage(why)}
);
}
}
WhyPaused.contextTypes = { fluentBundles: PropTypes.array };
const mapStateToProps = state => ({
endPanelCollapsed: getPaneCollapse(state, "end"),
why: getWhy(state, getCurrentThread(state)),
});
export default connect(mapStateToProps, {
openElementInInspector: actions.openElementInInspectorCommand,
highlightDomElement: actions.highlightDomElement,
unHighlightDomElement: actions.unHighlightDomElement,
})(WhyPaused);