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';