UNPKG

unique-selector

Version:

Given a DOM node, return a unique CSS selector matching only that element

267 lines (226 loc) 7.22 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = unique; var _getID = require('./getID'); var _getClasses = require('./getClasses'); var _getCombinations = require('./getCombinations'); var _getAttributes = require('./getAttributes'); var _getNthChild = require('./getNthChild'); var _getTag = require('./getTag'); var _isUnique = require('./isUnique'); var _getParents = require('./getParents'); /** * Returns all the selectors of the elmenet * @param { Object } element * @return { Object } */ /** * Expose `unique` */ function getAllSelectors(el, selectors, attributesToIgnore) { var funcs = { 'Tag': _getTag.getTag, 'NthChild': _getNthChild.getNthChild, 'Attributes': function Attributes(elem) { return (0, _getAttributes.getAttributes)(elem, attributesToIgnore); }, 'Class': _getClasses.getClassSelectors, 'ID': _getID.getID }; return selectors.reduce(function (res, next) { res[next] = funcs[next](el); return res; }, {}); } /** * Tests uniqueNess of the element inside its parent * @param { Object } element * @param { String } Selectors * @return { Boolean } */ function testUniqueness(element, selector) { var parentNode = element.parentNode; var elements = parentNode.querySelectorAll(selector); return elements.length === 1 && elements[0] === element; } /** * Tests all selectors for uniqueness and returns the first unique selector. * @param { Object } element * @param { Array } selectors * @return { String } */ function getFirstUnique(element, selectors) { return selectors.find(testUniqueness.bind(null, element)); } /** * Checks all the possible selectors of an element to find one unique and return it * @param { Object } element * @param { Array } items * @param { String } tag * @return { String } */ function getUniqueCombination(element, items, tag) { var combinations = (0, _getCombinations.getCombinations)(items, 3), firstUnique = getFirstUnique(element, combinations); if (Boolean(firstUnique)) { return firstUnique; } if (Boolean(tag)) { combinations = combinations.map(function (combination) { return tag + combination; }); firstUnique = getFirstUnique(element, combinations); if (Boolean(firstUnique)) { return firstUnique; } } return null; } /** * Returns a uniqueSelector based on the passed options * @param { DOM } element * @param { Array } options * @return { String } */ function getUniqueSelector(element, selectorTypes, attributesToIgnore, excludeRegex) { var foundSelector = void 0; var elementSelectors = getAllSelectors(element, selectorTypes, attributesToIgnore); if (excludeRegex && excludeRegex instanceof RegExp) { elementSelectors.ID = excludeRegex.test(elementSelectors.ID) ? null : elementSelectors.ID; elementSelectors.Class = elementSelectors.Class.filter(function (className) { return !excludeRegex.test(className); }); } var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = selectorTypes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var selectorType = _step.value; var ID = elementSelectors.ID, Tag = elementSelectors.Tag, Classes = elementSelectors.Class, Attributes = elementSelectors.Attributes, NthChild = elementSelectors.NthChild; switch (selectorType) { case 'ID': if (Boolean(ID) && testUniqueness(element, ID)) { return ID; } break; case 'Tag': if (Boolean(Tag) && testUniqueness(element, Tag)) { return Tag; } break; case 'Class': if (Boolean(Classes) && Classes.length) { foundSelector = getUniqueCombination(element, Classes, Tag); if (foundSelector) { return foundSelector; } } break; case 'Attributes': if (Boolean(Attributes) && Attributes.length) { foundSelector = getUniqueCombination(element, Attributes, Tag); if (foundSelector) { return foundSelector; } } break; case 'NthChild': if (Boolean(NthChild)) { return NthChild; } } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return '*'; } /** * Generate unique CSS selector for given DOM element * * @param {Element} el * @return {String} * @api private */ function unique(el) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var _options$selectorType = options.selectorTypes, selectorTypes = _options$selectorType === undefined ? ['ID', 'Class', 'Tag', 'NthChild'] : _options$selectorType, _options$attributesTo = options.attributesToIgnore, attributesToIgnore = _options$attributesTo === undefined ? ['id', 'class', 'length'] : _options$attributesTo, _options$excludeRegex = options.excludeRegex, excludeRegex = _options$excludeRegex === undefined ? null : _options$excludeRegex; var allSelectors = []; var parents = (0, _getParents.getParents)(el); var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = parents[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var elem = _step2.value; var selector = getUniqueSelector(elem, selectorTypes, attributesToIgnore, excludeRegex); if (Boolean(selector)) { allSelectors.push(selector); } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } var selectors = []; var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = allSelectors[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var it = _step3.value; selectors.unshift(it); var _selector = selectors.join(' > '); if ((0, _isUnique.isUnique)(el, _selector)) { return _selector; } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } return null; }