HTML form, make tab key trigger indent? - javascript

The default behaviour in browsers is to select the next form element. I want my textbox to indent code by, lets say 4 spaces when tab is pressed. Just like if you were indenting code in an IDE. How would I achieve this behaviour in JavaScript? If I have to use jQuery, or its easier, I'm fine with that.
Thanks!

Tracking the key code and adding 4 spaces to the element should do it. You can prevent the default when the tab key is pressed. Like so?:
Edit after all comments:
Ahh, ok so you're actually asking for several JS functions (get cursor position in text area, change text, set cursor position in text area). A little more looking around would have given you all of these, but since I'm a nice guy I'll put it in there for ya. The other answers can be found in this post about getCursorPosition() and this post about setCursorPosition(). I updated the jsFiddle for ya. Here's the code update
<script>
$('#myarea').on('keydown', function(e) {
var thecode = e.keyCode || e.which;
if (thecode == 9) {
e.preventDefault();
var html = $('#myarea').val();
var pos = $('#myarea').getCursorPosition(); // get cursor position
var prepend = html.substring(0,pos);
var append = html.replace(prepend,'');
var newVal = prepend+' '+append;
$('#myarea').val(newVal);
$('#myarea').setCursorPosition(pos+4);
}
});
new function($) {
$.fn.getCursorPosition = function() {
var pos = 0;
var el = $(this).get(0);
// IE Support
if (document.selection) {
el.focus();
var Sel = document.selection.createRange();
var SelLength = document.selection.createRange().text.length;
Sel.moveStart('character', -el.value.length);
pos = Sel.text.length - SelLength;
}
// Firefox support
else if (el.selectionStart || el.selectionStart == '0')
pos = el.selectionStart;
return pos;
}
} (jQuery);
new function($) {
$.fn.setCursorPosition = function(pos) {
if ($(this).get(0).setSelectionRange) {
$(this).get(0).setSelectionRange(pos, pos);
} else if ($(this).get(0).createTextRange) {
var range = $(this).get(0).createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}
}(jQuery);
​
</script>
<textarea id="myarea"></textarea>

Related

Trying to set the caret at the end of a contenteditable div on focus and then press enter for new line

I'm running this code to set the caret at the end of a contenteditable when the div is focused. I'm also running a script on enter key to fix linebreak weirdness in firefox. For some reason the two functions don't work together and I get this message on enter:
IndexSizeError: Index or size is negative or greater than the allowed
amount
Try to click on the div and press enter in Firefox and you'll see what I mean. It works in Safari and Chrome.
I can't use a textarea, but is there a cleaner way to solve this? I also added a setTimeout on the placeCaretAtEnd function because it sometimes placed the caret where I pressed anyway, and sometimes it selects a portion of the text instead of placing it at the end. It still acts odd every now and then so suggestions of a more bulletproof way to make it always appear at the end is welcome!
function placeCaretAtEnd(el) {
el.focus();
if (typeof window.getSelection != "undefined"
&& typeof document.createRange != "undefined") {
var range = document.createRange();
range.selectNodeContents(el);
range.collapse(false);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (typeof document.body.createTextRange != "undefined") {
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.collapse(false);
textRange.select();
}
}
$(document).on('keydown', 'div', function(e) {
var keyCode = e.keyCode || e.which;
var $self = $(this);
var esc = keyCode == 27;
var nl = keyCode == 13;
var tab = keyCode == 9;
var shift = e.shiftKey;
var sel, node, offset, text, textBefore, textAfter, range;
if(nl)
{
sel = window.getSelection();
// the node that contains the caret
node = sel.anchorNode;
// if ENTER was pressed while the caret was inside the input field
// prevent the browsers from inserting <div>, <p>, or <br> on their own
e.preventDefault();
// the caret position inside the node
offset = sel.anchorOffset;
// insert a '\n' character at that position
text = node.textContent;
textBefore = text.slice( 0, offset );
textAfter = text.slice( offset ) || ' ';
node.textContent = textBefore + '\n' + textAfter;
// position the caret after that new-line character
range = document.createRange();
range.setStart( node, offset + 1 );
range.setEnd( node, offset + 1 );
// update the selection
sel.removeAllRanges();
sel.addRange( range );
}
});
$(document).on('focus', 'div', function(e) {
var $self = $(this);
setTimeout(function() {
placeCaretAtEnd($self[0]);
},0);
});
div {
white-space: pre-wrap;
overflow-wrap: break-word;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div contenteditable>Lots of text
Lots of text
Lots of text</div>

how to insert text in textarea dynamicaly from jquery [duplicate]

I have a page with a lot of textboxes. When someone clicks a link, i want a word or two to be inserted where the cursor is, or appended to the textbox which has the focus.
For example, if the cursor/focus is on a textbox saying 'apple' and he clicks a link saying '[email]', then i want the textbox to say, 'apple bob#example.com'.
How can I do this? Is this even possible, since what if the focus is on a radio/dropdown/non textbox element? Can the last focused on textbox be remembered?
Use this, from here:
function insertAtCaret(areaId, text) {
var txtarea = document.getElementById(areaId);
if (!txtarea) {
return;
}
var scrollPos = txtarea.scrollTop;
var strPos = 0;
var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ?
"ff" : (document.selection ? "ie" : false));
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart('character', -txtarea.value.length);
strPos = range.text.length;
} else if (br == "ff") {
strPos = txtarea.selectionStart;
}
var front = (txtarea.value).substring(0, strPos);
var back = (txtarea.value).substring(strPos, txtarea.value.length);
txtarea.value = front + text + back;
strPos = strPos + text.length;
if (br == "ie") {
txtarea.focus();
var ieRange = document.selection.createRange();
ieRange.moveStart('character', -txtarea.value.length);
ieRange.moveStart('character', strPos);
ieRange.moveEnd('character', 0);
ieRange.select();
} else if (br == "ff") {
txtarea.selectionStart = strPos;
txtarea.selectionEnd = strPos;
txtarea.focus();
}
txtarea.scrollTop = scrollPos;
}
<textarea id="textareaid"></textarea>
Click Here to Insert
Maybe a shorter version, would be easier to understand?
jQuery("#btn").on('click', function() {
var $txt = jQuery("#txt");
var caretPos = $txt[0].selectionStart;
var textAreaTxt = $txt.val();
var txtToAdd = "stuff";
$txt.val(textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos) );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<textarea id="txt" rows="15" cols="70">There is some text here.</textarea>
<input type="button" id="btn" value="OK" />
I wrote this in response to How to add a text to a textbox from the current position of the pointer with jquery?
The approved answer from George Claghorn worked great for simply inserting text at the cursor position. If the user had selected text though, and you want that text to be replaced (the default experience with most text), you need to make a small change when setting the 'back' variable.
Also, if you don't need to support older versions of IE, modern versions support textarea.selectionStart, so you can take out all of the browser detection, and IE-specific code.
Here is a simplified version that works for Chrome and IE11 at least, and handles replacing selected text.
function insertAtCaret(areaId, text) {
var txtarea = document.getElementById(areaId);
var scrollPos = txtarea.scrollTop;
var caretPos = txtarea.selectionStart;
var front = (txtarea.value).substring(0, caretPos);
var back = (txtarea.value).substring(txtarea.selectionEnd, txtarea.value.length);
txtarea.value = front + text + back;
caretPos = caretPos + text.length;
txtarea.selectionStart = caretPos;
txtarea.selectionEnd = caretPos;
txtarea.focus();
txtarea.scrollTop = scrollPos;
}
The code above didn't work for me in IE. Here's some code based on this answer.
I took out the getElementById so I could reference the element in a different way.
function insertAtCaret(element, text) {
if (document.selection) {
element.focus();
var sel = document.selection.createRange();
sel.text = text;
element.focus();
} else if (element.selectionStart || element.selectionStart === 0) {
var startPos = element.selectionStart;
var endPos = element.selectionEnd;
var scrollTop = element.scrollTop;
element.value = element.value.substring(0, startPos) +
text + element.value.substring(endPos, element.value.length);
element.focus();
element.selectionStart = startPos + text.length;
element.selectionEnd = startPos + text.length;
element.scrollTop = scrollTop;
} else {
element.value += text;
element.focus();
}
}
input{width:100px}
label{display:block;margin:10px 0}
<label for="in2copy">Copy text from: <input id="in2copy" type="text" value="x"></label>
<label for="in2ins">Element to insert: <input id="in2ins" type="text" value="1,2,3" autofocus></label>
<button onclick="insertAtCaret(document.getElementById('in2ins'),document.getElementById('in2copy').value)">Insert</button>
EDIT: Added a running snippet, jQuery is not being used.
using #quick_sliv answer:
function insertAtCaret(el, text) {
var caretPos = el.selectionStart;
var textAreaTxt = el.value;
el.value = textAreaTxt.substring(0, caretPos) + text + textAreaTxt.substring(caretPos);
};
How to insert some Text to current cursor position of a TextBox through JQuery and JavaScript
Process
Find the Current Cursor Position
Get the Text to be Copied
Set the Text Over there
Update the Cursor position
Here I have 2 TextBoxes and a Button. I have to Click on a certain position on a textbox and then click on the button to paste the text from the
other textbox to the the position of the previous textbox.
Main issue here is that getting the current cursor position where we will paste the text.
//Textbox on which to be pasted
<input type="text" id="txtOnWhichToBePasted" />
//Textbox from where to be pasted
<input type="text" id="txtFromWhichToBePasted" />
//Button on which click the text to be pasted
<input type="button" id="btnInsert" value="Insert"/>
<script type="text/javascript">
$(document).ready(function () {
$('#btnInsert').bind('click', function () {
var TextToBePasted = $('#txtFromWhichToBePasted').value;
var ControlOnWhichToBePasted = $('#txtOnWhichToBePasted');
//Paste the Text
PasteTag(ControlOnWhichToBePasted, TextToBePasted);
});
});
//Function Pasting The Text
function PasteTag(ControlOnWhichToBePasted,TextToBePasted) {
//Get the position where to be paste
var CaretPos = 0;
// IE Support
if (document.selection) {
ControlOnWhichToBePasted.focus();
var Sel = document.selection.createRange();
Sel.moveStart('character', -ctrl.value.length);
CaretPos = Sel.text.length;
}
// Firefox support
else if (ControlOnWhichToBePasted.selectionStart || ControlOnWhichToBePasted.selectionStart == '0')
CaretPos = ControlOnWhichToBePasted.selectionStart;
//paste the text
var WholeString = ControlOnWhichToBePasted.value;
var txt1 = WholeString.substring(0, CaretPos);
var txt2 = WholeString.substring(CaretPos, WholeString.length);
WholeString = txt1 + TextToBePasted + txt2;
var CaretPos = txt1.length + TextToBePasted.length;
ControlOnWhichToBePasted.value = WholeString;
//update The cursor position
setCaretPosition(ControlOnWhichToBePasted, CaretPos);
}
function setCaretPosition(ControlOnWhichToBePasted, pos) {
if (ControlOnWhichToBePasted.setSelectionRange) {
ControlOnWhichToBePasted.focus();
ControlOnWhichToBePasted.setSelectionRange(pos, pos);
}
else if (ControlOnWhichToBePasted.createTextRange) {
var range = ControlOnWhichToBePasted.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}
</script>
Adding text to current cursor position involves two steps:
Adding the text at the current cursor position
Updating the current cursor position
Demo: https://codepen.io/anon/pen/qZXmgN
Tested in Chrome 48, Firefox 45, IE 11 and Edge 25
JS:
function addTextAtCaret(textAreaId, text) {
var textArea = document.getElementById(textAreaId);
var cursorPosition = textArea.selectionStart;
addTextAtCursorPosition(textArea, cursorPosition, text);
updateCursorPosition(cursorPosition, text, textArea);
}
function addTextAtCursorPosition(textArea, cursorPosition, text) {
var front = (textArea.value).substring(0, cursorPosition);
var back = (textArea.value).substring(cursorPosition, textArea.value.length);
textArea.value = front + text + back;
}
function updateCursorPosition(cursorPosition, text, textArea) {
cursorPosition = cursorPosition + text.length;
textArea.selectionStart = cursorPosition;
textArea.selectionEnd = cursorPosition;
textArea.focus();
}
HTML:
<div>
<button type="button" onclick="addTextAtCaret('textArea','Apple')">Insert Apple!</button>
<button type="button" onclick="addTextAtCaret('textArea','Mango')">Insert Mango!</button>
<button type="button" onclick="addTextAtCaret('textArea','Orange')">Insert Orange!</button>
</div>
<textarea id="textArea" rows="20" cols="50"></textarea>
I think you could use the following JavaScript to track the last-focused textbox:
<script>
var holdFocus;
function updateFocus(x)
{
holdFocus = x;
}
function appendTextToLastFocus(text)
{
holdFocus.value += text;
}
</script>
Usage:
<input type="textbox" onfocus="updateFocus(this)" />
<a href="#" onclick="appendTextToLastFocus('textToAppend')" />
A previous solution (props to gclaghorn) uses textarea and calculates the position of the cursor too, so it may be better for what you want. On the other hand, this one would be more lightweight, if that's what you're looking for.
This question's answer was posted so long ago and I stumbled upon it via a Google search. HTML5 provides the HTMLInputElement API that includes the setRangeText() method, which replaces a range of text in an <input> or <textarea> element with a new string:
element.setRangeText('abc');
The above would replace the selection made inside element with abc. You can also specify which part of the input value to replace:
element.setRangeText('abc', 3, 5);
The above would replace the 4th till 6th characters of the input value with abc. You can also specify how the selection should be set after the text has been replaced by providing one of the following strings as the 4th parameter:
'preserve' attempts to preserve the selection. This is the default.
'select' selects the newly inserted text.
'start' moves the selection to just before the inserted text.
'end' moves the selection to just after the inserted text.
Browser compatibility
The MDN page for setRangeText doesn't provide browser compatibility data, but I guess it'd be the same as HTMLInputElement.setSelectionRange(), which is basically all modern browsers, IE 9 and above, Edge 12 and above.
The accepted answer didn't work for me on Internet Explorer 9.
I checked it and the browser detection was not working properly, it detected ff (firefox) when i was at Internet Explorer.
I just did this change:
if ($.browser.msie)
Instead of:
if (br == "ie") {
The resulting code is this one:
function insertAtCaret(areaId,text) {
var txtarea = document.getElementById(areaId);
var scrollPos = txtarea.scrollTop;
var strPos = 0;
var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ?
"ff" : (document.selection ? "ie" : false ) );
if ($.browser.msie) {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart ('character', -txtarea.value.length);
strPos = range.text.length;
}
else if (br == "ff") strPos = txtarea.selectionStart;
var front = (txtarea.value).substring(0,strPos);
var back = (txtarea.value).substring(strPos,txtarea.value.length);
txtarea.value=front+text+back;
strPos = strPos + text.length;
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart ('character', -txtarea.value.length);
range.moveStart ('character', strPos);
range.moveEnd ('character', 0);
range.select();
}
else if (br == "ff") {
txtarea.selectionStart = strPos;
txtarea.selectionEnd = strPos;
txtarea.focus();
}
txtarea.scrollTop = scrollPos;
}
This jQuery plugin gives you a pre-made way of selection/caret manipulation.
you can only focus required textbox an insert the text there. there is no way to find out where focus is AFAIK (maybe interating over all DOM nodes?).
check this stackoverflow - it has a solution for you:
How do I find out which DOM element has the focus?
Content Editable, HTML or any other DOM element Selections
If you are trying to insert at caret on a <div contenteditable="true">, this becomes much more difficult, especially if there are children within the editable container.
I have had really great luck using the Rangy library:
GIT: https://github.com/timdown/rangy
NPM: https://www.npmjs.com/package/rangy
It has a ton of great features such as:
Save Position or Selection
Then later, Restore the Position or Selection
Get selection HTML or Plaintext
Among many others
The online demo was not working last I checked, however the repo has working demos. To get started, simple download the Repo from Git or NPM, then open ./rangy/demos/index.html
It makes working with caret pos and text selection a breeze!

How I can keep the cursor in its position in textarea after auto-submitting?

I have a form and textarea, I do auto submit for form after x seconds ... But every time auto submit is done the cursor jumps out of textarea ...
so how can I keep the cursor after submitting in old position in texrarea ?
In your auto submit code get the current position of the cursor in the textarea. You can do it with this function (where id is the id attribute of the textarea element):
function getCaretPosition(id) {
var txt = document.getElementById(id);
var startPos = txt.selectionStart;
var endPos = txt.selectionEnd;
return endPos;
}
Than store the the value somewhere (in localstorage for instance), and after the form submit restore the cursor position with this function:
function setCaretPosition(id) {
var txt = document.getElementById(id);
if(txt.createTextRange) {
var range = txt.createTextRange();
range.collapse(true);
range.moveEnd('character', caretPos);
range.moveStart('character', caretPos);
range.select();
return;
}
if(txt.selectionStart) {
txt.focus();
txt.setSelectionRange(caretPos, caretPos);
}
}
where the caretPos is the cursor position stored before the submit. Here is simple demo to see how the functions work https://jsfiddle.net/p0oc8tjs/2/
Use the autofocus textarea attribute. Example:
<textarea autofocus></textarea>
This Boolean attribute lets you specify that a form control should
have input focus when the page loads, unless the user overrides it,
for example by typing in a different control. Only one form-associated
element in a document can have this attribute specified.
If you still want to use script and set the last cursor position, than using sessionStorage you can do:
$.fn.getCursorPosition = function() {
var el = $(this).get(0);
var pos = 0;
if('selectionStart' in el) {
pos = el.selectionStart;
} else if('selection' in document) {
el.focus();
var Sel = document.selection.createRange();
var SelLength = document.selection.createRange().text.length;
Sel.moveStart('character', -el.value.length);
pos = Sel.text.length - SelLength;
}
return pos;
};
$.fn.selectRange = function(start, end) {
if(end === undefined) {
end = start;
};
return this.each(function() {
if('selectionStart' in this) {
this.selectionStart = start;
this.selectionEnd = end;
} else if(this.setSelectionRange) {
this.setSelectionRange(start, end);
} else if(this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
});
};
var textarea = $('.remember-cursor');
textarea.on('input click keyup', function(e) {
sessionStorage.cursorPosition = textarea.getCursorPosition();
});
$(document).on('ready', function(e) {
textarea.focus().selectRange( sessionStorage.cursorPosition );
});
$('button').on('click', function(e) {
$(document).trigger('ready');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea class="remember-cursor">adsfsadfsad</textarea>
<button>Trigger DOM ready</button>
Thanks to this posts and answers:
Cursor position in a textarea
jQuery Set Cursor Position in Text Area
Also on JSFiddle.
Still, I do not think this is a correct way to do it. You should post your data via AJAX and collect results.

Setting a Range for a Textarea based on User Input

I have a textarea and I'm trying to check if someone enters {{link that I can have a modal pop up to let them complete some information.
What I have now is that if someone enters the letter k, it will go back 6 characters and then determine if the text matches {{link
But I'm having a problem in setting setting the start and end points for the range. I think that the problem is with identifying the node, but I'm not sure.
Mainly when someone enters a the letter "k", I'm just trying to go back to check if they had typed: {{link and if they did, it would launch a modal.
This is what I have that isn't working at the part where I'm trying to set the range and get the selection.
$(document).on('keyup', 'textarea', function(e) {
if (e.keyCode == 75) {
var end = $('textarea').getCaretPosition();
var start = end - 6;
var node = $(this).get(0);
var range = document.createRange();
range.setStart(node, start);
range.setEnd(node, end);
var selection = range.toString();
if( selection == '{{link' ){
// we'll launch a modal here
}
}
});
$.fn.getCaretPosition = function() {
var el = $(this).get(0);
var pos = 0;
if ('selectionStart' in el) {
pos = el.selectionStart;
} else if ('selection' in document) {
el.focus();
var Sel = document.selection.createRange();
var SelLength = document.selection.createRange().text.length;
Sel.moveStart('character', -el.value.length);
pos = Sel.text.length - SelLength;
}
return pos;
}
This generates the error: Uncaught Error: INDEX_SIZE_ERR: DOM Exception 1 at range.setStart(node, start);
Not sure if this is what you mean http://jsfiddle.net/sailorob/J6PVJ/

Setting marker position inside textarea

I'm looking for a way to set the text marker to the beginning of a textarea when there's a value set or text between the textarea tags. I couldn't find anything on it when searching. So, does anyone know how to go about doing this?
var el = document.getElementById("myTextArea");
if (typeof el.setSelectionRange != "undefined") {
el.setSelectionRange(0, 0);
} else if (typeof el.createTextRange != "undefined") {
var range = el.createTextRange();
range.collapse(true);
range.select();
}
The following should be something like what you're looking for, although I haven't tested it.
var el = document.getElementById("myTextArea");
// IE
if (document.selection) {
var sel = el.createTextRange();
sel.moveStart("character", 0);
}
// Others
else if ("setSelectionRange" in el) {
el.setSelectionRange(0, 0);
}

Categories