mirror of https://github.com/roytam1/kmeleon.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
862 lines
27 KiB
862 lines
27 KiB
<?xml version="1.0"?> |
|
|
|
<!DOCTYPE bindings SYSTEM "chrome://console2/locale/console2.dtd"> |
|
|
|
<bindings id="console2Bindings" 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"> |
|
|
|
<!-- ######################## Console Box ######################## --> |
|
|
|
<binding id="console" extends="chrome://console2/content/global/richlistbox.xml#richlistbox"> |
|
<content console2themeable="true"> |
|
<xul:scrollbox allowevents="true" orient="vertical" anonid="main-box" flex="1" style="overflow: auto;"> |
|
<children/> |
|
</xul:scrollbox> |
|
<xul:stringbundle src="chrome://console2/locale/console2.properties" anonid="string-bundle"/> |
|
</content> |
|
|
|
<implementation implements="nsIConsoleListener"> |
|
<field name="mCService" readonly="true">Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService)</field> |
|
<field name="mListeners" readonly="true">[]</field> |
|
<field name="mMsgQueue" readonly="true">[]</field> |
|
<field name="mDupeCache">null</field> |
|
<field name="mPrefs" readonly="true">Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch2);</field> |
|
<field name="_limit">1000</field> |
|
|
|
<property name="reversed" onget="return this.sortOrder == 'reverse';" readonly="true"/> |
|
<property name="count" onget="return this.childNodes.length;" readonly="true"/> |
|
|
|
<property name="dupes" onget="return this.getAttribute('dupes') != 'false';"> |
|
<setter><![CDATA[ |
|
if (!val) |
|
{ |
|
this.setAttribute("dupes", "false"); |
|
} |
|
else |
|
{ |
|
this.removeAttribute("dupes"); |
|
} |
|
return val; |
|
]]></setter> |
|
</property> |
|
|
|
<property name="timestamps" onget="return this.getAttribute('timestamps') != 'false';"> |
|
<setter><![CDATA[ |
|
if (!val) |
|
{ |
|
this.setAttribute("timestamps", "false"); |
|
} |
|
else |
|
{ |
|
this.removeAttribute("timestamps"); |
|
} |
|
return val; |
|
]]></setter> |
|
</property> |
|
|
|
<property name="sortOrder" onget="return this.getAttribute('sortOrder');"> |
|
<setter><![CDATA[ |
|
if (this.reversed != (val == "reverse")) |
|
{ |
|
this.reverseRows(); |
|
this.setAttribute("sortOrder", val); |
|
} |
|
return val; |
|
]]></setter> |
|
</property> |
|
|
|
<!-- ///////////////// main functionality ///////////////// --> |
|
|
|
<method name="appendInitialItems"> |
|
<body><![CDATA[ |
|
var out = {}; // Mozilla Bug 664695 |
|
var messages = this.mCService.getMessageArray(out, {}) || out.value || []; |
|
|
|
// go back to the latest "Clear" marker |
|
var limit = Math.max(messages.length - this._limit, 0); |
|
for (var i = messages.length - 1; i >= limit && messages[i].message; i--); |
|
|
|
while (++i < messages.length) |
|
{ |
|
this.appendItem(messages[i]); |
|
} |
|
]]></body> |
|
</method> |
|
|
|
<method name="observe"> |
|
<parameter name="aMessage"/> |
|
<body><![CDATA[ |
|
try |
|
{ |
|
this.mMsgQueue.push(aMessage); |
|
if (this.mMsgQueue.length == 1) |
|
{ |
|
setTimeout(function(c) { c.observe_process(); }, 0, this); |
|
} |
|
} |
|
catch (ex) { } |
|
]]></body> |
|
</method> |
|
|
|
<method name="observe_process"> |
|
<body><![CDATA[ |
|
try |
|
{ // prevent a DoS by processing a maximum of 10 items without interruption |
|
for (var i = Math.min(this.mMsgQueue.length, 10); i > 0; i--) |
|
{ |
|
this.observe_delayed(this.mMsgQueue.shift()); |
|
} |
|
if (this.mMsgQueue.length > 0) |
|
{ |
|
setTimeout(function(c) { c.observe_process(); }, 0, this); |
|
} |
|
} |
|
catch (ex) { } |
|
]]></body> |
|
</method> |
|
|
|
<method name="observe_delayed"> |
|
<parameter name="aMessage"/> |
|
<body><![CDATA[ |
|
if (!this.reversed) |
|
{ |
|
for (var item = this.lastChild; item && !item.visible; item = item.previousSibling); |
|
var lastVisible = this._isItemVisible(item); |
|
} |
|
|
|
this.appendItem(aMessage); |
|
|
|
if (!this.reversed && lastVisible && this.lastChild.visible) |
|
{ |
|
this.ensureElementIsVisible(this.lastChild); |
|
} |
|
]]></body> |
|
</method> |
|
|
|
<method name="appendItem"> |
|
<parameter name="aMessage"/> |
|
<body><![CDATA[ |
|
/* This method may be called in cases where the code |
|
* called by this method has thrown an exception because |
|
* some resource ran OUT OF MEMORY (OOM). |
|
* |
|
* This method must not throw an exception, because |
|
* an exception thrown by it could be asynchrounously |
|
* dispatched back to this method resulting in an |
|
* asynchronous loop - bug 288544. |
|
* |
|
* If you need any try/catch handling for code in this |
|
* function, please stick it in its own try block inside |
|
* the main try block. Do *NOT* use the main try block. |
|
*/ |
|
try { |
|
if (aMessage instanceof Components.interfaces.nsIScriptError) |
|
{ |
|
this.appendError(aMessage); |
|
} |
|
else if (aMessage instanceof Components.interfaces.nsIConsoleMessage) |
|
{ |
|
if (aMessage.message) |
|
{ |
|
this.appendMessage(aMessage.message); |
|
} |
|
else if (this.firstChild) // reached a "Clear" marker |
|
{ |
|
this.removeAllRows(); |
|
} |
|
} |
|
else |
|
{ |
|
this.appendMessage(aMessage); |
|
} |
|
} catch (e) { |
|
/* This catch block is for bug 288544, |
|
* if you want to handle some edge case, please |
|
* make your own inner try block inside preceding |
|
* try block. Do *NOT* stick any code in here. |
|
*/ |
|
} |
|
]]></body> |
|
</method> |
|
|
|
<method name="appendError"> |
|
<parameter name="aMessage"/> |
|
<body><![CDATA[ |
|
var isWarning = (aMessage.flags & Components.interfaces.nsIScriptError.warningFlag) || |
|
(aMessage.flags & Components.interfaces.nsIScriptError.strictFlag); |
|
if (/^(uncaught exception: )?\[Exception... /.test(aMessage.errorMessage)) |
|
{ |
|
aMessage = this.parseUncaughtException(aMessage); |
|
} |
|
var row = this.createConsoleRow(aMessage.errorMessage, (isWarning)?"warning":"error"); |
|
|
|
row.setAttribute("typetext", this._bundle.getString((isWarning)?"typeWarning":"typeError")); |
|
|
|
if (aMessage.category) |
|
{ |
|
row.setAttribute("category", aMessage.category); |
|
} |
|
|
|
if (aMessage.sourceName) |
|
{ |
|
row.setAttribute("href", aMessage.sourceName.replace(/^resource\:\/\/\//, 'resource://app/')); |
|
row.setAttribute("line", aMessage.lineNumber || 0); |
|
} |
|
else |
|
{ |
|
row.setAttribute("hideSource", "true"); |
|
} |
|
|
|
if (aMessage.sourceLine) |
|
{ |
|
// malformed-xml errors include their own caret -----v |
|
if(aMessage.sourceLine.length > 100){row.setAttribute("code", aMessage.sourceLine.substring(0,100).replace(/\n\-+\^$/, "").replace(/\s/g, " ")+"/* ... */"); |
|
row.setAttribute("column", aMessage.columnNumber || 0); |
|
row.setAttribute("errorDots", this.repeatChar(" ", (aMessage.columnNumber > 100) ? 105 : aMessage.columnNumber)); |
|
} else { |
|
row.setAttribute("code", aMessage.sourceLine.replace(/\n\-+\^$/, "").replace(/\s/g, " ")); |
|
row.setAttribute("column", aMessage.columnNumber || 0); |
|
row.setAttribute("errorDots", this.repeatChar(" ", aMessage.columnNumber)); |
|
} |
|
} |
|
if (("nsIScriptError2" in Components.interfaces && |
|
aMessage instanceof Components.interfaces.nsIScriptError2 && |
|
"timeStamp" in aMessage) || |
|
(aMessage instanceof Components.interfaces.nsIScriptError && |
|
"timeStamp" in aMessage)) |
|
{ |
|
var ts = new Date(aMessage.timeStamp); |
|
var tss = ts.toTimeString(); |
|
tss = ts.toDateString() + " " + tss.substr(0, tss.indexOf(" ")); |
|
row.setAttribute("timestamp", tss); |
|
} |
|
|
|
this.appendConsoleRow(row); |
|
]]></body> |
|
</method> |
|
|
|
<method name="appendMessage"> |
|
<parameter name="aMessage"/> |
|
<parameter name="aType"/> |
|
<body><![CDATA[ |
|
var row = this.createConsoleRow(aMessage, aType); |
|
|
|
// all messages are from chrome |
|
row.setAttribute("href", "chrome://"); |
|
row.setAttribute("hideSource", "true"); |
|
|
|
this.appendConsoleRow(row); |
|
]]></body> |
|
</method> |
|
|
|
<method name="appendConsoleRow"> |
|
<parameter name="aRow"/> |
|
<body><![CDATA[ |
|
aRow.hidden = true; |
|
|
|
if (!this.reversed) |
|
{ |
|
this.appendChild(aRow); |
|
} |
|
else |
|
{ |
|
this.insertBefore(aRow, this.firstChild); |
|
} |
|
|
|
if (this.mListeners.length) |
|
{ |
|
try |
|
{ |
|
this.mListeners.forEach(function(aListener) { aListener.listen(aRow); }); |
|
} |
|
catch (ex) { } // in case a listener fails to handle an exception |
|
} |
|
|
|
aRow.hidden = !!aRow._hidden; // could be a hint from a listener |
|
|
|
var overflow = this.count - this._limit; |
|
while (overflow-- > 0) |
|
{ |
|
var item = (this.reversed)?this.lastChild:this.firstChild; |
|
this.removeConsoleRow(item); |
|
} |
|
]]></body> |
|
</method> |
|
|
|
<method name="removeConsoleRow"> |
|
<parameter name="aRow"/> |
|
<body><![CDATA[ |
|
if (!aRow || aRow.parentNode != this) |
|
{ |
|
return; |
|
} |
|
if (aRow.current) |
|
{ |
|
aRow.hidden = true; // otherwise we might find ourselves |
|
this.currentItem = this.getNextVisible(aRow, false) || aRow.nextSibling || aRow.previousSibling; |
|
} |
|
var label = aRow.label2; |
|
if (label in this.mDupeCache) if (this.mDupeCache[label] == aRow) { |
|
delete this.mDupeCache[label]; // avoiding a memory leak |
|
} |
|
this.removeChild(aRow); |
|
]]></body> |
|
</method> |
|
|
|
<method name="removeAllRows"> |
|
<body><![CDATA[ |
|
this.clearSelection(); |
|
this.current = null; |
|
while (this.firstChild) |
|
{ |
|
this.removeConsoleRow(this.lastChild); |
|
} |
|
]]></body> |
|
</method> |
|
|
|
<method name="reverseRows"> |
|
<body><![CDATA[ |
|
var children = this.children; |
|
for (var i = children.length - 2; i >= 0; i--) |
|
{ |
|
this.appendChild(children[i]); |
|
} |
|
]]></body> |
|
</method> |
|
|
|
<method name="clear"> |
|
<body><![CDATA[ |
|
this.mCService.logStringMessage(null); |
|
if (this.mCService.reset) |
|
{ |
|
this.mCService.reset(); |
|
} |
|
]]></body> |
|
</method> |
|
|
|
<method name="scrollToSelectedItem"> |
|
<body><![CDATA[ |
|
setTimeout(function(aConsole) { |
|
var item = (aConsole.currentItem && aConsole.currentItem.selected)?aConsole.currentItem:aConsole.selectedItem; |
|
if (item && item.visible) |
|
{ |
|
aConsole.ensureElementIsVisible(item); |
|
} |
|
}, 0, this); |
|
]]></body> |
|
</method> |
|
|
|
<!-- ///////////////// utility functions ///////////////// --> |
|
|
|
<method name="createConsoleRow"> |
|
<parameter name="aMessage"/> |
|
<parameter name="aType"/> |
|
<body><![CDATA[ |
|
var row = document.createElement("richlistitem"); |
|
|
|
row.setAttribute("class", "console-row"); |
|
row.setAttribute("msg", aMessage); |
|
row.setAttribute("type", aType || "message"); |
|
row.__console = this; |
|
|
|
return row; |
|
]]></body> |
|
</method> |
|
|
|
<method name="parseUncaughtException"> |
|
<parameter name="aMessage"/> |
|
<body><![CDATA[ |
|
/*** from the one-regexp-is-worth-a-whole-parser dept. ***/ |
|
|
|
// cf. http://lxr.mozilla.org/mozilla/source/js/src/xpconnect/src/xpcexception.cpp#347 and http://lxr.mozilla.org/mozilla/source/js/src/xpconnect/src/xpcstack.cpp#318 and http://lxr.mozilla.org/mozilla/source/dom/src/base/nsDOMException.cpp#315 |
|
if (/^(?:uncaught exception: )?\[Exception... "(?!<no message>)([\s\S]+)" nsresult: "0x\S+ \((.+)\)" location: "(?:(?:JS|native) frame :: (?!<unknown filename>)(.+) :: .+ :: line (\d+)|<unknown>)" data: (?:yes|no)\]$/.test(aMessage.errorMessage) || /^(?:uncaught exception: )?\[Exception... "(?!<no message>)([\s\S]+)" code: "\d+" nsresult: "0x\S+ \((.+)\)" location: "(?:(.+) Line: (\d+)|<unknown>)"\]$/.test(aMessage.errorMessage)) |
|
{ |
|
return { |
|
errorMessage: RegExp.$1 + ((RegExp.$1.indexOf(RegExp.$2) == -1)?" = " + RegExp.$2:""), |
|
sourceName: RegExp.$3, |
|
lineNumber: RegExp.$4 |
|
}; |
|
} |
|
return aMessage; |
|
]]></body> |
|
</method> |
|
|
|
<method name="getNextVisible"> |
|
<parameter name="aRow"/> |
|
<parameter name="aReversed"/> |
|
<body><![CDATA[ |
|
var row = !aReversed ? |
|
this.getNextItem(aRow, 1) || this.getPreviousItem(aRow, 1) : |
|
this.getPreviousItem(aRow, 1) || this.getNextItem(aRow, 1); |
|
return row; |
|
]]></body> |
|
</method> |
|
|
|
<method name="repeatChar"> |
|
<parameter name="aChar"/> |
|
<parameter name="aCol"/> |
|
<body><![CDATA[ |
|
var str = aChar; |
|
|
|
for (var i = aChar.length; i < aCol; i += i) |
|
{ |
|
str += str; |
|
} |
|
|
|
return str.slice(i - aCol); |
|
]]></body> |
|
</method> |
|
|
|
<method name="registerListener"> |
|
<parameter name="aListener"/> |
|
<parameter name="aDoesRemove"/> |
|
<body><![CDATA[ |
|
if (this.mListeners.indexOf(aListener) == -1) |
|
{ |
|
if (!aDoesRemove) |
|
{ |
|
this.mListeners.push(aListener); |
|
} |
|
else |
|
{ |
|
this.mListeners.unshift(aListener); |
|
} |
|
} |
|
]]></body> |
|
</method> |
|
|
|
<method name="unregisterListener"> |
|
<parameter name="aListener"/> |
|
<body><![CDATA[ |
|
var ix = this.mListeners.indexOf(aListener); |
|
if (ix > -1) |
|
{ |
|
this.mListeners.splice(ix, 1); |
|
} |
|
]]></body> |
|
</method> |
|
|
|
<method name="initDupeFinder"> |
|
<body><![CDATA[ |
|
this.mDupeCache = {}; |
|
this.registerListener({ |
|
mDupeCache: this.mDupeCache, |
|
listen: function(aRow) { |
|
if (!aRow.parentNode) |
|
{ |
|
return; |
|
} |
|
var label = aRow.label2; |
|
if (label in this.mDupeCache) |
|
{ |
|
var oldRow = this.mDupeCache[label]; |
|
oldRow.setAttribute("dupe", "true"); |
|
aRow.setAttribute("dupes", parseInt(oldRow.getAttribute("dupes") || "1") + 1); |
|
} |
|
this.mDupeCache[label] = aRow; |
|
} |
|
}); |
|
]]></body> |
|
</method> |
|
|
|
<!-- ///////////////// overwriting listbox ///////////////// --> |
|
|
|
<method name="moveByOffset"> |
|
<parameter name="offset"/> |
|
<parameter name="isSelecting"/> |
|
<parameter name="isSelectingRange"/> |
|
<body><![CDATA[ |
|
// !!! assert this.children.length == this.childNodes.length !!! |
|
if ((isSelectingRange || !isSelecting) && this.selType != "multiple") |
|
return; |
|
|
|
var newIndex = this.currentIndex + offset; |
|
if (newIndex < 0) |
|
newIndex = 0; |
|
|
|
var numItems = this.getRowCount(); |
|
if (newIndex > numItems - 1) |
|
newIndex = numItems - 1; |
|
|
|
var itemAtIndex = this.getItemAtIndex(newIndex); |
|
var newItem = itemAtIndex; |
|
// make sure that the item is actually visible/selectable |
|
if (this._userSelecting && newItem && !this._canUserSelect(newItem)) |
|
{ |
|
newItem = this.getNextVisible(itemAtIndex, offset > 1 || offset == -1); |
|
// make sure to scroll at least by one item when page scrolling |
|
if ((offset > 1 || offset < -1) && newItem == this.currentItem) |
|
newItem = this.getNextVisible(itemAtIndex, offset < 0); |
|
} |
|
if (newItem) |
|
{ |
|
if (isSelectingRange) |
|
this.selectItemRange(null, newItem); |
|
else if (isSelecting) |
|
this.selectItem(newItem); |
|
|
|
this.currentItem = newItem; |
|
this.ensureIndexIsVisible(this.getIndexOfItem(newItem)); |
|
if (!newItem || newItem.boxObject.height <= this.scrollBoxObject.height) |
|
this.ensureIndexIsVisible(this.getIndexOfItem(newItem)); |
|
else // always show the top of overlong rows |
|
this.scrollToIndex(this.currentIndex); |
|
} |
|
]]></body> |
|
</method> |
|
|
|
<method name="addItemToSelection"> |
|
<parameter name="item"/> |
|
<body><![CDATA[ |
|
if (item.selected || !item.visible) |
|
{ |
|
if (item.selected && !item.visible) |
|
{ // we probably don't expect hidden items to be selected |
|
this.removeItemFromSelection(item); |
|
} |
|
return; |
|
} |
|
|
|
this.selectedItems.push(item); |
|
item.selected = true; |
|
|
|
this._fireOnSelect(); |
|
]]></body> |
|
</method> |
|
|
|
<!-- ///////////////// overwriting richlistbox ///////////////// --> |
|
|
|
<constructor><![CDATA[ |
|
var x = document.getAnonymousElementByAttribute(this, "anonid", "main-box"); |
|
this.scrollBoxObject = x.boxObject; |
|
this._bundle = document.getAnonymousElementByAttribute(this, "anonid", "string-bundle"); |
|
this.initDupeFinder(); |
|
this._limit = this.mPrefs.getIntPref("extensions.console2.max-errors"); |
|
|
|
// delay message loading for faster startup |
|
setTimeout(function(aConsole, aTmpItem) { |
|
aConsole.removeChild(aTmpItem); |
|
aConsole.appendInitialItems(); |
|
aConsole.mCService.registerListener(aConsole); |
|
aConsole.currentItem = aConsole.firstChild; |
|
}, 0, this, this.insertItemAt(0, this._bundle.getString("msgLoading"))); |
|
]]></constructor> |
|
|
|
<destructor><![CDATA[ |
|
this.mCService.unregisterListener(this); |
|
]]></destructor> |
|
|
|
<property name="children" onget="return Array.slice(this.childNodes);" readonly="true"/> |
|
</implementation> |
|
</binding> |
|
|
|
<!-- ######################## Console Item ######################## --> |
|
|
|
<binding id="item" extends="chrome://console2/content/global/richlistbox.xml#richlistitem"> |
|
<content> |
|
<xul:box flex="1"> |
|
<xul:box class="console-row-icon" xbl:inherits="selected"> |
|
<xul:stack> |
|
<xul:image xbl:inherits="src,type"/> |
|
<xul:box/> |
|
</xul:stack> |
|
</xul:box> |
|
<xul:vbox class="console-row-content" flex="1"> |
|
<xul:box> |
|
<xul:description xbl:inherits="xbl:text=msg" flex="1"/> |
|
<xul:label class="console-row-dupes" xbl:inherits="value=dupes" tooltiptext="&dupes.tooltip;"/> |
|
<xul:label class="console-row-timestamp" xbl:inherits="value=timestamp"/> |
|
</xul:box> |
|
<xul:box xbl:inherits="hidden=hideSource"> |
|
<xul:sourcelink xbl:inherits="href,line,tooltiptext=href" flex="1" crop="end"/> |
|
<xul:spacer flex="99999"/> |
|
<xul:box class="console-row-number" xbl:inherits="number=line"> |
|
<xul:label value="&errLine.label;"/> |
|
<xul:label xbl:inherits="value=line"/> |
|
</xul:box> |
|
</xul:box> |
|
<xul:vbox class="console-row-code" xbl:inherits="selected,code"> |
|
<xul:label class="monospace" xbl:inherits="value=code" crop="end"/> |
|
<xul:box class="console-row-number" xbl:inherits="number=column"> |
|
<xul:label class="monospace console-dots" xbl:inherits="value=errorDots"/> |
|
<xul:label class="monospace console-caret" value=" "/> |
|
</xul:box> |
|
</xul:vbox> |
|
</xul:vbox> |
|
</xul:box> |
|
</content> |
|
|
|
<implementation> |
|
<property name="visible" readonly="true"> |
|
<getter><![CDATA[ |
|
try |
|
{ |
|
return this.boxObject.height > 0; |
|
} |
|
catch (ex) |
|
{ |
|
return this.parentNode && !this.hidden; |
|
} |
|
]]></getter> |
|
</property> |
|
|
|
<property name="label" readonly="true"> |
|
<getter><![CDATA[ |
|
var bundle = this.__console._bundle; |
|
|
|
function format(aID, aArgs) |
|
{ |
|
return bundle.getFormattedString(aID, aArgs); |
|
} |
|
|
|
var label = this.getAttribute("msg"); |
|
if (this.hasAttribute("typetext")) |
|
{ |
|
label = this.getAttribute("typetext") + " " + label; |
|
} |
|
if (this.hasAttribute("timestamp")) |
|
{ |
|
label = this.getAttribute("timestamp") + "\n" + label; |
|
} |
|
|
|
if (this.hasAttribute("href") && !this.getAttribute("hideSource")) |
|
{ |
|
label += "\n" + format("errFile", [this.getAttribute("href")]); |
|
if (this.hasAttribute("line") && this.hasAttribute("column") && this.getAttribute("column") != "0") |
|
{ |
|
label += "\n" + format("errLineCol", [this.getAttribute("line"), this.getAttribute("column")]); |
|
} |
|
else if (this.hasAttribute("line") && this.getAttribute("line") != "0") |
|
{ |
|
label += "\n" + format("errLine", [this.getAttribute("line")]); |
|
} |
|
} |
|
if (this.hasAttribute("code")) |
|
{ |
|
label += "\n" + bundle.getString("errCode") + "\n" + this.getAttribute("code"); |
|
} |
|
|
|
return label; |
|
]]></getter> |
|
</property> |
|
|
|
<property name="label2" readonly="true"> |
|
<getter><![CDATA[ |
|
var bundle = this.__console._bundle; |
|
|
|
function format(aID, aArgs) |
|
{ |
|
return bundle.getFormattedString(aID, aArgs); |
|
} |
|
|
|
var label = this.getAttribute("msg"); |
|
if (this.hasAttribute("typetext")) |
|
{ |
|
label = this.getAttribute("typetext") + " " + label; |
|
} |
|
|
|
if (this.hasAttribute("href") && !this.getAttribute("hideSource")) |
|
{ |
|
label += "\n" + format("errFile", [this.getAttribute("href")]); |
|
if (this.hasAttribute("line") && this.hasAttribute("column") && this.getAttribute("column") != "0") |
|
{ |
|
label += "\n" + format("errLineCol", [this.getAttribute("line"), this.getAttribute("column")]); |
|
} |
|
else if (this.hasAttribute("line") && this.getAttribute("line") != "0") |
|
{ |
|
label += "\n" + format("errLine", [this.getAttribute("line")]); |
|
} |
|
} |
|
if (this.hasAttribute("code")) |
|
{ |
|
label += "\n" + bundle.getString("errCode") + "\n" + this.getAttribute("code"); |
|
} |
|
|
|
return label; |
|
]]></getter> |
|
</property> |
|
|
|
<property name="searchLabel" onget="return (this.visible)?this.getAttribute('msg'):'';" readonly="true"/> |
|
</implementation> |
|
</binding> |
|
|
|
<!-- use this binding, if performance is more important than style --> |
|
<binding id="item-light" extends="#item"> |
|
<content> |
|
<xul:vbox flex="1"> |
|
<xul:label xbl:inherits="value=msg" flex="1" crop="end"/> |
|
<xul:sourcelink xbl:inherits="href,line,tooltiptext=href" flex="1" crop="end"/> |
|
</xul:vbox> |
|
</content> |
|
</binding> |
|
|
|
<!-- ######################## Source Link ######################## --> |
|
|
|
<binding id="sourcelink" extends="xul:box"> |
|
<content> |
|
<xul:label class="text-link" xbl:inherits="href,value=href,flex,crop" ondraggesture="nsDragAndDrop.startDrag(event, this.parentNode); event.stopPropagation();"/> |
|
</content> |
|
|
|
<implementation> |
|
<constructor><![CDATA[ |
|
// hack against one of the many bugs referenced by bug 302294 |
|
document.getAnonymousNodes(this)[0].setAttribute("value", this.getAttribute("href").replace(/^(.{253})(?=.{4,}).*/, "$1...")); |
|
]]></constructor> |
|
|
|
<field name="mPrefs" readonly="true">Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch2);</field> |
|
|
|
<method name="onDragStart"> |
|
<parameter name="aEvent"/> |
|
<parameter name="aXferData"/> |
|
<parameter name="aDragAction"/> |
|
<body><![CDATA[ |
|
var URI = this.getAttribute("href"); |
|
aXferData.data = new TransferData(); |
|
aXferData.data.addDataForFlavour("text/unicode", URI); |
|
aXferData.data.addDataForFlavour("text/x-moz-url", URI + "\n" + URI.replace(/^.*\//, "")); |
|
aXferData.data.addDataForFlavour("text/html", '<a href="' + URI + '">' + URI + '</a>'); |
|
]]></body> |
|
</method> |
|
|
|
<method name="_viewSource"> |
|
<body><![CDATA[ |
|
try |
|
{ |
|
if (!this.mPrefs.getBoolPref("view_source.editor.external")) |
|
{ |
|
return false; |
|
} |
|
|
|
var scriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader); |
|
var context = {}; |
|
|
|
scriptLoader.loadSubScript("chrome://global/content/contentAreaUtils.js", context); |
|
scriptLoader.loadSubScript("chrome://global/content/viewSourceUtils.js", context); |
|
} |
|
catch (ex) |
|
{ |
|
return false; |
|
} |
|
|
|
var url = this.getAttribute("href"); |
|
url = url.substring(url.lastIndexOf(" ") + 1); |
|
var line = (context.gViewSourceUtils.openInExternalEditor.length == 5) ? |
|
parseInt(this.getAttribute("line") || 0) : |
|
undefined; |
|
context.gViewSourceUtils.openInExternalEditor(url, null, null, line); |
|
|
|
return true; |
|
]]></body> |
|
</method> |
|
</implementation> |
|
|
|
<handlers> |
|
<handler event="click" phase="capturing" button="0" preventdefault="true"><![CDATA[ |
|
if (event.originalTarget.className == "text-link" && !this._viewSource()) |
|
{ |
|
var url = this.getAttribute("href"); |
|
//url = url.substring(url.lastIndexOf(" ") + 1); |
|
var line = this.getAttribute("line"); |
|
openDialog("chrome://global/content/viewSource.xul", "_blank", "all,dialog=no", url, null, null, line); |
|
} |
|
]]></handler> |
|
</handlers> |
|
</binding> |
|
|
|
<!-- ######################## Toolbar Button ######################## --> |
|
|
|
<binding id="toolbarbutton" extends="chrome://global/content/bindings/toolbarbutton.xml#menu"> |
|
<implementation> |
|
<method name="rotateValue"> |
|
<body><![CDATA[ |
|
var group = this.getAttribute("rotates"); |
|
var items = this.getElementsByAttribute("group", group); |
|
items = Array.prototype.slice.call(items).filter(function(aItem) { |
|
return aItem.getAttribute("disabled") != "true"; |
|
}); |
|
|
|
if (group && items.length) |
|
{ |
|
for (var i = 0; i < items.length && items[i].getAttribute("checked") != "true"; i++); |
|
if (i < items.length) |
|
{ |
|
items[i].removeAttribute("checked"); |
|
} |
|
if (++i >= items.length) |
|
{ |
|
i = 0; |
|
} |
|
items[i].setAttribute("checked", "true"); |
|
items[i].doCommand(); |
|
} |
|
]]></body> |
|
</method> |
|
</implementation> |
|
|
|
<handlers> |
|
<handler event="keypress" keycode="VK_ENTER" phase="target" action="this.doCommand();"/> |
|
<handler event="keypress" keycode="VK_RETURN" phase="target" action="this.doCommand();"/> |
|
<handler event="keypress" key=" " phase="target" action="this.doCommand();"/> |
|
<handler event="click" button="1" phase="target" action="this.rotateValue();"/> |
|
<handler event="click" button="2" modifiers="shift" phase="target" preventdefault="true" action="this.rotateValue();"/> <!-- for testing on a 2-button mouse (the context menu is more easily suppressed than the popup menu) --> |
|
|
|
<handler event="command" phase="target"><![CDATA[ |
|
var menus = document.getElementsByAttribute("type", "menu"); |
|
for (var i = 0; i < menus.length; i++) |
|
{ |
|
if (menus[i] != this) |
|
{ |
|
menus[i].open = false; |
|
} |
|
} |
|
setTimeout(function(aMenu) { aMenu.open = true; }, 0, this); |
|
]]></handler> |
|
|
|
<handler event="mouseover"><![CDATA[ |
|
var menus = document.getElementsByAttribute("type", "menu"); |
|
for (var i = 0; i < menus.length && !menus[i].open; i++); |
|
if (i < menus.length && !this.open) |
|
{ |
|
this.doCommand(); |
|
} |
|
]]></handler> |
|
</handlers> |
|
</binding> |
|
|
|
<!-- ######################## Evaluate Popup ######################## --> |
|
|
|
<binding id="popup" extends="chrome://global/content/bindings/popup.xml#popup"> |
|
<content> |
|
<children/> |
|
</content> |
|
|
|
<implementation> |
|
<field name="mTimeout" readonly="true">2500</field> |
|
|
|
<method name="_startTimeout"> |
|
<body><![CDATA[ |
|
this._clearTimeout(); |
|
this.__timeout = setTimeout(function(aPopup) { aPopup.hidePopup(); }, this.mTimeout, this); |
|
]]></body> |
|
</method> |
|
|
|
<method name="_clearTimeout"> |
|
<body><![CDATA[ |
|
if (this.__timeout) |
|
{ |
|
clearTimeout(this.__timeout); |
|
this.__timeout = null; |
|
} |
|
]]></body> |
|
</method> |
|
</implementation> |
|
|
|
<handlers> |
|
<handler event="click" phase="capturing" action="this.hidePopup(); event.stopPropagation();"/> |
|
<handler event="mousedown" phase="capturing" action="event.stopPropagation();"/> |
|
<handler event="mouseover" action="this._clearTimeout()"/> |
|
<handler event="mouseout" action="this._startTimeout();"/> |
|
<handler event="popupshown" action="this._startTimeout();"/> |
|
<handler event="popuphidden" action="this._clearTimeout();"/> |
|
</handlers> |
|
</binding> |
|
</bindings>
|
|
|