|
|
|
|
| 104 |
return obj.namesAndValuesOf; |
104 |
return obj.namesAndValuesOf; |
| 105 |
}); |
105 |
}); |
| 106 |
|
106 |
|
|
|
107 |
XPCOMUtils.defineLazyGetter(this, "sourceMapUtils", function () { |
| 108 |
let smu = {}; |
| 109 |
Cu.import("resource:///modules/SourceMapUtils.jsm", smu); |
| 110 |
return smu; |
| 111 |
}); |
| 112 |
|
| 107 |
function LogFactory(aMessagePrefix) |
113 |
function LogFactory(aMessagePrefix) |
| 108 |
{ |
114 |
{ |
| 109 |
function log(aMessage) { |
115 |
function log(aMessage) { |
|
|
| 1999 |
return; |
2005 |
return; |
| 2000 |
} |
2006 |
} |
| 2001 |
|
2007 |
|
|
|
2008 |
let window = this.getWindowByWindowId(aMessage.ID) |
| 2009 |
|| this.getWindowByWindowId(aMessage.innerID) |
| 2010 |
|| this.currentContext() |
| 2011 |
|| null; |
| 2002 |
let node = ConsoleUtils.createMessageNode(hud.outputNode.ownerDocument, |
2012 |
let node = ConsoleUtils.createMessageNode(hud.outputNode.ownerDocument, |
| 2003 |
CATEGORY_WEBDEV, |
2013 |
CATEGORY_WEBDEV, |
| 2004 |
LEVELS[level], |
2014 |
LEVELS[level], |
|
|
| 2006 |
sourceURL, |
2016 |
sourceURL, |
| 2007 |
sourceLine, |
2017 |
sourceLine, |
| 2008 |
clipboardText, |
2018 |
clipboardText, |
| 2009 |
level); |
2019 |
level, |
|
|
2020 |
window); |
| 2010 |
|
2021 |
|
| 2011 |
// Make the node bring up the property panel, to allow the user to inspect |
2022 |
// Make the node bring up the property panel, to allow the user to inspect |
| 2012 |
// the stack trace. |
2023 |
// the stack trace. |
|
|
| 2106 |
severity, |
2117 |
severity, |
| 2107 |
aScriptError.errorMessage, |
2118 |
aScriptError.errorMessage, |
| 2108 |
aScriptError.sourceName, |
2119 |
aScriptError.sourceName, |
| 2109 |
aScriptError.lineNumber); |
2120 |
aScriptError.lineNumber, |
|
|
2121 |
null, |
| 2122 |
null, |
| 2123 |
window, |
| 2124 |
null); |
| 2110 |
|
2125 |
|
| 2111 |
ConsoleUtils.outputMessageNode(node, hudId); |
2126 |
ConsoleUtils.outputMessageNode(node, hudId); |
| 2112 |
} |
2127 |
} |
|
|
| 5503 |
* a string, then the clipboard text must be supplied. |
5518 |
* a string, then the clipboard text must be supplied. |
| 5504 |
* @param number aLevel [optional] |
5519 |
* @param number aLevel [optional] |
| 5505 |
* The level of the console API message. |
5520 |
* The level of the console API message. |
|
|
5521 |
* @param nsIDOMWindow aWindow |
| 5522 |
* The window from which the message originates. This allows us to get |
| 5523 |
* the source map associated with the script that created this message |
| 5524 |
* and display the proper originating source file and line numbers. |
| 5506 |
* @return nsIDOMNode |
5525 |
* @return nsIDOMNode |
| 5507 |
* The message node: a XUL richlistitem ready to be inserted into |
5526 |
* The message node: a XUL richlistitem ready to be inserted into |
| 5508 |
* the Web Console output node. |
5527 |
* the Web Console output node. |
|
|
| 5510 |
createMessageNode: |
5529 |
createMessageNode: |
| 5511 |
function ConsoleUtils_createMessageNode(aDocument, aCategory, aSeverity, |
5530 |
function ConsoleUtils_createMessageNode(aDocument, aCategory, aSeverity, |
| 5512 |
aBody, aSourceURL, aSourceLine, |
5531 |
aBody, aSourceURL, aSourceLine, |
| 5513 |
aClipboardText, aLevel) { |
5532 |
aClipboardText, aLevel, aWindow, |
|
|
5533 |
aScript) { |
| 5514 |
if (aBody instanceof Ci.nsIDOMNode && aClipboardText == null) { |
5534 |
if (aBody instanceof Ci.nsIDOMNode && aClipboardText == null) { |
| 5515 |
throw new Error("HUDService.createMessageNode(): DOM node supplied " + |
5535 |
throw new Error("HUDService.createMessageNode(): DOM node supplied " + |
| 5516 |
"without any clipboard text"); |
5536 |
"without any clipboard text"); |
|
|
| 5544 |
// If a string was supplied for the body, turn it into a DOM node and an |
5564 |
// If a string was supplied for the body, turn it into a DOM node and an |
| 5545 |
// associated clipboard string now. |
5565 |
// associated clipboard string now. |
| 5546 |
aClipboardText = aClipboardText || |
5566 |
aClipboardText = aClipboardText || |
| 5547 |
(aBody + (aSourceURL ? " @ " + aSourceURL : "") + |
5567 |
this.makeClipboardText(aBody, aSourceURL, aSourceLine); |
| 5548 |
(aSourceLine ? ":" + aSourceLine : "")); |
|
|
| 5549 |
aBody = aBody instanceof Ci.nsIDOMNode && !(aLevel == "dir") ? |
5568 |
aBody = aBody instanceof Ci.nsIDOMNode && !(aLevel == "dir") ? |
| 5550 |
aBody : aDocument.createTextNode(aBody); |
5569 |
aBody : aDocument.createTextNode(aBody); |
| 5551 |
|
5570 |
|
|
|
| 5626 |
|
5645 |
|
| 5627 |
node.setAttribute("id", "console-msg-" + HUDService.sequenceId()); |
5646 |
node.setAttribute("id", "console-msg-" + HUDService.sequenceId()); |
| 5628 |
|
5647 |
|
|
|
5648 |
if (aSourceURL && aWindow) { |
| 5649 |
this.updateLocationInfoWithSourceMap(node, locationNode, aSourceURL, |
| 5650 |
aSourceLine, aWindow, aDocument, |
| 5651 |
aBody); |
| 5652 |
} |
| 5653 |
|
| 5629 |
return node; |
5654 |
return node; |
| 5630 |
}, |
5655 |
}, |
| 5631 |
|
5656 |
|
| 5632 |
/** |
5657 |
/** |
|
|
5658 |
* The panel which holds the original and generated location info for the |
| 5659 |
* currently focused console message. It is created the first time there is a |
| 5660 |
* console message which has source mapping info. |
| 5661 |
*/ |
| 5662 |
locationContainerPanel: null, |
| 5663 |
|
| 5664 |
/** |
| 5665 |
* What is the offset of a node? It is its offset from its offsetParent plus |
| 5666 |
* the offset of its parent. The offset of the null node is defined as 0 from |
| 5667 |
* the top and 0 from the left. |
| 5668 |
* |
| 5669 |
* @param aNode the node you would like the offset of. |
| 5670 |
* @returns an object with the left and top offsets of the given node. |
| 5671 |
*/ |
| 5672 |
elementOffset: |
| 5673 |
function ConsoleUtils_elementOffset(aNode) { |
| 5674 |
// This is the base case: no more offsetParents. |
| 5675 |
if (!aNode) { |
| 5676 |
return { |
| 5677 |
left: 0, |
| 5678 |
top: 0 |
| 5679 |
}; |
| 5680 |
} |
| 5681 |
|
| 5682 |
let { left, top } = aNode.getBoundingClientRect(); |
| 5683 |
let offsetOfParent = ConsoleUtils_elementOffset(aNode.offsetParent); |
| 5684 |
|
| 5685 |
return { |
| 5686 |
left: left + offsetOfParent.left, |
| 5687 |
top: top + offsetOfParent.top |
| 5688 |
}; |
| 5689 |
}, |
| 5690 |
|
| 5691 |
/** |
| 5692 |
* Handles the logic for whether or not the mouseout handler for the |
| 5693 |
* locationContainerPanel should be called. |
| 5694 |
* |
| 5695 |
* @param aTarget The target element of a mouseout event. |
| 5696 |
* @returns boolean based on whether or not the mouseout handler for the |
| 5697 |
* locationContainerPanel should fire. |
| 5698 |
*/ |
| 5699 |
mouseoutShouldFire: |
| 5700 |
function ConsoleUtils_mouseoutShouldFire(aTarget) { |
| 5701 |
if (aTarget === this.locationContainerPanel) { |
| 5702 |
return true; |
| 5703 |
} |
| 5704 |
let el = aTarget; |
| 5705 |
while (el) { |
| 5706 |
if (el === this.locationContainerPanel) { |
| 5707 |
return false; |
| 5708 |
} |
| 5709 |
el = el.parentNode; |
| 5710 |
} |
| 5711 |
return true; |
| 5712 |
}, |
| 5713 |
|
| 5714 |
/** |
| 5715 |
* Asynchronously check if there is a source map for this message's |
| 5716 |
* script. If there is, update the locationNode and clipboardText. |
| 5717 |
* |
| 5718 |
* TODO: Use column numbers. See bug 679181 |
| 5719 |
* TODO: Don't require aSourceURL and aWindow if aScript is supplied. See bug |
| 5720 |
* 679189. |
| 5721 |
* |
| 5722 |
* @param aParentNode The parent of the location node. |
| 5723 |
* @param aLocationNode The node which has the location info we would like to |
| 5724 |
* update. |
| 5725 |
* @param aSourceURL The URL of the script which generated the message or null |
| 5726 |
* if aScript is provided. |
| 5727 |
* @param aSourceLine The line number in the script where the message came |
| 5728 |
* from. |
| 5729 |
* @param aWindow The window associated with aSourceURL from which the message |
| 5730 |
* came, or null if aScript is provided. |
| 5731 |
* @param aDocument The document that contains aParentNode and aLocationNode. |
| 5732 |
* @param aBody The body of the message that was logged. |
| 5733 |
* @param aScript The script object that generated the message, or null if |
| 5734 |
* aSourceURL and aWindow are provided. |
| 5735 |
*/ |
| 5736 |
updateLocationInfoWithSourceMap: |
| 5737 |
function ConsoleUtils_updateLocationInfoWithSourceMap (aParentNode, aLocationNode, |
| 5738 |
aSourceURL, aSourceLine, |
| 5739 |
aWindow, aDocument, aBody, |
| 5740 |
aScript) { |
| 5741 |
sourceMapUtils.sourceMapForFilename(aSourceURL, aWindow, (function (aSourceMap) { |
| 5742 |
let { source, line } = aSourceMap.originalPositionFor({ |
| 5743 |
line: aSourceLine, |
| 5744 |
column: 0 |
| 5745 |
}); |
| 5746 |
|
| 5747 |
if (source != null && line != null) { |
| 5748 |
// Resolve the original source url relative to the generated script. |
| 5749 |
try { |
| 5750 |
let url = Services.io.newURI(aSourceURL, null, null).QueryInterface(Ci.nsIURL); |
| 5751 |
source = url.resolve(source); |
| 5752 |
} |
| 5753 |
catch (e) { |
| 5754 |
Cu.reportError(e); |
| 5755 |
return; |
| 5756 |
} |
| 5757 |
|
| 5758 |
// Create the new elements we need. |
| 5759 |
if (!this.locationContainerPanel) { |
| 5760 |
this.locationContainerPanel = aDocument.createElementNS(XUL_NS, "panel"); |
| 5761 |
this.locationContainerPanel.classList.add("webconsole-location-container"); |
| 5762 |
aDocument.documentElement.appendChild(this.locationContainerPanel); |
| 5763 |
} |
| 5764 |
let sourceMappedLocationNode = this.createLocationNode(aDocument, |
| 5765 |
source, |
| 5766 |
line); |
| 5767 |
|
| 5768 |
// Replace the generated source and line with the original, mapped |
| 5769 |
// source and line. |
| 5770 |
aParentNode.replaceChild(sourceMappedLocationNode, |
| 5771 |
aLocationNode); |
| 5772 |
|
| 5773 |
// Create another location node with the original, mapped location info |
| 5774 |
// which will be put in the panel popup. |
| 5775 |
let sourceMappedLocationNodeForPanel = this.createLocationNode(aDocument, |
| 5776 |
source, |
| 5777 |
line); |
| 5778 |
|
| 5779 |
sourceMappedLocationNode.addEventListener("mouseover", (function (event) { |
| 5780 |
if (event.target === sourceMappedLocationNode) { |
| 5781 |
// Remove all the children from the panel, we are about to populate |
| 5782 |
// it with our own location infos. |
| 5783 |
this.locationContainerPanel.hidePopup(); |
| 5784 |
while (this.locationContainerPanel.firstChild) { |
| 5785 |
this.locationContainerPanel |
| 5786 |
.removeChild(this.locationContainerPanel.firstChild); |
| 5787 |
} |
| 5788 |
|
| 5789 |
// Add the full original and generated location info to the panel. |
| 5790 |
this.locationContainerPanel.appendChild(sourceMappedLocationNodeForPanel); |
| 5791 |
this.locationContainerPanel.appendChild(aLocationNode); |
| 5792 |
|
| 5793 |
// Open the panel over the currently hovered over location node. |
| 5794 |
let { left, top } = this.elementOffset(sourceMappedLocationNode); |
| 5795 |
this.locationContainerPanel.openPopup(null, null, left, top, |
| 5796 |
false, false, null); |
| 5797 |
} |
| 5798 |
}).bind(this), false); |
| 5799 |
|
| 5800 |
this.locationContainerPanel.addEventListener("mouseout", (function (event) { |
| 5801 |
if (this.mouseoutShouldFire(event.target) |
| 5802 |
|| this.mouseoutShouldFire(event.relatedTarget)) { |
| 5803 |
this.locationContainerPanel.hidePopup(); |
| 5804 |
} |
| 5805 |
}).bind(this), false); |
| 5806 |
|
| 5807 |
// Update the clipboard text to reflect the original source. |
| 5808 |
aParentNode.clipboardText = this.makeClipboardText(aBody, source, line); |
| 5809 |
} |
| 5810 |
}).bind(this), function (errno, error) { |
| 5811 |
if (errno != sourceMapUtils.ERRORS.NO_SOURCE_MAP) { |
| 5812 |
Cu.reportError(error); |
| 5813 |
} |
| 5814 |
}); |
| 5815 |
}, |
| 5816 |
|
| 5817 |
/** |
| 5818 |
* Creates the string that will be copied to the clipboard for individual |
| 5819 |
* console message nodes. |
| 5820 |
*/ |
| 5821 |
makeClipboardText: |
| 5822 |
function ConsoleUtils_makeClipboardText(aBody, aSourceURL, aSourceLine) { |
| 5823 |
return aBody |
| 5824 |
+ (aSourceURL ? " @ " + aSourceURL : "") |
| 5825 |
+ (aSourceLine ? ":" + aSourceLine : ""); |
| 5826 |
}, |
| 5827 |
|
| 5828 |
/** |
| 5633 |
* Adjusts the category and severity of the given message, clearing the old |
5829 |
* Adjusts the category and severity of the given message, clearing the old |
| 5634 |
* category and severity if present. |
5830 |
* category and severity if present. |
| 5635 |
* |
5831 |
* |