All files / src/NodeLike/ParentNodeLike MParentNodeLike.ts

7.94% Statements 5/63
0% Branches 0/28
7.14% Functions 1/14
7.94% Lines 5/63
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143          2x 2x     2x                                                                                                                                                                                                                                                                   6x     2x
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';
function MParentNodeLike<T extends TConstructor<object>>(Base: T) {
  class MParentNodeLike extends Base {
    readonly nodeType:          number;
    protected __childNodes:     OrderedSet<IChildNodeLike> = OrderedSet([]);
    protected __children:       OrderedSet<IElementLike> = OrderedSet([]);
    readonly ownerDocument:     IDocumentLike | null;
    readonly children:          Array<IElementLike>;
    readonly firstElementChild: IElementLike | null;
    readonly lastElementChild:  IElementLike | null;
    readonly childElementCount: number;
 
    getDescendantNodes(): Array<IChildNodeLike> {
      return this.__childNodes
        .map((node: IChildNodeLike) => {
          if (isIParentNodeLike(node)) {
            const _node: IParentNodeLike = node;
            const arr: Array<IChildNodeLike> = [ node, ];
            return arr.concat(_node.getDescendantNodes());
          } else {
            return [ node, ];
          }
        }).reduce((previousArray: Array<IChildNodeLike>, nextArray: Array<IChildNodeLike>) => {
          return previousArray.concat(nextArray);
        }, []);
    }
 
    getDescendants(): Array<IElementLike> {
      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<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().select(selector, this);
    }
 
    append(...contents: Array<IChildNodeLike | string>): 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 = <IDocumentTypeLike | IElementLike>value;
          
          _this.appendChild(node);
        });
      } else if (isIParentNodeLike(this)) {
        const _this: IParentNodeLike = this;
        const document = (<IDocumentLike>this.ownerDocument);
        contents.forEach((value: INonDocumentTypeChildNodeLike | string) => {
          let node = value;
          if (typeof value === 'string') {
            node = document.createTextNode(value);
          }
 
          node = <INonDocumentTypeChildNodeLike>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<IChildNodeLike | string>): void {
      if (isIDocumentLike(this)) {
        const _this: IDocumentLike = <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 = <IDocumentTypeLike | IElementLike>value;
          if (firstChild) {
            _this.insertBefore(node, firstChild);
          } else {
            _this.appendChild(node);
          }
        });
      } else if (isIParentNodeLike(this)) {
        const _this: IParentNodeLike = <IParentNodeLike>this;
        const firstChild = _this.firstChild;
        const document = (<IDocumentLike>this.ownerDocument);
        contents.forEach((value: INonDocumentTypeChildNodeLike | string) => {
          let node = value;
          if (typeof value === 'string') {
            node = document.createTextNode(value);
          }
 
          node = <INonDocumentTypeChildNodeLike>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;