IssueItem.js (6100B)
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 "use strict"; 6 7 const { 8 createFactory, 9 PureComponent, 10 } = require("resource://devtools/client/shared/vendor/react.mjs"); 11 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); 12 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs"); 13 14 const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js"); 15 const Localized = createFactory(FluentReact.Localized); 16 17 loader.lazyRequireGetter( 18 this, 19 "openDocLink", 20 "resource://devtools/client/shared/link.js", 21 true 22 ); 23 24 const UnsupportedBrowserList = createFactory( 25 require("resource://devtools/client/inspector/compatibility/components/UnsupportedBrowserList.js") 26 ); 27 28 const Types = require("resource://devtools/client/inspector/compatibility/types.js"); 29 30 const NodePane = createFactory( 31 require("resource://devtools/client/inspector/compatibility/components/NodePane.js") 32 ); 33 34 // For test 35 loader.lazyRequireGetter( 36 this, 37 "toSnakeCase", 38 "resource://devtools/client/inspector/compatibility/utils/cases.js", 39 true 40 ); 41 42 const { getMdnLinkParams } = ChromeUtils.importESModule( 43 "resource://devtools/shared/mdn.mjs" 44 ); 45 const MDN_LINK_PARAMS = getMdnLinkParams("inspector-compatibility"); 46 47 class IssueItem extends PureComponent { 48 static get propTypes() { 49 return { 50 ...Types.issue, 51 dispatch: PropTypes.func.isRequired, 52 setSelectedNode: PropTypes.func.isRequired, 53 }; 54 } 55 56 constructor(props) { 57 super(props); 58 this._onLinkClicked = this._onLinkClicked.bind(this); 59 } 60 61 _onLinkClicked(e) { 62 e.preventDefault(); 63 e.stopPropagation(); 64 65 const isMacOS = Services.appinfo.OS === "Darwin"; 66 67 openDocLink(e.target.href, { 68 relatedToCurrent: true, 69 inBackground: isMacOS ? e.metaKey : e.ctrlKey, 70 }); 71 } 72 73 _getTestDataAttributes() { 74 const testDataSet = {}; 75 76 if (Services.prefs.getBoolPref("devtools.testing", false)) { 77 for (const [key, value] of Object.entries(this.props)) { 78 if (key === "nodes") { 79 continue; 80 } 81 const datasetKey = `data-qa-${toSnakeCase(key)}`; 82 testDataSet[datasetKey] = JSON.stringify(value); 83 } 84 } 85 86 return testDataSet; 87 } 88 89 _renderAliases() { 90 const { property } = this.props; 91 let { aliases } = this.props; 92 93 if (!aliases) { 94 return null; 95 } 96 97 aliases = aliases.filter(alias => alias !== property); 98 99 if (aliases.length === 0) { 100 return null; 101 } 102 103 return dom.ul( 104 { 105 className: "compatibility-issue-item__aliases", 106 }, 107 aliases.map(alias => 108 dom.li( 109 { 110 key: alias, 111 className: "compatibility-issue-item__alias", 112 }, 113 alias 114 ) 115 ) 116 ); 117 } 118 119 _renderCauses() { 120 const { deprecated, experimental, prefixNeeded } = this.props; 121 122 if (!deprecated && !experimental && !prefixNeeded) { 123 return null; 124 } 125 126 let localizationId = ""; 127 128 if (deprecated && experimental && prefixNeeded) { 129 localizationId = 130 "compatibility-issue-deprecated-experimental-prefixneeded"; 131 } else if (deprecated && experimental) { 132 localizationId = "compatibility-issue-deprecated-experimental"; 133 } else if (deprecated && prefixNeeded) { 134 localizationId = "compatibility-issue-deprecated-prefixneeded"; 135 } else if (experimental && prefixNeeded) { 136 localizationId = "compatibility-issue-experimental-prefixneeded"; 137 } else if (deprecated) { 138 localizationId = "compatibility-issue-deprecated"; 139 } else if (experimental) { 140 localizationId = "compatibility-issue-experimental"; 141 } else if (prefixNeeded) { 142 localizationId = "compatibility-issue-prefixneeded"; 143 } 144 145 return Localized( 146 { 147 id: localizationId, 148 }, 149 dom.span( 150 { className: "compatibility-issue-item__causes" }, 151 localizationId 152 ) 153 ); 154 } 155 156 _renderPropertyEl() { 157 const { property, url, specUrl } = this.props; 158 const baseCls = "compatibility-issue-item__property devtools-monospace"; 159 if (!url && !specUrl) { 160 return dom.span({ className: baseCls }, property); 161 } 162 163 const href = url ? `${url}?${MDN_LINK_PARAMS}` : specUrl; 164 165 return dom.a( 166 { 167 className: `${baseCls} ${ 168 url 169 ? "compatibility-issue-item__mdn-link" 170 : "compatibility-issue-item__spec-link" 171 }`, 172 href, 173 title: href, 174 onClick: e => this._onLinkClicked(e), 175 }, 176 property 177 ); 178 } 179 180 _renderDescription() { 181 return dom.div( 182 { 183 className: "compatibility-issue-item__description", 184 }, 185 this._renderPropertyEl(), 186 this._renderCauses(), 187 this._renderUnsupportedBrowserList() 188 ); 189 } 190 191 _renderNodeList() { 192 const { dispatch, nodes, setSelectedNode } = this.props; 193 194 if (!nodes) { 195 return null; 196 } 197 198 return NodePane({ 199 dispatch, 200 nodes, 201 setSelectedNode, 202 }); 203 } 204 205 _renderUnsupportedBrowserList() { 206 const { unsupportedBrowsers } = this.props; 207 208 return unsupportedBrowsers.length 209 ? UnsupportedBrowserList({ browsers: unsupportedBrowsers }) 210 : null; 211 } 212 213 render() { 214 const { deprecated, experimental, property, unsupportedBrowsers } = 215 this.props; 216 217 const classes = ["compatibility-issue-item"]; 218 219 if (deprecated) { 220 classes.push("compatibility-issue-item--deprecated"); 221 } 222 223 if (experimental) { 224 classes.push("compatibility-issue-item--experimental"); 225 } 226 227 if (unsupportedBrowsers.length) { 228 classes.push("compatibility-issue-item--unsupported"); 229 } 230 231 return dom.li( 232 { 233 className: classes.join(" "), 234 key: property, 235 ...this._getTestDataAttributes(), 236 }, 237 this._renderDescription(), 238 this._renderAliases(), 239 this._renderNodeList() 240 ); 241 } 242 } 243 244 module.exports = IssueItem;