mixpanel-js-utils
Advanced tools
Comparing version 0.0.5 to 0.0.6
'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/**' | ||
}) | ||
] | ||
}; |
117
src/index.js
@@ -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 }; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
44052881
13
482
2
1
18
11
2