Skip to content
This repository was archived by the owner on Mar 13, 2018. It is now read-only.

Commit 13e334d

Browse files
committed
Add support for /deep/ to querySelector and querySelectorAll
Fixes #436
1 parent 4702052 commit 13e334d

File tree

3 files changed

+124
-21
lines changed

3 files changed

+124
-21
lines changed

src/querySelector.js

+32-16
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
var OriginalElement = window.Element;
2727
var OriginalDocument = window.HTMLDocument || window.Document;
2828

29-
function filterNodeList(list, index, result) {
29+
function filterNodeList(list, index, result, deep) {
3030
var wrappedItem = null;
3131
var root = null;
3232
for (var i = 0, length = list.length; i < length; i++) {
3333
wrappedItem = wrap(list[i]);
34-
if (root = getTreeScope(wrappedItem).root) {
34+
if (!deep && (root = getTreeScope(wrappedItem).root)) {
3535
if (root instanceof scope.wrappers.ShadowRoot) {
3636
continue;
3737
}
@@ -42,6 +42,10 @@
4242
return index;
4343
}
4444

45+
function shimSelector(selector) {
46+
return String(selector).replace(/\/deep\//g, ' ');
47+
}
48+
4549
function findOne(node, selector) {
4650
var m, el = node.firstElementChild;
4751
while (el) {
@@ -98,7 +102,7 @@
98102
// Structural Pseudo Classes are not guarenteed to be correct
99103
// http://www.w3.org/TR/css3-selectors/#simple-selectors
100104

101-
function querySelectorAllFiltered (p, index, result, selector) {
105+
function querySelectorAllFiltered(p, index, result, selector, deep) {
102106
var target = unsafeUnwrap(this);
103107
var list;
104108
var root = getTreeScope(this).root;
@@ -116,11 +120,15 @@
116120
return findElements(this, index, result, p, selector, null);
117121
}
118122

119-
return filterNodeList(list, index, result);
123+
return filterNodeList(list, index, result, deep);
120124
}
121125

122126
var SelectorsInterface = {
123127
querySelector: function(selector) {
128+
var shimmed = shimSelector(selector);
129+
var deep = shimmed !== selector;
130+
selector = shimmed;
131+
124132
var target = unsafeUnwrap(this);
125133
var wrappedItem;
126134
var root = getTreeScope(this).root;
@@ -142,7 +150,7 @@
142150
// When the original query returns nothing
143151
// we return nothing (to be consistent with the other wrapped calls)
144152
return wrappedItem;
145-
} else if (root = getTreeScope(wrappedItem).root) {
153+
} else if (!deep && (root = getTreeScope(wrappedItem).root)) {
146154
if (root instanceof scope.wrappers.ShadowRoot) {
147155
// When the original query returns an element in the ShadowDOM
148156
// we must do a manual tree traversal
@@ -153,19 +161,25 @@
153161
return wrappedItem;
154162
},
155163
querySelectorAll: function(selector) {
164+
var shimmed = shimSelector(selector);
165+
var deep = shimmed !== selector;
166+
selector = shimmed;
167+
156168
var result = new NodeList();
157169

158170
result.length = querySelectorAllFiltered.call(this,
159171
matchesSelector,
160172
0,
161173
result,
162-
selector);
174+
selector,
175+
deep);
163176

164177
return result;
165178
}
166179
};
167180

168-
function getElementsByTagNameFiltered (p, index, result, localName, lowercase) {
181+
function getElementsByTagNameFiltered(p, index, result, localName,
182+
lowercase) {
169183
var target = unsafeUnwrap(this);
170184
var list;
171185
var root = getTreeScope(this).root;
@@ -174,19 +188,21 @@
174188
// going to be disconnected so we do a manual tree traversal
175189
return findElements(this, index, result, p, localName, lowercase);
176190
} else if (target instanceof OriginalElement) {
177-
list = originalElementGetElementsByTagName.call(target, localName, lowercase);
191+
list = originalElementGetElementsByTagName.call(target, localName,
192+
lowercase);
178193
} else if (target instanceof OriginalDocument) {
179-
list = originalDocumentGetElementsByTagName.call(target, localName, lowercase);
194+
list = originalDocumentGetElementsByTagName.call(target, localName,
195+
lowercase);
180196
} else {
181197
// When we get a ShadowRoot the logical tree is going to be disconnected
182198
// so we do a manual tree traversal
183199
return findElements(this, index, result, p, localName, lowercase);
184200
}
185201

186-
return filterNodeList(list, index, result);
202+
return filterNodeList(list, index, result, false);
187203
}
188204

189-
function getElementsByTagNameNSFiltered (p, index, result, ns, localName) {
205+
function getElementsByTagNameNSFiltered(p, index, result, ns, localName) {
190206
var target = unsafeUnwrap(this);
191207
var list;
192208
var root = getTreeScope(this).root;
@@ -204,17 +220,17 @@
204220
return findElements(this, index, result, p, ns, localName);
205221
}
206222

207-
return filterNodeList(list, index, result);
223+
return filterNodeList(list, index, result, false);
208224
}
209225

210226
var GetElementsByInterface = {
211227
getElementsByTagName: function(localName) {
212228
var result = new HTMLCollection();
213229
var match = localName === '*' ? matchesEveryThing : matchesTagName;
214230

215-
result.length = getElementsByTagNameFiltered.call(this,
231+
result.length = getElementsByTagNameFiltered.call(this,
216232
match,
217-
0,
233+
0,
218234
result,
219235
localName,
220236
localName.toLowerCase());
@@ -236,8 +252,8 @@
236252
} else {
237253
match = localName === '*' ? matchesNameSpace : matchesLocalNameNS;
238254
}
239-
240-
result.length = getElementsByTagNameNSFiltered.call(this,
255+
256+
result.length = getElementsByTagNameNSFiltered.call(this,
241257
match,
242258
0,
243259
result,

test/js/Document.js

+45-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ htmlSuite('Document', function() {
4949
assert.equal(doc.head.parentNode, doc.documentElement);
5050
});
5151

52-
skipTest('getElementsByTagName', function() {
52+
test('getElementsByTagName', function() {
5353
var elements = document.getElementsByTagName('body');
5454
assert.isTrue(elements instanceof HTMLCollection);
5555
assert.equal(elements.length, 1);
@@ -65,7 +65,9 @@ htmlSuite('Document', function() {
6565
assert.isTrue(elements2[0] instanceof HTMLElement);
6666
assert.equal(doc.body, elements2[0]);
6767
assert.equal(doc.body, elements2.item(0));
68+
});
6869

70+
skipTest('getElementsByTagName', function() {
6971
div = document.body.appendChild(document.createElement('div'));
7072
div.innerHTML = '<aa></aa><aa></aa>';
7173
var aa1 = div.firstChild;
@@ -143,7 +145,7 @@ htmlSuite('Document', function() {
143145
assert.equal(all.length, 0);
144146
});
145147

146-
skipTest('querySelectorAll', function() {
148+
test('querySelectorAll', function() {
147149
var elements = document.querySelectorAll('body');
148150
assert.isTrue(elements instanceof NodeList);
149151
assert.equal(elements.length, 1);
@@ -157,7 +159,9 @@ htmlSuite('Document', function() {
157159
assert.equal(elements2.length, 1);
158160
assert.isTrue(elements2[0] instanceof HTMLElement);
159161
assert.equal(doc.body, elements2[0]);
162+
});
160163

164+
skipTest('querySelectorAll', function() {
161165
div = document.body.appendChild(document.createElement('div'));
162166
div.innerHTML = '<aa></aa><aa></aa>';
163167
var aa1 = div.firstChild;
@@ -184,11 +188,49 @@ htmlSuite('Document', function() {
184188
assert.equal(z.length, 0);
185189
});
186190

187-
skipTest('querySelector', function() {
191+
test('querySelector', function() {
188192
var z = document.querySelector('z');
189193
assert.equal(z, null);
190194
});
191195

196+
test('querySelector deep', function() {
197+
div = document.body.appendChild(document.createElement('div'));
198+
div.innerHTML = '<aa></aa><aa></aa>';
199+
var aa1 = div.firstChild;
200+
var aa2 = div.lastChild;
201+
202+
var sr = div.createShadowRoot();
203+
sr.innerHTML = '<bb></bb><content></content>';
204+
var bb = sr.firstChild;
205+
206+
div.offsetHeight;
207+
208+
assert.equal(aa1, document.querySelector('div /deep/ aa'));
209+
assert.equal(bb, document.querySelector('div /deep/ bb'));
210+
});
211+
212+
test('querySelectorAll deep', function() {
213+
div = document.body.appendChild(document.createElement('div'));
214+
div.innerHTML = '<aa></aa><aa></aa>';
215+
var aa1 = div.firstChild;
216+
var aa2 = div.lastChild;
217+
218+
var sr = div.createShadowRoot();
219+
sr.innerHTML = '<bb></bb><content></content>';
220+
var bb = sr.firstChild;
221+
222+
div.offsetHeight;
223+
224+
var list = document.querySelectorAll('div /deep/ aa');
225+
assert.equal(2, list.length);
226+
assert.equal(aa1, list[0]);
227+
assert.equal(aa2, list[1]);
228+
229+
list = document.querySelectorAll('div /deep/ bb');
230+
assert.equal(1, list.length);
231+
assert.equal(bb, list[0]);
232+
});
233+
192234
test('addEventListener', function() {
193235
var calls = 0;
194236
var doc = wrap(document);

test/js/Element.js

+47-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ suite('Element', function() {
1717

1818
function skipTest () {}
1919

20-
skipTest('querySelector', function() {
20+
test('querySelector', function() {
2121
var div = document.createElement('div');
2222
div.innerHTML = '<a><b></b></a>';
2323
var b = div.firstChild.firstChild;
@@ -39,7 +39,7 @@ suite('Element', function() {
3939
assert.equal(z, null);
4040
});
4141

42-
skipTest('querySelectorAll', function() {
42+
test('querySelectorAll', function() {
4343
var div = document.createElement('div');
4444
div.innerHTML = '<a>0</a><a>1</a>';
4545
var a0 = div.firstChild;
@@ -51,6 +51,13 @@ suite('Element', function() {
5151
assert.equal(as.item(0), a0);
5252
assert.equal(as[1], a1);
5353
assert.equal(as.item(1), a1);
54+
});
55+
56+
skipTest('querySelectorAll', function() {
57+
var div = document.createElement('div');
58+
div.innerHTML = '<a>0</a><a>1</a>';
59+
var a0 = div.firstChild;
60+
var a1 = div.lastChild;
5461

5562
var sr = div.createShadowRoot();
5663
sr.innerHTML = '<a>3</a><a>4</a>';
@@ -76,6 +83,44 @@ suite('Element', function() {
7683
assert.equal(z.length, 0);
7784
});
7885

86+
test('querySelector deep', function() {
87+
var div = document.createElement('div');
88+
div.innerHTML = '<aa></aa><aa></aa>';
89+
var aa1 = div.firstChild;
90+
var aa2 = div.lastChild;
91+
92+
var sr = div.createShadowRoot();
93+
sr.innerHTML = '<bb></bb><content></content>';
94+
var bb = sr.firstChild;
95+
96+
div.offsetHeight;
97+
98+
assert.equal(aa1, div.querySelector('div /deep/ aa'));
99+
assert.equal(bb, div.querySelector('div /deep/ bb'));
100+
});
101+
102+
test('querySelectorAll deep', function() {
103+
var div = document.createElement('div');
104+
div.innerHTML = '<aa></aa><aa></aa>';
105+
var aa1 = div.firstChild;
106+
var aa2 = div.lastChild;
107+
108+
var sr = div.createShadowRoot();
109+
sr.innerHTML = '<bb></bb><content></content>';
110+
var bb = sr.firstChild;
111+
112+
div.offsetHeight;
113+
114+
var list = div.querySelectorAll('div /deep/ aa');
115+
assert.equal(2, list.length);
116+
assert.equal(aa1, list[0]);
117+
assert.equal(aa2, list[1]);
118+
119+
list = div.querySelectorAll('div /deep/ bb');
120+
assert.equal(1, list.length);
121+
assert.equal(bb, list[0]);
122+
});
123+
79124
skipTest('getElementsByTagName', function() {
80125
var div = document.createElement('div');
81126
div.innerHTML = '<a>0</a><a>1</a>';

0 commit comments

Comments
 (0)