diff --git a/lib/ace/css/editor.css b/lib/ace/css/editor.css
index 5a544076..11831f03 100644
--- a/lib/ace/css/editor.css
+++ b/lib/ace/css/editor.css
@@ -36,6 +36,12 @@
z-index: 1000;
}
+.ace_gutter_active_line {
+ position: absolute;
+ right: 0;
+ width: 100%;
+}
+
.ace_gutter.horscroll {
box-shadow: 0px 0px 20px rgba(0,0,0,0.4);
}
@@ -94,8 +100,8 @@
.ace_editor textarea {
position: fixed;
z-index: 0;
- width: 10px;
- height: 30px;
+ width: 0.5em;
+ height: 1em;
opacity: 0;
background: transparent;
appearance: none;
diff --git a/lib/ace/editor.js b/lib/ace/editor.js
index 851c314a..85d7076b 100644
--- a/lib/ace/editor.js
+++ b/lib/ace/editor.js
@@ -80,6 +80,7 @@ var Editor = function(renderer, session) {
this.commands = new CommandManager(useragent.isMac ? "mac" : "win", defaultCommands);
this.textInput = new TextInput(renderer.getTextAreaContainer(), this);
+ this.renderer.textarea = this.textInput.getElement();
this.keyBinding = new KeyBinding(this);
// TODO detect touch event support
@@ -385,11 +386,7 @@ var Editor = function(renderer, session) {
this.$cursorChange = function() {
this.renderer.updateCursor();
-
- // move text input over the cursor
- // this is required for iOS and IME
- this.renderer.moveTextAreaToCursor(this.textInput.getElement());
- }
+ };
/**
* Editor@onDocumentChange(e)
@@ -458,7 +455,6 @@ var Editor = function(renderer, session) {
this.$highlightBrackets();
this.$updateHighlightActiveLine();
- this.$updateHighlightGutterLine();
};
/** internal, hide
@@ -490,21 +486,6 @@ var Editor = function(renderer, session) {
}
};
- /** internal, hide
- * Editor.$updateHighlightGutterLine()
- *
- *
- **/
- this.$updateHighlightGutterLine = function(){
- if (typeof this.$lastrow == "number")
- this.renderer.removeGutterDecoration(this.$lastrow, "ace_gutter_active_line");
-
- this.$lastrow = null;
-
- if (this.$highlightGutterLine)
- this.renderer.addGutterDecoration(
- this.$lastrow = this.getCursorPosition().row, "ace_gutter_active_line");
- }
/**
* Editor@onSelectionChange(e)
@@ -526,7 +507,6 @@ var Editor = function(renderer, session) {
session.$selectionMarker = session.addMarker(range, "ace_selection", style);
} else {
this.$updateHighlightActiveLine();
- this.$updateHighlightGutterLine();
}
if (this.$highlightSelectedWord)
@@ -605,7 +585,6 @@ var Editor = function(renderer, session) {
// Update the active line marker as due to folding changes the current
// line range on the screen might have changed.
this.$updateHighlightActiveLine();
- this.$updateHighlightGutterLine();
// TODO: This might be too much updating. Okay for now.
this.renderer.updateFull();
};
@@ -891,12 +870,11 @@ var Editor = function(renderer, session) {
};
this.$highlightGutterLine = true;
- this.setHighlightGutterLine = function(shouldHighlightGutterLine) {
- if (this.$highlightGutterLine == shouldHighlightGutterLine)
+ this.setHighlightGutterLine = function(shouldHighlight) {
+ if (this.$highlightGutterLine == shouldHighlight)
return;
- this.$highlightGutterLine = shouldHighlightGutterLine;
- this.$updateHighlightGutterLine();
+ this.renderer.setHighlightGutterLine(shouldHighlight);
};
this.getHighlightGutterLine = function() {
diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js
index 10f12865..fa570e66 100644
--- a/lib/ace/keyboard/textinput.js
+++ b/lib/ace/keyboard/textinput.js
@@ -49,7 +49,9 @@ var TextInput = function(parentNode, host) {
var text = dom.createElement("textarea");
if (useragent.isTouchPad)
text.setAttribute("x-palm-disable-auto-cap", true);
-
+
+ text.setAttribute("wrap", "off");
+
text.style.left = "-10000px";
text.style.position = "fixed";
parentNode.insertBefore(text, parentNode.firstChild);
diff --git a/lib/ace/layer/cursor.js b/lib/ace/layer/cursor.js
index 1c55d7a8..f43b36b7 100644
--- a/lib/ace/layer/cursor.js
+++ b/lib/ace/layer/cursor.js
@@ -175,6 +175,9 @@ var Cursor = function(parentEl) {
if (overwrite != this.overwrite)
this.$setOverite(overwrite);
+ // cache for textarea and gutter highlight
+ this.$pixelPos = pixelPos;
+
this.restartTimer();
};
diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js
index e4069659..bb8d733d 100644
--- a/lib/ace/layer/text.js
+++ b/lib/ace/layer/text.js
@@ -395,9 +395,9 @@ var Text = function(parentEl) {
if (a) {
return new Array(c.length+1).join(" ");
} else if (c == "&") {
- return useragent.isOldGecko ? "&" : "&";
+ return "&";
} else if (c == "<") {
- return "<";
+ return "<";
} else if (c == "\t") {
var tabSize = self.session.getScreenTabSize(screenColumn + tabIdx);
screenColumn += tabSize - 1;
@@ -411,10 +411,7 @@ var Text = function(parentEl) {
(self.config.characterWidth * 2) +
"px'>" + space + "";
} else if (b) {
- if (self.showInvisibles)
- return "" + self.SPACE_CHAR + "";
- else
- return " ";
+ return "" + self.SPACE_CHAR + "";
} else {
screenColumn += 1;
return " lead.row || (anchor.row == lead.row && anchor.column > lead.column));
};
@@ -203,8 +203,8 @@ var Selection = function(session) {
* [Returns the [[Range `Range`]] for the selected text.]{: #Selection.getRange}
**/
this.getRange = function() {
- var anchor = this.selectionAnchor;
- var lead = this.selectionLead;
+ var anchor = this.anchor;
+ var lead = this.lead;
if (this.isEmpty())
return Range.fromPoints(lead, lead);
@@ -249,18 +249,23 @@ var Selection = function(session) {
*
**/
this.setSelectionRange = function(range, reverse) {
- if (reverse) {
- this.setSelectionAnchor(range.end.row, range.end.column);
- this.selectTo(range.start.row, range.start.column);
+ if (range.isEmpty()) {
+ this.lead.setPosition(range.start.row, range.start.column);
+ this.clearSelection();
+ } else if (reverse) {
+ this.$isEmpty = false;
+ this.anchor.setPosition(range.end.row, range.end.column);
+ this.lead.setPosition(range.start.row, range.start.column);
} else {
- this.setSelectionAnchor(range.start.row, range.start.column);
- this.selectTo(range.end.row, range.end.column);
+ this.$isEmpty = false;
+ this.anchor.setPosition(range.start.row, range.start.column);
+ this.lead.setPosition(range.end.row, range.end.column);
}
this.$desiredColumn = null;
};
this.$moveSelection = function(mover) {
- var lead = this.selectionLead;
+ var lead = this.lead;
if (this.$isEmpty)
this.setSelectionAnchor(lead.row, lead.column);
@@ -391,7 +396,7 @@ var Selection = function(session) {
**/
this.getWordRange = function(row, column) {
if (typeof column == "undefined") {
- var cursor = row || this.selectionLead;
+ var cursor = row || this.lead;
row = cursor.row;
column = cursor.column;
}
@@ -414,7 +419,7 @@ var Selection = function(session) {
};
this.getLineRange = function(row, excludeLastChar) {
- var rowStart = typeof row == "number" ? row : this.selectionLead.row;
+ var rowStart = typeof row == "number" ? row : this.lead.row;
var rowEnd;
var foldLine = this.session.getFoldLine(rowStart);
@@ -463,7 +468,7 @@ var Selection = function(session) {
* Moves the cursor left one column.
**/
this.moveCursorLeft = function() {
- var cursor = this.selectionLead.getPosition(),
+ var cursor = this.lead.getPosition(),
fold;
if (fold = this.session.getFoldAt(cursor.row, cursor.column, -1)) {
@@ -489,19 +494,19 @@ var Selection = function(session) {
* Moves the cursor right one column.
**/
this.moveCursorRight = function() {
- var cursor = this.selectionLead.getPosition(),
+ var cursor = this.lead.getPosition(),
fold;
if (fold = this.session.getFoldAt(cursor.row, cursor.column, 1)) {
this.moveCursorTo(fold.end.row, fold.end.column);
}
- else if (this.selectionLead.column == this.doc.getLine(this.selectionLead.row).length) {
- if (this.selectionLead.row < this.doc.getLength() - 1) {
- this.moveCursorTo(this.selectionLead.row + 1, 0);
+ else if (this.lead.column == this.doc.getLine(this.lead.row).length) {
+ if (this.lead.row < this.doc.getLength() - 1) {
+ this.moveCursorTo(this.lead.row + 1, 0);
}
}
else {
var tabSize = this.session.getTabSize();
- var cursor = this.selectionLead;
+ var cursor = this.lead;
if (this.session.isTabStop(cursor) && this.doc.getLine(cursor.row).slice(cursor.column, cursor.column+tabSize).split(" ").length-1 == tabSize)
this.moveCursorBy(0, tabSize);
else
@@ -515,8 +520,8 @@ var Selection = function(session) {
* Moves the cursor to the start of the line.
**/
this.moveCursorLineStart = function() {
- var row = this.selectionLead.row;
- var column = this.selectionLead.column;
+ var row = this.lead.row;
+ var column = this.lead.column;
var screenRow = this.session.documentToScreenRow(row, column);
// Determ the doc-position of the first character at the screen line.
@@ -548,7 +553,7 @@ var Selection = function(session) {
* Moves the cursor to the end of the line.
**/
this.moveCursorLineEnd = function() {
- var lead = this.selectionLead;
+ var lead = this.lead;
var lastRowColumnPosition =
this.session.getDocumentLastRowColumnPosition(lead.row, lead.column);
this.moveCursorTo(
@@ -583,8 +588,8 @@ var Selection = function(session) {
* Moves the cursor to the word on the right.
**/
this.moveCursorLongWordRight = function() {
- var row = this.selectionLead.row;
- var column = this.selectionLead.column;
+ var row = this.lead.row;
+ var column = this.lead.column;
var line = this.doc.getLine(row);
var rightOfCursor = line.substring(column);
@@ -630,8 +635,8 @@ var Selection = function(session) {
* Moves the cursor to the word on the left.
**/
this.moveCursorLongWordLeft = function() {
- var row = this.selectionLead.row;
- var column = this.selectionLead.column;
+ var row = this.lead.row;
+ var column = this.lead.column;
// skip folds
var fold;
@@ -712,8 +717,8 @@ var Selection = function(session) {
};
this.moveCursorShortWordRight = function() {
- var row = this.selectionLead.row;
- var column = this.selectionLead.column;
+ var row = this.lead.row;
+ var column = this.lead.column;
var line = this.doc.getLine(row);
var rightOfCursor = line.substring(column);
@@ -730,8 +735,8 @@ var Selection = function(session) {
};
this.moveCursorShortWordLeft = function() {
- var row = this.selectionLead.row;
- var column = this.selectionLead.column;
+ var row = this.lead.row;
+ var column = this.lead.column;
var fold;
if (fold = this.session.getFoldAt(row, column, -1))
@@ -770,8 +775,8 @@ var Selection = function(session) {
**/
this.moveCursorBy = function(rows, chars) {
var screenPos = this.session.documentToScreenPosition(
- this.selectionLead.row,
- this.selectionLead.column
+ this.lead.row,
+ this.lead.column
);
if (chars === 0) {
@@ -814,7 +819,7 @@ var Selection = function(session) {
}
this.$keepDesiredColumnOnChange = true;
- this.selectionLead.setPosition(row, column);
+ this.lead.setPosition(row, column);
this.$keepDesiredColumnOnChange = false;
if (!keepDesiredColumn)
@@ -836,8 +841,8 @@ var Selection = function(session) {
// remove listeners from document
this.detach = function() {
- this.selectionLead.detach();
- this.selectionAnchor.detach();
+ this.lead.detach();
+ this.anchor.detach();
this.session = this.doc = null;
}
diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js
index 69909c6a..fdff0160 100644
--- a/lib/ace/virtual_renderer.js
+++ b/lib/ace/virtual_renderer.js
@@ -82,6 +82,9 @@ var VirtualRenderer = function(container, theme) {
// TODO: this breaks rendering in Cloud9 with multiple ace instances
// // Imports CSS once per DOM document ('ace_editor' serves as an identifier).
// dom.importCssString(editorCss, "ace_editor", container.ownerDocument);
+
+ // in IE <= 9 the native cursor always shines through
+ this.$keepTextAreaAtCursor = !useragent.isIE;
dom.addCssClass(container, "ace_editor");
@@ -99,6 +102,7 @@ var VirtualRenderer = function(container, theme) {
this.content.className = "ace_content";
this.scroller.appendChild(this.content);
+ this.setHighlightGutterLine(true);
this.$gutterLayer = new GutterLayer(this.$gutter);
this.$gutterLayer.on("changeGutterWidth", this.onResize.bind(this, true));
this.setFadeFoldWidgets(true);
@@ -449,6 +453,33 @@ var VirtualRenderer = function(container, theme) {
dom.removeCssClass(this.$gutter, "ace_fade-fold-widgets");
};
+ this.$highlightGutterLine = false;
+ this.setHighlightGutterLine = function(shouldHighlight) {
+ if (this.$highlightGutterLine == shouldHighlight)
+ return;
+ this.$highlightGutterLine = shouldHighlight;
+
+
+ if (!this.$gutterLineHighlight) {
+ this.$gutterLineHighlight = dom.createElement("div");
+ this.$gutterLineHighlight.className = "ace_gutter_active_line";
+ this.$gutter.appendChild(this.$gutterLineHighlight);
+ return;
+ }
+
+ this.$gutterLineHighlight.style.display = shouldHighlight ? "" : "none";
+ this.$updateGutterLineHighlight();
+ };
+
+ this.getHighlightGutterLine = function() {
+ return this.$highlightGutterLine;
+ };
+
+ this.$updateGutterLineHighlight = function() {
+ this.$gutterLineHighlight.style.top = this.$cursorLayer.$pixelPos.top + "px";
+ this.$gutterLineHighlight.style.height = this.layerConfig.lineHeight + "px";
+ };
+
this.$updatePrintMargin = function() {
var containerEl;
@@ -496,30 +527,23 @@ var VirtualRenderer = function(container, theme) {
return this.container;
};
- /**
- * VirtualRenderer.moveTextAreaToCursor(textarea) -> Void
- * - textarea (DOMElement): A text area to work with
- *
- * Changes the position of `textarea` to where the cursor is pointing.
- **/
- this.moveTextAreaToCursor = function(textarea) {
- // in IE the native cursor always shines through
- // this persists in IE9
- if (useragent.isIE)
+ // move text input over the cursor
+ // this is required for iOS and IME
+ this.$moveTextAreaToCursor = function() {
+ if (!this.$keepTextAreaAtCursor)
return;
- if (this.layerConfig.lastRow === 0)
+ var posTop = this.$cursorLayer.$pixelPos.top;
+ var posLeft = this.$cursorLayer.$pixelPos.left;
+ posTop -= this.layerConfig.offset;
+
+ if (posTop < 0 || posTop > this.layerConfig.height)
return;
- var pos = this.$cursorLayer.getPixelPosition();
- if (!pos)
- return;
-
- var bounds = this.content.getBoundingClientRect();
- var offset = this.layerConfig.offset;
-
- textarea.style.left = (bounds.left + pos.left) + "px";
- textarea.style.top = (bounds.top + pos.top - this.scrollTop + offset) + "px";
+ posLeft += (this.showGutter ? this.$gutterLayer.gutterWidth : 0) - this.scrollLeft;
+ var bounds = this.container.getBoundingClientRect();
+ this.textarea.style.left = (bounds.left + posLeft) + "px";
+ this.textarea.style.top = (bounds.top + posTop) + "px";
};
/**
@@ -640,6 +664,8 @@ var VirtualRenderer = function(container, theme) {
this.$markerBack.update(this.layerConfig);
this.$markerFront.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
+ this.$moveTextAreaToCursor();
+ this.$highlightGutterLine && this.$updateGutterLineHighlight();
return;
}
@@ -656,6 +682,8 @@ var VirtualRenderer = function(container, theme) {
this.$markerBack.update(this.layerConfig);
this.$markerFront.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
+ this.$moveTextAreaToCursor();
+ this.$highlightGutterLine && this.$updateGutterLineHighlight();
return;
}
@@ -675,8 +703,11 @@ var VirtualRenderer = function(container, theme) {
this.$gutterLayer.update(this.layerConfig);
}
- if (changes & this.CHANGE_CURSOR)
+ if (changes & this.CHANGE_CURSOR) {
this.$cursorLayer.update(this.layerConfig);
+ this.$moveTextAreaToCursor();
+ this.$highlightGutterLine && this.$updateGutterLineHighlight();
+ }
if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_FRONT)) {
this.$markerFront.update(this.layerConfig);
@@ -753,7 +784,7 @@ var VirtualRenderer = function(container, theme) {
// For debugging.
// console.log(JSON.stringify(this.layerConfig));
- this.$gutterLayer.element.style.marginTop = (-offset) + "px";
+ this.$gutter.style.marginTop = (-offset) + "px";
this.content.style.marginTop = (-offset) + "px";
this.content.style.width = longestLine + 2 * this.$padding + "px";
this.content.style.height = minHeight + "px";
@@ -1103,14 +1134,24 @@ var VirtualRenderer = function(container, theme) {
// todo: handle horizontal scrolling
};
- this.screenToTextCoordinates = function(pageX, pageY) {
+ this.pixelToScreenCoordinates = function(x, y) {
+ var canvasPos = this.scroller.getBoundingClientRect();
+
+ var offset = (x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth;
+ var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight);
+ var col = Math.round(offset);
+
+ return {row: row, column: col, side: offset - col > 0 ? 1 : -1};
+ };
+
+ this.screenToTextCoordinates = function(x, y) {
var canvasPos = this.scroller.getBoundingClientRect();
var col = Math.round(
- (pageX + this.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft()) / this.characterWidth
+ (x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth
);
var row = Math.floor(
- (pageY + this.scrollTop - canvasPos.top - dom.getPageScrollTop()) / this.lineHeight
+ (y + this.scrollTop - canvasPos.top) / this.lineHeight
);
return this.session.screenToDocumentPosition(row, Math.max(col, 0));