OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * @fileoverview Tools is a main class that wires all components of the |
| 7 * DevTools frontend together. It is also responsible for overriding existing |
| 8 * WebInspector functionality while it is getting upstreamed into WebCore. |
| 9 */ |
| 10 goog.provide('devtools.Tools'); |
| 11 |
| 12 goog.require('devtools.DebuggerAgent'); |
| 13 |
| 14 |
| 15 /** |
| 16 * Dispatches raw message from the host. |
| 17 * @param {string} remoteName |
| 18 * @prama {string} methodName |
| 19 * @param {string} param1, param2, param3 Arguments to dispatch. |
| 20 */ |
| 21 devtools$$dispatch = function(remoteName, methodName, param1, param2, param3) { |
| 22 remoteName = 'Remote' + remoteName.substring(0, remoteName.length - 8); |
| 23 var agent = window[remoteName]; |
| 24 if (!agent) { |
| 25 debugPrint('No remote agent "' + remoteName + '" found.'); |
| 26 return; |
| 27 } |
| 28 var method = agent[methodName]; |
| 29 if (!method) { |
| 30 debugPrint('No method "' + remoteName + '.' + methodName + '" found.'); |
| 31 return; |
| 32 } |
| 33 method.call(this, param1, param2, param3); |
| 34 }; |
| 35 |
| 36 |
| 37 devtools.ToolsAgent = function() { |
| 38 RemoteToolsAgent.DidDispatchOn = |
| 39 WebInspector.Callback.processCallback; |
| 40 RemoteToolsAgent.FrameNavigate = |
| 41 goog.bind(this.frameNavigate_, this); |
| 42 RemoteToolsAgent.DispatchOnClient = |
| 43 goog.bind(this.dispatchOnClient_, this); |
| 44 this.debuggerAgent_ = new devtools.DebuggerAgent(); |
| 45 }; |
| 46 |
| 47 |
| 48 /** |
| 49 * Resets tools agent to its initial state. |
| 50 */ |
| 51 devtools.ToolsAgent.prototype.reset = function() { |
| 52 DevToolsHost.reset(); |
| 53 this.debuggerAgent_.reset(); |
| 54 }; |
| 55 |
| 56 |
| 57 /** |
| 58 * @param {string} script Script exression to be evaluated in the context of the |
| 59 * inspected page. |
| 60 * @param {function(Object|string, boolean):undefined} opt_callback Function to |
| 61 * call with the result. |
| 62 */ |
| 63 devtools.ToolsAgent.prototype.evaluateJavaScript = function(script, |
| 64 opt_callback) { |
| 65 InspectorController.evaluate(script, opt_callback || function() {}); |
| 66 }; |
| 67 |
| 68 |
| 69 /** |
| 70 * @return {devtools.DebuggerAgent} Debugger agent instance. |
| 71 */ |
| 72 devtools.ToolsAgent.prototype.getDebuggerAgent = function() { |
| 73 return this.debuggerAgent_; |
| 74 }; |
| 75 |
| 76 |
| 77 /** |
| 78 * @param {string} url Url frame navigated to. |
| 79 * @see tools_agent.h |
| 80 * @private |
| 81 */ |
| 82 devtools.ToolsAgent.prototype.frameNavigate_ = function(url) { |
| 83 this.reset(); |
| 84 // Do not reset Profiles panel. |
| 85 var profiles = null; |
| 86 if ('profiles' in WebInspector.panels) { |
| 87 profiles = WebInspector.panels['profiles']; |
| 88 delete WebInspector.panels['profiles']; |
| 89 } |
| 90 WebInspector.reset(); |
| 91 if (profiles != null) { |
| 92 WebInspector.panels['profiles'] = profiles; |
| 93 } |
| 94 }; |
| 95 |
| 96 |
| 97 /** |
| 98 * @param {string} message Serialized call to be dispatched on WebInspector. |
| 99 * @private |
| 100 */ |
| 101 devtools.ToolsAgent.prototype.dispatchOnClient_ = function(message) { |
| 102 var args = JSON.parse(message); |
| 103 var methodName = args[0]; |
| 104 var parameters = args.slice(1); |
| 105 WebInspector[methodName].apply(WebInspector, parameters); |
| 106 }; |
| 107 |
| 108 |
| 109 /** |
| 110 * Evaluates js expression. |
| 111 * @param {string} expr |
| 112 */ |
| 113 devtools.ToolsAgent.prototype.evaluate = function(expr) { |
| 114 RemoteToolsAgent.evaluate(expr); |
| 115 }; |
| 116 |
| 117 |
| 118 /** |
| 119 * Enables / disables resources panel in the ui. |
| 120 * @param {boolean} enabled New panel status. |
| 121 */ |
| 122 WebInspector.setResourcesPanelEnabled = function(enabled) { |
| 123 InspectorController.resourceTrackingEnabled_ = enabled; |
| 124 WebInspector.panels.resources.reset(); |
| 125 }; |
| 126 |
| 127 |
| 128 /** |
| 129 * Prints string to the inspector console or shows alert if the console doesn't |
| 130 * exist. |
| 131 * @param {string} text |
| 132 */ |
| 133 function debugPrint(text) { |
| 134 var console = WebInspector.console; |
| 135 if (console) { |
| 136 console.addMessage(new WebInspector.ConsoleMessage( |
| 137 WebInspector.ConsoleMessage.MessageSource.JS, |
| 138 WebInspector.ConsoleMessage.MessageType.Log, |
| 139 WebInspector.ConsoleMessage.MessageLevel.Log, |
| 140 1, 'chrome://devtools/<internal>', undefined, -1, text)); |
| 141 } else { |
| 142 alert(text); |
| 143 } |
| 144 } |
| 145 |
| 146 |
| 147 /** |
| 148 * Global instance of the tools agent. |
| 149 * @type {devtools.ToolsAgent} |
| 150 */ |
| 151 devtools.tools = null; |
| 152 |
| 153 |
| 154 var context = {}; // Used by WebCore's inspector routines. |
| 155 |
| 156 /////////////////////////////////////////////////////////////////////////////// |
| 157 // Here and below are overrides to existing WebInspector methods only. |
| 158 // TODO(pfeldman): Patch WebCore and upstream changes. |
| 159 var oldLoaded = WebInspector.loaded; |
| 160 WebInspector.loaded = function() { |
| 161 devtools.tools = new devtools.ToolsAgent(); |
| 162 devtools.tools.reset(); |
| 163 |
| 164 Preferences.ignoreWhitespace = false; |
| 165 Preferences.samplingCPUProfiler = true; |
| 166 Preferences.heapProfilerPresent = true; |
| 167 oldLoaded.call(this); |
| 168 |
| 169 // Hide dock button on Mac OS. |
| 170 // TODO(pfeldman): remove once Mac OS docking is implemented. |
| 171 if (InspectorController.platform().indexOf('mac') == 0) { |
| 172 document.getElementById('dock-status-bar-item').addStyleClass('hidden'); |
| 173 } |
| 174 |
| 175 // Mute refresh action. |
| 176 document.addEventListener("keydown", function(event) { |
| 177 if (event.keyIdentifier == 'F5') { |
| 178 event.preventDefault(); |
| 179 } else if (event.keyIdentifier == 'U+0052' /* 'R' */ && |
| 180 (event.ctrlKey || event.metaKey)) { |
| 181 event.preventDefault(); |
| 182 } |
| 183 }, true); |
| 184 |
| 185 DevToolsHost.loaded(); |
| 186 }; |
| 187 |
| 188 |
| 189 /** |
| 190 * This override is necessary for adding script source asynchronously. |
| 191 * @override |
| 192 */ |
| 193 WebInspector.ScriptView.prototype.setupSourceFrameIfNeeded = function() { |
| 194 if (!this._frameNeedsSetup) { |
| 195 return; |
| 196 } |
| 197 |
| 198 this.attach(); |
| 199 |
| 200 if (this.script.source) { |
| 201 this.didResolveScriptSource_(); |
| 202 } else { |
| 203 var self = this; |
| 204 devtools.tools.getDebuggerAgent().resolveScriptSource( |
| 205 this.script.sourceID, |
| 206 function(source) { |
| 207 self.script.source = source || |
| 208 WebInspector.UIString('<source is not available>'); |
| 209 self.didResolveScriptSource_(); |
| 210 }); |
| 211 } |
| 212 }; |
| 213 |
| 214 |
| 215 /** |
| 216 * Performs source frame setup when script source is aready resolved. |
| 217 */ |
| 218 WebInspector.ScriptView.prototype.didResolveScriptSource_ = function() { |
| 219 if (!InspectorController.addSourceToFrame( |
| 220 "text/javascript", this.script.source, this.sourceFrame.element)) { |
| 221 return; |
| 222 } |
| 223 |
| 224 delete this._frameNeedsSetup; |
| 225 |
| 226 this.sourceFrame.addEventListener( |
| 227 "syntax highlighting complete", this._syntaxHighlightingComplete, this); |
| 228 this.sourceFrame.syntaxHighlightJavascript(); |
| 229 }; |
| 230 |
| 231 |
| 232 /** |
| 233 * @param {string} type Type of the the property value('object' or 'function'). |
| 234 * @param {string} className Class name of the property value. |
| 235 * @constructor |
| 236 */ |
| 237 WebInspector.UnresolvedPropertyValue = function(type, className) { |
| 238 this.type = type; |
| 239 this.className = className; |
| 240 }; |
| 241 |
| 242 |
| 243 /** |
| 244 * This function overrides standard searchableViews getters to perform search |
| 245 * only in the current view (other views are loaded asynchronously, no way to |
| 246 * search them yet). |
| 247 */ |
| 248 WebInspector.searchableViews_ = function() { |
| 249 var views = []; |
| 250 const visibleView = this.visibleView; |
| 251 if (visibleView && visibleView.performSearch) { |
| 252 views.push(visibleView); |
| 253 } |
| 254 return views; |
| 255 }; |
| 256 |
| 257 |
| 258 /** |
| 259 * @override |
| 260 */ |
| 261 WebInspector.ResourcesPanel.prototype.__defineGetter__( |
| 262 'searchableViews', |
| 263 WebInspector.searchableViews_); |
| 264 |
| 265 |
| 266 /** |
| 267 * @override |
| 268 */ |
| 269 WebInspector.ScriptsPanel.prototype.__defineGetter__( |
| 270 'searchableViews', |
| 271 WebInspector.searchableViews_); |
| 272 |
| 273 |
| 274 (function() { |
| 275 var oldShow = WebInspector.ScriptsPanel.prototype.show; |
| 276 WebInspector.ScriptsPanel.prototype.show = function() { |
| 277 devtools.tools.getDebuggerAgent().initUI(); |
| 278 this.enableToggleButton.visible = false; |
| 279 oldShow.call(this); |
| 280 }; |
| 281 })(); |
| 282 |
| 283 |
| 284 (function InterceptProfilesPanelEvents() { |
| 285 var oldShow = WebInspector.ProfilesPanel.prototype.show; |
| 286 WebInspector.ProfilesPanel.prototype.show = function() { |
| 287 devtools.tools.getDebuggerAgent().initializeProfiling(); |
| 288 this.enableToggleButton.visible = false; |
| 289 oldShow.call(this); |
| 290 // Show is called on every show event of a panel, so |
| 291 // we only need to intercept it once. |
| 292 WebInspector.ProfilesPanel.prototype.show = oldShow; |
| 293 }; |
| 294 })(); |
| 295 |
| 296 |
| 297 /* |
| 298 * @override |
| 299 * TODO(mnaganov): Restore l10n when it will be agreed that it is needed. |
| 300 */ |
| 301 WebInspector.UIString = function(string) { |
| 302 return String.vsprintf(string, Array.prototype.slice.call(arguments, 1)); |
| 303 }; |
| 304 |
| 305 |
| 306 // There is no clear way of setting frame title yet. So sniffing main resource |
| 307 // load. |
| 308 (function OverrideUpdateResource() { |
| 309 var originalUpdateResource = WebInspector.updateResource; |
| 310 WebInspector.updateResource = function(identifier, payload) { |
| 311 originalUpdateResource.call(this, identifier, payload); |
| 312 var resource = this.resources[identifier]; |
| 313 if (resource && resource.mainResource && resource.finished) { |
| 314 document.title = |
| 315 WebInspector.UIString('Developer Tools - %s', resource.url); |
| 316 } |
| 317 }; |
| 318 })(); |
| 319 |
| 320 |
| 321 // Highlight extension content scripts in the scripts list. |
| 322 (function () { |
| 323 var original = WebInspector.ScriptsPanel.prototype._addScriptToFilesMenu; |
| 324 WebInspector.ScriptsPanel.prototype._addScriptToFilesMenu = function(script) { |
| 325 var result = original.apply(this, arguments); |
| 326 var debuggerAgent = devtools.tools.getDebuggerAgent(); |
| 327 var type = debuggerAgent.getScriptContextType(script.sourceID); |
| 328 var option = script.filesSelectOption; |
| 329 if (type == 'injected' && option) { |
| 330 option.addStyleClass('injected'); |
| 331 } |
| 332 return result; |
| 333 }; |
| 334 })(); |
| 335 |
| 336 |
| 337 /** Pending WebKit upstream by apavlov). Fixes iframe vs drag problem. */ |
| 338 (function() { |
| 339 var originalDragStart = WebInspector.elementDragStart; |
| 340 WebInspector.elementDragStart = function(element) { |
| 341 var glassPane = document.createElement("div"); |
| 342 glassPane.style.cssText = |
| 343 'position:absolute;width:100%;height:100%;opacity:0;z-index:1'; |
| 344 glassPane.id = 'glass-pane-for-drag'; |
| 345 element.parentElement.appendChild(glassPane); |
| 346 |
| 347 originalDragStart.apply(this, arguments); |
| 348 }; |
| 349 |
| 350 var originalDragEnd = WebInspector.elementDragEnd; |
| 351 WebInspector.elementDragEnd = function() { |
| 352 originalDragEnd.apply(this, arguments); |
| 353 |
| 354 var glassPane = document.getElementById('glass-pane-for-drag'); |
| 355 glassPane.parentElement.removeChild(glassPane); |
| 356 }; |
| 357 })(); |
| 358 |
| 359 |
| 360 (function () { |
| 361 var orig = InjectedScriptAccess.getProperties; |
| 362 InjectedScriptAccess.getProperties = function( |
| 363 objectProxy, ignoreHasOwnProperty, callback) { |
| 364 if (objectProxy.isScope) { |
| 365 devtools.tools.getDebuggerAgent().resolveScope(objectProxy.objectId, |
| 366 callback); |
| 367 } else if (objectProxy.isV8Ref) { |
| 368 devtools.tools.getDebuggerAgent().resolveChildren(objectProxy.objectId, |
| 369 callback, false); |
| 370 } else { |
| 371 orig.apply(this, arguments); |
| 372 } |
| 373 }; |
| 374 })(); |
| 375 |
| 376 |
| 377 InjectedScriptAccess.evaluateInCallFrame = function(callFrameId, code, |
| 378 objectGroup, callback) |
| 379 { |
| 380 //TODO(pfeldman): remove once 49084 is rolled. |
| 381 if (!callback) { |
| 382 callback = objectGroup; |
| 383 } |
| 384 devtools.tools.getDebuggerAgent().evaluateInCallFrame( |
| 385 callFrameId, code, callback); |
| 386 }; |
| 387 |
| 388 |
| 389 WebInspector.resourceTrackingWasEnabled = function() |
| 390 { |
| 391 InspectorController.resourceTrackingEnabled_ = true; |
| 392 this.panels.resources.resourceTrackingWasEnabled(); |
| 393 }; |
| 394 |
| 395 WebInspector.resourceTrackingWasDisabled = function() |
| 396 { |
| 397 InspectorController.resourceTrackingEnabled_ = false; |
| 398 this.panels.resources.resourceTrackingWasDisabled(); |
| 399 }; |
| 400 |
| 401 (function() { |
| 402 var orig = WebInspector.ConsoleMessage.prototype.setMessageBody; |
| 403 WebInspector.ConsoleMessage.prototype.setMessageBody = function(args) { |
| 404 for (var i = 0; i < args.length; ++i) { |
| 405 if (typeof args[i] == "string") { |
| 406 args[i] = WebInspector.ObjectProxy.wrapPrimitiveValue(args[i]); |
| 407 } |
| 408 } |
| 409 orig.call(this, args); |
| 410 }; |
| 411 })(); |
| 412 |
| 413 // Temporary fix for http://crbug/23260. |
| 414 (function() { |
| 415 var orig = WebInspector.ResourcesPanel.prototype._createResourceView; |
| 416 WebInspector.ResourcesPanel.prototype._createResourceView = function( |
| 417 resource) { |
| 418 if (resource.type == undefined && resource.url) { |
| 419 if (resource.url.search('\.js$') != -1) { |
| 420 resource.type = WebInspector.Resource.Type.Script; |
| 421 } else if (resource.url.search('\.html$') != -1) { |
| 422 resource.type = WebInspector.Resource.Type.Document; |
| 423 } |
| 424 } |
| 425 |
| 426 return orig.apply(this, arguments); |
| 427 }; |
| 428 })(); |
| 429 |
| 430 |
| 431 // Temporary workaround for a patch from WebKit bug 30328. |
| 432 // TODO(mnaganov): Remove when after WebKit roll. |
| 433 if (!('addProfile' in WebInspector)) { |
| 434 WebInspector.addProfile = function(profile) { |
| 435 WebInspector.__fullProfiles = WebInspector.__fullProfiles || {}; |
| 436 WebInspector.__fullProfiles[profile.uid] = profile; |
| 437 WebInspector.addProfileHeader(profile); |
| 438 }; |
| 439 } |
| 440 |
| 441 |
| 442 (function() { |
| 443 var orig = InjectedScriptAccess.getCompletions; |
| 444 InjectedScriptAccess.getCompletions = function(expressionString, |
| 445 includeInspectorCommandLineAPI, callFrameId, reportCompletions) { |
| 446 if (goog.isDef(callFrameId)) { |
| 447 devtools.tools.getDebuggerAgent().resolveCompletionsOnFrame( |
| 448 expressionString, callFrameId, reportCompletions); |
| 449 } else { |
| 450 return orig.apply(this, arguments); |
| 451 } |
| 452 }; |
| 453 })(); |
| 454 |
OLD | NEW |