Bug 492883: Add JavaScript error console to Fennec, r=mfinkle

This commit is contained in:
Nino D'Aversa 2009-06-09 13:55:14 -04:00
Родитель d8cade19c2
Коммит cfe5199c2e
16 изменённых файлов: 406 добавлений и 4 удалений

Просмотреть файл

@ -176,9 +176,9 @@ pref("browser.xul.error_pages.expert_bad_cert", false);
// disable logging for the search service by default
pref("browser.search.log", false);
// Ordering of Search Engines in the Engine list.
pref("browser.search.order.1", "chrome://browser/locale/region.properties");
pref("browser.search.order.2", "chrome://browser/locale/region.properties");
// ordering of search engines in the engine list.
pref("browser.search.order.1", "chrome://browser/locale/region.properties");
pref("browser.search.order.2", "chrome://browser/locale/region.properties");
// disable updating
pref("browser.search.update", false);
@ -191,7 +191,7 @@ pref("browser.search.suggest.enabled", true);
// enable xul error pages
pref("browser.xul.error_pages.enabled", true);
// Various and sundry awesomebar prefs (should remove/re-evaluate
// various and sundry awesomebar prefs (should remove/re-evaluate
// these once bug 447900 is fixed)
pref("browser.urlbar.clickSelectsAll", true);
pref("browser.urlbar.doubleClickSelectsAll", false);
@ -292,3 +292,5 @@ pref("javascript.options.jit.chrome", true);
pref("dom.max_chrome_script_run_time", 30);
pref("dom.max_script_run_time", 20);
// JS error console
pref("browser.console.showInPanel", true);

Просмотреть файл

@ -0,0 +1,57 @@
<?xml version="1.0"?>
<!DOCTYPE bindings [
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
%browserDTD;
]>
<bindings
xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="error" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
<content orient="vertical">
<xul:hbox class="console-row-internal-box" flex="1">
<xul:vbox class="console-row-content" flex="1">
<xul:hbox class="console-row-msg" align="start">
<xul:label class="label title" xbl:inherits="value=typetext"/>
<xul:description class="console-error-msg title" xbl:inherits="xbl:text=msg" flex="1"/>
</xul:hbox>
<xul:hbox class="console-row-file" xbl:inherits="hidden=hideSource">
<xul:label class="label title" value="&consoleErrFile.label;"/>
<xul:label class="title" xbl:inherits="value=href" crop="right"/>
<xul:spacer flex="1"/>
<xul:hbox class="lineNumberRow" xbl:inherits="line">
<xul:label class="label title" value="&consoleErrLine.label;"/>
<xul:label class="label title" xbl:inherits="value=line"/>
</xul:hbox>
</xul:hbox>
<xul:vbox class="console-row-code" xbl:inherits="hidden=hideCode">
<xul:label class="monospace console-code" xbl:inherits="value=code" crop="end"/>
<xul:hbox xbl:inherits="hidden=hideCaret">
<xul:label class="monospace console-dots title" xbl:inherits="value=errorDots"/>
<xul:label class="monospace console-caret title" xbl:inherits="value=errorCaret"/>
<xul:spacer flex="1"/>
</xul:hbox>
</xul:vbox>
</xul:vbox>
</xul:hbox>
</content>
</binding>
<binding id="message" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
<content>
<xul:hbox class="console-internal-box" flex="1">
<xul:vbox class="console-row-content" flex="1">
<xul:vbox class="console-row-msg" flex="1">
<xul:description class="console-msg-text title" xbl:inherits="xbl:text=msg"/>
</xul:vbox>
</xul:vbox>
</xul:hbox>
</content>
</binding>
</bindings>

Просмотреть файл

@ -184,3 +184,12 @@ richlistitem[opType="needs-enable"] .hide-on-enable,
richlistitem[opType="needs-disable"] .hide-on-disable {
display: none;
}
richlistitem[type="error"],
richlistitem[type="warning"] {
-moz-binding: url("chrome://browser/content/bindings/console.xml#error");
}
richlistitem[type="message"]{
-moz-binding: url("chrome://browser/content/bindings/console.xml#message");
}

Просмотреть файл

@ -237,6 +237,12 @@ var Browser = {
if (whereURI)
this.addTab(whereURI, true);
}
// JavaScript Error Console
if (gPrefService.getBoolPref("browser.console.showInPanel")){
let tool_console = document.getElementById("tool-console");
tool_console.hidden = false;
}
// Re-enable plugins if we had previously disabled them. We should get rid of
// this code eventually...

Просмотреть файл

@ -41,6 +41,7 @@
<?xml-stylesheet href="chrome://browser/skin/platform.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/console.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
@ -77,6 +78,7 @@
<script type="application/x-javascript" src="chrome://browser/content/sanitize.js"/>
<script type="application/x-javascript" src="chrome://browser/content/extensions.js"/>
<script type="application/x-javascript" src="chrome://browser/content/downloads.js"/>
<script type="application/x-javascript" src="chrome://browser/content/console.js"/>
<script type="application/x-javascript" src="chrome://browser/content/WidgetStack.js"/>
<script type="application/x-javascript" src="chrome://browser/content/CanvasBrowser.js"/>
<script type="application/x-javascript" src="chrome://browser/content/InputHandler.js"/>
@ -297,6 +299,7 @@
<hbox id="panel-container" hidden="true" class="panel-dark" top="0" left="0">
<vbox id="panel-controls" oncommand="BrowserUI.switchPane(event.target.getAttribute('linkedpanel'));">
<toolbarspring/>
<toolbarbutton id="tool-console" type="radio" group="1" hidden="true" class="panel-button button-image" linkedpanel="console-container" oncommand="ConsoleView.init();"/>
<toolbarbutton id="tool-addons" type="radio" group="1" class="panel-button button-image" linkedpanel="addons-container"/>
<toolbarbutton id="tool-downloads" type="radio" group="1" class="panel-button button-image" linkedpanel="downloads-container"/>
<toolbarbutton id="tool-preferences" type="radio" group="1" checked="true" class="panel-button button-image" linkedpanel="prefs-container"/>
@ -378,6 +381,30 @@
</richpref>
</richlistbox>
</vbox>
<vbox id="console-container" flex="1">
<vbox id="console-header" class="panel-header">
<hbox align="center">
<label value="&consoleHeader.label;" flex="1"/>
<radiogroup id="console-filter" class="toggle-dark" oncommand="ConsoleView.changeMode();">
<radio label="&consoleAll.label;" value="all" selected="true"/>
<radio label="&consoleErrors.label;" value="error"/>
<radio label="&consoleWarnings.label;" value="warning"/>
<radio label="&consoleMessages.label;" value="message"/>
</radiogroup>
<button id="console-clear" class="button-dark show-text" oncommand="ConsoleView.clearConsole();" label="&consoleClear.label;"/>
</hbox>
<hbox align="center">
<label value="&consoleCodeEval.label;" control="console-eval-textbox"/>
<textbox id="console-eval-textbox" class="toolbar" value="" onkeypress="ConsoleView.onEvalKeyPress(event)" flex="1"/>
<button id="console-button-eval" class="button-dark show-text" label="&consoleEvaluate.label;" oncommand="ConsoleView.evaluateTypein()"/>
</hbox>
</vbox>
<richlistbox id="console-box" class="console-box" flex="1"/>
<iframe name="console-evaluator" id="console-evaluator" collapsed="true"/>
</vbox>
</deck>
</hbox>

Просмотреть файл

@ -0,0 +1,267 @@
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Mobile Browser.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Nino D'Aversa <ninodaversa@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
let ConsoleView = {
_list: null,
_evalTextbox: null,
_evalFrame: null,
_evalCode: "",
_bundle: null,
_showChromeErrors: -1,
init: function cv_init() {
if (this._list)
return;
this._list = document.getElementById("console-box");
this._evalTextbox = document.getElementById("console-eval-textbox");
this._evalFrame = document.getElementById("console-evaluator");
this._bundle = document.getElementById("bundle_browser");
this._count = 0;
this.limit = 250;
this._console = Cc['@mozilla.org/consoleservice;1'].getService(Ci.nsIConsoleService);
this._console.registerListener(this);
this.appendInitialItems();
let self = this;
this._evalFrame.addEventListener("load", function() { self.loadOrDisplayResult(); }, true);
},
observe : function(aObject) {
this.appendItem(aObject);
},
showChromeErrors: function() {
if (this._showChromeErrors != -1)
return this._showChromeErrors;
let pref = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefBranch);
try {
return this._showChromeErrors = pref.getBoolPref("javascript.options.showInConsole");
}
catch(ex) {
return this._showChromeErrors = false;
}
},
appendItem: function cv_appendItem(aObject) {
try {
// Try to QI it to a script error to get more info
let scriptError = aObject.QueryInterface(Ci.nsIScriptError);
// filter chrome urls
if (!this.showChromeErrors && scriptError.sourceName.substr(0, 9) == "chrome://")
return;
this.appendError(scriptError);
}
catch (ex) {
try {
// Try to QI it to a console message
let msg = aObject.QueryInterface(Ci.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);
}
}
},
appendError: function cv_appendError(aObject) {
let row = this.createConsoleRow();
let nsIScriptError = Ci.nsIScriptError;
// Is this error actually just a non-fatal warning?
let warning = aObject.flags & nsIScriptError.warningFlag != 0;
let typetext = warning ? "typeWarning" : "typeError";
row.setAttribute("typetext", this._bundle.getString(typetext));
row.setAttribute("type", warning ? "warning" : "error");
row.setAttribute("msg", aObject.errorMessage);
row.setAttribute("category", aObject.category);
if (aObject.lineNumber || aObject.sourceName) {
row.setAttribute("href", aObject.sourceName);
row.setAttribute("line", aObject.lineNumber);
}
else {
row.setAttribute("hideSource", "true");
}
if (aObject.sourceLine) {
row.setAttribute("code", aObject.sourceLine.replace(/\s/g, " "));
if (aObject.columnNumber) {
row.setAttribute("col", aObject.columnNumber);
row.setAttribute("errorDots", this.repeatChar(" ", aObject.columnNumber));
row.setAttribute("errorCaret", " ");
}
else {
row.setAttribute("hideCaret", "true");
}
}
else {
row.setAttribute("hideCode", "true");
}
let mode = document.getElementById("console-filter").value;
if (mode != "all" && mode != row.getAttribute("type"))
row.collapsed = true;
this.appendConsoleRow(row);
},
appendMessage: function cv_appendMessage (aMessage) {
let row = this.createConsoleRow();
row.setAttribute("type", "message");
row.setAttribute("msg", aMessage);
let mode = document.getElementById("console-filter").value
if (mode != "all" && mode != "message")
row.collapsed = false;
this.appendConsoleRow(row);
},
createConsoleRow: function cv_createConsoleRow() {
let row = document.createElement("richlistitem");
row.setAttribute("class", "console-row");
return row;
},
appendConsoleRow: function cv_appendConsoleRow(aRow) {
this._list.appendChild(aRow);
if (++this._count > this.limit)
this.deleteFirst();
},
deleteFirst: function cv_deleteFirst() {
let node = this._list.firstChild;
this._list.removeChild(node);
--this._count;
},
appendInitialItems: function cv_appendInitialItems() {
let out = {}; // Throwaway references to support 'out' parameters.
this._console.getMessageArray(out, {});
let messages = out.value;
// In case getMessageArray returns 0-length array as null
if (!messages)
messages = [];
let 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]);
},
clearConsole: function cv_clearConsole() {
if (this._count == 0) // already clear
return;
this._count = 0;
let newRows = this._list.cloneNode(false);
this._list.parentNode.replaceChild(newRows, this._list);
this._list = newRows;
this.selectedItem = null;
},
changeMode: function cv_changeMode() {
let mode = document.getElementById("console-filter").value;
if (this._list.getAttribute("mode") != mode) {
let rows = this._list.childNodes;
for (let i=0; i < rows.length; i++) {
let row = rows[i];
if (mode == "all" || row.getAttribute ("type") == mode)
row.collapsed = false;
else
row.collapsed = true;
}
this._list.mode = mode;
this._list.scrollToIndex(0);
}
},
onEvalKeyPress: function cv_onEvalKeyPress(aEvent) {
if (aEvent.keyCode == 13)
this.evaluateTypein();
},
evaluateTypein: function cv_evaluateTypein() {
this._evalCode = this._evalTextbox.value;
this.loadOrDisplayResult();
},
loadOrDisplayResult: function cv_loadOrDisplayResult() {
if (this._evalCode) {
this._evalFrame.contentWindow.location = "javascript: " + this._evalCode.replace(/%/g, "%25");
this._evalCode = "";
return;
}
let resultRange = this._evalFrame.contentDocument.createRange();
resultRange.selectNode(this._evalFrame.contentDocument.documentElement);
let result = resultRange.toString();
if (result)
this._console.logStringMessage(result);
// or could use appendMessage which doesn't persist
},
repeatChar: function cv_repeatChar(aChar, aCol) {
if (--aCol <= 0)
return "";
for (let i = 2; i < aCol; i += i)
aChar += aChar;
return aChar + aChar.slice(0, aCol - aChar.length);
}
};

Просмотреть файл

@ -12,6 +12,7 @@ browser.jar:
content/notification.xml (content/notification.xml)
content/bindings/extensions.xml (content/bindings/extensions.xml)
content/bindings/downloads.xml (content/bindings/downloads.xml)
content/bindings/console.xml (content/bindings/console.xml)
content/browser.css (content/browser.css)
content/scrollbars.css (content/scrollbars.css)
content/content.css (content/content.css)
@ -25,3 +26,4 @@ browser.jar:
content/InputHandler.js (content/InputHandler.js)
content/extensions.js (content/extensions.js)
content/downloads.js (content/downloads.js)
content/console.js (content/console.js)

Просмотреть файл

@ -89,3 +89,15 @@
with that structure, consider a translation which ignores the preceding domain and
just addresses the organization to follow, e.g. "This site is run by " -->
<!ENTITY identity.runBy2 "run by">
<!ENTITY consoleHeader.label "Error Console">
<!ENTITY consoleAll.label "All">
<!ENTITY consoleErrors.label "Errors">
<!ENTITY consoleWarnings.label "Warnings">
<!ENTITY consoleMessages.label "Messages">
<!ENTITY consoleCodeEval.label "Code:">
<!ENTITY consoleClear.label "Clear">
<!ENTITY consoleEvaluate.label "Evaluate">
<!ENTITY consoleErrFile.label "Source File:">
<!ENTITY consoleErrLine.label "Line:">
<!ENTITY consoleErrColumn.label "Column:">

Просмотреть файл

@ -66,3 +66,7 @@ geolocation.share.accessKey=a
geolocation.dontShare=Don't share
geolocation.dontShare.accessKey=o
geolocation.siteWantsToKnow=%S wants your location.
# Error Console
typeError=Error:
typeWarning=Warning:

Просмотреть файл

@ -278,6 +278,15 @@ toolbarbutton.page-button {
list-style-image: url("chrome://browser/skin/images/preferences-active-64.png");
}
#tool-console {
list-style-image: url("chrome://browser/skin/images/console-default-64.png");
}
#tool-console:hover:active,
#tool-console[checked="true"] {
list-style-image: url("chrome://browser/skin/images/console-active-64.png");
}
/* URL List and autocomplete navigation popup ------------------------------ */
#tool-bookmarks-close,
#tool-folders-close {

Двоичные данные
mobile/themes/hildon/images/console-active-64.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
mobile/themes/hildon/images/console-default-64.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.7 KiB

Просмотреть файл

@ -41,6 +41,8 @@ classic.jar:
images/settings-active-64.png (images/settings-active-64.png)
images/preferences-default-64.png (images/preferences-default-64.png)
images/preferences-active-64.png (images/preferences-active-64.png)
images/console-default-64.png (images/console-default-64.png)
images/console-active-64.png (images/console-active-64.png)
images/newtab-default-64.png (images/newtab-default-64.png)
images/newtab-active-64.png (images/newtab-active-64.png)
images/leftcap-default-64.png (images/leftcap-default-64.png)

Просмотреть файл

@ -272,6 +272,10 @@ toolbarbutton.page-button {
list-style-image: url("chrome://browser/skin/images/preferences-24.png");
}
#tool-console {
list-style-image: url("chrome://browser/skin/images/console-24.png");
}
/* URL List and autocomplete navigation popup ------------------------------ */
#tool-bookmarks-close,
#tool-folders-close {

Двоичные данные
mobile/themes/wince/images/console-24.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 483 B

Просмотреть файл

@ -24,6 +24,7 @@ classic.jar:
images/addons-24.png (images/addons-24.png)
images/downloads-24.png (images/downloads-24.png)
images/preferences-24.png (images/preferences-24.png)
images/console-24.png (images/console-24.png)
images/settings-24.png (images/settings-24.png)
images/back-24.png (images/back-24.png)
images/back-disabled-24.png (images/back-disabled-24.png)