2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) IBM Corp. 2009 All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 WebInspector
.ResourceView = function(resource
)
32 WebInspector
.View
.call(this);
34 this.element
.addStyleClass("resource-view");
36 this.resource
= resource
;
38 this.headersElement
= document
.createElement("div");
39 this.headersElement
.className
= "resource-view-headers";
40 this.element
.appendChild(this.headersElement
);
42 this.contentElement
= document
.createElement("div");
43 this.contentElement
.className
= "resource-view-content";
44 this.element
.appendChild(this.contentElement
);
46 this.headersListElement
= document
.createElement("ol");
47 this.headersListElement
.className
= "outline-disclosure";
48 this.headersElement
.appendChild(this.headersListElement
);
50 this.headersTreeOutline
= new TreeOutline(this.headersListElement
);
51 this.headersTreeOutline
.expandTreeElementsWhenArrowing
= true;
53 this.urlTreeElement
= new TreeElement("", null, false);
54 this.urlTreeElement
.selectable
= false;
55 this.headersTreeOutline
.appendChild(this.urlTreeElement
);
57 this.httpInformationTreeElement
= new TreeElement("", null, true);
58 this.httpInformationTreeElement
.expanded
= false;
59 this.httpInformationTreeElement
.selectable
= false;
60 this.headersTreeOutline
.appendChild(this.httpInformationTreeElement
);
62 this.requestHeadersTreeElement
= new TreeElement("", null, true);
63 this.requestHeadersTreeElement
.expanded
= false;
64 this.requestHeadersTreeElement
.selectable
= false;
65 this.headersTreeOutline
.appendChild(this.requestHeadersTreeElement
);
67 this._decodeHover
= WebInspector
.UIString("Double-Click to toggle between URL encoded and decoded formats");
68 this._decodeRequestParameters
= true;
70 this.queryStringTreeElement
= new TreeElement("", null, true);
71 this.queryStringTreeElement
.expanded
= false;
72 this.queryStringTreeElement
.selectable
= false;
73 this.queryStringTreeElement
.hidden
= true;
74 this.headersTreeOutline
.appendChild(this.queryStringTreeElement
);
76 this.formDataTreeElement
= new TreeElement("", null, true);
77 this.formDataTreeElement
.expanded
= false;
78 this.formDataTreeElement
.selectable
= false;
79 this.formDataTreeElement
.hidden
= true;
80 this.headersTreeOutline
.appendChild(this.formDataTreeElement
);
82 this.requestPayloadTreeElement
= new TreeElement(WebInspector
.UIString("Request Payload"), null, true);
83 this.requestPayloadTreeElement
.expanded
= false;
84 this.requestPayloadTreeElement
.selectable
= false;
85 this.requestPayloadTreeElement
.hidden
= true;
86 this.headersTreeOutline
.appendChild(this.requestPayloadTreeElement
);
88 this.responseHeadersTreeElement
= new TreeElement("", null, true);
89 this.responseHeadersTreeElement
.expanded
= false;
90 this.responseHeadersTreeElement
.selectable
= false;
91 this.headersTreeOutline
.appendChild(this.responseHeadersTreeElement
);
93 this.headersVisible
= true;
95 resource
.addEventListener("url changed", this._refreshURL
, this);
96 resource
.addEventListener("requestHeaders changed", this._refreshRequestHeaders
, this);
97 resource
.addEventListener("responseHeaders changed", this._refreshResponseHeaders
, this);
98 resource
.addEventListener("finished", this._refreshHTTPInformation
, this);
101 this._refreshRequestHeaders();
102 this._refreshResponseHeaders();
103 this._refreshHTTPInformation();
106 WebInspector
.ResourceView
.prototype = {
109 return this._headersVisible
;
112 set headersVisible(x
)
114 if (x
=== this._headersVisible
)
117 this._headersVisible
= x
;
120 this.element
.addStyleClass("headers-visible");
122 this.element
.removeStyleClass("headers-visible");
127 if (!this.element
.parentNode
) {
128 var parentElement
= (document
.getElementById("resource-views") || document
.getElementById("script-resource-views"));
130 parentElement
.appendChild(this.element
);
134 _refreshURL: function()
136 var url
= this.resource
.url
;
137 var statusCodeImage
= "";
138 if (this.resource
.statusCode
) {
139 var statusImageSource
= "";
141 if (this.resource
.statusCode
< 300)
142 statusImageSource
= "Images/successGreenDot.png";
143 else if (this.resource
.statusCode
< 400)
144 statusImageSource
= "Images/warningOrangeDot.png";
146 statusImageSource
= "Images/errorRedDot.png";
148 statusCodeImage
= "<img class=\"resource-status-image\" src=\"" + statusImageSource
+ "\" title=\"" + WebInspector
.Resource
.StatusTextForCode(this.resource
.statusCode
) + "\">";
151 this.urlTreeElement
.title
= statusCodeImage
+ "<span class=\"resource-url\">" + url
.escapeHTML() + "</span>";
152 this._refreshQueryString();
155 _refreshQueryString: function()
157 var url
= this.resource
.url
;
158 var hasQueryString
= url
.indexOf("?") >= 0;
160 if (!hasQueryString
) {
161 this.queryStringTreeElement
.hidden
= true;
165 this.queryStringTreeElement
.hidden
= false;
166 var parmString
= url
.split("?", 2)[1];
167 this._refreshParms(WebInspector
.UIString("Query String Parameters"), parmString
, this.queryStringTreeElement
);
170 _refreshFormData: function()
172 this.formDataTreeElement
.hidden
= true;
173 this.requestPayloadTreeElement
.hidden
= true;
175 var isFormData
= this.resource
.requestFormData
;
179 var isFormEncoded
= false;
180 var requestContentType
= this._getHeaderValue(this.resource
.requestHeaders
, "Content-Type");
181 if (requestContentType
&& requestContentType
.match(/^application\/x-www-form-urlencoded\s*(;.*)?$/i))
182 isFormEncoded
= true;
185 this.formDataTreeElement
.hidden
= false;
186 this._refreshParms(WebInspector
.UIString("Form Data"), this.resource
.requestFormData
, this.formDataTreeElement
);
188 this.requestPayloadTreeElement
.hidden
= false;
189 this._refreshRequestPayload(this.resource
.requestFormData
);
193 _refreshRequestPayload: function(formData
)
195 this.requestPayloadTreeElement
.removeChildren();
197 var title
= "<div class=\"header-name\"> </div>";
198 title
+= "<div class=\"raw-form-data header-value\">" + formData
.escapeHTML() + "</div>";
199 var parmTreeElement
= new TreeElement(title
, null, false);
200 parmTreeElement
.selectable
= false;
201 this.requestPayloadTreeElement
.appendChild(parmTreeElement
);
204 _refreshParms: function(title
, parmString
, parmsTreeElement
)
206 var parms
= parmString
.split("&");
207 for (var i
= 0; i
< parms
.length
; ++i
) {
209 parm
= parm
.split("=", 2);
210 if (parm
.length
== 1)
215 parmsTreeElement
.removeChildren();
217 parmsTreeElement
.title
= title
+ "<span class=\"header-count\">" + WebInspector
.UIString(" (%d)", parms
.length
) + "</span>";
219 for (var i
= 0; i
< parms
.length
; ++i
) {
220 var key
= parms
[i
][0];
221 var value
= parms
[i
][1];
223 var errorDecoding
= false;
224 if (this._decodeRequestParameters
) {
225 if (value
.indexOf("%") >= 0) {
227 value
= decodeURIComponent(value
);
229 errorDecoding
= true;
233 value
= value
.replace(/\+/g, " ");
236 valueEscaped
= value
.escapeHTML();
238 valueEscaped
+= " <span class=\"error-message\">" + WebInspector
.UIString("(unable to decode value)").escapeHTML() + "</span>";
240 var title
= "<div class=\"header-name\">" + key
.escapeHTML() + ":</div>";
241 title
+= "<div class=\"header-value\">" + valueEscaped
+ "</div>";
243 var parmTreeElement
= new TreeElement(title
, null, false);
244 parmTreeElement
.selectable
= false;
245 parmTreeElement
.tooltip
= this._decodeHover
;
246 parmTreeElement
.ondblclick
= this._toggleURLdecoding
.bind(this);
247 parmsTreeElement
.appendChild(parmTreeElement
);
251 _toggleURLdecoding: function(event
)
253 this._decodeRequestParameters
= !this._decodeRequestParameters
;
254 this._refreshQueryString();
255 this._refreshFormData();
258 _getHeaderValue: function(headers
, key
)
260 var lowerKey
= key
.toLowerCase();
261 for (var testKey
in headers
) {
262 if (testKey
.toLowerCase() === lowerKey
)
263 return headers
[testKey
];
267 _refreshRequestHeaders: function()
269 this._refreshHeaders(WebInspector
.UIString("Request Headers"), this.resource
.sortedRequestHeaders
, this.requestHeadersTreeElement
);
270 this._refreshFormData();
273 _refreshResponseHeaders: function()
275 this._refreshHeaders(WebInspector
.UIString("Response Headers"), this.resource
.sortedResponseHeaders
, this.responseHeadersTreeElement
);
278 _refreshHTTPInformation: function()
280 const listElements
= 2;
282 var headerElement
= this.httpInformationTreeElement
;
283 headerElement
.removeChildren();
284 headerElement
.hidden
= !this.resource
.statusCode
;
286 if (this.resource
.statusCode
) {
287 headerElement
.title
= WebInspector
.UIString("HTTP Information") + "<span class=\"header-count\">" + WebInspector
.UIString(" (%d)", listElements
) + "</span>";
289 var title
= "<div class=\"header-name\">" + WebInspector
.UIString("Request Method") + ":</div>";
290 title
+= "<div class=\"header-value\">" + this.resource
.requestMethod
+ "</div>"
292 var headerTreeElement
= new TreeElement(title
, null, false);
293 headerTreeElement
.selectable
= false;
294 headerElement
.appendChild(headerTreeElement
);
296 title
= "<div class=\"header-name\">" + WebInspector
.UIString("Status Code") + ":</div>";
297 title
+= "<div class=\"header-value\">" + WebInspector
.Resource
.StatusTextForCode(this.resource
.statusCode
) + "</div>"
299 headerTreeElement
= new TreeElement(title
, null, false);
300 headerTreeElement
.selectable
= false;
301 headerElement
.appendChild(headerTreeElement
);
305 _refreshHeaders: function(title
, headers
, headersTreeElement
)
307 headersTreeElement
.removeChildren();
309 var length
= headers
.length
;
310 headersTreeElement
.title
= title
.escapeHTML() + "<span class=\"header-count\">" + WebInspector
.UIString(" (%d)", length
) + "</span>";
311 headersTreeElement
.hidden
= !length
;
313 var length
= headers
.length
;
314 for (var i
= 0; i
< length
; ++i
) {
315 var title
= "<div class=\"header-name\">" + headers
[i
].header
.escapeHTML() + ":</div>";
316 title
+= "<div class=\"header-value\">" + headers
[i
].value
.escapeHTML() + "</div>"
318 var headerTreeElement
= new TreeElement(title
, null, false);
319 headerTreeElement
.selectable
= false;
320 headersTreeElement
.appendChild(headerTreeElement
);
325 WebInspector
.ResourceView
.prototype.__proto__
= WebInspector
.View
.prototype;