Ничего лишнего
Vulk - Визуальный HTML-редактор - Как работает WYSIWYG-редактор?

Как работает WYSIWYG-редактор?

Ко мне регулярно обращаются посетители сайта с просьбами дать пояснения по работе моего визуального редактора и объяснить, как он работает, и как его применить для своих сайтов. Поэтому в этой статье я постараюсь максимально подробно описать работу всех его функций с точки зрения программиста. 

Что такое WYSIWYG и общий принцип работы

Аббревиатура WYSIWYG расшифровывается как «What You See Is What You Get» - что ты видишь, то и получишь, то есть смысл WYSIWYG-редактор в том, что при редактировании текста он выглядит так же, как будет выглядеть на странице сайта: тот же шрифт, межстрочный интервал, такого же цвета ссылки и т.д. Добавление новых элементов на страницу (ссылок, картинок, списков, таблиц и т.п.) происходит с помощью простого пользовательского интерфейса, таким образом любой человек, даже не знающий HTML, может редактировать страницу.

Каждый wysiwyg-редактор базируется на использовании фрейма, у которого свойство designMode установлено в состояние "On". Это переводит страницу в режим редактирования, когда изменения нужно сохранить, HTML-код получают из этого фрейма через свойство innerHTML и отправляют на сервер для сохранения.

Файлы Vulk Editor

Все файлы редактора в одном архиве Вы можете бесплатно скачать тут, всё то же самое посмотреть в действии можно на странице online-демонстрации. В архиве лежат файлы:

  1. VulkEditor.html - собственно страница с самим редактором;
  2. editor.js - все необходимые функции javascript;
  3. editor.css - стили для оформления редактора;
  4. canvas.html - страница для фрейма редактора, которая будет полем редактирования;
  5. canvas.css - стили для поля редактирования;
  6. папка images с иконками для кнопок.

Инициализация WYSIWYG-редактора

В коде страницы редактора располагается фрейм:

<iframe src="canvas.html" onLoad="editor_loaded();" scrolling="yes" frameborder="0" id="editor_frame" name="editor_frame" style="width:100%; height:300px;"></iframe>

Как видно, в нём будет отображаться страница canvas.html. Если открыть её исходный код, то будет видно, что в ней используется файл стилей canvas.css:

<link href="canvas.css" type="text/css" rel="stylesheet">

Эти стили идентичны стилям сайта, поэтому текст на странице canvas.html выглядит как на сайте. Так же будет и при редактировании, собственно за счёт этого и достигается эффект WYSIWYG.

Когда фрейм загружается, у него срабатывает событие onLoad и выполняется функция editor_loaded(). Она переводит фрейм в режим редактирования и вставляет в редактор текст, который надо отредактировать.


function editor_loaded() {
    f = document.getElementById('editor_frame');
    f.contentWindow.document.designMode = 'on';
    if (f.contentWindow.document.body) {
        f.contentWindow.document.body.innerHTML = document.getElementById('text_to_edit').innerHTML;
        document.all('edited_html').value = document.getElementById('text_to_edit').innerHTML;
    }
}


Текст для редактирования находится в блоке <div id="text_to_edit"></div>, document.getElementById('editor_frame') - это наш фрейм, в котором всё редактируется, document.all('edited_html') - это textarea, в которой будет html-код отредактированного текста.

Форматирование текста

Форматирование выделенного текста происходит с помощью функции editor_FormatText, она использует функцию javascript execCommand, которая позволяет выделять текст курсивом, подчёркиванием, жирным, выравнивать его по краям и по центру, и т.п. Операция, которая выполняется над текстом, подается в виде параметра.


function editor_FormatText(command, option) {
    editor_close_submenu();
    f = document.getElementById('editor_frame');
    f.contentWindow.document.execCommand(command, false, option);
}


Параметр command может принимать значения:

  • Copy - копировать текст;
  • Cut - вырезать текст;
  • Paste - вставить текст;
  • Bold - выделить жирным;
  • Italic - выделить курсивом;
  • Underline - выделить подчёркиванием;
  • removeformat - очистить форматирование текста;
  • Undo - отменить последнюю операцию;
  • Redo - повторить отменённую операцию;
  • JustifyLeft - выровнять абзац по левому краю;
  • JustifyCenter - выровнять абзац по центру страницы;
  • JustifyRight - выровнять абзац по правому краю;
  • JustifyFull - выровнять абзац по краям;
  • InsertUnorderedList - вставить маркированный список;
  • InsertOrderedList - вставить нумерованный список;
  • Indent - увеличить отступ;
  • Outdent - уменьшить отступ;
  • UnLink - удалить ссылку;
  • forecolor - выделить цветом (код цвета задаётся вторым параметром);
  • formatBlock - применить стиль к абзацу (<p>, <H1>, <H2> и т.д.).

Для вставки гиперссылки используется функция editor_createlink().


function editor_createlink() {
    if (document.getSelection) {
        editor_FormatText('CreateLink', prompt('Адрес','http://'));
    } else {
        editor_FormatText('CreateLink');
    }
}


Здесь так же используется функция editor_FormatText, но в отличие от всех других операций здесь требуется адрес ссылки. В браузере Internet Explorer диалоговое окно для запроса адреса ссылки открывается само, поэтому достаточно просто вызвать editor_FormatText('CreateLink'). В других браузерах из семейства Gecko (это FireFoxe, Opera и т.п.) приходится запрашивать адрес дополнительно, через функцию prompt().

Основное различие между этими браузерами (по крайней мере для WYSIWYG-редакторов) заключается в методе работы с выделениями. В IE используется document.selection(), а в других браузерах - document.getSelection(), поэтому различать разные браузеры можно по наличию этих функций. Далее при работе с выделенными областями текста я буду поступать так же.

Вставка html-кода

Вставка нового кода в страницу - это важнейшая функция редактора, она используется для добавления новых изображений, таблиц и произвольного кода (например, кода видеоплеера). Но для вставки нужно знать место на странице, где установлен курсор. Для этого есть переменная editor_range, которая объявляется в editor.js. Для вставки картинки или таблицы в редакторе открывается диалоговое окно, где нужно указать адрес изображения или количество столбцов таблицы. При этом фокус передаётся на другие поля ввода, так что положение курсора в редакторе нужно сохранять, прежде чем открыть диалоговое окно. Это делает функция editor_get_range().


function editor_get_range() {
    if (document.selection) {

        // для Internet Explorer
        editor_frame.focus();
        editor_range = editor_frame.document.selection.createRange();
    } else if (document.getSelection) {

        // для Gecko
        editor_range = document.getElementById('editor_frame').contentWindow.getSelection().getRangeAt(0).cloneRange();
    } else {

        // нет поддержки выделений
        alert('Браузер не поддерживает эту функцию! :(');
        editor_range = false;
    }
}


После того, как в диалоговом окне введены данные и нажата кнопка "Вставить", нужно выполнить непосредственную вставку кода. Опять же в зависимости от браузера, это реализуется разными способами в функции editor_PasteHTML.


function editor_PasteHTML(html) {
    if (editor_range.pasteHTML) {

        // для Internet Explorer
        editor_frame.focus();
        editor_range.pasteHTML(html);
        editor_range.select();
    } else {

        // для Gecko
        editor_FormatText('insertHTML', html);
    }
}


Диалоговые окна

Для выполнения некоторых действий в WYSIWYG-редакторе нужно открывать диалоговые окна, чтобы получить от пользователя данные. При открытии окна редактор закрывается полупрозрачным дивом, чтобы сделать недоступными все кнопочки, а сверху отображается диалоговое окно. Для этого есть функции открытия и закрытий окон - editor_open_dialog и editor_close_dialog


function editor_open_dialog(dialog, first_field) {
    document.all('editor_blocking').style.display = 'block';
    document.all('editor_select_style').disabled = 'disabled';
    document.all('editor_dialog_'+dialog).style.display = 'block';
    document.all(first_field).focus();
    document.all(first_field).select();
}


dialog - это id диалогового окна, first_field - это имя поля, которому передаётся фокус при открытии диалога.


function editor_close_dialog(dialog) {
    document.all('editor_blocking').style.display = 'none';
    document.all('editor_select_style').disabled = '';
    document.all('editor_dialog_'+dialog).style.display = 'none';
}


Сами диалоговые окна находятся в отдельных скрытых дивах, увидеть их можно в коде страницы редактора (VulkEditor.html).

Добавление произвольного HTML-кода:

<div id="editor_dialog_addhtml" class="dialog">

...

</div>

Добавление таблицы:

<div id="editor_dialog_addtable" class="dialog">

...

</div>

Свойства ячейки:

<div id="editor_dialog_cell" class="dialog">

...

</div>

Вставка рисунка:

<div id="editor_dialog_addimage" class="dialog">

...

</div>


Вставка изображения, таблицы и прочего кода делается через рассмотренную выше функцию editor_PasteHTML().




    © Vulk 2007-2014