UNPKG

simmerjs

Version:

A pure Javascript reverse CSS selector engine which calculates a DOM element's unique CSS selector on the current page.

96 lines (81 loc) 2.98 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.isUniqueElementID = isUniqueElementID; exports.wrap = wrap; exports.default = function (scope, configuredQueryEngine) { var queryEngine = typeof configuredQueryEngine === 'function' ? configuredQueryEngine : documentQuerySelector(scope // If no selector we return an empty array - no CSS selector will ever be generated in this situation! );return function (selector, onError) { return typeof selector !== 'string' ? [] : queryEngine(selector, onError, scope); }; }; /** * Verify a specific ID's uniqueness one the page * @param {object} element. The element we are trying to build a selector for * @param {object} state. The current selector state (has the stack and specificity sum) */ function isUniqueElementID(query, elementID) { // use selector to query an element and see if it is a one-to-one selection var results = query('[id="' + elementID + '"]') || []; return results.length === 1; } function traverseAttribute(el, dir) { var matched = []; var cur = el[dir]; while (cur && cur.nodeType !== 9) { if (cur.nodeType === 1) { matched.push(wrap(cur)); } cur = cur[dir]; } return matched; } function wrap(el) { /// When the DOM wrapper return the selected element it wrapps /// it with helper methods which aid in analyzing the result return { el: el, getClass: function getClass() { return this.el.getAttribute('class') || ''; }, getClasses: function getClasses() { return this.getClass().split(' ').map(function (className) { return className.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }).filter(function (className) { return className.length > 0; }); }, prevAll: function prevAll() { return traverseAttribute(this.el, 'previousSibling'); }, nextAll: function nextAll() { return traverseAttribute(this.el, 'nextSibling'); }, parent: function parent() { return this.el.parentNode && this.el.parentNode.nodeType !== 11 ? wrap(this.el.parentNode) : null; } }; } var INVALID_DOCUMENT = { querySelectorAll: function querySelectorAll() { throw new Error('An invalid context has been provided to Simmer, it doesnt know how to query it'); } }; var documentQuerySelector = function documentQuerySelector(scope) { var document = typeof scope.querySelectorAll === 'function' ? scope : scope.document ? scope.document : INVALID_DOCUMENT; return function (selector, onError) { try { return document.querySelectorAll(selector); } catch (ex) { // handle error onError(ex); } }; }; /** * A DOM manipulation object. Provides both CSS selector querying for verifications and a wrapper for the elements them selves to provide * key behavioural methods, such as sibling querying etc. * @param {object} elementOrSelector. An element we wish to wrapper or a CSS query string */