diff --git a/src/querySelector.js b/src/querySelector.js
index f1da41e..900ef95 100644
--- a/src/querySelector.js
+++ b/src/querySelector.js
@@ -5,6 +5,9 @@
(function(scope) {
'use strict';
+ var HTMLCollection = scope.wrappers.HTMLCollection;
+ var NodeList = scope.wrappers.NodeList;
+
function findOne(node, selector) {
var m, el = node.firstElementChild;
while (el) {
@@ -18,15 +21,46 @@
return null;
}
- function findAll(node, selector, results) {
+ function matchesSelector(el, selector) {
+ return el.matches(selector);
+ }
+
+ var XHTML_NS = 'http://www.w3.org/1999/xhtml';
+
+ function matchesTagName(el, localName, localNameLowerCase) {
+ if (localName === '*')
+ return true;
+
+ var ln = el.localName;
+ return ln === localName ||
+ ln === localNameLowerCase && el.namespaceURI === XHTML_NS;
+ }
+
+ function matchesEveryThing() {
+ return true;
+ }
+
+ function matchesLocalName(el, localName) {
+ return el.localName === localName;
+ }
+
+ function matchesNameSpace(el, ns) {
+ return el.namespaceURI === ns;
+ }
+
+ function matchesLocalNameNS(el, ns, localName) {
+ return el.namespaceURI === ns && el.localName === localName;
+ }
+
+ function findElements(node, result, p, arg0, arg1) {
var el = node.firstElementChild;
while (el) {
- if (el.matches(selector))
- results[results.length++] = el;
- findAll(el, selector, results);
+ if (p(el, arg0, arg1))
+ result[result.length++] = el;
+ findElements(el, result, p, arg0, arg1);
el = el.nextElementSibling;
}
- return results;
+ return result;
}
// find and findAll will only match Simple Selectors,
@@ -38,32 +72,38 @@
return findOne(this, selector);
},
querySelectorAll: function(selector) {
- return findAll(this, selector, new NodeList())
+ return findElements(this, new NodeList(), matchesSelector, selector);
}
};
var GetElementsByInterface = {
- getElementsByTagName: function(tagName) {
- // TODO(arv): Check tagName?
- return this.querySelectorAll(tagName);
+ getElementsByTagName: function(localName) {
+ return findElements(this, new HTMLCollection(),
+ matchesTagName,
+ localName,
+ localName.toLowerCase());
},
+
getElementsByClassName: function(className) {
// TODO(arv): Check className?
return this.querySelectorAll('.' + className);
},
- getElementsByTagNameNS: function(ns, tagName) {
- if (ns === '*')
- return this.getElementsByTagName(tagName);
-
- // TODO(arv): Check tagName?
- var result = new NodeList;
- var els = this.getElementsByTagName(tagName);
- for (var i = 0, j = 0; i < els.length; i++) {
- if (els[i].namespaceURI === ns)
- result[j++] = els[i];
+
+ getElementsByTagNameNS: function(ns, localName) {
+ var result = new HTMLCollection();
+
+ if (ns === '') {
+ ns = null;
+ } else if (ns === '*') {
+ if (localName === '*')
+ return findElements(this, result, matchesEveryThing);
+ return findElements(this, result, matchesLocalName, localName);
}
- result.length = j;
- return result;
+
+ if (localName === '*')
+ return findElements(this, result, matchesNameSpace, ns);
+
+ return findElements(this, result, matchesLocalNameNS, ns, localName);
}
};
diff --git a/test/js/Document.js b/test/js/Document.js
index a5afd72..41d1d6b 100644
--- a/test/js/Document.js
+++ b/test/js/Document.js
@@ -93,6 +93,10 @@ htmlSuite('Document', function() {
var nsTwo = 'http://two.com';
var aOne = div.appendChild(document.createElementNS(nsOne, 'a'));
var aTwo = div.appendChild(document.createElementNS(nsTwo, 'a'));
+ var aNull = div.appendChild(document.createElementNS(null, 'a'));
+ var bOne = div.appendChild(document.createElementNS(nsOne, 'b'));
+ var bTwo = div.appendChild(document.createElementNS(nsTwo, 'b'));
+ var bNull = div.appendChild(document.createElementNS(null, 'b'));
var all = div.getElementsByTagNameNS(nsOne, 'a');
assert.equal(all.length, 1);
@@ -102,10 +106,36 @@ htmlSuite('Document', function() {
assert.equal(all.length, 1);
assert.equal(all[0], aTwo);
+ var all = div.getElementsByTagNameNS(null, 'a');
+ assert.equal(all.length, 1);
+ assert.equal(all[0], aNull);
+
+ var all = div.getElementsByTagNameNS('', 'a');
+ assert.equal(all.length, 1);
+ assert.equal(all[0], aNull);
+
var all = div.getElementsByTagNameNS('*', 'a');
+ assert.equal(all.length, 3);
+ assert.equal(all[0], aOne);
+ assert.equal(all[1], aTwo);
+ assert.equal(all[2], aNull);
+
+ var all = div.getElementsByTagNameNS(nsOne, '*');
assert.equal(all.length, 2);
assert.equal(all[0], aOne);
+ assert.equal(all[1], bOne);
+
+ var all = div.getElementsByTagNameNS('*', '*');
+ assert.equal(all.length, 6);
+ assert.equal(all[0], aOne);
assert.equal(all[1], aTwo);
+ assert.equal(all[2], aNull);
+ assert.equal(all[3], bOne);
+ assert.equal(all[4], bTwo);
+ assert.equal(all[5], bNull);
+
+ var all = div.getElementsByTagNameNS('*', 'A');
+ assert.equal(all.length, 0);
});
test('querySelectorAll', function() {
diff --git a/test/js/Element.js b/test/js/Element.js
index 8291716..f5a9c27 100644
--- a/test/js/Element.js
+++ b/test/js/Element.js
@@ -84,6 +84,49 @@ suite('Element', function() {
assert.equal(as[1], a4);
});
+ test('getElementsByTagName with colon', function() {
+ var div = document.createElement('div');
+ div.innerHTML = '01';
+ var a0 = div.firstChild;
+ var a1 = div.lastChild;
+
+ var as = div.getElementsByTagName('a:b:c');
+ assert.equal(as.length, 2);
+ assert.equal(as[0], a0);
+ assert.equal(as.item(0), a0);
+ assert.equal(as[1], a1);
+ assert.equal(as.item(1), a1);
+ });
+
+ test('getElementsByTagName with namespace', function() {
+ var div = document.createElement('div');
+ div.innerHTML = '01';
+ var a0 = div.firstChild;
+ var a1 = div.lastChild;
+ var a2 = document.createElementNS('NS', 'a');
+ var a3 = document.createElementNS('NS', 'A');
+ div.appendChild(a2);
+ div.appendChild(a3);
+
+ var as = div.getElementsByTagName('a');
+ assert.equal(as.length, 3);
+ assert.equal(as[0], a0);
+ assert.equal(as.item(0), a0);
+ assert.equal(as[1], a1);
+ assert.equal(as.item(1), a1);
+ assert.equal(as[2], a2);
+ assert.equal(as.item(2), a2);
+
+ var as = div.getElementsByTagName('A');
+ assert.equal(as.length, 3);
+ assert.equal(as[0], a0);
+ assert.equal(as.item(0), a0);
+ assert.equal(as[1], a1);
+ assert.equal(as.item(1), a1);
+ assert.equal(as[2], a3);
+ assert.equal(as.item(2), a3);
+ });
+
test('getElementsByClassName', function() {
var div = document.createElement('div');
div.innerHTML = '01';