1 /* See license.txt for terms of usage */
  2 
  3 define([
  4     "firebug/lib/object",
  5     "firebug/firebug",
  6     "firebug/lib/domplate",
  7     "firebug/lib/locale",
  8     "firebug/lib/xpcom",
  9     "firebug/lib/css",
 10     "firebug/lib/http",
 11     "firebug/net/netUtils"
 12 ],
 13 function(Obj, Firebug, Domplate, Locale, Xpcom, Css, Http, NetUtils) {
 14 
 15 // ********************************************************************************************* //
 16 // Constants
 17 
 18 // List of XML related content types.
 19 var xmlContentTypes =
 20 [
 21     "text/xml",
 22     "application/xml",
 23     "application/xhtml+xml",
 24     "application/rss+xml",
 25     "application/atom+xml",,
 26     "application/vnd.mozilla.maybe.feed",
 27     "application/mathml+xml",
 28     "application/rdf+xml",
 29     "application/vnd.mozilla.xul+xml"
 30 ];
 31 
 32 // ********************************************************************************************* //
 33 // Model implementation
 34 
 35 /**
 36  * @module Implements viewer for XML based network responses. In order to create a new
 37  * tab wihin network request detail, a listener is registered into
 38  * <code>Firebug.NetMonitor.NetInfoBody</code> object.
 39  */
 40 Firebug.XMLViewerModel = Obj.extend(Firebug.Module,
 41 /** lends Firebug.XMLViewerModel */
 42 {
 43     dispatchName: "xmlViewer",
 44 
 45     initialize: function()
 46     {
 47         Firebug.ActivableModule.initialize.apply(this, arguments);
 48         Firebug.NetMonitor.NetInfoBody.addListener(this);
 49     },
 50 
 51     shutdown: function()
 52     {
 53         Firebug.ActivableModule.shutdown.apply(this, arguments);
 54         Firebug.NetMonitor.NetInfoBody.removeListener(this);
 55     },
 56 
 57     /**
 58      * Check response's content-type and if it's a Xml, create a new tab with XML preview.
 59      */
 60     initTabBody: function(infoBox, file)
 61     {
 62         if (FBTrace.DBG_XMLVIEWER)
 63             FBTrace.sysout("xmlviewer.initTabBody", infoBox);
 64 
 65         // If the response is XML let's display a pretty preview.
 66         if (this.isXML(Http.safeGetContentType(file.request)))
 67         {
 68             Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "XML",
 69                 Locale.$STR("xmlviewer.tab.XML"));
 70 
 71             if (FBTrace.DBG_XMLVIEWER)
 72                 FBTrace.sysout("xmlviewer.initTabBody; XML response available");
 73         }
 74     },
 75 
 76     isXML: function(contentType)
 77     {
 78         if (!contentType)
 79             return false;
 80 
 81         return NetUtils.matchesContentType(contentType, xmlContentTypes);
 82     },
 83 
 84     /**
 85      * Parse XML response and render pretty printed preview.
 86      */
 87     updateTabBody: function(infoBox, file, context)
 88     {
 89         var tab = infoBox.selectedTab;
 90         var tabBody = infoBox.getElementsByClassName("netInfoXMLText").item(0);
 91         if (!Css.hasClass(tab, "netInfoXMLTab") || tabBody.updated)
 92             return;
 93 
 94         tabBody.updated = true;
 95 
 96         this.insertXML(tabBody, NetUtils.getResponseText(file, context));
 97     },
 98 
 99     insertXML: function(parentNode, text)
100     {
101         var parser = Xpcom.CCIN("@mozilla.org/xmlextras/domparser;1", "nsIDOMParser");
102         var doc = parser.parseFromString(text, "text/xml");
103         var root = doc.documentElement;
104 
105         // Error handling
106         var nsURI = "http://www.mozilla.org/newlayout/xml/parsererror.xml";
107         if (root.namespaceURI == nsURI && root.nodeName == "parsererror")
108         {
109             this.ParseError.tag.replace({error: {
110                 message: root.firstChild.nodeValue,
111                 source: root.lastChild.textContent
112             }}, parentNode);
113             return;
114         }
115 
116         if (FBTrace.DBG_XMLVIEWER)
117             FBTrace.sysout("xmlviewer.updateTabBody; XML response parsed", doc);
118 
119         // Override getHidden in these templates. The parsed XML documen is
120         // hidden, but we want to display it using 'visible' styling.
121         var templates = [
122             Firebug.HTMLPanel.CompleteElement,
123             Firebug.HTMLPanel.Element,
124             Firebug.HTMLPanel.TextElement,
125             Firebug.HTMLPanel.EmptyElement,
126             Firebug.HTMLPanel.XEmptyElement,
127         ];
128 
129         var originals = [];
130         for (var i=0; i<templates.length; i++)
131         {
132             originals[i] = templates[i].getHidden;
133             templates[i].getHidden = function() {
134                 return "";
135             }
136         }
137 
138         // Generate XML preview.
139         Firebug.HTMLPanel.CompleteElement.tag.replace({object: doc.documentElement}, parentNode);
140 
141         for (var i=0; i<originals.length; i++)
142             templates[i].getHidden = originals[i];
143     }
144 });
145 
146 // ********************************************************************************************* //
147 // Domplate
148 
149 /**
150  * @domplate Represents a template for displaying XML parser errors. Used by
151  * <code>Firebug.XMLViewerModel</code>.
152  */
153 with (Domplate) {
154 Firebug.XMLViewerModel.ParseError = domplate(Firebug.Rep,
155 {
156     tag:
157         DIV({"class": "xmlInfoError"},
158             DIV({"class": "xmlInfoErrorMsg"}, "$error.message"),
159             PRE({"class": "xmlInfoErrorSource"}, "$error|getSource")
160         ),
161 
162     getSource: function(error)
163     {
164         var parts = error.source.split("\n");
165         if (parts.length != 2)
166             return error.source;
167 
168         var limit = 50;
169         var column = parts[1].length;
170         if (column >= limit) {
171             parts[0] = "..." + parts[0].substr(column - limit);
172             parts[1] = "..." + parts[1].substr(column - limit);
173         }
174 
175         if (parts[0].length > 80)
176             parts[0] = parts[0].substr(0, 80) + "...";
177 
178         return parts.join("\n");
179     }
180 })};
181 
182 // ********************************************************************************************* //
183 // Registration
184 
185 Firebug.registerModule(Firebug.XMLViewerModel);
186 
187 return Firebug.XMLViewerModel;
188 
189 // ********************************************************************************************* //
190 });
191