Manual Reference Source Test

src/query.js

/**
*  @file Q function definition
*  @author  Liqueur de Toile <contact@liqueurdetoile.com>
*  @license Apache-2.0 {@link https://www.apache.org/licenses/LICENSE-2.0}
*/

import Element from 'element';
import Collection from 'collection';

/**
*  The `Q` function can be used to create Elements,
*  enhance nodes and query DOM or nodes. It's the swiss army knife
*  of elementify
*
*  ### query syntax
*
*  `Q` will returns an empty collection if
*  no elements are found with the given query. A single HtmLElement (or extended
*  Form, FormElement) if there is only one result and a collection if
*  there is more than one result.
*
*  In query mode, the first parameter must be a valid CSS query selector :
*
*  <ul>
*  <li>#idname for single id search will trigger `getElementById`</li>
*  <li>.classname for single class search will trigger `getElementsByClassName`</li>
*  <li>@elementName for a single name attribute search will trigger `getElementsByName`</li>
*  <li>=tagName for a single tag name search will trigger `getElementsByTagName`</li>
*  </ul>
*
*  Any others queries will be treated through `querySelectorAll`. For single queries,
*  using the above functions will generally be faster than falling down to `querySelectorAll`.
*
*  `Q` tweaks the query so you can perform id or name search in nodes that are not in DOM.
*
*  The second parameter let restrict the search to a node.
*
*  ### Creating and enhancing syntax
*
*  If the first parameter is empty, `Q` will return an HtmlElement with an
*  underlying {@link DocumentFragment}.
*  You can use `Q` as an alias for [Element constructor]{@link elementify.Element}
*  with prepending a `+` on the string node description or providing
*  a valid Element node created with `document.createElement()`.
*
*  Any element node provided to `Q` will be returned enhanced.
*  Any HtmlElement or Collection will be returned as is.
*
*
*  @since 1.0.0
*  @version 1.0.0
*  @author Liqueur de Toile <contact@liqueurdetoile.com>
*
*  @param {Element|Node|String} [s] Element definition or search query
*  @param {Element|Node|String|ArrayObject} [e] Element options or search context
*  @returns {Collection|HtmlElement}
*/
function Q(s, e) {
  var q, r;

  // Create/Enhance mode
  if (typeof s === 'undefined') return new Element();
  if (s.enhanced) return s;
  if (s.nodeType || s === window) return new Element(s, e);
  if (s[0] === '+') return new Element(s.slice(1), e);

  // Query mode
  if (typeof e === 'undefined') e = document;
  else if (e.node) e = e.node;

  // Tweak search if e not equal to document
  if (e !== document) {
    // Let ID search into a node
    if (s[0] === '#') s = s.replace('#', '[id="') + '"]';
    // Let name search into a node
    if (s[0] === '@') s = s.replace('@', '[name="') + '"]';
  }

  try {
    q = e[ {
      '#': 'getElementById',
      '.': 'getElementsByClassName',
      '@': 'getElementsByName',
      '=': 'getElementsByTagName'
    }[ s[0] ] ](s.slice(1));
  } catch (ex) {
    try {
      q = e.querySelectorAll(s);
    } catch (ex) { throw new TypeError('Invalid CSS query Selector'); }
  }

  if (q === null) return new Element();

  if (
    typeof q !== 'undefined' &&
    typeof q.length !== 'undefined' &&
    q.nodeName !== 'FORM'
  ) {
    if (q.length > 1) {
      r = new Collection();
      r.query = s;
      for (let i = 0; i < q.length; i++) r.push(new Element(q.item([i])));
    } else if (q.length === 1) {
      r = new Element(q.item([0]));
    } else return new Element();
  } else r = new Element(q);
  return r;
}

export default Q;