зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1550031 - Part 4: Manage DOM Mutation breakpoints in the toolbox. r=jlast,ochameau
Differential Revision: https://phabricator.services.mozilla.com/D39898 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
6baad29f20
Коммит
19df4a9319
|
@ -18,3 +18,4 @@
|
|||
|
||||
[options]
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIgnore
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
// @flow
|
||||
|
||||
declare module "devtools/client/framework/store-provider" {
|
||||
declare module.exports: any;
|
||||
}
|
|
@ -71,6 +71,10 @@ DebuggerPanel.prototype = {
|
|||
return this._store.getState();
|
||||
},
|
||||
|
||||
getToolboxStore: function() {
|
||||
return this.toolbox.store;
|
||||
},
|
||||
|
||||
openLink: function(url) {
|
||||
openContentLink(url);
|
||||
},
|
||||
|
|
|
@ -382,4 +382,5 @@ export type Panel = {|
|
|||
openConsoleAndEvaluate: (input: string) => void,
|
||||
highlightDomElement: (grip: Object) => void,
|
||||
unHighlightDomElement: (grip: Object) => void,
|
||||
getToolboxStore: () => any,
|
||||
|};
|
||||
|
|
|
@ -101,7 +101,7 @@ export async function onConnect(
|
|||
client: client.clientCommands,
|
||||
});
|
||||
|
||||
bootstrapApp(store);
|
||||
bootstrapApp(store, panel);
|
||||
await connected;
|
||||
return { store, actions, selectors, client: commands };
|
||||
}
|
||||
|
|
|
@ -30,5 +30,8 @@ bootstrap(React, ReactDOM).then(connection => {
|
|||
console.log("highlighting dom element"),
|
||||
unHighlightDomElement: (grip: Object) =>
|
||||
console.log("unhighlighting dom element"),
|
||||
getToolboxStore: () => {
|
||||
throw new Error("Cannot connect to Toolbox store when running Launchpad");
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@ import { bindActionCreators, combineReducers } from "redux";
|
|||
import ReactDOM from "react-dom";
|
||||
const { Provider } = require("react-redux");
|
||||
|
||||
import ToolboxProvider from "devtools/client/framework/store-provider";
|
||||
import { isFirefoxPanel, isDevelopment, isTesting } from "devtools-environment";
|
||||
import SourceMaps, {
|
||||
startSourceMapWorker,
|
||||
|
@ -28,7 +29,7 @@ import type { Panel } from "../client/firefox/types";
|
|||
|
||||
let parser;
|
||||
|
||||
function renderPanel(component, store) {
|
||||
function renderPanel(component, store, panel: Panel) {
|
||||
const root = document.createElement("div");
|
||||
root.className = "launchpad-root theme-body";
|
||||
root.style.setProperty("flex", "1");
|
||||
|
@ -39,7 +40,15 @@ function renderPanel(component, store) {
|
|||
mount.appendChild(root);
|
||||
|
||||
ReactDOM.render(
|
||||
React.createElement(Provider, { store }, React.createElement(component)),
|
||||
React.createElement(
|
||||
Provider,
|
||||
{ store },
|
||||
React.createElement(
|
||||
ToolboxProvider,
|
||||
{ store: panel.getToolboxStore() },
|
||||
React.createElement(component)
|
||||
)
|
||||
),
|
||||
root
|
||||
);
|
||||
}
|
||||
|
@ -106,9 +115,9 @@ export function teardownWorkers() {
|
|||
search.stop();
|
||||
}
|
||||
|
||||
export function bootstrapApp(store: any) {
|
||||
export function bootstrapApp(store: any, panel: Panel) {
|
||||
if (isFirefoxPanel()) {
|
||||
renderPanel(App, store);
|
||||
renderPanel(App, store, panel);
|
||||
} else {
|
||||
const { renderRoot } = require("devtools-launchpad");
|
||||
renderRoot(React, ReactDOM, App, store);
|
||||
|
|
|
@ -8,10 +8,15 @@ import * as React from "react";
|
|||
|
||||
export function connect<Config, RSP: {}, MDP: {}>(
|
||||
mapStateToProps: (state: any, props: any) => RSP,
|
||||
mapDispatchToProps?: (Function => MDP) | MDP
|
||||
mapDispatchToProps?: (Function => MDP) | MDP,
|
||||
mergeProps?: void,
|
||||
opts?: ?{|
|
||||
storeKey?: string,
|
||||
|}
|
||||
): (
|
||||
Component: React.AbstractComponent<Config>
|
||||
) => React.AbstractComponent<$Diff<Config, RSP & MDP>> {
|
||||
// TODO: Bug 1572214 - We should use the standard type definitions directly.
|
||||
// $FlowFixMe
|
||||
return reduxConnect(mapStateToProps, mapDispatchToProps);
|
||||
return reduxConnect(mapStateToProps, mapDispatchToProps, null, opts);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
"use strict";
|
||||
|
||||
const { assert } = require("devtools/shared/DevToolsUtils");
|
||||
const {
|
||||
getDOMMutationBreakpoint,
|
||||
getDOMMutationBreakpoints,
|
||||
} = require("devtools/client/framework/reducers/dom-mutation-breakpoints");
|
||||
|
||||
exports.registerWalkerListeners = registerWalkerListeners;
|
||||
function registerWalkerListeners(toolbox) {
|
||||
const { walker } = toolbox;
|
||||
|
||||
walker.on("mutations", mutations =>
|
||||
handleWalkerMutations(mutations, toolbox)
|
||||
);
|
||||
}
|
||||
|
||||
function handleWalkerMutations(mutations, toolbox) {
|
||||
// If we got BP updates for detach/unload, we want to drop those nodes from
|
||||
// the list of active DOM mutation breakpoints. We explicitly check these
|
||||
// cases because BP updates could also happen due to explicitly API
|
||||
// operations to add/remove bps.
|
||||
const mutationItems = mutations.filter(
|
||||
mutation => mutation.type === "mutationBreakpoint"
|
||||
);
|
||||
if (mutationItems.length > 0) {
|
||||
toolbox.store.dispatch(updateBreakpointsForMutations(mutationItems));
|
||||
}
|
||||
}
|
||||
|
||||
exports.createDOMMutationBreakpoint = createDOMMutationBreakpoint;
|
||||
function createDOMMutationBreakpoint(nodeFront, mutationType) {
|
||||
assert(typeof nodeFront === "object" && nodeFront);
|
||||
assert(typeof mutationType === "string");
|
||||
|
||||
return async function(dispatch) {
|
||||
const walker = nodeFront.parent();
|
||||
|
||||
dispatch({
|
||||
type: "ADD_DOM_MUTATION_BREAKPOINT",
|
||||
nodeFront,
|
||||
mutationType,
|
||||
});
|
||||
|
||||
await walker.setMutationBreakpoints(nodeFront, {
|
||||
[mutationType]: true,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
exports.deleteDOMMutationBreakpoint = deleteDOMMutationBreakpoint;
|
||||
function deleteDOMMutationBreakpoint(nodeFront, mutationType) {
|
||||
assert(typeof nodeFront === "object" && nodeFront);
|
||||
assert(typeof mutationType === "string");
|
||||
|
||||
return async function(dispatch) {
|
||||
dispatch({
|
||||
type: "REMOVE_DOM_MUTATION_BREAKPOINT",
|
||||
nodeFront,
|
||||
mutationType,
|
||||
});
|
||||
|
||||
const walker = nodeFront.parent();
|
||||
await walker.setMutationBreakpoints(nodeFront, {
|
||||
[mutationType]: false,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function updateBreakpointsForMutations(mutationItems) {
|
||||
return async function(dispatch, getState) {
|
||||
const removedNodeFronts = [];
|
||||
const changedNodeFronts = new Set();
|
||||
|
||||
for (const { target: nodeFront, mutationReason } of mutationItems) {
|
||||
switch (mutationReason) {
|
||||
case "api":
|
||||
changedNodeFronts.add(nodeFront);
|
||||
break;
|
||||
default:
|
||||
console.error(
|
||||
"Unexpected mutation reason",
|
||||
mutationReason,
|
||||
", removing"
|
||||
);
|
||||
// Fall Through
|
||||
case "detach":
|
||||
case "unload":
|
||||
removedNodeFronts.push(nodeFront);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedNodeFronts.length > 0) {
|
||||
dispatch({
|
||||
type: "REMOVE_DOM_MUTATION_BREAKPOINTS_FOR_FRONTS",
|
||||
nodeFronts: removedNodeFronts,
|
||||
});
|
||||
}
|
||||
if (changedNodeFronts.length > 0) {
|
||||
const enabledStates = [];
|
||||
for (const {
|
||||
id,
|
||||
nodeFront,
|
||||
mutationType,
|
||||
enabled,
|
||||
} of getDOMMutationBreakpoints(getState())) {
|
||||
if (changedNodeFronts.has(nodeFront)) {
|
||||
const bpEnabledOnFront = nodeFront.mutationBreakpoints[mutationType];
|
||||
if (bpEnabledOnFront !== enabled) {
|
||||
// Sync the bp state from the front into the store.
|
||||
enabledStates.push([id, bpEnabledOnFront]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: "SET_DOM_MUTATION_BREAKPOINTS_ENABLED_STATE",
|
||||
enabledStates,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.toggleDOMMutationBreakpointState = toggleDOMMutationBreakpointState;
|
||||
function toggleDOMMutationBreakpointState(id, enabled) {
|
||||
assert(typeof id === "string");
|
||||
assert(typeof enabled === "boolean");
|
||||
|
||||
return async function(dispatch, getState) {
|
||||
const bp = getDOMMutationBreakpoint(getState(), id);
|
||||
if (!bp) {
|
||||
throw new Error(`No DOM mutation BP with ID ${id}`);
|
||||
}
|
||||
|
||||
const walker = bp.nodeFront.parent();
|
||||
await walker.setMutationBreakpoints(bp.nodeFront, {
|
||||
[bp.mutationType]: enabled,
|
||||
});
|
||||
};
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
...require("./dom-mutation-breakpoints"),
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'dom-mutation-breakpoints.js',
|
||||
'index.js',
|
||||
)
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('DevTools', 'Framework')
|
|
@ -17,6 +17,8 @@ XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
|||
|
||||
DIRS += [
|
||||
'components',
|
||||
'actions',
|
||||
'reducers',
|
||||
]
|
||||
|
||||
DevToolsModules(
|
||||
|
@ -28,6 +30,8 @@ DevToolsModules(
|
|||
'selection.js',
|
||||
'sidebar.js',
|
||||
'source-map-url-service.js',
|
||||
'store-provider.js',
|
||||
'store.js',
|
||||
'target-from-url.js',
|
||||
'target.js',
|
||||
'toolbox-context-menu.js',
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
"use strict";
|
||||
|
||||
const initialReducerState = {
|
||||
counter: 1,
|
||||
breakpoints: [],
|
||||
};
|
||||
|
||||
exports.reducer = domMutationBreakpointReducer;
|
||||
function domMutationBreakpointReducer(state = initialReducerState, action) {
|
||||
switch (action.type) {
|
||||
case "ADD_DOM_MUTATION_BREAKPOINT":
|
||||
const hasExistingBp = state.breakpoints.some(
|
||||
bp =>
|
||||
bp.nodeFront === action.nodeFront &&
|
||||
bp.mutationType === action.mutationType
|
||||
);
|
||||
|
||||
if (hasExistingBp) {
|
||||
break;
|
||||
}
|
||||
|
||||
state = {
|
||||
...state,
|
||||
counter: state.counter + 1,
|
||||
breakpoints: [
|
||||
...state.breakpoints,
|
||||
{
|
||||
id: `${state.counter}`,
|
||||
nodeFront: action.nodeFront,
|
||||
mutationType: action.mutationType,
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
case "REMOVE_DOM_MUTATION_BREAKPOINT":
|
||||
for (const [index, bp] of state.breakpoints.entries()) {
|
||||
if (
|
||||
bp.nodeFront === action.nodeFront &&
|
||||
bp.mutationType === action.mutationType
|
||||
) {
|
||||
state = {
|
||||
...state,
|
||||
breakpoints: [
|
||||
...state.breakpoints.slice(0, index),
|
||||
...state.breakpoints.slice(index + 1),
|
||||
],
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "REMOVE_DOM_MUTATION_BREAKPOINTS_FOR_FRONTS": {
|
||||
const { nodeFronts } = action;
|
||||
const nodeFrontSet = new Set(nodeFronts);
|
||||
|
||||
const breakpoints = state.breakpoints.filter(
|
||||
bp => !nodeFrontSet.has(bp.nodeFront)
|
||||
);
|
||||
|
||||
// Since we might not have made any actual changes, we verify first
|
||||
// to avoid unnecessary changes in the state.
|
||||
if (state.breakpoints.length !== breakpoints.length) {
|
||||
state = {
|
||||
...state,
|
||||
breakpoints,
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "SET_DOM_MUTATION_BREAKPOINTS_ENABLED_STATE": {
|
||||
const { enabledStates } = action;
|
||||
const toUpdateById = new Map(enabledStates);
|
||||
|
||||
const breakpoints = state.breakpoints.map(bp => {
|
||||
const newBpState = toUpdateById.get(bp.id);
|
||||
if (typeof newBpState === "boolean" && newBpState !== bp.enabled) {
|
||||
bp = {
|
||||
...bp,
|
||||
enabled: newBpState,
|
||||
};
|
||||
}
|
||||
|
||||
return bp;
|
||||
});
|
||||
|
||||
// Since we might not have made any actual changes, we verify first
|
||||
// to avoid unnecessary changes in the state.
|
||||
if (state.breakpoints.some((bp, i) => breakpoints[i] !== bp)) {
|
||||
state = {
|
||||
...state,
|
||||
breakpoints,
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
exports.getDOMMutationBreakpoints = getDOMMutationBreakpoints;
|
||||
function getDOMMutationBreakpoints(state) {
|
||||
return state.domMutationBreakpoints.breakpoints;
|
||||
}
|
||||
|
||||
exports.getDOMMutationBreakpoint = getDOMMutationBreakpoint;
|
||||
function getDOMMutationBreakpoint(state, id) {
|
||||
return (
|
||||
state.domMutationBreakpoints.breakpoints.find(v => v.id === id) || null
|
||||
);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
domMutationBreakpoints: require("./dom-mutation-breakpoints").reducer,
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'dom-mutation-breakpoints.js',
|
||||
'index.js',
|
||||
)
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('DevTools', 'Framework')
|
|
@ -0,0 +1,8 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { createProvider } = require("devtools/client/shared/vendor/react-redux");
|
||||
|
||||
module.exports = createProvider("toolbox-store");
|
|
@ -0,0 +1,13 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const createStore = require("devtools/client/shared/redux/create-store");
|
||||
const reducers = require("./reducers/index");
|
||||
|
||||
exports.createToolboxStore = () =>
|
||||
createStore(reducers, {
|
||||
// Uncomment this for logging in tests.
|
||||
// shouldLog: true,
|
||||
});
|
|
@ -25,6 +25,20 @@ var ChromeUtils = require("ChromeUtils");
|
|||
var { gDevTools } = require("devtools/client/framework/devtools");
|
||||
var EventEmitter = require("devtools/shared/event-emitter");
|
||||
var Telemetry = require("devtools/client/shared/telemetry");
|
||||
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"createToolboxStore",
|
||||
"devtools/client/framework/store",
|
||||
true
|
||||
);
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"registerWalkerListeners",
|
||||
"devtools/client/framework/actions/index",
|
||||
true
|
||||
);
|
||||
|
||||
const { getUnicodeUrl } = require("devtools/client/shared/unicode-url");
|
||||
var {
|
||||
DOMHelpers,
|
||||
|
@ -328,6 +342,13 @@ Toolbox.prototype = {
|
|||
SIDE_ENABLED: "devtools.toolbox.sideEnabled",
|
||||
},
|
||||
|
||||
get store() {
|
||||
if (!this._store) {
|
||||
this._store = createToolboxStore();
|
||||
}
|
||||
return this._store;
|
||||
},
|
||||
|
||||
get currentToolId() {
|
||||
return this._currentToolId;
|
||||
},
|
||||
|
@ -3321,6 +3342,7 @@ Toolbox.prototype = {
|
|||
this.walker.on("highlighter-ready", this._highlighterReady);
|
||||
this.walker.on("highlighter-hide", this._highlighterHidden);
|
||||
this._selection.on("new-node-front", this._onNewSelectedNodeFront);
|
||||
registerWalkerListeners(this);
|
||||
}.bind(this)();
|
||||
}
|
||||
return this._initInspector;
|
||||
|
|
|
@ -21,6 +21,18 @@ const MarkupReadOnlyContainer = require("devtools/client/inspector/markup/views/
|
|||
const MarkupTextContainer = require("devtools/client/inspector/markup/views/text-container");
|
||||
const RootContainer = require("devtools/client/inspector/markup/views/root-container");
|
||||
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"createDOMMutationBreakpoint",
|
||||
"devtools/client/framework/actions/index",
|
||||
true
|
||||
);
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"deleteDOMMutationBreakpoint",
|
||||
"devtools/client/framework/actions/index",
|
||||
true
|
||||
);
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"MarkupContextMenu",
|
||||
|
@ -1270,11 +1282,14 @@ MarkupView.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
const toolboxStore = this.inspector.toolbox.store;
|
||||
const nodeFront = this.inspector.selection.nodeFront;
|
||||
const mutationBreakpoints = nodeFront.mutationBreakpoints;
|
||||
await this.walker.setMutationBreakpoints(nodeFront, {
|
||||
[name]: !mutationBreakpoints[name],
|
||||
});
|
||||
|
||||
if (nodeFront.mutationBreakpoints[name]) {
|
||||
toolboxStore.dispatch(deleteDOMMutationBreakpoint(nodeFront, name));
|
||||
} else {
|
||||
toolboxStore.dispatch(createDOMMutationBreakpoint(nodeFront, name));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -1941,7 +1941,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
return obj;
|
||||
}, {});
|
||||
|
||||
this._updateMutationBreakpointState(rawNode, {
|
||||
this._updateMutationBreakpointState("api", rawNode, {
|
||||
...this.getMutationBreakpoints(node),
|
||||
...bpsForNode,
|
||||
});
|
||||
|
@ -1953,7 +1953,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
* @param {Node} rawNode The DOM node.
|
||||
* @param {Object} bpsForNode The state of each mutation bp type we support.
|
||||
*/
|
||||
_updateMutationBreakpointState(rawNode, bpsForNode) {
|
||||
_updateMutationBreakpointState(mutationReason, rawNode, bpsForNode) {
|
||||
const rawDoc = rawNode.ownerDocument || rawNode;
|
||||
|
||||
const docMutationBreakpoints = this._mutationBreakpointsForDoc(
|
||||
|
@ -2000,6 +2000,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
target: actor.actorID,
|
||||
type: "mutationBreakpoint",
|
||||
mutationBreakpoints: this.getMutationBreakpoints(actor),
|
||||
mutationReason,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -2145,7 +2146,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
|
||||
const walker = this.getDocumentWalker(targetNode);
|
||||
do {
|
||||
this._updateMutationBreakpointState(walker.currentNode, null);
|
||||
this._updateMutationBreakpointState("detach", walker.currentNode, null);
|
||||
} while (walker.nextNode());
|
||||
},
|
||||
|
||||
|
@ -2499,7 +2500,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
const mutationBps = this._mutationBreakpointsForDoc(doc);
|
||||
const nodes = mutationBps ? Array.from(mutationBps.nodes.keys()) : [];
|
||||
for (const node of nodes) {
|
||||
this._updateMutationBreakpointState(node, null);
|
||||
this._updateMutationBreakpointState("unload", node, null);
|
||||
}
|
||||
|
||||
if (this.rootDoc === doc) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче