Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(729)

Side by Side Diff: Source/devtools/front_end/console/ConsoleView.js

Issue 676193002: Navigate between individual search matches in DevTools console (Closed) Base URL: https://chromium.googlesource.com/chromium/blink@master
Patch Set: Improve test Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Joseph Pecoraro 3 * Copyright (C) 2009 Joseph Pecoraro
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 this._searchableView = new WebInspector.SearchableView(this); 43 this._searchableView = new WebInspector.SearchableView(this);
44 this._searchableView.setMinimalSearchQuerySize(0); 44 this._searchableView.setMinimalSearchQuerySize(0);
45 this._searchableView.show(this.element); 45 this._searchableView.show(this.element);
46 46
47 this._contentsElement = this._searchableView.element; 47 this._contentsElement = this._searchableView.element;
48 this._contentsElement.classList.add("console-view"); 48 this._contentsElement.classList.add("console-view");
49 this._visibleViewMessages = []; 49 this._visibleViewMessages = [];
50 this._urlToMessageCount = {}; 50 this._urlToMessageCount = {};
51 this._hiddenByFilterCount = 0; 51 this._hiddenByFilterCount = 0;
52 52
53 /**
54 * @type {!Array.<!WebInspector.ConsoleView.RegexMatchRange>}
55 */
56 this._regexMatchRanges = [];
57
53 this._clearConsoleButton = new WebInspector.StatusBarButton(WebInspector.UIS tring("Clear console log."), "clear-status-bar-item"); 58 this._clearConsoleButton = new WebInspector.StatusBarButton(WebInspector.UIS tring("Clear console log."), "clear-status-bar-item");
54 this._clearConsoleButton.addEventListener("click", this._requestClearMessage s, this); 59 this._clearConsoleButton.addEventListener("click", this._requestClearMessage s, this);
55 60
56 this._executionContextSelector = new WebInspector.StatusBarComboBox(this._ex ecutionContextChanged.bind(this), "console-context"); 61 this._executionContextSelector = new WebInspector.StatusBarComboBox(this._ex ecutionContextChanged.bind(this), "console-context");
57 62
58 /** 63 /**
59 * @type {!Map.<!WebInspector.ExecutionContext, !Element>} 64 * @type {!Map.<!WebInspector.ExecutionContext, !Element>}
60 */ 65 */
61 this._optionByExecutionContext = new Map(); 66 this._optionByExecutionContext = new Map();
62 67
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 this._currentGroup = this._currentGroup.parentGroup(); 586 this._currentGroup = this._currentGroup.parentGroup();
582 return; 587 return;
583 } 588 }
584 if (!this._currentGroup.messagesHidden()) { 589 if (!this._currentGroup.messagesHidden()) {
585 var originatingMessage = viewMessage.consoleMessage().originatingMes sage(); 590 var originatingMessage = viewMessage.consoleMessage().originatingMes sage();
586 if (lastMessage && originatingMessage && lastMessage.consoleMessage( ) === originatingMessage) 591 if (lastMessage && originatingMessage && lastMessage.consoleMessage( ) === originatingMessage)
587 lastMessage.toMessageElement().classList.add("console-adjacent-u ser-command-result"); 592 lastMessage.toMessageElement().classList.add("console-adjacent-u ser-command-result");
588 593
589 this._visibleViewMessages.push(viewMessage); 594 this._visibleViewMessages.push(viewMessage);
590 595
591 if (this._searchRegex && viewMessage.matchesRegex(this._searchRegex) ) { 596 if (this._searchRegex && this._searchMessage(this._visibleViewMessag es.length - 1))
592 this._searchResults.push(viewMessage); 597 this._searchableView.updateSearchMatchesCount(this._regexMatchRa nges.length);
593 this._searchableView.updateSearchMatchesCount(this._searchResult s.length);
594 }
595 } 598 }
596 599
597 if (viewMessage.consoleMessage().isGroupStartMessage()) 600 if (viewMessage.consoleMessage().isGroupStartMessage())
598 this._currentGroup = new WebInspector.ConsoleGroup(this._currentGrou p, viewMessage); 601 this._currentGroup = new WebInspector.ConsoleGroup(this._currentGrou p, viewMessage);
599 }, 602 },
600 603
601 /** 604 /**
602 * @param {!WebInspector.ConsoleMessage} message 605 * @param {!WebInspector.ConsoleMessage} message
603 * @return {!WebInspector.ConsoleViewMessage} 606 * @return {!WebInspector.ConsoleViewMessage}
604 */ 607 */
605 _createViewMessage: function(message) 608 _createViewMessage: function(message)
606 { 609 {
607 var nestingLevel = this._currentGroup.nestingLevel(); 610 var nestingLevel = this._currentGroup.nestingLevel();
608 switch (message.type) { 611 switch (message.type) {
609 case WebInspector.ConsoleMessage.MessageType.Command: 612 case WebInspector.ConsoleMessage.MessageType.Command:
610 return new WebInspector.ConsoleCommand(message, this._linkifier, nes tingLevel); 613 return new WebInspector.ConsoleCommand(message, this._linkifier, nes tingLevel);
611 case WebInspector.ConsoleMessage.MessageType.Result: 614 case WebInspector.ConsoleMessage.MessageType.Result:
612 return new WebInspector.ConsoleCommandResult(message, this._linkifie r, nestingLevel); 615 return new WebInspector.ConsoleCommandResult(message, this._linkifie r, nestingLevel);
613 case WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed: 616 case WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed:
614 case WebInspector.ConsoleMessage.MessageType.StartGroup: 617 case WebInspector.ConsoleMessage.MessageType.StartGroup:
615 return new WebInspector.ConsoleGroupViewMessage(message, this._linki fier, nestingLevel); 618 return new WebInspector.ConsoleGroupViewMessage(message, this._linki fier, nestingLevel);
616 default: 619 default:
617 return new WebInspector.ConsoleViewMessage(message, this._linkifier, nestingLevel); 620 return new WebInspector.ConsoleViewMessage(message, this._linkifier, nestingLevel);
618 } 621 }
619 }, 622 },
620 623
621 _consoleCleared: function() 624 _consoleCleared: function()
622 { 625 {
623 this._clearCurrentSearchResultHighlight(); 626 this._clearSearchResultHighlights();
624 this._consoleMessages = []; 627 this._consoleMessages = [];
625 this._updateMessageList(); 628 this._updateMessageList();
626 this._hidePromptSuggestBox(); 629 this._hidePromptSuggestBox();
627 630
628 if (this._searchRegex) 631 if (this._searchRegex)
629 this._searchableView.updateSearchMatchesCount(0); 632 this._searchableView.updateSearchMatchesCount(0);
630 633
631 this._linkifier.reset(); 634 this._linkifier.reset();
632 }, 635 },
633 636
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
692 return true; 695 return true;
693 } 696 }
694 697
695 return false; 698 return false;
696 }, 699 },
697 700
698 _updateMessageList: function() 701 _updateMessageList: function()
699 { 702 {
700 this._topGroup = WebInspector.ConsoleGroup.createTopGroup(); 703 this._topGroup = WebInspector.ConsoleGroup.createTopGroup();
701 this._currentGroup = this._topGroup; 704 this._currentGroup = this._topGroup;
702 this._searchResults = []; 705 this._regexMatchRanges = [];
703 this._hiddenByFilterCount = 0; 706 this._hiddenByFilterCount = 0;
704 for (var i = 0; i < this._visibleViewMessages.length; ++i) { 707 for (var i = 0; i < this._visibleViewMessages.length; ++i) {
705 this._visibleViewMessages[i].resetCloseGroupDecorationCount(); 708 this._visibleViewMessages[i].resetCloseGroupDecorationCount();
706 this._visibleViewMessages[i].resetIncrementRepeatCount(); 709 this._visibleViewMessages[i].resetIncrementRepeatCount();
707 } 710 }
708 this._visibleViewMessages = []; 711 this._visibleViewMessages = [];
709 for (var i = 0; i < this._consoleMessages.length; ++i) 712 for (var i = 0; i < this._consoleMessages.length; ++i)
710 this._appendMessageToEnd(this._consoleMessages[i]); 713 this._appendMessageToEnd(this._consoleMessages[i]);
711 this._updateFilterStatus(); 714 this._updateFilterStatus();
712 this._viewport.invalidate(); 715 this._viewport.invalidate();
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
910 elementsToRestoreScrollPositionsFor: function() 913 elementsToRestoreScrollPositionsFor: function()
911 { 914 {
912 return [this._messagesElement]; 915 return [this._messagesElement];
913 }, 916 },
914 917
915 /** 918 /**
916 * @override 919 * @override
917 */ 920 */
918 searchCanceled: function() 921 searchCanceled: function()
919 { 922 {
920 this._clearCurrentSearchResultHighlight(); 923 this._clearSearchResultHighlights();
921 delete this._searchResults; 924 this._regexMatchRanges = [];
922 delete this._searchRegex; 925 delete this._searchRegex;
923 this._viewport.refresh(); 926 this._viewport.refresh();
924 }, 927 },
925 928
926 /** 929 /**
927 * @override 930 * @override
928 * @param {!WebInspector.SearchableView.SearchConfig} searchConfig 931 * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
929 * @param {boolean} shouldJump 932 * @param {boolean} shouldJump
930 * @param {boolean=} jumpBackwards 933 * @param {boolean=} jumpBackwards
931 */ 934 */
932 performSearch: function(searchConfig, shouldJump, jumpBackwards) 935 performSearch: function(searchConfig, shouldJump, jumpBackwards)
933 { 936 {
934 var query = searchConfig.query; 937 var query = searchConfig.query;
935 this.searchCanceled(); 938 this.searchCanceled();
936 this._searchableView.updateSearchMatchesCount(0); 939 this._searchableView.updateSearchMatchesCount(0);
937 this._searchRegex = createPlainTextSearchRegex(query, "gi"); 940 this._searchRegex = createPlainTextSearchRegex(query, "gi");
938 941
939 /** @type {!Array.<number>} */ 942 this._regexMatchRanges = [];
940 this._searchResults = []; 943 this._currentMatchRangeIndex = -1;
941 for (var i = 0; i < this._visibleViewMessages.length; i++) { 944 for (var i = 0; i < this._visibleViewMessages.length; i++)
942 if (this._visibleViewMessages[i].matchesRegex(this._searchRegex)) 945 this._searchMessage(i);
943 this._searchResults.push(i); 946 this._searchableView.updateSearchMatchesCount(this._regexMatchRanges.len gth);
947 if (shouldJump)
948 this._jumpToMatch(jumpBackwards ? -1 : 0);
949 this._viewport.refresh();
950 },
951
952 /**
953 * @param {number} index
954 * @return {boolean}
955 */
956 _searchMessage: function(index)
957 {
958 // Reset regex wrt. global search.
959 this._searchRegex.lastIndex = 0;
960
961 var message = this._visibleViewMessages[index];
962 var text = message.renderedText();
963 var match;
964 var matchRanges = [];
965 var sourceRanges = [];
966 while ((match = this._searchRegex.exec(text)) && match[0]) {
967 matchRanges.push({
968 messageIndex: index,
969 highlightNode: null,
970 });
971 sourceRanges.push(new WebInspector.SourceRange(match.index, match[0] .length));
944 } 972 }
945 this._searchableView.updateSearchMatchesCount(this._searchResults.length ); 973
946 this._currentSearchResultIndex = -1; 974 var matchRange;
947 if (shouldJump && this._searchResults.length) 975 var highlightNodes = message.highlightMatches(sourceRanges);
948 this._jumpToSearchResult(jumpBackwards ? -1 : 0); 976 for (var i = 0; i < matchRanges.length; ++i) {
949 this._viewport.refresh(); 977 matchRange = matchRanges[i];
978 matchRange.highlightNode = highlightNodes[i];
979 this._regexMatchRanges.push(matchRange);
980 }
981
982 return !!matchRange;
950 }, 983 },
951 984
952 /** 985 /**
953 * @override 986 * @override
954 */ 987 */
955 jumpToNextSearchResult: function() 988 jumpToNextSearchResult: function()
956 { 989 {
957 if (!this._searchResults || !this._searchResults.length) 990 this._jumpToMatch(this._currentMatchRangeIndex + 1);
958 return;
959 this._jumpToSearchResult(this._currentSearchResultIndex + 1);
960 }, 991 },
961 992
962 /** 993 /**
963 * @override 994 * @override
964 */ 995 */
965 jumpToPreviousSearchResult: function() 996 jumpToPreviousSearchResult: function()
966 { 997 {
967 if (!this._searchResults || !this._searchResults.length) 998 this._jumpToMatch(this._currentMatchRangeIndex - 1);
968 return;
969 this._jumpToSearchResult(this._currentSearchResultIndex - 1);
970 }, 999 },
971 1000
972 /** 1001 /**
973 * @override 1002 * @override
974 * @return {boolean} 1003 * @return {boolean}
975 */ 1004 */
976 supportsCaseSensitiveSearch: function() 1005 supportsCaseSensitiveSearch: function()
977 { 1006 {
978 return false; 1007 return false;
979 }, 1008 },
980 1009
981 /** 1010 /**
982 * @override 1011 * @override
983 * @return {boolean} 1012 * @return {boolean}
984 */ 1013 */
985 supportsRegexSearch: function() 1014 supportsRegexSearch: function()
986 { 1015 {
987 return false; 1016 return false;
988 }, 1017 },
989 1018
990 _clearCurrentSearchResultHighlight: function() 1019 _clearSearchResultHighlights: function()
991 { 1020 {
992 if (!this._searchResults) 1021 for (var i = 0; i < this._regexMatchRanges.length; ++i) {
1022 var matchRange = this._regexMatchRanges[i];
1023 var message = this._visibleViewMessages[matchRange.messageIndex];
lushnikov 2014/12/17 13:21:23 You should not call clearHighlights() more then on
aknudsen 2014/12/21 17:58:23 Acknowledged.
aknudsen 2014/12/21 20:00:09 Done.
1024 if (message)
1025 message.clearHighlights();
1026 }
1027 this._currentMatchRangeIndex = -1;
1028 },
1029
1030 /**
1031 * @param {number} index
1032 */
1033 _jumpToMatch: function(index)
1034 {
1035 if (!this._regexMatchRanges.length)
993 return; 1036 return;
994 1037
995 var highlightedViewMessage = this._visibleViewMessages[this._searchResul ts[this._currentSearchResultIndex]]; 1038 var currentSearchResultClassName = "current-search-result";
996 if (highlightedViewMessage)
997 highlightedViewMessage.clearHighlight();
998 this._currentSearchResultIndex = -1;
999 },
1000 1039
1001 _jumpToSearchResult: function(index) 1040 var matchRange;
1002 { 1041 if (this._currentMatchRangeIndex >= 0) {
1003 index = mod(index, this._searchResults.length); 1042 matchRange = this._regexMatchRanges[this._currentMatchRangeIndex];
1004 this._clearCurrentSearchResultHighlight(); 1043 matchRange.highlightNode.classList.remove(currentSearchResultClassNa me);
1005 this._currentSearchResultIndex = index; 1044 }
1006 this._searchableView.updateCurrentMatchIndex(this._currentSearchResultIn dex); 1045
1007 var currentViewMessageIndex = this._searchResults[index]; 1046 index = mod(index, this._regexMatchRanges.length);
1008 this._viewport.scrollItemIntoView(currentViewMessageIndex); 1047 this._currentMatchRangeIndex = index;
1009 this._visibleViewMessages[currentViewMessageIndex].highlightSearchResult s(this._searchRegex); 1048 this._searchableView.updateCurrentMatchIndex(index);
1049 matchRange = this._regexMatchRanges[index];
1050 matchRange.highlightNode.classList.add(currentSearchResultClassName);
1051 // Scroll the message itself into view
lushnikov 2014/12/17 13:21:23 can we get rid of these comments?
aknudsen 2014/12/21 17:58:23 Do you want to also remove the comments at 1053-10
lushnikov 2014/12/23 13:43:33 I'd prefer it to, yes
aknudsen 2014/12/24 11:08:06 Done.
1052 this._viewport.scrollItemIntoView(matchRange.messageIndex);
1053 // In case the highlight node is in a tree element, it must be scrolled into view,
1054 // the message itself must first be scrolled into view though.
1055 matchRange.highlightNode.scrollIntoViewIfNeeded();
1010 }, 1056 },
1011 1057
1012 __proto__: WebInspector.VBox.prototype 1058 __proto__: WebInspector.VBox.prototype
1013 } 1059 }
1014 1060
1015 /** 1061 /**
1016 * @constructor 1062 * @constructor
1017 * @extends {WebInspector.Object} 1063 * @extends {WebInspector.Object}
1018 * @param {!WebInspector.ConsoleView} view 1064 * @param {!WebInspector.ConsoleView} view
1019 */ 1065 */
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
1153 * @param {!WebInspector.ConsoleMessage} message 1199 * @param {!WebInspector.ConsoleMessage} message
1154 * @param {!WebInspector.Linkifier} linkifier 1200 * @param {!WebInspector.Linkifier} linkifier
1155 * @param {number} nestingLevel 1201 * @param {number} nestingLevel
1156 */ 1202 */
1157 WebInspector.ConsoleCommand = function(message, linkifier, nestingLevel) 1203 WebInspector.ConsoleCommand = function(message, linkifier, nestingLevel)
1158 { 1204 {
1159 WebInspector.ConsoleViewMessage.call(this, message, linkifier, nestingLevel) ; 1205 WebInspector.ConsoleViewMessage.call(this, message, linkifier, nestingLevel) ;
1160 } 1206 }
1161 1207
1162 WebInspector.ConsoleCommand.prototype = { 1208 WebInspector.ConsoleCommand.prototype = {
1163 clearHighlight: function() 1209 clearHighlights: function()
1164 { 1210 {
1165 var highlightedMessage = this._formattedCommand; 1211 var highlightedMessage = this._formattedCommand;
1166 delete this._formattedCommand; 1212 delete this._formattedCommand;
1167 this._formatCommand(); 1213 this._formatCommand();
1168 this._element.replaceChild(this._formattedCommand, highlightedMessage); 1214 this._element.replaceChild(this._formattedCommand, highlightedMessage);
1169 }, 1215 },
1170 1216
1171 /** 1217 /**
1172 * @param {!RegExp} regexObject
1173 */
1174 highlightSearchResults: function(regexObject)
1175 {
1176 regexObject.lastIndex = 0;
1177 var match = regexObject.exec(this.text);
1178 var matchRanges = [];
1179 while (match) {
1180 matchRanges.push(new WebInspector.SourceRange(match.index, match[0]. length));
1181 match = regexObject.exec(this.text);
1182 }
1183 WebInspector.highlightSearchResults(this._formattedCommand, matchRanges) ;
1184 this._element.scrollIntoViewIfNeeded();
1185 },
1186
1187 /**
1188 * @override 1218 * @override
1189 * @param {!RegExp} regexObject 1219 * @param {!RegExp} regexObject
1190 * @return {boolean} 1220 * @return {boolean}
1191 */ 1221 */
1192 matchesRegex: function(regexObject) 1222 matchesRegex: function(regexObject)
1193 { 1223 {
1194 regexObject.lastIndex = 0; 1224 regexObject.lastIndex = 0;
1195 return regexObject.test(this.text); 1225 return regexObject.test(this.text);
1196 }, 1226 },
1197 1227
(...skipping 12 matching lines...) Expand all
1210 } 1240 }
1211 return this._element; 1241 return this._element;
1212 }, 1242 },
1213 1243
1214 _formatCommand: function() 1244 _formatCommand: function()
1215 { 1245 {
1216 this._formattedCommand = createElementWithClass("span", "console-message -text source-code"); 1246 this._formattedCommand = createElementWithClass("span", "console-message -text source-code");
1217 this._formattedCommand.textContent = this.text; 1247 this._formattedCommand.textContent = this.text;
1218 }, 1248 },
1219 1249
1250 /**
1251 * @override
1252 * @return {string}
1253 */
1254 renderedText: function()
1255 {
1256 return this.text;
1257 },
1258
1259 /**
1260 * @override
1261 * @param {!Array.<!Object>} ranges
1262 * @return {!Array.<!Element>}
1263 */
1264 highlightMatches: function(ranges)
1265 {
1266 var highlightNodes = [];
1267 if (this._formattedCommand) {
1268 highlightNodes = WebInspector.highlightRangesWithStyleClass(this._fo rmattedCommand, ranges, WebInspector.highlightedSearchResultClassName);
1269 }
1270 return highlightNodes;
1271 },
1272
1220 __proto__: WebInspector.ConsoleViewMessage.prototype 1273 __proto__: WebInspector.ConsoleViewMessage.prototype
1221 } 1274 }
1222 1275
1223 /** 1276 /**
1224 * @constructor 1277 * @constructor
1225 * @extends {WebInspector.ConsoleViewMessage} 1278 * @extends {WebInspector.ConsoleViewMessage}
1226 * @param {!WebInspector.ConsoleMessage} message 1279 * @param {!WebInspector.ConsoleMessage} message
1227 * @param {!WebInspector.Linkifier} linkifier 1280 * @param {!WebInspector.Linkifier} linkifier
1228 * @param {number} nestingLevel 1281 * @param {number} nestingLevel
1229 */ 1282 */
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
1316 /** 1369 /**
1317 * @override 1370 * @override
1318 * @return {boolean} 1371 * @return {boolean}
1319 */ 1372 */
1320 handleAction: function() 1373 handleAction: function()
1321 { 1374 {
1322 WebInspector.console.show(); 1375 WebInspector.console.show();
1323 return true; 1376 return true;
1324 } 1377 }
1325 } 1378 }
1379
1380 /**
1381 * @typedef {{messageIndex: number, highlightNode: !Element}}
1382 */
1383 WebInspector.ConsoleView.RegexMatchRange;
OLDNEW
« no previous file with comments | « LayoutTests/inspector/console/console-search-expected.txt ('k') | Source/devtools/front_end/console/ConsoleViewMessage.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698