summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/inspector/front-end/TextViewer.js
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-25 19:08:45 +0100
committerSteve Block <steveblock@google.com>2011-06-08 13:51:31 +0100
commit2bde8e466a4451c7319e3a072d118917957d6554 (patch)
tree28f4a1b869a513e565c7760d0e6a06e7cf1fe95a /Source/WebCore/inspector/front-end/TextViewer.js
parent6939c99b71d9372d14a0c74a772108052e8c48c8 (diff)
downloadexternal_webkit-2bde8e466a4451c7319e3a072d118917957d6554.zip
external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.tar.gz
external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.tar.bz2
Merge WebKit at r82507: Initial merge by git
Change-Id: I60ce9d780725b58b45e54165733a8ffee23b683e
Diffstat (limited to 'Source/WebCore/inspector/front-end/TextViewer.js')
-rw-r--r--Source/WebCore/inspector/front-end/TextViewer.js283
1 files changed, 174 insertions, 109 deletions
diff --git a/Source/WebCore/inspector/front-end/TextViewer.js b/Source/WebCore/inspector/front-end/TextViewer.js
index 65b4724..43b34f6 100644
--- a/Source/WebCore/inspector/front-end/TextViewer.js
+++ b/Source/WebCore/inspector/front-end/TextViewer.js
@@ -45,6 +45,11 @@ WebInspector.TextViewer = function(textModel, platform, url)
this._gutterPanel = new WebInspector.TextEditorGutterPanel(this._textModel, syncDecorationsForLineListener);
this.element.appendChild(this._mainPanel.element);
this.element.appendChild(this._gutterPanel.element);
+
+ // Forward mouse wheel events from the unscrollable gutter to the main panel.
+ this._gutterPanel.element.addEventListener("mousewheel", function(e) {
+ this._mainPanel.element.dispatchEvent(e);
+ }.bind(this), false)
}
WebInspector.TextViewer.prototype = {
@@ -58,6 +63,11 @@ WebInspector.TextViewer.prototype = {
this._mainPanel.readOnly = readOnly;
},
+ get readOnly()
+ {
+ return this._mainPanel.readOnly;
+ },
+
set startEditingListener(startEditingListener)
{
this._startEditingListener = startEditingListener;
@@ -111,11 +121,6 @@ WebInspector.TextViewer.prototype = {
this._gutterPanel.freeCachedElements();
},
- editLine: function(lineRow, callback)
- {
- this._mainPanel.editLine(lineRow, callback);
- },
-
get scrollTop()
{
return this._mainPanel.element.scrollTop;
@@ -395,15 +400,19 @@ WebInspector.TextEditorChunkedPanel.prototype = {
return this._textChunks[this._chunkNumberForLine(lineNumber)];
},
- _findVisibleChunks: function(visibleFrom, visibleTo)
+ _findFirstVisibleChunkNumber: function(visibleFrom)
{
function compareOffsetTops(value, chunk)
{
return value < chunk.offsetTop ? -1 : 1;
}
var insertBefore = insertionIndexForObjectInListSortedByFunction(visibleFrom, this._textChunks, compareOffsetTops);
+ return insertBefore - 1;
+ },
- var from = insertBefore - 1;
+ _findVisibleChunks: function(visibleFrom, visibleTo)
+ {
+ var from = this._findFirstVisibleChunkNumber(visibleFrom);
for (var to = from + 1; to < this._textChunks.length; ++to) {
if (this._textChunks[to].offsetTop >= visibleTo)
break;
@@ -411,6 +420,26 @@ WebInspector.TextEditorChunkedPanel.prototype = {
return { start: from, end: to };
},
+ _findFirstVisibleLineNumber: function(visibleFrom)
+ {
+ var chunk = this._textChunks[this._findFirstVisibleChunkNumber(visibleFrom)];
+ if (!chunk.expanded)
+ return chunk.startLine;
+
+ var lineNumbers = [];
+ for (var i = 0; i < chunk.linesCount; ++i) {
+ lineNumbers.push(chunk.startLine + i);
+ }
+
+ function compareLineRowOffsetTops(value, lineNumber)
+ {
+ var lineRow = chunk.getExpandedLineRow(lineNumber);
+ return value < lineRow.offsetTop ? -1 : 1;
+ }
+ var insertBefore = insertionIndexForObjectInListSortedByFunction(visibleFrom, lineNumbers, compareLineRowOffsetTops);
+ return lineNumbers[insertBefore - 1];
+ },
+
_repaintAll: function()
{
delete this._repaintAllTimer;
@@ -430,6 +459,17 @@ WebInspector.TextEditorChunkedPanel.prototype = {
}
},
+ _expandChunks: function(fromIndex, toIndex)
+ {
+ // First collapse chunks to collect the DOM elements into a cache to reuse them later.
+ for (var i = 0; i < fromIndex; ++i)
+ this._textChunks[i].expanded = false;
+ for (var i = toIndex; i < this._textChunks.length; ++i)
+ this._textChunks[i].expanded = false;
+ for (var i = fromIndex; i < toIndex; ++i)
+ this._textChunks[i].expanded = true;
+ },
+
_totalHeight: function(firstElement, lastElement)
{
lastElement = (lastElement || firstElement).nextElementSibling;
@@ -484,12 +524,6 @@ WebInspector.TextEditorGutterPanel.prototype = {
return new WebInspector.TextEditorGutterChunk(this, startLine, endLine);
},
- _expandChunks: function(fromIndex, toIndex)
- {
- for (var i = 0; i < this._textChunks.length; ++i)
- this._textChunks[i].expanded = (fromIndex <= i && i < toIndex);
- },
-
textChanged: function(oldRange, newRange)
{
if (!this._textChunks) {
@@ -689,10 +723,6 @@ WebInspector.TextEditorMainPanel = function(textModel, url, syncScrollListener,
this.element.addEventListener("scroll", this._scroll.bind(this), false);
- // FIXME: Remove old live editing functionality and Preferences.sourceEditorEnabled flag.
- if (!Preferences.sourceEditorEnabled)
- this._container.addEventListener("keydown", this._handleKeyDown.bind(this), false);
-
// In WebKit the DOMNodeRemoved event is fired AFTER the node is removed, thus it should be
// attached to all DOM nodes that we want to track. Instead, we attach the DOMNodeRemoved
// listeners only on the line rows, and use DOMSubtreeModified to track node removals inside
@@ -714,10 +744,6 @@ WebInspector.TextEditorMainPanel.prototype = {
set readOnly(readOnly)
{
- // FIXME: Remove the Preferences.sourceEditorEnabled flag.
- if (!Preferences.sourceEditorEnabled)
- return;
-
this.beginDomUpdates();
this._readOnly = readOnly;
if (this._readOnly)
@@ -727,6 +753,11 @@ WebInspector.TextEditorMainPanel.prototype = {
this.endDomUpdates();
},
+ get readOnly()
+ {
+ return this._readOnly;
+ },
+
markAndRevealRange: function(range)
{
if (this._rangeToMark) {
@@ -768,58 +799,8 @@ WebInspector.TextEditorMainPanel.prototype = {
this._cachedRows = [];
},
- _handleKeyDown: function()
- {
- if (this._editingLine || event.metaKey || event.shiftKey || event.ctrlKey || event.altKey)
- return;
-
- var scrollValue = 0;
- if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Up.code)
- scrollValue = -1;
- else if (event.keyCode == WebInspector.KeyboardShortcut.Keys.Down.code)
- scrollValue = 1;
-
- if (scrollValue) {
- event.preventDefault();
- event.stopPropagation();
- this.element.scrollByLines(scrollValue);
- return;
- }
-
- scrollValue = 0;
- if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Left.code)
- scrollValue = -40;
- else if (event.keyCode == WebInspector.KeyboardShortcut.Keys.Right.code)
- scrollValue = 40;
-
- if (scrollValue) {
- event.preventDefault();
- event.stopPropagation();
- this.element.scrollLeft += scrollValue;
- }
- },
-
- editLine: function(lineRow, callback)
- {
- var oldContent = lineRow.innerHTML;
- function finishEditing(committed, e, newContent)
- {
- if (committed)
- callback(newContent);
- lineRow.innerHTML = oldContent;
- delete this._editingLine;
- }
- this._editingLine = WebInspector.startEditing(lineRow, {
- context: null,
- commitHandler: finishEditing.bind(this, true),
- cancelHandler: finishEditing.bind(this, false),
- multiline: true
- });
- },
-
_buildChunks: function()
{
- this._highlighter.reset();
for (var i = 0; i < this._textModel.linesCount; ++i)
this._textModel.removeAttribute(i, "highlight");
@@ -842,8 +823,8 @@ WebInspector.TextEditorMainPanel.prototype = {
this._highlighter.highlight(lastVisibleLine);
delete this._muteHighlightListener;
- for (var i = 0; i < this._textChunks.length; ++i)
- this._textChunks[i].expanded = (fromIndex <= i && i < toIndex);
+ this._restorePaintLinesOperationsCredit();
+ WebInspector.TextEditorChunkedPanel.prototype._expandChunks.call(this, fromIndex, toIndex);
this._restoreSelection(selection);
},
@@ -852,64 +833,118 @@ WebInspector.TextEditorMainPanel.prototype = {
{
if (this._muteHighlightListener)
return;
+ this._restorePaintLinesOperationsCredit();
this._paintLines(fromLine, toLine, true /*restoreSelection*/);
},
- _markSkippedPaintLines: function(startLine, endLine)
+ _schedulePaintLines: function(startLine, endLine)
{
- if (!this._skippedPaintLines)
- this._skippedPaintLines = [ { startLine: startLine, endLine: endLine } ];
- else {
- for (var i = 0; i < this._skippedPaintLines.length; ++i) {
- var chunk = this._skippedPaintLines[i];
+ if (startLine >= endLine)
+ return;
+
+ if (!this._scheduledPaintLines) {
+ this._scheduledPaintLines = [ { startLine: startLine, endLine: endLine } ];
+ this._paintScheduledLinesTimer = setTimeout(this._paintScheduledLines.bind(this), 10);
+ } else {
+ for (var i = 0; i < this._scheduledPaintLines.length; ++i) {
+ var chunk = this._scheduledPaintLines[i];
if (chunk.startLine <= endLine && chunk.endLine >= startLine) {
chunk.startLine = Math.min(chunk.startLine, startLine);
chunk.endLine = Math.max(chunk.endLine, endLine);
return;
}
+ if (chunk.startLine > endLine) {
+ this._scheduledPaintLines.splice(i, 0, { startLine: startLine, endLine: endLine });
+ return;
+ }
}
- this._skippedPaintLines.push({ startLine: startLine, endLine: endLine });
+ this._scheduledPaintLines.push({ startLine: startLine, endLine: endLine });
}
},
- _paintSkippedLines: function()
+ _paintScheduledLines: function(skipRestoreSelection)
{
- if (!this._skippedPaintLines || this._dirtyLines)
+ if (this._paintScheduledLinesTimer)
+ clearTimeout(this._paintScheduledLinesTimer);
+ delete this._paintScheduledLinesTimer;
+
+ if (!this._scheduledPaintLines)
+ return;
+
+ // Reschedule the timer if we can not paint the lines yet, or the user is scrolling.
+ if (this._dirtyLines || this._repaintAllTimer) {
+ this._paintScheduledLinesTimer = setTimeout(this._paintScheduledLines.bind(this), 50);
return;
- for (var i = 0; i < this._skippedPaintLines.length; ++i) {
- var chunk = this._skippedPaintLines[i];
- this._paintLines(chunk.startLine, chunk.endLine);
}
- delete this._skippedPaintLines;
+
+ var scheduledPaintLines = this._scheduledPaintLines;
+ delete this._scheduledPaintLines;
+
+ this._restorePaintLinesOperationsCredit();
+ this._paintLineChunks(scheduledPaintLines, !skipRestoreSelection);
+ },
+
+ _restorePaintLinesOperationsCredit: function()
+ {
+ this._paintLinesOperationsCredit = 250;
},
_paintLines: function(fromLine, toLine, restoreSelection)
{
- if (this._dirtyLines) {
- this._markSkippedPaintLines(fromLine, toLine);
- return;
- }
+ this._paintLineChunks([ { startLine: fromLine, endLine: toLine } ], restoreSelection);
+ },
+
+ _paintLineChunks: function(lineChunks, restoreSelection)
+ {
+ // First, paint visible lines, so that in case of long lines we should start highlighting
+ // the visible area immediately, instead of waiting for the lines above the visible area.
+ var visibleFrom = this.element.scrollTop;
+ var firstVisibleLineNumber = this._findFirstVisibleLineNumber(visibleFrom);
+ var chunk;
var selection;
- var chunk = this.chunkForLine(fromLine);
- for (var i = fromLine; i < toLine; ++i) {
- if (i >= chunk.startLine + chunk.linesCount)
- chunk = this.chunkForLine(i);
- var lineRow = chunk.getExpandedLineRow(i);
- if (!lineRow)
+ var invisibleLineRows = [];
+ for (var i = 0; i < lineChunks.length; ++i) {
+ var lineChunk = lineChunks[i];
+ if (this._dirtyLines || this._scheduledPaintLines) {
+ this._schedulePaintLines(lineChunk.startLine, lineChunk.endLine);
continue;
+ }
+ for (var lineNumber = lineChunk.startLine; lineNumber < lineChunk.endLine; ++lineNumber) {
+ if (!chunk || lineNumber < chunk.startLine || lineNumber >= chunk.startLine + chunk.linesCount)
+ chunk = this.chunkForLine(lineNumber);
+ var lineRow = chunk.getExpandedLineRow(lineNumber);
+ if (!lineRow)
+ continue;
+ if (lineNumber < firstVisibleLineNumber) {
+ invisibleLineRows.push(lineRow);
+ continue;
+ }
+ if (restoreSelection && !selection)
+ selection = this._getSelection();
+ this._paintLine(lineRow);
+ if (this._paintLinesOperationsCredit < 0) {
+ this._schedulePaintLines(lineNumber + 1, lineChunk.endLine);
+ break;
+ }
+ }
+ }
+
+ for (var i = 0; i < invisibleLineRows.length; ++i) {
if (restoreSelection && !selection)
selection = this._getSelection();
- this._paintLine(lineRow, i);
+ this._paintLine(invisibleLineRows[i]);
}
+
if (restoreSelection)
this._restoreSelection(selection);
},
- _paintLine: function(lineRow, lineNumber)
+ _paintLine: function(lineRow)
{
- if (this._dirtyLines) {
- this._markSkippedPaintLines(lineNumber, lineNumber + 1);
+ var lineNumber = lineRow.lineNumber;
+ if (this._dirtyLines || this._scheduledPaintLines || this._paintLinesOperationsCredit < 0) {
+ this._schedulePaintLines(lineNumber, lineNumber + 1);
return;
}
@@ -944,13 +979,17 @@ WebInspector.TextEditorMainPanel.prototype = {
if (plainTextStart !== -1) {
this._appendTextNode(lineRow, line.substring(plainTextStart, j));
plainTextStart = -1;
+ --this._paintLinesOperationsCredit;
}
this._appendSpan(lineRow, line.substring(j, j + attribute.length), attribute.tokenType);
j += attribute.length;
+ --this._paintLinesOperationsCredit;
}
}
- if (plainTextStart !== -1)
+ if (plainTextStart !== -1) {
this._appendTextNode(lineRow, line.substring(plainTextStart, line.length));
+ --this._paintLinesOperationsCredit;
+ }
if (this._rangeToMark && this._rangeToMark.startLine === lineNumber)
this._markedRangeElement = highlightSearchResult(lineRow, this._rangeToMark.startColumn, this._rangeToMark.endColumn - this._rangeToMark.startColumn);
if (lineRow.decorationsElement)
@@ -1141,12 +1180,37 @@ WebInspector.TextEditorMainPanel.prototype = {
if (this._readOnly)
return;
- var lineNumber = lineRow.lineNumber;
+ if (target === lineRow && e.type === "DOMNodeInserted") {
+ // Ensure that the newly inserted line row has no lineNumber.
+ delete lineRow.lineNumber;
+ }
+
+ var startLine = 0;
+ for (var row = lineRow; row; row = row.previousSibling) {
+ if (typeof row.lineNumber === "number") {
+ startLine = row.lineNumber;
+ break;
+ }
+ }
+
+ var endLine = startLine + 1;
+ for (var row = lineRow.nextSibling; row; row = row.nextSibling) {
+ if (typeof row.lineNumber === "number") {
+ endLine = row.lineNumber;
+ break;
+ }
+ }
+
+ if (target === lineRow && e.type === "DOMNodeRemoved") {
+ // Now this will no longer be valid.
+ delete lineRow.lineNumber;
+ }
+
if (this._dirtyLines) {
- this._dirtyLines.start = Math.min(this._dirtyLines.start, lineNumber);
- this._dirtyLines.end = Math.max(this._dirtyLines.end, lineNumber + 1);
+ this._dirtyLines.start = Math.min(this._dirtyLines.start, startLine);
+ this._dirtyLines.end = Math.max(this._dirtyLines.end, endLine);
} else {
- this._dirtyLines = { start: lineNumber, end: lineNumber + 1 };
+ this._dirtyLines = { start: startLine, end: endLine };
setTimeout(this._applyDomUpdates.bind(this), 0);
// Remove marked ranges, if any.
this.markAndRevealRange(null);
@@ -1227,7 +1291,7 @@ WebInspector.TextEditorMainPanel.prototype = {
this._removeDecorationsInRange(oldRange);
this._updateChunksForRanges(oldRange, newRange);
this._updateHighlightsForRange(newRange);
- this._paintSkippedLines();
+ this._paintScheduledLines(true);
this.endDomUpdates();
this._restoreSelection(selection);
@@ -1348,7 +1412,8 @@ WebInspector.TextEditorMainPanel.prototype = {
var chunk = this._textChunks[result.end - 1];
var lastVisibleLine = chunk.startLine + chunk.linesCount;
- lastVisibleLine = Math.max(lastVisibleLine, range.endLine);
+ lastVisibleLine = Math.max(lastVisibleLine, range.endLine + 1);
+ lastVisibleLine = Math.min(lastVisibleLine, this._textModel.linesCount);
var updated = this._highlighter.updateHighlight(range.startLine, lastVisibleLine);
if (!updated) {
@@ -1479,7 +1544,7 @@ WebInspector.TextEditorMainChunk.prototype = {
if (this.linesCount === 1) {
if (expanded)
- this._textViewer._paintLine(this.element, this.startLine);
+ this._textViewer._paintLine(this.element);
return;
}
@@ -1492,9 +1557,9 @@ WebInspector.TextEditorMainChunk.prototype = {
var lineRow = this._createRow(i);
parentElement.insertBefore(lineRow, this.element);
this._expandedLineRows.push(lineRow);
- this._textViewer._paintLine(lineRow, i);
}
parentElement.removeChild(this.element);
+ this._textViewer._paintLines(this.startLine, this.startLine + this.linesCount);
} else {
var elementInserted = false;
for (var i = 0; i < this._expandedLineRows.length; ++i) {