/**
* @extends {WebInspector.View}
* @constructor
+ * @param {WebInspector.TextEditorModel} textModel
+ * @param {?string} url
+ * @param {WebInspector.TextViewerDelegate} delegate
*/
-WebInspector.TextViewer = function(textModel, platform, url, delegate)
+WebInspector.TextViewer = function(textModel, url, delegate)
{
WebInspector.View.call(this);
this.registerRequiredCSS("textViewer.css");
}
WebInspector.TextViewer.prototype = {
+ /**
+ * @param {string} mimeType
+ */
set mimeType(mimeType)
{
this._mainPanel.mimeType = mimeType;
WebInspector.markBeingEdited(this.element, !readOnly);
},
+ /**
+ * @return {boolean}
+ */
readOnly: function()
{
return this._mainPanel.readOnly();
},
+ /**
+ * @return {WebInspector.TextEditorModel}
+ */
get textModel()
{
return this._textModel;
},
+ /**
+ * @return {Element}
+ */
defaultFocusedElement: function()
{
return this._mainPanel.defaultFocusedElement();
},
+ /**
+ * @param {number} lineNumber
+ */
revealLine: function(lineNumber)
{
this._mainPanel.revealLine(lineNumber);
},
+ /**
+ * @param {number} lineNumber
+ * @param {string|Element} decoration
+ */
addDecoration: function(lineNumber, decoration)
{
this._mainPanel.addDecoration(lineNumber, decoration);
this._gutterPanel.addDecoration(lineNumber, decoration);
},
+ /**
+ * @param {number} lineNumber
+ * @param {string|Element} decoration
+ */
removeDecoration: function(lineNumber, decoration)
{
this._mainPanel.removeDecoration(lineNumber, decoration);
this._gutterPanel.removeDecoration(lineNumber, decoration);
},
+ /**
+ * @param {WebInspector.TextRange} range
+ */
markAndRevealRange: function(range)
{
this._mainPanel.markAndRevealRange(range);
},
+ /**
+ * @param {number} lineNumber
+ */
highlightLine: function(lineNumber)
{
if (typeof lineNumber !== "number" || lineNumber < 0)
this._gutterPanel.freeCachedElements();
},
+ /**
+ * @return {Array.<Element>}
+ */
elementsToRestoreScrollPositionsFor: function()
{
return [this._mainPanel.element];
},
+ /**
+ * @param {WebInspector.TextViewer} textViewer
+ */
inheritScrollPositions: function(textViewer)
{
this._mainPanel.element._scrollTop = textViewer._mainPanel.element.scrollTop;
this._delegate.beforeTextChanged();
},
+ /**
+ * @param {WebInspector.TextRange} oldRange
+ * @param {WebInspector.TextRange} newRange
+ */
_exitInternalTextChangeMode: function(oldRange, newRange)
{
this._internalTextChangeMode = false;
gutterElement.scrollTop = mainElement.scrollTop;
},
+ /**
+ * @param {number} lineNumber
+ */
_syncDecorationsForLine: function(lineNumber)
{
if (lineNumber >= this._textModel.linesCount)
}
},
+ /**
+ * @param {Element} gutterRow
+ */
_syncLineHeight: function(gutterRow)
{
if (this._lineHeightSynced)
{
return this._mainPanel._getSelection();
},
-
+
/**
* @param {WebInspector.TextRange} textRange
*/
{
this._mainPanel._restoreSelection(textRange);
},
-
+
wasShown: function()
{
if (!this.readOnly())
WebInspector.TextViewerDelegate.prototype = {
beforeTextChanged: function() { },
+ /**
+ * @param {WebInspector.TextRange} oldRange
+ * @param {WebInspector.TextRange} newRange
+ */
afterTextChanged: function(oldRange, newRange) { },
commitEditing: function() { },
+ /**
+ * @param {WebInspector.ContextMenu} contextMenu
+ * @param {number} lineNumber
+ */
populateLineGutterContextMenu: function(contextMenu, lineNumber) { },
+ /**
+ * @param {WebInspector.ContextMenu} contextMenu
+ * @param {number} lineNumber
+ */
populateTextAreaContextMenu: function(contextMenu, lineNumber) { }
}
/**
* @constructor
+ * @param {WebInspector.TextEditorModel} textModel
*/
WebInspector.TextEditorChunkedPanel = function(textModel)
{
}
WebInspector.TextEditorChunkedPanel.prototype = {
+ /**
+ * @return {WebInspector.TextEditorModel}
+ */
get textModel()
{
return this._textModel;
},
+ /**
+ * @param {number} lineNumber
+ */
revealLine: function(lineNumber)
{
if (lineNumber >= this._textModel.linesCount)
chunk.element.scrollIntoViewIfNeeded();
},
+ /**
+ * @param {number} lineNumber
+ * @param {string|Element} decoration
+ */
addDecoration: function(lineNumber, decoration)
{
if (lineNumber >= this._textModel.linesCount)
chunk.addDecoration(decoration);
},
+ /**
+ * @param {number} lineNumber
+ * @param {string|Element} decoration
+ */
removeDecoration: function(lineNumber, decoration)
{
if (lineNumber >= this._textModel.linesCount)
this.endDomUpdates();
},
+ /**
+ * @param {number} lineNumber
+ */
makeLineAChunk: function(lineNumber)
{
var chunkNumber = this._chunkNumberForLine(lineNumber);
return this._splitChunkOnALine(lineNumber, chunkNumber, true);
},
+ /**
+ * @param {number} lineNumber
+ * @param {number} chunkNumber
+ * @param {boolean=} createSuffixChunk
+ */
_splitChunkOnALine: function(lineNumber, chunkNumber, createSuffixChunk)
{
this.beginDomUpdates();
this._domUpdateCoalescingLevel--;
},
+ /**
+ * @param {number} lineNumber
+ */
_chunkNumberForLine: function(lineNumber)
{
function compareLineNumbers(value, chunk)
return insertBefore - 1;
},
+ /**
+ * @param {number} lineNumber
+ */
chunkForLine: function(lineNumber)
{
return this._textChunks[this._chunkNumberForLine(lineNumber)];
},
+ /**
+ * @param {number} visibleFrom
+ */
_findFirstVisibleChunkNumber: function(visibleFrom)
{
function compareOffsetTops(value, chunk)
return insertBefore - 1;
},
+ /**
+ * @param {number} visibleFrom
+ * @param {number} visibleTo
+ */
_findVisibleChunks: function(visibleFrom, visibleTo)
{
var from = this._findFirstVisibleChunkNumber(visibleFrom);
return { start: from, end: to };
},
+ /**
+ * @param {number} visibleFrom
+ */
_findFirstVisibleLineNumber: function(visibleFrom)
{
var chunk = this._textChunks[this._findFirstVisibleChunkNumber(visibleFrom)];
}
},
+ /**
+ * @param {number} fromIndex
+ * @param {number} toIndex
+ */
_expandChunks: function(fromIndex, toIndex)
{
// First collapse chunks to collect the DOM elements into a cache to reuse them later.
this._textChunks[i].expanded = true;
},
+ /**
+ * @param {Element} firstElement
+ * @param {Element=} lastElement
+ */
_totalHeight: function(firstElement, lastElement)
{
lastElement = (lastElement || firstElement).nextElementSibling;
/**
* @constructor
* @extends {WebInspector.TextEditorChunkedPanel}
+ * @param {WebInspector.TextEditorModel} textModel
*/
WebInspector.TextEditorGutterPanel = function(textModel, syncDecorationsForLineListener, syncLineHeightListener)
{
this._cachedRows = [];
},
+ /**
+ * @param {number} startLine
+ * @param {number} endLine
+ */
_createNewChunk: function(startLine, endLine)
{
return new WebInspector.TextEditorGutterChunk(this, startLine, endLine);
},
+ /**
+ * @param {WebInspector.TextRange} oldRange
+ * @param {WebInspector.TextRange} newRange
+ */
textChanged: function(oldRange, newRange)
{
this.beginDomUpdates();
this.endDomUpdates();
},
+ /**
+ * @param {number} clientHeight
+ */
syncClientHeight: function(clientHeight)
{
if (this.element.offsetHeight > clientHeight)
this._container.style.removeProperty("padding-bottom");
},
+ /**
+ * @param {number} lineNumber
+ * @param {string|Element} decoration
+ */
addDecoration: function(lineNumber, decoration)
{
WebInspector.TextEditorChunkedPanel.prototype.addDecoration.call(this, lineNumber, decoration);
decorations.push(decoration);
},
+ /**
+ * @param {number} lineNumber
+ * @param {string|Element} decoration
+ */
removeDecoration: function(lineNumber, decoration)
{
WebInspector.TextEditorChunkedPanel.prototype.removeDecoration.call(this, lineNumber, decoration);
}
WebInspector.TextEditorGutterChunk.prototype = {
+ /**
+ * @param {string} decoration
+ */
addDecoration: function(decoration)
{
this._textViewer.beginDomUpdates();
this._textViewer.endDomUpdates();
},
+ /**
+ * @param {string} decoration
+ */
removeDecoration: function(decoration)
{
this._textViewer.beginDomUpdates();
this._textViewer.endDomUpdates();
},
+ /**
+ * @return {boolean}
+ */
get expanded()
{
return this._expanded;
this._textViewer.endDomUpdates();
},
+ /**
+ * @return {number}
+ */
get height()
{
if (!this._expandedLineRows)
return this._textViewer._totalHeight(this._expandedLineRows[0], this._expandedLineRows[this._expandedLineRows.length - 1]);
},
+ /**
+ * @return {number}
+ */
get offsetTop()
{
return (this._expandedLineRows && this._expandedLineRows.length) ? this._expandedLineRows[0].offsetTop : this.element.offsetTop;
},
+ /**
+ * @param {number} lineNumber
+ * @return {Element}
+ */
_createRow: function(lineNumber)
{
var lineRow = this._textViewer._cachedRows.pop() || document.createElement("div");
/**
* @constructor
* @extends {WebInspector.TextEditorChunkedPanel}
+ * @param {WebInspector.TextEditorModel} textModel
+ * @param {?string} url
*/
WebInspector.TextEditorMainPanel = function(textModel, url, syncScrollListener, syncDecorationsForLineListener, enterTextChangeMode, exitTextChangeMode)
{
}
WebInspector.TextEditorMainPanel.prototype = {
+ /**
+ * @param {string} mimeType
+ */
set mimeType(mimeType)
{
this._highlighter.mimeType = mimeType;
},
+ /**
+ * @param {boolean} readOnly
+ * @param {boolean} requestFocus
+ */
setReadOnly: function(readOnly, requestFocus)
{
if (this._readOnly === readOnly)
this.endDomUpdates();
},
+ /**
+ * @return {boolean}
+ */
readOnly: function()
{
return this._readOnly;
this._container.focus();
},
+ /**
+ * @return {Element}
+ */
defaultFocusedElement: function()
{
if (this._readOnly)
selection.addRange(range);
},
+ /**
+ * @param {number} startLine
+ * @param {number} endLine
+ */
setEditableRange: function(startLine, endLine)
{
this.beginDomUpdates();
this._textChunks[chunkNumber].readOnly = false;
},
+ /**
+ * @param {WebInspector.TextRange} range
+ */
markAndRevealRange: function(range)
{
if (this._rangeToMark) {
delete this._markedRangeElement;
},
+ /**
+ * @param {number} lineNumber
+ */
highlightLine: function(lineNumber)
{
this.clearLineHighlight();
this._cachedRows = [];
},
+ /**
+ * @param {boolean} redo
+ */
handleUndoRedo: function(redo)
{
if (this._dirtyLines)
return true;
},
+ /**
+ * @param {boolean} shiftKey
+ */
handleTabKeyPress: function(shiftKey)
{
if (this._dirtyLines)
return true;
},
+ /**
+ * @param {WebInspector.TextRange} range
+ */
_indentLines: function(range)
{
var indent = WebInspector.settings.textEditorIndent.get();
indentEndLine--;
for (var lineNumber = range.startLine; lineNumber <= indentEndLine; lineNumber++)
- this._textModel.editRange(new WebInspector.TextRange.createFromLocation(lineNumber, 0), indent);
+ this._textModel.editRange(WebInspector.TextRange.createFromLocation(lineNumber, 0), indent);
this._lastEditedRange = newRange;
return newRange;
},
+ /**
+ * @param {WebInspector.TextRange} range
+ */
_unindentLines: function(range)
{
if (this._lastEditedRange)
return true;
},
+ /**
+ * @param {number} lineNumber
+ * @param {number} chunkNumber
+ * @param {boolean=} createSuffixChunk
+ */
_splitChunkOnALine: function(lineNumber, chunkNumber, createSuffixChunk)
{
var selection = this._getSelection();
}
},
+ /**
+ * @param {Element} lineRow
+ * @param {boolean} enable
+ */
_enableDOMNodeRemovedListener: function(lineRow, enable)
{
if (enable)
WebInspector.TextEditorChunkedPanel.prototype._buildChunks.call(this);
},
+ /**
+ * @param {number} startLine
+ * @param {number} endLine
+ */
_createNewChunk: function(startLine, endLine)
{
return new WebInspector.TextEditorMainChunk(this, startLine, endLine);
},
+ /**
+ * @param {number} fromIndex
+ * @param {number} toIndex
+ */
_expandChunks: function(fromIndex, toIndex)
{
var lastChunk = this._textChunks[toIndex - 1];
this._restoreSelection(selection);
},
+ /**
+ * @param {number} fromLine
+ * @param {number} toLine
+ */
_highlightDataReady: function(fromLine, toLine)
{
if (this._muteHighlightListener)
this._paintLines(fromLine, toLine, true /*restoreSelection*/);
},
+ /**
+ * @param {number} startLine
+ * @param {number} endLine
+ */
_schedulePaintLines: function(startLine, endLine)
{
if (startLine >= endLine)
}
},
+ /**
+ * @param {boolean} skipRestoreSelection
+ */
_paintScheduledLines: function(skipRestoreSelection)
{
if (this._paintScheduledLinesTimer)
},
/**
+ * @param {number} fromLine
+ * @param {number} toLine
* @param {boolean=} restoreSelection
*/
_paintLines: function(fromLine, toLine, restoreSelection)
this._paintLineChunks([ { startLine: fromLine, endLine: toLine } ], restoreSelection);
},
+ /**
+ * @param {boolean=} restoreSelection
+ */
_paintLineChunks: function(lineChunks, restoreSelection)
{
// First, paint visible lines, so that in case of long lines we should start highlighting
this._restoreSelection(selection);
},
+ /**
+ * @param {Element} lineRow
+ */
_paintLine: function(lineRow)
{
var lineNumber = lineRow.lineNumber;
}
},
+ /**
+ * @param {Element} lineRow
+ */
_releaseLinesHighlight: function(lineRow)
{
if (!lineRow)
}
},
+ /**
+ * @param {Node} container
+ * @param {number} offset
+ */
_selectionToPosition: function(container, offset)
{
if (container === this._container && offset === 0)
return { line: lineNumber, column: column };
},
+ /**
+ * @param {number} line
+ * @param {number} column
+ */
_positionToSelection: function(line, column)
{
var chunk = this.chunkForLine(line);
return rangeBoundary;
},
+ /**
+ * @param {Node} element
+ */
_enclosingLineRowOrSelf: function(element)
{
var lineRow = element.enclosingNodeOrSelfWithClass("webkit-line-content");
return null;
},
+ /**
+ * @param {Element} element
+ * @param {string} content
+ * @param {string} className
+ */
_appendSpan: function(element, content, className)
{
if (className === "html-resource-link" || className === "html-external-link") {
element.spans.push(span);
},
+ /**
+ * @param {Element} element
+ * @param {string} text
+ */
_appendTextNode: function(element, text)
{
var textNode = this._cachedTextNodes.pop();
element.textNodes.push(textNode);
},
+ /**
+ * @param {string} content
+ * @param {boolean} isExternal
+ */
_createLink: function(content, isExternal)
{
var quote = content.charAt(0);
},
/**
+ * @param {string=} hrefValue
* @param {boolean=} isExternal
*/
_rewriteHref: function(hrefValue, isExternal)
this._exitTextChangeMode(oldRange, newRange);
},
+ /**
+ * @param {WebInspector.TextRange} oldRange
+ * @param {WebInspector.TextRange} newRange
+ */
textChanged: function(oldRange, newRange)
{
this.beginDomUpdates();
this.endDomUpdates();
},
+ /**
+ * @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))
return newRange;
},
+ /**
+ * @param {WebInspector.TextRange} range
+ */
_removeDecorationsInRange: function(range)
{
for (var i = this._chunkNumberForLine(range.startLine); i < this._textChunks.length; ++i) {
}
},
+ /**
+ * @param {WebInspector.TextRange} oldRange
+ * @param {WebInspector.TextRange} newRange
+ */
_updateChunksForRanges: function(oldRange, newRange)
{
// Update the chunks in range: firstChunkNumber <= index <= lastChunkNumber
this.element.scrollLeft = scrollLeft;
},
+ /**
+ * @param {WebInspector.TextRange} range
+ */
_updateHighlightsForRange: function(range)
{
var visibleFrom = this.element.scrollTop;
this._repaintAll();
},
+ /**
+ * @param {Array.<string>} lines
+ * @param {Element} element
+ */
_collectLinesFromDiv: function(lines, element)
{
var textContents = [];
/**
* @constructor
- */
-WebInspector.TextEditorMainChunk = function(textViewer, startLine, endLine)
+ * @param {WebInspector.TextEditorChunkedPanel} chunkedPanel
+ * @param {number} startLine
+ * @param {number} endLine
+*/
+WebInspector.TextEditorMainChunk = function(chunkedPanel, startLine, endLine)
{
- this._textViewer = textViewer;
- this._textModel = textViewer._textModel;
+ this._chunkedPanel = chunkedPanel;
+ this._textModel = chunkedPanel._textModel;
this.element = document.createElement("div");
this.element.lineNumber = startLine;
this.element.className = "webkit-line-content";
- this._textViewer._enableDOMNodeRemovedListener(this.element, true);
+ this._chunkedPanel._enableDOMNodeRemovedListener(this.element, true);
this._startLine = startLine;
endLine = Math.min(this._textModel.linesCount, endLine);
WebInspector.TextEditorMainChunk.prototype = {
addDecoration: function(decoration)
{
- this._textViewer.beginDomUpdates();
+ this._chunkedPanel.beginDomUpdates();
if (typeof decoration === "string")
this.element.addStyleClass(decoration);
else {
}
this.element.decorationsElement.appendChild(decoration);
}
- this._textViewer.endDomUpdates();
+ this._chunkedPanel.endDomUpdates();
},
+ /**
+ * @param {string|Element} decoration
+ */
removeDecoration: function(decoration)
{
- this._textViewer.beginDomUpdates();
+ this._chunkedPanel.beginDomUpdates();
if (typeof decoration === "string")
this.element.removeStyleClass(decoration);
else if (this.element.decorationsElement)
this.element.decorationsElement.removeChild(decoration);
- this._textViewer.endDomUpdates();
+ this._chunkedPanel.endDomUpdates();
},
removeAllDecorations: function()
{
- this._textViewer.beginDomUpdates();
+ this._chunkedPanel.beginDomUpdates();
this.element.className = "webkit-line-content";
if (this.element.decorationsElement) {
this.element.removeChild(this.element.decorationsElement);
delete this.element.decorationsElement;
}
- this._textViewer.endDomUpdates();
+ this._chunkedPanel.endDomUpdates();
},
+ /**
+ * @return {boolean}
+ */
get decorated()
{
return this.element.className !== "webkit-line-content" || !!(this.element.decorationsElement && this.element.decorationsElement.firstChild);
},
+ /**
+ * @return {number}
+ */
get startLine()
{
return this._startLine;
}
},
+ /**
+ * @return {boolean}
+ */
get expanded()
{
return this._expanded;
if (this.linesCount === 1) {
if (expanded)
- this._textViewer._paintLine(this.element);
+ this._chunkedPanel._paintLine(this.element);
return;
}
- this._textViewer.beginDomUpdates();
+ this._chunkedPanel.beginDomUpdates();
if (expanded) {
this._expandedLineRows = [];
var parentElement = this.element.parentElement;
for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) {
var lineRow = this._createRow(i);
- this._textViewer._enableDOMNodeRemovedListener(lineRow, true);
+ this._chunkedPanel._enableDOMNodeRemovedListener(lineRow, true);
this._updateElementReadOnlyState(lineRow);
parentElement.insertBefore(lineRow, this.element);
this._expandedLineRows.push(lineRow);
}
- this._textViewer._enableDOMNodeRemovedListener(this.element, false);
+ this._chunkedPanel._enableDOMNodeRemovedListener(this.element, false);
parentElement.removeChild(this.element);
- this._textViewer._paintLines(this.startLine, this.startLine + this.linesCount);
+ this._chunkedPanel._paintLines(this.startLine, this.startLine + this.linesCount);
} else {
var elementInserted = false;
for (var i = 0; i < this._expandedLineRows.length; ++i) {
var lineRow = this._expandedLineRows[i];
- this._textViewer._enableDOMNodeRemovedListener(lineRow, false);
+ this._chunkedPanel._enableDOMNodeRemovedListener(lineRow, false);
var parentElement = lineRow.parentElement;
if (parentElement) {
if (!elementInserted) {
elementInserted = true;
- this._textViewer._enableDOMNodeRemovedListener(this.element, true);
+ this._chunkedPanel._enableDOMNodeRemovedListener(this.element, true);
parentElement.insertBefore(this.element, lineRow);
}
parentElement.removeChild(lineRow);
}
- this._textViewer._releaseLinesHighlight(lineRow);
+ this._chunkedPanel._releaseLinesHighlight(lineRow);
}
delete this._expandedLineRows;
}
- this._textViewer.endDomUpdates();
+ this._chunkedPanel.endDomUpdates();
},
set readOnly(readOnly)
}
},
+ /**
+ * @return {boolean}
+ */
get readOnly()
{
return this._readOnly;
element.removeStyleClass("text-editor-read-only");
},
+ /**
+ * @return {number}
+ */
get height()
{
if (!this._expandedLineRows)
- return this._textViewer._totalHeight(this.element);
- return this._textViewer._totalHeight(this._expandedLineRows[0], this._expandedLineRows[this._expandedLineRows.length - 1]);
+ return this._chunkedPanel._totalHeight(this.element);
+ return this._chunkedPanel._totalHeight(this._expandedLineRows[0], this._expandedLineRows[this._expandedLineRows.length - 1]);
},
+ /**
+ * @return {number}
+ */
get offsetTop()
{
return (this._expandedLineRows && this._expandedLineRows.length) ? this._expandedLineRows[0].offsetTop : this.element.offsetTop;
},
+ /**
+ * @param {number} lineNumber
+ * @return {Element}
+ */
_createRow: function(lineNumber)
{
- var lineRow = this._textViewer._cachedRows.pop() || document.createElement("div");
+ var lineRow = this._chunkedPanel._cachedRows.pop() || document.createElement("div");
lineRow.lineNumber = lineNumber;
lineRow.className = "webkit-line-content";
lineRow.textContent = this._textModel.line(lineNumber);
return lineRow;
},
+ /**
+ * @param {number} lineNumber
+ * @return {Element}
+ */
getExpandedLineRow: function(lineNumber)
{
if (!this._expanded || lineNumber < this.startLine || lineNumber >= this.startLine + this.linesCount)