diff --git a/README.md b/README.md index e115d86..5d95e3e 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,14 @@ See [*selection*.data](#selection_data) for more. This method is not intended for concatenating arbitrary selections, however: if both this selection and the specified *other* selection have (non-null) elements at the same index, this selection’s element is returned in the merge and the *other* selection’s element is ignored. +# selection.selectChild([selector]) [<>](https://github.com/d3/d3-selection/blob/master/src/selection/selectChild.js "Source") + +Returns a new selection with the (first) child of each element of the current selection matching the *selector* (if specified). + +# selection.selectChildren([selector]) [<>](https://github.com/d3/d3-selection/blob/master/src/selection/selectChildren.js "Source") + +Returns a new selection with the children of each element of the current selection matching the *selector* (if specified). + # d3.matcher(selector) [<>](https://github.com/d3/d3-selection/blob/master/src/matcher.js "Source") Given the specified *selector*, returns a function which returns true if `this` element [matches](https://developer.mozilla.org/en-US/docs/Web/API/Element/matches) the specified selector. This method is used internally by [*selection*.filter](#selection_filter). For example, this: diff --git a/src/matcher.js b/src/matcher.js index 4d6aadc..e6d4f50 100644 --- a/src/matcher.js +++ b/src/matcher.js @@ -1,5 +1,4 @@ export default function(selector) { - selector += ""; return function() { return this.matches(selector); }; diff --git a/src/selection/selectChild.js b/src/selection/selectChild.js index c7c28bb..6711d30 100644 --- a/src/selection/selectChild.js +++ b/src/selection/selectChild.js @@ -1,13 +1,17 @@ import matcher from "../matcher.js"; +import constant from "../constant.js"; var find = Array.prototype.find; function childFind(match) { + match = typeof match === "function" ? match + : match == null ? constant(true) + : matcher(match); return function() { - return find.call(this.children, match); + return find.call(this.children, function(e) { return match.call(e); }); }; } export default function(match) { - return this.select(childFind(typeof match === "function" ? match : matcher(match))); + return this.select(childFind(match)); } diff --git a/src/selection/selectChildren.js b/src/selection/selectChildren.js index 32cb607..5f263e3 100644 --- a/src/selection/selectChildren.js +++ b/src/selection/selectChildren.js @@ -7,8 +7,9 @@ function children() { } function childrenFilter(match) { + match = typeof match === "function" ? match : matcher(match); return function() { - return filter.call(this.children, match); + return filter.call(this.children, function(e) { return match.call(e); }); }; } diff --git a/test/selection/selectChildren-test.js b/test/selection/selectChildren-test.js new file mode 100644 index 0000000..ac5adf8 --- /dev/null +++ b/test/selection/selectChildren-test.js @@ -0,0 +1,65 @@ +var tape = require("tape"), + jsdom = require("../jsdom"), + d3 = require("../../"); + +tape("select.selectChild(…) selects the first (matching) child", function(test) { + var document = jsdom("

hello, world!

"); + var sel = d3.select(document).select("h1"); + test.ok(sel.selectChild(() => true) instanceof d3.selection); + test.deepEqual(sel.selectChild(() => true), sel.select("*")); + test.ok(sel.selectChild() instanceof d3.selection); + test.ok(sel.selectChild("*") instanceof d3.selection); + test.deepEqual(sel.selectChild("*"), sel.select("*")); + test.deepEqual(sel.selectChild(), sel.select("*")); + test.deepEqual(sel.selectChild("div"), sel.select("div")); + test.equal(sel.selectChild("span").text(), "hello"); + test.end(); +}); + +tape("selectAll.selectChild(…) selects the first (matching) child", function(test) { + var document = jsdom(` +
hello, world!
+
hello2, world2!2
+ `); + var sel = d3.select(document).selectAll("div"); + test.ok(sel.selectChild(() => true) instanceof d3.selection); + test.deepEqual(sel.selectChild(() => true), sel.select("*")); + test.ok(sel.selectChild() instanceof d3.selection); + test.ok(sel.selectChild("*") instanceof d3.selection); + test.deepEqual(sel.selectChild("*"), sel.select("*")); + test.deepEqual(sel.selectChild(), sel.select("*")); + test.deepEqual(sel.selectChild("div"), sel.select("div")); + test.equal(sel.selectChild("span").text(), "hello"); + test.end(); +}); + + +tape("select.selectChildren(…) selects the matching children", function(test) { + var document = jsdom("

hello, world!

"); + var sel = d3.select(document).select("h1"); + test.ok(sel.selectChildren("*") instanceof d3.selection); + test.equal(sel.selectChildren("*").text(), "hello"); + test.equal(sel.selectChildren().size(), 2); + test.equal(sel.selectChildren("*").size(), 2); + test.deepEqual(sel.selectChildren(), sel.selectChildren("*")); + test.equal(sel.selectChildren("span").size(), 2); + test.equal(sel.selectChildren("div").size(), 0); + test.end(); +}); + +tape("selectAll.selectChildren(…) selects the matching children", function(test) { + var document = jsdom(` +
hello, world!
+
hello2, world2!2
+ `); + var sel = d3.select(document).selectAll("div"); + test.ok(sel.selectChildren("*") instanceof d3.selection); + test.equal(sel.selectChildren("*").text(), "hello"); + test.equal(sel.selectChildren().size(), 4); + test.equal(sel.selectChildren("*").size(), 4); + test.deepEqual(sel.selectChildren(), sel.selectChildren("*")); + test.equal(sel.selectChildren("span").size(), 4); + test.equal(sel.selectChildren("div").size(), 0); + test.end(); +}); +