/* 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 . */ // @flow import { PureComponent } from "react"; import classnames from "classnames"; import { getDocument, toEditorLine } from "../../utils/editor"; import { getSelectedLocation } from "../../utils/selected-location"; import { features } from "../../utils/prefs"; import { showMenu } from "devtools-contextmenu"; import { breakpointItems } from "./menus/breakpoints"; import type { BreakpointItemActions } from "./menus/breakpoints"; import type { EditorItemActions } from "./menus/editor"; import type { Source, Breakpoint as BreakpointType, ThreadContext } from "../../types"; const breakpointSvg = document.createElement("div"); breakpointSvg.innerHTML = ''; type Props = { cx: ThreadContext, breakpoint: BreakpointType, selectedSource: Source, editor: Object, breakpointActions: BreakpointItemActions, editorActions: EditorItemActions }; class Breakpoint extends PureComponent { componentDidMount() { this.addBreakpoint(this.props); } componentDidUpdate(prevProps: Props) { 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; // NOTE: flow does not know about oncontextmenu (bp: any).oncontextmenu = this.onContextMenu; return bp; } onClick = (event: MouseEvent) => { const { cx, breakpointActions, editorActions, breakpoint, selectedSource } = this.props; // ignore right clicks if ((event.ctrlKey && event.button === 0) || event.button === 2) { return; } event.stopPropagation(); event.preventDefault(); const selectedLocation = getSelectedLocation(breakpoint, selectedSource); if (event.metaKey) { return editorActions.continueToHere(cx, selectedLocation.line); } if (event.shiftKey) { if (features.columnBreakpoints) { return breakpointActions.toggleBreakpointsAtLine( cx, !breakpoint.disabled, selectedLocation.line ); } return breakpointActions.toggleDisabledBreakpoint(cx, breakpoint); } return breakpointActions.removeBreakpointsAtLine( cx, selectedLocation.sourceId, selectedLocation.line ); }; onContextMenu = (event: MouseEvent) => { const { cx, breakpoint, breakpointActions } = this.props; event.stopPropagation(); event.preventDefault(); showMenu(event, breakpointItems(cx, breakpoint, breakpointActions)); }; addBreakpoint(props: Props) { const { breakpoint, editor, selectedSource } = props; const selectedLocation = getSelectedLocation(breakpoint, selectedSource); // Hidden Breakpoints are never rendered on the client if (breakpoint.options.hidden) { return; } if (!selectedSource) { return; } const sourceId = selectedSource.id; const line = toEditorLine(sourceId, selectedLocation.line); const doc = getDocument(sourceId); doc.setGutterMarker(line, "breakpoints", this.makeMarker()); editor.codeMirror.addLineClass(line, "line", "new-breakpoint"); editor.codeMirror.removeLineClass(line, "line", "has-condition"); editor.codeMirror.removeLineClass(line, "line", "has-log"); if (breakpoint.options.logValue) { editor.codeMirror.addLineClass(line, "line", "has-log"); } else if (breakpoint.options.condition) { editor.codeMirror.addLineClass(line, "line", "has-condition"); } } removeBreakpoint(props: Props) { const { selectedSource, breakpoint } = props; if (!selectedSource) { return; } const sourceId = selectedSource.id; const doc = getDocument(sourceId); if (!doc) { return; } const selectedLocation = getSelectedLocation(breakpoint, selectedSource); const line = toEditorLine(sourceId, selectedLocation.line); doc.setGutterMarker(line, "breakpoints", null); doc.removeLineClass(line, "line", "new-breakpoint"); doc.removeLineClass(line, "line", "has-condition"); doc.removeLineClass(line, "line", "has-log"); } render() { return null; } } export default Breakpoint;