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

Commit

Permalink
Merge pull request #419 from arv/get-elements-by-tag-name
Browse files Browse the repository at this point in the history
Fix getElementsByTagName to handle colon and more
  • Loading branch information
dfreedm committed Apr 9, 2014
2 parents 9513e0c + 83f2229 commit ea43716
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 21 deletions.
81 changes: 60 additions & 21 deletions src/querySelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
(function(scope) {
'use strict';

var HTMLCollection = scope.wrappers.HTMLCollection;
var NodeList = scope.wrappers.NodeList;

function findOne(node, selector) {
Expand All @@ -20,15 +21,43 @@
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) {
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,
Expand All @@ -40,32 +69,42 @@
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) {
var result = new HTMLCollection();
if (localName === '*')
return findElements(this, result, matchesEveryThing);

return findElements(this, result,
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);
}
};

Expand Down
30 changes: 30 additions & 0 deletions test/js/Document.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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() {
Expand Down
43 changes: 43 additions & 0 deletions test/js/Element.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,49 @@ suite('Element', function() {
assert.equal(as[1], a4);
});

test('getElementsByTagName with colon', function() {
var div = document.createElement('div');
div.innerHTML = '<a:b:c>0</a:b:c><a:b:c>1</a:b:c>';
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 = '<a>0</a><a>1</a>';
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 = '<span class=a>0</span><span class=a>1</span>';
Expand Down

0 comments on commit ea43716

Please sign in to comment.