Skip to content

Commit

Permalink
feat: add iterator function to NodeList and NamedNodeMap (#634)
Browse files Browse the repository at this point in the history
Closes #633
  • Loading branch information
Ponynjaa committed Mar 17, 2024
1 parent 91039af commit 6b21971
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 1 deletion.
49 changes: 49 additions & 0 deletions lib/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ function docGUID(doc) {
* without defining or constraining how this collection is implemented.
* NodeList objects in the DOM are live.
* The items in the NodeList are accessible via an integral index, starting from 0.
* You can also access the items of the NodeList with a `for...of` loop.
*
* @class NodeList
* @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
Expand Down Expand Up @@ -361,6 +362,30 @@ NodeList.prototype = {
return Array.prototype.indexOf.call(this, item);
},
};
NodeList.prototype[Symbol.iterator] = function () {
var me = this;
var index = 0;

return {
next: function () {
if (index < me.length) {
return {
value: me[index++],
done: false,
};
} else {
return {
done: true,
};
}
},
return: function () {
return {
done: true,
};
},
};
};

/**
* Represents a live collection of nodes that is automatically updated when its associated
Expand Down Expand Up @@ -667,6 +692,30 @@ NamedNodeMap.prototype = {
return null;
},
};
NamedNodeMap.prototype[Symbol.iterator] = function () {
var me = this;
var index = 0;

return {
next: function () {
if (index < me.length) {
return {
value: me[index++],
done: false,
};
} else {
return {
done: true,
};
}
},
return: function () {
return {
done: true,
};
},
};
};

/**
* The DOMImplementation interface provides a number of methods for performing operations that
Expand Down
57 changes: 57 additions & 0 deletions test/dom/named-node-map.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,63 @@ const HTML_OWNER_ELEMENT = { _isInHTMLDocumentAndNamespace: () => true };
const XML_OWNER_ELEMENT = { _isInHTMLDocumentAndNamespace: () => false };

describe('NamedNodeMap', () => {
describe('Iterator', () => {
test('should iterate over 3/3 items when using a for...of loop without interruption', () => {
const it = new NamedNodeMap();
const first = new Attr();
it[0] = first;
const second = new Attr();
it[1] = second;
const third = new Attr();
it[2] = third;
it.length = 3;

let count = 0;
for (const _item of it) {
count++;
}
expect(count).toBe(it.length);
});
test('should iterate over 1/3 items when using a for...of loop and breaking after first iteration', () => {
const it = new NamedNodeMap();
const first = new Attr();
it[0] = first;
const second = new Attr();
it[1] = second;
const third = new Attr();
it[2] = third;
it.length = 3;

let count = 0;
for (const _item of it) {
count++;
break;
}
expect(count).toBe(1);
});
test('should iterate over 3/3 items when using two for...of loops subsequently', () => {
const it = new NamedNodeMap();
const first = new Attr();
it[0] = first;
const second = new Attr();
it[1] = second;
const third = new Attr();
it[2] = third;
it.length = 3;

let firstCount = 0;
for (const _item of it) {
firstCount++;
}
let secondCount = 0;
for (const _item of it) {
secondCount++;
}

expect(firstCount).toBe(it.length);
expect(secondCount).toBe(it.length);
});
});
describe('getNamedItem', () => {
test('should return null when no attribute is found', () => {
const it = new NamedNodeMap();
Expand Down
59 changes: 58 additions & 1 deletion test/dom/node-list.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,66 @@
'use strict';

const { describe, expect, test } = require('@jest/globals');
const { NodeList, LiveNodeList, DOMImplementation } = require('../../lib/dom');
const { NodeList, LiveNodeList, DOMImplementation, Element } = require('../../lib/dom');

describe('NodeList', () => {
describe('Iterator', () => {
test('should iterate over 3/3 items when using a for...of loop without interruption', () => {
const it = new NodeList();
const first = new Element();
it[0] = first;
const second = new Element();
it[1] = second;
const third = new Element();
it[2] = third;
it.length = 3;

let count = 0;
for (const _item of it) {
count++;
}
expect(count).toBe(it.length);
});
test('should iterate over 1/3 items when using a for...of loop and breaking after first iteration', () => {
const it = new NodeList();
const first = new Element();
it[0] = first;
const second = new Element();
it[1] = second;
const third = new Element();
it[2] = third;
it.length = 3;

let count = 0;
for (const _item of it) {
count++;
break;
}
expect(count).toBe(1);
});
test('should iterate over 3/3 items when using two for...of loops subsequently', () => {
const it = new NodeList();
const first = new Element();
it[0] = first;
const second = new Element();
it[1] = second;
const third = new Element();
it[2] = third;
it.length = 3;

let firstCount = 0;
for (const _item of it) {
firstCount++;
}
let secondCount = 0;
for (const _item of it) {
secondCount++;
}

expect(firstCount).toBe(it.length);
expect(secondCount).toBe(it.length);
});
});
describe('item', () => {
test('should return null for items outside length', () => {
const it = new NodeList();
Expand Down

0 comments on commit 6b21971

Please sign in to comment.