Визуальный HTML редактор своими руками |
Previous Top Next |
Визуальный HTML редактор своими руками
Здравствуйте, дорогие друзья. Понадобилась мне недавно компонента визуального html редактора. Сколько в internete не искал я информации по этому поводу - не нашел. В смысле, не нашел приемлемого решения, ведь платить $19.99 за одну компоненточку жалко. Поэтому сейчас я отмниму хлеб у некоторых компоненто-писателей и расскажу вам, как можно сделать полноценный html редактор своими руками, тем более, что для этого практически ничего не нежно.
Нам понадобится самая малость. В первую очередь - delphi 5-7 (у меня стоит 7-я версия, и весь код тестировался именно в этой версии). Такое ограничение версий вызвано тем, что компонент twebbrowser впервые "прописался" на вкладке internet именно в 5-й версии (в 4-й его надо было устанавливать как компонент activex). Еще необходимо, чтобы в системе был установлен internet explorer 4 и выше, по тем причинам, что именно его части являются основой webbrowser'a.
Сначала нам надо перевести webbrowser в режим редактирования. Для этого у каждого документа (согласно объектной модели это document) существует свойство designmode. Если установить его в 'on', то наша компонента автоматически переключается в режим редактирования, а если установить его в 'off', то компонент вернется в режим просмотра.
Проверим это! Создадим новую форму, разместим на ней компоненту twebbrowser и несколько компонент tspeedbutton. Затем напишем такой код:
Code: |
unit main;
interface ...
var form1: tform1; disp: idispatch; editor: ihtmldocument2;
implementation
{$r *.dfm}
procedure tform1.webbrowser1documentcomplete(sender: tobject; const pdisp: idispatch; var url: olevariant); var currentwb: iwebbrowser; editor: ihtmldocument2; begin disp:=pdisp; end;
procedure tform1.speedbutton1click(sender: tobject); var currentwb: iwebbrowser; begin currentwb := disp as iwebbrowser; editor:=(currentwb.document as ihtmldocument2); editor.designmode := 'on';
end; procedure tform1.formcreate(sender: tobject); begin webbrowser1.navigate('about:<html><body></body></html>'); end; |
Теперь по порядку о том, что мы написали. В событии oncreate формы мы загружаем в браузер простую страницу (напомню, что протокол about: позволяет загружать в браузер html строку). Это необходимо для того, чтобы в последующем мы могли обращаться к документу. Сразу после этого будет вызван обработчик события ondocumentcomplete. Но пока еще ничего не произошло. Внимательный читатель мог обратить внимание, что для перевода браузера в режим редактирования надо нажать кнопку 1. editor - это экземпляр нашего документа (document). Его свойство designmode устанавливается в 'on'. Теперь наш редактор практически готов. Он уже умеет править текст, копировать/вырезать/вставлять текст и картинки, делать текст жирным/подчеркнутым/наклонным. Для этого есть соответствующие комбинации клавиш.
Стандартые сочетания клавиш
ctrl + c |
Копировать |
ctrl + x |
Вырезать |
ctrl + v |
Вставить |
ctrl + b |
Жирный текст |
ctrl + i |
Наклонный текст |
ctrl + u |
Подчеркнутый текст |
ctrl + z |
Отменить |
ctrl + y |
Повторить |
ctrl + k |
Гиперссылка |
ctrl + f |
Найти |
ctrl + a |
Выделить всё |
ctrl + left-click |
Выделить блок |
"Это, конечно, хорошо, что есть горячие клавиши, но мне не хотелось бы все их запоминать" - можете сказать вы. Хорошо. Тогда давайте разберем, как из delphi заставить webbrowser выполнять все эти действия. Для этого есть метод execcommand интерфейса ihtmltxtrange (он описан в модуле mshtml_tlb). Рассмотрим простой пример.
Code: |
procedure tform1.speedbutton2click(sender: tobject); var range: ihtmltxtrange; begin range:=(editor.selection.createrange as ihtmltxtrange); range.execcommand('bold',false,emptyparam) end; |
Сначала в этой процедуре создается объект range. После этого вызывается метод execcommand:
function execcommand(cmdid: widestring; showui: wordbool; value: olevariant): wordbool;
cmdid – это строка идентификатор команды (в нашем примере 'bold' заставляет редактор переключаться между жирным и обычным начертанием текста); полный список команд смотри в приложении.
showui – show user interface - показывать интерфейс пользователя (если таковой имеется, как правило это различные диалоговые окна). Если параметр равен false, то команда выполняется без предупреждения.
value – содержит дополнительную информацию в зависимости от команды.
Несколько слов об объекте range. Помимо уже знакомого нам execcommand этот объект обладает еще рядом свойств и методов, некоторые из которых сейчас рассмотрим.
text |
widestring |
Содержит текст выделения (без тегов html) |
htmltext |
widestring |
Полный текст выделения |
movestart(const unit_:widestring; |
procedure |
Перемещает начальную позицию выделения на count символов вправо (если count<0, то влево), unit_-единицы измерения смещения (чаще всего используется 'character': 1 символ). При этом конечная позиция не смещается. |
movestart(const unit_:widestring;count:integer) |
procedure |
То же самое, только для конечной позиции выделения. |
pastehtml(const html: widestring); |
procedure |
Вставляет html-строку |
execcommandshowhelp(cmdid: widestring); |
function, |
Отображает помощь по команде, указанной в cmdid |
Пожалуй, на сегодня всё. Об остальных объектах (картинки, таблицы, элементы управления) поговорим в другой раз. Будут вопросы - пишите: samum2000@mail15.com.
Приложение.
Доступные команды
backcolor |
Устанавливает или получает цвет фона текущего выделения. value должно содержать имя цвета или его шеснадцитиричный rgb эквивалент (например, #ffcc00). |
bold |
Переключает начертание текста текущего выделения между полужирным и нормальным. |
copy |
Копирует выделение в буфер обмена |
createbookmark |
Получает имя якоря или создает его для текущего выделения. value - строка, содержащая имя якоря. |
createlink |
Получает url ссылки или создает новую ссылку. Параметр value должен содержать url. |
cut |
Вырезает текущее выделение в буфер обмена. |
delete |
Очищает текущее выделение (удаляет всё его содержимое). |
find |
Находит текст, заданный в параметре value в текущем выделении. |
fontname |
Устанавливает шрифт для текущего выделения. value содержит описание этого шрифта (как в теге font). |
fontsize |
Устанавливает размер шрифта. value - число от 1 до 7 включительно. |
forecolor |
Устанавливает цвет текста. value должно содержать имя цвета или его шеснадцитиричный rgb эквивалент (например, #ffcc00) |
formatblock |
Устанавливает или получает форматирование текущего блока. value может содержать теги-описатели. |
indent |
Увеличивает отступ выделенного текста на одну единицу приращения |
insertbutton |
Записывает идентификатор кнопки вместо текущего выделения. value - строка, содержащая идентификатор кнопки. |
insertfieldset |
То же для поля ввода. |
inserthorizontalrule |
То же для горизонтальной полосы. |
insertiframe |
То же для встроеных фреймов (iframe). |
insertimage |
То же для изображений. |
insertinputbutton |
То же для кнопки. |
insertinputcheckbox |
То же для чекбоксов (checkbox). |
insertinputfileupload |
То же для элемента выбора файла. |
insertinputhidden |
То же для скрытого поля (hidden) |
insertinputimage |
То же для изображения. |
insertinputpassword |
То же для поля ввода пароля. |
insertinputradio |
То же для радио-кнопок (radio) |
insertinputreset |
То же для кнопки reset. |
insertinputsubmit |
То же для кнопки submit. |
insertinputtext |
То же для поля ввода текста. |
insertparagraph |
Вставляет новый раздел (абзац). |
insertorderedlist |
Переключает стиль текущего выделения между списком и простым текстом. |
insertunorderedlist |
То же самое. |
insertselectdropdown |
Записывает элемент drop-down вместо текущего выделения. value должно содержать идентификатор элемента. |
inserttextarea |
То же для элемента textarea. |
italic |
Переключает начертание текста текущего выделения между наклонным и обычным. |
justifycenter |
Устанавливает выравнивание по центру для всего блока, в котором расположено текущее выделение. |
justifyleft |
Устанавливает выравнивание по левому краю для всего блока, в котором расположено текущее выделение. |
justifyright |
Устанавливает выравнивание по правому краю для всего блока, в котором расположено текущее выделение. |
outdent |
Уменьшает отступ для всего блока, в котором расположено выделение, на одну единицу. |
overwrite |
Переключается между режимами вставки текста и замены текста при вводе. value: true - замена, false - вставка. |
paste |
Вставляет текст из буфера обмена вместо текущего выделения. |
refresh |
Обновляет текущий документ. |
removeformat |
Удаляет из текущего фрагмента все теги форматирования |
selectall |
Выделяет все содержимое документа. |
unbookmark |
Удаляет все закладки из текущего выделения. |
underline |
Переключает начертание текста текущего выделения между подчеркнутым и обычным. |
unlink |
Удаляет все гиперссылки из текущего выделенного фрагмента. |
unselect |
Снимает выделение. |
Часть ii.
В прошлый раз речь шла о том, как работать с текстом в html редакторе. В этот раз мы поговорим о том, как работать с другими объектами html страниц - контролами. К ним относятся всевозможные элементы управления, изображения, фреймы, таблицы.
Рассмотрим общий принцип работы с этими элементами. Как и в случае с текстом, прежде всего надо создать объект-выделение (назовем его range):
range: ihtmlcontrolrange;
Интерфейс ihtmlcontrolrange предназначен специально для выполнения различных операций с выделенными объектами страницы, однако, его совершенно невозможно применять для работы с текстовым выделением - вы получите исключительную ситуацию eintfcasterror с сообщением о том, что выбраннй интерфейс не поддерживается (тоже самое будет, если использовать ihtmltxtrange для работы с контролами). Чтобы избегать подобных ситуаций, в интерфейсе ihtmlselectionobject введено поле type_: widestring. В зависимости от типа выделения оно будет содержать 'control' или 'text' (если ничего не выделено, то это поле будет содежать 'none'). Вот простой пример того, как можно вставить картинку в определенное место документа (как открыть документ в режиме редактирования было описано в первой статейке):
Code: |
procedure tform1.speedbutton13click(sender: tobject); var ctrlrange: ihtmlcontrolrange; textrange: ihtmltxtrange; begin if editor.selection.type_='control' then begin ctrlrange:=(editor.selection.createrange as ihtmlcontrolrange); if not ctrlrange.querycommandenabled('insertimage') then application.messagebox('not supported!',''); else ctrlrange.execcommand('insertimage',false,'c:\my files\porshe1.jpg') end else begin textrange:=(editor.selection.createrange as ihtmltxtrange); textrange.execcommand('insertimage',false,'c:\my files\porshe1.jpg') end; end; |
Обратите внимание на то, что когда веделен объект, мы используем метод querycommandenabled чтобы убедиться, что данную комманду можно выполнить над выделенным контролом. Это связано с тем, что, например, встроенный фрейм нельзя заменить на картинку. На самом деле это проверка необязательная, но я все же рекомендую её проводить во избежание неприятных последствий. Еще один метод - querycommandsupported(cmdid: widestring): boolean позволяет выянить, поддерживается ли данная комманда данным типом выделения. Такие же методы есть и у интерфейса ihtmltxtrange, но в данном случае в них нет необходимости.
С таблицами дело обстоит гораздо сложнеее. Контролы типа htmltable, htmlrow и htmlcell, согласно документации от microsoft, предназначены для создания таблиц при формировании страницы на стороне сервера. Соответсвенно, в нашем случае возникают некоторые трудности: в частности, как добавить полученную таблицу в документ (во всяком случае, у меня ничего не вышло). Как вариант я предлагаю следующее: создавать таблицу типа htmltable, работать с ней так, как будто мы формируем документ на сервере, а затем, использовать свойство outerhtml. Это поле содержит текстовое представление таблицы в формате html. Рассмотрим подробнее этот способ на примере:
Code: |
procedure tform1.speedbutton14click(sender: tobject); var table: htmltable; textrange: ihtmltxtrange; row: htmltablerow; col: htmltablecol; i: integer; begin if editor.selection.type_<>'control' then begin table:=(editor.createelement('table') as htmltable); for i:=0 to 3 do begin row:=(table.insertrow(i) as disphtmltablerow); col:=(row.insertcell(0) as disphtmltablecol); col.width:='200'; col.style.bordercolor:='#ff0000'; col.innertext:='Ячейка #'+inttostr(i); end; table.style.bordercolor:='#00ff00'; textrange:=(editor.selection.createrange as ihtmltxtrange); textrange.pastehtml(table.outerhtml); end; end; |
На мой взгляд, этот пример достаточно информативен. Очевидное преимущество использования объекта htmltable и сопутствующих ему объектов состоит в том, что программисту не надо беспокоится о том, как описать на html то или иное свойство таблицы, нет необходимости работать со строками, писать парсеры и т.п. - таблица сама себя опишет. Однако, очевидным недостатком такого метода является то, что в последствии невозможно будет обратиться к созданной таблице как к объекту, и изменить её програмным методом (использование парсеров и интерпритаторов кода в расчет брать не будем).
[Дополнение от 27.07.2004:
Я еще несколько раз прочитал msdn и нашел таки способ нормально работать с таблицами и ячейками. Вот простой пример того, как можно заменить текст в уже созданной таблице:
Code: |
var i, j: integer; ovtable: olevariant; t: htmltable; begin // В документе должна быть таблица, описанная примерно так: //<table ... id="mytable">
ovtable := webbrowser1.oleobject.document.getelementsbyname('mytable').item(0); //webbrowser1.oleobject.document.getelementsbyname('mytable') - //это коллекция элементов (ведь несколько элементов могут иметь //id равный "mytable" for i := 0 to (ovtable.rows.length - 1) do for j := 0 to (ovtable.rows.item(i).cells.length - 1) do ovtable.rows.item(i).cells.item(j).innertext:='new text!'; end; |
То есть теперь у нас есть возможность как получать данные из таблицы, так и заносить их туда в любой момент времени. Все свойства соответствуют свойствам dom. Остается только сказать, что таким образом можно работать и с формами, и с изображениями, в общем со всем, что поддерживается в Объектной модели докумета (dom).]
Если вы знаете более изящный способ работы с таблицами, или можете чем-то дополнить изложенное выше, очень прошу вас написать мне на e-mail : samum2000@mail15.com
Источник: www.samum2000.narod.ru
©Drkb::03541