ColumnBreakpoints.js (5540B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 import { Component } from "devtools/client/shared/vendor/react"; 6 import PropTypes from "devtools/client/shared/vendor/react-prop-types"; 7 8 const classnames = require("resource://devtools/client/shared/classnames.js"); 9 10 import { 11 getSelectedSource, 12 visibleColumnBreakpoints, 13 isSourceBlackBoxed, 14 } from "../../selectors/index"; 15 import actions from "../../actions/index"; 16 import { connect } from "devtools/client/shared/vendor/react-redux"; 17 18 const breakpointButton = document.createElement("button"); 19 const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 20 svg.setAttribute("viewBox", "0 0 11 13"); 21 svg.setAttribute("width", 11); 22 svg.setAttribute("height", 13); 23 24 const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); 25 path.setAttributeNS( 26 null, 27 "d", 28 "M5.07.5H1.5c-.54 0-1 .46-1 1v10c0 .54.46 1 1 1h3.57c.58 0 1.15-.26 1.53-.7l3.7-5.3-3.7-5.3C6.22.76 5.65.5 5.07.5z" 29 ); 30 31 svg.appendChild(path); 32 breakpointButton.appendChild(svg); 33 34 class ColumnBreakpoints extends Component { 35 static get propTypes() { 36 return { 37 columnBreakpoints: PropTypes.array, 38 editor: PropTypes.object.isRequired, 39 selectedSource: PropTypes.object, 40 addBreakpoint: PropTypes.func, 41 removeBreakpoint: PropTypes.func, 42 setSkipPausing: PropTypes.func, 43 toggleDisabledBreakpoint: PropTypes.func, 44 showEditorCreateBreakpointContextMenu: PropTypes.func, 45 showEditorEditBreakpointContextMenu: PropTypes.func, 46 }; 47 } 48 49 componentDidUpdate() { 50 const { selectedSource, columnBreakpoints, editor } = this.props; 51 52 if (!selectedSource || !editor) { 53 return; 54 } 55 56 if (!columnBreakpoints.length) { 57 editor.removePositionContentMarker( 58 editor.markerTypes.COLUMN_BREAKPOINT_MARKER 59 ); 60 return; 61 } 62 63 editor.setPositionContentMarker({ 64 id: editor.markerTypes.COLUMN_BREAKPOINT_MARKER, 65 positions: columnBreakpoints.map(cbp => { 66 return { 67 line: cbp.location.line, 68 column: cbp.location.column, 69 positionData: cbp, 70 }; 71 }), 72 createPositionElementNode: ( 73 line, 74 column, 75 isFirstNonSpaceColumn, 76 positionData 77 ) => { 78 const breakpointNode = breakpointButton.cloneNode(true); 79 breakpointNode.className = classnames("column-breakpoint", { 80 "has-condition": positionData.breakpoint?.options.condition, 81 "has-log": positionData.breakpoint?.options.logValue, 82 active: positionData.breakpoint && !positionData.breakpoint.disabled, 83 disabled: positionData.breakpoint?.disabled, 84 }); 85 breakpointNode.addEventListener("click", event => 86 this.onClick(event, positionData) 87 ); 88 breakpointNode.addEventListener("contextmenu", event => 89 this.onContextMenu(event, positionData) 90 ); 91 return breakpointNode; 92 }, 93 customEq: (positionData, prevPositionData) => { 94 return ( 95 positionData?.breakpoint?.id == prevPositionData?.breakpoint?.id && 96 positionData?.breakpoint?.options.condition == 97 prevPositionData?.breakpoint?.options.condition && 98 positionData?.breakpoint?.options.logValue == 99 prevPositionData?.breakpoint?.options.logValue && 100 positionData?.breakpoint?.disabled == 101 prevPositionData?.breakpoint?.disabled 102 ); 103 }, 104 }); 105 } 106 107 onClick = (event, columnBreakpoint) => { 108 event.stopPropagation(); 109 event.preventDefault(); 110 const { 111 toggleDisabledBreakpoint, 112 removeBreakpoint, 113 addBreakpoint, 114 setSkipPausing, 115 } = this.props; 116 117 // disable column breakpoint on shift-click. 118 if (event.shiftKey) { 119 toggleDisabledBreakpoint(columnBreakpoint.breakpoint); 120 return; 121 } 122 123 if (columnBreakpoint.breakpoint) { 124 removeBreakpoint(columnBreakpoint.breakpoint); 125 } else { 126 setSkipPausing(false); 127 addBreakpoint(columnBreakpoint.location); 128 } 129 }; 130 131 onContextMenu = (event, columnBreakpoint) => { 132 event.stopPropagation(); 133 event.preventDefault(); 134 135 if (columnBreakpoint.breakpoint) { 136 this.props.showEditorEditBreakpointContextMenu( 137 event, 138 columnBreakpoint.breakpoint 139 ); 140 } else { 141 this.props.showEditorCreateBreakpointContextMenu( 142 event, 143 columnBreakpoint.location 144 ); 145 } 146 }; 147 148 render() { 149 return null; 150 } 151 } 152 153 const mapStateToProps = state => { 154 // Avoid rendering this component is there is no selected source, 155 // or if the selected source is blackboxed. 156 // Also avoid computing visible column breakpoint when this happens. 157 const selectedSource = getSelectedSource(state); 158 if (!selectedSource || isSourceBlackBoxed(state, selectedSource)) { 159 return {}; 160 } 161 return { 162 selectedSource, 163 columnBreakpoints: visibleColumnBreakpoints(state), 164 }; 165 }; 166 167 export default connect(mapStateToProps, { 168 showEditorCreateBreakpointContextMenu: 169 actions.showEditorCreateBreakpointContextMenu, 170 showEditorEditBreakpointContextMenu: 171 actions.showEditorEditBreakpointContextMenu, 172 toggleDisabledBreakpoint: actions.toggleDisabledBreakpoint, 173 removeBreakpoint: actions.removeBreakpoint, 174 addBreakpoint: actions.addBreakpoint, 175 setSkipPausing: actions.setSkipPausing, 176 })(ColumnBreakpoints);