All files / src/core/dom manipulation.ts

100% Statements 33/33
100% Branches 24/24
100% Functions 8/8
100% Lines 32/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                        4x         24x 20x       20x 16x 8x     8x 24x 3x   24x     8x       16x 12x 1x 11x 2x       16x                   4x 6x               4x 6x               4x 6x               4x 6x             4x 23x 9x 21x 20x 20x 15x        
import { isArrayLike } from 'core/utils/types';
import { each } from 'core/utils/arrays';
import { parent } from 'core/dom/traversal';
 
type NodeCollection = ArrayLike<Node> | Node | undefined | null;
 
/**
 * Inserts Nodes before the given preferredAnchor element.
 * @param parentElm The parent of the preferredAnchor element or the element which shall be the parent of the inserted Nodes.
 * @param preferredAnchor The element before which the Nodes shall be inserted or null if the elements shall be appended at the end.
 * @param insertedElms The Nodes which shall be inserted.
 */
const before: (parentElm: Node | null, preferredAnchor: Node | null, insertedElms: NodeCollection) => void = (
  parentElm,
  preferredAnchor,
  insertedElms,
) => {
  if (insertedElms) {
    let anchor: Node | null = preferredAnchor;
    let fragment: DocumentFragment | Node | undefined | null;
 
    // parent must be defined
    if (parentElm) {
      if (isArrayLike(insertedElms)) {
        fragment = document.createDocumentFragment();
 
        // append all insertedElms to the fragment and if one of these is the anchor, change the anchor
        each(insertedElms, (insertedElm) => {
          if (insertedElm === anchor) {
            anchor = insertedElm.previousSibling;
          }
          fragment!.appendChild(insertedElm);
        });
      } else {
        fragment = insertedElms;
      }
 
      // if the preferred anchor isn't null set it to a valid anchor
      if (preferredAnchor) {
        if (!anchor) {
          anchor = parentElm.firstChild;
        } else if (anchor !== preferredAnchor) {
          anchor = anchor.nextSibling;
        }
      }
 
      parentElm.insertBefore(fragment, anchor);
    }
  }
};
 
/**
 * Appends the given children at the end of the given Node.
 * @param node The Node to which the children shall be appended.
 * @param children The Nodes which shall be appended.
 */
export const appendChildren: (node: Node | null, children: NodeCollection) => void = (node, children) => {
  before(node, null, children);
};
 
/**
 * Prepends the given children at the start of the given Node.
 * @param node The Node to which the children shall be prepended.
 * @param children The Nodes which shall be prepended.
 */
export const prependChildren: (node: Node | null, children: NodeCollection) => void = (node, children) => {
  before(node, node && node.firstChild, children);
};
 
/**
 * Inserts the given Nodes before the given Node.
 * @param node The Node before which the given Nodes shall be inserted.
 * @param insertedNodes The Nodes which shall be inserted.
 */
export const insertBefore: (node: Node | null, insertedNodes: NodeCollection) => void = (node, insertedNodes) => {
  before(parent(node), node, insertedNodes);
};
 
/**
 * Inserts the given Nodes after the given Node.
 * @param node The Node after which the given Nodes shall be inserted.
 * @param insertedNodes The Nodes which shall be inserted.
 */
export const insertAfter: (node: Node | null, insertedNodes: NodeCollection) => void = (node, insertedNodes) => {
  before(parent(node), node && node.nextSibling, insertedNodes);
};
 
/**
 * Removes the given Nodes from their parent.
 * @param nodes The Nodes which shall be removed.
 */
export const removeElements: (nodes: NodeCollection) => void = (nodes) => {
  if (isArrayLike(nodes)) {
    each(Array.from(nodes), (e) => removeElements(e));
  } else if (nodes) {
    const { parentNode } = nodes;
    if (parentNode) {
      parentNode.removeChild(nodes);
    }
  }
};