Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Разработка Rich Text Editor: проблемы и решения / Егор Яковишен (Setka)

253 views

Published on

РИТ++ 2017, Frontend Сonf
Зал Дели + Калькутта, 6 июня, 18:00

Тезисы:
http://frontendconf.ru/2017/abstracts/2550.html

Краткая история редактирования текста в браузерах. Родовые проблемы WYSIWYG-редакторов. Типы и функции современных веб-редакторов.

Обработка различных способов ввода (клавиатура, голос, copy&paste, autocomplete/autocorrect, gesture input). Проблемы с использованием contenteditable и execCommand. Браузерные API: Selection, Input Method Editor, Clipboard, MutationObserver, CompositionEvents. Спецификация W3C Input Events.
...

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

Разработка Rich Text Editor: проблемы и решения / Егор Яковишен (Setka)

  1. 1. Разработка Rich Text Editor: проблемы и решения Егор Яковишен, Setka
  2. 2. Setka Editor • многоколоночная верстка • гибкая настройка стилей • адаптивная верстка • CSS и JS эмбеды • live preview • плагин для WordPress
  3. 3. Более 20 млн просмотров
  4. 4. Текстовые редакторы появились давно…
  5. 5. MS-DOS Editor
  6. 6. Notepad
  7. 7. Microsoft Word
  8. 8. Adobe InDesign
  9. 9. А что в браузере?
  10. 10. <textarea>
  11. 11. TinyMCE
  12. 12. CKEditor
  13. 13. Froala Editor
  14. 14. Есть проблемы :-(
  15. 15. Проблемы • What You See is not What You Get • Функций очень мало или слишком много • Сложно «подружить» редактор с существующим дизайном сайта • Кроссбраузерность (IE, Safari, …) • Редакторы создаются как инструменты общего назначения
  16. 16. Проблемы • Строгая очистка HTML-кода — или наоборот • Проблемы с SEO • Верстка только под десктоп • Поддержка очень старых браузеров или только новых • …
  17. 17. Итак, вы решили сделать свой редактор…
  18. 18. Хорошая попытка!
  19. 19. Что предстоит? • Как редактировать контент? • Как хранить контент? • Как быть с CSS? • Как расширять функциональность редактора?
  20. 20. Как редактировать контент?
  21. 21. Как редактируется контент на странице? • document.designMode = "on” • <div contenteditable=“true”></div> • document.execCommand()
  22. 22. document.designMode = "on"
  23. 23. document.designMode = "on"
  24. 24. contenteditable <div contenteditable=“true”> Hello, world </div>
  25. 25. contenteditable: Chrome, Safari <div contenteditable=“true”> Hello, <div>&nbsp;world</div> </div>
  26. 26. contenteditable: Firefox <div contenteditable=“true”> Hello, <br> world </div>
  27. 27. document.execCommand // JS document.execCommand(‘bold’); document.execCommand(‘fontSize’, false, 7); <!-- HTML --> <b>Hello</b>, world <font size=“7”>Hello</font>, world
  28. 28. Проблемы • Разные браузеры генерируют разный HTML • execCommand работает не везде и не всегда (и тоже по-разному) • Вы не контролируете, что происходит :—(
  29. 29. Проблемы
  30. 30. Альтернативные способы • <canvas> • contenteditable + document state
  31. 31. contenteditable + document state • contenteditable используется только как интерфейс для отслеживания событий • все события перехватываются и происходит изменение document state • после изменения state обновляется DOM-представление документа • controlled input
  32. 32. document и editor state • Контент (текст, картинки, …) • Позиция курсора • Выделение текста • UI редактора
  33. 33. Draft.js
  34. 34. Google Docs: kix
  35. 35. Google Docs: kix
  36. 36. Google Docs: kix
  37. 37. Как хранить контент?
  38. 38. Хранение в виде HTML: плюсы • Легко показать в браузере • Легко изменять без редактора • Скорее всего, сейчас хранится именно так • Другой код приучен работать с HTML
  39. 39. Хранение в виде HTML: минусы • Разные браузеры выдают разный HTML из contenteditable • Сложнее экспортировать в другие форматы (FB IA, JSON, …) • Контент тесно связан с оформлением (style, class, …)
  40. 40. Декомпозиция на сущности • Заголовок • Параграф • Картинка • Врезка • Комментарий • …
  41. 41. Структура данных { type: “Paragraph”, content: “this is a text”, style: [ { range: [0,3], format: [“bold”] } ] }
  42. 42. Представления • Plain text • HTML • PDF • JSON, XML • RSS • Facebook Instant Articles, Google AMP, Apple News • А также разный рендеринг сущностей в редакторе и вне его
  43. 43. Workaround • Хранить данные в том формате, который уже есть (HTML) • При загрузке в редактор парсить их и работать со своим форматом • Удобно в тех случаях, когда нужно работать в устоявшейся экосистеме (например, CMS с плагинами)
  44. 44. Как работать с пользовательским вводом?
  45. 45. Клавиатура
  46. 46. Виртуальная клавиатура
  47. 47. Контекстное меню
  48. 48. Copy & Paste
  49. 49. Drag’n’drop
  50. 50. Голосовой ввод
  51. 51. Рукописный ввод
  52. 52. autocorrect и autosuggest
  53. 53. Браузерные API • У contenteditable нет единого события change • Selection API • Clipboard API • CompositionEvents • MutationObserver
  54. 54. Selection API • События selectstart и selectionchange • window.getSelection() • Range, anchorNode, offsetNode
  55. 55. Selection API
  56. 56. Clipboard API • События: copy, cut, paste, beforecopy, beforecut, beforepaste • document.execCommand(‘copy’) • Разные типы содержимого • Что можно сделать? • изменить содержимое буфера • запретить вставку • изменить алгоритм вставки • Чего нельзя сделать? • инициировать вставку
  57. 57. Clipboard API
  58. 58. Clipboard API
  59. 59. Clipboard API
  60. 60. Composition Events • à, è, ù, … • compositionstart • compositionupdate • compositionend
  61. 61. Undo / Redo • Системный механизм не подойдет • Храним снэпшоты state
  62. 62. Как быть с CSS?
  63. 63. В чем проблема? • Редактор — это компонент • У редактора есть свои стили (UI) • Редактор живет внутри приложения (CMS) • У приложения есть свои стили • Внутри редактора живет пост • У поста тоже есть свои стили (шрифты, цвета, …)
  64. 64. При этом… • CSS-правила живут в глобальной области видимости • Порядок применения правил определяется специфичностью • Помним про WYSIWYG!
  65. 65. WordPress CSS #poststuff h2 { font-size: 14px; padding: 8px 12px; margin: 0; line-height: 1.4; }
  66. 66. Итак, что изолируем? • Редактор • Пост • CMS • Шаблон сайта (в некоторых случаях)
  67. 67. Способы изоляции CSS • CSS reset + БЭМ • iframe • Shadow DOM + Custom Elements
  68. 68. Побеждаем специфичность WordPress CSS: #poststuff h2 { font-size: 14px; } CSS редактора: #my-editor h2 { font-size: 28px; }
  69. 69. Скользкая дорожка • инлайн-стили • !important
  70. 70. CSS reset + БЭМ • Раздувает размер CSS-файла • Постоянные войны со специфичностью (своей и чужой) • Не дает 100% гарантии (на каждый хитрый селектор…)
  71. 71. iframe • Создает барьер между страницей и редактором (и хорошо, и плохо) • Не адаптируется автоматически под размеры содержимого
  72. 72. Shadow DOM + Custom Elements <my-editor> #shadow-root </my-editor>
  73. 73. Shadow DOM + Custom Elements
  74. 74. Shadow DOM + Custom Elements
  75. 75. Адаптивная верстка • Верстаем на десктопе • Хотим видеть, как это выглядит на мобилке • А также менять определенные параметры для мобилки
  76. 76. Как расширять функциональность?
  77. 77. Расширение функциональности • Public API • Система плагинов • Документация
  78. 78. Public API • Получение и изменение контента в редакторе • Система событий • Интеграция с внешней средой (загрузка файлов, взаимодействие с CMS API и т.д.)
  79. 79. Система плагинов • Плагины должны уметь влиять на state редактора • Плагин — набор actions и reducers • API для расширения UI редактора • Примеры плагинов: • Проверка орфографии • Автотипограф • Интеграция с Google Drive
  80. 80. О чем еще надо подумать? • oembed и санитайзинг HTML • Контекстное меню • Горячие клавиши • Режим редактирования HTML и Custom CSS • Мета-сущности (комментарии) • Анимации • Оффлайн-режим • Запуск и остановка редактора
  81. 81. Что нас ждет?
  82. 82. Будущее rich text editing • W3C Input Events • Web Components
  83. 83. Input Events • События input и beforeinput • InputEvent.inputType • insert • insertReplacementText • deleteByCut • formatBold
  84. 84. Input Events • InputEvent.data (insert*, format*) • InputEvent.dataTransfer (text/plain, text/html) • InputEvent.getTargetRanges()
  85. 85. Итоги
  86. 86. Как редактировать данные? • Используйте contenteditable для отслеживания событий • Храните состояние редактора и контента в хранилище • Не храните состояние в DOM
  87. 87. Как хранить данные? • Определитесь с сущностями • Продумайте структуру документа • Напишите сериализацию и десериализацию
  88. 88. Как быть с CSS? • Редактор будет жить во внешней среде, которую вы не контролируете • Заранее подумайте об изоляции CSS • Кладите редактор в iframe или очищайте все, что можно
  89. 89. Расширение функциональности • Модульная архитектура • API • Плагины
  90. 90. Хорошие примеры • Quill (Salesforce, Telegra.ph) • Draft.js (Facebook) • Trix (Basecamp) • ProseMirror, CodeMirror • Google Docs • iCloud Pages
  91. 91. Спасибо! Егор Яковишен yakovishen@setka.io Telegram: @yaplusplus Facebook: Yegor Yakovishen

×