UNPKG

uikit

Version:

UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.

105 lines (85 loc) 3.08 kB
import { attr } from './attr'; import { closest, index, matches, parent } from './filter'; import { isDocument, isString, memoize, toNode, toNodes } from './lang'; export function query(selector, context) { return find(selector, getContext(selector, context)); } export function queryAll(selector, context) { return findAll(selector, getContext(selector, context)); } export function find(selector, context) { return toNode(_query(selector, context, 'querySelector')); } export function findAll(selector, context) { return toNodes(_query(selector, context, 'querySelectorAll')); } const contextSelectorRe = /(^|[^\\],)\s*[!>+~-]/; const isContextSelector = memoize((selector) => selector.match(contextSelectorRe)); function getContext(selector, context = document) { return (isString(selector) && isContextSelector(selector)) || isDocument(context) ? context : context.ownerDocument; } const contextSanitizeRe = /([!>+~-])(?=\s+[!>+~-]|\s*$)/g; const sanatize = memoize((selector) => selector.replace(contextSanitizeRe, '$1 *')); function _query(selector, context = document, queryFn) { if (!selector || !isString(selector)) { return selector; } selector = sanatize(selector); if (isContextSelector(selector)) { const split = splitSelector(selector); selector = ''; for (let sel of split) { let ctx = context; if (sel[0] === '!') { const selectors = sel.substr(1).trim().split(' '); ctx = closest(parent(context), selectors[0]); sel = selectors.slice(1).join(' ').trim(); if (!sel.length && split.length === 1) { return ctx; } } if (sel[0] === '-') { const selectors = sel.substr(1).trim().split(' '); const prev = (ctx || context).previousElementSibling; ctx = matches(prev, sel.substr(1)) ? prev : null; sel = selectors.slice(1).join(' '); } if (ctx) { selector += `${selector ? ',' : ''}${domPath(ctx)} ${sel}`; } } context = document; } try { return context[queryFn](selector); } catch (e) { return null; } } const selectorRe = /.*?[^\\](?:,|$)/g; const splitSelector = memoize((selector) => selector.match(selectorRe).map((selector) => selector.replace(/,$/, '').trim()) ); function domPath(element) { const names = []; while (element.parentNode) { const id = attr(element, 'id'); if (id) { names.unshift(`#${escape(id)}`); break; } else { let { tagName } = element; if (tagName !== 'HTML') { tagName += `:nth-child(${index(element) + 1})`; } names.unshift(tagName); element = element.parentNode; } } return names.join(' > '); } export function escape(css) { return isString(css) ? CSS.escape(css) : ''; }