dom-mutation-breakpoints.js (4619B)
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 "use strict"; 5 6 const { assert } = require("resource://devtools/shared/DevToolsUtils.js"); 7 const { 8 getDOMMutationBreakpoint, 9 getDOMMutationBreakpoints, 10 } = require("resource://devtools/client/framework/reducers/dom-mutation-breakpoints.js"); 11 12 exports.registerWalkerListeners = registerWalkerListeners; 13 function registerWalkerListeners(store, walker) { 14 walker.on("mutations", mutations => handleWalkerMutations(mutations, store)); 15 } 16 17 /** 18 * Called when a target is destroyed. This will allow the reducer to remove breakpoints on 19 * nodeFront associated with the passed target 20 * 21 * @param {ToolboxStore} store: The toolbox redux store 22 * @param {TargetFront} targetFront 23 */ 24 function removeTarget(store, targetFront) { 25 store.dispatch({ 26 type: "REMOVE_TARGET", 27 targetFront, 28 }); 29 } 30 exports.removeTarget = removeTarget; 31 32 function handleWalkerMutations(mutations, store) { 33 // If we got BP updates for detach/unload, we want to drop those nodes from 34 // the list of active DOM mutation breakpoints. We explicitly check these 35 // cases because BP updates could also happen due to explicitly API 36 // operations to add/remove bps. 37 const mutationItems = mutations.filter( 38 mutation => mutation.type === "mutationBreakpoint" 39 ); 40 if (mutationItems.length) { 41 store.dispatch(updateBreakpointsForMutations(mutationItems)); 42 } 43 } 44 45 exports.createDOMMutationBreakpoint = createDOMMutationBreakpoint; 46 function createDOMMutationBreakpoint(nodeFront, mutationType) { 47 assert(typeof nodeFront === "object" && nodeFront); 48 assert(typeof mutationType === "string"); 49 50 return async function ({ dispatch }) { 51 const walker = nodeFront.walkerFront; 52 53 dispatch({ 54 type: "ADD_DOM_MUTATION_BREAKPOINT", 55 nodeFront, 56 mutationType, 57 }); 58 59 await walker.setMutationBreakpoints(nodeFront, { 60 [mutationType]: true, 61 }); 62 }; 63 } 64 65 exports.deleteDOMMutationBreakpoint = deleteDOMMutationBreakpoint; 66 function deleteDOMMutationBreakpoint(nodeFront, mutationType) { 67 assert(typeof nodeFront === "object" && nodeFront); 68 assert(typeof mutationType === "string"); 69 70 return async function ({ dispatch }) { 71 const walker = nodeFront.walkerFront; 72 await walker.setMutationBreakpoints(nodeFront, { 73 [mutationType]: false, 74 }); 75 76 dispatch({ 77 type: "REMOVE_DOM_MUTATION_BREAKPOINT", 78 nodeFront, 79 mutationType, 80 }); 81 }; 82 } 83 84 function updateBreakpointsForMutations(mutationItems) { 85 return async function ({ dispatch, getState }) { 86 const removedNodeFronts = []; 87 const changedNodeFronts = new Set(); 88 89 for (const { target: nodeFront, mutationReason } of mutationItems) { 90 switch (mutationReason) { 91 case "api": 92 changedNodeFronts.add(nodeFront); 93 break; 94 default: 95 console.error( 96 "Unexpected mutation reason", 97 mutationReason, 98 ", removing" 99 ); 100 // Fall Through 101 case "detach": 102 case "unload": 103 removedNodeFronts.push(nodeFront); 104 break; 105 } 106 } 107 108 if (removedNodeFronts.length) { 109 dispatch({ 110 type: "REMOVE_DOM_MUTATION_BREAKPOINTS_FOR_FRONTS", 111 nodeFronts: removedNodeFronts, 112 }); 113 } 114 if (changedNodeFronts.size > 0) { 115 const enabledStates = []; 116 for (const { 117 id, 118 nodeFront, 119 mutationType, 120 enabled, 121 } of getDOMMutationBreakpoints(getState())) { 122 if (changedNodeFronts.has(nodeFront)) { 123 const bpEnabledOnFront = nodeFront.mutationBreakpoints[mutationType]; 124 if (bpEnabledOnFront !== enabled) { 125 // Sync the bp state from the front into the store. 126 enabledStates.push([id, bpEnabledOnFront]); 127 } 128 } 129 } 130 131 dispatch({ 132 type: "SET_DOM_MUTATION_BREAKPOINTS_ENABLED_STATE", 133 enabledStates, 134 }); 135 } 136 }; 137 } 138 139 exports.toggleDOMMutationBreakpointState = toggleDOMMutationBreakpointState; 140 function toggleDOMMutationBreakpointState(id, enabled) { 141 assert(typeof id === "string"); 142 assert(typeof enabled === "boolean"); 143 144 return async function ({ getState }) { 145 const bp = getDOMMutationBreakpoint(getState(), id); 146 if (!bp) { 147 throw new Error(`No DOM mutation BP with ID ${id}`); 148 } 149 150 const walker = bp.nodeFront.getParent(); 151 await walker.setMutationBreakpoints(bp.nodeFront, { 152 [bp.mutationType]: enabled, 153 }); 154 }; 155 }