Issue N/A - Restore the Toolkit Error Console - Part 1: Toolkit

This commit is contained in:
NTD 2018-02-02 07:11:37 -05:00 • committed by Roy Tam
commit b5846d500d
27 changed files with 1522 additions and 0 deletions

View file

@ -0,0 +1,74 @@
/* 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/. */
.console-box {
-moz-binding: url("chrome://global/content/consoleBindings.xml#console-box");
overflow: auto;
}
.console-rows {
-moz-user-focus: normal;
}
.console-row[type="error"],
.console-row[type="warning"] {
-moz-binding: url("chrome://global/content/consoleBindings.xml#error");
}
.console-row[type="message"] {
-moz-binding: url("chrome://global/content/consoleBindings.xml#message");
}
.console-msg-text,
.console-error-msg {
white-space: pre-wrap;
}
.console-error-source {
-moz-binding: url("chrome://global/content/consoleBindings.xml#console-error-source");
}
.console-dots {
width: 1px;
}
/* :::::::::: hiding and showing of rows for each mode :::::::::: */
.console-box[mode="Warnings"] > .console-box-internal > .console-rows
> .console-row[type="error"],
.console-box[mode="Messages"] > .console-box-internal > .console-rows
> .console-row[type="error"]
{
display: none;
}
.console-box[mode="Errors"] > .console-box-internal > .console-rows
> .console-row[type="warning"],
.console-box[mode="Messages"] > .console-box-internal > .console-rows
> .console-row[type="warning"]
{
display: none;
}
.console-box[mode="Errors"] > .console-box-internal > .console-rows
> .console-row[type="message"],
.console-box[mode="Warnings"] > .console-box-internal > .console-rows
> .console-row[type="message"]
{
display: none;
}
.filtered-by-string {
display: none;
}
/* If line number is 0, hide the line number section */
.lineNumberRow[line="0"] {
display: none;
}
#TextboxEval {
direction: ltr;
}

View file

@ -0,0 +1,111 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
var gConsole, gConsoleBundle, gTextBoxEval, gEvaluator, gCodeToEvaluate;
var gFilter;
/* :::::::: Console Initialization ::::::::::::::: */
window.onload = function()
{
gConsole = document.getElementById("ConsoleBox");
gConsoleBundle = document.getElementById("ConsoleBundle");
gTextBoxEval = document.getElementById("TextboxEval");
gEvaluator = document.getElementById("Evaluator");
gFilter = document.getElementById("Filter");
updateSortCommand(gConsole.sortOrder);
updateModeCommand(gConsole.mode);
gEvaluator.addEventListener("load", loadOrDisplayResult, true);
}
/* :::::::: Console UI Functions ::::::::::::::: */
function changeFilter()
{
gConsole.filter = gFilter.value;
document.persist("ConsoleBox", "filter");
}
function changeMode(aMode)
{
switch (aMode) {
case "Errors":
case "Warnings":
case "Messages":
gConsole.mode = aMode;
break;
case "All":
gConsole.mode = null;
}
document.persist("ConsoleBox", "mode");
}
function clearConsole()
{
gConsole.clear();
}
function changeSortOrder(aOrder)
{
updateSortCommand(gConsole.sortOrder = aOrder);
}
function updateSortCommand(aOrder)
{
var orderString = aOrder == 'reverse' ? "Descend" : "Ascend";
var bc = document.getElementById("Console:sort"+orderString);
bc.setAttribute("checked", true);
orderString = aOrder == 'reverse' ? "Ascend" : "Descend";
bc = document.getElementById("Console:sort"+orderString);
bc.setAttribute("checked", false);
}
function updateModeCommand(aMode)
{
/* aMode can end up invalid if it set by an extension that replaces */
/* mode and then it is uninstalled or disabled */
var bc = document.getElementById("Console:mode" + aMode) ||
document.getElementById("Console:modeAll");
bc.setAttribute("checked", true);
}
function onEvalKeyPress(aEvent)
{
if (aEvent.keyCode == 13)
evaluateTypein();
}
function evaluateTypein()
{
gCodeToEvaluate = gTextBoxEval.value;
// reset the iframe first; the code will be evaluated in loadOrDisplayResult
// below, once about:blank has completed loading (see bug 385092)
gEvaluator.contentWindow.location = "about:blank";
}
function loadOrDisplayResult()
{
if (gCodeToEvaluate) {
gEvaluator.contentWindow.location = "javascript: " +
gCodeToEvaluate.replace(/%/g, "%25");
gCodeToEvaluate = "";
return;
}
var resultRange = gEvaluator.contentDocument.createRange();
resultRange.selectNode(gEvaluator.contentDocument.documentElement);
var result = resultRange.toString();
if (result)
Services.console.logStringMessage(result);
// or could use appendMessage which doesn't persist
}

View file

@ -0,0 +1,101 @@
<?xml version="1.0"?> <!-- -*- tab-width: 4; indent-tabs-mode: nil -*- -->
<!-- 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/. -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://global/skin/console/console.css" type="text/css"?>
<?xml-stylesheet href="chrome://global/content/console.css" type="text/css"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<!DOCTYPE window [
<!ENTITY % console SYSTEM "chrome://global/locale/console.dtd"> %console;
]>
<window id="JSConsoleWindow"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&errorConsole.title;"
windowtype="global:console"
width="640" height="480"
screenX="10" screenY="10"
persist="screenX screenY width height sizemode"
onclose="return closeWindow(false);">
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
<script type="application/javascript" src="chrome://global/content/console.js"/>
<script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>
<stringbundle id="ConsoleBundle" src="chrome://global/locale/console.properties"/>
<commandset id="editMenuCommands"/>
<commandset id="consoleCommands">
<command id="cmd_close" oncommand="closeWindow(true)"/>
</commandset>
<keyset id="consoleKeys">
<key id="key_close" key="&closeCmd.commandkey;" modifiers="accel"
command="cmd_close"/>
<key id="key_close2" keycode="VK_ESCAPE" command="cmd_close"/>
<key id="key_focus1" key="&focus1.commandkey;" modifiers="accel"
oncommand="gTextBoxEval.focus()"/>
<key id="key_focus2" key="&focus2.commandkey;" modifiers="alt"
oncommand="gTextBoxEval.focus()"/>
</keyset>
<popupset id="ContextMenus">
<menupopup id="ConsoleContext">
<menuitem type="radio" id="Console:sortAscend"
label="&sortFirst.label;" accesskey="&sortFirst.accesskey;"
oncommand="changeSortOrder('forward');"/>
<menuitem type="radio" id="Console:sortDescend"
label="&sortLast.label;" accesskey="&sortLast.accesskey;"
oncommand="changeSortOrder('reverse');"/>
<menuseparator/>
<menuitem id="menu_copy_cm" command="cmd_copy"
label="&copyCmd.label;" accesskey="&copyCmd.accesskey;"/>
</menupopup>
</popupset>
<toolbox id="console-toolbox">
<toolbar class="chromeclass-toolbar" id="ToolbarMode">
<hbox id="viewGroup">
<toolbarbutton type="radio" group="mode" id="Console:modeAll"
label="&all.label;" accesskey="&all.accesskey;"
oncommand="changeMode('All');"/>
<toolbarbutton type="radio" group="mode" id="Console:modeErrors"
label="&errors.label;" accesskey="&errors.accesskey;"
oncommand="changeMode('Errors');"/>
<toolbarbutton type="radio" group="mode" id="Console:modeWarnings"
label="&warnings.label;" accesskey="&warnings.accesskey;"
oncommand="changeMode('Warnings');"/>
<toolbarbutton type="radio" group="mode" id="Console:modeMessages"
label="&messages.label;" accesskey="&messages.accesskey;"
oncommand="changeMode('Messages');"/>
</hbox>
<toolbarseparator/>
<toolbarbutton id="Console:clear" oncommand="clearConsole();"
label="&clear.label;" accesskey="&clear.accesskey;"/>
</toolbar>
<toolbar class="chromeclass-toolbar" id="ToolbarEval" align="center" nowindowdrag="true">
<label value="&codeEval.label;" accesskey="&codeEval.accesskey;" control="TextboxEval"/>
<textbox id="TextboxEval" class="toolbar" value="" onkeypress="onEvalKeyPress(event)" flex="1"/>
<toolbarbutton id="ButtonEval" label="&evaluate.label;"
accesskey="&evaluate.accesskey;" oncommand="evaluateTypein()"/>
</toolbar>
</toolbox>
<vbox id="ConsoleBox" class="console-box" flex="1" context="ConsoleContext" persist="sortOrder"/>
<iframe name="Evaluator" id="Evaluator" collapsed="true"/>
<statusbar>
<statusbarpanel flex="1" pack="start">
<label value="&filter2.label;" control="Filter"/>
<textbox accesskey="&filter2.accesskey;" type="search"
id="Filter" oncommand="changeFilter();"/>
</statusbarpanel>
</statusbar>
</window>

View file

@ -0,0 +1,547 @@
<?xml version="1.0"?>
<!-- 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/. -->
<!DOCTYPE bindings SYSTEM "chrome://global/locale/console.dtd">
<bindings id="consoleBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="console-box" extends="xul:box">
<content>
<xul:stringbundle src="chrome://global/locale/console.properties" role="string-bundle"/>
<xul:vbox class="console-box-internal">
<xul:vbox class="console-rows" role="console-rows" xbl:inherits="dir=sortOrder"/>
</xul:vbox>
</content>
<implementation>
<field name="limit" readonly="true">
250
</field>
<field name="fieldMaxLength" readonly="true">
<!-- Limit displayed string lengths to avoid performance issues. (Bug 796179 and 831020) -->
200
</field>
<field name="showChromeErrors" readonly="true">
Services.prefs.getBoolPref("javascript.options.showInConsole");
</field>
<property name="count" readonly="true">
<getter>return this.mCount</getter>
</property>
<property name="mode">
<getter>return this.mMode;</getter>
<setter><![CDATA[
if (this.mode != val) {
this.mMode = val || "All";
this.setAttribute("mode", this.mMode);
this.selectedItem = null;
}
return val;
]]></setter>
</property>
<property name="filter">
<getter>return this.mFilter;</getter>
<setter><![CDATA[
val = val.toLowerCase();
if (this.mFilter != val) {
this.mFilter = val;
for (let aRow of this.mConsoleRowBox.children) {
this.filterElement(aRow);
}
}
return val;
]]></setter>
</property>
<property name="sortOrder">
<getter>return this.getAttribute("sortOrder");</getter>
<setter>this.setAttribute("sortOrder", val); return val;</setter>
</property>
<field name="mSelectedItem">null</field>
<property name="selectedItem">
<getter>return this.mSelectedItem</getter>
<setter><![CDATA[
if (this.mSelectedItem)
this.mSelectedItem.removeAttribute("selected");
this.mSelectedItem = val;
if (val)
val.setAttribute("selected", "true");
// Update edit commands
window.updateCommands("focus");
return val;
]]></setter>
</property>
<method name="init">
<body><![CDATA[
this.mCount = 0;
this.mConsoleListener = {
console: this,
observe : function(aObject) {
// The message can arrive a little bit after the xbl binding has been
// unbind. So node.appendItem will not be available anymore.
if ('appendItem' in this.console)
this.console.appendItem(aObject);
}
};
this.mConsoleRowBox = document.getAnonymousElementByAttribute(this, "role", "console-rows");
this.mStrBundle = document.getAnonymousElementByAttribute(this, "role", "string-bundle");
try {
Services.console.registerListener(this.mConsoleListener);
} catch (ex) {
appendItem(
"Unable to display errors - couldn't get Console Service component. " +
"(Missing @mozilla.org/consoleservice;1)");
return;
}
this.mMode = this.getAttribute("mode") || "All";
this.mFilter = "";
this.appendInitialItems();
window.controllers.insertControllerAt(0, this._controller);
]]></body>
</method>
<method name="destroy">
<body><![CDATA[
Services.console.unregisterListener(this.mConsoleListener);
window.controllers.removeController(this._controller);
]]></body>
</method>
<method name="appendInitialItems">
<body><![CDATA[
var messages = Services.console.getMessageArray();
// In case getMessageArray returns 0-length array as null
if (!messages)
messages = [];
var limit = messages.length - this.limit;
if (limit < 0) limit = 0;
// Checks if console ever been cleared
for (var i = messages.length - 1; i >= limit; --i)
if (!messages[i].message)
break;
// Populate with messages after latest "clear"
while (++i < messages.length)
this.appendItem(messages[i]);
]]></body>
</method>
<method name="appendItem">
<parameter name="aObject"/>
<body><![CDATA[
try {
// Try to QI it to a script error to get more info
var scriptError = aObject.QueryInterface(Components.interfaces.nsIScriptError);
// filter chrome urls
if (!this.showChromeErrors && scriptError.sourceName.substr(0, 9) == "chrome://")
return;
// filter private windows
if (scriptError.isFromPrivateWindow)
return;
this.appendError(scriptError);
} catch (ex) {
try {
// Try to QI it to a console message
var msg = aObject.QueryInterface(Components.interfaces.nsIConsoleMessage);
if (msg.message)
this.appendMessage(msg.message);
else // observed a null/"clear" message
this.clearConsole();
} catch (ex2) {
// Give up and append the object itself as a string
this.appendMessage(aObject);
}
}
]]></body>
</method>
<method name="_truncateIfNecessary">
<parameter name="aString"/>
<parameter name="aMiddleCharacter"/>
<body><![CDATA[
if (!aString || aString.length <= this.fieldMaxLength)
return {string: aString, column: aMiddleCharacter};
let halfLimit = this.fieldMaxLength / 2;
if (!aMiddleCharacter || aMiddleCharacter < 0 || aMiddleCharacter > aString.length)
aMiddleCharacter = halfLimit;
let startPosition = 0;
let endPosition = aString.length;
if (aMiddleCharacter - halfLimit >= 0)
startPosition = aMiddleCharacter - halfLimit;
if (aMiddleCharacter + halfLimit <= aString.length)
endPosition = aMiddleCharacter + halfLimit;
if (endPosition - startPosition < this.fieldMaxLength)
endPosition += this.fieldMaxLength - (endPosition - startPosition);
let truncatedString = aString.substring(startPosition, endPosition);
let Ci = Components.interfaces;
let ellipsis = Services.prefs.getComplexValue("intl.ellipsis",
Ci.nsIPrefLocalizedString).data;
if (startPosition > 0) {
truncatedString = ellipsis + truncatedString;
aMiddleCharacter += ellipsis.length;
}
if (endPosition < aString.length)
truncatedString = truncatedString + ellipsis;
return {
string: truncatedString,
column: aMiddleCharacter - startPosition
};
]]></body>
</method>
<method name="appendError">
<parameter name="aObject"/>
<body><![CDATA[
var row = this.createConsoleRow();
var nsIScriptError = Components.interfaces.nsIScriptError;
// Is this error actually just a non-fatal warning?
var warning = aObject.flags & nsIScriptError.warningFlag != 0;
var typetext = warning ? "typeWarning" : "typeError";
row.setAttribute("typetext", this.mStrBundle.getString(typetext));
row.setAttribute("type", warning ? "warning" : "error");
row.setAttribute("msg", aObject.errorMessage);
row.setAttribute("category", aObject.category);
row.setAttribute("time", this.properFormatTime(aObject.timeStamp));
if (aObject.lineNumber || aObject.sourceName) {
row.setAttribute("href", this._truncateIfNecessary(aObject.sourceName).string);
row.mSourceName = aObject.sourceName;
row.setAttribute("line", aObject.lineNumber);
} else {
row.setAttribute("hideSource", "true");
}
if (aObject.sourceLine) {
let sourceLine = aObject.sourceLine.replace(/\s/g, " ");
let truncatedLineObj = this._truncateIfNecessary(sourceLine, aObject.columnNumber);
row.setAttribute("code", truncatedLineObj.string);
row.mSourceLine = sourceLine;
if (aObject.columnNumber) {
row.setAttribute("col", aObject.columnNumber);
row.setAttribute("errorDots", this.repeatChar(" ", truncatedLineObj.column));
row.setAttribute("errorCaret", " ");
} else {
row.setAttribute("hideCaret", "true");
}
} else {
row.setAttribute("hideCode", "true");
}
this.appendConsoleRow(row);
]]></body>
</method>
<method name="appendMessage">
<parameter name="aMessage"/>
<parameter name="aType"/>
<body><![CDATA[
var row = this.createConsoleRow();
row.setAttribute("type", aType || "message");
row.setAttribute("msg", aMessage);
this.appendConsoleRow(row);
]]></body>
</method>
<method name="clear">
<body><![CDATA[
// add a "clear" message (mainly for other listeners)
Services.console.logStringMessage(null);
Services.console.reset();
]]></body>
</method>
<method name="properFormatTime">
<parameter name="aTime"/>
<body><![CDATA[
const dateServ = Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
.getService(Components.interfaces.nsIScriptableDateFormat);
let errorTime = new Date(aTime);
return dateServ.FormatDateTime("", dateServ.dateFormatShort, dateServ.timeFormatSeconds,
errorTime.getFullYear(), errorTime.getMonth() + 1, errorTime.getDate(),
errorTime.getHours(), errorTime.getMinutes(), errorTime.getSeconds());
]]></body>
</method>
<method name="copySelectedItem">
<body><![CDATA[
if (this.mSelectedItem) try {
const clipURI = "@mozilla.org/widget/clipboardhelper;1";
const clipI = Components.interfaces.nsIClipboardHelper;
var clipboard = Components.classes[clipURI].getService(clipI);
clipboard.copyString(this.mSelectedItem.toString(), document);
} catch (ex) {
// Unable to copy anything, die quietly
}
]]></body>
</method>
<method name="createConsoleRow">
<body><![CDATA[
var row = document.createElement("box");
row.setAttribute("class", "console-row");
row._IsConsoleRow = true;
row._ConsoleBox = this;
return row;
]]></body>
</method>
<method name="appendConsoleRow">
<parameter name="aRow"/>
<body><![CDATA[
this.filterElement(aRow);
this.mConsoleRowBox.appendChild(aRow);
if (++this.mCount > this.limit) this.deleteFirst();
]]></body>
</method>
<method name="deleteFirst">
<body><![CDATA[
var node = this.mConsoleRowBox.firstChild;
this.mConsoleRowBox.removeChild(node);
--this.mCount;
]]></body>
</method>
<method name="clearConsole">
<body><![CDATA[
if (this.mCount == 0) // already clear
return;
this.mCount = 0;
var newRows = this.mConsoleRowBox.cloneNode(false);
this.mConsoleRowBox.parentNode.replaceChild(newRows, this.mConsoleRowBox);
this.mConsoleRowBox = newRows;
this.selectedItem = null;
]]></body>
</method>
<method name="filterElement">
<parameter name="aRow" />
<body><![CDATA[
let anyMatch = ["msg", "line", "code"].some(function (key) {
return (aRow.hasAttribute(key) &&
this.stringMatchesFilters(aRow.getAttribute(key), this.mFilter));
}, this) || (aRow.mSourceName &&
this.stringMatchesFilters(aRow.mSourceName, this.mFilter));
if (anyMatch) {
aRow.classList.remove("filtered-by-string")
} else {
aRow.classList.add("filtered-by-string")
}
]]></body>
</method>
<!-- UTILITY FUNCTIONS -->
<method name="repeatChar">
<parameter name="aChar"/>
<parameter name="aCol"/>
<body><![CDATA[
if (--aCol <= 0)
return "";
for (var i = 2; i < aCol; i += i)
aChar += aChar;
return aChar + aChar.slice(0, aCol - aChar.length);
]]></body>
</method>
<method name="stringMatchesFilters">
<parameter name="aString"/>
<parameter name="aFilter"/>
<body><![CDATA[
if (!aString || !aFilter) {
return true;
}
let searchStr = aString.toLowerCase();
let filterStrings = aFilter.split(/\s+/);
return !filterStrings.some(function (f) {
return searchStr.indexOf(f) == -1;
});
]]></body>
</method>
<constructor> this.init(); </constructor>
<destructor> this.destroy(); </destructor>
<!-- Command controller for the copy command -->
<field name="_controller"><![CDATA[({
_outer: this,
QueryInterface: function(aIID) {
if (aIID.equals(Components.interfaces.nsIController) ||
aIID.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_NOINTERFACE;
},
supportsCommand: function(aCommand) {
return aCommand == "cmd_copy";
},
isCommandEnabled: function(aCommand) {
return aCommand == "cmd_copy" && this._outer.selectedItem;
},
doCommand: function(aCommand) {
if (aCommand == "cmd_copy")
this._outer.copySelectedItem();
},
onEvent: function() { }
});]]></field>
</implementation>
<handlers>
<handler event="mousedown"><![CDATA[
if (event.button == 0 || event.button == 2) {
var target = event.originalTarget;
while (target && !("_IsConsoleRow" in target))
target = target.parentNode;
if (target)
this.selectedItem = target;
}
]]></handler>
</handlers>
</binding>
<binding id="error" extends="xul:box">
<content>
<xul:box class="console-row-internal-box" flex="1">
<xul:box class="console-row-icon" align="center" xbl:inherits="selected">
<xul:image class="console-icon" xbl:inherits="src,type"/>
</xul:box>
<xul:vbox class="console-row-content" xbl:inherits="selected" flex="1">
<xul:box class="console-row-msg" align="start">
<xul:label class="label" xbl:inherits="value=typetext"/>
<xul:description class="console-error-msg" xbl:inherits="xbl:text=msg" flex="1"/>
<xul:label class="label console-time" xbl:inherits="value=time"/>
</xul:box>
<xul:box class="console-row-file" xbl:inherits="hidden=hideSource">
<xul:label class="label" value="&errFile.label;"/>
<xul:box class="console-error-source" xbl:inherits="href,line"/>
<xul:spacer flex="1"/>
<xul:hbox class="lineNumberRow" xbl:inherits="line">
<xul:label class="label" value="&errLine.label;"/>
<xul:label class="label" xbl:inherits="value=line"/>
</xul:hbox>
</xul:box>
<xul:vbox class="console-row-code" xbl:inherits="selected,hidden=hideCode">
<xul:label class="monospace console-code" xbl:inherits="value=code" crop="end"/>
<xul:box xbl:inherits="hidden=hideCaret">
<xul:label class="monospace console-dots" xbl:inherits="value=errorDots"/>
<xul:label class="monospace console-caret" xbl:inherits="value=errorCaret"/>
<xul:spacer flex="1"/>
</xul:box>
</xul:vbox>
</xul:vbox>
</xul:box>
</content>
<implementation>
<field name="mSourceName">null</field>
<field name="mSourceLine">null</field>
<method name="toString">
<body><![CDATA[
let msg = "";
let strBundle = this._ConsoleBox.mStrBundle;
if (this.hasAttribute("time"))
msg += strBundle.getFormattedString("errTime", [this.getAttribute("time")]) + "\n";
msg += this.getAttribute("typetext") + " " + this.getAttribute("msg");
if (this.hasAttribute("line") && this.mSourceName) {
msg += "\n" + strBundle.getFormattedString("errFile",
[this.mSourceName]) + "\n";
if (this.hasAttribute("col")) {
msg += strBundle.getFormattedString("errLineCol",
[this.getAttribute("line"), this.getAttribute("col")]);
} else
msg += strBundle.getFormattedString("errLine", [this.getAttribute("line")]);
}
if (this.hasAttribute("code"))
msg += "\n" + strBundle.getString("errCode") + "\n" + this.mSourceLine;
return msg;
]]></body>
</method>
</implementation>
</binding>
<binding id="message" extends="xul:box">
<content>
<xul:box class="console-internal-box" flex="1">
<xul:box class="console-row-icon" align="center">
<xul:image class="console-icon" xbl:inherits="src,type"/>
</xul:box>
<xul:vbox class="console-row-content" xbl:inherits="selected" flex="1">
<xul:vbox class="console-row-msg" flex="1">
<xul:description class="console-msg-text" xbl:inherits="xbl:text=msg"/>
</xul:vbox>
</xul:vbox>
</xul:box>
</content>
<implementation>
<method name="toString">
<body><![CDATA[
return this.getAttribute("msg");
]]></body>
</method>
</implementation>
</binding>
<binding id="console-error-source" extends="xul:box">
<content>
<xul:label class="text-link" xbl:inherits="value=href" crop="right"/>
</content>
<handlers>
<handler event="click" phase="capturing" button="0" preventdefault="true">
<![CDATA[
var url = document.getBindingParent(this).mSourceName;
url = url.substring(url.lastIndexOf(" ") + 1);
var line = getAttribute("line");
gViewSourceUtils.viewSource(url, null, null, line);
]]>
</handler>
</handlers>
</binding>
</bindings>

View file

@ -0,0 +1,9 @@
# 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/.
toolkit.jar:
content/global/console.js (content/console.js)
content/global/console.xul (content/console.xul)
content/global/console.css (content/console.css)
content/global/consoleBindings.xml (content/consoleBindings.xml)

View file

@ -0,0 +1,40 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
/* vim:sw=4:sr:sta:et:sts: */
/* 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/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function jsConsoleHandler() {}
jsConsoleHandler.prototype = {
handle: function clh_handle(cmdLine) {
if (!cmdLine.handleFlag("jsconsole", false))
return;
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
var console = wm.getMostRecentWindow("global:console");
if (!console) {
var wwatch = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
wwatch.openWindow(null, "chrome://global/content/console.xul", "_blank",
"chrome,dialog=no,all", cmdLine);
} else {
console.focus(); // the Error console was already open
}
if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO)
cmdLine.preventDefault = true;
},
helpInfo : " -jsconsole Open the Error console.\n",
classID: Components.ID("{2cd0c310-e127-44d0-88fc-4435c9ab4d4b}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([jsConsoleHandler]);

View file

@ -0,0 +1,3 @@
component {2cd0c310-e127-44d0-88fc-4435c9ab4d4b} jsconsole-clhandler.js
contract @mozilla.org/toolkit/console-clh;1 {2cd0c310-e127-44d0-88fc-4435c9ab4d4b}
category command-line-handler b-jsconsole @mozilla.org/toolkit/console-clh;1

View file

@ -0,0 +1,14 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
EXTRA_COMPONENTS += [
'jsconsole-clhandler.js',
'jsconsole-clhandler.manifest',
]
JAR_MANIFESTS += ['jar.mn']

View file

@ -0,0 +1,3 @@
[DEFAULT]
[test_hugeURIs.xul]

View file

@ -0,0 +1,64 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=796179
-->
<window title="Mozilla Bug 796179"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="RunTest();">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- Detect severe performance and memory issues when large amounts of errors
are reported from CSS embedded in a file with a long data URI. Addressed
by 786108 for issues internal to the style system and by 796179 for issues
related to the error console. This error console test should finish quickly
with those patches and run for a very long time or OOM otherwise. -->
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=796179"
target="_blank">Mozilla Bug 796179</a>
<div id="badSVG" style="max-width: 1; max-height: 1; overflow: hidden"></div>
</body>
<!-- display the error console so we can test its reaction to the test -->
<iframe id="errorConsoleFrame" height="400" src="chrome://global/content/console.xul"></iframe>
<!-- test code -->
<script type="application/javascript">
<![CDATA[
function RunTest()
{
// Create the bad SVG and add it to the document.
var img = new Array;
img.push('<img src="data:image/svg+xml,');
img.push(encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="300px">'));
for (var i = 0 ; i < 10000 ; i++)
img.push(encodeURIComponent('<circle cx="0" cy="0" r="1" style="xxx-invalid-property: 0;"/>'));
img.push(encodeURIComponent('</svg>'));
img.push('" />');
document.getElementById('badSVG').innerHTML = img.join('');
// We yield control of the thread, allowing the error console to render.
// If we get control back without timing out or OOMing then the test passed.
SimpleTest.waitForExplicitFinish();
SimpleTest.executeSoon(function() {
// Clean up.
var elem = document.getElementById('errorConsoleFrame');
elem.parentNode.removeChild(elem);
elem = document.getElementById('badSVG');
elem.parentNode.removeChild(elem);
elem = null;
// Finish the test with a pass.
ok(true, 'Error console rendered OK.');
SimpleTest.finish();
}, 0);
}
]]>
</script>
</window>

View file

@ -18,6 +18,7 @@ DIRS += [
'apppicker',
'asyncshutdown',
'commandlines',
'console',
'contentprefs',
'contextualidentity',
'cookie',