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) { | |
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 var inspectedWindow = InspectorController.inspectedWindow(); | |
402 if (!inspectedWindow._inspectorCommandLineAPI) { | |
403 inspectedWindow.eval("window._inspectorCommandLineAPI = { \ | |
404 $: function() { return document.getElementById.apply(document, a
rguments) }, \ | |
405 $$: function() { return document.querySelectorAll.apply(document
, arguments) }, \ | |
406 $x: function(xpath, context) { \ | |
407 var nodes = []; \ | |
408 try { \ | |
409 var doc = context || document; \ | |
410 var results = doc.evaluate(xpath, doc, null, XPathResult
.ANY_TYPE, null); \ | |
411 var node; \ | |
412 while (node = results.iterateNext()) nodes.push(node); \ | |
413 } catch (e) {} \ | |
414 return nodes; \ | |
415 }, \ | |
416 dir: function() { return console.dir.apply(console, arguments) }
, \ | |
417 dirxml: function() { return console.dirxml.apply(console, argume
nts) }, \ | |
418 keys: function(o) { var a = []; for (k in o) a.push(k); return a
; }, \ | |
419 values: function(o) { var a = []; for (k in o) a.push(o[k]); ret
urn a; }, \ | |
420 profile: function() { return console.profile.apply(console, argu
ments) }, \ | |
421 profileEnd: function() { return console.profileEnd.apply(console
, arguments) } \ | |
422 };"); | |
423 | |
424 inspectedWindow._inspectorCommandLineAPI.clear = InspectorController
.wrapCallback(this.clearMessages.bind(this)); | |
425 } | |
426 | |
427 // Surround the expression in with statements to inject our command line
API so that | |
428 // the window object properties still take more precedent than our API f
unctions. | |
429 expression = "with (window._inspectorCommandLineAPI) { with (window) { "
+ expression + " } }"; | |
430 | |
431 return inspectedWindow.eval(expression); | |
432 }, | |
433 | |
434 _enterKeyPressed: function(event) | |
435 { | |
436 if (event.altKey) | |
437 return; | |
438 | |
439 event.preventDefault(); | |
440 event.stopPropagation(); | |
441 | |
442 this.prompt.clearAutoComplete(true); | |
443 | |
444 var str = this.prompt.text; | |
445 if (!str.length) | |
446 return; | |
447 | |
448 var result; | |
449 var exception = false; | |
450 try { | |
451 result = this._evalInInspectedWindow(str); | |
452 } catch(e) { | |
453 result = e; | |
454 exception = true; | |
455 } | |
456 | |
457 this.prompt.history.push(str); | |
458 this.prompt.historyOffset = 0; | |
459 this.prompt.text = ""; | |
460 | |
461 var level = exception ? WebInspector.ConsoleMessage.MessageLevel.Error :
WebInspector.ConsoleMessage.MessageLevel.Log; | |
462 this.addMessage(new WebInspector.ConsoleCommand(str, result, this._forma
t(result), level)); | |
463 }, | |
464 | |
465 _mouseOverNode: function(event) | |
466 { | |
467 var anchorElement = event.target.enclosingNodeOrSelfWithNodeName("a"); | |
468 WebInspector.hoveredDOMNode = (anchorElement ? anchorElement.represented
Node : null); | |
469 }, | |
470 | |
471 _mouseOutOfNode: function(event) | |
472 { | |
473 var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY)
; | |
474 var anchorElement = nodeUnderMouse.enclosingNodeOrSelfWithNodeName("a"); | |
475 if (!anchorElement || !anchorElement.representedNode) | |
476 WebInspector.hoveredDOMNode = null; | |
477 }, | |
478 | |
479 _format: function(output, inline) | |
480 { | |
481 var type = Object.type(output, InspectorController.inspectedWindow()); | |
482 if (type === "object") { | |
483 if (output instanceof InspectorController.inspectedWindow().Node) | |
484 type = "node"; | |
485 } | |
486 | |
487 // We don't perform any special formatting on these types, so we just | |
488 // pass them through the simple _formatvalue function. | |
489 var undecoratedTypes = { | |
490 "undefined": 1, | |
491 "null": 1, | |
492 "boolean": 1, | |
493 "number": 1, | |
494 "date": 1, | |
495 "function": 1, | |
496 }; | |
497 | |
498 var formatter; | |
499 if (type in undecoratedTypes) | |
500 formatter = "_formatvalue"; | |
501 else { | |
502 formatter = "_format" + type; | |
503 if (!(formatter in this)) { | |
504 formatter = "_formatobject"; | |
505 type = "object"; | |
506 } | |
507 } | |
508 | |
509 var span = document.createElement("span"); | |
510 span.addStyleClass("console-formatted-" + type); | |
511 this[formatter](output, span, inline); | |
512 return span; | |
513 }, | |
514 | |
515 _formatvalue: function(val, elem, inline) | |
516 { | |
517 elem.appendChild(document.createTextNode(val)); | |
518 }, | |
519 | |
520 _formatstring: function(str, elem, inline) | |
521 { | |
522 elem.appendChild(document.createTextNode("\"" + str + "\"")); | |
523 }, | |
524 | |
525 _formatregexp: function(re, elem, inline) | |
526 { | |
527 var formatted = String(re).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[g
im]*)$/, "$1").substring(1); | |
528 elem.appendChild(document.createTextNode(formatted)); | |
529 }, | |
530 | |
531 _formatarray: function(arr, elem, inline) | |
532 { | |
533 elem.appendChild(document.createTextNode("[")); | |
534 for (var i = 0; i < arr.length; ++i) { | |
535 elem.appendChild(this._format(arr[i], true)); | |
536 if (i < arr.length - 1) | |
537 elem.appendChild(document.createTextNode(", ")); | |
538 } | |
539 elem.appendChild(document.createTextNode("]")); | |
540 }, | |
541 | |
542 _formatnode: function(node, elem, inline) | |
543 { | |
544 var anchor = document.createElement("a"); | |
545 anchor.className = "inspectible-node"; | |
546 anchor.innerHTML = nodeTitleInfo.call(node).title; | |
547 anchor.representedNode = node; | |
548 anchor.addEventListener("mouseover", this._mouseOverNode.bind(this), fal
se); | |
549 anchor.addEventListener("mouseout", this._mouseOutOfNode.bind(this), fal
se); | |
550 | |
551 if (inline) | |
552 elem.appendChild(anchor); | |
553 else | |
554 elem.appendChild(new WebInspector.ObjectPropertiesSection(node, anch
or, null, null, true).element); | |
555 }, | |
556 | |
557 _formatobject: function(obj, elem, inline) | |
558 { | |
559 if (inline) | |
560 elem.appendChild(document.createTextNode(Object.describe(obj))); | |
561 else | |
562 elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, null,
null, null, true).element); | |
563 }, | |
564 | |
565 _formaterror: function(obj, elem, inline) | |
566 { | |
567 elem.appendChild(document.createTextNode(obj.name + ": " + obj.message +
" ")); | |
568 | |
569 if (obj.sourceURL) { | |
570 var urlElement = document.createElement("a"); | |
571 urlElement.className = "console-message-url webkit-html-resource-lin
k"; | |
572 urlElement.href = obj.sourceURL; | |
573 urlElement.lineNumber = obj.line; | |
574 urlElement.preferredPanel = "scripts"; | |
575 | |
576 if (obj.line > 0) | |
577 urlElement.textContent = WebInspector.UIString("%s (line %d)", o
bj.sourceURL, obj.line); | |
578 else | |
579 urlElement.textContent = obj.sourceURL; | |
580 | |
581 elem.appendChild(urlElement); | |
582 } | |
583 }, | |
584 } | |
585 | |
586 WebInspector.Console.prototype.__proto__ = WebInspector.View.prototype; | |
587 | |
588 WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, rep
eatCount) | |
589 { | |
590 this.source = source; | |
591 this.level = level; | |
592 this.line = line; | |
593 this.url = url; | |
594 this.groupLevel = groupLevel; | |
595 this.repeatCount = repeatCount; | |
596 | |
597 switch (this.level) { | |
598 case WebInspector.ConsoleMessage.MessageLevel.Object: | |
599 var propertiesSection = new WebInspector.ObjectPropertiesSection(arg
uments[6], null, null, null, true); | |
600 propertiesSection.element.addStyleClass("console-message"); | |
601 this.propertiesSection = propertiesSection; | |
602 break; | |
603 case WebInspector.ConsoleMessage.MessageLevel.Node: | |
604 var node = arguments[6]; | |
605 if (!(node instanceof InspectorController.inspectedWindow().Node)) | |
606 return; | |
607 this.elementsTreeOutline = new WebInspector.ElementsTreeOutline(); | |
608 this.elementsTreeOutline.rootDOMNode = node; | |
609 break; | |
610 case WebInspector.ConsoleMessage.MessageLevel.Trace: | |
611 var span = document.createElement("span"); | |
612 span.addStyleClass("console-formatted-trace"); | |
613 var stack = Array.prototype.slice.call(arguments, 6); | |
614 var funcNames = stack.map(function(f) { | |
615 return f || WebInspector.UIString("(anonymous function)"); | |
616 }); | |
617 span.appendChild(document.createTextNode(funcNames.join("\n"))); | |
618 this.formattedMessage = span; | |
619 break; | |
620 default: | |
621 // The formatedMessage property is used for the rich and interactive
console. | |
622 this.formattedMessage = this._format(Array.prototype.slice.call(argu
ments, 6)); | |
623 | |
624 // This is used for inline message bubbles in SourceFrames, or other
plain-text representations. | |
625 this.message = this.formattedMessage.textContent; | |
626 break; | |
627 } | |
628 } | |
629 | |
630 WebInspector.ConsoleMessage.prototype = { | |
631 isErrorOrWarning: function() | |
632 { | |
633 return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning
|| this.level === WebInspector.ConsoleMessage.MessageLevel.Error); | |
634 }, | |
635 | |
636 _format: function(parameters) | |
637 { | |
638 var formattedResult = document.createElement("span"); | |
639 | |
640 if (!parameters.length) | |
641 return formattedResult; | |
642 | |
643 function formatForConsole(obj) | |
644 { | |
645 return WebInspector.console._format(obj, true); | |
646 } | |
647 | |
648 if (Object.type(parameters[0], InspectorController.inspectedWindow()) ==
= "string") { | |
649 var formatters = {} | |
650 for (var i in String.standardFormatters) | |
651 formatters[i] = String.standardFormatters[i]; | |
652 | |
653 // Firebug uses %o for formatting objects. | |
654 formatters.o = formatForConsole; | |
655 // Firebug allows both %i and %d for formatting integers. | |
656 formatters.i = formatters.d; | |
657 | |
658 function append(a, b) | |
659 { | |
660 if (!(b instanceof Node)) | |
661 a.appendChild(WebInspector.linkifyStringAsFragment(b.toStrin
g())); | |
662 else | |
663 a.appendChild(b); | |
664 return a; | |
665 } | |
666 | |
667 var result = String.format(parameters[0], parameters.slice(1), forma
tters, formattedResult, append); | |
668 formattedResult = result.formattedResult; | |
669 parameters = result.unusedSubstitutions; | |
670 if (parameters.length) | |
671 formattedResult.appendChild(document.createTextNode(" ")); | |
672 } | |
673 | |
674 for (var i = 0; i < parameters.length; ++i) { | |
675 if (typeof parameters[i] === "string") | |
676 formattedResult.appendChild(WebInspector.linkifyStringAsFragment
(parameters[i])); | |
677 else if (parameters.length === 1) | |
678 formattedResult.appendChild(WebInspector.console._format(paramet
ers[0])); | |
679 else | |
680 formattedResult.appendChild(formatForConsole(parameters[i])); | |
681 if (i < parameters.length - 1) | |
682 formattedResult.appendChild(document.createTextNode(" ")); | |
683 } | |
684 | |
685 return formattedResult; | |
686 }, | |
687 | |
688 toMessageElement: function() | |
689 { | |
690 if (this.propertiesSection) | |
691 return this.propertiesSection.element; | |
692 | |
693 var element = document.createElement("div"); | |
694 element.message = this; | |
695 element.className = "console-message"; | |
696 | |
697 switch (this.source) { | |
698 case WebInspector.ConsoleMessage.MessageSource.HTML: | |
699 element.addStyleClass("console-html-source"); | |
700 break; | |
701 case WebInspector.ConsoleMessage.MessageSource.WML: | |
702 element.addStyleClass("console-wml-source"); | |
703 break; | |
704 case WebInspector.ConsoleMessage.MessageSource.XML: | |
705 element.addStyleClass("console-xml-source"); | |
706 break; | |
707 case WebInspector.ConsoleMessage.MessageSource.JS: | |
708 element.addStyleClass("console-js-source"); | |
709 break; | |
710 case WebInspector.ConsoleMessage.MessageSource.CSS: | |
711 element.addStyleClass("console-css-source"); | |
712 break; | |
713 case WebInspector.ConsoleMessage.MessageSource.Other: | |
714 element.addStyleClass("console-other-source"); | |
715 break; | |
716 } | |
717 | |
718 switch (this.level) { | |
719 case WebInspector.ConsoleMessage.MessageLevel.Tip: | |
720 element.addStyleClass("console-tip-level"); | |
721 break; | |
722 case WebInspector.ConsoleMessage.MessageLevel.Log: | |
723 element.addStyleClass("console-log-level"); | |
724 break; | |
725 case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
726 element.addStyleClass("console-warning-level"); | |
727 break; | |
728 case WebInspector.ConsoleMessage.MessageLevel.Error: | |
729 element.addStyleClass("console-error-level"); | |
730 break; | |
731 case WebInspector.ConsoleMessage.MessageLevel.StartGroup: | |
732 element.addStyleClass("console-group-title-level"); | |
733 } | |
734 | |
735 if (this.elementsTreeOutline) { | |
736 element.addStyleClass("outline-disclosure"); | |
737 element.appendChild(this.elementsTreeOutline.element); | |
738 return element; | |
739 } | |
740 | |
741 if (this.repeatCount > 1) { | |
742 var messageRepeatCountElement = document.createElement("span"); | |
743 messageRepeatCountElement.className = "bubble"; | |
744 messageRepeatCountElement.textContent = this.repeatCount; | |
745 | |
746 element.appendChild(messageRepeatCountElement); | |
747 element.addStyleClass("repeated-message"); | |
748 } | |
749 | |
750 if (this.url && this.url !== "undefined") { | |
751 var urlElement = document.createElement("a"); | |
752 urlElement.className = "console-message-url webkit-html-resource-lin
k"; | |
753 urlElement.href = this.url; | |
754 urlElement.lineNumber = this.line; | |
755 | |
756 if (this.source === WebInspector.ConsoleMessage.MessageSource.JS) | |
757 urlElement.preferredPanel = "scripts"; | |
758 | |
759 if (this.line > 0) | |
760 urlElement.textContent = WebInspector.UIString("%s (line %d)", W
ebInspector.displayNameForURL(this.url), this.line); | |
761 else | |
762 urlElement.textContent = WebInspector.displayNameForURL(this.url
); | |
763 | |
764 element.appendChild(urlElement); | |
765 } | |
766 | |
767 var messageTextElement = document.createElement("span"); | |
768 messageTextElement.className = "console-message-text"; | |
769 messageTextElement.appendChild(this.formattedMessage); | |
770 element.appendChild(messageTextElement); | |
771 | |
772 return element; | |
773 }, | |
774 | |
775 toString: function() | |
776 { | |
777 var sourceString; | |
778 switch (this.source) { | |
779 case WebInspector.ConsoleMessage.MessageSource.HTML: | |
780 sourceString = "HTML"; | |
781 break; | |
782 case WebInspector.ConsoleMessage.MessageSource.WML: | |
783 sourceString = "WML"; | |
784 break; | |
785 case WebInspector.ConsoleMessage.MessageSource.XML: | |
786 sourceString = "XML"; | |
787 break; | |
788 case WebInspector.ConsoleMessage.MessageSource.JS: | |
789 sourceString = "JS"; | |
790 break; | |
791 case WebInspector.ConsoleMessage.MessageSource.CSS: | |
792 sourceString = "CSS"; | |
793 break; | |
794 case WebInspector.ConsoleMessage.MessageSource.Other: | |
795 sourceString = "Other"; | |
796 break; | |
797 } | |
798 | |
799 var levelString; | |
800 switch (this.level) { | |
801 case WebInspector.ConsoleMessage.MessageLevel.Tip: | |
802 levelString = "Tip"; | |
803 break; | |
804 case WebInspector.ConsoleMessage.MessageLevel.Log: | |
805 levelString = "Log"; | |
806 break; | |
807 case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
808 levelString = "Warning"; | |
809 break; | |
810 case WebInspector.ConsoleMessage.MessageLevel.Error: | |
811 levelString = "Error"; | |
812 break; | |
813 case WebInspector.ConsoleMessage.MessageLevel.Object: | |
814 levelString = "Object"; | |
815 break; | |
816 case WebInspector.ConsoleMessage.MessageLevel.GroupTitle: | |
817 levelString = "GroupTitle"; | |
818 break; | |
819 } | |
820 | |
821 return sourceString + " " + levelString + ": " + this.formattedMessage.t
extContent + "\n" + this.url + " line " + this.line; | |
822 }, | |
823 | |
824 isEqual: function(msg, disreguardGroup) | |
825 { | |
826 if (!msg) | |
827 return false; | |
828 | |
829 var ret = (this.source == msg.source) | |
830 && (this.level == msg.level) | |
831 && (this.line == msg.line) | |
832 && (this.url == msg.url) | |
833 && (this.message == msg.message); | |
834 | |
835 return (disreguardGroup ? ret : (ret && (this.groupLevel == msg.groupLev
el))); | |
836 } | |
837 } | |
838 | |
839 // Note: Keep these constants in sync with the ones in Console.h | |
840 WebInspector.ConsoleMessage.MessageSource = { | |
841 HTML: 0, | |
842 WML: 1, | |
843 XML: 2, | |
844 JS: 3, | |
845 CSS: 4, | |
846 Other: 5 | |
847 } | |
848 | |
849 WebInspector.ConsoleMessage.MessageLevel = { | |
850 Tip: 0, | |
851 Log: 1, | |
852 Warning: 2, | |
853 Error: 3, | |
854 Object: 4, | |
855 Node: 5, | |
856 Trace: 6, | |
857 StartGroup: 7, | |
858 EndGroup: 8 | |
859 } | |
860 | |
861 WebInspector.ConsoleCommand = function(command, result, formattedResultElement,
level) | |
862 { | |
863 this.command = command; | |
864 this.formattedResultElement = formattedResultElement; | |
865 this.level = level; | |
866 } | |
867 | |
868 WebInspector.ConsoleCommand.prototype = { | |
869 toMessageElement: function() | |
870 { | |
871 var element = document.createElement("div"); | |
872 element.command = this; | |
873 element.className = "console-user-command"; | |
874 | |
875 var commandTextElement = document.createElement("span"); | |
876 commandTextElement.className = "console-message-text"; | |
877 commandTextElement.textContent = this.command; | |
878 element.appendChild(commandTextElement); | |
879 | |
880 var resultElement = document.createElement("div"); | |
881 resultElement.className = "console-message"; | |
882 element.appendChild(resultElement); | |
883 | |
884 switch (this.level) { | |
885 case WebInspector.ConsoleMessage.MessageLevel.Log: | |
886 resultElement.addStyleClass("console-log-level"); | |
887 break; | |
888 case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
889 resultElement.addStyleClass("console-warning-level"); | |
890 break; | |
891 case WebInspector.ConsoleMessage.MessageLevel.Error: | |
892 resultElement.addStyleClass("console-error-level"); | |
893 } | |
894 | |
895 var resultTextElement = document.createElement("span"); | |
896 resultTextElement.className = "console-message-text"; | |
897 resultTextElement.appendChild(this.formattedResultElement); | |
898 resultElement.appendChild(resultTextElement); | |
899 | |
900 return element; | |
901 } | |
902 } | |
903 | |
904 WebInspector.ConsoleGroup = function(parentGroup, level) | |
905 { | |
906 this.parentGroup = parentGroup; | |
907 this.level = level; | |
908 | |
909 var element = document.createElement("div"); | |
910 element.className = "console-group"; | |
911 element.group = this; | |
912 this.element = element; | |
913 | |
914 var messagesElement = document.createElement("div"); | |
915 messagesElement.className = "console-group-messages"; | |
916 element.appendChild(messagesElement); | |
917 this.messagesElement = messagesElement; | |
918 } | |
919 | |
920 WebInspector.ConsoleGroup.prototype = { | |
921 addMessage: function(msg) | |
922 { | |
923 var element = msg.toMessageElement(); | |
924 | |
925 if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) { | |
926 this.messagesElement.parentNode.insertBefore(element, this.messagesE
lement); | |
927 element.addEventListener("click", this._titleClicked.bind(this), tru
e); | |
928 } else | |
929 this.messagesElement.appendChild(element); | |
930 }, | |
931 | |
932 _titleClicked: function(event) | |
933 { | |
934 var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("conso
le-group-title-level"); | |
935 if (groupTitleElement) { | |
936 var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("c
onsole-group"); | |
937 if (groupElement) | |
938 if (groupElement.hasStyleClass("collapsed")) | |
939 groupElement.removeStyleClass("collapsed"); | |
940 else | |
941 groupElement.addStyleClass("collapsed"); | |
942 groupTitleElement.scrollIntoViewIfNeeded(true); | |
943 } | |
944 | |
945 event.stopPropagation(); | |
946 event.preventDefault(); | |
947 } | |
948 } | |
OLD | NEW |