index.js (5353B)
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 React, { Component } from "devtools/client/shared/vendor/react"; 6 import { div } from "devtools/client/shared/vendor/react-dom-factories"; 7 import PropTypes from "devtools/client/shared/vendor/react-prop-types"; 8 import { connect } from "devtools/client/shared/vendor/react-redux"; 9 10 import ExceptionOption from "./ExceptionOption"; 11 12 import Breakpoint from "./Breakpoint"; 13 import BreakpointHeading from "./BreakpointHeading"; 14 15 import actions from "../../../actions/index"; 16 import { getSelectedLocation } from "../../../utils/selected-location"; 17 import { createHeadlessEditor } from "../../../utils/editor/create-editor"; 18 19 import { makeBreakpointId } from "../../../utils/breakpoint/index"; 20 21 import { 22 getSelectedSource, 23 getBreakpointSources, 24 getShouldPauseOnDebuggerStatement, 25 getShouldPauseOnExceptions, 26 getShouldPauseOnCaughtExceptions, 27 } from "../../../selectors/index"; 28 29 const classnames = require("resource://devtools/client/shared/classnames.js"); 30 31 class Breakpoints extends Component { 32 static get propTypes() { 33 return { 34 breakpointSources: PropTypes.array.isRequired, 35 pauseOnExceptions: PropTypes.func.isRequired, 36 selectedSource: PropTypes.object, 37 shouldPauseOnDebuggerStatement: PropTypes.bool.isRequired, 38 shouldPauseOnCaughtExceptions: PropTypes.bool.isRequired, 39 shouldPauseOnExceptions: PropTypes.bool.isRequired, 40 }; 41 } 42 43 componentWillUnmount() { 44 this.removeEditor(); 45 } 46 47 /** 48 * Get an headless editor that can be used for syntax highlighting 49 * 50 * @returns {CodeMirror} 51 */ 52 getHeadlessEditor() { 53 if (!this.headlessEditor) { 54 this.headlessEditor = createHeadlessEditor(); 55 } 56 return this.headlessEditor; 57 } 58 59 removeEditor() { 60 if (!this.headlessEditor) { 61 return; 62 } 63 this.headlessEditor.destroy(); 64 this.headlessEditor = null; 65 } 66 67 togglePauseOnDebuggerStatement = () => { 68 this.props.pauseOnDebuggerStatement( 69 !this.props.shouldPauseOnDebuggerStatement 70 ); 71 }; 72 73 togglePauseOnException = () => { 74 this.props.pauseOnExceptions(!this.props.shouldPauseOnExceptions, false); 75 }; 76 77 togglePauseOnCaughtException = () => { 78 this.props.pauseOnExceptions( 79 true, 80 !this.props.shouldPauseOnCaughtExceptions 81 ); 82 }; 83 84 renderExceptionsOptions() { 85 const { 86 breakpointSources, 87 shouldPauseOnDebuggerStatement, 88 shouldPauseOnExceptions, 89 shouldPauseOnCaughtExceptions, 90 } = this.props; 91 92 const isEmpty = !breakpointSources.length; 93 return div( 94 { 95 className: classnames("breakpoints-options", { 96 empty: isEmpty, 97 }), 98 }, 99 React.createElement(ExceptionOption, { 100 className: "breakpoints-debugger-statement", 101 label: L10N.getStr("pauseOnDebuggerStatement"), 102 isChecked: shouldPauseOnDebuggerStatement, 103 onChange: this.togglePauseOnDebuggerStatement, 104 }), 105 React.createElement(ExceptionOption, { 106 className: "breakpoints-exceptions", 107 label: L10N.getStr("pauseOnExceptionsItem2"), 108 isChecked: shouldPauseOnExceptions, 109 onChange: this.togglePauseOnException, 110 }), 111 shouldPauseOnExceptions && 112 React.createElement(ExceptionOption, { 113 className: "breakpoints-exceptions-caught", 114 label: L10N.getStr("pauseOnCaughtExceptionsItem"), 115 isChecked: shouldPauseOnCaughtExceptions, 116 onChange: this.togglePauseOnCaughtException, 117 }) 118 ); 119 } 120 121 renderBreakpoints() { 122 const { breakpointSources, selectedSource } = this.props; 123 if (!breakpointSources.length) { 124 return null; 125 } 126 127 // We need to create a specific editor instance to handle cases where we don't have 128 // any editor opened yet. 129 const editor = this.getHeadlessEditor(); 130 const sources = breakpointSources.map(({ source }) => source); 131 return div( 132 { 133 className: "pane breakpoints-list", 134 }, 135 breakpointSources.map(({ source, breakpoints }) => { 136 return [ 137 React.createElement(BreakpointHeading, { 138 key: source.id, 139 source, 140 sources, 141 }), 142 breakpoints.map(breakpoint => 143 React.createElement(Breakpoint, { 144 breakpoint, 145 source, 146 editor, 147 key: makeBreakpointId( 148 getSelectedLocation(breakpoint, selectedSource) 149 ), 150 }) 151 ), 152 ]; 153 }) 154 ); 155 } 156 157 render() { 158 return div( 159 { 160 className: "pane", 161 }, 162 this.renderExceptionsOptions(), 163 this.renderBreakpoints() 164 ); 165 } 166 } 167 168 const mapStateToProps = state => ({ 169 breakpointSources: getBreakpointSources(state), 170 selectedSource: getSelectedSource(state), 171 shouldPauseOnDebuggerStatement: getShouldPauseOnDebuggerStatement(state), 172 shouldPauseOnExceptions: getShouldPauseOnExceptions(state), 173 shouldPauseOnCaughtExceptions: getShouldPauseOnCaughtExceptions(state), 174 }); 175 176 export default connect(mapStateToProps, { 177 pauseOnDebuggerStatement: actions.pauseOnDebuggerStatement, 178 pauseOnExceptions: actions.pauseOnExceptions, 179 })(Breakpoints);