Changeset 160483 in webkit
- Timestamp:
- Dec 12, 2013 2:17:20 AM (10 years ago)
- Location:
- trunk/Source/WebInspectorUI
- Files:
-
- 3 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebInspectorUI/ChangeLog
r160203 r160483 1 2013-12-12 Antoine Quint <graouts@apple.com> 2 3 Web Inspector: allow editing of colors in CSS resources 4 https://bugs.webkit.org/show_bug.cgi?id=124364 5 6 Reviewed by Timothy Hatcher. 7 8 Identify colors in CSS and HTML resources so that hovering these colors shows a HoverMenu 9 allowing a ColorPicker hosted in a Popover to be shown to edit the hovered color. 10 11 * UserInterface/CSSStyleDeclarationTextEditor.js: 12 (WebInspector.CSSStyleDeclarationTextEditor.prototype._createColorSwatches): 13 Remove the code that goes through the lines of the CodeMirror editor to look for 14 color strings and replace it with a call to the .createColorMarkers() CodeMirror 15 extension in which the code was refactored. The callback passed to 16 .createColorMarkers() handles the CSSStyleDeclarationTextEditor-specific creation 17 of color swatches to show the popover, keeping the existing behavior of the Styles 18 sidebar panel. 19 20 * UserInterface/CodeMirrorAdditions.js: 21 Refactor existing code into two new CodeMirror extensions: .boundsForRange(), which 22 was previously defined on the CodeMirrorTokenTrackingController but was also needed 23 in the new CodeMirrorColorEditingController, and .createColorMarkers(), discussed above. 24 25 * UserInterface/CodeMirrorColorEditingController.js: Added. 26 (WebInspector.CodeMirrorColorEditingController): 27 New class used by SourceCodeTextEditor to coordinate the editing of a color in a CodeMirror 28 TextMarker by a ColorPicker hosted in a Popover shown by the activation of a HoverMenu. This 29 controller automatically gets the color set by the user using the ColorPicker and updates 30 the CodeMirror text editor with the new value. When the user presses the Esc. key while the 31 popover is shown, it's automatically dismissed and the original color is reset in the editor. 32 33 (WebInspector.CodeMirrorColorEditingController.prototype.get marker): 34 (WebInspector.CodeMirrorColorEditingController.prototype.get range): 35 (WebInspector.CodeMirrorColorEditingController.prototype.get delegate): 36 (WebInspector.CodeMirrorColorEditingController.prototype.set delegate): 37 Getters and setters for public properties. 38 39 (WebInspector.CodeMirrorColorEditingController.prototype.get color): 40 (WebInspector.CodeMirrorColorEditingController.prototype.set color): 41 Get and set the color for the edited color marker, replacing the text in the marker's range 42 upon setting. 43 44 (WebInspector.CodeMirrorColorEditingController.prototype.presentHoverMenu): 45 Public API allowing for a HoverMenu to be shown around the bounds of the TextMarker passed 46 in the constructor. This method is called from SourceCodeTextEditor when the 47 CodeMirrorTokenTrackingController identifies that a token that is part of a TextMarker is 48 hovered and that token is a color. 49 50 (WebInspector.CodeMirrorColorEditingController.prototype.dismissHoverMenu): 51 Public API allowing for the HoverMenu to be dismissed. This method is called when the 52 CodeMirrorTokenTrackingController identifies that its "hoveredMarker" is no longer being 53 hovered as well as when we identify that editing of the color has completed. 54 55 (WebInspector.CodeMirrorColorEditingController.prototype.handleEvent): 56 Event handler for the "keydown" event that are being listened to when the HoverMenu 57 is activated such that the Esc. key can be used to dimiss the popover and reset the 58 original color before any edits. 59 60 (WebInspector.CodeMirrorColorEditingController.prototype.hoverMenuButtonWasPressed): 61 Implementation of the HoverMenu delegation method used to show a Popover containing a 62 ColorPicker upon clicking on the color wheel attached to the HoverMenu. We also remember 63 the color set on the marker so that it may be restored when Esc. is pressed and used to 64 set the original state of the ColorPicker. The delegation method 65 colorEditingControllerDidStartEditing() is also called at this point, which the 66 SourceCodeTextEditor implements. 67 68 (WebInspector.CodeMirrorColorEditingController.prototype.didDismissPopover): 69 Implementation of the Popover delegation method used to identify that color editing has 70 completed. The delegation method colorEditingControllerDidFinishEditing() is called 71 at this point, which the SourceCodeTextEditor implements. 72 73 (WebInspector.CodeMirrorColorEditingController.prototype._colorPickerColorChanged): 74 Apply the color set in the color picker to the CodeMirror text editor. 75 76 * UserInterface/CodeMirrorTokenTrackingController.js: 77 Add two new modes to CodeMirrorTokenTrackingController. The first mode is "None" and is 78 the default, incurring no specific token handling behavior. The second mode is "MarkedTokens" 79 which identifies hover of a token contained in a CodeMirror TextMarker range. The new 80 "MarkedTokens" mode is used by SourceCodeTextEditor to identify when a marked color is being 81 hovered to display a HoverMenu. 82 83 (WebInspector.CodeMirrorTokenTrackingController): 84 (WebInspector.CodeMirrorTokenTrackingController.prototype.set mode): 85 Make "None" the new default mode for CodeMirrorTokenTrackingController. 86 87 (WebInspector.CodeMirrorTokenTrackingController.prototype.get hoveredMarker): 88 (WebInspector.CodeMirrorTokenTrackingController.prototype.set hoveredMarker): 89 (WebInspector.CodeMirrorTokenTrackingController.prototype._updateHoveredTokenInfo): 90 Check, when we have a "hoveredMarker" set on the CodeMirrorTokenTrackingController, 91 whether the "hoveredMarker" is still being hovered when there is no token at the current 92 mouse position. We can then determine when we're mousing out of the "hoveredMarker" and 93 notify the delegate via the new tokenTrackingControllerMouseOutOfHoveredMarker delegate 94 method. The SourceCodeTextEditor uses this method to dismiss its CodeMirrorColorEditingController. 95 96 (WebInspector.CodeMirrorTokenTrackingController.prototype._processNewHoveredToken): 97 Add support for the new "MarkedTokens" mode. 98 99 (WebInspector.CodeMirrorTokenTrackingController.prototype._processMarkedToken): 100 For the moment, use the same behavior as the existing "MarkedTokens" mode. 101 102 * UserInterface/Color.js: 103 (WebInspector.Color): 104 Add a new "valid" property to identify whether a color has any invalid (NaN) component. This property 105 is used by SourceCodeTextEditor to establish whether a hovered color marker is indeed set to a 106 valid color still. 107 108 (WebInspector.Color.prototype.copy): 109 New method to create an exact copy of a Color instance, used by CodeMirrorColorEditingController 110 to duplicate the edited color in case we need to revert it. 111 112 * UserInterface/HoverMenu.js: 113 (WebInspector.HoverMenu.prototype._handleClickEvent): 114 Rename hoverMenuWasActivated to hoverMenuButtonWasPressed per review feedback. 115 116 * UserInterface/Images/ColorIcon.png: Added. 117 * UserInterface/Images/ColorIcon@2x.png: Added. 118 New color wheel icon used to customize the HoverMenu shown by a CodeMirrorColorEditingController. 119 120 * UserInterface/Main.html: 121 Link to the new CodeMirrorColorEditingController.js file. 122 123 * UserInterface/SourceCodeTextEditor.css: 124 (.hover-menu.color): 125 (.hover-menu.color > img): 126 Customize the HoverMenu shown by a CodeMirrorColorEditingController to use the new ColorIcon asset. 127 128 * UserInterface/SourceCodeTextEditor.js: 129 (WebInspector.SourceCodeTextEditor): 130 Add a new "_ignoreContentDidChange" ivar that increments and decrements to track when handling 131 of CodeMirror content changes should be disabled. 132 133 (WebInspector.SourceCodeTextEditor.prototype.close): 134 Adopt the new ._updateTokenTrackingControllerState() method to update the state of the 135 CodeMirrorTokenTrackingController. 136 137 (WebInspector.SourceCodeTextEditor.prototype.contentDidChange): 138 Override the new TextEditor public API called when content in the CodeMirror text editor is changed. 139 We use this method to process any newly added line to create any newly added color marker. 140 141 (WebInspector.SourceCodeTextEditor.prototype._contentDidPopulate): 142 (WebInspector.SourceCodeTextEditor.prototype._debuggerDidPause): 143 (WebInspector.SourceCodeTextEditor.prototype._debuggerDidResume): 144 (WebInspector.SourceCodeTextEditor.prototype._sourceCodeSourceMapAdded): 145 Adopt the new ._updateTokenTrackingControllerState() method to update the state of the 146 CodeMirrorTokenTrackingController. 147 148 (WebInspector.SourceCodeTextEditor.prototype._updateTokenTrackingControllerState): 149 New method acting as the only point where we check the state of the text editor and set the right 150 mode and settings on the CodeMirrorTokenTrackingController, including setting the new "MarkedTokens" 151 mode when we have color markers, as determined by ._hasColorMarkers(). 152 153 (WebInspector.SourceCodeTextEditor.prototype._hasColorMarkers): 154 Check whether any of the TextMarkers set on the CodeMirror text editor were created for a color. 155 156 (WebInspector.SourceCodeTextEditor.prototype.tokenTrackingControllerHighlightedRangeWasClicked): 157 Check the CodeMirrorTokenTrackingController mode rather than the removed "_jumpToSymbolTrackingModeEnabled" 158 ivar to identify we're in the "NonSymbolTokens" mode. 159 160 (WebInspector.SourceCodeTextEditor.prototype.tokenTrackingControllerNewHighlightCandidate): 161 Refactor method to use the CodeMirrorTokenTrackingController mode to branch into mode-specific code 162 and add a new branch for the new "MarkedTokens" mode where we check if the newly hovered token 163 is part of a color TextMarker range. 164 165 (WebInspector.SourceCodeTextEditor.prototype.tokenTrackingControllerMouseOutOfHoveredMarker): 166 Implement this new CodeMirrorTokenTrackingController delegation method to dismiss the 167 CodeMirrorColorEditingController as we identify we're no longer hovering over the TextMarker 168 for which the CodeMirrorColorEditingController was created. 169 170 (WebInspector.SourceCodeTextEditor.prototype._showPopover): 171 Adopt the new TextEditor boundsForRange() method. 172 173 (WebInspector.SourceCodeTextEditor.prototype._updateColorMarkers): 174 Harness the new TextEditor createColorMarkers() method to create new TextMarkers for the provided 175 line, or the entire text editor content if none provided. We then immediately call _updateTokenTrackingControllerState() 176 so that the new "MarkedTokens" mode is entered in case color TextMarkers were created for the first 177 time for this text editor. 178 179 (WebInspector.SourceCodeTextEditor.prototype._tokenTrackingControllerHighlightedMarkedExpression): 180 Called when we've identified the CodeMirrorTokenTrackingController highlighted a TextMarker. We check 181 if any of the hovered TextMarkers are for a color, and in this case create a CodeMirrorColorEditingController 182 to coordinate the display of a ColorPicker in a Popover to edit the hovered color token. We also check 183 whether the hovered marker still contains a valid color, clearing the marker in case it was edited to 184 no longer contain a color. 185 186 (WebInspector.SourceCodeTextEditor.prototype._dismissCodeMirrorColorEditingController): 187 Used to dismiss the CodeMirrorColorEditingController, if previously presented, and reset some internal state. 188 189 (WebInspector.SourceCodeTextEditor.prototype.colorEditingControllerDidStartEditing): 190 Implement this CodeMirrorColorEditingController delegation method to temporarily disable the 191 CodeMirrorTokenTrackingController while we edit the color with the ColorPicker, remove 192 the TextMarker for the edited color and instruct that content changes should be ignored 193 such that we act on the complete set of color edits upon completion. 194 195 (WebInspector.SourceCodeTextEditor.prototype.colorEditingControllerDidFinishEditing): 196 Update color markers for the edited line such that any color edits are correctly updated for 197 the future and so that, as a side-effect, the CodeMirrorColorEditingController is reset to the 198 appropriate mode depending on whether color TextMarkers are indeed available, resetting states 199 that may have been altered by colorEditingControllerDidStartEditing(). 200 201 * UserInterface/TextEditor.js: 202 (WebInspector.TextEditor.prototype.contentDidChange): 203 New public method meant to be overriden by subclasses, added for the use of SourceCodeTextEditor, exposing 204 the list of TextRanges affected by the content change, both in the context of the old content and new content. 205 206 (WebInspector.TextEditor.prototype.boundsForRange): 207 (WebInspector.TextEditor.prototype.get markers): 208 (WebInspector.TextEditor.prototype.findMarkersAtPosition): 209 (WebInspector.TextEditor.prototype.createColorMarkers): 210 (WebInspector.TextEditor.prototype.colorEditingControllerForMarker): 211 New public methods calling into the CodeMirror private ivar for the benefit of SourceCodeTextEditor. 212 213 (WebInspector.TextEditor.prototype._contentChanged): 214 Call the new contentDidChange() method. 215 1 216 2013-12-05 Seokju Kwon <seokju@webkit.org> 2 217 -
trunk/Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js
r160132 r160483 391 391 function update() 392 392 { 393 // Matches rgba(0, 0, 0, 0.5), rgb(0, 0, 0), hsl(), hsla(), #fff, #ffffff, white394 const colorRegex = /((?:rgb|hsl)a?\([^)]+\)|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}|\b\w+\b(?![-.]))/g;395 396 var start = typeof lineNumber === "number" ? lineNumber : 0;397 var end = typeof lineNumber === "number" ? lineNumber + 1 : this._codeMirror.lineCount();398 399 393 // Look for color strings and add swatches in front of them. 400 for (var i = start; i < end; ++i) { 401 var lineContent = this._codeMirror.getLine(i); 402 403 var match = colorRegex.exec(lineContent); 404 while (match) { 405 406 // Act as a negative look-behind and disallow the color from being prefixing with certain characters. 407 if (match.index > 0 && /[-.]/.test(lineContent[match.index - 1])) { 408 match = colorRegex.exec(lineContent); 409 continue; 410 } 411 412 var from = {line: i, ch: match.index}; 413 var to = {line: i, ch: match.index + match[0].length}; 414 415 var foundColorMarker = false; 416 var marks = this._codeMirror.findMarksAt(to); 417 for (var j = 0; j < marks.length; ++j) { 418 if (!marks[j].__markedColor) 419 continue; 420 foundColorMarker = true; 421 break; 422 } 423 424 if (foundColorMarker) { 425 match = colorRegex.exec(lineContent); 426 continue; 427 } 428 429 430 var color = WebInspector.Color.fromString(match[0]); 431 if (!color) { 432 match = colorRegex.exec(lineContent); 433 continue; 434 } 435 436 var swatchElement = document.createElement("span"); 437 swatchElement.title = WebInspector.UIString("Click to open a colorpicker. Shift-click to change color format."); 438 swatchElement.className = WebInspector.CSSStyleDeclarationTextEditor.ColorSwatchElementStyleClassName; 439 swatchElement.addEventListener("click", this._colorSwatchClicked.bind(this)); 440 441 var swatchInnerElement = document.createElement("span"); 442 swatchInnerElement.style.backgroundColor = match[0]; 443 swatchElement.appendChild(swatchInnerElement); 444 445 var swatchMarker = this._codeMirror.setUniqueBookmark(from, swatchElement); 446 447 var colorTextMarker = this._codeMirror.markText(from, to); 448 colorTextMarker.__markedColor = true; 449 450 swatchInnerElement.__colorTextMarker = colorTextMarker; 451 swatchInnerElement.__color = color; 452 453 match = colorRegex.exec(lineContent); 454 } 455 } 394 this._codeMirror.createColorMarkers(lineNumber, function(marker, color, colorString) { 395 var swatchElement = document.createElement("span"); 396 swatchElement.title = WebInspector.UIString("Click to open a colorpicker. Shift-click to change color format."); 397 swatchElement.className = WebInspector.CSSStyleDeclarationTextEditor.ColorSwatchElementStyleClassName; 398 swatchElement.addEventListener("click", this._colorSwatchClicked.bind(this)); 399 400 var swatchInnerElement = document.createElement("span"); 401 swatchInnerElement.style.backgroundColor = colorString; 402 swatchElement.appendChild(swatchInnerElement); 403 404 var swatchMarker = this._codeMirror.setUniqueBookmark(marker.find().from, swatchElement); 405 406 swatchInnerElement.__colorTextMarker = marker; 407 swatchInnerElement.__color = color; 408 }.bind(this)); 456 409 } 457 410 -
trunk/Source/WebInspectorUI/UserInterface/CodeMirrorAdditions.js
r158061 r160483 419 419 } 420 420 421 CodeMirror.defineExtension("boundsForRange", function(range) { 422 var firstCharCoords = this.cursorCoords(range.start); 423 var lastCharCoords = this.cursorCoords(range.end); 424 return new WebInspector.Rect(firstCharCoords.left, firstCharCoords.top, lastCharCoords.right - firstCharCoords.left, firstCharCoords.bottom - firstCharCoords.top); 425 }); 426 427 CodeMirror.defineExtension("createColorMarkers", function(lineNumber, callback) { 428 var createdMarkers = []; 429 430 var start = typeof lineNumber === "number" ? lineNumber : 0; 431 var end = typeof lineNumber === "number" ? lineNumber + 1 : this.lineCount(); 432 433 // Matches rgba(0, 0, 0, 0.5), rgb(0, 0, 0), hsl(), hsla(), #fff, #ffffff, white 434 const colorRegex = /((?:rgb|hsl)a?\([^)]+\)|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}|\b\w+\b(?![-.]))/g; 435 436 for (var lineNumber = start; lineNumber < end; ++lineNumber) { 437 var lineContent = this.getLine(lineNumber); 438 var match = colorRegex.exec(lineContent); 439 while (match) { 440 441 // Act as a negative look-behind and disallow the color from being prefixing with certain characters. 442 if (match.index > 0 && /[-.]/.test(lineContent[match.index - 1])) { 443 match = colorRegex.exec(lineContent); 444 continue; 445 } 446 447 var from = {line: lineNumber, ch: match.index}; 448 var to = {line: lineNumber, ch: match.index + match[0].length}; 449 450 var foundColorMarker = false; 451 var markers = this.findMarksAt(to); 452 for (var j = 0; j < markers.length; ++j) { 453 if (!markers[j].__markedColor) 454 continue; 455 foundColorMarker = true; 456 break; 457 } 458 459 if (foundColorMarker) { 460 match = colorRegex.exec(lineContent); 461 continue; 462 } 463 464 var colorString = match[0]; 465 var color = WebInspector.Color.fromString(colorString); 466 if (!color) { 467 match = colorRegex.exec(lineContent); 468 continue; 469 } 470 471 var marker = this.markText(from, to); 472 marker.__markedColor = true; 473 474 createdMarkers.push(marker); 475 476 if (callback) 477 callback(marker, color, colorString); 478 479 match = colorRegex.exec(lineContent); 480 } 481 } 482 483 return createdMarkers; 484 }); 485 421 486 function ignoreKey(codeMirror) 422 487 { -
trunk/Source/WebInspectorUI/UserInterface/CodeMirrorTokenTrackingController.js
r156923 r160483 32 32 this._codeMirror = codeMirror; 33 33 this._delegate = delegate || null; 34 this._mode = WebInspector.CodeMirrorTokenTrackingController.Mode.Non SymbolTokens;34 this._mode = WebInspector.CodeMirrorTokenTrackingController.Mode.None; 35 35 36 36 this._mouseOverDelayDuration = 0; … … 41 41 this._tracking = false; 42 42 this._hoveredTokenInfo = null; 43 this._hoveredMarker = null; 43 44 }; 44 45 … … 46 47 47 48 WebInspector.CodeMirrorTokenTrackingController.Mode = { 49 None: "none", 48 50 NonSymbolTokens: "non-symbol-tokens", 49 51 JavaScriptExpression: "javascript-expression", 52 MarkedTokens: "marked-tokens" 50 53 } 51 54 … … 95 98 }, 96 99 97 set mode( x)100 set mode(mode) 98 101 { 99 102 var oldMode = this._mode; 100 103 101 this._mode = x || WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens;104 this._mode = mode || WebInspector.CodeMirrorTokenTrackingController.Mode.None; 102 105 103 106 if (oldMode !== this._mode && this._tracking && this._hoveredTokenInfo) … … 140 143 { 141 144 return this._candidate; 145 }, 146 147 get hoveredMarker() 148 { 149 return this._hoveredMarker; 150 }, 151 152 set hoveredMarker(hoveredMarker) 153 { 154 this._hoveredMarker = hoveredMarker; 142 155 }, 143 156 … … 175 188 176 189 window.removeEventListener("mousemove", this, true); 177 },178 179 boundsForRange: function(range)180 {181 var firstCharCoords = this._codeMirror.cursorCoords(range.start);182 var lastCharCoords = this._codeMirror.cursorCoords(range.end);183 return new WebInspector.Rect(firstCharCoords.left, firstCharCoords.top, lastCharCoords.right - firstCharCoords.left, firstCharCoords.bottom - firstCharCoords.top);184 190 }, 185 191 … … 299 305 300 306 if (!token || !token.type || !token.string) { 307 if (this._hoveredMarker && this._delegate && typeof this._delegate.tokenTrackingControllerMouseOutOfHoveredMarker === "function") { 308 var markers = this._codeMirror.findMarksAt(position); 309 if (!markers.contains(this._hoveredMarker)) 310 this._delegate.tokenTrackingControllerMouseOutOfHoveredMarker(this, this._hoveredMarker); 311 } 312 301 313 this._resetTrackingStates(); 302 314 return; … … 380 392 case WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptExpression: 381 393 this._candidate = this._processJavaScriptExpression(); 394 break; 395 case WebInspector.CodeMirrorTokenTrackingController.Mode.MarkedTokens: 396 this._candidate = this._processMarkedToken(); 382 397 break; 383 398 } … … 479 494 }, 480 495 496 _processMarkedToken: function() 497 { 498 return this._processNonSymbolToken(); 499 }, 500 481 501 _resetTrackingStates: function() 482 502 { -
trunk/Source/WebInspectorUI/UserInterface/Color.js
r160132 r160483 35 35 else 36 36 this._rgba = components; 37 38 this.valid = !components.some(function(component) { 39 return isNaN(component); 40 }); 37 41 } 38 42 … … 210 214 this._hsla = this._rgbaToHSLA(this.rgba); 211 215 return this._hsla; 216 }, 217 218 copy: function() 219 { 220 switch (this.format) { 221 case WebInspector.Color.Format.RGB: 222 case WebInspector.Color.Format.HEX: 223 case WebInspector.Color.Format.ShortHEX: 224 case WebInspector.Color.Format.Nickname: 225 case WebInspector.Color.Format.RGBA: 226 return new WebInspector.Color(this.format, this.rgba); 227 case WebInspector.Color.Format.HSL: 228 case WebInspector.Color.Format.HSLA: 229 return new WebInspector.Color(this.format, this.hsla); 230 } 212 231 }, 213 232 -
trunk/Source/WebInspectorUI/UserInterface/HoverMenu.js
r160134 r160483 102 102 _handleClickEvent: function(event) 103 103 { 104 if (this.delegate && typeof this.delegate.hoverMenu WasActivated === "function")105 this.delegate.hoverMenu WasActivated(this);104 if (this.delegate && typeof this.delegate.hoverMenuButtonWasPressed === "function") 105 this.delegate.hoverMenuButtonWasPressed(this); 106 106 } 107 107 } -
trunk/Source/WebInspectorUI/UserInterface/Main.html
r160198 r160483 413 413 <script src="ContentFlowDOMTreeContentView.js"></script> 414 414 <script src="HoverMenu.js"></script> 415 <script src="CodeMirrorColorEditingController.js"></script> 415 416 <script src="Main.js"></script> 416 417 -
trunk/Source/WebInspectorUI/UserInterface/SourceCodeTextEditor.css
r151687 r160483 62 62 padding-right: 10px; 63 63 } 64 65 /* Custom styling for the hover menu attached to color tokens */ 66 67 .hover-menu.color { 68 padding-right: 15px; 69 } 70 71 .hover-menu.color > img { 72 width: 16px; 73 height: 16px; 74 -webkit-transform: translateX(14px); 75 content: -webkit-image-set(url(Images/ColorIcon.png) 1x, url(Images/ColorIcon@2x.png) 2x); 76 } -
trunk/Source/WebInspectorUI/UserInterface/SourceCodeTextEditor.js
r159946 r160483 33 33 this._contentPopulated = false; 34 34 this._invalidLineNumbers = {0: true}; 35 this._ignoreContentDidChange = 0; 35 36 36 37 WebInspector.TextEditor.call(this, null, null, this); 37 38 38 39 // FIXME: Currently this just jumps between resources and related source map resources. It doesn't "jump to symbol" yet. 39 this._jumpToSymbolTrackingModeEnabled = false; 40 this._disableJumpToSymbolTrackingModeSettings(); 40 this._updateTokenTrackingControllerState(); 41 41 42 42 this.element.classList.add(WebInspector.SourceCodeTextEditor.StyleClassName); … … 62 62 63 63 if (this._sourceCode instanceof WebInspector.SourceMapResource || this._sourceCode.sourceMaps.length > 0) 64 WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._update JumpToSymbolTrackingMode, this);64 WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateTokenTrackingControllerState, this); 65 65 else 66 66 this._sourceCode.addEventListener(WebInspector.SourceCode.Event.SourceMapAdded, this._sourceCodeSourceMapAdded, this); … … 128 128 WebInspector.issueManager.removeEventListener(WebInspector.IssueManager.Event.IssueWasAdded, this._issueWasAdded, this); 129 129 130 WebInspector.notifications.removeEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._update JumpToSymbolTrackingMode, this);130 WebInspector.notifications.removeEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateTokenTrackingControllerState, this); 131 131 this._sourceCode.removeEventListener(WebInspector.SourceCode.Event.SourceMapAdded, this._sourceCodeSourceMapAdded, this); 132 132 }, … … 216 216 { 217 217 this.focus(); 218 }, 219 220 contentDidChange: function(replacedRanges, newRanges) 221 { 222 WebInspector.TextEditor.prototype.contentDidChange.call(this, replacedRanges, newRanges); 223 224 if (this._ignoreContentDidChange > 0) 225 return; 226 227 // Gather all lines containing new text. 228 var lines = new Set; 229 for (var range of newRanges) { 230 // If the range is on a single line, only add the line if the range is not empty. 231 if (range.startLine === range.endLine) { 232 if (range.endColumn > range.startColumn) 233 lines.add(range.startLine); 234 } else { 235 // Only add the last line if the range has characters on this line. 236 for (var line = range.startLine; line < range.endLine || range.endColumn > 0; ++line) 237 lines.add(line); 238 } 239 } 240 241 // Consider all new lines for new color markers. 242 for (var line of lines) 243 this._updateColorMarkers(line); 218 244 }, 219 245 … … 333 359 } 334 360 335 this._updateJumpToSymbolTrackingMode(); 361 this._updateTokenTrackingControllerState(); 362 this._updateColorMarkers(); 336 363 }, 337 364 … … 932 959 }, 933 960 934 _updateTokenTrackingControllerEnabled: function()935 {936 this.tokenTrackingController.enabled = this._jumpToSymbolTrackingModeEnabled || WebInspector.debuggerManager.activeCallFrame;937 },938 939 961 _debuggerDidPause: function(event) 940 962 { 941 this._updateTokenTrackingController Enabled();963 this._updateTokenTrackingControllerState(); 942 964 }, 943 965 944 966 _debuggerDidResume: function(event) 945 967 { 946 this._updateTokenTrackingController Enabled();968 this._updateTokenTrackingControllerState(); 947 969 this._dismissPopover(); 948 970 }, … … 950 972 _sourceCodeSourceMapAdded: function(event) 951 973 { 952 WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._update JumpToSymbolTrackingMode, this);974 WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateTokenTrackingControllerState, this); 953 975 this._sourceCode.removeEventListener(WebInspector.SourceCode.Event.SourceMapAdded, this._sourceCodeSourceMapAdded, this); 954 976 955 this._updateJumpToSymbolTrackingMode(); 956 }, 957 958 _updateJumpToSymbolTrackingMode: function() 959 { 960 var oldJumpToSymbolTrackingModeEnabled = this._jumpToSymbolTrackingModeEnabled; 961 962 if (!(this._sourceCode instanceof WebInspector.SourceMapResource) && this._sourceCode.sourceMaps.length === 0) 963 this._jumpToSymbolTrackingModeEnabled = false; 964 else 965 this._jumpToSymbolTrackingModeEnabled = WebInspector.modifierKeys.metaKey && !WebInspector.modifierKeys.altKey && !WebInspector.modifierKeys.shiftKey; 966 967 if (oldJumpToSymbolTrackingModeEnabled !== this._jumpToSymbolTrackingModeEnabled) { 968 if (this._jumpToSymbolTrackingModeEnabled) { 969 this._enableJumpToSymbolTrackingModeSettings(); 970 this.tokenTrackingController.highlightLastHoveredRange(); 971 } else { 972 this._disableJumpToSymbolTrackingModeSettings(); 973 this.tokenTrackingController.removeHighlightedRange(); 974 } 975 } 976 }, 977 978 _enableJumpToSymbolTrackingModeSettings: function() 979 { 980 this.tokenTrackingController.classNameForHighlightedRange = WebInspector.CodeMirrorTokenTrackingController.JumpToSymbolHighlightStyleClassName; 981 this.tokenTrackingController.mouseOverDelayDuration = 0; 982 this.tokenTrackingController.mouseOutReleaseDelayDuration = 0; 983 984 this.tokenTrackingController.mode = WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens; 985 this._updateTokenTrackingControllerEnabled(); 986 987 this._dismissPopover(); 988 }, 989 990 _disableJumpToSymbolTrackingModeSettings: function() 991 { 992 this.tokenTrackingController.classNameForHighlightedRange = WebInspector.SourceCodeTextEditor.HoveredExpressionHighlightStyleClassName; 993 this.tokenTrackingController.mouseOverDelayDuration = WebInspector.SourceCodeTextEditor.DurationToMouseOverTokenToMakeHoveredToken; 994 this.tokenTrackingController.mouseOutReleaseDelayDuration = WebInspector.SourceCodeTextEditor.DurationToMouseOutOfHoveredTokenToRelease; 995 996 this.tokenTrackingController.mode = WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptExpression; 997 this._updateTokenTrackingControllerEnabled(); 977 this._updateTokenTrackingControllerState(); 978 }, 979 980 _updateTokenTrackingControllerState: function() 981 { 982 var mode = WebInspector.CodeMirrorTokenTrackingController.Mode.None; 983 if (WebInspector.debuggerManager.paused) 984 mode = WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptExpression; 985 else if (this._hasColorMarkers()) 986 mode = WebInspector.CodeMirrorTokenTrackingController.Mode.MarkedTokens; 987 else if ((this._sourceCode instanceof WebInspector.SourceMapResource || this._sourceCode.sourceMaps.length !== 0) && WebInspector.modifierKeys.metaKey && !WebInspector.modifierKeys.altKey && !WebInspector.modifierKeys.shiftKey) 988 mode = WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens; 989 990 this.tokenTrackingController.enabled = mode !== WebInspector.CodeMirrorTokenTrackingController.Mode.None; 991 992 if (mode === this.tokenTrackingController.mode) 993 return; 994 995 switch (mode) { 996 case WebInspector.CodeMirrorTokenTrackingController.Mode.MarkedTokens: 997 this.tokenTrackingController.mouseOverDelayDuration = 0; 998 this.tokenTrackingController.mouseOutReleaseDelayDuration = 0; 999 break; 1000 case WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens: 1001 this.tokenTrackingController.mouseOverDelayDuration = 0; 1002 this.tokenTrackingController.mouseOutReleaseDelayDuration = 0; 1003 this.tokenTrackingController.classNameForHighlightedRange = WebInspector.CodeMirrorTokenTrackingController.JumpToSymbolHighlightStyleClassName; 1004 this._dismissPopover(); 1005 break; 1006 case WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptExpression: 1007 this.tokenTrackingController.mouseOverDelayDuration = WebInspector.SourceCodeTextEditor.DurationToMouseOverTokenToMakeHoveredToken; 1008 this.tokenTrackingController.mouseOutReleaseDelayDuration = WebInspector.SourceCodeTextEditor.DurationToMouseOutOfHoveredTokenToRelease; 1009 this.tokenTrackingController.classNameForHighlightedRange = WebInspector.SourceCodeTextEditor.HoveredExpressionHighlightStyleClassName; 1010 break; 1011 } 1012 1013 this.tokenTrackingController.mode = mode; 1014 }, 1015 1016 _hasColorMarkers: function() 1017 { 1018 for (var marker of this.markers) { 1019 if (marker.__markedColor) 1020 return true; 1021 } 1022 return false; 998 1023 }, 999 1024 … … 1019 1044 tokenTrackingControllerHighlightedRangeWasClicked: function(tokenTrackingController) 1020 1045 { 1021 if (this._jumpToSymbolTrackingModeEnabled) { 1022 // Links are handled by TextEditor. 1023 if (/\blink\b/.test(this.tokenTrackingController.candidate.hoveredToken.type)) 1024 return; 1025 1026 var sourceCodeLocation = this._sourceCodeLocationForEditorPosition(this.tokenTrackingController.candidate.hoveredTokenRange.start); 1027 if (this.sourceCode instanceof WebInspector.SourceMapResource) 1028 WebInspector.resourceSidebarPanel.showOriginalOrFormattedSourceCodeLocation(sourceCodeLocation); 1046 if (this.tokenTrackingController.mode !== WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens) 1047 return; 1048 1049 // Links are handled by TextEditor. 1050 if (/\blink\b/.test(this.tokenTrackingController.candidate.hoveredToken.type)) 1051 return; 1052 1053 var sourceCodeLocation = this._sourceCodeLocationForEditorPosition(this.tokenTrackingController.candidate.hoveredTokenRange.start); 1054 if (this.sourceCode instanceof WebInspector.SourceMapResource) 1055 WebInspector.resourceSidebarPanel.showOriginalOrFormattedSourceCodeLocation(sourceCodeLocation); 1056 else 1057 WebInspector.resourceSidebarPanel.showSourceCodeLocation(sourceCodeLocation); 1058 }, 1059 1060 tokenTrackingControllerNewHighlightCandidate: function(tokenTrackingController, candidate) 1061 { 1062 if (this.tokenTrackingController.mode === WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens) { 1063 this.tokenTrackingController.highlightRange(candidate.hoveredTokenRange); 1064 return; 1065 } 1066 1067 if (this.tokenTrackingController.mode === WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptExpression) { 1068 this._tokenTrackingControllerHighlightedJavaScriptExpression(candidate); 1069 return; 1070 } 1071 1072 if (this.tokenTrackingController.mode === WebInspector.CodeMirrorTokenTrackingController.Mode.MarkedTokens) { 1073 var markers = this.findMarkersAtPosition(candidate.hoveredTokenRange.start); 1074 if (markers.length > 0) 1075 this._tokenTrackingControllerHighlightedMarkedExpression(candidate, markers); 1029 1076 else 1030 WebInspector.resourceSidebarPanel.showSourceCodeLocation(sourceCodeLocation); 1031 } 1032 }, 1033 1034 tokenTrackingControllerNewHighlightCandidate: function(tokenTrackingController, candidate) 1035 { 1036 if (this._jumpToSymbolTrackingModeEnabled) { 1037 this.tokenTrackingController.highlightRange(candidate.hoveredTokenRange); 1038 return; 1039 } 1040 1041 if (!WebInspector.debuggerManager.activeCallFrame) 1042 return; 1043 1077 this._dismissCodeMirrorColorEditingController(); 1078 } 1079 }, 1080 1081 tokenTrackingControllerMouseOutOfHoveredMarker: function(tokenTrackingController, hoveredMarker) 1082 { 1083 this._dismissCodeMirrorColorEditingController(); 1084 }, 1085 1086 _tokenTrackingControllerHighlightedJavaScriptExpression: function(candidate) 1087 { 1044 1088 console.assert(candidate.expression); 1045 1089 … … 1086 1130 return; 1087 1131 1088 var bounds = this. tokenTrackingController.boundsForRange(candidate.hoveredTokenRange);1132 var bounds = this.boundsForRange(candidate.hoveredTokenRange); 1089 1133 if (!bounds) 1090 1134 return; … … 1242 1286 { 1243 1287 this._mouseIsOverPopover = this._popover.element.contains(event.relatedTarget); 1288 }, 1289 1290 _updateColorMarkers: function(lineNumber) 1291 { 1292 this.createColorMarkers(lineNumber); 1293 1294 this._updateTokenTrackingControllerState(); 1295 }, 1296 1297 _tokenTrackingControllerHighlightedMarkedExpression: function(candidate, markers) 1298 { 1299 var colorMarker; 1300 for (var marker of markers) { 1301 if (marker.__markedColor) { 1302 colorMarker = marker; 1303 break; 1304 } 1305 } 1306 1307 if (!colorMarker) { 1308 this.tokenTrackingController.hoveredMarker = null; 1309 return; 1310 } 1311 1312 if (this.tokenTrackingController.hoveredMarker === colorMarker) 1313 return; 1314 1315 this._dismissCodeMirrorColorEditingController(); 1316 1317 this.tokenTrackingController.hoveredMarker = colorMarker; 1318 1319 this._colorEditingController = this.colorEditingControllerForMarker(colorMarker); 1320 1321 var color = this._colorEditingController.color; 1322 if (!color || !color.valid) { 1323 colorMarker.clear(); 1324 delete this._colorEditingController; 1325 return; 1326 } 1327 1328 this._colorEditingController.delegate = this; 1329 this._colorEditingController.presentHoverMenu(); 1330 }, 1331 1332 _dismissCodeMirrorColorEditingController: function() 1333 { 1334 if (this._colorEditingController) 1335 this._colorEditingController.dismissHoverMenu(); 1336 1337 this.tokenTrackingController.hoveredMarker = null; 1338 delete this._colorEditingController; 1339 }, 1340 1341 // CodeMirrorColorEditingController Delegate 1342 1343 colorEditingControllerDidStartEditing: function(colorEditingController) 1344 { 1345 // We can pause the token tracking controller during editing, it will be reset 1346 // to the expected state by calling _updateColorMarkers() in the 1347 // colorEditingControllerDidFinishEditing delegate. 1348 this.tokenTrackingController.enabled = false; 1349 1350 // We clear the marker since we'll reset it after editing. 1351 colorEditingController.marker.clear(); 1352 1353 // We ignore content changes made as a result of color editing. 1354 this._ignoreContentDidChange++; 1355 }, 1356 1357 colorEditingControllerDidFinishEditing: function(colorEditingController) 1358 { 1359 this._updateColorMarkers(colorEditingController.range.from.line); 1360 1361 this._ignoreContentDidChange--; 1362 1363 delete this._colorEditingController; 1244 1364 } 1245 1365 }; -
trunk/Source/WebInspectorUI/UserInterface/TextEditor.js
r158404 r160483 592 592 }, 593 593 594 contentDidChange: function(replacedRanges, newRanges) 595 { 596 // Implemented by subclasses. 597 }, 598 599 boundsForRange: function(range) 600 { 601 return this._codeMirror.boundsForRange(range); 602 }, 603 604 get markers() 605 { 606 // FIXME: we should not return CodeMirror TextMarker objects but rather wrappers. 607 return this._codeMirror.getAllMarks(); 608 }, 609 610 findMarkersAtPosition: function(position) 611 { 612 return this._codeMirror.findMarksAt(position); 613 }, 614 615 createColorMarkers: function(lineNumber) 616 { 617 return this._codeMirror.createColorMarkers(lineNumber); 618 }, 619 620 colorEditingControllerForMarker: function(colorMarker) 621 { 622 return new WebInspector.CodeMirrorColorEditingController(this._codeMirror, colorMarker); 623 }, 624 594 625 // Private 595 626 … … 598 629 if (this._ignoreCodeMirrorContentDidChangeEvent > 0) 599 630 return; 631 632 var replacedRanges = []; 633 var newRanges = []; 634 while (change) { 635 replacedRanges.push(new WebInspector.TextRange( 636 change.from.line, 637 change.from.ch, 638 change.to.line, 639 change.to.ch 640 )); 641 newRanges.push(new WebInspector.TextRange( 642 change.from.line, 643 change.from.ch, 644 change.from.line + change.text.length - 1, 645 change.text.length === 1 ? change.from.ch + change.text[0].length : change.text.lastValue.length 646 )); 647 change = change.next; 648 } 649 this.contentDidChange(replacedRanges, newRanges); 600 650 601 651 if (this._formatted) {
Note: See TracChangeset
for help on using the changeset viewer.