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

WYSIWYG: вставляем произвольный HTML-код

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

  1. Простейший WYSIWYG (визуальный редактор)
  2. WYSIWYG: вставляем произвольный HTML-код
Метод execCommand позволяет вставлять как простейшие элементы форматирования (жирность, курсив, подчеркивание), так и более сложные. Начнем с них.

Диалог с пользователем — создаем ссылки

Усложним код нашего простейшего висивига, добавив туда кнопку для добавления ссылок. Прежде чем добавить ссылку, необходимо спросить у пользователя её URL. Сделаем это с помощью метода prompt. Всего несколько строк кода необходимо добавить к текущему коду висивига, чтобы заработало добавление ссылок:

// Выведем HTML-код этих элементов
document.write("<input type='button' value='Link' onclick='setLink()' class='under' />");
// Запишем код функции для выставления форматирования
// Используется метод execCommand объекта document
function setLink() {
    var url = prompt("Введите URL:", "http://");
    if (!url) return;
    iWin.focus();
    iWin.document.execCommand("CreateLink", null, url);
}

Пример простейшего ВИСИВИГа с функцией добавления ссылок

Как видно из примера, метод execCommand принимает в качестве третьего аргумента параметр команды CreateLink — URL ссылки. Не только создание ссылки требует диалога с пользователем. Чтобы задать цвет текста или цвет фона (команды ForeColor и BackColor соот-но), необходимо попросить юзера выбрать этот цвет (обычно из какого-то списка), а затем передать его методу в формате #RRGGBB.

Вставляем произвольный HTML-контент

Вам необходимо вставить в визуальный редактор вполне конкретный HTML-код, например такой:

<h1 class="oranzh"></h1>

Метод execCommand бессилен для решении такой задачи. Необходимо собственное решение, например, такой обходной путь:

  • Чтобы поставить произвольное форматирование на выделенный фрагмент, воспользуемся командой forecolor, которая выставит цвет текста. Цвет специально подберем такой, которым пользуются нечасто.
  • В зависимости от браузера цвет выставляется либо с помощью <font color="#RRGGBB"></font> (IE, Opera), либо с помощью <span style="color:rgb(RR,GG,BB)"></span> (Gecko). Чтобы привести цвет к единому формату #RRGGBB воспользуемся функцией rgbNormal().
  • Пройдемся по всем узлам DOM-дерева документа, найдем фонты и спаны с нужным цветом и добавим в них необходимый HTML-код, не забывая почистить за собой. Обход по узлам — дело не простое. Т.к. мы удаляем узлы с нужным цветом, необходимо идти от самых вложенных элементов вверх по иерархии узлов, чтобы не получилось сбоя. Для этого восопользуемся функцией nodeList, которая отдаст массив узлов с указанием степени их вложенности, который можно отсортировать.

Новый код:

// ***********************
// ШАГ 5: Форматирование произвольным HTML-контентом
// ***********************
// nodeList - формирует массив всех узлов с указанием степени их вложенности
function nodeList(parentNode, list, level) {
    var i, node, count;
    if (!list) list = new Array();
    level++;
    for (i = 0; i < parentNode.childNodes.length; i++) {
        node = parentNode.childNodes[i];
        if (node.nodeType != 1) continue;
        count = list.length;
        list[count] = new Array();
        list[count][0] = node;
        list[count][1] = level;
        nodeList(node, list, level);
    }
    return list;
}
// rgbNormal - приводит цвет к стандарту #RRGGBB
function rgbNormal(color) {
    color = color.toString();
    var re = /rgb\((.*?)\)/i;
    if(re.test(color)) {
        compose = RegExp.$1.split(",");
        var hex = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];
        var result = "#";
        for (var i = 0; i < compose.length; i++) {
            rgb = parseInt(compose[i]);
            result += hex[parseInt(rgb / 16)] + hex[rgb % 16];
        }
        return result;
    } else return color;
}
function execCommandImitation(start, end) {
    // Cтавим ForeColor-форматирование с помощью специального цвета
    iDoc.execCommand("ForeColor", false, "#f5F856");
    // Получаем все элементы форматируемого документа
    var allNodes = nodeList(iDoc.body, false, 0);
    // Сортируем их по уровню вложенности
    var maxLevel = 0;
    for (i = 0; i < allNodes.length; i++) {
        maxLevel = allNodes[i][1] > maxLevel ? allNodes[i][1] : maxLevel;
    }
    // 4. Для всех элементов заменяем FONT и SPAN со специальным цветом на переданный код
    var node, newnode, color, parent;
    for (j = maxLevel; j >= 1; j--) {
        for (i = 0; i < allNodes.length; i++) {
            if (allNodes[i][1] != j) continue;
            node = allNodes[i][0];
            sname = node.nodeName.toLowerCase();
            color = node.color ? rgbNormal(node.color) : rgbNormal(node.style.color);
            if (color) color = color.toLowerCase();
            if (sname == "font" || sname == "span" && color == "#f5f856") {
                try {
                    node.innerHTML = start + node.innerHTML + end;
                } catch(e) {}
                parent = node.parentNode;
                while (node.childNodes.length > 0) parent.insertBefore(node.firstChild, node);
                parent.removeChild(node);
            }
        }
    }
    iWin.focus();
}

Пример ВИСИВИГа c произвольным HTML-форматированием

Чтобы заголовок был оранжевым, при формировании стилей документа был добавлен класс:

iHTML += ".oranzh {color:#FF6300;}";

Поверено в WIN: IE6, IE7, FF2, Opera 9.5, Safari 3.

Задача решена!

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

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

Комментарии

rgbeast 3 сентября 2008, 14:42 #
Хочется WYSISYG, в котором можно переключаться в режим исходного HTML-кода
 
Bur 3 сентября 2008, 14:45 #
Итогом цикла статей будет простой, но абсолютно настраиваемый полноценный висивиг. Важно иметь не только готовый продукт, но и понимать как он работает, особенно для JavaScript-разработчика.
 
mindwork 3 сентября 2008, 17:24 #
Я вот как раз пытаюсь разобраться и столкнулся с такой проблемой. Никак не получается убрать редактор в отдельный js. По идее хочется подключать JS и вызывать функцию типа editor();

И мне пока непонятно как передавать в редактор данные и получать их обратно в такой реализации ?
 
Bur 3 сентября 2008, 17:40 #
В 2-х словах объяснить не получится, но решение у этой задачи есть, причем не самое сложное.

В качестве готового продукта можно использовать редактор tinymce. Если интересуют более легкие решения, или решения с кодом, который можно изменять - следите за обновлениями статей на фасткодере.
 
mindwork 3 сентября 2008, 19:08 #
Ну tiny давно известен, но хочется сделать собственную разработку, так что жду обновлений ваших статей.
 
Bur 3 сентября 2008, 19:10 #
Ок. Для удобства можно подписаться на рассылку новых статей в разделе JavaScript или RSS.
 
sstib 13 октября 2008, 20:23 #
Bur, здравствуйте!

Громадное спасибо за вашу работу. Среди груды мусора, вкаченной в поисковики, ваша разработка единственно понятна и проиллюстрированна. Особенно радует список команд.
И еще вопрос, можно ли использовать вашу разработку для создания собственного редактора? То есть апгрейдить его на основе вашего кода?

спасибо за внимание, с уважением, sstib.
 
Bur 13 октября 2008, 20:56 #
Спасибо за слова благодарности.
Модифицировать код, естественно,можно как угодно под свои нужды. Будет замечательно, если потом поделитесь ссылкой на получившийся результат.
 
sstib 14 октября 2008, 00:13 #
спасибо! будем работать)
 
byorty 21 февраля 2009, 14:43 #
Добрый день Bur!я тоже перекопал много инфы про висивиги и только с помощью Ваших статей, я понял в каком направлении нужно двигаться))Но как это обычно бывает в моей практике - нет ничего лучше, чем собственная голова и какой-нибудь справочник по языку. И таким образом я добился таких же результатов, но более коротким путем.Используя appendChild(),insertBefore,textRange() или Range() Вы облегчите себе жизнь и сократите свой скрипт в четверо.Я могу ошибаться,но при вставке заголовков и параграфов нет особой необходимости формировать массив элементов и степень их вложенности(ведь два узла h1 или р будут являться соседними по отношению друг к другу)Задать цвет элементу проще через style.color, не разрабатывая собственную функцию. В общем спасибо Вам за всесторонее рассмотрение JavaScript, у Вас есть что почитать(особенно начинающим)))если у Вас будут вопросы или какие-либо предложения пишите мне на мыло.
 
Bur 24 февраля 2009, 11:20 #
Приветствую!
Опубликуете в комментарии вашу реализацию? Интересно было бы взглянуть.
 
byorty 24 февраля 2009, 14:57 #
Я не очень люблю делиться своими скриптами, но небольшой кусочек опубликую))function createNodes() вставляет в тело фрейма только теги типа p или любой из H.myIframe - id фрейма.myBody - id тела фрейма.
function createNodes(){
//Шаг 1: создание елемента.
var newElement = frames.myIframe.document.createElement("H1");//создаём тег H1
var createNode = frames.myIframe.document.all.myBody.appendChild(newElement);//вставляем тег H1 в тело фрейма
//Шаг 2: создание текстовой области.
var range = frames.myIframe.document.body.createTextRange();//новая текстовая область
range.move("textedit");//перемещение курсора в начало текстовой области, то есть между тегами <H1></H1>
range.select();//выделение текстовой области
}

Таков мой подход к реализации форматирования заголовков и обзацов в визуальном редакторе.НО! должен оговориться, что объект TextRange() можно применять только для IE4+.Для Safari,Opera и Mozilla следует применить объект Range(). Если будут какие-нибудь интересные соображения пишите))
 
Krisp 3 декабря 2008, 10:49 #
Мне нужно было иметь возможность вставить рамку
Дополнил так на основе вашего скрипта
function setLine() {
    iWin.focus();
    execCommandImitation("<div style='border: 2px solid rgb(255, 0, 0); padding: 3px;'>", "</div>");
}

Но проблема вот в чём.... если вставить текст в редактор и потом выбрать рамку то рамка появляется у каждой новой строки. Не подскажите можно ли это поправить и как?
 
Bur 3 декабря 2008, 11:44 #
Попробуйте в после ДИВа добавить перенос строки:
execCommandImitation("<div style='border: 2px solid rgb(255, 0, 0); padding: 3px;'>", "</div><br/>");

Если я правильно понял суть проблемы - поможет.
 
Krisp 3 декабря 2008, 11:55 #
Нет, теперь просто между рамками добавился перенос строки.

<div style="border: 2px solid rgb(255, 0, 0); padding: 3px;">=-=--</div><br><br style="color: rgb(245, 248, 86);"><div style="border: 2px solid rgb(255, 0, 0); padding: 3px;">зз</div><br><br>

То есть вот так теперь во фрейме
 
Bur 3 декабря 2008, 12:08 #
Надо эксперименторивать. Первое что приходит в голову:
1) Заменить стиль на class.
2) Сделать обертку из внешнего ДИВа без стиля.
Мой опыт создания висивигов говорит, что лучше использовать первый фикс.
Если не получится - покажите страницу с примером.
 
Krisp 3 декабря 2008, 12:59 #
тут дело немного в другом - у вас все стили так работаю(то есть оборачивается каждая отдельно взятая строка). Это можно увидеть например вбив несколько строк текста и посмотрев иходный код. получается.
<span style="font-weight: bold;">11111111111111111</span><br style="font-weight: bold;"><span style="font-weight: bold;">2222222222222222</span><br style="font-weight: bold;"><span style="font-weight: bold;">33333333333333</span><br style="font-weight: bold;"><span style="font-weight: bold;">44444444444444</span><br style="font-weight: bold;"><span style="font-weight: bold;">55555555555555</span><br>

Я попробовал внести изменения в код
            if (sname == "font" || sname == "span" && color == "#f5f856") {
                try {
                    i == 0 ? start = start : start = "";
                    i == allNodes.length ? end = end : end = "";
                    node.innerHTML = start + node.innerHTML + end;

                } catch(e) {}

Но я в яваскрипте не ахти, к сожалению код не работает. Всё равно закрывает конечный тег каждый раз. Очень на вас надеюсь, в интернте единственный вменяемый скрипт который избавлен от лишнего ненужного мне функционала. Есть идеи какие-нибудь по исправлению?
Если всё таки понадобится сама страничка с примером после 14 по Москве выложу в инет.
 
Bur 3 декабря 2008, 13:02 #
Выкладывайте, надо смотреть пример.
 
Krisp 3 декабря 2008, 14:15 #
 
Bur 3 декабря 2008, 15:43 #
Да, теперь я понял суть вашей проблемы. Быстро-фикса не получится. Вечером попробую полностью переписать ф-ию execCommandImitation, чтобы избавиться от этого недостатка. Напишу вам в коммент что вышло.
 
Krisp 5 декабря 2008, 10:23 #
Нету никаких продвижений?))
 
Bur 5 декабря 2008, 11:45 #
Пока не получилось, но уже понятно что вторая версия execCommandImitation усложнится и будет работать по совершенно другому принципу...
 
Krisp 5 декабря 2008, 11:53 #
Понятно, а не подскажете, когда примерно ожидать выход новой версии?
 
Bur 5 декабря 2008, 12:14 #
В ближайшие выходные
 
Krisp 19 декабря 2008, 09:30 #
Никаких новостей нету:(
 
Krisp 29 января 2009, 17:51 #
Я конечно дико извиняюсь за наглость, но всё таки вы предполагаете закончить код?))
 
Bur 29 января 2009, 17:52 #
Извиняться надо не вам, а мне.
Сначала я был занят, а потом забыл.
Пока этот комментарий висит в топе на морде - не забуду. Первым делом напишу вам скрипт.
 
tascam 5 февраля 2009, 12:32 #
паметка :)
"Пока этот комментарий висит в топе на морде - не забуду"
 
Krisp 25 марта 2009, 17:06 #
"Пока этот комментарий висит в топе на морде - не забуду"

:))
 
Bur 26 марта 2009, 16:37 #
Да-да, не хватало ясности по реализации Range и Selection.. Теперь, когда статья написана, займусь вашей проблемой.
 
Krisp 26 марта 2009, 16:46 #
Хорошо, спасибо, буду ждать)
 
Bur 26 марта 2009, 16:49 #
Ваше письмо о баге в ИЕ пришло в странной кодировке, не могу его прочесть.
Можете здесь продублировать?
 
gigi 31 марта 2009, 23:56 #
Супер!
Долго пытался прикрутить готовые решения по WYSISYG к своей админке , чего терпеть не могу делать, уже было остановился на TinyMCE, но крутился по ночам. Сильно буржуйский и сильно много для меня кода там. Как ни странно толковых статей на эту тему в инете по пальцам можно пересчитать. С языком java знаком совсем чуть-чуть, но подробные коменты и логичная последовательность информации в статье помогла разобраться со всем.
Теперь понятно куда копать и какой ширины напильник брать

Зарегился только, чтобы сказать автору СПАСИБО! )
 
Bur 1 апреля 2009, 08:09 #
Вэлкам!
А TinyMCE, кстати, вы зря обижаете, очень правильный визуальный редактор с хорошо выверенным кодом и богатым набором возможностей. Но чего не сделаешь ради душевоного спокойствия :-)
Еще поправка. Язык, на котором написан wysiwyg, называется JavaScript (джаваскрипт). Язык Java - это совсем другая песня.
 
gigi 3 апреля 2009, 12:25 #
Правильный, но своя рубашка ближе к телу )
На счет языка, конечно же яваскрипт )
уж простите за некорректное сокращение. Разницу я вроде как понимаю )))

Еще все визивиги которые я посмотрел не умеют корректно чистить код MS Word

Начал наполнять один сайтик контентом через визивиг. Контент копипастил из Worda

Команда RemoveFormat убирает не весь мусор
в итоге после очистки такое предложение

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

превращается в
<link rel="File-List" href="file:///C:%5CDOCUME%7E1%5CGigi%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"><!--[if gte mso 9]>
<xml> <w:WordDocument>  <w:View>Normal</w:View>  <w:Zoom>0</w:Zoom>  <w:PunctuationKerning/>  <w:ValidateAgainstSchemas/>  <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>  <w:IgnoreMixedContent>false</w:IgnoreMixedContent>  <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>  <w:Compatibility>   <w:BreakWrappedTables/>   <w:SnapToGridInCell/>   <w:WrapTextWithPunct/>   <w:UseAsianBreakRules/>   <w:DontGrowAutofit/>  </w:Compatibility>  <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument></xml><![endif]--><!--[if gte mso 9]>
<xml> <w:LatentStyles DefLockedState="false" LatentStyleCount="156"> </w:LatentStyles></xml><![endif]--><style><!-- /* Font Definitions */ @font-face   {font-family:Calibri;   panose-1:2 15 5 2 2 2 4 3 2 4;  mso-font-charset:204;   mso-generic-font-family:swiss;  mso-font-pitch:variable;    mso-font-signature:-1610611985 1073750139 0 0 159 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal  {mso-style-parent:"";   margin:0cm; margin-bottom:.0001pt;  mso-pagination:widow-orphan;    font-size:12.0pt;   font-family:"Times New Roman";  mso-fareast-font-family:Calibri;}@page Section1 {size:612.0pt 792.0pt;  margin:2.0cm 42.5pt 2.0cm 3.0cm;    mso-header-margin:36.0pt;   mso-footer-margin:36.0pt;   mso-paper-source:0;}div.Section1    {page:Section1;}--></style><!--[if gte mso 10]>
<style> /* Style Definitions */ table.MsoNormalTable    {mso-style-name:"Обычная таблица";    mso-tstyle-rowband-size:0;  mso-tstyle-colband-size:0;  mso-style-noshow:yes;   mso-style-parent:"";    mso-padding-alt:0cm 5.4pt 0cm 5.4pt;    mso-para-margin:0cm;    mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan;    font-size:10.0pt;   font-family:"Times New Roman";  mso-ansi-language:#0400;    mso-fareast-language:#0400; mso-bidi-language:#0400;}</style><![endif]-->пылесос для влажной и сухой уборки, нержавеющийкорпус, с возможностью подключения ручного инструмента


соображения: пройтись по всем узлам и удалить их сразу после вставки, потом продолжать редактировать. Либо изначально вставлять текст в textarea а при начале форматирования переключение в iframe? А может я велосипед изобретаю?...)
 
Bur 3 апреля 2009, 16:52 #
Если вам совсем не нужна разметка, то лучше копировать в текстарию, а потом переключаться в визуальный режим.
Если хочется оставить часть разметки (заголовки, ссылки), то можно сделать так:
1) Получить все узлы документа из висивига: iDoc.getElementByTagName('*');
2) Идти итерационно от самых вложенных (это важно!) узлов и при нахождении неугодного безжалостно его заменять на текстовый узел.

Примерно так.
 
cube 25 апреля 2009, 19:17 #
1) Спасибо автору! Мне показалось что необходимо постараться внести свой маленький вклад в эту ветку обсуждения, которая мне сильно помогла.
2)Тоже сталкнулся с такой проблемой, я сделал так:

function removeFormat() {
subject=iWin.document.body.innerHTML;
re = /<.*?[^<>]>/gi;
iWin.document.body.innerHTML=subject.replace(re, "");
}

- удаляет все теги HTML с помощью рег.выражений.

НО! Нужно оставить разрывы строк для этого предварительно меняем "<BR>" на "\r\n", например так str=str.split("<BR>").join("\r\n"); После удаления всех тегов возвращаем обратно - str=str.split("\r\n").join("<BR>");
 
becool 20 апреля 2009, 15:06 #
Приветствую, хотелось бы сделать опросник для статуса кнопок. (если курсор на жирном тексте то кнопка B активна), Но не совсем понимаю каким методом это можно реализовать... Нужен этакий get_text_format_under_cursor() :)
 
Bur 20 апреля 2009, 17:02 #
В статье о Range, TextRange и Selection вы можете узнать как определить узел для фокусной точки. Далее алгоритм прост. По событиям mousedown, click (или таймауту) обходите все родительские узлы контейнера фокуса и смотрите нет ли там жирности/курсива/и др.
 
becool 21 апреля 2009, 02:50 #
Ага, спасибо. По ходу проявилась ещё одно проблема, BackColor красит либо body целиком либо блоки (p,div и тд), тоесть сделать заливку отдельной букве не получается. Так и должно быть или это у меня баг?
 
Bur 21 апреля 2009, 19:31 #
Если я правильно помню, backcolor нормально работает только в ИЕ.
В остальных браузерах можно "руками" ставить <font> с нужным фоновым цветом, например, при помощи функции execCommandImitation.
 
suppcolor 6 мая 2009, 21:45 #
Интересно реализован WYSISYG редактор в knol ... меня привлекла возможность области для редактирования расширяться вниз, по ходу добавления материалов... как можно этого добиться?
 
Denis Usenko 2 июля 2009, 09:20 #
Bur
В зависимости от браузера цвет выставляется либо с помощью <font color="#RRGGBB"></font> (IE, Opera), либо с помощью <span style="color:rgb(RR,GG,BB)"></span> (Gecko). Чтобы привести цвет к единому формату #RRGGBB воспользуемся функцией rgbNormal().

В лисе сейчас это: <i style="color: rgb(245, 248, 86);">разметкой</i>
Есть команда useCSS, хотя она в статусе deprecated, но вроде помогает:
try { iDoc.execCommand('useCSS', false, true) } catch(e) {}
По статье в целом: очень интересно, хотя код действительно стоит переписать, слишком уж неоптимально.
 
devil943 10 августа 2009, 00:09 #
Интересен момент создания таблиц. Если можно, приведите пример.
 
devil943 12 августа 2009, 16:51 #
Сегодня весь день прокопался с вашей функцией execCommandImitation().
1. Не понял, зачем вам нужны циклы? Мы сначала выделяем нужный кусок текста, закрашиваем его, создаем нод. => Самый первый тег будет font или span, значит можно сразу присвоить
node = allNodes[maxLevel-1][0];
, и без поиска в массиве нодов нужно с цветом и и тегом.

2. У вас, при выделении области, которая обрамлена h1 и повторного нажатия кнопки - область снова обрамляется h1. ИМХО нелогично. Выделение h1 должно убираться. После некотрых мучений, пришел к выводу, что в функцию надо передавать еще и сам тег. Прогонять в цикле
for(i = maxLevel - 2; i >= 0; i--) {
ноды, сравнивая их теги с переданным в функцию (вдруг наш нод обрамлеен h1, а потом, скажем, b?
Короче говоря найти момент, где h1 надо тереть мне удалось. Но выполнить само удаление не вышло. Догадываюсь, что нужно чистить все от найденного блока от тегов вообще, (например встроенным в АПИ RemoveFormat), потом обойти еще раз ноды и по создавать удаленные элементы заново (без h1, естественно). Короче говоря идея кривая, можете предложить что-нибудь поинтереснее?

Кстати, в chrome обнаружил баг с RemoveFormat - после юзания команды все пробелы заменяются неразрывными &nbsp; (((

А по поводу таблиц - нужна функция по вставке произвольного кода не по выделению текста...
 
exzibit 24 сентября 2009, 15:52 #
Можете пожалуйста продемонстрировать код дураку , при котором по нажатию кнопки выполнялся сабмит и отформатированный текс отправляля вместе с html тегами ? заранее благодарен.
 
Bur 25 сентября 2009, 11:48 #
Если взять код простейшего визуального редактора, то процесс отправки HTML-кода на сервер будет довольно примитивен:
1) Пусть у вас есть форма со скрытой текстарией:
<form onsubmit="getCode();">
     <textarea id="codeId" name="code" style="display:none;"></textarea>
     <input type="submit" value="Отправить" />
</form>

2) При сабмите происходит вызов ф-ии getCode:
function getCode() {
     document.getElementById("codeId").value = iDoc.body.innerHTML;
}

3) В скрытую текстарию запишется HTML-код, который уйдет на сервер.
 
exzibit 25 сентября 2009, 19:09 #
пытался в php файле...
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=cp1251" />
    <title>Простой ВИСИВИГ (WYSIWYG)</title>
    <link type="text/css" rel="stylesheet" href="http://fastcoder.org/style.css" />
    <style type="text/css">
        body {margin:10px;}
        iframe {
            width:600px; height:150px;
            border:1px solid #000;
            margin-bottom:5px;
        }
        input {margin-right:5px; padding:3px;}
        .bold {font-weight:bold;}
        .ital {font-style:italic;}
        .under {text-decoration:underline;}
    </style>
</head>
<body>
<h1>post message</h1>

<script type="text/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 += ".oranzh {color:#FF6300;}";
iHTML += "</style>\n";
iHTML += "<body></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' />");
document.write("<input type='button' value='Link' onclick='setLink()' 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, "");
}
function setLink() {
    var url = prompt("Введите URL:", "http://");
    if (!url) return;
    iWin.focus();
    iWin.document.execCommand("CreateLink", null, url);
}
function setH1() {
    iWin.focus();
    execCommandImitation("<h1 class='oranzh'>", "</h1>");
}

// ***********************
// ШАГ 5: Форматирование произвольным HTML-контентом
// ***********************
// nodeList - формирует массив всех узлов с указанием степени их вложенности
function nodeList(parentNode, list, level) {
    var i, node, count;
    if (!list) list = new Array();
    level++;
    for (i = 0; i < parentNode.childNodes.length; i++) {
        node = parentNode.childNodes[i];
        if (node.nodeType != 1) continue;
        count = list.length;
        list[count] = new Array();
        list[count][0] = node;
        list[count][1] = level;
        nodeList(node, list, level);
    }
    return list;
}
// rgbNormal - приводит цвет к стандарту #RRGGBB

function execCommandImitation(start, end) {
    // Cтавим ForeColor-форматирование с помощью специального цвета
    iDoc.execCommand("ForeColor", false, "#f5F856");
    // Получаем все элементы форматируемого документа
    var allNodes = nodeList(iDoc.body, false, 0);
    // Сортируем их по уровню вложенности
    var maxLevel = 0;
    for (i = 0; i < allNodes.length; i++) {
        maxLevel = allNodes[i][1] > maxLevel ? allNodes[i][1] : maxLevel;
    }
    // 4. Для всех элементов заменяем FONT и SPAN со специальным цветом на переданный код
   
    iWin.focus();
}
function getCode() {
     document.getElementById("codeId").value = iDoc.body.innerHTML;
}
</script>
<form onsubmit="getCode();" method='POST'>
     <textarea id="codeId" name="code" style="display:none;"></textarea>
     <input type="submit" value="Отправить" />
</form>
<?php

print "$_POST[code]";
   
?>
</body>
</html>


если писать

function setBold() {
    iWin.focus();
    iWin.document.execCommand("bold", null, "");    }

то текст передается не отформатированый, а если заменить
execCommandImitation("<h1 class='oranzh'>", "</h1>");

function setBold() {
    iWin.focus();
    execCommandImitation("<b class='bold'>", "</b>");    }

то в фрейме форматирования, при задании жирности, ее нельзя отменить =(, но зато передается POSTom форматированный..
как быть? ( JS вообще впервые вижу, освоил только Php)
 
Bur 28 сентября 2009, 12:16 #
Я так понимаю, что задача отправки HTML-кода на сервер успешно решена? И теперь созрел новый вопрос?
Сформулируйте его более четко.
 
exzibit 29 сентября 2009, 20:17 #
да, с передачей в бд разобрался, с редактированием цветами текста тоже нахимичил :) а вот например шрифт поменять незнаю как сделать :(
 
exzibit 29 сентября 2009, 20:17 #
т.е размер шрифта..
 
Bur 30 сентября 2009, 11:09 #
Команда FontSize метода execCommand вам в помощь.
 
azholy 21 декабря 2009, 22:32 #
Первая часть статьи порадовала своей простотой. Спасибо автору. Правда когда прочел вторую часть очень захотелось назвать автора МУДАКОМ. Вставить произвольный html код средствами яваскрипт можно всего в пару строчек. Зачем людям мозги морочить?
 
Bur 22 декабря 2009, 11:13 #
Код в студию.
 
azholy 22 декабря 2009, 18:24 #
var text = document.createTextNode("");
text.nodeValue = "Пример абзаца.";
var elem = document.createElement("P");
elem.appendChild(text);

iWin.focus();
iWin.document.execCommand('CreateLink', null, 'http://1234567890/');
var list = iWin.document.body.getElementsByTagName("a");
for (var i = 0; i < list.length; i++)
if (list[i].href == 'http://1234567890/')
{
list[i].parentNode.replaceChild(elem, list[i]);
}
 
azholy 22 декабря 2009, 18:25 #
 
GENEROUS 27 января 2010, 04:53 #
А Вы можете написать рабочий пример?
 
azholy 27 января 2010, 16:09 #
У меня работает нормально.
Суть в том, чтобы отметить выделенный текст по какому-то параметру затем найти его элемент по этому параметру и заменить, определив его через ссылку на родителя. Бывают проблемы, если выделенный текст принадлежит разным форматам, например [b]111[i]222[\b]333[\i] но такого при нормальной верстке не бывает, поэтому я пользуюсь этим вариантом.
 
 
Rambler's Top100 Flede HTML valid CSS valid