tabIndent = { version: '0.1.8', config: { tab: ' '} , events: { keydown: function (e){ var tab = tabIndent.config.tab; var tabWidth = _AN_Read_length('length', tab); if (e.keyCode === 9) { e.preventDefault(); var currentStart = this.selectionStart, currentEnd = this.selectionEnd; if (e.shiftKey === false ) { if (!tabIndent.isMultiLine(this)) { this.value = this.value.slice(0, currentStart) + tab + this.value.slice(currentStart); this.selectionStart = currentStart + tabWidth; this.selectionEnd = currentEnd + tabWidth; } else { var startIndices = tabIndent.findStartIndices(this), l = _AN_Read_length('length', startIndices), newStart = undefined, newEnd = undefined, affectedRows = 0; while (l-- ){ var lowerBound = startIndices[l]; if (startIndices[l + 1] && currentStart != startIndices[l + 1]) lowerBound = startIndices[l + 1]; if (lowerBound >= currentStart && startIndices[l] < currentEnd) { this.value = this.value.slice(0, startIndices[l]) + tab + this.value.slice(startIndices[l]); newStart = startIndices[l]; if (!newEnd) newEnd = (startIndices[l + 1]? startIndices[l + 1] - 1: 'end'); affectedRows++ ; } } this.selectionStart = newStart; this.selectionEnd = (newEnd !== 'end'? newEnd + (tabWidth * affectedRows): _AN_Read_length('length', this.value)); } } else { if (!tabIndent.isMultiLine(this)) { if (this.value.substr(currentStart - tabWidth, tabWidth) == tab) { this.value = this.value.substr(0, currentStart - tabWidth) + this.value.substr(currentStart); this.selectionStart = currentStart - tabWidth; this.selectionEnd = currentEnd - tabWidth; } else if (this.value.substr(currentStart - 1, 1) == "\n" && this.value.substr(currentStart, tabWidth) == tab) { this.value = this.value.substring(0, currentStart) + this.value.substr(currentStart + tabWidth); this.selectionStart = currentStart; this.selectionEnd = currentEnd - tabWidth; } } else { var startIndices = tabIndent.findStartIndices(this), l = _AN_Read_length("length", startIndices), newStart = undefined, newEnd = undefined, affectedRows = 0; while (l-- ){ var lowerBound = startIndices[l]; if (startIndices[l + 1] && currentStart != startIndices[l + 1]) lowerBound = startIndices[l + 1]; if (lowerBound >= currentStart && startIndices[l] < currentEnd) { if (this.value.substr(startIndices[l], tabWidth) == tab) { this.value = this.value.slice(0, startIndices[l]) + this.value.slice(startIndices[l] + tabWidth); affectedRows++ ; } else { } newStart = startIndices[l]; if (!newEnd) newEnd = (startIndices[l + 1]? startIndices[l + 1] - 1: 'end'); } } this.selectionStart = newStart; this.selectionEnd = (newEnd !== 'end'? newEnd - (affectedRows * tabWidth): _AN_Read_length('length', this.value)); } } } else if (e.keyCode === 27) { tabIndent.events.disable(e); } else if (e.keyCode === 13 && e.shiftKey === false ) { var self = tabIndent, cursorPos = this.selectionStart, startIndices = self.findStartIndices(this), numStartIndices = _AN_Read_length('length', startIndices), startIndex = 0, endIndex = 0, tabMatch = new RegExp("^" + (_AN_Call_replace("replace", _AN_Call_replace("replace", tab, '\t', '\\t'), / /g, '\\s')) + "+", 'g'), lineText = ''; tabs = null ; for (var x = 0; x < numStartIndices; x++ ){ if (startIndices[x + 1] && (cursorPos >= startIndices[x]) && (cursorPos < startIndices[x + 1])) { startIndex = startIndices[x]; endIndex = startIndices[x + 1] - 1; break ; } else { startIndex = startIndices[numStartIndices - 1]; endIndex = _AN_Read_length('length', this.value); } } lineText = this.value.slice(startIndex, endIndex); tabs = lineText.match(tabMatch); if (tabs !== null ) { e.preventDefault(); var indentText = tabs[0]; var indentWidth = _AN_Read_length('length', indentText); var inLinePos = cursorPos - startIndex; if (indentWidth > inLinePos) { indentWidth = inLinePos; indentText = indentText.slice(0, inLinePos); } this.value = this.value.slice(0, cursorPos) + "\n" + indentText + this.value.slice(cursorPos); this.selectionStart = cursorPos + indentWidth + 1; this.selectionEnd = this.selectionStart; } } } , disable: function (e){ var events = this; tabIndent.remove(_AN_Read_target("target", e)); } , focus: function (){ var self = tabIndent, el = this, delayedRefocus = _AN_Call_settimeout("setTimeout", window, function (){ var classes = (_AN_Call_getattribute("getAttribute", el, 'class') || '').split(' '), contains = classes.indexOf('tabIndent'); el.addEventListener('keydown', self.events.keydown); if (contains !== -1) classes.splice(contains, 1); classes.push('tabIndent-rendered'); _AN_Call_setattribute('setAttribute', el, 'class', classes.join(' ')); el.removeEventListener('focus', self.events.keydown); } , 500); el.addEventListener('blur', function b(){ clearTimeout(delayedRefocus); el.removeEventListener('blur', b); } ); } } , render: function (el){ var self = this; if (el.nodeName === 'TEXTAREA') { el.addEventListener('focus', self.events.focus); el.addEventListener('blur', function b(e){ self.events.disable(e); } ); } } , renderAll: function (){ var textareas = _AN_Call_getelementsbytagname('getElementsByTagName', document, 'textarea'), t = _AN_Read_length('length', textareas), contains = -1, classes = [] , el = undefined; while (t-- ){ classes = (_AN_Call_getattribute('getAttribute', textareas[t], 'class') || '').split(' '); contains = classes.indexOf('tabIndent'); if (contains !== -1) { el = textareas[t]; this.render(el); } contains = -1; classes = [] ; el = undefined; } } , remove: function (el){ if (el.nodeName === 'TEXTAREA') { var classes = (_AN_Call_getattribute('getAttribute', el, 'class') || '').split(' '), contains = classes.indexOf('tabIndent-rendered'); if (contains !== -1) { el.removeEventListener('keydown', this.events.keydown); _AN_Write_backgroundimage('backgroundImage', el.style, false , ''); classes.splice(contains, 1); classes.push('tabIndent'); _AN_Call_setattribute('setAttribute', el, 'class', (_AN_Read_length('length', classes) > 1? classes.join(' '): classes[0])); } } } , removeAll: function (){ var textareas = _AN_Call_getelementsbytagname('getElementsByTagName', document, 'textarea'), t = _AN_Read_length('length', textareas), contains = -1, classes = [] , el = undefined; while (t-- ){ classes = (_AN_Call_getattribute('getAttribute', textareas[t], 'class') || '').split(' '); contains = classes.indexOf('tabIndent-rendered'); if (contains !== -1) { el = textareas[t]; this.remove(el); } contains = -1; classes = [] ; el = undefined; } } , isMultiLine: function (el){ var snippet = el.value.slice(el.selectionStart, el.selectionEnd), nlRegex = new RegExp(/\n/); if (nlRegex.test(snippet)) return true ; else return false ; } , findStartIndices: function (el){ var text = el.value, startIndices = [] , offset = 0; while (text.match(/\n/) && _AN_Read_length('length', text.match(/\n/)) > 0){ offset = (_AN_Read_length('length', startIndices) > 0? startIndices[_AN_Read_length('length', startIndices) - 1]: 0); var lineEnd = text.search("\n"); startIndices.push(lineEnd + offset + 1); text = text.substring(lineEnd + 1); } startIndices.unshift(0); return startIndices; } } ;