diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Views/LogContentView.js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Views/LogContentView.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/Views/LogContentView.js | 1032 |
1 files changed, 1032 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Views/LogContentView.js b/Source/WebInspectorUI/UserInterface/Views/LogContentView.js new file mode 100644 index 000000000..10b85c610 --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/Views/LogContentView.js @@ -0,0 +1,1032 @@ +/* + * 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 + +WebInspector.LogContentView = class LogContentView extends WebInspector.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 = WebInspector.quickConsole.prompt; + + this._keyboardShortcutCommandA = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl, "A"); + this._keyboardShortcutEsc = new WebInspector.KeyboardShortcut(null, WebInspector.KeyboardShortcut.Key.Escape); + + this._logViewController = new WebInspector.JavaScriptLogViewController(this.messagesElement, this.element, this.prompt, this, "console-prompt-history"); + this._lastMessageView = null; + + const fixed = true; + this._findBanner = new WebInspector.FindBanner(this, "console-find-banner", fixed); + this._findBanner.inputField.placeholder = WebInspector.UIString("Filter Console Log"); + this._findBanner.targetElement = this.element; + + this._currentSearchQuery = ""; + this._searchMatches = []; + this._selectedSearchMatch = null; + this._selectedSearchMatchIsValid = false; + + var scopeBarItems = [ + new WebInspector.ScopeBarItem(WebInspector.LogContentView.Scopes.All, WebInspector.UIString("All"), true), + new WebInspector.ScopeBarItem(WebInspector.LogContentView.Scopes.Errors, WebInspector.UIString("Errors"), false, "errors"), + new WebInspector.ScopeBarItem(WebInspector.LogContentView.Scopes.Warnings, WebInspector.UIString("Warnings"), false, "warnings"), + new WebInspector.ScopeBarItem(WebInspector.LogContentView.Scopes.Logs, WebInspector.UIString("Logs"), false, "logs") + ]; + + this._scopeBar = new WebInspector.ScopeBar("log-scope-bar", scopeBarItems, scopeBarItems[0]); + this._scopeBar.addEventListener(WebInspector.ScopeBar.Event.SelectionChanged, this._scopeBarSelectionDidChange, this); + + this._garbageCollectNavigationItem = new WebInspector.ButtonNavigationItem("clear-log", WebInspector.UIString("Collect garbage"), "Images/NavigationItemGarbageCollect.svg", 16, 16); + this._garbageCollectNavigationItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._garbageCollect, this); + + let clearImageDimensions = WebInspector.Platform.name === "mac" ? 16 : 15; + this._clearLogNavigationItem = new WebInspector.ButtonNavigationItem("clear-log", WebInspector.UIString("Clear log (%s or %s)").format(WebInspector.clearKeyboardShortcut.displayName, this._logViewController.messagesAlternateClearKeyboardShortcut.displayName), "Images/NavigationItemClear.svg", clearImageDimensions, clearImageDimensions); + this._clearLogNavigationItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._clearLog, this); + + this._showConsoleTabNavigationItem = new WebInspector.ButtonNavigationItem("show-tab", WebInspector.UIString("Show console tab"), "Images/SplitToggleUp.svg", 16, 16); + this._showConsoleTabNavigationItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._showConsoleTab, this); + + this.messagesElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false); + + WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.SessionStarted, this._sessionStarted, this); + WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, this._messageAdded, this); + WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.PreviousMessageRepeatCountUpdated, this._previousMessageRepeatCountUpdated, this); + WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.Cleared, this._logCleared, this); + + WebInspector.Frame.addEventListener(WebInspector.Frame.Event.ProvisionalLoadStarted, this._provisionalLoadStarted, this); + } + + // Public + + get navigationItems() + { + let navigationItems = [this._findBanner, this._scopeBar]; + if (HeapAgent.gc) + navigationItems.push(this._garbageCollectNavigationItem); + navigationItems.push(this._clearLogNavigationItem); + if (WebInspector.isShowingSplitConsole()) + navigationItems.push(this._showConsoleTabNavigationItem); + 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 WebInspector.ConsoleMessageView || messageView instanceof WebInspector.ConsoleCommandView); + + // Nest the message. + var type = messageView instanceof WebInspector.ConsoleCommandView ? null : messageView.message.type; + if (this._nestingLevel && type !== WebInspector.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 WebInspector.ConsoleMessage.MessageType.StartGroup: + case WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed: + ++this._nestingLevel; + break; + case WebInspector.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 : WebInspector.runtimeManager.activeExecutionContext.target; + target.connection.runAfterPendingDispatches(this._clearFocusableChildren.bind(this)); + + if (type && type !== WebInspector.ConsoleMessage.MessageType.EndGroup) { + console.assert(messageView.message instanceof WebInspector.ConsoleMessage); + if (!(messageView.message instanceof WebInspector.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 WebInspector.isShowingConsoleTab(); + } + + showCustomFindBanner() + { + if (!this.visible) + return; + + this._findBanner.focus(); + } + + get supportsSave() + { + if (!this.visible) + return false; + + if (WebInspector.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(); + } + + findBannerRevealPreviousResult() + { + if (!this.hasPerformedSearch || isEmptyObject(this._searchMatches)) + return; + + var index = this._selectedSearchMatch ? this._searchMatches.indexOf(this._selectedSearchMatch) : this._searchMatches.length; + this._highlightSearchMatchAtIndex(index - 1); + } + + findBannerRevealNextResult() + { + 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(WebInspector.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 (WebInspector.settings.clearLogOnNavigate.value) { + this._reappendProvisionalMessages(); + return; + } + + const isFirstSession = false; + const newSessionReason = event.data.wasReloaded ? WebInspector.ConsoleSession.NewSessionReason.PageReloaded : WebInspector.ConsoleSession.NewSessionReason.PageNavigated; + this._logViewController.startNewSession(isFirstSession, {newSessionReason, timestamp: event.data.timestamp}); + + this._clearProvisionalState(); + } + + _scopeFromMessageLevel(level) + { + var messageLevel; + + switch (level) { + case WebInspector.ConsoleMessage.MessageLevel.Warning: + messageLevel = WebInspector.LogContentView.Scopes.Warnings; + break; + case WebInspector.ConsoleMessage.MessageLevel.Error: + messageLevel = WebInspector.LogContentView.Scopes.Errors; + break; + case WebInspector.ConsoleMessage.MessageLevel.Log: + case WebInspector.ConsoleMessage.MessageLevel.Info: + case WebInspector.ConsoleMessage.MessageLevel.Debug: + messageLevel = WebInspector.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(WebInspector.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 = WebInspector.ContextMenu.createFromEvent(event); + + if (this._selectedMessages.length) { + contextMenu.appendItem(WebInspector.UIString("Copy Selected"), () => { + InspectorFrontendHost.copyText(this._formatMessagesAsData(true)); + }); + contextMenu.appendSeparator(); + } + + contextMenu.appendItem(WebInspector.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(WebInspector.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(WebInspector.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(WebInspector.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(WebInspector.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(WebInspector.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(WebInspector.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(WebInspector.LogContentView.SelectedStyleClassName)) { + messageInRange.classList.add(WebInspector.LogContentView.SelectedStyleClassName); + this._selectedMessages.push(messageInRange); + } else if (i < newRange[0] || i > newRange[1] && messageInRange.classList.contains(WebInspector.LogContentView.SelectedStyleClassName)) { + messageInRange.classList.remove(WebInspector.LogContentView.SelectedStyleClassName); + this._selectedMessages.remove(messageInRange); + } + } + + this._selectionRange = newRange; + } else { + message.classList.add(WebInspector.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(WebInspector.LogContentView.FilteredOutStyleClassName)) + return false; + + if (this.hasPerformedSearch && node.classList.contains(WebInspector.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(WebInspector.LogContentView.SelectedStyleClassName); + } + + _clearMessagesSelection() + { + this._selectedMessages.forEach(function(message) { + message.classList.remove(WebInspector.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(WebInspector.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(WebInspector.LogContentView.FilteredOutStyleClassName); + }); + } + + _visibleMessageElements() + { + var unfilteredMessages = this._unfilteredMessageElements(); + + if (!this.hasPerformedSearch) + return unfilteredMessages; + + return unfilteredMessages.filter(function(message) { + return !message.classList.contains(WebInspector.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() + { + WebInspector.showConsoleTab(); + } + + _clearLog() + { + WebInspector.logManager.requestClearMessages(); + } + + _garbageCollect() + { + // COMPATIBILITY (iOS 10.3): Worker targets did not support HeapAgent. + for (let target of WebInspector.targets) { + if (target.HeapAgent) + target.HeapAgent.gc(); + } + } + + _scopeBarSelectionDidChange(event) + { + var item = this._scopeBar.selectedItems[0]; + + if (item.id === WebInspector.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(WebInspector.LogContentView.Scopes.All).selected; + + messageElements.forEach(function(messageElement) { + var visible = showsAll || messageElement.__commandView instanceof WebInspector.ConsoleCommandView || messageElement.__message instanceof WebInspector.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(WebInspector.LogContentView.FilteredOutStyleClassName); + else { + this._selectedMessages.remove(messageElement); + classList.remove(WebInspector.LogContentView.SelectedStyleClassName); + classList.add(WebInspector.LogContentView.FilteredOutStyleClassName); + } + }, this); + + this.performSearch(this._currentSearchQuery); + } + + _keyDown(event) + { + 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 (event.keyIdentifier === "Left") + this._leftArrowWasPressed(event); + else if (event.keyIdentifier === "Right") + 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)) + WebInspector.revertDomChanges(this._searchHighlightDOMChanges); + + this._currentSearchQuery = searchQuery; + this._searchHighlightDOMChanges = []; + this._searchMatches = []; + this._selectedSearchMatchIsValid = false; + this._selectedSearchMatch = null; + + if (this._currentSearchQuery === "") { + this.element.classList.remove(WebInspector.LogContentView.SearchInProgressStyleClassName); + this.dispatchEventToListeners(WebInspector.ContentView.Event.NumberOfSearchResultsDidChange); + return; + } + + this.element.classList.add(WebInspector.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) { + 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 WebInspector.ConsoleCommandView || message.__message instanceof WebInspector.ConsoleCommandResultMessage) + classList.remove(WebInspector.LogContentView.FilteredOutBySearchStyleClassName); + else + classList.add(WebInspector.LogContentView.FilteredOutBySearchStyleClassName); + }, this); + + this.dispatchEventToListeners(WebInspector.ContentView.Event.NumberOfSearchResultsDidChange); + + if (!this._selectedSearchMatchIsValid && this._selectedSearchMatch) { + this._selectedSearchMatch.highlight.classList.remove(WebInspector.LogContentView.SelectedStyleClassName); + this._selectedSearchMatch = null; + } + } + + searchCleared() + { + this.performSearch(""); + } + + _highlightRanges(message, matchRanges) + { + var highlightedElements = WebInspector.highlightRangesWithStyleClass(message, matchRanges, WebInspector.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(WebInspector.LogContentView.SelectedStyleClassName); + + this._selectedSearchMatch = this._searchMatches[index]; + this._selectedSearchMatch.highlight.classList.add(WebInspector.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 = []; + } +}; + +WebInspector.LogContentView.Scopes = { + All: "log-all", + Errors: "log-errors", + Warnings: "log-warnings", + Logs: "log-logs" +}; + +WebInspector.LogContentView.ItemWrapperStyleClassName = "console-item"; +WebInspector.LogContentView.FilteredOutStyleClassName = "filtered-out"; +WebInspector.LogContentView.SelectedStyleClassName = "selected"; +WebInspector.LogContentView.SearchInProgressStyleClassName = "search-in-progress"; +WebInspector.LogContentView.FilteredOutBySearchStyleClassName = "filtered-out-by-search"; +WebInspector.LogContentView.HighlightedStyleClassName = "highlighted"; |