From 074ed41db00477eb2e8a302aff32c6765043a996 Mon Sep 17 00:00:00 2001 From: DanyaPostfactum Date: Fri, 12 Oct 2012 22:59:51 +1100 Subject: [PATCH] Clipboard API support, context menu Delete command support --- lib/ace/editor.js | 11 +- lib/ace/keyboard/textinput.js | 276 ++++++++++++++++------------------ 2 files changed, 136 insertions(+), 151 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 937e0e73..340e8e7f 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -656,6 +656,15 @@ var Editor = function(renderer, session) { this.insert(text); }; + /** + * Editor.onDelete() + * + * called whenever a text "delete" happens. + **/ + this.onDelete = function() { + this.commands.exec("del", this); + }; + /** * Editor.insert(text) * - text (String): The new text to add @@ -2126,4 +2135,4 @@ var Editor = function(renderer, session) { exports.Editor = Editor; -}); \ No newline at end of file +}); diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 7204c022..876872f0 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -54,69 +54,46 @@ var TextInput = function(parentNode, host) { parentNode.insertBefore(text, parentNode.firstChild); var PLACEHOLDER = useragent.isIE ? "\x01" : "\x00"; - reset(true); if (isFocused()) host.onFocus(); - var inCompostion = false; - var copied = false; var pasted = false; + var inCompostion = false; + var isSelectionEmpty = true; var tempStyle = ''; - function reset(full) { - try { - if (full) { - text.value = PLACEHOLDER; - text.selectionStart = 0; - text.selectionEnd = 1; - } else - text.select(); - } catch (e) {} - } - - function sendText(valueToSend) { - if (!copied) { - var value = valueToSend || text.value; - if (value) { - if (value.length > 1) { - if (value.charAt(0) == PLACEHOLDER) - value = value.substr(1); - else if (value.charAt(value.length - 1) == PLACEHOLDER) - value = value.slice(0, -1); - } - - if (value && value != PLACEHOLDER) { - if (pasted) - host.onPaste(value); - else - host.onTextInput(value); - } - } + host.addEventListener('changeSelection', function(){ + if (host.selection.isEmpty() != isSelectionEmpty) { + isSelectionEmpty = !isSelectionEmpty; + text.value = isSelectionEmpty ? '' : PLACEHOLDER; + text.select(); } + }); - copied = false; - pasted = false; + var onInput = function(e) { + if (inCompostion) + return; - // Safari doesn't fire copy events if no text is selected - reset(true); - } + if (pasted) { + var data = text.value; + if (data) + host.onPaste(data); + pasted = false; + } else { + var data = text.value; + if (data) + host.onTextInput(data); + else + host.onDelete(); + } + text.value = ""; - var onTextInput = function(e) { - if (!inCompostion) - sendText(e.data); - setTimeout(function () { - if (!inCompostion) - reset(true); - }, 0); - }; - - var onPropertyChange = function(e) { - setTimeout(function() { - if (!inCompostion) - if(text.value != "") { - sendText(); - } - }, 0); + //http://code.google.com/p/chromium/issues/detail?id=76516 + if (useragent.isWebKit) + setTimeout(function(){ + text.blur(); + text.focus(); + }); }; var onCompositionStart = function(e) { @@ -135,37 +112,106 @@ var TextInput = function(parentNode, host) { host.onCompositionEnd(); }; - var onCopy = function(e) { - copied = true; - var copyText = host.getCopyText(); - if(copyText) - text.value = copyText; - else - e.preventDefault(); - reset(); - setTimeout(function () { - sendText(); - }, 0); + var onCut = function(e) { + var data = host.getCopyText(); + if (!data) { + event.preventDefault(e); + return; + } + + e.clipboardData = e.clipboardData || window.clipboardData; + + if (e.clipboardData) { + // Safari 5 has clipboardData object, but does not handle setData() + var supported = e.clipboardData.setData("Text", data); + if (supported) { + host.onCut(); + event.preventDefault(e); + } + } + + if (!supported) { + text.value = data; + text.select(); + setTimeout(function(){ host.onCut() }); + } }; - var onCut = function(e) { - copied = true; - var copyText = host.getCopyText(); - if(copyText) { - text.value = copyText; - host.onCut(); - } else - e.preventDefault(); - reset(); - setTimeout(function () { - sendText(); - }, 0); + var onCopy = function(e) { + var data = host.getCopyText(); + if (!data) { + event.preventDefault(e); + return; + } + + e.clipboardData = e.clipboardData || window.clipboardData; + + if (e.clipboardData) { + // Safari 5 has clipboardData object, but does not handle setData() + var supported = e.clipboardData.setData("Text", data); + if (supported) { + host.onCopy(); + event.preventDefault(e); + } + } + if (!supported) { + text.value = data; + text.select(); + setTimeout(function(){ host.onCopy() }); + } + + + }; + + var onPaste = function(e) { + e.clipboardData = e.clipboardData || window.clipboardData; + + if (e.clipboardData) { + var data = e.clipboardData.getData("Text"); + if (data) + host.onPaste(data); + event.preventDefault(e); + } + else { + pasted = true; + } }; event.addCommandKeyListener(text, host.onCommandKey.bind(host)); - event.addListener(text, "input", onTextInput); - + + event.addListener(text, "input", onInput); + + event.addListener(text, "cut", onCut); + event.addListener(text, "copy", onCopy); + event.addListener(text, "paste", onPaste); + + + // Opera has no clipboard events + if (!('oncut' in text) || !('oncopy' in text) || !('onpaste' in text)){ + event.addListener(parentNode, "keydown", function(e) { + if ((useragent.isMac && !e.metaKey) || !e.ctrlKey) + return; + + switch (e.keyCode) { + case 67: + onCopy(e); + break; + case 86: + onPaste(e); + break; + case 88: + onCut(e); + break; + } + }); + } + if (useragent.isOldIE) { + event.addListener(text, "propertychange", function(e){ + if (text.value != "" && text.value != PLACEHOLDER) + onInput(e); + }); + var keytable = { 13:1, 27:1 }; event.addListener(text, "keyup", function (e) { if (inCompostion && (!text.value || keytable[e.keyCode])) @@ -175,70 +221,6 @@ var TextInput = function(parentNode, host) { } inCompostion ? onCompositionUpdate() : onCompositionStart(); }); - - event.addListener(text, "propertychange", function() { - if (text.value != PLACEHOLDER) - setTimeout(sendText, 0); - }); - } - - event.addListener(text, "paste", function(e) { - // Mark that the next input text comes from past. - pasted = true; - // Some browsers support the event.clipboardData API. Use this to get - // the pasted content which increases speed if pasting a lot of lines. - if (e.clipboardData && e.clipboardData.getData) { - sendText(e.clipboardData.getData("text/plain")); - e.preventDefault(); - } - else { - // If a browser doesn't support any of the things above, use the regular - // method to detect the pasted input. - onPropertyChange(); - } - }); - - if ("onbeforecopy" in text && typeof clipboardData !== "undefined") { - event.addListener(text, "beforecopy", function(e) { - if (tempStyle) - return; // without this text is copied when contextmenu is shown - var copyText = host.getCopyText(); - if (copyText) - clipboardData.setData("Text", copyText); - else - e.preventDefault(); - }); - event.addListener(parentNode, "keydown", function(e) { - if (e.ctrlKey && e.keyCode == 88) { - var copyText = host.getCopyText(); - if (copyText) { - clipboardData.setData("Text", copyText); - host.onCut(); - } - event.preventDefault(e); - } - }); - event.addListener(text, "cut", onCut); // for ie9 context menu - } - else if (useragent.isOpera && !("KeyboardEvent" in window)) { - event.addListener(parentNode, "keydown", function(e) { - if ((useragent.isMac && !e.metaKey) || !e.ctrlKey) - return; - - if ((e.keyCode == 88 || e.keyCode == 67)) { - var copyText = host.getCopyText(); - if (copyText) { - text.value = copyText; - text.select(); - if (e.keyCode == 88) - host.onCut(); - } - } - }); - } - else { - event.addListener(text, "copy", onCopy); - event.addListener(text, "cut", onCut); } event.addListener(text, "compositionstart", onCompositionStart); @@ -256,11 +238,11 @@ var TextInput = function(parentNode, host) { event.addListener(text, "focus", function() { host.onFocus(); - reset(); + text.select(); }); this.focus = function() { - reset(); + text.select(); text.focus(); }; @@ -286,11 +268,6 @@ var TextInput = function(parentNode, host) { (useragent.isIE ? "background:rgba(0, 0, 0, 0.03); opacity:0.1;" : "") + //"background:rgba(250, 0, 0, 0.3); opacity:1;" + "left:" + (e.clientX - 2) + "px; top:" + (e.clientY - 2) + "px;"; - if (host.selection.isEmpty()) - text.value = ""; - else - reset(true); - if (e.type != "mousedown") return; @@ -311,7 +288,6 @@ var TextInput = function(parentNode, host) { text.style.cssText = tempStyle; tempStyle = ''; } - sendText(); if (host.renderer.$keepTextAreaAtCursor == null) { host.renderer.$keepTextAreaAtCursor = true; host.renderer.$moveTextAreaToCursor();