WYSIWYG HTML редактор в браузере. Часть 1

Автор оригинала: OLAV JUNKER KJÆR
  • Перевод
Это первая часть перевода статьи о свойствах designMode и contentEditable, их поведении и особенностях.

В статье рассматриваются базовые принципы и проблемы унификации особенностей редактирования в современных браузерах. Темы рассматриваемые в статье:
  • Различные методы включения режима редактирования
  • Команды редактирования
  • HTML генерируемый в процессе редактирования
  • Взаимодействие с DOM

Вступление


В самом первом браузере, созданном Тимом Бернесом-Ли в 1990 году, веб-страницы можно было редактировать непосредственно в браузере в WYSIWYG режиме. Веб рассматривался как среда доступная как для чтения так и для записи. Более поздние браузеры, однако, в основном, давали возможности только для чтения информации, исключая разве что ввод текста в поля ввода форм.

WYSIWYG редактирование в браузере снова стало нормой с выходом Internet Explorer 5: новое свойство designMode позволяло пользователю редактировать весь документ. Сначала эта особенность как то упускалась из виду, возможно, ввиду того, что появилась вместе с массой других не стандартных, доступных только под ОС Windows, проприетарных возможностей IE.

В последние годы остальные браузеры-конкуренты — Mozilla, Safari и Opera (примечание переводчика: Chrome на момент написания статьи еще не появился. Первая бета выйдет только через несколько месяцев.) — последовали примеру IE и тоже реализовали эту возможность. WHATWG работает над стандартизацией режима редактирования — свойства designMode и contentEditable представлены в HTML 5. Похоже что браузерное WYSIWYG редактирование все же становится неотъемлемой частью веба.

В статье рассматриваются базовые принципы и проблемы унификации особенностей редактирования в современных браузерах. Темы рассматриваемые в статье:
  • Различные методы включения режима редактирования
  • Команды редактирования
  • HTML генерируемый в процессе редактирования
  • Взаимодействие с DOM
Статья состоит из двух частей. Вторая часть будет более детально рассматривать применение редактора.

Примечание: Я рассматриваю только особенности редактирования в браузерах: Opera 9.5, Firefox 2+ и Safari 3, так как в предыдущих версиях редакторы были через-чур глючными и неполноценными. А редактор в IE практически не менялся с версии 5.5 )))

Обзор режима редактирования


Режим редактирования делает страницу или ее часть доступной для редактирования. Это выражается в том, что:
  • Курсор показывает текущую точку ввода. Пользователь может вводить текст, удалять его и т.д. используя клавиатуру или мышь.
  • Некоторые браузеры обеспечивают интерфейсы, позволяющие изменять и двигать изображения, таблицы и абсолютно позиционированные элементы.
  • Есть множество встроенных команд — Bold, Italic, InsertLink, Paste, Undo и так далее. (Полужирное начертание, курсивное начертание, вставить ссылку, вставить из буфера обмена, отменить действие и так далее.) Эти команды могут быть вызваны горячими комбинациями клавиш или с помощью скрипта с использованием соответствующего API.
  • С использованием Range и Selection API вы можете реализовать любые изменения в HTML. Это можно использовать для реализации нестандартных команд.
  • Режим редактирования позволяет изменять HTML. И все. Если вы, например, хотите выслать его на сервер, что бы сохранить изменения, то вам придется написать соответствующий скрипт.
Есть несколько оговорок в использовании режима редактирования:
  • Команды и поведение редактора в основном не описаны спецификацией и результирующий HTML код сильно отличается в разных браузерах.
  • Реализация в IE почти не менялась с выхода IE 5.5 (2000 год). HTML код, который он генерирует может сильно напугать чувствительных людей. Если вы думаете, что уже давным давно увидели последний в вашей жизни тег font, то вас ждет сюрприз! (Примечание переводчика: Уи-и-и-и-и-и-и-и!)


Включение режима редактирования


Есть два способа включения режима редактирования — свойства designMode и contentEditable.

Окно или фрейм становятся доступными для редактирования установкой свойства designMode объекта document в true. (Оговорка: В IE надо получить ссылку на document из объекта window.) Обычно редактируемый блок создается с использованием IFrame и designMode.

Любой элемент, содержащий текст, можно сделать редактируемым установкой свойства contentEditable в true. (contentEditable не поддерживается Firefox 2, поддержка появилась в Firefox 3. Так же она есть во всех актуальных версиях IE, Opera и Safari.)

Редактирование с помощью клавиатуры


Редактирование с помощью клавиатуры и мыши работает более менее так, как можно ожидать от простого текстового редактора. Курсор показывает точку ввода документа и ее можно перемещать по всему документу. Набор и удаление работают вполне предсказуемо. Выделение можно перемещать, удалять и перезаписывать.

Очень приятная особенность — по умолчанию работают redo и undo (запись и отмена действий). (Позже будет описано, как вызвать команду Undo.)

Сложности начинаются когда нажимаются кнопки Enter/Return. Не совсем понятно какой HTML код должен получится в результате и, действительно, этот код сильно отличается в различных браузерах и зависит от контекста. Если курсор находится внутри не пустого тега p, все браузеры закроют его и откроют новый (с теми же атрибутами) и переместят курсор в него. А Mozilla еще и вставит (излишний) элемент br после курсора. Например (в примерах символ вертикальной черты означает курсор):

  1. <p>bla bla|</p>


И нажатие Enter/Return в IE или Safari:
  1. <p>bla bla</p>
  2. <p>|</p>


Если курсор находится в конце не пустого элемента h1, все браузеры закроют h1, но IE и Opera вставят новый элемент p и поместят курсор в него. Safari вставит новый h1 элемент и поместит курсор внутрь. Mozilla не будет создавать никаких дополнительных элементов, но зачем то добавит два дополнительны тега br после курсора. Например:
  1. <h1>bla bla|</h1>

После нажатия Enter/Return в IE или Opera:
  1. <h1>bla bla</h1>
  2. <p>|</p>

А в Mozilla:
  1. <h1>bla bla</h1>
  2. |<br><br>

And in Safari:
  1. <h1>bla bla</h1>
  2. <h1>|</h1>
Если писать текст непосредственно в body (без каких либо элементов-оберток), и нажать Enter/Return, Mozilla вставит br. IE и Opera обернут предыдущий текст в p и создадут новый p. Safari вставит div.

Если набирать текст внутри div, Safari, Opera и IE закроют текущий элемент div и откроют новый. Mozilla вставит br и поместит курсор после него.

Если вокруг курсора несколько элементов-оберток, то все браузеры закроют (и дублируют) только обертку с наибольшей степенью вложенности. Курсор останется в обертке.

Примечание: Это жутковато! Неожиданно у IE оказался наиболее разумный подход всегда гарантирующий осмысленное применение блочных элементов. Mozilla ведет себя ужасно используя элементы br внутри блочных элементов, благодаря этому невозможно реализовать осмысленную стилизацию текста.

Позиционирование курсора


Курсор перемещается между символами. Не видно, как курсор позиционируется относительно тегов. Логика перемещения остается неизменной вне зависимости от браузера. Относительно блочных элементов: курсор всегда позиционируется внутри блочного элемента с наибольшей вложенностью. Например невозможно поместить курсор между двумя параграфами.

Например, посмотрите сюда; Символ вертикальной черты обозначает возможные положения курсора:
  1. <p>|P|1|</p><p>|P|2|</p>
  2. <div><p>|P|3|</p><div><p>|P|4|</p></div></div>
Относительно текстовых элементов, курсор позиционируется вне всех оберток, если находится слева от текста; если он находится в самой правой части, то помещается внутрь оберток. Например:
  1. <p>|A|<strong><em>B|</strong></em>C|</p>
Так что если вы набираете символы слева от полужирного текста, новый текст будет отображен в нормальном начертании. Если наберете справа, то он тоже будет полужирным.

Удаление


Если вы удаляете границу параграфа, результат будет неизменен: левый блок «побеждает» и содержимое правого блока включается в левый:
  1. <h1>Overskrift</h1><p>|Text</p>
Если вы нажмете Bk Sp, то получите:
  1. <h1>Overskrift|Text</h1>

Safari, впрочем, ведет себя умно (или ужасно, в зависимости от точки зрения) и сохраняет представление правого элемента неизменным:
  1. <h1>Overskrift|<span class="Apple-style-span" style="font-size: 16px; font-weight: normal; ">Text</span></h1>


Редактирование объектов


Браузеры поддерживают некоторые дополнительные интерфейсы для редактирования.

IE позволяет изменять размер изображений, таблиц, элементов форм или абсолютно позиционированных элементов перетягивая их уголки (когда объект выделен, то появляется соответствующий контейнер)

Mozilla тоже позволяет менять размер картинок и таблиц, но у нее есть еще и дополнительные элементы управления, которые позволяют создавать в таблице новые колонки и строки. Кроме того Mozilla позволяет изменять положение абсолютно позиционированных элементов.

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

От переводчика: Так как хабр отказался публиковать 35кб текста за раз, то разбиваю перевод на две части.

WYSIWYG HTML редактор в браузере. Часть 2
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

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

    +2
    1. <h1>Overskrift</h1><p>|Text</p>
    Если вы нажмете delete, то получите:
    1. <h1>Overskrift|Text</h1>

    Меня глючит или тут должен быть backspace а не delete, или курсор не там? (в оригинале так же)
      0
      В оригинале там именно delete, но вы определенно правы. Спасибо дважды.
      0
      Про Сафари явно взаимоисключающие параграфы :-)

      Надеюсь лет через 5 это стандартизируют.
        +5
        Искренне надеюсь, что раньше.
        Но сейчас «практическое применение» designMode и contentEditable описываются словосочетанием: «неописуемый ппц ».
        0
        Теперь понятно почему в генерируемый код отличается в разных браузерах (в моём случае с Elrte-редактором)
          +3
          Mazilla


          Это что за мазилла? :-)
            +1
            Спасибо, поправил.
            +1
            ага, только «автор» еще не упомянул момент изменения выделенного текста. В идеале там должно учитываться блочные элементы и не все учитывают их одинаково. А большинство визивигов вообще тупо оборачивают слева и справа без учета блочных элементов.

            Скажем:
            <p>asasasasasas [начало выделения] fsfsfs sfsdfs fsdfs</p>
            sfsdfsdfsd xvcvxcvx vxcvsfsfsdfsdf sfsdf
            
            <h1>a asda sdas dasdasd sdad a</h1>
            <p> sda sdadas [конец выделения] asdasda </p>
            


            и допустим надо все это сделать жирным. так вот большинство визивигов тупо вставить в начале и в конце. И это будет уже кривой дом. По-идее такие вещи должны как раз разлуривать броузеры когда «выполняешь команду редактора», но они тоже не все это делают одинаково, хотя большинство делает все правильно. в общем там хватаем тонкостей. Если визиг не занимает какое=то особое место в основном проекте, то лучше и не начинать писать его — запаришься потом фиксить под все броузеры-версии.
              0
              тупо вставит <b>в начале и </b>в конце. 
                0
                кстати, по-идее результат должен быть таким:
                <p>asasasasasas <b>fsfsfs sfsdfs fsdfs</b></p>
                <b>sfsdfsdfsd xvcvxcvx vxcvsfsfsdfsdf sfsdf</b>
                
                <h1><b>a asda sdas dasdasd sdad a</b></h1>
                <p><b>sda sdadas </b> asdasda </p>
                
                0
                У ИЕ еще особенность, не спрашивая находить при редактировании гиперссылки в тексте и обрамлять их в соответствующий тег. Писал в МС — отчеканили, что By Design. Отлавливайте сами, что было, а что он нагенерил.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое