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

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

Issue 2179123004: DevTools: fix stick to bottom in console viewport (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Visible ranges too Created 4 years, 4 months 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 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 /** @type {!Array.<!WebInspector.ConsoleViewMessage>} */ 129 /** @type {!Array.<!WebInspector.ConsoleViewMessage>} */
130 this._consoleMessages = []; 130 this._consoleMessages = [];
131 this._viewMessageSymbol = Symbol("viewMessage"); 131 this._viewMessageSymbol = Symbol("viewMessage");
132 132
133 this._prompt = new WebInspector.TextPromptWithHistory(WebInspector.Execution ContextSelector.completionsForTextPromptInCurrentContext); 133 this._prompt = new WebInspector.TextPromptWithHistory(WebInspector.Execution ContextSelector.completionsForTextPromptInCurrentContext);
134 this._prompt.setSuggestBoxEnabled(true); 134 this._prompt.setSuggestBoxEnabled(true);
135 this._prompt.setAutocompletionTimeout(0); 135 this._prompt.setAutocompletionTimeout(0);
136 this._prompt.renderAsBlock(); 136 this._prompt.renderAsBlock();
137 var proxyElement = this._prompt.attach(this._promptElement); 137 var proxyElement = this._prompt.attach(this._promptElement);
138 proxyElement.addEventListener("keydown", this._promptKeyDown.bind(this), fal se); 138 proxyElement.addEventListener("keydown", this._promptKeyDown.bind(this), fal se);
139 proxyElement.addEventListener("input", this._promptInput.bind(this), false);
139 140
140 this._consoleHistorySetting = WebInspector.settings.createLocalSetting("cons oleHistory", []); 141 this._consoleHistorySetting = WebInspector.settings.createLocalSetting("cons oleHistory", []);
141 var historyData = this._consoleHistorySetting.get(); 142 var historyData = this._consoleHistorySetting.get();
142 this._prompt.history().setHistoryData(historyData); 143 this._prompt.history().setHistoryData(historyData);
143 144
144 this._consoleHistoryAutocompleteSetting = WebInspector.moduleSetting("consol eHistoryAutocomplete"); 145 this._consoleHistoryAutocompleteSetting = WebInspector.moduleSetting("consol eHistoryAutocomplete");
145 this._consoleHistoryAutocompleteSetting.addChangeListener(this._consoleHisto ryAutocompleteChanged, this); 146 this._consoleHistoryAutocompleteSetting.addChangeListener(this._consoleHisto ryAutocompleteChanged, this);
146 this._consoleHistoryAutocompleteChanged(); 147 this._consoleHistoryAutocompleteChanged();
147 148
148 this._updateFilterStatus(); 149 this._updateFilterStatus();
149 WebInspector.moduleSetting("consoleTimestampsEnabled").addChangeListener(thi s._consoleTimestampsSettingChanged, this); 150 WebInspector.moduleSetting("consoleTimestampsEnabled").addChangeListener(thi s._consoleTimestampsSettingChanged, this);
150 151
151 this._registerWithMessageSink(); 152 this._registerWithMessageSink();
152 WebInspector.targetManager.observeTargets(this); 153 WebInspector.targetManager.observeTargets(this);
153 154
154 this._initConsoleMessages(); 155 this._initConsoleMessages();
155 156
156 WebInspector.context.addFlavorChangeListener(WebInspector.ExecutionContext, this._executionContextChanged, this); 157 WebInspector.context.addFlavorChangeListener(WebInspector.ExecutionContext, this._executionContextChanged, this);
158
159 this._messagesElement.addEventListener("mousedown", this._updateStickToBotto mOnMouseDown.bind(this), false);
160 this._messagesElement.addEventListener("mouseup", this._updateStickToBottomO nMouseUp.bind(this), false);
161 this._messagesElement.addEventListener("mouseleave", this._updateStickToBott omOnMouseUp.bind(this), false);
162 this._messagesElement.addEventListener("wheel", this._updateStickToBottomOnW heel.bind(this), false);
157 } 163 }
158 164
159 WebInspector.ConsoleView.persistedHistorySize = 300; 165 WebInspector.ConsoleView.persistedHistorySize = 300;
160 166
161 WebInspector.ConsoleView.prototype = { 167 WebInspector.ConsoleView.prototype = {
162 /** 168 /**
163 * @return {!WebInspector.SearchableView} 169 * @return {!WebInspector.SearchableView}
164 */ 170 */
165 searchableView: function() 171 searchableView: function()
166 { 172 {
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 if (this._promptElement === WebInspector.currentFocusElement()) 343 if (this._promptElement === WebInspector.currentFocusElement())
338 return; 344 return;
339 // Set caret position before setting focus in order to avoid scrolling 345 // Set caret position before setting focus in order to avoid scrolling
340 // by focus(). 346 // by focus().
341 this._prompt.moveCaretToEndOfPrompt(); 347 this._prompt.moveCaretToEndOfPrompt();
342 WebInspector.setCurrentFocusElement(this._promptElement); 348 WebInspector.setCurrentFocusElement(this._promptElement);
343 }, 349 },
344 350
345 restoreScrollPositions: function() 351 restoreScrollPositions: function()
346 { 352 {
347 if (this._viewport.scrolledToBottom()) 353 if (this._viewport.stickToBottom())
348 this._immediatelyScrollToBottom(); 354 this._immediatelyScrollToBottom();
349 else 355 else
350 WebInspector.Widget.prototype.restoreScrollPositions.call(this); 356 WebInspector.Widget.prototype.restoreScrollPositions.call(this);
351 }, 357 },
352 358
353 onResize: function() 359 onResize: function()
354 { 360 {
355 this._scheduleViewportRefresh(); 361 this._scheduleViewportRefresh();
356 this._hidePromptSuggestBox(); 362 this._hidePromptSuggestBox();
357 if (this._viewport.scrolledToBottom()) 363 if (this._viewport.stickToBottom())
358 this._immediatelyScrollToBottom(); 364 this._immediatelyScrollToBottom();
359 for (var i = 0; i < this._visibleViewMessages.length; ++i) 365 for (var i = 0; i < this._visibleViewMessages.length; ++i)
360 this._visibleViewMessages[i].onResize(); 366 this._visibleViewMessages[i].onResize();
361 }, 367 },
362 368
363 _hidePromptSuggestBox: function() 369 _hidePromptSuggestBox: function()
364 { 370 {
365 this._prompt.hideSuggestBox(); 371 this._prompt.hideSuggestBox();
366 this._prompt.clearAutoComplete(true); 372 this._prompt.clearAutoComplete(true);
367 }, 373 },
368 374
369 _scheduleViewportRefresh: function() 375 _scheduleViewportRefresh: function()
370 { 376 {
371 /** 377 /**
372 * @this {WebInspector.ConsoleView} 378 * @this {WebInspector.ConsoleView}
373 * @return {!Promise.<undefined>} 379 * @return {!Promise.<undefined>}
374 */ 380 */
375 function invalidateViewport() 381 function invalidateViewport()
376 { 382 {
383 if (this._muteViewportUpdates) {
384 this._maybeDirtyWhileMuted = true;
385 return Promise.resolve();
386 }
377 if (this._needsFullUpdate) { 387 if (this._needsFullUpdate) {
378 this._updateMessageList(); 388 this._updateMessageList();
379 delete this._needsFullUpdate; 389 delete this._needsFullUpdate;
380 } else { 390 } else {
381 this._viewport.invalidate(); 391 this._viewport.invalidate();
382 } 392 }
383 return Promise.resolve(); 393 return Promise.resolve();
384 } 394 }
395 if (this._muteViewportUpdates) {
396 this._maybeDirtyWhileMuted = true;
397 this._scheduleViewportRefreshForTest(true);
398 return;
399 } else {
400 this._scheduleViewportRefreshForTest(false);
401 }
385 this._viewportThrottler.schedule(invalidateViewport.bind(this)); 402 this._viewportThrottler.schedule(invalidateViewport.bind(this));
386 }, 403 },
387 404
405 /**
406 * @param {boolean} muted
407 */
408 _scheduleViewportRefreshForTest: function(muted)
409 {
410 // This functions is sniffed in tests.
411 },
412
388 _immediatelyScrollToBottom: function() 413 _immediatelyScrollToBottom: function()
389 { 414 {
390 // This will scroll viewport and trigger its refresh. 415 // This will scroll viewport and trigger its refresh.
416 this._viewport.setStickToBottom(true);
391 this._promptElement.scrollIntoView(true); 417 this._promptElement.scrollIntoView(true);
392 }, 418 },
393 419
394 _updateFilterStatus: function() 420 _updateFilterStatus: function()
395 { 421 {
396 this._filterStatusTextElement.textContent = WebInspector.UIString(this._ hiddenByFilterCount === 1 ? "%d message is hidden by filters." : "%d messages ar e hidden by filters.", this._hiddenByFilterCount); 422 this._filterStatusTextElement.textContent = WebInspector.UIString(this._ hiddenByFilterCount === 1 ? "%d message is hidden by filters." : "%d messages ar e hidden by filters.", this._hiddenByFilterCount);
397 this._filterStatusMessageElement.style.display = this._hiddenByFilterCou nt ? "" : "none"; 423 this._filterStatusMessageElement.style.display = this._hiddenByFilterCou nt ? "" : "none";
398 }, 424 },
399 425
400 /** 426 /**
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Enter), WebInspecto r.UIString("Execute command")); 763 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Enter), WebInspecto r.UIString("Execute command"));
738 }, 764 },
739 765
740 _clearPromptBackwards: function() 766 _clearPromptBackwards: function()
741 { 767 {
742 this._prompt.setText(""); 768 this._prompt.setText("");
743 }, 769 },
744 770
745 _promptKeyDown: function(event) 771 _promptKeyDown: function(event)
746 { 772 {
747 if (isEnterKey(event)) { 773 if (event.key === "PageUp") {
luoe 2016/08/12 18:18:12 Remove this
774 this._updateStickToBottomOnWheel();
775 } else if (isEnterKey(event)) {
748 this._enterKeyPressed(event); 776 this._enterKeyPressed(event);
749 return; 777 return;
750 } 778 }
751 779
752 var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event); 780 var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
753 var handler = this._shortcuts[shortcut]; 781 var handler = this._shortcuts[shortcut];
754 if (handler) { 782 if (handler) {
755 handler(); 783 handler();
756 event.preventDefault(); 784 event.preventDefault();
757 } 785 }
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
988 this._currentMatchRangeIndex = index; 1016 this._currentMatchRangeIndex = index;
989 this._searchableView.updateCurrentMatchIndex(index); 1017 this._searchableView.updateCurrentMatchIndex(index);
990 matchRange = this._regexMatchRanges[index]; 1018 matchRange = this._regexMatchRanges[index];
991 var message = this._visibleViewMessages[matchRange.messageIndex]; 1019 var message = this._visibleViewMessages[matchRange.messageIndex];
992 var highlightNode = message.searchHighlightNode(matchRange.matchIndex); 1020 var highlightNode = message.searchHighlightNode(matchRange.matchIndex);
993 highlightNode.classList.add(WebInspector.highlightedCurrentSearchResultC lassName); 1021 highlightNode.classList.add(WebInspector.highlightedCurrentSearchResultC lassName);
994 this._viewport.scrollItemIntoView(matchRange.messageIndex); 1022 this._viewport.scrollItemIntoView(matchRange.messageIndex);
995 highlightNode.scrollIntoViewIfNeeded(); 1023 highlightNode.scrollIntoViewIfNeeded();
996 }, 1024 },
997 1025
1026 _updateStickToBottomOnMouseDown: function()
1027 {
1028 this._muteViewportUpdates = true;
1029 this._viewport.setStickToBottom(false);
1030 if (this._waitForScrollTimeout) {
1031 clearTimeout(this._waitForScrollTimeout);
1032 delete this._waitForScrollTimeout;
1033 }
1034 },
1035
1036 _updateStickToBottomOnMouseUp: function()
1037 {
1038 if (!this._muteViewportUpdates)
1039 return;
1040
1041 var selectedRange = cloneRange(this._viewport.getVisibleRange());
1042 var isSelectionInPrompt = selectedRange && selectedRange.startContainer === this._promptElement;
1043 var isMessagesSelected = selectedRange && this._messagesElement.isSelfOr Ancestor(selectedRange.startContainer);
1044
1045 // Delay querying isScrolledToBottom to give time for smooth scroll
1046 // events to arrive. The value for the longest timeout duration is
1047 // retrieved from crbug.com/575409. Force the viewport to stop sticking
1048 // and allow keyboard navigation of the viewport (native behavior) when
1049 // the user selects a new range inside viewport messages.
1050 if (isMessagesSelected && !isSelectionInPrompt && !rangesAreEqual(select edRange, this._lastSelectedRange))
1051 this._waitForScrollTimeout = setTimeout(updateViewportState.bind(thi s, false), 200);
1052 else
1053 this._waitForScrollTimeout = setTimeout(updateViewportState.bind(thi s), 200);
1054 this._lastSelectedRange = selectedRange;
1055
1056 /**
1057 * @param {?{startContainer: ?Node, startOffset: number, endContainer: ? Node, endOffset: number, collapsed: boolean}} range1
1058 * @param {?{startContainer: ?Node, startOffset: number, endContainer: ? Node, endOffset: number, collapsed: boolean}} range2
1059 * @return {boolean}
1060 */
1061 function rangesAreEqual(range1, range2)
1062 {
1063 var collapsedOrNull1 = !range1 || range1.collapsed;
1064 var collapsedOrNull2 = !range2 || range2.collapsed;
1065 if (collapsedOrNull1 && collapsedOrNull2)
1066 return true;
1067 else if (collapsedOrNull1 !== collapsedOrNull2)
1068 return false;
1069 return range1.startContainer === range2.startContainer &&
1070 range1.startOffset === range2.startOffset &&
1071 range1.endContainer === range2.endContainer &&
1072 range1.endOffset === range2.endOffset &&
1073 range1.collapsed === range2.collapsed;
1074 }
1075
1076 /**
1077 * @param {?Range} range
1078 * @return {?{startContainer: ?Node, startOffset: number, endContainer: ?Node, endOffset: number, collapsed: boolean}}
1079 */
1080 function cloneRange(range)
1081 {
1082 // Return a safe copy of Range data just in case the native Range
1083 // has changed without notice after DOM mutation.
1084 if (!range)
1085 return range;
1086 return {
1087 startContainer: range.startContainer,
1088 startOffset: range.startOffset,
1089 endContainer: range.endContainer,
1090 endOffset: range.endOffset,
1091 collapsed: range.collapsed
1092 };
1093 }
1094
1095 /**
1096 * @this {!WebInspector.ConsoleView}
1097 * @param {boolean=} shouldStickToBottom
1098 */
1099 function updateViewportState(shouldStickToBottom)
1100 {
1101 if (typeof shouldStickToBottom === "undefined")
1102 shouldStickToBottom = this._messagesElement.isScrolledToBottom() ;
1103 this._viewport.setStickToBottom(shouldStickToBottom);
1104 this._muteViewportUpdates = false;
1105 if (this._maybeDirtyWhileMuted) {
1106 this._scheduleViewportRefresh();
1107 delete this._maybeDirtyWhileMuted;
1108 }
1109 delete this._waitForScrollTimeout;
1110 this._updateViewportStickinessForTest();
1111 }
1112 },
1113
1114 _updateViewportStickinessForTest: function()
1115 {
1116 // This method is sniffed in tests.
1117 },
1118
1119 _updateStickToBottomOnWheel: function()
1120 {
1121 this._updateStickToBottomOnMouseDown();
1122 this._updateStickToBottomOnMouseUp();
1123 },
1124
1125 _promptInput: function(event)
1126 {
1127 // Scroll to the bottom, except when the prompt is the only visible item .
1128 if (this.itemCount() !== 0 && this._viewport.firstVisibleIndex() !== thi s.itemCount())
1129 this._immediatelyScrollToBottom();
1130 },
1131
998 __proto__: WebInspector.VBox.prototype 1132 __proto__: WebInspector.VBox.prototype
999 } 1133 }
1000 1134
1001 /** 1135 /**
1002 * @constructor 1136 * @constructor
1003 * @extends {WebInspector.Object} 1137 * @extends {WebInspector.Object}
1004 * @param {!WebInspector.ConsoleView} view 1138 * @param {!WebInspector.ConsoleView} view
1005 */ 1139 */
1006 WebInspector.ConsoleViewFilter = function(view) 1140 WebInspector.ConsoleViewFilter = function(view)
1007 { 1141 {
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after
1330 return true; 1464 return true;
1331 } 1465 }
1332 return false; 1466 return false;
1333 } 1467 }
1334 } 1468 }
1335 1469
1336 /** 1470 /**
1337 * @typedef {{messageIndex: number, matchIndex: number}} 1471 * @typedef {{messageIndex: number, matchIndex: number}}
1338 */ 1472 */
1339 WebInspector.ConsoleView.RegexMatchRange; 1473 WebInspector.ConsoleView.RegexMatchRange;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698