Профессиональные курсы: Практика верстки HTML JavaScript для начинающих Программирование на PHP Онлайн-курсы по веб-технологиям

Простейший WYSIWYG (визуальный редактор)

Задача: написать простейший визуальный редактор и немного разобраться как он работает.

  1. Простейший WYSIWYG (визуальный редактор)
  2. WYSIWYG: вставляем произвольный HTML-код

Что такое WYSIWYG?

WYSIWYG — аббревиатура What You See Is What You Get. В переводе: "что вижу, то и получаю". В висивиге можно просматривать и редактировать HTML-содержимое не редактируя HTML-код. Наиболее близкая аналогия ВИСИВИГу - это текстовый процессор от Microsoft Word, с которым многие знакомы. В нем, чтобы поставить жирность или курсив, не нужно писать теги или другие элементы форматирования, достаточно просто нажать соотствующую функциональную кнопку.

Как это работает?

Для написания простого ВИСИВИГа не нужно изобретать велосипед, все средства уже встроены и успешно работают. Механизм работы большинства визуальных редакторов основан на свойстве designMode объекта document. Это встроенное свойство (к сожалению, далеко не для всех браузеров, но для большинства современных) как раз и позволяет редактировать HTML-контент. После его активанции (designMode='On') на web-страницу можно ставить привычный нам курсор и набивать/удалять текст или изменять форматирование контента.

Бывает удобно не редактировать всю страницу, а иметь какую-то фиксированную область, для чего используется iframe. Именно его объект document используется для активации свойства designMode.

Форматирование содержимого в пределах ВИСИВИГа осуществляется с помощью непростого метода execCommand, реализация которого сильно различается от браузера к браузеру.

Смотрим JavaScript-код для простейшего ВИСИВИГа:

// ***********************
// ШАГ 1: Выводим iframe и получаем доступ к нему
// ***********************

// Выводим в HTML-поток iframe
document.write("<iframe scrolling='no' frameborder='no' src='#' id='frameId' name='frameId'></iframe><br/>");
// Определим Gecko-браузеры, т.к. они отличаются в своей работе от Оперы и IE
var isGecko = navigator.userAgent.toLowerCase().indexOf("gecko") != -1;
// Получаем доступ к объектам window & document для ифрейма
var iframe = (isGecko) ? document.getElementById("frameId") : frames["frameId"];
var iWin = (isGecko) ? iframe.contentWindow : iframe.window;
var iDoc = (isGecko) ? iframe.contentDocument : iframe.document;

// ***********************
// ШАГ 2: Добавим на пустую страницу ифрейма произвольный HTML-код
// ***********************

// Формируем HTML-код
iHTML = "<html><head>\n";
iHTML += "<style>\n";
iHTML += "body, div, p, td {font-size:12px; font-family:tahoma; margin:0px; padding:0px;}";
iHTML += "body {margin:5px;}";
iHTML += "</style>\n";
iHTML += "<body><u>Содержимое</u> с <b>HTML</b>-<i>разметкой</i></body>";
iHTML += "</html>";
// Добавляем его с помощью методов объекта document
iDoc.open();
iDoc.write(iHTML);
iDoc.close();

// ***********************
// ШАГ 3: Инициализация свойства designMode объекта document
// ***********************

if (!iDoc.designMode) alert("Визуальный режим редактирования не поддерживается Вашим браузером");
else iDoc.designMode = (isGecko) ? "on" : "On";

// ***********************
// ШАГ 4: Простейшие элементы редактирования: жирность, курсив, подчеркивание
// ***********************

// Выведем HTML-код этих элементов
document.write("<input type='button' value='Ж' onclick='setBold()' class='bold' />");
document.write("<input type='button' value='К' onclick='setItal()' class='ital' />");
document.write("<input type='button' value='Ч' onclick='setUnder()' class='under' />");
// Запишем код функции, для выставления форматирования
// Используется метод execCommand объекта document
function setBold() {
    iWin.focus();
    iWin.document.execCommand("bold", null, "");
}
function setItal() {
    iWin.focus();
    iWin.document.execCommand("italic", null, "");
}
function setUnder() {
    iWin.focus();
    iWin.document.execCommand("underline", null, "");
}

Пример работы простейшего ВИСИВИГа

Замечение:

Данная версия визуального редактора не может работать в Опере ниже версии 9.01 и покажет предупреждение "Визуальный режим редактирования не поддерживается Вашим браузером".

Работоспособность проверена в:

  • IE 6,
  • FF 1.5,
  • Opera 9.01 +,
  • Mozilla 1.7.2,
  • NN 7.1 +.

Александр Бурцев 1 сентября 2008

© Все права на данную статью принадлежат порталу fastcoder.org. Перепечатка в интернет-изданиях разрешается только с указанием автора и прямой ссылки на оригинальную статью. Перепечатка в печатных изданиях допускается только с разрешения редакции.

Комментарии

mindwork 3 сентября 2008, 11:25 #
Очень доступно спасибо !!!
Жду часть два - форматирование с помощью <h1></h1> и создание списков.
 
Bur 3 сентября 2008, 11:50 #
Со списками, как и со многими другими элементами форматирования всё довольно просто. Читайте статью "Список комманд для метода execCommand".

К примеру, нумерованный список по аналогии вставляется так:
function setOrderList() {
    iWin.focus();
    iWin.document.execCommand("InsertOrderedList", null, "");
}

С заголовками, как и со вставкой любого произвольного HTML-контента сложнее. Постараюсь описать это в отдельной статье.
 
aisthetes 14 октября 2008, 16:28 #
у меня возник вопрос: а как теперь форматированные данные в mysql записать? (сорри, в яве не шарю)
 
Bur 14 октября 2008, 16:37 #
Возможно, вы имеете в виду как получить форматированный текст из висивига и отправить на сервер?
Добавьте на страницу скрытую текстарию (которая, кстати, может быть видна при отключенном яваскрипте) и кнопку "Отправить".
При клике на кнопку в текстарию записывайте содержимое висивига, примерно так:

<form method="post" onsubmit="this.data.value=iDoc.body.innerHTML">
     <textarea id="dataId" name="data" />
     <input type="submit" value="Отправить" />
</form>
<script type="text/javascript">
    document.getElementById('dataId').style.display = 'none';
</script>


Совместите это с кодом висивига - должно помочь.
 
aisthetes 14 октября 2008, 17:21 #
сработало! а насчет отключенной явы можно и без нее:
<textarea name="data" style="display:none;"></textarea>
 
Bur 14 октября 2008, 17:23 #
Тогда при отключенном JavaScript текстария не будет видна и юзер не сможет ввести даже простой неотформатированный текст.
Смотрите сами, всё зависит от решаемой задачи.
 
Onuphriy 19 ноября 2009, 13:51 #
А не проще ли вместо невидимой <textarea> использовать <input type="hidden"> ?
 
Bur 19 ноября 2009, 14:31 #
Лучше позаботиться о пользователях без JavaScript и оставить им возможность ввода хотя бы в textarea.
 
sstib 15 октября 2008, 02:56 #
у меня по такому сценарию только в огнелисе корректно сработало..
остальные нормально выводят только неформатированный код...
 
Bur 15 октября 2008, 13:07 #
Попробуйте потестировать с помощью алерта:
onsubmit="alert(iDoc.body.innerHTML);"
 
So-author 17 января 2009, 14:39 #
Товарищи программисты, подскажите, может кто сталкивался. вобщем, проблема следующая: редактор сделал, данные нормально сохраняются в БД, все форматируется, но если вставлять большой кусок форматированного текста из Ворда - почему-то не сохраняет. причем, объем текста не влияет, а вот если там попадается допустим заголовки, или списки какие-то большие - вот тогда в БД не сохраняется =(
да, и еще вопрос сразу - много мусора в получаемом коде - можно как-нибудь малой кровью избавиться от него? или только через регулярные выражения?
Спасибо, заранее =)
 
So-author 17 января 2009, 14:46 #
аха, с первой проблемой разобрался. оказывается символ "разрыв строки" видимо расценивается как окончание фрагмента, и все, что после него отсекается. по крайней мере в БД не хочет сохранять.
 
kamagan 29 апреля 2009, 14:03 #
Автору огромное спасибо. Пользуясь этой и другими статьями сейчас пишу свой редактор.
Для отладки использую такой код.
<h3 onmousedown="document.getElementById('dataId').value=iDoc.body.innerHTML">Обновить</h3>
<form method="post" action="result.php" onsubmit="this.data.value=iDoc.body.innerHTML">
     <textarea id="dataId" name="data"></textarea>
     <input type="submit" value="Отправить" />
</form>

Т.е. при нажатии на слово "Обновить" можно просмотреть html-код который генерирует редактор. Может кому пригодиться.
 
RSV 3 декабря 2008, 17:51 #
Попробовал сделать UserControl.aspx. Испытываю в IE.
К сожалению, строка iDoc.designMode = (isGecko) ? "on" : "On";
не срабатывает. До присовения "On" iDoc.designMode = inherit, а после присвоения "On" становится равным "Off". Есть подозрение, что родительская страница блокирует изменения iDoc.designMode.
Буду благодарен за помощь. Уж очень не хочется использовать contentEditable
 
Bur 3 декабря 2008, 17:53 #
Код в студию.
 
nextkmv 14 мая 2009, 01:07 #
Спасибо за код очень помог. Возникла проблема при загрузки в редактор из сервера. Делаю так.
iHTML = "<?php echo $result_server; ?>";
iDoc.open();
iDoc.write(iHTML);
iDoc.close();


Если сервер возвращает просто текст, без тегов, то он спокойно попадает для редактирования. А вот если сервер возвращает HTML, что и требуется, то редактор просто не хочет работать.
Пробовал также записывать код вот сюда
window.frames["frameId"].document.body.innerHTML = "<?php echo $result_server; ?>";

Результат тот же. Что посоветуете?
 
Bur 14 мая 2009, 01:26 #
В JavaScript, в отличие от PHP, если в строке есть переносы строк, то их необходимо экранировать слэшами, иначе получим синтаксическую ошибку:
var goodMultyString = "First\
Second\
Third"
;

Возможно из-за этого у вас не работает скрипт?
 
nextkmv 14 мая 2009, 02:34 #
Благодарю, за скорую помощь.
Убрал средствами ПХП все символы перевода строки.
Потом еще косяк нашёл. Редактор при вставке ссылки использует вот такие кавычки
<a href="http://site.com">Сайт</a>

Заменил кавычки на одинарные ' теперь всё ништяк....
Примного благодарен!!!!!!
 
becool 15 мая 2009, 03:41 #
я конечно же опоздал, но можно делать примерно так:
<textarea id='someid' style='display:none;'><?=$text></textarea>
window.frames["frameId"].document.body.innerHTML =document.getElementById('someid').value


Таким образом не нужно изменять оригинальное форматирование текста и т.п.
 
Bur 15 мая 2009, 12:15 #
+1
Это более удобно, чем экранировать переносы и следить за кавычками на стороне сервера...
 
callisto 13 августа 2009, 14:35 #
Здравствуйте! Во-первых, спасибо большое за статью. Реально, единственная из миллиона, которая помогла.
Но есть один важный вопрос. Как быть, если я хочу поместить редактор в конкретном месте на странице. Пробовала вывсети iframe не через document.write, а сразу в htm'ой странице там, где нужно. Но тогда он почему перестаёт быть виден через document.getElementById("frameId").
Подскажите, пожалуйста, как быть.
 
Bur 13 августа 2009, 14:56 #
Хорошо бы ссылку на примерчик.
 
Onuphriy 16 ноября 2009, 20:46 #
Автору уважение за проделанную работу! Вопрос насчет безопасности: как это защитить от xss атак? Ведь если использовать функцию htmlspecialchars(), то она порежет все форматирование, т.е. текст покажет вместе с тегами. Спасибо.
 
Bur 17 ноября 2009, 14:56 #
Придется писать RegExp-фильтры на разрешенные теги, остальное заменять на html-сущности.
 
muns 16 декабря 2009, 22:49 #
А как можно почистить вставляемый из ворда текст?
 
Bur 17 декабря 2009, 02:14 #
Почистить от чего?
 
muns 17 декабря 2009, 20:27 #
от всего html кода, что бы вставлялся только текст, как в редакторе wordpress'а сделано
 
Bur 17 декабря 2009, 23:00 #
Воспользуйтесь командой RemoveFormat метода execCommand.
 
daima 16 июня 2010, 14:47 #
реализовал добавление смайликов
function setImage(url) {
iWin.focus();
iWin.document.execCommand("InsertImage", null, url);
}
но, если выделить добавленный смайл, то вокруг него появляется рамка и его можно растянуть. Более того, новый текст и смайлы можно после этого вводить только если щелкнуть вне ранее введенного смайла. Запрет на ресайз можно (правдо дост. криво) реализовать через css: img {width: auto !important; height: auto !important;}. А вот как победить остальные глюки?
 
 
Rambler's Top100 Flede HTML valid CSS valid