| Index: third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js
|
| diff --git a/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js
|
| index 60617f396623f94838a257c25e50cad66bf195b3..af503388e301ea172e26a82dde6800621a489d4b 100644
|
| --- a/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js
|
| +++ b/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js
|
| @@ -36,10 +36,13 @@ WebInspector.UISourceCodeFrame = function(uiSourceCode)
|
| this._uiSourceCode = uiSourceCode;
|
| WebInspector.SourceFrame.call(this, this._uiSourceCode);
|
| this.textEditor.setAutocompleteDelegate(new WebInspector.SimpleAutocompleteDelegate());
|
| -
|
| + this._rowMessageBuckets = {};
|
| this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._onWorkingCopyChanged, this);
|
| this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._onWorkingCopyCommitted, this);
|
| this._updateStyle();
|
| +
|
| + this._errorPopoverHelper = new WebInspector.PopoverHelper(this.element, this._getErrorAnchor.bind(this), this._showErrorPopover.bind(this));
|
| + this._errorPopoverHelper.setTimeout(100, 100);
|
| }
|
|
|
| WebInspector.UISourceCodeFrame.prototype = {
|
| @@ -57,6 +60,8 @@ WebInspector.UISourceCodeFrame.prototype = {
|
| this._boundWindowFocused = this._windowFocused.bind(this);
|
| this.element.ownerDocument.defaultView.addEventListener("focus", this._boundWindowFocused, false);
|
| this._checkContentUpdated();
|
| + // We need CodeMirrorTextEditor to be initialized prior to this call as it calls |cursorPositionToCoordinates| internally. @see crbug.com/506566
|
| + setImmediate(this._updateBucketDecorations.bind(this));
|
| },
|
|
|
| willHide: function()
|
| @@ -106,6 +111,7 @@ WebInspector.UISourceCodeFrame.prototype = {
|
| onTextChanged: function(oldRange, newRange)
|
| {
|
| WebInspector.SourceFrame.prototype.onTextChanged.call(this, oldRange, newRange);
|
| + this.clearMessages();
|
| if (this._isSettingContent)
|
| return;
|
| this._muteSourceCodeEvents = true;
|
| @@ -116,6 +122,12 @@ WebInspector.UISourceCodeFrame.prototype = {
|
| delete this._muteSourceCodeEvents;
|
| },
|
|
|
| + onTextEditorContentLoaded: function()
|
| + {
|
| + WebInspector.SourceFrame.prototype.onTextEditorContentLoaded.call(this);
|
| + this.clearMessages();
|
| + },
|
| +
|
| /**
|
| * @param {!WebInspector.Event} event
|
| */
|
| @@ -200,6 +212,90 @@ WebInspector.UISourceCodeFrame.prototype = {
|
| this.detach();
|
| },
|
|
|
| + /**
|
| + * @param {!WebInspector.UISourceCode.Message} message
|
| + */
|
| + addMessageToSource: function(message)
|
| + {
|
| + var lineNumber = message.lineNumber();
|
| + if (lineNumber >= this._textEditor.linesCount)
|
| + lineNumber = this._textEditor.linesCount - 1;
|
| + if (lineNumber < 0)
|
| + lineNumber = 0;
|
| +
|
| + if (!this._rowMessageBuckets[lineNumber])
|
| + this._rowMessageBuckets[lineNumber] = new WebInspector.UISourceCodeFrame.RowMessageBucket(this, this._textEditor, lineNumber);
|
| + var messageBucket = this._rowMessageBuckets[lineNumber];
|
| + messageBucket.addMessage(message);
|
| + },
|
| +
|
| + /**
|
| + * @param {!WebInspector.UISourceCode.Message} message
|
| + */
|
| + removeMessageFromSource: function(message)
|
| + {
|
| + var lineNumber = message.lineNumber();
|
| + if (lineNumber >= this._textEditor.linesCount)
|
| + lineNumber = this._textEditor.linesCount - 1;
|
| + if (lineNumber < 0)
|
| + lineNumber = 0;
|
| +
|
| + var messageBucket = this._rowMessageBuckets[lineNumber];
|
| + if (!messageBucket)
|
| + return;
|
| + messageBucket.removeMessage(message);
|
| + if (!messageBucket.uniqueMessagesCount()) {
|
| + messageBucket.detachFromEditor();
|
| + delete this._rowMessageBuckets[lineNumber];
|
| + }
|
| + },
|
| +
|
| + clearMessages: function()
|
| + {
|
| + for (var line in this._rowMessageBuckets) {
|
| + var bubble = this._rowMessageBuckets[line];
|
| + bubble.detachFromEditor();
|
| + }
|
| +
|
| + this._rowMessageBuckets = {};
|
| + this._errorPopoverHelper.hidePopover();
|
| + },
|
| +
|
| + /**
|
| + * @param {!Element} target
|
| + * @param {!Event} event
|
| + * @return {(!Element|undefined)}
|
| + */
|
| + _getErrorAnchor: function(target, event)
|
| + {
|
| + var element = target.enclosingNodeOrSelfWithClass("text-editor-line-decoration-icon")
|
| + || target.enclosingNodeOrSelfWithClass("text-editor-line-decoration-wave");
|
| + if (!element)
|
| + return;
|
| + this._errorWavePopoverAnchor = new AnchorBox(event.clientX, event.clientY, 1, 1);
|
| + return element;
|
| + },
|
| +
|
| + /**
|
| + * @param {!Element} anchor
|
| + * @param {!WebInspector.Popover} popover
|
| + */
|
| + _showErrorPopover: function(anchor, popover)
|
| + {
|
| + var messageBucket = anchor.enclosingNodeOrSelfWithClass("text-editor-line-decoration")._messageBucket;
|
| + var messagesOutline = messageBucket.messagesDescription();
|
| + var popoverAnchor = anchor.enclosingNodeOrSelfWithClass("text-editor-line-decoration-icon") ? anchor : this._errorWavePopoverAnchor;
|
| + popover.showForAnchor(messagesOutline, popoverAnchor);
|
| + },
|
| +
|
| + _updateBucketDecorations: function()
|
| + {
|
| + for (var line in this._rowMessageBuckets) {
|
| + var bucket = this._rowMessageBuckets[line];
|
| + bucket._updateDecoration();
|
| + }
|
| + },
|
| +
|
| __proto__: WebInspector.SourceFrame.prototype
|
| }
|
|
|
| @@ -276,3 +372,238 @@ WebInspector.UISourceCodeFrame.Infobar.prototype = {
|
|
|
| __proto__: WebInspector.Infobar.prototype
|
| }
|
| +
|
| +/**
|
| + * @param {!WebInspector.ConsoleMessage} consoleMessage
|
| + * @param {number} lineNumber
|
| + * @param {number} columnNumber
|
| + * @return {!WebInspector.UISourceCode.Message}
|
| + */
|
| +WebInspector.UISourceCodeFrame.uiMessageFromConsoleMessage = function(consoleMessage, lineNumber, columnNumber)
|
| +{
|
| + console.assert(consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel.Error || consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel.Warning);
|
| + var level = consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel.Error ? WebInspector.UISourceCode.Message.Level.Error : WebInspector.UISourceCode.Message.Level.Warning;
|
| + return new WebInspector.UISourceCode.Message(level, consoleMessage.messageText, lineNumber, columnNumber);
|
| +}
|
| +
|
| +WebInspector.UISourceCodeFrame._iconClassPerLevel = {};
|
| +WebInspector.UISourceCodeFrame._iconClassPerLevel[WebInspector.UISourceCode.Message.Level.Error] = "error-icon";
|
| +WebInspector.UISourceCodeFrame._iconClassPerLevel[WebInspector.UISourceCode.Message.Level.Warning] = "warning-icon";
|
| +
|
| +WebInspector.UISourceCodeFrame._lineClassPerLevel = {};
|
| +WebInspector.UISourceCodeFrame._lineClassPerLevel[WebInspector.UISourceCode.Message.Level.Error] = "text-editor-line-with-error";
|
| +WebInspector.UISourceCodeFrame._lineClassPerLevel[WebInspector.UISourceCode.Message.Level.Warning] = "text-editor-line-with-warning";
|
| +
|
| +/**
|
| + * @constructor
|
| + * @param {!WebInspector.UISourceCode.Message} message
|
| + */
|
| +WebInspector.UISourceCodeFrame.RowMessage = function(message)
|
| +{
|
| + this._message = message;
|
| + this._repeatCount = 1;
|
| + this.element = createElementWithClass("div", "text-editor-row-message");
|
| + this._icon = this.element.createChild("label", "", "dt-icon-label");
|
| + this._icon.type = WebInspector.UISourceCodeFrame._iconClassPerLevel[message.level()];
|
| + this._repeatCountElement = this.element.createChild("span", "bubble-repeat-count hidden error");
|
| + var linesContainer = this.element.createChild("div", "text-editor-row-message-lines");
|
| + var lines = this._message.text().split("\n");
|
| + for (var i = 0; i < lines.length; ++i) {
|
| + var messageLine = linesContainer.createChild("div");
|
| + messageLine.textContent = lines[i];
|
| + }
|
| +}
|
| +
|
| +WebInspector.UISourceCodeFrame.RowMessage.prototype = {
|
| + /**
|
| + * @return {!WebInspector.UISourceCode.Message}
|
| + */
|
| + message: function()
|
| + {
|
| + return this._message;
|
| + },
|
| +
|
| + /**
|
| + * @return {number}
|
| + */
|
| + repeatCount: function()
|
| + {
|
| + return this._repeatCount;
|
| + },
|
| +
|
| + setRepeatCount: function(repeatCount)
|
| + {
|
| + if (this._repeatCount === repeatCount)
|
| + return;
|
| + this._repeatCount = repeatCount;
|
| + this._updateMessageRepeatCount();
|
| + },
|
| +
|
| + _updateMessageRepeatCount: function()
|
| + {
|
| + this._repeatCountElement.textContent = this._repeatCount;
|
| + var showRepeatCount = this._repeatCount > 1;
|
| + this._repeatCountElement.classList.toggle("hidden", !showRepeatCount);
|
| + this._icon.classList.toggle("hidden", showRepeatCount);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * @constructor
|
| + * @param {!WebInspector.UISourceCodeFrame} sourceFrame
|
| + * @param {!WebInspector.CodeMirrorTextEditor} textEditor
|
| + * @param {number} lineNumber
|
| + */
|
| +WebInspector.UISourceCodeFrame.RowMessageBucket = function(sourceFrame, textEditor, lineNumber)
|
| +{
|
| + this._sourceFrame = sourceFrame;
|
| + this._textEditor = textEditor;
|
| + this._lineHandle = textEditor.textEditorPositionHandle(lineNumber, 0);
|
| + this._decoration = createElementWithClass("div", "text-editor-line-decoration");
|
| + this._decoration._messageBucket = this;
|
| + this._wave = this._decoration.createChild("div", "text-editor-line-decoration-wave");
|
| + this._icon = this._wave.createChild("label", "text-editor-line-decoration-icon", "dt-icon-label");
|
| +
|
| + this._textEditor.addDecoration(lineNumber, this._decoration);
|
| +
|
| + this._messagesDescriptionElement = createElementWithClass("div", "text-editor-messages-description-container");
|
| + /** @type {!Array.<!WebInspector.UISourceCodeFrame.RowMessage>} */
|
| + this._messages = [];
|
| +
|
| + this._level = null;
|
| +}
|
| +
|
| +WebInspector.UISourceCodeFrame.RowMessageBucket.prototype = {
|
| + /**
|
| + * @param {number} lineNumber
|
| + * @param {number} columnNumber
|
| + */
|
| + _updateWavePosition: function(lineNumber, columnNumber)
|
| + {
|
| + lineNumber = Math.min(lineNumber, this._textEditor.linesCount - 1);
|
| + var lineText = this._textEditor.line(lineNumber);
|
| + columnNumber = Math.min(columnNumber, lineText.length);
|
| + var lineIndent = WebInspector.TextUtils.lineIndent(lineText).length;
|
| + var base = this._textEditor.cursorPositionToCoordinates(lineNumber, 0);
|
| +
|
| + var start = this._textEditor.cursorPositionToCoordinates(lineNumber, Math.max(columnNumber - 1, lineIndent));
|
| + var end = this._textEditor.cursorPositionToCoordinates(lineNumber, lineText.length);
|
| + /** @const */
|
| + var codeMirrorLinesLeftPadding = 4;
|
| + this._wave.style.left = (start.x - base.x + codeMirrorLinesLeftPadding) + "px";
|
| + this._wave.style.width = (end.x - start.x) + "px";
|
| + },
|
| +
|
| + /**
|
| + * @return {!Element}
|
| + */
|
| + messagesDescription: function()
|
| + {
|
| + this._messagesDescriptionElement.removeChildren();
|
| + for (var i = 0; i < this._messages.length; ++i) {
|
| + this._messagesDescriptionElement.appendChild(this._messages[i].element);
|
| + }
|
| + return this._messagesDescriptionElement;
|
| + },
|
| +
|
| + detachFromEditor: function()
|
| + {
|
| + var position = this._lineHandle.resolve();
|
| + if (!position)
|
| + return;
|
| + var lineNumber = position.lineNumber;
|
| + if (this._level)
|
| + this._textEditor.toggleLineClass(lineNumber, WebInspector.UISourceCodeFrame._lineClassPerLevel[this._level], false);
|
| + this._textEditor.removeDecoration(lineNumber, this._decoration);
|
| + },
|
| +
|
| + /**
|
| + * @return {number}
|
| + */
|
| + uniqueMessagesCount: function()
|
| + {
|
| + return this._messages.length;
|
| + },
|
| +
|
| + /**
|
| + * @param {!WebInspector.UISourceCode.Message} message
|
| + */
|
| + addMessage: function(message)
|
| + {
|
| + for (var i = 0; i < this._messages.length; ++i) {
|
| + var rowMessage = this._messages[i];
|
| + if (rowMessage.message().isEqual(message)) {
|
| + rowMessage.setRepeatCount(rowMessage.repeatCount() + 1);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + var rowMessage = new WebInspector.UISourceCodeFrame.RowMessage(message);
|
| + this._messages.push(rowMessage);
|
| + this._updateDecoration();
|
| + },
|
| +
|
| + /**
|
| + * @param {!WebInspector.UISourceCode.Message} message
|
| + */
|
| + removeMessage: function(message)
|
| + {
|
| + for (var i = 0; i < this._messages.length; ++i) {
|
| + var rowMessage = this._messages[i];
|
| + if (!rowMessage.message().isEqual(message))
|
| + continue;
|
| + rowMessage.setRepeatCount(rowMessage.repeatCount() - 1);
|
| + if (!rowMessage.repeatCount())
|
| + this._messages.splice(i, 1);
|
| + this._updateDecoration();
|
| + return;
|
| + }
|
| + },
|
| +
|
| + _updateDecoration: function()
|
| + {
|
| + if (!this._sourceFrame.isEditorShowing())
|
| + return;
|
| + if (!this._messages.length)
|
| + return;
|
| + var position = this._lineHandle.resolve();
|
| + if (!position)
|
| + return;
|
| +
|
| + var lineNumber = position.lineNumber;
|
| + var columnNumber = Number.MAX_VALUE;
|
| + var maxMessage = null;
|
| + for (var i = 0; i < this._messages.length; ++i) {
|
| + var message = this._messages[i].message();
|
| + columnNumber = Math.min(columnNumber, message.columnNumber());
|
| + if (!maxMessage || WebInspector.UISourceCode.Message.messageLevelComparator(maxMessage, message) < 0)
|
| + maxMessage = message;
|
| + }
|
| + this._updateWavePosition(lineNumber, columnNumber);
|
| +
|
| + if (this._level) {
|
| + this._textEditor.toggleLineClass(lineNumber, WebInspector.UISourceCodeFrame._lineClassPerLevel[this._level], false);
|
| + this._icon.type = "";
|
| + }
|
| + this._level = maxMessage.level();
|
| + if (!this._level)
|
| + return;
|
| + this._textEditor.toggleLineClass(lineNumber, WebInspector.UISourceCodeFrame._lineClassPerLevel[this._level], true);
|
| + this._icon.type = WebInspector.UISourceCodeFrame._iconClassPerLevel[this._level];
|
| + }
|
| +}
|
| +
|
| +WebInspector.UISourceCode.Message._messageLevelPriority = {
|
| + "Warning": 3,
|
| + "Error": 4
|
| +};
|
| +
|
| +/**
|
| + * @param {!WebInspector.UISourceCode.Message} a
|
| + * @param {!WebInspector.UISourceCode.Message} b
|
| + * @return {number}
|
| + */
|
| +WebInspector.UISourceCode.Message.messageLevelComparator = function(a, b)
|
| +{
|
| + return WebInspector.UISourceCode.Message._messageLevelPriority[a.level()] - WebInspector.UISourceCode.Message._messageLevelPriority[b.level()];
|
| +}
|
|
|