fix textinput and contextmenu
This commit is contained in:
parent
972a33a518
commit
1de8c413c6
5 changed files with 110 additions and 101 deletions
|
|
@ -18,13 +18,6 @@
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ace_composition {
|
|
||||||
position: absolute;
|
|
||||||
background: #555;
|
|
||||||
color: #DDD;
|
|
||||||
z-index: 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ace_gutter {
|
.ace_gutter {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
overflow : hidden;
|
overflow : hidden;
|
||||||
|
|
@ -95,8 +88,8 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ace_editor textarea {
|
.ace_editor > textarea {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
width: 0.5em;
|
width: 0.5em;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
|
|
@ -110,6 +103,15 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ace_editor > textarea.ace_composition {
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
z-index: 1000;
|
||||||
|
opacity: 1;
|
||||||
|
border: solid lightgray 1px;
|
||||||
|
margin: -1px
|
||||||
|
}
|
||||||
|
|
||||||
.ace_layer {
|
.ace_layer {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
||||||
|
|
@ -45,18 +45,22 @@ var useragent = require("../lib/useragent");
|
||||||
var dom = require("../lib/dom");
|
var dom = require("../lib/dom");
|
||||||
|
|
||||||
var TextInput = function(parentNode, host) {
|
var TextInput = function(parentNode, host) {
|
||||||
|
|
||||||
var text = dom.createElement("textarea");
|
var text = dom.createElement("textarea");
|
||||||
|
/*/ debug
|
||||||
|
text.style.opacity = 1
|
||||||
|
text.style.background = "rgba(0, 250, 0, 0.3)"
|
||||||
|
text.style.outline = "rgba(0, 250, 0, 0.8) solid 1px"
|
||||||
|
text.style.outlineOffset = "3px"
|
||||||
|
/**/
|
||||||
if (useragent.isTouchPad)
|
if (useragent.isTouchPad)
|
||||||
text.setAttribute("x-palm-disable-auto-cap", true);
|
text.setAttribute("x-palm-disable-auto-cap", true);
|
||||||
|
|
||||||
text.setAttribute("wrap", "off");
|
text.setAttribute("wrap", "off");
|
||||||
|
|
||||||
text.style.left = "-10000px";
|
text.style.top = "-2em";
|
||||||
text.style.position = "fixed";
|
|
||||||
parentNode.insertBefore(text, parentNode.firstChild);
|
parentNode.insertBefore(text, parentNode.firstChild);
|
||||||
|
|
||||||
var PLACEHOLDER = String.fromCharCode(0);
|
var PLACEHOLDER = useragent.isIE ? "\x01" : "\x01";
|
||||||
sendText();
|
sendText();
|
||||||
|
|
||||||
var inCompostion = false;
|
var inCompostion = false;
|
||||||
|
|
@ -64,9 +68,14 @@ var TextInput = function(parentNode, host) {
|
||||||
var pasted = false;
|
var pasted = false;
|
||||||
var tempStyle = '';
|
var tempStyle = '';
|
||||||
|
|
||||||
function select() {
|
function reset(full) {
|
||||||
try {
|
try {
|
||||||
text.select();
|
if (full) {
|
||||||
|
text.value = PLACEHOLDER;
|
||||||
|
text.selectionStart = 0;
|
||||||
|
text.selectionEnd = 1;
|
||||||
|
} else
|
||||||
|
text.select();
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,11 +96,6 @@ var TextInput = function(parentNode, host) {
|
||||||
else
|
else
|
||||||
host.onTextInput(value);
|
host.onTextInput(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If editor is no longer focused we quit immediately, since
|
|
||||||
// it means that something else is in charge now.
|
|
||||||
if (!isFocused())
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,19 +103,19 @@ var TextInput = function(parentNode, host) {
|
||||||
pasted = false;
|
pasted = false;
|
||||||
|
|
||||||
// Safari doesn't fire copy events if no text is selected
|
// Safari doesn't fire copy events if no text is selected
|
||||||
text.value = PLACEHOLDER;
|
reset(true);
|
||||||
select();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var onTextInput = function(e) {
|
var onTextInput = function(e) {
|
||||||
|
if (!inCompostion)
|
||||||
|
sendText(e.data);
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
if (!inCompostion)
|
if (!inCompostion)
|
||||||
sendText(e.data);
|
reset(true);
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
var onPropertyChange = function(e) {
|
var onPropertyChange = function(e) {
|
||||||
if (useragent.isOldIE && text.value.charCodeAt(0) > 128) return;
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
if (!inCompostion)
|
if (!inCompostion)
|
||||||
sendText();
|
sendText();
|
||||||
|
|
@ -121,7 +125,7 @@ var TextInput = function(parentNode, host) {
|
||||||
var onCompositionStart = function(e) {
|
var onCompositionStart = function(e) {
|
||||||
inCompostion = true;
|
inCompostion = true;
|
||||||
host.onCompositionStart();
|
host.onCompositionStart();
|
||||||
if (!useragent.isGecko) setTimeout(onCompositionUpdate, 0);
|
setTimeout(onCompositionUpdate, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
var onCompositionUpdate = function() {
|
var onCompositionUpdate = function() {
|
||||||
|
|
@ -141,12 +145,12 @@ var TextInput = function(parentNode, host) {
|
||||||
text.value = copyText;
|
text.value = copyText;
|
||||||
else
|
else
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
select();
|
reset();
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
sendText();
|
sendText();
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
var onCut = function(e) {
|
var onCut = function(e) {
|
||||||
copied = true;
|
copied = true;
|
||||||
var copyText = host.getCopyText();
|
var copyText = host.getCopyText();
|
||||||
|
|
@ -155,31 +159,15 @@ var TextInput = function(parentNode, host) {
|
||||||
host.onCut();
|
host.onCut();
|
||||||
} else
|
} else
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
select();
|
reset();
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
sendText();
|
sendText();
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
|
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
|
||||||
|
event.addListener(text, "input", useragent.isIE ? onPropertyChange : onTextInput);
|
||||||
|
|
||||||
if (useragent.isOldIE) {
|
|
||||||
var keytable = { 13:1, 27:1 };
|
|
||||||
event.addListener(text, "keyup", function (e) {
|
|
||||||
if (inCompostion && (!text.value || keytable[e.keyCode]))
|
|
||||||
setTimeout(onCompositionEnd, 0);
|
|
||||||
if ((text.value.charCodeAt(0)|0) < 129) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
inCompostion ? onCompositionUpdate() : onCompositionStart();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("onpropertychange" in text && !("oninput" in text))
|
|
||||||
event.addListener(text, "propertychange", onPropertyChange);
|
|
||||||
else
|
|
||||||
event.addListener(text, "input", onTextInput);
|
|
||||||
|
|
||||||
event.addListener(text, "paste", function(e) {
|
event.addListener(text, "paste", function(e) {
|
||||||
// Mark that the next input text comes from past.
|
// Mark that the next input text comes from past.
|
||||||
pasted = true;
|
pasted = true;
|
||||||
|
|
@ -198,6 +186,8 @@ var TextInput = function(parentNode, host) {
|
||||||
|
|
||||||
if ("onbeforecopy" in text && typeof clipboardData !== "undefined") {
|
if ("onbeforecopy" in text && typeof clipboardData !== "undefined") {
|
||||||
event.addListener(text, "beforecopy", function(e) {
|
event.addListener(text, "beforecopy", function(e) {
|
||||||
|
if (tempStyle)
|
||||||
|
return; // without this text is copied when contextmenu is shown
|
||||||
var copyText = host.getCopyText();
|
var copyText = host.getCopyText();
|
||||||
if (copyText)
|
if (copyText)
|
||||||
clipboardData.setData("Text", copyText);
|
clipboardData.setData("Text", copyText);
|
||||||
|
|
@ -214,6 +204,7 @@ var TextInput = function(parentNode, host) {
|
||||||
event.preventDefault(e);
|
event.preventDefault(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
event.addListener(text, "cut", onCut); // for ie9 context menu
|
||||||
}
|
}
|
||||||
else if (useragent.isOpera) {
|
else if (useragent.isOpera) {
|
||||||
event.addListener(parentNode, "keydown", function(e) {
|
event.addListener(parentNode, "keydown", function(e) {
|
||||||
|
|
@ -251,12 +242,12 @@ var TextInput = function(parentNode, host) {
|
||||||
|
|
||||||
event.addListener(text, "focus", function() {
|
event.addListener(text, "focus", function() {
|
||||||
host.onFocus();
|
host.onFocus();
|
||||||
select();
|
reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.focus = function() {
|
this.focus = function() {
|
||||||
host.onFocus();
|
host.onFocus();
|
||||||
select();
|
reset();
|
||||||
text.focus();
|
text.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -273,28 +264,50 @@ var TextInput = function(parentNode, host) {
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onContextMenu = function(mousePos, isEmpty){
|
this.onContextMenu = function(e) {
|
||||||
if (mousePos) {
|
if (!tempStyle)
|
||||||
if (!tempStyle)
|
tempStyle = text.style.cssText;
|
||||||
tempStyle = text.style.cssText;
|
|
||||||
|
text.style.cssText =
|
||||||
text.style.cssText =
|
"position:fixed; z-index:100000;" + //"background:rgba(250, 0, 0, 0.3); opacity:1;" +
|
||||||
'position:fixed; z-index:1000;' +
|
"left:" + (e.clientX - 2) + "px; top:" + (e.clientY - 2) + "px;";
|
||||||
'left:' + (mousePos.x - 2) + 'px; top:' + (mousePos.y - 2) + 'px;';
|
|
||||||
}
|
if (host.selection.isEmpty())
|
||||||
if (isEmpty)
|
text.value = "";
|
||||||
text.value='';
|
|
||||||
|
if (e.type != "mousedown")
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (host.renderer.$keepTextAreaAtCursor)
|
||||||
|
host.renderer.$keepTextAreaAtCursor = null;
|
||||||
|
|
||||||
|
event.capture(host.container, function(e) {
|
||||||
|
text.style.left = e.clientX - 2 + "px";
|
||||||
|
text.style.top = e.clientY - 2 + "px";
|
||||||
|
}, onContextMenuClose);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onContextMenuClose = function(){
|
function onContextMenuClose() {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
if (tempStyle) {
|
if (tempStyle) {
|
||||||
text.style.cssText = tempStyle;
|
text.style.cssText = tempStyle;
|
||||||
tempStyle = '';
|
tempStyle = '';
|
||||||
}
|
}
|
||||||
sendText();
|
sendText();
|
||||||
|
if (host.renderer.$keepTextAreaAtCursor == null) {
|
||||||
|
host.renderer.$keepTextAreaAtCursor = true;
|
||||||
|
host.renderer.$moveTextAreaToCursor();
|
||||||
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
this.onContextMenuClose = onContextMenuClose;
|
||||||
|
|
||||||
|
// firefox fires contextmenu event after opening it
|
||||||
|
if (!useragent.isGecko)
|
||||||
|
event.addListener(text, "contextmenu", function(e) {
|
||||||
|
host.textInput.onContextMenu(e);
|
||||||
|
onContextMenuClose()
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.TextInput = TextInput;
|
exports.TextInput = TextInput;
|
||||||
|
|
|
||||||
|
|
@ -80,26 +80,19 @@ function DefaultHandlers(mouseHandler) {
|
||||||
var editor = this.editor;
|
var editor = this.editor;
|
||||||
var _self = this;
|
var _self = this;
|
||||||
|
|
||||||
this.ev = ev
|
|
||||||
var selectionRange = editor.getSelectionRange();
|
|
||||||
var selectionEmpty = selectionRange.isEmpty();
|
|
||||||
|
|
||||||
var button = ev.getButton();
|
var button = ev.getButton();
|
||||||
if (button !== 0) {
|
if (button !== 0) {
|
||||||
|
var selectionRange = editor.getSelectionRange();
|
||||||
|
var selectionEmpty = selectionRange.isEmpty();
|
||||||
|
|
||||||
if (selectionEmpty) {
|
if (selectionEmpty) {
|
||||||
editor.moveCursorToPosition(pos);
|
editor.moveCursorToPosition(pos);
|
||||||
editor.selection.clearSelection();
|
editor.selection.clearSelection();
|
||||||
}
|
}
|
||||||
// 2: contextmenu, 1: linux paste
|
|
||||||
this.moveTextarea = function() {
|
|
||||||
editor.textInput.onContextMenu({x: _self.x, y: _self.y});
|
|
||||||
};
|
|
||||||
this.moveTextareaEnd = editor.textInput.onContextMenuClose;
|
|
||||||
|
|
||||||
editor.textInput.onContextMenu({x: this.x, y: this.y}, selectionEmpty);
|
|
||||||
this.captureMouse(ev, "moveTextarea");
|
|
||||||
|
|
||||||
return;
|
// 2: contextmenu, 1: linux paste
|
||||||
|
editor.textInput.onContextMenu(ev.domEvent);
|
||||||
|
return ev.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this click caused the editor to be focused should not clear the
|
// if this click caused the editor to be focused should not clear the
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,6 @@ var MouseHandler = function(editor) {
|
||||||
editor.focus();
|
editor.focus();
|
||||||
return event.preventDefault(e);
|
return event.preventDefault(e);
|
||||||
});
|
});
|
||||||
event.addListener(editor.container, "selectstart", function(e) {
|
|
||||||
return event.preventDefault(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
var mouseTarget = editor.renderer.getMouseEventTarget();
|
var mouseTarget = editor.renderer.getMouseEventTarget();
|
||||||
event.addListener(mouseTarget, "mousedown", this.onMouseEvent.bind(this, "mousedown"));
|
event.addListener(mouseTarget, "mousedown", this.onMouseEvent.bind(this, "mousedown"));
|
||||||
|
|
|
||||||
|
|
@ -533,13 +533,23 @@ var VirtualRenderer = function(container, theme) {
|
||||||
var posLeft = this.$cursorLayer.$pixelPos.left;
|
var posLeft = this.$cursorLayer.$pixelPos.left;
|
||||||
posTop -= this.layerConfig.offset;
|
posTop -= this.layerConfig.offset;
|
||||||
|
|
||||||
if (posTop < 0 || posTop > this.layerConfig.height)
|
if (posTop < 0 || posTop > this.layerConfig.height - this.lineHeight)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
posLeft += (this.showGutter ? this.$gutterLayer.gutterWidth : 0) - this.scrollLeft;
|
var w = this.characterWidth;
|
||||||
var bounds = this.container.getBoundingClientRect();
|
if (this.$composition)
|
||||||
this.textarea.style.left = (bounds.left + posLeft) + "px";
|
w += this.textarea.scrollWidth;
|
||||||
this.textarea.style.top = (bounds.top + posTop) + "px";
|
posLeft -= this.scrollLeft;
|
||||||
|
if (posLeft > this.$size.scrollerWidth - w)
|
||||||
|
posLeft = this.$size.scrollerWidth - w;
|
||||||
|
|
||||||
|
if (this.showGutter)
|
||||||
|
posLeft += this.$gutterLayer.gutterWidth;
|
||||||
|
|
||||||
|
this.textarea.style.height = this.lineHeight + "px";
|
||||||
|
this.textarea.style.width = w + "px";
|
||||||
|
this.textarea.style.left = posLeft + "px";
|
||||||
|
this.textarea.style.top = posTop - 1 + "px";
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1211,21 +1221,16 @@ var VirtualRenderer = function(container, theme) {
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
this.showComposition = function(position) {
|
this.showComposition = function(position) {
|
||||||
if (!this.$composition) {
|
if (!this.$composition)
|
||||||
this.$composition = dom.createElement("div");
|
this.$composition = {
|
||||||
this.$composition.className = "ace_composition";
|
keepTextAreaAtCursor: this.$keepTextAreaAtCursor,
|
||||||
this.content.appendChild(this.$composition);
|
cssText: this.textarea.style.cssText
|
||||||
}
|
};
|
||||||
|
|
||||||
this.$composition.innerHTML = " ";
|
this.$keepTextAreaAtCursor = true;
|
||||||
|
dom.addCssClass(this.textarea, "ace_composition");
|
||||||
var pos = this.$cursorLayer.getPixelPosition();
|
this.textarea.style.cssText = "";
|
||||||
var style = this.$composition.style;
|
this.$moveTextAreaToCursor();
|
||||||
style.top = pos.top + "px";
|
|
||||||
style.left = (pos.left + this.$padding) + "px";
|
|
||||||
style.height = this.lineHeight + "px";
|
|
||||||
|
|
||||||
this.hideCursor();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1235,7 +1240,7 @@ var VirtualRenderer = function(container, theme) {
|
||||||
* Sets the inner text of the current composition to `text`.
|
* Sets the inner text of the current composition to `text`.
|
||||||
**/
|
**/
|
||||||
this.setCompositionText = function(text) {
|
this.setCompositionText = function(text) {
|
||||||
dom.setInnerText(this.$composition, text);
|
this.$moveTextAreaToCursor();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1244,14 +1249,13 @@ var VirtualRenderer = function(container, theme) {
|
||||||
* Hides the current composition.
|
* Hides the current composition.
|
||||||
**/
|
**/
|
||||||
this.hideComposition = function() {
|
this.hideComposition = function() {
|
||||||
this.showCursor();
|
|
||||||
|
|
||||||
if (!this.$composition)
|
if (!this.$composition)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var style = this.$composition.style;
|
dom.removeCssClass(this.textarea, "ace_composition");
|
||||||
style.top = "-10000px";
|
this.$keepTextAreaAtCursor = this.$composition.keepTextAreaAtCursor;
|
||||||
style.left = "-10000px";
|
this.textarea.style.cssText = this.$composition.cssText;
|
||||||
|
this.$composition = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
this._loadTheme = function(name, callback) {
|
this._loadTheme = function(name, callback) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue