Big News: Socket Selected for OpenAI's Cybersecurity Grant Program.Details
Socket
Book a DemoSign in
Socket

mixpanel-js-utils

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mixpanel-js-utils - npm Package Compare versions

Comparing version
0.0.5
to
0.0.6
+3
.babelrc
{
"presets": [ "es2015-rollup" ]
}

Sorry, the diff of this file is not supported yet

{
"browser": true,
"curly": true,
"latedef": true,
"esnext": true,
"mocha": true,
"module": true,
"node": true,
"quotmark": true,
"strict": true,
"undef": true,
"unused": true,
"trailing": true
}

Sorry, the diff of this file is not supported yet

# mixpanel-js-utils
A JS utility library for Mixpanel. Currently this is used to share code between our application and our JS library.
# Installing and using
Install via NPM:
`npm install mixpanel-js-utils`
Import to use:
`import utils from 'mixpanel-js-utils'`
# Developing
* Create a branch
* Add your changes
* Build and test your changes via `npm test`
* Update the version in `package.json`
* Commit, review, merge, and tag the new release
* `npm publish` to push to npm
var jsdom = require('mocha-jsdom');
var expect = require('chai').expect;
var utils = require('../build/index.cjs.js');
jsdom();
describe('elementHasOwnHandler', function() {
var elementHasOwnHandler = utils.elementHasOwnHandler;
describe('testTags', function() {
it('should return true for "interactive" tags, false for everything else', function() {
['div', 'span', 'strong'].forEach(function(tagName) {
var el = document.createElement(tagName);
expect(false).to.equal(elementHasOwnHandler(el));
});
['form', 'input', 'select', 'textarea', 'submit', 'a'].forEach(function(tagName) {
var el = document.createElement(tagName);
expect(true).to.equal(elementHasOwnHandler(el));
});
});
});
describe('testOnClick', function() {
it('should return true for elements with an onclick handler', function() {
var el = document.createElement('div');
expect(false).to.equal(elementHasOwnHandler(el));
el.setAttribute('onclick', 'test');
expect(true).to.equal(elementHasOwnHandler(el));
el = document.createElement('div');
el.onclick = 'test';
expect(true).to.equal(elementHasOwnHandler(el));
});
});
describe('testJqueryEventHandlers', function() {
it('should return true for elements that have bound jQuery event handlers', function() {
var div = document.createElement('div');
var divBound = document.createElement('div');
var divBound2 = document.createElement('div');
div.id = 'div';
divBound.id = 'div_bound';
divBound2.id = 'div_bound2';
// mock
window.jQuery = {
_data: function(elem, name) {
var _bound = {
'div_bound': {
'events': ['some_event_binding']
}
};
return _bound[elem.id] && _bound[elem.id][name];
}
};
expect(false).to.equal(elementHasOwnHandler(div));
expect(true).to.equal(elementHasOwnHandler(divBound));
// mock
window.jQuery = {
data: function(elem, name) {
var _bound = {
'div_bound2': {
'events': ['some_event_binding']
}
};
return _bound[elem.id] && _bound[elem.id][name];
},
};
expect(true).to.equal(elementHasOwnHandler(divBound2));
});
it('should return true for elements with data-events attribute', function() {
var div = document.createElement('div');
expect(false).to.equal(elementHasOwnHandler(div));
div.setAttribute('data-events', 'some_event_bindings');
expect(true).to.equal(elementHasOwnHandler(div));
});
it('should return true if Event.observers contains the node', function() {
var div = document.createElement('div');
// mock
window.Event = {};
window.Event.observers = [];
expect(false).to.equal(elementHasOwnHandler(div));
window.Event.observers.push([div]);
expect(true).to.equal(elementHasOwnHandler(div));
});
it('should return true if Event.cache contains a reference to the node', function() {
var div = document.createElement('div');
div._eventId = 'event_1';
// mock
window.Event = {};
window.Event.cache = {};
expect(false).to.equal(elementHasOwnHandler(div));
window.Event.cache[div._eventId] = {
click: ['some_event_binding']
};
expect(true).to.equal(elementHasOwnHandler(div));
var div2 = document.createElement('div');
div2._prototypeEventID = ['event_1'];
window.Event.cache = {};
window.Event.cache[div2._prototypeEventID[0]] = {
click: ['some_event_binding']
};
expect(true).to.equal(elementHasOwnHandler(div2));
});
});
});
describe('nearestInteractiveElement', function() {
var nearestInteractiveElement = utils.nearestInteractiveElement;
it('should return cached version', function() {
var div = document.createElement('div');
var cache = {};
expect(div).to.equal(nearestInteractiveElement(div, cache));
cache[div] = {
element: div,
closest: 'cached'
};
expect('cached').to.equal(nearestInteractiveElement(div, cache));
});
it('should return null for html and head tags', function() {
var html = document.createElement('html');
expect(null).to.equal(nearestInteractiveElement(html));
var head = document.createElement('head');
expect(null).to.equal(nearestInteractiveElement(head));
});
describe('find closest element that seems interactive', function() {
var buildTestDom = function() {
var body = document.createElement('body');
var div1 = document.createElement('div');
div1.id = 'div_1';
var div2 = document.createElement('div');
div2.id = 'div_2';
var div3 = document.createElement('div');
div3.id = 'div_3';
body.appendChild(div1);
div1.appendChild(div2);
div2.appendChild(div3);
return [body, div1, div2, div3];
};
it('should return the original element if no element is matched', function() {
var elements = buildTestDom();
var div3 = elements[3];
expect(div3.id).to.equal(nearestInteractiveElement(div3).id);
});
it('should match elements with data- attributes', function() {
var elements = buildTestDom();
var div2 = elements[2];
var div3 = elements[3];
div2.setAttribute('data-test', 'test');
expect(div2.id).to.equal(nearestInteractiveElement(div3).id);
});
it('should ignore elements with pointer-events css set to none', function() {
var elements = buildTestDom();
var div1 = elements[1];
var div2 = elements[2];
var div3 = elements[3];
div1.setAttribute('data-test', 'test');
div2.setAttribute('data-test', 'test');
div2.style['pointer-events'] = 'none';
expect(div1.id).to.equal(nearestInteractiveElement(div3).id);
});
it('should match the child element if the cursor goes to default or auto from something else', function() {
var elements = buildTestDom();
var div1 = elements[1];
var div2 = elements[2];
var div3 = elements[3];
div2.style.cursor = 'pointer';
div1.style.cursor = 'default';
expect(div2.id).to.equal(nearestInteractiveElement(div3).id);
});
it('should match elements with their own click handler', function() {
var elements = buildTestDom();
var div1 = elements[1];
var div3 = elements[3];
div1.onclick = 'test';
expect(div1.id).to.equal(nearestInteractiveElement(div3).id);
});
});
});
+45
-45
'use strict';
var hasOwnHandler = function (element) {
var tests = [
function (node) {
return ['form', 'input', 'select', 'textarea', 'submit', 'a'].indexOf(node.tagName.toLowerCase()) !== -1;
},
function (node) {
// for onclick properties and attributes
return node.onclick || node.getAttribute('onclick');
},
function (node) {
return !!(jQuery._data || jQuery.data)(node, 'events')
},
function (node) {
// jquery 1.3.x and 1.4x
return !!node.getAttributes('data-events');
},
function (node) {
// jquery 1.5.x
for(var i = 0; i < Event.observers.length; i++) {
var observer = Event.observers[i];
if ((observer || [])[0] === node) {
return true;
}
var elementHasOwnHandler = function elementHasOwnHandler(element) {
var tests = [function (node) {
return ['form', 'input', 'select', 'textarea', 'submit', 'a'].indexOf(node.tagName.toLowerCase()) > -1;
}, function (node) {
// for onclick properties and attributes
return node.onclick || node.getAttribute('onclick');
}, function (node) {
return !!(window.jQuery._data || window.jQuery.data)(node, 'events');
}, function (node) {
// jquery 1.3.x and 1.4x
return node.getAttribute('data-events');
}, function (node) {
// jquery 1.5.x
for (var i = 0; i < window.Event.observers.length; i++) {
var observer = window.Event.observers[i];
if ((observer || [])[0] === node) {
return true;
}
return false;
},
function (node) {
// jquery 1.6 to 1.6.0.3
return Event.cache[node._eventId || node._prototypeEventID[0]].click[0];
}
];
return false;
}, function (node) {
// jquery 1.6 to 1.6.0.3
return window.Event.cache[node._eventId || node._prototypeEventID[0]].click[0];
}];

@@ -46,3 +39,3 @@ for (var i = 0; i < tests.length; i++) {

var nearestInteractiveElement = function(element, cache) {
var nearestInteractiveElement = function nearestInteractiveElement(element, cache) {
if (cache && cache[element] && cache[element].element === element) {

@@ -52,13 +45,14 @@ return cache[element].closest;

if (['html', 'head'].indexOf(element.tagName.toLowerCase()) > -1) { // can't call css on these
if (['html', 'head'].indexOf(element.tagName.toLowerCase()) > -1) {
// can't call css on these
return null;
}
// next, try to find the closest element with a click handler
var child, closest;
// next, try to find the closest element that seems interactive
var child = void 0,
closest = void 0;
var candidate = element;
var visited_candidates = [];
for (var candidate = element;
!closest && candidate && !(candidate.tagName.toLowerCase() === 'body');
child = candidate, candidate = candidate.parentElement) {
do {
visited_candidates.push(candidate);

@@ -68,2 +62,4 @@

if (candidate.style['pointer-events'] === 'none') {
child = candidate;
candidate = candidate.parentElement;
continue;

@@ -76,4 +72,4 @@ }

var childStyles = window.getComputedStyle(child);
var cursor = candidateStyles['cursor'];
if ((cursor === 'default' || cursor === 'auto') && cursor !== childStyles['cursor']) {
var cursor = candidateStyles.cursor;
if ((cursor === 'default' || cursor === 'auto') && cursor !== childStyles.cursor) {
closest = child;

@@ -86,3 +82,3 @@ break;

var attrs = candidate.attributes;
for(var i = 0; i < attrs.length; i++) {
for (var i = 0; i < attrs.length; i++) {
if (/^data\-/.test(attrs[i].name)) {

@@ -95,13 +91,16 @@ closest = candidate;

// if the element has its own click handler, it is almost certainly clickable
if (hasOwnHandler(candidate)) {
if (elementHasOwnHandler(candidate)) {
closest = candidate;
break;
}
}
child = candidate;
candidate = candidate.parentElement;
} while (candidate && candidate.tagName.toLowerCase() !== 'body');
if (cache && closest) {
for (var i = 0; i < visited_candidates.length; i++) {
var candidate = visited_candidates[i];
cache[candidate] = closest;
};
for (var _i = 0; _i < visited_candidates.length; _i++) {
var _candidate = visited_candidates[_i];
cache[_candidate] = closest;
}
cache[element] = {

@@ -116,2 +115,3 @@ closest: closest,

exports.elementHasOwnHandler = elementHasOwnHandler;
exports.nearestInteractiveElement = nearestInteractiveElement;

@@ -1,32 +0,27 @@

var hasOwnHandler = function (element) {
var tests = [
function (node) {
return ['form', 'input', 'select', 'textarea', 'submit', 'a'].indexOf(node.tagName.toLowerCase()) !== -1;
},
function (node) {
// for onclick properties and attributes
return node.onclick || node.getAttribute('onclick');
},
function (node) {
return !!(jQuery._data || jQuery.data)(node, 'events')
},
function (node) {
// jquery 1.3.x and 1.4x
return !!node.getAttributes('data-events');
},
function (node) {
// jquery 1.5.x
for(var i = 0; i < Event.observers.length; i++) {
var observer = Event.observers[i];
if ((observer || [])[0] === node) {
return true;
}
'use strict';
var elementHasOwnHandler = function elementHasOwnHandler(element) {
var tests = [function (node) {
return ['form', 'input', 'select', 'textarea', 'submit', 'a'].indexOf(node.tagName.toLowerCase()) > -1;
}, function (node) {
// for onclick properties and attributes
return node.onclick || node.getAttribute('onclick');
}, function (node) {
return !!(window.jQuery._data || window.jQuery.data)(node, 'events');
}, function (node) {
// jquery 1.3.x and 1.4x
return node.getAttribute('data-events');
}, function (node) {
// jquery 1.5.x
for (var i = 0; i < window.Event.observers.length; i++) {
var observer = window.Event.observers[i];
if ((observer || [])[0] === node) {
return true;
}
return false;
},
function (node) {
// jquery 1.6 to 1.6.0.3
return Event.cache[node._eventId || node._prototypeEventID[0]].click[0];
}
];
return false;
}, function (node) {
// jquery 1.6 to 1.6.0.3
return window.Event.cache[node._eventId || node._prototypeEventID[0]].click[0];
}];

@@ -44,3 +39,3 @@ for (var i = 0; i < tests.length; i++) {

var nearestInteractiveElement = function(element, cache) {
var nearestInteractiveElement = function nearestInteractiveElement(element, cache) {
if (cache && cache[element] && cache[element].element === element) {

@@ -50,13 +45,14 @@ return cache[element].closest;

if (['html', 'head'].indexOf(element.tagName.toLowerCase()) > -1) { // can't call css on these
if (['html', 'head'].indexOf(element.tagName.toLowerCase()) > -1) {
// can't call css on these
return null;
}
// next, try to find the closest element with a click handler
var child, closest;
// next, try to find the closest element that seems interactive
var child = void 0,
closest = void 0;
var candidate = element;
var visited_candidates = [];
for (var candidate = element;
!closest && candidate && !(candidate.tagName.toLowerCase() === 'body');
child = candidate, candidate = candidate.parentElement) {
do {
visited_candidates.push(candidate);

@@ -66,2 +62,4 @@

if (candidate.style['pointer-events'] === 'none') {
child = candidate;
candidate = candidate.parentElement;
continue;

@@ -74,4 +72,4 @@ }

var childStyles = window.getComputedStyle(child);
var cursor = candidateStyles['cursor'];
if ((cursor === 'default' || cursor === 'auto') && cursor !== childStyles['cursor']) {
var cursor = candidateStyles.cursor;
if ((cursor === 'default' || cursor === 'auto') && cursor !== childStyles.cursor) {
closest = child;

@@ -84,3 +82,3 @@ break;

var attrs = candidate.attributes;
for(var i = 0; i < attrs.length; i++) {
for (var i = 0; i < attrs.length; i++) {
if (/^data\-/.test(attrs[i].name)) {

@@ -93,13 +91,16 @@ closest = candidate;

// if the element has its own click handler, it is almost certainly clickable
if (hasOwnHandler(candidate)) {
if (elementHasOwnHandler(candidate)) {
closest = candidate;
break;
}
}
child = candidate;
candidate = candidate.parentElement;
} while (candidate && candidate.tagName.toLowerCase() !== 'body');
if (cache && closest) {
for (var i = 0; i < visited_candidates.length; i++) {
var candidate = visited_candidates[i];
cache[candidate] = closest;
};
for (var _i = 0; _i < visited_candidates.length; _i++) {
var _candidate = visited_candidates[_i];
cache[_candidate] = closest;
}
cache[element] = {

@@ -114,2 +115,3 @@ closest: closest,

export { nearestInteractiveElement };
exports.elementHasOwnHandler = elementHasOwnHandler;
exports.nearestInteractiveElement = nearestInteractiveElement;
{
"name": "mixpanel-js-utils",
"version": "0.0.5",
"version": "0.0.6",
"description": "Javascript utilities for use across Mixpanel products",

@@ -8,4 +8,10 @@ "main": "build/index.cjs.js",

"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "./node_modules/rollup/bin/rollup -c rollup.config.cjs.js && ./node_modules/rollup/bin/rollup -c rollup.config.es6.js"
"test": "npm run-script build && ./node_modules/mocha/bin/mocha test/index.js",
"build": "./node_modules/rollup/bin/rollup -c rollup.config.cjs.js && ./node_modules/rollup/bin/rollup -c rollup.config.es6.js",
"lint": "jshint .",
"validate": "npm ls",
"pre-commit": [
"lint",
"test"
]
},

@@ -23,4 +29,19 @@ "repository": {

"devDependencies": {
"rollup": "^0.25.4"
}
"babel": "^6.5.2",
"babel-preset-es2015-rollup": "^1.1.1",
"chai": "^3.5.0",
"js-fixtures": "^1.5.3",
"jsdom": "^8.1.0",
"mocha": "^2.4.5",
"mocha-jsdom": "^1.1.0",
"precommit-hook": "^3.0.0",
"rollup": "^0.25.4",
"rollup-plugin-babel": "^2.4.0",
"rollup-plugin-multi-entry": "^1.2.0"
},
"pre-commit": [
"lint",
"validate",
"test"
]
}

@@ -0,5 +1,12 @@

import babel from 'rollup-plugin-babel';
export default {
entry: 'src/index.js',
format: 'cjs',
dest: 'build/index.cjs.js'
entry: './src/index.js',
dest: './build/index.cjs.js',
plugins: [
babel({
exclude: 'node_modules/**'
})
]
};

@@ -0,5 +1,12 @@

import babel from 'rollup-plugin-babel';
export default {
format: 'cjs',
entry: 'src/index.js',
format: 'es6',
dest: 'build/index.es6.js'
dest: 'build/index.es6.js',
plugins: [
babel({
exclude: 'node_modules/**'
})
]
};

@@ -1,4 +0,113 @@

import nearestInteractiveElement from './nearestInteractiveElement';
export {
nearestInteractiveElement
}
var elementHasOwnHandler = function (element) {
const tests = [
function (node) {
return ['form', 'input', 'select', 'textarea', 'submit', 'a'].indexOf(node.tagName.toLowerCase()) > -1;
},
function (node) {
// for onclick properties and attributes
return node.onclick || node.getAttribute('onclick');
},
function (node) {
return !!(window.jQuery._data || window.jQuery.data)(node, 'events');
},
function (node) {
// jquery 1.3.x and 1.4x
return node.getAttribute('data-events');
},
function (node) {
// jquery 1.5.x
for(let i = 0; i < window.Event.observers.length; i++) {
const observer = window.Event.observers[i];
if ((observer || [])[0] === node) {
return true;
}
}
return false;
},
function (node) {
// jquery 1.6 to 1.6.0.3
return window.Event.cache[node._eventId || node._prototypeEventID[0]].click[0];
}
];
for (let i = 0; i < tests.length; i++) {
const test = tests[i];
try {
if (test(element)) {
return true;
}
} catch (e) {}
}
return false;
};
var nearestInteractiveElement = function(element, cache) {
if (cache && cache[element] && cache[element].element === element) {
return cache[element].closest;
}
if (['html', 'head'].indexOf(element.tagName.toLowerCase()) > -1) { // can't call css on these
return null;
}
// next, try to find the closest element that seems interactive
let child, closest;
let candidate = element;
let visited_candidates = [];
do {
visited_candidates.push(candidate);
// skip candidates that don't accept pointer events
if (candidate.style['pointer-events'] === 'none') {
child = candidate;
candidate = candidate.parentElement;
continue;
}
// if the cursor becomes default, assume that the child was clickable
if (child) {
const candidateStyles = window.getComputedStyle(candidate);
const childStyles = window.getComputedStyle(child);
const cursor = candidateStyles.cursor;
if ((cursor === 'default' || cursor === 'auto') && cursor !== childStyles.cursor) {
closest = child;
break;
}
}
// if there are data- attributes we assume that it's used for something interactive
const attrs = candidate.attributes;
for(let i = 0; i < attrs.length; i++) {
if (/^data\-/.test(attrs[i].name)) {
closest = candidate;
break;
}
}
// if the element has its own click handler, it is almost certainly clickable
if (elementHasOwnHandler(candidate)) {
closest = candidate;
break;
}
child = candidate;
candidate = candidate.parentElement;
} while (candidate && candidate.tagName.toLowerCase() !== 'body');
if (cache && closest) {
for (let i = 0; i < visited_candidates.length; i++) {
const candidate = visited_candidates[i];
cache[candidate] = closest;
}
cache[element] = {
closest: closest,
element: element
};
}
return closest || element;
};
export { elementHasOwnHandler, nearestInteractiveElement };
var hasOwnHandler = function (element) {
var tests = [
function (node) {
return ['form', 'input', 'select', 'textarea', 'submit', 'a'].indexOf(node.tagName.toLowerCase()) !== -1;
},
function (node) {
// for onclick properties and attributes
return node.onclick || node.getAttribute('onclick');
},
function (node) {
return !!(jQuery._data || jQuery.data)(node, 'events')
},
function (node) {
// jquery 1.3.x and 1.4x
return !!node.getAttributes('data-events');
},
function (node) {
// jquery 1.5.x
for(var i = 0; i < Event.observers.length; i++) {
var observer = Event.observers[i];
if ((observer || [])[0] === node) {
return true;
}
}
return false;
},
function (node) {
// jquery 1.6 to 1.6.0.3
return Event.cache[node._eventId || node._prototypeEventID[0]].click[0];
}
];
for (var i = 0; i < tests.length; i++) {
var test = tests[i];
try {
if (test(element)) {
return true;
}
} catch (e) {}
}
return false;
};
var nearestInteractiveElement = function(element, cache) {
if (cache && cache[element] && cache[element].element === element) {
return cache[element].closest;
}
if (['html', 'head'].indexOf(element.tagName.toLowerCase()) > -1) { // can't call css on these
return null;
}
// next, try to find the closest element with a click handler
var child, closest;
var visited_candidates = [];
for (var candidate = element;
!closest && candidate && !(candidate.tagName.toLowerCase() === 'body');
child = candidate, candidate = candidate.parentElement) {
visited_candidates.push(candidate);
// skip candidates that don't accept pointer events
if (candidate.style['pointer-events'] === 'none') {
continue;
}
// if the cursor becomes default, assume that the child was clickable
if (child) {
var candidateStyles = window.getComputedStyle(candidate);
var childStyles = window.getComputedStyle(child);
var cursor = candidateStyles['cursor'];
if ((cursor === 'default' || cursor === 'auto') && cursor !== childStyles['cursor']) {
closest = child;
break;
}
}
// if there are data- attributes we assume that it's used for something interactive
var attrs = candidate.attributes;
for(var i = 0; i < attrs.length; i++) {
if (/^data\-/.test(attrs[i].name)) {
closest = candidate;
break;
}
}
// if the element has its own click handler, it is almost certainly clickable
if (hasOwnHandler(candidate)) {
closest = candidate;
break;
}
}
if (cache && closest) {
for (var i = 0; i < visited_candidates.length; i++) {
var candidate = visited_candidates[i];
cache[candidate] = closest;
};
cache[element] = {
closest: closest,
element: element
};
}
return closest || element;
};
export default nearestInteractiveElement;