simmerjs
Version:
A pure Javascript reverse CSS selector engine which calculates a DOM element's unique CSS selector on the current page.
74 lines (61 loc) • 3.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.analyzeElementSiblings = analyzeElementSiblings;
exports.default = function (hierarchy, state, validateSelector) {
return hierarchy.reduce(function (selectorState, currentElem, index) {
if (!selectorState.verified) {
// get siblings BEFORE out element
var prevSiblings = currentElem.prevAll();
var nextSiblings = currentElem.nextAll
// get element's index by the number of elements before it
// note that the nth-child selector uses a 1 based index, not 0
();var indexOfElement = prevSiblings.length + 1;
// If the element has no siblings!
// we have no need for the nth-child selector
if ((prevSiblings.length || nextSiblings.length) && !analyzeElementSiblings(currentElem, [].concat(_toConsumableArray(prevSiblings), _toConsumableArray(nextSiblings)))) {
// if we don't have a unique tag or a unique class, then we need a nth-child to help us
// differenciate our element from the rest of the pack
selectorState.stack[index].push(':nth-child(' + indexOfElement + ')'
// Verify the selector as we don't want to go on and parse the parent's siblings
// if we don't have to!
);selectorState.verified = validateSelector(selectorState);
}
}
return selectorState;
}, state);
};
var _lodash = require('lodash.difference');
var _lodash2 = _interopRequireDefault(_lodash);
var _lodash3 = require('lodash.flatmap');
var _lodash4 = _interopRequireDefault(_lodash3);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
/**
* Inspect the element's siblings by index (nth-child) name and compare them to the analyzed element.
* The sibling comparison is done from level 0 (the analyzed element) upwards in the hierarchy, In an effort to avoid unneeded parsing.
* @param {array} hierarchy. The hierarchy of elements
* @param {object} state. The current calculated CSS selector
*/
var not = function not(i) {
return !i;
};
var getNodeNames = function getNodeNames(siblings) {
return siblings.map(function (sibling) {
return sibling.el.nodeName;
}
/***
* The main method splits up the hierarchy and isolates each element, while this helper method is designed
* to then take each level in the hierarchy and fid into it's surounding siblings.
* We've separated these to make the code more managable.
* @param siblingElement
* @param siblings
* @returns {boolean}
*/
);
};function analyzeElementSiblings(element, siblings) {
return (0, _lodash2.default)(element.getClasses(), (0, _lodash4.default)(siblings, function (sibling) {
return sibling.getClasses();
})).length > 0 || not(getNodeNames(siblings).includes(element.el.nodeName));
}