gecko/toolkit/components/console/content/consoleBindings.xml

548 lines
19 KiB
XML

<?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>