1 /* See license.txt for terms of usage */
  2 
  3 define([
  4     "firebug/lib/object",
  5     "firebug/lib/array",
  6     "firebug/firebug",
  7     "firebug/lib/domplate",
  8     "firebug/chrome/firefox",
  9     "firebug/lib/xpcom",
 10     "firebug/lib/locale",
 11     "firebug/html/htmlLib",
 12     "firebug/lib/events",
 13     "firebug/lib/wrapper",
 14     "firebug/lib/options",
 15     "firebug/lib/url",
 16     "firebug/js/sourceLink",
 17     "firebug/js/stackFrame",
 18     "firebug/lib/css",
 19     "firebug/lib/dom",
 20     "firebug/chrome/window",
 21     "firebug/lib/system",
 22     "firebug/lib/xpath",
 23     "firebug/lib/string",
 24     "firebug/lib/xml",
 25     "firebug/dom/toggleBranch",
 26     "firebug/console/eventMonitor",
 27     "firebug/chrome/menu",
 28     "arch/compilationunit",
 29 ],
 30 function(Obj, Arr, Firebug, Domplate, Firefox, Xpcom, Locale, HTMLLib, Events, Wrapper, Options,
 31     Url, SourceLink, StackFrame, Css, Dom, Win, System, Xpath, Str, Xml, ToggleBranch,
 32     EventMonitor, Menu, CompilationUnit) {
 33 
 34 with (Domplate) {
 35 
 36 // ********************************************************************************************* //
 37 // Constants
 38 
 39 const Cc = Components.classes;
 40 const Ci = Components.interfaces;
 41 
 42 // xxxHonza: the only global should be Firebug object.
 43 var FirebugReps = window.FirebugReps = {};
 44 
 45 try
 46 {
 47     // xxxHonza: RJS
 48     var FBS = {};
 49     Components.utils["import"]("resource://firebug/firebug-service.js", FBS);
 50     var jsd = Cc["@mozilla.org/js/jsd/debugger-service;1"].getService(Ci.jsdIDebuggerService);
 51 }
 52 catch (err)
 53 {
 54 }
 55 
 56 // ********************************************************************************************* //
 57 // Common Tags
 58 
 59 // use pre here to keep line breaks while copying multiline strings 
 60 var OBJECTBOX = FirebugReps.OBJECTBOX =
 61     PRE({"class": "objectBox inline objectBox-$className", role : "presentation"});
 62 
 63 var OBJECTBLOCK = FirebugReps.OBJECTBLOCK =
 64     DIV({"class": "objectBox objectBox-$className focusRow subLogRow", role : "listitem"});
 65 
 66 var OBJECTLINK = FirebugReps.OBJECTLINK =
 67     A({
 68         "class": "objectLink objectLink-$className a11yFocus",
 69         _repObject: "$object"
 70     });
 71 
 72 // ********************************************************************************************* //
 73 
 74 FirebugReps.Undefined = domplate(Firebug.Rep,
 75 {
 76     tag: OBJECTBOX("undefined"),
 77 
 78     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 79 
 80     className: "undefined",
 81 
 82     supportsObject: function(object, type)
 83     {
 84         return type == "undefined";
 85     }
 86 });
 87 
 88 // ********************************************************************************************* //
 89 
 90 FirebugReps.Null = domplate(Firebug.Rep,
 91 {
 92     tag: OBJECTBOX("null"),
 93 
 94     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 95 
 96     className: "null",
 97 
 98     supportsObject: function(object, type)
 99     {
100         return object == null;
101     }
102 });
103 
104 // ********************************************************************************************* //
105 
106 FirebugReps.Hint = domplate(Firebug.Rep,
107 {
108     tag: OBJECTBOX("$object"),
109 
110     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
111 
112     className: "hint",
113 });
114 
115 // ********************************************************************************************* //
116 
117 FirebugReps.Nada = domplate(Firebug.Rep,
118 {
119     tag: SPAN(""),
120 
121     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
122 
123     className: "nada"
124 });
125 
126 // ********************************************************************************************* //
127 
128 FirebugReps.Number = domplate(Firebug.Rep,
129 {
130     tag: OBJECTBOX("$object"),
131 
132     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
133 
134     className: "number",
135 
136     supportsObject: function(object, type)
137     {
138         return type == "boolean" || type == "number";
139     }
140 });
141 
142 // ********************************************************************************************* //
143 
144 FirebugReps.String = domplate(Firebug.Rep,
145 {
146     tag: OBJECTBOX(""$object""),
147 
148     shortTag: OBJECTBOX(""$object|cropMultipleLines""),
149 
150     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
151 
152     className: "string",
153 
154     supportsObject: function(object, type)
155     {
156         return type == "string";
157     }
158 });
159 
160 // ********************************************************************************************* //
161 
162 FirebugReps.XML = domplate(Firebug.Rep,
163 {
164     tag: OBJECTBOX("$object|asString"),
165 
166     shortTag: OBJECTBOX("$object|asShortString"),
167 
168     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
169 
170     className: "xml",
171 
172     supportsObject: function(object, type)
173     {
174         return type == "xml";
175     },
176 
177     asString: function(object)
178     {
179         return object.toXMLString();
180     },
181 
182     asShortString: function(object)
183     {
184         return cropMultipleLines(this.asString(object));
185     },
186 });
187 
188 // ********************************************************************************************* //
189 
190 FirebugReps.Text = domplate(Firebug.Rep,
191 {
192     tag: OBJECTBOX("$object"),
193 
194     shortTag: OBJECTBOX("$object|cropMultipleLines"),
195 
196     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
197 
198     className: "text"
199 });
200 
201 // ********************************************************************************************* //
202 
203 FirebugReps.Caption = domplate(Firebug.Rep,
204 {
205     tag: SPAN({"class": "caption"}, "$object")
206 });
207 
208 // ********************************************************************************************* //
209 
210 FirebugReps.Warning = domplate(Firebug.Rep,
211 {
212     tag: DIV({"class": "warning focusRow", role : 'listitem'}, "$object|STR")
213 });
214 
215 // ********************************************************************************************* //
216 
217 FirebugReps.Func = domplate(Firebug.Rep,
218 {
219     tag:
220         OBJECTLINK("$object|summarizeFunction"),
221 
222     summarizeFunction: function(fn)
223     {
224         var fnText = Str.safeToString(fn);
225         var namedFn = /^function ([^(]+\([^)]*\)) \{/.exec(fnText);
226         var anonFn  = /^function \(/.test(fnText);
227         var displayName = fn.displayName;
228 
229         return namedFn ? namedFn[1] : (displayName ? displayName + "()" :
230             (anonFn ? "function()" : fnText));
231     },
232 
233     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
234 
235     copySource: function(fn)
236     {
237         if (fn && typeof (fn['toSource']) == 'function')
238             System.copyToClipboard(fn.toSource());
239     },
240 
241     monitor: function(fn, monitored)
242     {
243         if (monitored)
244             Firebug.Debugger.unmonitorFunction(fn,  "monitor");
245         else
246             Firebug.Debugger.monitorFunction(fn, "monitor");
247     },
248 
249     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
250 
251     className: "function",
252 
253     supportsObject: function(object, type)
254     {
255         return type == "function";
256     },
257 
258     inspectObject: function(fn, context)
259     {
260         var sourceLink = Firebug.SourceFile.findSourceForFunction(fn, context);
261         if (sourceLink)
262             Firebug.chrome.select(sourceLink);
263         if (FBTrace.DBG_FUNCTION_NAME)
264             FBTrace.sysout("reps.function.inspectObject selected sourceLink is ", sourceLink);
265     },
266 
267     getTooltip: function(fn, context)
268     {
269         var script = Firebug.SourceFile.findScriptForFunctionInContext(context, fn);
270         if (script)
271         {
272             return Locale.$STRF("Line", [Url.normalizeURL(script.fileName),
273                 script.baseLineNumber]);
274         }
275         else
276         {
277             if (fn.toString)
278                 return fn.toString();
279         }
280     },
281 
282     getTitle: function(fn, context)
283     {
284         var name = fn.name ? fn.name : "function";
285         return name + "()";
286     },
287 
288     getContextMenuItems: function(fn, target, context, script)
289     {
290         if (!script)
291             script = Firebug.SourceFile.findScriptForFunctionInContext(context, fn);
292         if (!script)
293             return;
294 
295         var scriptInfo = Firebug.SourceFile.getSourceFileAndLineByScript(context, script);
296         var monitored = scriptInfo ? FBS.fbs.isMonitored(scriptInfo.sourceFile.href,
297             scriptInfo.lineNo) : false;
298 
299         var self = this;
300         var name = script ? StackFrame.getFunctionName(script, context) : fn.name;
301         return [
302             {
303                 label: Locale.$STRF("ShowCallsInConsole", [name]),
304                 tooltiptext: Locale.$STRF("dom.tip.Log_Calls_To_Function", [name]),
305                 nol10n: true,
306                 type: "checkbox",
307                 checked: monitored,
308                 command: function()
309                 {
310                     var checked = this.hasAttribute("checked");
311                     self.monitor(fn, !checked);
312                 }
313             },
314             "-",
315             {
316                 label: "CopySource",
317                 tooltiptext: "dom.tip.Copy_Source",
318                 command: Obj.bindFixed(this.copySource, this, fn)
319             }
320         ];
321     }
322 });
323 
324 // ********************************************************************************************* //
325 
326 FirebugReps.Obj = domplate(Firebug.Rep,
327 {
328     tag:
329         OBJECTLINK(
330             SPAN({"class": "objectTitle"}, "$object|getTitle "),
331             SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"),
332             FOR("prop", "$object|shortPropIterator",
333                 " $prop.name",
334                 SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"),
335                 TAG("$prop.tag", {object: "$prop.object"}),
336                 SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim")
337             ),
338             SPAN({"class": "objectRightBrace"}, "}")
339         ),
340 
341     shortTag:
342         OBJECTLINK(
343             SPAN({"class": "objectTitle"}, "$object|getTitle "),
344             SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"),
345             FOR("prop", "$object|shortPropIterator",
346                 " $prop.name",
347                 SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"),
348                 TAG("$prop.tag", {object: "$prop.object"}),
349                 SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim")
350             ),
351             SPAN({"class": "objectRightBrace"}, "}")
352         ),
353 
354     titleTag:
355         SPAN({"class": "objectTitle"}, "$object|getTitleTag"),
356 
357     getTitleTag: function(object)
358     {
359         var title;
360         if (typeof(object) == "string")
361             title = object;
362         else
363             title = this.getTitle(object);
364 
365         if (title == "Object")
366             title = "{...}";
367 
368         return title;
369     },
370 
371     longPropIterator: function (object)
372     {
373         return this.propIterator(object, 100);
374     },
375 
376     shortPropIterator: function (object)
377     {
378         return this.propIterator(object, Options.get("ObjectShortIteratorMax"));
379     },
380 
381     propIterator: function (object, max)
382     {
383         var props = [];
384 
385         // Object members with non-empty values are preferred since it gives the
386         // user a better overview of the object.
387         this.getProps(props, object, max, function(t, value)
388         {
389             return (t == "boolean" || t == "number" || (t == "string" && value) ||
390                 (t == "object" && value && value.toString));
391         });
392 
393         if (props.length+1 <= max)
394         {
395             // There is not enough props yet, let's display also empty members and functions.
396             this.getProps(props, object, max, function(t, value)
397             {
398                 return ((t == "string" && !value) || (t == "object" && !value) ||
399                     (t == "function"));
400             });
401         }
402 
403         if (props.length > max)
404         {
405             props[props.length-1] = {
406                 object: Locale.$STR("firebug.reps.more") + "...",
407                 tag: FirebugReps.Caption.tag,
408                 name: "",
409                 equal: "",
410                 delim: ""
411             };
412         }
413         else if (props.length > 0)
414         {
415             props[props.length-1].delim = '';
416         }
417 
418         return props;
419     },
420 
421     getProps: function (props, object, max, filter)
422     {
423         max = max || 3;
424         if (!object)
425             return [];
426 
427         var len = 0;
428 
429         try
430         {
431             for (var name in object)
432             {
433                 var value;
434                 try
435                 {
436                     value = object[name];
437                 }
438                 catch (exc)
439                 {
440                     continue;
441                 }
442 
443                 var t = typeof(value);
444                 if (filter(t, value))
445                 {
446                     var rep = Firebug.getRep(value);
447                     var tag = rep.shortTag || rep.tag;
448                     if ((t == "object" || t == "function") && value)
449                     {
450                         value = rep.getTitle(value);
451                         if (rep.titleTag)
452                             tag = rep.titleTag;
453                         else
454                             tag = FirebugReps.Obj.titleTag;
455                     }
456 
457                     if (props.length <= max)
458                         props.push({tag: tag, name: name, object: value, equal: "=", delim: ", "});
459                     else
460                         break;
461                 }
462             }
463         }
464         catch (exc)
465         {
466             // Sometimes we get exceptions when trying to read from certain objects, like
467             // StorageList, but don't let that gum up the works
468             // XXXjjb also History.previous fails because object is a web-page object
469             // which does not have permission to read the history
470         }
471     },
472 
473     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
474 
475     className: "object",
476 
477     supportsObject: function(object, type)
478     {
479         return true;
480     }
481 });
482 
483 // ********************************************************************************************* //
484 // Reference
485 
486 /**
487  * A placeholder used instead of cycle reference within arrays.
488  * @param {Object} target The original referenced object
489  */
490 FirebugReps.ReferenceObj = function(target)
491 {
492     this.target = target;
493 }
494 
495 /**
496  * Rep for cycle reference in an array.
497  */
498 FirebugReps.Reference = domplate(Firebug.Rep,
499 {
500     tag:
501         OBJECTLINK({_repObject: "$object"},
502             SPAN({title: "$object|getTooltip"},
503                 "[...]")
504         ),
505 
506     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
507 
508     className: "Reference",
509 
510     supportsObject: function(object, type)
511     {
512         return (object instanceof FirebugReps.ReferenceObj);
513     },
514 
515     getTooltip: function(object)
516     {
517         return Locale.$STR("firebug.reps.reference");
518     },
519 
520     getRealObject: function(object)
521     {
522         return object.target;
523     },
524 });
525 
526 // ********************************************************************************************* //
527 
528 FirebugReps.ArrBase = domplate(FirebugReps.Obj,
529 {
530     className: "array",
531     toggles: new ToggleBranch.ToggleBranch(),
532 
533     titleTag:
534         SPAN({"class": "objectTitle"}, "$object|getTitleTag"),
535 
536     getTitle: function(object, context)
537     {
538         return "[" + object.length + "]";
539     },
540 
541     supportsObject: function(object, type)
542     {
543         return this.isArray(object);
544     },
545 
546     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
547 
548     longArrayIterator: function(array)
549     {
550         return this.arrayIterator(array, 300);
551     },
552 
553     shortArrayIterator: function(array)
554     {
555         return this.arrayIterator(array, Options.get("ObjectShortIteratorMax"));
556     },
557 
558     arrayIterator: function(array, max)
559     {
560         var items = [];
561         for (var i = 0; i < array.length && i <= max; ++i)
562         {
563             try
564             {
565                 var delim = (i == array.length-1 ? "" : ", ");
566                 var value = array[i];
567 
568                 // Cycle detected
569                 if (value === array)
570                     value = new FirebugReps.ReferenceObj(value);
571 
572                 var rep = Firebug.getRep(value);
573                 var tag = rep.shortTag || rep.tag;
574                 items.push({object: value, tag: tag, delim: delim});
575             }
576             catch (exc)
577             {
578                 var rep = Firebug.getRep(exc);
579                 var tag = rep.shortTag || rep.tag;
580 
581                 items.push({object: exc, tag: tag, delim: delim});
582             }
583         }
584 
585         if (array.length > max + 1)
586         {
587             items[max] = {
588                 object: (array.length-max) + " " + Locale.$STR("firebug.reps.more") + "...",
589                 tag: FirebugReps.Caption.tag,
590                 delim: ""
591             };
592         }
593 
594         return items;
595     },
596 
597     getItemIndex: function(child)
598     {
599         var arrayIndex = 0;
600         for (child = child.previousSibling; child; child = child.previousSibling)
601         {
602             if (child.repObject)
603                 ++arrayIndex;
604         }
605         return arrayIndex;
606     },
607 
608     /**
609      * Returns true if the passed object is an array with additional (custom) properties,
610      * otherwise returns false. Custom properties should be displayed in extra expandable
611      * section.
612      *
613      * Example array with a custom property.
614      * var arr = [0, 1];
615      * arr.myProp = "Hello";
616      *
617      * @param {Array} array The array object.
618      */
619     hasSpecialProperties: function(array)
620     {
621         function isInteger(x)
622         {
623             var y = parseInt(x, 10);
624             if (isNaN(y))
625                 return false;
626            return x === y.toString();
627         }
628 
629         var n = 0;
630         var props = Object.getOwnPropertyNames(array);
631         for (var i=0; i<props.length; i++)
632         {
633             var p = props[i];
634 
635             // Valid indexes are skipped
636             if (isInteger(p))
637                 continue;
638 
639             // Ignore standard 'length' property, anything else is custom.
640             if (p != "length")
641                 return true;
642         }
643 
644         return false;
645     },
646 
647     onToggleProperties: function(event)
648     {
649         var target = event.originalTarget;
650         if (Css.hasClass(target, "objectBox-array"))
651         {
652             Events.cancelEvent(event);
653 
654             Css.toggleClass(target, "opened");
655 
656             var propBox = target.getElementsByClassName("arrayProperties").item(0);
657             if (Css.hasClass(target, "opened"))
658             {
659                 Firebug.DOMPanel.DirTable.tag.replace(
660                     {object: target.repObject, toggles: this.toggles}, propBox);
661             }
662             else
663             {
664                 Dom.clearNode(propBox);
665             }
666         }
667     },
668 
669     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
670 
671     highlightObject: function(object, context, target)
672     {
673         // Highlighting huge amount of elements on the page can cause serious performance
674         // problems (see issue 4736). So, avoid highlighting if the number of elements in
675         // the array exceeds specified limit.
676         var arr = this.getRealObject(object, context);
677         var limit = Options.get("multiHighlightLimit");
678         if (!arr || (limit > 0 && arr.length > limit))
679         {
680             if (Css.hasClass(target, "arrayLeftBracket") ||
681                 Css.hasClass(target, "arrayRightBracket"))
682             {
683                 var tooltip = Locale.$STRF("console.multiHighlightLimitExceeded", [limit]);
684                 target.setAttribute("title", tooltip);
685             }
686 
687             // Do not highlight, a tooltip will be displayed instead.
688             return;
689         }
690 
691         target.removeAttribute("title");
692 
693         // Highlight multiple elements on the page.
694         Firebug.Inspector.highlightObject(arr, context);
695     },
696 
697     isArray: function(obj)
698     {
699         return false;
700     }
701 });
702 
703 // ********************************************************************************************* //
704 
705 FirebugReps.Arr = domplate(FirebugReps.ArrBase,
706 {
707     tag:
708         OBJECTBOX({_repObject: "$object",
709             $hasTwisty: "$object|hasSpecialProperties",
710             onclick: "$onToggleProperties"},
711             SPAN({"class": "arrayLeftBracket", role: "presentation"}, "["),
712             FOR("item", "$object|longArrayIterator",
713                 TAG("$item.tag", {object: "$item.object"}),
714                 SPAN({"class": "arrayComma", role: "presentation"}, "$item.delim")
715             ),
716             SPAN({"class": "arrayRightBracket", role: "presentation"}, "]"),
717             SPAN({"class": "arrayProperties", role: "group"})
718         ),
719 
720     shortTag:
721         OBJECTBOX({_repObject: "$object",
722             $hasTwisty: "$object|hasSpecialProperties",
723             onclick: "$onToggleProperties"},
724             SPAN({"class": "arrayLeftBracket", role: "presentation"}, "["),
725             FOR("item", "$object|shortArrayIterator",
726                 TAG("$item.tag", {object: "$item.object"}),
727                 SPAN({"class": "arrayComma", role: "presentation"}, "$item.delim")
728             ),
729             SPAN({"class": "arrayRightBracket"}, "]"),
730             SPAN({"class": "arrayProperties", role: "group"})
731         ),
732 
733     // http://code.google.com/p/fbug/issues/detail?id=874
734     isArray: function(obj)
735     {
736         try
737         {
738             if (Arr.isArray(obj))
739                 return true;
740             else if (isFinite(obj.length) && typeof obj.callee === "function") // arguments
741                 return true;
742         }
743         catch (exc) {}
744         return false;
745     }
746 });
747 
748 // ********************************************************************************************* //
749 
750 /**
751  * Any arrayish object that is not directly Array type (e.g. HTMLCollection, NodeList, etc.)
752  */
753 FirebugReps.ArrayLikeObject = domplate(FirebugReps.ArrBase,
754 {
755     tag:
756         OBJECTBOX({_repObject: "$object",
757             $hasTwisty: "$object|hasSpecialProperties",
758             onclick: "$onToggleProperties"},
759             A({"class": "objectTitle objectLink", onclick: "$onClickTitle"},
760                 "$object|getTitle"
761             ),
762             SPAN({"class": "arrayLeftBracket", role: "presentation"}, "["),
763             FOR("item", "$object|longArrayIterator",
764                 TAG("$item.tag", {object: "$item.object"}),
765                 SPAN({"class": "arrayComma", role: "presentation"}, "$item.delim")
766             ),
767             SPAN({"class": "arrayRightBracket", role: "presentation"}, "]"),
768             SPAN({"class": "arrayProperties", role: "group"})
769         ),
770 
771     shortTag:
772         OBJECTBOX({_repObject: "$object",
773             $hasTwisty: "$object|hasSpecialProperties",
774             onclick: "$onToggleProperties"},
775             A({"class": "objectTitle objectLink", onclick: "$onClickTitle"},
776                 "$object|getTitle"
777             ),
778             SPAN({"class": "arrayLeftBracket", role: "presentation"}, "["),
779             FOR("item", "$object|shortArrayIterator",
780                 TAG("$item.tag", {object: "$item.object"}),
781                 SPAN({"class": "arrayComma", role: "presentation"}, "$item.delim")
782             ),
783             SPAN({"class": "arrayRightBracket"}, "]"),
784             SPAN({"class": "arrayProperties", role: "group"})
785         ),
786 
787     onClickTitle: function(event)
788     {
789         var obj = Firebug.getRepObject(event.target);
790         Firebug.chrome.select(obj);
791     },
792 
793     getTitle: function(obj, context)
794     {
795         var arr = Wrapper.unwrapObject(obj);
796         const re =/\[object ([^\]]*)/;
797         var label = Str.safeToString(arr);
798         var m = re.exec(label);
799         if (m)
800             return m[1] || label;
801 
802         if ((arr instanceof Ci.nsIDOMDOMTokenList) || (this.isTokenList_Fx19(obj)))
803             return "DOMTokenList";
804 
805         return "";
806     },
807 
808     isArray: function(obj)
809     {
810         if (this.isArrayLike_Fx19(obj))
811             return true;
812 
813         return Arr.isArrayLike(obj);
814     },
815 
816     /**
817      * Hack for Firefox 19 where obj instanceof Ci.nsIDOMDOMTokenList doesn't work.
818      */
819     isTokenList_Fx19: function(obj)
820     {
821         var context = Firebug.currentContext;
822         if (!context)
823             return false;
824 
825         var view = Wrapper.getContentView(context.window);
826         if (!view)
827             return false;
828 
829         obj = Wrapper.unwrapObject(obj);
830         return (obj instanceof view.DOMTokenList);
831     },
832 
833     /**
834      * Hack for Firefox 19 where obj instanceof Ci.nsIDOMDOMTokenList,
835      * Ci.nsIDOMHTMLCollection and nsIDOMNodeList doesn't work.
836      */
837     isArrayLike_Fx19: function(obj)
838     {
839         var context = Firebug.currentContext;
840         if (!context)
841             return false;
842 
843         var view = Wrapper.getContentView(context.window);
844         if (!view)
845             return false;
846 
847         obj = Wrapper.unwrapObject(obj);
848         return (obj instanceof view.DOMTokenList) || (obj instanceof view.HTMLCollection) ||
849             (obj instanceof view.NodeList);
850     },
851 });
852 
853 // ********************************************************************************************* //
854 
855 FirebugReps.Property = domplate(Firebug.Rep,
856 {
857     supportsObject: function(object, type)
858     {
859         return object instanceof FirebugReps.PropertyObj;
860     },
861 
862     getRealObject: function(prop, context)
863     {
864         return prop.object[prop.name];
865     },
866 
867     getTitle: function(prop, context)
868     {
869         return prop.name;
870     }
871 });
872 
873 // ********************************************************************************************* //
874 
875 FirebugReps.PropertyObj = function(object, name)
876 {
877     this.object = object;
878     this.name = name;
879 
880     this.getObject = function()
881     {
882         return object[name];
883     };
884 };
885 
886 // ********************************************************************************************* //
887 
888 FirebugReps.NetFile = domplate(FirebugReps.Obj,
889 {
890     supportsObject: function(object, type)
891     {
892         if (typeof(Firebug.NetFile) == "undefined")
893             return false;
894 
895         return object instanceof Firebug.NetFile;
896     },
897 
898     browseObject: function(file, context)
899     {
900         Win.openNewTab(file.href);
901         return true;
902     },
903 
904     getRealObject: function(file, context)
905     {
906         return null;
907     }
908 });
909 
910 // ********************************************************************************************* //
911 
912 function instanceOf(object, Klass)
913 {
914     while (object != null)
915     {
916         if (object == Klass.prototype)
917            return true;
918 
919         if ( typeof(object) === 'xml')
920             return (Klass.prototype === Xml.prototype);
921 
922         object = object.__proto__;
923     }
924     return false;
925 }
926 
927 
928 
929 // ********************************************************************************************* //
930 
931 FirebugReps.Element = domplate(Firebug.Rep,
932 {
933     tag:
934         OBJECTLINK(
935             "<",
936             SPAN({"class": "nodeTag"}, "$object|getLocalName"),
937             FOR("attr", "$object|attrIterator",
938                 " $attr.localName="",
939                 SPAN({"class": "nodeValue"}, "$attr|getAttrValue"),
940                 """
941             ),
942             ">"
943          ),
944 
945     shortTag:
946         OBJECTLINK(
947             SPAN({"class": "$object|getVisible"},
948                 SPAN({"class": "selectorTag"}, "$object|getSelectorTag"),
949                 SPAN({"class": "selectorId"}, "$object|getSelectorId"),
950                 SPAN({"class": "selectorClass"}, "$object|getSelectorClass"),
951                 SPAN({"class": "selectorValue"}, "$object|getValue")
952             )
953          ),
954 
955     getLocalName: function(object)
956     {
957         try
958         {
959             return Xml.getLocalName(object);
960         }
961         catch (err)
962         {
963             return "";
964         }
965     },
966 
967     getNodeName: function(object)
968     {
969         try
970         {
971             return Xml.getNodeName(object);
972         }
973         catch (err)
974         {
975             return "";
976         }
977     },
978 
979     getAttrValue: function(attr)
980     {
981         var limit = Firebug.displayedAttributeValueLimit;
982         return (limit > 0) ? Str.cropString(attr.value, limit) : attr.value;
983     },
984 
985     getVisible: function(elt)
986     {
987         return Xml.isVisible(elt) ? "" : "selectorHidden";
988     },
989 
990     getSelectorTag: function(elt)
991     {
992         return this.getLocalName(elt);
993     },
994 
995     getSelectorId: function(elt)
996     {
997         try
998         {
999             return elt.id ? ("#" + elt.id) : "";
1000         }
1001         catch (e)
1002         {
1003             return "";
1004         }
1005     },
1006 
1007     getSelectorClass: function(elt)
1008     {
1009         try
1010         {
1011             return elt.classList.length > 0 ? ("." + elt.classList[0]) : "";
1012         }
1013         catch (err)
1014         {
1015             return "";
1016         }
1017     },
1018 
1019     getValue: function(elt)
1020     {
1021         var value;
1022 
1023         if (elt instanceof window.HTMLImageElement)
1024             value = Url.getFileName(elt.getAttribute("src"));
1025         else if (elt instanceof window.HTMLAnchorElement)
1026             value = Url.getFileName(elt.getAttribute("href"));
1027         else if (elt instanceof window.HTMLInputElement)
1028             value = elt.getAttribute("value");
1029         else if (elt instanceof window.HTMLFormElement)
1030             value = Url.getFileName(elt.getAttribute("action"));
1031         else if (elt instanceof window.HTMLScriptElement)
1032             value = Url.getFileName(elt.getAttribute("src"));
1033 
1034         return value ? " " + Str.cropMultipleLines(value, 20) : "";
1035     },
1036 
1037     attrIterator: function(elt)
1038     {
1039         var attrs = [];
1040         var idAttr, classAttr;
1041         if (elt.attributes)
1042         {
1043             for (var i = 0; i < elt.attributes.length; ++i)
1044             {
1045                 var attr = elt.attributes[i];
1046                 if (attr.localName.indexOf("-moz-math") != -1)
1047                     continue;
1048                 if (attr.localName.indexOf("firebug-") != -1)
1049                     continue;
1050                 else if (attr.localName == "id")
1051                     idAttr = attr;
1052                 else if (attr.localName == "class")
1053                     classAttr = attr;
1054                 else
1055                     attrs.push(attr);
1056             }
1057         }
1058 
1059         // Make sure 'id' and 'class' attributes are displayed first.
1060         if (classAttr)
1061             attrs.splice(0, 0, classAttr);
1062         if (idAttr)
1063             attrs.splice(0, 0, idAttr);
1064 
1065         return attrs;
1066     },
1067 
1068     shortAttrIterator: function(elt)
1069     {
1070         // Short version returns only 'id' and 'class' attributes.
1071         var attrs = [];
1072         if (elt.attributes)
1073         {
1074             for (var i = 0; i < elt.attributes.length; ++i)
1075             {
1076                 var attr = elt.attributes[i];
1077                 if (attr.localName == "id" || attr.localName == "class")
1078                     attrs.push(attr);
1079             }
1080         }
1081         return attrs;
1082     },
1083 
1084     getHidden: function(elt)
1085     {
1086         return Xml.isVisible(elt) ? "" : "nodeHidden";
1087     },
1088 
1089     getXPath: function(elt)
1090     {
1091         return Xpath.getElementTreeXPath(elt);
1092     },
1093 
1094     getNodeTextGroups: function(element)
1095     {
1096         var text =  element.textContent;
1097         if (!Firebug.showFullTextNodes)
1098         {
1099             text = Str.cropString(text,50);
1100         }
1101 
1102         var escapeGroups=[];
1103 
1104         if (Firebug.showTextNodesWithWhitespace)
1105             escapeGroups.push({
1106                 "group": "whitespace",
1107                 "class": "nodeWhiteSpace",
1108                 "extra": {
1109                     "\t": "_Tab",
1110                     "\n": "_Para",
1111                     " " : "_Space"
1112                 }
1113             });
1114 
1115         if (Firebug.entityDisplay != "symbols")
1116             escapeGroups.push({
1117                 "group": "text",
1118                 "class": "nodeTextEntity",
1119                 "extra": {}
1120             });
1121 
1122         if (escapeGroups.length)
1123             return Str.escapeGroupsForEntities(text, escapeGroups, Options.get("entityDisplay"));
1124         else
1125             return [{str:text, "class": "", extra: ""}];
1126     },
1127 
1128     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1129 
1130     copyHTML: function(elt)
1131     {
1132         var html = Xml.getElementHTML(elt);
1133         System.copyToClipboard(html);
1134     },
1135 
1136     copyInnerHTML: function(elt)
1137     {
1138         System.copyToClipboard(elt.innerHTML);
1139     },
1140 
1141     copyXPath: function(elt)
1142     {
1143         var xpath = Xpath.getElementXPath(elt);
1144         System.copyToClipboard(xpath);
1145     },
1146 
1147     copyCSSPath: function(elt)
1148     {
1149         var csspath = Css.getElementCSSPath(elt);
1150         System.copyToClipboard(csspath);
1151     },
1152 
1153     paste: function(elt, clipboardContent, mode)
1154     {
1155         if (elt instanceof window.HTMLElement)
1156             return this.pasteHTML.apply(this, arguments);
1157         else
1158             return this.pasteXML.apply(this, arguments);
1159     },
1160 
1161     pasteHTML: function(elt, clipboardContent, mode)
1162     {
1163         if (mode === "replaceInner")
1164             elt.innerHTML = clipboardContent;
1165         else if (mode === "replaceOuter")
1166             elt.outerHTML = clipboardContent;
1167         else
1168             elt.insertAdjacentHTML(mode, clipboardContent);
1169     },
1170 
1171     pasteXML: function(elt, clipboardContent, mode)
1172     {
1173         var contextNode, parentNode = elt.parentNode;
1174         if (["beforeBegin", "afterEnd", "replaceOuter"].indexOf(mode) >= 0)
1175             contextNode = parentNode;
1176         else
1177             contextNode = elt;
1178 
1179         var pastedElements = Dom.markupToDocFragment(clipboardContent, contextNode);
1180         switch (mode)
1181         {
1182             case "beforeBegin":
1183                 parentNode.insertBefore(pastedElements, elt);
1184                 break;
1185             case "afterBegin":
1186                 elt.insertBefore(pastedElements, elt.firstChild);
1187                 break;
1188             case "beforeEnd":
1189                 elt.appendChild(pastedElements);
1190                 break;
1191             case "afterEnd":
1192                 Dom.insertAfter(pastedElements, elt);
1193                 break;
1194             case "replaceInner":
1195                 Dom.eraseNode(elt);
1196                 elt.appendChild(pastedElements);
1197                 break;
1198             case "replaceOuter":
1199                 parentNode.replaceChild(pastedElements, elt);
1200                 break;
1201         }
1202     },
1203 
1204     persistor: function(context, xpath)
1205     {
1206         var elts = xpath
1207             ? Xpath.getElementsByXPath(context.window.document, xpath)
1208             : null;
1209 
1210         return elts && elts.length ? elts[0] : null;
1211     },
1212 
1213     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1214 
1215     className: "element",
1216 
1217     supportsObject: function(object, type)
1218     {
1219         return object instanceof window.Element;
1220     },
1221 
1222     browseObject: function(elt, context)
1223     {
1224         var tag = elt.localName.toLowerCase();
1225         if (tag == "script")
1226             Win.openNewTab(elt.src);
1227         else if (tag == "link")
1228             Win.openNewTab(elt.href);
1229         else if (tag == "a")
1230             Win.openNewTab(elt.href);
1231         else if (tag == "img")
1232             Win.openNewTab(elt.src);
1233 
1234         return true;
1235     },
1236 
1237     persistObject: function(elt, context)
1238     {
1239         var xpath = Xpath.getElementXPath(elt);
1240 
1241         return Obj.bind(this.persistor, window.top, xpath);
1242     },
1243 
1244     getTitle: function(element, context)
1245     {
1246         return Css.getElementCSSSelector(element);
1247     },
1248 
1249     getTooltip: function(elt)
1250     {
1251         var tooltip = this.getXPath(elt);
1252 
1253         if (elt.namespaceURI)
1254             tooltip += " (" + elt.namespaceURI + ")";
1255 
1256         return tooltip;
1257     },
1258 
1259     getContextMenuItems: function(elt, target, context)
1260     {
1261         // XXX: Temporary fix for issue 5577.
1262         if (Dom.getAncestorByClass(target, "cssElementRuleContainer"))
1263             return;
1264 
1265         var type;
1266         var items = [];
1267         var clipboardContent = System.getStringDataFromClipboard();
1268         var isEltRoot = (elt === elt.ownerDocument.documentElement);
1269 
1270         if (Xml.isElementHTML(elt) || Xml.isElementXHTML(elt))
1271             type = "HTML";
1272         else if (Xml.isElementMathML(elt))
1273             type = "MathML";
1274         else if (Xml.isElementSVG(elt))
1275             type = "SVG";
1276         else if (Xml.isElementXUL(elt))
1277             type = "XUL";
1278         else
1279             type = "XML";
1280 
1281         items.push(
1282         {
1283             label: Locale.$STRF("html.Copy_Node", [type]),
1284             tooltiptext: Locale.$STRF("html.tip.Copy_Node", [type]),
1285             command: Obj.bindFixed(this.copyHTML, this, elt)
1286         });
1287 
1288         if (Xml.isElementHTML(elt) || Xml.isElementXHTML(elt))
1289         {
1290             items.push(
1291             {
1292                 label: "CopyInnerHTML",
1293                 tooltiptext: "html.tip.Copy_innerHTML",
1294                 command: Obj.bindFixed(this.copyInnerHTML, this, elt)
1295             });
1296         }
1297 
1298         items = items.concat([
1299             {
1300                 label: "CopyXPath",
1301                 tooltiptext: "html.tip.Copy_XPath",
1302                 id: "fbCopyXPath",
1303                 command: Obj.bindFixed(this.copyXPath, this, elt)
1304             },
1305             {
1306                 label: "Copy_CSS_Path",
1307                 tooltiptext: "html.tip.Copy_CSS_Path",
1308                 id: "fbCopyCSSPath",
1309                 command: Obj.bindFixed(this.copyCSSPath, this, elt)
1310             },
1311             {
1312                 label: Locale.$STRF("html.menu.Paste", [type]),
1313                 tooltiptext: Locale.$STRF("html.tip.Paste", [type]),
1314                 disabled: !clipboardContent,
1315                 id: "fbPaste",
1316                 items: [
1317                     {
1318                         label: "html.menu.Paste_Replace_Content",
1319                         tooltiptext: "html.tip.Paste_Replace_Content",
1320                         id: "fbPasteReplaceInner",
1321                         command: Obj.bindFixed(this.paste, this, elt, clipboardContent, 
1322                             "replaceInner")
1323                     },
1324                     {
1325                         label: "html.menu.Paste_Replace_Node",
1326                         tooltiptext: "html.tip.Paste_Replace_Node",
1327                         id: "fbPasteReplaceOuter",
1328                         disabled: isEltRoot,
1329                         command: Obj.bindFixed(this.paste, this, elt, clipboardContent, 
1330                             "replaceOuter")
1331                     },
1332                     {
1333                         label: "html.menu.Paste_AsFirstChild",
1334                         tooltiptext: "html.tip.Paste_AsFirstChild",
1335                         id: "fbPasteFirstChild",
1336                         command: Obj.bindFixed(this.paste, this, elt, clipboardContent,
1337                             "afterBegin")
1338                     },
1339                     {
1340                         label: "html.menu.Paste_AsLastChild",
1341                         tooltiptext: "html.tip.Paste_AsLastChild",
1342                         id: "fbPasteLastChild",
1343                         command: Obj.bindFixed(this.paste, this, elt, clipboardContent, "beforeEnd")
1344                     },
1345                     {
1346                         label: "html.menu.Paste_Before",
1347                         tooltiptext: "html.tip.Paste_Before",
1348                         id: "fbPasteBefore",
1349                         disabled: isEltRoot,
1350                         command: Obj.bindFixed(this.paste, this, elt, clipboardContent,
1351                             "beforeBegin")
1352                     },
1353                     {
1354                         label: "html.menu.Paste_After",
1355                         tooltiptext: "html.tip.Paste_After",
1356                         id: "fbPasteAfter",
1357                         disabled: isEltRoot,
1358                         command: Obj.bindFixed(this.paste, this, elt, clipboardContent, "afterEnd")
1359                     }
1360                 ]
1361             }
1362         ]);
1363 
1364         var tag = elt.localName.toLowerCase();
1365         if (tag == "script" || tag == "link" || tag == "a" || tag == "img")
1366         {
1367             items = items.concat([
1368                 "-",
1369                 {
1370                     label: "OpenInTab",
1371                     tooltiptext: "firebug.tip.Open_In_Tab",
1372                     command: Obj.bindFixed(this.browseObject, this, elt, context)
1373                 }
1374             ]);
1375         }
1376 
1377         items = items.concat([
1378             "-",
1379             {
1380                 label: "ShowEventsInConsole",
1381                 tooltiptext: "html.tip.Show_Events_In_Console",
1382                 id: "fbShowEventsInConsole",
1383                 type: "checkbox",
1384                 checked: EventMonitor.areEventsMonitored(elt, null, context),
1385                 command: function()
1386                 {
1387                     var checked = this.hasAttribute("checked");
1388                     EventMonitor.toggleMonitorEvents(elt, null, !checked, context);
1389                 }
1390             },
1391             "-",
1392             {
1393                 label: "ScrollIntoView",
1394                 tooltiptext: "html.tip.Scroll_Into_View",
1395                 id: "fbScrollIntoView",
1396                 command: Obj.bindFixed(elt.scrollIntoView, elt)
1397             }
1398         ]);
1399 
1400         return items;
1401     }
1402 });
1403 
1404 // ********************************************************************************************* //
1405 
1406 FirebugReps.TextNode = domplate(Firebug.Rep,
1407 {
1408     tag:
1409         OBJECTLINK(
1410             "<",
1411             SPAN({"class": "nodeTag"}, "TextNode"),
1412             " textContent="",
1413             SPAN({"class": "nodeValue"}, "$object.textContent|cropMultipleLines"),
1414             """,
1415             ">"
1416         ),
1417 
1418     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1419 
1420     className: "textNode",
1421 
1422     inspectObject: function(node, context)
1423     {
1424         // Text nodes have two displays in HTML panel, inline and distinct
1425         // node. We need to examine which case we are dealing with in order to
1426         // select the proper object.
1427         if (HTMLLib.hasNoElementChildren(node.parentNode))
1428         {
1429             node = node.parentNode;
1430         }
1431 
1432         Firebug.chrome.select(node, "html", "domSide");
1433     },
1434 
1435     supportsObject: function(object, type)
1436     {
1437         return object instanceof window.Text;
1438     },
1439 
1440     getTitle: function(win, context)
1441     {
1442         return "textNode";
1443     }
1444 });
1445 
1446 // ********************************************************************************************* //
1447 
1448 FirebugReps.RegExp = domplate(Firebug.Rep,
1449 {
1450     tag:
1451         OBJECTLINK(
1452             SPAN({"class": "objectTitle"}, "$object|getTitle"),
1453             SPAN(" "),
1454             SPAN({"class": "regexpSource"}, "$object|getSource")
1455         ),
1456 
1457     className: "regexp",
1458 
1459     supportsObject: function(object, type)
1460     {
1461         try
1462         {
1463             return type == "object" && Object.prototype.toString.call(object) === "[object RegExp]";
1464         }
1465         catch (err)
1466         {
1467             if (FBTrace.DBG_ERRORS)
1468                 FBTrace.sysout("reps.RegExp.supportsObject; EXCEPTION " + err, err)
1469         }
1470     },
1471 
1472     getSource: function(object)
1473     {
1474         var source = "/" + object.source + "/";
1475         source += object.ignoreCase ? "i" : "";
1476         source += object.global ? "g" : "";
1477         source += object.multiline ? "m" : "";
1478         return source;
1479     }
1480 });
1481 
1482 // ********************************************************************************************* //
1483 
1484 FirebugReps.Document = domplate(Firebug.Rep,
1485 {
1486     tag:
1487         OBJECTLINK("Document ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
1488 
1489     getLocation: function(doc)
1490     {
1491         return doc.location ? Url.getFileName(doc.location.href) : "";
1492     },
1493 
1494     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1495 
1496     className: "object",
1497 
1498     supportsObject: function(object, type)
1499     {
1500         return object instanceof window.Document || object instanceof window.XMLDocument;
1501     },
1502 
1503     browseObject: function(doc, context)
1504     {
1505         Win.openNewTab(doc.location.href);
1506         return true;
1507     },
1508 
1509     persistObject: function(doc, context)
1510     {
1511         return this.persistor;
1512     },
1513 
1514     persistor: function(context)
1515     {
1516         return context.window.document;
1517     },
1518 
1519     getTitle: function(win, context)
1520     {
1521         return "document";
1522     },
1523 
1524     getTooltip: function(doc)
1525     {
1526         return doc.location.href;
1527     }
1528 });
1529 
1530 // ********************************************************************************************* //
1531 
1532 FirebugReps.StyleSheet = domplate(Firebug.Rep,
1533 {
1534     tag:
1535         OBJECTLINK("StyleSheet ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
1536 
1537     getLocation: function(styleSheet)
1538     {
1539         return Url.getFileName(styleSheet.href);
1540     },
1541 
1542     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1543 
1544     copyURL: function(styleSheet)
1545     {
1546         var url = Css.getURLForStyleSheet(styleSheet);
1547         if (url)
1548             System.copyToClipboard(url);
1549 
1550         if (FBTrace.DBG_ERRORS && !url)
1551             FBTrace.sysout("reps.StyleSheet.copyURL; ERROR no URL", styleSheet);
1552     },
1553 
1554     openInTab: function(styleSheet)
1555     {
1556         var url = Css.getURLForStyleSheet(styleSheet);
1557         if (url)
1558             Win.openNewTab(url);
1559 
1560         if (FBTrace.DBG_ERRORS && !url)
1561             FBTrace.sysout("reps.StyleSheet.openInTab; ERROR no URL", styleSheet);
1562     },
1563 
1564     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1565 
1566     className: "object",
1567 
1568     supportsObject: function(object, type)
1569     {
1570         return object instanceof window.CSSStyleSheet;
1571     },
1572 
1573     browseObject: function(styleSheet, context)
1574     {
1575         Win.openNewTab(styleSheet.href);
1576         return true;
1577     },
1578 
1579     persistObject: function(styleSheet, context)
1580     {
1581         return Obj.bind(this.persistor, top, styleSheet.href);
1582     },
1583 
1584     getTooltip: function(styleSheet)
1585     {
1586         return styleSheet.href;
1587     },
1588 
1589     getContextMenuItems: function(styleSheet, target, context)
1590     {
1591         return [
1592             {
1593                 label: "CopyLocation",
1594                 tooltiptext: "clipboard.tip.Copy_Location",
1595                 command: Obj.bindFixed(this.copyURL, this, styleSheet)
1596             },
1597             "-",
1598             {
1599                 label: "OpenInTab",
1600                 tooltiptext: "firebug.tip.Open_In_Tab",
1601                 command: Obj.bindFixed(this.openInTab, this, styleSheet)
1602             }
1603         ];
1604     },
1605 
1606     persistor: function(context, href)
1607     {
1608         return Css.getStyleSheetByHref(href, context);
1609     }
1610 });
1611 
1612 //********************************************************************************************* //
1613 
1614 FirebugReps.CSSRule = domplate(Firebug.Rep,
1615 {
1616     tag:
1617         OBJECTLINK("$object|getType ", SPAN({"class": "objectPropValue"}, "$object|getDescription")),
1618 
1619     getType: function(rule)
1620     {
1621         if (rule instanceof window.CSSStyleRule)
1622         {
1623             return "CSSStyleRule";
1624         }
1625         else if (rule instanceof window.CSSFontFaceRule)
1626         {
1627             return "CSSFontFaceRule";
1628         }
1629         else if (rule instanceof window.CSSImportRule)
1630         {
1631             return "CSSImportRule";
1632         }
1633         else if (rule instanceof window.CSSMediaRule)
1634         {
1635             return "CSSMediaRule";
1636         }
1637         else if (rule instanceof window.CSSCharsetRule)
1638         {
1639             return "CSSCharsetRule";
1640         }
1641         else if ((window.CSSKeyframesRule && rule instanceof window.CSSKeyframesRule) ||
1642             rule instanceof window.MozCSSKeyframesRule)
1643         {
1644             return "CSSKeyframesRule";
1645         }
1646         else if ((window.CSSKeyframeRule && rule instanceof window.CSSKeyframeRule) ||
1647             rule instanceof window.MozCSSKeyframeRule)
1648         {
1649             return "CSSKeyframeRule";
1650         }
1651         else if (rule instanceof window.CSSNameSpaceRule)
1652         {
1653             return "CSSNameSpaceRule";
1654         }
1655 
1656         return "CSSRule";
1657     },
1658 
1659     getDescription: function(rule)
1660     {
1661         if (rule instanceof window.CSSStyleRule)
1662         {
1663             return rule.selectorText;
1664         }
1665         else if (rule instanceof window.CSSFontFaceRule)
1666         {
1667             return rule.style.getPropertyValue("font-family");
1668         }
1669         else if (rule instanceof window.CSSImportRule)
1670         {
1671             return Url.getFileName(rule.href);
1672         }
1673         else if (rule instanceof window.CSSMediaRule)
1674         {
1675             return rule.media.mediaText;
1676         }
1677         else if (rule instanceof window.CSSCharsetRule)
1678         {
1679             return rule.encoding;
1680         }
1681         else if ((window.CSSKeyframesRule && rule instanceof window.CSSKeyframesRule) ||
1682             rule instanceof window.MozCSSKeyframesRule)
1683         {
1684             return rule.name;
1685         }
1686         else if ((window.CSSKeyframeRule && rule instanceof window.CSSKeyframeRule) ||
1687             rule instanceof window.MozCSSKeyframeRule)
1688         {
1689             return rule.keyText;
1690         }
1691         else if (rule instanceof window.CSSNameSpaceRule)
1692         {
1693             var reNamespace = /^@namespace (.+ )?url\("(.*?)"\);$/;
1694             var namespace = rule.cssText.match(reNamespace);
1695             var prefix = namespace[1] || "";
1696             var name = namespace[2];
1697             return prefix + name;
1698         }
1699 
1700         return "";
1701     },
1702 
1703     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1704 
1705     className: "object",
1706 
1707     supportsObject: function(object, type)
1708     {
1709         return object instanceof window.CSSRule;
1710     },
1711 
1712     getTooltip: function(rule)
1713     {
1714         if (rule instanceof CSSFontFaceRule)
1715             return Css.extractURLs(rule.style.getPropertyValue("src")).join(", ");
1716         else if (rule instanceof window.CSSImportRule)
1717             return rule.href;
1718 
1719         return "";
1720     }
1721 });
1722 
1723 // ********************************************************************************************* //
1724 
1725 FirebugReps.Window = domplate(Firebug.Rep,
1726 {
1727     tag:
1728         OBJECTLINK("$object|getWindowTitle ",
1729             SPAN({"class": "objectPropValue"},
1730                 "$object|getLocation"
1731             )
1732         ),
1733 
1734     getLocation: function(win)
1735     {
1736         try
1737         {
1738             return (win && win.location && !win.closed) ? Url.getFileName(win.location.href) : "";
1739         }
1740         catch (exc)
1741         {
1742             if (FBTrace.DBG_ERRORS)
1743                 FBTrace.sysout("reps.Window window closed? "+exc, exc);
1744         }
1745     },
1746 
1747     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1748 
1749     className: "object",
1750 
1751     supportsObject: function(object, type)
1752     {
1753         return object instanceof window.Window;
1754     },
1755 
1756     browseObject: function(win, context)
1757     {
1758         Win.openNewTab(win.location.href);
1759         return true;
1760     },
1761 
1762     persistObject: function(win, context)
1763     {
1764         return this.persistor;
1765     },
1766 
1767     persistor: function(context)
1768     {
1769         return context.window;
1770     },
1771 
1772     getTitle: function(win, context)
1773     {
1774         return "window";
1775     },
1776 
1777     getWindowTitle: function(win)
1778     {
1779         if (Firebug.viewChrome)
1780         {
1781             if (win.toString().indexOf('XrayWrapper') !== -1)
1782                 return "XrayWrapper[Window]";
1783         }
1784         return "Window";
1785     },
1786 
1787     getTooltip: function(win)
1788     {
1789         if (win && !win.closed)
1790             return win.location.href;
1791     }
1792 });
1793 
1794 // ********************************************************************************************* //
1795 
1796 FirebugReps.Event = domplate(Firebug.Rep,
1797 {
1798     className: "event",
1799 
1800     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1801 
1802     tag:
1803         TAG("$copyEventTag", {object: "$object|copyEvent"}),
1804 
1805     copyEventTag:
1806         OBJECTLINK("$object|summarizeEvent"),
1807 
1808     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1809 
1810     summarizeEvent: function(event)
1811     {
1812         var info = [event.type, " "];
1813 
1814         var eventFamily = Events.getEventFamily(event.type);
1815         if (eventFamily == "mouse")
1816             info.push("clientX=", event.clientX, ", clientY=", event.clientY);
1817         else if (eventFamily == "key")
1818             info.push("charCode=", event.charCode, ", keyCode=", event.keyCode);
1819         else if (event.type == "message")
1820             info.push("origin=", event.origin, ", data=", event.data);
1821 
1822         return info.join("");
1823     },
1824 
1825     copyEvent: function(event)
1826     {
1827         return new Dom.EventCopy(event);
1828     },
1829 
1830     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1831 
1832     supportsObject: function(object, type)
1833     {
1834         return object instanceof window.Event || object instanceof Dom.EventCopy;
1835     },
1836 
1837     getTitle: function(event, context)
1838     {
1839         return "Event " + event.type;
1840     }
1841 });
1842 
1843 // ********************************************************************************************* //
1844 
1845 FirebugReps.EventLog = domplate(FirebugReps.Event,
1846 {
1847     className: "eventLog",
1848 
1849     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1850 
1851     tag:
1852         TAG("$copyEventTag", {object: "$object|copyEvent"}),
1853 
1854     copyEventTag:
1855         SPAN(
1856             OBJECTLINK("$object|summarizeEvent"),
1857             SPAN(" "),
1858             SPAN("»"),
1859             SPAN(" "),
1860             TAG("$object|getTargetTag", {object: "$object|getTarget"})
1861         ),
1862 
1863     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1864 
1865     copyEvent: function(log)
1866     {
1867         return new Dom.EventCopy(log.event);
1868     },
1869 
1870     getTarget: function(event)
1871     {
1872         return event.target;
1873     },
1874 
1875     getTargetTag: function(event)
1876     {
1877         var rep = Firebug.getRep(event.target);
1878         return rep.shortTag ? rep.shortTag : rep.tag;
1879     },
1880 
1881     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1882 
1883     supportsObject: function(object, type)
1884     {
1885         return object instanceof EventMonitor.EventLog;
1886     },
1887 });
1888 
1889 // ********************************************************************************************* //
1890 
1891 FirebugReps.SourceLink = domplate(Firebug.Rep,
1892 {
1893     tag:
1894         OBJECTLINK(
1895             {$collapsed: "$object|hideSourceLink"},
1896             DIV("$object|getSourceLinkTitle"),
1897             DIV({$systemLink: "$object|isSystemLink"}, "$object|getSystemFlagTitle")),
1898 
1899     isSystemLink: function(sourceLink)
1900     {
1901         return sourceLink && Url.isSystemURL(sourceLink.href);
1902     },
1903 
1904     hideSourceLink: function(sourceLink)
1905     {
1906         try
1907         {
1908             return (sourceLink && sourceLink.href && sourceLink.href.indexOf) ?
1909                 (sourceLink.href.indexOf("XPCSafeJSObjectWrapper") != -1) : true;
1910         }
1911         catch (e)
1912         {
1913             // xxxHonza: I see "Security error" code: "1000" nsresult:
1914             // "0x805303e8 (NS_ERROR_DOM_SECURITY_ERR)"
1915             // when accessing globalStorage property of a page.
1916             if (FBTrace.DBG_ERRORS)
1917                 FBTrace.sysout("reps.hideSourceLink; EXCEPTION " + sourceLink + ", " + e, e);
1918         }
1919 
1920         return true;
1921     },
1922 
1923     getSourceLinkTitle: function(sourceLink)
1924     {
1925         if (!sourceLink || !sourceLink.href || typeof(sourceLink.href) !== 'string')
1926             return "";
1927 
1928         try
1929         {
1930             var fileName = Url.getFileName(sourceLink.href);
1931             fileName = decodeURIComponent(fileName);
1932         }
1933         catch(exc)
1934         {
1935             if (FBTrace.DBG_ERRORS)
1936                 FBTrace.sysout("reps.getSourceLinkTitle decodeURIComponent fails for \'" +
1937                     sourceLink.href + "\': " + exc, exc);
1938 
1939             fileName = sourceLink.href;
1940         }
1941 
1942         var maxWidth = Firebug.sourceLinkLabelWidth;
1943         if (maxWidth > 0)
1944             fileName = Str.cropString(fileName, maxWidth);
1945 
1946         if (sourceLink.instance)
1947         {
1948             return Locale.$STRF("InstanceLine", [fileName, sourceLink.instance + 1,
1949                 sourceLink.line]);
1950         }
1951         else if (sourceLink.line && typeof(sourceLink.col) != "undefined")
1952         {
1953             return Locale.$STRF("LineAndCol", [fileName, sourceLink.line, sourceLink.col]);
1954         }
1955         else if (sourceLink.line)
1956         {
1957             return Locale.$STRF("Line", [fileName, sourceLink.line]);
1958         }
1959         else
1960         {
1961             return fileName;
1962         }
1963     },
1964 
1965     getSystemFlagTitle: function(sourceLink)
1966     {
1967         if (this.isSystemLink(sourceLink))
1968             return Locale.$STRF("SystemItem", [""]);
1969         else
1970             return "";
1971     },
1972 
1973     copyLink: function(sourceLink)
1974     {
1975         System.copyToClipboard(sourceLink.href);
1976     },
1977 
1978     openInTab: function(sourceLink)
1979     {
1980         Win.openNewTab(sourceLink.href);
1981     },
1982 
1983     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1984 
1985     className: "sourceLink",
1986 
1987     supportsObject: function(object, type)
1988     {
1989         return object instanceof SourceLink.SourceLink;
1990     },
1991 
1992     getTooltip: function(sourceLink)
1993     {
1994         var text;
1995         try
1996         {
1997             text = decodeURI(sourceLink.href);
1998         }
1999         catch(exc)
2000         {
2001             if (FBTrace.DBG_ERRORS)
2002                 FBTrace.sysout("reps.getTooltip decodeURI fails for " + sourceLink.href, exc);
2003         }
2004 
2005         text = unescape(sourceLink.href);
2006 
2007         var lines = Str.splitLines(text);
2008         if (lines.length < 10)
2009             return text;
2010 
2011         lines.splice(10);
2012         return lines.join("") + "...";
2013     },
2014 
2015     inspectObject: function(sourceLink, context)
2016     {
2017         if (sourceLink.type == "js")
2018         {
2019             var scriptFile = Firebug.SourceFile.getSourceFileByHref(sourceLink.href, context);
2020             if (scriptFile)
2021                 return Firebug.chrome.select(sourceLink);
2022         }
2023         else if (sourceLink.type == "css")
2024         {
2025             // If an object is defined, treat it as the highest priority for
2026             // inspect actions
2027             if (sourceLink.object) {
2028                 Firebug.chrome.select(sourceLink.object);
2029                 return;
2030             }
2031 
2032             var stylesheet = Css.getStyleSheetByHref(sourceLink.href, context);
2033             if (stylesheet)
2034             {
2035                 var ownerNode = stylesheet.ownerNode;
2036                 if (ownerNode)
2037                 {
2038                     Firebug.chrome.select(sourceLink, "html");
2039                     return;
2040                 }
2041 
2042                 var panel = context.getPanel("stylesheet");
2043                 if (panel && panel.getRuleByLine(stylesheet, sourceLink.line))
2044                     return Firebug.chrome.select(sourceLink);
2045             }
2046         }
2047         else if (sourceLink.type == "net")
2048         {
2049             return Firebug.chrome.select(sourceLink);
2050         }
2051 
2052         // Fallback is to just open the view-source window on the file
2053         Firefox.viewSource(sourceLink.href, sourceLink.line);
2054     },
2055 
2056     browseObject: function(sourceLink, context)
2057     {
2058         Win.openNewTab(sourceLink.href);
2059         return true;
2060     },
2061 
2062     getContextMenuItems: function(sourceLink, target, context)
2063     {
2064         return [
2065             {
2066                 label: "CopyLocation",
2067                 tooltiptext: "clipboard.tip.Copy_Location",
2068                 command: Obj.bindFixed(this.copyLink, this, sourceLink)
2069             },
2070             "-",
2071             {
2072                 label: "OpenInTab",
2073                 tooltiptext: "firebug.tip.Open_In_Tab",
2074                 command: Obj.bindFixed(this.openInTab, this, sourceLink)
2075             }
2076         ];
2077     }
2078 });
2079 
2080 // ********************************************************************************************* //
2081 
2082 FirebugReps.CompilationUnit = domplate(FirebugReps.SourceLink,
2083 {
2084     tag:
2085         OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"),
2086 
2087     persistor: function(context, href)
2088     {
2089         return context.getCompilationUnit(href);
2090     },
2091 
2092     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2093 
2094     className: "CompilationUnit",
2095 
2096     supportsObject: function(object, type)
2097     {
2098        return (object instanceof CompilationUnit) ? 2 : 0;
2099     },
2100 
2101     persistObject: function(compilationUnit)
2102     {
2103         var href = compilationUnit.getURL();
2104         return Obj.bind(this.persistor, top, href);
2105     },
2106 
2107     browseObject: function(sourceLink, context)
2108     {
2109     },
2110 
2111     getTooltip: function(compilationUnit)
2112     {
2113         return compilationUnit.getURL();
2114     }
2115 });
2116 
2117 // ********************************************************************************************* //
2118 
2119 // XXXjjb Since the repObject is fn the stack does not have correct line numbers
2120 FirebugReps.StackFrame = domplate(Firebug.Rep,
2121 {
2122     tag:
2123         OBJECTBLOCK({$hasTwisty: "$object|hasArguments", _repObject: "$object",
2124             onclick: "$onToggleArguments"},
2125             SPAN({"class":"stackFrameMarker"}, ""),
2126             A({"class": "objectLink a11yFocus", _repObject: "$object"}, "$object|getCallName"),
2127             SPAN("("),
2128             SPAN({"class": "arguments"},
2129                 FOR("arg", "$object|argIterator",
2130                     SPAN({"class": "argName"}, "$arg.name"),
2131                     SPAN("="),
2132                     TAG("$arg.tag", {object: "$arg.value"}),
2133                     SPAN({"class": "arrayComma"}, "$arg.delim")
2134                 )
2135             ),
2136             SPAN(")"),
2137             SPAN({"class": "objectLink-sourceLink objectLink a11yFocus",
2138                 _repObject: "$object|getSourceLink",
2139                 role: "link"},
2140                 "$object|getSourceLinkTitle"),
2141             DIV({"class": "argList"})
2142         ),
2143 
2144     argList:
2145         DIV({"class": "argListBox", onclick: "$onSelectFrame"},
2146             FOR("arg", "$object|argIterator",
2147                 DIV({"class": "argBox"},
2148                     SPAN({"class": "argName"}, "$arg.name"),
2149                     SPAN(" = "),
2150                     TAG("$arg.tag", {object: "$arg.value"})
2151                 )
2152             )
2153         ),
2154 
2155     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2156 
2157     getTitle: function(frame)
2158     {
2159         return frame.getFunctionName();
2160     },
2161 
2162     hasArguments: function(frame)
2163     {
2164         return frame.args.length;
2165     },
2166 
2167     getCallName: function(frame)
2168     {
2169         return frame.getFunctionName();
2170     },
2171 
2172     getSourceLinkTitle: function(frame)
2173     {
2174         var fileName = Url.getFileName(frame.href);
2175 
2176         var maxWidth = Firebug.sourceLinkLabelWidth;
2177         if (maxWidth > 0)
2178             var fileName = Str.cropString(fileName, maxWidth);
2179 
2180         return Locale.$STRF("Line", [fileName, frame.line]);
2181     },
2182 
2183     argIterator: function(frame)
2184     {
2185         if (!frame.args)
2186             return [];
2187 
2188         var items = [];
2189 
2190         for (var i = 0; i < frame.args.length; ++i)
2191         {
2192             var arg = frame.args[i];
2193 
2194             if (!arg)
2195                 break;
2196 
2197             if (arg.hasOwnProperty('value')) // then we got these from jsd
2198             {
2199                 var rep = Firebug.getRep(arg.value);
2200                 var tag = rep.shortTag ? rep.shortTag : rep.tag;
2201 
2202                 var delim = (i == frame.args.length-1 ? "" : ", ");
2203 
2204                 items.push({name: arg.name, value: arg.value, tag: tag, delim: delim});
2205             }
2206             else if (arg.hasOwnProperty('name'))
2207             {
2208                 items.push({name: arg.name, delim: delim});
2209             }
2210             else  // eg from Error object
2211             {
2212                 var delim = (i == frame.args.length-1 ? "" : ", ");
2213                 var rep = Firebug.getRep(arg);
2214                 var tag = rep.shortTag ? rep.shortTag : rep.tag;
2215 
2216                 items.push({value: arg, tag: tag, delim: delim});
2217             }
2218 
2219             if (FBTrace.DBG_DOMPLATE)
2220                 FBTrace.sysout("reps.stackframe args[" + i + "]: " + arg.name + " = " +
2221                     arg.value, {arg: arg, item: items[items.length - 1]});
2222         }
2223 
2224         return items;
2225     },
2226 
2227     getSourceLink: function(stackFrame)
2228     {
2229         var sourceLink = new SourceLink.SourceLink(stackFrame.href, stackFrame.line, "js");
2230         return sourceLink;
2231     },
2232 
2233     onToggleArguments: function(event)
2234     {
2235         this.toggleArguments(event.originalTarget);
2236     },
2237 
2238     toggleArguments: function(target)
2239     {
2240         if (Css.hasClass(target, "objectBox-stackFrame"))
2241         {
2242             if (Css.hasClass(target, "opened"))
2243                 this.collapseArguments(target);
2244             else
2245                 this.expandArguments(target);
2246         }
2247     },
2248 
2249     collapseArguments: function(target)
2250     {
2251         if (!Css.hasClass(target, "opened"))
2252             return;
2253 
2254         Css.toggleClass(target, "opened");
2255 
2256         var argList = target.getElementsByClassName("argList").item(0);
2257         Dom.clearNode(argList);
2258     },
2259 
2260     expandArguments: function(target)
2261     {
2262         if (Css.hasClass(target, "opened"))
2263             return;
2264 
2265         var frame = target.repObject;
2266         if (!this.hasArguments(frame))
2267             return;
2268 
2269         Css.toggleClass(target, "opened");
2270 
2271         var argList = target.getElementsByClassName("argList").item(0);
2272         this.argList.replace({object: frame}, argList);
2273     },
2274 
2275     onSelectFrame: function(event)
2276     {
2277         var target = event.currentTarget;
2278         if (Css.hasClass(target, "argListBox"))
2279         {
2280             var stackFrame = Dom.getAncestorByClass(target, "objectBox-stackFrame");
2281             var panel = Firebug.getElementPanel(target);
2282             this.inspectObject(stackFrame.repObject, panel.context);
2283             Events.cancelEvent(event);
2284         }
2285     },
2286 
2287     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2288     // Rep
2289 
2290     className: "stackFrame",
2291 
2292     supportsObject: function(object, type)
2293     {
2294         return object instanceof StackFrame.StackFrame;
2295     },
2296 
2297     inspectObject: function(stackFrame, context)
2298     {
2299         if (context.stopped)
2300             Firebug.chrome.select(stackFrame);
2301         else
2302             Firebug.chrome.select(this.getSourceLink(stackFrame));
2303     },
2304 
2305     getTooltip: function(stackFrame, context)
2306     {
2307         return Locale.$STRF("Line", [stackFrame.href, stackFrame.line]);
2308     }
2309 });
2310 
2311 // ********************************************************************************************* //
2312 
2313 FirebugReps.StackTrace = domplate(Firebug.Rep,
2314 {
2315     tag:
2316         DIV({role : "group", "aria-label" : Locale.$STR("aria.labels.stack trace")},
2317             FOR("frame", "$object.frames|frameIterator",
2318                 TAG(FirebugReps.StackFrame.tag, {object: "$frame"})
2319             )
2320         ),
2321 
2322     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2323 
2324     className: "stackTrace",
2325 
2326     supportsObject: function(object, type)
2327     {
2328         return object instanceof StackFrame.StackTrace;
2329     },
2330 
2331     frameIterator: function(frames)
2332     {
2333         // Skip Firebug internal frames.
2334         // xxxHonza: this is anoter place where stack frame is peeling off.
2335         var result = [];
2336         for (var i=0; frames && i<frames.length; i++)
2337         {
2338             var frame = frames[i];
2339             var sf = frame.sourceFile;
2340             if ((sf && sf.href && Str.hasPrefix(sf.href, "chrome")) ||
2341                 (frame.fn == "_firebugRerun") ||
2342                 (frame.fn == "jsdbug_NoScriptFunctionName"))
2343             {
2344                 continue;
2345             }
2346 
2347             result.push(frames[i]);
2348         }
2349         return result;
2350     }
2351 });
2352 
2353 // ********************************************************************************************* //
2354 
2355 FirebugReps.ErrorMessage = domplate(Firebug.Rep,
2356 {
2357     sourceLimit: 80,
2358     alterText: "...",
2359 
2360     tag:
2361         OBJECTBOX({
2362             $hasTwisty: "$object|hasStackTrace",
2363             $hasBreakSwitch: "$object|hasBreakSwitch",
2364             $breakForError: "$object|hasErrorBreak",
2365             _repObject: "$object",
2366             _stackTrace: "$object|getLastErrorStackTrace",
2367             onclick: "$onToggleError"},
2368             DIV({"class": "errorTitle focusRow subLogRow", role: "listitem"},
2369                 SPAN({"class": "errorDuplication"}, "$object.msgId|getDuplication"),
2370                 SPAN({"class": "errorMessage"},
2371                     "$object.message"
2372                 )
2373             ),
2374             DIV({"class": "errorTrace", role: "presentation"}),
2375             TAG("$object|getObjectsTag", {object: "$object.objects"}),
2376             DIV({"class": "errorSourceBox errorSource-$object|getSourceType focusRow subLogRow",
2377                 role : "listitem"},
2378                 TABLE({cellspacing: 0, cellpadding: 0},
2379                     TBODY(
2380                         TR(
2381                             TD(
2382                                 IMG({"class": "$object|isBreakableError a11yFocus",
2383                                     src:"blank.gif", role: "checkbox",
2384                                     "aria-checked": "$object|hasErrorBreak",
2385                                     title: Locale.$STR("console.Break On This Error")})
2386                             ),
2387                             TD(
2388                                 A({"class": "errorSource a11yFocus"},
2389                                     PRE({"class": "errorSourceCode",
2390                                         title: "$object|getSourceTitle"}, "$object|getSource")
2391                                 ),
2392                                 TAG(FirebugReps.SourceLink.tag, {object: "$object|getSourceLink"})
2393                             )
2394                         ),
2395                         TR({$collapsed: "$object|hideErrorCaret"},
2396                             TD(),
2397                             TD(
2398                                 DIV({"class": "errorColPosition"},
2399                                     "$object|getColumnPosition"
2400                                 ),
2401                                 DIV({"class": "errorColCaret"})
2402                             )
2403                         )
2404                     )
2405                 )
2406             )
2407         ),
2408 
2409     getObjectsTag: function(error)
2410     {
2411         return error.objects ? FirebugReps.Arr.tag : SPAN();
2412     },
2413 
2414     getLastErrorStackTrace: function(error)
2415     {
2416         return error.trace;
2417     },
2418 
2419     hasStackTrace: function(error)
2420     {
2421         return error && error.trace;
2422     },
2423 
2424     hasBreakSwitch: function(error)
2425     {
2426         return error.href && error.lineNo > 0;
2427     },
2428 
2429     isBreakableError: function(error)
2430     {
2431         return (error.category === "js") ? "errorBreak" : "errorUnbreakable";
2432     },
2433 
2434     hasErrorBreak: function(error)
2435     {
2436         return FBS.fbs.hasErrorBreakpoint(Url.normalizeURL(error.href), error.lineNo);
2437     },
2438 
2439     getDuplication: function(msgId)
2440     {
2441         return ""; // filled in later
2442     },
2443 
2444     getSource: function(error, noCrop)
2445     {
2446         if (error.source && noCrop)
2447         {
2448             return error.source;
2449         }
2450         else if (error.source)
2451         {
2452             return Str.cropStringEx(Str.trim(error.source), this.sourceLimit,
2453                 this.alterText, error.colNumber);
2454         }
2455 
2456         if (error.category == "js" && error.href &&
2457             error.href.indexOf("XPCSafeJSObjectWrapper") != -1)
2458         {
2459             return "";
2460         }
2461 
2462         var source = error.getSourceLine();
2463         if (source && noCrop)
2464         {
2465             return source;
2466         }
2467         else if (source)
2468         {
2469             return Str.cropStringEx(Str.trim(source), this.sourceLimit,
2470                 this.alterText, error.colNumber);
2471         }
2472 
2473         return "";
2474     },
2475 
2476     hideErrorCaret: function(error)
2477     {
2478         var source = this.getSource(error);
2479         if (!source)
2480             return true;
2481 
2482         if (typeof(error.colNumber) == "undefined")
2483             return true;
2484 
2485         return false;
2486     },
2487 
2488     getColumnPosition: function(error)
2489     {
2490         if (this.hideErrorCaret(error))
2491             return "";
2492 
2493         var colNumber = error.colNumber;
2494         var originalLength = error.source.length;
2495         var trimmedLength = Str.trimLeft(error.source).length;
2496 
2497         // The source line is displayed without starting whitespaces.
2498         colNumber -= (originalLength - trimmedLength);
2499 
2500         var source = this.getSource(error, true);
2501         if (!source)
2502             return "";
2503 
2504         source = Str.trim(source);
2505 
2506         // Count how much the pivot needs to be adjusted (based on Str.cropStringEx)
2507         var halfLimit = this.sourceLimit/2;
2508         var pivot = error.colNumber;
2509         if (pivot < halfLimit)
2510             pivot = halfLimit;
2511 
2512         if (pivot > source.length - halfLimit)
2513             pivot = source.length - halfLimit;
2514 
2515         // Subtract some columns if the text has been cropped at the beginning.
2516         var begin = Math.max(0, pivot - halfLimit);
2517         colNumber -= begin;
2518 
2519         // Add come cols because there is an alterText at the beginning now.
2520         if (begin > 0)
2521             colNumber += this.alterText.length;
2522 
2523         var text = "";
2524         for (var i=0; i<colNumber; i++)
2525             text += "-";
2526 
2527         return text;
2528     },
2529 
2530     getSourceTitle: function(error)
2531     {
2532         var source = this.getSource(error, true);
2533         return source ? Str.trim(source) : "";
2534     },
2535 
2536     getSourceLink: function(error)
2537     {
2538         var ext = error.category == "css" ? "css" : "js";
2539         return error.lineNo ? new SourceLink.SourceLink(error.href, error.lineNo, ext,
2540             null, null, error.colNumber) : null;
2541     },
2542 
2543     getSourceType: function(error)
2544     {
2545         // Errors occurring inside of HTML event handlers look like "foo.html (line 1)"
2546         // so let's try to skip those
2547         if (error.source)
2548             return "syntax";
2549         else if (error.category == "css")
2550             return "show";
2551         else if (!error.href || !error.lineNo)
2552             return "none";
2553         // Why do we have that at all?
2554         else if (error.lineNo == 1 && Url.getFileExtension(error.href) != "js")
2555             return "none";
2556         else
2557             return "show";
2558     },
2559 
2560     onToggleError: function(event)
2561     {
2562         var target = event.currentTarget;
2563         if (Css.hasClass(event.target, "errorBreak"))
2564         {
2565             var panel = Firebug.getElementPanel(event.target);
2566             this.breakOnThisError(target.repObject, panel.context);
2567             return;
2568         }
2569         else if (Css.hasClass(event.target, "errorSourceCode"))
2570         {
2571             var panel = Firebug.getElementPanel(event.target);
2572             this.inspectObject(target.repObject, panel.context);
2573             return;
2574         }
2575 
2576         var errorTitle = Dom.getAncestorByClass(event.target, "errorTitle");
2577         if (errorTitle)
2578         {
2579             var traceBox = target.childNodes[1];
2580             Css.toggleClass(target, "opened");
2581             event.target.setAttribute('aria-expanded', Css.hasClass(target, "opened"));
2582 
2583             if (Css.hasClass(target, "opened"))
2584             {
2585                 if (target.stackTrace)
2586                     FirebugReps.StackTrace.tag.append({object: target.stackTrace}, traceBox);
2587 
2588                 if (Firebug.A11yModel.enabled)
2589                 {
2590                     var panel = Firebug.getElementPanel(event.target);
2591                     Events.dispatch(panel.fbListeners, "modifyLogRow", [panel, traceBox]);
2592                 }
2593             }
2594             else
2595             {
2596                 Dom.clearNode(traceBox);
2597             }
2598         }
2599     },
2600 
2601     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2602 
2603     copyError: function(error)
2604     {
2605         var message = [
2606             error.message,
2607             error.href,
2608             "Line " +  error.lineNo
2609         ];
2610         System.copyToClipboard(message.join(Str.lineBreak()));
2611     },
2612 
2613     breakOnThisError: function(error, context)
2614     {
2615         var compilationUnit = context.getCompilationUnit(Url.normalizeURL(error.href));
2616         if (!compilationUnit)
2617         {
2618             if (FBTrace.DBG_ERRORS)
2619                 FBTrace.sysout("reps.breakOnThisError has no source file for error.href: " +
2620                     error.href + "  error:" + error, context);
2621             return;
2622         }
2623 
2624         if (this.hasErrorBreak(error))
2625             Firebug.Debugger.clearErrorBreakpoint(compilationUnit, error.lineNo);
2626         else
2627             Firebug.Debugger.setErrorBreakpoint(compilationUnit, error.lineNo);
2628     },
2629 
2630     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2631 
2632     className: "errorMessage",
2633     inspectable: false,
2634 
2635     supportsObject: function(object, type)
2636     {
2637         return object instanceof FirebugReps.ErrorMessageObj;
2638     },
2639 
2640     inspectObject: function(error, context)
2641     {
2642         var sourceLink = this.getSourceLink(error);
2643         FirebugReps.SourceLink.inspectObject(sourceLink, context);
2644     },
2645 
2646     getContextMenuItems: function(error, target, context)
2647     {
2648         var breakOnThisError = this.hasErrorBreak(error);
2649 
2650         var items = [
2651             {
2652                 label: "CopyError",
2653                 tooltiptext: "console.menu.tip.Copy_Error",
2654                 command: Obj.bindFixed(this.copyError, this, error)
2655             }
2656         ];
2657 
2658         if (error.category != "css")
2659         {
2660             items.push(
2661                 "-",
2662                 {
2663                     label: "BreakOnThisError",
2664                     tooltiptext: "console.menu.tip.Break_On_This_Error",
2665                     type: "checkbox",
2666                     checked: breakOnThisError,
2667                     command: Obj.bindFixed(this.breakOnThisError, this, error, context)
2668                 },
2669                 Menu.optionMenu("BreakOnAllErrors", "breakOnErrors",
2670                     "console.menu.tip.Break_On_All_Errors")
2671             );
2672         }
2673 
2674         return items;
2675     }
2676 });
2677 
2678 // ********************************************************************************************* //
2679 
2680 FirebugReps.Except = domplate(Firebug.Rep,
2681 {
2682     tag:
2683         TAG(FirebugReps.ErrorMessage.tag, {object: "$object|getErrorMessage"}),
2684 
2685     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2686 
2687     className: "exception",
2688 
2689     getTitle: function(object)
2690     {
2691         if (object.name)
2692             return object.name + (object.message ? ": " + object.message : "");
2693 
2694         if (object.message)
2695             return object.message;
2696 
2697         return "Exception";
2698     },
2699 
2700     getErrorMessage: function(object)
2701     {
2702         var context = Firebug.currentContext;
2703         var win = context ? context.window : null;
2704 
2705         var url = object.fileName ? object.fileName : (win ? win.location.href : "");
2706         var lineNo = object.lineNumber ? object.lineNumber : 0;
2707         var message = this.getTitle(object);
2708 
2709         var trace;
2710         if (object.stack)
2711         {
2712             trace = StackFrame.parseToStackTrace(object.stack, context);
2713             trace = StackFrame.cleanStackTraceOfFirebug(trace);
2714 
2715             if (!trace)
2716                 lineNo = 0;
2717         }
2718 
2719         var errorObject = new FirebugReps.ErrorMessageObj(message, url, lineNo, "", "js",
2720             context, trace);
2721 
2722         if (trace && trace.frames && trace.frames[0])
2723             errorObject.correctWithStackTrace(trace);
2724 
2725         errorObject.resetSource();
2726         return errorObject;
2727     },
2728 
2729     supportsObject: function(object, type)
2730     {
2731         return (object instanceof FirebugReps.ErrorCopy) || Obj.XW_instanceof(object, Error);
2732     }
2733 });
2734 
2735 // ********************************************************************************************* //
2736 
2737 // xxxsz: Is this code still in use? 
2738 FirebugReps.Assert = domplate(Firebug.Rep,
2739 {
2740     tag:
2741         DIV(
2742             DIV({"class": "errorTitle"}),
2743             DIV({"class": "assertDescription"})
2744         ),
2745 
2746     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2747 
2748     className: "assert",
2749 
2750     inspectObject: function(error, context)
2751     {
2752         var sourceLink = this.getSourceLink(error);
2753         Firebug.chrome.select(sourceLink);
2754     },
2755 
2756     getContextMenuItems: function(error, target, context)
2757     {
2758         var breakOnThisError = this.hasErrorBreak(error);
2759 
2760         return [
2761             {
2762                 label: "CopyError",
2763                 tooltiptext: "console.tip.Copy_Error",
2764                 command: Obj.bindFixed(this.copyError, this, error)
2765             },
2766             "-",
2767             {
2768                 label: "BreakOnThisError",
2769                 tooltiptext: "console.menu.tip.Break_On_This_Error",
2770                 type: "checkbox",
2771                 checked: breakOnThisError,
2772                 command: Obj.bindFixed(this.breakOnThisError, this, error, context)
2773             },
2774             Menu.optionMenu("BreakOnAllErrors", "breakOnErrors",
2775                 "console.menu.tip.Break_On_All_Errors")
2776         ];
2777     }
2778 });
2779 
2780 // ********************************************************************************************* //
2781 
2782 FirebugReps.SourceText = domplate(Firebug.Rep,
2783 {
2784     tag:
2785         DIV(
2786             FOR("line", "$object|lineIterator",
2787                 DIV({"class": "sourceRow", role : "presentation"},
2788                     SPAN({"class": "sourceLine", role : "presentation"}, "$line.lineNo"),
2789                     SPAN({"class": "sourceRowText", role : "presentation"}, "$line.text")
2790                 )
2791             )
2792         ),
2793 
2794     lineIterator: function(sourceText)
2795     {
2796         var maxLineNoChars = (sourceText.lines.length + "").length;
2797         var list = [];
2798 
2799         for (var i = 0; i < sourceText.lines.length; ++i)
2800         {
2801             // Make sure all line numbers are the same width (with a fixed-width font)
2802             var lineNo = (i+1) + "";
2803             while (lineNo.length < maxLineNoChars)
2804                 lineNo = " " + lineNo;
2805 
2806             list.push({lineNo: lineNo, text: sourceText.lines[i]});
2807         }
2808 
2809         return list;
2810     },
2811 
2812     getHTML: function(sourceText)
2813     {
2814         return getSourceLineRange(sourceText, 1, sourceText.lines.length);
2815     }
2816 });
2817 
2818 //********************************************************************************************** //
2819 
2820 FirebugReps.nsIDOMHistory = domplate(Firebug.Rep,
2821 {
2822     tag:
2823         OBJECTBOX({onclick: "$showHistory", _repObject: "$object"},
2824             OBJECTLINK("$object|summarizeHistory")
2825         ),
2826 
2827     className: "nsIDOMHistory",
2828 
2829     summarizeHistory: function(history)
2830     {
2831         try
2832         {
2833             var items = history.length;
2834             return Locale.$STRP("firebug.reps.historyEntries", [items]);
2835         }
2836         catch (exc)
2837         {
2838             return "object does not support history (nsIDOMHistory)";
2839         }
2840     },
2841 
2842     showHistory: function(event)
2843     {
2844         try
2845         {
2846             var history = event.currentTarget.repObject;
2847             history.length;  // if this throws, then unsupported
2848             Firebug.chrome.select(history);
2849         }
2850         catch (exc)
2851         {
2852         }
2853     },
2854 
2855     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2856 
2857     supportsObject: function(object, type)
2858     {
2859         return (object instanceof Ci.nsIDOMHistory);
2860     }
2861 });
2862 
2863 // ********************************************************************************************* //
2864 
2865 FirebugReps.ApplicationCache = domplate(Firebug.Rep,
2866 {
2867     tag:
2868         OBJECTLINK("$object|summarizeCache"),
2869 
2870     summarizeCache: function(applicationCache)
2871     {
2872         try
2873         {
2874             return applicationCache.mozItems.length + " items in offline cache";
2875         }
2876         catch(exc)
2877         {
2878             return "https://bugzilla.mozilla.org/show_bug.cgi?id=422264";
2879         }
2880     },
2881 
2882     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2883 
2884     className: "applicationCache",
2885 
2886     supportsObject: function(object, type)
2887     {
2888         if (Ci.nsIDOMOfflineResourceList)
2889             return (object instanceof Ci.nsIDOMOfflineResourceList);
2890     }
2891 });
2892 
2893 // ********************************************************************************************* //
2894 
2895 FirebugReps.Storage = domplate(Firebug.Rep,
2896 {
2897     tag:
2898         OBJECTLINK(
2899             SPAN({"class": "storageTitle"}, "$object|summarize "),
2900             FOR("prop", "$object|longPropIterator",
2901                 "$prop.name",
2902                 SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"),
2903                 TAG("$prop.tag", {object: "$prop.object"}),
2904                 SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim")
2905             )
2906         ),
2907 
2908     shortTag:
2909         OBJECTLINK(
2910             SPAN({"class": "storageTitle"}, "$object|summarize "),
2911             FOR("prop", "$object|shortPropIterator",
2912                 "$prop.name",
2913                 SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"),
2914                 TAG("$prop.tag", {object: "$prop.object"}),
2915                 SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim")
2916             )
2917         ),
2918 
2919     summarize: function(storage)
2920     {
2921         var object = this.objectView(storage);
2922         return Locale.$STRP("firebug.storage.totalItems", [Object.keys(object).length]);
2923     },
2924 
2925     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2926 
2927     className: "Storage",
2928 
2929     supportsObject: function(object, type)
2930     {
2931         return (object instanceof window.Storage);
2932     },
2933 
2934     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2935     // Iterator
2936 
2937     longPropIterator: function(object)
2938     {
2939         return this.propIterator(object, 100);
2940     },
2941 
2942     shortPropIterator: function(object)
2943     {
2944         return this.propIterator(object, Options.get("ObjectShortIteratorMax"));
2945     },
2946 
2947     propIterator: function(storage, max)
2948     {
2949         var object = this.objectView(storage);
2950         return FirebugReps.Obj.propIterator(object, max);
2951     },
2952 
2953     objectView: function(storage)
2954     {
2955         var object = this.makeObject(storage);
2956         for (var any in object)
2957             return object;
2958 
2959         // We might have hit upon an https site (bug 709238).
2960         // As a hack, we'll check if the current context's window
2961         // contains the object as localStorage or sessionStorage.
2962         try {
2963             var context = Firebug.currentContext;
2964             var win = context && context.window;
2965             if (win && win.location.protocol === "https:")
2966             {
2967                 var names = ["localStorage", "sessionStorage"], done = false;
2968                 for (var i = 0; i < 2; ++i)
2969                 {
2970                     if (win[names[i]] !== storage)
2971                         continue;
2972                     Firebug.CommandLine.evaluate(
2973                         "((" + this.makeObject + ")(" + names[i] + "))",
2974                         context,
2975                         null, null,
2976                         function(result) {
2977                             object = result;
2978                             done = true;
2979                         },
2980                         function() {},
2981                         true
2982                     );
2983                     if (done)
2984                         break;
2985                 }
2986             }
2987         }
2988         catch(e)
2989         {
2990             if (FBTrace.DBG_ERRORS)
2991                 FBTrace.sysout("reps.Storage.objectView; EXCEPTION " + e, e);
2992         }
2993 
2994         return object;
2995     },
2996 
2997     makeObject: function(storage)
2998     {
2999         // Create a raw object, free from getItem etc., from a storage.
3000         // May be serialized and run in page scope.
3001         var object = {};
3002         try
3003         {
3004             for (var name in storage)
3005             {
3006                 var value = storage.getItem(name);
3007                 Object.defineProperty(object, name, {value: value, enumerable: true});
3008             }
3009         }
3010         catch(e)
3011         {
3012             // We can't log an error in page scope.
3013         }
3014         return object;
3015     }
3016 });
3017 
3018 // ********************************************************************************************* //
3019 
3020 FirebugReps.XPathResult = domplate(FirebugReps.Arr,
3021 {
3022     className: "array xPathResult",
3023     toggles: new ToggleBranch.ToggleBranch(),
3024 
3025     tag:
3026         SPAN(FirebugReps.Arr.tag),
3027 
3028     shortTag:
3029         SPAN(FirebugReps.Arr.shortTag),
3030 
3031     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
3032 
3033     supportsObject: function(xpathresult, type)
3034     {
3035         return (xpathresult instanceof window.XPathResult);
3036     },
3037 
3038     arrayIterator: function(xpathresult, max)
3039     {
3040         var items = [];
3041         for (var i=0; i<xpathresult.snapshotLength && i<=max; i++)
3042         {
3043             var value = xpathresult.snapshotItem(i);
3044             var rep = Firebug.getRep(value);
3045             var tag = rep.shortTag || rep.tag;
3046             var delim = (i == xpathresult.snapshotLength-1 ? "" : ", ");
3047 
3048             items.push({object: value, tag: tag, delim: delim});
3049         }
3050 
3051         if (xpathresult.snapshotLength > max + 1)
3052         {
3053             items[max] = {
3054                 object: (xpathresult.snapshotLength-max) + " " +
3055                     Locale.$STR("firebug.reps.more") + "...",
3056                 tag: FirebugReps.Caption.tag,
3057                 delim: ""
3058             };
3059         }
3060 
3061         return items;
3062     },
3063 });
3064 
3065 // ********************************************************************************************* //
3066 
3067 FirebugReps.Description = domplate(Firebug.Rep,
3068 {
3069     className: "Description",
3070 
3071     tag:
3072         DIV({onclick: "$onClickLink"}),
3073 
3074     render: function(text, parentNode, listener)
3075     {
3076         var params = {};
3077         if (listener)
3078         {
3079             params.onClickLink = function(event)
3080             {
3081                 // Only clicks on links are passed to the original listener.
3082                 var localName = event.target.localName;
3083                 if (listener && localName && localName.toLowerCase() == "a")
3084                     listener(event);
3085             };
3086         }
3087 
3088         var rootNode = this.tag.replace(params, parentNode, this);
3089 
3090         var parser = Xpcom.CCIN("@mozilla.org/xmlextras/domparser;1", "nsIDOMParser");
3091         var doc = parser.parseFromString("<div>" + text + "</div>", "text/xml");
3092         var root = doc.documentElement;
3093 
3094         // Error handling
3095         var nsURI = "http://www.mozilla.org/newlayout/xml/parsererror.xml";
3096         if (root.namespaceURI == nsURI && root.nodeName == "parsererror")
3097         {
3098             FBTrace.sysout("reps.Description; parse ERROR " + root.firstChild.nodeValue, root);
3099 
3100             return FirebugReps.Warning.tag.replace({object: "css.EmptyElementCSS"},
3101                 parentNode, FirebugReps.Warning);
3102         }
3103 
3104         // Nodes from external documents need to be imported.
3105         root = rootNode.ownerDocument.importNode(root, true);
3106 
3107         rootNode.appendChild(root);
3108         return rootNode;
3109     }
3110 });
3111 
3112 // ********************************************************************************************* //
3113 
3114 FirebugReps.Attr = domplate(Firebug.Rep,
3115 {
3116     tag:
3117         OBJECTLINK(
3118             SPAN(
3119                 SPAN({"class": "attrTitle"}, "$object|getTitle"),
3120                 SPAN({"class": "attrEqual"}, "="),
3121                 TAG("$object|getValueTag", {object: "$object.value"})
3122             )
3123         ),
3124 
3125     getTitle: function(attr)
3126     {
3127         return attr.name;
3128     },
3129 
3130     getValueTag: function(object)
3131     {
3132         return Firebug.getRep(object.value).tag;
3133     },
3134 
3135     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
3136 
3137     className: "Attr",
3138 
3139     supportsObject: function(object, type)
3140     {
3141         return (object instanceof window.Attr);
3142     },
3143 });
3144 
3145 // ********************************************************************************************* //
3146 
3147 FirebugReps.Date = domplate(Firebug.Rep,
3148 {
3149     tag:
3150         OBJECTLINK(
3151             SPAN({"class": "objectTitle"}, "$object|getTitle "),
3152             SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"),
3153             SPAN({"class": "attrEqual"}, "$object|getValue"),
3154             SPAN({"class": "objectRightBrace"}, "}")
3155         ),
3156 
3157     getValue: function(object)
3158     {
3159         return object.toString();
3160     },
3161 
3162     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
3163 
3164     className: "Date",
3165 
3166     supportsObject: function(object, type)
3167     {
3168         return object && object.constructor && object.constructor.name == "Date";
3169     },
3170 });
3171 
3172 // ********************************************************************************************* //
3173 
3174 FirebugReps.NamedNodeMap = domplate(Firebug.Rep,
3175 {
3176     tag:
3177         OBJECTLINK(
3178             SPAN({"class": "arrayLeftBracket", role: "presentation"}, "["),
3179             FOR("prop", "$object|longPropIterator",
3180                 SPAN({"class": "nodeName"}, "$prop.name"),
3181                 SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"),
3182                 TAG("$prop.tag", {object: "$prop.object"}),
3183                 SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim")
3184             ),
3185             SPAN({"class": "arrayRightBracket", role: "presentation"}, "]")
3186         ),
3187 
3188     shortTag:
3189         OBJECTLINK(
3190             SPAN({"class": "arrayLeftBracket", role: "presentation"}, "["),
3191             FOR("prop", "$object|shortPropIterator",
3192                 SPAN({"class": "nodeName"}, "$prop.name"),
3193                 SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"),
3194                 TAG("$prop.tag", {object: "$prop.object"}),
3195                 SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim")
3196             ),
3197             SPAN({"class": "arrayRightBracket", role: "presentation"}, "]")
3198         ),
3199 
3200     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
3201 
3202     className: "NamedNodeMap",
3203 
3204     supportsObject: function(object, type)
3205     {
3206         return (object instanceof window.NamedNodeMap);
3207     },
3208 
3209     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
3210     // Iterator
3211 
3212     longPropIterator: function(object)
3213     {
3214         return this.propIterator(object, 100);
3215     },
3216 
3217     shortPropIterator: function(object)
3218     {
3219         return this.propIterator(object, Options.get("ObjectShortIteratorMax"));
3220     },
3221 
3222     propIterator: function (object, max)
3223     {
3224         max = max || 3;
3225         if (!object)
3226             return [];
3227 
3228         var props = [];
3229         for (var i=0; i<object.length && i<max; i++)
3230         {
3231             var item = object.item(i);
3232             var name = item.name;
3233             var value = item.value;
3234 
3235             var rep = Firebug.getRep(value);
3236             var tag = rep.tag;
3237 
3238             props.push({tag: tag, name: name, object: value, equal: "=", delim: ", "});
3239         }
3240 
3241         if (object.length > max)
3242         {
3243             props[Math.max(1,max-1)] = {
3244                 object: (object.length-max) + " " + Locale.$STR("firebug.reps.more") + "...",
3245                 tag: FirebugReps.Caption.tag,
3246                 name: "",
3247                 equal:"",
3248                 delim:""
3249             };
3250         }
3251         else if (props.length > 0)
3252         {
3253             props[props.length-1].delim = '';
3254         }
3255 
3256         return props;
3257     },
3258 });
3259 
3260 // ********************************************************************************************* //
3261 // Error Message
3262 
3263 FirebugReps.ErrorMessageObj = function(message, href, lineNo, source, category, context,
3264     trace, msgId, colNumber)
3265 {
3266     this.message = message;
3267     this.href = href;
3268     this.lineNo = lineNo;
3269     this.source = source;
3270     this.category = category;
3271     this.context = context;
3272     this.trace = trace;
3273     this.msgId = msgId;
3274     this.colNumber = colNumber;
3275 };
3276 
3277 FirebugReps.ErrorMessageObj.prototype =
3278 {
3279     getSourceLine: function()
3280     {
3281         if (!this.context.sourceCache)
3282         {
3283             if (FBTrace.DBG_ERRORS)
3284                 FBTrace.sysout("reps.ErrorMessageObj.getSourceLine; ERROR no source cache!")
3285             return;
3286         }
3287 
3288         return this.context.sourceCache.getLine(this.href, this.lineNo);
3289     },
3290 
3291     resetSource: function()
3292     {
3293         if (this.href && this.lineNo)
3294             this.source = this.getSourceLine();
3295     },
3296 
3297     correctWithStackTrace: function(trace)
3298     {
3299         var frame = trace.frames[0];
3300         if (frame)
3301         {
3302             this.href = frame.href;
3303             this.lineNo = frame.line;
3304             this.trace = trace;
3305         }
3306     },
3307 
3308     correctSourcePoint: function(sourceName, lineNumber)
3309     {
3310         this.href = sourceName;
3311         this.lineNo = lineNumber;
3312     },
3313 };
3314 
3315 // ********************************************************************************************* //
3316 
3317 FirebugReps.ErrorCopy = function(message)
3318 {
3319     this.message = message;
3320 };
3321 
3322 // ********************************************************************************************* //
3323 // Registration
3324 
3325 Firebug.registerRep(
3326     FirebugReps.Undefined,
3327     FirebugReps.Null,
3328     FirebugReps.Number,
3329     FirebugReps.String,
3330     FirebugReps.nsIDOMHistory, // make this early to avoid exceptions
3331     FirebugReps.ApplicationCache, // this also
3332     FirebugReps.RegExp,
3333     FirebugReps.Window,
3334     FirebugReps.ErrorMessage,
3335     FirebugReps.Element,
3336     FirebugReps.TextNode,
3337     FirebugReps.Document,
3338     FirebugReps.StyleSheet,
3339     FirebugReps.CSSRule,
3340     FirebugReps.Event,
3341     FirebugReps.SourceLink,
3342     FirebugReps.CompilationUnit,
3343     FirebugReps.StackTrace,
3344     FirebugReps.StackFrame,
3345     FirebugReps.NetFile,
3346     FirebugReps.Property,
3347     FirebugReps.Except,
3348     FirebugReps.XML,
3349     FirebugReps.Arr,
3350     FirebugReps.ArrayLikeObject,
3351     FirebugReps.XPathResult,
3352     FirebugReps.Storage,
3353     FirebugReps.Attr,
3354     FirebugReps.Date,
3355     FirebugReps.NamedNodeMap,
3356     FirebugReps.Reference,
3357     FirebugReps.EventLog
3358 );
3359 
3360 Firebug.setDefaultReps(FirebugReps.Func, FirebugReps.Obj);
3361 
3362 return Firebug.Reps = FirebugReps;
3363 
3364 // ********************************************************************************************* //
3365 }});
3366