'use strict';
~(function (w, $) {
if (!document.addEventListener) return 'IE8 sucks';
var TRACKER = 'https://perf.ele.me/_.gif?';
var ERROR = {
id: function id(ev) {
return 'You need a "project/id", like perf-' + ev + '="project/id"';
},
data: '`perf-data` show be a json string'
};
var img = new Image();
var errorCache = {};
// by default: log errors
errorHandler();
// save performance
var isLoad = 0;
if (w.performance) {
w.addEventListener('beforeunload', savePerf);
w.addEventListener('load', savePerf);
}
// auto save use `perf-EVENT`
['click', 'contextmenu', 'dblclick', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseover', 'mouseout', 'mouseup', 'keydown', 'keypress', 'keyup', 'abort', 'beforeunload', 'error', 'hashchange', 'load', 'pageshow', 'pagehide', 'resize', 'scroll', 'unload', 'blur', 'change', 'focus', 'focusin', 'focusout', 'input', 'invalid', 'reset', 'search', 'select', 'submit', 'drag', 'dragend', 'dragenter', 'dragleave', 'dragover', 'dragstart', 'drop', 'copy', 'cut', 'paste', 'afterprint', 'beforeprint', 'abort', 'canplay', 'canplaythrough', 'durationchange', 'ended', 'error', 'loadeddata', 'loadedmetadata', 'loadstart', 'pause', 'play', 'playing', 'progress', 'ratechange', 'seeked', 'seeking', 'stalled', 'suspend', 'timeupdate', 'volumechange', 'waiting', 'animationend', 'animationiteration', 'animationstart', 'transitionend'].forEach(function (ev) {
var els = $('[perf-' + ev + ']');
if (!els.length) return;
[].slice.call(els).forEach(function (el) {
return el.addEventListener(ev, eventHandler);
});
});
// expose for access
w.perf = { send: send, stat: caculatePerf };
function send(message) {
if (!message.id) {
if (w.PERF_DEBUG) throw new Error(ERROR.id('click'));
console.log(ERROR.id(click));
}
img.src = TRACKER + obj2Query(message) + ('&time=' + Date.now());
// for debug
if (typeof w.PERF_DEBUG === 'function') w.PERF_DEBUG(message);
return perf;
}
function errorHandler() {
w.addEventListener('error', function (e) {
var key = e.filename + e.lineno + e.colno + w.location.href;
if (errorCache[key]) return;
errorCache[key] = true;
send({
id: w.location.href,
line: e.lineno + ':' + e.colno,
file: e.filename,
error: e.message
});
});
}
function eventHandler(e) {
var ev = e.type;
var raw = {};
var message = {
id: this.getAttribute('perf-' + ev),
event: ev
};
if (!message.id) {
if (w.PERF_DEBUG) throw new Error(ERROR.id(ev));
return console.log(ERROR.id(ev));
}
if (this.getAttribute('perf-route')) message.route = this.getAttribute('perf-route');
var err = null;
if (this.getAttribute('perf-data')) {
raw = this.getAttribute('perf-data');
try {
raw = JSON.parse(raw);
} catch (e) {
err = 1;
if (w.PERF_DEBUG) throw new Error(ERROR.data);
console.log(err);
}
}
if (!err) send(asign(raw, message));
}
function type(obj) {
return Object.prototype.toString.call(obj).slice(8, -1);
}
function caculatePerf() {
var table = [['lookup', ['requestStart', 'navigationStart']], ['waiting', ['responseStart', 'requestStart']], ['receiving', ['responseEnd', 'responseStart']], ['parsing', ['domComplete', 'domLoading']], ['contentLoaded', ['domContentLoadedEventStart', 'navigationStart']], ['pageLoaded', ['loadEventStart', 'navigationStart']]];
var detail = {};
table.forEach(function (item) {
return detail[item[0]] = time.apply(w.performance, item[1]);
});
return detail;
function time(end, start) {
return this.timing[end] - this.timing[start];
}
}
function savePerf() {
if (isLoad) return;
isLoad = 1;
send({ id: w.location.href, perf: caculatePerf() });
}
function obj2Query(obj) {
var str = '';
var _loop = function _loop() {
if (!obj.hasOwnProperty(p)) return 'continue';
var encodedP = encodeURIComponent(p);
if (type(obj[p]) === 'Array') {
str += obj[p].map(function (item) {
return encodedP + '[]=' + encodeURIComponent(item);
}).join('&');
str += '&';
} else if (type(obj[p]) === 'Object') {
var cur = obj[p];
for (k in cur) {
str += cur[k] ? encodedP + '[' + k + ']=' + encodeURIComponent(cur[k]) + '&' : '';
}
} else {
str += encodedP + '=' + encodeURIComponent(obj[p]) + '&';
}
};
for (var p in obj) {
var k;
var _ret = _loop();
if (_ret === 'continue') continue;
}
return str.slice(0, -1);
}
function asign(dist, src) {
for (var p in src) {
dist[p] = src[p];
}return dist;
}
})(window, function (selector, parent) {
parent = document || parent;
return parent.querySelectorAll(selector);
});