Как сделать редактор изображений на javascript

Обновлено: 08.07.2024

Задача: написать простейший визуальный редактор и немного разобраться как он работает.

Что такое WYSIWYG?

Как это работает?

Для написания простого ВИСИВИГа не нужно изобретать велосипед, все средства уже встроены и успешно работают. Механизм работы большинства визуальных редакторов основан на свойстве designMode объекта document. Это встроенное свойство (к сожалению, далеко не для всех браузеров, но для большинства современных) как раз и позволяет редактировать HTML-контент. После его активанции (designMode=’On’) на web-страницу можно ставить привычный нам курсор и набивать, удалять или изменять форматирование контента.

Бывает удобно не редактировать всю страницу, а иметь какую-то фиксированную область, для чего используется iframe. Именно его объект document используется для активации свойства designMode.

Форматирование содержимого в пределах ВИСИВИГа осуществляется с помощью непростого метода execCommand, реализация которого сильно различается от браузера к браузеру.

Смотрим JavaScript-код для простейшего ВИСИВИГа:

Данная версия визуального редактора не может работать в Опере ниже версии 9.01 и покажет предупреждение "Визуальный режим редактирования не поддерживается Вашим браузером". Работоспособность проверена в:
— IE 6;
— FF 1.5;
— Opera 9.01 +;
— Mozilla 1.7.2;
— NN 7.1 +;

Lorem ipsum dolor

Чертим прямую линию

Задаем расцветку прямой

public void paint(Graphics f)

Color oldColor = f.getColor(); //фиксируем исходную расцветку

Color newColor = new Color (1, 1, 255)//формируем новую расцветку

f.setColor(newColor)//определяем новую расцветку

f.drawLine(40, 50, 380, 50)//выводим нашу прямую с новой расцветкой

f.setColor(oldColor);//определяем исходную расцветку

>;

Задаем цвет фона

public void paint(Graphics f)

mainFrame.setBackground(Color.green);

>;

Рисуем прямоугольник

public void paint(Graphics f)

f.drawRect(40, 50, 380, 50)

>;

гд е 4 0 и 50 — координаты верхнего левого угла, 380 — длина, а 50 — высота.

Рисуем прямоугольник и закругл яе м ему углы

public void paint(Graphics f)

f.drawRoundRect(40, 50, 380, 50, 40, 35)

>;

гд е п ервые 4 аргумента — как и в примере выше, 40 — ширина прямоугольника, в который вписан овал сопряжения, а 35 — высота прямоугольника, в который вписан овал сопряжения.

Рисуем овал

public void paint(Graphics f)

f.drawOval(30, 100, 140, 70)

>;

где числа — это аргументы прямоугольника, в который вписан овал.

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

Заключение

Графика в Java требует определенных навыков работы с самим языком и дополнительными библиотеками. Мы показали, как происходит рисование примитивных фигур. Однако примитивными фигурами невозможно разработать полноценную 3D-игру. Для 3D-игры на Java нужны совсем другие знания.

Мы будем очень благодарны

если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.


Поскольку изображения стали неотъемлемой частью Интернета, потребность в обработке изображений становится постоянной. Существуют различные библиотеки и двоичные файлы, которые используются для обработки изображений в Node.js, две из которых - GraphicsMagick и ImageMagick.

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

Некоторые из преимуществ GraphicsMagick перед ImageMagick включают в себя большую эффективность, меньший размер, меньшее количество уязвимостей безопасности и, как правило, более стабильный, чем ImageMagick. Оба они доступны для использования в Node.js как пакеты NPM: GraphicsMagick и ImageMagick.

Установка GraphicsMagick и ImageMagick

Перед установкой любого из этих пакетов вы должны загрузить и установить в своей системе инструменты интерфейса командной строки (CLI). Вы также можете использовать ImageMagick прямо из GraphicsMagick.

Если вы планируете использовать модуль GraphicsMagick, вы можете установить инструменты ImageMagick или GraphicsMagick CLI. Если вместо этого вы хотите использовать ImageMagick, вам необходимо установить инструмент CLI ImageMagick.

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

Если оно было успешно установлено, на терминал будут распечатаны сведения об установленном программном обеспечении.

Аналогичным образом, если установка прошла успешно, в окне отобразится логотип GraphicsMagick.

Далее, чтобы добавить модуль в ваш проект, мы будем использовать npm .

Обработка изображений в Node.js с помощью GraphicsMagick

В этом руководстве мы узнаем, как работать с изображениями в Node.js, используя как GraphicsMagick, так и ImageMagick. В этом разделе мы начнем с GraphicsMagick.

Создайте папку с именем node-graphics-magick , инициализируйте проект Node с настройками по умолчанию и установите GraphicsMagick, как показано ниже:

Затем откройте папку с вашим любимым редактором кода и создайте файл index.js . Чтобы использовать модуль в проекте, импортируйте его с помощью require() . Мы также добавим модуль файловой системы fs , чтобы помочь нам взаимодействовать с файловой системой:

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

Как упоминалось ранее, модуль GraphicsMagick также позволяет использовать ImageMagick. Если вы хотите использовать эту опцию, вам нужно импортировать подкласс:

Вызов конструктора GM

Есть три способа вызвать метод конструктора gm .

1. Передавая путь к изображению в виде строкового аргумента:

2. Вы также можете передать ReadableStream или Buffer в качестве первого аргумента с необязательным именем файла для вывода формата:

3. Другой вариант - передать два целых числа для width и height с необязательным цветом фона для создания нового изображения на лету:

Получение информации об изображении

GraphicsMagick предоставляет несколько методов получения информации об изображениях. Один из них - это метод identify() . Он возвращает все доступные данные изображения:

После включения модуля gm мы вызвали конструктор gm() , а затем вызвали функцию identify() , передав функцию, которая принимает два аргумента - err для получения любой возникающей ошибки, value которая содержит информацию об изображении.

Обратите внимание, что значение может быть undefined .

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

В нем содержится информация о size , resolution , file size и depth , цвет изображения. Если вы хотите, получить некоторые из этих деталей по отдельности, есть отдельные функции, чтобы получить их, такие как: size() , format() , depth() , orientation() , res() и т.д.

Все они имеют тот же синтаксис, что и функция identify() . Например, если мы хотим получить размер изображения, мы должны использовать:

Изменение размера изображений

Также распространено изменение размера изображений. Синтаксис функций resize() :

Где параметры height и options не являются обязательными. Параметр options может быть либо % , @ , ! , или > . Мы рассмотрим каждый из них.

Указанные width и height являются максимальными значениями, допустимыми для обоих свойств.

Без указания каких-либо параметров options GraphicsMagick будет поддерживать соотношение сторон исходного изображения. Если заданы оба width и height , размер изображения будет изменяться до тех пор, пока он не достигнет максимального значения для одного или другого.

Тем не менее, вы можете заставить модуль изменить к данности width и height с помощью опции ! .

Мы также используем функцию write() для сохранения вывода в новый файл.

Изменение размера изображения до определенного width с сохранением соотношения сторон:

Мы также можем изменять размер изображения до тех пор, пока его размер не достигнет максимума width или height с сохранением соотношения сторон:

Или мы можем изменить размер изображения, чтобы оно соответствовало точному width и height , возможно, изменив исходное соотношение сторон:

Мы также можем использовать проценты вместо пикселей для изменения размера изображений, то есть мы можем изменить размер изображения до 50% от его исходного размера:

Конечно, вы также можете указать процентное значение выше 100%, чтобы увеличить изображение.

Другой интересный вариант, который вы можете использовать @ - это изменение размера изображения таким образом, чтобы оно занимало не более width * height пикселей. Это означает, что если вы напишете что-то вроде этого:

Размер изображения будет изменен таким образом, чтобы оно умещалось в области 10.000 пикселей (100 * 100 = 10.000 пикселей). Другими словами, если мы умножим ширину и высоту получившегося изображения, то получится число, меньшее или равное 10.000.

Теперь мы возьмем варианты > и :

  1. Параметр > изменяет размер изображения только в том случае, если ширина и высота данного изображения больше заданных width и height .
  2. Параметр изменяет размер изображения только в том случае, если ширина и высота данного изображения меньше заданных width и height .

Преобразование изображений из одного формата в другой

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

Обрезка изображений

Помимо изменения размера изображений, вы также можете обрезать изображения в своем приложении. GraphicsMagick имеет функцию crop() и ее синтаксис:

Где параметры имеют следующее значение:

  1. width и height - это размеры, до которых вы хотите обрезать изображение. Они обрабатываются либо как количество пикселей, либо как процент от исходного изображения в зависимости от параметра percentage .
  2. x и y являются необязательными параметрами, и они представляют собой координаты позиции, с которой должна начинаться обрезка. Значение по умолчанию - для обоих 0 , что означает, что обрезка начинается с верхнего левого угла изображения.
  3. Параметр percentage также является необязательным, и используется для определения, если значение данных width и height представляют собой проценты от размеров изображения или пикселей. Значение percentage по умолчанию - false .

Опять же, если вы проверите размеры нового изображения resized_img_crop1 , вы увидите, что оно составляет половину размера исходного изображения и обрезано в определенной позиции, а не в верхнем левом углу.

На изображении ниже показан пример:


Мы рассмотрели, как выполнять манипуляции с изображениями с помощью GraphicsMagick. Далее мы увидим, как это сделать в ImageMagick.

Обработка изображений в Node.js с помощью ImageMagick

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

Создайте папку с именем node-image-magick , следуя шагам, описанным в предыдущем разделе, установите модуль ImageMagick с помощью npm и создайте файл index.js .

В файл index.js добавьте модуль, используя require() :

Получение информации об изображении

Для получения информации об изображении в модуле image-magick также есть метод identify() . Первый аргумент - это путь к изображению, а второй - функция обратного вызова, которая имеет два аргумента: err для обработки ошибок и info для получения информации об изображении:

Запуск этого кода для нашего изображения выводит на печать:

Изменение размера изображений

ImageMagick предоставляет удобную функцию для изменения размера изображений, которая принимает объект, с параметрами для изменения размера изображения и функцией обратного вызова. Изменение размера изображений с помощью модуля ImageMagick следует следующему синтаксису:

Обрезка изображений

ImageMagick также предоставляет функцию обрезки изображений с тем же синтаксисом, что и функция resize() . Давайте посмотрим на простой пример использования:

В документации представлен список опций для каждой из вышеперечисленных функций.

Вывод

В этой статье мы изучили, как работать с изображениями в Node.js, используя как модули ImageMagick, так и GraphicsMagick. GraphicsMagick - лучший вариант из двух, учитывая все преимущества, которые он имеет перед ImageMagick.

Модуль GraphicsMagick содержит обширную документацию по дополнительным параметрам управления изображениями.

Стоит задача: сделать примитивный векторный редактор на JavaScript.

Должен уметь рисовать прямоугольники и писать текст (если под наклоном, вообще замечательно). Результат должен отдавать серверу в векторном виде, естественно.

Не обязательно должен работать в IE (т.е. использовать canvas или svg можно).

а) Что бы хорошее почитать про сам ECMAScript?

б) Какую библиотеку использовать, чтоб было не очень низкоуровнево? Вообще, для JavaScript сейчас уйма библиотек. И совершенно не ясно, какая для чего хороша.


D raft.js — часть огромной инфраструктуры, выстраиваемой в Facebook вокруг концепции React.js. Технологию, изначально созданную инженерами Facebook внутри компании, представили сообществу в феврале 2016 года на React Conf, исходники проекта появились на github, и к текущему моменту репозиторий собрал уже более 11 000 звёзд.


Конечно же, необходимо сразу отметить, что Draft.js — это инструмент для решения весьма узкого спектра задач, а именно — задач управления текстовым вводом и редактирования текста.

“R ich text editor framework for React” (фреймворк для создания текстовых редакторов на React), как представляют его на официальном сайте.

На финише у нас накопится довольно внушительная кодовая база. Поэтому я решил выделить каждую стадию в отдельную ветку в репозитории и демо-страницу на github pages, а в тексте статьи будут разобраны наиболее значимые фрагменты кода. Также я не буду останавливаться на структуре папок, config-файлах для Webpack и стилях. Если вы уже работали с React.js и Webpack, не думаю, что эти моменты вызовут у вас какие-либо вопросы. Если какие-то вопросы все же возникли — пишите в комментарии, я отвечу.

Начнем с ветки starting point — это будет отправная точка. Все, что должно нас здесь интересовать — это файл src/components/DraftEditor/DraftEditor.js .

Здесь мы просто подключили на страницу React-компонент Editor , который пока ничего не умеет. Давайте, однако, подробнее рассмотрим приведенный выше фрагмент кода, а потом уже возьмемся за добавление более интересного функционала. У компонента, помимо не требующего объяснений свойства placeholder , объявлены свойства:

  • editorState — текущее состояние редактора.
  • onChange — функция вызывающаяся при любых манипуляциях внутри редактора, первый аргументом эта функция получает объект — изменившейся editorState .

Как вы можете видеть из кода, мы будем хранить editorState редактора в стейте родительского компонента и обновлять его в методе onChange через setState . В конструкторе класса присвоим начальное значение свойству editorState с помощью EditorState.createEmpty() . Для тех случаев, когда редактор должен появится на странице уже с предопределенным контентом, используется метод createWithContent . Также в методе onChange поставим console.log , чтобы при каждом изменении видеть текущий editorState в консоли. Здесь нужно обратить внимание, что сам editorState — это сущность Record библиотеки Immutable.js , поэтому мы переводим его в привычный JavaScript объект вызовом toJS() .

Посмотрите, какой сложной структуры этот объект:


Здесь, помимо данных непосредственно о текущем контенте редактора, хранится информация о выделенном фрагменте текста ( selection ), полная история изменений ( undoStack / redoStack ) и прочая информация. За счет использования immutable структур удается хранить историю изменений оптимальным для памяти и производительности приложения образом. Попробуйте стандартные горячие клавиши (Ctrl/Cmd + Z и Ctrl/Cmd + Shift + Z) для отмены и возвращения сделанных изменений. Конечно, сейчас, когда наш редактор по своему функционалу мало чем отличается от обычной textarea, это выглядит не так эффектно, поэтому, давайте перейдем к следующему шагу.


В этой части, рассмотрим, как с помощью Draft.js применить стилизацию к тексту. Мы повторим знакомое всем пользователям Medium поведение с появлением тулбара с вариантами действий непосредственно над выделенным участком текста.


Переключитесь в ветку inline-stylization . У нас появился новый компонент src/components/InlineToolbar и файл для хранения утилитарных функций utils/index.js . Сейчас их там две: getSelectionRange для получения данных о текущем выделении (selection):

И getSelectionCoords для получения координат выделенного фрагмента относительно контейнера редактора:

Следует заметить, что эти функции даже никак не связанны с Draft.js, здесь используется стандартный браузерный Selection API. Воспользуемся ими в методе onChange компонента DraftEditor , где теперь мы не просто обновляем свойство editorState стейта компонента, но и проверяем, есть ли внутри редактора выделенный фрагмент текста (как упоминалось выше, объект editorState хранит в себе информацию в том числе и о selection). В положительном случае мы вычисляем координаты, необходимые, чтобы наш тулбар появился непосредственно над выделенным текстом и обновляем стейт компонента.

В компоненте DraftEditor также появился новый метод:

Здесь мы впервые воспользуемся методом из модуля RichUtils — это набор утилит для Draft.js, в дальнейшем мы ещё неоднократно к нему обратимся. Метод RichUtils.toggleInlineStyle , получая первым аргументом текущий editorState редактора, а вторым — строку с названием стиля, который должен быть применен (например 'BOLD' ), вернет новый editorState, в котором уже будет храниться информация, что выделенный на момент вызова фрагмент текста стилизован соответствующим образом.

Метод toggleInlineStyle прокидываем в свойство onToggle компонента InlineToolbar :

В самом компоненте ( src/components/InlineToolbar ) вызываем его в функции обработчике события onMouseDown :

Тулбар будет состоять из трех элементов, по клику на которые выделенный текст будет стилизован одним из следующий типов стилей: BOLD — жирное начертание, ITALIC — курсив и HIGHLIGHT — выделенный текст. И здесь необходимо заметить, что BOLD и ITALIC — это стандартные типы стилей для Draft.js. То есть, когда один из них применяется к фрагменту текста, Draft.js знает о том, что к соответствующей этому фрагменту DOM-ноде, следует применить инлайновые стили font-weight: bold и font-style: italic соответственно. А вот для того, чтобы фреймворк знал, какие css-правила необходимо применять для кастомных стилей (в нашем случае — HIGHLIGHТ ), объявляем в компоненте src/components/DraftEditor объект customStyleMap :

Формат этот объекта должен быть следующим: ключи — названия кастомного стиля, значение — соответствующие ему css-свойства. В случае, если нам понадобятся другие кастомные стили, мы просто расширим этот объект новыми свойствами. Теперь передаем этот объект в одноименное свойство компонента Editor :

Последнее, что осталось рассмотреть в этой части — метод handleKeyCommand . Как вы видите, из фрагмента кода выше, он также передается в соответствующее свойство компонента Editor . Этот метод необходим, чтобы наш редактор мог реагировать на стандартные для инструментов редактирования текста горячие клавиши.

Попробуйте выделить текст и нажать Ctrl/Cmd + B или Ctrl/Cmd + I, текст примет жирное или курсивное начертание. И опять же, что бы нам определить кастомные горячие клавиши для стилизации либо каких то других манипуляций внутри редактора, придется проделать немного дополнительной работы. Наглядный пример реализации этого есть на официальном сайте Draft.js.

В этой части расширим наш редактор возможностью добавления ссылок и на этом примере рассмотрим две широкоиспользуемые в Draft.js концепции: Entities — особым образом аннотированные участки текста, которые могут иметь некоторые метаданные (для нашего случая это url ссылки) и систему декораторов (Draft.js Decorators).
Переключимся в ветку link-entity . Обратите внимание на то, что в тулбаре появился новый элемент для добавления ссылки.


Для простоты мы будем использовать стандартный prompt диалог. Рассмотрим метод setLink , который вызывается при клике на соответствующий элемент тулбара.

Подробнее остановимся на создании Entity . Для создания Entity необходимо на текущем contentState вызвать метод createEntity , который принимает два обязательных аргумента и один опциональный. Давайте рассмотрим каждый из них на нашем примере:

  • LINK (строка) — собственно тип создаваемого Entity . Ниже, когда мы начнем рассматривать декораторы, мы увидим пример использования этого свойства.
  • SEGMENTED (строка) — это свойство определяет поведение текста связанного с создаваемым Entity в случае его редактирования. Возможные значения: IMMUTABLE — любое редактирование текста приведет к разрыву связи фрагмента текста с Entity и, соответственно, её удалению; MUTABLE — полная свобода редактирования текста, Entity будет удалено вместе с удалением последнего символа из ассоциированного участка текста; SEGMENTED — связь между текстом и Entity разрывается при добавлении символов к тексту, однако, при удалении, сохраняется пока не удален последний сегмент текста. Как именно Entity ведет себя в этом случае, лучше увидеть наглядно, поэтому мы используем именно SEGMENTED в нашем примере, в реальных условиях, для ссылки логично использовать тип MUTABLE .
  • < url: urlValue >(объект) — метаданные, которые будут привязаны к создаваемому Entity (опциональный аргумент).

Если бы мы, все же, дополняли наш код последовательно, то сейчас, заметили бы, что после добавления Entity визуально контент редактора никак не изменился. Чтобы в контенте редактора отрендерить ссылку желаемым образом, воспользуемся концепцией декораторов в Draft.js. Она заключается в том, что содержимое редактора сканируется, и участки текста удовлетворяющие определенному условию рендерятся с помощью отдельного React.js компонента. В нашем случае таким условием будет то, что фрагмент текста имеет ассоциированное Entity с типом LINK .

Создаем экземпляр класса CompositeDecorator передавая в качестве аргумента массив объектов со свойствами strategy — функция для выборки фрагментов текста и component — компонент, с помощью которого этот фрагмент будет отрендерен, сохраняем его в переменную decorator , которую передаем в метод createEmpty . Код компонента и функции выборки приведен ниже.

Возможность определения кастомных блоков — это, пожалуй, самая мощная фича в арсенале Draft.js. В этой части мы реализуем возможность добавления в контент редактора слайдера изображений. Причем сделать это можно будет просто перетащив несколько изображений в область редактора.

В законченном виде этот функционал сохранен в ветке custom-component демо-репозитория (попробовать как это работает).

Начнем с того, что в Draft.js есть и набор дефолтных блоков (с полным их перечнем можно ознакомиться здесь). Подобно случаю с дефолтными стилями, для их добавления в редактор не потребуется создавать отдельного компонента.

В случае же с кастомным блоком нам потребуется создать отдельный react-компонент и сообщить редактору, что он должен рендерить блок определенного типа [1], (в нашем случае SLIDER ) с помощью указанного компонента [2]. Для этого мы определяем функцию customBlockRenderer , получающую перым аргументом функцию для обновления editorState , а вторым — функцию для получения текущего editorState , эти же функции мы пробросим в props нашего компонента [3]. Также, определим RenderMap [4] — правила, сообщающие редактору, какой элемент должен быть оберткой для нашего компонента, в конкретном случае, это будет простой

RenderMap и метод this.blockRenderFn мы передаем в соответствующие свойства компонента Editor [1]. У компонента появилось еще два ранее не рассмотренных свойства: handleReturn и handleDroppedFiles . Первое из них [3] необходимо, что бы корректно обрабатывать нажатие пользователем кнопки Enter (переход на новую строку) для случая, когда курсор находится в пределах нашего кастомного блока. Дело в том, что если в момент нажатия Enter , курсор находится на участке текста являющимся блоком, Draft.js переводит курсор на новую строку и добавляет контейнер именно для того блока, на котором курсор находился, поэтому, чтобы у нас не вставлялся новый слайдер, мы предотвращаем такое поведение в методе this.handleReturn . В свойство handleDroppedFiles передается обработчик для события, перетаскивания файла/файлов в область редактора.

Здесь мы отфильтруем только изображения из массива переданных файлов [1], и если среди этих файлов изображений нет — то мы никак не будем обрабатывать это событие [2], а в положительном случае — обновим состояние редактора с помощью метода addNewBlockAt , реализацию которого можно посмотреть в файле для хранения утилит — /src/utils/index.js .

Изучая код множества open-source проектов, использующих Draft.js, можно найти для себя массу полезных рецептов для реиспользования кода. Также, хотел бы отметить вот этот репозиторий, где подобные утилитарные методы агрегируются. Чтобы метод addNewBlockAt разобрался, какой блок необходимо добавить и куда именно, в качестве аргументов мы передаем ему: текущий стейт редактора, ключ фрагмента текста, являющегося началом текущего selection , тип блока и данные для этого блока. Данные (url слайдов) мы для упрощения создадим с помощью метода URL.createObjectURL [4], то есть это будут blob-объекты. В реальных условиях здесь должен быть метод, отправляющий файлы на сервер и получающий в ответ url файлов лежащих на сервере. На коде самого компонента слайдера /src/components/Slider/EditorSlider.js не будем останавливаться, так как он является и работает как стандартный react-компонент, в props которого Draft.js передает необходимые данные. Приведу ниже лишь код метода updateData , обновляющего данные кастомного блока и вызывающегося после выхода из режима редактирования слайдов, в котором мы можем удалить, добавить или изменить порядок слайдов:

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

Демо-страница, ветка в репозитории — markup-export .

Что касается инициализации с предопределенным контентом — в Draft.js есть все необходимое для этого уже из коробки. Как упоминалось выше, для этого вместо EditorState.createEmpty , используется метод EditorState.createWithContent , в качестве аргументов необходимо передать объект особого формата и, опционально, декоратор. “Объект особого формата” получаем с помощью функции convertToRaw , передав ей на вход текущий ContentState редактора. Увидеть структуру этого объекта можно на demo-странице, открыв консоль и кликнув кнопку “Log state”. Код обработчика клика приведен ниже:

С генерацией же html-разметки все не так просто. Дело в том, что в Draft.js из коробки способов решения этой задачи нет. Предполагаю, что связанно это с тем, что в Draft.js допустимо определять кастомные сущности — стили, блоки. Однако, существует масса решений в виде отдельных модулей. Для нашего случая мы будем использовать draft-convert . В файле src/components/DraftEditor/converter.js определяем набор правил, в соответствии с которыми контент нашего редактора будет преобразован в html-строку:

Необходимо определить три функции: styleToHTML [1], blockToHTML [2] и entityToHTML [3]— их названия говорят сами за себя — каждая из них возвращает фрагмент разметки на основании типа инлайн стилизации, блока или entity . Также прошу обратить внимание, что в функции blockToHTML , определяя разметку для блока SLIDER , мы сохранили данные ассоциированные с блоком в переменную slides [4], преобразовали в JSON-строку и записали в data-атрибут data-slides .

Эти функции используются в конфигурационном объекте[1], который передается в метод convertToHTML , его вызов вернет функцию [2], которая в свою очередь получает первым аргументом contentState редактора и возвращает желаемое — html-строку. В файле DraftEditor.js мы импортируем нужный нам метод и используем его в обработчике клика по кнопке “Export & log markup”:

Сохраняем строку с html в переменную markup [1], для наглядности добавляем разметку на страницу и выводим в консоль [2]. Так как мы ожидаем увидеть на странице работающий слайдер, потребуется еще немного кода. Как вы помните, определяя разметку для блока SLIDER , мы записали массив с url слайдов в data-атрибут data-slides и присвоили особый класс js-slider , теперь, найдя на страницы все DOM-ноды с этим классом [3], используя стандартный метод render из React.js, мы просто рендерим на месте данной ноды компонент ContentSlider , передавая в его свойства массив url слайдов и текст подписи под слайдером [4]. Сам компонент ContentSlider — это урезанный EditorSlider , из которого удален весь лишний функционал.

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

Читайте также: