webpro/DOMtastic

View on GitHub
src/selector/closest.js

Summary

Maintainability
A
1 hr
Test Coverage
/**
 * @module closest
 */

import { $, matches } from './index';
import { each, uniq } from '../util';

/**
 * Return the closest element matching the selector (starting by itself) for each element in the collection.
 *
 * @param {String} selector Filter
 * @param {Object} [context] If provided, matching elements must be a descendant of this element
 * @return {Object} New wrapped collection (containing zero or one element)
 * @chainable
 * @example
 *     $('.selector').closest('.container');
 */

export const closest = (() => {

  const closest = function(selector, context) {
    const nodes = [];
    each(this, node => {
      while(node && node !== context) {
        if(matches(node, selector)) {
          nodes.push(node);
          break;
        }
        node = node.parentElement;
      }
    });
    return $(uniq(nodes));
  };

  return typeof Element === 'undefined' || !Element.prototype.closest ? closest : function(selector, context) {
    if(!context) {
      const nodes = [];
      each(this, node => {
        const n = node.closest(selector);
        if(n) {
          nodes.push(n);
        }
      });
      return $(uniq(nodes));
    } else {
      return closest.call(this, selector, context);
    }
  };
})();