This commit is contained in:
Tom Tasche 2011-02-02 14:00:37 +01:00
commit 33642f84cc
55 changed files with 16437 additions and 1497 deletions

View file

@ -41,8 +41,7 @@ var oop = require("pilot/oop");
var EventEmitter = require("pilot/event_emitter").EventEmitter;
var BackgroundTokenizer = function(tokenizer, editor) {
this.running = false;
this.doc = [];
this.running = false;
this.lines = [];
this.currentLine = 0;
this.tokenizer = tokenizer;
@ -134,6 +133,9 @@ var BackgroundTokenizer = function(tokenizer, editor) {
};
this.$tokenizeRows = function(firstRow, lastRow) {
if (!this.doc)
return [];
var rows = [];
// determine start state

View file

@ -1,15 +1,15 @@
.ace_editor {
position: absolute;
overflow: hidden;
position: absolute;
overflow: hidden;
font-family: "Menlo", "Monaco", "Courier New", monospace;
font-size: 12px;
font-family: "Menlo", "Monaco", "Courier New", monospace;
font-size: 12px;
}
.ace_scroller {
position: absolute;
overflow-x: scroll;
overflow-y: hidden;
position: absolute;
overflow-x: scroll;
overflow-y: hidden;
}
.ace_content {
@ -27,10 +27,10 @@
}
.ace_gutter {
position: absolute;
overflow-x: hidden;
overflow-y: hidden;
height: 100%;
position: absolute;
overflow-x: hidden;
overflow-y: hidden;
height: 100%;
}
.ace_gutter-cell.ace_error {
@ -46,57 +46,59 @@
}
.ace_editor .ace_sb {
position: absolute;
overflow-x: hidden;
overflow-y: scroll;
right: 0;
position: absolute;
overflow-x: hidden;
overflow-y: scroll;
right: 0;
}
.ace_editor .ace_sb div {
position: absolute;
width: 1px;
left: 0px;
position: absolute;
width: 1px;
left: 0;
}
.ace_editor .ace_print_margin_layer {
z-index: 0;
position: absolute;
overflow: hidden;
margin: 0px;
left: 0px;
height: 100%;
width: 100%;
z-index: 0;
position: absolute;
overflow: hidden;
margin: 0;
left: 0;
height: 100%;
width: 100%;
}
.ace_editor .ace_print_margin {
position: absolute;
height: 100%;
position: absolute;
height: 100%;
}
.ace_editor textarea {
position: "absolute";
z-index: -1;
opacity: 0;
width: 10px;
height: 30px;
border: none;
resize: none;
outline: none;
overflow: hidden;
position: fixed;
z-index: -1;
width: 10px;
height: 30px;
opacity: 0;
background: transparent;
appearance: none;
border: none;
resize: none;
outline: none;
overflow: hidden;
}
.ace_layer {
z-index: 1;
position: absolute;
overflow: hidden;
white-space: nowrap;
height: 100%;
width: 100%;
z-index: 1;
position: absolute;
overflow: hidden;
white-space: nowrap;
height: 100%;
width: 100%;
}
.ace_text-layer {
font-family: Monaco, "Courier New", monospace;
color: black;
font-family: Monaco, "Courier New", monospace;
color: black;
}
.ace_cjk {
@ -105,39 +107,39 @@
}
.ace_cursor-layer {
z-index: 4;
cursor: text;
pointer-events: none;
z-index: 4;
cursor: text;
pointer-events: none;
}
.ace_cursor {
z-index: 4;
position: absolute;
z-index: 4;
position: absolute;
}
.ace_line {
white-space: nowrap;
white-space: nowrap;
}
.ace_marker-layer {
}
.ace_marker-layer .ace_step {
position: absolute;
z-index: 3;
position: absolute;
z-index: 3;
}
.ace_marker-layer .ace_selection {
position: absolute;
z-index: 4;
position: absolute;
z-index: 4;
}
.ace_marker-layer .ace_bracket {
position: absolute;
z-index: 5;
position: absolute;
z-index: 5;
}
.ace_marker-layer .ace_active_line {
position: absolute;
z-index: 2;
position: absolute;
z-index: 2;
}

View file

@ -57,8 +57,8 @@ var Document = function(text) {
this.setValue = function(text) {
var len = this.getLength();
this.remove(new Range(0, 0, len, this.getLine(len-1).length));
this.insertLines(0, this.$split(text));
this.remove(new Range(0, 0, len, this.getLine(len-1).length));
this.insert({row: 0, column:0}, text);
};
this.getValue = function() {
@ -262,14 +262,20 @@ var Document = function(text) {
var firstRow = range.start.row;
var lastRow = range.end.row;
if (range.isMultiLine()) {
// TODO removeInLine can be optimized away!
this.removeInLine(lastRow, 0, range.end.column);
if (lastRow - firstRow >= 2)
this.removeLines(firstRow + 1, lastRow - 1);
this.removeInLine(firstRow, range.start.column, this.$lines[firstRow].length);
this.removeNewLine(range.start.row);
if (range.isMultiLine()) {
var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
var lastFullRow = lastRow - 1;
if (range.end.column > 0)
this.removeInLine(lastRow, 0, range.end.column);
if (lastFullRow >= firstFullRow)
this.removeLines(firstFullRow, lastFullRow);
if (firstFullRow != firstRow) {
this.removeInLine(firstRow, range.start.column, this.$lines[firstRow].length);
this.removeNewLine(range.start.row);
}
}
else {
this.removeInLine(firstRow, range.start.column, range.end.column);

View file

@ -52,9 +52,10 @@ var EditSession = function(text, mode) {
this.selection = new Selection(this);
this.$breakpoints = [];
this.$wrapData = [];
this.listeners = [];
if (text instanceof Document) {
this.setDocument(text)
this.setDocument(text);
} else {
this.setDocument(new Document(text));
}
@ -244,7 +245,8 @@ var EditSession = function(text, mode) {
};
this.tokenRe = /^[\w\d]+/g;
this.nonTokenRe = /^(?:[^\w\d|[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF])+/g
this.nonTokenRe = /^(?:[^\w\d|[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF])+/g;
this.getWordRange = function(row, column) {
var line = this.getLine(row);
@ -293,6 +295,8 @@ var EditSession = function(text, mode) {
if (window.Worker)
this.$worker = mode.createWorker(this);
else
this.$worker = null;
this.$mode = mode;
this._dispatchEvent("changeMode");
@ -504,7 +508,7 @@ var EditSession = function(text, mode) {
return {
rows: end ? end.row - rows[0] : 0,
columns: end ? end.column - column : 0
}
};
};
this.remove = function(range) {
@ -541,7 +545,7 @@ var EditSession = function(text, mode) {
if (firstDelta.action == "insertText" || firstDelta.action == "insertLines")
this.selection.moveCursorToPosition(firstDelta.range.start);
if (firstDelta.action == "removeText" || firstDelta.action == "removeLines")
this.selection.setSelectionRange(Range.fromPoints(firstDelta.range.start, lastDelta.range.end));
this.selection.setSelectionRange(Range.fromPoints(lastDelta.range.start, firstDelta.range.end));
},
this.redoChanges = function(deltas) {
@ -560,7 +564,7 @@ var EditSession = function(text, mode) {
if (firstDelta.action == "insertText" || firstDelta.action == "insertLines")
this.selection.setSelectionRange(Range.fromPoints(firstDelta.range.start, lastDelta.range.end));
if (firstDelta.action == "removeText" || firstDelta.action == "removeLines")
this.selection.moveCursorToPosition(firstDelta.range.start);
this.selection.moveCursorToPosition(lastDelta.range.start);
},
this.replace = function(range, text) {
@ -602,7 +606,7 @@ var EditSession = function(text, mode) {
this.remove(deleteRange);
}
return range;
}
};
this.moveLinesUp = function(firstRow, lastRow) {
if (firstRow <= 0) return 0;
@ -764,14 +768,14 @@ var EditSession = function(text, mode) {
addSplit(split);
} else {
// Search for the first non space/tab token.
for (split; split != lastSplit; split--) {
for (split; split != lastSplit - 1; split--) {
if (tokens[split] >= SPACE) {
split++;
break;
}
}
// If we found one, then add the split.
if (split != lastSplit) {
if (split > lastSplit) {
addSplit(split);
}
// No space or tab around? Well, force a split then.
@ -918,7 +922,7 @@ var EditSession = function(text, mode) {
/**
*
* @returns array
* - array[0]: The documentRow aquivalent.
* - array[0]: The documentRow equivalent.
* - array[1]: The screenRowOffset to the first documentRow on the screen.
*/
this.$screenToDocumentRow = function(row) {
@ -949,55 +953,77 @@ var EditSession = function(text, mode) {
var docRow;
var docColumn;
var remaining = column;
var linesCount = this.getLength();
if (!this.$useWrapMode) {
docRow = row;
docRow = row >= linesCount? linesCount-1 : (row < 0 ? 0 : row);
row = 0;
docColumn = 0;
line = this.getLine(docRow).split("\t");
line = this.getLine(docRow);
} else {
var wrapData = this.$wrapData, linesCount = this.getLength();
var wrapData = this.$wrapData;
var rowData = this.$screenToDocumentRow(row);
row = rowData[1];
docRow = rowData[0];
var docRow = 0;
while (docRow < linesCount && row >= wrapData[docRow].length + 1) {
row -= wrapData[docRow].length + 1;
docRow ++;
}
if (docRow >= linesCount) {
return {
row: docRow,
column: 0
};
docRow = linesCount-1
row = wrapData[docRow].length;
}
docColumn = wrapData[docRow][row - 1] || 0;
line = this.getLine(docRow).substring(docColumn).split("\t");
line = this.getLine(docRow).substring(docColumn);
}
var tabSize = this.getTabSize();
for (var i=0; i<line.length; i++) {
var len = line[i].length;
if (remaining >= len + tabSize) {
remaining -= (len + tabSize);
docColumn += (len + 1);
}
else if (remaining > len){
docColumn += len;
break;
}
else {
docColumn += remaining;
for(var i = 0; i < line.length; i++) {
var c = line.charCodeAt(i);
if (remaining > 0) {
docColumn += 1;
// tab
if (c == 9) {
if (remaining >= tabSize) {
remaining -= tabSize;
} else {
remaining = 0;
docColumn -= 1;
}
}
// CJK characters
else if (
c >= 0x3040 && c <= 0x309F || // Hiragana
c >= 0x30A0 && c <= 0x30FF || // Katakana
c >= 0x4E00 && c <= 0x9FFF || // Single CJK ideographs
c >= 0xF900 && c <= 0xFAFF ||
c >= 0x3400 && c <= 0x4DBF
) {
if (remaining >= 2) {
remaining -= 2;
} else {
remaining = 0;
docColumn -= 1;
}
} else {
remaining -= 1;
}
} else {
break;
}
}
// Clamp docColumn.
if (docRow < linesCount && wrapData[docRow][row]) {
if (docColumn >= wrapData[docRow][row]) {
if (this.$useWrapMode) {
column = wrapData[docRow][row]
if (docColumn >= column) {
// We remove one character at the end such that the docColumn
// position returned is not associated to the next row on the
// screen.
docColumn = wrapData[docRow][row] - 1;
docColumn = column - 1;
}
} else if (this.getLine(docRow)) {
docColumn = Math.min(docColumn, this.getLine(docRow).length);
} else if (line) {
docColumn = Math.min(docColumn, line.length);
}
return {
@ -1065,7 +1091,7 @@ var EditSession = function(text, mode) {
if (!this.$useWrapMode) {
str = this.getLine(row).substring(0, column);
column += (str.split("\t").length - 1) * (tabSize - 1);
column = this.$getStringScreenWidth(str);
return {
row: row,
column: column
@ -1085,11 +1111,10 @@ var EditSession = function(text, mode) {
var rowData = this.$documentToScreenRow(row, column);
screenRow = rowData[0];
screenRowOffset = rowData[1];
screenColumn = column - (wrapRowData[screenRowOffset - 1] || 0);
str = this.getLine(row).substring(
wrapRowData[screenRowOffset - 1] || 0, column);
screenColumn += (str.split("\t").length - 1) * (tabSize - 1);
screenColumn = this.$getStringScreenWidth(str);
return {
row: screenRow,

View file

@ -40,10 +40,15 @@
define(function(require, exports, module) {
require("pilot/fixoldbrowsers");
var oop = require("pilot/oop");
var event = require("pilot/event");
var lang = require("pilot/lang");
var useragent = require("pilot/useragent");
var TextInput = require("ace/keyboard/textinput").TextInput;
var MouseHandler = require("ace/mouse_handler").MouseHandler;
//var TouchHandler = require("ace/touch_handler").TouchHandler;
var KeyBinding = require("ace/keyboard/keybinding").KeyBinding;
var EditSession = require("ace/edit_session").EditSession;
var Search = require("ace/search").Search;
@ -58,20 +63,13 @@ var Editor =function(renderer, session) {
this.textInput = new TextInput(renderer.getTextAreaContainer(), this);
this.keyBinding = new KeyBinding(this);
var self = this;
event.addListener(container, "mousedown", function(e) {
self.focus();
return event.preventDefault(e);
});
event.addListener(container, "selectstart", function(e) {
return event.preventDefault(e);
});
var mouseTarget = renderer.getMouseEventTarget();
event.addListener(mouseTarget, "mousedown", this.onMouseDown.bind(this));
event.addMultiMouseDownListener(mouseTarget, 0, 2, 500, this.onMouseDoubleClick.bind(this));
event.addMultiMouseDownListener(mouseTarget, 0, 3, 600, this.onMouseTripleClick.bind(this));
event.addMouseWheelListener(mouseTarget, this.onMouseWheel.bind(this));
// TODO detect touch event support
if (useragent.isIPad) {
//this.$mouseHandler = new TouchHandler(this);
} else {
this.$mouseHandler = new MouseHandler(this);
}
this.$selectionMarker = null;
this.$highlightLineMarker = null;
@ -82,7 +80,6 @@ var Editor =function(renderer, session) {
});
this.setSession(session || new EditSession(""));
this.focus();
};
(function(){
@ -252,11 +249,13 @@ var Editor =function(renderer, session) {
this.onFocus = function() {
this.renderer.showCursor();
this.renderer.visualizeFocus();
this._dispatchEvent("focus");
};
this.onBlur = function() {
this.renderer.hideCursor();
this.renderer.visualizeBlur();
this._dispatchEvent("blur");
};
this.onDocumentChange = function(e) {
@ -264,7 +263,7 @@ var Editor =function(renderer, session) {
var range = delta.range;
this.bgTokenizer.start(range.start.row);
if (range.start.row == range.end.row)
if (range.start.row == range.end.row && delta.action != "insertLines" && delta.action != "removeLines")
var lastRow = range.end.row;
else
lastRow = Infinity;
@ -280,17 +279,17 @@ var Editor =function(renderer, session) {
};
this.onCursorChange = function(e) {
this.$highlightBrackets();
// move text input over the cursor
// this is required for iOS and IME
this.renderer.moveTextAreaToCursor(this.textInput.getElement());
this.renderer.updateCursor(this.getCursorPosition(), this.$overwrite);
if (!this.$blockScrolling && (!e || !e.blockScrolling)) {
this.renderer.scrollCursorIntoView();
}
// move text input over the cursor
// this is required for iOS and IME
this.renderer.moveTextAreaToCursor(this.textInput.getElement());
this.$highlightBrackets();
this.$updateHighlightActiveLine();
};
@ -349,94 +348,6 @@ var Editor =function(renderer, session) {
this.renderer.setTokenizer(this.bgTokenizer);
};
this.onMouseDown = function(e) {
var pageX = event.getDocumentX(e);
var pageY = event.getDocumentY(e);
var pos = this.renderer.screenToTextCoordinates(pageX, pageY);
pos.row = Math.max(0, Math.min(pos.row, this.session.getLength()-1));
if (event.getButton(e) != 0) {
if (this.selection.isEmpty()) {
this.moveCursorToPosition(pos);
}
return;
}
if (e.shiftKey)
this.selection.selectToPosition(pos)
else {
this.moveCursorToPosition(pos);
if (!this.$clickSelection)
this.selection.clearSelection(pos.row, pos.column);
}
this.renderer.scrollCursorIntoView();
var self = this;
var mousePageX, mousePageY;
var onMouseSelection = function(e) {
mousePageX = event.getDocumentX(e);
mousePageY = event.getDocumentY(e);
};
var onMouseSelectionEnd = function() {
clearInterval(timerId);
self.$clickSelection = null;
};
var onSelectionInterval = function() {
if (mousePageX === undefined || mousePageY === undefined)
return;
var cursor = self.renderer.screenToTextCoordinates(mousePageX, mousePageY);
cursor.row = Math.max(0, Math.min(cursor.row, self.session.getLength()-1));
if (self.$clickSelection) {
if (self.$clickSelection.contains(cursor.row, cursor.column)) {
self.selection.setSelectionRange(self.$clickSelection);
} else {
if (self.$clickSelection.compare(cursor.row, cursor.column) == -1) {
var anchor = self.$clickSelection.end;
} else {
var anchor = self.$clickSelection.start;
}
self.selection.setSelectionAnchor(anchor.row, anchor.column);
self.selection.selectToPosition(cursor);
}
}
else {
self.selection.selectToPosition(cursor);
}
self.renderer.scrollCursorIntoView();
};
event.capture(this.container, onMouseSelection, onMouseSelectionEnd);
var timerId = setInterval(onSelectionInterval, 20);
return event.preventDefault(e);
};
this.onMouseDoubleClick = function(e) {
this.selection.selectWord();
this.$clickSelection = this.getSelectionRange();
};
this.onMouseTripleClick = function(e) {
this.selection.selectLine();
this.$clickSelection = this.getSelectionRange();
};
this.onMouseWheel = function(e) {
var speed = this.$scrollSpeed * 2;
this.renderer.scrollBy(e.wheelX * speed, e.wheelY * speed);
return event.preventDefault(e);
};
this.getCopyText = function() {
if (!this.selection.isEmpty()) {
return this.session.getTextRange(this.getSelectionRange());
@ -561,15 +472,13 @@ var Editor =function(renderer, session) {
this.setOverwrite(!this.$overwrite);
};
this.$scrollSpeed = 1;
this.setScrollSpeed = function(speed) {
this.$scrollSpeed = speed;
}
this.$mouseHandler.setScrollSpeed(speed);
};
this.getScrollSpeed = function() {
return this.$scrollSpeed;
}
return this.$mouseHandler.getScrollSpeed()
};
this.$selectionStyle = "line";
this.setSelectionStyle = function(style) {
@ -580,7 +489,6 @@ var Editor =function(renderer, session) {
this._dispatchEvent("changeSelectionStyle", {data: style});
};
this.getSelectionStyle = function() {
return this.$selectionStyle;
};

View file

@ -43,6 +43,7 @@ var useragent = require("pilot/useragent");
var TextInput = function(parentNode, host) {
var text = document.createElement("textarea");
text.style.left = "-10000px";
parentNode.appendChild(text);
var PLACEHOLDER = String.fromCharCode(0);
@ -50,6 +51,7 @@ var TextInput = function(parentNode, host) {
var inCompostion = false;
var copied = false;
var tempStyle = '';
function sendText(valueToSend) {
if (!copied) {
@ -101,18 +103,25 @@ var TextInput = function(parentNode, host) {
}, 0);
};
var onCopy = function() {
var onCopy = function(e) {
copied = true;
text.value = host.getCopyText();
var copyText = host.getCopyText();
if(copyText)
text.value = copyText;
else
e.preventDefault();
text.select();
copied = true;
setTimeout(sendText, 0);
};
var onCut = function() {
var onCut = function(e) {
copied = true;
text.value = host.getCopyText();
host.onCut();
var copyText = host.getCopyText();
if(copyText) {
text.value = copyText;
host.onCut();
} else
e.preventDefault();
text.select();
setTimeout(sendText, 0);
};
@ -177,10 +186,32 @@ var TextInput = function(parentNode, host) {
this.blur = function() {
text.blur();
};
this.getElement = function() {
return text;
};
this.onContextMenu = function(mousePos, isEmpty){
if (mousePos) {
if(!tempStyle)
tempStyle = text.style.cssText;
text.style.cssText = 'position:fixed; z-index:1000;' +
'left:' + (mousePos.x - 2) + 'px; top:' + (mousePos.y - 2) + 'px;'
}
if (isEmpty)
text.value='';
}
this.onContextMenuClose = function(){
setTimeout(function () {
if (tempStyle) {
text.style.cssText = tempStyle;
tempStyle = '';
}
sendText();
}, 0);
}
};
exports.TextInput = TextInput;

View file

@ -274,12 +274,13 @@ var Text = function(parentEl) {
}
var _self = this;
var characterWidth = this.config.characterWidth;
function addToken(token, value) {
var output = value
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(spaceRe, spaceReplace)
.replace(/\t/g, this.$tabString)
.replace(/\t/g, _self.$tabString)
.replace(/[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF]/g, function(c) {
return "<span class='ace_cjk' style='width:" + (characterWidth * 2) + "px'>" + c + "</span>"
});

View file

@ -124,7 +124,7 @@ oop.inherits(Mode, TextMode);
this.createWorker = function(session) {
var doc = session.getDocument();
var worker = new WorkerClient("../..", ["ace", "pilot"], "ace/mode/javascript_worker", "JavaScriptWorker");
var worker = new WorkerClient("../..", ["ace", "pilot"], "worker-javascript.js", "ace/mode/javascript_worker", "JavaScriptWorker");
worker.call("setValue", [doc.getValue()]);
doc.on("change", function(e) {

168
lib/ace/mouse_handler.js Normal file
View file

@ -0,0 +1,168 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var event = require("pilot/event");
var MouseHandler = function(editor) {
this.editor = editor;
event.addListener(editor.container, "mousedown", function(e) {
editor.focus();
return event.preventDefault(e);
});
event.addListener(editor.container, "selectstart", function(e) {
return event.preventDefault(e);
});
var mouseTarget = editor.renderer.getMouseEventTarget();
event.addListener(mouseTarget, "mousedown", this.onMouseDown.bind(this));
event.addMultiMouseDownListener(mouseTarget, 0, 2, 500, this.onMouseDoubleClick.bind(this));
event.addMultiMouseDownListener(mouseTarget, 0, 3, 600, this.onMouseTripleClick.bind(this));
event.addMouseWheelListener(mouseTarget, this.onMouseWheel.bind(this));
};
(function() {
this.$scrollSpeed = 1;
this.setScrollSpeed = function(speed) {
this.$scrollSpeed = speed;
};
this.getScrollSpeed = function() {
return this.$scrollSpeed;
};
this.onMouseDown = function(e) {
var pageX = event.getDocumentX(e);
var pageY = event.getDocumentY(e);
var editor = this.editor;
var pos = editor.renderer.screenToTextCoordinates(pageX, pageY);
pos.row = Math.max(0, Math.min(pos.row, editor.session.getLength()-1));
var button = event.getButton(e)
if (button != 0) {
var isEmpty = editor.selection.isEmpty()
if (isEmpty) {
editor.moveCursorToPosition(pos);
}
if(button == 2) {
editor.textInput.onContextMenu({x: pageX, y: pageY}, isEmpty);
event.capture(editor.container, function(){}, editor.textInput.onContextMenuClose);
}
return;
}
if (e.shiftKey)
editor.selection.selectToPosition(pos)
else {
editor.moveCursorToPosition(pos);
if (!editor.$clickSelection)
editor.selection.clearSelection(pos.row, pos.column);
}
editor.renderer.scrollCursorIntoView();
var self = this;
var mousePageX, mousePageY;
var onMouseSelection = function(e) {
mousePageX = event.getDocumentX(e);
mousePageY = event.getDocumentY(e);
};
var onMouseSelectionEnd = function() {
clearInterval(timerId);
self.$clickSelection = null;
};
var onSelectionInterval = function() {
if (mousePageX === undefined || mousePageY === undefined)
return;
var cursor = editor.renderer.screenToTextCoordinates(mousePageX, mousePageY);
cursor.row = Math.max(0, Math.min(cursor.row, editor.session.getLength()-1));
if (self.$clickSelection) {
if (self.$clickSelection.contains(cursor.row, cursor.column)) {
self.selection.setSelectionRange(self.$clickSelection);
} else {
if (self.$clickSelection.compare(cursor.row, cursor.column) == -1) {
var anchor = self.$clickSelection.end;
} else {
var anchor = self.$clickSelection.start;
}
editor.selection.setSelectionAnchor(anchor.row, anchor.column);
editor.selection.selectToPosition(cursor);
}
}
else {
editor.selection.selectToPosition(cursor);
}
editor.renderer.scrollCursorIntoView();
};
event.capture(editor.container, onMouseSelection, onMouseSelectionEnd);
var timerId = setInterval(onSelectionInterval, 20);
return event.preventDefault(e);
};
this.onMouseDoubleClick = function(e) {
this.editor.selection.selectWord();
this.$clickSelection = this.editor.getSelectionRange();
};
this.onMouseTripleClick = function(e) {
this.editor.selection.selectLine();
this.$clickSelection = this.editor.getSelectionRange();
};
this.onMouseWheel = function(e) {
var speed = this.$scrollSpeed * 2;
this.editor.renderer.scrollBy(e.wheelX * speed, e.wheelY * speed);
return event.preventDefault(e);
};
}).call(MouseHandler.prototype);
exports.MouseHandler = MouseHandler;
});

View file

@ -37,7 +37,6 @@
* ***** END LICENSE BLOCK ***** */
var Document = require("../document").Document,
EditSession = require("../edit_session").EditSession,
Range = require("../range").Range,
assert = require("./assertions"),
async = require("asyncjs");
@ -280,68 +279,19 @@ var Test = {
doc.replace(new Range(0, 0, 2, 1), ["4", "5", "6"].join("\n"));
assert.equal(["4", "5", "6"].join("\n"), doc.getValue());
},
"test: wrapLine split function" : function() {
var splits;
var tabSize = 4;
var wrapLimit = 12;
var computeWrapSplits = EditSession.prototype.$computeWrapSplits;
var c = 0;
function computeAndAssert(line, assertEqual) {
splits = computeWrapSplits.call(EditSession.prototype, line, wrapLimit, tabSize);
// console.log("String:", line, "Result:", splits, "Expected:", assertEqual);
assert.ok(splits.length == assertEqual.length);
for (var i = 0; i < splits.length; i++) {
assert.ok(splits[i] == assertEqual[i]);
}
}
// Basic splitting.
computeAndAssert("foo bar foo bar", [ 12 ]);
computeAndAssert("foo bar f bar", [ 12 ]);
computeAndAssert("foo bar f r", [ 14 ]);
computeAndAssert("foo bar foo bar foo bara foo", [12, 25]);
// Don't split if there is only whitespaces/tabs at the end of the line.
computeAndAssert("foo foo foo \t \t", [ ]);
// If there is no space to split, force split.
computeAndAssert("foooooooooooooo", [ 12 ]);
computeAndAssert("fooooooooooooooooooooooooooo", [12, 24]);
computeAndAssert("foo bar fooooooooooobooooooo", [8, 20]);
// Basic splitting + tabs.
computeAndAssert("foo \t\tbar", [ 6 ]);
computeAndAssert("foo \t \tbar", [ 7 ]);
// Ignore spaces/tabs at beginning of split.
computeAndAssert("foo \t \t \t \t bar", [ 14 ]);
},
"test: documentToScreen": function() {
var tabSize = 4;
var wrapLimit = 12;
var session = new EditSession(["foo bar foo bar"]);
session.setUseWrapMode(true);
session.setWrapLimit(12);
assert.position(session.documentToScreenPosition(0, 11), 0, 11);
assert.position(session.documentToScreenPosition(0, 12), 1, 0);
},
"test: screenToDocument": function() {
var tabSize = 4;
var wrapLimit = 12;
var session = new EditSession(["foo bar foo bar"]);
session.setUseWrapMode(true);
session.setWrapLimit(12);
assert.position(session.screenToDocumentPosition(1, 0), 0, 12);
assert.position(session.screenToDocumentPosition(0, 11), 0, 11);
// Check if the position is clamped the right way.
assert.position(session.screenToDocumentPosition(0, 12), 0, 11);
assert.position(session.screenToDocumentPosition(0, 20), 0, 11);
"test: set value": function() {
var doc = new Document("1");
assert.equal("1", doc.getValue());
doc.setValue(doc.getValue());
assert.equal("1", doc.getValue());
var doc = new Document("1\n2");
assert.equal("1\n2", doc.getValue());
doc.setValue(doc.getValue());
assert.equal("1\n2", doc.getValue());
}
};

View file

@ -153,7 +153,7 @@ var Test = {
assert.equal(session.documentToScreenColumn(0, 13), 15);
},
"test: convert document to scrren coordinates with leading tabs": function() {
"test: convert document to screen coordinates with leading tabs": function() {
var session = new EditSession("\t\t123");
session.setTabSize(4);
@ -162,6 +162,24 @@ var Test = {
assert.equal(session.documentToScreenColumn(0, 2), 8);
assert.equal(session.documentToScreenColumn(0, 3), 9);
},
"test: documentToScreen with soft wrap and multibyte characters": function() {
var tabSize = 4;
var wrapLimit = 12;
var session = new EditSession(["foo bar foo bar"]);
session.setUseWrapMode(true);
session.setWrapLimit(12);
assert.position(session.documentToScreenPosition(0, 11), 0, 11);
assert.position(session.documentToScreenPosition(0, 12), 1, 0);
session = new EditSession(["ぁぁa"]);
session.setUseWrapMode(true);
session.setWrapLimit(2);
assert.position(session.documentToScreenPosition(0, 1), 1, 0);
assert.position(session.documentToScreenPosition(0, 2), 2, 0);
assert.position(session.documentToScreenPosition(0, 4), 2, 1);
},
"test: convert screen to document coordinates" : function() {
var session = new EditSession("01234\t567890\t1234");
@ -177,6 +195,72 @@ var Test = {
assert.equal(session.screenToDocumentColumn(0, 15), 12);
assert.equal(session.screenToDocumentColumn(0, 19), 13);
},
"test: screenToDocument with soft wrap and multi byte characters": function() {
var tabSize = 4;
var wrapLimit = 12;
var session = new EditSession(["foo bar foo bar"]);
session.setUseWrapMode(true);
session.setWrapLimit(12);
assert.position(session.screenToDocumentPosition(1, 0), 0, 12);
assert.position(session.screenToDocumentPosition(0, 11), 0, 11);
// Check if the position is clamped the right way.
assert.position(session.screenToDocumentPosition(0, 12), 0, 11);
assert.position(session.screenToDocumentPosition(0, 20), 0, 11);
session = new EditSession(["ぁ a"]);
session.setUseWrapMode(true);
assert.position(session.screenToDocumentPosition(0, 1), 0, 0);
assert.position(session.screenToDocumentPosition(0, 2), 0, 1);
assert.position(session.screenToDocumentPosition(0, 3), 0, 2);
assert.position(session.screenToDocumentPosition(0, 4), 0, 3);
assert.position(session.screenToDocumentPosition(0, 5), 0, 3);
},
"test: wrapLine split function" : function() {
var splits;
var computeWrapSplits = EditSession.prototype.$computeWrapSplits;
var c = 0;
function computeAndAssert(line, assertEqual, wrapLimit, tabSize) {
wrapLimit = wrapLimit || 12;
tabSize = tabSize || 4;
splits = computeWrapSplits.call(EditSession.prototype, line, wrapLimit, tabSize);
console.log("String:", line, "Result:", splits, "Expected:", assertEqual);
assert.ok(splits.length == assertEqual.length);
for (var i = 0; i < splits.length; i++) {
assert.ok(splits[i] == assertEqual[i]);
}
}
// Basic splitting.
computeAndAssert("foo bar foo bar", [ 12 ]);
computeAndAssert("foo bar f bar", [ 12 ]);
computeAndAssert("foo bar f r", [ 14 ]);
computeAndAssert("foo bar foo bar foo bara foo", [12, 25]);
// Don't split if there is only whitespaces/tabs at the end of the line.
computeAndAssert("foo foo foo \t \t", [ ]);
// If there is no space to split, force split.
computeAndAssert("foooooooooooooo", [ 12 ]);
computeAndAssert("fooooooooooooooooooooooooooo", [12, 24]);
computeAndAssert("foo bar fooooooooooobooooooo", [8, 20]);
// Basic splitting + tabs.
computeAndAssert("foo \t\tbar", [ 6 ]);
computeAndAssert("foo \t \tbar", [ 7 ]);
// Ignore spaces/tabs at beginning of split.
computeAndAssert("foo \t \t \t \t bar", [ 14 ]);
// Test wrapping for asian characters.
computeAndAssert("ぁぁ", [1], 2);
computeAndAssert(" ぁぁ", [1, 2], 2);
computeAndAssert(" ぁ\tぁ", [1, 3], 2);
computeAndAssert(" ぁぁ\tぁ", [1, 4], 4);
},
"test: insert text in multiple rows": function() {
var session = new EditSession(["12", "", "abcd"]);

View file

@ -71,6 +71,13 @@ MockRenderer.prototype.getMouseEventTarget = function() {
return this.container;
};
MockRenderer.prototype.getTextAreaContainer = function() {
return this.container;
};
MockRenderer.prototype.moveTextAreaToCursor = function() {
};
MockRenderer.prototype.setSession = function(session) {
this.session = session;
};

View file

@ -20,7 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Fabian Jakobs <fabian@ajax.org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
* Julian Viereck <julian.viereck@gmail.com>
*
@ -43,6 +43,7 @@ define(function(require, exports, module) {
var oop = require("pilot/oop");
var dom = require("pilot/dom");
var event = require("pilot/event");
var useragent = require("pilot/useragent");
var GutterLayer = require("ace/layer/gutter").Gutter;
var MarkerLayer = require("ace/layer/marker").Marker;
var TextLayer = require("ace/layer/text").Text;
@ -96,12 +97,13 @@ var VirtualRenderer = function(container, theme) {
column : 0
};
var self = this;
var _self = this;
this.$textLayer.addEventListener("changeCharaterSize", function() {
self.characterWidth = textLayer.getCharacterWidth();
self.lineHeight = textLayer.getLineHeight();
_self.characterWidth = textLayer.getCharacterWidth();
_self.lineHeight = textLayer.getLineHeight();
_self.$updatePrintMargin();
self.$loop.schedule(self.CHANGE_FULL);
_self.$loop.schedule(_self.CHANGE_FULL);
});
event.addListener(this.$gutter, "click", this.$onGutterClick.bind(this));
event.addListener(this.$gutter, "dblclick", this.$onGutterClick.bind(this));
@ -272,6 +274,7 @@ var VirtualRenderer = function(container, theme) {
if (!this.$showPrintMargin && !this.$printMarginEl)
return;
if (!this.$printMarginEl) {
containerEl = document.createElement("div");
containerEl.className = "ace_print_margin_layer";
@ -295,16 +298,23 @@ var VirtualRenderer = function(container, theme) {
};
this.getTextAreaContainer = function() {
return this.scroller;
return this.container;
};
this.moveTextAreaToCursor = function(textarea) {
this.moveTextAreaToCursor = function(textarea) {
// in IE the native cursor always shines through
if (useragent.isIE)
return;
var pos = this.$cursorLayer.getPixelPosition();
if (!pos)
return;
textarea.style.left = (pos.left + this.$padding) + "px";
textarea.style.top = pos.top + "px";
var bounds = this.content.getBoundingClientRect();
var offset = (this.layerConfig && this.layerConfig.offset) || 0;
textarea.style.left = (bounds.left + pos.left + this.$padding) + "px";
textarea.style.top = (bounds.top + pos.top - this.scrollTop + offset) + "px";
};
this.getFirstVisibleRow = function() {

View file

@ -11,12 +11,12 @@ define(function(require, exports, module) {
var oop = require("pilot/oop");
var EventEmitter = require("pilot/event_emitter").EventEmitter;
var WorkerClient = function(baseUrl, topLevelNamespaces, module, classname) {
var WorkerClient = function(baseUrl, topLevelNamespaces, packagedJs, module, classname) {
this.callbacks = [];
if (require.packaged) {
var worker = this.$worker = new Worker("worker.js");
var worker = this.$worker = new Worker(packagedJs);
}
else {
var workerUrl = require.nameToUrl("ace/worker/worker", null, "_");