(function () {
let inlineConsole,
logCount = 0,
XMLHttpRequestCount = 0;
const consoleHeight = 240,
// watchEvents = ['click','focus','unfocus','blur','unblur','touchstart','touchend']
watchEvents = [],
startMs = new Date().getTime(),
oldLog = console.log,
oldDebug = console.debug,
oldWarn = console.warn,
oldInfo = console.info,
oldError = console.error,
consoleWrapper = document.createElement("div");
/** From: http://stackoverflow.com/questions/2234979/how-to-check-in-javascript-if-one-element-is-contained-within-another **/
const isDescendant = function (parent, child) {
let node = child.parentNode;
while (node !== null) {
if (node === parent) {
return true;
}
node = node.parentNode;
}
return false;
};
const clearConsole = function () {
inlineConsole.innerHTML = null;
};
const initInlineConsole = function () {
if (!inlineConsole) {
const consoleTitle = document.createElement("h3"),
clearButton = document.createElement("button");
inlineConsole = document.createElement("div");
consoleWrapper.appendChild(consoleTitle);
consoleWrapper.appendChild(inlineConsole);
consoleWrapper.style.backgroundColor = "#333333";
consoleWrapper.style.color = "#cccccc";
consoleWrapper.style.position = "fixed";
consoleWrapper.style.bottom = "0";
consoleWrapper.style.right = "0";
consoleWrapper.style.left = "0";
consoleWrapper.style.clear = "both";
consoleWrapper.classList.add("inline-console");
clearButton.innerHTML = "clear";
clearButton.style.fontSize = "0.5em";
clearButton.style.float = "right";
clearButton.style.color = "black";
clearButton.onclick = clearConsole;
consoleTitle.innerHTML = "Inline Console";
consoleTitle.style.padding = "0.3em";
consoleTitle.style.margin = "0";
consoleTitle.style.fontFamily = "monospace";
consoleTitle.appendChild(clearButton);
inlineConsole.style.backgroundColor = "black";
inlineConsole.style.border = "0";
inlineConsole.style.color = "#00ff00";
inlineConsole.style.height = consoleHeight + "px";
inlineConsole.style.resize = "none";
inlineConsole.style.overflowY = "auto";
inlineConsole.style.fontFamily = "monospace";
}
};
const toggleVisible = function (event, id, toggleElement) {
const element = document.getElementById(id);
const hiddenElement = document.getElementById(id + "-hidden");
if (element.style.display) {
element.style.display = null;
hiddenElement.style.display = "none";
toggleElement.innerHTML = "hide";
} else {
element.style.display = "none";
hiddenElement.style.display = null;
toggleElement.innerHTML = "show";
}
};
const sendMsg = function (type, args, color) {
const el = document.createElement("div"),
eId = type + "-" + ++logCount,
firstElementString = JSON.stringify(args[0]),
toggleElement = document.createElement("button"),
hrElement = document.createElement("hr"),
currentMs = new Date().getTime();
let nElement;
initInlineConsole();
el.style.clear = "both";
el.style.margin = "0";
el.style.padding = "0";
el.style.textAlign = "left";
if (color) {
el.style.color = color;
}
// Add Header
el.innerHTML +=
"" +
type +
" [" +
(currentMs - startMs) +
'ms]: ' +
firstElementString.substring(0, 48) +
"...";
// Add Content
if (args.length === 1) {
nElement = document.createElement("span");
nElement.id = eId;
nElement.innerHTML = firstElementString;
el.appendChild(nElement);
} else if (args.length > 1) {
nElement = document.createElement("ol");
nElement.id = eId;
nElement.style.margin = "0";
nElement.style.padding = "0";
for (let i = 0, len = args.length, item; i < len; i++) {
item = document.createElement("li");
item.innerHTML = JSON.stringify(args[i]);
nElement.appendChild(item);
}
el.appendChild(nElement);
}
// Add Toggle Text
if (firstElementString.length > 64 || args.length > 1) {
toggleElement.onclick = function (event) {
toggleVisible(event, eId, toggleElement);
};
toggleElement.innerHTML = "hide";
toggleElement.style.float = "right";
toggleElement.style.color = "black";
toggleElement.style.fontSize = "0.7em";
el.appendChild(toggleElement);
}
// Add line between entries
hrElement.style.clear = "both";
hrElement.style.margin = "0";
hrElement.style.padding = "0";
el.appendChild(hrElement);
// Add everything to consoles
inlineConsole.appendChild(el);
if (el.clientHeight > consoleHeight) {
toggleVisible(null, eId, toggleElement);
}
inlineConsole.scrollTop = inlineConsole.scrollHeight;
};
console.log = function (_message) {
sendMsg("LOG", arguments);
oldLog.apply(console, arguments);
};
console.debug = function (_message) {
sendMsg("DEBUG", arguments, "#cccccc");
oldDebug.apply(console, arguments);
};
console.warn = function (_message) {
sendMsg("WARN", arguments, "#ff9900");
oldWarn.apply(console, arguments);
};
console.info = function (_message) {
sendMsg("INFO", arguments, "#0066ff");
oldInfo.apply(console, arguments);
};
console.error = function (_message) {
sendMsg("ERROR", arguments, "#ff0000");
oldError.apply(console, arguments);
};
for (let ei = 0, eLen = watchEvents.length; ei < eLen; ei++) {
document.addEventListener(
watchEvents[ei],
function (e) {
if (!isDescendant(consoleWrapper, e.target)) {
sendMsg(
"EVENT",
[
"An event type "" +
e.type +
"" was triggered by a "" +
e.target.nodeName +
"" node.",
],
"#cccccc"
);
}
},
true
);
}
/*document.addEventListener('error', function(e) {
if(!isDescendant(consoleWrapper, e.target)) {
sendMsg('EVENT-ERROR', ['An event type "'+e.type+'" was triggered by a "'+e.target.nodeName+'" node.'], '#ff0000');
}
}, true);*/
window.onerror = function (message, lineNumber, file) {
sendMsg("ERROR", [message, lineNumber, file], "#ff0000");
};
window.onload = function () {
document.body.appendChild(consoleWrapper);
};
/**
* Override and extend the default open/send methods for XMLHttpRequest so we can log this activity
*
* Based on code by Julien Couvreur (http://blog.monstuff.com/archives/cat_greasemonkey.html)
* and included here with his gracious permission
*/
XMLHttpRequest.prototype.oldOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.oldSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.getId = function () {
if (!this.threadId) {
this.threadId = ++XMLHttpRequestCount;
}
return ("00" + this.threadId).slice(-3);
};
XMLHttpRequest.prototype.open = function (
method,
url,
async,
user,
password
) {
sendMsg(
"HTTP",
[
"Opening Connection #" + this.getId(),
{
method: method,
url: url,
async: async,
user: user,
password: password,
},
],
"#cccccc"
);
this.oldOpen(method, url, async, user, password);
};
XMLHttpRequest.prototype.send = function (a) {
this.addEventListener(
"load",
function () {
sendMsg(
"HTTP",
[
"Connection #" +
this.getId() +
" Completed Successfully: " +
this.status,
],
"#cccccc"
);
},
false
);
this.addEventListener(
"error",
function () {
sendMsg(
"HTTP-ERROR",
["Connection #" + this.getId() + " Failed: " + this.status],
"#ff0000"
);
},
false
);
this.oldSend(a);
};
})();