Web Inspector: Adopt ES6 Class Syntax for all Model Objects
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Models / Resource.js
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.Resource = class Resource extends WebInspector.SourceCode
27 {
28     constructor(url, mimeType, type, loaderIdentifier, requestIdentifier, requestMethod, requestHeaders, requestData, requestSentTimestamp, initiatorSourceCodeLocation)
29     {
30         super();
31
32         console.assert(url);
33
34         if (type in WebInspector.Resource.Type)
35             type = WebInspector.Resource.Type[type];
36
37         this._url = url;
38         this._mimeType = mimeType;
39         this._type = type || WebInspector.Resource.typeFromMIMEType(mimeType);
40         this._loaderIdentifier = loaderIdentifier || null;
41         this._requestIdentifier = requestIdentifier || null;
42         this._requestMethod = requestMethod || null;
43         this._requestData = requestData || null;
44         this._requestHeaders = requestHeaders || {};
45         this._responseHeaders = {};
46         this._parentFrame = null;
47         this._initiatorSourceCodeLocation = initiatorSourceCodeLocation || null;
48         this._requestSentTimestamp = requestSentTimestamp || NaN;
49         this._responseReceivedTimestamp = NaN;
50         this._lastRedirectReceivedTimestamp = NaN;
51         this._lastDataReceivedTimestamp = NaN;
52         this._finishedOrFailedTimestamp = NaN;
53         this._size = NaN;
54         this._transferSize = NaN;
55         this._cached = false;
56     }
57
58     // Static
59
60     static typeFromMIMEType(mimeType)
61     {
62         if (!mimeType)
63             return WebInspector.Resource.Type.Other;
64
65         mimeType = parseMIMEType(mimeType).type;
66
67         if (mimeType in WebInspector.Resource._mimeTypeMap)
68             return WebInspector.Resource._mimeTypeMap[mimeType];
69
70         if (mimeType.startsWith("image/"))
71             return WebInspector.Resource.Type.Image;
72
73         if (mimeType.startsWith("font/"))
74             return WebInspector.Resource.Type.Font;
75
76         return WebInspector.Resource.Type.Other;
77     }
78
79     static displayNameForType(type, plural)
80     {
81         switch(type) {
82         case WebInspector.Resource.Type.Document:
83             if (plural)
84                 return WebInspector.UIString("Documents");
85             return WebInspector.UIString("Document");
86         case WebInspector.Resource.Type.Stylesheet:
87             if (plural)
88                 return WebInspector.UIString("Stylesheets");
89             return WebInspector.UIString("Stylesheet");
90         case WebInspector.Resource.Type.Image:
91             if (plural)
92                 return WebInspector.UIString("Images");
93             return WebInspector.UIString("Image");
94         case WebInspector.Resource.Type.Font:
95             if (plural)
96                 return WebInspector.UIString("Fonts");
97             return WebInspector.UIString("Font");
98         case WebInspector.Resource.Type.Script:
99             if (plural)
100                 return WebInspector.UIString("Scripts");
101             return WebInspector.UIString("Script");
102         case WebInspector.Resource.Type.XHR:
103             if (plural)
104                 return WebInspector.UIString("XHRs");
105             return WebInspector.UIString("XHR");
106         case WebInspector.Resource.Type.WebSocket:
107             if (plural)
108                 return WebInspector.UIString("Sockets");
109             return WebInspector.UIString("Socket");
110         case WebInspector.Resource.Type.Other:
111             return WebInspector.UIString("Other");
112         default:
113             console.error("Unknown resource type: ", type);
114             return null;
115         }
116     }
117
118     // Public
119
120     get url()
121     {
122         return this._url;
123     }
124
125     get urlComponents()
126     {
127         if (!this._urlComponents)
128             this._urlComponents = parseURL(this._url);
129         return this._urlComponents;
130     }
131
132     get displayName()
133     {
134         return WebInspector.displayNameForURL(this._url, this.urlComponents);
135     }
136
137     get initiatorSourceCodeLocation()
138     {
139         return this._initiatorSourceCodeLocation;
140     }
141
142     get type()
143     {
144         return this._type;
145     }
146
147     get mimeType()
148     {
149         return this._mimeType;
150     }
151
152     get mimeTypeComponents()
153     {
154         if (!this._mimeTypeComponents)
155             this._mimeTypeComponents = parseMIMEType(this._mimeType);
156         return this._mimeTypeComponents;
157     }
158
159     get syntheticMIMEType()
160     {
161         // Resources are often transferred with a MIME-type that doesn't match the purpose the
162         // resource was loaded for, which is what WebInspector.Resource.Type represents.
163         // This getter generates a MIME-type, if needed, that matches the resource type.
164
165         // If the type matches the Resource.Type of the MIME-type, then return the actual MIME-type.
166         if (this._type === WebInspector.Resource.typeFromMIMEType(this._mimeType))
167             return this._mimeType;
168
169         // Return the default MIME-types for the Resource.Type, since the current MIME-type
170         // does not match what is expected for the Resource.Type.
171         switch (this._type) {
172         case WebInspector.Resource.Type.Document:
173             return "text/html";
174         case WebInspector.Resource.Type.Stylesheet:
175             return "text/css";
176         case WebInspector.Resource.Type.Script:
177             return "text/javascript";
178         }
179
180         // Return the actual MIME-type since we don't have a better synthesized one to return.
181         return this._mimeType;
182     }
183
184     createObjectURL()
185     {
186         // If content is not available, fallback to using original URL.
187         // The client may try to revoke it, but nothing will happen.
188         if (!this.content)
189             return this._url;
190
191         var content = this.content;
192         console.assert(content instanceof Blob, content);
193
194         return URL.createObjectURL(content);
195     }
196
197     isMainResource()
198     {
199         return this._parentFrame ? this._parentFrame.mainResource === this : false;
200     }
201
202     get parentFrame()
203     {
204         return this._parentFrame;
205     }
206
207     get loaderIdentifier()
208     {
209         return this._loaderIdentifier;
210     }
211
212     get requestIdentifier()
213     {
214         return this._requestIdentifier;
215     }
216
217     get finished()
218     {
219         return this._finished;
220     }
221
222     get failed()
223     {
224         return this._failed;
225     }
226
227     get canceled()
228     {
229         return this._canceled;
230     }
231
232     get requestMethod()
233     {
234         return this._requestMethod;
235     }
236
237     get requestData()
238     {
239         return this._requestData;
240     }
241
242     get requestDataContentType()
243     {
244         return this._requestHeaders.valueForCaseInsensitiveKey("Content-Type") || null;
245     }
246
247     get requestHeaders()
248     {
249         return this._requestHeaders;
250     }
251
252     get responseHeaders()
253     {
254         return this._responseHeaders;
255     }
256
257     get requestSentTimestamp()
258     {
259         return this._requestSentTimestamp;
260     }
261
262     get lastRedirectReceivedTimestamp()
263     {
264         return this._lastRedirectReceivedTimestamp;
265     }
266
267     get responseReceivedTimestamp()
268     {
269         return this._responseReceivedTimestamp;
270     }
271
272     get lastDataReceivedTimestamp()
273     {
274         return this._lastDataReceivedTimestamp;
275     }
276
277     get finishedOrFailedTimestamp()
278     {
279         return this._finishedOrFailedTimestamp;
280     }
281
282     get firstTimestamp()
283     {
284         return this.requestSentTimestamp || this.lastRedirectReceivedTimestamp || this.responseReceivedTimestamp || this.lastDataReceivedTimestamp || this.finishedOrFailedTimestamp;
285     }
286
287     get lastTimestamp()
288     {
289         return this.finishedOrFailedTimestamp || this.lastDataReceivedTimestamp || this.responseReceivedTimestamp || this.lastRedirectReceivedTimestamp || this.requestSentTimestamp;
290     }
291
292     get duration()
293     {
294         return this._finishedOrFailedTimestamp - this._requestSentTimestamp;
295     }
296
297     get latency()
298     {
299         return this._responseReceivedTimestamp - this._requestSentTimestamp;
300     }
301
302     get receiveDuration()
303     {
304         return this._finishedOrFailedTimestamp - this._responseReceivedTimestamp;
305     }
306
307     get cached()
308     {
309         return this._cached;
310     }
311
312     get statusCode()
313     {
314         return this._statusCode;
315     }
316
317     get statusText()
318     {
319         return this._statusText;
320     }
321
322     get size()
323     {
324         return this._size;
325     }
326
327     get encodedSize()
328     {
329         if (!isNaN(this._transferSize))
330             return this._transferSize;
331
332         // If we did not receive actual transfer size from network
333         // stack, we prefer using Content-Length over resourceSize as
334         // resourceSize may differ from actual transfer size if platform's
335         // network stack performed decoding (e.g. gzip decompression).
336         // The Content-Length, though, is expected to come from raw
337         // response headers and will reflect actual transfer length.
338         // This won't work for chunked content encoding, so fall back to
339         // resourceSize when we don't have Content-Length. This still won't
340         // work for chunks with non-trivial encodings. We need a way to
341         // get actual transfer size from the network stack.
342
343         return Number(this._responseHeaders.valueForCaseInsensitiveKey("Content-Length") || this._size);
344     }
345
346     get transferSize()
347     {
348         if (this.statusCode === 304) // Not modified
349             return this._responseHeadersSize;
350
351         if (this._cached)
352             return 0;
353
354         return this._responseHeadersSize + this.encodedSize;
355     }
356
357     get compressed()
358     {
359         var contentEncoding = this._responseHeaders.valueForCaseInsensitiveKey("Content-Encoding");
360         return contentEncoding && /\b(?:gzip|deflate)\b/.test(contentEncoding);
361     }
362
363     get scripts()
364     {
365         return this._scripts || [];
366     }
367
368     scriptForLocation(sourceCodeLocation)
369     {
370         console.assert(!(this instanceof WebInspector.SourceMapResource));
371         console.assert(sourceCodeLocation.sourceCode === this, "SourceCodeLocation must be in this Resource");
372         if (sourceCodeLocation.sourceCode !== this)
373             return null;
374
375         var lineNumber = sourceCodeLocation.lineNumber;
376         var columnNumber = sourceCodeLocation.columnNumber;
377         for (var i = 0; i < this._scripts.length; ++i) {
378             var script = this._scripts[i];
379             if (script.range.startLine <= lineNumber && script.range.endLine >= lineNumber) {
380                 if (script.range.startLine === lineNumber && columnNumber < script.range.startColumn)
381                     continue;
382                 if (script.range.endLine === lineNumber && columnNumber > script.range.endColumn)
383                     continue;
384                 return script;
385             }
386         }
387
388         return null;
389     }
390
391     updateForRedirectResponse(url, requestHeaders, elapsedTime)
392     {
393         console.assert(!this._finished);
394         console.assert(!this._failed);
395         console.assert(!this._canceled);
396
397         var oldURL = this._url;
398
399         this._url = url;
400         this._requestHeaders = requestHeaders || {};
401         this._lastRedirectReceivedTimestamp = elapsedTime || NaN;
402
403         if (oldURL !== url) {
404             // Delete the URL components so the URL is re-parsed the next time it is requested.
405             delete this._urlComponents;
406
407             this.dispatchEventToListeners(WebInspector.Resource.Event.URLDidChange, {oldURL});
408         }
409
410         this.dispatchEventToListeners(WebInspector.Resource.Event.RequestHeadersDidChange);
411         this.dispatchEventToListeners(WebInspector.Resource.Event.TimestampsDidChange);
412     }
413
414     updateForResponse(url, mimeType, type, responseHeaders, statusCode, statusText, elapsedTime)
415     {
416         console.assert(!this._finished);
417         console.assert(!this._failed);
418         console.assert(!this._canceled);
419
420         var oldURL = this._url;
421         var oldMIMEType = this._mimeType;
422         var oldType = this._type;
423
424         if (type in WebInspector.Resource.Type)
425             type = WebInspector.Resource.Type[type];
426
427         this._url = url;
428         this._mimeType = mimeType;
429         this._type = type || WebInspector.Resource.typeFromMIMEType(mimeType);
430         this._statusCode = statusCode;
431         this._statusText = statusText;
432         this._responseHeaders = responseHeaders || {};
433         this._responseReceivedTimestamp = elapsedTime || NaN;
434
435         this._responseHeadersSize = String(this._statusCode).length + this._statusText.length + 12; // Extra length is for "HTTP/1.1 ", " ", and "\r\n".
436         for (var name in this._responseHeaders)
437             this._responseHeadersSize += name.length + this._responseHeaders[name].length + 4; // Extra length is for ": ", and "\r\n".
438
439         if (statusCode === 304 && !this._cached)
440             this.markAsCached();
441
442         if (oldURL !== url) {
443             // Delete the URL components so the URL is re-parsed the next time it is requested.
444             delete this._urlComponents;
445
446             this.dispatchEventToListeners(WebInspector.Resource.Event.URLDidChange, {oldURL});
447         }
448
449         if (oldMIMEType !== mimeType) {
450             // Delete the MIME-type components so the MIME-type is re-parsed the next time it is requested.
451             delete this._mimeTypeComponents;
452
453             this.dispatchEventToListeners(WebInspector.Resource.Event.MIMETypeDidChange, {oldMIMEType});
454         }
455
456         if (oldType !== type)
457             this.dispatchEventToListeners(WebInspector.Resource.Event.TypeDidChange, {oldType});
458
459         console.assert(isNaN(this._size));
460         console.assert(isNaN(this._transferSize));
461
462         // The transferSize becomes 0 when status is 304 or Content-Length is available, so
463         // notify listeners of that change.
464         if (statusCode === 304 || this._responseHeaders.valueForCaseInsensitiveKey("Content-Length"))
465             this.dispatchEventToListeners(WebInspector.Resource.Event.TransferSizeDidChange);
466
467         this.dispatchEventToListeners(WebInspector.Resource.Event.ResponseReceived);
468         this.dispatchEventToListeners(WebInspector.Resource.Event.TimestampsDidChange);
469     }
470
471     canRequestContent()
472     {
473         return this._finished;
474     }
475
476     requestContentFromBackend()
477     {
478         // If we have the requestIdentifier we can get the actual response for this specific resource.
479         // Otherwise the content will be cached resource data, which might not exist anymore.
480         if (this._requestIdentifier)
481             return NetworkAgent.getResponseBody.promise(this._requestIdentifier);
482
483         // There is no request identifier or frame to request content from.
484         if (this._parentFrame)
485             return PageAgent.getResourceContent.promise(this._parentFrame.id, this._url);
486
487         return Promise.reject(new Error("Content request failed."));
488     }
489
490     increaseSize(dataLength, elapsedTime)
491     {
492         console.assert(dataLength >= 0);
493
494         if (isNaN(this._size))
495             this._size = 0;
496
497         var previousSize = this._size;
498
499         this._size += dataLength;
500
501         this._lastDataReceivedTimestamp = elapsedTime || NaN;
502
503         this.dispatchEventToListeners(WebInspector.Resource.Event.SizeDidChange, {previousSize});
504
505         // The transferSize is based off of size when status is not 304 or Content-Length is missing.
506         if (isNaN(this._transferSize) && this._statusCode !== 304 && !this._responseHeaders.valueForCaseInsensitiveKey("Content-Length"))
507             this.dispatchEventToListeners(WebInspector.Resource.Event.TransferSizeDidChange);
508     }
509
510     increaseTransferSize(encodedDataLength)
511     {
512         console.assert(encodedDataLength >= 0);
513
514         if (isNaN(this._transferSize))
515             this._transferSize = 0;
516         this._transferSize += encodedDataLength;
517
518         this.dispatchEventToListeners(WebInspector.Resource.Event.TransferSizeDidChange);
519     }
520
521     markAsCached()
522     {
523         this._cached = true;
524
525         this.dispatchEventToListeners(WebInspector.Resource.Event.CacheStatusDidChange);
526
527         // The transferSize is starts returning 0 when cached is true, unless status is 304.
528         if (this._statusCode !== 304)
529             this.dispatchEventToListeners(WebInspector.Resource.Event.TransferSizeDidChange);
530     }
531
532     markAsFinished(elapsedTime)
533     {
534         console.assert(!this._failed);
535         console.assert(!this._canceled);
536
537         this._finished = true;
538         this._finishedOrFailedTimestamp = elapsedTime || NaN;
539
540         if (this._finishThenRequestContentPromise)
541             delete this._finishThenRequestContentPromise;
542
543         this.dispatchEventToListeners(WebInspector.Resource.Event.LoadingDidFinish);
544         this.dispatchEventToListeners(WebInspector.Resource.Event.TimestampsDidChange);
545     }
546
547     markAsFailed(canceled, elapsedTime)
548     {
549         console.assert(!this._finished);
550
551         this._failed = true;
552         this._canceled = canceled;
553         this._finishedOrFailedTimestamp = elapsedTime || NaN;
554
555         this.dispatchEventToListeners(WebInspector.Resource.Event.LoadingDidFail);
556         this.dispatchEventToListeners(WebInspector.Resource.Event.TimestampsDidChange);
557     }
558
559     revertMarkAsFinished()
560     {
561         console.assert(!this._failed);
562         console.assert(!this._canceled);
563         console.assert(this._finished);
564
565         this._finished = false;
566         this._finishedOrFailedTimestamp = NaN;
567     }
568
569     getImageSize(callback)
570     {
571         // Throw an error in the case this resource is not an image.
572         if (this.type !== WebInspector.Resource.Type.Image)
573             throw "Resource is not an image.";
574
575         // See if we've already computed and cached the image size,
576         // in which case we can provide them directly.
577         if (this._imageSize) {
578             callback(this._imageSize);
579             return;
580         }
581
582         var objectURL = null;
583
584         // Event handler for the image "load" event.
585         function imageDidLoad()
586         {
587             URL.revokeObjectURL(objectURL);
588
589             // Cache the image metrics.
590             this._imageSize = {
591                 width: image.width,
592                 height: image.height
593             };
594
595             callback(this._imageSize);
596         }
597
598         // Create an <img> element that we'll use to load the image resource
599         // so that we can query its intrinsic size.
600         var image = new Image;
601         image.addEventListener("load", imageDidLoad.bind(this), false);
602
603         // Set the image source using an object URL once we've obtained its data.
604         this.requestContent().then(function(content) {
605             objectURL = image.src = content.sourceCode.createObjectURL();
606         });
607     }
608
609     requestContent()
610     {
611         if (this._finished)
612             return super.requestContent();
613
614         if (this._failed)
615             return Promise.resolve({error: WebInspector.UIString("An error occurred trying to load the resource.")});
616
617         if (!this._finishThenRequestContentPromise) {
618             this._finishThenRequestContentPromise = new Promise(function (resolve, reject) {
619                 this.addEventListener(WebInspector.Resource.Event.LoadingDidFinish, resolve);
620                 this.addEventListener(WebInspector.Resource.Event.LoadingDidFail, reject);
621             }.bind(this)).then(WebInspector.SourceCode.prototype.requestContent.bind(this));
622         }
623
624         return this._finishThenRequestContentPromise;
625     }
626
627     associateWithScript(script)
628     {
629         if (!this._scripts)
630             this._scripts = [];
631
632         this._scripts.push(script);
633
634         // COMPATIBILITY (iOS 6): Resources did not know their type until a response
635         // was received. We can set the Resource type to be Script here.
636         if (this._type === WebInspector.Resource.Type.Other) {
637             var oldType = this._type;
638             this._type = WebInspector.Resource.Type.Script;
639             this.dispatchEventToListeners(WebInspector.Resource.Event.TypeDidChange, {oldType});
640         }
641     }
642
643     saveIdentityToCookie(cookie)
644     {
645         cookie[WebInspector.Resource.URLCookieKey] = this.url.hash;
646         cookie[WebInspector.Resource.MainResourceCookieKey] = this.isMainResource();
647     }
648 };
649
650 WebInspector.Resource.TypeIdentifier = "resource";
651 WebInspector.Resource.URLCookieKey = "resource-url";
652 WebInspector.Resource.MainResourceCookieKey = "resource-is-main-resource";
653
654 WebInspector.Resource.Event = {
655     URLDidChange: "resource-url-did-change",
656     MIMETypeDidChange: "resource-mime-type-did-change",
657     TypeDidChange: "resource-type-did-change",
658     RequestHeadersDidChange: "resource-request-headers-did-change",
659     ResponseReceived: "resource-response-received",
660     LoadingDidFinish: "resource-loading-did-finish",
661     LoadingDidFail: "resource-loading-did-fail",
662     TimestampsDidChange: "resource-timestamps-did-change",
663     SizeDidChange: "resource-size-did-change",
664     TransferSizeDidChange: "resource-transfer-size-did-change",
665     CacheStatusDidChange: "resource-cached-did-change"
666 };
667
668 // Keep these in sync with the "ResourceType" enum defined by the "Page" domain.
669 WebInspector.Resource.Type = {
670     Document: "resource-type-document",
671     Stylesheet: "resource-type-stylesheet",
672     Image: "resource-type-image",
673     Font: "resource-type-font",
674     Script: "resource-type-script",
675     XHR: "resource-type-xhr",
676     WebSocket: "resource-type-websocket",
677     Other: "resource-type-other"
678 };
679
680 // This MIME Type map is private, use WebInspector.Resource.typeFromMIMEType().
681 WebInspector.Resource._mimeTypeMap = {
682     "text/html": WebInspector.Resource.Type.Document,
683     "text/xml": WebInspector.Resource.Type.Document,
684     "text/plain": WebInspector.Resource.Type.Document,
685     "application/xhtml+xml": WebInspector.Resource.Type.Document,
686     "image/svg+xml": WebInspector.Resource.Type.Document,
687
688     "text/css": WebInspector.Resource.Type.Stylesheet,
689     "text/xsl": WebInspector.Resource.Type.Stylesheet,
690     "text/x-less": WebInspector.Resource.Type.Stylesheet,
691     "text/x-sass": WebInspector.Resource.Type.Stylesheet,
692     "text/x-scss": WebInspector.Resource.Type.Stylesheet,
693
694     "application/pdf": WebInspector.Resource.Type.Image,
695
696     "application/x-font-type1": WebInspector.Resource.Type.Font,
697     "application/x-font-ttf": WebInspector.Resource.Type.Font,
698     "application/x-font-woff": WebInspector.Resource.Type.Font,
699     "application/x-truetype-font": WebInspector.Resource.Type.Font,
700
701     "text/javascript": WebInspector.Resource.Type.Script,
702     "text/ecmascript": WebInspector.Resource.Type.Script,
703     "application/javascript": WebInspector.Resource.Type.Script,
704     "application/ecmascript": WebInspector.Resource.Type.Script,
705     "application/x-javascript": WebInspector.Resource.Type.Script,
706     "application/json": WebInspector.Resource.Type.Script,
707     "application/x-json": WebInspector.Resource.Type.Script,
708     "text/x-javascript": WebInspector.Resource.Type.Script,
709     "text/x-json": WebInspector.Resource.Type.Script,
710     "text/javascript1.1": WebInspector.Resource.Type.Script,
711     "text/javascript1.2": WebInspector.Resource.Type.Script,
712     "text/javascript1.3": WebInspector.Resource.Type.Script,
713     "text/jscript": WebInspector.Resource.Type.Script,
714     "text/livescript": WebInspector.Resource.Type.Script,
715     "text/x-livescript": WebInspector.Resource.Type.Script,
716     "text/typescript": WebInspector.Resource.Type.Script,
717     "text/x-clojure": WebInspector.Resource.Type.Script,
718     "text/x-coffeescript": WebInspector.Resource.Type.Script
719 };