home *** CD-ROM | disk | FTP | other *** search
/ Computer Active 2010 July / CA07.iso / Multimedija / QuickTimeInstaller.exe / AppleApplicationSupport.msi / WebKit.resources_inspector_inspector.js < prev    next >
Encoding:
JavaScript  |  2010-03-15  |  43.7 KB  |  1,382 lines

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