textarea tab2

insert tab character in textarea; no selection: at cursor, with selection: at start of line(s).

by Laurens Maneschijn

HTML

<input><br>
<textarea cols="100" rows="10">
aaa	
	bbb
		ccc

</textarea><br>
<input><br>
<hr>
<pre>
without selection:
	without shift: insert tab at cursor.
	with    shift: remove tab before cursor if there (inverse of above).
with selection:
	witout shift: for all lines that the selection covers; insert a tab at the start of line.
	with   shift: for all lines that the selection covers; remove a tab at the start of line (inverse of above).
</pre>

oneliner for bookmarklet:<br>
<input value="javascript:(function(){if(window.textareatabalreadyapplied){return;}window.textareatabalreadyapplied = true;var allowShiftTab = true;var tabChars = '\t';window.addEventListener('keydown',function(ev){var target,start,end,ostart,oend,step,text,newselectionstart,newselectionend;if(ev.keyCode == 9 && ev.target instanceof HTMLTextAreaElement){target = ev.target;if( target ){if(target.selectionEnd < target.selectionStart){start = target.selectionEnd;end   = target.selectionStart;}else{start = target.selectionStart;end   = target.selectionEnd;}step = tabChars.length;target.focus();text = '\n'+target.value.substring(0);ostart = start;oend = end;console.log(start,end);if(start==end){text = ''+target.value;if( allowShiftTab && ev.shiftKey ){if(start >= step && text.substring(start-step,start) == tabChars){target.value = text.substring(0, start-step) + text.substring(start);newselectionstart = newselectionendstart = start - step;target.setSelectionRange(newselectionstart, newselectionendstart);}}else{target.value = text.substring(0,start) + tabChars + text.substring(start);newselectionstart = newselectionendstart = start + step;target.setSelectionRange(newselectionstart, newselectionendstart);}}else{if( allowShiftTab && ev.shiftKey ){while(start > 0 && text.charAt(start) != '\n'){start--;}end++;if( text.substring(start,end).indexOf(tabChars)!=-1){ostart -= (text.substring(start,ostart).indexOf('\n'+tabChars)==-1?0:step);oend -=...

JavaScript

// should work as bookmarklet; just prepend with: `javascript:` and copy paste the rest after it:
// TODO: lots of code cleanup
(function(){
	if(window.textareatabalreadyapplied){
		return;
	}
	window.textareatabalreadyapplied = true;
	
	var allowShiftTab = true;
	var tabChars = '\t';
	
	window.addEventListener('keydown',function(ev){
		var target,start,end,ostart,oend,step,text,newselectionstart,newselectionend;
		if(ev.keyCode == 9 && ev.target instanceof HTMLTextAreaElement){
			target = ev.target;
			if( target ){
				// apparently it can be that target.selectionEnd < target.selectionStart; make sure start is the lowest one:
//				start = target.selectionStart;
//				end   = target.selectionEnd;
//				if(start>end){var t=end;start=end;start=t;}
				if(target.selectionEnd < target.selectionStart){
					start = target.selectionEnd;
					end   = target.selectionStart;
				}else{
					start = target.selectionStart;
					end   = target.selectionEnd;
				}
				
				step = tabChars.length;
				
				target.focus();	// TODO: not needed? focus should already be on element?
				
				// NB: prepend '\n' so it can be matched in pregmatch so a tab also gets inserted on first line
				// TODO: should only be needed for inserting?
				text = '\n'+target.value.substring(0);
				ostart = start;
				oend = end;
				
				
//				var linestart = start, lineend = end;
//				while(linestart > 0           && text.charAt(linestart) != '\n'){linestart--;}
//				while(lineend   < text.length && text.charAt(lineend)   != '\n'){lineend++;}

				// TODO: shift + noselection : remove tab before cursor instead of at start of line?
				console.log(start,end);
				if(start==end){
					// nothing selected; just insert a tab character at the current caret position:
					// (as if just typing a tab character)
					text = ''+target.value;
					if( allowShiftTab && ev.shiftKey ){
						// check if string before cursor position matches tab, and if so, remove it:
						if(start >= step &&...