simulate backspace key on text input field - javascript

Can someone provide a good example to simulate the backspace key on a <INPUT> text field?
I need this for a virtual keyboard done in HTML5 and it only needs to work in Webkit browsers.
Notes:
createEvent/initTextEvent/dispatchEvent with charcode 8 (backspace) is being ignored (that seems to work only for printable characters)
changing manually the value using substr() sort of works, but this way the caret moves to the end of the input field (and I want to be able to delete characters in the middle of the input field, just like when using a normal keyboard).

Alright here you go: http://jsfiddle.net/dan_barzilay/WWAh7/2/
The get caret function is used to know where to delete the character, if you need more explaining comment.
The reset cursor function is used to restore the caret position after the backspacing.
**it's using jquery but you can change it to normal js in secounds

Edit: the below is too complicated to use. According to
https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand,
it's just enough to call document.execCommand("delete");.
Here's my solution using setSelectionRange, which works well on Chrome:
https://github.com/gdh1995/vimium-plus/blob/master/lib/dom_utils.js#L169
simulateBackspace: function(element) {
var start = element.selectionStart, end = element.selectionEnd, event;
if (!element.setRangeText) { return; }
if (start >= end) {
if (start <= 0 || !element.setSelectionRange) { return; }
element.setSelectionRange(start - 1, start);
}
element.setRangeText("");
event = document.createEvent("HTMLEvents");
event.initEvent("input", true, false);
element.dispatchEvent(event);
}
Well, the only shortage is that we can not undo the changes it makes.
Add: I find a method to enable undo & redo:
in Javascript textarea undo redo , the both anwsers work well on Chrome

Related

How to change the behavior of Ctrl+Backspace

I'm trying to create a Brainfuck IDE with Electron JS. The text-editing part is a <textarea> HTML element.
Right now, when I press Ctrl+Backspace the entire script gets deleted because of what is considered a "word".
How can I change the behavior of Ctrl+Backspace? Is it a Chrome thing, or a JS/Electron thing, or an HTML thing, or a CSS thing?
I would like for each of the 8 Brainfuck characters to be treated as a word. With this behavior, a script that looks like this:
>>><<<+++---...,,,[[[]]]
would be completely deleted in 8 strokes of Ctrl+Backspace. Each block of 3 of the same character is a "word".
Just prevent the default behavior when a Ctrl+Backspace is pressed:
var ta = document.getElementById("ta");
ta.addEventListener("keydown", function(ev) { // when a keydown event happens in the textarea
if(ev.ctrlKey && ev.keyCode === 8) { // check if control key is pressed along with the backspace (key code 8)
ev.preventDefault(); // if so, prevent the default behavior of this event
}
});
<textarea id="ta"></textarea>
Note: After you prevent the default behavior, you can do whatever you like (add some text at the current cursor, delete some characters, ... anything you want).

IE9 input setSelectionRange() after paste not working

I have to manually set the caret-position to 0 in an input-field (in the input-event). I need to support >= IE9. Even in IE9 this works ok as long as I do normal input (pressing keys on my keyboard). But as soon as I use copy&paste, the caret isn't set to the desired position (0).
Steps to reproduce:
Open IE in IE9-Mode
Open fiddle below
Type into the input-field (works ok, the caret gets set to 0)
Paste something into the input-field (fails, the caret gets set to the end of the pasted text)
Fiddle: https://jsfiddle.net/wv61t7k5/7/
Code
<input type="text" />
document.querySelector('input').addEventListener('input', function(){
this.setSelectionRange(0,0);
});
Funny. First I thought IE9 maybe would not fire the event on pasting, but it does. No idea why this would not work.
However, you could use the keyup event. This is definitely not as good as using input but will work in IE9.
document.querySelector('input').addEventListener('keyup', function(e){
if (e.key != 'Left' && e.key != 'Right' &&
e.key != 'Shift' && e.key != 'Control') {
this.setSelectionRange(0,0);
}
});
To still be able to select text by keyboard, you'd have to exclude some keys.
Here is an updated Fiddle.
Update
Well, this still does not work if the user pastes text by using mouse and context menu. Happily IE knows the paste event. Unhappily there is no after paste event, so you'd end up using a timeout:
document.querySelector('input').addEventListener('input', function(e){
this.setSelectionRange(0,0);
});
document.querySelector('input').addEventListener('paste', function() {
var that = this;
setTimeout(function() {
that.setSelectionRange(0,0);
}, 100);
});
Here is a Fiddle.

Ace Editor (javascript): Triggering a tab press event for Ace Editors event handlers (not just inserting '/t' or spaces)

I am using Ace Editor to build a code replay program. I store all the keys pressed when you type code, and then I replay them in Ace Editor. I have finished storing and replaying all keyboard/mouse input, but am having issues replaying tab presses.
Ace Editor handles tabs within a textarea DOM. The default behavior for a textarea when tab is pressed is to move to the next DOM, so I know they are using preventDefault() and using their own handler in order to allow softTab (insertion of 1,2,3, or 4 spaces before all highlighted text).
My goal is to cause Ace editor to trigger the tab event - such that whatever is currently highlighted in the Ace editor is tabbed over the correct number of spaces. Does anyone know how to do this?
Here are a list of options I've tried and why they don't work:
Store tab presses on keydown and then calculate the column value and insert the spaces in that location. BUT - this fails when you have some text half highlighted. The correct functionality should shift the entire word over, but this would just insert spaces in the middle of the word.
Store the location and keys pressed whenever editor.on('change', some_event_handler) fires, which gives me exactly what was input and the location (perfect for replay) except it doesnt tell me whether tab or spacebar was pressed (it will fire for both and spacebar is already handled). Plus this still inserts spaces at the location (potentially in middle of a word instead of shifting word over) as in number 1.
For example:
editor.getSession().on('change', function(e) {
if (handlers) {
var text = e.data.text;
if (text == ' ' || text == ' ' || text == ' ' || text == ' ') {
//FAILS because it doesn't know if its space or a single space tab.
Try to trick Ace Editor to trigger a tab by storing '/t' and inserting it into the ace Editor.
For example (storage code):
function keypress_handler(e) {
var key = e.which;
var text = String.fromCharCode(key);
switch(key) {
case 9: //Tab
text = '\t'; // manually add tab
//Code to store this event for replay later
break;
}
For example (replay code):
// Assuming the cursor/selection is in the correct position
editor.insert(log.text);
At this point, I was beginning to think about building tab from scratch (when to shift multiple things if multiple lines are selected, how far to shift, how to handle if a word is half highlighted when tab is pressed), but Ace clearly already does this when tab is pressed, so I would like to just trigger the tab press. Normally to trigger a tab press, I'd simply do:
// trigger an artificial Tab Keydown event for Ace Editor using jQuery
var tab_press= $.Event('keydown');
tab_press = 9; // Tab keycode
$('.editor').trigger(tab_press);
But this causes results in no behavior. Any suggestions?
I read through the source code here:
https://github.com/ajaxorg/ace/blob/master/lib/ace/commands/default_commands.js
And found the following snippet of code:
{
name: "indent",
bindKey: bindKey("Tab", "Tab"),
exec: function(editor) { editor.indent(); },
multiSelectAction: "forEach",
scrollIntoView: "selectionPart"
}
Thus, to trigger a tab (that works in all cases), simply call:
editor.indent();
How incredibly simple - wish there was some documentation out there for this so that many hours could have been spared.
In Ace all of the user input from keyboard is processed via commands. This is used in Ace to record and replay macros see https://github.com/ajaxorg/ace/blob/v1.1.4/lib/ace/commands/command_manager.js#L52-L96.
If you want to record user input and then to replay it you can use
// record
commands=[]
editor.commands.on("afterExec", function(e) {
commands.push({name: e.command.name, args: e.args})
});
// replay
commands.forEach(function(e) {editor.execCommand(e.name, e.args)})
Capturing mouse input is a bit tricker, but from question it seems you already know how to do it.
This pull request is somewhat related to your question. It allows to emulate user input by calling simulateKeys("a", "b", "ctrl-Left", "Tab")

prevent "up arrow" key reseting cursor position within textbox

I recently added some predictive text input fields to the web-app I am supporting.
Big deal, right? Not really, seems like if your web-app doesn't do this -- you are already behind the times and your end-users are complaining. (At least that's how it is over here).
So, my question has to do with the "up" arrow key.
The predictive textbox has a onkeyup listener.
The handler segregates the key strokes and does something depending on the character the user entered.
The up arrow key allows the user to navigate in a div I created loaded with "suggestions."
I have several variables tracking indexes, etc...
Basically, when the user hits the up arrow I will change the id of the div to an id that has some css associated with it that will make the div appear as though it is selected. Additionally I will grab the value in that div and assign it to the textbox where the user is able to type.
The problem is an aesthetic one. Inherently with all text boxes I am learning, the up arrow key will reset the cursor position. This is happening just before I am writing the new value to the text field.
So, on each up arrow stroke, the user is seeing a jumping cursor in the textbox (it will jump to the beginning and immediately it will appear at the end).
Here's the code -
if (event.keyCode === 38 && currentUserInput.length > 0) {
// user has toggled out of the text input field, save their typing thus far
if (currentToggledIndex == -1) {
currentToggledIndex = autoFillKeywordsList.length-1;
savedKeywordUserInput = currentUserInput;
}
else {
// revert currently selected index back to its original id
document.getElementById("kw_selected").id = "kw_" + currentToggledIndex ;
// user has toggled back into user input field
if (currentToggledIndex == 0) {
currentToggledIndex = -1;
}
// user has toggled to the next suggestion
else {
currentToggledIndex--;
}
}
// 2. Determine next action based on the updated currentToggledIndex position
// revert the user input field back to what the user had typed prior to
// toggling out of the field
if (currentToggledIndex == -1) {
element.value = savedKeywordUserInput;
}
// mark the toggled index/keyword suggestion as "selected" and copy
// its value into the text field
else {
document.getElementById("kw_"+currentToggledIndex).id = "kw_selected";
element.value = autoFillKeywordsList[currentToggledIndex];
}
// 3. Determine what the user can do based on the current value currently
// selected/displayed
displayAppropriateButtonActions(element.value);
}
The funny thing is - the "down" arrow works perfectly since by default the down arrow key will place the cursor at the end of the string currently located in the textbox.
Ok, so things that I have already tried -
event.preventDefault();
event.stopPropogation();
I also tried to set the cursor position PRIOR to setting the new value to no avail using a setCursorPosition function I found on another post here. (Yeah, I was reaching with this one)
I tagged this as JavaScript and Jquery. I prefer to use JavaScript, but open to suggestions in Jquery too!
As Ryan suggested. how I achieved this in angular 4.x is
.html
<.. (keydown)="keyDownEvent($event)" >
.ts
keyDownEvent(event: any){
if (event.keyCode === 38 && event.key == "ArrowUp")
{
event.preventDefault();
//logic..
}
I think what you can do is when they move the cursor, grab that and find out what element it is ... then store it in a variable and focus() it and erase it and then put the value you stored back into it.
var holdme = $("#myelement").val();
$("#myelement").focus().val('').val(holdme);
This works for me when having weird cursor issues in jquery/javascript most of the time. Give it a try and if it doesn't work, let me know and I'll see what else might be wrong.
I found that it worked well to capture the caret position, blur, restore the caret position, then focus again.
myTextInput.onkeydown = function(e){
//some other code
if(e.key == "ArrowDown" || e.key == 40 || e.key == "ArrowUp" || e.key == 38){
var caretPos = this.selectionStart;
//do your stuff with up and down arrows
e.preventDefault();
this.blur();
this.selectionStart = caretPos;
this.selectionEnd = caretPos;
this.focus();
}
}
The caret will very briefly disappear, but I think you have to be incredibly observant to notice.

Javascript to make input field in edit mode(insert mode)

How is it possible to make a input field editable in javascript. I mean onFocus putting it in insert mode so that values can be overwritten. Any suggestions ???
This should work in modern browsers (also on mobile):
var input = document.querySelector('input'); // or a textarea
input.addEventListener('keypress', function(){
var s = this.selectionStart;
this.value = this.value.substr(0, s) + this.value.substr(s + 1);
this.selectionEnd = s;
}, false);
jsfiddle
Note: This is a basic form of insert functionality so some default functionality like CTRL+Z may break.
After doing some googling, this seems to be related. It might be working trying the play with the following code a bit, but it might only work in specific browsers on specific operating systems, but it's worth a shot anyway.
document.execCommand('OverWrite', false, true);
document.execCommand('OverWrite', false, false);
As per your request, I would say the implementation would work something like this:
<input type="text"
onFocus="document.execCommand('OverWrite', false, true);"
onBlur="document.execCommand('OverWrite', false, false);">
EDIT: May be totally off-topic, depending on the meaning behind the question.
If you can use jQuery, Jeditable is a nice plugin to do just that.
If you must roll your own code, take a look at how that plugin works and use it as a starting point.
Basically, the steps are:
onFocus/onClick - swap your field with an input.
When the user is "done" (hit Enter, click a button), push the result back to the server via Ajax.
When your request completes, update the interface with the new value, hiding the input.
You can try to mimic Insert mode by rewriting the input value on keyup :
var input = $('input'); // your input element
Event.observe(input, 'keydown', function(e) { // event handler
input._lastvalue = input.value;
});
Event.observe(input, 'keyup', function(e) { // event handler
if(input.value == input._lastvalue) return;
if(input.value.length <= input._lastvalue.length) return;
var caretPos = doGetCaretPosition(input);
input.value = input.value.slice(0,caretPos) + input.value.slice(caretPos+1);
doSetCaretPosition(input, caretPos);
});
Here is a demo : http://jsfiddle.net/z6khW/

Categories

Resources