From 1829d8b88f162dadc53125671c617793cb38cd47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Tue, 2 Feb 2021 11:20:07 +0100 Subject: [PATCH 1/3] remove all children fixes #275 --- src/selection/selectChildren.js | 2 +- test/selection/remove-test.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/selection/selectChildren.js b/src/selection/selectChildren.js index a1d0836..d514d3b 100644 --- a/src/selection/selectChildren.js +++ b/src/selection/selectChildren.js @@ -3,7 +3,7 @@ import {childMatcher} from "../matcher.js"; var filter = Array.prototype.filter; function children() { - return this.children; + return Array.from(this.children); } function childrenFilter(match) { diff --git a/test/selection/remove-test.js b/test/selection/remove-test.js index f673b6f..f398b24 100644 --- a/test/selection/remove-test.js +++ b/test/selection/remove-test.js @@ -29,3 +29,13 @@ it("selection.remove() skips missing elements", "

assert.strictEqual(one.parentNode, null); assert.strictEqual(two.parentNode, document.body); }); + +tape("selectChildren().remove() removes all children", function(test) { + var document = jsdom("
0123456789
"), + p = document.querySelector("div"), + selection = d3.select(p).selectChildren(); + test.equal(selection.size(), 10); + test.equal(selection.remove(), selection); + test.equal(d3.select(p).selectChildren().size(), 0); + test.end(); +}); From 887ccbdcce0f1670e29828bd273169692aa6611e Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sun, 6 Jun 2021 11:14:49 -0700 Subject: [PATCH 2/3] more defensive copy selectAll --- src/array.js | 6 ++---- src/selectAll.js | 2 +- src/selection/data.js | 15 +++++++++++++-- src/selection/selectAll.js | 3 +-- test/selection/remove-test.js | 16 +++++++--------- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/array.js b/src/array.js index f82c3ac..4fb51b1 100644 --- a/src/array.js +++ b/src/array.js @@ -1,5 +1,3 @@ -export default function(x) { - return typeof x === "object" && "length" in x - ? x // Array, TypedArray, NodeList, array-like - : Array.from(x); // Map, Set, iterable, string, or anything else +export default function array(x) { + return x == null ? [] : Array.isArray(x) ? x : Array.from(x); } diff --git a/src/selectAll.js b/src/selectAll.js index 9345898..b6ecc3d 100644 --- a/src/selectAll.js +++ b/src/selectAll.js @@ -4,5 +4,5 @@ import {Selection, root} from "./selection/index.js"; export default function(selector) { return typeof selector === "string" ? new Selection([document.querySelectorAll(selector)], [document.documentElement]) - : new Selection([selector == null ? [] : array(selector)], root); + : new Selection([array(selector)], root); } diff --git a/src/selection/data.js b/src/selection/data.js index 4e0cf0a..8eb0713 100644 --- a/src/selection/data.js +++ b/src/selection/data.js @@ -1,6 +1,5 @@ import {Selection} from "./index.js"; import {EnterNode} from "./enter.js"; -import array from "../array.js"; import constant from "../constant.js"; function bindIndex(parent, group, enter, update, exit, data) { @@ -90,7 +89,7 @@ export default function(value, key) { var parent = parents[j], group = groups[j], groupLength = group.length, - data = array(value.call(parent, parent && parent.__data__, j, parents)), + data = arraylike(value.call(parent, parent && parent.__data__, j, parents)), dataLength = data.length, enterGroup = enter[j] = new Array(dataLength), updateGroup = update[j] = new Array(dataLength), @@ -115,3 +114,15 @@ export default function(value, key) { update._exit = exit; return update; } + +// Given some data, this returns an array-like view of it: an object that +// exposes a length property and allows numeric indexing. Note that unlike +// selectAll, this isn’t worried about “live” collections because the resulting +// array will only be used briefly while data is being bound. (It is possible to +// cause the data to change while iterating by using a key function, but please +// don’t; we’d rather avoid a gratuitous copy.) +function arraylike(data) { + return typeof data === "object" && "length" in data + ? data // Array, TypedArray, NodeList, array-like + : Array.from(data); // Map, Set, iterable, string, or anything else +} diff --git a/src/selection/selectAll.js b/src/selection/selectAll.js index 1eb9027..2a87a27 100644 --- a/src/selection/selectAll.js +++ b/src/selection/selectAll.js @@ -4,8 +4,7 @@ import selectorAll from "../selectorAll.js"; function arrayAll(select) { return function() { - var group = select.apply(this, arguments); - return group == null ? [] : array(group); + return array(select.apply(this, arguments)); }; } diff --git a/test/selection/remove-test.js b/test/selection/remove-test.js index f398b24..8541759 100644 --- a/test/selection/remove-test.js +++ b/test/selection/remove-test.js @@ -1,5 +1,5 @@ import assert from "assert"; -import {selectAll} from "../../src/index.js"; +import {select, selectAll} from "../../src/index.js"; import it from "../jsdom.js"; it("selection.remove() removes selected elements from their parent", "

", () => { @@ -30,12 +30,10 @@ it("selection.remove() skips missing elements", "

assert.strictEqual(two.parentNode, document.body); }); -tape("selectChildren().remove() removes all children", function(test) { - var document = jsdom("
0123456789
"), - p = document.querySelector("div"), - selection = d3.select(p).selectChildren(); - test.equal(selection.size(), 10); - test.equal(selection.remove(), selection); - test.equal(d3.select(p).selectChildren().size(), 0); - test.end(); +it("selectChildren().remove() removes all children", "
0123456789
", () => { + const p = document.querySelector("div"); + const selection = select(p).selectChildren(); + assert.strictEqual(selection.size(), 10); + assert.strictEqual(selection.remove(), selection); + assert.strictEqual(select(p).selectChildren().size(), 0); }); From 457aea5d0f8034dcb44a7e882b353c753f4feba6 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Mon, 7 Jun 2021 10:30:55 -0700 Subject: [PATCH 3/3] comment array --- src/array.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/array.js b/src/array.js index 4fb51b1..978c22a 100644 --- a/src/array.js +++ b/src/array.js @@ -1,3 +1,9 @@ +// Given something array like (or null), returns something that is strictly an +// array. This is used to ensure that array-like objects passed to d3.selectAll +// or selection.selectAll are converted into proper arrays when creating a +// selection; we don’t ever want to create a selection backed by a live +// HTMLCollection or NodeList. However, note that selection.selectAll will use a +// static NodeList as a group, since it safely derived from querySelectorAll. export default function array(x) { return x == null ? [] : Array.isArray(x) ? x : Array.from(x); }