import IChildNodeLike from '../IChildNodeLike'; import IDocumentLike from './DocumentLike/IDocumentLike'; import IDocumentTypeLike from '../DocumentTypeLike/IDocumentTypeLike'; import IElementLike from './ElementLike/IElementLike'; import INonDocumentTypeChildNodeLike from '../INonDocumentTypeChildNodeLike'; import isIDocumentLike from '../../TypeGuards/isIDocumentLike'; import isIParentNodeLike from '../../TypeGuards/isIParentNodeLike'; import IParentNodeLike from './IParentNodeLike'; import TConstructor from '../../TypeAliases/TConstructor'; import { OrderedSet, } from 'immutable'; export function MParentNodeLike>(Base: T) { class MParentNodeLike extends Base { readonly nodeType: number; protected __childNodes: OrderedSet = OrderedSet([]); protected __children: OrderedSet = OrderedSet([]); readonly ownerDocument: IDocumentLike | null; readonly children: Array; readonly firstElementChild: IElementLike | null; readonly lastElementChild: IElementLike | null; readonly childElementCount: number; getDescendantNodes(): Array { return this.__childNodes .map((node: IChildNodeLike) => { if (isIParentNodeLike(node)) { const _node: IParentNodeLike = node; const arr: Array = [ node, ]; return arr.concat(_node.getDescendantNodes()); } else { return [ node, ]; } }).reduce((previousArray: Array, nextArray: Array) => { return previousArray.concat(nextArray); }, []); } getDescendants(): Array { if (!isIParentNodeLike(this)) { throw new Error('This node is not a parent node, and therefore cannot ' + 'have children.'); } return this.__getMatcher().byTag('*'); } querySelector(selector: string): IElementLike { if (!isIParentNodeLike(this)) { throw new Error('The node on which the MParentNodeLike mixin was ' + 'applied does not satisfy the type guard for parent ' + 'nodes.'); } return this.__getMatcher().first(selector, this); } querySelectorAll(selector: string): Array { if (!isIParentNodeLike(this)) { throw new Error('The node on which the MParentNodeLike mixin was ' + 'applied does not satisfy the type guard for parent ' + 'nodes.'); } return this.__getMatcher().select(selector, this); } append(...contents: Array): void { if (isIDocumentLike(this)) { const _this: IDocumentLike = this; contents.forEach((value: IDocumentTypeLike | IElementLike | string) => { if (typeof value === 'string') { throw new Error('A document cannot contain a text node as a ' + 'child.'); } const node = value; _this.appendChild(node); }); } else if (isIParentNodeLike(this)) { const _this: IParentNodeLike = this; const document = (this.ownerDocument); contents.forEach((value: INonDocumentTypeChildNodeLike | string) => { let node = value; if (typeof value === 'string') { node = document.createTextNode(value); } node = node; _this.appendChild(node); }); } else { throw new Error('The node to which the ParentNodeLike mixin was ' + 'applied does not meet the IParentNodeLike type ' + 'guard.'); } } prepend(...contents: Array): void { if (isIDocumentLike(this)) { const _this: IDocumentLike = this; const firstChild = _this.firstChild; contents.forEach((value: IDocumentTypeLike | IElementLike | string) => { if (typeof value === 'string') { throw new Error('A document cannot contain a text node as a ' + 'child.'); } const node = value; if (firstChild) { _this.insertBefore(node, firstChild); } else { _this.appendChild(node); } }); } else if (isIParentNodeLike(this)) { const _this: IParentNodeLike = this; const firstChild = _this.firstChild; const document = (this.ownerDocument); contents.forEach((value: INonDocumentTypeChildNodeLike | string) => { let node = value; if (typeof value === 'string') { node = document.createTextNode(value); } node = node; if (firstChild) { _this.insertBefore(node, firstChild); } else { _this.appendChild(node); } }); } else { throw new Error('The node to which the ParentNodeLike mixin was ' + 'applied does not meet the IParentNodeLike type ' + 'guard.'); } } } return MParentNodeLike; } export default MParentNodeLike;