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
JavaScript
;
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
*/