Вставка кода в текстовые поля Сложность: средняя Сложность: средняя

Задача: написать сценарий, способный обрамлять выделения в текстовых полях формы, любым кодом.

Определимся с терминолигией.
Текстовыми полями формы будем считать textarea и input type="text".
Выделением в этих полях будем считать установленный фокус или участок текста в случае, когда выделено несколько символов.

Необходимо написать JavaScript-сценарий, умеющий:
- запоминать пользовательское выделение
- обрамлять выделение с обеих сторон любыми текстовыми данными, например тегами.
- не терять выделение после обрамления.

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>');
}

HTML
• Код 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="">

Снова JavaScript
• Код JavaScript
// Инициализируем объекты, чтобы сразу отслеживать выделения
getTextAreaSelection('textareaId');
getTextAreaSelection('inputId');

Смотрим пример обрамления выделелений в текстовых полях.

Замечание
В Opera до девятой версии скрипт работает нестабильно, т.к. в старых версиях этого браузера не было полноценных возможностей для обработки выделений. В худшем случае теги вставляются в конец текстовой области.



Комментарии [ Написать комментарий ]

Метки

AJAX Canvas & VML JS::Unsorted JS::Разработка JSправочник Дата и время Координаты, размеры, ресайз, скролл Обработка изображений Работа с DOM События (event) Строковые данные (String) Формы (<form>)

Полезные ссылки

DOM onReady на habr DomContentLoaded fixing Google Map API JavaScript 1.5 на Mozilla.org (eng) JavaScript и не только на suncloud (рус) Измерение размеров и полей элементов в ИЕ Нововведения в JavaScript 1.6 (eng) Правильный WYSIWYG (рус) Редактор jEdit Рисуем JavaScript-ом

Новый портал для web-программистов!

Рад вам сообщить, что открылся новый информационный проект о web-технологиях - webew.ru. Здесь вы найдете актуальные статьи по XML, HTML, PHP, MySQL, Javascript, SEO и др. Заходите, регистрируйтесь и оставляйте свои посты и комментарии!

Комментарии!

У вас появилась возможность добавлять комментарии. В конце каждой статьи найдется ссылка "Написать комментарий", открывающая форму. Новая возможность не требует авторизации. Просьба не злоупотреблять тем, что двери открыты ;)

Пишите...

Если вы увидели на fastcoder.org ошибку или неточность, захотели написать и разместить здесь свою статью или просто решили поблагодарить авторов за понравившийся скрипт - заходите сюда и отправляйте сообщения.