toolkit/components/console/content/consoleBindings.xml

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:89f182e433bc
1 <?xml version="1.0"?>
2 <!-- This Source Code Form is subject to the terms of the Mozilla Public
3 - License, v. 2.0. If a copy of the MPL was not distributed with this
4 - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
5
6
7 <!DOCTYPE bindings SYSTEM "chrome://global/locale/console.dtd">
8
9 <bindings id="consoleBindings"
10 xmlns="http://www.mozilla.org/xbl"
11 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
12 xmlns:xbl="http://www.mozilla.org/xbl">
13
14 <binding id="console-box" extends="xul:box">
15 <content>
16 <xul:stringbundle src="chrome://global/locale/console.properties" role="string-bundle"/>
17 <xul:vbox class="console-box-internal">
18 <xul:vbox class="console-rows" role="console-rows" xbl:inherits="dir=sortOrder"/>
19 </xul:vbox>
20 </content>
21
22 <implementation>
23 <field name="limit" readonly="true">
24 250
25 </field>
26
27 <field name="fieldMaxLength" readonly="true">
28 <!-- Limit displayed string lengths to avoid performance issues. (Bug 796179 and 831020) -->
29 200
30 </field>
31
32 <field name="showChromeErrors" readonly="true">
33 Services.prefs.getBoolPref("javascript.options.showInConsole");
34 </field>
35
36 <property name="count" readonly="true">
37 <getter>return this.mCount</getter>
38 </property>
39
40 <property name="mode">
41 <getter>return this.mMode;</getter>
42 <setter><![CDATA[
43 if (this.mode != val) {
44 this.mMode = val || "All";
45 this.setAttribute("mode", this.mMode);
46 this.selectedItem = null;
47 }
48 return val;
49 ]]></setter>
50 </property>
51
52 <property name="filter">
53 <getter>return this.mFilter;</getter>
54 <setter><![CDATA[
55 val = val.toLowerCase();
56 if (this.mFilter != val) {
57 this.mFilter = val;
58 for (let aRow of this.mConsoleRowBox.children) {
59 this.filterElement(aRow);
60 }
61 }
62 return val;
63 ]]></setter>
64 </property>
65
66 <property name="sortOrder">
67 <getter>return this.getAttribute("sortOrder");</getter>
68 <setter>this.setAttribute("sortOrder", val); return val;</setter>
69 </property>
70 <field name="mSelectedItem">null</field>
71 <property name="selectedItem">
72 <getter>return this.mSelectedItem</getter>
73 <setter><![CDATA[
74 if (this.mSelectedItem)
75 this.mSelectedItem.removeAttribute("selected");
76
77 this.mSelectedItem = val;
78 if (val)
79 val.setAttribute("selected", "true");
80
81 // Update edit commands
82 window.updateCommands("focus");
83 return val;
84 ]]></setter>
85 </property>
86
87 <method name="init">
88 <body><![CDATA[
89 this.mCount = 0;
90
91 this.mConsoleListener = {
92 console: this,
93 observe : function(aObject) {
94 // The message can arrive a little bit after the xbl binding has been
95 // unbind. So node.appendItem will not be available anymore.
96 if ('appendItem' in this.console)
97 this.console.appendItem(aObject);
98 }
99 };
100
101 this.mConsoleRowBox = document.getAnonymousElementByAttribute(this, "role", "console-rows");
102 this.mStrBundle = document.getAnonymousElementByAttribute(this, "role", "string-bundle");
103
104 try {
105 Services.console.registerListener(this.mConsoleListener);
106 } catch (ex) {
107 appendItem(
108 "Unable to display errors - couldn't get Console Service component. " +
109 "(Missing @mozilla.org/consoleservice;1)");
110 return;
111 }
112
113 this.mMode = this.getAttribute("mode") || "All";
114 this.mFilter = "";
115
116 this.appendInitialItems();
117 window.controllers.insertControllerAt(0, this._controller);
118 ]]></body>
119 </method>
120
121 <method name="destroy">
122 <body><![CDATA[
123 Services.console.unregisterListener(this.mConsoleListener);
124 window.controllers.removeController(this._controller);
125 ]]></body>
126 </method>
127
128 <method name="appendInitialItems">
129 <body><![CDATA[
130 var messages = Services.console.getMessageArray();
131
132 // In case getMessageArray returns 0-length array as null
133 if (!messages)
134 messages = [];
135
136 var limit = messages.length - this.limit;
137 if (limit < 0) limit = 0;
138
139 // Checks if console ever been cleared
140 for (var i = messages.length - 1; i >= limit; --i)
141 if (!messages[i].message)
142 break;
143
144 // Populate with messages after latest "clear"
145 while (++i < messages.length)
146 this.appendItem(messages[i]);
147 ]]></body>
148 </method>
149
150 <method name="appendItem">
151 <parameter name="aObject"/>
152 <body><![CDATA[
153 try {
154 // Try to QI it to a script error to get more info
155 var scriptError = aObject.QueryInterface(Components.interfaces.nsIScriptError);
156
157 // filter chrome urls
158 if (!this.showChromeErrors && scriptError.sourceName.substr(0, 9) == "chrome://")
159 return;
160
161 // filter private windows
162 if (scriptError.isFromPrivateWindow)
163 return;
164
165 this.appendError(scriptError);
166 } catch (ex) {
167 try {
168 // Try to QI it to a console message
169 var msg = aObject.QueryInterface(Components.interfaces.nsIConsoleMessage);
170 if (msg.message)
171 this.appendMessage(msg.message);
172 else // observed a null/"clear" message
173 this.clearConsole();
174 } catch (ex2) {
175 // Give up and append the object itself as a string
176 this.appendMessage(aObject);
177 }
178 }
179 ]]></body>
180 </method>
181
182 <method name="_truncateIfNecessary">
183 <parameter name="aString"/>
184 <parameter name="aMiddleCharacter"/>
185 <body><![CDATA[
186 if (!aString || aString.length <= this.fieldMaxLength)
187 return {string: aString, column: aMiddleCharacter};
188 let halfLimit = this.fieldMaxLength / 2;
189 if (!aMiddleCharacter || aMiddleCharacter < 0 || aMiddleCharacter > aString.length)
190 aMiddleCharacter = halfLimit;
191
192 let startPosition = 0;
193 let endPosition = aString.length;
194 if (aMiddleCharacter - halfLimit >= 0)
195 startPosition = aMiddleCharacter - halfLimit;
196 if (aMiddleCharacter + halfLimit <= aString.length)
197 endPosition = aMiddleCharacter + halfLimit;
198 if (endPosition - startPosition < this.fieldMaxLength)
199 endPosition += this.fieldMaxLength - (endPosition - startPosition);
200 let truncatedString = aString.substring(startPosition, endPosition);
201 let Ci = Components.interfaces;
202 let ellipsis = Services.prefs.getComplexValue("intl.ellipsis",
203 Ci.nsIPrefLocalizedString).data;
204 if (startPosition > 0) {
205 truncatedString = ellipsis + truncatedString;
206 aMiddleCharacter += ellipsis.length;
207 }
208 if (endPosition < aString.length)
209 truncatedString = truncatedString + ellipsis;
210
211 return {
212 string: truncatedString,
213 column: aMiddleCharacter - startPosition
214 };
215 ]]></body>
216 </method>
217
218 <method name="appendError">
219 <parameter name="aObject"/>
220 <body><![CDATA[
221 var row = this.createConsoleRow();
222 var nsIScriptError = Components.interfaces.nsIScriptError;
223
224 // Is this error actually just a non-fatal warning?
225 var warning = aObject.flags & nsIScriptError.warningFlag != 0;
226
227 var typetext = warning ? "typeWarning" : "typeError";
228 row.setAttribute("typetext", this.mStrBundle.getString(typetext));
229 row.setAttribute("type", warning ? "warning" : "error");
230 row.setAttribute("msg", aObject.errorMessage);
231 row.setAttribute("category", aObject.category);
232 row.setAttribute("time", this.properFormatTime(aObject.timeStamp));
233 if (aObject.lineNumber || aObject.sourceName) {
234 row.setAttribute("href", this._truncateIfNecessary(aObject.sourceName).string);
235 row.mSourceName = aObject.sourceName;
236 row.setAttribute("line", aObject.lineNumber);
237 } else {
238 row.setAttribute("hideSource", "true");
239 }
240 if (aObject.sourceLine) {
241 let sourceLine = aObject.sourceLine.replace(/\s/g, " ");
242 let truncatedLineObj = this._truncateIfNecessary(sourceLine, aObject.columnNumber);
243 row.setAttribute("code", truncatedLineObj.string);
244 row.mSourceLine = sourceLine;
245 if (aObject.columnNumber) {
246 row.setAttribute("col", aObject.columnNumber);
247 row.setAttribute("errorDots", this.repeatChar(" ", truncatedLineObj.column));
248 row.setAttribute("errorCaret", " ");
249 } else {
250 row.setAttribute("hideCaret", "true");
251 }
252 } else {
253 row.setAttribute("hideCode", "true");
254 }
255
256 this.appendConsoleRow(row);
257 ]]></body>
258 </method>
259
260 <method name="appendMessage">
261 <parameter name="aMessage"/>
262 <parameter name="aType"/>
263 <body><![CDATA[
264 var row = this.createConsoleRow();
265 row.setAttribute("type", aType || "message");
266 row.setAttribute("msg", aMessage);
267 this.appendConsoleRow(row);
268 ]]></body>
269 </method>
270
271 <method name="clear">
272 <body><![CDATA[
273 // add a "clear" message (mainly for other listeners)
274 Services.console.logStringMessage(null);
275 Services.console.reset();
276 ]]></body>
277 </method>
278
279 <method name="properFormatTime">
280 <parameter name="aTime"/>
281 <body><![CDATA[
282 const dateServ = Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
283 .getService(Components.interfaces.nsIScriptableDateFormat);
284 let errorTime = new Date(aTime);
285 return dateServ.FormatDateTime("", dateServ.dateFormatShort, dateServ.timeFormatSeconds,
286 errorTime.getFullYear(), errorTime.getMonth() + 1, errorTime.getDate(),
287 errorTime.getHours(), errorTime.getMinutes(), errorTime.getSeconds());
288 ]]></body>
289 </method>
290
291 <method name="copySelectedItem">
292 <body><![CDATA[
293 if (this.mSelectedItem) try {
294 const clipURI = "@mozilla.org/widget/clipboardhelper;1";
295 const clipI = Components.interfaces.nsIClipboardHelper;
296 var clipboard = Components.classes[clipURI].getService(clipI);
297
298 clipboard.copyString(this.mSelectedItem.toString(), document);
299 } catch (ex) {
300 // Unable to copy anything, die quietly
301 }
302 ]]></body>
303 </method>
304
305 <method name="createConsoleRow">
306 <body><![CDATA[
307 var row = document.createElement("box");
308 row.setAttribute("class", "console-row");
309 row._IsConsoleRow = true;
310 row._ConsoleBox = this;
311 return row;
312 ]]></body>
313 </method>
314
315 <method name="appendConsoleRow">
316 <parameter name="aRow"/>
317 <body><![CDATA[
318 this.filterElement(aRow);
319 this.mConsoleRowBox.appendChild(aRow);
320 if (++this.mCount > this.limit) this.deleteFirst();
321 ]]></body>
322 </method>
323
324 <method name="deleteFirst">
325 <body><![CDATA[
326 var node = this.mConsoleRowBox.firstChild;
327 this.mConsoleRowBox.removeChild(node);
328 --this.mCount;
329 ]]></body>
330 </method>
331
332 <method name="clearConsole">
333 <body><![CDATA[
334 if (this.mCount == 0) // already clear
335 return;
336 this.mCount = 0;
337
338 var newRows = this.mConsoleRowBox.cloneNode(false);
339 this.mConsoleRowBox.parentNode.replaceChild(newRows, this.mConsoleRowBox);
340 this.mConsoleRowBox = newRows;
341 this.selectedItem = null;
342 ]]></body>
343 </method>
344
345 <method name="filterElement">
346 <parameter name="aRow" />
347 <body><![CDATA[
348 let anyMatch = ["msg", "line", "code"].some(function (key) {
349 return (aRow.hasAttribute(key) &&
350 this.stringMatchesFilters(aRow.getAttribute(key), this.mFilter));
351 }, this) || (aRow.mSourceName &&
352 this.stringMatchesFilters(aRow.mSourceName, this.mFilter));
353
354 if (anyMatch) {
355 aRow.classList.remove("filtered-by-string")
356 } else {
357 aRow.classList.add("filtered-by-string")
358 }
359 ]]></body>
360 </method>
361
362 <!-- UTILITY FUNCTIONS -->
363
364 <method name="repeatChar">
365 <parameter name="aChar"/>
366 <parameter name="aCol"/>
367 <body><![CDATA[
368 if (--aCol <= 0)
369 return "";
370
371 for (var i = 2; i < aCol; i += i)
372 aChar += aChar;
373
374 return aChar + aChar.slice(0, aCol - aChar.length);
375 ]]></body>
376 </method>
377
378 <method name="stringMatchesFilters">
379 <parameter name="aString"/>
380 <parameter name="aFilter"/>
381 <body><![CDATA[
382 if (!aString || !aFilter) {
383 return true;
384 }
385
386 let searchStr = aString.toLowerCase();
387 let filterStrings = aFilter.split(/\s+/);
388 return !filterStrings.some(function (f) {
389 return searchStr.indexOf(f) == -1;
390 });
391 ]]></body>
392 </method>
393
394 <constructor> this.init(); </constructor>
395 <destructor> this.destroy(); </destructor>
396
397 <!-- Command controller for the copy command -->
398 <field name="_controller"><![CDATA[({
399 _outer: this,
400
401 QueryInterface: function(aIID) {
402 if (aIID.equals(Components.interfaces.nsIController) ||
403 aIID.equals(Components.interfaces.nsISupports))
404 return this;
405 throw Components.results.NS_NOINTERFACE;
406 },
407
408 supportsCommand: function(aCommand) {
409 return aCommand == "cmd_copy";
410 },
411
412 isCommandEnabled: function(aCommand) {
413 return aCommand == "cmd_copy" && this._outer.selectedItem;
414 },
415
416 doCommand: function(aCommand) {
417 if (aCommand == "cmd_copy")
418 this._outer.copySelectedItem();
419 },
420
421 onEvent: function() { }
422 });]]></field>
423 </implementation>
424
425 <handlers>
426 <handler event="mousedown"><![CDATA[
427 if (event.button == 0 || event.button == 2) {
428 var target = event.originalTarget;
429
430 while (target && !("_IsConsoleRow" in target))
431 target = target.parentNode;
432
433 if (target)
434 this.selectedItem = target;
435 }
436 ]]></handler>
437 </handlers>
438 </binding>
439
440 <binding id="error" extends="xul:box">
441 <content>
442 <xul:box class="console-row-internal-box" flex="1">
443 <xul:box class="console-row-icon" align="center" xbl:inherits="selected">
444 <xul:image class="console-icon" xbl:inherits="src,type"/>
445 </xul:box>
446 <xul:vbox class="console-row-content" xbl:inherits="selected" flex="1">
447 <xul:box class="console-row-msg" align="start">
448 <xul:label class="label" xbl:inherits="value=typetext"/>
449 <xul:description class="console-error-msg" xbl:inherits="xbl:text=msg" flex="1"/>
450 <xul:label class="label console-time" xbl:inherits="value=time"/>
451 </xul:box>
452 <xul:box class="console-row-file" xbl:inherits="hidden=hideSource">
453 <xul:label class="label" value="&errFile.label;"/>
454 <xul:box class="console-error-source" xbl:inherits="href,line"/>
455 <xul:spacer flex="1"/>
456 <xul:hbox class="lineNumberRow" xbl:inherits="line">
457 <xul:label class="label" value="&errLine.label;"/>
458 <xul:label class="label" xbl:inherits="value=line"/>
459 </xul:hbox>
460 </xul:box>
461 <xul:vbox class="console-row-code" xbl:inherits="selected,hidden=hideCode">
462 <xul:label class="monospace console-code" xbl:inherits="value=code" crop="end"/>
463 <xul:box xbl:inherits="hidden=hideCaret">
464 <xul:label class="monospace console-dots" xbl:inherits="value=errorDots"/>
465 <xul:label class="monospace console-caret" xbl:inherits="value=errorCaret"/>
466 <xul:spacer flex="1"/>
467 </xul:box>
468 </xul:vbox>
469 </xul:vbox>
470 </xul:box>
471 </content>
472
473 <implementation>
474 <field name="mSourceName">null</field>
475 <field name="mSourceLine">null</field>
476
477 <method name="toString">
478 <body><![CDATA[
479 let msg = "";
480 let strBundle = this._ConsoleBox.mStrBundle;
481
482 if (this.hasAttribute("time"))
483 msg += strBundle.getFormattedString("errTime", [this.getAttribute("time")]) + "\n";
484
485 msg += this.getAttribute("typetext") + " " + this.getAttribute("msg");
486
487 if (this.hasAttribute("line") && this.mSourceName) {
488 msg += "\n" + strBundle.getFormattedString("errFile",
489 [this.mSourceName]) + "\n";
490 if (this.hasAttribute("col")) {
491 msg += strBundle.getFormattedString("errLineCol",
492 [this.getAttribute("line"), this.getAttribute("col")]);
493 } else
494 msg += strBundle.getFormattedString("errLine", [this.getAttribute("line")]);
495 }
496
497 if (this.hasAttribute("code"))
498 msg += "\n" + strBundle.getString("errCode") + "\n" + this.mSourceLine;
499
500 return msg;
501 ]]></body>
502 </method>
503 </implementation>
504
505 </binding>
506
507 <binding id="message" extends="xul:box">
508 <content>
509 <xul:box class="console-internal-box" flex="1">
510 <xul:box class="console-row-icon" align="center">
511 <xul:image class="console-icon" xbl:inherits="src,type"/>
512 </xul:box>
513 <xul:vbox class="console-row-content" xbl:inherits="selected" flex="1">
514 <xul:vbox class="console-row-msg" flex="1">
515 <xul:description class="console-msg-text" xbl:inherits="xbl:text=msg"/>
516 </xul:vbox>
517 </xul:vbox>
518 </xul:box>
519 </content>
520
521 <implementation>
522 <method name="toString">
523 <body><![CDATA[
524 return this.getAttribute("msg");
525 ]]></body>
526 </method>
527 </implementation>
528 </binding>
529
530 <binding id="console-error-source" extends="xul:box">
531 <content>
532 <xul:label class="text-link" xbl:inherits="value=href" crop="right"/>
533 </content>
534
535 <handlers>
536 <handler event="click" phase="capturing" button="0" preventdefault="true">
537 <![CDATA[
538 var url = document.getBindingParent(this).mSourceName;
539 url = url.substring(url.lastIndexOf(" ") + 1);
540 var line = getAttribute("line");
541 gViewSourceUtils.viewSource(url, null, null, line);
542 ]]>
543 </handler>
544 </handlers>
545 </binding>
546
547 </bindings>

mercurial