/* 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 . */ import { PureComponent } from "devtools/client/shared/vendor/react"; import PropTypes from "devtools/client/shared/vendor/react-prop-types"; import { getDocument, toEditorLine } from "../../utils/editor/index"; import { getSelectedLocation } from "../../utils/selected-location"; import { features } from "../../utils/prefs"; const classnames = require("resource://devtools/client/shared/classnames.js"); const breakpointSvg = document.createElement("div"); breakpointSvg.innerHTML = ''; class Breakpoint extends PureComponent { static get propTypes() { return { breakpoint: PropTypes.object.isRequired, editor: PropTypes.object.isRequired, selectedSource: PropTypes.object, }; } componentDidMount() { this.addBreakpoint(this.props); } componentDidUpdate(prevProps) { this.removeBreakpoint(prevProps); this.addBreakpoint(this.props); } componentWillUnmount() { this.removeBreakpoint(this.props); } makeMarker() { const { breakpoint } = this.props; const bp = breakpointSvg.cloneNode(true); bp.className = classnames("editor new-breakpoint", { "breakpoint-disabled": breakpoint.disabled, "folding-enabled": features.codeFolding, }); bp.onmousedown = this.onClick; bp.oncontextmenu = this.onContextMenu; return bp; } onClick = event => { const { continueToHere, toggleBreakpointsAtLine, removeBreakpointsAtLine, breakpoint, selectedSource, } = this.props; // ignore ctrl + click and right clicks when clicking on the breakpoint if ((event.ctrlKey && event.button === 0) || event.button === 2) { return; } event.stopPropagation(); event.preventDefault(); const selectedLocation = getSelectedLocation(breakpoint, selectedSource); if (event.metaKey) { continueToHere(selectedLocation); return; } if (event.shiftKey) { toggleBreakpointsAtLine(!breakpoint.disabled, selectedLocation.line); return; } removeBreakpointsAtLine(selectedLocation.source, selectedLocation.line); }; onContextMenu = event => { event.stopPropagation(); event.preventDefault(); this.props.showEditorEditBreakpointContextMenu( event, this.props.breakpoint ); }; addBreakpoint(props) { const { breakpoint, editor, selectedSource } = props; // Hidden Breakpoints are never rendered on the client if (breakpoint.options.hidden) { return; } if (!selectedSource) { return; } const doc = getDocument(selectedSource.id); if (!doc) { return; } const selectedLocation = getSelectedLocation(breakpoint, selectedSource); const line = toEditorLine(selectedSource.id, selectedLocation.line); doc.setGutterMarker(line, "breakpoints", this.makeMarker()); editor.codeMirror.addLineClass(line, "wrap", "new-breakpoint"); editor.codeMirror.removeLineClass(line, "wrap", "breakpoint-disabled"); editor.codeMirror.removeLineClass(line, "wrap", "has-condition"); editor.codeMirror.removeLineClass(line, "wrap", "has-log"); if (breakpoint.disabled) { editor.codeMirror.addLineClass(line, "wrap", "breakpoint-disabled"); } if (breakpoint.options.logValue) { editor.codeMirror.addLineClass(line, "wrap", "has-log"); } else if (breakpoint.options.condition) { editor.codeMirror.addLineClass(line, "wrap", "has-condition"); } } removeBreakpoint(props) { const { selectedSource, breakpoint } = props; if (!selectedSource) { return; } const doc = getDocument(selectedSource.id); if (!doc) { return; } const selectedLocation = getSelectedLocation(breakpoint, selectedSource); const line = toEditorLine(selectedSource.id, selectedLocation.line); doc.setGutterMarker(line, "breakpoints", null); doc.removeLineClass(line, "wrap", "new-breakpoint"); doc.removeLineClass(line, "wrap", "breakpoint-disabled"); doc.removeLineClass(line, "wrap", "has-condition"); doc.removeLineClass(line, "wrap", "has-log"); } render() { return null; } } export default Breakpoint;