commit 90643ae4bec103c63271da0d04d83988f7d6b73a
parent b4c5b7eb301672683481d4e35a5322ab7316129f
Author: Nicolas Chevobbe <nchevobbe@mozilla.com>
Date: Fri, 3 Oct 2025 07:56:43 +0000
Bug 1991683 - [devtools] Use Element.replaceChildren where possible. r=devtools-reviewers,ochameau.
In most of the case, we're using it to remove all children, where we used
to loop through children and removing them one by one.
In a few cases where we would actually update the element right away,
clearing the item and adding new children, we migrate to replaceChildren
so we update the Element in one go.
Differential Revision: https://phabricator.services.mozilla.com/D266984
Diffstat:
9 files changed, 21 insertions(+), 62 deletions(-)
diff --git a/devtools/client/inspector/breadcrumbs.js b/devtools/client/inspector/breadcrumbs.js
@@ -666,9 +666,7 @@ HTMLBreadcrumbs.prototype = {
* Empty the breadcrumbs container.
*/
empty() {
- while (this.container.hasChildNodes()) {
- this.container.firstChild.remove();
- }
+ this.container.replaceChildren();
},
/**
@@ -826,10 +824,7 @@ HTMLBreadcrumbs.prototype = {
}
// Otherwise, update the whole markup for the button.
- while (button.hasChildNodes()) {
- button.firstChild.remove();
- }
- button.appendChild(this.prettyPrintNodeAsXHTML(node));
+ button.replaceChildren(this.prettyPrintNodeAsXHTML(node));
button.setAttribute("title", textOutput);
this.nodeHierarchy[i].currentPrettyPrintText = textOutput;
diff --git a/devtools/client/inspector/markup/markup.js b/devtools/client/inspector/markup/markup.js
@@ -2455,11 +2455,8 @@ MarkupView.prototype = {
if (container.node.inlineTextChild) {
container.setExpanded(false);
- // this container will do double duty as the container for the single
- // text child.
- while (container.children.firstChild) {
- container.children.firstChild.remove();
- }
+ // this container will do double duty as the container for the single text child.
+ container.children.replaceChildren();
container.setInlineTextChild(container.node.inlineTextChild);
@@ -2469,9 +2466,7 @@ MarkupView.prototype = {
}
if (!container.hasChildren) {
- while (container.children.firstChild) {
- container.children.firstChild.remove();
- }
+ container.children.replaceChildren();
container.childrenDirty = false;
container.setExpanded(false);
return Promise.resolve(container);
@@ -2519,9 +2514,7 @@ MarkupView.prototype = {
fragment.appendChild(childContainer.elt);
}
- while (container.children.firstChild) {
- container.children.firstChild.remove();
- }
+ container.children.replaceChildren();
if (!children.hasFirst) {
const topItem = this.buildMoreNodesButtonMarkup(container);
diff --git a/devtools/client/inspector/markup/test/browser_markup_mutation_01.js b/devtools/client/inspector/markup/test/browser_markup_mutation_01.js
@@ -284,9 +284,7 @@ const TEST_DATA = [
async test() {
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
const node4 = content.document.querySelector("#node4");
- while (node4.firstChild) {
- node4.firstChild.remove();
- }
+ node4.replaceChildren();
});
},
async check(inspector) {
diff --git a/devtools/client/netmonitor/src/components/StatisticsPanel.js b/devtools/client/netmonitor/src/components/StatisticsPanel.js
@@ -233,12 +233,8 @@ class StatisticsPanel extends Component {
const container = this.refs[id];
- // Nuke all existing charts of the specified type.
- while (container.hasChildNodes()) {
- container.firstChild.remove();
- }
-
- container.appendChild(chart.node);
+ // Update the charts of the specified type.
+ container.replaceChildren(chart.node);
}
onLayoutChange() {
diff --git a/devtools/client/shared/widgets/Spectrum.js b/devtools/client/shared/widgets/Spectrum.js
@@ -320,11 +320,6 @@ class Spectrum {
return;
}
- // Clear previously appended children before appending any new children
- while (this.contrastLabel.firstChild) {
- this.contrastLabel.firstChild.remove();
- }
-
const largeTextStr = L10N.getStr("accessibility.contrast.large.text");
const contrastLabelStr = L10N.getFormatStr(
"colorPickerTooltip.contrast.large.title",
@@ -343,10 +338,8 @@ class Spectrum {
);
contents.splice(1, 0, largeTextIndicator);
- // Append children to contrast label
- for (const content of contents) {
- this.contrastLabel.appendChild(content);
- }
+ // Update contrast label
+ this.contrastLabel.replaceChildren(...contents);
}
/**
diff --git a/devtools/client/shared/widgets/TableWidget.js b/devtools/client/shared/widgets/TableWidget.js
@@ -771,9 +771,7 @@ TableWidget.prototype = {
return;
}
- while (this.menupopup.firstChild) {
- this.menupopup.firstChild.remove();
- }
+ this.menupopup.replaceChildren();
for (const column of this.columns.values()) {
if (privateColumns.includes(column.id)) {
@@ -1781,12 +1779,7 @@ Cell.prototype = {
if (Node.isInstance(value)) {
this.label.removeAttribute("value");
-
- while (this.label.firstChild) {
- this.label.firstChild.remove();
- }
-
- this.label.appendChild(value);
+ this.label.replaceChildren(value);
} else {
this.label.setAttribute("value", value + "");
}
diff --git a/devtools/client/shared/widgets/tooltip/SwatchFilterTooltip.js b/devtools/client/shared/widgets/tooltip/SwatchFilterTooltip.js
@@ -71,17 +71,13 @@ class SwatchFilterTooltip extends SwatchBasedEditorTooltip {
return;
}
- // Remove the old children and reparse the property value to
- // recompute them.
- while (this.currentFilterValue.firstChild) {
- this.currentFilterValue.firstChild.remove();
- }
+ // Reparse the property value to update the UI
const node = this._parser.parseCssProperty(
"filter",
filters,
this._options
);
- this.currentFilterValue.appendChild(node);
+ this.currentFilterValue.replaceChildren(node);
this.preview();
}
diff --git a/devtools/client/storage/VariablesView.sys.mjs b/devtools/client/storage/VariablesView.sys.mjs
@@ -150,10 +150,7 @@ VariablesView.prototype = {
return;
}
- while (this._list.hasChildNodes()) {
- this._list.firstChild.remove();
- }
-
+ this._list.replaceChildren();
this._appendEmptyNotice();
this._toggleSearchVisibility(false);
},
diff --git a/devtools/client/styleeditor/StyleEditorUI.sys.mjs b/devtools/client/styleeditor/StyleEditorUI.sys.mjs
@@ -1391,18 +1391,13 @@ export class StyleEditorUI extends EventEmitter {
#updateAtRulesList = editor => {
(async function () {
const details = await this.getEditorDetails(editor);
- const list = details.querySelector(".stylesheet-at-rules-list");
-
- while (list.firstChild) {
- list.firstChild.remove();
- }
-
const rules = editor.atRules;
const showSidebar = Services.prefs.getBoolPref(PREF_AT_RULES_SIDEBAR);
const sidebar = details.querySelector(".stylesheet-sidebar");
let inSource = false;
+ const listItems = [];
for (const rule of rules) {
const { line, column } = rule;
@@ -1468,9 +1463,12 @@ export class StyleEditorUI extends EventEmitter {
ruleTextContainer.append(type, cond);
div.append(ruleTextContainer, link);
- list.appendChild(div);
+ listItems.push(div);
}
+ const list = details.querySelector(".stylesheet-at-rules-list");
+ list.replaceChildren(...listItems);
+
sidebar.hidden = !showSidebar || !inSource;
this.emit("at-rules-list-changed", editor);