Skip to content

Commit

Permalink
Merge pull request #852 from danielrentz/task/297-document-createNode…
Browse files Browse the repository at this point in the history
…Iterator

#297@minor: Add method Document.createNodeIterator.
  • Loading branch information
capricorn86 committed Apr 12, 2023
2 parents f9a7a22 + 263c2a3 commit 121fc96
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 7 deletions.
2 changes: 2 additions & 0 deletions packages/happy-dom/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ import Comment from './nodes/comment/Comment';
import IComment from './nodes/comment/IComment';
import DocumentType from './nodes/document-type/DocumentType';
import IDocumentType from './nodes/document-type/IDocumentType';
import NodeIterator from './tree-walker/NodeIterator';
import TreeWalker from './tree-walker/TreeWalker';
import CustomElementRegistry from './custom-element/CustomElementRegistry';
import XMLParser from './xml-parser/XMLParser';
Expand Down Expand Up @@ -250,6 +251,7 @@ export {
IComment,
DocumentType,
IDocumentType,
NodeIterator,
TreeWalker,
CustomElementRegistry,
XMLParser,
Expand Down
16 changes: 16 additions & 0 deletions packages/happy-dom/src/nodes/document/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Text from '../text/Text';
import Comment from '../comment/Comment';
import IWindow from '../../window/IWindow';
import Node from '../node/Node';
import NodeIterator from '../../tree-walker/NodeIterator';
import TreeWalker from '../../tree-walker/TreeWalker';
import DocumentFragment from '../document-fragment/DocumentFragment';
import XMLParser from '../../xml-parser/XMLParser';
Expand Down Expand Up @@ -836,6 +837,21 @@ export default class Document extends Node implements IDocument {
return new DocumentFragment();
}

/**
* Creates a node iterator.
*
* @param root Root.
* @param [whatToShow] What to show.
* @param [filter] Filter.
*/
public createNodeIterator(
root: INode,
whatToShow = -1,
filter: INodeFilter = null
): NodeIterator {
return new NodeIterator(root, whatToShow, filter);
}

/**
* Creates a Tree Walker.
*
Expand Down
10 changes: 10 additions & 0 deletions packages/happy-dom/src/nodes/document/IDocument.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import IElement from '../element/IElement';
import IHTMLElement from '../html-element/IHTMLElement';
import IWindow from '../../window/IWindow';
import NodeIterator from '../../tree-walker/NodeIterator';
import TreeWalker from '../../tree-walker/TreeWalker';
import Event from '../../event/Event';
import DOMImplementation from '../../dom-implementation/DOMImplementation';
Expand Down Expand Up @@ -218,6 +219,15 @@ export default interface IDocument extends IParentNode {
*/
createDocumentFragment(): IDocumentFragment;

/**
* Creates a node iterator.
*
* @param root Root.
* @param [whatToShow] What to show.
* @param [filter] Filter.
*/
createNodeIterator(root: INode, whatToShow: number, filter: INodeFilter): NodeIterator;

/**
* Creates a Tree Walker.
*
Expand Down
6 changes: 3 additions & 3 deletions packages/happy-dom/src/tree-walker/INodeFilter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import INode from '../nodes/node/INode';

export default interface INodeFilter {
acceptNode(node: INode): number;
}
type INodeFilter = ((node: INode) => number) | { acceptNode(node: INode): number };

export default INodeFilter;
49 changes: 49 additions & 0 deletions packages/happy-dom/src/tree-walker/NodeIterator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import INodeFilter from './INodeFilter';
import TreeWalker from './TreeWalker';
import INode from '../nodes/node/INode';

/**
* The NodeIterator object represents the nodes of a document subtree and a position within them.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/NodeIterator
*/
export default class NodeIterator {
public root: INode = null;
public whatToShow = -1;
public filter: INodeFilter = null;

private readonly _walker: TreeWalker;

/**
* Constructor.
*
* @param root Root.
* @param [whatToShow] What to show.
* @param [filter] Filter.
*/
constructor(root: INode, whatToShow = -1, filter: INodeFilter = null) {
this.root = root;
this.whatToShow = whatToShow;
this.filter = filter;
this._walker = new TreeWalker(root, whatToShow, filter);
}

/**
* Moves the current Node to the next visible node in the document order.
*
* @returns Current node.
*/
public nextNode(): INode {
return this._walker.nextNode();
}

/**
* Moves the current Node to the previous visible node in the document order, and returns the found node. It also moves the current node to this one. If no such node exists, or if it is before that the root node defined at the object construction, returns null and the current node is not changed.
*
* @returns Current node.
*/
public previousNode(): INode {
return this._walker.previousNode();
}
}
6 changes: 5 additions & 1 deletion packages/happy-dom/src/tree-walker/TreeWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,11 @@ export default class TreeWalker {

if (mask && (this.whatToShow & mask) == 0) {
return NodeFilter.FILTER_SKIP;
} else if (this.filter) {
}
if (typeof this.filter === 'function') {
return this.filter(node);
}
if (this.filter) {
return this.filter.acceptNode(node);
}

Expand Down
2 changes: 2 additions & 0 deletions packages/happy-dom/src/window/IWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import HTMLImageElement from '../nodes/html-image-element/HTMLImageElement';
import Image from '../nodes/html-image-element/Image';
import DocumentFragment from '../nodes/document-fragment/DocumentFragment';
import CharacterData from '../nodes/character-data/CharacterData';
import NodeIterator from '../tree-walker/NodeIterator';
import TreeWalker from '../tree-walker/TreeWalker';
import Event from '../event/Event';
import CustomEvent from '../event/events/CustomEvent';
Expand Down Expand Up @@ -171,6 +172,7 @@ export default interface IWindow extends IEventTarget, INodeJSGlobal {
readonly CharacterData: typeof CharacterData;
readonly ProcessingInstruction: typeof ProcessingInstruction;
readonly NodeFilter: typeof NodeFilter;
readonly NodeIterator: typeof NodeIterator;
readonly TreeWalker: typeof TreeWalker;
readonly DOMParser: typeof DOMParser;
readonly MutationObserver: typeof MutationObserver;
Expand Down
2 changes: 2 additions & 0 deletions packages/happy-dom/src/window/Window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import HTMLImageElement from '../nodes/html-image-element/HTMLImageElement';
import { default as ImageImplementation } from '../nodes/html-image-element/Image';
import DocumentFragment from '../nodes/document-fragment/DocumentFragment';
import CharacterData from '../nodes/character-data/CharacterData';
import NodeIterator from '../tree-walker/NodeIterator';
import TreeWalker from '../tree-walker/TreeWalker';
import Event from '../event/Event';
import CustomEvent from '../event/events/CustomEvent';
Expand Down Expand Up @@ -214,6 +215,7 @@ export default class Window extends EventTarget implements IWindow {
public readonly DocumentFragment = DocumentFragment;
public readonly CharacterData = CharacterData;
public readonly NodeFilter = NodeFilter;
public readonly NodeIterator = NodeIterator;
public readonly TreeWalker = TreeWalker;
public readonly MutationObserver = MutationObserver;
public readonly Document = Document;
Expand Down
27 changes: 24 additions & 3 deletions packages/happy-dom/test/nodes/document/Document.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import HTMLElement from '../../../src/nodes/html-element/HTMLElement';
import Text from '../../../src/nodes/text/Text';
import Comment from '../../../src/nodes/comment/Comment';
import DocumentFragment from '../../../src/nodes/document-fragment/DocumentFragment';
import NodeIterator from '../../../src/tree-walker/NodeIterator';
import TreeWalker from '../../../src/tree-walker/TreeWalker';
import Node from '../../../src/nodes/node/Node';
import IDocument from '../../../src/nodes/document/IDocument';
Expand Down Expand Up @@ -976,8 +977,28 @@ describe('Document', () => {
});
});

describe('createNodeIterator()', () => {
it('Creates a node iterator.', () => {
const root = document.createElement('div');
const whatToShow = 1;
const filter = {
acceptNode(node) {
if (node === Node.ELEMENT_NODE) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_REJECT;
}
};
const nodeIterator = document.createNodeIterator(root, whatToShow, filter);
expect(nodeIterator.root).toBe(root);
expect(nodeIterator.whatToShow).toBe(whatToShow);
expect(nodeIterator.filter).toBe(filter);
expect(nodeIterator).toBeInstanceOf(NodeIterator);
});
});

describe('createTreeWalker()', () => {
it('Creates a document fragment.', () => {
it('Creates a tree walker.', () => {
const root = document.createElement('div');
const whatToShow = 1;
const filter = {
Expand All @@ -989,10 +1010,10 @@ describe('Document', () => {
}
};
const treeWalker = document.createTreeWalker(root, whatToShow, filter);
expect(treeWalker.root === root).toBe(true);
expect(treeWalker.root).toBe(root);
expect(treeWalker.whatToShow).toBe(whatToShow);
expect(treeWalker.filter).toBe(filter);
expect(treeWalker instanceof TreeWalker).toBe(true);
expect(treeWalker).toBeInstanceOf(TreeWalker);
});
});

Expand Down

0 comments on commit 121fc96

Please sign in to comment.