blob: dbc9a520da03dd815a30e84a66a3b95064177329 [file] [log] [blame]
/*
* Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
// FIXME: <https://webkit.org/b/143545> Web Inspector: LogContentView should use higher level objects
WI.LogContentView = class LogContentView extends WI.ContentView
{
constructor(representedObject)
{
super(representedObject);
this._nestingLevel = 0;
this._selectedMessages = [];
// FIXME: Try to use a marker, instead of a list of messages that get re-added.
this._provisionalMessages = [];
this.element.classList.add("log");
this.messagesElement = document.createElement("div");
this.messagesElement.classList.add("console-messages");
this.messagesElement.tabIndex = 0;
this.messagesElement.setAttribute("role", "log");
this.messagesElement.addEventListener("mousedown", this._mousedown.bind(this));
this.messagesElement.addEventListener("keydown", this._keyDown.bind(this));
this.messagesElement.addEventListener("keypress", this._keyPress.bind(this));
this.messagesElement.addEventListener("dragstart", this._ondragstart.bind(this), true);
this.element.appendChild(this.messagesElement);
this.prompt = WI.quickConsole.prompt;
this._keyboardShortcutCommandA = new WI.KeyboardShortcut(WI.KeyboardShortcut.Modifier.CommandOrControl, "A");
this._keyboardShortcutEsc = new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Escape);
this._logViewController = new WI.JavaScriptLogViewController(this.messagesElement, this.element, this.prompt, this, "console-prompt-history");
this._lastMessageView = null;
const fixed = true;
this._findBanner = new WI.FindBanner(this, "console-find-banner", fixed);
this._findBanner.targetElement = this.element;
this._currentSearchQuery = "";
this._searchMatches = [];
this._selectedSearchMatch = null;
this._selectedSearchMatchIsValid = false;
var scopeBarItems = [
new WI.ScopeBarItem(WI.LogContentView.Scopes.All, WI.UIString("All"), true),
new WI.ScopeBarItem(WI.LogContentView.Scopes.Errors, WI.UIString("Errors"), false, "errors"),
new WI.ScopeBarItem(WI.LogContentView.Scopes.Warnings, WI.UIString("Warnings"), false, "warnings"),
new WI.ScopeBarItem(WI.LogContentView.Scopes.Logs, WI.UIString("Logs"), false, "logs")
];
this._scopeBar = new WI.ScopeBar("log-scope-bar", scopeBarItems, scopeBarItems[0]);
this._scopeBar.addEventListener(WI.ScopeBar.Event.SelectionChanged, this._scopeBarSelectionDidChange, this);
this._garbageCollectNavigationItem = new WI.ButtonNavigationItem("clear-log", WI.UIString("Collect garbage"), "Images/NavigationItemGarbageCollect.svg", 16, 16);
this._garbageCollectNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
this._garbageCollectNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._garbageCollect, this);
this._clearLogNavigationItem = new WI.ButtonNavigationItem("clear-log", WI.UIString("Clear log (%s or %s)").format(WI.clearKeyboardShortcut.displayName, this._logViewController.messagesAlternateClearKeyboardShortcut.displayName), "Images/NavigationItemClear.svg", 16, 16);
this._clearLogNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
this._clearLogNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._clearLog, this);
this._showConsoleTabNavigationItem = new WI.ButtonNavigationItem("show-tab", WI.UIString("Show Console tab"), "Images/SplitToggleUp.svg", 16, 16);
this._showConsoleTabNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High;
this._showConsoleTabNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._showConsoleTab, this);
this.messagesElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
WI.logManager.addEventListener(WI.LogManager.Event.SessionStarted, this._sessionStarted, this);
WI.logManager.addEventListener(WI.LogManager.Event.MessageAdded, this._messageAdded, this);
WI.logManager.addEventListener(WI.LogManager.Event.PreviousMessageRepeatCountUpdated, this._previousMessageRepeatCountUpdated, this);
WI.logManager.addEventListener(WI.LogManager.Event.Cleared, this._logCleared, this);
WI.Frame.addEventListener(WI.Frame.Event.ProvisionalLoadStarted, this._provisionalLoadStarted, this);
}
// Public
get navigationItems()
{
let navigationItems = [this._scopeBar];
if (HeapAgent.gc)
navigationItems.push(this._garbageCollectNavigationItem);
navigationItems.push(this._clearLogNavigationItem);
if (WI.isShowingSplitConsole())
navigationItems.push(this._showConsoleTabNavigationItem);
else if (WI.isShowingConsoleTab())
navigationItems.unshift(this._findBanner);
return navigationItems;
}
get scopeBar()
{
return this._scopeBar;
}
get logViewController()
{
return this._logViewController;
}
get scrollableElements()
{
return [this.element];
}
get shouldKeepElementsScrolledToBottom()
{
return true;
}
shown()
{
super.shown();
this._logViewController.renderPendingMessages();
}
didAppendConsoleMessageView(messageView)
{
console.assert(messageView instanceof WI.ConsoleMessageView || messageView instanceof WI.ConsoleCommandView);
// Nest the message.
var type = messageView instanceof WI.ConsoleCommandView ? null : messageView.message.type;
if (this._nestingLevel && type !== WI.ConsoleMessage.MessageType.EndGroup) {
var x = 16 * this._nestingLevel;
var messageElement = messageView.element;
messageElement.style.left = x + "px";
messageElement.style.width = "calc(100% - " + x + "px)";
}
// Update the nesting level.
switch (type) {
case WI.ConsoleMessage.MessageType.StartGroup:
case WI.ConsoleMessage.MessageType.StartGroupCollapsed:
++this._nestingLevel;
break;
case WI.ConsoleMessage.MessageType.EndGroup:
if (this._nestingLevel > 0)
--this._nestingLevel;
break;
}
this._clearFocusableChildren();
// Some results don't populate until further backend dispatches occur (like the DOM tree).
// We want to remove focusable children after those pending dispatches too.
let target = messageView.message ? messageView.message.target : WI.runtimeManager.activeExecutionContext.target;
target.connection.runAfterPendingDispatches(this._clearFocusableChildren.bind(this));
if (type && type !== WI.ConsoleMessage.MessageType.EndGroup) {
console.assert(messageView.message instanceof WI.ConsoleMessage);
if (!(messageView.message instanceof WI.ConsoleCommandResultMessage))
this._markScopeBarItemUnread(messageView.message.level);
console.assert(messageView.element instanceof Element);
this._filterMessageElements([messageView.element]);
}
}
get supportsSearch() { return true; }
get numberOfSearchResults() { return this.hasPerformedSearch ? this._searchMatches.length : null; }
get hasPerformedSearch() { return this._currentSearchQuery !== ""; }
get supportsCustomFindBanner()
{
return WI.isShowingConsoleTab();
}
showCustomFindBanner()
{
if (!this.visible)
return;
this._findBanner.focus();
}
get supportsSave()
{
if (!this.visible)
return false;
if (WI.isShowingSplitConsole())
return false;
return true;
}
get saveData()
{
return {url: "web-inspector:///Console.txt", content: this._formatMessagesAsData(false), forceSaveAs: true};
}
handleCopyEvent(event)
{
if (!this._selectedMessages.length)
return;
event.clipboardData.setData("text/plain", this._formatMessagesAsData(true));
event.stopPropagation();
event.preventDefault();
}
handleClearShortcut(event)
{
this._logViewController.requestClearMessages();
}
handlePopulateFindShortcut()
{
let searchQuery = this.searchQueryWithSelection();
if (!searchQuery)
return;
this._findBanner.searchQuery = searchQuery;
this.performSearch(this._findBanner.searchQuery);
}
handleFindNextShortcut()
{
this.findBannerRevealNextResult(this._findBanner);
}
handleFindPreviousShortcut()
{
this.findBannerRevealPreviousResult(this._findBanner);
}
findBannerRevealPreviousResult()
{
this.highlightPreviousSearchMatch();
}
highlightPreviousSearchMatch()
{
if (!this.hasPerformedSearch || isEmptyObject(this._searchMatches))
return;
var index = this._selectedSearchMatch ? this._searchMatches.indexOf(this._selectedSearchMatch) : this._searchMatches.length;
this._highlightSearchMatchAtIndex(index - 1);
}
findBannerRevealNextResult()
{
this.highlightNextSearchMatch();
}
highlightNextSearchMatch()
{
if (!this.hasPerformedSearch || isEmptyObject(this._searchMatches))
return;
var index = this._selectedSearchMatch ? this._searchMatches.indexOf(this._selectedSearchMatch) + 1 : 0;
this._highlightSearchMatchAtIndex(index);
}
findBannerWantsToClearAndBlur(findBanner)
{
if (this._selectedMessages.length)
this.messagesElement.focus();
else
this.prompt.focus();
}
// Protected
layout()
{
this._scrollElementHeight = this.messagesElement.getBoundingClientRect().height;
}
// Private
_formatMessagesAsData(onlySelected)
{
var messages = this._allMessageElements();
if (onlySelected) {
messages = messages.filter(function(message) {
return message.classList.contains(WI.LogContentView.SelectedStyleClassName);
});
}
var data = "";
var isPrefixOptional = messages.length <= 1 && onlySelected;
messages.forEach(function(messageElement, index) {
var messageView = messageElement.__messageView || messageElement.__commandView;
if (!messageView)
return;
if (index > 0)
data += "\n";
data += messageView.toClipboardString(isPrefixOptional);
});
return data;
}
_sessionStarted(event)
{
if (WI.settings.clearLogOnNavigate.value) {
this._reappendProvisionalMessages();
return;
}
const isFirstSession = false;
const newSessionReason = event.data.wasReloaded ? WI.ConsoleSession.NewSessionReason.PageReloaded : WI.ConsoleSession.NewSessionReason.PageNavigated;
this._logViewController.startNewSession(isFirstSession, {newSessionReason, timestamp: event.data.timestamp});
this._clearProvisionalState();
}
_scopeFromMessageLevel(level)
{
var messageLevel;
switch (level) {
case WI.ConsoleMessage.MessageLevel.Warning:
messageLevel = WI.LogContentView.Scopes.Warnings;
break;
case WI.ConsoleMessage.MessageLevel.Error:
messageLevel = WI.LogContentView.Scopes.Errors;
break;
case WI.ConsoleMessage.MessageLevel.Log:
case WI.ConsoleMessage.MessageLevel.Info:
case WI.ConsoleMessage.MessageLevel.Debug:
messageLevel = WI.LogContentView.Scopes.Logs;
break;
}
return messageLevel;
}
_markScopeBarItemUnread(level)
{
let messageLevel = this._scopeFromMessageLevel(level);
if (!messageLevel)
return;
let item = this._scopeBar.item(messageLevel);
if (item && !item.selected && !this._scopeBar.item(WI.LogContentView.Scopes.All).selected)
item.element.classList.add("unread");
}
_messageAdded(event)
{
if (this._startedProvisionalLoad)
this._provisionalMessages.push(event.data.message);
this._logViewController.appendConsoleMessage(event.data.message);
}
_previousMessageRepeatCountUpdated(event)
{
if (this._logViewController.updatePreviousMessageRepeatCount(event.data.count) && this._lastMessageView)
this._markScopeBarItemUnread(this._lastMessageView.message.level);
}
_handleContextMenuEvent(event)
{
if (!window.getSelection().isCollapsed) {
// If there is a selection, we want to show our normal context menu
// (with Copy, etc.), and not Clear Log.
return;
}
// In the case that there are selected messages, only clear that selection if the right-click
// is not on the element or descendants of the selected messages.
if (this._selectedMessages.length && !this._selectedMessages.some(element => event.target.isSelfOrDescendant(element))) {
this._clearMessagesSelection();
this._mousedown(event);
}
// If there are no selected messages, right-clicking will not reset the current mouse state
// meaning that when the context menu is dismissed, console messages will be selected when
// the user moves the mouse even though no buttons are pressed.
if (!this._selectedMessages.length)
this._mouseup(event);
// We don't want to show the custom menu for links in the console.
if (event.target.enclosingNodeOrSelfWithNodeName("a"))
return;
let contextMenu = WI.ContextMenu.createFromEvent(event);
if (this._selectedMessages.length) {
contextMenu.appendItem(WI.UIString("Copy Selected"), () => {
InspectorFrontendHost.copyText(this._formatMessagesAsData(true));
});
contextMenu.appendItem(WI.UIString("Save Selected"), () => {
const forceSaveAs = true;
WI.saveDataToFile({
url: "web-inspector:///Console.txt",
content: this._formatMessagesAsData(true),
}, forceSaveAs);
});
contextMenu.appendSeparator();
}
contextMenu.appendItem(WI.UIString("Clear Log"), this._clearLog.bind(this));
contextMenu.appendSeparator();
}
_mousedown(event)
{
if (this._selectedMessages.length && (event.button !== 0 || event.ctrlKey))
return;
if (event.defaultPrevented) {
// Default was prevented on the event, so this means something deeper (like a disclosure triangle)
// handled the mouse down. In this case we want to clear the selection and don't make a new selection.
this._clearMessagesSelection();
return;
}
this._mouseDownWrapper = event.target.enclosingNodeOrSelfWithClass(WI.LogContentView.ItemWrapperStyleClassName);
this._mouseDownShiftKey = event.shiftKey;
this._mouseDownCommandKey = event.metaKey;
this._mouseMoveIsRowSelection = false;
window.addEventListener("mousemove", this);
window.addEventListener("mouseup", this);
}
_targetInMessageCanBeSelected(target, message)
{
if (target.enclosingNodeOrSelfWithNodeName("a"))
return false;
return true;
}
_mousemove(event)
{
var selection = window.getSelection();
var wrapper = event.target.enclosingNodeOrSelfWithClass(WI.LogContentView.ItemWrapperStyleClassName);
if (!wrapper) {
// No wrapper under the mouse, so look at the selection to try and find one.
if (!selection.isCollapsed) {
wrapper = selection.focusNode.parentNode.enclosingNodeOrSelfWithClass(WI.LogContentView.ItemWrapperStyleClassName);
selection.removeAllRanges();
}
if (!wrapper)
return;
}
if (!selection.isCollapsed)
this._clearMessagesSelection();
if (wrapper === this._mouseDownWrapper && !this._mouseMoveIsRowSelection)
return;
selection.removeAllRanges();
if (!this._mouseMoveIsRowSelection)
this._updateMessagesSelection(this._mouseDownWrapper, this._mouseDownCommandKey, this._mouseDownShiftKey, false);
this._updateMessagesSelection(wrapper, false, true, false);
this._mouseMoveIsRowSelection = true;
event.preventDefault();
event.stopPropagation();
}
_mouseup(event)
{
window.removeEventListener("mousemove", this);
window.removeEventListener("mouseup", this);
var selection = window.getSelection();
var wrapper = event.target.enclosingNodeOrSelfWithClass(WI.LogContentView.ItemWrapperStyleClassName);
if (wrapper && (selection.isCollapsed || event.shiftKey)) {
selection.removeAllRanges();
if (this._targetInMessageCanBeSelected(event.target, wrapper)) {
var sameWrapper = wrapper === this._mouseDownWrapper;
this._updateMessagesSelection(wrapper, sameWrapper ? this._mouseDownCommandKey : false, sameWrapper ? this._mouseDownShiftKey : true, false);
}
} else if (!selection.isCollapsed) {
// There is a text selection, clear the row selection.
this._clearMessagesSelection();
} else if (!this._mouseDownWrapper) {
// The mouse didn't hit a console item, so clear the row selection.
this._clearMessagesSelection();
// Focus the prompt. Focusing the prompt needs to happen after the click to work.
setTimeout(() => { this.prompt.focus(); }, 0);
}
delete this._mouseMoveIsRowSelection;
delete this._mouseDownWrapper;
delete this._mouseDownShiftKey;
delete this._mouseDownCommandKey;
}
_ondragstart(event)
{
if (event.target.enclosingNodeOrSelfWithClass(WI.DOMTreeOutline.StyleClassName)) {
event.stopPropagation();
event.preventDefault();
}
}
handleEvent(event)
{
switch (event.type) {
case "mousemove":
this._mousemove(event);
break;
case "mouseup":
this._mouseup(event);
break;
}
}
_updateMessagesSelection(message, multipleSelection, rangeSelection, shouldScrollIntoView)
{
console.assert(message);
if (!message)
return;
var alreadySelectedMessage = this._selectedMessages.includes(message);
if (alreadySelectedMessage && this._selectedMessages.length && multipleSelection) {
message.classList.remove(WI.LogContentView.SelectedStyleClassName);
this._selectedMessages.remove(message);
return;
}
if (!multipleSelection && !rangeSelection)
this._clearMessagesSelection();
if (rangeSelection) {
var messages = this._visibleMessageElements();
var refIndex = this._referenceMessageForRangeSelection ? messages.indexOf(this._referenceMessageForRangeSelection) : 0;
var targetIndex = messages.indexOf(message);
var newRange = [Math.min(refIndex, targetIndex), Math.max(refIndex, targetIndex)];
if (this._selectionRange && this._selectionRange[0] === newRange[0] && this._selectionRange[1] === newRange[1])
return;
var startIndex = this._selectionRange ? Math.min(this._selectionRange[0], newRange[0]) : newRange[0];
var endIndex = this._selectionRange ? Math.max(this._selectionRange[1], newRange[1]) : newRange[1];
for (var i = startIndex; i <= endIndex; ++i) {
var messageInRange = messages[i];
if (i >= newRange[0] && i <= newRange[1] && !messageInRange.classList.contains(WI.LogContentView.SelectedStyleClassName)) {
messageInRange.classList.add(WI.LogContentView.SelectedStyleClassName);
this._selectedMessages.push(messageInRange);
} else if (i < newRange[0] || i > newRange[1] && messageInRange.classList.contains(WI.LogContentView.SelectedStyleClassName)) {
messageInRange.classList.remove(WI.LogContentView.SelectedStyleClassName);
this._selectedMessages.remove(messageInRange);
}
}
this._selectionRange = newRange;
} else {
message.classList.add(WI.LogContentView.SelectedStyleClassName);
this._selectedMessages.push(message);
}
if (!rangeSelection)
this._referenceMessageForRangeSelection = message;
if (shouldScrollIntoView && !alreadySelectedMessage)
this._ensureMessageIsVisible(this._selectedMessages.lastValue);
}
_ensureMessageIsVisible(message)
{
if (!message)
return;
var y = this._positionForMessage(message).y;
if (y < 0) {
this.element.scrollTop += y;
return;
}
var nextMessage = this._nextMessage(message);
if (nextMessage) {
y = this._positionForMessage(nextMessage).y;
if (y > this._scrollElementHeight)
this.element.scrollTop += y - this._scrollElementHeight;
} else {
y += message.getBoundingClientRect().height;
if (y > this._scrollElementHeight)
this.element.scrollTop += y - this._scrollElementHeight;
}
}
_positionForMessage(message)
{
var pagePoint = window.webkitConvertPointFromNodeToPage(message, new WebKitPoint(0, 0));
return window.webkitConvertPointFromPageToNode(this.element, pagePoint);
}
_isMessageVisible(message)
{
var node = message;
if (node.classList.contains(WI.LogContentView.FilteredOutStyleClassName))
return false;
if (this.hasPerformedSearch && node.classList.contains(WI.LogContentView.FilteredOutBySearchStyleClassName))
return false;
if (message.classList.contains("console-group-title"))
node = node.parentNode.parentNode;
while (node && node !== this.messagesElement) {
if (node.classList.contains("collapsed"))
return false;
node = node.parentNode;
}
return true;
}
_isMessageSelected(message)
{
return message.classList.contains(WI.LogContentView.SelectedStyleClassName);
}
_clearMessagesSelection()
{
this._selectedMessages.forEach(function(message) {
message.classList.remove(WI.LogContentView.SelectedStyleClassName);
});
this._selectedMessages = [];
delete this._referenceMessageForRangeSelection;
}
_selectAllMessages()
{
this._clearMessagesSelection();
var messages = this._visibleMessageElements();
for (var i = 0; i < messages.length; ++i) {
var message = messages[i];
message.classList.add(WI.LogContentView.SelectedStyleClassName);
this._selectedMessages.push(message);
}
}
_allMessageElements()
{
return Array.from(this.messagesElement.querySelectorAll(".console-message, .console-user-command"));
}
_unfilteredMessageElements()
{
return this._allMessageElements().filter(function(message) {
return !message.classList.contains(WI.LogContentView.FilteredOutStyleClassName);
});
}
_visibleMessageElements()
{
var unfilteredMessages = this._unfilteredMessageElements();
if (!this.hasPerformedSearch)
return unfilteredMessages;
return unfilteredMessages.filter(function(message) {
return !message.classList.contains(WI.LogContentView.FilteredOutBySearchStyleClassName);
});
}
_logCleared(event)
{
for (let item of this._scopeBar.items)
item.element.classList.remove("unread");
this._logViewController.clear();
this._nestingLevel = 0;
if (this._currentSearchQuery)
this.performSearch(this._currentSearchQuery);
}
_showConsoleTab()
{
WI.showConsoleTab();
}
_clearLog()
{
WI.logManager.requestClearMessages();
}
_garbageCollect()
{
// COMPATIBILITY (iOS 10.3): Worker targets did not support HeapAgent.
for (let target of WI.targets) {
if (target.HeapAgent)
target.HeapAgent.gc();
}
}
_scopeBarSelectionDidChange(event)
{
var item = this._scopeBar.selectedItems[0];
if (item.id === WI.LogContentView.Scopes.All) {
for (var item of this._scopeBar.items)
item.element.classList.remove("unread");
} else
item.element.classList.remove("unread");
this._filterMessageElements(this._allMessageElements());
}
_filterMessageElements(messageElements)
{
var showsAll = this._scopeBar.item(WI.LogContentView.Scopes.All).selected;
messageElements.forEach(function(messageElement) {
var visible = showsAll || messageElement.__commandView instanceof WI.ConsoleCommandView || messageElement.__message instanceof WI.ConsoleCommandResultMessage;
if (!visible) {
var messageLevel = this._scopeFromMessageLevel(messageElement.__message.level);
if (messageLevel)
visible = this._scopeBar.item(messageLevel).selected;
}
var classList = messageElement.classList;
if (visible)
classList.remove(WI.LogContentView.FilteredOutStyleClassName);
else {
this._selectedMessages.remove(messageElement);
classList.remove(WI.LogContentView.SelectedStyleClassName);
classList.add(WI.LogContentView.FilteredOutStyleClassName);
}
}, this);
this.performSearch(this._currentSearchQuery);
}
_keyDown(event)
{
let isRTL = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL;
if (this._keyboardShortcutCommandA.matchesEvent(event))
this._commandAWasPressed(event);
else if (this._keyboardShortcutEsc.matchesEvent(event))
this._escapeWasPressed(event);
else if (event.keyIdentifier === "Up")
this._upArrowWasPressed(event);
else if (event.keyIdentifier === "Down")
this._downArrowWasPressed(event);
else if ((!isRTL && event.keyIdentifier === "Left") || (isRTL && event.keyIdentifier === "Right"))
this._leftArrowWasPressed(event);
else if ((!isRTL && event.keyIdentifier === "Right") || (isRTL && event.keyIdentifier === "Left"))
this._rightArrowWasPressed(event);
else if (event.keyIdentifier === "Enter" && event.metaKey)
this._commandEnterWasPressed(event);
}
_keyPress(event)
{
const isCommandC = event.metaKey && event.keyCode === 99;
if (!isCommandC)
this.prompt.focus();
}
_commandAWasPressed(event)
{
this._selectAllMessages();
event.preventDefault();
}
_escapeWasPressed(event)
{
if (this._selectedMessages.length)
this._clearMessagesSelection();
else
this.prompt.focus();
event.preventDefault();
}
_upArrowWasPressed(event)
{
var messages = this._visibleMessageElements();
if (!this._selectedMessages.length) {
if (messages.length)
this._updateMessagesSelection(messages.lastValue, false, false, true);
return;
}
var lastMessage = this._selectedMessages.lastValue;
var previousMessage = this._previousMessage(lastMessage);
if (previousMessage)
this._updateMessagesSelection(previousMessage, false, event.shiftKey, true);
else if (!event.shiftKey) {
this._clearMessagesSelection();
this._updateMessagesSelection(messages[0], false, false, true);
}
event.preventDefault();
}
_downArrowWasPressed(event)
{
var messages = this._visibleMessageElements();
if (!this._selectedMessages.length) {
if (messages.length)
this._updateMessagesSelection(messages[0], false, false, true);
return;
}
var lastMessage = this._selectedMessages.lastValue;
var nextMessage = this._nextMessage(lastMessage);
if (nextMessage)
this._updateMessagesSelection(nextMessage, false, event.shiftKey, true);
else if (!event.shiftKey) {
this._clearMessagesSelection();
this._updateMessagesSelection(messages.lastValue, false, false, true);
}
event.preventDefault();
}
_leftArrowWasPressed(event)
{
if (this._selectedMessages.length !== 1)
return;
var currentMessage = this._selectedMessages[0];
if (currentMessage.classList.contains("console-group-title")) {
currentMessage.parentNode.classList.add("collapsed");
event.preventDefault();
} else if (currentMessage.__messageView && currentMessage.__messageView.expandable) {
currentMessage.__messageView.collapse();
event.preventDefault();
}
}
_rightArrowWasPressed(event)
{
if (this._selectedMessages.length !== 1)
return;
var currentMessage = this._selectedMessages[0];
if (currentMessage.classList.contains("console-group-title")) {
currentMessage.parentNode.classList.remove("collapsed");
event.preventDefault();
} else if (currentMessage.__messageView && currentMessage.__messageView.expandable) {
currentMessage.__messageView.expand();
event.preventDefault();
}
}
_commandEnterWasPressed(event)
{
if (this._selectedMessages.length !== 1)
return;
let message = this._selectedMessages[0];
if (message.__commandView && message.__commandView.commandText) {
this._logViewController.consolePromptTextCommitted(null, message.__commandView.commandText);
event.preventDefault();
}
}
_previousMessage(message)
{
var messages = this._visibleMessageElements();
for (var i = messages.indexOf(message) - 1; i >= 0; --i) {
if (this._isMessageVisible(messages[i]))
return messages[i];
}
return null;
}
_nextMessage(message)
{
var messages = this._visibleMessageElements();
for (var i = messages.indexOf(message) + 1; i < messages.length; ++i) {
if (this._isMessageVisible(messages[i]))
return messages[i];
}
return null;
}
_clearFocusableChildren()
{
var focusableElements = this.messagesElement.querySelectorAll("[tabindex]");
for (var i = 0, count = focusableElements.length; i < count; ++i)
focusableElements[i].removeAttribute("tabindex");
}
findBannerPerformSearch(findBanner, searchQuery)
{
this.performSearch(searchQuery);
}
findBannerSearchCleared()
{
this.searchCleared();
}
revealNextSearchResult()
{
this.findBannerRevealNextResult();
}
revealPreviousSearchResult()
{
this.findBannerRevealPreviousResult();
}
performSearch(searchQuery)
{
if (!isEmptyObject(this._searchHighlightDOMChanges))
WI.revertDOMChanges(this._searchHighlightDOMChanges);
this._currentSearchQuery = searchQuery;
this._searchHighlightDOMChanges = [];
this._searchMatches = [];
this._selectedSearchMatchIsValid = false;
this._selectedSearchMatch = null;
let numberOfResults = 0;
if (this._currentSearchQuery === "") {
this.element.classList.remove(WI.LogContentView.SearchInProgressStyleClassName);
this.dispatchEventToListeners(WI.ContentView.Event.NumberOfSearchResultsDidChange);
return;
}
this.element.classList.add(WI.LogContentView.SearchInProgressStyleClassName);
let searchRegex = new RegExp(this._currentSearchQuery.escapeForRegExp(), "gi");
this._unfilteredMessageElements().forEach(function(message) {
let matchRanges = [];
let text = message.textContent;
let match = searchRegex.exec(text);
while (match) {
numberOfResults++;
matchRanges.push({offset: match.index, length: match[0].length});
match = searchRegex.exec(text);
}
if (!isEmptyObject(matchRanges))
this._highlightRanges(message, matchRanges);
let classList = message.classList;
if (!isEmptyObject(matchRanges) || message.__commandView instanceof WI.ConsoleCommandView || message.__message instanceof WI.ConsoleCommandResultMessage)
classList.remove(WI.LogContentView.FilteredOutBySearchStyleClassName);
else
classList.add(WI.LogContentView.FilteredOutBySearchStyleClassName);
}, this);
this.dispatchEventToListeners(WI.ContentView.Event.NumberOfSearchResultsDidChange);
this._findBanner.numberOfResults = numberOfResults;
if (!this._selectedSearchMatchIsValid && this._selectedSearchMatch) {
this._selectedSearchMatch.highlight.classList.remove(WI.LogContentView.SelectedStyleClassName);
this._selectedSearchMatch = null;
}
}
searchCleared()
{
this.performSearch("");
}
_highlightRanges(message, matchRanges)
{
var highlightedElements = WI.highlightRangesWithStyleClass(message, matchRanges, WI.LogContentView.HighlightedStyleClassName, this._searchHighlightDOMChanges);
console.assert(highlightedElements.length === matchRanges.length);
matchRanges.forEach(function(range, index) {
this._searchMatches.push({message, range, highlight: highlightedElements[index]});
if (this._selectedSearchMatch && !this._selectedSearchMatchIsValid && this._selectedSearchMatch.message === message) {
this._selectedSearchMatchIsValid = this._rangesOverlap(this._selectedSearchMatch.range, range);
if (this._selectedSearchMatchIsValid) {
delete this._selectedSearchMatch;
this._highlightSearchMatchAtIndex(this._searchMatches.length - 1);
}
}
}, this);
}
_rangesOverlap(range1, range2)
{
return range1.offset <= range2.offset + range2.length && range2.offset <= range1.offset + range1.length;
}
_highlightSearchMatchAtIndex(index)
{
if (index >= this._searchMatches.length)
index = 0;
else if (index < 0)
index = this._searchMatches.length - 1;
if (this._selectedSearchMatch)
this._selectedSearchMatch.highlight.classList.remove(WI.LogContentView.SelectedStyleClassName);
this._selectedSearchMatch = this._searchMatches[index];
this._selectedSearchMatch.highlight.classList.add(WI.LogContentView.SelectedStyleClassName);
this._ensureMessageIsVisible(this._selectedSearchMatch.message);
}
_provisionalLoadStarted()
{
this._startedProvisionalLoad = true;
}
_reappendProvisionalMessages()
{
if (!this._startedProvisionalLoad)
return;
this._startedProvisionalLoad = false;
for (let provisionalMessage of this._provisionalMessages)
this._logViewController.appendConsoleMessage(provisionalMessage);
this._provisionalMessages = [];
}
_clearProvisionalState()
{
this._startedProvisionalLoad = false;
this._provisionalMessages = [];
}
};
WI.LogContentView.Scopes = {
All: "log-all",
Errors: "log-errors",
Warnings: "log-warnings",
Logs: "log-logs"
};
WI.LogContentView.ItemWrapperStyleClassName = "console-item";
WI.LogContentView.FilteredOutStyleClassName = "filtered-out";
WI.LogContentView.SelectedStyleClassName = "selected";
WI.LogContentView.SearchInProgressStyleClassName = "search-in-progress";
WI.LogContentView.FilteredOutBySearchStyleClassName = "filtered-out-by-search";
WI.LogContentView.HighlightedStyleClassName = "highlighted";