OLD | NEW |
(Empty) | |
| 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 |
| 31 var Preferences = { |
| 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 heapProfilerPresent: false, |
| 42 samplingCPUProfiler: false, |
| 43 showColorNicknames: true, |
| 44 colorFormat: "hex", |
| 45 eventListenersFilter: "all", |
| 46 resourcesLargeRows: true |
| 47 } |
| 48 |
| 49 var WebInspector = { |
| 50 resources: {}, |
| 51 resourceURLMap: {}, |
| 52 missingLocalizedStrings: {}, |
| 53 |
| 54 get previousFocusElement() |
| 55 { |
| 56 return this._previousFocusElement; |
| 57 }, |
| 58 |
| 59 get currentFocusElement() |
| 60 { |
| 61 return this._currentFocusElement; |
| 62 }, |
| 63 |
| 64 set currentFocusElement(x) |
| 65 { |
| 66 if (this._currentFocusElement !== x) |
| 67 this._previousFocusElement = this._currentFocusElement; |
| 68 this._currentFocusElement = x; |
| 69 |
| 70 if (this._currentFocusElement) { |
| 71 this._currentFocusElement.focus(); |
| 72 |
| 73 // Make a caret selection inside the new element if there isn't a ra
nge selection and |
| 74 // there isn't already a caret selection inside. |
| 75 var selection = window.getSelection(); |
| 76 if (selection.isCollapsed && !this._currentFocusElement.isInsertionC
aretInside()) { |
| 77 var selectionRange = this._currentFocusElement.ownerDocument.cre
ateRange(); |
| 78 selectionRange.setStart(this._currentFocusElement, 0); |
| 79 selectionRange.setEnd(this._currentFocusElement, 0); |
| 80 |
| 81 selection.removeAllRanges(); |
| 82 selection.addRange(selectionRange); |
| 83 } |
| 84 } else if (this._previousFocusElement) |
| 85 this._previousFocusElement.blur(); |
| 86 }, |
| 87 |
| 88 get currentPanel() |
| 89 { |
| 90 return this._currentPanel; |
| 91 }, |
| 92 |
| 93 set currentPanel(x) |
| 94 { |
| 95 if (this._currentPanel === x) |
| 96 return; |
| 97 |
| 98 if (this._currentPanel) |
| 99 this._currentPanel.hide(); |
| 100 |
| 101 this._currentPanel = x; |
| 102 |
| 103 this.updateSearchLabel(); |
| 104 |
| 105 if (x) { |
| 106 x.show(); |
| 107 |
| 108 if (this.currentQuery) { |
| 109 if (x.performSearch) { |
| 110 function performPanelSearch() |
| 111 { |
| 112 this.updateSearchMatchesCount(); |
| 113 |
| 114 x.currentQuery = this.currentQuery; |
| 115 x.performSearch(this.currentQuery); |
| 116 } |
| 117 |
| 118 // Perform the search on a timeout so the panel switches fas
t. |
| 119 setTimeout(performPanelSearch.bind(this), 0); |
| 120 } else { |
| 121 // Update to show Not found for panels that can't be searche
d. |
| 122 this.updateSearchMatchesCount(); |
| 123 } |
| 124 } |
| 125 } |
| 126 |
| 127 for (var panelName in WebInspector.panels) { |
| 128 if (WebInspector.panels[panelName] == x) |
| 129 InspectorController.storeLastActivePanel(panelName); |
| 130 } |
| 131 }, |
| 132 |
| 133 _createPanels: function() |
| 134 { |
| 135 var hiddenPanels = (InspectorController.hiddenPanels() || "").split(',')
; |
| 136 if (hiddenPanels.indexOf("elements") === -1) |
| 137 this.panels.elements = new WebInspector.ElementsPanel(); |
| 138 if (hiddenPanels.indexOf("resources") === -1) |
| 139 this.panels.resources = new WebInspector.ResourcesPanel(); |
| 140 if (hiddenPanels.indexOf("scripts") === -1) |
| 141 this.panels.scripts = new WebInspector.ScriptsPanel(); |
| 142 if (hiddenPanels.indexOf("profiles") === -1) { |
| 143 this.panels.profiles = new WebInspector.ProfilesPanel(); |
| 144 this.panels.profiles.registerProfileType(new WebInspector.CPUProfile
Type()); |
| 145 } |
| 146 |
| 147 // Uncomment this when timeline is ready. |
| 148 // if (hiddenPanels.indexOf("timeline") === -1 && hiddenPanels.indexOf("
timeline") === -1) |
| 149 // this.panels.timeline = new WebInspector.TimelinePanel(); |
| 150 |
| 151 if (hiddenPanels.indexOf("storage") === -1 && hiddenPanels.indexOf("data
bases") === -1) |
| 152 this.panels.storage = new WebInspector.StoragePanel(); |
| 153 }, |
| 154 |
| 155 _loadPreferences: function() |
| 156 { |
| 157 var colorFormat = InspectorController.setting("color-format"); |
| 158 if (colorFormat) |
| 159 Preferences.colorFormat = colorFormat; |
| 160 |
| 161 var eventListenersFilter = InspectorController.setting("event-listeners-
filter"); |
| 162 if (eventListenersFilter) |
| 163 Preferences.eventListenersFilter = eventListenersFilter; |
| 164 |
| 165 var resourcesLargeRows = InspectorController.setting("resources-large-ro
ws"); |
| 166 if (typeof resourcesLargeRows !== "undefined") |
| 167 Preferences.resourcesLargeRows = resourcesLargeRows; |
| 168 }, |
| 169 |
| 170 get attached() |
| 171 { |
| 172 return this._attached; |
| 173 }, |
| 174 |
| 175 set attached(x) |
| 176 { |
| 177 if (this._attached === x) |
| 178 return; |
| 179 |
| 180 this._attached = x; |
| 181 |
| 182 this.updateSearchLabel(); |
| 183 |
| 184 var dockToggleButton = document.getElementById("dock-status-bar-item"); |
| 185 var body = document.body; |
| 186 |
| 187 if (x) { |
| 188 InspectorController.attach(); |
| 189 body.removeStyleClass("detached"); |
| 190 body.addStyleClass("attached"); |
| 191 dockToggleButton.title = WebInspector.UIString("Undock into separate
window."); |
| 192 } else { |
| 193 InspectorController.detach(); |
| 194 body.removeStyleClass("attached"); |
| 195 body.addStyleClass("detached"); |
| 196 dockToggleButton.title = WebInspector.UIString("Dock to main window.
"); |
| 197 } |
| 198 }, |
| 199 |
| 200 get errors() |
| 201 { |
| 202 return this._errors || 0; |
| 203 }, |
| 204 |
| 205 set errors(x) |
| 206 { |
| 207 x = Math.max(x, 0); |
| 208 |
| 209 if (this._errors === x) |
| 210 return; |
| 211 this._errors = x; |
| 212 this._updateErrorAndWarningCounts(); |
| 213 }, |
| 214 |
| 215 get warnings() |
| 216 { |
| 217 return this._warnings || 0; |
| 218 }, |
| 219 |
| 220 set warnings(x) |
| 221 { |
| 222 x = Math.max(x, 0); |
| 223 |
| 224 if (this._warnings === x) |
| 225 return; |
| 226 this._warnings = x; |
| 227 this._updateErrorAndWarningCounts(); |
| 228 }, |
| 229 |
| 230 _updateErrorAndWarningCounts: function() |
| 231 { |
| 232 var errorWarningElement = document.getElementById("error-warning-count")
; |
| 233 if (!errorWarningElement) |
| 234 return; |
| 235 |
| 236 if (!this.errors && !this.warnings) { |
| 237 errorWarningElement.addStyleClass("hidden"); |
| 238 return; |
| 239 } |
| 240 |
| 241 errorWarningElement.removeStyleClass("hidden"); |
| 242 |
| 243 errorWarningElement.removeChildren(); |
| 244 |
| 245 if (this.errors) { |
| 246 var errorElement = document.createElement("span"); |
| 247 errorElement.id = "error-count"; |
| 248 errorElement.textContent = this.errors; |
| 249 errorWarningElement.appendChild(errorElement); |
| 250 } |
| 251 |
| 252 if (this.warnings) { |
| 253 var warningsElement = document.createElement("span"); |
| 254 warningsElement.id = "warning-count"; |
| 255 warningsElement.textContent = this.warnings; |
| 256 errorWarningElement.appendChild(warningsElement); |
| 257 } |
| 258 |
| 259 if (this.errors) { |
| 260 if (this.warnings) { |
| 261 if (this.errors == 1) { |
| 262 if (this.warnings == 1) |
| 263 errorWarningElement.title = WebInspector.UIString("%d er
ror, %d warning", this.errors, this.warnings); |
| 264 else |
| 265 errorWarningElement.title = WebInspector.UIString("%d er
ror, %d warnings", this.errors, this.warnings); |
| 266 } else if (this.warnings == 1) |
| 267 errorWarningElement.title = WebInspector.UIString("%d errors
, %d warning", this.errors, this.warnings); |
| 268 else |
| 269 errorWarningElement.title = WebInspector.UIString("%d errors
, %d warnings", this.errors, this.warnings); |
| 270 } else if (this.errors == 1) |
| 271 errorWarningElement.title = WebInspector.UIString("%d error", th
is.errors); |
| 272 else |
| 273 errorWarningElement.title = WebInspector.UIString("%d errors", t
his.errors); |
| 274 } else if (this.warnings == 1) |
| 275 errorWarningElement.title = WebInspector.UIString("%d warning", this
.warnings); |
| 276 else if (this.warnings) |
| 277 errorWarningElement.title = WebInspector.UIString("%d warnings", thi
s.warnings); |
| 278 else |
| 279 errorWarningElement.title = null; |
| 280 }, |
| 281 |
| 282 get styleChanges() |
| 283 { |
| 284 return this._styleChanges; |
| 285 }, |
| 286 |
| 287 set styleChanges(x) |
| 288 { |
| 289 x = Math.max(x, 0); |
| 290 |
| 291 if (this._styleChanges === x) |
| 292 return; |
| 293 this._styleChanges = x; |
| 294 this._updateChangesCount(); |
| 295 }, |
| 296 |
| 297 _updateChangesCount: function() |
| 298 { |
| 299 // TODO: Remove immediate return when enabling the Changes Panel |
| 300 return; |
| 301 |
| 302 var changesElement = document.getElementById("changes-count"); |
| 303 if (!changesElement) |
| 304 return; |
| 305 |
| 306 if (!this.styleChanges) { |
| 307 changesElement.addStyleClass("hidden"); |
| 308 return; |
| 309 } |
| 310 |
| 311 changesElement.removeStyleClass("hidden"); |
| 312 changesElement.removeChildren(); |
| 313 |
| 314 if (this.styleChanges) { |
| 315 var styleChangesElement = document.createElement("span"); |
| 316 styleChangesElement.id = "style-changes-count"; |
| 317 styleChangesElement.textContent = this.styleChanges; |
| 318 changesElement.appendChild(styleChangesElement); |
| 319 } |
| 320 |
| 321 if (this.styleChanges) { |
| 322 if (this.styleChanges === 1) |
| 323 changesElement.title = WebInspector.UIString("%d style change",
this.styleChanges); |
| 324 else |
| 325 changesElement.title = WebInspector.UIString("%d style changes",
this.styleChanges); |
| 326 } |
| 327 }, |
| 328 |
| 329 get hoveredDOMNode() |
| 330 { |
| 331 return this._hoveredDOMNode; |
| 332 }, |
| 333 |
| 334 set hoveredDOMNode(x) |
| 335 { |
| 336 if (this._hoveredDOMNode === x) |
| 337 return; |
| 338 |
| 339 this._hoveredDOMNode = x; |
| 340 |
| 341 if (this._hoveredDOMNode) |
| 342 this._updateHoverHighlightSoon(this.showingDOMNodeHighlight ? 50 : 5
00); |
| 343 else |
| 344 this._updateHoverHighlight(); |
| 345 }, |
| 346 |
| 347 _updateHoverHighlightSoon: function(delay) |
| 348 { |
| 349 if ("_updateHoverHighlightTimeout" in this) |
| 350 clearTimeout(this._updateHoverHighlightTimeout); |
| 351 this._updateHoverHighlightTimeout = setTimeout(this._updateHoverHighligh
t.bind(this), delay); |
| 352 }, |
| 353 |
| 354 _updateHoverHighlight: function() |
| 355 { |
| 356 if ("_updateHoverHighlightTimeout" in this) { |
| 357 clearTimeout(this._updateHoverHighlightTimeout); |
| 358 delete this._updateHoverHighlightTimeout; |
| 359 } |
| 360 |
| 361 if (this._hoveredDOMNode) { |
| 362 InspectorController.highlightDOMNode(this._hoveredDOMNode.id); |
| 363 this.showingDOMNodeHighlight = true; |
| 364 } else { |
| 365 InspectorController.hideDOMNodeHighlight(); |
| 366 this.showingDOMNodeHighlight = false; |
| 367 } |
| 368 } |
| 369 } |
| 370 |
| 371 WebInspector.loaded = function() |
| 372 { |
| 373 var platform = InspectorController.platform(); |
| 374 document.body.addStyleClass("platform-" + platform); |
| 375 |
| 376 this._loadPreferences(); |
| 377 |
| 378 this.drawer = new WebInspector.Drawer(); |
| 379 this.console = new WebInspector.ConsoleView(this.drawer); |
| 380 // TODO: Uncomment when enabling the Changes Panel |
| 381 // this.changes = new WebInspector.ChangesView(this.drawer); |
| 382 // TODO: Remove class="hidden" from inspector.html on button#changes-status-
bar-item |
| 383 this.drawer.visibleView = this.console; |
| 384 this.domAgent = new WebInspector.DOMAgent(); |
| 385 |
| 386 this.resourceCategories = { |
| 387 documents: new WebInspector.ResourceCategory(WebInspector.UIString("Docu
ments"), "documents"), |
| 388 stylesheets: new WebInspector.ResourceCategory(WebInspector.UIString("St
ylesheets"), "stylesheets"), |
| 389 images: new WebInspector.ResourceCategory(WebInspector.UIString("Images"
), "images"), |
| 390 scripts: new WebInspector.ResourceCategory(WebInspector.UIString("Script
s"), "scripts"), |
| 391 xhr: new WebInspector.ResourceCategory(WebInspector.UIString("XHR"), "xh
r"), |
| 392 fonts: new WebInspector.ResourceCategory(WebInspector.UIString("Fonts"),
"fonts"), |
| 393 other: new WebInspector.ResourceCategory(WebInspector.UIString("Other"),
"other") |
| 394 }; |
| 395 |
| 396 this.panels = {}; |
| 397 this._createPanels(); |
| 398 |
| 399 var toolbarElement = document.getElementById("toolbar"); |
| 400 var previousToolbarItem = toolbarElement.children[0]; |
| 401 |
| 402 this.panelOrder = []; |
| 403 for (var panelName in this.panels) { |
| 404 var panel = this.panels[panelName]; |
| 405 var panelToolbarItem = panel.toolbarItem; |
| 406 this.panelOrder.push(panel); |
| 407 panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind
(this)); |
| 408 if (previousToolbarItem) |
| 409 toolbarElement.insertBefore(panelToolbarItem, previousToolbarItem.ne
xtSibling); |
| 410 else |
| 411 toolbarElement.insertBefore(panelToolbarItem, toolbarElement.firstCh
ild); |
| 412 previousToolbarItem = panelToolbarItem; |
| 413 } |
| 414 |
| 415 this.Tips = { |
| 416 ResourceNotCompressed: {id: 0, message: WebInspector.UIString("You could
save bandwidth by having your web server compress this transfer with gzip or zl
ib.")} |
| 417 }; |
| 418 |
| 419 this.Warnings = { |
| 420 IncorrectMIMEType: {id: 0, message: WebInspector.UIString("Resource inte
rpreted as %s but transferred with MIME type %s.")} |
| 421 }; |
| 422 |
| 423 this.addMainEventListeners(document); |
| 424 |
| 425 window.addEventListener("unload", this.windowUnload.bind(this), true); |
| 426 window.addEventListener("resize", this.windowResize.bind(this), true); |
| 427 |
| 428 document.addEventListener("focus", this.focusChanged.bind(this), true); |
| 429 document.addEventListener("keydown", this.documentKeyDown.bind(this), true); |
| 430 document.addEventListener("keyup", this.documentKeyUp.bind(this), true); |
| 431 document.addEventListener("beforecopy", this.documentCanCopy.bind(this), tru
e); |
| 432 document.addEventListener("copy", this.documentCopy.bind(this), true); |
| 433 document.addEventListener("contextmenu", this.contextMenu.bind(this), true); |
| 434 |
| 435 var mainPanelsElement = document.getElementById("main-panels"); |
| 436 mainPanelsElement.handleKeyEvent = this.mainKeyDown.bind(this); |
| 437 mainPanelsElement.handleKeyUpEvent = this.mainKeyUp.bind(this); |
| 438 mainPanelsElement.handleCopyEvent = this.mainCopy.bind(this); |
| 439 |
| 440 // Focus the mainPanelsElement in a timeout so it happens after the initial
focus, |
| 441 // so it doesn't get reset to the first toolbar button. This initial focus h
appens |
| 442 // on Mac when the window is made key and the WebHTMLView becomes the first
responder. |
| 443 setTimeout(function() { WebInspector.currentFocusElement = mainPanelsElement
}, 0); |
| 444 |
| 445 var dockToggleButton = document.getElementById("dock-status-bar-item"); |
| 446 dockToggleButton.addEventListener("click", this.toggleAttach.bind(this), fal
se); |
| 447 |
| 448 if (this.attached) |
| 449 dockToggleButton.title = WebInspector.UIString("Undock into separate win
dow."); |
| 450 else |
| 451 dockToggleButton.title = WebInspector.UIString("Dock to main window."); |
| 452 |
| 453 var errorWarningCount = document.getElementById("error-warning-count"); |
| 454 errorWarningCount.addEventListener("click", this.showConsole.bind(this), fal
se); |
| 455 this._updateErrorAndWarningCounts(); |
| 456 |
| 457 this.styleChanges = 0; |
| 458 // TODO: Uncomment when enabling the Changes Panel |
| 459 // var changesElement = document.getElementById("changes-count"); |
| 460 // changesElement.addEventListener("click", this.showChanges.bind(this), fal
se); |
| 461 // this._updateErrorAndWarningCounts(); |
| 462 |
| 463 var searchField = document.getElementById("search"); |
| 464 searchField.addEventListener("keydown", this.searchKeyDown.bind(this), false
); |
| 465 searchField.addEventListener("keyup", this.searchKeyUp.bind(this), false); |
| 466 searchField.addEventListener("search", this.performSearch.bind(this), false)
; // when the search is emptied |
| 467 |
| 468 toolbarElement.addEventListener("mousedown", this.toolbarDragStart, true); |
| 469 document.getElementById("close-button-left").addEventListener("click", this.
close, true); |
| 470 document.getElementById("close-button-right").addEventListener("click", this
.close, true); |
| 471 |
| 472 InspectorController.loaded(); |
| 473 } |
| 474 |
| 475 var windowLoaded = function() |
| 476 { |
| 477 var localizedStringsURL = InspectorController.localizedStringsURL(); |
| 478 if (localizedStringsURL) { |
| 479 var localizedStringsScriptElement = document.createElement("script"); |
| 480 localizedStringsScriptElement.addEventListener("load", WebInspector.load
ed.bind(WebInspector), false); |
| 481 localizedStringsScriptElement.type = "text/javascript"; |
| 482 localizedStringsScriptElement.src = localizedStringsURL; |
| 483 document.getElementsByTagName("head").item(0).appendChild(localizedStrin
gsScriptElement); |
| 484 } else |
| 485 WebInspector.loaded(); |
| 486 |
| 487 window.removeEventListener("load", windowLoaded, false); |
| 488 delete windowLoaded; |
| 489 }; |
| 490 |
| 491 window.addEventListener("load", windowLoaded, false); |
| 492 |
| 493 WebInspector.dispatch = function() { |
| 494 var methodName = arguments[0]; |
| 495 var parameters = Array.prototype.slice.call(arguments, 1); |
| 496 |
| 497 // We'd like to enforce asynchronous interaction between the inspector contr
oller and the frontend. |
| 498 // This is important to LayoutTests. |
| 499 function delayDispatch() |
| 500 { |
| 501 WebInspector[methodName].apply(WebInspector, parameters); |
| 502 } |
| 503 setTimeout(delayDispatch, 0); |
| 504 } |
| 505 |
| 506 WebInspector.windowUnload = function(event) |
| 507 { |
| 508 InspectorController.windowUnloading(); |
| 509 } |
| 510 |
| 511 WebInspector.windowResize = function(event) |
| 512 { |
| 513 if (this.currentPanel && this.currentPanel.resize) |
| 514 this.currentPanel.resize(); |
| 515 } |
| 516 |
| 517 WebInspector.windowFocused = function(event) |
| 518 { |
| 519 // Fires after blur, so when focusing on either the main inspector |
| 520 // or an <iframe> within the inspector we should always remove the |
| 521 // "inactive" class. |
| 522 if (event.target.document.nodeType === Node.DOCUMENT_NODE) |
| 523 document.body.removeStyleClass("inactive"); |
| 524 } |
| 525 |
| 526 WebInspector.windowBlurred = function(event) |
| 527 { |
| 528 // Leaving the main inspector or an <iframe> within the inspector. |
| 529 // We can add "inactive" now, and if we are moving the focus to another |
| 530 // part of the inspector then windowFocused will correct this. |
| 531 if (event.target.document.nodeType === Node.DOCUMENT_NODE) |
| 532 document.body.addStyleClass("inactive"); |
| 533 } |
| 534 |
| 535 WebInspector.focusChanged = function(event) |
| 536 { |
| 537 this.currentFocusElement = event.target; |
| 538 } |
| 539 |
| 540 WebInspector.setAttachedWindow = function(attached) |
| 541 { |
| 542 this.attached = attached; |
| 543 } |
| 544 |
| 545 WebInspector.close = function(event) |
| 546 { |
| 547 InspectorController.closeWindow(); |
| 548 } |
| 549 |
| 550 WebInspector.documentClick = function(event) |
| 551 { |
| 552 var anchor = event.target.enclosingNodeOrSelfWithNodeName("a"); |
| 553 if (!anchor) |
| 554 return; |
| 555 |
| 556 // Prevent the link from navigating, since we don't do any navigation by fol
lowing links normally. |
| 557 event.preventDefault(); |
| 558 |
| 559 function followLink() |
| 560 { |
| 561 // FIXME: support webkit-html-external-link links here. |
| 562 if (anchor.href in WebInspector.resourceURLMap) { |
| 563 if (anchor.hasStyleClass("webkit-html-external-link")) { |
| 564 anchor.removeStyleClass("webkit-html-external-link"); |
| 565 anchor.addStyleClass("webkit-html-resource-link"); |
| 566 } |
| 567 |
| 568 WebInspector.showResourceForURL(anchor.href, anchor.lineNumber, anch
or.preferredPanel); |
| 569 } else { |
| 570 var profileString = WebInspector.ProfileType.URLRegExp.exec(anchor.h
ref); |
| 571 if (profileString) |
| 572 WebInspector.showProfileForURL(anchor.href); |
| 573 } |
| 574 } |
| 575 |
| 576 if (WebInspector.followLinkTimeout) |
| 577 clearTimeout(WebInspector.followLinkTimeout); |
| 578 |
| 579 if (anchor.preventFollowOnDoubleClick) { |
| 580 // Start a timeout if this is the first click, if the timeout is cancele
d |
| 581 // before it fires, then a double clicked happened or another link was c
licked. |
| 582 if (event.detail === 1) |
| 583 WebInspector.followLinkTimeout = setTimeout(followLink, 333); |
| 584 return; |
| 585 } |
| 586 |
| 587 followLink(); |
| 588 } |
| 589 |
| 590 WebInspector.documentKeyDown = function(event) |
| 591 { |
| 592 if (!this.currentFocusElement) |
| 593 return; |
| 594 if (this.currentFocusElement.handleKeyEvent) |
| 595 this.currentFocusElement.handleKeyEvent(event); |
| 596 else if (this.currentFocusElement.id && this.currentFocusElement.id.length &
& WebInspector[this.currentFocusElement.id + "KeyDown"]) |
| 597 WebInspector[this.currentFocusElement.id + "KeyDown"](event); |
| 598 |
| 599 if (!event.handled) { |
| 600 var isMac = InspectorController.platform().indexOf("mac-") === 0; |
| 601 |
| 602 switch (event.keyIdentifier) { |
| 603 case "U+001B": // Escape key |
| 604 this.drawer.visible = !this.drawer.visible; |
| 605 event.preventDefault(); |
| 606 break; |
| 607 |
| 608 case "U+0046": // F key |
| 609 if (isMac) |
| 610 var isFindKey = event.metaKey && !event.ctrlKey && !event.al
tKey && !event.shiftKey; |
| 611 else |
| 612 var isFindKey = event.ctrlKey && !event.metaKey && !event.al
tKey && !event.shiftKey; |
| 613 |
| 614 if (isFindKey) { |
| 615 var searchField = document.getElementById("search"); |
| 616 searchField.focus(); |
| 617 searchField.select(); |
| 618 event.preventDefault(); |
| 619 } |
| 620 |
| 621 break; |
| 622 |
| 623 case "U+0047": // G key |
| 624 if (isMac) |
| 625 var isFindAgainKey = event.metaKey && !event.ctrlKey && !eve
nt.altKey; |
| 626 else |
| 627 var isFindAgainKey = event.ctrlKey && !event.metaKey && !eve
nt.altKey; |
| 628 |
| 629 if (isFindAgainKey) { |
| 630 if (event.shiftKey) { |
| 631 if (this.currentPanel.jumpToPreviousSearchResult) |
| 632 this.currentPanel.jumpToPreviousSearchResult(); |
| 633 } else if (this.currentPanel.jumpToNextSearchResult) |
| 634 this.currentPanel.jumpToNextSearchResult(); |
| 635 event.preventDefault(); |
| 636 } |
| 637 |
| 638 break; |
| 639 |
| 640 case "U+005B": // [ key |
| 641 if (isMac) |
| 642 var isRotateLeft = event.metaKey && !event.shiftKey && !even
t.ctrlKey && !event.altKey; |
| 643 else |
| 644 var isRotateLeft = event.ctrlKey && !event.shiftKey && !even
t.metaKey && !event.altKey; |
| 645 |
| 646 if (isRotateLeft) { |
| 647 var index = this.panelOrder.indexOf(this.currentPanel); |
| 648 index = (index === 0) ? this.panelOrder.length - 1 : index -
1; |
| 649 this.panelOrder[index].toolbarItem.click(); |
| 650 event.preventDefault(); |
| 651 } |
| 652 |
| 653 break; |
| 654 |
| 655 case "U+005D": // ] key |
| 656 if (isMac) |
| 657 var isRotateRight = event.metaKey && !event.shiftKey && !eve
nt.ctrlKey && !event.altKey; |
| 658 else |
| 659 var isRotateRight = event.ctrlKey && !event.shiftKey && !eve
nt.metaKey && !event.altKey; |
| 660 |
| 661 if (isRotateRight) { |
| 662 var index = this.panelOrder.indexOf(this.currentPanel); |
| 663 index = (index + 1) % this.panelOrder.length; |
| 664 this.panelOrder[index].toolbarItem.click(); |
| 665 event.preventDefault(); |
| 666 } |
| 667 |
| 668 break; |
| 669 } |
| 670 } |
| 671 } |
| 672 |
| 673 WebInspector.documentKeyUp = function(event) |
| 674 { |
| 675 if (!this.currentFocusElement || !this.currentFocusElement.handleKeyUpEvent) |
| 676 return; |
| 677 this.currentFocusElement.handleKeyUpEvent(event); |
| 678 } |
| 679 |
| 680 WebInspector.documentCanCopy = function(event) |
| 681 { |
| 682 if (!this.currentFocusElement) |
| 683 return; |
| 684 // Calling preventDefault() will say "we support copying, so enable the Copy
menu". |
| 685 if (this.currentFocusElement.handleCopyEvent) |
| 686 event.preventDefault(); |
| 687 else if (this.currentFocusElement.id && this.currentFocusElement.id.length &
& WebInspector[this.currentFocusElement.id + "Copy"]) |
| 688 event.preventDefault(); |
| 689 } |
| 690 |
| 691 WebInspector.documentCopy = function(event) |
| 692 { |
| 693 if (!this.currentFocusElement) |
| 694 return; |
| 695 if (this.currentFocusElement.handleCopyEvent) |
| 696 this.currentFocusElement.handleCopyEvent(event); |
| 697 else if (this.currentFocusElement.id && this.currentFocusElement.id.length &
& WebInspector[this.currentFocusElement.id + "Copy"]) |
| 698 WebInspector[this.currentFocusElement.id + "Copy"](event); |
| 699 } |
| 700 |
| 701 WebInspector.contextMenu = function(event) |
| 702 { |
| 703 if (event.handled || event.target.hasStyleClass("popup-glasspane")) |
| 704 event.preventDefault(); |
| 705 } |
| 706 |
| 707 WebInspector.mainKeyDown = function(event) |
| 708 { |
| 709 if (this.currentPanel && this.currentPanel.handleKeyEvent) |
| 710 this.currentPanel.handleKeyEvent(event); |
| 711 } |
| 712 |
| 713 WebInspector.mainKeyUp = function(event) |
| 714 { |
| 715 if (this.currentPanel && this.currentPanel.handleKeyUpEvent) |
| 716 this.currentPanel.handleKeyUpEvent(event); |
| 717 } |
| 718 |
| 719 WebInspector.mainCopy = function(event) |
| 720 { |
| 721 if (this.currentPanel && this.currentPanel.handleCopyEvent) |
| 722 this.currentPanel.handleCopyEvent(event); |
| 723 } |
| 724 |
| 725 WebInspector.animateStyle = function(animations, duration, callback, complete) |
| 726 { |
| 727 if (complete === undefined) |
| 728 complete = 0; |
| 729 var slice = (1000 / 30); // 30 frames per second |
| 730 |
| 731 var defaultUnit = "px"; |
| 732 var propertyUnit = {opacity: ""}; |
| 733 |
| 734 for (var i = 0; i < animations.length; ++i) { |
| 735 var animation = animations[i]; |
| 736 var element = null; |
| 737 var start = null; |
| 738 var current = null; |
| 739 var end = null; |
| 740 var key = null; |
| 741 for (key in animation) { |
| 742 if (key === "element") |
| 743 element = animation[key]; |
| 744 else if (key === "start") |
| 745 start = animation[key]; |
| 746 else if (key === "current") |
| 747 current = animation[key]; |
| 748 else if (key === "end") |
| 749 end = animation[key]; |
| 750 } |
| 751 |
| 752 if (!element || !end) |
| 753 continue; |
| 754 |
| 755 var computedStyle = element.ownerDocument.defaultView.getComputedStyle(e
lement); |
| 756 if (!start) { |
| 757 start = {}; |
| 758 for (key in end) |
| 759 start[key] = parseInt(computedStyle.getPropertyValue(key)); |
| 760 animation.start = start; |
| 761 } else if (complete == 0) |
| 762 for (key in start) |
| 763 element.style.setProperty(key, start[key] + (key in propertyUnit
? propertyUnit[key] : defaultUnit)); |
| 764 |
| 765 if (!current) { |
| 766 current = {}; |
| 767 for (key in start) |
| 768 current[key] = start[key]; |
| 769 animation.current = current; |
| 770 } |
| 771 |
| 772 function cubicInOut(t, b, c, d) |
| 773 { |
| 774 if ((t/=d/2) < 1) return c/2*t*t*t + b; |
| 775 return c/2*((t-=2)*t*t + 2) + b; |
| 776 } |
| 777 |
| 778 var style = element.style; |
| 779 for (key in end) { |
| 780 var startValue = start[key]; |
| 781 var currentValue = current[key]; |
| 782 var endValue = end[key]; |
| 783 if ((complete + slice) < duration) { |
| 784 var delta = (endValue - startValue) / (duration / slice); |
| 785 var newValue = cubicInOut(complete, startValue, endValue - start
Value, duration); |
| 786 style.setProperty(key, newValue + (key in propertyUnit ? propert
yUnit[key] : defaultUnit)); |
| 787 current[key] = newValue; |
| 788 } else { |
| 789 style.setProperty(key, endValue + (key in propertyUnit ? propert
yUnit[key] : defaultUnit)); |
| 790 } |
| 791 } |
| 792 } |
| 793 |
| 794 if (complete < duration) |
| 795 setTimeout(WebInspector.animateStyle, slice, animations, duration, callb
ack, complete + slice); |
| 796 else if (callback) |
| 797 callback(); |
| 798 } |
| 799 |
| 800 WebInspector.updateSearchLabel = function() |
| 801 { |
| 802 if (!this.currentPanel) |
| 803 return; |
| 804 |
| 805 var newLabel = WebInspector.UIString("Search %s", this.currentPanel.toolbarI
temLabel); |
| 806 if (this.attached) |
| 807 document.getElementById("search").setAttribute("placeholder", newLabel); |
| 808 else { |
| 809 document.getElementById("search").removeAttribute("placeholder"); |
| 810 document.getElementById("search-toolbar-label").textContent = newLabel; |
| 811 } |
| 812 } |
| 813 |
| 814 WebInspector.toggleAttach = function() |
| 815 { |
| 816 this.attached = !this.attached; |
| 817 } |
| 818 |
| 819 WebInspector.toolbarDragStart = function(event) |
| 820 { |
| 821 if ((!WebInspector.attached && InspectorController.platform() !== "mac-leopa
rd") || InspectorController.platform() == "qt") |
| 822 return; |
| 823 |
| 824 var target = event.target; |
| 825 if (target.hasStyleClass("toolbar-item") && target.hasStyleClass("toggleable
")) |
| 826 return; |
| 827 |
| 828 var toolbar = document.getElementById("toolbar"); |
| 829 if (target !== toolbar && !target.hasStyleClass("toolbar-item")) |
| 830 return; |
| 831 |
| 832 toolbar.lastScreenX = event.screenX; |
| 833 toolbar.lastScreenY = event.screenY; |
| 834 |
| 835 WebInspector.elementDragStart(toolbar, WebInspector.toolbarDrag, WebInspecto
r.toolbarDragEnd, event, (WebInspector.attached ? "row-resize" : "default")); |
| 836 } |
| 837 |
| 838 WebInspector.toolbarDragEnd = function(event) |
| 839 { |
| 840 var toolbar = document.getElementById("toolbar"); |
| 841 |
| 842 WebInspector.elementDragEnd(event); |
| 843 |
| 844 delete toolbar.lastScreenX; |
| 845 delete toolbar.lastScreenY; |
| 846 } |
| 847 |
| 848 WebInspector.toolbarDrag = function(event) |
| 849 { |
| 850 var toolbar = document.getElementById("toolbar"); |
| 851 |
| 852 if (WebInspector.attached) { |
| 853 var height = window.innerHeight - (event.screenY - toolbar.lastScreenY); |
| 854 |
| 855 InspectorController.setAttachedWindowHeight(height); |
| 856 } else { |
| 857 var x = event.screenX - toolbar.lastScreenX; |
| 858 var y = event.screenY - toolbar.lastScreenY; |
| 859 |
| 860 // We cannot call window.moveBy here because it restricts the movement |
| 861 // of the window at the edges. |
| 862 InspectorController.moveByUnrestricted(x, y); |
| 863 } |
| 864 |
| 865 toolbar.lastScreenX = event.screenX; |
| 866 toolbar.lastScreenY = event.screenY; |
| 867 |
| 868 event.preventDefault(); |
| 869 } |
| 870 |
| 871 WebInspector.elementDragStart = function(element, dividerDrag, elementDragEnd, e
vent, cursor) |
| 872 { |
| 873 if (this._elementDraggingEventListener || this._elementEndDraggingEventListe
ner) |
| 874 this.elementDragEnd(event); |
| 875 |
| 876 this._elementDraggingEventListener = dividerDrag; |
| 877 this._elementEndDraggingEventListener = elementDragEnd; |
| 878 |
| 879 document.addEventListener("mousemove", dividerDrag, true); |
| 880 document.addEventListener("mouseup", elementDragEnd, true); |
| 881 |
| 882 document.body.style.cursor = cursor; |
| 883 |
| 884 event.preventDefault(); |
| 885 } |
| 886 |
| 887 WebInspector.elementDragEnd = function(event) |
| 888 { |
| 889 document.removeEventListener("mousemove", this._elementDraggingEventListener
, true); |
| 890 document.removeEventListener("mouseup", this._elementEndDraggingEventListene
r, true); |
| 891 |
| 892 document.body.style.removeProperty("cursor"); |
| 893 |
| 894 delete this._elementDraggingEventListener; |
| 895 delete this._elementEndDraggingEventListener; |
| 896 |
| 897 event.preventDefault(); |
| 898 } |
| 899 |
| 900 WebInspector.showConsole = function() |
| 901 { |
| 902 this.drawer.showView(this.console); |
| 903 } |
| 904 |
| 905 WebInspector.showChanges = function() |
| 906 { |
| 907 this.drawer.showView(this.changes); |
| 908 } |
| 909 |
| 910 WebInspector.showElementsPanel = function() |
| 911 { |
| 912 this.currentPanel = this.panels.elements; |
| 913 } |
| 914 |
| 915 WebInspector.showResourcesPanel = function() |
| 916 { |
| 917 this.currentPanel = this.panels.resources; |
| 918 } |
| 919 |
| 920 WebInspector.showScriptsPanel = function() |
| 921 { |
| 922 this.currentPanel = this.panels.scripts; |
| 923 } |
| 924 |
| 925 WebInspector.showProfilesPanel = function() |
| 926 { |
| 927 this.currentPanel = this.panels.profiles; |
| 928 } |
| 929 |
| 930 WebInspector.showStoragePanel = function() |
| 931 { |
| 932 this.currentPanel = this.panels.storage; |
| 933 } |
| 934 |
| 935 WebInspector.addResource = function(identifier, payload) |
| 936 { |
| 937 var resource = new WebInspector.Resource( |
| 938 payload.requestHeaders, |
| 939 payload.requestURL, |
| 940 payload.host, |
| 941 payload.path, |
| 942 payload.lastPathComponent, |
| 943 identifier, |
| 944 payload.isMainResource, |
| 945 payload.cached, |
| 946 payload.requestMethod, |
| 947 payload.requestFormData); |
| 948 this.resources[identifier] = resource; |
| 949 this.resourceURLMap[resource.url] = resource; |
| 950 |
| 951 if (resource.mainResource) |
| 952 this.mainResource = resource; |
| 953 |
| 954 if (this.panels.resources) |
| 955 this.panels.resources.addResource(resource); |
| 956 } |
| 957 |
| 958 WebInspector.clearConsoleMessages = function() |
| 959 { |
| 960 WebInspector.console.clearMessages(false); |
| 961 } |
| 962 |
| 963 WebInspector.selectDatabase = function(o) |
| 964 { |
| 965 WebInspector.showStoragePanel(); |
| 966 WebInspector.panels.storage.selectDatabase(o); |
| 967 } |
| 968 |
| 969 WebInspector.selectDOMStorage = function(o) |
| 970 { |
| 971 WebInspector.showStoragePanel(); |
| 972 WebInspector.panels.storage.selectDOMStorage(o); |
| 973 } |
| 974 |
| 975 WebInspector.updateResource = function(identifier, payload) |
| 976 { |
| 977 var resource = this.resources[identifier]; |
| 978 if (!resource) |
| 979 return; |
| 980 |
| 981 if (payload.didRequestChange) { |
| 982 resource.url = payload.url; |
| 983 resource.domain = payload.domain; |
| 984 resource.path = payload.path; |
| 985 resource.lastPathComponent = payload.lastPathComponent; |
| 986 resource.requestHeaders = payload.requestHeaders; |
| 987 resource.mainResource = payload.mainResource; |
| 988 resource.requestMethod = payload.requestMethod; |
| 989 resource.requestFormData = payload.requestFormData; |
| 990 } |
| 991 |
| 992 if (payload.didResponseChange) { |
| 993 resource.mimeType = payload.mimeType; |
| 994 resource.suggestedFilename = payload.suggestedFilename; |
| 995 resource.expectedContentLength = payload.expectedContentLength; |
| 996 resource.statusCode = payload.statusCode; |
| 997 resource.suggestedFilename = payload.suggestedFilename; |
| 998 resource.responseHeaders = payload.responseHeaders; |
| 999 } |
| 1000 |
| 1001 if (payload.didTypeChange) { |
| 1002 resource.type = payload.type; |
| 1003 } |
| 1004 |
| 1005 if (payload.didLengthChange) { |
| 1006 resource.contentLength = payload.contentLength; |
| 1007 } |
| 1008 |
| 1009 if (payload.didCompletionChange) { |
| 1010 resource.failed = payload.failed; |
| 1011 resource.finished = payload.finished; |
| 1012 } |
| 1013 |
| 1014 if (payload.didTimingChange) { |
| 1015 if (payload.startTime) |
| 1016 resource.startTime = payload.startTime; |
| 1017 if (payload.responseReceivedTime) |
| 1018 resource.responseReceivedTime = payload.responseReceivedTime; |
| 1019 if (payload.endTime) |
| 1020 resource.endTime = payload.endTime; |
| 1021 |
| 1022 if (payload.loadEventTime) { |
| 1023 // This loadEventTime is for the main resource, and we want to show
it |
| 1024 // for all resources on this page. This means we want to set it as a
member |
| 1025 // of the resources panel instead of the individual resource. |
| 1026 if (this.panels.resources) |
| 1027 this.panels.resources.mainResourceLoadTime = payload.loadEventTi
me; |
| 1028 } |
| 1029 |
| 1030 if (payload.domContentEventTime) { |
| 1031 // This domContentEventTime is for the main resource, so it should g
o in |
| 1032 // the resources panel for the same reasons as above. |
| 1033 if (this.panels.resources) |
| 1034 this.panels.resources.mainResourceDOMContentTime = payload.domCo
ntentEventTime; |
| 1035 } |
| 1036 } |
| 1037 } |
| 1038 |
| 1039 WebInspector.removeResource = function(identifier) |
| 1040 { |
| 1041 var resource = this.resources[identifier]; |
| 1042 if (!resource) |
| 1043 return; |
| 1044 |
| 1045 resource.category.removeResource(resource); |
| 1046 delete this.resourceURLMap[resource.url]; |
| 1047 delete this.resources[identifier]; |
| 1048 |
| 1049 if (this.panels.resources) |
| 1050 this.panels.resources.removeResource(resource); |
| 1051 } |
| 1052 |
| 1053 WebInspector.addDatabase = function(payload) |
| 1054 { |
| 1055 var database = new WebInspector.Database( |
| 1056 payload.id, |
| 1057 payload.domain, |
| 1058 payload.name, |
| 1059 payload.version); |
| 1060 this.panels.storage.addDatabase(database); |
| 1061 } |
| 1062 |
| 1063 WebInspector.addCookieDomain = function(domain) |
| 1064 { |
| 1065 if (this.panels.storage) |
| 1066 this.panels.storage.addCookieDomain(domain); |
| 1067 } |
| 1068 |
| 1069 WebInspector.addDOMStorage = function(payload) |
| 1070 { |
| 1071 var domStorage = new WebInspector.DOMStorage( |
| 1072 payload.id, |
| 1073 payload.host, |
| 1074 payload.isLocalStorage); |
| 1075 this.panels.storage.addDOMStorage(domStorage); |
| 1076 } |
| 1077 |
| 1078 WebInspector.updateDOMStorage = function(storageId) |
| 1079 { |
| 1080 this.panels.storage.updateDOMStorage(storageId); |
| 1081 } |
| 1082 |
| 1083 WebInspector.resourceTrackingWasEnabled = function() |
| 1084 { |
| 1085 this.panels.resources.resourceTrackingWasEnabled(); |
| 1086 } |
| 1087 |
| 1088 WebInspector.resourceTrackingWasDisabled = function() |
| 1089 { |
| 1090 this.panels.resources.resourceTrackingWasDisabled(); |
| 1091 } |
| 1092 |
| 1093 WebInspector.attachDebuggerWhenShown = function() |
| 1094 { |
| 1095 this.panels.scripts.attachDebuggerWhenShown(); |
| 1096 } |
| 1097 |
| 1098 WebInspector.debuggerWasEnabled = function() |
| 1099 { |
| 1100 this.panels.scripts.debuggerWasEnabled(); |
| 1101 } |
| 1102 |
| 1103 WebInspector.debuggerWasDisabled = function() |
| 1104 { |
| 1105 this.panels.scripts.debuggerWasDisabled(); |
| 1106 } |
| 1107 |
| 1108 WebInspector.profilerWasEnabled = function() |
| 1109 { |
| 1110 this.panels.profiles.profilerWasEnabled(); |
| 1111 } |
| 1112 |
| 1113 WebInspector.profilerWasDisabled = function() |
| 1114 { |
| 1115 this.panels.profiles.profilerWasDisabled(); |
| 1116 } |
| 1117 |
| 1118 WebInspector.parsedScriptSource = function(sourceID, sourceURL, source, starting
Line) |
| 1119 { |
| 1120 this.panels.scripts.addScript(sourceID, sourceURL, source, startingLine); |
| 1121 } |
| 1122 |
| 1123 WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLin
e, errorLine, errorMessage) |
| 1124 { |
| 1125 this.panels.scripts.addScript(null, sourceURL, source, startingLine, errorLi
ne, errorMessage); |
| 1126 } |
| 1127 |
| 1128 WebInspector.pausedScript = function(callFrames) |
| 1129 { |
| 1130 this.panels.scripts.debuggerPaused(callFrames); |
| 1131 } |
| 1132 |
| 1133 WebInspector.resumedScript = function() |
| 1134 { |
| 1135 this.panels.scripts.debuggerResumed(); |
| 1136 } |
| 1137 |
| 1138 WebInspector.populateInterface = function() |
| 1139 { |
| 1140 for (var panelName in this.panels) { |
| 1141 var panel = this.panels[panelName]; |
| 1142 if ("populateInterface" in panel) |
| 1143 panel.populateInterface(); |
| 1144 } |
| 1145 } |
| 1146 |
| 1147 WebInspector.reset = function() |
| 1148 { |
| 1149 for (var panelName in this.panels) { |
| 1150 var panel = this.panels[panelName]; |
| 1151 if ("reset" in panel) |
| 1152 panel.reset(); |
| 1153 } |
| 1154 |
| 1155 for (var category in this.resourceCategories) |
| 1156 this.resourceCategories[category].removeAllResources(); |
| 1157 |
| 1158 this.resources = {}; |
| 1159 this.resourceURLMap = {}; |
| 1160 this.hoveredDOMNode = null; |
| 1161 |
| 1162 delete this.mainResource; |
| 1163 |
| 1164 this.console.clearMessages(); |
| 1165 } |
| 1166 |
| 1167 WebInspector.resourceURLChanged = function(resource, oldURL) |
| 1168 { |
| 1169 delete this.resourceURLMap[oldURL]; |
| 1170 this.resourceURLMap[resource.url] = resource; |
| 1171 } |
| 1172 |
| 1173 WebInspector.didCommitLoad = function() |
| 1174 { |
| 1175 // Cleanup elements panel early on inspected page refresh. |
| 1176 WebInspector.setDocument(null); |
| 1177 } |
| 1178 |
| 1179 WebInspector.addMessageToConsole = function(payload) |
| 1180 { |
| 1181 var consoleMessage = new WebInspector.ConsoleMessage( |
| 1182 payload.source, |
| 1183 payload.type, |
| 1184 payload.level, |
| 1185 payload.line, |
| 1186 payload.url, |
| 1187 payload.groupLevel, |
| 1188 payload.repeatCount); |
| 1189 consoleMessage.setMessageBody(Array.prototype.slice.call(arguments, 1)); |
| 1190 this.console.addMessage(consoleMessage); |
| 1191 } |
| 1192 |
| 1193 WebInspector.log = function(message) |
| 1194 { |
| 1195 // remember 'this' for setInterval() callback |
| 1196 var self = this; |
| 1197 |
| 1198 // return indication if we can actually log a message |
| 1199 function isLogAvailable() |
| 1200 { |
| 1201 return WebInspector.ConsoleMessage && WebInspector.ObjectProxy && self.c
onsole; |
| 1202 } |
| 1203 |
| 1204 // flush the queue of pending messages |
| 1205 function flushQueue() |
| 1206 { |
| 1207 var queued = WebInspector.log.queued; |
| 1208 if (!queued) |
| 1209 return; |
| 1210 |
| 1211 for (var i = 0; i < queued.length; ++i) |
| 1212 logMessage(queued[i]); |
| 1213 |
| 1214 delete WebInspector.log.queued; |
| 1215 } |
| 1216 |
| 1217 // flush the queue if it console is available |
| 1218 // - this function is run on an interval |
| 1219 function flushQueueIfAvailable() |
| 1220 { |
| 1221 if (!isLogAvailable()) |
| 1222 return; |
| 1223 |
| 1224 clearInterval(WebInspector.log.interval); |
| 1225 delete WebInspector.log.interval; |
| 1226 |
| 1227 flushQueue(); |
| 1228 } |
| 1229 |
| 1230 // actually log the message |
| 1231 function logMessage(message) |
| 1232 { |
| 1233 var repeatCount = 1; |
| 1234 if (message == WebInspector.log.lastMessage) |
| 1235 repeatCount = WebInspector.log.repeatCount + 1; |
| 1236 |
| 1237 WebInspector.log.lastMessage = message; |
| 1238 WebInspector.log.repeatCount = repeatCount; |
| 1239 |
| 1240 // ConsoleMessage expects a proxy object |
| 1241 message = new WebInspector.ObjectProxy(null, [], 0, message, false); |
| 1242 |
| 1243 // post the message |
| 1244 var msg = new WebInspector.ConsoleMessage( |
| 1245 WebInspector.ConsoleMessage.MessageSource.Other, |
| 1246 WebInspector.ConsoleMessage.MessageType.Log, |
| 1247 WebInspector.ConsoleMessage.MessageLevel.Debug, |
| 1248 -1, |
| 1249 null, |
| 1250 null, |
| 1251 repeatCount, |
| 1252 message); |
| 1253 |
| 1254 self.console.addMessage(msg); |
| 1255 } |
| 1256 |
| 1257 // if we can't log the message, queue it |
| 1258 if (!isLogAvailable()) { |
| 1259 if (!WebInspector.log.queued) |
| 1260 WebInspector.log.queued = []; |
| 1261 |
| 1262 WebInspector.log.queued.push(message); |
| 1263 |
| 1264 if (!WebInspector.log.interval) |
| 1265 WebInspector.log.interval = setInterval(flushQueueIfAvailable, 1000)
; |
| 1266 |
| 1267 return; |
| 1268 } |
| 1269 |
| 1270 // flush the pending queue if any |
| 1271 flushQueue(); |
| 1272 |
| 1273 // log the message |
| 1274 logMessage(message); |
| 1275 } |
| 1276 |
| 1277 WebInspector.addProfileHeader = function(profile) |
| 1278 { |
| 1279 this.panels.profiles.addProfileHeader(WebInspector.CPUProfileType.TypeId, ne
w WebInspector.CPUProfile(profile)); |
| 1280 } |
| 1281 |
| 1282 WebInspector.setRecordingProfile = function(isProfiling) |
| 1283 { |
| 1284 this.panels.profiles.getProfileType(WebInspector.CPUProfileType.TypeId).setR
ecordingProfile(isProfiling); |
| 1285 this.panels.profiles.updateProfileTypeButtons(); |
| 1286 } |
| 1287 |
| 1288 WebInspector.drawLoadingPieChart = function(canvas, percent) { |
| 1289 var g = canvas.getContext("2d"); |
| 1290 var darkColor = "rgb(122, 168, 218)"; |
| 1291 var lightColor = "rgb(228, 241, 251)"; |
| 1292 var cx = 8; |
| 1293 var cy = 8; |
| 1294 var r = 7; |
| 1295 |
| 1296 g.beginPath(); |
| 1297 g.arc(cx, cy, r, 0, Math.PI * 2, false); |
| 1298 g.closePath(); |
| 1299 |
| 1300 g.lineWidth = 1; |
| 1301 g.strokeStyle = darkColor; |
| 1302 g.fillStyle = lightColor; |
| 1303 g.fill(); |
| 1304 g.stroke(); |
| 1305 |
| 1306 var startangle = -Math.PI / 2; |
| 1307 var endangle = startangle + (percent * Math.PI * 2); |
| 1308 |
| 1309 g.beginPath(); |
| 1310 g.moveTo(cx, cy); |
| 1311 g.arc(cx, cy, r, startangle, endangle, false); |
| 1312 g.closePath(); |
| 1313 |
| 1314 g.fillStyle = darkColor; |
| 1315 g.fill(); |
| 1316 } |
| 1317 |
| 1318 WebInspector.updateFocusedNode = function(nodeId) |
| 1319 { |
| 1320 var node = WebInspector.domAgent.nodeForId(nodeId); |
| 1321 if (!node) |
| 1322 // FIXME: Should we deselect if null is passed in? |
| 1323 return; |
| 1324 |
| 1325 this.currentPanel = this.panels.elements; |
| 1326 this.panels.elements.focusedDOMNode = node; |
| 1327 } |
| 1328 |
| 1329 WebInspector.displayNameForURL = function(url) |
| 1330 { |
| 1331 if (!url) |
| 1332 return ""; |
| 1333 var resource = this.resourceURLMap[url]; |
| 1334 if (resource) |
| 1335 return resource.displayName; |
| 1336 return url.trimURL(WebInspector.mainResource ? WebInspector.mainResource.dom
ain : ""); |
| 1337 } |
| 1338 |
| 1339 WebInspector.resourceForURL = function(url) |
| 1340 { |
| 1341 if (url in this.resourceURLMap) |
| 1342 return this.resourceURLMap[url]; |
| 1343 |
| 1344 // No direct match found. Search for resources that contain |
| 1345 // a substring of the URL. |
| 1346 for (var resourceURL in this.resourceURLMap) { |
| 1347 if (resourceURL.hasSubstring(url)) |
| 1348 return this.resourceURLMap[resourceURL]; |
| 1349 } |
| 1350 |
| 1351 return null; |
| 1352 } |
| 1353 |
| 1354 WebInspector.showResourceForURL = function(url, line, preferredPanel) |
| 1355 { |
| 1356 var resource = this.resourceForURL(url); |
| 1357 if (!resource) |
| 1358 return false; |
| 1359 |
| 1360 if (preferredPanel && preferredPanel in WebInspector.panels) { |
| 1361 var panel = this.panels[preferredPanel]; |
| 1362 if (!("showResource" in panel)) |
| 1363 panel = null; |
| 1364 else if ("canShowResource" in panel && !panel.canShowResource(resource)) |
| 1365 panel = null; |
| 1366 } |
| 1367 |
| 1368 this.currentPanel = panel || this.panels.resources; |
| 1369 if (!this.currentPanel) |
| 1370 return false; |
| 1371 this.currentPanel.showResource(resource, line); |
| 1372 return true; |
| 1373 } |
| 1374 |
| 1375 WebInspector.linkifyStringAsFragment = function(string) |
| 1376 { |
| 1377 var container = document.createDocumentFragment(); |
| 1378 var linkStringRegEx = new RegExp("(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}://|www\\.)[\
\w$\\-_+*'=\\|/\\\\(){}[\\]%@&#~,:;.!?]{2,}[\\w$\\-_+*=\\|/\\\\({%@&#~]"); |
| 1379 |
| 1380 while (string) { |
| 1381 var linkString = linkStringRegEx.exec(string); |
| 1382 if (!linkString) |
| 1383 break; |
| 1384 |
| 1385 linkString = linkString[0]; |
| 1386 var title = linkString; |
| 1387 var linkIndex = string.indexOf(linkString); |
| 1388 var nonLink = string.substring(0, linkIndex); |
| 1389 container.appendChild(document.createTextNode(nonLink)); |
| 1390 |
| 1391 var profileStringMatches = WebInspector.ProfileType.URLRegExp.exec(title
); |
| 1392 if (profileStringMatches) |
| 1393 title = WebInspector.panels.profiles.displayTitleForProfileLink(prof
ileStringMatches[2], profileStringMatches[1]); |
| 1394 |
| 1395 var realURL = (linkString.indexOf("www.") === 0 ? "http://" + linkString
: linkString); |
| 1396 container.appendChild(WebInspector.linkifyURLAsNode(realURL, title, null
, (realURL in WebInspector.resourceURLMap))); |
| 1397 string = string.substring(linkIndex + linkString.length, string.length); |
| 1398 } |
| 1399 |
| 1400 if (string) |
| 1401 container.appendChild(document.createTextNode(string)); |
| 1402 |
| 1403 return container; |
| 1404 } |
| 1405 |
| 1406 WebInspector.showProfileForURL = function(url) { |
| 1407 WebInspector.showProfilesPanel(); |
| 1408 WebInspector.panels.profiles.showProfileForURL(url); |
| 1409 } |
| 1410 |
| 1411 WebInspector.linkifyURLAsNode = function(url, linkText, classes, isExternal) |
| 1412 { |
| 1413 if (!linkText) |
| 1414 linkText = url; |
| 1415 classes = (classes ? classes + " " : ""); |
| 1416 classes += isExternal ? "webkit-html-external-link" : "webkit-html-resource-
link"; |
| 1417 |
| 1418 var a = document.createElement("a"); |
| 1419 a.href = url; |
| 1420 a.className = classes; |
| 1421 a.title = url; |
| 1422 a.target = "_blank"; |
| 1423 a.textContent = linkText; |
| 1424 |
| 1425 return a; |
| 1426 } |
| 1427 |
| 1428 WebInspector.linkifyURL = function(url, linkText, classes, isExternal) |
| 1429 { |
| 1430 // Use the DOM version of this function so as to avoid needing to escape att
ributes. |
| 1431 // FIXME: Get rid of linkifyURL entirely. |
| 1432 return WebInspector.linkifyURLAsNode(url, linkText, classes, isExternal).out
erHTML; |
| 1433 } |
| 1434 |
| 1435 WebInspector.addMainEventListeners = function(doc) |
| 1436 { |
| 1437 doc.defaultView.addEventListener("focus", this.windowFocused.bind(this), fal
se); |
| 1438 doc.defaultView.addEventListener("blur", this.windowBlurred.bind(this), fals
e); |
| 1439 doc.addEventListener("click", this.documentClick.bind(this), true); |
| 1440 } |
| 1441 |
| 1442 WebInspector.searchKeyDown = function(event) |
| 1443 { |
| 1444 if (event.keyIdentifier !== "Enter") |
| 1445 return; |
| 1446 |
| 1447 // Call preventDefault since this was the Enter key. This prevents a "search
" event |
| 1448 // from firing for key down. We handle the Enter key on key up in searchKeyU
p. This |
| 1449 // stops performSearch from being called twice in a row. |
| 1450 event.preventDefault(); |
| 1451 } |
| 1452 |
| 1453 WebInspector.searchKeyUp = function(event) |
| 1454 { |
| 1455 if (event.keyIdentifier !== "Enter") |
| 1456 return; |
| 1457 |
| 1458 // Select all of the text so the user can easily type an entirely new query. |
| 1459 event.target.select(); |
| 1460 |
| 1461 // Only call performSearch if the Enter key was pressed. Otherwise the searc
h |
| 1462 // performance is poor because of searching on every key. The search field h
as |
| 1463 // the incremental attribute set, so we still get incremental searches. |
| 1464 this.performSearch(event); |
| 1465 } |
| 1466 |
| 1467 WebInspector.performSearch = function(event) |
| 1468 { |
| 1469 var query = event.target.value; |
| 1470 var forceSearch = event.keyIdentifier === "Enter"; |
| 1471 var isShortSearch = (query.length < 3); |
| 1472 |
| 1473 // Clear a leftover short search flag due to a non-conflicting forced search
. |
| 1474 if (isShortSearch && this.shortSearchWasForcedByKeyEvent && this.currentQuer
y !== query) |
| 1475 delete this.shortSearchWasForcedByKeyEvent; |
| 1476 |
| 1477 // Indicate this was a forced search on a short query. |
| 1478 if (isShortSearch && forceSearch) |
| 1479 this.shortSearchWasForcedByKeyEvent = true; |
| 1480 |
| 1481 if (!query || !query.length || (!forceSearch && isShortSearch)) { |
| 1482 // Prevent clobbering a short search forced by the user. |
| 1483 if (this.shortSearchWasForcedByKeyEvent) { |
| 1484 delete this.shortSearchWasForcedByKeyEvent; |
| 1485 return; |
| 1486 } |
| 1487 |
| 1488 delete this.currentQuery; |
| 1489 |
| 1490 for (var panelName in this.panels) { |
| 1491 var panel = this.panels[panelName]; |
| 1492 if (panel.currentQuery && panel.searchCanceled) |
| 1493 panel.searchCanceled(); |
| 1494 delete panel.currentQuery; |
| 1495 } |
| 1496 |
| 1497 this.updateSearchMatchesCount(); |
| 1498 |
| 1499 return; |
| 1500 } |
| 1501 |
| 1502 if (query === this.currentPanel.currentQuery && this.currentPanel.currentQue
ry === this.currentQuery) { |
| 1503 // When this is the same query and a forced search, jump to the next |
| 1504 // search result for a good user experience. |
| 1505 if (forceSearch && this.currentPanel.jumpToNextSearchResult) |
| 1506 this.currentPanel.jumpToNextSearchResult(); |
| 1507 return; |
| 1508 } |
| 1509 |
| 1510 this.currentQuery = query; |
| 1511 |
| 1512 this.updateSearchMatchesCount(); |
| 1513 |
| 1514 if (!this.currentPanel.performSearch) |
| 1515 return; |
| 1516 |
| 1517 this.currentPanel.currentQuery = query; |
| 1518 this.currentPanel.performSearch(query); |
| 1519 } |
| 1520 |
| 1521 WebInspector.addNodesToSearchResult = function(nodeIds) |
| 1522 { |
| 1523 WebInspector.panels.elements.addNodesToSearchResult(nodeIds); |
| 1524 } |
| 1525 |
| 1526 WebInspector.updateSearchMatchesCount = function(matches, panel) |
| 1527 { |
| 1528 if (!panel) |
| 1529 panel = this.currentPanel; |
| 1530 |
| 1531 panel.currentSearchMatches = matches; |
| 1532 |
| 1533 if (panel !== this.currentPanel) |
| 1534 return; |
| 1535 |
| 1536 if (!this.currentPanel.currentQuery) { |
| 1537 document.getElementById("search-results-matches").addStyleClass("hidden"
); |
| 1538 return; |
| 1539 } |
| 1540 |
| 1541 if (matches) { |
| 1542 if (matches === 1) |
| 1543 var matchesString = WebInspector.UIString("1 match"); |
| 1544 else |
| 1545 var matchesString = WebInspector.UIString("%d matches", matches); |
| 1546 } else |
| 1547 var matchesString = WebInspector.UIString("Not Found"); |
| 1548 |
| 1549 var matchesToolbarElement = document.getElementById("search-results-matches"
); |
| 1550 matchesToolbarElement.removeStyleClass("hidden"); |
| 1551 matchesToolbarElement.textContent = matchesString; |
| 1552 } |
| 1553 |
| 1554 WebInspector.UIString = function(string) |
| 1555 { |
| 1556 if (window.localizedStrings && string in window.localizedStrings) |
| 1557 string = window.localizedStrings[string]; |
| 1558 else { |
| 1559 if (!(string in this.missingLocalizedStrings)) { |
| 1560 console.error("Localized string \"" + string + "\" not found."); |
| 1561 this.missingLocalizedStrings[string] = true; |
| 1562 } |
| 1563 |
| 1564 if (Preferences.showMissingLocalizedStrings) |
| 1565 string += " (not localized)"; |
| 1566 } |
| 1567 |
| 1568 return String.vsprintf(string, Array.prototype.slice.call(arguments, 1)); |
| 1569 } |
| 1570 |
| 1571 WebInspector.isBeingEdited = function(element) |
| 1572 { |
| 1573 return element.__editing; |
| 1574 } |
| 1575 |
| 1576 WebInspector.startEditing = function(element, committedCallback, cancelledCallba
ck, context) |
| 1577 { |
| 1578 if (element.__editing) |
| 1579 return; |
| 1580 element.__editing = true; |
| 1581 |
| 1582 var oldText = getContent(element); |
| 1583 var oldHandleKeyEvent = element.handleKeyEvent; |
| 1584 var moveDirection = ""; |
| 1585 |
| 1586 element.addStyleClass("editing"); |
| 1587 |
| 1588 var oldTabIndex = element.tabIndex; |
| 1589 if (element.tabIndex < 0) |
| 1590 element.tabIndex = 0; |
| 1591 |
| 1592 function blurEventListener() { |
| 1593 editingCommitted.call(element); |
| 1594 } |
| 1595 |
| 1596 function getContent(element) { |
| 1597 if (element.tagName === "INPUT" && element.type === "text") |
| 1598 return element.value; |
| 1599 else |
| 1600 return element.textContent; |
| 1601 } |
| 1602 |
| 1603 function cleanUpAfterEditing() { |
| 1604 delete this.__editing; |
| 1605 |
| 1606 this.removeStyleClass("editing"); |
| 1607 this.tabIndex = oldTabIndex; |
| 1608 this.scrollTop = 0; |
| 1609 this.scrollLeft = 0; |
| 1610 |
| 1611 this.handleKeyEvent = oldHandleKeyEvent; |
| 1612 element.removeEventListener("blur", blurEventListener, false); |
| 1613 |
| 1614 if (element === WebInspector.currentFocusElement || element.isAncestor(W
ebInspector.currentFocusElement)) |
| 1615 WebInspector.currentFocusElement = WebInspector.previousFocusElement
; |
| 1616 } |
| 1617 |
| 1618 function editingCancelled() { |
| 1619 if (this.tagName === "INPUT" && this.type === "text") |
| 1620 this.value = oldText; |
| 1621 else |
| 1622 this.textContent = oldText; |
| 1623 |
| 1624 cleanUpAfterEditing.call(this); |
| 1625 |
| 1626 if (cancelledCallback) |
| 1627 cancelledCallback(this, context); |
| 1628 } |
| 1629 |
| 1630 function editingCommitted() { |
| 1631 cleanUpAfterEditing.call(this); |
| 1632 |
| 1633 if (committedCallback) |
| 1634 committedCallback(this, getContent(this), oldText, context, moveDire
ction); |
| 1635 } |
| 1636 |
| 1637 element.handleKeyEvent = function(event) { |
| 1638 if (oldHandleKeyEvent) |
| 1639 oldHandleKeyEvent(event); |
| 1640 if (event.handled) |
| 1641 return; |
| 1642 |
| 1643 if (event.keyIdentifier === "Enter") { |
| 1644 editingCommitted.call(element); |
| 1645 event.preventDefault(); |
| 1646 } else if (event.keyCode === 27) { // Escape key |
| 1647 editingCancelled.call(element); |
| 1648 event.preventDefault(); |
| 1649 event.handled = true; |
| 1650 } else if (event.keyIdentifier === "U+0009") // Tab key |
| 1651 moveDirection = (event.shiftKey ? "backward" : "forward"); |
| 1652 } |
| 1653 |
| 1654 element.addEventListener("blur", blurEventListener, false); |
| 1655 |
| 1656 WebInspector.currentFocusElement = element; |
| 1657 } |
| 1658 |
| 1659 WebInspector._toolbarItemClicked = function(event) |
| 1660 { |
| 1661 var toolbarItem = event.currentTarget; |
| 1662 this.currentPanel = toolbarItem.panel; |
| 1663 } |
| 1664 |
| 1665 // This table maps MIME types to the Resource.Types which are valid for them. |
| 1666 // The following line: |
| 1667 // "text/html": {0: 1}, |
| 1668 // means that text/html is a valid MIME type for resources that have type |
| 1669 // WebInspector.Resource.Type.Document (which has a value of 0). |
| 1670 WebInspector.MIMETypes = { |
| 1671 "text/html": {0: true}, |
| 1672 "text/xml": {0: true}, |
| 1673 "text/plain": {0: true}, |
| 1674 "application/xhtml+xml": {0: true}, |
| 1675 "text/css": {1: true}, |
| 1676 "text/xsl": {1: true}, |
| 1677 "image/jpeg": {2: true}, |
| 1678 "image/png": {2: true}, |
| 1679 "image/gif": {2: true}, |
| 1680 "image/bmp": {2: true}, |
| 1681 "image/vnd.microsoft.icon": {2: true}, |
| 1682 "image/x-icon": {2: true}, |
| 1683 "image/x-xbitmap": {2: true}, |
| 1684 "font/ttf": {3: true}, |
| 1685 "font/opentype": {3: true}, |
| 1686 "application/x-font-type1": {3: true}, |
| 1687 "application/x-font-ttf": {3: true}, |
| 1688 "application/x-truetype-font": {3: true}, |
| 1689 "text/javascript": {4: true}, |
| 1690 "text/ecmascript": {4: true}, |
| 1691 "application/javascript": {4: true}, |
| 1692 "application/ecmascript": {4: true}, |
| 1693 "application/x-javascript": {4: true}, |
| 1694 "text/javascript1.1": {4: true}, |
| 1695 "text/javascript1.2": {4: true}, |
| 1696 "text/javascript1.3": {4: true}, |
| 1697 "text/jscript": {4: true}, |
| 1698 "text/livescript": {4: true}, |
| 1699 } |
OLD | NEW |