Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use native query selector parser in track_links and track_forms #382

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 8 additions & 194 deletions dist/mixpanel.amd.js
Original file line number Diff line number Diff line change
Expand Up @@ -1220,201 +1220,15 @@ define(function () { 'use strict';
})();


var TOKEN_MATCH_REGEX = new RegExp('^(\\w*)\\[(\\w+)([=~\\|\\^\\$\\*]?)=?"?([^\\]"]*)"?\\]$');

_.dom_query = (function() {
/* document.getElementsBySelector(selector)
- returns an array of element objects from the current document
matching the CSS selector. Selectors can contain element names,
class names and ids and can be nested. For example:

elements = document.getElementsBySelector('div#main p a.external')

Will return an array of all 'a' elements with 'external' in their
class attribute that are contained inside 'p' elements that are
contained inside the 'div' element which has id="main"

New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
See http://www.w3.org/TR/css3-selectors/#attribute-selectors

Version 0.4 - Simon Willison, March 25th 2003
-- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
-- Opera 7 fails

Version 0.5 - Carl Sverre, Jan 7th 2013
-- Now uses jQuery-esque `hasClass` for testing class name
equality. This fixes a bug related to '-' characters being
considered not part of a 'word' in regex.
*/

function getAllChildren(e) {
// Returns all children of element. Workaround required for IE5/Windows. Ugh.
return e.all ? e.all : e.getElementsByTagName('*');
}

var bad_whitespace = /[\t\r\n]/g;

function hasClass(elem, selector) {
var className = ' ' + selector + ' ';
return ((' ' + elem.className + ' ').replace(bad_whitespace, ' ').indexOf(className) >= 0);
}

function getElementsBySelector(selector) {
// Attempt to fail gracefully in lesser browsers
if (!document$1.getElementsByTagName) {
return [];
}
// Split selector in to tokens
var tokens = selector.split(' ');
var token, bits, tagName, found, foundCount, i, j, k, elements, currentContextIndex;
var currentContext = [document$1];
for (i = 0; i < tokens.length; i++) {
token = tokens[i].replace(/^\s+/, '').replace(/\s+$/, '');
if (token.indexOf('#') > -1) {
// Token is an ID selector
bits = token.split('#');
tagName = bits[0];
var id = bits[1];
var element = document$1.getElementById(id);
if (!element || (tagName && element.nodeName.toLowerCase() != tagName)) {
// element not found or tag with that ID not found, return false
return [];
}
// Set currentContext to contain just this element
currentContext = [element];
continue; // Skip to next token
}
if (token.indexOf('.') > -1) {
// Token contains a class selector
bits = token.split('.');
tagName = bits[0];
var className = bits[1];
if (!tagName) {
tagName = '*';
}
// Get elements matching tag, filter them for class selector
found = [];
foundCount = 0;
for (j = 0; j < currentContext.length; j++) {
if (tagName == '*') {
elements = getAllChildren(currentContext[j]);
} else {
elements = currentContext[j].getElementsByTagName(tagName);
}
for (k = 0; k < elements.length; k++) {
found[foundCount++] = elements[k];
}
}
currentContext = [];
currentContextIndex = 0;
for (j = 0; j < found.length; j++) {
if (found[j].className &&
_.isString(found[j].className) && // some SVG elements have classNames which are not strings
hasClass(found[j], className)
) {
currentContext[currentContextIndex++] = found[j];
}
}
continue; // Skip to next token
}
// Code to deal with attribute selectors
var token_match = token.match(TOKEN_MATCH_REGEX);
if (token_match) {
tagName = token_match[1];
var attrName = token_match[2];
var attrOperator = token_match[3];
var attrValue = token_match[4];
if (!tagName) {
tagName = '*';
}
// Grab all of the tagName elements within current context
found = [];
foundCount = 0;
for (j = 0; j < currentContext.length; j++) {
if (tagName == '*') {
elements = getAllChildren(currentContext[j]);
} else {
elements = currentContext[j].getElementsByTagName(tagName);
}
for (k = 0; k < elements.length; k++) {
found[foundCount++] = elements[k];
}
}
currentContext = [];
currentContextIndex = 0;
var checkFunction; // This function will be used to filter the elements
switch (attrOperator) {
case '=': // Equality
checkFunction = function(e) {
return (e.getAttribute(attrName) == attrValue);
};
break;
case '~': // Match one of space seperated words
checkFunction = function(e) {
return (e.getAttribute(attrName).match(new RegExp('\\b' + attrValue + '\\b')));
};
break;
case '|': // Match start with value followed by optional hyphen
checkFunction = function(e) {
return (e.getAttribute(attrName).match(new RegExp('^' + attrValue + '-?')));
};
break;
case '^': // Match starts with value
checkFunction = function(e) {
return (e.getAttribute(attrName).indexOf(attrValue) === 0);
};
break;
case '$': // Match ends with value - fails with "Warning" in Opera 7
checkFunction = function(e) {
return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length);
};
break;
case '*': // Match ends with value
checkFunction = function(e) {
return (e.getAttribute(attrName).indexOf(attrValue) > -1);
};
break;
default:
// Just test for existence of attribute
checkFunction = function(e) {
return e.getAttribute(attrName);
};
}
currentContext = [];
currentContextIndex = 0;
for (j = 0; j < found.length; j++) {
if (checkFunction(found[j])) {
currentContext[currentContextIndex++] = found[j];
}
}
// alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
continue; // Skip to next token
}
// If we get here, token is JUST an element (not a class or ID selector)
tagName = token;
found = [];
foundCount = 0;
for (j = 0; j < currentContext.length; j++) {
elements = currentContext[j].getElementsByTagName(tagName);
for (k = 0; k < elements.length; k++) {
found[foundCount++] = elements[k];
}
}
currentContext = found;
}
return currentContext;
_.dom_query = function(query) {
if (_.isElement(query)) {
return [query];
} else if (typeof query === 'string') {
return Array.from(document$1.querySelectorAll(query));
} else {
return query;
}

return function(query) {
if (_.isElement(query)) {
return [query];
} else if (_.isObject(query) && !_.isUndefined(query.length)) {
return query;
} else {
return getElementsBySelector.call(this, query);
}
};
})();
};

var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid'];
Expand Down
Loading