OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright | |
11 * notice, this list of conditions and the following disclaimer in the | |
12 * documentation and/or other materials provided with the distribution. | |
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
14 * its contributors may be used to endorse or promote products derived | |
15 * from this software without specific prior written permission. | |
16 * | |
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 */ | |
28 | |
29 WebInspector.Console = function() | |
30 { | |
31 this.messages = []; | |
32 | |
33 WebInspector.View.call(this, document.getElementById("console")); | |
34 | |
35 this.messagesElement = document.getElementById("console-messages"); | |
36 this.messagesElement.addEventListener("selectstart", this._messagesSelectSta
rt.bind(this), false); | |
37 this.messagesElement.addEventListener("click", this._messagesClicked.bind(th
is), true); | |
38 | |
39 this.promptElement = document.getElementById("console-prompt"); | |
40 this.promptElement.handleKeyEvent = this._promptKeyDown.bind(this); | |
41 this.prompt = new WebInspector.TextPrompt(this.promptElement, this.completio
ns.bind(this), " .=:[({;"); | |
42 | |
43 this.toggleButton = document.getElementById("console-status-bar-item"); | |
44 this.toggleButton.title = WebInspector.UIString("Show console."); | |
45 this.toggleButton.addEventListener("click", this._toggleButtonClicked.bind(t
his), false); | |
46 | |
47 this.clearButton = document.getElementById("clear-console-status-bar-item"); | |
48 this.clearButton.title = WebInspector.UIString("Clear console log."); | |
49 this.clearButton.addEventListener("click", this._clearButtonClicked.bind(thi
s), false); | |
50 | |
51 this.topGroup = new WebInspector.ConsoleGroup(null, 0); | |
52 this.messagesElement.insertBefore(this.topGroup.element, this.promptElement)
; | |
53 this.groupLevel = 0; | |
54 this.currentGroup = this.topGroup; | |
55 | |
56 document.getElementById("main-status-bar").addEventListener("mousedown", thi
s._startStatusBarDragging.bind(this), true); | |
57 } | |
58 | |
59 WebInspector.Console.prototype = { | |
60 show: function() | |
61 { | |
62 if (this._animating || this.visible) | |
63 return; | |
64 | |
65 WebInspector.View.prototype.show.call(this); | |
66 | |
67 this._animating = true; | |
68 | |
69 this.toggleButton.addStyleClass("toggled-on"); | |
70 this.toggleButton.title = WebInspector.UIString("Hide console."); | |
71 | |
72 document.body.addStyleClass("console-visible"); | |
73 | |
74 var anchoredItems = document.getElementById("anchored-status-bar-items")
; | |
75 | |
76 var animations = [ | |
77 {element: document.getElementById("main"), end: {bottom: this.elemen
t.offsetHeight}}, | |
78 {element: document.getElementById("main-status-bar"), start: {"paddi
ng-left": anchoredItems.offsetWidth - 1}, end: {"padding-left": 0}}, | |
79 {element: document.getElementById("other-console-status-bar-items"),
start: {opacity: 0}, end: {opacity: 1}} | |
80 ]; | |
81 | |
82 var consoleStatusBar = document.getElementById("console-status-bar"); | |
83 consoleStatusBar.insertBefore(anchoredItems, consoleStatusBar.firstChild
); | |
84 | |
85 function animationFinished() | |
86 { | |
87 if ("updateStatusBarItems" in WebInspector.currentPanel) | |
88 WebInspector.currentPanel.updateStatusBarItems(); | |
89 WebInspector.currentFocusElement = this.promptElement; | |
90 delete this._animating; | |
91 } | |
92 | |
93 WebInspector.animateStyle(animations, window.event && window.event.shift
Key ? 2000 : 250, animationFinished.bind(this)); | |
94 | |
95 if (!this.prompt.isCaretInsidePrompt()) | |
96 this.prompt.moveCaretToEndOfPrompt(); | |
97 }, | |
98 | |
99 hide: function() | |
100 { | |
101 if (this._animating || !this.visible) | |
102 return; | |
103 | |
104 WebInspector.View.prototype.hide.call(this); | |
105 | |
106 this._animating = true; | |
107 | |
108 this.toggleButton.removeStyleClass("toggled-on"); | |
109 this.toggleButton.title = WebInspector.UIString("Show console."); | |
110 | |
111 if (this.element === WebInspector.currentFocusElement || this.element.is
Ancestor(WebInspector.currentFocusElement)) | |
112 WebInspector.currentFocusElement = WebInspector.previousFocusElement
; | |
113 | |
114 var anchoredItems = document.getElementById("anchored-status-bar-items")
; | |
115 | |
116 // Temporally set properties and classes to mimic the post-animation val
ues so panels | |
117 // like Elements in their updateStatusBarItems call will size things to
fit the final location. | |
118 document.getElementById("main-status-bar").style.setProperty("padding-le
ft", (anchoredItems.offsetWidth - 1) + "px"); | |
119 document.body.removeStyleClass("console-visible"); | |
120 if ("updateStatusBarItems" in WebInspector.currentPanel) | |
121 WebInspector.currentPanel.updateStatusBarItems(); | |
122 document.body.addStyleClass("console-visible"); | |
123 | |
124 var animations = [ | |
125 {element: document.getElementById("main"), end: {bottom: 0}}, | |
126 {element: document.getElementById("main-status-bar"), start: {"paddi
ng-left": 0}, end: {"padding-left": anchoredItems.offsetWidth - 1}}, | |
127 {element: document.getElementById("other-console-status-bar-items"),
start: {opacity: 1}, end: {opacity: 0}} | |
128 ]; | |
129 | |
130 function animationFinished() | |
131 { | |
132 var mainStatusBar = document.getElementById("main-status-bar"); | |
133 mainStatusBar.insertBefore(anchoredItems, mainStatusBar.firstChild); | |
134 mainStatusBar.style.removeProperty("padding-left"); | |
135 document.body.removeStyleClass("console-visible"); | |
136 delete this._animating; | |
137 } | |
138 | |
139 WebInspector.animateStyle(animations, window.event && window.event.shift
Key ? 2000 : 250, animationFinished.bind(this)); | |
140 }, | |
141 | |
142 addMessage: function(msg) | |
143 { | |
144 if (msg instanceof WebInspector.ConsoleMessage && !(msg instanceof WebIn
spector.ConsoleCommandResult)) { | |
145 msg.totalRepeatCount = msg.repeatCount; | |
146 msg.repeatDelta = msg.repeatCount; | |
147 | |
148 var messageRepeated = false; | |
149 | |
150 if (msg.isEqual && msg.isEqual(this.previousMessage)) { | |
151 // Because sometimes we get a large number of repeated messages
and sometimes | |
152 // we get them one at a time, we need to know the difference bet
ween how many | |
153 // repeats we used to have and how many we have now. | |
154 msg.repeatDelta -= this.previousMessage.totalRepeatCount; | |
155 | |
156 if (!isNaN(this.repeatCountBeforeCommand)) | |
157 msg.repeatCount -= this.repeatCountBeforeCommand; | |
158 | |
159 if (!this.commandSincePreviousMessage) { | |
160 // Recreate the previous message element to reset the repeat
count. | |
161 var messagesElement = this.currentGroup.messagesElement; | |
162 messagesElement.removeChild(messagesElement.lastChild); | |
163 messagesElement.appendChild(msg.toMessageElement()); | |
164 | |
165 messageRepeated = true; | |
166 } | |
167 } else | |
168 delete this.repeatCountBeforeCommand; | |
169 | |
170 // Increment the error or warning count | |
171 switch (msg.level) { | |
172 case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
173 WebInspector.warnings += msg.repeatDelta; | |
174 break; | |
175 case WebInspector.ConsoleMessage.MessageLevel.Error: | |
176 WebInspector.errors += msg.repeatDelta; | |
177 break; | |
178 } | |
179 | |
180 // Add message to the resource panel | |
181 if (msg.url in WebInspector.resourceURLMap) { | |
182 msg.resource = WebInspector.resourceURLMap[msg.url]; | |
183 if (WebInspector.panels.resources) | |
184 WebInspector.panels.resources.addMessageToResource(msg.resou
rce, msg); | |
185 } | |
186 | |
187 this.commandSincePreviousMessage = false; | |
188 this.previousMessage = msg; | |
189 | |
190 if (messageRepeated) | |
191 return; | |
192 } else if (msg instanceof WebInspector.ConsoleCommand) { | |
193 if (this.previousMessage) { | |
194 this.commandSincePreviousMessage = true; | |
195 this.repeatCountBeforeCommand = this.previousMessage.totalRepeat
Count; | |
196 } | |
197 } | |
198 | |
199 this.messages.push(msg); | |
200 | |
201 if (msg.level === WebInspector.ConsoleMessage.MessageLevel.EndGroup) { | |
202 if (this.groupLevel < 1) | |
203 return; | |
204 | |
205 this.groupLevel--; | |
206 | |
207 this.currentGroup = this.currentGroup.parentGroup; | |
208 } else { | |
209 if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGrou
p) { | |
210 this.groupLevel++; | |
211 | |
212 var group = new WebInspector.ConsoleGroup(this.currentGroup, thi
s.groupLevel); | |
213 this.currentGroup.messagesElement.appendChild(group.element); | |
214 this.currentGroup = group; | |
215 } | |
216 | |
217 this.currentGroup.addMessage(msg); | |
218 } | |
219 | |
220 this.promptElement.scrollIntoView(false); | |
221 }, | |
222 | |
223 clearMessages: function(clearInspectorController) | |
224 { | |
225 if (clearInspectorController) | |
226 InspectorController.clearMessages(); | |
227 if (WebInspector.panels.resources) | |
228 WebInspector.panels.resources.clearMessages(); | |
229 | |
230 this.messages = []; | |
231 | |
232 this.groupLevel = 0; | |
233 this.currentGroup = this.topGroup; | |
234 this.topGroup.messagesElement.removeChildren(); | |
235 | |
236 WebInspector.errors = 0; | |
237 WebInspector.warnings = 0; | |
238 | |
239 delete this.commandSincePreviousMessage; | |
240 delete this.repeatCountBeforeCommand; | |
241 delete this.previousMessage; | |
242 }, | |
243 | |
244 completions: function(wordRange, bestMatchOnly) | |
245 { | |
246 // Pass less stop characters to rangeOfWord so the range will be a more
complete expression. | |
247 const expressionStopCharacters = " =:{;"; | |
248 var expressionRange = wordRange.startContainer.rangeOfWord(wordRange.sta
rtOffset, expressionStopCharacters, this.promptElement, "backward"); | |
249 var expressionString = expressionRange.toString(); | |
250 var lastIndex = expressionString.length - 1; | |
251 | |
252 var dotNotation = (expressionString[lastIndex] === "."); | |
253 var bracketNotation = (expressionString[lastIndex] === "["); | |
254 | |
255 if (dotNotation || bracketNotation) | |
256 expressionString = expressionString.substr(0, lastIndex); | |
257 | |
258 var prefix = wordRange.toString(); | |
259 if (!expressionString && !prefix) | |
260 return; | |
261 | |
262 var result; | |
263 if (expressionString) { | |
264 try { | |
265 result = this._evalInInspectedWindow(expressionString); | |
266 } catch(e) { | |
267 // Do nothing, the prefix will be considered a window property. | |
268 } | |
269 } else { | |
270 // There is no expressionString, so the completion should happen aga
inst global properties. | |
271 // Or if the debugger is paused, against properties in scope of the
selected call frame. | |
272 if (WebInspector.panels.scripts && WebInspector.panels.scripts.pause
d) | |
273 result = WebInspector.panels.scripts.variablesInScopeForSelected
CallFrame(); | |
274 else | |
275 result = InspectorController.inspectedWindow(); | |
276 } | |
277 | |
278 if (bracketNotation) { | |
279 if (prefix.length && prefix[0] === "'") | |
280 var quoteUsed = "'"; | |
281 else | |
282 var quoteUsed = "\""; | |
283 } | |
284 | |
285 var results = []; | |
286 var properties = Object.sortedProperties(result); | |
287 for (var i = 0; i < properties.length; ++i) { | |
288 var property = properties[i]; | |
289 | |
290 if (dotNotation && !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(property)) | |
291 continue; | |
292 | |
293 if (bracketNotation) { | |
294 if (!/^[0-9]+$/.test(property)) | |
295 property = quoteUsed + property.escapeCharacters(quoteUsed +
"\\") + quoteUsed; | |
296 property += "]"; | |
297 } | |
298 | |
299 if (property.length < prefix.length) | |
300 continue; | |
301 if (property.indexOf(prefix) !== 0) | |
302 continue; | |
303 | |
304 results.push(property); | |
305 if (bestMatchOnly) | |
306 break; | |
307 } | |
308 | |
309 return results; | |
310 }, | |
311 | |
312 _toggleButtonClicked: function() | |
313 { | |
314 this.visible = !this.visible; | |
315 }, | |
316 | |
317 _clearButtonClicked: function() | |
318 { | |
319 this.clearMessages(true); | |
320 }, | |
321 | |
322 _messagesSelectStart: function(event) | |
323 { | |
324 if (this._selectionTimeout) | |
325 clearTimeout(this._selectionTimeout); | |
326 | |
327 this.prompt.clearAutoComplete(); | |
328 | |
329 function moveBackIfOutside() | |
330 { | |
331 delete this._selectionTimeout; | |
332 if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCo
llapsed) | |
333 this.prompt.moveCaretToEndOfPrompt(); | |
334 this.prompt.autoCompleteSoon(); | |
335 } | |
336 | |
337 this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100); | |
338 }, | |
339 | |
340 _messagesClicked: function(event) | |
341 { | |
342 var link = event.target.enclosingNodeOrSelfWithNodeName("a"); | |
343 if (!link || !link.representedNode) | |
344 return; | |
345 | |
346 WebInspector.updateFocusedNode(link.representedNode); | |
347 event.stopPropagation(); | |
348 event.preventDefault(); | |
349 }, | |
350 | |
351 _promptKeyDown: function(event) | |
352 { | |
353 switch (event.keyIdentifier) { | |
354 case "Enter": | |
355 this._enterKeyPressed(event); | |
356 return; | |
357 } | |
358 | |
359 this.prompt.handleKeyEvent(event); | |
360 }, | |
361 | |
362 _startStatusBarDragging: function(event) | |
363 { | |
364 if (!this.visible || event.target !== document.getElementById("main-stat
us-bar")) | |
365 return; | |
366 | |
367 WebInspector.elementDragStart(document.getElementById("main-status-bar")
, this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), eve
nt, "row-resize"); | |
368 | |
369 this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop; | |
370 | |
371 event.stopPropagation(); | |
372 }, | |
373 | |
374 _statusBarDragging: function(event) | |
375 { | |
376 var mainElement = document.getElementById("main"); | |
377 | |
378 var height = window.innerHeight - event.pageY + this._statusBarDragOffse
t; | |
379 height = Number.constrain(height, Preferences.minConsoleHeight, window.i
nnerHeight - mainElement.totalOffsetTop - Preferences.minConsoleHeight); | |
380 | |
381 mainElement.style.bottom = height + "px"; | |
382 this.element.style.height = height + "px"; | |
383 | |
384 event.preventDefault(); | |
385 event.stopPropagation(); | |
386 }, | |
387 | |
388 _endStatusBarDragging: function(event) | |
389 { | |
390 WebInspector.elementDragEnd(event); | |
391 | |
392 delete this._statusBarDragOffset; | |
393 | |
394 event.stopPropagation(); | |
395 }, | |
396 | |
397 _evalInInspectedWindow: function(expression) | |
398 { | |
399 if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) | |
400 return WebInspector.panels.scripts.evaluateInSelectedCallFrame(expre
ssion); | |
401 | |
402 var inspectedWindow = InspectorController.inspectedWindow(); | |
403 if (!inspectedWindow._inspectorCommandLineAPI) { | |
404 inspectedWindow.eval("window._inspectorCommandLineAPI = { \ | |
405 $: function() { return document.getElementById.apply(document, a
rguments) }, \ | |
406 $$: function() { return document.querySelectorAll.apply(document
, arguments) }, \ | |
407 $x: function(xpath, context) { \ | |
408 var nodes = []; \ | |
409 try { \ | |
410 var doc = context || document; \ | |
411 var results = doc.evaluate(xpath, doc, null, XPathResult
.ANY_TYPE, null); \ | |
412 var node; \ | |
413 while (node = results.iterateNext()) nodes.push(node); \ | |
414 } catch (e) {} \ | |
415 return nodes; \ | |
416 }, \ | |
417 dir: function() { return console.dir.apply(console, arguments) }
, \ | |
418 dirxml: function() { return console.dirxml.apply(console, argume
nts) }, \ | |
419 keys: function(o) { var a = []; for (k in o) a.push(k); return a
; }, \ | |
420 values: function(o) { var a = []; for (k in o) a.push(o[k]); ret
urn a; }, \ | |
421 profile: function() { return console.profile.apply(console, argu
ments) }, \ | |
422 profileEnd: function() { return console.profileEnd.apply(console
, arguments) } \ | |
423 };"); | |
424 | |
425 inspectedWindow._inspectorCommandLineAPI.clear = InspectorController
.wrapCallback(this.clearMessages.bind(this)); | |
426 } | |
427 | |
428 // Surround the expression in with statements to inject our command line
API so that | |
429 // the window object properties still take more precedent than our API f
unctions. | |
430 expression = "with (window._inspectorCommandLineAPI) { with (window) { "
+ expression + " } }"; | |
431 | |
432 return inspectedWindow.eval(expression); | |
433 }, | |
434 | |
435 _enterKeyPressed: function(event) | |
436 { | |
437 if (event.altKey) | |
438 return; | |
439 | |
440 event.preventDefault(); | |
441 event.stopPropagation(); | |
442 | |
443 this.prompt.clearAutoComplete(true); | |
444 | |
445 var str = this.prompt.text; | |
446 if (!str.length) | |
447 return; | |
448 | |
449 var commandMessage = new WebInspector.ConsoleCommand(str); | |
450 this.addMessage(commandMessage); | |
451 | |
452 var result; | |
453 var exception = false; | |
454 try { | |
455 result = this._evalInInspectedWindow(str); | |
456 } catch(e) { | |
457 result = e; | |
458 exception = true; | |
459 } | |
460 | |
461 this.prompt.history.push(str); | |
462 this.prompt.historyOffset = 0; | |
463 this.prompt.text = ""; | |
464 | |
465 this.addMessage(new WebInspector.ConsoleCommandResult(result, exception,
commandMessage)); | |
466 }, | |
467 | |
468 _format: function(output, forceObjectFormat) | |
469 { | |
470 var type = (forceObjectFormat ? "object" : Object.type(output, Inspector
Controller.inspectedWindow())); | |
471 | |
472 // We don't perform any special formatting on these types, so we just | |
473 // pass them through the simple _formatvalue function. | |
474 var undecoratedTypes = { | |
475 "undefined": 1, | |
476 "null": 1, | |
477 "boolean": 1, | |
478 "number": 1, | |
479 "date": 1, | |
480 "function": 1, | |
481 }; | |
482 | |
483 var formatter; | |
484 if (forceObjectFormat) | |
485 formatter = "_formatobject"; | |
486 else if (type in undecoratedTypes) | |
487 formatter = "_formatvalue"; | |
488 else { | |
489 formatter = "_format" + type; | |
490 if (!(formatter in this)) { | |
491 formatter = "_formatobject"; | |
492 type = "object"; | |
493 } | |
494 } | |
495 | |
496 var span = document.createElement("span"); | |
497 span.addStyleClass("console-formatted-" + type); | |
498 this[formatter](output, span); | |
499 return span; | |
500 }, | |
501 | |
502 _formatvalue: function(val, elem) | |
503 { | |
504 elem.appendChild(document.createTextNode(val)); | |
505 }, | |
506 | |
507 _formatstring: function(str, elem) | |
508 { | |
509 elem.appendChild(document.createTextNode("\"" + str + "\"")); | |
510 }, | |
511 | |
512 _formatregexp: function(re, elem) | |
513 { | |
514 var formatted = String(re).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[g
im]*)$/, "$1").substring(1); | |
515 elem.appendChild(document.createTextNode(formatted)); | |
516 }, | |
517 | |
518 _formatarray: function(arr, elem) | |
519 { | |
520 elem.appendChild(document.createTextNode("[")); | |
521 for (var i = 0; i < arr.length; ++i) { | |
522 elem.appendChild(this._format(arr[i])); | |
523 if (i < arr.length - 1) | |
524 elem.appendChild(document.createTextNode(", ")); | |
525 } | |
526 elem.appendChild(document.createTextNode("]")); | |
527 }, | |
528 | |
529 _formatnode: function(node, elem) | |
530 { | |
531 var treeOutline = new WebInspector.ElementsTreeOutline(); | |
532 treeOutline.rootDOMNode = node; | |
533 treeOutline.element.addStyleClass("outline-disclosure"); | |
534 if (!treeOutline.children[0].hasChildren) | |
535 treeOutline.element.addStyleClass("single-node"); | |
536 elem.appendChild(treeOutline.element); | |
537 }, | |
538 | |
539 _formatobject: function(obj, elem) | |
540 { | |
541 elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, null, nul
l, null, true).element); | |
542 }, | |
543 | |
544 _formaterror: function(obj, elem) | |
545 { | |
546 var messageElement = document.createElement("span"); | |
547 messageElement.className = "error-message"; | |
548 messageElement.textContent = obj.name + ": " + obj.message; | |
549 elem.appendChild(messageElement); | |
550 | |
551 if (obj.sourceURL) { | |
552 var urlElement = document.createElement("a"); | |
553 urlElement.className = "webkit-html-resource-link"; | |
554 urlElement.href = obj.sourceURL; | |
555 urlElement.lineNumber = obj.line; | |
556 urlElement.preferredPanel = "scripts"; | |
557 | |
558 if (obj.line > 0) | |
559 urlElement.textContent = WebInspector.displayNameForURL(obj.sour
ceURL) + ":" + obj.line; | |
560 else | |
561 urlElement.textContent = WebInspector.displayNameForURL(obj.sour
ceURL); | |
562 | |
563 elem.appendChild(document.createTextNode(" (")); | |
564 elem.appendChild(urlElement); | |
565 elem.appendChild(document.createTextNode(")")); | |
566 } | |
567 }, | |
568 } | |
569 | |
570 WebInspector.Console.prototype.__proto__ = WebInspector.View.prototype; | |
571 | |
572 WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, rep
eatCount) | |
573 { | |
574 this.source = source; | |
575 this.level = level; | |
576 this.line = line; | |
577 this.url = url; | |
578 this.groupLevel = groupLevel; | |
579 this.repeatCount = repeatCount; | |
580 if (arguments.length > 6) | |
581 this.setMessageBody(Array.prototype.slice.call(arguments, 6)); | |
582 } | |
583 | |
584 WebInspector.ConsoleMessage.prototype = { | |
585 setMessageBody: function(args) | |
586 { | |
587 switch (this.level) { | |
588 case WebInspector.ConsoleMessage.MessageLevel.Trace: | |
589 var span = document.createElement("span"); | |
590 span.addStyleClass("console-formatted-trace"); | |
591 var stack = Array.prototype.slice.call(args); | |
592 var funcNames = stack.map(function(f) { | |
593 return f || WebInspector.UIString("(anonymous function)"); | |
594 }); | |
595 span.appendChild(document.createTextNode(funcNames.join("\n"))); | |
596 this.formattedMessage = span; | |
597 break; | |
598 case WebInspector.ConsoleMessage.MessageLevel.Object: | |
599 this.formattedMessage = this._format(["%O", args[0]]); | |
600 break; | |
601 default: | |
602 this.formattedMessage = this._format(args); | |
603 break; | |
604 } | |
605 | |
606 // This is used for inline message bubbles in SourceFrames, or other pla
in-text representations. | |
607 this.message = this.formattedMessage.textContent; | |
608 }, | |
609 | |
610 isErrorOrWarning: function() | |
611 { | |
612 return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning
|| this.level === WebInspector.ConsoleMessage.MessageLevel.Error); | |
613 }, | |
614 | |
615 _format: function(parameters) | |
616 { | |
617 var formattedResult = document.createElement("span"); | |
618 | |
619 if (!parameters.length) | |
620 return formattedResult; | |
621 | |
622 function formatForConsole(obj) | |
623 { | |
624 return WebInspector.console._format(obj); | |
625 } | |
626 | |
627 function formatAsObjectForConsole(obj) | |
628 { | |
629 return WebInspector.console._format(obj, true); | |
630 } | |
631 | |
632 if (Object.type(parameters[0], InspectorController.inspectedWindow()) ==
= "string") { | |
633 var formatters = {} | |
634 for (var i in String.standardFormatters) | |
635 formatters[i] = String.standardFormatters[i]; | |
636 | |
637 // Firebug uses %o for formatting objects. | |
638 formatters.o = formatForConsole; | |
639 // Firebug allows both %i and %d for formatting integers. | |
640 formatters.i = formatters.d; | |
641 // Support %O to force object formating, instead of the type-based %
o formatting. | |
642 formatters.O = formatAsObjectForConsole; | |
643 | |
644 function append(a, b) | |
645 { | |
646 if (!(b instanceof Node)) | |
647 a.appendChild(WebInspector.linkifyStringAsFragment(b.toStrin
g())); | |
648 else | |
649 a.appendChild(b); | |
650 return a; | |
651 } | |
652 | |
653 var result = String.format(parameters[0], parameters.slice(1), forma
tters, formattedResult, append); | |
654 formattedResult = result.formattedResult; | |
655 parameters = result.unusedSubstitutions; | |
656 if (parameters.length) | |
657 formattedResult.appendChild(document.createTextNode(" ")); | |
658 } | |
659 | |
660 for (var i = 0; i < parameters.length; ++i) { | |
661 if (typeof parameters[i] === "string") | |
662 formattedResult.appendChild(WebInspector.linkifyStringAsFragment
(parameters[i])); | |
663 else | |
664 formattedResult.appendChild(formatForConsole(parameters[i])); | |
665 | |
666 if (i < parameters.length - 1) | |
667 formattedResult.appendChild(document.createTextNode(" ")); | |
668 } | |
669 | |
670 return formattedResult; | |
671 }, | |
672 | |
673 toMessageElement: function() | |
674 { | |
675 if (this.propertiesSection) | |
676 return this.propertiesSection.element; | |
677 | |
678 var element = document.createElement("div"); | |
679 element.message = this; | |
680 element.className = "console-message"; | |
681 | |
682 switch (this.source) { | |
683 case WebInspector.ConsoleMessage.MessageSource.HTML: | |
684 element.addStyleClass("console-html-source"); | |
685 break; | |
686 case WebInspector.ConsoleMessage.MessageSource.WML: | |
687 element.addStyleClass("console-wml-source"); | |
688 break; | |
689 case WebInspector.ConsoleMessage.MessageSource.XML: | |
690 element.addStyleClass("console-xml-source"); | |
691 break; | |
692 case WebInspector.ConsoleMessage.MessageSource.JS: | |
693 element.addStyleClass("console-js-source"); | |
694 break; | |
695 case WebInspector.ConsoleMessage.MessageSource.CSS: | |
696 element.addStyleClass("console-css-source"); | |
697 break; | |
698 case WebInspector.ConsoleMessage.MessageSource.Other: | |
699 element.addStyleClass("console-other-source"); | |
700 break; | |
701 } | |
702 | |
703 switch (this.level) { | |
704 case WebInspector.ConsoleMessage.MessageLevel.Tip: | |
705 element.addStyleClass("console-tip-level"); | |
706 break; | |
707 case WebInspector.ConsoleMessage.MessageLevel.Log: | |
708 element.addStyleClass("console-log-level"); | |
709 break; | |
710 case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
711 element.addStyleClass("console-warning-level"); | |
712 break; | |
713 case WebInspector.ConsoleMessage.MessageLevel.Error: | |
714 element.addStyleClass("console-error-level"); | |
715 break; | |
716 case WebInspector.ConsoleMessage.MessageLevel.StartGroup: | |
717 element.addStyleClass("console-group-title-level"); | |
718 } | |
719 | |
720 if (this.elementsTreeOutline) { | |
721 element.addStyleClass("outline-disclosure"); | |
722 element.appendChild(this.elementsTreeOutline.element); | |
723 return element; | |
724 } | |
725 | |
726 if (this.repeatCount > 1) { | |
727 var messageRepeatCountElement = document.createElement("span"); | |
728 messageRepeatCountElement.className = "bubble"; | |
729 messageRepeatCountElement.textContent = this.repeatCount; | |
730 | |
731 element.appendChild(messageRepeatCountElement); | |
732 element.addStyleClass("repeated-message"); | |
733 } | |
734 | |
735 if (this.url && this.url !== "undefined") { | |
736 var urlElement = document.createElement("a"); | |
737 urlElement.className = "console-message-url webkit-html-resource-lin
k"; | |
738 urlElement.href = this.url; | |
739 urlElement.lineNumber = this.line; | |
740 | |
741 if (this.source === WebInspector.ConsoleMessage.MessageSource.JS) | |
742 urlElement.preferredPanel = "scripts"; | |
743 | |
744 if (this.line > 0) | |
745 urlElement.textContent = WebInspector.displayNameForURL(this.url
) + ":" + this.line; | |
746 else | |
747 urlElement.textContent = WebInspector.displayNameForURL(this.url
); | |
748 | |
749 element.appendChild(urlElement); | |
750 } | |
751 | |
752 var messageTextElement = document.createElement("span"); | |
753 messageTextElement.className = "console-message-text"; | |
754 messageTextElement.appendChild(this.formattedMessage); | |
755 element.appendChild(messageTextElement); | |
756 | |
757 return element; | |
758 }, | |
759 | |
760 toString: function() | |
761 { | |
762 var sourceString; | |
763 switch (this.source) { | |
764 case WebInspector.ConsoleMessage.MessageSource.HTML: | |
765 sourceString = "HTML"; | |
766 break; | |
767 case WebInspector.ConsoleMessage.MessageSource.WML: | |
768 sourceString = "WML"; | |
769 break; | |
770 case WebInspector.ConsoleMessage.MessageSource.XML: | |
771 sourceString = "XML"; | |
772 break; | |
773 case WebInspector.ConsoleMessage.MessageSource.JS: | |
774 sourceString = "JS"; | |
775 break; | |
776 case WebInspector.ConsoleMessage.MessageSource.CSS: | |
777 sourceString = "CSS"; | |
778 break; | |
779 case WebInspector.ConsoleMessage.MessageSource.Other: | |
780 sourceString = "Other"; | |
781 break; | |
782 } | |
783 | |
784 var levelString; | |
785 switch (this.level) { | |
786 case WebInspector.ConsoleMessage.MessageLevel.Tip: | |
787 levelString = "Tip"; | |
788 break; | |
789 case WebInspector.ConsoleMessage.MessageLevel.Log: | |
790 levelString = "Log"; | |
791 break; | |
792 case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
793 levelString = "Warning"; | |
794 break; | |
795 case WebInspector.ConsoleMessage.MessageLevel.Error: | |
796 levelString = "Error"; | |
797 break; | |
798 case WebInspector.ConsoleMessage.MessageLevel.Object: | |
799 levelString = "Object"; | |
800 break; | |
801 case WebInspector.ConsoleMessage.MessageLevel.Trace: | |
802 levelString = "Trace"; | |
803 break; | |
804 case WebInspector.ConsoleMessage.MessageLevel.StartGroup: | |
805 levelString = "Start Group"; | |
806 break; | |
807 case WebInspector.ConsoleMessage.MessageLevel.EndGroup: | |
808 levelString = "End Group"; | |
809 break; | |
810 } | |
811 | |
812 return sourceString + " " + levelString + ": " + this.formattedMessage.t
extContent + "\n" + this.url + " line " + this.line; | |
813 }, | |
814 | |
815 isEqual: function(msg, disreguardGroup) | |
816 { | |
817 if (!msg) | |
818 return false; | |
819 | |
820 var ret = (this.source == msg.source) | |
821 && (this.level == msg.level) | |
822 && (this.line == msg.line) | |
823 && (this.url == msg.url) | |
824 && (this.message == msg.message); | |
825 | |
826 return (disreguardGroup ? ret : (ret && (this.groupLevel == msg.groupLev
el))); | |
827 } | |
828 } | |
829 | |
830 // Note: Keep these constants in sync with the ones in Console.h | |
831 WebInspector.ConsoleMessage.MessageSource = { | |
832 HTML: 0, | |
833 WML: 1, | |
834 XML: 2, | |
835 JS: 3, | |
836 CSS: 4, | |
837 Other: 5 | |
838 } | |
839 | |
840 WebInspector.ConsoleMessage.MessageLevel = { | |
841 Tip: 0, | |
842 Log: 1, | |
843 Warning: 2, | |
844 Error: 3, | |
845 Object: 4, | |
846 Trace: 5, | |
847 StartGroup: 6, | |
848 EndGroup: 7 | |
849 } | |
850 | |
851 WebInspector.ConsoleCommand = function(command) | |
852 { | |
853 this.command = command; | |
854 } | |
855 | |
856 WebInspector.ConsoleCommand.prototype = { | |
857 toMessageElement: function() | |
858 { | |
859 var element = document.createElement("div"); | |
860 element.command = this; | |
861 element.className = "console-user-command"; | |
862 | |
863 var commandTextElement = document.createElement("span"); | |
864 commandTextElement.className = "console-message-text"; | |
865 commandTextElement.textContent = this.command; | |
866 element.appendChild(commandTextElement); | |
867 | |
868 return element; | |
869 } | |
870 } | |
871 | |
872 WebInspector.ConsoleCommandResult = function(result, exception, originatingComma
nd) | |
873 { | |
874 var level = (exception ? WebInspector.ConsoleMessage.MessageLevel.Error : We
bInspector.ConsoleMessage.MessageLevel.Log); | |
875 var message = (exception ? String(result) : result); | |
876 var line = (exception ? result.line : -1); | |
877 var url = (exception ? result.sourceURL : null); | |
878 | |
879 WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSo
urce.JS, level, line, url, null, 1, message); | |
880 | |
881 this.originatingCommand = originatingCommand; | |
882 } | |
883 | |
884 WebInspector.ConsoleCommandResult.prototype = { | |
885 toMessageElement: function() | |
886 { | |
887 var element = WebInspector.ConsoleMessage.prototype.toMessageElement.cal
l(this); | |
888 element.addStyleClass("console-user-command-result"); | |
889 return element; | |
890 } | |
891 } | |
892 | |
893 WebInspector.ConsoleCommandResult.prototype.__proto__ = WebInspector.ConsoleMess
age.prototype; | |
894 | |
895 WebInspector.ConsoleGroup = function(parentGroup, level) | |
896 { | |
897 this.parentGroup = parentGroup; | |
898 this.level = level; | |
899 | |
900 var element = document.createElement("div"); | |
901 element.className = "console-group"; | |
902 element.group = this; | |
903 this.element = element; | |
904 | |
905 var messagesElement = document.createElement("div"); | |
906 messagesElement.className = "console-group-messages"; | |
907 element.appendChild(messagesElement); | |
908 this.messagesElement = messagesElement; | |
909 } | |
910 | |
911 WebInspector.ConsoleGroup.prototype = { | |
912 addMessage: function(msg) | |
913 { | |
914 var element = msg.toMessageElement(); | |
915 | |
916 if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) { | |
917 this.messagesElement.parentNode.insertBefore(element, this.messagesE
lement); | |
918 element.addEventListener("click", this._titleClicked.bind(this), tru
e); | |
919 } else | |
920 this.messagesElement.appendChild(element); | |
921 | |
922 if (element.previousSibling && msg.originatingCommand && element.previou
sSibling.command === msg.originatingCommand) | |
923 element.previousSibling.addStyleClass("console-adjacent-user-command
-result"); | |
924 }, | |
925 | |
926 _titleClicked: function(event) | |
927 { | |
928 var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("conso
le-group-title-level"); | |
929 if (groupTitleElement) { | |
930 var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("c
onsole-group"); | |
931 if (groupElement) | |
932 if (groupElement.hasStyleClass("collapsed")) | |
933 groupElement.removeStyleClass("collapsed"); | |
934 else | |
935 groupElement.addStyleClass("collapsed"); | |
936 groupTitleElement.scrollIntoViewIfNeeded(true); | |
937 } | |
938 | |
939 event.stopPropagation(); | |
940 event.preventDefault(); | |
941 } | |
942 } | |
OLD | NEW |