1. Вы находитесь в архивной версии форума xaker.name. Здесь собраны темы с 2007 по 2012 год, большинство инструкций и мануалов уже неактуальны.
    Скрыть объявление

WYSIWYG HTML редактор в браузере

Тема в разделе "Разное", создана пользователем Koller, 10 ноя 2010.

  1. Koller

    Koller Исчез... Глобальный модератор

    Регистрация:
    3 ноя 2006
    Сообщения:
    401
    Симпатии:
    234
    Баллы:
    0
    В статье рассматриваются базовые принципы и проблемы унификации особенностей редактирования в современных браузерах. Темы рассматриваемые в статье:

    • Различные методы включения режима редактирования
    • Команды редактирования
    • 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="[COLOR="Red"]Apple-style-span[/COLOR]" style="[COLOR="Red"]font-size: 16px; font-weight: normal[/COLOR]; ">Text</span></h1>
    Редактирование объектов

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

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

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

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

    Команды редактирования

    В браузерах поддерживается множество команд редактирования. HTML генерируемый этими командами не стандартизирован и отличается от браузера к браузеру. Например, в IE «Bold» сгенерирует код:
    Код:
    1. <strong>Hello!</strong>
    Safari генерирует:
    Код:
    1. <span class="[COLOR="Red"]Apple-style-span[/COLOR]" style=[COLOR="Red"]"font-weight: bold;"[/COLOR]>hello!</span>
    Код, как минимум в IE, несколько старомоден. Во множестве команд используется ужасный тег font:
    Код:
    1. <FONT color=[COLOR="Green"]#ff0000[/COLOR]>23</FONT>
    Генерируемая разметка не является валидным XHTML и как правило даже валидным HTML кодом.

    Opera генерирует код сходный с IE (нет, не полностью), используя тег font и так далее.

    Safari генерирует форматирование используя span'ы и инлайн CSS. Достоинство подхода Safari в том, что он по крайней мере является валидным HTML 4.01 Strict.

    Mozilla поддерживает 2 режима работы — она либо генерирует презентационные теги как IE/Opera или же стилизирует контейнеры как Safari.

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

    Горячие сочетания клавиш

    Множество команд доступно через горячие сочетания клавиш, например Ctrl/Cmd + B для полужирного начертания, Ctrl/Cmd + Z для отмены последнего действия и т.д. Но эти сочетания могут различаться в зависимости от локализации браузера.

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

    API редактора

    Возможно, вы захотите сделать панель управления, что бы позволить пользователю использовать команды редактирования. Это можно сделать с использованием API редактора. Это API не похоже на обычное API DOM, на самом деле это скриптовая адаптация интерфейса IOleCommandTarget, который является COM интерфейсом используемым Microsoft для синхронизации панели управления и редактирования документа.

    API находится в объекте document и состоит из метода execCommand и нескольких методов с префиксом «query» которые возвращает информацию о команде.

    Все методы принимают ID команды в качестве первого аргумента, это строка, содержащая имя команды. Собственно, методы:

    ExecCommand

    Выполняет команду применительно к текущему выделению. Некоторые команды переключаются между состояниями в зависимости от контекста. Например, если вы применяете команду «Bold» к выделению, которое уже имеет полужирное начертание, то выделение будет отображено в нормальном начертании. Некоторые команды тредуют аргументов, например forecolor требует в качестве аргумента код цвета.

    Некоторые команды вызывают модальные диалоги — например, команда link вызовет диалог, который предложит ввести URL. Диалоги нельзя изменить, но возможно заменить их. Например:
    Код:
    1. result = document.execCommand(command, useDialog, value)
    Что есть что:
    command: Строка; имя команды.
    useDialog: Булев тип; Показывать ли встроенный диалог (Не все команды могут вызывать диалоги).
    value: Значение, принимаемое командой. Не все команды принимают значения; Если вызывает диалог, то значение береться из него.
    result: true если команда выполнена, false если отменена пользователем (закрытием диалога) или команда не может быть выполнена.

    Если выделения нет (только курсор), команды форматирования текста применяются по разному, в зависимости от браузера. Если курсор внутри слова, IE применит форматирование к слову; остальные браузеры применят его к следующему символу, который будет набран, если курсор не будет перемещен назад.

    QueryCommands


    Query-команды имеет смысл использовать для определения состояния кнопок на панели управления в зависимости от текущего выделения и положения курсора.

    QueryCommandEnabled


    Определяет возможно ли выполнение команды применительно к текущему выделению. Например «unlink» можно применить только в том случае, если курсор находится внутри ссылки. Если выделение содержит область недоступную для редактирования, то никакие команды выполнятся не будут.

    QueryCommandState

    Показывает была ли команда применена к выделению, тоесть если выделение имеет полужирное начертание, то QueryCommandState вернет true для команды bold.

    QueryCommandValue

    Возвращает значение некой команды для выделения. Значение соответствует тому, которое было задано при использовании execCommand, тоесть, например для ForeColor это будет код цвета (в виде строки) для текущего выделения.

    Формат будет отличаться в разных браузерах. Например, ForeColor возвращает шестнадцатеричное значение в IE (такое как #ff0000), а другие вернут RGB выражение, такое как Rgb(255,0,0).

    Некоторые значения вариируются в зависимости от локализации браузера, например значение для FormatBlock в IE вернет имя для параграфа на языке локализации интерфейса баузера.

    Команды, для которых значений нет, например bold, просто вернут false. (API содержит два дополнительных метода, queryCommandSupported и queryCommandIndeterminate, но они слишком глючные, что бы хоть как то их использовать.)

    Range и Selection API


    Встроенные команды полезны, но невозможно изменить их поведение или добавить нестандартную реализацию. Используя Range и Selection API вы можете использовать произвольные HTML трансформации, которые можно использовать для реализации нестандартных команд.

    Проблема в том, что любые трансформации затрагивающие DOM разрушают стек undo, который используется для реализации команд UnDo/ReDo. Это не слишком хорошо, но может быть приемлемой ценой за нестандартные команды.

    Range/selection API имеют два основных класса:

    Range — непрерывный диапазон символов документа. Диапазон может перекрывать границы элементов. У диапазона есть стартовая и конечная точки. Если стартовая точка совпадает с конечной, то диапазон называется вырожденным.

    Selection — представляет текущее пользовательское выделение в документе. Выделение содержит один подсвеченный диапазон. Если диапазон выделения вырожден, то он отображается как курсор. (Диапазоны и выделения могут быть использованы вне элементов в режиме редактирования. Вы можете создать выделение в документе, доступном только для чтения. Такое выделение, впрочем, не может быть вырожденным, так как курсор показывается только когда элемент в режиме редактирования.)

    Эти принципы идентичны во всех браузерах, но сами API отличаются по реализации в IE и всех остальных браузерах. IE использует собственное проприетарное решение для range м selection API, остальные браузеры используют W3C DOM Range API в комбинации с нестанжартизированным selection API.

    Основное отличие в том, что в IE содержимое диапазона доступно как строка с HTML разметкой. В W3C DOM Range API, содержимое диапазона доступно как дерево узлов DOM.

    Пример диапазона

    Что бы показать различные подходы, ниже приведена команда, которая применяет тег «code» к текущему выделению.

    В IE (editWindow это ссылка на frame в designMode):
    Код:
    1. var rng [COLOR="Green"]=[/COLOR] editWindow.[COLOR="DarkOrchid"]document.selection.createRange[/COLOR][COLOR="Green"]();[/COLOR]
    2. rng.[COLOR="DarkOrchid"]pasteHTML[/COLOR][COLOR="Green"]([/COLOR]"" + rng.[COLOR="DarkOrchid"]htmlText[/COLOR] + ""[COLOR="Green"]);[/COLOR]
    В Mozilla:
    Код:
    1. var rng = editWindow.[COLOR="DarkOrchid"]getSelection[/COLOR][COLOR="Green"]()[/COLOR].[COLOR="DarkOrchid"]getRangeAt[/COLOR]([COLOR="Red"][B]0[/B][/COLOR]);
    2. rng.[COLOR="DarkOrchid"]surroundContents[/COLOR][COLOR="Green"]([/COLOR]document.[COLOR="DarkOrchid"]createElement[/COLOR][COLOR="Green"]([/COLOR][COLOR="RoyalBlue"]"code"[/COLOR][COLOR="Green"]));[/COLOR]
    Выделение элементов управления

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

    В IE возможно выделение более, чем одного элемента одновременно с использование комбинации ctrl+клик. Остальные браузеры не поддерживают концепцию выделения элементов управления; в остальных браузерах выделение это всегда текстовый диапазон.

    Выводы

    Статья рассматривает основные принципы редактирования данных в браузере. Часть вторая статьи показывает множество примеров применения вышеописанных API.

    И пара ссылок на дополнительные материалы:
    (c) habrahabr.ru​
     
    1 человеку нравится это.

Поделиться этой страницей