ConsoleView.js 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239
  1. /*
  2. * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  3. * Copyright (C) 2009 Joseph Pecoraro
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  15. * its contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. /**
  30. * @extends {WebInspector.View}
  31. * @implements {WebInspector.Searchable}
  32. * @constructor
  33. * @param {boolean} hideContextSelector
  34. */
  35. WebInspector.ConsoleView = function(hideContextSelector)
  36. {
  37. WebInspector.View.call(this);
  38. this.element.id = "console-view";
  39. this._visibleMessagesIndices = [];
  40. this._urlToMessageCount = {};
  41. this._clearConsoleButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear console log."), "clear-status-bar-item");
  42. this._clearConsoleButton.addEventListener("click", this._requestClearMessages, this);
  43. this._frameSelector = new WebInspector.StatusBarComboBox(this._frameChanged.bind(this), "console-context");
  44. this._contextSelector = new WebInspector.StatusBarComboBox(this._contextChanged.bind(this), "console-context");
  45. this._filter = new WebInspector.ConsoleViewFilter();
  46. this._filter.addEventListener(WebInspector.ConsoleViewFilter.Events.FilterChanged, this._updateMessageList.bind(this));
  47. if (hideContextSelector) {
  48. this._frameSelector.element.addStyleClass("hidden");
  49. this._contextSelector.element.addStyleClass("hidden");
  50. }
  51. this.messagesElement = document.createElement("div");
  52. this.messagesElement.id = "console-messages";
  53. this.messagesElement.className = "monospace";
  54. this.messagesElement.addEventListener("click", this._messagesClicked.bind(this), true);
  55. this.element.appendChild(this.messagesElement);
  56. this._scrolledToBottom = true;
  57. this.promptElement = document.createElement("div");
  58. this.promptElement.id = "console-prompt";
  59. this.promptElement.className = "source-code";
  60. this.promptElement.spellcheck = false;
  61. this.messagesElement.appendChild(this.promptElement);
  62. this.messagesElement.appendChild(document.createElement("br"));
  63. this.topGroup = new WebInspector.ConsoleGroup(null);
  64. this.messagesElement.insertBefore(this.topGroup.element, this.promptElement);
  65. this.currentGroup = this.topGroup;
  66. this._registerShortcuts();
  67. this.registerRequiredCSS("textPrompt.css");
  68. this.messagesElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
  69. WebInspector.settings.monitoringXHREnabled.addChangeListener(this._monitoringXHREnabledSettingChanged.bind(this));
  70. WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._consoleMessageAdded, this);
  71. WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this);
  72. this._linkifier = new WebInspector.Linkifier();
  73. this.prompt = new WebInspector.TextPromptWithHistory(WebInspector.runtimeModel.completionsForTextPrompt.bind(WebInspector.runtimeModel));
  74. this.prompt.setSuggestBoxEnabled("generic-suggest");
  75. this.prompt.renderAsBlock();
  76. this.prompt.attach(this.promptElement);
  77. this.prompt.proxyElement.addEventListener("keydown", this._promptKeyDown.bind(this), false);
  78. this.prompt.setHistoryData(WebInspector.settings.consoleHistory.get());
  79. WebInspector.runtimeModel.contextLists().forEach(this._addFrame, this);
  80. WebInspector.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.FrameExecutionContextListAdded, this._frameAdded, this);
  81. WebInspector.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.FrameExecutionContextListRemoved, this._frameRemoved, this);
  82. this._filterStatusMessageElement = document.createElement("div");
  83. this._filterStatusMessageElement.classList.add("console-message");
  84. this._filterStatusTextElement = this._filterStatusMessageElement.createChild("span", "console-info");
  85. this._filterStatusMessageElement.createTextChild(" ");
  86. var resetFiltersLink = this._filterStatusMessageElement.createChild("span", "console-info node-link");
  87. resetFiltersLink.textContent = WebInspector.UIString("Show all messages.");
  88. resetFiltersLink.addEventListener("click", this._filter.reset.bind(this._filter), true);
  89. this.messagesElement.insertBefore(this._filterStatusMessageElement, this.topGroup.element);
  90. this._updateFilterStatus();
  91. }
  92. WebInspector.ConsoleView.prototype = {
  93. get statusBarItems()
  94. {
  95. return [this._clearConsoleButton.element, this._frameSelector.element, this._contextSelector.element, this._filter.sourceFilterButton.element, this._filter.filterBarElement];
  96. },
  97. /**
  98. * @param {WebInspector.Event} event
  99. */
  100. _frameAdded: function(event)
  101. {
  102. var contextList = /** @type {WebInspector.FrameExecutionContextList} */ (event.data);
  103. this._addFrame(contextList);
  104. },
  105. /**
  106. * @param {WebInspector.FrameExecutionContextList} contextList
  107. */
  108. _addFrame: function(contextList)
  109. {
  110. var option = this._frameSelector.createOption(contextList.displayName, contextList.url);
  111. option._contextList = contextList;
  112. contextList._consoleOption = option;
  113. contextList.addEventListener(WebInspector.FrameExecutionContextList.EventTypes.ContextsUpdated, this._frameUpdated, this);
  114. contextList.addEventListener(WebInspector.FrameExecutionContextList.EventTypes.ContextAdded, this._contextAdded, this);
  115. this._frameChanged();
  116. },
  117. /**
  118. * @param {WebInspector.Event} event
  119. */
  120. _frameRemoved: function(event)
  121. {
  122. var contextList = /** @type {WebInspector.FrameExecutionContextList} */ (event.data);
  123. this._frameSelector.removeOption(contextList._consoleOption);
  124. this._frameChanged();
  125. },
  126. _frameChanged: function()
  127. {
  128. var context = this._currentFrame();
  129. if (!context) {
  130. WebInspector.runtimeModel.setCurrentExecutionContext(null);
  131. this._contextSelector.element.addStyleClass("hidden");
  132. return;
  133. }
  134. var executionContexts = context.executionContexts();
  135. if (executionContexts.length)
  136. WebInspector.runtimeModel.setCurrentExecutionContext(executionContexts[0]);
  137. if (executionContexts.length === 1) {
  138. this._contextSelector.element.addStyleClass("hidden");
  139. return;
  140. }
  141. this._contextSelector.element.removeStyleClass("hidden");
  142. this._contextSelector.removeOptions();
  143. for (var i = 0; i < executionContexts.length; ++i)
  144. this._appendContextOption(executionContexts[i]);
  145. },
  146. /**
  147. * @param {WebInspector.ExecutionContext} executionContext
  148. */
  149. _appendContextOption: function(executionContext)
  150. {
  151. if (!WebInspector.runtimeModel.currentExecutionContext())
  152. WebInspector.runtimeModel.setCurrentExecutionContext(executionContext);
  153. var option = this._contextSelector.createOption(executionContext.name, executionContext.id);
  154. option._executionContext = executionContext;
  155. },
  156. /**
  157. * @param {Event} event
  158. */
  159. _contextChanged: function(event)
  160. {
  161. var option = this._contextSelector.selectedOption();
  162. WebInspector.runtimeModel.setCurrentExecutionContext(option ? option._executionContext : null);
  163. },
  164. /**
  165. * @param {WebInspector.Event} event
  166. */
  167. _frameUpdated: function(event)
  168. {
  169. var contextList = /** @type {WebInspector.FrameExecutionContextList} */ (event.data);
  170. var option = contextList._consoleOption;
  171. option.text = contextList.displayName;
  172. option.title = contextList.url;
  173. },
  174. /**
  175. * @param {WebInspector.Event} event
  176. */
  177. _contextAdded: function(event)
  178. {
  179. var contextList = /** @type {WebInspector.FrameExecutionContextList} */ (event.data);
  180. if (contextList === this._currentFrame())
  181. this._frameChanged();
  182. },
  183. /**
  184. * @return {WebInspector.FrameExecutionContextList|undefined}
  185. */
  186. _currentFrame: function()
  187. {
  188. var option = this._frameSelector.selectedOption();
  189. return option ? option._contextList : undefined;
  190. },
  191. willHide: function()
  192. {
  193. this.prompt.hideSuggestBox();
  194. this.prompt.clearAutoComplete(true);
  195. },
  196. wasShown: function()
  197. {
  198. if (!this.prompt.isCaretInsidePrompt())
  199. this.prompt.moveCaretToEndOfPrompt();
  200. },
  201. afterShow: function()
  202. {
  203. WebInspector.setCurrentFocusElement(this.promptElement);
  204. },
  205. storeScrollPositions: function()
  206. {
  207. WebInspector.View.prototype.storeScrollPositions.call(this);
  208. this._scrolledToBottom = this.messagesElement.isScrolledToBottom();
  209. },
  210. restoreScrollPositions: function()
  211. {
  212. if (this._scrolledToBottom)
  213. this._immediatelyScrollIntoView();
  214. else
  215. WebInspector.View.prototype.restoreScrollPositions.call(this);
  216. },
  217. onResize: function()
  218. {
  219. this.restoreScrollPositions();
  220. },
  221. _isScrollIntoViewScheduled: function()
  222. {
  223. return !!this._scrollIntoViewTimer;
  224. },
  225. _scheduleScrollIntoView: function()
  226. {
  227. if (this._scrollIntoViewTimer)
  228. return;
  229. function scrollIntoView()
  230. {
  231. delete this._scrollIntoViewTimer;
  232. this.promptElement.scrollIntoView(true);
  233. }
  234. this._scrollIntoViewTimer = setTimeout(scrollIntoView.bind(this), 20);
  235. },
  236. _immediatelyScrollIntoView: function()
  237. {
  238. this.promptElement.scrollIntoView(true);
  239. this._cancelScheduledScrollIntoView();
  240. },
  241. _cancelScheduledScrollIntoView: function()
  242. {
  243. if (!this._isScrollIntoViewScheduled())
  244. return;
  245. clearTimeout(this._scrollIntoViewTimer);
  246. delete this._scrollIntoViewTimer;
  247. },
  248. /**
  249. * @param {number=} count
  250. */
  251. _updateFilterStatus: function(count) {
  252. count = (typeof count === undefined) ? (WebInspector.console.messages.length - this._visibleMessagesIndices.length) : count;
  253. this._filterStatusTextElement.textContent = WebInspector.UIString(count == 1 ? "%d message is hidden by filters." : "%d messages are hidden by filters.", count);
  254. this._filterStatusMessageElement.style.display = count ? "" : "none";
  255. },
  256. /**
  257. * @param {WebInspector.Event} event
  258. */
  259. _consoleMessageAdded: function(event)
  260. {
  261. var message = /** @type {WebInspector.ConsoleMessage} */ (event.data);
  262. var index = message.index;
  263. if (this._urlToMessageCount[message.url])
  264. this._urlToMessageCount[message.url]++;
  265. else
  266. this._urlToMessageCount[message.url] = 1;
  267. if (this._filter.shouldBeVisible(message))
  268. this._showConsoleMessage(index);
  269. else
  270. this._updateFilterStatus();
  271. },
  272. _showConsoleMessage: function(index)
  273. {
  274. var message = WebInspector.console.messages[index];
  275. // this.messagesElement.isScrolledToBottom() is forcing style recalculation.
  276. // We just skip it if the scroll action has been scheduled.
  277. if (!this._isScrollIntoViewScheduled() && ((message instanceof WebInspector.ConsoleCommandResult) || this.messagesElement.isScrolledToBottom()))
  278. this._scheduleScrollIntoView();
  279. this._visibleMessagesIndices.push(index);
  280. if (message.type === WebInspector.ConsoleMessage.MessageType.EndGroup) {
  281. var parentGroup = this.currentGroup.parentGroup;
  282. if (parentGroup)
  283. this.currentGroup = parentGroup;
  284. } else {
  285. if (message.type === WebInspector.ConsoleMessage.MessageType.StartGroup || message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
  286. var group = new WebInspector.ConsoleGroup(this.currentGroup);
  287. this.currentGroup.messagesElement.appendChild(group.element);
  288. this.currentGroup = group;
  289. message.group = group;
  290. }
  291. this.currentGroup.addMessage(message);
  292. }
  293. if (this._searchRegex && message.matchesRegex(this._searchRegex)) {
  294. this._searchResultsIndices.push(index);
  295. WebInspector.searchController.updateSearchMatchesCount(this._searchResultsIndices.length, this._searchProvider);
  296. }
  297. },
  298. _consoleCleared: function()
  299. {
  300. this._scrolledToBottom = true;
  301. for (var i = 0; i < this._visibleMessagesIndices.length; ++i)
  302. WebInspector.console.messages[this._visibleMessagesIndices[i]].willHide();
  303. this._visibleMessagesIndices = [];
  304. this._searchResultsIndices = [];
  305. if (this._searchRegex)
  306. WebInspector.searchController.updateSearchMatchesCount(0, this._searchProvider);
  307. this.currentGroup = this.topGroup;
  308. this.topGroup.messagesElement.removeChildren();
  309. this._clearCurrentSearchResultHighlight();
  310. this._updateFilterStatus(0);
  311. this._linkifier.reset();
  312. },
  313. _handleContextMenuEvent: function(event)
  314. {
  315. if (!window.getSelection().isCollapsed) {
  316. // If there is a selection, we want to show our normal context menu
  317. // (with Copy, etc.), and not Clear Console.
  318. return;
  319. }
  320. if (event.target.enclosingNodeOrSelfWithNodeName("a"))
  321. return;
  322. var contextMenu = new WebInspector.ContextMenu(event);
  323. function monitoringXHRItemAction()
  324. {
  325. WebInspector.settings.monitoringXHREnabled.set(!WebInspector.settings.monitoringXHREnabled.get());
  326. }
  327. contextMenu.appendCheckboxItem(WebInspector.UIString("Log XMLHttpRequests"), monitoringXHRItemAction.bind(this), WebInspector.settings.monitoringXHREnabled.get());
  328. function preserveLogItemAction()
  329. {
  330. WebInspector.settings.preserveConsoleLog.set(!WebInspector.settings.preserveConsoleLog.get());
  331. }
  332. contextMenu.appendCheckboxItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Preserve log upon navigation" : "Preserve Log upon Navigation"), preserveLogItemAction.bind(this), WebInspector.settings.preserveConsoleLog.get());
  333. var sourceElement = event.target.enclosingNodeOrSelfWithClass("console-message");
  334. var filterSubMenu = contextMenu.appendSubMenuItem(WebInspector.UIString("Filter"));
  335. if (sourceElement && sourceElement.message.url) {
  336. var menuTitle = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Hide messages from %s" : "Hide Messages from %s", new WebInspector.ParsedURL(sourceElement.message.url).displayName);
  337. filterSubMenu.appendItem(menuTitle, this._filter.addMessageURLFilter.bind(this._filter, sourceElement.message.url));
  338. }
  339. filterSubMenu.appendSeparator();
  340. var unhideAll = filterSubMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Unhide all" : "Unhide All"), this._filter.removeMessageURLFilter.bind(this._filter));
  341. filterSubMenu.appendSeparator();
  342. var hasFilters = false;
  343. for (var url in this._filter.messageURLFilters) {
  344. filterSubMenu.appendCheckboxItem(String.sprintf("%s (%d)", new WebInspector.ParsedURL(url).displayName, this._urlToMessageCount[url]), this._filter.removeMessageURLFilter.bind(this._filter, url), true);
  345. hasFilters = true;
  346. }
  347. filterSubMenu.setEnabled(hasFilters || (sourceElement && sourceElement.message.url));
  348. unhideAll.setEnabled(hasFilters);
  349. contextMenu.appendSeparator();
  350. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear console" : "Clear Console"), this._requestClearMessages.bind(this));
  351. var request = (sourceElement && sourceElement.message) ? sourceElement.message.request() : null;
  352. if (request && request.type === WebInspector.resourceTypes.XHR) {
  353. contextMenu.appendSeparator();
  354. contextMenu.appendItem(WebInspector.UIString("Replay XHR"), NetworkAgent.replayXHR.bind(null, request.requestId));
  355. }
  356. contextMenu.show();
  357. },
  358. _updateMessageList: function()
  359. {
  360. var group = this.topGroup;
  361. var sourceMessages = WebInspector.console.messages;
  362. var visibleMessageIndex = 0;
  363. var newVisibleMessages = [];
  364. if (this._searchRegex)
  365. this._searchResultsIndices = [];
  366. var anchor = null;
  367. for (var i = 0; i < sourceMessages.length; ++i) {
  368. var sourceMessage = sourceMessages[i];
  369. var visibleMessage = WebInspector.console.messages[this._visibleMessagesIndices[visibleMessageIndex]];
  370. if (visibleMessage === sourceMessage) {
  371. if (this._filter.shouldBeVisible(visibleMessage)) {
  372. newVisibleMessages.push(this._visibleMessagesIndices[visibleMessageIndex]);
  373. if (this._searchRegex && sourceMessage.matchesRegex(this._searchRegex))
  374. this._searchResultsIndices.push(i);
  375. if (sourceMessage.type === WebInspector.ConsoleMessage.MessageType.EndGroup) {
  376. anchor = group.element;
  377. group = group.parentGroup || group;
  378. } else if (sourceMessage.type === WebInspector.ConsoleMessage.MessageType.StartGroup || sourceMessage.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
  379. group = sourceMessage.group;
  380. anchor = group.messagesElement.firstChild;
  381. } else
  382. anchor = visibleMessage.toMessageElement();
  383. } else {
  384. visibleMessage.willHide();
  385. visibleMessage.toMessageElement().remove();
  386. }
  387. ++visibleMessageIndex;
  388. } else {
  389. if (this._filter.shouldBeVisible(sourceMessage)) {
  390. if (this._searchRegex && sourceMessage.matchesRegex(this._searchRegex))
  391. this._searchResultsIndices.push(i);
  392. group.addMessage(sourceMessage, anchor ? anchor.nextSibling : group.messagesElement.firstChild);
  393. newVisibleMessages.push(i);
  394. anchor = sourceMessage.toMessageElement();
  395. }
  396. }
  397. }
  398. if (this._searchRegex)
  399. WebInspector.searchController.updateSearchMatchesCount(this._searchResultsIndices.length, this._searchProvider);
  400. this._visibleMessagesIndices = newVisibleMessages;
  401. this._updateFilterStatus();
  402. },
  403. _monitoringXHREnabledSettingChanged: function(event)
  404. {
  405. ConsoleAgent.setMonitoringXHREnabled(event.data);
  406. },
  407. _messagesClicked: function()
  408. {
  409. if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
  410. this.prompt.moveCaretToEndOfPrompt();
  411. },
  412. _registerShortcuts: function()
  413. {
  414. this._shortcuts = {};
  415. var shortcut = WebInspector.KeyboardShortcut;
  416. var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("Console"));
  417. var shortcutL = shortcut.makeDescriptor("l", WebInspector.KeyboardShortcut.Modifiers.Ctrl);
  418. this._shortcuts[shortcutL.key] = this._requestClearMessages.bind(this);
  419. var keys = [shortcutL];
  420. if (WebInspector.isMac()) {
  421. var shortcutK = shortcut.makeDescriptor("k", WebInspector.KeyboardShortcut.Modifiers.Meta);
  422. this._shortcuts[shortcutK.key] = this._requestClearMessages.bind(this);
  423. keys.unshift(shortcutK);
  424. }
  425. section.addAlternateKeys(keys, WebInspector.UIString("Clear console"));
  426. section.addKey(shortcut.makeDescriptor(shortcut.Keys.Tab), WebInspector.UIString("Autocomplete common prefix"));
  427. section.addKey(shortcut.makeDescriptor(shortcut.Keys.Right), WebInspector.UIString("Accept suggestion"));
  428. keys = [
  429. shortcut.makeDescriptor(shortcut.Keys.Down),
  430. shortcut.makeDescriptor(shortcut.Keys.Up)
  431. ];
  432. section.addRelatedKeys(keys, WebInspector.UIString("Next/previous line"));
  433. if (WebInspector.isMac()) {
  434. keys = [
  435. shortcut.makeDescriptor("N", shortcut.Modifiers.Alt),
  436. shortcut.makeDescriptor("P", shortcut.Modifiers.Alt)
  437. ];
  438. section.addRelatedKeys(keys, WebInspector.UIString("Next/previous command"));
  439. }
  440. section.addKey(shortcut.makeDescriptor(shortcut.Keys.Enter), WebInspector.UIString("Execute command"));
  441. },
  442. _requestClearMessages: function()
  443. {
  444. WebInspector.console.requestClearMessages();
  445. },
  446. _promptKeyDown: function(event)
  447. {
  448. if (isEnterKey(event)) {
  449. this._enterKeyPressed(event);
  450. return;
  451. }
  452. var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
  453. var handler = this._shortcuts[shortcut];
  454. if (handler) {
  455. handler();
  456. event.preventDefault();
  457. }
  458. },
  459. /**
  460. * @param {string} expression
  461. * @param {boolean} showResultOnly
  462. */
  463. evaluateUsingTextPrompt: function(expression, showResultOnly)
  464. {
  465. this._appendCommand(expression, this.prompt.text, false, showResultOnly);
  466. },
  467. _enterKeyPressed: function(event)
  468. {
  469. if (event.altKey || event.ctrlKey || event.shiftKey)
  470. return;
  471. event.consume(true);
  472. this.prompt.clearAutoComplete(true);
  473. var str = this.prompt.text;
  474. if (!str.length)
  475. return;
  476. this._appendCommand(str, "", true, false);
  477. },
  478. /**
  479. * @param {WebInspector.RemoteObject} result
  480. * @param {boolean} wasThrown
  481. * @param {WebInspector.ConsoleCommand} originatingCommand
  482. */
  483. _printResult: function(result, wasThrown, originatingCommand)
  484. {
  485. if (!result)
  486. return;
  487. /**
  488. * @param {string=} url
  489. * @param {number=} lineNumber
  490. * @param {number=} columnNumber
  491. */
  492. function addMessage(url, lineNumber, columnNumber)
  493. {
  494. var message = new WebInspector.ConsoleCommandResult(result, wasThrown, originatingCommand, this._linkifier, url, lineNumber, columnNumber);
  495. WebInspector.console.addMessage(message);
  496. }
  497. if (result.type !== "function") {
  498. addMessage.call(this);
  499. return;
  500. }
  501. DebuggerAgent.getFunctionDetails(result.objectId, didGetDetails.bind(this));
  502. /**
  503. * @param {?Protocol.Error} error
  504. * @param {DebuggerAgent.FunctionDetails} response
  505. */
  506. function didGetDetails(error, response)
  507. {
  508. if (error) {
  509. console.error(error);
  510. addMessage.call(this);
  511. return;
  512. }
  513. var url;
  514. var lineNumber;
  515. var columnNumber;
  516. var script = WebInspector.debuggerModel.scriptForId(response.location.scriptId);
  517. if (script && script.sourceURL) {
  518. url = script.sourceURL;
  519. lineNumber = response.location.lineNumber + 1;
  520. columnNumber = response.location.columnNumber + 1;
  521. }
  522. addMessage.call(this, url, lineNumber, columnNumber);
  523. }
  524. },
  525. /**
  526. * @param {string} text
  527. * @param {string} newPromptText
  528. * @param {boolean} useCommandLineAPI
  529. * @param {boolean} showResultOnly
  530. */
  531. _appendCommand: function(text, newPromptText, useCommandLineAPI, showResultOnly)
  532. {
  533. if (!showResultOnly) {
  534. var commandMessage = new WebInspector.ConsoleCommand(text);
  535. WebInspector.console.addMessage(commandMessage);
  536. }
  537. this.prompt.text = newPromptText;
  538. /**
  539. * @param {WebInspector.RemoteObject} result
  540. * @param {boolean} wasThrown
  541. * @param {RuntimeAgent.RemoteObject=} valueResult
  542. */
  543. function printResult(result, wasThrown, valueResult)
  544. {
  545. if (!result)
  546. return;
  547. if (!showResultOnly) {
  548. this.prompt.pushHistoryItem(text);
  549. WebInspector.settings.consoleHistory.set(this.prompt.historyData.slice(-30));
  550. }
  551. this._printResult(result, wasThrown, commandMessage);
  552. }
  553. WebInspector.runtimeModel.evaluate(text, "console", useCommandLineAPI, false, false, true, printResult.bind(this));
  554. WebInspector.userMetrics.ConsoleEvaluated.record();
  555. },
  556. elementsToRestoreScrollPositionsFor: function()
  557. {
  558. return [this.messagesElement];
  559. },
  560. searchCanceled: function()
  561. {
  562. this._clearCurrentSearchResultHighlight();
  563. delete this._searchProvider;
  564. delete this._searchResultsIndices;
  565. delete this._searchRegex;
  566. },
  567. canSearchAndReplace: function()
  568. {
  569. return false;
  570. },
  571. canFilter: function()
  572. {
  573. return true;
  574. },
  575. /**
  576. * @param {string} query
  577. * @param {boolean} shouldJump
  578. * @param {WebInspector.Searchable=} self
  579. */
  580. performSearch: function(query, shouldJump, self)
  581. {
  582. this.searchCanceled();
  583. this._searchProvider = self || this;
  584. WebInspector.searchController.updateSearchMatchesCount(0, this._searchProvider);
  585. this._searchRegex = createPlainTextSearchRegex(query, "gi");
  586. this._searchResultsIndices = [];
  587. for (var i = 0; i < this._visibleMessagesIndices.length; i++) {
  588. if (WebInspector.console.messages[this._visibleMessagesIndices[i]].matchesRegex(this._searchRegex))
  589. this._searchResultsIndices.push(this._visibleMessagesIndices[i]);
  590. }
  591. WebInspector.searchController.updateSearchMatchesCount(this._searchResultsIndices.length, this._searchProvider);
  592. this._currentSearchResultIndex = -1;
  593. if (shouldJump && this._searchResultsIndices.length)
  594. this._jumpToSearchResult(0, self);
  595. },
  596. /**
  597. * @return {number}
  598. */
  599. minimalSearchQuerySize: function()
  600. {
  601. return 0;
  602. },
  603. /**
  604. * @param {string} query
  605. */
  606. performFilter: function(query)
  607. {
  608. this._filter.performFilter(query);
  609. },
  610. /**
  611. * @param {WebInspector.Searchable=} self
  612. */
  613. jumpToNextSearchResult: function(self)
  614. {
  615. if (!this._searchResultsIndices || !this._searchResultsIndices.length)
  616. return;
  617. this._jumpToSearchResult((this._currentSearchResultIndex + 1) % this._searchResultsIndices.length, self);
  618. },
  619. /**
  620. * @param {WebInspector.Searchable=} self
  621. */
  622. jumpToPreviousSearchResult: function(self)
  623. {
  624. if (!this._searchResultsIndices || !this._searchResultsIndices.length)
  625. return;
  626. var index = this._currentSearchResultIndex - 1;
  627. if (index === -1)
  628. index = this._searchResultsIndices.length - 1;
  629. this._jumpToSearchResult(index, self);
  630. },
  631. _clearCurrentSearchResultHighlight: function()
  632. {
  633. if (!this._searchResultsIndices)
  634. return;
  635. var highlightedMessage = WebInspector.console.messages[this._searchResultsIndices[this._currentSearchResultIndex]];
  636. if (highlightedMessage)
  637. highlightedMessage.clearHighlight();
  638. this._currentSearchResultIndex = -1;
  639. },
  640. _jumpToSearchResult: function(index, self)
  641. {
  642. this._clearCurrentSearchResultHighlight();
  643. this._currentSearchResultIndex = index;
  644. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this._searchProvider);
  645. WebInspector.console.messages[this._searchResultsIndices[index]].highlightSearchResults(this._searchRegex);
  646. },
  647. __proto__: WebInspector.View.prototype
  648. }
  649. /**
  650. * @extends {WebInspector.Object}
  651. * @constructor
  652. */
  653. WebInspector.ConsoleViewFilter = function()
  654. {
  655. this._messageURLFilters = WebInspector.settings.messageURLFilters.get();
  656. this._messageSourceFilters = WebInspector.settings.messageSourceFilters.get();
  657. this._messageLevelFilters = WebInspector.settings.messageLevelFilters.get();
  658. this._sourceToKeyMap = {};
  659. for (var key in WebInspector.ConsoleViewFilter._messageSourceGroups) {
  660. if (!WebInspector.ConsoleViewFilter._messageSourceGroups[key].sources) {
  661. console.assert(!this._otherKey);
  662. this._otherKey = key;
  663. continue;
  664. }
  665. for (var i = 0; i < WebInspector.ConsoleViewFilter._messageSourceGroups[key].sources.length; ++i)
  666. this._sourceToKeyMap[WebInspector.ConsoleViewFilter._messageSourceGroups[key].sources[i]] = key;
  667. }
  668. this._filterChanged = this.dispatchEventToListeners.bind(this, WebInspector.ConsoleViewFilter.Events.FilterChanged);
  669. WebInspector.settings.messageSourceFilters.addChangeListener(this._updateSourceFilterButton.bind(this));
  670. WebInspector.settings.messageLevelFilters.addChangeListener(this._updateLevelFilterBar.bind(this));
  671. this.sourceFilterButton = new WebInspector.StatusBarButton(WebInspector.UIString("Filter"), "console-filter", 2);
  672. this.sourceFilterButton.element.addEventListener("mousedown", this._handleSourceFilterButtonClick.bind(this), false);
  673. this._filterBarElements = [];
  674. this.filterBarElement = document.createElement("div");
  675. this.filterBarElement.className = "scope-bar status-bar-item";
  676. this._createLevelFilterBarElement("all", WebInspector.UIString("All"));
  677. var dividerElement = document.createElement("div");
  678. dividerElement.addStyleClass("scope-bar-divider");
  679. this.filterBarElement.appendChild(dividerElement);
  680. this._createLevelFilterBarElement("error", WebInspector.UIString("Errors"));
  681. this._createLevelFilterBarElement("warning", WebInspector.UIString("Warnings"));
  682. this._createLevelFilterBarElement("log", WebInspector.UIString("Logs"));
  683. this._createLevelFilterBarElement("debug", WebInspector.UIString("Debug"));
  684. this._updateLevelFilterBar();
  685. this._updateSourceFilterButton();
  686. };
  687. WebInspector.ConsoleViewFilter.Events = {
  688. FilterChanged: "FilterChanged"
  689. };
  690. WebInspector.ConsoleViewFilter._messageSourceGroups = {
  691. JS: { sources: [WebInspector.ConsoleMessage.MessageSource.JS], title: "JavaScript", styleClass: "filter-type-javascript"},
  692. Network: { sources: [WebInspector.ConsoleMessage.MessageSource.Network], title: "Network", styleClass: "filter-type-network"},
  693. Logging: { sources: [WebInspector.ConsoleMessage.MessageSource.ConsoleAPI], title: "Logging", styleClass: "filter-type-logging"},
  694. CSS: { sources: [WebInspector.ConsoleMessage.MessageSource.CSS], title: "CSS", styleClass: "filter-type-css"},
  695. Other: { title: "Other", styleClass: "filter-type-other"}
  696. };
  697. WebInspector.ConsoleViewFilter.prototype = {
  698. /**
  699. * @param {string} url
  700. */
  701. addMessageURLFilter: function(url)
  702. {
  703. this._messageURLFilters[url] = true;
  704. WebInspector.settings.messageURLFilters.set(this._messageURLFilters);
  705. this._filterChanged();
  706. },
  707. /**
  708. * @param {string} url
  709. */
  710. removeMessageURLFilter: function(url)
  711. {
  712. if (!url)
  713. this._messageURLFilters = {};
  714. else
  715. delete this._messageURLFilters[url];
  716. WebInspector.settings.messageURLFilters.set(this._messageURLFilters);
  717. this._filterChanged();
  718. },
  719. /**
  720. * @returns {Object}
  721. */
  722. get messageURLFilters()
  723. {
  724. return this._messageURLFilters;
  725. },
  726. /**
  727. * @param {WebInspector.ConsoleMessage} message
  728. * @return {boolean}
  729. */
  730. shouldBeVisible: function(message)
  731. {
  732. if ((message.type === WebInspector.ConsoleMessage.MessageType.StartGroup || message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed || message.type === WebInspector.ConsoleMessage.MessageType.EndGroup))
  733. return true;
  734. if (message.url && this._messageURLFilters[message.url])
  735. return false;
  736. if (message.level && this._messageLevelFilters[message.level])
  737. return false;
  738. if (this._filterRegex) {
  739. this._filterRegex.lastIndex = 0;
  740. if (!message.matchesRegex(this._filterRegex))
  741. return false;
  742. }
  743. // We store group keys, and we have resolved group by message source
  744. if (message.source) {
  745. if (this._sourceToKeyMap[message.source])
  746. return !this._messageSourceFilters[this._sourceToKeyMap[message.source]];
  747. else
  748. return !this._messageSourceFilters[this._otherKey];
  749. }
  750. return true;
  751. },
  752. reset: function()
  753. {
  754. this._messageSourceFilters = {};
  755. WebInspector.settings.messageSourceFilters.set(this._messageSourceFilters);
  756. this._messageURLFilters = {};
  757. WebInspector.settings.messageURLFilters.set(this._messageURLFilters);
  758. this._messageLevelFilters = {};
  759. WebInspector.settings.messageLevelFilters.set(this._messageLevelFilters);
  760. this._filterChanged();
  761. },
  762. /**
  763. * @param {string} query
  764. */
  765. performFilter: function(query)
  766. {
  767. if (!query)
  768. delete this._filterRegex;
  769. else
  770. this._filterRegex = createPlainTextSearchRegex(query, "gi");
  771. this._filterChanged();
  772. },
  773. /**
  774. * @param {string} sourceGroup
  775. * @private
  776. */
  777. _toggleMessageSourceFilter: function(sourceGroup)
  778. {
  779. if (!this._messageSourceFilters[sourceGroup])
  780. this._messageSourceFilters[sourceGroup] = true;
  781. else
  782. delete this._messageSourceFilters[sourceGroup];
  783. WebInspector.settings.messageSourceFilters.set(this._messageSourceFilters);
  784. this._filterChanged();
  785. },
  786. /**
  787. * @private
  788. */
  789. _updateSourceFilterButton: function()
  790. {
  791. var hasActiveSourceFilter = false;
  792. for (var sourceGroup in WebInspector.ConsoleViewFilter._messageSourceGroups) {
  793. if (this._messageSourceFilters[sourceGroup]) {
  794. hasActiveSourceFilter = true;
  795. break;
  796. }
  797. }
  798. this.sourceFilterButton.state = hasActiveSourceFilter;
  799. },
  800. /**
  801. * @param {Event} event
  802. * @returns {WebInspector.ContextMenu}
  803. * @private
  804. */
  805. _createSourceFilterMenu: function(event)
  806. {
  807. var menu = new WebInspector.ContextMenu(event);
  808. for (var sourceGroup in WebInspector.ConsoleViewFilter._messageSourceGroups) {
  809. var filter = WebInspector.ConsoleViewFilter._messageSourceGroups[sourceGroup];
  810. menu.appendCheckboxItem(WebInspector.UIString(WebInspector.UIString(filter.title)), this._toggleMessageSourceFilter.bind(this, sourceGroup), !this._messageSourceFilters[sourceGroup]);
  811. }
  812. return menu;
  813. },
  814. /**
  815. * @param {string} level
  816. * @param {string} label
  817. * @private
  818. */
  819. _createLevelFilterBarElement: function(level, label)
  820. {
  821. var categoryElement = document.createElement("li");
  822. categoryElement.category = level;
  823. categoryElement.className = level;
  824. categoryElement.textContent = label;
  825. categoryElement.addEventListener("click", this._toggleLevelFilter.bind(this, level), false);
  826. this._filterBarElements[level] = categoryElement;
  827. this.filterBarElement.appendChild(categoryElement);
  828. },
  829. /**
  830. * @param {string} level
  831. * @param {Event} event
  832. * @private
  833. */
  834. _toggleLevelFilter: function(level, event)
  835. {
  836. var isMac = WebInspector.isMac();
  837. var selectMultiple = false;
  838. if (isMac && event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey)
  839. selectMultiple = true;
  840. if (!isMac && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey)
  841. selectMultiple = true;
  842. if (level === "all")
  843. this._messageLevelFilters = {};
  844. else {
  845. if (!selectMultiple) {
  846. this._messageLevelFilters = {error: true, warning: true, log: true, debug: true};
  847. delete this._messageLevelFilters[level];
  848. } else {
  849. if (this._messageLevelFilters[level])
  850. delete this._messageLevelFilters[level];
  851. else
  852. this._messageLevelFilters[level] = true;
  853. }
  854. }
  855. WebInspector.settings.messageLevelFilters.set(this._messageLevelFilters);
  856. this._filterChanged();
  857. },
  858. /**
  859. * @private
  860. */
  861. _updateLevelFilterBar: function()
  862. {
  863. var all = !(this._messageLevelFilters["error"] || this._messageLevelFilters["warning"] || this._messageLevelFilters["log"] || this._messageLevelFilters["debug"]);
  864. this._filterBarElements["all"].enableStyleClass("selected", all);
  865. this._filterBarElements["error"].enableStyleClass("selected", !all && !this._messageLevelFilters["error"]);
  866. this._filterBarElements["warning"].enableStyleClass("selected", !all && !this._messageLevelFilters["warning"]);
  867. this._filterBarElements["log"].enableStyleClass("selected", !all && !this._messageLevelFilters["log"]);
  868. this._filterBarElements["debug"].enableStyleClass("selected", !all && !this._messageLevelFilters["debug"]);
  869. },
  870. /**
  871. * @param {Event} event
  872. * @private
  873. */
  874. _handleSourceFilterButtonClick: function(event)
  875. {
  876. if (!event.button)
  877. this._createSourceFilterMenu(event).showSoftMenu();
  878. },
  879. __proto__: WebInspector.Object.prototype
  880. };
  881. /**
  882. * @constructor
  883. * @extends WebInspector.ConsoleMessage
  884. */
  885. WebInspector.ConsoleCommand = function(text)
  886. {
  887. this.text = text;
  888. }
  889. WebInspector.ConsoleCommand.prototype = {
  890. wasShown: function()
  891. {
  892. },
  893. willHide: function()
  894. {
  895. },
  896. clearHighlight: function()
  897. {
  898. var highlightedMessage = this._formattedCommand;
  899. delete this._formattedCommand;
  900. this._formatCommand();
  901. this._element.replaceChild(this._formattedCommand, highlightedMessage);
  902. },
  903. /**
  904. * @param {RegExp} regexObject
  905. */
  906. highlightSearchResults: function(regexObject)
  907. {
  908. regexObject.lastIndex = 0;
  909. var match = regexObject.exec(this.text);
  910. var matchRanges = [];
  911. while (match) {
  912. matchRanges.push({ offset: match.index, length: match[0].length });
  913. match = regexObject.exec(this.text);
  914. }
  915. WebInspector.highlightSearchResults(this._formattedCommand, matchRanges);
  916. this._element.scrollIntoViewIfNeeded();
  917. },
  918. /**
  919. * @param {RegExp} regexObject
  920. */
  921. matchesRegex: function(regexObject)
  922. {
  923. regexObject.lastIndex = 0;
  924. return regexObject.test(this.text);
  925. },
  926. toMessageElement: function()
  927. {
  928. if (!this._element) {
  929. this._element = document.createElement("div");
  930. this._element.command = this;
  931. this._element.className = "console-user-command";
  932. this._formatCommand();
  933. this._element.appendChild(this._formattedCommand);
  934. }
  935. return this._element;
  936. },
  937. _formatCommand: function()
  938. {
  939. this._formattedCommand = document.createElement("span");
  940. this._formattedCommand.className = "console-message-text source-code";
  941. this._formattedCommand.textContent = this.text;
  942. },
  943. __proto__: WebInspector.ConsoleMessage.prototype
  944. }
  945. /**
  946. * @extends {WebInspector.ConsoleMessageImpl}
  947. * @constructor
  948. * @param {WebInspector.RemoteObject} result
  949. * @param {boolean} wasThrown
  950. * @param {WebInspector.ConsoleCommand} originatingCommand
  951. * @param {WebInspector.Linkifier} linkifier
  952. * @param {string=} url
  953. * @param {number=} lineNumber
  954. * @param {number=} columnNumber
  955. */
  956. WebInspector.ConsoleCommandResult = function(result, wasThrown, originatingCommand, linkifier, url, lineNumber, columnNumber)
  957. {
  958. var level = (wasThrown ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log);
  959. this.originatingCommand = originatingCommand;
  960. WebInspector.ConsoleMessageImpl.call(this, WebInspector.ConsoleMessage.MessageSource.JS, level, "", linkifier, WebInspector.ConsoleMessage.MessageType.Result, url, lineNumber, columnNumber, undefined, [result]);
  961. }
  962. WebInspector.ConsoleCommandResult.prototype = {
  963. /**
  964. * @override
  965. * @param {WebInspector.RemoteObject} array
  966. * @return {boolean}
  967. */
  968. useArrayPreviewInFormatter: function(array)
  969. {
  970. return false;
  971. },
  972. toMessageElement: function()
  973. {
  974. var element = WebInspector.ConsoleMessageImpl.prototype.toMessageElement.call(this);
  975. element.addStyleClass("console-user-command-result");
  976. return element;
  977. },
  978. __proto__: WebInspector.ConsoleMessageImpl.prototype
  979. }
  980. /**
  981. * @constructor
  982. */
  983. WebInspector.ConsoleGroup = function(parentGroup)
  984. {
  985. this.parentGroup = parentGroup;
  986. var element = document.createElement("div");
  987. element.className = "console-group";
  988. element.group = this;
  989. this.element = element;
  990. if (parentGroup) {
  991. var bracketElement = document.createElement("div");
  992. bracketElement.className = "console-group-bracket";
  993. element.appendChild(bracketElement);
  994. }
  995. var messagesElement = document.createElement("div");
  996. messagesElement.className = "console-group-messages";
  997. element.appendChild(messagesElement);
  998. this.messagesElement = messagesElement;
  999. }
  1000. WebInspector.ConsoleGroup.prototype = {
  1001. /**
  1002. * @param {WebInspector.ConsoleMessage} message
  1003. * @param {Node=} node
  1004. */
  1005. addMessage: function(message, node)
  1006. {
  1007. var element = message.toMessageElement();
  1008. if (message.type === WebInspector.ConsoleMessage.MessageType.StartGroup || message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
  1009. this.messagesElement.parentNode.insertBefore(element, this.messagesElement);
  1010. element.addEventListener("click", this._titleClicked.bind(this), false);
  1011. var groupElement = element.enclosingNodeOrSelfWithClass("console-group");
  1012. if (groupElement && message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed)
  1013. groupElement.addStyleClass("collapsed");
  1014. } else {
  1015. this.messagesElement.insertBefore(element, node || null);
  1016. message.wasShown();
  1017. }
  1018. if (element.previousSibling && message.originatingCommand && element.previousSibling.command === message.originatingCommand)
  1019. element.previousSibling.addStyleClass("console-adjacent-user-command-result");
  1020. },
  1021. _titleClicked: function(event)
  1022. {
  1023. var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title");
  1024. if (groupTitleElement) {
  1025. var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("console-group");
  1026. if (groupElement)
  1027. if (groupElement.hasStyleClass("collapsed"))
  1028. groupElement.removeStyleClass("collapsed");
  1029. else
  1030. groupElement.addStyleClass("collapsed");
  1031. groupTitleElement.scrollIntoViewIfNeeded(true);
  1032. }
  1033. event.consume(true);
  1034. }
  1035. }
  1036. /**
  1037. * @type {?WebInspector.ConsoleView}
  1038. */
  1039. WebInspector.consoleView = null;
  1040. WebInspector.ConsoleMessage.create = function(source, level, message, type, url, line, column, repeatCount, parameters, stackTrace, requestId, isOutdated)
  1041. {
  1042. return new WebInspector.ConsoleMessageImpl(source, level, message, WebInspector.consoleView._linkifier, type, url, line, column, repeatCount, parameters, stackTrace, requestId, isOutdated);
  1043. }