Changeset 160483 in webkit


Ignore:
Timestamp:
Dec 12, 2013 2:17:20 AM (10 years ago)
Author:
Antoine Quint
Message:

Web Inspector: allow editing of colors in CSS resources
https://bugs.webkit.org/show_bug.cgi?id=124364

Reviewed by Timothy Hatcher.

Identify colors in CSS and HTML resources so that hovering these colors shows a HoverMenu
allowing a ColorPicker hosted in a Popover to be shown to edit the hovered color.

  • UserInterface/CSSStyleDeclarationTextEditor.js:

(WebInspector.CSSStyleDeclarationTextEditor.prototype._createColorSwatches):
Remove the code that goes through the lines of the CodeMirror editor to look for
color strings and replace it with a call to the .createColorMarkers() CodeMirror
extension in which the code was refactored. The callback passed to
.createColorMarkers() handles the CSSStyleDeclarationTextEditor-specific creation
of color swatches to show the popover, keeping the existing behavior of the Styles
sidebar panel.

  • UserInterface/CodeMirrorAdditions.js:

Refactor existing code into two new CodeMirror extensions: .boundsForRange(), which
was previously defined on the CodeMirrorTokenTrackingController but was also needed
in the new CodeMirrorColorEditingController, and .createColorMarkers(), discussed above.

  • UserInterface/CodeMirrorColorEditingController.js: Added.

(WebInspector.CodeMirrorColorEditingController):
New class used by SourceCodeTextEditor to coordinate the editing of a color in a CodeMirror
TextMarker by a ColorPicker hosted in a Popover shown by the activation of a HoverMenu. This
controller automatically gets the color set by the user using the ColorPicker and updates
the CodeMirror text editor with the new value. When the user presses the Esc. key while the
popover is shown, it's automatically dismissed and the original color is reset in the editor.

(WebInspector.CodeMirrorColorEditingController.prototype.get marker):
(WebInspector.CodeMirrorColorEditingController.prototype.get range):
(WebInspector.CodeMirrorColorEditingController.prototype.get delegate):
(WebInspector.CodeMirrorColorEditingController.prototype.set delegate):
Getters and setters for public properties.

(WebInspector.CodeMirrorColorEditingController.prototype.get color):
(WebInspector.CodeMirrorColorEditingController.prototype.set color):
Get and set the color for the edited color marker, replacing the text in the marker's range
upon setting.

(WebInspector.CodeMirrorColorEditingController.prototype.presentHoverMenu):
Public API allowing for a HoverMenu to be shown around the bounds of the TextMarker passed
in the constructor. This method is called from SourceCodeTextEditor when the
CodeMirrorTokenTrackingController identifies that a token that is part of a TextMarker is
hovered and that token is a color.

(WebInspector.CodeMirrorColorEditingController.prototype.dismissHoverMenu):
Public API allowing for the HoverMenu to be dismissed. This method is called when the
CodeMirrorTokenTrackingController identifies that its "hoveredMarker" is no longer being
hovered as well as when we identify that editing of the color has completed.

(WebInspector.CodeMirrorColorEditingController.prototype.handleEvent):
Event handler for the "keydown" event that are being listened to when the HoverMenu
is activated such that the Esc. key can be used to dimiss the popover and reset the
original color before any edits.

(WebInspector.CodeMirrorColorEditingController.prototype.hoverMenuButtonWasPressed):
Implementation of the HoverMenu delegation method used to show a Popover containing a
ColorPicker upon clicking on the color wheel attached to the HoverMenu. We also remember
the color set on the marker so that it may be restored when Esc. is pressed and used to
set the original state of the ColorPicker. The delegation method
colorEditingControllerDidStartEditing() is also called at this point, which the
SourceCodeTextEditor implements.

(WebInspector.CodeMirrorColorEditingController.prototype.didDismissPopover):
Implementation of the Popover delegation method used to identify that color editing has
completed. The delegation method colorEditingControllerDidFinishEditing() is called
at this point, which the SourceCodeTextEditor implements.

(WebInspector.CodeMirrorColorEditingController.prototype._colorPickerColorChanged):
Apply the color set in the color picker to the CodeMirror text editor.

  • UserInterface/CodeMirrorTokenTrackingController.js:

Add two new modes to CodeMirrorTokenTrackingController. The first mode is "None" and is
the default, incurring no specific token handling behavior. The second mode is "MarkedTokens"
which identifies hover of a token contained in a CodeMirror TextMarker range. The new
"MarkedTokens" mode is used by SourceCodeTextEditor to identify when a marked color is being
hovered to display a HoverMenu.

(WebInspector.CodeMirrorTokenTrackingController):
(WebInspector.CodeMirrorTokenTrackingController.prototype.set mode):
Make "None" the new default mode for CodeMirrorTokenTrackingController.

(WebInspector.CodeMirrorTokenTrackingController.prototype.get hoveredMarker):
(WebInspector.CodeMirrorTokenTrackingController.prototype.set hoveredMarker):
(WebInspector.CodeMirrorTokenTrackingController.prototype._updateHoveredTokenInfo):
Check, when we have a "hoveredMarker" set on the CodeMirrorTokenTrackingController,
whether the "hoveredMarker" is still being hovered when there is no token at the current
mouse position. We can then determine when we're mousing out of the "hoveredMarker" and
notify the delegate via the new tokenTrackingControllerMouseOutOfHoveredMarker delegate
method. The SourceCodeTextEditor uses this method to dismiss its CodeMirrorColorEditingController.

(WebInspector.CodeMirrorTokenTrackingController.prototype._processNewHoveredToken):
Add support for the new "MarkedTokens" mode.

(WebInspector.CodeMirrorTokenTrackingController.prototype._processMarkedToken):
For the moment, use the same behavior as the existing "MarkedTokens" mode.

  • UserInterface/Color.js:

(WebInspector.Color):
Add a new "valid" property to identify whether a color has any invalid (NaN) component. This property
is used by SourceCodeTextEditor to establish whether a hovered color marker is indeed set to a
valid color still.

(WebInspector.Color.prototype.copy):
New method to create an exact copy of a Color instance, used by CodeMirrorColorEditingController
to duplicate the edited color in case we need to revert it.

  • UserInterface/HoverMenu.js:

(WebInspector.HoverMenu.prototype._handleClickEvent):
Rename hoverMenuWasActivated to hoverMenuButtonWasPressed per review feedback.

  • UserInterface/Images/ColorIcon.png: Added.
  • UserInterface/Images/ColorIcon@2x.png: Added.

New color wheel icon used to customize the HoverMenu shown by a CodeMirrorColorEditingController.

  • UserInterface/Main.html:

Link to the new CodeMirrorColorEditingController.js file.

  • UserInterface/SourceCodeTextEditor.css:

(.hover-menu.color):
(.hover-menu.color > img):
Customize the HoverMenu shown by a CodeMirrorColorEditingController to use the new ColorIcon asset.

  • UserInterface/SourceCodeTextEditor.js:

(WebInspector.SourceCodeTextEditor):
Add a new "_ignoreContentDidChange" ivar that increments and decrements to track when handling
of CodeMirror content changes should be disabled.

(WebInspector.SourceCodeTextEditor.prototype.close):
Adopt the new ._updateTokenTrackingControllerState() method to update the state of the
CodeMirrorTokenTrackingController.

(WebInspector.SourceCodeTextEditor.prototype.contentDidChange):
Override the new TextEditor public API called when content in the CodeMirror text editor is changed.
We use this method to process any newly added line to create any newly added color marker.

(WebInspector.SourceCodeTextEditor.prototype._contentDidPopulate):
(WebInspector.SourceCodeTextEditor.prototype._debuggerDidPause):
(WebInspector.SourceCodeTextEditor.prototype._debuggerDidResume):
(WebInspector.SourceCodeTextEditor.prototype._sourceCodeSourceMapAdded):
Adopt the new ._updateTokenTrackingControllerState() method to update the state of the
CodeMirrorTokenTrackingController.

(WebInspector.SourceCodeTextEditor.prototype._updateTokenTrackingControllerState):
New method acting as the only point where we check the state of the text editor and set the right
mode and settings on the CodeMirrorTokenTrackingController, including setting the new "MarkedTokens"
mode when we have color markers, as determined by ._hasColorMarkers().

(WebInspector.SourceCodeTextEditor.prototype._hasColorMarkers):
Check whether any of the TextMarkers set on the CodeMirror text editor were created for a color.

(WebInspector.SourceCodeTextEditor.prototype.tokenTrackingControllerHighlightedRangeWasClicked):
Check the CodeMirrorTokenTrackingController mode rather than the removed "_jumpToSymbolTrackingModeEnabled"
ivar to identify we're in the "NonSymbolTokens" mode.

(WebInspector.SourceCodeTextEditor.prototype.tokenTrackingControllerNewHighlightCandidate):
Refactor method to use the CodeMirrorTokenTrackingController mode to branch into mode-specific code
and add a new branch for the new "MarkedTokens" mode where we check if the newly hovered token
is part of a color TextMarker range.

(WebInspector.SourceCodeTextEditor.prototype.tokenTrackingControllerMouseOutOfHoveredMarker):
Implement this new CodeMirrorTokenTrackingController delegation method to dismiss the
CodeMirrorColorEditingController as we identify we're no longer hovering over the TextMarker
for which the CodeMirrorColorEditingController was created.

(WebInspector.SourceCodeTextEditor.prototype._showPopover):
Adopt the new TextEditor boundsForRange() method.

(WebInspector.SourceCodeTextEditor.prototype._updateColorMarkers):
Harness the new TextEditor createColorMarkers() method to create new TextMarkers for the provided
line, or the entire text editor content if none provided. We then immediately call _updateTokenTrackingControllerState()
so that the new "MarkedTokens" mode is entered in case color TextMarkers were created for the first
time for this text editor.

(WebInspector.SourceCodeTextEditor.prototype._tokenTrackingControllerHighlightedMarkedExpression):
Called when we've identified the CodeMirrorTokenTrackingController highlighted a TextMarker. We check
if any of the hovered TextMarkers are for a color, and in this case create a CodeMirrorColorEditingController
to coordinate the display of a ColorPicker in a Popover to edit the hovered color token. We also check
whether the hovered marker still contains a valid color, clearing the marker in case it was edited to
no longer contain a color.

(WebInspector.SourceCodeTextEditor.prototype._dismissCodeMirrorColorEditingController):
Used to dismiss the CodeMirrorColorEditingController, if previously presented, and reset some internal state.

(WebInspector.SourceCodeTextEditor.prototype.colorEditingControllerDidStartEditing):
Implement this CodeMirrorColorEditingController delegation method to temporarily disable the
CodeMirrorTokenTrackingController while we edit the color with the ColorPicker, remove
the TextMarker for the edited color and instruct that content changes should be ignored
such that we act on the complete set of color edits upon completion.

(WebInspector.SourceCodeTextEditor.prototype.colorEditingControllerDidFinishEditing):
Update color markers for the edited line such that any color edits are correctly updated for
the future and so that, as a side-effect, the CodeMirrorColorEditingController is reset to the
appropriate mode depending on whether color TextMarkers are indeed available, resetting states
that may have been altered by colorEditingControllerDidStartEditing().

  • UserInterface/TextEditor.js:

(WebInspector.TextEditor.prototype.contentDidChange):
New public method meant to be overriden by subclasses, added for the use of SourceCodeTextEditor, exposing
the list of TextRanges affected by the content change, both in the context of the old content and new content.

(WebInspector.TextEditor.prototype.boundsForRange):
(WebInspector.TextEditor.prototype.get markers):
(WebInspector.TextEditor.prototype.findMarkersAtPosition):
(WebInspector.TextEditor.prototype.createColorMarkers):
(WebInspector.TextEditor.prototype.colorEditingControllerForMarker):
New public methods calling into the CodeMirror private ivar for the benefit of SourceCodeTextEditor.

(WebInspector.TextEditor.prototype._contentChanged):
Call the new contentDidChange() method.

Location:
trunk/Source/WebInspectorUI
Files:
3 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r160203 r160483  
     12013-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
    12162013-12-05  Seokju Kwon  <seokju@webkit.org>
    2217
  • trunk/Source/WebInspectorUI/UserInterface/CSSStyleDeclarationTextEditor.js

    r160132 r160483  
    391391        function update()
    392392        {
    393             // Matches rgba(0, 0, 0, 0.5), rgb(0, 0, 0), hsl(), hsla(), #fff, #ffffff, white
    394             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 
    399393            // 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));
    456409        }
    457410
  • trunk/Source/WebInspectorUI/UserInterface/CodeMirrorAdditions.js

    r158061 r160483  
    419419    }
    420420
     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
    421486    function ignoreKey(codeMirror)
    422487    {
  • trunk/Source/WebInspectorUI/UserInterface/CodeMirrorTokenTrackingController.js

    r156923 r160483  
    3232    this._codeMirror = codeMirror;
    3333    this._delegate = delegate || null;
    34     this._mode = WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens;
     34    this._mode = WebInspector.CodeMirrorTokenTrackingController.Mode.None;
    3535
    3636    this._mouseOverDelayDuration = 0;
     
    4141    this._tracking = false;
    4242    this._hoveredTokenInfo = null;
     43    this._hoveredMarker = null;
    4344};
    4445
     
    4647
    4748WebInspector.CodeMirrorTokenTrackingController.Mode = {
     49    None: "none",
    4850    NonSymbolTokens: "non-symbol-tokens",
    4951    JavaScriptExpression: "javascript-expression",
     52    MarkedTokens: "marked-tokens"
    5053}
    5154
     
    9598    },
    9699
    97     set mode(x)
     100    set mode(mode)
    98101    {
    99102        var oldMode = this._mode;
    100103
    101         this._mode = x || WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens;
     104        this._mode = mode || WebInspector.CodeMirrorTokenTrackingController.Mode.None;
    102105
    103106        if (oldMode !== this._mode && this._tracking && this._hoveredTokenInfo)
     
    140143    {
    141144        return this._candidate;
     145    },
     146
     147    get hoveredMarker()
     148    {
     149        return this._hoveredMarker;
     150    },
     151   
     152    set hoveredMarker(hoveredMarker)
     153    {
     154        this._hoveredMarker = hoveredMarker;
    142155    },
    143156
     
    175188
    176189        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);
    184190    },
    185191
     
    299305
    300306        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
    301313            this._resetTrackingStates();
    302314            return;
     
    380392        case WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptExpression:
    381393            this._candidate = this._processJavaScriptExpression();
     394            break;
     395        case WebInspector.CodeMirrorTokenTrackingController.Mode.MarkedTokens:
     396            this._candidate = this._processMarkedToken();
    382397            break;
    383398        }
     
    479494    },
    480495
     496    _processMarkedToken: function()
     497    {
     498        return this._processNonSymbolToken();
     499    },
     500
    481501    _resetTrackingStates: function()
    482502    {
  • trunk/Source/WebInspectorUI/UserInterface/Color.js

    r160132 r160483  
    3535    else
    3636        this._rgba = components;
     37
     38    this.valid = !components.some(function(component) {
     39        return isNaN(component);
     40    });
    3741}
    3842
     
    210214            this._hsla = this._rgbaToHSLA(this.rgba);
    211215        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        }
    212231    },
    213232
  • trunk/Source/WebInspectorUI/UserInterface/HoverMenu.js

    r160134 r160483  
    102102    _handleClickEvent: function(event)
    103103    {
    104         if (this.delegate && typeof this.delegate.hoverMenuWasActivated === "function")
    105             this.delegate.hoverMenuWasActivated(this);
     104        if (this.delegate && typeof this.delegate.hoverMenuButtonWasPressed === "function")
     105            this.delegate.hoverMenuButtonWasPressed(this);
    106106    }
    107107}
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r160198 r160483  
    413413    <script src="ContentFlowDOMTreeContentView.js"></script>
    414414    <script src="HoverMenu.js"></script>
     415    <script src="CodeMirrorColorEditingController.js"></script>
    415416    <script src="Main.js"></script>
    416417
  • trunk/Source/WebInspectorUI/UserInterface/SourceCodeTextEditor.css

    r151687 r160483  
    6262    padding-right: 10px;
    6363}
     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  
    3333    this._contentPopulated = false;
    3434    this._invalidLineNumbers = {0: true};
     35    this._ignoreContentDidChange = 0;
    3536
    3637    WebInspector.TextEditor.call(this, null, null, this);
    3738
    3839    // 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();
    4141
    4242    this.element.classList.add(WebInspector.SourceCodeTextEditor.StyleClassName);
     
    6262
    6363    if (this._sourceCode instanceof WebInspector.SourceMapResource || this._sourceCode.sourceMaps.length > 0)
    64         WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateJumpToSymbolTrackingMode, this);
     64        WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateTokenTrackingControllerState, this);
    6565    else
    6666        this._sourceCode.addEventListener(WebInspector.SourceCode.Event.SourceMapAdded, this._sourceCodeSourceMapAdded, this);
     
    128128        WebInspector.issueManager.removeEventListener(WebInspector.IssueManager.Event.IssueWasAdded, this._issueWasAdded, this);
    129129
    130         WebInspector.notifications.removeEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateJumpToSymbolTrackingMode, this);
     130        WebInspector.notifications.removeEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateTokenTrackingControllerState, this);
    131131        this._sourceCode.removeEventListener(WebInspector.SourceCode.Event.SourceMapAdded, this._sourceCodeSourceMapAdded, this);
    132132    },
     
    216216    {
    217217        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);
    218244    },
    219245
     
    333359        }
    334360
    335         this._updateJumpToSymbolTrackingMode();
     361        this._updateTokenTrackingControllerState();
     362        this._updateColorMarkers();
    336363    },
    337364
     
    932959    },
    933960
    934     _updateTokenTrackingControllerEnabled: function()
    935     {
    936         this.tokenTrackingController.enabled = this._jumpToSymbolTrackingModeEnabled || WebInspector.debuggerManager.activeCallFrame;
    937     },
    938 
    939961    _debuggerDidPause: function(event)
    940962    {
    941         this._updateTokenTrackingControllerEnabled();
     963        this._updateTokenTrackingControllerState();
    942964    },
    943965
    944966    _debuggerDidResume: function(event)
    945967    {
    946         this._updateTokenTrackingControllerEnabled();
     968        this._updateTokenTrackingControllerState();
    947969        this._dismissPopover();
    948970    },
     
    950972    _sourceCodeSourceMapAdded: function(event)
    951973    {
    952         WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateJumpToSymbolTrackingMode, this);
     974        WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateTokenTrackingControllerState, this);
    953975        this._sourceCode.removeEventListener(WebInspector.SourceCode.Event.SourceMapAdded, this._sourceCodeSourceMapAdded, this);
    954976
    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;
    9981023    },
    9991024
     
    10191044    tokenTrackingControllerHighlightedRangeWasClicked: function(tokenTrackingController)
    10201045    {
    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);
    10291076            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    {
    10441088        console.assert(candidate.expression);
    10451089
     
    10861130            return;
    10871131
    1088         var bounds = this.tokenTrackingController.boundsForRange(candidate.hoveredTokenRange);
     1132        var bounds = this.boundsForRange(candidate.hoveredTokenRange);
    10891133        if (!bounds)
    10901134            return;
     
    12421286    {
    12431287        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;
    12441364    }
    12451365};
  • trunk/Source/WebInspectorUI/UserInterface/TextEditor.js

    r158404 r160483  
    592592    },
    593593
     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
    594625    // Private
    595626
     
    598629        if (this._ignoreCodeMirrorContentDidChangeEvent > 0)
    599630            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);
    600650
    601651        if (this._formatted) {
Note: See TracChangeset for help on using the changeset viewer.