diff --git a/lib/ace/config.js b/lib/ace/config.js index c617959d..4a7dc286 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -103,12 +103,12 @@ exports.loadModule = function(moduleName, onLoad) { module = require(moduleName); } catch (e) {}; if (module) - return onLoad(module); + return onLoad && onLoad(module); var afterLoad = function() { require([moduleName], function(module) { exports._emit("load.module", {name: moduleName, module: module}); - onLoad(module); + onLoad && onLoad(module); }); }; diff --git a/lib/ace/ext/spellcheck.js b/lib/ace/ext/spellcheck.js new file mode 100644 index 00000000..b3600e5f --- /dev/null +++ b/lib/ace/ext/spellcheck.js @@ -0,0 +1,68 @@ +define(function(require, exports, module) { +"use strict"; +var event = require("../lib/event"); + +exports.contextMenuHandler = function(e){ + var host = e.target; + var text = host.textInput.getElement(); + if (!host.selection.isEmpty()) + return; + var c = host.getCursorPosition(); + var r = host.session.getWordRange(c.row, c.column); + var w = host.session.getTextRange(r); + + host.session.tokenRe.lastIndex = 0; + if (!host.session.tokenRe.test(w)) + return; + var PLACEHOLDER = "\x01\x01"; + var value = w + " " + PLACEHOLDER; + text.value = value; + text.setSelectionRange(w.length + 1, w.length + 1); + text.setSelectionRange(0, 0); + + var afterKeydown = false; + event.addListener(text, "keydown", function onKeydown() { + event.removeListener(text, "keydown", onKeydown); + afterKeydown = true; + }); + + host.textInput.setInputHandler(function(newVal) { + console.log(newVal , value, text.selectionStart, text.selectionEnd) + if (newVal == value) + return ''; + if (newVal.lastIndexOf(value, 0) === 0) + return newVal.slice(value.length); + if (newVal.substr(text.selectionEnd) == value) + return newVal.slice(0, -value.length); + if (newVal.slice(-2) == PLACEHOLDER) { + var val = newVal.slice(0, -2); + if (val.slice(-1) == " ") { + if (afterKeydown) + return val.substring(0, text.selectionEnd); + val = val.slice(0, -1); + host.session.replace(r, val); + return ""; + } + } + + return newVal; + }); +}; +// todo support highlighting with typo.js +var Editor = require("../editor").Editor; +require("../config").defineOptions(Editor.prototype, "editor", { + spellcheck: { + set: function(val) { + var text = this.textInput.getElement(); + text.spellcheck = !!val; + if (!val) + this.removeListener("nativecontextmenu", exports.contextMenuHandler); + else + this.on("nativecontextmenu", exports.contextMenuHandler); + }, + value: true + } +}); + +}); + diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 397a0917..049ddca4 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -96,8 +96,13 @@ var TextInput = function(parentNode, host) { function resetSelection(isEmpty) { if (inCompostion) return; - var selectionStart = isEmpty ? 2 : 1; - var selectionEnd = 2; + if (inputHandler) { + selectionStart = 0; + selectionEnd = isEmpty ? 0 : text.value.length - 1; + } else { + var selectionStart = isEmpty ? 2 : 1; + var selectionEnd = 2; + } // on firefox this throws if textarea is hidden try { text.setSelectionRange(selectionStart, selectionEnd); @@ -180,26 +185,33 @@ var TextInput = function(parentNode, host) { var onSelect = function(e) { if (cut) { cut = false; - return; - } - if (copied) { + } else if (copied) { copied = false; - return; - } - if (isAllSelected(text)) { + } else if (isAllSelected(text)) { host.selectAll(); resetSelection(); + } else if (inputHandler) { + resetSelection(host.selection.isEmpty()); } }; + var inputHandler = null; + this.setInputHandler = function(cb) {inputHandler = cb}; + this.getInputHandler = function() {return inputHandler}; + var sendText = function(data) { + if (inputHandler) { + data = inputHandler(data); + inputHandler = null; + } if (pasted) { resetSelection(); if (data) host.onPaste(data); pasted = false; } else if (data == PLACEHOLDER[0]) { - host.execCommand("del", {source: "ace"}); + if (Date.now() - lastCompositionTime > 100) + host.execCommand("del", {source: "ace"}); } else { if (data.substring(0, 2) == PLACEHOLDER) data = data.substr(2); @@ -219,9 +231,8 @@ var TextInput = function(parentNode, host) { if (inCompostion) return; var data = text.value; - resetValue(); - sendText(data); + resetValue(); }; var onCut = function(e) { @@ -344,10 +355,12 @@ var TextInput = function(parentNode, host) { if (!inCompostion) return; host.onCompositionUpdate(text.value); }; - + + var lastCompositionTime = -1; var onCompositionEnd = function(e) { inCompostion = false; host.onCompositionEnd(); + lastCompositionTime = Date.now(); }; var syncComposition = lang.delayedCall(onCompositionUpdate, 50); @@ -377,10 +390,11 @@ var TextInput = function(parentNode, host) { var style = dom.computedStyle(host.container); var top = rect.top + (parseInt(style.borderTopWidth) || 0); var left = rect.left + (parseInt(rect.borderLeftWidth) || 0); + var maxTop = rect.bottom - top - text.clientHeight; var move = function(e) { text.style.left = e.clientX - left - 2 + "px"; - text.style.top = e.clientY - top - 2 + "px"; - }; + text.style.top = Math.min(e.clientY - top - 2, maxTop) + "px"; + }; move(e); if (e.type != "mousedown") diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 719df69a..0de955cb 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -549,8 +549,8 @@ var VirtualRenderer = function(container, theme) { this.textarea.style.height = this.lineHeight + "px"; this.textarea.style.width = w + "px"; - this.textarea.style.right = this.$size.scrollerWidth - posLeft - w + "px"; - this.textarea.style.bottom = this.$size.height - posTop - this.lineHeight + "px"; + this.textarea.style.right = Math.max(0, this.$size.scrollerWidth - posLeft - w) + "px"; + this.textarea.style.bottom = Math.max(0, this.$size.height - posTop - this.lineHeight) + "px"; }; /**