Comparing version 0.1.0 to 0.1.1
@@ -94,3 +94,3 @@ (function webpackUniversalModuleDefinition(root, factory) { | ||
/******/ // Load entry module and return exports | ||
/******/ return __webpack_require__(__webpack_require__.s = 1); | ||
/******/ return __webpack_require__(__webpack_require__.s = 5); | ||
/******/ }) | ||
@@ -102,329 +102,524 @@ /************************************************************************/ | ||
class Config { | ||
// Set up a default config | ||
constructor() { | ||
// Type: string, REQUIRED | ||
// Endpoint Url | ||
this.uploadEndpoint = "http://localhost:9000"; | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : { | ||
"default": obj | ||
}; | ||
} | ||
// Type: string | ||
// Website ID | ||
this.websiteId = "unknown"; | ||
module.exports = _interopRequireDefault; | ||
// Endpoint type, "absolute" or "relative" | ||
this.endpointType = "absolute"; | ||
/***/ }), | ||
/* 1 */ | ||
/***/ (function(module, exports) { | ||
// Upload mode, "mixed", "periodic" or "event-triggered" | ||
this.uploadMode = "mixed"; | ||
function _classCallCheck(instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
} | ||
// Type: number | ||
// If `uploadMode` is "mixed", "periodic", data will be uploaded every `uploadPeriod` ms. | ||
// If no data are collected in a period, no data will be uploaded | ||
this.uploadPeriod = 5000; | ||
module.exports = _classCallCheck; | ||
// Type: number | ||
// If `uploadMode` == "event-triggered" | ||
// The website interaction data will be uploaded when every `frequency` events are captured. | ||
this.frequency = 50; | ||
/***/ }), | ||
/* 2 */ | ||
/***/ (function(module, exports) { | ||
// Type: bool | ||
// Use GET method to upload data? (stringified data will be embedded in URI) | ||
this.enableGet = false; | ||
function _defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
} | ||
} | ||
// Type: number | ||
// Time interval for resending the failed trace data | ||
this.resendInterval = 3000; | ||
function _createClass(Constructor, protoProps, staticProps) { | ||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) _defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
} | ||
// Type: HTML DOM Element | ||
// Capture the events occur in `this.scope` | ||
this.scope = window.document; | ||
module.exports = _createClass; | ||
// These parameters are required for runing a Mouselog agent | ||
this._requiredParams = [ | ||
"uploadEndpoint", | ||
] | ||
/***/ }), | ||
/* 3 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
// These parameters will be ignored when updating config | ||
this._ignoredParams = [ | ||
"scope", | ||
] | ||
} | ||
"use strict"; | ||
build(config, isUpdating = false) { | ||
try { | ||
this._requiredParams.forEach(key => { | ||
if (!config.hasOwnProperty(key)) { | ||
throw new Error(`Param ${key} is required but not declared.`); | ||
} | ||
}); | ||
// Overwrite the default config | ||
Object.keys(config).forEach( key => { | ||
// Overwriting Class private members / function method is not allowed | ||
if (this[key] && !key.startsWith("_") && typeof(this[key]) != "function") { | ||
// Do not update some `ignored` parameter | ||
if (!(isUpdating && key in this._ignoredParams)) { | ||
this[key] = config[key] | ||
} | ||
} | ||
}) | ||
this.absoluteUrl = this._formatUrl(); | ||
} catch(err) { | ||
console.log(err); | ||
return false; | ||
} | ||
return true; | ||
var debugMode = false; | ||
var outputElement; | ||
function activate(id) { | ||
debugMode = true; | ||
if (id) { | ||
outputElement = window.document.getElementById(id); | ||
if (!outputElement) { | ||
console.log("Fail to find the output element."); | ||
} | ||
} | ||
} | ||
update(config) { | ||
return this.build(config, true); | ||
function write(info) { | ||
if (debugMode) { | ||
if (outputElement) { | ||
var p = document.createElement("p"); | ||
p.style.display = "block"; | ||
p.style.fontSize = "10px"; | ||
p.style.margin = "2px"; | ||
var t = document.createTextNode(info); | ||
p.appendChild(t); | ||
outputElement.appendChild(p); | ||
} | ||
_formatUrl() { | ||
let url = this.uploadEndpoint; | ||
if (this.endpointType == "relative") { | ||
if (url.startsWith("./")) { | ||
url = url.slice(1); | ||
} else if (url[0] !== "/") { | ||
url = "/" + url; | ||
} | ||
// Format the tail | ||
if (url[url.length-1] === "/") { | ||
url = url.slice(0, url.length-1); | ||
} | ||
// Construct absolute URL | ||
url = `${window.location.origin}${url}` | ||
} else if (this.endpointType !== "absolute") { | ||
throw new Error('`endpointType` can only be "absolute" or "relative"'); | ||
} | ||
return url; | ||
} | ||
console.log(info); | ||
} | ||
} | ||
module.exports = { Config }; | ||
module.exports = { | ||
activate: activate, | ||
write: write | ||
}; | ||
/***/ }), | ||
/* 1 */ | ||
/* 4 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
const uuidv4 = __webpack_require__(2); | ||
const Uploader = __webpack_require__(5); | ||
let { Config } = __webpack_require__(0); | ||
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (name, context, definition) { | ||
if ( true && module.exports) module.exports = definition(); | ||
else if (true) !(__WEBPACK_AMD_DEFINE_FACTORY__ = (definition), | ||
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? | ||
(__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : | ||
__WEBPACK_AMD_DEFINE_FACTORY__), | ||
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); | ||
else {} | ||
})('urljoin', this, function () { | ||
let targetEvents = [ | ||
"mousemove", | ||
"mousedown", | ||
"mouseup", | ||
"mouseclick", | ||
"dblclick", | ||
"contextmenu", | ||
"wheel", | ||
"torchstart", | ||
"touchmove", | ||
"touchend" | ||
]; | ||
let pageLoadTime = new Date(); | ||
function normalize (strArray) { | ||
var resultArray = []; | ||
if (strArray.length === 0) { return ''; } | ||
if (typeof strArray[0] !== 'string') { | ||
throw new TypeError('Url must be a string. Received ' + strArray[0]); | ||
} | ||
class Mouselog{ | ||
constructor() { | ||
this.config = new Config(); | ||
this.impressionId = uuidv4(); | ||
this.mouselogLoadTime = new Date(); | ||
this.uploader = new Uploader(); | ||
this.eventsList = []; | ||
this.eventsCount = 0; | ||
this.uploadInterval; // For "periodic" upload mode | ||
this.uploadTimeout; // For "mixed" upload mode | ||
// If the first part is a plain protocol, we combine it with the next part. | ||
if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) { | ||
var first = strArray.shift(); | ||
strArray[0] = first + strArray[0]; | ||
} | ||
_clearBuffer() { | ||
this.eventsList = []; | ||
// There must be two or three slashes in the file protocol, two slashes in anything else. | ||
if (strArray[0].match(/^file:\/\/\//)) { | ||
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1:///'); | ||
} else { | ||
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1://'); | ||
} | ||
_newTrace() { | ||
let trace = { | ||
id: '0', | ||
idx: this.uploadIdx, | ||
url: window.location.hostname ? window.location.hostname : "localhost", | ||
path: window.location.pathname, | ||
width: document.body.scrollWidth, | ||
height: document.body.scrollHeight, | ||
pageLoadTime: pageLoadTime, | ||
events: [] | ||
} | ||
this.uploadIdx += 1; | ||
return trace; | ||
for (var i = 0; i < strArray.length; i++) { | ||
var component = strArray[i]; | ||
if (typeof component !== 'string') { | ||
throw new TypeError('Url must be a string. Received ' + component); | ||
} | ||
if (component === '') { continue; } | ||
if (i > 0) { | ||
// Removing the starting slashes for each component but the first. | ||
component = component.replace(/^[\/]+/, ''); | ||
} | ||
if (i < strArray.length - 1) { | ||
// Removing the ending slashes for each component but the last. | ||
component = component.replace(/[\/]+$/, ''); | ||
} else { | ||
// For the last component we will combine multiple slashes to a single one. | ||
component = component.replace(/[\/]+$/, '/'); | ||
} | ||
resultArray.push(component); | ||
} | ||
_mouseHandler(evt) { | ||
// PC's Chrome on Mobile mode can still receive "contextmenu" event with zero X, Y, so we ignore these events. | ||
if (evt.type === 'contextmenu' && evt.pageX === 0 && evt.pageY === 0) { | ||
return; | ||
} | ||
let x = evt.pageX; | ||
let y = evt.pageY; | ||
if (x === undefined) { | ||
x = evt.changedTouches[0].pageX; | ||
y = evt.changedTouches[0].pageY; | ||
} | ||
let tmpEvt = { | ||
id: this.eventsCount, | ||
timestamp: getRelativeTimestampInSeconds(), | ||
type: evt.type, | ||
x: x, | ||
y: y, | ||
button: getButton(evt.button) | ||
} | ||
var str = resultArray.join('/'); | ||
// Each input component is now separated by a single slash except the possible first plain protocol part. | ||
// remove trailing slash before parameters or hash | ||
str = str.replace(/\/(\?|&|#[^!])/g, '$1'); | ||
if (evt.type == "wheel") { | ||
tmpEvt.deltaX = evt.deltaX; | ||
tmpEvt.deltaY = evt.deltaY; | ||
} | ||
this.eventsList.push(tmpEvt); | ||
this.eventsCount += 1; | ||
// replace ? in parameters with & | ||
var parts = str.split('?'); | ||
str = parts.shift() + (parts.length > 0 ? '?': '') + parts.join('&'); | ||
if ( this.config.uploadMode == "event-triggered" && this.eventsList.length % this.config.frequency == 0 ) { | ||
this._uploadTrace(); | ||
} | ||
return str; | ||
} | ||
if ( this.config.uploadMode == "mixed" && this.eventsList.length % this.config.frequency == 0) { | ||
this._periodUploadTimeout(); | ||
this._uploadTrace(); | ||
} | ||
return function () { | ||
var input; | ||
if (typeof arguments[0] === 'object') { | ||
input = arguments[0]; | ||
} else { | ||
input = [].slice.call(arguments); | ||
} | ||
_fetchConfigFromServer() { | ||
// Upload an empty trace to fetch config from server | ||
let trace = this._newTrace(); | ||
return this.uploader.upload(trace); // This is a promise | ||
return normalize(input); | ||
}; | ||
}); | ||
/***/ }), | ||
/* 5 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
"use strict"; | ||
var _interopRequireDefault = __webpack_require__(0); | ||
var _classCallCheck2 = _interopRequireDefault(__webpack_require__(1)); | ||
var _createClass2 = _interopRequireDefault(__webpack_require__(2)); | ||
var uuidv4 = __webpack_require__(6); | ||
var Uploader = __webpack_require__(9); | ||
var _require = __webpack_require__(10), | ||
Config = _require.Config; | ||
var _debug = __webpack_require__(3); | ||
var targetEvents = ["mousemove", "mousedown", "mouseup", "mouseclick", "dblclick", "contextmenu", "wheel", "torchstart", "touchmove", "touchend"]; | ||
var pageLoadTime = new Date(); | ||
var hiddenProperty = 'hidden' in document ? 'hidden' : 'webkitHidden' in document ? 'webkitHidden' : 'mozHidden' in document ? 'mozHidden' : null; | ||
var visibilityChangeEvent = hiddenProperty ? hiddenProperty.replace(/hidden/i, 'visibilitychange') : null; | ||
function maxNumber() { | ||
for (var _len = arguments.length, nums = new Array(_len), _key = 0; _key < _len; _key++) { | ||
nums[_key] = arguments[_key]; | ||
} | ||
var res = nums[0]; | ||
for (var i = 1; i < nums.length; ++i) { | ||
res = res > nums[i] ? res : nums[i]; | ||
} | ||
return res; | ||
} | ||
function getRelativeTimestampInSeconds() { | ||
var diff = new Date() - pageLoadTime; | ||
return Math.trunc(diff) / 1000; | ||
} | ||
function getButton(btn) { | ||
if (btn === '2') { | ||
return 'Right'; | ||
} else { | ||
return ""; | ||
} | ||
} | ||
var Mouselog = | ||
/*#__PURE__*/ | ||
function () { | ||
function Mouselog() { | ||
(0, _classCallCheck2["default"])(this, Mouselog); | ||
this.config = new Config(); | ||
this.impressionId = uuidv4(); | ||
this.mouselogLoadTime = new Date(); | ||
this.uploader = new Uploader(); | ||
this.eventsList = []; | ||
this.eventsCount = 0; | ||
this.uploadInterval; // For "periodic" upload mode | ||
this.uploadTimeout; // For "mixed" upload mode | ||
} | ||
(0, _createClass2["default"])(Mouselog, [{ | ||
key: "_clearBuffer", | ||
value: function _clearBuffer() { | ||
this.eventsList = []; | ||
} | ||
}, { | ||
key: "_newTrace", | ||
value: function _newTrace() { | ||
var trace = { | ||
id: '0', | ||
idx: this.uploadIdx, | ||
url: window.location.hostname ? window.location.hostname : "localhost", | ||
path: window.location.pathname, | ||
width: maxNumber(document.body.scrollWidth, window.innerWidth), | ||
height: maxNumber(document.body.scrollHeight, window.innerHeight), | ||
pageLoadTime: pageLoadTime, | ||
events: [] | ||
}; | ||
this.uploadIdx += 1; | ||
return trace; | ||
} | ||
}, { | ||
key: "_onVisibilityChange", | ||
value: function _onVisibilityChange(evt) { | ||
if (window.document[hiddenProperty]) { | ||
// the page is not activated | ||
this._pause(); | ||
} else { | ||
// the page is activated | ||
this._resume(); | ||
} | ||
} | ||
}, { | ||
key: "_mouseHandler", | ||
value: function _mouseHandler(evt) { | ||
// PC's Chrome on Mobile mode can still receive "contextmenu" event with zero X, Y, so we ignore these events. | ||
if (evt.type === 'contextmenu' && evt.pageX === 0 && evt.pageY === 0) { | ||
return; | ||
} | ||
_uploadTrace() { | ||
let trace = this._newTrace(); | ||
trace.events = this.eventsList; | ||
this.eventsList = []; | ||
return this.uploader.upload(trace); // This is a promise | ||
var x = evt.pageX; | ||
var y = evt.pageY; | ||
if (x === undefined) { | ||
x = evt.changedTouches[0].pageX; | ||
y = evt.changedTouches[0].pageY; | ||
} | ||
var tmpEvt = { | ||
id: this.eventsCount, | ||
timestamp: getRelativeTimestampInSeconds(), | ||
type: evt.type, | ||
x: x, | ||
y: y, | ||
button: getButton(evt.button) | ||
}; | ||
if (evt.type == "wheel") { | ||
tmpEvt.deltaX = evt.deltaX; | ||
tmpEvt.deltaY = evt.deltaY; | ||
} | ||
this.eventsList.push(tmpEvt); | ||
this.eventsCount += 1; | ||
if (this.config.uploadMode == "event-triggered" && this.eventsList.length % this.config.frequency == 0) { | ||
this._uploadTrace(); | ||
} | ||
if (this.config.uploadMode == "mixed" && this.eventsList.length % this.config.frequency == 0) { | ||
this._periodUploadTimeout(); | ||
this._uploadTrace(); | ||
} | ||
} | ||
}, { | ||
key: "_fetchConfigFromServer", | ||
value: function _fetchConfigFromServer() { | ||
// Upload an empty trace to fetch config from server | ||
var trace = this._newTrace(); | ||
_periodUploadTimeout() { | ||
clearTimeout(this.uploadTimeout); | ||
this.uploadTimeout = setTimeout(() => { | ||
if (this.eventsList.length > 0) { | ||
this._uploadTrace(); | ||
} | ||
}) | ||
return this.uploader.upload(trace); // This is a promise | ||
} | ||
}, { | ||
key: "_uploadTrace", | ||
value: function _uploadTrace() { | ||
var trace = this._newTrace(); | ||
_periodUploadInterval() { | ||
clearInterval(this.uploadInterval); | ||
this.uploadInterval = setInterval(() => { | ||
if (this.eventsList.length > 0) { | ||
this._uploadTrace(); | ||
} | ||
}, this.config.uploadPeriod); | ||
trace.events = this.eventsList; | ||
this.eventsList = []; | ||
return this.uploader.upload(trace); // This is a promise | ||
} | ||
}, { | ||
key: "_periodUploadTimeout", | ||
value: function _periodUploadTimeout() { | ||
var _this = this; | ||
_runCollector() { | ||
targetEvents.forEach( s => { | ||
this.config.scope.addEventListener(s, (evt) => this._mouseHandler(evt)); | ||
}); | ||
if (this.config.uploadMode === "periodic") { | ||
this._periodUploadInterval(); | ||
clearTimeout(this.uploadTimeout); | ||
this.uploadTimeout = setTimeout(function () { | ||
if (_this.eventsList.length > 0) { | ||
_this._uploadTrace(); | ||
} | ||
}, this.config.uploadPeriod); | ||
} | ||
}, { | ||
key: "_periodUploadInterval", | ||
value: function _periodUploadInterval() { | ||
var _this2 = this; | ||
if (this.config.uploadMode === "mixed") { | ||
this._periodUploadTimeout(); | ||
clearInterval(this.uploadInterval); | ||
this.uploadInterval = setInterval(function () { | ||
if (_this2.eventsList.length > 0) { | ||
_this2._uploadTrace(); | ||
} | ||
}, this.config.uploadPeriod); | ||
} | ||
}, { | ||
key: "_runCollector", | ||
value: function _runCollector() { | ||
var _this3 = this; | ||
_stopCollector() { | ||
targetEvents.forEach( s => { | ||
this.config.scope.removeEventListener(s, (evt) => this._mouseHandler(evt)); | ||
targetEvents.forEach(function (s) { | ||
_this3.config.scope.addEventListener(s, function (evt) { | ||
return _this3._mouseHandler(evt); | ||
}); | ||
clearInterval(this.uploadInterval); | ||
clearTimeout(this.uploadTimeout); | ||
}); | ||
if (this.config.uploadMode === "periodic") { | ||
this._periodUploadInterval(); | ||
} | ||
if (this.config.uploadMode === "mixed") { | ||
this._periodUploadTimeout(); | ||
} | ||
} | ||
}, { | ||
key: "_stopCollector", | ||
value: function _stopCollector() { | ||
var _this4 = this; | ||
_resetCollector() { | ||
this._stopCollector(); | ||
this._runCollector(); | ||
targetEvents.forEach(function (s) { | ||
_this4.config.scope.removeEventListener(s, function (evt) { | ||
return _this4._mouseHandler(evt); | ||
}); | ||
}); | ||
clearInterval(this.uploadInterval); | ||
clearTimeout(this.uploadTimeout); | ||
} | ||
}, { | ||
key: "_resetCollector", | ||
value: function _resetCollector() { | ||
this._stopCollector(); | ||
_init(config) { | ||
this.impressionId = uuidv4(); | ||
this._clearBuffer(); | ||
this.uploadIdx = 0; | ||
this.uploader = new Uploader(this.impressionId, this.config); | ||
this.uploader.setImpressionId(this.impressionId); | ||
if (this.config.build(config)) { | ||
// Async: Upload an empty data to fetch config from server | ||
this._fetchConfigFromServer().then( result => { | ||
if (result.status == 1) { | ||
if (this.config.update(result.config)) { | ||
this._resetCollector(); | ||
this.uploader.setConfig(this.config); | ||
console.log("Config updated.") | ||
} else { | ||
throw new Error(`Unable to update config with server config.`); | ||
} | ||
} else { | ||
throw new Error(`Fail to get config from server.`); | ||
} | ||
}).catch(err => { | ||
console.log(err); | ||
}); | ||
window.onbeforeunload = (evt) => { | ||
if (this.eventsList.length != 0) { | ||
this._uploadTrace(); | ||
} | ||
this._runCollector(); | ||
} | ||
}, { | ||
key: "_init", | ||
value: function _init(config) { | ||
var _this5 = this; | ||
this.impressionId = uuidv4(); | ||
this._clearBuffer(); | ||
this.uploadIdx = 0; | ||
this.uploader = new Uploader(this.impressionId, this.config); | ||
this.uploader.setImpressionId(this.impressionId); | ||
if (this.config.build(config)) { | ||
// Async: Upload an empty data to fetch config from server | ||
this._fetchConfigFromServer().then(function (result) { | ||
if (result.status == 1) { | ||
if (_this5.config.update(result.config)) { | ||
_this5._resetCollector(); | ||
_this5.uploader.setConfig(_this5.config); | ||
_debug.write("Successfully update config from backend."); | ||
} else { | ||
throw new Error("Unable to update config with server config."); | ||
} | ||
return {status: 0}; | ||
} else { | ||
return {status: -1, msg: `Invalid configuration.`}; | ||
} | ||
} else { | ||
throw new Error("Fail to get config from server."); | ||
} | ||
})["catch"](function (err) { | ||
_debug.write(err); | ||
}); | ||
window.onbeforeunload = function (evt) { | ||
if (_this5.eventsList.length != 0) { | ||
_this5._uploadTrace(); | ||
} | ||
}; | ||
return { | ||
status: 0 | ||
}; | ||
} else { | ||
return { | ||
status: -1, | ||
msg: "Invalid configuration." | ||
}; | ||
} | ||
} | ||
}, { | ||
key: "_pause", | ||
value: function _pause() { | ||
this._stopCollector(); | ||
} | ||
}, { | ||
key: "_resume", | ||
value: function _resume() { | ||
this._runCollector(); | ||
} | ||
}, { | ||
key: "run", | ||
value: function run(config) { | ||
var _this6 = this; | ||
run(config) { | ||
let res = this._init(config); | ||
if (res.status == 0) { | ||
this._runCollector(); | ||
this.uploader.start(this.impressionId); | ||
console.log("Mouselog agent is activated!"); | ||
} else { | ||
console.log(res.msg); | ||
console.log("Fail to initialize Mouselog agent."); | ||
var res = this._init(config); | ||
if (res.status == 0) { | ||
if (visibilityChangeEvent) { | ||
document.addEventListener(visibilityChangeEvent, function (evt) { | ||
return _this6._onVisibilityChange(evt); | ||
}); | ||
} | ||
this._runCollector(); | ||
this.uploader.start(this.impressionId); | ||
_debug.write("Mouselog agent is activated!"); | ||
_debug.write("Website ID: ".concat(this.config.websiteId)); | ||
_debug.write("Impression ID: ".concat(this.impressionId)); | ||
_debug.write("User-Agent: ".concat(navigator.userAgent)); | ||
_debug.write("Page load time: ".concat(pageLoadTime)); | ||
} else { | ||
_debug.write(res.msg); | ||
_debug.write("Fail to initialize Mouselog agent."); | ||
} | ||
} | ||
}, { | ||
key: "debug", | ||
value: function debug(config, debugOutputElementId) { | ||
_debug.activate(debugOutputElementId); | ||
stop() { | ||
this.uploader.stop(); | ||
this._stopCollector(); | ||
this._clearBuffer(); | ||
console.log(`Mouselog agent ${this.impressionId} is stopped!`); | ||
this.run(config); | ||
} | ||
} | ||
}, { | ||
key: "stop", | ||
value: function stop() { | ||
this.uploader.stop(); | ||
function getRelativeTimestampInSeconds() { | ||
let diff = new Date() - pageLoadTime; | ||
return Math.trunc(diff) / 1000; | ||
} | ||
this._stopCollector(); | ||
function getButton(btn) { | ||
if (btn === '2') { | ||
return 'Right'; | ||
} else { | ||
return "" | ||
this._clearBuffer(); | ||
_debug.write("Mouselog agent ".concat(this.impressionId, " is stopped!")); | ||
} | ||
} | ||
}]); | ||
return Mouselog; | ||
}(); | ||
module.exports = { Mouselog }; | ||
module.exports = { | ||
Mouselog: Mouselog | ||
}; | ||
/***/ }), | ||
/* 2 */ | ||
/* 6 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
var rng = __webpack_require__(3); | ||
var bytesToUuid = __webpack_require__(4); | ||
var rng = __webpack_require__(7); | ||
var bytesToUuid = __webpack_require__(8); | ||
@@ -460,3 +655,3 @@ function v4(options, buf, offset) { | ||
/***/ }), | ||
/* 3 */ | ||
/* 7 */ | ||
/***/ (function(module, exports) { | ||
@@ -501,3 +696,3 @@ | ||
/***/ }), | ||
/* 4 */ | ||
/* 8 */ | ||
/***/ (function(module, exports) { | ||
@@ -534,124 +729,294 @@ | ||
/***/ }), | ||
/* 5 */ | ||
/* 9 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
let {config, updateConfig} = __webpack_require__(0); | ||
"use strict"; | ||
let StatusEnum = { | ||
WAITING: 0, | ||
SENDING: 1, | ||
SUCCESS: 2, | ||
} | ||
class Uploader { | ||
constructor(impressionId, config) { | ||
this.impressionId = impressionId; | ||
this.config = config; | ||
this.resendQueue = []; | ||
} | ||
var _interopRequireDefault = __webpack_require__(0); | ||
start() { | ||
this.resendInterval = setInterval(()=>{ | ||
this._resendFailedData.call(this); | ||
}, this.config.resendInterval); | ||
} | ||
var _classCallCheck2 = _interopRequireDefault(__webpack_require__(1)); | ||
stop() { | ||
clearInterval(this.resendInterval); | ||
// TODO?: Send all the remaining data in this.buf | ||
var _createClass2 = _interopRequireDefault(__webpack_require__(2)); | ||
var urljoin = __webpack_require__(4); | ||
var debug = __webpack_require__(3); | ||
var StatusEnum = { | ||
WAITING: 0, | ||
SENDING: 1, | ||
SUCCESS: 2 | ||
}; | ||
var Uploader = | ||
/*#__PURE__*/ | ||
function () { | ||
function Uploader(impressionId, config) { | ||
(0, _classCallCheck2["default"])(this, Uploader); | ||
this.impressionId = impressionId; | ||
this.config = config; | ||
this.resendQueue = []; | ||
} | ||
(0, _createClass2["default"])(Uploader, [{ | ||
key: "start", | ||
value: function start() { | ||
var _this = this; | ||
this.resendInterval = setInterval(function () { | ||
_this._resendFailedData.call(_this); | ||
}, this.config.resendInterval); | ||
} | ||
}, { | ||
key: "stop", | ||
value: function stop() { | ||
clearInterval(this.resendInterval); // TODO?: Send all the remaining data in this.buf | ||
} | ||
}, { | ||
key: "upload", | ||
value: function upload(data) { | ||
var _this2 = this; | ||
upload(data) { | ||
// resolve({status:-1/0/1, ...}): uploading success/fail. | ||
// reject(ErrorMessage): Errors occur when updating the config. | ||
return new Promise( (resolve, reject) => { | ||
let encodedData = JSON.stringify(data); | ||
this._upload(encodedData).then(res => { | ||
if (res.status == 200) { | ||
res.json().then( resObj => { | ||
if (resObj.status !== "ok") { | ||
throw new Error("Response object status is not ok."); | ||
} | ||
if (resObj.msg == "config") { | ||
resolve({ | ||
status: 1, | ||
msg: `Get config from server`, | ||
config: resObj.data | ||
}); | ||
} | ||
resolve({status: 0}); | ||
}); | ||
} else { | ||
throw new Error("Response status code is not 200."); | ||
} | ||
}).catch(err => { | ||
this._appendFailedData(data); | ||
resolve({ | ||
status: -1, | ||
msg: `Fail to upload a bunch of data, ${err.message}` | ||
}); | ||
}) | ||
// resolve({status:-1/0/1, ...}): uploading success/fail. | ||
// reject(ErrorMessage): Errors occur when updating the config. | ||
return new Promise(function (resolve, reject) { | ||
var encodedData = JSON.stringify(data); | ||
debug.write("Uploading Pkg ".concat(data.idx, ", window size: ").concat(data.width, "*").concat(data.height, ", events count: ").concat(data.events.length)); | ||
_this2._upload(encodedData).then(function (res) { | ||
if (res.status == 200) { | ||
return res.json(); | ||
} else { | ||
throw new Error("Response status code is not 200."); | ||
} | ||
}).then(function (resObj) { | ||
debug.write("Pkg ".concat(data.idx, " response=").concat(JSON.stringify(resObj))); | ||
if (resObj.status !== "ok") { | ||
throw new Error("Response object status is not ok."); | ||
} | ||
if (resObj.msg == "config") { | ||
resolve({ | ||
status: 1, | ||
msg: "Get config from server", | ||
config: resObj.data | ||
}); | ||
} | ||
resolve({ | ||
status: 0 | ||
}); | ||
})["catch"](function (err) { | ||
debug.write("Pkg ".concat(data.idx, " failed, wait for resending. Error message: ").concat(err.message)); | ||
_this2._appendFailedData(data); | ||
resolve({ | ||
status: -1, | ||
msg: "Fail to upload data bunch #".concat(data.idx, ", ").concat(err.message) | ||
}); | ||
}); | ||
}); | ||
} | ||
setImpressionId(impId) { | ||
this.impressionId = impId; | ||
}, { | ||
key: "setImpressionId", | ||
value: function setImpressionId(impId) { | ||
this.impressionId = impId; | ||
} | ||
setConfig(config) { | ||
this.stop(); | ||
this.config = config; | ||
this.start(); | ||
}, { | ||
key: "setConfig", | ||
value: function setConfig(config) { | ||
this.stop(); | ||
this.config = config; | ||
this.start(); | ||
} | ||
}, { | ||
key: "_resendFailedData", | ||
value: function _resendFailedData() { | ||
var _this3 = this; | ||
_resendFailedData() { | ||
let i = 0; | ||
let obj = this.resendQueue[i]; | ||
while (i < this.resendQueue.length) { | ||
if (obj.status == StatusEnum.SUCCESS) { | ||
this.resendQueue.splice(i, 1); // Remove it from resendQueue | ||
} else { | ||
i += 1; | ||
if (obj.status == StatusEnum.WAITING) { | ||
obj.status = StatusEnum.SENDING; | ||
this.upload(obj.data).then( result => { | ||
if (result) { // Successfully resend the data | ||
obj.status = StatusEnum.SUCCESS; | ||
} else { | ||
obj.status = StatusEnum.WAITING; | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
var i = 0; | ||
_upload(encodedData) { | ||
if (this.config.enableGet) { | ||
return fetch(`${this.config.absoluteUrl}/api/upload-trace?websiteId=${this.config.websiteId}&impressionId=${this.impressionId}&data=${encodedData}`, { | ||
method: "GET", | ||
credentials: "include" | ||
}); | ||
if (this.resendQueue.length > 0) { | ||
debug.write("Resending data..."); | ||
} | ||
var _loop = function _loop() { | ||
var obj = _this3.resendQueue[i]; | ||
if (obj.status == StatusEnum.SUCCESS) { | ||
_this3.resendQueue.splice(i, 1); // Remove it from resendQueue | ||
} else { | ||
return fetch(`${this.config.absoluteUrl}/api/upload-trace?websiteId=${this.config.websiteId}&impressionId=${this.impressionId}`, { | ||
method: "POST", | ||
credentials: "include", | ||
body: encodedData | ||
i += 1; | ||
debug.write("Resending Pkg ".concat(obj.data.idx)); | ||
if (obj.status == StatusEnum.WAITING) { | ||
obj.status = StatusEnum.SENDING; | ||
_this3.upload(obj.data).then(function (result) { | ||
if (result) { | ||
// Successfully resend the data | ||
obj.status = StatusEnum.SUCCESS; | ||
} else { | ||
obj.status = StatusEnum.WAITING; | ||
} | ||
}); | ||
} | ||
} | ||
}; | ||
while (i < this.resendQueue.length) { | ||
_loop(); | ||
} | ||
} | ||
}, { | ||
key: "_upload", | ||
value: function _upload(encodedData) { | ||
var url = urljoin(this.config.absoluteUrl, '/api/upload-trace', "?websiteId=".concat(this.config.websiteId, "&impressionId=").concat(this.impressionId)); | ||
_appendFailedData(data) { | ||
this.resendQueue.push({ | ||
status: StatusEnum.WAITING, | ||
data: data | ||
if (this.config.enableGet) { | ||
return fetch("".concat(url, "&data=").concat(encodedData), { | ||
method: "GET", | ||
credentials: "include" | ||
}); | ||
} else { | ||
return fetch(url, { | ||
method: "POST", | ||
credentials: "include", | ||
body: encodedData | ||
}); | ||
} | ||
} | ||
} | ||
}, { | ||
key: "_appendFailedData", | ||
value: function _appendFailedData(data) { | ||
this.resendQueue.push({ | ||
status: StatusEnum.WAITING, | ||
data: data | ||
}); | ||
} | ||
}]); | ||
return Uploader; | ||
}(); | ||
module.exports = Uploader; | ||
/***/ }), | ||
/* 10 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
"use strict"; | ||
var _interopRequireDefault = __webpack_require__(0); | ||
var _classCallCheck2 = _interopRequireDefault(__webpack_require__(1)); | ||
var _createClass2 = _interopRequireDefault(__webpack_require__(2)); | ||
var urljoin = __webpack_require__(4); | ||
var debug = __webpack_require__(3); | ||
var Config = | ||
/*#__PURE__*/ | ||
function () { | ||
// Set up a default config | ||
function Config() { | ||
(0, _classCallCheck2["default"])(this, Config); | ||
// Type: string, REQUIRED | ||
// Endpoint Url | ||
this.uploadEndpoint = "http://localhost:9000"; // Type: string | ||
// Website ID | ||
this.websiteId = "unknown"; // Endpoint type, "absolute" or "relative" | ||
this.endpointType = "absolute"; // Upload mode, "mixed", "periodic" or "event-triggered" | ||
this.uploadMode = "mixed"; // Type: number | ||
// If `uploadMode` is "mixed", "periodic", data will be uploaded every `uploadPeriod` ms. | ||
// If no data are collected in a period, no data will be uploaded | ||
this.uploadPeriod = 5000; // Type: number | ||
// If `uploadMode` == "event-triggered" | ||
// The website interaction data will be uploaded when every `frequency` events are captured. | ||
this.frequency = 50; // Type: bool | ||
// Use GET method to upload data? (stringified data will be embedded in URI) | ||
this.enableGet = false; // Type: number | ||
// Time interval for resending the failed trace data | ||
this.resendInterval = 3000; // Type: HTML DOM Element | ||
// Capture the events occur in `this.scope` | ||
this.scope = window.document; // These parameters are required for runing a Mouselog agent | ||
this._requiredParams = ["uploadEndpoint"]; // These parameters will be ignored when updating config | ||
this._ignoredParams = ["scope"]; | ||
} | ||
(0, _createClass2["default"])(Config, [{ | ||
key: "build", | ||
value: function build(config) { | ||
var _this = this; | ||
var isUpdating = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; | ||
try { | ||
this._requiredParams.forEach(function (key) { | ||
if (!config.hasOwnProperty(key)) { | ||
throw new Error("Param ".concat(key, " is required but not declared.")); | ||
} | ||
}); // Overwrite the default config | ||
Object.keys(config).forEach(function (key) { | ||
// Overwriting Class private members / function method is not allowed | ||
if (_this[key] && !key.startsWith("_") && typeof _this[key] != "function") { | ||
// Do not update some `ignored` parameter | ||
if (!(isUpdating && key in _this._ignoredParams)) { | ||
_this[key] = config[key]; | ||
} | ||
} | ||
}); | ||
this._formatUrl(); | ||
} catch (err) { | ||
debug.write(err); | ||
return false; | ||
} | ||
return true; | ||
} | ||
}, { | ||
key: "update", | ||
value: function update(config) { | ||
return this.build(config, true); | ||
} | ||
}, { | ||
key: "_formatUrl", | ||
value: function _formatUrl() { | ||
if (this.endpointType == "relative") { | ||
this.absoluteUrl = urljoin(window.location.origin, this.uploadEndpoint); | ||
} else if (this.endpointType == "absolute") { | ||
this.absoluteUrl = this.uploadEndpoint; | ||
} else { | ||
throw new Error('`endpointType` can only be "absolute" or "relative"'); | ||
} | ||
} | ||
}]); | ||
return Config; | ||
}(); | ||
module.exports = { | ||
Config: Config | ||
}; | ||
/***/ }) | ||
/******/ ]); | ||
}); |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.mouselog=e():t.mouselog=e()}(window,(function(){return function(t){var e={};function o(i){if(e[i])return e[i].exports;var s=e[i]={i:i,l:!1,exports:{}};return t[i].call(s.exports,s,s.exports,o),s.l=!0,s.exports}return o.m=t,o.c=e,o.d=function(t,e,i){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(o.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var s in t)o.d(i,s,function(e){return t[e]}.bind(null,s));return i},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="",o(o.s=1)}([function(t,e){t.exports={Config:class{constructor(){this.uploadEndpoint="http://localhost:9000",this.websiteId="unknown",this.endpointType="absolute",this.uploadMode="mixed",this.uploadPeriod=5e3,this.frequency=50,this.enableGet=!1,this.resendInterval=3e3,this.scope=window.document,this._requiredParams=["uploadEndpoint"],this._ignoredParams=["scope"]}build(t,e=!1){try{this._requiredParams.forEach(e=>{if(!t.hasOwnProperty(e))throw new Error(`Param ${e} is required but not declared.`)}),Object.keys(t).forEach(o=>{this[o]&&!o.startsWith("_")&&"function"!=typeof this[o]&&(e&&o in this._ignoredParams||(this[o]=t[o]))}),this.absoluteUrl=this._formatUrl()}catch(t){return console.log(t),!1}return!0}update(t){return this.build(t,!0)}_formatUrl(){let t=this.uploadEndpoint;if("relative"==this.endpointType)t.startsWith("./")?t=t.slice(1):"/"!==t[0]&&(t="/"+t),"/"===t[t.length-1]&&(t=t.slice(0,t.length-1)),t=`${window.location.origin}${t}`;else if("absolute"!==this.endpointType)throw new Error('`endpointType` can only be "absolute" or "relative"');return t}}}},function(t,e,o){const i=o(2),s=o(5);let{Config:n}=o(0),r=["mousemove","mousedown","mouseup","mouseclick","dblclick","contextmenu","wheel","torchstart","touchmove","touchend"],a=new Date;function l(){let t=new Date-a;return Math.trunc(t)/1e3}function u(t){return"2"===t?"Right":""}t.exports={Mouselog:class{constructor(){this.config=new n,this.impressionId=i(),this.mouselogLoadTime=new Date,this.uploader=new s,this.eventsList=[],this.eventsCount=0,this.uploadInterval,this.uploadTimeout}_clearBuffer(){this.eventsList=[]}_newTrace(){let t={id:"0",idx:this.uploadIdx,url:window.location.hostname?window.location.hostname:"localhost",path:window.location.pathname,width:document.body.scrollWidth,height:document.body.scrollHeight,pageLoadTime:a,events:[]};return this.uploadIdx+=1,t}_mouseHandler(t){if("contextmenu"===t.type&&0===t.pageX&&0===t.pageY)return;let e=t.pageX,o=t.pageY;void 0===e&&(e=t.changedTouches[0].pageX,o=t.changedTouches[0].pageY);let i={id:this.eventsCount,timestamp:l(),type:t.type,x:e,y:o,button:u(t.button)};"wheel"==t.type&&(i.deltaX=t.deltaX,i.deltaY=t.deltaY),this.eventsList.push(i),this.eventsCount+=1,"event-triggered"==this.config.uploadMode&&this.eventsList.length%this.config.frequency==0&&this._uploadTrace(),"mixed"==this.config.uploadMode&&this.eventsList.length%this.config.frequency==0&&(this._periodUploadTimeout(),this._uploadTrace())}_fetchConfigFromServer(){let t=this._newTrace();return this.uploader.upload(t)}_uploadTrace(){let t=this._newTrace();return t.events=this.eventsList,this.eventsList=[],this.uploader.upload(t)}_periodUploadTimeout(){clearTimeout(this.uploadTimeout),this.uploadTimeout=setTimeout(()=>{this.eventsList.length>0&&this._uploadTrace()})}_periodUploadInterval(){clearInterval(this.uploadInterval),this.uploadInterval=setInterval(()=>{this.eventsList.length>0&&this._uploadTrace()},this.config.uploadPeriod)}_runCollector(){r.forEach(t=>{this.config.scope.addEventListener(t,t=>this._mouseHandler(t))}),"periodic"===this.config.uploadMode&&this._periodUploadInterval(),"mixed"===this.config.uploadMode&&this._periodUploadTimeout()}_stopCollector(){r.forEach(t=>{this.config.scope.removeEventListener(t,t=>this._mouseHandler(t))}),clearInterval(this.uploadInterval),clearTimeout(this.uploadTimeout)}_resetCollector(){this._stopCollector(),this._runCollector()}_init(t){return this.impressionId=i(),this._clearBuffer(),this.uploadIdx=0,this.uploader=new s(this.impressionId,this.config),this.uploader.setImpressionId(this.impressionId),this.config.build(t)?(this._fetchConfigFromServer().then(t=>{if(1!=t.status)throw new Error("Fail to get config from server.");if(!this.config.update(t.config))throw new Error("Unable to update config with server config.");this._resetCollector(),this.uploader.setConfig(this.config),console.log("Config updated.")}).catch(t=>{console.log(t)}),window.onbeforeunload=t=>{0!=this.eventsList.length&&this._uploadTrace()},{status:0}):{status:-1,msg:"Invalid configuration."}}run(t){let e=this._init(t);0==e.status?(this._runCollector(),this.uploader.start(this.impressionId),console.log("Mouselog agent is activated!")):(console.log(e.msg),console.log("Fail to initialize Mouselog agent."))}stop(){this.uploader.stop(),this._stopCollector(),this._clearBuffer(),console.log(`Mouselog agent ${this.impressionId} is stopped!`)}}}},function(t,e,o){var i=o(3),s=o(4);t.exports=function(t,e,o){var n=e&&o||0;"string"==typeof t&&(e="binary"===t?new Array(16):null,t=null);var r=(t=t||{}).random||(t.rng||i)();if(r[6]=15&r[6]|64,r[8]=63&r[8]|128,e)for(var a=0;a<16;++a)e[n+a]=r[a];return e||s(r)}},function(t,e){var o="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof window.msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto);if(o){var i=new Uint8Array(16);t.exports=function(){return o(i),i}}else{var s=new Array(16);t.exports=function(){for(var t,e=0;e<16;e++)0==(3&e)&&(t=4294967296*Math.random()),s[e]=t>>>((3&e)<<3)&255;return s}}},function(t,e){for(var o=[],i=0;i<256;++i)o[i]=(i+256).toString(16).substr(1);t.exports=function(t,e){var i=e||0,s=o;return[s[t[i++]],s[t[i++]],s[t[i++]],s[t[i++]],"-",s[t[i++]],s[t[i++]],"-",s[t[i++]],s[t[i++]],"-",s[t[i++]],s[t[i++]],"-",s[t[i++]],s[t[i++]],s[t[i++]],s[t[i++]],s[t[i++]],s[t[i++]]].join("")}},function(t,e,o){let{config:i,updateConfig:s}=o(0),n=0,r=1,a=2;t.exports=class{constructor(t,e){this.impressionId=t,this.config=e,this.resendQueue=[]}start(){this.resendInterval=setInterval(()=>{this._resendFailedData.call(this)},this.config.resendInterval)}stop(){clearInterval(this.resendInterval)}upload(t){return new Promise((e,o)=>{let i=JSON.stringify(t);this._upload(i).then(t=>{if(200!=t.status)throw new Error("Response status code is not 200.");t.json().then(t=>{if("ok"!==t.status)throw new Error("Response object status is not ok.");"config"==t.msg&&e({status:1,msg:"Get config from server",config:t.data}),e({status:0})})}).catch(o=>{this._appendFailedData(t),e({status:-1,msg:`Fail to upload a bunch of data, ${o.message}`})})})}setImpressionId(t){this.impressionId=t}setConfig(t){this.stop(),this.config=t,this.start()}_resendFailedData(){let t=0,e=this.resendQueue[t];for(;t<this.resendQueue.length;)e.status==a?this.resendQueue.splice(t,1):(t+=1,e.status==n&&(e.status=r,this.upload(e.data).then(t=>{e.status=t?a:n})))}_upload(t){return this.config.enableGet?fetch(`${this.config.absoluteUrl}/api/upload-trace?websiteId=${this.config.websiteId}&impressionId=${this.impressionId}&data=${t}`,{method:"GET",credentials:"include"}):fetch(`${this.config.absoluteUrl}/api/upload-trace?websiteId=${this.config.websiteId}&impressionId=${this.impressionId}`,{method:"POST",credentials:"include",body:t})}_appendFailedData(t){this.resendQueue.push({status:n,data:t})}}}])})); | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.mouselog=t():e.mouselog=t()}(window,(function(){return function(e){var t={};function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=5)}([function(e,t){e.exports=function(e){return e&&e.__esModule?e:{default:e}}},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t){function n(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}e.exports=function(e,t,o){return t&&n(e.prototype,t),o&&n(e,o),e}},function(e,t,n){"use strict";var o,i=!1;e.exports={activate:function(e){i=!0,e&&((o=window.document.getElementById(e))||console.log("Fail to find the output element."))},write:function(e){if(i){if(o){var t=document.createElement("p");t.style.display="block",t.style.fontSize="10px",t.style.margin="2px";var n=document.createTextNode(e);t.appendChild(n),o.appendChild(t)}console.log(e)}}}},function(e,t,n){var o,i,r;r=function(){function e(e){var t=[];if(0===e.length)return"";if("string"!=typeof e[0])throw new TypeError("Url must be a string. Received "+e[0]);if(e[0].match(/^[^/:]+:\/*$/)&&e.length>1){var n=e.shift();e[0]=n+e[0]}e[0].match(/^file:\/\/\//)?e[0]=e[0].replace(/^([^/:]+):\/*/,"$1:///"):e[0]=e[0].replace(/^([^/:]+):\/*/,"$1://");for(var o=0;o<e.length;o++){var i=e[o];if("string"!=typeof i)throw new TypeError("Url must be a string. Received "+i);""!==i&&(o>0&&(i=i.replace(/^[\/]+/,"")),i=o<e.length-1?i.replace(/[\/]+$/,""):i.replace(/[\/]+$/,"/"),t.push(i))}var r=t.join("/"),a=(r=r.replace(/\/(\?|&|#[^!])/g,"$1")).split("?");return r=a.shift()+(a.length>0?"?":"")+a.join("&")}return function(){return e("object"==typeof arguments[0]?arguments[0]:[].slice.call(arguments))}},e.exports?e.exports=r():void 0===(i="function"==typeof(o=r)?o.call(t,n,t,e):o)||(e.exports=i)},function(e,t,n){"use strict";var o=n(0),i=o(n(1)),r=o(n(2)),a=n(6),s=n(9),u=n(10).Config,c=n(3),l=["mousemove","mousedown","mouseup","mouseclick","dblclick","contextmenu","wheel","torchstart","touchmove","touchend"],d=new Date,f="hidden"in document?"hidden":"webkitHidden"in document?"webkitHidden":"mozHidden"in document?"mozHidden":null,h=f?f.replace(/hidden/i,"visibilitychange"):null;function p(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];for(var o=t[0],i=1;i<t.length;++i)o=o>t[i]?o:t[i];return o}var v=function(){function e(){(0,i.default)(this,e),this.config=new u,this.impressionId=a(),this.mouselogLoadTime=new Date,this.uploader=new s,this.eventsList=[],this.eventsCount=0,this.uploadInterval,this.uploadTimeout}return(0,r.default)(e,[{key:"_clearBuffer",value:function(){this.eventsList=[]}},{key:"_newTrace",value:function(){var e={id:"0",idx:this.uploadIdx,url:window.location.hostname?window.location.hostname:"localhost",path:window.location.pathname,width:p(document.body.scrollWidth,window.innerWidth),height:p(document.body.scrollHeight,window.innerHeight),pageLoadTime:d,events:[]};return this.uploadIdx+=1,e}},{key:"_onVisibilityChange",value:function(e){window.document[f]?this._pause():this._resume()}},{key:"_mouseHandler",value:function(e){if("contextmenu"!==e.type||0!==e.pageX||0!==e.pageY){var t=e.pageX,n=e.pageY;void 0===t&&(t=e.changedTouches[0].pageX,n=e.changedTouches[0].pageY);var o,i,r={id:this.eventsCount,timestamp:(i=new Date-d,Math.trunc(i)/1e3),type:e.type,x:t,y:n,button:(o=e.button,"2"===o?"Right":"")};"wheel"==e.type&&(r.deltaX=e.deltaX,r.deltaY=e.deltaY),this.eventsList.push(r),this.eventsCount+=1,"event-triggered"==this.config.uploadMode&&this.eventsList.length%this.config.frequency==0&&this._uploadTrace(),"mixed"==this.config.uploadMode&&this.eventsList.length%this.config.frequency==0&&(this._periodUploadTimeout(),this._uploadTrace())}}},{key:"_fetchConfigFromServer",value:function(){var e=this._newTrace();return this.uploader.upload(e)}},{key:"_uploadTrace",value:function(){var e=this._newTrace();return e.events=this.eventsList,this.eventsList=[],this.uploader.upload(e)}},{key:"_periodUploadTimeout",value:function(){var e=this;clearTimeout(this.uploadTimeout),this.uploadTimeout=setTimeout((function(){e.eventsList.length>0&&e._uploadTrace()}),this.config.uploadPeriod)}},{key:"_periodUploadInterval",value:function(){var e=this;clearInterval(this.uploadInterval),this.uploadInterval=setInterval((function(){e.eventsList.length>0&&e._uploadTrace()}),this.config.uploadPeriod)}},{key:"_runCollector",value:function(){var e=this;l.forEach((function(t){e.config.scope.addEventListener(t,(function(t){return e._mouseHandler(t)}))})),"periodic"===this.config.uploadMode&&this._periodUploadInterval(),"mixed"===this.config.uploadMode&&this._periodUploadTimeout()}},{key:"_stopCollector",value:function(){var e=this;l.forEach((function(t){e.config.scope.removeEventListener(t,(function(t){return e._mouseHandler(t)}))})),clearInterval(this.uploadInterval),clearTimeout(this.uploadTimeout)}},{key:"_resetCollector",value:function(){this._stopCollector(),this._runCollector()}},{key:"_init",value:function(e){var t=this;return this.impressionId=a(),this._clearBuffer(),this.uploadIdx=0,this.uploader=new s(this.impressionId,this.config),this.uploader.setImpressionId(this.impressionId),this.config.build(e)?(this._fetchConfigFromServer().then((function(e){if(1!=e.status)throw new Error("Fail to get config from server.");if(!t.config.update(e.config))throw new Error("Unable to update config with server config.");t._resetCollector(),t.uploader.setConfig(t.config),c.write("Successfully update config from backend.")})).catch((function(e){c.write(e)})),window.onbeforeunload=function(e){0!=t.eventsList.length&&t._uploadTrace()},{status:0}):{status:-1,msg:"Invalid configuration."}}},{key:"_pause",value:function(){this._stopCollector()}},{key:"_resume",value:function(){this._runCollector()}},{key:"run",value:function(e){var t=this,n=this._init(e);0==n.status?(h&&document.addEventListener(h,(function(e){return t._onVisibilityChange(e)})),this._runCollector(),this.uploader.start(this.impressionId),c.write("Mouselog agent is activated!"),c.write("Website ID: ".concat(this.config.websiteId)),c.write("Impression ID: ".concat(this.impressionId)),c.write("User-Agent: ".concat(navigator.userAgent)),c.write("Page load time: ".concat(d))):(c.write(n.msg),c.write("Fail to initialize Mouselog agent."))}},{key:"debug",value:function(e,t){c.activate(t),this.run(e)}},{key:"stop",value:function(){this.uploader.stop(),this._stopCollector(),this._clearBuffer(),c.write("Mouselog agent ".concat(this.impressionId," is stopped!"))}}]),e}();e.exports={Mouselog:v}},function(e,t,n){var o=n(7),i=n(8);e.exports=function(e,t,n){var r=t&&n||0;"string"==typeof e&&(t="binary"===e?new Array(16):null,e=null);var a=(e=e||{}).random||(e.rng||o)();if(a[6]=15&a[6]|64,a[8]=63&a[8]|128,t)for(var s=0;s<16;++s)t[r+s]=a[s];return t||i(a)}},function(e,t){var n="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof window.msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto);if(n){var o=new Uint8Array(16);e.exports=function(){return n(o),o}}else{var i=new Array(16);e.exports=function(){for(var e,t=0;t<16;t++)0==(3&t)&&(e=4294967296*Math.random()),i[t]=e>>>((3&t)<<3)&255;return i}}},function(e,t){for(var n=[],o=0;o<256;++o)n[o]=(o+256).toString(16).substr(1);e.exports=function(e,t){var o=t||0,i=n;return[i[e[o++]],i[e[o++]],i[e[o++]],i[e[o++]],"-",i[e[o++]],i[e[o++]],"-",i[e[o++]],i[e[o++]],"-",i[e[o++]],i[e[o++]],"-",i[e[o++]],i[e[o++]],i[e[o++]],i[e[o++]],i[e[o++]],i[e[o++]]].join("")}},function(e,t,n){"use strict";var o=n(0),i=o(n(1)),r=o(n(2)),a=n(4),s=n(3),u=0,c=1,l=2,d=function(){function e(t,n){(0,i.default)(this,e),this.impressionId=t,this.config=n,this.resendQueue=[]}return(0,r.default)(e,[{key:"start",value:function(){var e=this;this.resendInterval=setInterval((function(){e._resendFailedData.call(e)}),this.config.resendInterval)}},{key:"stop",value:function(){clearInterval(this.resendInterval)}},{key:"upload",value:function(e){var t=this;return new Promise((function(n,o){var i=JSON.stringify(e);s.write("Uploading Pkg ".concat(e.idx,", window size: ").concat(e.width,"*").concat(e.height,", events count: ").concat(e.events.length)),t._upload(i).then((function(e){if(200==e.status)return e.json();throw new Error("Response status code is not 200.")})).then((function(t){if(s.write("Pkg ".concat(e.idx," response=").concat(JSON.stringify(t))),"ok"!==t.status)throw new Error("Response object status is not ok.");"config"==t.msg&&n({status:1,msg:"Get config from server",config:t.data}),n({status:0})})).catch((function(o){s.write("Pkg ".concat(e.idx," failed, wait for resending. Error message: ").concat(o.message)),t._appendFailedData(e),n({status:-1,msg:"Fail to upload data bunch #".concat(e.idx,", ").concat(o.message)})}))}))}},{key:"setImpressionId",value:function(e){this.impressionId=e}},{key:"setConfig",value:function(e){this.stop(),this.config=e,this.start()}},{key:"_resendFailedData",value:function(){var e=this,t=0;this.resendQueue.length>0&&s.write("Resending data...");for(var n=function(){var n=e.resendQueue[t];n.status==l?e.resendQueue.splice(t,1):(t+=1,s.write("Resending Pkg ".concat(n.data.idx)),n.status==u&&(n.status=c,e.upload(n.data).then((function(e){n.status=e?l:u}))))};t<this.resendQueue.length;)n()}},{key:"_upload",value:function(e){var t=a(this.config.absoluteUrl,"/api/upload-trace","?websiteId=".concat(this.config.websiteId,"&impressionId=").concat(this.impressionId));return this.config.enableGet?fetch("".concat(t,"&data=").concat(e),{method:"GET",credentials:"include"}):fetch(t,{method:"POST",credentials:"include",body:e})}},{key:"_appendFailedData",value:function(e){this.resendQueue.push({status:u,data:e})}}]),e}();e.exports=d},function(e,t,n){"use strict";var o=n(0),i=o(n(1)),r=o(n(2)),a=n(4),s=n(3),u=function(){function e(){(0,i.default)(this,e),this.uploadEndpoint="http://localhost:9000",this.websiteId="unknown",this.endpointType="absolute",this.uploadMode="mixed",this.uploadPeriod=5e3,this.frequency=50,this.enableGet=!1,this.resendInterval=3e3,this.scope=window.document,this._requiredParams=["uploadEndpoint"],this._ignoredParams=["scope"]}return(0,r.default)(e,[{key:"build",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];try{this._requiredParams.forEach((function(t){if(!e.hasOwnProperty(t))throw new Error("Param ".concat(t," is required but not declared."))})),Object.keys(e).forEach((function(o){t[o]&&!o.startsWith("_")&&"function"!=typeof t[o]&&(n&&o in t._ignoredParams||(t[o]=e[o]))})),this._formatUrl()}catch(e){return s.write(e),!1}return!0}},{key:"update",value:function(e){return this.build(e,!0)}},{key:"_formatUrl",value:function(){if("relative"==this.endpointType)this.absoluteUrl=a(window.location.origin,this.uploadEndpoint);else{if("absolute"!=this.endpointType)throw new Error('`endpointType` can only be "absolute" or "relative"');this.absoluteUrl=this.uploadEndpoint}}}]),e}();e.exports={Config:u}}])})); |
{ | ||
"name": "mouselog", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"description": "The mouse tracking agent for Mouselog.", | ||
"main": "index.js", | ||
"main": "./src/index.js", | ||
"homepage": "https://github.com/microsoft/mouselog.js", | ||
@@ -20,5 +20,12 @@ "scripts": { | ||
"dependencies": { | ||
"@babel/runtime": "^7.8.4", | ||
"url-join": "^4.0.1", | ||
"uuid": "^3.3.3" | ||
}, | ||
"devDependencies": { | ||
"@babel/cli": "^7.8.4", | ||
"@babel/core": "^7.8.4", | ||
"@babel/plugin-transform-runtime": "^7.8.3", | ||
"@babel/preset-env": "^7.8.4", | ||
"babel-loader": "^8.0.6", | ||
"webpack": "^4.41.5", | ||
@@ -25,0 +32,0 @@ "webpack-cli": "^3.3.10" |
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
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
66293
11
1282
3
7
7
+ Added@babel/runtime@^7.8.4
+ Addedurl-join@^4.0.1
+ Added@babel/runtime@7.26.0(transitive)
+ Addedregenerator-runtime@0.14.1(transitive)
+ Addedurl-join@4.0.1(transitive)