<!---
soups up a textarea so it recognizes the tab key (and does other things to make coding suck less).
does NOT handle ajax concerns (ex. saving the code).
--->
<tag.js_headers expires="90">
function fcode(el) { // where el is a textarea
// soup-up the text area
var t = el;
$(t).attr('wrap','off');
t.last_range = [0,0];
t.is_focused = 0;
t.getVal = function() {
return this.happy_newlines(this.value);
}
t.setVal = function(str) {
this.value = str;
}
t.getRange = function() {
var pos = 0;
var _end = 0;
if (document.selection) { // IE Support
var range = document.selection.createRange();
var stored_range = range.duplicate();
stored_range.moveToElementText( this );
stored_range.setEndPoint( 'EndToEnd', range );
pos = this.happy_newlines(stored_range.text).length - this.happy_newlines(range.text).length;
_end = pos + this.happy_newlines(range.text).length;
}
else if (this.selectionStart || this.selectionStart == '0') { // Firefox support
pos = this.selectionStart;
_end = this.selectionEnd;
}
var _arr = [pos,_end];
this.last_range = _arr;
return _arr;
}
t.setRange = function(selectionStart, selectionEnd) {
if (typeof selectionStart == 'undefined') {
var selectionStart = this.last_range[0];
var selectionEnd = this.last_range[1];
}
else if (typeof selectionEnd == 'undefined') {
var selectionEnd = selectionStart;
}
if (this.setSelectionRange) {
this.focus();
this.setSelectionRange(selectionStart, selectionEnd);
}
else if (this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', selectionEnd);
range.moveStart('character', selectionStart);
range.select();
}
}
t.getScroll = function() {
var _arr = [this.scrollLeft,this.scrollTop];
this.last_scroll = _arr;
return _arr;
}
t.setScroll = function(x,y) {
if (typeof x == 'undefined' || typeof y == 'undefined') {
var x = this.last_scroll[0];
var y = this.last_scroll[1];
}
this.scrollLeft = x;
this.scrollTop = y;
var _arr = [x,y];
this.last_scroll = _arr;
return _arr;
}
$(t).blur(function() {
this.is_focused = 0;
try {
this.last_range = this.getRange();
} catch(err) { this.last_range = [0,0]; }
});
$(t).focus(function() {
this.is_focused = 1;
});
$(t).keydown(function(e) {
if (e.keyCode == 9) { // tab key
if (e.ctrlKey) { return false; } // control tab is supposed to be a browser move!
var _r = this.getRange();
var a = _r[0];
var b = _r[1];
var _s = this.getScroll();
var x = _s[0];
var y = _s[1];
var v = this.getVal()
if (a == b) { // insert tab char
var _pre = v.substring(0,a);
var _post = v.substring(a);
if (BROWSER_TYPE == 'IE') {
var _first_post_char = _post.substr(0,1);
if (_first_post_char == '\n') {
this.setVal(_pre + '\n\t' + _post.substring(1));
this.setRange(a+2);
}
else {
this.setVal(_pre + '\t' + _post);
this.setRange(a+1);
}
}
else {
this.setVal(_pre + '\t' + _post);
this.setRange(a+1);
}
}
else { // indent/outdent code
var _a = v.lastIndexOf('\n',a);
if (_a == -1) { var _a = 0; }
var _b = v.indexOf('\n',b);
if (_b == -1) { var _b = this.getVal().length; }
var _pre = v.substring(0,_a);
var _mid = v.substring(_a,_b);
var _post = v.substring(_b);
if (e.shiftKey) { // outdent
var _mid = _mid.replace(/\n( {1,7}|\t)/g,'\n');
if (_a == 0) { var _mid = _mid.replace(/^( {1,7}|\t)/g,''); }
this.setVal(_pre + _mid + _post);
}
else { // indent
var _mid = _mid.replace(/\n/g,'\n\t');
if (_a == 0) { var _mid = '\t' + _mid; }
this.setVal(_pre + _mid + _post);
}
this.setRange(_a,_a+_mid.length);
}
this.setScroll(x,y);
return false;
}
else if (e.keyCode == 13) { // enter
var _r = this.getRange();
var a = _r[0];
var b = _r[1];
var _s = this.getScroll();
var x = _s[0];
var y = _s[1];
var v = this.getVal()
var _pre = v.substring(0,a);
var _post = v.substring(a);
var _last_nl = _pre.lastIndexOf('\n',a);
if (_last_nl == -1) { var _last_nl = 0; }
var _line = v.substring(_last_nl,a);
if (_last_nl == 0) {
var _spaces = _line.match(/^([ \t]+)/);
}
else {
var _spaces = _line.replace('\n','').match(/^([ \t]+)/);
}
if (_spaces) {
var _txt = _spaces[0];
if (BROWSER_TYPE == 'IE') {
var _first_post_char = _post.substr(0,1);
if (_first_post_char == '\n') {
this.setVal(_pre + '\n\r' + _txt + _post.substring(1));
this.setRange(a+_txt.length+1);
}
else {
this.setVal(_pre + '\n\r' + _txt + _post);
this.setRange(a+_txt.length+1);
}
}
else {
this.setVal(_pre + '\n' + _txt + _post);
this.setRange(a+_txt.length+1);
}
this.setScroll(x,y+16);
return false;
}
}
});
$(t).keyup(function(e) {
if (e.keyCode == 9) { // tab key
return false;
}
else if (e.keyCode == 13) { // enter
return false;
}
});
t.happy_newlines = function(str) {
return str.replace(/(\r\n|\r|\n)/g,'\n');
}
}