Contenteditable — редактирование контента «на лету». Урок 2


Содержание материала:

ContentEditable div заменить innerHTML на лету

Есть ли способ (кроме библиотеки Rangy), чтобы изменить contentEditable Div InnerHTML на лету, как на клавиатуре, без потери позиции курсора/фокуса? Я бы хотел использовать чистый код javascript, насколько это возможно.

Если вы заменяете HTML, вам понадобятся некоторые средства для сохранения и восстановления вашего выбора. Возможные варианты:

  • Вставляйте элементы с идентификаторами в начале и конце выбора перед заменой HTML, затем возвращайте их по идентификатору и перемещайте границы выделения с помощью этих элементов. Это самый надежный метод, и это то, что делает Rangy.
  • Храните какое-то смещение на основе символов для начала и конца выделения перед заменой HTML и последующим повторным созданием выделения. У этого есть все проблемы в общем случае, но может быть достаточно хорошим, в зависимости от ваших потребностей. Я размещал функции SO, чтобы сделать это до, которые зависят от Rangy, но вы можете легко лишить материал Rangy, если вы не против потери поддержки IE

Это не использует событие keyup, но, возможно, этого будет достаточно? Обратите внимание, что применительно к телу вы, очевидно, можете ориентироваться только на определенный элемент.

Изменить контент на лету

В настоящее время я работаю в создании динамического шаблона, где пользователь может перетащить любой определенный элемент из области источника в область назначения. Теперь после удаления пользователь может изменить его текст (изменить / добавить новый).

Я сделал перетаскивание, но как изменить его текст после удаления. ?

Есть ли библиотека JavaScript, чтобы помочь мне?

2 ответа

Ответ прост. После удаления вашего элемента измените его содержимое на textarea, которое можно оформить так, чтобы оно выглядело так же, как перед перетаскиванием.

По вопросу о библиотеке. Я бы использовал jQuery из-за легкого манипулирования контентом. Вы делаете что-то вроде этого:

Это будет делать только одно, и это изменение контента на textarea. Это можно сделать разными способами. Я просто пытаюсь показать вам, куда идти.

PS: Если вы покажете какой-то код, кто-то может помочь вам сделать это именно для вашего кода.

Редактирование контента на лету. Урок 2

WebForMySelf 23 СКАЧАТЬ

Бесплатные уроки по созданию сайта тут:
https://webformyself.com/hivideo/

От автора: в этом мы продолжим работу с атрибутом HTML5 contenteditable. При изменении значения редактируемого поля, скрипт будет отправлять асинхронным запросом (средствами AJAX) новое значение, и сохранять его в БД.

редактирование сайта «на лету» с последующим сохранением

Дубликаты не найдены

в смысле для chrome? chrome это браузер, а движок у сайта, на него поищи плагины, которые позволят редактировать сайт в визуальном редакторе.

p.s. у меня id в вк такой же, если что пиши

я в этих целях использую FileZilla+Notepad++
но в посте речь немного о другом.
то, что предлагаешь ты, подразумевает, что нужно открыть через ftp-клиент нужный файл, внести изменения редактором, сохранить, а ftp-клиент автоматически заменит файл на сервере обновленным.

А я говорю о том, что я меняю «на лету» через «проинспектировать элемент» в Chrome. И затем сохраняю.
а приложение само вычисляет, в каком файле этот код прописан и вносит в него изменения.

понимаешь разницу?
искать файлик самой или это за меня сделает приложение ^^

Разработка Rich Text Editor: проблемы и решения

Текстовые редакторы, как тип программного обеспечения, появились чуть позже чем динозавры, и вероятнее всего это был вообще первый софт, с которым вы столкнулись в своей жизни, возможно кто-то даже застал MS-DOS Editor.

Однако с переходом большой части ПО в браузеры актуальны и соответствующие визуальные редакторы Rich Text Editors, и проблемных мест в их разработке масса. Если вы по какой-то причине решили сделать свой собственный редактор, то подумайте еще раз — есть мнение, что делать этого не нужно.

Чтобы вы могли принять более взвешенное решение, Егор Яковишен обобщил весь свой опыт, полученный в процессе создания Setka Editor, и рассказал про проблемы, с которыми придется столкнуться, и что можно предпринять для их решения.

Disclaimer: статья написана на основании доклада Егора на конференции Frontend Conf 2020 в июне 2020 года. Ситуация с поддержкой браузерами определенных API с тех пор уже могла измениться.

Про опыт

Компания Setka, в которой я работаю, разрабатывает инструменты для оптимизации процессов в командах, занимающихся контент-маркетингом, редакциях онлайн СМИ, а также в контентных командах брендов, запускающих свои издания. Один из наших продуктов — крутой визуальный редактор Setka Editor, позволяющий создавать вовлекающий пользователей контент действительно быстро и не теряя качества. Вот ряд возможностей редактора:

  • многоколоночная «журнальная» верстка;
  • гибкая настройка стилей под каждое издание или бренд;
  • адаптивная верстка под все устройства;
  • шаблонизация и автоматизация процессов создания статей (сниппеты, темплейты);
  • кастомные блоки CSS и JS-эмбеды;
  • live preview – возможность на лету смотреть чистовой вариант верстки.

Редактором можно пользоваться в WordPress (мы выпустили для этого специальный плагин), а также интегрировать в любую другую CMS.

Setka родилась в стенах издательского дома Look At Media, который объединяет популярные издания The Village, Furfur, Wonderzine и другие. Подробнее о предпосылках и истории разработки Setka Editor вы можете прочитать в статье из корпоративного блога Setka. Ниже пример верстки поста, который сделан в нашем редакторе.

Это могут быть как ежедневные новости, так и лонгриды, и спецпроекты.

Посты, сверстанные в Setka Editor только на наших изданиях ежемесячно генерят более 20 млн просмотров в месяц – просто чтобы вы понимали масштабы тех задач, с которыми нам приходится сталкиваться.

Предыстория

Текстовые редакторы, как тип программного обеспечения, появились очень давно. Наверное, для многих это был вообще первый софт, с которым они столкнулись в своей жизни. Кто-то, может быть, застал MS-DOS Editor:

Очевидно, все видели блокнот Notepad в разных его исполнениях:

Microsoft Word тоже уже пережил много версий:

Помимо этого существуют специализированные программы, например, Adobe InDesign, для действительно сложной журнальной верстки:

Но это все классическое ПО, которое работает в операционной системе как десктопный софт.

Тем временем, в браузере ситуация другая. Во-первых, у нас есть обычная textarea. Это поле, куда можно писать текст, оно работает абсолютно везде – отличная кроссбраузерность! Но есть проблема: никакой стилизации, а уж тем более сложной верстки в этой textarea никогда не сделать, потому что это просто поле для ввода plain text. Оно лишь чуть сложнее, чем текстовый input.

Есть много продуктов, которые называют себя Rich Text Editor. Вы наверняка много раз с ними сталкивались на разных сайтах. Вот некоторые классические представители.

TinyMCE

CKEditor

Froala Editor

И еще десятки других проектов разного уровня проработки, у большинства которых есть так называемые «родовые проблемы».

Типовые проблемы Rich Text Editors

WYSIWYG

Практически во всех редакторах не соблюдается ключевой принцип WYSIWYG (What You See is What You Get). Это означает, что верстка, которую вы видите в редакторе, не обязательно будет совпадать с тем, что посетители увидят на вашем сайте. В редакторе вы работаете с маленьким окошком фиксированного размера, а на страницах сайта всё оказывается совсем иначе, т.к. там определенный шаблон сайта со своими стилями, другая ширина контентной области, дополнительные блоки и т.д. А если пользователь заходит на сайт с мобильного устройства, там уже применяются совсем другие правила.

Функций очень мало или слишком много

Функций в таких редакторах, как правило, или очень мало (bold, italic, выравнивание текста), или слишком много – 5 строчек кнопок, в которых невозможно разобраться.

Сложно «подружить» с уже существующим дизайном сайта

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


Кроссбраузерность

У многих редакторов есть проблемы с кроссбраузерностью — как с их интерфейсом, так и с версткой, которую они генерируют. Особенно это касатеся старых IE и Safari, но и Firefox временами преподносит сюрпризы.

Инструменты общего назначения

В большинстве случаев, Rich Text Editor – это просто инструмент для перевода визуальных блоков в HTML и CSS-код, созданный для людей, которые по разным причинам не хотят или не умеют писать код вручную. Если же вам нужен более продвинутый инструмент для решения своих задач, то часто WYSIWYG-редакторы из помощников превращаются в препятствия.

Также есть масса других проблем, например:

  • HTML-код в таких редакторах, как правило, проходит очень сильную очистку или, наоборот, вообще её не проходит. То есть либо вы сильно ограничены в возможностях, либо создаете потенциальную XSS-уязвимость.
  • Это же часто создает проблемы с SEO.
  • Как правило, такие редакторы позволяют верстать посты только под десктоп, и вы не знаете заранее, как ваш контент будет преобразован под mobile. Хотя, например, на наших сайтах мобильного трафика уже сейчас более 50%.
  • Поддержка очень старых браузеров (и масса легаси-кода вследствие этого) или, наоборот, только самых новых

И так далее. Проблем и вопросов действительно очень много.

Вы решили сделать свой редактор

Итак, наступил момент X, и вы по какой-то причине вы решили сделать свой собственный редактор.

Хорошая попытка, но не делайте этого!

Интернет просто пестрит постами, где написано, что не стоит этого делать. Cкорее всего, масса ограничений помешают вам сделать действительно хороший продукт.

В частности, это скриншот со StackOverflow, на котором один из разработчиков CKEditor (один из старых и известных редакторов) пишет, что они делают его уже 10 лет, у них до сих пор тысячи issues и, к сожалению, они не могут получить хороший результат — не потому, что они плохие разработчики, а потому, что плохие браузеры.

Тем не менее, вы все-таки отвергли все сомнения и хотите сделать свой редактор. С какими ключевыми вопросами вам предстоит столкнуться? Надо будет разобраться:

  1. как редактировать контент на веб-странице;
  2. как хранить этот контент;
  3. как быть со стилями (CSS);
  4. как расширять функциональность редактора.

Про это мы сегодня и поговорим. Начнем по порядку.

Как редактировать контент?

Исторически браузеры для этого предоставляют следующие возможности.

DesignMode

У объекта document есть такое свойство, оно существует очень давно – наверное, еще в конце 90-х годов было реализовано в первых версиях Internet Explorer.

Когда это свойство переключается в режим on, то абсолютно вся страница, все содержимое body становится редактируемым. Вы можете поставить курсор в любое место и отредактировать текст.

Если погуглить, можно увидеть восторженные комментарии 10-15 летней давности на форумах типа Античата, о том, как классно можно отредактировать любую страницу, например, сайты Microsoft, Google и так далее.

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

Contenteditable

Это основной браузерный API для создания редактируемых блоков. При переключении этого атрибута в значение true все, что находится внутри блока, становится редактируемым. Именно таким образом сейчас сделано большинство визуальных редакторов, и наш – не исключение.

Проблема в том, что каждый браузер реализует пользовательские действия в этом блоке по-разному. Простейший пример: есть блок с текстом «Hello, world», включаем contenteditable=”true”, он становится редактируемым. Далее ставим курсор за запятой после слова «Hello» и нажимаем кнопку Enter.

После этого в Chrome и Safari появится новый

внутри блока, в нем неразрывный пробел и оставшееся слово «world».

А в Firefox – перенос строки
.

Таким образом, вы никак не контролируете ситуацию, потому что каждый браузер действует по-разному.

Document.execCommand

Это специальный метод, который позволяет к выделенному участку текста применять браузерные команды. Таких команд есть фиксированное количество, например, bold, fontSize, formatText и так далее.

JS

HTML

Этот API тоже существует очень давно и он крайне нестабилен. Допустим, в том же самом примере вы выделили слово «Hello» и выполнили команду execCommand (‘bold’). Текст обернулся в тег . Какие тут могут быть потенциальные проблемы? Во-первых, может быть, я хочу не , а (меня СЕОшники попросили). Или, может быть, я хочу на этот тег еще какой-то класс добавить и мне придется делать совершать дополнительное действие.

Ладно, еще не так страшно, а если я хочу, допустим, шрифт сделать большим заголовком? Я выполняю браузерную команду fontSize, передаю значение 7. И что же? Вставляется тег , который мы уже не видели на сайтах с начала 2000-х годов, причем 7-го размера. Да, визуально это похоже на то, что требовалось, но с точки зрения кода, семантики, SEO и последующей поддержки — это кошмар.

  • Разные браузеры генерируют разный HTML.
  • execCommand работает не везде и не всегда (и тоже по-разному).
  • Вы не контролируете, что происходит.

В итоге, если использовать только стандартные API, то редактор получается неполноценным. Вы не можете использовать семантические теги и применять корректные стили, не знаете, как потом это парсить и как это повлияет на SEO.

Есть хрестоматийная статья «Why ContentEditable is Terrible», в которой разработчики описывают, почему contenteditable плох, и что с этим делать.

Альтернативные способы

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

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

Второй способ, который чаще всего используется на практике почти во всех современных редакторах (и в частности, у нас) — это связка contenteditable-области и хранения состояния документа (document state) на основе тех действий, которые в этой области происходят.

Допустим, у вас есть contenteditable область. В классическом ее использовании вы ставите курсор, пишете текст, и контент меняется, причем как мы уже говорили, меняется непрогнозируемо. В данном же случае, когда вы что-то пишите в input, сначала нужным образом меняется state, а затем input перерендривается на основании изменения состояния. По сути, это подход, который в React называется Controlled Input. Это, в свою очередь, может вызвать проблемы с производительностью при быстром наборе текста. Тогда нужно использовать гибридный вариант: ввод текстовых символов сразу отображать в DOM, а более сложные действия обрабатывать сначала самостоятельно.

Допустим, вы поставили курсор в текстовое поле и нажали Enter. Редактор понимает, что надо вставить перенос строки, или, если у вас в этот момент был выделен не текст, а объект, то надо произвести какое-то другое действие. Таким образом, вы можете контролировать абсолютно всё: что происходит у вас в редакторе: выполнять нужные действия, отменять ненужные и пр.

Общая схема:

  • contenteditable используется как интерфейс для отслеживания событий;
  • все события перехватываются и происходит изменение document state (кроме тех событий, которые происходят очень часто и отрицательно влияют на производительность, например, передвижение каретки курсора — их можно отслеживать отдельно и использовать debounce или throttle);
  • после изменения state подключается React и обновляет DOM-представление документа;
  • controlled input.

В state может храниться:

  • Контент (текст, картинки, эмбеды, разделители). Структура может быть вложенной — например, наша верстка построена во многом на использовании многоколоночных сеток любой глубины вложенности.
  • Позиция курсора. Полезно запоминать, куда ставится курсор, чтобы потом его можно было возвращать на место, сохранять, сериализовать и т.д.
  • Выделение текста. Мы поговорим об этом чуть подробнее ниже.
  • UI редактора – например, какая панель сейчас открыта, что активно, что не активно, в каком режиме вы находитесь и т.д.

Таким образом, всё это можно хранить в state, и работать с редактором как с приложением, которое этот state меняет. Например, вот редактор Draft.js от Facebook, сделанный на React:

На скриншоте видно, как они хранят state своего редактора. Текст состоит из двух строк, а справа они представлены в виде JS-объекта. У них есть атрибуты text, у каждого свой уникальный ключ key, они могут быть стилизованы или нет, и т.д.

Но дальше всех в этом вопросе пошел Google Docs со своим движком kix. У них была совсем нестандартная задача: не просто разработать редактор, но еще и реализовать одновременную многопользовательскую работу. Это означает синхронизацию изменений, множественные курсоры и все прочие сложные штуки, которые вообще лежат за пределами вопросов разработки редактора.

Для этого они отслеживают все события, которые происходят на странице, в специальном Iframe’е, который вообще находится далеко-далеко за пределами экрана. На скриншоте видно, что у этого iframe координата top равна –10000px, а высота всего 1px. Он используется только для того, чтобы перехватывать события, которые происходят на странице. Как вы можете видеть, у этого iframe даже нет содержимого, только пустой контейнер с contenteditable=«true». То есть это исключительно служебный инструмент.

Чтобы решить все поставленные задачи, разработчикам Google Docs, пришлось, по сути дела, переизобрести всю систему рендеринга текста в редактора.

На скриншоте сверху показано выделение текста, и видно, что это не стандартное выделение операционной системы, а тоже специальный div, который называется kix-selection-overlay. У него есть background-color, opacity, размеры и координаты. То есть это специальная DOM-обертка вокруг контента, которая представляет собой выделение.

Мало того, у них даже курсор – это div шириной 1-2px, высотой в строчку, к нему применены определенные CSS свойства, которые ему позволяют мигать каждые полсекунды. Таким образом, на странице может быть одновременно 5 курсоров, если ее редактируют 5 человек.


Как хранить контент?

Тут мы переходим к вопросу, в каком виде хранить состояние контента в state. Традиционно контент, который отображается на веб-страницах, хранится в виде HTML.

У этого есть свои плюсы:

  • Такой контент легко показать в браузере, потому что браузеры отлично умеют рендерить HTML. Если же вы передадите в например, JSON, то он отобразится как JSON-дерево. Вам придется предварительно превратить его в HTML и стилизовать нужным образом.
  • HTML легко изменить без редактора. Если по какой-то причине редактор не работает, вы можете всегда подправить код так, как считаете нужным,
  • Скорее всего, сейчас контент хранится в базе данных вашего сайта именно таким образом (в виде HTML).
  • Наконец, что тоже немаловажно, другой код, например, поисковые боты или сторонние плагины, приучен работать с HTML, а не с той структурой, которую вы можете придумать.

Но есть и минусы:

  • Во-первых, как мы уже обсуждали, разные браузеры выдают разный HTML из contenteditable-областей.
  • Такой код сложнее экспортировать в другие форматы типа Facebook Instant Articles или JSON. Это актуально, если вы хотите, чтобы ваш контент отображался не только на сайте, но и улетал в мобильное приложение, был доступен для скачивания в PDF и т.д. Придется каждый раз парсить HTML, вычищать лишнее и превращать его в тот формат, который требуется.
  • Такой контент тесно связан с оформлением при помощи таких HTML атрибутов, как style, class и т.д.

Свой формат

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

Декомпозиция на сущности

Во-первых, нужно декомпозировать на сущности то, с чем вы работаете в редакторе. Скорее всего, у вас будут классические элементы любого текста:

  • заголовок;
  • параграф;
  • картинка;
  • таблица;
  • список;
  • комментарий.

В редакторе кода будут свои сущности, в графическом редакторе – другие. Надо понять, с каким контентом вы работаете.

Структура данных

Далее эти сущности надо представить в виде структуры с типами и атрибутами, с которой потом можно работать. Вот абстрактный пример структуры текстового элемента:

В этом примере видно, что есть элемент Paragraph, у него есть определенный content, и первые 4 буквы у него отформатированы в полужирном формате. Такую структуру можно рендерить в какие угодно представления, например:

  • Plain text без какого-либо оформления;
  • HTML;
  • PDF для печати и сохранения;
  • JSON, XML;
  • RSS;
  • Facebook Instant Articles, Google AMP, Apple News.

Что немаловажно, такую структуру можно в редакторе отображать одним образом (например, с дополнительными элементами редактирования, кнопками и т.д.), а снаружи – совсем по-другому. Таким образом, вы снова становитесь полноценным хозяином того, что у вас с контентом происходит.

Вы можете задать ожидаемый вопрос: «Послушай, у меня контент хранится в HTML много лет, у меня своя CMS. Ты предлагаешь все забыть, придумать свой формат и потом весь код переписать, чтобы с ним работать? Очевидно, что я делать это не хочу, потому что польза с точки зрения бизнеса непонятна»

У нас была та же самая проблема, когда мы внедряли редактор на наши сайты, где была большая доля legacy-кода и тысячи сверстанных постов.

  • Хранить данные в базе данных в том виде, в котором они есть уже. Скорее всего это HTML.
  • При загрузке в редактор парсить их и работать со своим форматом. А при сохранении данных в базу сериализовать обратно в HTML и сохранять в таком виде.
  • Это удобно в тех случаях, когда нужно работать в устоявшейся экосистеме (например, CMS с плагинами вроде WordPress).

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

Как работать с пользовательским вводом?

Виды пользовательского ввода в браузере:

  • Старая добрая клавиатура. Бывает еще и виртуальной, а также позволяет использовать горячие клавиши.
  • Контекстное меню.
  • Copy&Paste.
  • Drag&drop.
  • Голосовой ввод, который становится все более популярным.
  • Рукописный ввод, который актуален в азиатских странах: вы рисуете что-то, что превращается в текстовый символ, и затем попадает в текстовое поле.
  • Автокоррекция и автодополнение.

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

Браузерные API

Браузер для этого предлагает целый «зоопарк» различных API, потому что у contenteditable-областей, к сожалению, нет единого события change, на которое можно подписаться и точно знать, когда происходят изменения. Есть несколько ключевых API, при помощи которых можно хоть как-то работать. Хотя подчеркну, практически в каждом посте про создание визуальных редакторов – и мой рассказ не исключение – подчеркивается, что ситуация с браузерными API плохая.

Selection API позволяет работать с выделением текста на странице.

Содержит 2 полезных события: selectstart и selectionchange. Selectstart срабатывает, когда мы начинаем выделять область текста на странице, а selectionchange срабатывает каждый раз, когда область выделения меняется. Причем, что полезно, оно срабатывает не только когда выделение меняется при помощи курсора, но и когда мы нажимаем Shift + стрелки или Ctrl-A для выделения всего контента на странице.

Window.getSelection() – при помощи этого метода можно получить объект с информацией о текущем выделении текста на странице. Этот объект содержит полезные свойства, в частности anchorNode и focusNode. AnchorNode – это та нода, на которой выделение началось, а focusNode – нода, на которой выделение закончилось. У каждой из этих нод может быть свой offset, т.е. кол-во выделенных символов в этой ноде.

В качестве примера рассмотрим скриншот страницы сайта FrontendConf. Я выделил текст, начиная со слова «дизайн» и заканчивая фразой «мобильные сайты», считал текущее выделение и посмотрел, что именно выделено. Можно увидеть, что anchorNode и focusNode – обе текстовые ноды, anchorOffset=11 (слово «дизайн» начинается на 11-й позиции), а focusOffset=15. Таким образом мы можем понять, какой текст на странице сейчас выделен.

Selection API поддерживается достаточно хорошо и довольно стабилен.

Следующий API — работа с буфером обмена, Clipboard API. С ним проблем гораздо больше, везде есть какие-то звездочки и комментарии.

Clipboard API предлагает несколько событий, на которые можно подписываться: копирование контента (copy), вырезание (cut), вставка (paste), а также то, что происходит прямо перед этим: beforecopy, beforecut, beforepaste.

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

Например, если пользователь сам инициировал копирование, нажал или , возникает событие копирования, и в этот момент разработчик может вмешаться и выполнить определенные действия:

  • изменить содержимое буфера обмена;
  • запретить вставку;
  • изменить алгоритм вставки;

Но при этом нельзя инициировать операцию с буфером обмена, если пользователь этого сам не хочет.

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

Поддержка Clipboard API хорошая, но есть определенные ограничения. Предположим, вы в вашем редакторе хотите реализовать копирование не просто текста, а какого-то сложного объекта. Но событие copy не возникнет, если на странице нет выделенного текста. Для этого можно использовать алгоритм компании Trello, о котором они открыто пишут на Stack Overflow. Для пользователя этого работает так: вы наводите курсор на какую-то карточку в доске, нажимаете Ctrl-C, потом перемещаете курсор в другое место, нажимаете Ctrl-V, и эта карточка вставляется в нужное место.

Реализовано это следующим образом:

  • Перехватывается нажатие клавиши Ctrl. Разработчики Trello отловили паттерн поведения: когда человек нажимает Ctrl, то есть большая вероятность того, что вслед за этим он нажмет для копирования.
  • Создается невидимая textarea с кодом того элемента, который нужно скопировать. При нажатии Ctrl за пределами экрана создается невидимая textarea, куда помещается код того элемента, который человек хочет скопировать, и туда ставится курсор и фокус.
  • Пользователь нажимает , и у него копируется код, который находится в этой textarea (потому что там стоит курсор).
  • Перехватывается событие вставки.

Когда пользователь потом перемещает курсор в другое место и нажимает «Вставить», то перехватывается событие вставки, и при помощи JS карточка вставляется в тот список, на который наведен курсор.

У себя мы копирование сложных объектов реализовали похожим образом.

Composition Events

Есть отдельный тип событий API, с которым мы не очень часто сталкиваемся, потому что они во многом связаны с диакритическими знаками и иероглифами, которые вставляются несколькими составными действиями. Также эти события связаны с альтернативными способами ввода, например, голосовым.

В двух словах о том, как они работают: если вы хотите вставить à – символ с диакритическим знаком, в macOS вы нажимаете , потом , и они склеиваются в единый символ à.

Это вызывает сразу несколько событий:

  • compositionstart – начало процесса композиции одного символа из нескольких;
  • compositionupdate – добавление каждой составной части этого символа;
  • compositionend – формирование финального символа.

Так же работает и голосовой ввод: вы наговариваете текст, браузер его декодирует, превращает в строку, происходит compositionupdate. Когда вы заканчиваете говорить, происходит compositionend, и появляется финальная строка.

Undo / Redo

Еще одна привычная функция текстовых редакторов — undo и redo, т.е. возможность отменять свои действия. Но системный механизм нам для этого уже не подойдет, потому что, напоминаю, мы храним данные в своем собственном формате в state, а системный механизм повлияет только на те изменения, которые произошли в DOM, т.е. state не откатится обратно.

Поэтому приходится перехватывать нажатие кнопок / и реализовывать свой механизм Undo/Redo, который, как правило, основан на хранении снэпшотов state. Алгоритм простой: произошло какое-то действие, мы сохранили снэпшот, и потом можем к нему вернуться. Некоторые изменения имеет смысл группировать в одну запись истории. Для работы с историей существует удобный модуль redux-undo.

Как быть с CSS?


Итак, у вас есть формат документа и вы научились его редактировать. Но помимо структуры у него есть еще и стили, и тут тоже не все не так просто:

  • Редактор — это компонент, которые сам по себе (вне приложения) малопригоден.
  • У редактора есть свои стили (UI) – панели, кнопки, размеры и т.д.
  • Редактор живет внутри приложения, например, CMS.
  • У приложения есть свои стили.
  • Внутри редактора живет сам пост, который вы редактируете.
  • У поста тоже есть свои стили (шрифты, цвета, и т.д.) Они могут быть совсем разные. Вы можете в одном и том же редакторе верстать посты с разными фирменными стилями.

Нам нужно все это друг от друга изолировать, при этом мы помним:

  • CSS-правила живут в глобальной области видимости;
  • Порядок применения правил определяется специфичностью;
  • При всем этом нам надо обеспечивать принцип WYSIWYG – то, что в редакторе, то и на сайте.

Пример WordPress CSS

На скриншоте ниже мы видим интерфейс создания поста в WordPress. Вся страница — это приложение, у него есть свои стили UI-элементов (текстовые поля, кнопки, заголовки и т.д.). Зеленая область — это плагин нашего редактора со своими UI-стилями. Внутри редактора находится пост (синий блок). Поскольку редактор находится прямо в DOM-дереве страницы, а не внутри iframe, нам нужно сделать так, чтобы стили всех этих составляющих не влияли друг на друга.

Реальный пример CSS из кода WordPress: для всех заголовков H2, которые лежат внутри блока с >

Итак, нам нужно изолировать:

  • редактор от CMS;
  • пост от редактора и CMS;
  • CMS от редактора и поста;
  • Шаблон сайта (шапка, подвал, боковая колонка, дополнительные виджеты) от стилей поста, созданного в редакторе.

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

3 основных способа изоляции CSS:

  1. CSS reset + БЭМ – все заресетить и применять определенную систему именования ваших классов. В данном случае это самый распространенный БЭМ, но можно заменить любую другую методологию.
  2. Положить все в iframe – это более «железобетонная» защита, но со своими недостатками.
  3. Все спрятать в Shadow DOM и Custom Elements, но очевидный недостаток этого способа в плохой браузерной поддержке.

CSS reset + БЭМ

Допустим, мы хотим своими стилями перебить те CSS-стили WordPress, которые рассматривали выше. Единственный способ, как это можно сделать при помощи селекторов — это задать селектор с таким же весом и переопределить правило.

WordPress CSS

CSS редактора

Либо можно встать на скользкую дорожку инлайн-стилей и !important, но тогда в дальнейшем у нас начнутся постоянные конфликты со специфичностью (как чужой, так и своей собственной).

К сожалению, всё это не дает 100% гарантии – на каждый хитрый селектор найдется еще более хитрый селектор, который его перебьет.

iframe

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

Shadow DOM + Custom Elements

Пожалуй, самый продвинутый подход, который все очень ждут, – это использование Shadow DOM и Custom Elements. Тогда можно будет превратить редактор в веб-компонент, внутри у него будет shadow-root и все содержимое будет полностью изолировано.

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

С Custom Elements та же самая история.

Адаптивная верстка

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

У себя в редакторе мы реализовали специальный режим предпросмотра (preview), в котором можно посмотреть, как пост выглядит на десктопе, а потом переключиться в режим mobile и посмотреть, как это будет смотреться на мобильных устройствах (а на широких экранах отображается оба режима одновременно). Для этого мы на лету генерируем 2 iframe с определенной шириной – один под десктоп, второй под mobile. В них подключается тот же CSS-файл, который используется потом и на сайте. Тем самым обеспечивается принцип WYSIWYG. Но из-за того, что ширина iframe ограничена, становится возможным применять мобильные правила media queries. Таким образом, можно видеть реальный результат, который потом будет на смартфоне. При каждом нажатии кнопки переключения в режим Preview мы генерируем нужный HTML и кладем его внутрь iframe, это происходит довольно быстро. У iframe отсутствует атрибут SRC, его контент программно изменяется каждый раз программно.

Как расширять функциональность?

Поздравляю, вы написали редактор, и он работает. У вас есть ядро, но этого мало: постоянно нужно доделывать новые фичи. Поэтому у редактора, как у любого расширяемого продукта, должен быть публичный API и система подключения плагинов. И, разумеется, это все должно быть снабжено документацией.

API должен уметь:

Система плагинов

Если вы построили редактор по принципу immutable state, то, по сути дела, каждый плагин, если говорить в терминологии Redux, – это набор actions и reducers. Примеры плагинов:

  • проверка орфографии;
  • автотипограф;
  • интеграция с внешними сервисами (Google Drive и т.д.).

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

  • oembed и санитайзинг HTML;
  • контекстное меню;
  • горячие клавиши;
  • режим редактирования HTML и CSS-кода;
  • мета-сущности (комментарии);
  • анимации;
  • оффлайн-режим;
  • запуск и остановка редактора при помощи API.

Будущее rich text editing

Во-первых, грядут Web Components, которые помогут решить вопросы с изоляцией компонентов и их стилей на странице, что было бы очень кстати. Если говорить про API редактирования текста, то сейчас в разработке находится спецификация W3C Input Events, которая вводит для редактируемых областей события input и beforeinput, и позволяет получить подробную информацию о том, какое действие произошло, например:

  • Insert – вставка текста;
  • insertReplacementText – замена определенного текста при помощи автокоррекции;
  • deleteByCut – удаление;
  • formatBold – форматирование.

Дополнительные свойства:

  • InputEvent.data (insert*, format*) дает понять, какое именно форматирование применяется.
  • InputEvent.dataTransfer (text/plain, text/html) позволяет получить контент, который меняется в режиме text/plain или text/html.
  • InputEvent.getTargetRanges()

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

Выводы

Как редактировать данные?

Как хранить данные?

Как быть с CSS?

Расширение функциональности

  • Модульную архитектуру.
  • API.
  • Возможность написания и подключения плагинов.

Примеры хороших современных редакторов:

  • Quill (Salesforce, Telegra.ph);
  • Draft.js (Facebook);
  • Trix (Basecamp);
  • ProseMirror, CodeMirror;
  • Google Docs;
  • iCloud Pages.

Контакты:

» E-mail: yakovishen@setka.io
» Telegram: t.me/yaplusplus
» Facebook: facebook.com/yaplusplus
» Twitter: twitter.com/yaplusplus
» Сайт Setka: https://setka.io

В вебе и фронтенде в частности, с одной стороны, все очень быстро развивается, фреймворки там, за которыми невозможно уследить. С другой – есть базовые вопросы, такие как в этой статье. И об этом, и о том мы будем говорить на майском фестивале конференций РИТ++ и приглашаем деятельных специалистов подавать заявки и выступать с докладами.


Contenteditable — редактирование контента «на лету». Урок 2

На сайте wp есть 1 конкретная страница, на которой некоторые блоки div с контентом должны быть редактируемы через contenteditable для 1 конкретного пользователя без входа в админку сайта (+для админа).

Как должно работать:
То есть пользователель логинится, если его .(это уже сделано)
Нажали на кнопку – false сменился на true и можно редактировать.
Блоки div это custom fields.
Содержание div это текст или фото.
Когда внесли изменения просто щелкаем мышкой вне активного блока и изменения сохраняются в бд.

Здесь пример решения этой задачи для общего случая (вам можно просто адаптировать под wp) через асинхронный ajax-запрос и php-обработчик: webformyself.com/contente.

Нужно объяснить мне, чтобы я сам прописал на сайте нужный код. Я с wp хорошо знаком.
Если есть идеи изменений в алгоритм или другие варианты реализации – можно обсудить.

Оплата по безопасной сделке.
Напишите ориентировочную цену и срок.

Чтобы оставить свое предложение необходимо войти в систему!

Donec lacinia venenatis metus at bibendum? In hac habitasse platea dictumst. Proin ac nibh rutrum lectus rhoncus eleifend. Sed porttitor pretium venenatis. Suspendisse potenti. Aliquam quis ligula elit. Aliquam at orci ac neque semper dictum. Sed tincidunt scelerisque ligula, et facilisis nulla hendrerit non. Suspendisse potenti. Pellentesque non accumsan orci. Praesent at lacinia dolor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Donec lacinia venenatis metus at bibendum? In hac habitasse platea dictumst. Proin ac nibh rutrum lectus rhoncus eleifend. Sed porttitor pretium venenatis. Suspendisse potenti. Aliquam quis ligula elit. Aliquam at orci ac neque semper dictum. Sed tincidunt scelerisque ligula, et facilisis nulla hendrerit non. Suspendisse potenti. Pellentesque non accumsan orci. Praesent at lacinia dolor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Замена contenteditable текста на лету

Я хочу, чтобы добавить некоторые HTML, как пользователь вводит вещи в contenteditable. Например,

Ну для одного, это не появляется, чтобы заменить что-нибудь. Во-вторых, я получаю странные проблемы, что я больше не может ввести в contenteditable дел. Я проверил событие обжигало на DIV, нет «размытости» события поднятия. Я, кажется, есть DIV подсвечивается, но я должен нажать на DIV снова ничего типа. Что я здесь отсутствует?

В первой части, проблема заключается в том , что replace() метод строки в JavaScript возвращает новую строку , и не влияет на исходную строку. Что вам нужно:

Для второго вопроса, то проблема, вероятно , тот факт , что установка innerHTML свойства элемента разрушает и воссоздает весь DOM дерево внутри элемента, и так как выбор или каретка содержится в пределах этого DOM дерева , которое больше не существует, браузер должен сделать что — то , чтобы восстановиться. Я думаю, что браузер вы тестируете в просто очищает выбор.

Борьба с подобной проблемой: мне нужно, чтобы выделить некоторые специальные символы в contenteditable. Например, выделить & NBSP; с красным фоном. Так что я делаю что-то вроде

Java скрипт для редактирования содержимого страницы на лету

Я пишу статью о редактировании страниц для того, чтобы выбрать то, что вы действительно хотите напечатать. Есть много инструментов (например, «Print What you like»), но я также нашел этот скрипт. Кто-нибудь знает об этом? Я не нашел никаких документов или ссылок.

3 ответов

свойство contentEditable-это то, что вы хотите-оно поддерживается IE, Safari (и chrome в качестве побочного продукта), и I думаю firefox 3 (увы, не FFX2). И Эй, это также часть HTML5: D

Firefox 2 поддерживает designMode, но это ограничено отдельными кадрами, в то время как свойство contentEditable применяется к отдельным элементам, поэтому вы можете более хорошо воспроизводить редактируемый контент на своей странице 😀

[Edit (olliej): удалено пример как атрибут contentEditable не проходит мимо выходных фильтров SO (несмотря на работу в предварительном просмотре): (]

[Edit (olliej): я ударил очень простой демо чтобы проиллюстрировать, как он себя ведет]

[Edit (olliej): так что да, атрибут contentEditable в связанной демонстрации отлично работает в IE, Firefox и Safari. Увы, изменение размера-это функция css3, которую поддерживает только webkit, и IE делает все возможное, чтобы бороться почти со всеми CSS. вздох]

документ.designMode поддерживается в IE 4+ (который, по-видимому, запустил его) и FireFox 1.3+. Вы включаете его, и вы можете редактировать контент прямо в браузере, это довольно Триппи. Я никогда не использовал его раньше, но похоже, что он будет довольно идеальным для ручного выбора печатной информации.

отредактировано, чтобы сказать: он также работает в Google Chrome. Я тестировал его только в Chrome и Firefox, так как это браузеры, в которых у меня есть консоль javascript, поэтому я не могу гарантируйте, что он работает в Internet Explorer, поскольку я никогда лично не использовал его. Я понимаю, что это было свойство IE-only, которое другие браузеры подобрали и в настоящее время не соответствует никаким стандартам, поэтому я был бы удивлен, если Firefox и Chrome поддерживают его, но IE остановился.

Он включает встроенные функции редактирования браузера, где это возможно. Как упоминалось выше, designMode-это Gecko, а contentEditable-все остальные (и добавлен в Gecko 1.9). Эти функции используются в качестве основы (почти?) каждый редактор WYSIWYG, построенный с помощью HTML / Javascript. Если вы просто вводите / удаляете, ничего больше не должно быть необходимо, чем предоставленный вами скрипт. (Однако все, начиная с «пустоты», излишне.)

для документации о том, как эти функции могут быть использованы в приложении, лучшая ссылка Mozilla в спецификация Мидас (MSDN может быть также полезно. ).

Редактирование контента на лету. Часть 1

Уроки по созданию сайта тут:
webformyself.com/hivideo/
От автора: в этом и следующем уроках мы познакомимся с одним из новых атрибутов в HTML5 под названием contenteditable. Из самого названия понятно, что данный атрибут как-то связан с редактированием контента. И действительно, он позволяет редактировать содержимое элементов прямо на странице.

YORUMLAR

Понимаю что прошло два года, но как испрвить «mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in» ?

Андрей, когда уже вторая часть урока и продолжение каталога?)

@Андрей Кудлай Шикарно!) Спасибо, очень жду!

@Владислав Старковски в этом уроке вряд ли, поскольку для урока уже подготовлен список вопросов, некоторые из которых довольно объемны. Но в одном из ближайших, наверное, покажу.

@Андрей Кудлай больше жду каталог!) Пожалуйста, ты не мог бы ответить на вопрос в следующем уроке по каталогу: как сделать вывод похожих записей? ну то есть непосредственно показать/ Спасибо заранее/

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

Андрей, привет. А стоит ли использовать этот атрибут? Я к тому, что если пользователь сидит на XP и у него там древний IE установлен, будет ли работать? Вообще работает ли на всех браузерах? Как, стоит ли ее использовать?

@Владислав Старковски Пожалуйста)

@Андрей Кудлай ага, тоесть еще 7 версия поддерживает? значит смело можно использовать!) спасибо!

Если исходить из того, что нужно подстраиваться под древний IE, тогда нужно забыть как минимум об использовании HTML5 и CSS3. А так, в IE7 под XP этот атрибут работает. Ну а стоит ли использовать? Это возможность. использовать или нет эту возможность — каждый решает для себя сам. Например, можно использовать тени, переходы и многие другие современные возможности HTML5/CSS3. а можно, оглядываясь на древние версии браузеров, по старинке делать их с помощью картинок и JS. тут уже каждый решает для себя. я давно для себя все решил и смело использую новые возможности. собственно, сам Microsoft уже давно отказался от поддержки старых версий IE и даже от XP.

Добрый день Андрей. Если вам не сложно, могли бы вы показать реализацию поиска на сайте? и желательно 2 варианта, через GET и без GET(тоесть в url ничего не добавляется и после обновления страницы все пропадает). Заранее благодарю.

Редактирование контента на лету. Часть 1

Ойнатқышты басқару элементтерін көрсету

Автоматты түрде ойнату

  • Жарияланды 2014 ж. 5 Мау.
  • Уроки по созданию сайта тут:
    webformyself.com/hivideo/
    От автора: в этом и следующем уроках мы познакомимся с одним из новых атрибутов в HTML5 под названием contenteditable. Из самого названия понятно, что данный атрибут как-то связан с редактированием контента. И действительно, он позволяет редактировать содержимое элементов прямо на странице.

Пікірлер • 18

Понимаю что прошло два года, но как испрвить «mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in» ?

Андрей, когда уже вторая часть урока и продолжение каталога?)

@Андрей Кудлай Шикарно!) Спасибо, очень жду!

@Владислав Старковски в этом уроке вряд ли, поскольку для урока уже подготовлен список вопросов, некоторые из которых довольно объемны. Но в одном из ближайших, наверное, покажу.

@Андрей Кудлай больше жду каталог!) Пожалуйста, ты не мог бы ответить на вопрос в следующем уроке по каталогу: как сделать вывод похожих записей? ну то есть непосредственно показать/ Спасибо заранее/

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

Андрей, привет. А стоит ли использовать этот атрибут? Я к тому, что если пользователь сидит на XP и у него там древний IE установлен, будет ли работать? Вообще работает ли на всех браузерах? Как, стоит ли ее использовать?

@Андрей Кудлай ага, тоесть еще 7 версия поддерживает? значит смело можно использовать!) спасибо!

Если исходить из того, что нужно подстраиваться под древний IE, тогда нужно забыть как минимум об использовании HTML5 и CSS3. А так, в IE7 под XP этот атрибут работает. Ну а стоит ли использовать? Это возможность. использовать или нет эту возможность — каждый решает для себя сам. Например, можно использовать тени, переходы и многие другие современные возможности HTML5/CSS3. а можно, оглядываясь на древние версии браузеров, по старинке делать их с помощью картинок и JS. тут уже каждый решает для себя. я давно для себя все решил и смело использую новые возможности. собственно, сам Microsoft уже давно отказался от поддержки старых версий IE и даже от XP.

Добрый день Андрей. Если вам не сложно, могли бы вы показать реализацию поиска на сайте? и желательно 2 варианта, через GET и без GET(тоесть в url ничего не добавляется и после обновления страницы все пропадает). Заранее благодарю.

Топ-пост этого месяца:  Администратор MySQL – герой не только в анекдоте, но и в жизни
Добавить комментарий