1/* 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com). 4 * Copyright (C) 2009 Joseph Pecoraro 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 16 * its contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31var Preferences = { 32 ignoreWhitespace: true, 33 showUserAgentStyles: true, 34 maxInlineTextChildLength: 80, 35 minConsoleHeight: 75, 36 minSidebarWidth: 100, 37 minElementsSidebarWidth: 200, 38 minScriptsSidebarWidth: 200, 39 showInheritedComputedStyleProperties: false, 40 styleRulesExpandedState: {}, 41 showMissingLocalizedStrings: false, 42 useDOMAgent: false 43} 44 45var WebInspector = { 46 resources: {}, 47 resourceURLMap: {}, 48 missingLocalizedStrings: {}, 49 50 get previousFocusElement() 51 { 52 return this._previousFocusElement; 53 }, 54 55 get currentFocusElement() 56 { 57 return this._currentFocusElement; 58 }, 59 60 set currentFocusElement(x) 61 { 62 if (this._currentFocusElement !== x) 63 this._previousFocusElement = this._currentFocusElement; 64 this._currentFocusElement = x; 65 66 if (this._currentFocusElement) { 67 this._currentFocusElement.focus(); 68 69 // Make a caret selection inside the new element if there isn't a range selection and 70 // there isn't already a caret selection inside. 71 var selection = window.getSelection(); 72 if (selection.isCollapsed && !this._currentFocusElement.isInsertionCaretInside()) { 73 var selectionRange = document.createRange(); 74 selectionRange.setStart(this._currentFocusElement, 0); 75 selectionRange.setEnd(this._currentFocusElement, 0); 76 77 selection.removeAllRanges(); 78 selection.addRange(selectionRange); 79 } 80 } else if (this._previousFocusElement) 81 this._previousFocusElement.blur(); 82 }, 83 84 get currentPanel() 85 { 86 return this._currentPanel; 87 }, 88 89 set currentPanel(x) 90 { 91 if (this._currentPanel === x) 92 return; 93 94 if (this._currentPanel) 95 this._currentPanel.hide(); 96 97 this._currentPanel = x; 98 99 this.updateSearchLabel(); 100 101 if (x) { 102 x.show(); 103 104 if (this.currentQuery) { 105 if (x.performSearch) { 106 function performPanelSearch() 107 { 108 this.updateSearchMatchesCount(); 109 110 x.currentQuery = this.currentQuery; 111 x.performSearch(this.currentQuery); 112 } 113 114 // Perform the search on a timeout so the panel switches fast. 115 setTimeout(performPanelSearch.bind(this), 0); 116 } else { 117 // Update to show Not found for panels that can't be searched. 118 this.updateSearchMatchesCount(); 119 } 120 } 121 } 122 123 for (var panelName in WebInspector.panels) { 124 if (WebInspector.panels[panelName] == x) 125 InspectorController.storeLastActivePanel(panelName); 126 } 127 }, 128 129 _createPanels: function() 130 { 131 var hiddenPanels = (InspectorController.hiddenPanels() || "").split(','); 132 if (hiddenPanels.indexOf("elements") === -1) 133 this.panels.elements = new WebInspector.ElementsPanel(); 134 if (hiddenPanels.indexOf("resources") === -1) 135 this.panels.resources = new WebInspector.ResourcesPanel(); 136 if (hiddenPanels.indexOf("scripts") === -1) 137 this.panels.scripts = new WebInspector.ScriptsPanel(); 138 if (hiddenPanels.indexOf("profiles") === -1) 139 this.panels.profiles = new WebInspector.ProfilesPanel(); 140 if (hiddenPanels.indexOf("databases") === -1) 141 this.panels.databases = new WebInspector.DatabasesPanel(); 142 }, 143 144 get attached() 145 { 146 return this._attached; 147 }, 148 149 set attached(x) 150 { 151 if (this._attached === x) 152 return; 153 154 this._attached = x; 155 156 this.updateSearchLabel(); 157 158 var dockToggleButton = document.getElementById("dock-status-bar-item"); 159 var body = document.body; 160 161 if (x) { 162 InspectorController.attach(); 163 body.removeStyleClass("detached"); 164 body.addStyleClass("attached"); 165 dockToggleButton.title = WebInspector.UIString("Undock into separate window."); 166 } else { 167 InspectorController.detach(); 168 body.removeStyleClass("attached"); 169 body.addStyleClass("detached"); 170 dockToggleButton.title = WebInspector.UIString("Dock to main window."); 171 } 172 }, 173 174 get errors() 175 { 176 return this._errors || 0; 177 }, 178 179 set errors(x) 180 { 181 x = Math.max(x, 0); 182 183 if (this._errors === x) 184 return; 185 this._errors = x; 186 this._updateErrorAndWarningCounts(); 187 }, 188 189 get warnings() 190 { 191 return this._warnings || 0; 192 }, 193 194 set warnings(x) 195 { 196 x = Math.max(x, 0); 197 198 if (this._warnings === x) 199 return; 200 this._warnings = x; 201 this._updateErrorAndWarningCounts(); 202 }, 203 204 _updateErrorAndWarningCounts: function() 205 { 206 var errorWarningElement = document.getElementById("error-warning-count"); 207 if (!errorWarningElement) 208 return; 209 210 if (!this.errors && !this.warnings) { 211 errorWarningElement.addStyleClass("hidden"); 212 return; 213 } 214 215 errorWarningElement.removeStyleClass("hidden"); 216 217 errorWarningElement.removeChildren(); 218 219 if (this.errors) { 220 var errorElement = document.createElement("span"); 221 errorElement.id = "error-count"; 222 errorElement.textContent = this.errors; 223 errorWarningElement.appendChild(errorElement); 224 } 225 226 if (this.warnings) { 227 var warningsElement = document.createElement("span"); 228 warningsElement.id = "warning-count"; 229 warningsElement.textContent = this.warnings; 230 errorWarningElement.appendChild(warningsElement); 231 } 232 233 if (this.errors) { 234 if (this.warnings) { 235 if (this.errors == 1) { 236 if (this.warnings == 1) 237 errorWarningElement.title = WebInspector.UIString("%d error, %d warning", this.errors, this.warnings); 238 else 239 errorWarningElement.title = WebInspector.UIString("%d error, %d warnings", this.errors, this.warnings); 240 } else if (this.warnings == 1) 241 errorWarningElement.title = WebInspector.UIString("%d errors, %d warning", this.errors, this.warnings); 242 else 243 errorWarningElement.title = WebInspector.UIString("%d errors, %d warnings", this.errors, this.warnings); 244 } else if (this.errors == 1) 245 errorWarningElement.title = WebInspector.UIString("%d error", this.errors); 246 else 247 errorWarningElement.title = WebInspector.UIString("%d errors", this.errors); 248 } else if (this.warnings == 1) 249 errorWarningElement.title = WebInspector.UIString("%d warning", this.warnings); 250 else if (this.warnings) 251 errorWarningElement.title = WebInspector.UIString("%d warnings", this.warnings); 252 else 253 errorWarningElement.title = null; 254 }, 255 256 get styleChanges() 257 { 258 return this._styleChanges; 259 }, 260 261 set styleChanges(x) 262 { 263 x = Math.max(x, 0); 264 265 if (this._styleChanges === x) 266 return; 267 this._styleChanges = x; 268 this._updateChangesCount(); 269 }, 270 271 _updateChangesCount: function() 272 { 273 // TODO: Remove immediate return when enabling the Changes Panel 274 return; 275 276 var changesElement = document.getElementById("changes-count"); 277 if (!changesElement) 278 return; 279 280 if (!this.styleChanges) { 281 changesElement.addStyleClass("hidden"); 282 return; 283 } 284 285 changesElement.removeStyleClass("hidden"); 286 changesElement.removeChildren(); 287 288 if (this.styleChanges) { 289 var styleChangesElement = document.createElement("span"); 290 styleChangesElement.id = "style-changes-count"; 291 styleChangesElement.textContent = this.styleChanges; 292 changesElement.appendChild(styleChangesElement); 293 } 294 295 if (this.styleChanges) { 296 if (this.styleChanges === 1) 297 changesElement.title = WebInspector.UIString("%d style change", this.styleChanges); 298 else 299 changesElement.title = WebInspector.UIString("%d style changes", this.styleChanges); 300 } 301 }, 302 303 get hoveredDOMNode() 304 { 305 return this._hoveredDOMNode; 306 }, 307 308 set hoveredDOMNode(x) 309 { 310 if (objectsAreSame(this._hoveredDOMNode, x)) 311 return; 312 313 this._hoveredDOMNode = x; 314 315 if (this._hoveredDOMNode) 316 this._updateHoverHighlightSoon(this.showingDOMNodeHighlight ? 50 : 500); 317 else 318 this._updateHoverHighlight(); 319 }, 320 321 _updateHoverHighlightSoon: function(delay) 322 { 323 if ("_updateHoverHighlightTimeout" in this) 324 clearTimeout(this._updateHoverHighlightTimeout); 325 this._updateHoverHighlightTimeout = setTimeout(this._updateHoverHighlight.bind(this), delay); 326 }, 327 328 _updateHoverHighlight: function() 329 { 330 if ("_updateHoverHighlightTimeout" in this) { 331 clearTimeout(this._updateHoverHighlightTimeout); 332 delete this._updateHoverHighlightTimeout; 333 } 334 335 if (this._hoveredDOMNode) { 336 InspectorController.highlightDOMNode(this._hoveredDOMNode); 337 this.showingDOMNodeHighlight = true; 338 } else { 339 InspectorController.hideDOMNodeHighlight(); 340 this.showingDOMNodeHighlight = false; 341 } 342 } 343} 344 345WebInspector.loaded = function() 346{ 347 var platform = InspectorController.platform(); 348 document.body.addStyleClass("platform-" + platform); 349 350 this.drawer = new WebInspector.Drawer(); 351 this.console = new WebInspector.ConsoleView(this.drawer); 352 // TODO: Uncomment when enabling the Changes Panel 353 // this.changes = new WebInspector.ChangesView(this.drawer); 354 // TODO: Remove class="hidden" from inspector.html on button#changes-status-bar-item 355 this.drawer.visibleView = this.console; 356 357 if (Preferences.useDOMAgent) 358 this.domAgent = new WebInspector.DOMAgent(); 359 360 this.resourceCategories = { 361 documents: new WebInspector.ResourceCategory(WebInspector.UIString("Documents"), "documents"), 362 stylesheets: new WebInspector.ResourceCategory(WebInspector.UIString("Stylesheets"), "stylesheets"), 363 images: new WebInspector.ResourceCategory(WebInspector.UIString("Images"), "images"), 364 scripts: new WebInspector.ResourceCategory(WebInspector.UIString("Scripts"), "scripts"), 365 xhr: new WebInspector.ResourceCategory(WebInspector.UIString("XHR"), "xhr"), 366 fonts: new WebInspector.ResourceCategory(WebInspector.UIString("Fonts"), "fonts"), 367 other: new WebInspector.ResourceCategory(WebInspector.UIString("Other"), "other") 368 }; 369 370 this.panels = {}; 371 this._createPanels(); 372 373 var toolbarElement = document.getElementById("toolbar"); 374 var previousToolbarItem = toolbarElement.children[0]; 375 376 this.panelOrder = []; 377 for (var panelName in this.panels) { 378 var panel = this.panels[panelName]; 379 var panelToolbarItem = panel.toolbarItem; 380 this.panelOrder.push(panel); 381 panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind(this)); 382 if (previousToolbarItem) 383 toolbarElement.insertBefore(panelToolbarItem, previousToolbarItem.nextSibling); 384 else 385 toolbarElement.insertBefore(panelToolbarItem, toolbarElement.firstChild); 386 previousToolbarItem = panelToolbarItem; 387 } 388 389 this.Tips = { 390 ResourceNotCompressed: {id: 0, message: WebInspector.UIString("You could save bandwidth by having your web server compress this transfer with gzip or zlib.")} 391 }; 392 393 this.Warnings = { 394 IncorrectMIMEType: {id: 0, message: WebInspector.UIString("Resource interpreted as %s but transferred with MIME type %s.")} 395 }; 396 397 this.addMainEventListeners(document); 398 399 window.addEventListener("unload", this.windowUnload.bind(this), true); 400 window.addEventListener("resize", this.windowResize.bind(this), true); 401 402 document.addEventListener("focus", this.focusChanged.bind(this), true); 403 document.addEventListener("keydown", this.documentKeyDown.bind(this), true); 404 document.addEventListener("keyup", this.documentKeyUp.bind(this), true); 405 document.addEventListener("beforecopy", this.documentCanCopy.bind(this), true); 406 document.addEventListener("copy", this.documentCopy.bind(this), true); 407 408 var mainPanelsElement = document.getElementById("main-panels"); 409 mainPanelsElement.handleKeyEvent = this.mainKeyDown.bind(this); 410 mainPanelsElement.handleKeyUpEvent = this.mainKeyUp.bind(this); 411 mainPanelsElement.handleCopyEvent = this.mainCopy.bind(this); 412 413 // Focus the mainPanelsElement in a timeout so it happens after the initial focus, 414 // so it doesn't get reset to the first toolbar button. This initial focus happens 415 // on Mac when the window is made key and the WebHTMLView becomes the first responder. 416 setTimeout(function() { WebInspector.currentFocusElement = mainPanelsElement }, 0); 417 418 var dockToggleButton = document.getElementById("dock-status-bar-item"); 419 dockToggleButton.addEventListener("click", this.toggleAttach.bind(this), false); 420 421 if (this.attached) 422 dockToggleButton.title = WebInspector.UIString("Undock into separate window."); 423 else 424 dockToggleButton.title = WebInspector.UIString("Dock to main window."); 425 426 var errorWarningCount = document.getElementById("error-warning-count"); 427 errorWarningCount.addEventListener("click", this.showConsole.bind(this), false); 428 this._updateErrorAndWarningCounts(); 429 430 this.styleChanges = 0; 431 // TODO: Uncomment when enabling the Changes Panel 432 // var changesElement = document.getElementById("changes-count"); 433 // changesElement.addEventListener("click", this.showChanges.bind(this), false); 434 // this._updateErrorAndWarningCounts(); 435 436 var searchField = document.getElementById("search"); 437 searchField.addEventListener("keydown", this.searchKeyDown.bind(this), false); 438 searchField.addEventListener("keyup", this.searchKeyUp.bind(this), false); 439 searchField.addEventListener("search", this.performSearch.bind(this), false); // when the search is emptied 440 441 document.getElementById("toolbar").addEventListener("mousedown", this.toolbarDragStart, true); 442 document.getElementById("close-button").addEventListener("click", this.close, true); 443 444 InspectorController.loaded(Preferences.useDOMAgent); 445} 446 447var windowLoaded = function() 448{ 449 var localizedStringsURL = InspectorController.localizedStringsURL(); 450 if (localizedStringsURL) { 451 var localizedStringsScriptElement = document.createElement("script"); 452 localizedStringsScriptElement.addEventListener("load", WebInspector.loaded.bind(WebInspector), false); 453 localizedStringsScriptElement.type = "text/javascript"; 454 localizedStringsScriptElement.src = localizedStringsURL; 455 document.getElementsByTagName("head").item(0).appendChild(localizedStringsScriptElement); 456 } else 457 WebInspector.loaded(); 458 459 window.removeEventListener("load", windowLoaded, false); 460 delete windowLoaded; 461}; 462 463window.addEventListener("load", windowLoaded, false); 464 465WebInspector.dispatch = function() { 466 var methodName = arguments[0]; 467 var parameters = Array.prototype.slice.call(arguments, 1); 468 WebInspector[methodName].apply(this, parameters); 469} 470 471WebInspector.windowUnload = function(event) 472{ 473 InspectorController.windowUnloading(); 474} 475 476WebInspector.windowResize = function(event) 477{ 478 if (this.currentPanel && this.currentPanel.resize) 479 this.currentPanel.resize(); 480} 481 482WebInspector.windowFocused = function(event) 483{ 484 if (event.target.nodeType === Node.DOCUMENT_NODE) 485 document.body.removeStyleClass("inactive"); 486} 487 488WebInspector.windowBlured = function(event) 489{ 490 if (event.target.nodeType === Node.DOCUMENT_NODE) 491 document.body.addStyleClass("inactive"); 492} 493 494WebInspector.focusChanged = function(event) 495{ 496 this.currentFocusElement = event.target; 497} 498 499WebInspector.setAttachedWindow = function(attached) 500{ 501 this.attached = attached; 502} 503 504WebInspector.close = function(event) 505{ 506 InspectorController.closeWindow(); 507} 508 509WebInspector.documentClick = function(event) 510{ 511 var anchor = event.target.enclosingNodeOrSelfWithNodeName("a"); 512 if (!anchor) 513 return; 514 515 // Prevent the link from navigating, since we don't do any navigation by following links normally. 516 event.preventDefault(); 517 518 function followLink() 519 { 520 // FIXME: support webkit-html-external-link links here. 521 if (anchor.href in WebInspector.resourceURLMap) { 522 if (anchor.hasStyleClass("webkit-html-external-link")) { 523 anchor.removeStyleClass("webkit-html-external-link"); 524 anchor.addStyleClass("webkit-html-resource-link"); 525 } 526 527 WebInspector.showResourceForURL(anchor.href, anchor.lineNumber, anchor.preferredPanel); 528 } else { 529 var profileStringRegEx = new RegExp("webkit-profile://.+/([0-9]+)"); 530 var profileString = profileStringRegEx.exec(anchor.href); 531 if (profileString) 532 WebInspector.showProfileById(profileString[1]) 533 } 534 } 535 536 if (WebInspector.followLinkTimeout) 537 clearTimeout(WebInspector.followLinkTimeout); 538 539 if (anchor.preventFollowOnDoubleClick) { 540 // Start a timeout if this is the first click, if the timeout is canceled 541 // before it fires, then a double clicked happened or another link was clicked. 542 if (event.detail === 1) 543 WebInspector.followLinkTimeout = setTimeout(followLink, 333); 544 return; 545 } 546 547 followLink(); 548} 549 550WebInspector.documentKeyDown = function(event) 551{ 552 if (!this.currentFocusElement) 553 return; 554 if (this.currentFocusElement.handleKeyEvent) 555 this.currentFocusElement.handleKeyEvent(event); 556 else if (this.currentFocusElement.id && this.currentFocusElement.id.length && WebInspector[this.currentFocusElement.id + "KeyDown"]) 557 WebInspector[this.currentFocusElement.id + "KeyDown"](event); 558 559 if (!event.handled) { 560 var isMac = InspectorController.platform().indexOf("mac-") === 0; 561 562 switch (event.keyIdentifier) { 563 case "U+001B": // Escape key 564 this.drawer.visible = !this.drawer.visible; 565 event.preventDefault(); 566 break; 567 568 case "U+0046": // F key 569 if (isMac) 570 var isFindKey = event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey; 571 else 572 var isFindKey = event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey; 573 574 if (isFindKey) { 575 var searchField = document.getElementById("search"); 576 searchField.focus(); 577 searchField.select(); 578 event.preventDefault(); 579 } 580 581 break; 582 583 case "U+0047": // G key 584 if (isMac) 585 var isFindAgainKey = event.metaKey && !event.ctrlKey && !event.altKey; 586 else 587 var isFindAgainKey = event.ctrlKey && !event.metaKey && !event.altKey; 588 589 if (isFindAgainKey) { 590 if (event.shiftKey) { 591 if (this.currentPanel.jumpToPreviousSearchResult) 592 this.currentPanel.jumpToPreviousSearchResult(); 593 } else if (this.currentPanel.jumpToNextSearchResult) 594 this.currentPanel.jumpToNextSearchResult(); 595 event.preventDefault(); 596 } 597 598 break; 599 600 case "U+005B": // [ key 601 if (isMac) 602 var isRotateLeft = event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey; 603 else 604 var isRotateLeft = event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey; 605 606 if (isRotateLeft) { 607 var index = this.panelOrder.indexOf(this.currentPanel); 608 index = (index === 0) ? this.panelOrder.length - 1 : index - 1; 609 this.panelOrder[index].toolbarItem.click(); 610 event.preventDefault(); 611 } 612 613 break; 614 615 case "U+005D": // ] key 616 if (isMac) 617 var isRotateRight = event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey; 618 else 619 var isRotateRight = event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey; 620 621 if (isRotateRight) { 622 var index = this.panelOrder.indexOf(this.currentPanel); 623 index = (index + 1) % this.panelOrder.length; 624 this.panelOrder[index].toolbarItem.click(); 625 event.preventDefault(); 626 } 627 628 break; 629 } 630 } 631} 632 633WebInspector.documentKeyUp = function(event) 634{ 635 if (!this.currentFocusElement || !this.currentFocusElement.handleKeyUpEvent) 636 return; 637 this.currentFocusElement.handleKeyUpEvent(event); 638} 639 640WebInspector.documentCanCopy = function(event) 641{ 642 if (!this.currentFocusElement) 643 return; 644 // Calling preventDefault() will say "we support copying, so enable the Copy menu". 645 if (this.currentFocusElement.handleCopyEvent) 646 event.preventDefault(); 647 else if (this.currentFocusElement.id && this.currentFocusElement.id.length && WebInspector[this.currentFocusElement.id + "Copy"]) 648 event.preventDefault(); 649} 650 651WebInspector.documentCopy = function(event) 652{ 653 if (!this.currentFocusElement) 654 return; 655 if (this.currentFocusElement.handleCopyEvent) 656 this.currentFocusElement.handleCopyEvent(event); 657 else if (this.currentFocusElement.id && this.currentFocusElement.id.length && WebInspector[this.currentFocusElement.id + "Copy"]) 658 WebInspector[this.currentFocusElement.id + "Copy"](event); 659} 660 661WebInspector.mainKeyDown = function(event) 662{ 663 if (this.currentPanel && this.currentPanel.handleKeyEvent) 664 this.currentPanel.handleKeyEvent(event); 665} 666 667WebInspector.mainKeyUp = function(event) 668{ 669 if (this.currentPanel && this.currentPanel.handleKeyUpEvent) 670 this.currentPanel.handleKeyUpEvent(event); 671} 672 673WebInspector.mainCopy = function(event) 674{ 675 if (this.currentPanel && this.currentPanel.handleCopyEvent) 676 this.currentPanel.handleCopyEvent(event); 677} 678 679WebInspector.animateStyle = function(animations, duration, callback, complete) 680{ 681 if (complete === undefined) 682 complete = 0; 683 var slice = (1000 / 30); // 30 frames per second 684 685 var defaultUnit = "px"; 686 var propertyUnit = {opacity: ""}; 687 688 for (var i = 0; i < animations.length; ++i) { 689 var animation = animations[i]; 690 var element = null; 691 var start = null; 692 var current = null; 693 var end = null; 694 var key = null; 695 for (key in animation) { 696 if (key === "element") 697 element = animation[key]; 698 else if (key === "start") 699 start = animation[key]; 700 else if (key === "current") 701 current = animation[key]; 702 else if (key === "end") 703 end = animation[key]; 704 } 705 706 if (!element || !end) 707 continue; 708 709 var computedStyle = element.ownerDocument.defaultView.getComputedStyle(element); 710 if (!start) { 711 start = {}; 712 for (key in end) 713 start[key] = parseInt(computedStyle.getPropertyValue(key)); 714 animation.start = start; 715 } else if (complete == 0) 716 for (key in start) 717 element.style.setProperty(key, start[key] + (key in propertyUnit ? propertyUnit[key] : defaultUnit)); 718 719 if (!current) { 720 current = {}; 721 for (key in start) 722 current[key] = start[key]; 723 animation.current = current; 724 } 725 726 function cubicInOut(t, b, c, d) 727 { 728 if ((t/=d/2) < 1) return c/2*t*t*t + b; 729 return c/2*((t-=2)*t*t + 2) + b; 730 } 731 732 var style = element.style; 733 for (key in end) { 734 var startValue = start[key]; 735 var currentValue = current[key]; 736 var endValue = end[key]; 737 if ((complete + slice) < duration) { 738 var delta = (endValue - startValue) / (duration / slice); 739 var newValue = cubicInOut(complete, startValue, endValue - startValue, duration); 740 style.setProperty(key, newValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit)); 741 current[key] = newValue; 742 } else { 743 style.setProperty(key, endValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit)); 744 } 745 } 746 } 747 748 if (complete < duration) 749 setTimeout(WebInspector.animateStyle, slice, animations, duration, callback, complete + slice); 750 else if (callback) 751 callback(); 752} 753 754WebInspector.updateSearchLabel = function() 755{ 756 if (!this.currentPanel) 757 return; 758 759 var newLabel = WebInspector.UIString("Search %s", this.currentPanel.toolbarItemLabel); 760 if (this.attached) 761 document.getElementById("search").setAttribute("placeholder", newLabel); 762 else { 763 document.getElementById("search").removeAttribute("placeholder"); 764 document.getElementById("search-toolbar-label").textContent = newLabel; 765 } 766} 767 768WebInspector.toggleAttach = function() 769{ 770 this.attached = !this.attached; 771} 772 773WebInspector.toolbarDragStart = function(event) 774{ 775 if (!WebInspector.attached && InspectorController.platform() !== "mac-leopard") 776 return; 777 778 var target = event.target; 779 if (target.hasStyleClass("toolbar-item") && target.hasStyleClass("toggleable")) 780 return; 781 782 var toolbar = document.getElementById("toolbar"); 783 if (target !== toolbar && !target.hasStyleClass("toolbar-item")) 784 return; 785 786 toolbar.lastScreenX = event.screenX; 787 toolbar.lastScreenY = event.screenY; 788 789 WebInspector.elementDragStart(toolbar, WebInspector.toolbarDrag, WebInspector.toolbarDragEnd, event, (WebInspector.attached ? "row-resize" : "default")); 790} 791 792WebInspector.toolbarDragEnd = function(event) 793{ 794 var toolbar = document.getElementById("toolbar"); 795 796 WebInspector.elementDragEnd(event); 797 798 delete toolbar.lastScreenX; 799 delete toolbar.lastScreenY; 800} 801 802WebInspector.toolbarDrag = function(event) 803{ 804 var toolbar = document.getElementById("toolbar"); 805 806 if (WebInspector.attached) { 807 var height = window.innerHeight - (event.screenY - toolbar.lastScreenY); 808 809 InspectorController.setAttachedWindowHeight(height); 810 } else { 811 var x = event.screenX - toolbar.lastScreenX; 812 var y = event.screenY - toolbar.lastScreenY; 813 814 // We cannot call window.moveBy here because it restricts the movement 815 // of the window at the edges. 816 InspectorController.moveByUnrestricted(x, y); 817 } 818 819 toolbar.lastScreenX = event.screenX; 820 toolbar.lastScreenY = event.screenY; 821 822 event.preventDefault(); 823} 824 825WebInspector.elementDragStart = function(element, dividerDrag, elementDragEnd, event, cursor) 826{ 827 if (this._elementDraggingEventListener || this._elementEndDraggingEventListener) 828 this.elementDragEnd(event); 829 830 this._elementDraggingEventListener = dividerDrag; 831 this._elementEndDraggingEventListener = elementDragEnd; 832 833 document.addEventListener("mousemove", dividerDrag, true); 834 document.addEventListener("mouseup", elementDragEnd, true); 835 836 document.body.style.cursor = cursor; 837 838 event.preventDefault(); 839} 840 841WebInspector.elementDragEnd = function(event) 842{ 843 document.removeEventListener("mousemove", this._elementDraggingEventListener, true); 844 document.removeEventListener("mouseup", this._elementEndDraggingEventListener, true); 845 846 document.body.style.removeProperty("cursor"); 847 848 delete this._elementDraggingEventListener; 849 delete this._elementEndDraggingEventListener; 850 851 event.preventDefault(); 852} 853 854WebInspector.showConsole = function() 855{ 856 this.drawer.visibleView = this.console; 857} 858 859WebInspector.showChanges = function() 860{ 861 this.drawer.visibleView = this.changes; 862} 863 864WebInspector.showElementsPanel = function() 865{ 866 this.currentPanel = this.panels.elements; 867} 868 869WebInspector.showResourcesPanel = function() 870{ 871 this.currentPanel = this.panels.resources; 872} 873 874WebInspector.showScriptsPanel = function() 875{ 876 this.currentPanel = this.panels.scripts; 877} 878 879WebInspector.showProfilesPanel = function() 880{ 881 this.currentPanel = this.panels.profiles; 882} 883 884WebInspector.showDatabasesPanel = function() 885{ 886 this.currentPanel = this.panels.databases; 887} 888 889WebInspector.addResource = function(identifier, payload) 890{ 891 var resource = new WebInspector.Resource( 892 payload.requestHeaders, 893 payload.requestURL, 894 payload.host, 895 payload.path, 896 payload.lastPathComponent, 897 identifier, 898 payload.isMainResource, 899 payload.cached); 900 this.resources[identifier] = resource; 901 this.resourceURLMap[resource.url] = resource; 902 903 if (resource.mainResource) { 904 this.mainResource = resource; 905 this.panels.elements.reset(); 906 } 907 908 if (this.panels.resources) 909 this.panels.resources.addResource(resource); 910} 911 912WebInspector.updateResource = function(identifier, payload) 913{ 914 var resource = this.resources[identifier]; 915 if (!resource) 916 return; 917 918 if (payload.didRequestChange) { 919 resource.url = payload.url; 920 resource.domain = payload.domain; 921 resource.path = payload.path; 922 resource.lastPathComponent = payload.lastPathComponent; 923 resource.requestHeaders = payload.requestHeaders; 924 resource.mainResource = payload.mainResource; 925 } 926 927 if (payload.didResponseChange) { 928 resource.mimeType = payload.mimeType; 929 resource.suggestedFilename = payload.suggestedFilename; 930 resource.expectedContentLength = payload.expectedContentLength; 931 resource.statusCode = payload.statusCode; 932 resource.suggestedFilename = payload.suggestedFilename; 933 resource.responseHeaders = payload.responseHeaders; 934 } 935 936 if (payload.didTypeChange) { 937 resource.type = payload.type; 938 } 939 940 if (payload.didLengthChange) { 941 resource.contentLength = payload.contentLength; 942 } 943 944 if (payload.didCompletionChange) { 945 resource.failed = payload.failed; 946 resource.finished = payload.finished; 947 } 948 949 if (payload.didTimingChange) { 950 if (payload.startTime) 951 resource.startTime = payload.startTime; 952 if (payload.responseReceivedTime) 953 resource.responseReceivedTime = payload.responseReceivedTime; 954 if (payload.endTime) 955 resource.endTime = payload.endTime; 956 } 957} 958 959WebInspector.removeResource = function(identifier) 960{ 961 var resource = this.resources[identifier]; 962 if (!resource) 963 return; 964 965 resource.category.removeResource(resource); 966 delete this.resourceURLMap[resource.url]; 967 delete this.resources[identifier]; 968 969 if (this.panels.resources) 970 this.panels.resources.removeResource(resource); 971} 972 973WebInspector.addDatabase = function(payload) 974{ 975 var database = new WebInspector.Database( 976 payload.database, 977 payload.domain, 978 payload.name, 979 payload.version); 980 this.panels.databases.addDatabase(database); 981} 982 983WebInspector.addDOMStorage = function(payload) 984{ 985 var domStorage = new WebInspector.DOMStorage( 986 payload.domStorage, 987 payload.host, 988 payload.isLocalStorage); 989 this.panels.databases.addDOMStorage(domStorage); 990} 991 992WebInspector.resourceTrackingWasEnabled = function() 993{ 994 this.panels.resources.resourceTrackingWasEnabled(); 995} 996 997WebInspector.resourceTrackingWasDisabled = function() 998{ 999 this.panels.resources.resourceTrackingWasDisabled(); 1000} 1001 1002WebInspector.attachDebuggerWhenShown = function() 1003{ 1004 this.panels.scripts.attachDebuggerWhenShown(); 1005} 1006 1007WebInspector.debuggerWasEnabled = function() 1008{ 1009 this.panels.scripts.debuggerWasEnabled(); 1010} 1011 1012WebInspector.debuggerWasDisabled = function() 1013{ 1014 this.panels.scripts.debuggerWasDisabled(); 1015} 1016 1017WebInspector.profilerWasEnabled = function() 1018{ 1019 this.panels.profiles.profilerWasEnabled(); 1020} 1021 1022WebInspector.profilerWasDisabled = function() 1023{ 1024 this.panels.profiles.profilerWasDisabled(); 1025} 1026 1027WebInspector.parsedScriptSource = function(sourceID, sourceURL, source, startingLine) 1028{ 1029 this.panels.scripts.addScript(sourceID, sourceURL, source, startingLine); 1030} 1031 1032WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLine, errorLine, errorMessage) 1033{ 1034 this.panels.scripts.addScript(null, sourceURL, source, startingLine, errorLine, errorMessage); 1035} 1036 1037WebInspector.pausedScript = function() 1038{ 1039 this.panels.scripts.debuggerPaused(); 1040} 1041 1042WebInspector.resumedScript = function() 1043{ 1044 this.panels.scripts.debuggerResumed(); 1045} 1046 1047WebInspector.populateInterface = function() 1048{ 1049 for (var panelName in this.panels) { 1050 var panel = this.panels[panelName]; 1051 if ("populateInterface" in panel) 1052 panel.populateInterface(); 1053 } 1054} 1055 1056WebInspector.reset = function() 1057{ 1058 for (var panelName in this.panels) { 1059 var panel = this.panels[panelName]; 1060 if ("reset" in panel) 1061 panel.reset(); 1062 } 1063 1064 for (var category in this.resourceCategories) 1065 this.resourceCategories[category].removeAllResources(); 1066 1067 this.resources = {}; 1068 this.resourceURLMap = {}; 1069 this.hoveredDOMNode = null; 1070 1071 delete this.mainResource; 1072 1073 this.console.clearMessages(); 1074} 1075 1076WebInspector.inspectedWindowCleared = function(inspectedWindow) 1077{ 1078 this.panels.elements.inspectedWindowCleared(inspectedWindow); 1079} 1080 1081WebInspector.resourceURLChanged = function(resource, oldURL) 1082{ 1083 delete this.resourceURLMap[oldURL]; 1084 this.resourceURLMap[resource.url] = resource; 1085} 1086 1087WebInspector.addMessageToConsole = function(payload) 1088{ 1089 var consoleMessage = new WebInspector.ConsoleMessage( 1090 payload.source, 1091 payload.type, 1092 payload.level, 1093 payload.line, 1094 payload.url, 1095 payload.groupLevel, 1096 payload.repeatCount); 1097 consoleMessage.setMessageBody(Array.prototype.slice.call(arguments, 1)); 1098 this.console.addMessage(consoleMessage); 1099} 1100 1101WebInspector.addProfile = function(profile) 1102{ 1103 this.panels.profiles.addProfile(profile); 1104} 1105 1106WebInspector.setRecordingProfile = function(isProfiling) 1107{ 1108 this.panels.profiles.setRecordingProfile(isProfiling); 1109} 1110 1111WebInspector.drawLoadingPieChart = function(canvas, percent) { 1112 var g = canvas.getContext("2d"); 1113 var darkColor = "rgb(122, 168, 218)"; 1114 var lightColor = "rgb(228, 241, 251)"; 1115 var cx = 8; 1116 var cy = 8; 1117 var r = 7; 1118 1119 g.beginPath(); 1120 g.arc(cx, cy, r, 0, Math.PI * 2, false); 1121 g.closePath(); 1122 1123 g.lineWidth = 1; 1124 g.strokeStyle = darkColor; 1125 g.fillStyle = lightColor; 1126 g.fill(); 1127 g.stroke(); 1128 1129 var startangle = -Math.PI / 2; 1130 var endangle = startangle + (percent * Math.PI * 2); 1131 1132 g.beginPath(); 1133 g.moveTo(cx, cy); 1134 g.arc(cx, cy, r, startangle, endangle, false); 1135 g.closePath(); 1136 1137 g.fillStyle = darkColor; 1138 g.fill(); 1139} 1140 1141WebInspector.updateFocusedNode = function(node) 1142{ 1143 if (!node) 1144 // FIXME: Should we deselect if null is passed in? 1145 return; 1146 1147 this.currentPanel = this.panels.elements; 1148 this.panels.elements.focusedDOMNode = node; 1149} 1150 1151WebInspector.displayNameForURL = function(url) 1152{ 1153 if (!url) 1154 return ""; 1155 var resource = this.resourceURLMap[url]; 1156 if (resource) 1157 return resource.displayName; 1158 return url.trimURL(WebInspector.mainResource ? WebInspector.mainResource.domain : ""); 1159} 1160 1161WebInspector.resourceForURL = function(url) 1162{ 1163 if (url in this.resourceURLMap) 1164 return this.resourceURLMap[url]; 1165 1166 // No direct match found. Search for resources that contain 1167 // a substring of the URL. 1168 for (var resourceURL in this.resourceURLMap) { 1169 if (resourceURL.hasSubstring(url)) 1170 return this.resourceURLMap[resourceURL]; 1171 } 1172 1173 return null; 1174} 1175 1176WebInspector.showResourceForURL = function(url, line, preferredPanel) 1177{ 1178 var resource = this.resourceForURL(url); 1179 if (!resource) 1180 return false; 1181 1182 if (preferredPanel && preferredPanel in WebInspector.panels) { 1183 var panel = this.panels[preferredPanel]; 1184 if (!("showResource" in panel)) 1185 panel = null; 1186 else if ("canShowResource" in panel && !panel.canShowResource(resource)) 1187 panel = null; 1188 } 1189 1190 this.currentPanel = panel || this.panels.resources; 1191 if (!this.currentPanel) 1192 return false; 1193 this.currentPanel.showResource(resource, line); 1194 return true; 1195} 1196 1197WebInspector.linkifyStringAsFragment = function(string) 1198{ 1199 var container = document.createDocumentFragment(); 1200 var linkStringRegEx = new RegExp("(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}://|www\\.)[\\w$\\-_+*'=\\|/\\\\(){}[\\]%@&#~,:;.!?]{2,}[\\w$\\-_+*=\\|/\\\\({%@&#~]"); 1201 1202 while (string) { 1203 var linkString = linkStringRegEx.exec(string); 1204 if (!linkString) 1205 break; 1206 1207 linkString = linkString[0]; 1208 var title = linkString; 1209 var linkIndex = string.indexOf(linkString); 1210 var nonLink = string.substring(0, linkIndex); 1211 container.appendChild(document.createTextNode(nonLink)); 1212 1213 var profileStringRegEx = new RegExp("webkit-profile://(.+)/[0-9]+"); 1214 var profileStringMatches = profileStringRegEx.exec(title); 1215 var profileTitle; 1216 if (profileStringMatches) 1217 profileTitle = profileStringMatches[1]; 1218 if (profileTitle) 1219 title = WebInspector.panels.profiles.displayTitleForProfileLink(profileTitle); 1220 1221 var realURL = (linkString.indexOf("www.") === 0 ? "http://" + linkString : linkString); 1222 container.appendChild(WebInspector.linkifyURLAsNode(realURL, title, null, (realURL in WebInspector.resourceURLMap))); 1223 string = string.substring(linkIndex + linkString.length, string.length); 1224 } 1225 1226 if (string) 1227 container.appendChild(document.createTextNode(string)); 1228 1229 return container; 1230} 1231 1232WebInspector.showProfileById = function(uid) { 1233 WebInspector.showProfilesPanel(); 1234 WebInspector.panels.profiles.showProfileById(uid); 1235} 1236 1237WebInspector.linkifyURLAsNode = function(url, linkText, classes, isExternal) 1238{ 1239 if (!linkText) 1240 linkText = url; 1241 classes = (classes ? classes + " " : ""); 1242 classes += isExternal ? "webkit-html-external-link" : "webkit-html-resource-link"; 1243 1244 var a = document.createElement("a"); 1245 a.href = url; 1246 a.className = classes; 1247 a.title = url; 1248 a.target = "_blank"; 1249 a.textContent = linkText; 1250 1251 return a; 1252} 1253 1254WebInspector.linkifyURL = function(url, linkText, classes, isExternal) 1255{ 1256 // Use the DOM version of this function so as to avoid needing to escape attributes. 1257 // FIXME: Get rid of linkifyURL entirely. 1258 return WebInspector.linkifyURLAsNode(url, linkText, classes, isExternal).outerHTML; 1259} 1260 1261WebInspector.addMainEventListeners = function(doc) 1262{ 1263 doc.defaultView.addEventListener("focus", this.windowFocused.bind(this), true); 1264 doc.defaultView.addEventListener("blur", this.windowBlured.bind(this), true); 1265 doc.addEventListener("click", this.documentClick.bind(this), true); 1266} 1267 1268WebInspector.searchKeyDown = function(event) 1269{ 1270 if (event.keyIdentifier !== "Enter") 1271 return; 1272 1273 // Call preventDefault since this was the Enter key. This prevents a "search" event 1274 // from firing for key down. We handle the Enter key on key up in searchKeyUp. This 1275 // stops performSearch from being called twice in a row. 1276 event.preventDefault(); 1277} 1278 1279WebInspector.searchKeyUp = function(event) 1280{ 1281 if (event.keyIdentifier !== "Enter") 1282 return; 1283 1284 // Select all of the text so the user can easily type an entirely new query. 1285 event.target.select(); 1286 1287 // Only call performSearch if the Enter key was pressed. Otherwise the search 1288 // performance is poor because of searching on every key. The search field has 1289 // the incremental attribute set, so we still get incremental searches. 1290 this.performSearch(event); 1291} 1292 1293WebInspector.performSearch = function(event) 1294{ 1295 var query = event.target.value; 1296 var forceSearch = event.keyIdentifier === "Enter"; 1297 1298 if (!query || !query.length || (!forceSearch && query.length < 3)) { 1299 delete this.currentQuery; 1300 1301 for (var panelName in this.panels) { 1302 var panel = this.panels[panelName]; 1303 if (panel.currentQuery && panel.searchCanceled) 1304 panel.searchCanceled(); 1305 delete panel.currentQuery; 1306 } 1307 1308 this.updateSearchMatchesCount(); 1309 1310 return; 1311 } 1312 1313 if (query === this.currentPanel.currentQuery && this.currentPanel.currentQuery === this.currentQuery) { 1314 // When this is the same query and a forced search, jump to the next 1315 // search result for a good user experience. 1316 if (forceSearch && this.currentPanel.jumpToNextSearchResult) 1317 this.currentPanel.jumpToNextSearchResult(); 1318 return; 1319 } 1320 1321 this.currentQuery = query; 1322 1323 this.updateSearchMatchesCount(); 1324 1325 if (!this.currentPanel.performSearch) 1326 return; 1327 1328 this.currentPanel.currentQuery = query; 1329 this.currentPanel.performSearch(query); 1330} 1331 1332WebInspector.updateSearchMatchesCount = function(matches, panel) 1333{ 1334 if (!panel) 1335 panel = this.currentPanel; 1336 1337 panel.currentSearchMatches = matches; 1338 1339 if (panel !== this.currentPanel) 1340 return; 1341 1342 if (!this.currentPanel.currentQuery) { 1343 document.getElementById("search-results-matches").addStyleClass("hidden"); 1344 return; 1345 } 1346 1347 if (matches) { 1348 if (matches === 1) 1349 var matchesString = WebInspector.UIString("1 match"); 1350 else 1351 var matchesString = WebInspector.UIString("%d matches", matches); 1352 } else 1353 var matchesString = WebInspector.UIString("Not Found"); 1354 1355 var matchesToolbarElement = document.getElementById("search-results-matches"); 1356 matchesToolbarElement.removeStyleClass("hidden"); 1357 matchesToolbarElement.textContent = matchesString; 1358} 1359 1360WebInspector.UIString = function(string) 1361{ 1362 if (window.localizedStrings && string in window.localizedStrings) 1363 string = window.localizedStrings[string]; 1364 else { 1365 if (!(string in this.missingLocalizedStrings)) { 1366 console.error("Localized string \"" + string + "\" not found."); 1367 this.missingLocalizedStrings[string] = true; 1368 } 1369 1370 if (Preferences.showMissingLocalizedStrings) 1371 string += " (not localized)"; 1372 } 1373 1374 return String.vsprintf(string, Array.prototype.slice.call(arguments, 1)); 1375} 1376 1377WebInspector.isBeingEdited = function(element) 1378{ 1379 return element.__editing; 1380} 1381 1382WebInspector.startEditing = function(element, committedCallback, cancelledCallback, context) 1383{ 1384 if (element.__editing) 1385 return; 1386 element.__editing = true; 1387 1388 var oldText = element.textContent; 1389 var oldHandleKeyEvent = element.handleKeyEvent; 1390 var moveDirection = ""; 1391 1392 element.addStyleClass("editing"); 1393 1394 var oldTabIndex = element.tabIndex; 1395 if (element.tabIndex < 0) 1396 element.tabIndex = 0; 1397 1398 function blurEventListener() { 1399 editingCommitted.call(element); 1400 } 1401 1402 function cleanUpAfterEditing() { 1403 delete this.__editing; 1404 1405 this.removeStyleClass("editing"); 1406 this.tabIndex = oldTabIndex; 1407 this.scrollTop = 0; 1408 this.scrollLeft = 0; 1409 1410 this.handleKeyEvent = oldHandleKeyEvent; 1411 element.removeEventListener("blur", blurEventListener, false); 1412 1413 if (element === WebInspector.currentFocusElement || element.isAncestor(WebInspector.currentFocusElement)) 1414 WebInspector.currentFocusElement = WebInspector.previousFocusElement; 1415 } 1416 1417 function editingCancelled() { 1418 this.innerText = oldText; 1419 1420 cleanUpAfterEditing.call(this); 1421 1422 cancelledCallback(this, context); 1423 } 1424 1425 function editingCommitted() { 1426 cleanUpAfterEditing.call(this); 1427 1428 committedCallback(this, this.textContent, oldText, context, moveDirection); 1429 } 1430 1431 element.handleKeyEvent = function(event) { 1432 if (oldHandleKeyEvent) 1433 oldHandleKeyEvent(event); 1434 if (event.handled) 1435 return; 1436 1437 if (event.keyIdentifier === "Enter") { 1438 editingCommitted.call(element); 1439 event.preventDefault(); 1440 } else if (event.keyCode === 27) { // Escape key 1441 editingCancelled.call(element); 1442 event.preventDefault(); 1443 event.handled = true; 1444 } else if (event.keyIdentifier === "U+0009") // Tab key 1445 moveDirection = (event.shiftKey ? "backward" : "forward"); 1446 } 1447 1448 element.addEventListener("blur", blurEventListener, false); 1449 1450 WebInspector.currentFocusElement = element; 1451} 1452 1453WebInspector._toolbarItemClicked = function(event) 1454{ 1455 var toolbarItem = event.currentTarget; 1456 this.currentPanel = toolbarItem.panel; 1457} 1458 1459// This table maps MIME types to the Resource.Types which are valid for them. 1460// The following line: 1461// "text/html": {0: 1}, 1462// means that text/html is a valid MIME type for resources that have type 1463// WebInspector.Resource.Type.Document (which has a value of 0). 1464WebInspector.MIMETypes = { 1465 "text/html": {0: true}, 1466 "text/xml": {0: true}, 1467 "text/plain": {0: true}, 1468 "application/xhtml+xml": {0: true}, 1469 "text/css": {1: true}, 1470 "text/xsl": {1: true}, 1471 "image/jpeg": {2: true}, 1472 "image/png": {2: true}, 1473 "image/gif": {2: true}, 1474 "image/bmp": {2: true}, 1475 "image/vnd.microsoft.icon": {2: true}, 1476 "image/x-icon": {2: true}, 1477 "image/x-xbitmap": {2: true}, 1478 "font/ttf": {3: true}, 1479 "font/opentype": {3: true}, 1480 "application/x-font-type1": {3: true}, 1481 "application/x-font-ttf": {3: true}, 1482 "application/x-truetype-font": {3: true}, 1483 "text/javascript": {4: true}, 1484 "text/ecmascript": {4: true}, 1485 "application/javascript": {4: true}, 1486 "application/ecmascript": {4: true}, 1487 "application/x-javascript": {4: true}, 1488 "text/javascript1.1": {4: true}, 1489 "text/javascript1.2": {4: true}, 1490 "text/javascript1.3": {4: true}, 1491 "text/jscript": {4: true}, 1492 "text/livescript": {4: true}, 1493} 1494