Skip to content

Commit

Permalink
Fix a bug in selector functions.
Browse files Browse the repository at this point in the history
They weren't being invoked with the correct syntax (being passed the data and
index, with the current node as the context). This commit also removes the
d3_array wrapper, which does not appear to be necessary; I've forgotten why it
was there in the first place.
  • Loading branch information
mbostock committed Aug 24, 2011
1 parent 2db0875 commit 9d4b6a0
Show file tree
Hide file tree
Showing 15 changed files with 88 additions and 82 deletions.
62 changes: 22 additions & 40 deletions d3.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,6 @@ if (!Object.create) Object.create = function(o) {
f.prototype = o;
return new f;
};
var d3_array = d3_arraySlice; // conversion for NodeLists

function d3_arrayCopy(pseudoarray) {
var i = -1, n = pseudoarray.length, array = [];
while (++i < n) array.push(pseudoarray[i]);
return array;
}

function d3_arraySlice(pseudoarray) {
return Array.prototype.slice.call(pseudoarray);
}

try {
d3_array(document.documentElement.childNodes)[0].nodeType;
} catch(e) {
d3_array = d3_arrayCopy;
}

var d3_arraySubclass = [].__proto__?

// Until ECMAScript supports array subclassing, prototype injection works well.
Expand Down Expand Up @@ -1207,15 +1189,15 @@ d3.select = function(selector) {
d3.selectAll = function(selector) {
return typeof selector === "string"
? d3_selectionRoot.selectAll(selector)
: d3_selection([d3_array(selector)]); // assume node[]
: d3_selection([selector]); // assume node[]
};
function d3_selection(groups) {
d3_arraySubclass(groups, d3_selectionPrototype);
return groups;
}

var d3_select = function(s, n) { return n.querySelector(s); },
d3_selectAll = function(s, n) { return d3_array(n.querySelectorAll(s)); };
d3_selectAll = function(s, n) { return n.querySelectorAll(s); };

// Prefer Sizzle, if available.
if (typeof Sizzle === "function") {
Expand Down Expand Up @@ -1247,7 +1229,7 @@ d3_selectionPrototype.select = function(selector) {
subgroup.parentNode = (group = this[j]).parentNode;
for (var i = -1, n = group.length; ++i < n;) {
if (node = group[i]) {
subgroup.push(subnode = selector(node));
subgroup.push(subnode = selector.call(node, node.__data__, i));
if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
} else {
subgroup.push(null);
Expand All @@ -1259,8 +1241,8 @@ d3_selectionPrototype.select = function(selector) {
};

function d3_selection_selector(selector) {
return function(node) {
return d3_select(selector, node);
return function() {
return d3_select(selector, this);
};
}
d3_selectionPrototype.selectAll = function(selector) {
Expand All @@ -1273,7 +1255,7 @@ d3_selectionPrototype.selectAll = function(selector) {
for (var j = -1, m = this.length; ++j < m;) {
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
if (node = group[i]) {
subgroups.push(subgroup = selector(node));
subgroups.push(subgroup = selector.call(node, node.__data__, i));
subgroup.parentNode = node;
}
}
Expand All @@ -1283,8 +1265,8 @@ d3_selectionPrototype.selectAll = function(selector) {
};

function d3_selection_selectorAll(selector) {
return function(node) {
return d3_selectAll(selector, node);
return function() {
return d3_selectAll(selector, this);
};
}
d3_selectionPrototype.attr = function(name, value) {
Expand Down Expand Up @@ -1443,12 +1425,12 @@ d3_selectionPrototype.html = function(value) {
d3_selectionPrototype.append = function(name) {
name = d3.ns.qualify(name);

function append(node) {
return node.appendChild(document.createElement(name));
function append() {
return this.appendChild(document.createElement(name));
}

function appendNS(node) {
return node.appendChild(document.createElementNS(name.space, name.local));
function appendNS() {
return this.appendChild(document.createElementNS(name.space, name.local));
}

return this.select(name.local ? appendNS : append);
Expand All @@ -1459,16 +1441,16 @@ d3_selectionPrototype.append = function(name) {
d3_selectionPrototype.insert = function(name, before) {
name = d3.ns.qualify(name);

function insert(node) {
return node.insertBefore(
function insert() {
return this.insertBefore(
document.createElement(name),
d3_select(before, node));
d3_select(before, this));
}

function insertNS(node) {
return node.insertBefore(
function insertNS() {
return this.insertBefore(
document.createElementNS(name.space, name.local),
d3_select(before, node));
d3_select(before, this));
}

return this.select(name.local ? insertNS : insert);
Expand Down Expand Up @@ -1616,7 +1598,7 @@ d3_selection_enterPrototype.select = function(selector) {
subgroup.parentNode = group.parentNode;
for (var i = -1, n = group.length; ++i < n;) {
if (node = group[i]) {
subgroup.push(upgroup[i] = subnode = selector(group.parentNode));
subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i));
subnode.__data__ = node.__data__;
} else {
subgroup.push(null);
Expand Down Expand Up @@ -1865,7 +1847,7 @@ d3_transitionPrototype.select = function(selector) {
for (var j = -1, m = this.length; ++j < m;) {
subgroups.push(subgroup = []);
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
if ((node = group[i]) && (subnode = selector(node.node))) {
if ((node = group[i]) && (subnode = selector.call(node.node, node.node.__data__, i))) {
if ("__data__" in node.node) subnode.__data__ = node.node.__data__;
subgroup.push({node: subnode, delay: node.delay, duration: node.duration});
} else {
Expand All @@ -1886,7 +1868,7 @@ d3_transitionPrototype.selectAll = function(selector) {
for (var j = -1, m = this.length; ++j < m;) {
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
if (node = group[i]) {
subgroups.push(subgroup = selector(node.node));
subgroups.push(subgroup = selector.call(node.node, node.node.__data__, i));
for (var k = -1, o = subgroup.length; ++k < o;) {
subgroup[k] = {node: subgroup[k], delay: node.delay, duration: node.duration};
}
Expand Down Expand Up @@ -3401,7 +3383,7 @@ function d3_svg_mousePoint(container, e) {
};
d3.svg.touches = function(container) {
var touches = d3.event.touches;
return touches ? d3_array(touches).map(function(touch) {
return touches ? Array.prototype.map.call(touches, function(touch) {
var point = d3_svg_mousePoint(container, touch);
point.identifier = touch.identifier;
return point;
Expand Down
4 changes: 2 additions & 2 deletions d3.min.js

Large diffs are not rendered by default.

18 changes: 0 additions & 18 deletions src/core/array.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
var d3_array = d3_arraySlice; // conversion for NodeLists

function d3_arrayCopy(pseudoarray) {
var i = -1, n = pseudoarray.length, array = [];
while (++i < n) array.push(pseudoarray[i]);
return array;
}

function d3_arraySlice(pseudoarray) {
return Array.prototype.slice.call(pseudoarray);
}

try {
d3_array(document.documentElement.childNodes)[0].nodeType;
} catch(e) {
d3_array = d3_arrayCopy;
}

var d3_arraySubclass = [].__proto__?

// Until ECMAScript supports array subclassing, prototype injection works well.
Expand Down
2 changes: 1 addition & 1 deletion src/core/selectAll.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
d3.selectAll = function(selector) {
return typeof selector === "string"
? d3_selectionRoot.selectAll(selector)
: d3_selection([d3_array(selector)]); // assume node[]
: d3_selection([selector]); // assume node[]
};
8 changes: 4 additions & 4 deletions src/core/selection-append.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
d3_selectionPrototype.append = function(name) {
name = d3.ns.qualify(name);

function append(node) {
return node.appendChild(document.createElement(name));
function append() {
return this.appendChild(document.createElement(name));
}

function appendNS(node) {
return node.appendChild(document.createElementNS(name.space, name.local));
function appendNS() {
return this.appendChild(document.createElementNS(name.space, name.local));
}

return this.select(name.local ? appendNS : append);
Expand Down
2 changes: 1 addition & 1 deletion src/core/selection-enter-select.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ d3_selection_enterPrototype.select = function(selector) {
subgroup.parentNode = group.parentNode;
for (var i = -1, n = group.length; ++i < n;) {
if (node = group[i]) {
subgroup.push(upgroup[i] = subnode = selector(group.parentNode));
subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i));
subnode.__data__ = node.__data__;
} else {
subgroup.push(null);
Expand Down
12 changes: 6 additions & 6 deletions src/core/selection-insert.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
d3_selectionPrototype.insert = function(name, before) {
name = d3.ns.qualify(name);

function insert(node) {
return node.insertBefore(
function insert() {
return this.insertBefore(
document.createElement(name),
d3_select(before, node));
d3_select(before, this));
}

function insertNS(node) {
return node.insertBefore(
function insertNS() {
return this.insertBefore(
document.createElementNS(name.space, name.local),
d3_select(before, node));
d3_select(before, this));
}

return this.select(name.local ? insertNS : insert);
Expand Down
6 changes: 3 additions & 3 deletions src/core/selection-select.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ d3_selectionPrototype.select = function(selector) {
subgroup.parentNode = (group = this[j]).parentNode;
for (var i = -1, n = group.length; ++i < n;) {
if (node = group[i]) {
subgroup.push(subnode = selector(node));
subgroup.push(subnode = selector.call(node, node.__data__, i));
if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
} else {
subgroup.push(null);
Expand All @@ -24,7 +24,7 @@ d3_selectionPrototype.select = function(selector) {
};

function d3_selection_selector(selector) {
return function(node) {
return d3_select(selector, node);
return function() {
return d3_select(selector, this);
};
}
6 changes: 3 additions & 3 deletions src/core/selection-selectAll.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ d3_selectionPrototype.selectAll = function(selector) {
for (var j = -1, m = this.length; ++j < m;) {
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
if (node = group[i]) {
subgroups.push(subgroup = selector(node));
subgroups.push(subgroup = selector.call(node, node.__data__, i));
subgroup.parentNode = node;
}
}
Expand All @@ -18,7 +18,7 @@ d3_selectionPrototype.selectAll = function(selector) {
};

function d3_selection_selectorAll(selector) {
return function(node) {
return d3_selectAll(selector, node);
return function() {
return d3_selectAll(selector, this);
};
}
2 changes: 1 addition & 1 deletion src/core/selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ function d3_selection(groups) {
}

var d3_select = function(s, n) { return n.querySelector(s); },
d3_selectAll = function(s, n) { return d3_array(n.querySelectorAll(s)); };
d3_selectAll = function(s, n) { return n.querySelectorAll(s); };

// Prefer Sizzle, if available.
if (typeof Sizzle === "function") {
Expand Down
2 changes: 1 addition & 1 deletion src/core/transition-select.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ d3_transitionPrototype.select = function(selector) {
for (var j = -1, m = this.length; ++j < m;) {
subgroups.push(subgroup = []);
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
if ((node = group[i]) && (subnode = selector(node.node))) {
if ((node = group[i]) && (subnode = selector.call(node.node, node.node.__data__, i))) {
if ("__data__" in node.node) subnode.__data__ = node.node.__data__;
subgroup.push({node: subnode, delay: node.delay, duration: node.duration});
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/core/transition-selectAll.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ d3_transitionPrototype.selectAll = function(selector) {
for (var j = -1, m = this.length; ++j < m;) {
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
if (node = group[i]) {
subgroups.push(subgroup = selector(node.node));
subgroups.push(subgroup = selector.call(node.node, node.node.__data__, i));
for (var k = -1, o = subgroup.length; ++k < o;) {
subgroup[k] = {node: subgroup[k], delay: node.delay, duration: node.duration};
}
Expand Down
2 changes: 1 addition & 1 deletion src/svg/touches.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
d3.svg.touches = function(container) {
var touches = d3.event.touches;
return touches ? d3_array(touches).map(function(touch) {
return touches ? Array.prototype.map.call(touches, function(touch) {
var point = d3_svg_mousePoint(container, touch);
point.identifier = touch.identifier;
return point;
Expand Down
20 changes: 20 additions & 0 deletions test/core/selection-select-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ suite.addBatch({
assert.equal(span[0][0], null);
assert.equal(span.length, 1);
assert.equal(span[0].length, 1);
},
"can select via function": function(body) {
body.append("foo");
var d = {}, dd = [], ii = [], tt = [],
s = body.data([d]).select(function(d, i) { dd.push(d); ii.push(i); tt.push(this); return this.firstChild; });
assert.deepEqual(dd, [d], "expected data, got {actual}");
assert.deepEqual(ii, [0], "expected index, got {actual}");
assert.domEqual(tt[0], document.body, "expected this, got {actual}");
assert.domEqual(s[0][0], document.body.firstChild);
delete document.body.__data__;
}
}
});
Expand Down Expand Up @@ -98,6 +108,16 @@ suite.addBatch({
assert.equal(span[0].length, 2);
assert.isTrue(span[0][0].parentNode === div[0][0]);
assert.isNull(span[0][1]);
},
"can select via function": function(div) {
var dd = [], ii = [], tt = [],
s = div.data(["a", "b"]).select(function(d, i) { dd.push(d); ii.push(i); tt.push(this); return this.firstChild; });
assert.deepEqual(dd, ["a", "b"], "expected data, got {actual}");
assert.deepEqual(ii, [0, 1], "expected index, got {actual}");
assert.domEqual(tt[0], div[0][0], "expected this, got {actual}");
assert.domEqual(tt[1], div[0][1], "expected this, got {actual}");
assert.domEqual(s[0][0], div[0][0].firstChild);
assert.domEqual(s[0][1], div[0][1].firstChild);
}
}
});
Expand Down
22 changes: 22 additions & 0 deletions test/core/selection-selectAll-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ suite.addBatch({
var span = body.selectAll("span");
assert.equal(span.length, 1);
assert.equal(span[0].length, 0);
},
"can select via function": function(body) {
var d = {}, dd = [], ii = [], tt = [],
s = body.data([d]).selectAll(function(d, i) { dd.push(d); ii.push(i); tt.push(this); return this.childNodes; });
assert.deepEqual(dd, [d], "expected data, got {actual}");
assert.deepEqual(ii, [0], "expected index, got {actual}");
assert.domEqual(tt[0], document.body, "expected this, got {actual}");
assert.domEqual(s[0][0], document.body.firstChild);
assert.domEqual(s[0][1], document.body.lastChild);
delete document.body.__data__;
}
}
});
Expand Down Expand Up @@ -98,6 +108,18 @@ suite.addBatch({
assert.equal(span[0].length, 2);
assert.isTrue(span[0][0].parentNode === div[0][0]);
assert.isTrue(span[0][1].parentNode === div[0][0]);
},
"can select via function": function(div) {
var dd = [], ii = [], tt = [],
s = div.data(["a", "b"]).selectAll(function(d, i) { dd.push(d); ii.push(i); tt.push(this); return this.childNodes; });
assert.deepEqual(dd, ["a", "b"], "expected data, got {actual}");
assert.deepEqual(ii, [0, 1], "expected index, got {actual}");
assert.domEqual(tt[0], div[0][0], "expected this, got {actual}");
assert.domEqual(tt[1], div[0][1], "expected this, got {actual}");
assert.domEqual(s[0][0], div[0][0].firstChild);
assert.domEqual(s[0][1], div[0][0].lastChild);
assert.domEqual(s[1][0], div[0][1].firstChild);
assert.domEqual(s[1][1], div[0][1].lastChild);
}
}
});
Expand Down

0 comments on commit 9d4b6a0

Please sign in to comment.