I am making a web based code editor and am using a textarea for text editing. I want to add tab support to the textarea so that pressing tab doesn't de-focus the element.
I have the textarea defined like this:
<textarea id="codeEdit_txt" rows="50" cols="80" onkeydown="return codeEdit_keyDown(event);">
and the function codeEdit_keyDown defined as:
function codeEdit_keyDown(e) {
if (e.keyCode == 9) {
return false;
}
}
This prevents the tab key press from de-focusing the textarea, though it doesn't leave the tab character behind. While I was trying to get this to work initially, I noticed that if I defined the function as below, it would put a tab character at the cursor position.
function codeEdit_keyDown(e) {
if (e.keyCode == 9) {
alert("");
return false;
}
}
My two questions are:
Why does adding the alert cause a tab to be added?
Is there a way to add the tab at the cursor without having to find the cursor
position, split the text in the texarea and manually add a tab
character (and without having to have an alert every time the user pressed tab)?
Thanks
EDIT: This only seems to work in Chrome, not in IE, Safari or Firefox
See this question:
https://stackoverflow.com/a/13130/420001
You're looking for .preventDefault();
EDIT: A fiddle.
EDIT 2: A better fiddle, thanks to rainecc.
The other answer is nice, but it ends tabs at the end.
I looked up how to add the tab at the cursor location, and added that to the solution.
You can find the working code here: http://jsfiddle.net/felixc/o2ptfd5z/9/
Code inline as a safeguard:
function insertAtCursor(myField, myValue) {
//IE support
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
//MOZILLA and others
else if (myField.selectionStart || myField.selectionStart == '0') {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)
+ myValue
+ myField.value.substring(endPos, myField.value.length);
myField.selectionStart = startPos + myValue.length;
myField.selectionEnd = startPos + myValue.length;
} else {
myField.value += myValue;
}
}
function addTabSupport(elementID, tabString) {
// Get textarea element
var myInput = document.getElementById(elementID);
// At keydown: Add tab character at cursor location
function keyHandler(e) {
var TABKEY = 9;
if(e.keyCode == TABKEY) {
insertAtCursor(myInput, tabString);
if(e.preventDefault) {
e.preventDefault();
}
return false;
}
}
// Add keydown listener
if(myInput.addEventListener ) {
myInput.addEventListener('keydown',keyHandler,false);
} else if(myInput.attachEvent ) {
myInput.attachEvent('onkeydown',this.keyHandler); /* damn IE hack */
}
}
// easily add tab support to any textarea you like
addTabSupport("input", "\t");
<h1>Click in the text and hit tab</h1>
<textarea id="input" rows=10 cols=50>function custom(data){
return data;
}</textarea>
Here's what I used for my own editor (using some other answers) :
function insertAtCursor (el, text) {
text = text || '';
if (document.selection) {
// IE
el.focus();
var sel = document.selection.createRange();
sel.text = text;
} else if (el.selectionStart || el.selectionStart === 0) {
// Others
var startPos = el.selectionStart;
var endPos = el.selectionEnd;
el.value = el.value.substring(0, startPos) +
text +
el.value.substring(endPos, el.value.length);
el.selectionStart = startPos + text.length;
el.selectionEnd = startPos + text.length;
} else {
el.value += text;
}
};
document.querySelector("#editor").addEventListener("keydown", function(e) {
var TABKEY = 9;
if(e.keyCode == TABKEY) {
insertAtCursor(this, "\t");
if(e.preventDefault) {
e.preventDefault();
}
return false;
}
}, false);
Related
Friends ,I have a text box for date to be inserted by the user but i want it to allow user to insert only "dd" ,"mm" and "yyyy" values ,slashes(/)should be already present and as soon as the user inserts "dd" values the pointer should move directly behind the slash for "mm" value and on pressing backspace it should delete the "mm" or "dd "values not the slashes(/).
Here is what i have tried but it does not give me the desired result-
function dateCheck(){
var d_value=$("#pdate").val();
if(d_value.length =="2" || d_value.length =="5")
{
$('#pdate').val($('#pdate').val()+"/");
}
}
html code-
Date:<input type="text" name="p_date" id="pdate" onkeydown="dateCheck()" placeholder="DD/MM/YYYY" required />
There's probably plugins out there, but nobody's been too forthcoming with any. Here's something I've knocked up during my lunch break :).
It's not perfect, and could be improved with some tweaking. For example, highlighting multiple characters for deletion is a bit screwy, but hopefully it's not a bad starter for 10. Credit to this post for getting/setting the caret position. Also, it does allow invalid dates right now - 12/34/5678. It wouldn't be too difficult to sort that out. I might stick something on Git and finish it off when I get home.
I've hard-coded it for dd/mm/yyyy format, but, again, with improvments, it could use the user locale.
$.fn.textboxDatePicker = function() {
var _getCaret = function(el) {
if (el.selectionStart) {
return el.selectionStart;
} else if (document.selection) {
el.focus();
var r = document.selection.createRange();
if (r == null) {
return 0;
}
var re = el.createTextRange(), rc = re.duplicate();
re.moveToBookmark(r.getBookmark());
rc.setEndPoint('EndToStart', re);
return rc.text.length;
}
return 0;
};
var _setCaretPosition = function(elem, caretPos) {
if (caretPos == 2 || caretPos == 5) {
caretPos++;
}
if (elem != null) {
if (elem.createTextRange) {
var range = elem.createTextRange();
range.move('character', caretPos);
range.select();
} else {
if (elem.selectionStart) {
elem.focus();
elem.setSelectionRange(caretPos, caretPos);
}
else elem.focus();
}
}
};
$(this).val('dd/mm/yyyy');
$(this).on("keydown", function(e) {
var keyCode = e.which || e.charCode || e.keyCode;
var key = String.fromCharCode(keyCode);
// arrows, home, end
if ([35, 36].indexOf(keyCode) > -1) {
return true;
}
if (keyCode == 37) {
var newCaretPos = _getCaret(this) - 1;
if ([2, 5].indexOf(newCaretPos) > -1) {
_setCaretPosition(this, newCaretPos - 1);
return false;
}
return true;
}
if (keyCode == 39) {
var newCaretPos = _getCaret(this) + 1;
if ([2, 5].indexOf(newCaretPos) > -1) {
_setCaretPosition(this, newCaretPos + 1);
return false;
}
return true;
}
// backspace
if (keyCode == 8) {
var text = this.value;
var caret = _getCaret(this);
if (caret == 3 || caret == 6) {
caret = caret - 2;
} else {
caret--;
}
if (caret < 0) {
return false;
}
var output = text.substring(0, caret);
key = 'd';
if (caret > 2) {
key = 'm'
};
if (caret > 4) {
key = 'y'
};
this.value = output + key + text.substring(caret + 1);
_setCaretPosition(this, caret);
return false;
}
if (/[0-9]/.test(key)) {
var text = this.value;
var caret = _getCaret(this);
if (caret > 9) {
return false;
}
var output = text.substring(0, caret);
this.value = output + key + text.substring(caret + 1);
_setCaretPosition(this, caret + 1);
}
return false;
});
};
$('.date').textboxDatePicker();
UPDATE
Might be overthinking this. Could you just use 3 separate boxes and style them to look like one, with a little JS to sort out focusing between them?
https://jsfiddle.net/w9by2350/3/
MUCH cleaner!
Try it
function datecheck(){
value=$(#input_id).val();
if(value.match(/^\d\d?\/\d\d?\/\d\d\d\d$/){
return true;
}else{
alert("not valid format")
}
}
I have a textarea with a lot of text in it, and I have code so that when you press Shift+Enter, it will insert a piece of text. However, at the moment, as soon as that happens, the text scrolls so that the carets at the bottom of the screen.
My insert code:
$("#body textarea").bind('keydown', function(event) {
var caret = $("#body textarea").caret();
if(event.keyCode == 13 && event.shiftKey)
{
var text = "[br]"
insertText("#body textarea", caret.start, caret.end, text, "");
$("#body textarea").caret(caret.start+(text.length), caret.start+(text.length));
}
});
Does anyone know what I can do to stop it forcing the caret to the bottom?
Cheers
BlackWraith
I found on stackoverflow.com same trouble and make sample for you
http://jsfiddle.net/deerua/WAZBQ/
You can set the Caret Position manually after inserting your text:
See http://blog.vishalon.net/index.php/javascript-getting-and-setting-caret-position-in-textarea/:
function doGetCaretPosition (ctrl) {
var CaretPos = 0; // IE Support
if (document.selection) {
ctrl.focus ();
var Sel = document.selection.createRange ();
Sel.moveStart ('character', -ctrl.value.length);
CaretPos = Sel.text.length;
}
// Firefox support
else if (ctrl.selectionStart || ctrl.selectionStart == '0')
CaretPos = ctrl.selectionStart;
return (CaretPos);
}
function setCaretPosition(ctrl, pos){
if(ctrl.setSelectionRange)
{
ctrl.focus();
ctrl.setSelectionRange(pos,pos);
}
else if (ctrl.createTextRange) {
var range = ctrl.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}
ctrl is your textarea-element.
setCaretPosition(document.getElementById("textarea", 0);
I would like a textarea that handles a situation of pressing tab key.
In default case if you press a tab key then focus leaves the textarea. But what about the situation when user wants to type tab key in textarea?
Can I catch this event and return focus to the textarea and add a tab to a current cursor position?
You can: http://jsfiddle.net/sdDVf/8/.
$("textarea").keydown(function(e) {
if(e.keyCode === 9) { // tab was pressed
// get caret position/selection
var start = this.selectionStart;
var end = this.selectionEnd;
var $this = $(this);
var value = $this.val();
// set textarea value to: text before caret + tab + text after caret
$this.val(value.substring(0, start)
+ "\t"
+ value.substring(end));
// put caret at right position again (add one for the tab)
this.selectionStart = this.selectionEnd = start + 1;
// prevent the focus lose
e.preventDefault();
}
});
Here is a modified version of pimvdb's answer that doesn't need JQuery:
document.querySelector("textarea").addEventListener('keydown',function(e) {
if(e.keyCode === 9) { // tab was pressed
// get caret position/selection
var start = this.selectionStart;
var end = this.selectionEnd;
var target = e.target;
var value = target.value;
// set textarea value to: text before caret + tab + text after caret
target.value = value.substring(0, start)
+ "\t"
+ value.substring(end);
// put caret at right position again (add one for the tab)
this.selectionStart = this.selectionEnd = start + 1;
// prevent the focus lose
e.preventDefault();
}
},false);
I tested it in Firefox 21.0 and Chrome 27. Don't know if it works anywhere else.
Good god, all previous answers failed to provide the commonly decent (i.e. for programmers) tab control.
That is, a hitting TAB on selection of lines will indent those lines, and SHIFTTAB will un-indent them.
_edited (Nov 2016): keyCode replaced with charCode || keyCode, per KeyboardEvent.charCode - Web APIs | MDN
(function($) {
$.fn.enableSmartTab = function() {
var $this;
$this = $(this);
$this.keydown(function(e) {
var after, before, end, lastNewLine, changeLength, re, replace, selection, start, val;
if ((e.charCode === 9 || e.keyCode === 9) && !e.altKey && !e.ctrlKey && !e.metaKey) {
e.preventDefault();
start = this.selectionStart;
end = this.selectionEnd;
val = $this.val();
before = val.substring(0, start);
after = val.substring(end);
replace = true;
if (start !== end) {
selection = val.substring(start, end);
if (~selection.indexOf('\n')) {
replace = false;
changeLength = 0;
lastNewLine = before.lastIndexOf('\n');
if (!~lastNewLine) {
selection = before + selection;
changeLength = before.length;
before = '';
} else {
selection = before.substring(lastNewLine) + selection;
changeLength = before.length - lastNewLine;
before = before.substring(0, lastNewLine);
}
if (e.shiftKey) {
re = /(\n|^)(\t|[ ]{1,8})/g;
if (selection.match(re)) {
start--;
changeLength--;
}
selection = selection.replace(re, '$1');
} else {
selection = selection.replace(/(\n|^)/g, '$1\t');
start++;
changeLength++;
}
$this.val(before + selection + after);
this.selectionStart = start;
this.selectionEnd = start + selection.length - changeLength;
}
}
if (replace && !e.shiftKey) {
$this.val(before + '\t' + after);
this.selectionStart = this.selectionEnd = start + 1;
}
}
});
};
})(jQuery);
$(function() {
$("textarea").enableSmartTab();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea rows="10" cols="80">
/* Just some code to edit with our new superTab */
(function($) {
$.fn.enableSmartTab = function() {
$this = $(this);
$this.keydown(function(e) {
if ((e.charCode === 9 || e.keyCode === 9) && !e.metaKey && !e.ctrlKey && !e.altKey) {
e.preventDefault();
}
}
}
}
</textarea>
In Vanilla (Default) JS this would be:
var textareas = document.getElementsByTagName('textarea');
if ( textareas ) {
for ( var i = 0; i < textareas.length; i++ ) {
textareas[i].addEventListener( 'keydown', function ( e ) {
if ( e.which != 9 ) return;
var start = this.selectionStart;
var end = this.selectionEnd;
this.value = this.value.substr( 0, start ) + "\t" + this.value.substr( end );
this.selectionStart = this.selectionEnd = start + 1;
e.preventDefault();
return false;
});
}
}
textarea {
border: 1px solid #cfcfcf;
width: 100%;
margin-left: 0px;
top: 0px;
bottom: 0px;
position: absolute;
}
<textarea>
var x = 10;
var y = 10;
</textarea>
Found this while searching google. I made a really short one that can also indent and reverse indent selections of text:
jQ(document).on('keydown', 'textarea', function(e) {
if (e.keyCode !== 9) return;
var Z;
var S = this.selectionStart;
var E = Z = this.selectionEnd;
var A = this.value.slice(S, E);
A = A.split('\n');
if (!e.shiftKey)
for (var x in A) {
A[x] = '\t' + A[x];
Z++;
}
else
for (var x in A) {
if (A[x][0] == '\t')
A[x] = A[x].substr(1);
Z--;
}
A = A.join('\n');
this.value = this.value.slice(0, S) + A + this.value.slice(E);
this.selectionStart = S != E ? S : Z;;
this.selectionEnd = Z;
e.preventDefault();
});
Enable tabbing inside (multiple) textarea elements
Correcting #alexwells answer and enable a live demo
var textAreaArray = document.querySelectorAll("textarea");
for (var i = textAreaArray.length-1; i >=0;i--){
textAreaArray[i].addEventListener('keydown',function(e) {
if(e.keyCode === 9) { // tab was pressed
// get caret position/selection
var start = this.selectionStart;
var end = this.selectionEnd;
var target = e.target;
var value = target.value;
// set textarea value to: text before caret + tab + text after caret
target.value = value.substring(0, start)
+ "\t"
+ value.substring(end);
// put caret at right position again (add one for the tab)
this.selectionStart = this.selectionEnd = start + 1;
// prevent the focus lose
e.preventDefault();
}
},false);
}
<textarea rows="10" cols="80"></textarea>
<textarea rows="10" cols="80"></textarea>
I don't want to highlight text (by changing background color to yellow - NO), I just want to select a portion of the text inside textarea, exactly as if the user clicked and hold the click then moved the mouse to highlight only a portion of the text
How to do that? is it possible?
http://help.dottoro.com/ljtfkhio.php
Example 1 would be relevant in your case:
function Select () {
var input = document.getElementById ("myText");
if (input.selectionStart === undefined) { // Internet Explorer
var inputRange = input.createTextRange ();
inputRange.moveStart ("character", 1);
inputRange.collapse ();
inputRange.moveEnd ("character", 1);
inputRange.select ();
}
else { // Firefox, Opera, Google Chrome and Safari
input.selectionStart = 1;
input.selectionEnd = 2;
input.focus ();
}
}
In non-IE browsers, this is easy: you can set the values of the textarea's selectionStart and selectionEnd properties, or use the setSelectionRange() function (although I've never been clear why that method is present: it seems unnecessary). In IE, however, it's a bit more complicated. Here's a cross-browser function that does it:
var setInputSelection = (function() {
function offsetToRangeCharacterMove(el, offset) {
return offset - (el.value.slice(0, offset).split("\r\n").length - 1);
}
return function(el, startOffset, endOffset) {
el.focus();
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
el.selectionStart = startOffset;
el.selectionEnd = endOffset;
} else {
var range = el.createTextRange();
var startCharMove = offsetToRangeCharacterMove(el, startOffset);
range.collapse(true);
if (startOffset == endOffset) {
range.move("character", startCharMove);
} else {
range.moveEnd("character", offsetToRangeCharacterMove(el, endOffset));
range.moveStart("character", startCharMove);
}
range.select();
}
};
})();
var textarea = document.getElementById("foo");
// Select the text between the second and third characters inclusive
setInputSelection(textarea, 1, 3);
you can use this plugin
http://www.dennydotnet.com/post/TypeWatch-jQuery-Plugin.aspx
you have a callback function after the user has "finished" typing , and more things..
Is there anyway to check if the character at the cursor in TEXTAREA is a "space"? If it is, return TRUE. Let me know how to do this using jQuery.
Thanks
This works in recent versions of the main browsers and has the added bonus of not requiring jQuery or any other library:
function nextCharIsSpace(textArea) {
var selectedRange, range, selectionEndIndex;
// Non-IE browsers
if (typeof textArea.selectionEnd == "number") {
selectionEndIndex = textArea.selectionEnd;
}
// IE is more complicated
else if (document.selection && document.selection.createRange) {
textArea.focus();
selectedRange = document.selection.createRange();
range = selectedRange.duplicate();
range.moveToElementText(textArea);
range.setEndPoint("EndToEnd", selectedRange);
selectionEndIndex = range.text.length;
}
return textArea.value.charAt(selectionEndIndex) === " ";
}