DomTree.js (3730B)
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 /* global DomProvider */ 6 7 "use strict"; 8 9 // React & Redux 10 const { 11 Component, 12 createFactory, 13 } = require("resource://devtools/client/shared/vendor/react.mjs"); 14 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs"); 15 16 const { 17 connect, 18 } = require("resource://devtools/client/shared/vendor/react-redux.js"); 19 20 const TreeView = createFactory( 21 ChromeUtils.importESModule( 22 "resource://devtools/client/shared/components/tree/TreeView.mjs" 23 ).default 24 ); 25 // Reps 26 const { REPS, MODE } = ChromeUtils.importESModule( 27 "resource://devtools/client/shared/components/reps/index.mjs" 28 ); 29 const { Rep } = REPS; 30 31 const Grip = REPS.Grip; 32 // DOM Panel 33 const { 34 GripProvider, 35 } = require("resource://devtools/client/dom/content/grip-provider.js"); 36 37 const { 38 DomDecorator, 39 } = require("resource://devtools/client/dom/content/dom-decorator.js"); 40 41 /** 42 * Renders DOM panel tree. 43 */ 44 class DomTree extends Component { 45 static get propTypes() { 46 return { 47 dispatch: PropTypes.func.isRequired, 48 filter: PropTypes.string, 49 grips: PropTypes.object, 50 object: PropTypes.any, 51 openLink: PropTypes.func, 52 }; 53 } 54 55 constructor(props) { 56 super(props); 57 this.onFilter = this.onFilter.bind(this); 58 this.expandedNodes = new Set(); 59 } 60 61 /** 62 * Filter DOM properties. Return true if the object 63 * should be visible in the tree. 64 */ 65 onFilter(object) { 66 if (!this.props.filter) { 67 return true; 68 } 69 70 return object.name && object.name.indexOf(this.props.filter) > -1; 71 } 72 73 /** 74 * Render DOM panel content 75 */ 76 render() { 77 const { dispatch, grips, object, openLink } = this.props; 78 79 const columns = [ 80 { 81 id: "value", 82 }, 83 ]; 84 85 let onDOMNodeMouseOver; 86 let onDOMNodeMouseOut; 87 let onInspectIconClick; 88 const toolbox = DomProvider.getToolbox(); 89 if (toolbox) { 90 const highlighter = toolbox.getHighlighter(); 91 onDOMNodeMouseOver = async (grip, options = {}) => { 92 return highlighter.highlight(grip, options); 93 }; 94 onDOMNodeMouseOut = async () => { 95 return highlighter.unhighlight(); 96 }; 97 onInspectIconClick = async grip => { 98 return toolbox.viewElementInInspector(grip, "inspect_dom"); 99 }; 100 } 101 102 // This is the integration point with Reps. The DomTree is using 103 // Reps to render all values. The code also specifies default rep 104 // used for data types that don't have its own specific template. 105 const renderValue = props => { 106 const repProps = Object.assign({}, props, { 107 onDOMNodeMouseOver, 108 onDOMNodeMouseOut, 109 onInspectIconClick, 110 defaultRep: Grip, 111 cropLimit: 50, 112 }); 113 114 // Object can be an objectFront, while Rep always expect grips. 115 if (props?.object?.getGrip) { 116 repProps.object = props.object.getGrip(); 117 } 118 119 return Rep(repProps); 120 }; 121 122 return TreeView({ 123 columns, 124 decorator: new DomDecorator(), 125 mode: MODE.SHORT, 126 object, 127 onFilter: this.onFilter, 128 openLink, 129 provider: new GripProvider(grips, dispatch), 130 renderValue, 131 // Ensure passing a stable expanded Set, 132 // so that TreeView doesn't reset to default prop's Set 133 // on each new received props. 134 expandedNodes: this.expandedNodes, 135 }); 136 } 137 } 138 139 const mapStateToProps = state => { 140 return { 141 grips: state.grips, 142 filter: state.filter, 143 }; 144 }; 145 146 // Exports from this module 147 module.exports = connect(mapStateToProps)(DomTree);