| Код | var ZRGLF = function () { /* собсно это и есть типа индент такой, 4 пробела, можно и 2 или 20...*/ var p = ' '; /* инициализирующая функция, в ней вызов функции, прикрепляющей обработчик, первый аргумент - textarea, меняем его по-желанию или добавляем вызовы*/ function I() { E(document.getElementsByTagName('textarea')[0], 'keydown', F, 1); } /* функция, прикрепляющая обработчик, выглядит стрёмно, но я к ней привык последний параметр (s) может быть числом 1 (прикрепить) или 0 (открепить), но этому скрипту это по-барабану, объяснил, чтоб не пугались, остальные параметры обычные - объект, имя события, функция*/ function E(o, e, f, s) { var p = '', b = ['remove', 'add', 'detach', 'attach']; (o[b[s]+'EventListener'] || (p = 'on', o[b[s+2]+'Event']))(p + e, f, false); } /* основная функция, в ней всё и происходит*/ function F() { /* e - это объект события, он автоматом приходит в эту функцию первым аргументом, a - кнопки индента, b - кнопки анинтдента, n - textarea*/ var e = arguments[0], n = e.target, a = (e.ctrlKey && String.fromCharCode(e.keyCode).match(/^\u00FD|\]|\u042A$/i)), b = (e.ctrlKey && String.fromCharCode(e.keyCode).match(/^\u00FB|\[|\u0425$/i)); if (a || b) { /* если IE или Opera (они поддерживают selection)*/ if (document.selection) { var r = document.selection.createRange(), o = window.opera, r2, t, c = 'character'; /* идея в том, чтобы выделить ПОЛНОСТЬЮ строку (строки), где стоит курсор или где местами есть выделение, соответственно нам нужно расширить текстовый диапазон налево (направо) до метки новой строки (\r в IE) или (\n в Opera) или до начала/конца textarea value. Функция работает так: создаём дубликат диапазона, расширяем этот дубликат на 1 символ влево (вправо). Затем запускаем цикл, который должен остановиться, когда мы или упрёмся в метку новой строки или в начало (конец) textarea value. В цикле наращивается число шагов (i), на это самое число мы должны потом сдвинуть реальный диапазон (не дубликат). Параметр m - это или 'moveStart' (идём налево) или 'moveEnd' (идём направо), в первом случае шаг отрицательный, во втором - наоборот.*/ function F(m, n) { var r2 = r.duplicate(), l = r.text.length, s = (n) ? -1 : 1, i = 0; r2[m](c, s); while (r2.text.length > l && r2.text.charAt(n || r2.text.length - 1) != ((o) ? '\n' : '\r')) { l = r2.text.length; r2[m](c, s); i--; } return i; } /* расширяем диапазон влево*/ r.moveStart(c, F('moveStart', '0')); /* расширяем диапазон вправо, но предварительно определяем, не зацепили ли мы выделением скрытый символ \r справа, для этого создаём дубликат, делаем шаг вправо на один символ и сразу сравниваем длины текста в дубликате и текста в оригинале. Если разница = 3, то мы зацепили \r. В этом случае нам нет необходимости расширять диапазон вправо, а нужно сделать один шаг влево, чтобы убрать \r из диапазона*/ (((r2 = r.duplicate()).moveEnd(c, 1), r2.text.length) - r.text.length != 3) ? r.moveEnd(c, - F('moveEnd')) : r.moveEnd(c, -1); /*тут всё просто, меняем текст внутри текстового диапазона в зависимости от нажатых кнопок*/ r.text = (t = (b) ? r.text.split('\n' + p).join('\n').replace(eval('/^' + p + '/'), '') : p + r.text.split('\n').join('\n' + p)); /*двигаем диапазон, для Оперы на длину нового текста, а для IE с поправкой на скрытые \r*/ r.moveStart(c, (!o) ? t.split('\r').length - t.length - 1 : - t.length); /*выделяем*/ r.select(); /* если FF, Seamonkey и проч... (не поддерживают selection)*/ } else { /*по-моему всё более-менее понятно, выделяем вставляем, снова выделяем*/ var ss = 'selectionStart', se = 'selectionEnd', x = n[ss], y = n[se], l = n.value.length, z; x = (n[ss] = n.value.slice(0, x).lastIndexOf('\n') + 1); y = (n[se] = (((z = n.value.slice(y, l)).indexOf('\n') != -1) ? y + z.indexOf('\n') : l)); if (a) { n.value = n.value.slice(0, x) + p + n.value.slice(x, y).split('\n').join('\n' + p) + n.value.slice(y, l); n[ss] = x; n[se] = y + n.value.length - l; } else { n.value = n.value.slice(0, x) + n.value.slice(x, y).split('\n' + p).join('\n').replace(eval('/^' + p + '/'), '') + n.value.slice(y, n.value.length); n[ss] = x; n[se] = y - (l - n.value.length); } } /*отменяем стандартные действия для выбранных кнопок, Опера подглючивает*/ e.preventDefault ? e.preventDefault() : e.returnValue = false; return false; } } /*вешаем обработчик на окно*/ window.onload = I; /*вызываем самоё себя*/ }();
|
|