compatibility.js (9670B)
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 nodeConstants = require("resource://devtools/shared/dom-node-constants.js"); 8 9 const UserSettings = require("resource://devtools/shared/compatibility/compatibility-user-settings.js"); 10 11 const { 12 COMPATIBILITY_APPEND_NODE_START, 13 COMPATIBILITY_APPEND_NODE_SUCCESS, 14 COMPATIBILITY_APPEND_NODE_FAILURE, 15 COMPATIBILITY_APPEND_NODE_COMPLETE, 16 COMPATIBILITY_CLEAR_DESTROYED_NODES, 17 COMPATIBILITY_INIT_USER_SETTINGS_START, 18 COMPATIBILITY_INIT_USER_SETTINGS_SUCCESS, 19 COMPATIBILITY_INIT_USER_SETTINGS_FAILURE, 20 COMPATIBILITY_INIT_USER_SETTINGS_COMPLETE, 21 COMPATIBILITY_INTERNAL_APPEND_NODE, 22 COMPATIBILITY_INTERNAL_NODE_UPDATE, 23 COMPATIBILITY_INTERNAL_REMOVE_NODE, 24 COMPATIBILITY_INTERNAL_UPDATE_SELECTED_NODE_ISSUES, 25 COMPATIBILITY_REMOVE_NODE_START, 26 COMPATIBILITY_REMOVE_NODE_SUCCESS, 27 COMPATIBILITY_REMOVE_NODE_FAILURE, 28 COMPATIBILITY_REMOVE_NODE_COMPLETE, 29 COMPATIBILITY_UPDATE_NODE_START, 30 COMPATIBILITY_UPDATE_NODE_SUCCESS, 31 COMPATIBILITY_UPDATE_NODE_FAILURE, 32 COMPATIBILITY_UPDATE_NODE_COMPLETE, 33 COMPATIBILITY_UPDATE_NODES_START, 34 COMPATIBILITY_UPDATE_NODES_SUCCESS, 35 COMPATIBILITY_UPDATE_NODES_FAILURE, 36 COMPATIBILITY_UPDATE_NODES_COMPLETE, 37 COMPATIBILITY_UPDATE_SELECTED_NODE_START, 38 COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS, 39 COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE, 40 COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE, 41 COMPATIBILITY_UPDATE_SETTINGS_VISIBILITY, 42 COMPATIBILITY_UPDATE_TARGET_BROWSERS_START, 43 COMPATIBILITY_UPDATE_TARGET_BROWSERS_SUCCESS, 44 COMPATIBILITY_UPDATE_TARGET_BROWSERS_FAILURE, 45 COMPATIBILITY_UPDATE_TARGET_BROWSERS_COMPLETE, 46 COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START, 47 COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_SUCCESS, 48 COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_FAILURE, 49 COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_COMPLETE, 50 } = require("resource://devtools/client/inspector/compatibility/actions/index.js"); 51 52 function appendNode(node) { 53 return async ({ dispatch, getState }) => { 54 dispatch({ type: COMPATIBILITY_APPEND_NODE_START }); 55 56 try { 57 const { targetBrowsers, topLevelTarget } = getState().compatibility; 58 const { walker } = await topLevelTarget.getFront("inspector"); 59 await _inspectNode(node, targetBrowsers, walker, dispatch); 60 dispatch({ type: COMPATIBILITY_APPEND_NODE_SUCCESS }); 61 } catch (error) { 62 dispatch({ 63 type: COMPATIBILITY_APPEND_NODE_FAILURE, 64 error, 65 }); 66 } 67 68 dispatch({ type: COMPATIBILITY_APPEND_NODE_COMPLETE }); 69 }; 70 } 71 72 function clearDestroyedNodes() { 73 return { type: COMPATIBILITY_CLEAR_DESTROYED_NODES }; 74 } 75 76 function initUserSettings() { 77 return async ({ dispatch }) => { 78 dispatch({ type: COMPATIBILITY_INIT_USER_SETTINGS_START }); 79 80 try { 81 const [defaultTargetBrowsers, targetBrowsers] = await Promise.all([ 82 UserSettings.getBrowsersList(), 83 UserSettings.getTargetBrowsers(), 84 ]); 85 86 dispatch({ 87 type: COMPATIBILITY_INIT_USER_SETTINGS_SUCCESS, 88 defaultTargetBrowsers, 89 targetBrowsers, 90 }); 91 } catch (error) { 92 dispatch({ 93 type: COMPATIBILITY_INIT_USER_SETTINGS_FAILURE, 94 error, 95 }); 96 } 97 98 dispatch({ type: COMPATIBILITY_INIT_USER_SETTINGS_COMPLETE }); 99 }; 100 } 101 102 function removeNode(node) { 103 return async ({ dispatch, getState }) => { 104 dispatch({ type: COMPATIBILITY_REMOVE_NODE_START }); 105 106 try { 107 const { topLevelTarget } = getState().compatibility; 108 const { walker } = await topLevelTarget.getFront("inspector"); 109 await _removeNode(node, walker, dispatch); 110 dispatch({ type: COMPATIBILITY_REMOVE_NODE_SUCCESS }); 111 } catch (error) { 112 dispatch({ 113 type: COMPATIBILITY_REMOVE_NODE_FAILURE, 114 error, 115 }); 116 } 117 118 dispatch({ type: COMPATIBILITY_REMOVE_NODE_COMPLETE }); 119 }; 120 } 121 122 function updateNodes(selector) { 123 return async ({ dispatch, getState }) => { 124 dispatch({ type: COMPATIBILITY_UPDATE_NODES_START }); 125 126 try { 127 const { selectedNode, topLevelTarget, targetBrowsers } = 128 getState().compatibility; 129 const { walker } = await topLevelTarget.getFront("inspector"); 130 const nodeList = await walker.querySelectorAll(walker.rootNode, selector); 131 132 for (const node of await nodeList.items()) { 133 await _updateNode(node, selectedNode, targetBrowsers, dispatch); 134 } 135 dispatch({ type: COMPATIBILITY_UPDATE_NODES_SUCCESS }); 136 } catch (error) { 137 dispatch({ 138 type: COMPATIBILITY_UPDATE_NODES_FAILURE, 139 error, 140 }); 141 } 142 143 dispatch({ type: COMPATIBILITY_UPDATE_NODES_COMPLETE }); 144 }; 145 } 146 147 function updateSelectedNode(node) { 148 return async ({ dispatch, getState }) => { 149 dispatch({ type: COMPATIBILITY_UPDATE_SELECTED_NODE_START }); 150 151 try { 152 const { targetBrowsers } = getState().compatibility; 153 await _updateSelectedNodeIssues(node, targetBrowsers, dispatch); 154 155 dispatch({ 156 type: COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS, 157 node, 158 }); 159 } catch (error) { 160 dispatch({ 161 type: COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE, 162 error, 163 }); 164 } 165 166 dispatch({ type: COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE }); 167 }; 168 } 169 170 function updateSettingsVisibility(visibility) { 171 return { 172 type: COMPATIBILITY_UPDATE_SETTINGS_VISIBILITY, 173 visibility, 174 }; 175 } 176 177 function updateTargetBrowsers(targetBrowsers) { 178 return async ({ dispatch, getState }) => { 179 dispatch({ type: COMPATIBILITY_UPDATE_TARGET_BROWSERS_START }); 180 181 try { 182 UserSettings.setTargetBrowsers(targetBrowsers); 183 184 const { selectedNode, topLevelTarget } = getState().compatibility; 185 186 if (selectedNode) { 187 await _updateSelectedNodeIssues(selectedNode, targetBrowsers, dispatch); 188 } 189 190 if (topLevelTarget) { 191 await _updateTopLevelTargetIssues( 192 topLevelTarget, 193 targetBrowsers, 194 dispatch 195 ); 196 } 197 198 dispatch({ 199 type: COMPATIBILITY_UPDATE_TARGET_BROWSERS_SUCCESS, 200 targetBrowsers, 201 }); 202 } catch (error) { 203 dispatch({ type: COMPATIBILITY_UPDATE_TARGET_BROWSERS_FAILURE, error }); 204 } 205 206 dispatch({ type: COMPATIBILITY_UPDATE_TARGET_BROWSERS_COMPLETE }); 207 }; 208 } 209 210 function updateTopLevelTarget(target) { 211 return async ({ dispatch, getState }) => { 212 dispatch({ type: COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START }); 213 214 try { 215 const { targetBrowsers } = getState().compatibility; 216 await _updateTopLevelTargetIssues(target, targetBrowsers, dispatch); 217 218 dispatch({ type: COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_SUCCESS, target }); 219 } catch (error) { 220 dispatch({ type: COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_FAILURE, error }); 221 } 222 223 dispatch({ type: COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_COMPLETE }); 224 }; 225 } 226 227 function updateNode(node) { 228 return async ({ dispatch, getState }) => { 229 dispatch({ type: COMPATIBILITY_UPDATE_NODE_START }); 230 231 try { 232 const { selectedNode, targetBrowsers } = getState().compatibility; 233 await _updateNode(node, selectedNode, targetBrowsers, dispatch); 234 dispatch({ type: COMPATIBILITY_UPDATE_NODE_SUCCESS }); 235 } catch (error) { 236 dispatch({ 237 type: COMPATIBILITY_UPDATE_NODE_FAILURE, 238 error, 239 }); 240 } 241 242 dispatch({ type: COMPATIBILITY_UPDATE_NODE_COMPLETE }); 243 }; 244 } 245 246 async function _getNodeIssues(node, targetBrowsers) { 247 const compatibility = await node.inspectorFront.getCompatibilityFront(); 248 const declarationBlocksIssues = await compatibility.getNodeCssIssues( 249 node, 250 targetBrowsers 251 ); 252 253 return declarationBlocksIssues; 254 } 255 256 async function _inspectNode(node, targetBrowsers, walker, dispatch) { 257 if (node.nodeType !== nodeConstants.ELEMENT_NODE) { 258 return; 259 } 260 261 const issues = await _getNodeIssues(node, targetBrowsers); 262 263 if (issues.length) { 264 dispatch({ 265 type: COMPATIBILITY_INTERNAL_APPEND_NODE, 266 node, 267 issues, 268 }); 269 } 270 271 const { nodes: children } = await walker.children(node); 272 for (const child of children) { 273 await _inspectNode(child, targetBrowsers, walker, dispatch); 274 } 275 } 276 277 async function _removeNode(node, walker, dispatch) { 278 if (node.nodeType !== nodeConstants.ELEMENT_NODE) { 279 return; 280 } 281 282 dispatch({ 283 type: COMPATIBILITY_INTERNAL_REMOVE_NODE, 284 node, 285 }); 286 287 const { nodes: children } = await walker.children(node); 288 for (const child of children) { 289 await _removeNode(child, walker, dispatch); 290 } 291 } 292 293 async function _updateNode(node, selectedNode, targetBrowsers, dispatch) { 294 if (selectedNode.actorID === node.actorID) { 295 await _updateSelectedNodeIssues(node, targetBrowsers, dispatch); 296 } 297 298 const issues = await _getNodeIssues(node, targetBrowsers); 299 dispatch({ 300 type: COMPATIBILITY_INTERNAL_NODE_UPDATE, 301 node, 302 issues, 303 }); 304 } 305 306 async function _updateSelectedNodeIssues(node, targetBrowsers, dispatch) { 307 const issues = await _getNodeIssues(node, targetBrowsers); 308 309 dispatch({ 310 type: COMPATIBILITY_INTERNAL_UPDATE_SELECTED_NODE_ISSUES, 311 issues, 312 }); 313 } 314 315 async function _updateTopLevelTargetIssues(target, targetBrowsers, dispatch) { 316 const { walker } = await target.getFront("inspector"); 317 const documentElement = await walker.documentElement(); 318 await _inspectNode(documentElement, targetBrowsers, walker, dispatch); 319 } 320 321 module.exports = { 322 appendNode, 323 clearDestroyedNodes, 324 initUserSettings, 325 removeNode, 326 updateNodes, 327 updateSelectedNode, 328 updateSettingsVisibility, 329 updateTargetBrowsers, 330 updateTopLevelTarget, 331 updateNode, 332 };