Web Inspector: move indentation logic into TextEditorModel
authorpfeldman@chromium.org <pfeldman@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2012 08:48:42 +0000 (08:48 +0000)
committerpfeldman@chromium.org <pfeldman@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2012 08:48:42 +0000 (08:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=101842

Reviewed by Vsevolod Vlasov.

Source/WebCore:

I'd like to move as much headless logic into the TextEditorModel as possible.
Drive by: removed some dead code, converted getter into function and moved undo
mark state into the model as well.

* inspector/front-end/DefaultTextEditor.js:
(WebInspector.DefaultTextEditor.prototype.editRange):
(WebInspector.DefaultTextEditor.prototype._syncDecorationsForLine):
(WebInspector.TextEditorChunkedPanel.prototype._splitChunkOnALine):
(WebInspector.TextEditorMainPanel.prototype.handleEnterKey.get var):
(WebInspector.TextEditorMainPanel.prototype.handleEnterKey):
(WebInspector.TextEditorMainPanel.prototype._applyDomUpdates):
(WebInspector.TextEditorMainPanel.prototype._updateChunksForRanges):
(WebInspector.TextEditorMainChunk):
(WebInspector.TextEditorMainChunk.prototype.isDecorated):
(WebInspector.TextEditorMainChunk.prototype.set expanded):
* inspector/front-end/TextEditorModel.js:
(WebInspector.TextEditorModel.endsWithBracketRegex.):

LayoutTests:

* inspector/editor/indentation.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@134382 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/inspector/editor/indentation.html
Source/WebCore/ChangeLog
Source/WebCore/inspector/front-end/DefaultTextEditor.js
Source/WebCore/inspector/front-end/TextEditorModel.js

index 686d16a..c4fe268 100644 (file)
@@ -1,3 +1,12 @@
+2012-11-13  Pavel Feldman  <pfeldman@chromium.org>
+
+        Web Inspector: move indentation logic into TextEditorModel
+        https://bugs.webkit.org/show_bug.cgi?id=101842
+
+        Reviewed by Vsevolod Vlasov.
+
+        * inspector/editor/indentation.html:
+
 2012-11-13  Takashi Sakamoto  <tasak@google.com>
 
         Crash when replacing parts of text inputs with content: url(...)
index e51a0d5..58b17c9 100644 (file)
@@ -11,8 +11,6 @@ function test()
 
     var model = new WebInspector.TextEditorModel();
     model.setText(src);
-    function noop() {}
-    var textEditorMainPanel = new WebInspector.TextEditorMainPanel(null, model, '', noop, noop, noop, noop);
 
     var selection;
     function dumpTextModel(msg)
@@ -22,19 +20,19 @@ function test()
         InspectorTest.addResult('Selection ' + selection.startLine + ',' + selection.startColumn  + ' ' + selection.endLine + ',' + selection.endColumn + '\n');
     }
 
-    selection = textEditorMainPanel._indentLines(new WebInspector.TextRange(0, 0, 1, 0));
+    selection = model.indentLines(new WebInspector.TextRange(0, 0, 1, 0));
     dumpTextModel("After indenting first fully selected line");
 
-    selection = textEditorMainPanel._indentLines(new WebInspector.TextRange(0, 5, 1, 0));
+    selection = model.indentLines(new WebInspector.TextRange(0, 5, 1, 0));
     dumpTextModel("After indenting first partially selected line");
 
-    selection = textEditorMainPanel._unindentLines(new WebInspector.TextRange(0, 0, 2, 0));
+    selection = model.unindentLines(new WebInspector.TextRange(0, 0, 2, 0));
     dumpTextModel("After unindenting two fully selected lines");
 
-    selection = textEditorMainPanel._unindentLines(new WebInspector.TextRange(0, 5, 1, 6));
+    selection = model.unindentLines(new WebInspector.TextRange(0, 5, 1, 6));
     dumpTextModel("After unindenting two partially selected lines (bug 97462)");
 
-    selection = textEditorMainPanel._unindentLines(new WebInspector.TextRange(0, 0, 2, 3));
+    selection = model.unindentLines(new WebInspector.TextRange(0, 0, 2, 3));
     dumpTextModel("After unindenting three partially selected lines");
 
     InspectorTest.completeTest();
index 4712374..5ffeaef 100644 (file)
@@ -1,3 +1,28 @@
+2012-11-13  Pavel Feldman  <pfeldman@chromium.org>
+
+        Web Inspector: move indentation logic into TextEditorModel
+        https://bugs.webkit.org/show_bug.cgi?id=101842
+
+        Reviewed by Vsevolod Vlasov.
+
+        I'd like to move as much headless logic into the TextEditorModel as possible.
+        Drive by: removed some dead code, converted getter into function and moved undo
+        mark state into the model as well.
+
+        * inspector/front-end/DefaultTextEditor.js:
+        (WebInspector.DefaultTextEditor.prototype.editRange):
+        (WebInspector.DefaultTextEditor.prototype._syncDecorationsForLine):
+        (WebInspector.TextEditorChunkedPanel.prototype._splitChunkOnALine):
+        (WebInspector.TextEditorMainPanel.prototype.handleEnterKey.get var):
+        (WebInspector.TextEditorMainPanel.prototype.handleEnterKey):
+        (WebInspector.TextEditorMainPanel.prototype._applyDomUpdates):
+        (WebInspector.TextEditorMainPanel.prototype._updateChunksForRanges):
+        (WebInspector.TextEditorMainChunk):
+        (WebInspector.TextEditorMainChunk.prototype.isDecorated):
+        (WebInspector.TextEditorMainChunk.prototype.set expanded):
+        * inspector/front-end/TextEditorModel.js:
+        (WebInspector.TextEditorModel.endsWithBracketRegex.):
+
 2012-11-13  Hayato Ito  <hayato@chromium.org>
 
         Unreviewed attempt to fix the chromium mac-build after r134348.
index cc67546..294592a 100644 (file)
@@ -321,7 +321,6 @@ WebInspector.DefaultTextEditor.prototype = {
     editRange: function(range, text)
     {
         this._enterInternalTextChangeMode();
-        this._textModel.markUndoableState();
         var newRange = this._textModel.editRange(range, text);
         this._exitInternalTextChangeMode(range, newRange);
         return newRange;
@@ -369,7 +368,7 @@ WebInspector.DefaultTextEditor.prototype = {
             return;
 
         var mainChunk = this._mainPanel.chunkForLine(lineNumber);
-        if (mainChunk.linesCount === 1 && mainChunk.decorated) {
+        if (mainChunk.linesCount === 1 && mainChunk.isDecorated()) {
             var gutterChunk = this._gutterPanel.makeLineAChunk(lineNumber);
             var height = mainChunk.height;
             if (height)
@@ -731,7 +730,6 @@ WebInspector.TextEditorChunkedPanel.prototype = {
         // Prefix chunk.
         if (lineNumber > oldChunk.startLine) {
             var prefixChunk = this._createNewChunk(oldChunk.startLine, lineNumber);
-            prefixChunk.readOnly = oldChunk.readOnly;
             this._textChunks.splice(insertIndex++, 0, prefixChunk);
             this._container.insertBefore(prefixChunk.element, oldChunk.element);
         }
@@ -739,14 +737,12 @@ WebInspector.TextEditorChunkedPanel.prototype = {
         // Line chunk.
         var endLine = createSuffixChunk ? lineNumber + 1 : oldChunk.startLine + oldChunk.linesCount;
         var lineChunk = this._createNewChunk(lineNumber, endLine);
-        lineChunk.readOnly = oldChunk.readOnly;
         this._textChunks.splice(insertIndex++, 0, lineChunk);
         this._container.insertBefore(lineChunk.element, oldChunk.element);
 
         // Suffix chunk.
         if (oldChunk.startLine + oldChunk.linesCount > endLine) {
             var suffixChunk = this._createNewChunk(endLine, oldChunk.startLine + oldChunk.linesCount);
-            suffixChunk.readOnly = oldChunk.readOnly;
             this._textChunks.splice(insertIndex, 0, suffixChunk);
             this._container.insertBefore(suffixChunk.element, oldChunk.element);
         }
@@ -1364,47 +1360,6 @@ WebInspector.TextEditorMainPanel.prototype = {
     },
 
     /**
-     * @param {number} startLine
-     * @param {number} endLine
-     */
-    setEditableRange: function(startLine, endLine)
-    {
-        this.beginDomUpdates();
-
-        var firstChunkNumber = this._chunkNumberForLine(startLine);
-        var firstChunk = this._textChunks[firstChunkNumber];
-        if (firstChunk.startLine !== startLine) {
-            this._splitChunkOnALine(startLine, firstChunkNumber);
-            firstChunkNumber += 1;
-        }
-
-        var lastChunkNumber = this._textChunks.length;
-        if (endLine !== this._textModel.linesCount) {
-            lastChunkNumber = this._chunkNumberForLine(endLine);
-            var lastChunk = this._textChunks[lastChunkNumber];
-            if (lastChunk && lastChunk.startLine !== endLine) {
-                this._splitChunkOnALine(endLine, lastChunkNumber);
-                lastChunkNumber += 1;
-            }
-        }
-
-        for (var chunkNumber = 0; chunkNumber < firstChunkNumber; ++chunkNumber)
-            this._textChunks[chunkNumber].readOnly = true;
-        for (var chunkNumber = firstChunkNumber; chunkNumber < lastChunkNumber; ++chunkNumber)
-            this._textChunks[chunkNumber].readOnly = false;
-        for (var chunkNumber = lastChunkNumber; chunkNumber < this._textChunks.length; ++chunkNumber)
-            this._textChunks[chunkNumber].readOnly = true;
-
-        this.endDomUpdates();
-    },
-
-    clearEditableRange: function()
-    {
-        for (var chunkNumber = 0; chunkNumber < this._textChunks.length; ++chunkNumber)
-            this._textChunks[chunkNumber].readOnly = false;
-    },
-
-    /**
      * @param {WebInspector.TextRange} range
      */
     markAndRevealRange: function(range)
@@ -1514,12 +1469,12 @@ WebInspector.TextEditorMainPanel.prototype = {
         var newRange;
         var rangeWasEmpty = range.isEmpty();
         if (shiftKey)
-            newRange = this._unindentLines(range);
+            newRange = this._textModel.unindentLines(range);
         else {
             if (rangeWasEmpty)
-                newRange = this._editRange(range, WebInspector.settings.textEditorIndent.get());
+                newRange = this._textModel.editRange(range, WebInspector.settings.textEditorIndent.get());
             else
-                newRange = this._indentLines(range);
+                newRange = this._textModel.indentLines(range);
         }
 
         this._exitTextChangeMode(range, newRange);
@@ -1530,78 +1485,6 @@ WebInspector.TextEditorMainPanel.prototype = {
         return true;
     },
 
-    /**
-     * @param {WebInspector.TextRange} range
-     */
-    _indentLines: function(range)
-    {
-        var indent = WebInspector.settings.textEditorIndent.get();
-
-        if (this._lastEditedRange)
-            this._textModel.markUndoableState();
-
-        var newRange = range.clone();
-
-        // Do not change a selection start position when it is at the beginning of a line
-        if (range.startColumn)
-            newRange.startColumn += indent.length;
-
-        var indentEndLine = range.endLine;
-        if (range.endColumn)
-            newRange.endColumn += indent.length;
-        else
-            indentEndLine--;
-
-        for (var lineNumber = range.startLine; lineNumber <= indentEndLine; lineNumber++)
-            this._textModel.editRange(WebInspector.TextRange.createFromLocation(lineNumber, 0), indent);
-
-        this._lastEditedRange = newRange;
-
-        return newRange;
-    },
-
-    /**
-     * @param {WebInspector.TextRange} range
-     */
-    _unindentLines: function(range)
-    {
-        if (this._lastEditedRange)
-            this._textModel.markUndoableState();
-
-        var indent = WebInspector.settings.textEditorIndent.get();
-        var indentLength = indent === WebInspector.TextEditorModel.Indent.TabCharacter ? 4 : indent.length;
-        var lineIndentRegex = new RegExp("^ {1," + indentLength + "}");
-        var newRange = range.clone();
-
-        var indentEndLine = range.endLine;
-        if (!range.endColumn)
-            indentEndLine--;
-
-        for (var lineNumber = range.startLine; lineNumber <= indentEndLine; lineNumber++) {
-            var line = this._textModel.line(lineNumber);
-            var firstCharacter = line.charAt(0);
-            var lineIndentLength;
-
-            if (firstCharacter === " ")
-                lineIndentLength = line.match(lineIndentRegex)[0].length;
-            else if (firstCharacter === "\t")
-                lineIndentLength = 1;
-            else
-                continue;
-
-            this._textModel.editRange(new WebInspector.TextRange(lineNumber, 0, lineNumber, lineIndentLength), "");
-
-            if (lineNumber === range.startLine)
-                newRange.startColumn = Math.max(0, newRange.startColumn - lineIndentLength);
-            if (lineNumber === range.endLine)
-                newRange.endColumn = Math.max(0, newRange.endColumn - lineIndentLength);
-        }
-
-        this._lastEditedRange = newRange;
-
-        return newRange;
-    },
-
     handleEnterKey: function()
     {
         if (this.readOnly())
@@ -1638,11 +1521,11 @@ WebInspector.TextEditorMainPanel.prototype = {
             // {
             //     |
             // }
-            newRange = this._editRange(range, lineBreak + indent + lineBreak + currentIndent);
+            newRange = this._textModel.editRange(range, lineBreak + indent + lineBreak + currentIndent);
             newRange.endLine--;
             newRange.endColumn += textEditorIndent.length;
         } else
-            newRange = this._editRange(range, lineBreak + indent);
+            newRange = this._textModel.editRange(range, lineBreak + indent);
 
         this._exitTextChangeMode(range, newRange);
         this.endUpdates();
@@ -2334,7 +2217,7 @@ WebInspector.TextEditorMainPanel.prototype = {
         // This is a "foreign" call outside of this class. Should be before we delete the dirty lines flag.
         this._enterTextChangeMode();
 
-        var newRange = this._editRange(oldRange, newContent);
+        var newRange = this._textModel.editRange(oldRange, newContent);
 
         this._paintScheduledLines(true);
         this._restoreSelection(selection);
@@ -2389,21 +2272,6 @@ WebInspector.TextEditorMainPanel.prototype = {
 
     /**
      * @param {WebInspector.TextRange} range
-     * @param {string} text
-     */
-    _editRange: function(range, text)
-    {
-        if (this._lastEditedRange && (!text || text.indexOf("\n") !== -1 || this._lastEditedRange.endLine !== range.startLine || this._lastEditedRange.endColumn !== range.startColumn))
-            this._textModel.markUndoableState();
-
-        var newRange = this._textModel.editRange(range, text);
-        this._lastEditedRange = newRange;
-
-        return newRange;
-    },
-
-    /**
-     * @param {WebInspector.TextRange} range
      */
     _removeDecorationsInRange: function(range)
     {
@@ -2475,7 +2343,7 @@ WebInspector.TextEditorMainPanel.prototype = {
         // Maybe merge with the next chunk, so that we should not create 1-sized chunks when appending new lines one by one.
         var chunk = this._textChunks[lastChunkNumber + 1];
         var linesInLastChunk = linesCount % this._defaultChunkSize;
-        if (chunk && !chunk.decorated && linesInLastChunk > 0 && linesInLastChunk + chunk.linesCount <= this._defaultChunkSize) {
+        if (chunk && !chunk.isDecorated() && linesInLastChunk > 0 && linesInLastChunk + chunk.linesCount <= this._defaultChunkSize) {
             ++lastChunkNumber;
             linesCount += chunk.linesCount;
         }
@@ -2577,7 +2445,7 @@ WebInspector.TextEditorMainPanel.prototype = {
  * @param {WebInspector.TextEditorChunkedPanel} chunkedPanel
  * @param {number} startLine
  * @param {number} endLine
-*/
+ */
 WebInspector.TextEditorMainChunk = function(chunkedPanel, startLine, endLine)
 {
     this._chunkedPanel = chunkedPanel;
@@ -2592,7 +2460,6 @@ WebInspector.TextEditorMainChunk = function(chunkedPanel, startLine, endLine)
     this.linesCount = endLine - startLine;
 
     this._expanded = false;
-    this._readOnly = false;
 
     this.updateCollapsedLineRow();
 }
@@ -2641,7 +2508,7 @@ WebInspector.TextEditorMainChunk.prototype = {
     /**
      * @return {boolean}
      */
-    get decorated()
+    isDecorated: function()
     {
         return this.element.className !== "webkit-line-content" || !!(this.element.decorationsElement && this.element.decorationsElement.firstChild);
     },
@@ -2692,7 +2559,6 @@ WebInspector.TextEditorMainChunk.prototype = {
             var parentElement = this.element.parentElement;
             for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) {
                 var lineRow = this._createRow(i);
-                this._updateElementReadOnlyState(lineRow);
                 parentElement.insertBefore(lineRow, this.element);
                 this._expandedLineRows.push(lineRow);
             }
@@ -2718,35 +2584,6 @@ WebInspector.TextEditorMainChunk.prototype = {
         this._chunkedPanel.endDomUpdates();
     },
 
-    set readOnly(readOnly)
-    {
-        if (this._readOnly === readOnly)
-            return;
-
-        this._readOnly = readOnly;
-        this._updateElementReadOnlyState(this.element);
-        if (this._expandedLineRows) {
-            for (var i = 0; i < this._expandedLineRows.length; ++i)
-                this._updateElementReadOnlyState(this._expandedLineRows[i]);
-        }
-    },
-
-    /**
-     * @return {boolean}
-     */
-    get readOnly()
-    {
-        return this._readOnly;
-    },
-
-    _updateElementReadOnlyState: function(element)
-    {
-        if (this._readOnly)
-            element.addStyleClass("text-editor-read-only");
-        else
-            element.removeStyleClass("text-editor-read-only");
-    },
-
     /**
      * @return {number}
      */
index 6a8b2de..d8ac2bd 100644 (file)
@@ -238,12 +238,25 @@ WebInspector.TextEditorModel.prototype = {
      * @return {WebInspector.TextRange}
      */
     editRange: function(range, text)
+    {   
+        if (this._lastEditedRange && (!text || text.indexOf("\n") !== -1 || this._lastEditedRange.endLine !== range.startLine || this._lastEditedRange.endColumn !== range.startColumn))
+            this._markUndoableState();
+        return this._innerEditRange(range, text);
+    },
+
+    /**
+     * @param {WebInspector.TextRange} range
+     * @param {string} text
+     * @return {WebInspector.TextRange}
+     */
+    _innerEditRange: function(range, text)
     {
         var originalText = this.copyRange(range);
         if (text === originalText)
             return range; // Noop
 
         var newRange = this._innerSetText(range, text);
+        this._lastEditedRange = newRange;
         this._pushUndoableCommand(newRange, originalText);
         this.dispatchEventToListeners(WebInspector.TextEditorModel.Events.TextChanged, { oldRange: range, newRange: newRange });
         return newRange;
@@ -477,7 +490,7 @@ WebInspector.TextEditorModel.prototype = {
     {
         if (!this._redoStack || !this._redoStack.length)
             return null;
-        this.markUndoableState();
+        this._markUndoableState();
 
         this._inRedo = true;
         var range = this._doUndo(this._redoStack, beforeCallback, afterCallback);
@@ -502,7 +515,7 @@ WebInspector.TextEditorModel.prototype = {
             if (beforeCallback)
                 beforeCallback();
 
-            range = this.editRange(command.newRange, command.originalText);
+            range = this._innerEditRange(command.newRange, command.originalText);
 
             if (afterCallback)
                 afterCallback(command.newRange, range);
@@ -513,7 +526,7 @@ WebInspector.TextEditorModel.prototype = {
         return range;
     },
 
-    markUndoableState: function()
+    _markUndoableState: function()
     {
         if (this._undoStack.length)
             this._undoStack[this._undoStack.length - 1].explicit = true;
@@ -530,5 +543,71 @@ WebInspector.TextEditorModel.prototype = {
         this._undoStack = [];
     },
 
+    /**
+     * @param {WebInspector.TextRange} range
+     * @return {WebInspector.TextRange}
+     */
+    indentLines: function(range)
+    {
+        this._markUndoableState();
+
+        var indent = WebInspector.settings.textEditorIndent.get();
+        var newRange = range.clone();
+        // Do not change a selection start position when it is at the beginning of a line
+        if (range.startColumn)
+            newRange.startColumn += indent.length;
+
+        var indentEndLine = range.endLine;
+        if (range.endColumn)
+            newRange.endColumn += indent.length;
+        else
+            indentEndLine--;
+
+        for (var lineNumber = range.startLine; lineNumber <= indentEndLine; lineNumber++)
+            this._innerEditRange(WebInspector.TextRange.createFromLocation(lineNumber, 0), indent);
+
+        return newRange;
+    },
+
+    /**
+     * @param {WebInspector.TextRange} range
+     * @return {WebInspector.TextRange}
+     */
+    unindentLines: function(range)
+    {
+        this._markUndoableState();
+
+        var indent = WebInspector.settings.textEditorIndent.get();
+        var indentLength = indent === WebInspector.TextEditorModel.Indent.TabCharacter ? 4 : indent.length;
+        var lineIndentRegex = new RegExp("^ {1," + indentLength + "}");
+        var newRange = range.clone();
+
+        var indentEndLine = range.endLine;
+        if (!range.endColumn)
+            indentEndLine--;
+
+        for (var lineNumber = range.startLine; lineNumber <= indentEndLine; lineNumber++) {
+            var line = this.line(lineNumber);
+            var firstCharacter = line.charAt(0);
+            var lineIndentLength;
+
+            if (firstCharacter === " ")
+                lineIndentLength = line.match(lineIndentRegex)[0].length;
+            else if (firstCharacter === "\t")
+                lineIndentLength = 1;
+            else
+                continue;
+
+            this._innerEditRange(new WebInspector.TextRange(lineNumber, 0, lineNumber, lineIndentLength), "");
+
+            if (lineNumber === range.startLine)
+                newRange.startColumn = Math.max(0, newRange.startColumn - lineIndentLength);
+            if (lineNumber === range.endLine)
+                newRange.endColumn = Math.max(0, newRange.endColumn - lineIndentLength);
+        }
+
+        return newRange;
+    },
+
     __proto__: WebInspector.Object.prototype
 }