mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-22 12:23:08 +09:00
309 lines
9.1 KiB
JavaScript
309 lines
9.1 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/**
|
|
* This file contains helper methods for debugging -- things like logging
|
|
* exception objects, dumping DOM nodes, Events, and generic object dumps.
|
|
*/
|
|
|
|
this.EXPORTED_SYMBOLS = ["logObject", "logException", "logElement", "logEvent",
|
|
"errorWithDebug"];
|
|
|
|
/**
|
|
* Report on an object to stdout.
|
|
* @param aObj the object to be dumped
|
|
* @param aName the name of the object, for informational purposes
|
|
*/
|
|
function logObject(aObj, aName) {
|
|
dump("Dumping Object: " + aName + "\n");
|
|
stringifier.dumpObj(aObj, aName);
|
|
}
|
|
|
|
/**
|
|
* Log an exception to stdout. This function should not be called in
|
|
* expected circumstances.
|
|
* @param aException the exception to log
|
|
* @param [aRethrow] set to true to rethrow the exception after logging
|
|
* @param [aMsg] optional message to log
|
|
*/
|
|
function logException(aException, aRethrow, aMsg) {
|
|
stringifier.dumpException(aException, aMsg);
|
|
|
|
if (aMsg)
|
|
Components.utils.reportError(aMsg);
|
|
Components.utils.reportError(aException);
|
|
|
|
if (aRethrow)
|
|
throw aException;
|
|
}
|
|
|
|
/**
|
|
* Log an DOM element to stdout.
|
|
* @param aElement the DOM element to dump
|
|
*/
|
|
function logElement(aElement) {
|
|
stringifier.dumpDOM(aElement);
|
|
}
|
|
|
|
/**
|
|
* Log an DOM event to stdout.
|
|
* @param aEvent the DOM event object to dump
|
|
*/
|
|
function logEvent(aEvent) {
|
|
stringifier.dumpEvent(aEvent);
|
|
}
|
|
|
|
/**
|
|
* Dump the current stack and return an Error suitable for throwing. We return
|
|
* the new Error so that your code can use a "throw" statement which makes it
|
|
* obvious to syntactic analysis that there is an exit occuring at that point.
|
|
*
|
|
* Example:
|
|
* throw errorWithDebug("I did not expect this!");
|
|
*
|
|
* @param aString The message payload for the exception.
|
|
*/
|
|
function errorWithDebug(aString) {
|
|
dump("PROBLEM: " + aString + "\n");
|
|
dump("CURRENT STACK (and throwing):\n");
|
|
// skip this frame.
|
|
dump(stringifier.getStack(1));
|
|
return new Error(aString);
|
|
}
|
|
|
|
function Stringifier() {};
|
|
|
|
Stringifier.prototype = {
|
|
dumpObj: function (o, name) {
|
|
this._reset();
|
|
this._append(this.objectTreeAsString(o, true, true, 0));
|
|
dump(this._asString());
|
|
},
|
|
|
|
dumpDOM: function(node, level, recursive) {
|
|
this._reset();
|
|
let s = this.DOMNodeAsString(node, level, recursive);
|
|
dump(s);
|
|
},
|
|
|
|
dumpEvent: function(event) {
|
|
dump(this.eventAsString(event));
|
|
},
|
|
|
|
dumpException: function(exc, message) {
|
|
dump(exc + "\n");
|
|
this._reset();
|
|
if (message)
|
|
this._append("Exception (" + message + ")\n");
|
|
|
|
this._append("-- Exception object --\n");
|
|
this._append(this.objectTreeAsString(exc));
|
|
if (exc.stack) {
|
|
this._append("-- Stack Trace --\n");
|
|
this._append(exc.stack); // skip dumpException and logException
|
|
}
|
|
dump(this._asString());
|
|
},
|
|
|
|
_reset: function() {
|
|
this._buffer = [];
|
|
},
|
|
|
|
_append: function(string) {
|
|
this._buffer.push(string);
|
|
},
|
|
|
|
_asString: function() {
|
|
let str = this._buffer.join('');
|
|
this._reset();
|
|
return str;
|
|
},
|
|
|
|
getStack: function(skipCount) {
|
|
if (!((typeof Components == "object") &&
|
|
(typeof Components.classes == "object")))
|
|
return "No stack trace available.";
|
|
if (typeof(skipCount) === undefined)
|
|
skipCount = 0;
|
|
|
|
let frame = Components.stack.caller;
|
|
let str = "<top>";
|
|
|
|
while (frame) {
|
|
if (skipCount > 0) {
|
|
// Skip this frame.
|
|
skipCount -= 1;
|
|
}
|
|
else {
|
|
// Include the data from this frame.
|
|
let name = frame.name ? frame.name : "[anonymous]";
|
|
str += "\n" + name + "@" + frame.filename + ':' + frame.lineNumber;
|
|
}
|
|
frame = frame.caller;
|
|
}
|
|
return str + "\n";
|
|
},
|
|
|
|
objectTreeAsString: function(o, recurse, compress, level) {
|
|
let s = "";
|
|
if (recurse === undefined)
|
|
recurse = 0;
|
|
if (level === undefined)
|
|
level = 0;
|
|
if (compress === undefined)
|
|
compress = true;
|
|
let pfx = "";
|
|
|
|
for (var junk = 0; junk < level; junk++)
|
|
pfx += (compress) ? "| " : "| ";
|
|
|
|
let tee = (compress) ? "+ " : "+- ";
|
|
|
|
if (typeof(o) != "object") {
|
|
s += pfx + tee + " (" + typeof(o) + ") " + o + "\n";
|
|
}
|
|
else {
|
|
for (let i in o) {
|
|
try {
|
|
let t = typeof o[i];
|
|
switch (t) {
|
|
case "function":
|
|
let sfunc = String(o[i]).split("\n");
|
|
if (sfunc[2] == " [native code]")
|
|
sfunc = "[native code]";
|
|
else
|
|
sfunc = sfunc.length + " lines";
|
|
s += pfx + tee + i + " (function) " + sfunc + "\n";
|
|
break;
|
|
case "object":
|
|
s += pfx + tee + i + " (object) " + o[i] + "\n";
|
|
if (!compress)
|
|
s += pfx + "|\n";
|
|
if ((i != "parent") && (recurse))
|
|
s += this.objectTreeAsString(o[i], recurse - 1,
|
|
compress, level + 1);
|
|
break;
|
|
case "string":
|
|
if (o[i].length > 200)
|
|
s += pfx + tee + i + " (" + t + ") " + o[i].length + " chars\n";
|
|
else
|
|
s += pfx + tee + i + " (" + t + ") '" + o[i] + "'\n";
|
|
break;
|
|
default:
|
|
s += pfx + tee + i + " (" + t + ") " + o[i] + "\n";
|
|
}
|
|
} catch (ex) {
|
|
s += pfx + tee + " (exception) " + ex + "\n";
|
|
}
|
|
if (!compress)
|
|
s += pfx + "|\n";
|
|
}
|
|
}
|
|
s += pfx + "*\n";
|
|
return s;
|
|
},
|
|
|
|
_repeatStr: function (str, aCount) {
|
|
let res = "";
|
|
while (--aCount >= 0)
|
|
res += str;
|
|
return res;
|
|
},
|
|
|
|
DOMNodeAsString: function(node, level, recursive) {
|
|
if (level === undefined)
|
|
level = 0
|
|
if (recursive === undefined)
|
|
recursive = true;
|
|
this._append(this._repeatStr(" ", 2*level) + "<" + node.nodeName + "\n");
|
|
|
|
if (node.nodeType == 3) {
|
|
this._append(this._repeatStr(" ", (2*level) + 4) + node.nodeValue + "'\n");
|
|
}
|
|
else {
|
|
if (node.attributes) {
|
|
for (let i = 0; i < node.attributes.length; i++) {
|
|
this._append(this._repeatStr(
|
|
" ", (2*level) + 4) + node.attributes[i].nodeName +
|
|
"='" + node.attributes[i].nodeValue + "'\n");
|
|
}
|
|
}
|
|
if (node.childNodes.length == 0) {
|
|
this._append(this._repeatStr(" ", (2*level)) + "/>\n");
|
|
}
|
|
else if (recursive) {
|
|
this._append(this._repeatStr(" ", (2*level)) + ">\n");
|
|
for (let i = 0; i < node.childNodes.length; i++) {
|
|
this._append(this.DOMNodeAsString(node.childNodes[i], level + 1));
|
|
}
|
|
this._append(this._repeatStr(" ", 2*level) + "</" + node.nodeName + ">\n");
|
|
}
|
|
}
|
|
return this._asString();
|
|
},
|
|
|
|
eventAsString: function (event) {
|
|
this._reset();
|
|
this._append("-EVENT --------------------------\n");
|
|
this._append("type: " + event.type + "\n");
|
|
this._append("eventPhase: " + event.eventPhase + "\n");
|
|
if ("charCode" in event) {
|
|
this._append("charCode: " + event.charCode + "\n");
|
|
if ("name" in event)
|
|
this._append("str(charCode): '" + String.fromCharCode(event.charCode) + "'\n");
|
|
}
|
|
if (("target" in event) && event.target) {
|
|
this._append("target: " + event.target + "\n");
|
|
if ("nodeName" in event.target)
|
|
this._append("target.nodeName: " + event.target.nodeName + "\n");
|
|
if ("getAttribute" in event.target)
|
|
this._append("target.id: " + event.target.getAttribute("id") + "\n");
|
|
}
|
|
if (("currentTarget" in event) && event.currentTarget) {
|
|
this._append("currentTarget: " + event.currentTarget + "\n");
|
|
if ("nodeName" in event.currentTarget)
|
|
this._append("currentTarget.nodeName: "+ event.currentTarget.nodeName + "\n");
|
|
if ("getAttribute" in event.currentTarget)
|
|
this._append("currentTarget.id: "+ event.currentTarget.getAttribute("id") + "\n");
|
|
}
|
|
if (("originalTarget" in event) && event.originalTarget) {
|
|
this._append("originalTarget: " + event.originalTarget + "\n");
|
|
if ("nodeName" in event.originalTarget)
|
|
this._append("originalTarget.nodeName: "+ event.originalTarget.nodeName + "\n");
|
|
if ("getAttribute" in event.originalTarget)
|
|
this._append("originalTarget.id: "+ event.originalTarget.getAttribute("id") + "\n");
|
|
}
|
|
let names = [
|
|
"bubbles",
|
|
"cancelable",
|
|
"detail",
|
|
"button",
|
|
"keyCode",
|
|
"isChar",
|
|
"shiftKey",
|
|
"altKey",
|
|
"ctrlKey",
|
|
"metaKey",
|
|
"clientX",
|
|
"clientY",
|
|
"screenX",
|
|
"screenY",
|
|
"layerX",
|
|
"layerY",
|
|
"isTrusted",
|
|
"timeStamp",
|
|
"currentTargetXPath",
|
|
"targetXPath",
|
|
"originalTargetXPath"
|
|
];
|
|
for (let i in names) {
|
|
if (names[i] in event)
|
|
this._append(names[i] + ": " + event[names[i]] + "\n");
|
|
}
|
|
this._append("-------------------------------------\n");
|
|
return this._asString();
|
|
}
|
|
};
|
|
|
|
var stringifier = new Stringifier();
|