Вставка кода в текстовые поля
4 апреля 2008, 12:11
Автор: Александр Бурцев [bur]
Задача: написать сценарий, способный обрамлять выделения в текстовых полях формы, любым кодом.
Определимся с терминолигией.
Текстовыми полями формы будем считать textarea и input type="text".
Выделением в этих полях будем считать установленный фокус или участок текста в случае, когда выделено несколько символов.
Необходимо написать JavaScript-сценарий, умеющий:
– запоминать пользовательское выделение
– обрамлять выделение с обеих сторон любыми текстовыми данными, например тегами.
– не терять выделение после обрамления.
Работающий пример:
JavaScript
// >>> За основу взят объект, написанный автором Sardar <Sardar@vingrad.ru>
// Массив экземпляров объекта
var textAreaSelectionObjects = [];
// Получаем экземпляр объекта
function getTextAreaSelection(id) {
if (typeof(textAreaSelectionObjects[id]) == "undefined") {
textAreaSelectionObjects[id] = new textAreaSelectionHelper(id);
}
return textAreaSelectionObjects[id];
}
// Конструктор, принимает в качестве аргумента ID текстарии
function textAreaSelectionHelper(id) {
var obj = document.getElementById(id);
this.target = obj;
// Создаем свойства carretHandler для доступа к объекту в контексте узла
// из обработчиков событий
this.target.carretHandler = this;
// Добавляем обработчик событий
this.target.onchange = _textareaSaver;
this.target.onclick = _textareaSaver;
this.target.onkeyup = _textareaSaver;
this.target.onfocus = _textareaSaver;
if(!document.selection) this.target.onSelect = _textareaSaver;
// Свойства для запоминания позиции выделения
this.start=-1;
this.end=-1;
this.scroll=-1;
this.iesel=null;
}
// В прототип записываем методы
textAreaSelectionHelper.prototype = {
// Получим выделение
getSelectedText : function() {
return this.iesel? this.iesel.text: (this.start>=0&&this.end>this.start)? this.target.value.substring(this.start,this.end): "";
},
// Установим текстовые фрагменты до выделения - text
// и после него, если нужно - secondtag
setSelectedText : function(text, secondtag) {
if (this.iesel) {
if (typeof(secondtag) == "string") {
var l = this.iesel.text.length;
this.iesel.text = text + this.iesel.text + secondtag;
this.iesel.moveEnd("character", -secondtag.length);
this.iesel.moveStart("character", -l);
} else {
this.iesel.text = text;
}
this.iesel.select();
} else if (this.start >= 0 && this.end >= this.start) {
var left = this.target.value.substring(0, this.start);
var right = this.target.value.substr(this.end);
var scont = this.target.value.substring(this.start, this.end);
if (typeof(secondtag) == "string") {
this.target.value = left + text + scont + secondtag + right;
this.end = this.target.selectionEnd=this.start+text.length+scont.length;
this.start = this.target.selectionStart = this.start + text.length;
} else {
this.target.value = left + text + right;
this.end = this.target.selectionEnd = this.start + text.length;
this.start = this.target.selectionStart = this.start + text.length;
}
this.target.scrollTop = this.scroll;
this.target.focus();
} else {
this.target.value += text + ((typeof(secondtag) == "string") ? secondtag: "");
if (this.scroll >= 0) this.target.scrollTop = this.scroll;
}
},
}
// Обработчик событий. Занимается сохранением информации о выделении и позиции скролла
function _textareaSaver() {
if(document.selection) {
this.carretHandler.iesel = document.selection.createRange().duplicate();
} else if(typeof(this.selectionStart) != "undefined") {
this.carretHandler.start = this.selectionStart;
this.carretHandler.end = this.selectionEnd;
this.carretHandler.scroll = this.scrollTop;
} else {
this.carretHandler.start = this.carretHandler.end = -1;
}
}
// Клиентские функции, хотя можно обойтись и без них
function setBold(id) { // Жирность
getTextAreaSelection(id).setSelectedText('<b>', '</b>');
}
function setItalic(id) { // Курсив
getTextAreaSelection(id).setSelectedText('<i>', '</i>');
}
function setUnderline(id) { // Подчеркивание
getTextAreaSelection(id).setSelectedText('<u>', '</u>');
}
// Массив экземпляров объекта
var textAreaSelectionObjects = [];
// Получаем экземпляр объекта
function getTextAreaSelection(id) {
if (typeof(textAreaSelectionObjects[id]) == "undefined") {
textAreaSelectionObjects[id] = new textAreaSelectionHelper(id);
}
return textAreaSelectionObjects[id];
}
// Конструктор, принимает в качестве аргумента ID текстарии
function textAreaSelectionHelper(id) {
var obj = document.getElementById(id);
this.target = obj;
// Создаем свойства carretHandler для доступа к объекту в контексте узла
// из обработчиков событий
this.target.carretHandler = this;
// Добавляем обработчик событий
this.target.onchange = _textareaSaver;
this.target.onclick = _textareaSaver;
this.target.onkeyup = _textareaSaver;
this.target.onfocus = _textareaSaver;
if(!document.selection) this.target.onSelect = _textareaSaver;
// Свойства для запоминания позиции выделения
this.start=-1;
this.end=-1;
this.scroll=-1;
this.iesel=null;
}
// В прототип записываем методы
textAreaSelectionHelper.prototype = {
// Получим выделение
getSelectedText : function() {
return this.iesel? this.iesel.text: (this.start>=0&&this.end>this.start)? this.target.value.substring(this.start,this.end): "";
},
// Установим текстовые фрагменты до выделения - text
// и после него, если нужно - secondtag
setSelectedText : function(text, secondtag) {
if (this.iesel) {
if (typeof(secondtag) == "string") {
var l = this.iesel.text.length;
this.iesel.text = text + this.iesel.text + secondtag;
this.iesel.moveEnd("character", -secondtag.length);
this.iesel.moveStart("character", -l);
} else {
this.iesel.text = text;
}
this.iesel.select();
} else if (this.start >= 0 && this.end >= this.start) {
var left = this.target.value.substring(0, this.start);
var right = this.target.value.substr(this.end);
var scont = this.target.value.substring(this.start, this.end);
if (typeof(secondtag) == "string") {
this.target.value = left + text + scont + secondtag + right;
this.end = this.target.selectionEnd=this.start+text.length+scont.length;
this.start = this.target.selectionStart = this.start + text.length;
} else {
this.target.value = left + text + right;
this.end = this.target.selectionEnd = this.start + text.length;
this.start = this.target.selectionStart = this.start + text.length;
}
this.target.scrollTop = this.scroll;
this.target.focus();
} else {
this.target.value += text + ((typeof(secondtag) == "string") ? secondtag: "");
if (this.scroll >= 0) this.target.scrollTop = this.scroll;
}
},
}
// Обработчик событий. Занимается сохранением информации о выделении и позиции скролла
function _textareaSaver() {
if(document.selection) {
this.carretHandler.iesel = document.selection.createRange().duplicate();
} else if(typeof(this.selectionStart) != "undefined") {
this.carretHandler.start = this.selectionStart;
this.carretHandler.end = this.selectionEnd;
this.carretHandler.scroll = this.scrollTop;
} else {
this.carretHandler.start = this.carretHandler.end = -1;
}
}
// Клиентские функции, хотя можно обойтись и без них
function setBold(id) { // Жирность
getTextAreaSelection(id).setSelectedText('<b>', '</b>');
}
function setItalic(id) { // Курсив
getTextAreaSelection(id).setSelectedText('<i>', '</i>');
}
function setUnderline(id) { // Подчеркивание
getTextAreaSelection(id).setSelectedText('<u>', '</u>');
}
HTML
<h1>Вставка тегов для текстарии</h1>
<input type="button" value="B" class="bold" onclick="setBold('textareaId');">
<input type="button" value="I" class="ital" onclick="setItalic('textareaId');">
<input type="button" value="U" class="under" onclick="setUnderline('textareaId');">
<textarea id="textareaId"></textarea>
<h1>Вставка тегов для текстового инпута</h1>
<input type="button" value="B" class="bold" onclick="setBold('inputId');">
<input type="button" value="I" class="ital" onclick="setItalic('inputId');">
<input type="button" value="U" class="under" onclick="setUnderline('inputId');">
<input type="text" id="inputId" value="">
<input type="button" value="B" class="bold" onclick="setBold('textareaId');">
<input type="button" value="I" class="ital" onclick="setItalic('textareaId');">
<input type="button" value="U" class="under" onclick="setUnderline('textareaId');">
<textarea id="textareaId"></textarea>
<h1>Вставка тегов для текстового инпута</h1>
<input type="button" value="B" class="bold" onclick="setBold('inputId');">
<input type="button" value="I" class="ital" onclick="setItalic('inputId');">
<input type="button" value="U" class="under" onclick="setUnderline('inputId');">
<input type="text" id="inputId" value="">
Снова JavaScript
// Инициализируем объекты, чтобы сразу отслеживать выделения
getTextAreaSelection('textareaId');
getTextAreaSelection('inputId');
getTextAreaSelection('textareaId');
getTextAreaSelection('inputId');
Замечание
В Opera до девятой версии скрипт работает нестабильно, т.к. в старых версиях этого браузера не было полноценных возможностей для обработки выделений. В худшем случае теги вставляются в конец текстовой области.© Все права на данную статью принадлежат порталу webew.ru. Перепечатка в интернет-изданиях разрешается только с указанием автора и прямой ссылки на оригинальную статью. Перепечатка в печатных изданиях допускается только с разрешения редакции.