wysiwyg scheme что это
Информация
Новый редактор построен на принципе WYSIWYG. Эта аббревиатура расшифровывается как What You See Is What You Get — Что видишь то и получишь. То есть вы редактируете публикацию сразу в том виде, в каком её увидят ваши читатели. Потребность в использовании тегов отпала — форматировать текст можно на лету.
Создание публикации в новом редакторе разделено на два этапа. На первом вы пишете текст поста, на втором определяете его настройки отображения в ленте.
Создание публикации
Когда вы заходите на страницу создания нового поста (например, через иконку «карандаш» в верхнем правом углу), сразу открывается чистый лист редактора. Всё, что вы разместите на этом экране, увидят читатели, открывшие публикацию из ленты.
Сначала заголовок поста — не более 120 символов.
Ниже сам редактор — ставьте курсор под заголовком и начинайте вводить текст. Для форматирования можно использовать любой из удобных способов:
Выделить текст — появится всплывающее меню с кнопками:
Использовать стандартные горячие клавиши, например:
⌘/CTRL + B — выделение текста жирным
⌘/CTRL + U — подчёркнутый текст
⌘/CTRL + I — курсив
⌘/CTRL + K — привязка ссылки к тексту
⌘/CTRL + Z — отмена действия
Вставлять дополнительные элементы также можно несколькими способами:
через кнопку « + » с левой стороны редактора
через клавишу « / » на клавиатуре
Любой из этих вариантов вызовет всплывающее меню вставки элементов, о которых чуть ниже.
Элементы могут быть не только блочными, но и строчными — через клавишу «/» внутри строки можно вставить небольшое изображение или формулу.
Ну или можно сразу вставить markdown-код из внешнего редактора, должно сработать.
Меню с блочными элементами
Просто выберите нужный элемент в появившемся меню и он вставится. Можно пользоваться только клавиатурой: жмём « / » → появляется меню → начинаем вводить « та… » → выбирается « Таблица ». Или набираем на клавиатуре « /ци », жмём Enter → вставляется цитата.
Заголовок. Размер заголовка можно поменять в меню настроек блока (троеточие справа).
Цитата. Вставляет блок с вертикальной чертой слева.
Маркированный список. Может быть разных уровней вложенности.
Медиаэлемент. Пункт для вставки в статью информации с внешних ресурсов: твиты, записи из соцсетей, ролики с YouTube, сниппеты с Codepen и т. д.
Изображение. Загрузка картинок с вашего устройства. Из настроек — можно расположить по левому краю, добавить рамку или подпись.
Разделитель. Выровненная по центру полоска, можно использовать для отделения одного раздела от другого.
Таблица. По умолчанию вставляется таблица 3х3, но можно добавлять как строки, так и столбцы — соответствующие кнопки появятся при нажатии на таблицу. Главное не переусердствовать: всего-всего уместить в таблицу не получится, поэтому следите за тем, чтобы содержимое таблицы было удобно считывать пользователям разных устройств. Ячейки таблицы можно объединять/разделять, а их содержимое — расположить по центру или правому/левому краю.
Код. Вставка блока с кодом, который будет обрамлён в рамку, а строки будут пронумерованы. Опционально можно выбрать язык для подсветки синтаксиса.
Формула. Ввод математических формул в Tex-формате.
Спойлер. Вставка разворачиваемого блока, внутри которого обычно прячут какую-то дополнительную информацию (текст, ссылки, длинный код) — для вставки доступны все перечисленные выше элементы. Опционально можно задать заголовок спойлера.
Якорь. Элемент, который может быть полезен для составления оглавления. Вставьте якорь в нужном месте поста и присвойте ему имя, а в другом месте сделайте ссылку на него.
Со временем список элементов может меняться.Каждый описанный выше элемент является блоком, который можно двигать вверх-вниз или удалять.
Важно: в новом редакторе нет понятия «кат», то есть элемента, разделяющего пост на вступление (выводимое в ленте) и основное содержимое. Текст вводной части поста (для ленты) настраивается на втором экране редактора и может отличаться от текста в начале самого поста.
Важно: в редакторе имеется автосохранение — оно сохраняет в localStorage браузера весь тот материал, который вы вставили в редактор. То есть если вы случайно закроете вкладку с редактором, всегда можно открыть её заново и восстановить текст.
Но если вы откроете форму редактора в другом браузере (например, с другого устройства), текст не восстановится. Чтобы иметь возможность править пост из разных браузеров на разных устройствах, нужно сохранить черновик публикации (чтобы ей присвоился ID).
Если вы готовите статью во внешнем редакторе
Написать большую статью на одном дыхании бывает сложно, почти всегда это занимает немало времени — возможно, вместо формы на Хабре вы захотите использовать удобный вам текстовый редактор. А если статью нужно предварительно согласовать с кем-то, то совершенно точно есть смысл подготовить материал где-нибудь в GoogleDocs.
Если вы пишете статью в обычном текстовом редакторе, то можете сразу форматировать текст markdown-разметкой — потом просто скопируйте всё и вставьте в форму редактора. Он автоматически преобразует разметку в нужный результат.
Если вы пишете статью в Google Docs или ворде, то можете выделить там весь текст (с картинками) и вставить в форму создания поста — должно подхватиться всё форматирование (включая заголовки) и даже картинки.
Но в обоих случаях убедитесь, что всё корректно перенеслось и загрузилось. Если что-то не работает — пишите в форму обратной связи.
Размещение
Когда вы допишете текст, отформатируете его (заголовки-шрифты-ссылки) и вставите все необходимые медиаэлементы (изображения, видео) ещё раз проверьте публикацию — именно в таком виде её увидят все читатели.
А дальше останется всего ничего: нажмите кнопку «Готово к публикации» и на втором экране редактора укажите «системные» настройки. Среди них:
Тип публикации. «Статья» или «Новость». Первый вариант подходит для больших материалов — выбрав его, вы подтверждаете, что являетесь автором текста и рейтинг поста зачислится вашему профилю в полном объёме. Второй вариант подходит для небольших материалов, которые имеют признаки «новостей» (некая информация, актуальная здесь и сейчас).
Язык публикации. Укажите язык, на котором написана публикация — чтобы статью видели те пользователи сайта, которым ваша статья подойдёт по языковым настройкам.
Хабы. Выберите в выпадающем меню один или несколько (до пяти) хабов, в которые вы планируете разместить свой пост. Вместо одного из хабов можно выбрать блог компании — укажите, если он есть (тогда рейтинг за пост пойдёт в зачёт и вашей компании).
Ключевые слова. Ещё одно обязательное поле, где через запятую укажите до 10 ключевых слов по теме вашего материала. Через запятую, без #. Подберите такие слова, по которым ваш пост смог бы найти кто-то посторонний. Эти ключевые слова будут в самом конце вашей публикации.
Переводы и обучающие материалы. Если вы готовите перевод, то следует нажать чекбокс «Переведённый материал» — тогда дополнительно потребуется указать автора оригинала и ссылку на него, а в зачёт пойдёт лишь половина рейтинга. У опубликованной статьи под заголовком будет пометка «Перевод» со ссылкой на первоисточник — чтобы свести к минимуму риск претензий от автора. А если ваша статья носит обучающий характер, то нажмите чекбокс «Tutorial». Тогда после публикации под заголовком появится одноимённый значок.
Отображение публикации в ленте
В этом разделе редактора настраивается внешний вид той части, которая будет видна в лентах пользователей — на главной странице, внутри хаба и т. д. Здесь свободы действий чуть меньше, но зато вступительные части публикаций стали выглядеть в одном формате.
Желательно загрузить обложку поста (картинка в формате jpg, gif или png, рекомендуемый размер 780×440), а также ввести текст вводной части (до 2 тысяч символов).
Важно: изображение (обложка) и содержимое вводной части поста (выводимое в ленте) может отличаться от того вступления, которое будет видеть пользователь на странице самой публикации. Это даёт дополнительную свободу действий, но иногда может мешать — в таком случае используйте первые абзацы своей статьи (по умолчанию эта часть будет подгружаться автоматически). У вводного текста также есть возможности форматирования, но вставить видеоролик или несколько картинок не получится.
Текст кнопки «Читать далее» можно оставить по умолчанию, но при необходимости его также можно поменять.
Если пост нужно выпустить в определённое время, воспользуйтесь функцией запланированной публикации — выберите желаемые дату и время.
Всё, финишная прямая с тремя вариантами: можно вернуться к редактированию поста, сохранить его в черновики или опубликовать. В первом случае вы вернётесь на первый экран редактора, во втором — пост сохранится у вас в профиле с присвоением ID, а в последнем случае он сразу окажется на сайте и его начнут читать пользователи Хабра.
Не забывайте следить за комментариями и отвечать на них в случае необходимости. Советы по работе с обратной связью мы уже давали.
Если остались вопросы по работе редактора или появились предложения — можете смело отправлять их в форму обратной связи.
Пишем простой WYSIWYG-редактор с помощью ProseMirror
Обзор ProseMirror
Автор ProseMirror – Marijn Haverbeke, который известен в сообществе фронтенд-разработчиков в первую очередь как автор популярной книги Eloquent Javascript. На момент начала нашей работы (осень 2018 года), никаких материалов по работе с этой библиотеке не было, кроме официальной документации и туториалов от автора. В пакет документации от автора входят несколько разделов, самые полезные из них — это ProseMirror Guide (описание базовых концепций) и Reference Manual (спека библиотеки). Ниже будет пересказ ключевых идей из ProseMirror Guide.
ProseMirror всегда хранит состояние документа в своей собственной структуре данных. И уже из этой структуры в рантайме генерируются соответствующие DOM-элементы на странице, с которыми взаимодействует конечный пользователь. Причем ProseMirror хранит не только текущее состояние (state), но и историю предыдущих изменений, к которым можно при необходимости откатиться. Любое изменение состояния должно происходить через транзакции (transactions), привычные манипуляции с DOM-деревом напрямую тут не сработают. Транзакция – это абстракция, которая описывает логику пошагового изменения состояния. Суть их работы напоминает отправку и исполнение экшнов в библиотеках для управления состоянием, например, Redux и Vuex.
Сама библиотека построена на независимых модулях, которые можно отключать или добавлять в зависимости от потребностей. Список основных модулей, которые, как нам показалось, нужны будут практически всем:
Редактор с помощью ProseMirror
Начнем с создания схемы редактора. Схема в ProseMirror задает список элементов, которые в нашем документе могут быть, и их свойства. У каждого элемента есть метод toDOM, который определяет, как этот элемент будет представлен в DOM-дереве на веб-странице.
Принцип WYSIWYG реализуется именно в том, что у нас при создании схемы есть полный контроль над тем, как отображается редактируемый контент на странице, и, соответственно, мы можем задать каждому элементу такую HTML-структуру и задать стили так же, как контенту для просмотра. Ноды можно создавать и настраивать под свои требования, в частности, скорее всего вам могут понадобиться абзацы, заголовки, списки, картинки, абзацы, медиа.
Допустим, у нас каждый абзац текста должен оборачиваться в тег «p» с классом «paragraph», который определяет необходимые по макету правила стилей абзаца. Тогда схема ProseMirror в этом случае может выглядеть так:
Для начала импортируем конструктор для создания своей схемы и передаем в него объект, описывающий nodes (далее – ноды) в будущем редакторе. Ноды – это абстракции, описывающие типы создаваемого контента. Например, с такой схемой в редакторе могут быть только ноды типов text и paragraph. Doc – это имя ноды верхнего уровня, которая будет состоять только из блочных элементов, т.е. в данном случае только из параграфов (потому что другие мы не описали).
Text – это текстовые ноды, чем-то похожие на текстовые DOM-ноды. С помощью свойства group мы можем разными способами группировать наши ноды, чтобы к ним можно было проще обращаться в коде. Группы можно задать любым удобным нам способом. В нашем случае мы разделили ноды только на блочные и инлайные. Text является инлайновым по умолчанию, поэтому это можно явно не указывать.
Совсем другое дело paragraph (абзац). Мы объявили, что абзацы состоят из инлайновых текстовых элементов, а также имеют свое представление в DOM. Абзац будет являться блочным элементом, примерно в том смысле, в каком являются блочными элементы DOM. По этой схеме абзацы на странице будут представлены в онлайн-редакторе следующим образом:
Теперь можно создать сам редактор:
В начале, как обычно, импортируем все необходимые конструкторы из соответствующих модулей и берем уже описанную выше схему. Редактор создаем в виде класса с набором необходимых методов. Для того чтобы на веб-странице появилась возможность редактировать и создавать контент, нужно создать состояние – state, – используя схему и контент статьи, и представление контента из текущего состояния в заданном корневом элементе. Мы поместили эти действия в метод setArticle, кроме которого пока ничего не нужно.
При этом контент передавать необязательно. Если его нет, то получится пустой редактор, и контент уже можно будет создать непосредственно на месте. Допустим, у нас есть HTML-файл с такой разметкой:
Для создания на странице пустого WYSIWYG-редактора понадобится всего несколько строк в скрипте, который выполняется на странице с такой разметкой:
С помощью такого кода можно написать с нуля любой текст. На этом этапе уже можно посмотреть, как работает ProseMirror.
Когда пользователь печатает текст в этом редакторе, возникают транзакции состояния. Например, если в редакторе с описанной выше схемой напечатать фразу «Это мой новый классный WYSIWYG-редактор», ProseMirror отреагирует на ввод с клавиатуры тем, что вызовет соответствующий набор транзакций, и после окончания ввода в состоянии документа обновится контент, который будет выглядет так:
Если же мы хотим, чтобы в редакторе сразу открывался для редактирования какой-нибудь текст, например, контент уже созданной ранее статьи, то необходимо, чтобы этот контент соответствовал созданной ранее схеме. Тогда код инициализации редактора будет выглядеть немного по-другому:
Ура! Мы сделали наш первый редактор, который умеет создавать чистую страницу для создания нового контента и открывать для редактирования существующий.
Что делать с редактором дальше
Но даже с полным набором нод в нашем редакторе все еще отсутствуют важные функции — форматирование текста, абзацев. Для этого помимо нод в схему надо еще передать объект с настройками для форматирования – marks. Для простоты мы их так и называем – марками. А для управления добавлением, удалением и форматированием всех этих элементов пользователям нужно будет меню. Меню можно добавить с помощью кастомных плагинов, которые стилизуют объекты меню и описывают изменение состояния документа при выборе тех или иных действий.
С помощью плагинов можно создавать любые конструкции, расширяющие встроенные возможности редактора. Основная идея плагинов заключается в том, что они обрабатывают определенные действия пользователя, чтобы генерировать соответствующие им транзакции. Например, если нужно, чтобы клик по иконке списка в меню создавал новый пустой список и переводил курсор в начало первого элемента, то нам точно понадобится описать эту транзакцию в соответствующем плагине.
Подробнее про настройки форматирования и плагины можно почитать в официальной документации, также очень полезными могут быть наглядные небольшие примеры использования возможностей ProseMirror.
UPD Если вам интересно, как мы интегрировали новый редактор на основе ProseMirror в уже существующий проект, то мы рассказали об этом в другой статье.
Suit Up! Простой и легкий WYSIWYG
Вступление
Не так давно, а, точнее, года два назад, в кругу разработчиков, с которыми я имел честь общаться (почти все — новички), каждый, кому поступила задача поставить WYSIWYG, ставили монстрообразный TinyMCE. Этот редактор считался почему-то стандартом у многих веб разработчиков, хотя, мало кому нужны были то большое количество функций, которые предлагались программистам. Тут тебе и то и это. Наверно, таким образом, новички пытались сказать клиенту «смотри, мы тебе на сайт запилили Ворд».
Однажды (не помню при каких условиях), мне захотелось или понадобилось разобраться в том, как работают браузерные «рич эдиторы». Моему удивлению не было предела, когда я сам, не имея каких-либо глубоких познаний в веб разработке, сделал две кнопочки: Bold и Italic, что оказалось очень простой задачей. Мне захотелось больше узнать о том, что же делать дальше. Так я познакомился с серией статей «WYSIWYG HTML редактор в браузере» (по ссылке первая статья, советую прочесть). Но информация на тот момент мне показалась несколько сложноватой. Поэтому я решил методом тыка, наступая на уже растоптанные кем-то грабли, написать свой простой редактор.
Сделал я его в виде jQuery плагина, и, думаю, не стоит отвечать «почему». Получилось кое-как заставить работать его в разных браузерах. Тут мне пришла в голову идея написать статью на хабр, после некоторых доработок. Время шло, допиливание я откладывал, откладывал… Два года, черт, целых два года. Но я постараюсь исправиться.
Простейший редактор
Для того, чтоб дать возможность пользователю менять содержимое блока (в данном случае, обычного дива) просто задаём ему (блоку) атрибут contenteditable:
Редактор готов!
Шучу 🙂
Добавим на страницу кнопку Bold, делающую текст жирным:
Пишем простейший обработчик клика:
Готово. Выделяем текст в диве, нажимает на кнопку: оп, текст жирный. Нажимаем еще раз: хоба, текст стал прежним.
Добавляем еще две кнопки
Первая будет делать текст наклонным (italic, как и bold не требует значения, так как он и в Африке italic), вторая — менять цвет текста на красный.
Редактор SuitUp
Демо
Итак, хочу показать свою версию легковесного редактора, который, конечно, не так крут, как многофункциональные фено-морозилко-будильнико-утюги, но неплохо справляется с задачами нетребовательного разработчика. Хотя, количество поддерживаемых методов велико.
Задачей было предоставить удобную прослойку между командами и программистом 🙂
Запускается это дело, как и все плагины таким образом:
В качестве аргументов можно передать список команд:
Или один аргумент в виде массива
«|» в списке означает обычный разделитель, как элемент дизайна. Элементы, в которых присутствует решетка, говорят нам о том, что перед решеткой находится команда, после — значение. Просто пишете название_команды#значение, получив при этом обычную кнопку. Остальные элементы — это команды, которые следует определить, иначе не известно, как мы должны получать значение. Если поведение не определено, то, по умолчанию, значением будет считаться null. Ниже я попробую привести примеры для большей наглядности.
Определение команд (как должны вести себя команды)
Для определения команд был создан объект jQuery.suitUp.commands, содержащий пары ключ-значение (ваш кэп), где ключём является имя команды, например, ‘forecolor’, а значение может иметь три типа:
1. Собственно, само значение: для forecolor это может быть red:
2. Словарь значений (объект)
Он преобразуется в обычный тег select, опции которого выглядят как ключ словаря, при выборе которых задействуется значение словаря.
3. Функция, которая отвечает за то, как мы должны получить значение команды. Она асинхронна, то есть, в функции можно создать модальное окно с запросом значения. Для примера приведу обычный propmt:
Часть команд определена в самом скрипте, часть — в отдельном файле, список команд достаточно велик для того, чтоб не заморачиваться с определением. То есть, можно просто передать аргументы в метод suitUp и это будет просто работать:
Попробуем добавить несколько кнопочек. Смотрим команды на сайте мозиллы. Скажем, нам хочется добавить:
1. Опять Bold.
2. Выбор шрифта.
3. Диалог, в котором пользователю нужно ввести значение цвета в кастомное окошко и нажать «ок».
И представим, что ни одна из этих команд не определена.
С первой и второй командой, думаю, всё понятно. В третьей большую часть кода занимает создание элементов, стоит только обратить внимание на обработчик клика на button. В нем, после получения значения цвета и удаления попапа, вызывается callback, в который и передаётся полученный цвет. Callback возвращает редактору фокус, восстанавливает выделение, сделанное до нажатия кнопки и применяет команду forecolor к выделению.
Внимание! Несмотря не то, что команды из разных источников обозначены в виде camelCase, для корректной работы плагина, все символы должны быть в нижнем регистре. Это касается и значений команд.
Кастомные команды
Кроме возможности использования стандартных команд, плагин поддерживает создание собственных элементов. Дабы не мудрить, я решил сделать добавление кастомных контролов обычными функциями, возвращающими элемент.
Как и в случае с командами, для кастомных элементов используется обычный объект:
Добавим элемент, при нажатии на который вызывается обычный алерт с приветствием.
Обратите внимание, что в кастомных командах регистр не имеет значения.
По дефолту, в списке кастомных элементов наличествует элемент «link», который кроме добавления ссылки (команда «createlink»), убирает ссылку в текущем выделении (команда «unlink»).
Как видно, кастомные элементы нужны не только для создания необычных контролов (как в случае с helloWorld), но и позволяет решить проблемы со стандартными командами.
Список команд по умолчанию
Вместо постоянной передачи аргументов в метод suitUp можно объявить набор кнопок лишь однажды:
В массиве controls содержится список кнопок, которые подключаются по умолчанию. Это самый обычный массив. Например, можно добавить к списку по умолчанию еще один элемент:
Или сделать так:
для того, чтоб добавить кнопки для конкретного редактора (если их несколько на странице).
Несколько дополнительных функций
$.suitUp.getSelection
Возвращает текущее выделение. Для нормальных браузеров и для ослов возвращаемые значения будут разными.
$.suitUp.restoreSelection
Восстанавливает выделение. В качестве единственного аргумента передается значение, полученное в getSelection.
$.suitUp.getSelectedNode
Возвращает ноду текущего выделения (это может быть как тег так и текстовая нода)
$.suitUp.hasSelectedNodeParent
Малозначимая функция, используется только в кастомном элементе «link». Проверяет, есть ли у ноды текущего выделения родитель с тегом, определенным в единственном аргументе.
Скрипт тестировался в Chrome, Firefox, IE10 (+IE7 Mode)
На скорую руку создал репозиторий, пользуйтесь: github.com/finom/Suitup
В файле extended-commands.suitup.jquery.js содержится несколько команд для тестов. Раскомментируйте код с 50 строки и оцените изобилие далеко не всех команд, которые поддерживаются плагином.
С опечатками и не точностями, пожалуйте в личку.
Критика из комментариев
Наверное, стоит уведомить потенциальных пользователей, с какими проблемами они могут столкнуться при работе с редактором. Вся критика из комментариев сводится к особенностям браузеров, которые могут быть неподобающими, если проект требует унифицированного форматирования.
1. Для разных браузеров некоторые команды обрамляют текст в разные теги. Например, команда bold в Chrome обрамляет текст в тег b, а в IE в тег strong.
2. Обработка пользовательских действий может быть разной в разных браузерах (примеров пока что не приходит в голову).
3. Юзер может использовать форматирование, которое не подразумевалось. Например, может скопировать текст из ворда и вставить в редактор.
Всё это — дань компактности плагина. Если желаете использовать редактор для серьезного публичного проекта, я, как автор, советую воспользоваться альтернативными решениями. Редактор подойдет для небольших проектов и внутреннего использования, например, в админках. Впечатление от использования в таком ключе — исключительно положительные.