UNPKG

vuikit

Version:

A responsive Vue UI library for web site interfaces based on UIkit

146 lines (97 loc) 3.4 kB
/** * Copyright (c) 2013-2018 YOOtheme GmbH, getuikit.com */ /* eslint-disable one-var, no-mixed-operators, no-useless-call */ import {removeAttr} from './attr' import {isNode, isString, startsWith, toNode, toNodes} from './lang' export function query (selector, context) { return toNode(selector) || find(selector, isContextSelector(selector) ? context : document) } export function queryAll (selector, context) { const nodes = toNodes(selector) return nodes.length && nodes || findAll(selector, isContextSelector(selector) ? context : document) } export function find (selector, context) { return toNode(_query(selector, context, 'querySelector')) } export function findAll (selector, context) { return toNodes(_query(selector, context, 'querySelectorAll')) } function _query (selector, context = document, queryFn) { if (!selector || !isString(selector)) { return null } selector = selector.replace(contextSanitizeRe, '$1 *') let removes if (isContextSelector(selector)) { removes = [] selector = selector.split(',').map((selector, i) => { let ctx = context selector = selector.trim() if (selector[0] === '!') { const selectors = selector.substr(1).trim().split(' ') ctx = closest(context.parentNode, selectors[0]) selector = selectors.slice(1).join(' ') } if (!ctx) { return null } if (!ctx.id) { ctx.id = `uk-${Date.now()}${i}` removes.push(() => removeAttr(ctx, 'id')) } return `#${escape(ctx.id)} ${selector}` }).filter(Boolean).join(',') context = document } try { return context[queryFn](selector) } catch (e) { return null } finally { removes && removes.forEach(remove => remove()) } } const contextSelectorRe = /(^|,)\s*[!>+~]/ const contextSanitizeRe = /([!>+~])(?=\s+[!>+~]|\s*$)/g function isContextSelector (selector) { return isString(selector) && selector.match(contextSelectorRe) } export function matches (element, selector) { const elProto = window.Element.prototype const matchesFn = elProto.matches || elProto.webkitMatchesSelector || elProto.msMatchesSelector return toNodes(element).some(element => matchesFn.call(element, selector)) } export function closest (element, selector) { const elProto = window.Element.prototype const closestFn = elProto.closest || function (selector) { let ancestor = this do { if (matches(ancestor, selector)) { return ancestor } ancestor = ancestor.parentNode } while (ancestor && ancestor.nodeType === 1) } if (startsWith(selector, '>')) { selector = selector.slice(1) } return isNode(element) ? element.parentNode && closestFn.call(element, selector) : toNodes(element).map(element => element.parentNode && closestFn.call(element, selector)).filter(Boolean) } export function parents (element, selector) { const elements = [] let parent = toNode(element).parentNode while (parent && parent.nodeType === 1) { if (matches(parent, selector)) { elements.push(parent) } parent = parent.parentNode } return elements } export function escape (css) { const escapeFn = window.CSS && CSS.escape || function (css) { return css.replace(/([^\x7f-\uFFFF\w-])/g, match => `\\${match}`) } return isString(css) ? escapeFn.call(null, css) : '' }