| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * 1. Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * | |
| 11 * 2. Redistributions in binary form must reproduce the above | |
| 12 * copyright notice, this list of conditions and the following disclaimer | |
| 13 * in the documentation and/or other materials provided with the | |
| 14 * distribution. | |
| 15 * | |
| 16 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS | |
| 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. | |
| 20 * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 27 */ | |
| 28 | |
| 29 /** | |
| 30 * @unrestricted | |
| 31 */ | |
| 32 Sources.UISourceCodeFrame = class extends SourceFrame.SourceFrame { | |
| 33 /** | |
| 34 * @param {!Workspace.UISourceCode} uiSourceCode | |
| 35 */ | |
| 36 constructor(uiSourceCode) { | |
| 37 super(uiSourceCode.contentURL(), workingCopy); | |
| 38 this._uiSourceCode = uiSourceCode; | |
| 39 this.setEditable(this._canEditSource()); | |
| 40 | |
| 41 if (Runtime.experiments.isEnabled('sourceDiff')) | |
| 42 this._diff = new Sources.SourceCodeDiff(uiSourceCode.requestOriginalConten
t(), this.textEditor); | |
| 43 | |
| 44 /** @type {?UI.AutocompleteConfig} */ | |
| 45 this._autocompleteConfig = {isWordChar: Common.TextUtils.isWordChar}; | |
| 46 Common.moduleSetting('textEditorAutocompletion').addChangeListener(this._upd
ateAutocomplete, this); | |
| 47 this._updateAutocomplete(); | |
| 48 | |
| 49 /** @type {?Persistence.PersistenceBinding} */ | |
| 50 this._persistenceBinding = Persistence.persistence.binding(uiSourceCode); | |
| 51 | |
| 52 /** @type {!Map<number, !Sources.UISourceCodeFrame.RowMessageBucket>} */ | |
| 53 this._rowMessageBuckets = new Map(); | |
| 54 /** @type {!Set<string>} */ | |
| 55 this._typeDecorationsPending = new Set(); | |
| 56 this._uiSourceCode.addEventListener( | |
| 57 Workspace.UISourceCode.Events.WorkingCopyChanged, this._onWorkingCopyCha
nged, this); | |
| 58 this._uiSourceCode.addEventListener( | |
| 59 Workspace.UISourceCode.Events.WorkingCopyCommitted, this._onWorkingCopyC
ommitted, this); | |
| 60 | |
| 61 this._messageAndDecorationListeners = []; | |
| 62 this._installMessageAndDecorationListeners(); | |
| 63 | |
| 64 Persistence.persistence.subscribeForBindingEvent(this._uiSourceCode, this._o
nBindingChanged.bind(this)); | |
| 65 | |
| 66 this.textEditor.addEventListener( | |
| 67 SourceFrame.SourcesTextEditor.Events.EditorBlurred, | |
| 68 () => UI.context.setFlavor(Sources.UISourceCodeFrame, null)); | |
| 69 this.textEditor.addEventListener( | |
| 70 SourceFrame.SourcesTextEditor.Events.EditorFocused, | |
| 71 () => UI.context.setFlavor(Sources.UISourceCodeFrame, this)); | |
| 72 | |
| 73 this._updateStyle(); | |
| 74 | |
| 75 this._errorPopoverHelper = new UI.PopoverHelper(this.element); | |
| 76 this._errorPopoverHelper.initializeCallbacks(this._getErrorAnchor.bind(this)
, this._showErrorPopover.bind(this)); | |
| 77 | |
| 78 this._errorPopoverHelper.setTimeout(100, 100); | |
| 79 | |
| 80 /** | |
| 81 * @return {!Promise<?string>} | |
| 82 */ | |
| 83 function workingCopy() { | |
| 84 if (uiSourceCode.isDirty()) | |
| 85 return /** @type {!Promise<?string>} */ (Promise.resolve(uiSourceCode.wo
rkingCopy())); | |
| 86 return uiSourceCode.requestContent(); | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 _installMessageAndDecorationListeners() { | |
| 91 if (this._persistenceBinding) { | |
| 92 var networkSourceCode = this._persistenceBinding.network; | |
| 93 var fileSystemSourceCode = this._persistenceBinding.fileSystem; | |
| 94 this._messageAndDecorationListeners = [ | |
| 95 networkSourceCode.addEventListener(Workspace.UISourceCode.Events.Message
Added, this._onMessageAdded, this), | |
| 96 networkSourceCode.addEventListener(Workspace.UISourceCode.Events.Message
Removed, this._onMessageRemoved, this), | |
| 97 networkSourceCode.addEventListener( | |
| 98 Workspace.UISourceCode.Events.LineDecorationAdded, this._onLineDecor
ationAdded, this), | |
| 99 networkSourceCode.addEventListener( | |
| 100 Workspace.UISourceCode.Events.LineDecorationRemoved, this._onLineDec
orationRemoved, this), | |
| 101 | |
| 102 fileSystemSourceCode.addEventListener(Workspace.UISourceCode.Events.Mess
ageAdded, this._onMessageAdded, this), | |
| 103 fileSystemSourceCode.addEventListener( | |
| 104 Workspace.UISourceCode.Events.MessageRemoved, this._onMessageRemoved
, this), | |
| 105 ]; | |
| 106 } else { | |
| 107 this._messageAndDecorationListeners = [ | |
| 108 this._uiSourceCode.addEventListener(Workspace.UISourceCode.Events.Messag
eAdded, this._onMessageAdded, this), | |
| 109 this._uiSourceCode.addEventListener(Workspace.UISourceCode.Events.Messag
eRemoved, this._onMessageRemoved, this), | |
| 110 this._uiSourceCode.addEventListener( | |
| 111 Workspace.UISourceCode.Events.LineDecorationAdded, this._onLineDecor
ationAdded, this), | |
| 112 this._uiSourceCode.addEventListener( | |
| 113 Workspace.UISourceCode.Events.LineDecorationRemoved, this._onLineDec
orationRemoved, this) | |
| 114 ]; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 /** | |
| 119 * @return {!Workspace.UISourceCode} | |
| 120 */ | |
| 121 uiSourceCode() { | |
| 122 return this._uiSourceCode; | |
| 123 } | |
| 124 | |
| 125 /** | |
| 126 * @override | |
| 127 */ | |
| 128 wasShown() { | |
| 129 super.wasShown(); | |
| 130 // We need CodeMirrorTextEditor to be initialized prior to this call as it c
alls |cursorPositionToCoordinates| internally. @see crbug.com/506566 | |
| 131 setImmediate(this._updateBucketDecorations.bind(this)); | |
| 132 } | |
| 133 | |
| 134 /** | |
| 135 * @override | |
| 136 */ | |
| 137 willHide() { | |
| 138 super.willHide(); | |
| 139 UI.context.setFlavor(Sources.UISourceCodeFrame, null); | |
| 140 this._uiSourceCode.removeWorkingCopyGetter(); | |
| 141 } | |
| 142 | |
| 143 /** | |
| 144 * @return {boolean} | |
| 145 */ | |
| 146 _canEditSource() { | |
| 147 if (Persistence.persistence.binding(this._uiSourceCode)) | |
| 148 return true; | |
| 149 if (this._uiSourceCode.project().canSetFileContent()) | |
| 150 return true; | |
| 151 if (this._uiSourceCode.project().isServiceProject()) | |
| 152 return false; | |
| 153 return this._uiSourceCode.contentType() !== Common.resourceTypes.Document; | |
| 154 } | |
| 155 | |
| 156 commitEditing() { | |
| 157 if (!this._uiSourceCode.isDirty()) | |
| 158 return; | |
| 159 | |
| 160 this._muteSourceCodeEvents = true; | |
| 161 this._uiSourceCode.commitWorkingCopy(); | |
| 162 delete this._muteSourceCodeEvents; | |
| 163 } | |
| 164 | |
| 165 /** | |
| 166 * @override | |
| 167 */ | |
| 168 onTextEditorContentSet() { | |
| 169 if (this._diff) | |
| 170 this._diff.updateDiffMarkersImmediately(); | |
| 171 super.onTextEditorContentSet(); | |
| 172 for (var message of this._allMessages()) | |
| 173 this._addMessageToSource(message); | |
| 174 this._decorateAllTypes(); | |
| 175 } | |
| 176 | |
| 177 /** | |
| 178 * @return {!Array<!Workspace.UISourceCode.Message>} | |
| 179 */ | |
| 180 _allMessages() { | |
| 181 return this._persistenceBinding ? | |
| 182 this._persistenceBinding.network.messages().concat(this._persistenceBind
ing.fileSystem.messages()) : | |
| 183 this._uiSourceCode.messages(); | |
| 184 } | |
| 185 | |
| 186 /** | |
| 187 * @override | |
| 188 * @param {!Common.TextRange} oldRange | |
| 189 * @param {!Common.TextRange} newRange | |
| 190 */ | |
| 191 onTextChanged(oldRange, newRange) { | |
| 192 if (this._diff) | |
| 193 this._diff.updateDiffMarkersWhenPossible(); | |
| 194 super.onTextChanged(oldRange, newRange); | |
| 195 this._errorPopoverHelper.hidePopover(); | |
| 196 if (this._isSettingContent) | |
| 197 return; | |
| 198 this._muteSourceCodeEvents = true; | |
| 199 if (this.textEditor.isClean()) | |
| 200 this._uiSourceCode.resetWorkingCopy(); | |
| 201 else | |
| 202 this._uiSourceCode.setWorkingCopyGetter(this.textEditor.text.bind(this.tex
tEditor)); | |
| 203 delete this._muteSourceCodeEvents; | |
| 204 } | |
| 205 | |
| 206 /** | |
| 207 * @param {!Common.Event} event | |
| 208 */ | |
| 209 _onWorkingCopyChanged(event) { | |
| 210 if (this._muteSourceCodeEvents) | |
| 211 return; | |
| 212 this._innerSetContent(this._uiSourceCode.workingCopy()); | |
| 213 this.onUISourceCodeContentChanged(); | |
| 214 } | |
| 215 | |
| 216 /** | |
| 217 * @param {!Common.Event} event | |
| 218 */ | |
| 219 _onWorkingCopyCommitted(event) { | |
| 220 if (!this._muteSourceCodeEvents) { | |
| 221 this._innerSetContent(this._uiSourceCode.workingCopy()); | |
| 222 this.onUISourceCodeContentChanged(); | |
| 223 } | |
| 224 this.textEditor.markClean(); | |
| 225 this._updateStyle(); | |
| 226 } | |
| 227 | |
| 228 _onBindingChanged() { | |
| 229 var binding = Persistence.persistence.binding(this._uiSourceCode); | |
| 230 if (binding === this._persistenceBinding) | |
| 231 return; | |
| 232 for (var message of this._allMessages()) | |
| 233 this._removeMessageFromSource(message); | |
| 234 Common.EventTarget.removeEventListeners(this._messageAndDecorationListeners)
; | |
| 235 | |
| 236 this._persistenceBinding = binding; | |
| 237 | |
| 238 for (var message of this._allMessages()) | |
| 239 this._addMessageToSource(message); | |
| 240 this._installMessageAndDecorationListeners(); | |
| 241 this._updateStyle(); | |
| 242 this._decorateAllTypes(); | |
| 243 this.onBindingChanged(); | |
| 244 } | |
| 245 | |
| 246 /** | |
| 247 * @protected | |
| 248 */ | |
| 249 onBindingChanged() { | |
| 250 // Overriden in subclasses. | |
| 251 } | |
| 252 | |
| 253 _updateStyle() { | |
| 254 this.element.classList.toggle( | |
| 255 'source-frame-unsaved-committed-changes', | |
| 256 Persistence.persistence.hasUnsavedCommittedChanges(this._uiSourceCode)); | |
| 257 this.setEditable(this._canEditSource()); | |
| 258 } | |
| 259 | |
| 260 onUISourceCodeContentChanged() { | |
| 261 } | |
| 262 | |
| 263 _updateAutocomplete() { | |
| 264 this.textEditor.configureAutocomplete( | |
| 265 Common.moduleSetting('textEditorAutocompletion').get() ? this._autocompl
eteConfig : null); | |
| 266 } | |
| 267 | |
| 268 /** | |
| 269 * @param {?UI.AutocompleteConfig} config | |
| 270 */ | |
| 271 configureAutocomplete(config) { | |
| 272 this._autocompleteConfig = config; | |
| 273 this._updateAutocomplete(); | |
| 274 } | |
| 275 | |
| 276 /** | |
| 277 * @param {string} content | |
| 278 */ | |
| 279 _innerSetContent(content) { | |
| 280 this._isSettingContent = true; | |
| 281 if (this._diff) { | |
| 282 var oldContent = this.textEditor.text(); | |
| 283 this.setContent(content); | |
| 284 this._diff.highlightModifiedLines(oldContent, content); | |
| 285 } else { | |
| 286 this.setContent(content); | |
| 287 } | |
| 288 delete this._isSettingContent; | |
| 289 } | |
| 290 | |
| 291 /** | |
| 292 * @override | |
| 293 * @return {!Promise} | |
| 294 */ | |
| 295 populateTextAreaContextMenu(contextMenu, lineNumber, columnNumber) { | |
| 296 /** | |
| 297 * @this {Sources.UISourceCodeFrame} | |
| 298 */ | |
| 299 function appendItems() { | |
| 300 contextMenu.appendApplicableItems(this._uiSourceCode); | |
| 301 contextMenu.appendApplicableItems(new Workspace.UILocation(this._uiSourceC
ode, lineNumber, columnNumber)); | |
| 302 contextMenu.appendApplicableItems(this); | |
| 303 } | |
| 304 | |
| 305 return super.populateTextAreaContextMenu(contextMenu, lineNumber, columnNumb
er).then(appendItems.bind(this)); | |
| 306 } | |
| 307 | |
| 308 /** | |
| 309 * @param {!Array.<!UI.Infobar|undefined>} infobars | |
| 310 */ | |
| 311 attachInfobars(infobars) { | |
| 312 for (var i = infobars.length - 1; i >= 0; --i) { | |
| 313 var infobar = infobars[i]; | |
| 314 if (!infobar) | |
| 315 continue; | |
| 316 this.element.insertBefore(infobar.element, this.element.children[0]); | |
| 317 infobar.setParentView(this); | |
| 318 } | |
| 319 this.doResize(); | |
| 320 } | |
| 321 | |
| 322 dispose() { | |
| 323 this.textEditor.dispose(); | |
| 324 Common.moduleSetting('textEditorAutocompletion').removeChangeListener(this._
updateAutocomplete, this); | |
| 325 this.detach(); | |
| 326 } | |
| 327 | |
| 328 /** | |
| 329 * @param {!Common.Event} event | |
| 330 */ | |
| 331 _onMessageAdded(event) { | |
| 332 var message = /** @type {!Workspace.UISourceCode.Message} */ (event.data); | |
| 333 this._addMessageToSource(message); | |
| 334 } | |
| 335 | |
| 336 /** | |
| 337 * @param {!Workspace.UISourceCode.Message} message | |
| 338 */ | |
| 339 _addMessageToSource(message) { | |
| 340 if (!this.loaded) | |
| 341 return; | |
| 342 var lineNumber = message.lineNumber(); | |
| 343 if (lineNumber >= this.textEditor.linesCount) | |
| 344 lineNumber = this.textEditor.linesCount - 1; | |
| 345 if (lineNumber < 0) | |
| 346 lineNumber = 0; | |
| 347 | |
| 348 var messageBucket = this._rowMessageBuckets.get(lineNumber); | |
| 349 if (!messageBucket) { | |
| 350 messageBucket = new Sources.UISourceCodeFrame.RowMessageBucket(this, this.
textEditor, lineNumber); | |
| 351 this._rowMessageBuckets.set(lineNumber, messageBucket); | |
| 352 } | |
| 353 messageBucket.addMessage(message); | |
| 354 } | |
| 355 | |
| 356 /** | |
| 357 * @param {!Common.Event} event | |
| 358 */ | |
| 359 _onMessageRemoved(event) { | |
| 360 var message = /** @type {!Workspace.UISourceCode.Message} */ (event.data); | |
| 361 this._removeMessageFromSource(message); | |
| 362 } | |
| 363 | |
| 364 /** | |
| 365 * @param {!Workspace.UISourceCode.Message} message | |
| 366 */ | |
| 367 _removeMessageFromSource(message) { | |
| 368 if (!this.loaded) | |
| 369 return; | |
| 370 | |
| 371 var lineNumber = message.lineNumber(); | |
| 372 if (lineNumber >= this.textEditor.linesCount) | |
| 373 lineNumber = this.textEditor.linesCount - 1; | |
| 374 if (lineNumber < 0) | |
| 375 lineNumber = 0; | |
| 376 | |
| 377 var messageBucket = this._rowMessageBuckets.get(lineNumber); | |
| 378 if (!messageBucket) | |
| 379 return; | |
| 380 messageBucket.removeMessage(message); | |
| 381 if (!messageBucket.uniqueMessagesCount()) { | |
| 382 messageBucket.detachFromEditor(); | |
| 383 this._rowMessageBuckets.delete(lineNumber); | |
| 384 } | |
| 385 } | |
| 386 | |
| 387 /** | |
| 388 * @param {!Element} target | |
| 389 * @param {!Event} event | |
| 390 * @return {(!Element|undefined)} | |
| 391 */ | |
| 392 _getErrorAnchor(target, event) { | |
| 393 var element = target.enclosingNodeOrSelfWithClass('text-editor-line-decorati
on-icon') || | |
| 394 target.enclosingNodeOrSelfWithClass('text-editor-line-decoration-wave'); | |
| 395 if (!element) | |
| 396 return; | |
| 397 this._errorWavePopoverAnchor = new AnchorBox(event.clientX, event.clientY, 1
, 1); | |
| 398 return element; | |
| 399 } | |
| 400 | |
| 401 /** | |
| 402 * @param {!Element} anchor | |
| 403 * @param {!UI.Popover} popover | |
| 404 */ | |
| 405 _showErrorPopover(anchor, popover) { | |
| 406 var messageBucket = anchor.enclosingNodeOrSelfWithClass('text-editor-line-de
coration')._messageBucket; | |
| 407 var messagesOutline = messageBucket.messagesDescription(); | |
| 408 var popoverAnchor = | |
| 409 anchor.enclosingNodeOrSelfWithClass('text-editor-line-decoration-icon')
? anchor : this._errorWavePopoverAnchor; | |
| 410 popover.showForAnchor(messagesOutline, popoverAnchor); | |
| 411 } | |
| 412 | |
| 413 _updateBucketDecorations() { | |
| 414 for (var bucket of this._rowMessageBuckets.values()) | |
| 415 bucket._updateDecoration(); | |
| 416 } | |
| 417 | |
| 418 /** | |
| 419 * @param {!Common.Event} event | |
| 420 */ | |
| 421 _onLineDecorationAdded(event) { | |
| 422 var marker = /** @type {!Workspace.UISourceCode.LineMarker} */ (event.data); | |
| 423 this._decorateTypeThrottled(marker.type()); | |
| 424 } | |
| 425 | |
| 426 /** | |
| 427 * @param {!Common.Event} event | |
| 428 */ | |
| 429 _onLineDecorationRemoved(event) { | |
| 430 var marker = /** @type {!Workspace.UISourceCode.LineMarker} */ (event.data); | |
| 431 this._decorateTypeThrottled(marker.type()); | |
| 432 } | |
| 433 | |
| 434 /** | |
| 435 * @param {string} type | |
| 436 */ | |
| 437 _decorateTypeThrottled(type) { | |
| 438 if (this._typeDecorationsPending.has(type)) | |
| 439 return; | |
| 440 this._typeDecorationsPending.add(type); | |
| 441 self.runtime.extensions(Sources.UISourceCodeFrame.LineDecorator) | |
| 442 .find(extension => extension.descriptor()['decoratorType'] === type) | |
| 443 .instance() | |
| 444 .then(decorator => { | |
| 445 this._typeDecorationsPending.delete(type); | |
| 446 decorator.decorate( | |
| 447 this._persistenceBinding ? this._persistenceBinding.network : this
.uiSourceCode(), this.textEditor); | |
| 448 }); | |
| 449 } | |
| 450 | |
| 451 _decorateAllTypes() { | |
| 452 var extensions = self.runtime.extensions(Sources.UISourceCodeFrame.LineDecor
ator); | |
| 453 extensions.forEach(extension => this._decorateTypeThrottled(extension.descri
ptor()['decoratorType'])); | |
| 454 } | |
| 455 }; | |
| 456 | |
| 457 Sources.UISourceCodeFrame._iconClassPerLevel = {}; | |
| 458 Sources.UISourceCodeFrame._iconClassPerLevel[Workspace.UISourceCode.Message.Leve
l.Error] = 'smallicon-error'; | |
| 459 Sources.UISourceCodeFrame._iconClassPerLevel[Workspace.UISourceCode.Message.Leve
l.Warning] = 'smallicon-warning'; | |
| 460 | |
| 461 Sources.UISourceCodeFrame._bubbleTypePerLevel = {}; | |
| 462 Sources.UISourceCodeFrame._bubbleTypePerLevel[Workspace.UISourceCode.Message.Lev
el.Error] = 'error'; | |
| 463 Sources.UISourceCodeFrame._bubbleTypePerLevel[Workspace.UISourceCode.Message.Lev
el.Warning] = 'warning'; | |
| 464 | |
| 465 Sources.UISourceCodeFrame._lineClassPerLevel = {}; | |
| 466 Sources.UISourceCodeFrame._lineClassPerLevel[Workspace.UISourceCode.Message.Leve
l.Error] = | |
| 467 'text-editor-line-with-error'; | |
| 468 Sources.UISourceCodeFrame._lineClassPerLevel[Workspace.UISourceCode.Message.Leve
l.Warning] = | |
| 469 'text-editor-line-with-warning'; | |
| 470 | |
| 471 /** | |
| 472 * @interface | |
| 473 */ | |
| 474 Sources.UISourceCodeFrame.LineDecorator = function() {}; | |
| 475 | |
| 476 Sources.UISourceCodeFrame.LineDecorator.prototype = { | |
| 477 /** | |
| 478 * @param {!Workspace.UISourceCode} uiSourceCode | |
| 479 * @param {!TextEditor.CodeMirrorTextEditor} textEditor | |
| 480 */ | |
| 481 decorate(uiSourceCode, textEditor) {} | |
| 482 }; | |
| 483 | |
| 484 /** | |
| 485 * @unrestricted | |
| 486 */ | |
| 487 Sources.UISourceCodeFrame.RowMessage = class { | |
| 488 /** | |
| 489 * @param {!Workspace.UISourceCode.Message} message | |
| 490 */ | |
| 491 constructor(message) { | |
| 492 this._message = message; | |
| 493 this._repeatCount = 1; | |
| 494 this.element = createElementWithClass('div', 'text-editor-row-message'); | |
| 495 this._icon = this.element.createChild('label', '', 'dt-icon-label'); | |
| 496 this._icon.type = Sources.UISourceCodeFrame._iconClassPerLevel[message.level
()]; | |
| 497 this._repeatCountElement = this.element.createChild('label', 'message-repeat
-count hidden', 'dt-small-bubble'); | |
| 498 this._repeatCountElement.type = Sources.UISourceCodeFrame._bubbleTypePerLeve
l[message.level()]; | |
| 499 var linesContainer = this.element.createChild('div', 'text-editor-row-messag
e-lines'); | |
| 500 var lines = this._message.text().split('\n'); | |
| 501 for (var i = 0; i < lines.length; ++i) { | |
| 502 var messageLine = linesContainer.createChild('div'); | |
| 503 messageLine.textContent = lines[i]; | |
| 504 } | |
| 505 } | |
| 506 | |
| 507 /** | |
| 508 * @return {!Workspace.UISourceCode.Message} | |
| 509 */ | |
| 510 message() { | |
| 511 return this._message; | |
| 512 } | |
| 513 | |
| 514 /** | |
| 515 * @return {number} | |
| 516 */ | |
| 517 repeatCount() { | |
| 518 return this._repeatCount; | |
| 519 } | |
| 520 | |
| 521 setRepeatCount(repeatCount) { | |
| 522 if (this._repeatCount === repeatCount) | |
| 523 return; | |
| 524 this._repeatCount = repeatCount; | |
| 525 this._updateMessageRepeatCount(); | |
| 526 } | |
| 527 | |
| 528 _updateMessageRepeatCount() { | |
| 529 this._repeatCountElement.textContent = this._repeatCount; | |
| 530 var showRepeatCount = this._repeatCount > 1; | |
| 531 this._repeatCountElement.classList.toggle('hidden', !showRepeatCount); | |
| 532 this._icon.classList.toggle('hidden', showRepeatCount); | |
| 533 } | |
| 534 }; | |
| 535 | |
| 536 /** | |
| 537 * @unrestricted | |
| 538 */ | |
| 539 Sources.UISourceCodeFrame.RowMessageBucket = class { | |
| 540 /** | |
| 541 * @param {!Sources.UISourceCodeFrame} sourceFrame | |
| 542 * @param {!TextEditor.CodeMirrorTextEditor} textEditor | |
| 543 * @param {number} lineNumber | |
| 544 */ | |
| 545 constructor(sourceFrame, textEditor, lineNumber) { | |
| 546 this._sourceFrame = sourceFrame; | |
| 547 this.textEditor = textEditor; | |
| 548 this._lineHandle = textEditor.textEditorPositionHandle(lineNumber, 0); | |
| 549 this._decoration = createElementWithClass('div', 'text-editor-line-decoratio
n'); | |
| 550 this._decoration._messageBucket = this; | |
| 551 this._wave = this._decoration.createChild('div', 'text-editor-line-decoratio
n-wave'); | |
| 552 this._icon = this._wave.createChild('label', 'text-editor-line-decoration-ic
on', 'dt-icon-label'); | |
| 553 this._hasDecoration = false; | |
| 554 | |
| 555 this._messagesDescriptionElement = createElementWithClass('div', 'text-edito
r-messages-description-container'); | |
| 556 /** @type {!Array.<!Sources.UISourceCodeFrame.RowMessage>} */ | |
| 557 this._messages = []; | |
| 558 | |
| 559 this._level = null; | |
| 560 } | |
| 561 | |
| 562 /** | |
| 563 * @param {number} lineNumber | |
| 564 * @param {number} columnNumber | |
| 565 */ | |
| 566 _updateWavePosition(lineNumber, columnNumber) { | |
| 567 lineNumber = Math.min(lineNumber, this.textEditor.linesCount - 1); | |
| 568 var lineText = this.textEditor.line(lineNumber); | |
| 569 columnNumber = Math.min(columnNumber, lineText.length); | |
| 570 var lineIndent = Common.TextUtils.lineIndent(lineText).length; | |
| 571 if (this._hasDecoration) | |
| 572 this.textEditor.removeDecoration(this._decoration, lineNumber); | |
| 573 this._hasDecoration = true; | |
| 574 this.textEditor.addDecoration(this._decoration, lineNumber, Math.max(columnN
umber - 1, lineIndent)); | |
| 575 } | |
| 576 | |
| 577 /** | |
| 578 * @return {!Element} | |
| 579 */ | |
| 580 messagesDescription() { | |
| 581 this._messagesDescriptionElement.removeChildren(); | |
| 582 for (var i = 0; i < this._messages.length; ++i) | |
| 583 this._messagesDescriptionElement.appendChild(this._messages[i].element); | |
| 584 | |
| 585 return this._messagesDescriptionElement; | |
| 586 } | |
| 587 | |
| 588 detachFromEditor() { | |
| 589 var position = this._lineHandle.resolve(); | |
| 590 if (!position) | |
| 591 return; | |
| 592 var lineNumber = position.lineNumber; | |
| 593 if (this._level) | |
| 594 this.textEditor.toggleLineClass(lineNumber, Sources.UISourceCodeFrame._lin
eClassPerLevel[this._level], false); | |
| 595 if (this._hasDecoration) | |
| 596 this.textEditor.removeDecoration(this._decoration, lineNumber); | |
| 597 this._hasDecoration = false; | |
| 598 } | |
| 599 | |
| 600 /** | |
| 601 * @return {number} | |
| 602 */ | |
| 603 uniqueMessagesCount() { | |
| 604 return this._messages.length; | |
| 605 } | |
| 606 | |
| 607 /** | |
| 608 * @param {!Workspace.UISourceCode.Message} message | |
| 609 */ | |
| 610 addMessage(message) { | |
| 611 for (var i = 0; i < this._messages.length; ++i) { | |
| 612 var rowMessage = this._messages[i]; | |
| 613 if (rowMessage.message().isEqual(message)) { | |
| 614 rowMessage.setRepeatCount(rowMessage.repeatCount() + 1); | |
| 615 return; | |
| 616 } | |
| 617 } | |
| 618 | |
| 619 var rowMessage = new Sources.UISourceCodeFrame.RowMessage(message); | |
| 620 this._messages.push(rowMessage); | |
| 621 this._updateDecoration(); | |
| 622 } | |
| 623 | |
| 624 /** | |
| 625 * @param {!Workspace.UISourceCode.Message} message | |
| 626 */ | |
| 627 removeMessage(message) { | |
| 628 for (var i = 0; i < this._messages.length; ++i) { | |
| 629 var rowMessage = this._messages[i]; | |
| 630 if (!rowMessage.message().isEqual(message)) | |
| 631 continue; | |
| 632 rowMessage.setRepeatCount(rowMessage.repeatCount() - 1); | |
| 633 if (!rowMessage.repeatCount()) | |
| 634 this._messages.splice(i, 1); | |
| 635 this._updateDecoration(); | |
| 636 return; | |
| 637 } | |
| 638 } | |
| 639 | |
| 640 _updateDecoration() { | |
| 641 if (!this._sourceFrame.isEditorShowing()) | |
| 642 return; | |
| 643 if (!this._messages.length) | |
| 644 return; | |
| 645 var position = this._lineHandle.resolve(); | |
| 646 if (!position) | |
| 647 return; | |
| 648 | |
| 649 var lineNumber = position.lineNumber; | |
| 650 var columnNumber = Number.MAX_VALUE; | |
| 651 var maxMessage = null; | |
| 652 for (var i = 0; i < this._messages.length; ++i) { | |
| 653 var message = this._messages[i].message(); | |
| 654 columnNumber = Math.min(columnNumber, message.columnNumber()); | |
| 655 if (!maxMessage || Workspace.UISourceCode.Message.messageLevelComparator(m
axMessage, message) < 0) | |
| 656 maxMessage = message; | |
| 657 } | |
| 658 this._updateWavePosition(lineNumber, columnNumber); | |
| 659 | |
| 660 if (this._level) { | |
| 661 this.textEditor.toggleLineClass(lineNumber, Sources.UISourceCodeFrame._lin
eClassPerLevel[this._level], false); | |
| 662 this._icon.type = ''; | |
| 663 } | |
| 664 this._level = maxMessage.level(); | |
| 665 if (!this._level) | |
| 666 return; | |
| 667 this.textEditor.toggleLineClass(lineNumber, Sources.UISourceCodeFrame._lineC
lassPerLevel[this._level], true); | |
| 668 this._icon.type = Sources.UISourceCodeFrame._iconClassPerLevel[this._level]; | |
| 669 } | |
| 670 }; | |
| 671 | |
| 672 Workspace.UISourceCode.Message._messageLevelPriority = { | |
| 673 'Warning': 3, | |
| 674 'Error': 4 | |
| 675 }; | |
| 676 | |
| 677 /** | |
| 678 * @param {!Workspace.UISourceCode.Message} a | |
| 679 * @param {!Workspace.UISourceCode.Message} b | |
| 680 * @return {number} | |
| 681 */ | |
| 682 Workspace.UISourceCode.Message.messageLevelComparator = function(a, b) { | |
| 683 return Workspace.UISourceCode.Message._messageLevelPriority[a.level()] - | |
| 684 Workspace.UISourceCode.Message._messageLevelPriority[b.level()]; | |
| 685 }; | |
| OLD | NEW |