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


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

wysiwyg contenteditable editor — как установить максимальную длину для редактора расширенного текста — jquery

Я использую wysiwyg contenteditable editor — я хочу установить максимальную длину текстового редактора как 200, если я дам maxlength = «200» в текстовом поле, не работает, поскольку он сгенерирован как html-формат div с классом = «wysiwyg -editor «, так как я могу исправить maxlength для этого компонента?

    3 1
  • 30 июл 2020 2020-07-30 05:39:40
  • Krish

1 ответ

Я ранее опубликовал аналогичный вопрос. Ответ заключается в том, что вы действительно не должны ограничивать длину текстовых редакторов. HTML генерируется на лету текстовым редактором, поэтому вы не можете ограничить ввод данных. Вы можете с технической точки зрения ограничить длину выходного HTML, но это может привести к неправильному HTML, который не будет корректно запускаться/отображаться. Хотя это может показаться не ответом, вам лучше не ограничивать ввод, а вместо этого убедиться, что вы сможете справиться с ним на задней панели, если вы сохраняете базу данных и т.д.

OtherMedia

Информация должна принадлежать людям

Разработка Rich Text 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 появится новый

А в 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 и все содержимое будет полностью изолировано.

Топ-пост этого месяца:  Интеграция Электронной коммерции Яндекс.Метрика в Woocommerce

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

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

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

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

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

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

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

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

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

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

Если вы построили редактор по принципу 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, который позволит делать более совершенные веб-редакторы. Более того, в комментариях к этой спецификации написано, что это все равно еще не идеальное решение, и разработчики приглашаются поучаствовать в процессе написания и утверждения документа.

Выводы

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

  • Используйте contenteditable для отслеживания событий. Сейчас это наилучший инструмент для создания редакторов: отслеживайте пользовательские события, меняйте state и обновляйте ваш редактор.
  • Храните состояние редактора и контента в state.
  • Не храните состояние в DOM. Это касается, наверное, любого приложения, не только редактора.

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

  • Определите сущности, с которыми вы работаете.
  • Продумайте структуру state.
  • Напишите код, который будет переводить эту структуру в те форматы, которые вам нужны.

Как быть с CSS?

  • Редактор будет жить во внешней среде, которую вы не контролируете.
  • Заранее подумайте об изоляции CSS.
  • Кладите редактор в iframe или очищайте все, что можно.

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

  • Модульную архитектуру.
  • 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

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

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

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

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

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

2 ответа

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

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

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

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

Сохранить изменения в contenteditable с отметкой времени

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

Теперь возникает вопрос: Как лучше всего сохранить информацию (какая часть изменилась, когда)?

Я рассмотрел следующие варианты, которые кажутся невероятными:

  1. Каждый раз, когда пользователь посещает сайт в конце документа, я вставляю флаг (например, диапазон emtpy с классом и атрибутом данных, в котором хранится начало редактирования). Этот флаг затем сохраняется в базе данных при вызове скрипта сохранения. Эта опция позволила бы очень легко показывать дату сбоку — я просто поместил бы их на той же высоте, что и пустой интервал, и интервал сообщает мне дату. Недостатки: пользователь может случайно удалить диапазон отметки времени, и если пользователь не закрывает окно в течение длительного времени, новые промежутки времени не вставляются (этого можно избежать, вставляя новые отрезки отметки времени каждые X минут, поэтому удаляемая часть более актуально)
  2. Попытка выполнить сравнение различий строк каждый раз, когда данные передаются в сценарий сохранения, и сохранять различие только с отметкой времени. Затем, когда страница загружена, соберите все части в правильном порядке и в Javascript поместите заметки с датами в нужное место. Для меня это звучит как чрезмерная нагрузка, хотя + при замене старых деталей две части могут стать одной и т. Д. В целом эти параметры звучат очень сложно.

Любой вклад /идеи /предложения высоко ценятся!

3 ответа

То, что вы пытаетесь реализовать, — это функция, называемая «аннотировать» или «обвинять» в мире контроля исходного кода (хотя вам просто нужна дата обновления, а не дата + автор или просто автор).

Чтобы сделать это правильно, вам нужен способ сделать diff ( php-diff может помочь задание) и получить варианты текста. Есть несколько стратегий:

хранит последнюю версию и сохраняет только дельты (такие как унифицированные различия, мои предпочтения)

сохраняйте все версии и вычисляйте дельты на лету

Если у вас есть текущая версия и список дельт (вы можете определенно сократить список, если скажете несколько десятков дельт, и позволить пользователю спросить больше, если это действительно важно). Вы составляете дельты вместе, здесь происходит фаза аннотации, так как вы можете сделать эту часть, помня, из какой версии идет каждая строка. На самом деле составление довольно простое (начните с самого последнего, все строки, добавленные в патч, ведущие к нему, относятся к последнему, остальные нужно объяснить, поэтому начните снова со следующего патча, пока не дойдете до самого древнего патча, который вы хотите обработать остальные строки взяты из этой версии или самой ранней, поэтому можно использовать флаг с надписью «на или перед»).

У Google есть библиотека diff для Javascript , поэтому можно сделать все тяжелая работа на машине пользователя. У них есть часть патча в этой библиотеке. Я не нашел библиотеку аннотаций /обвинений.

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

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

В бэкэнде вы создаете две таблицы. В одной таблице, назовем ее «currentdocs», вы всегда храните самую последнюю версию данных. Когда пользователь загружает документ, вся информация поступает из этой таблицы «currentdocs». В другой таблице, давайте назовем это «docsintime», вы сохраняете каждое новое сохранение. Он имеет внешний ключ к таблице «currentdocs», и вы можете найти последнюю строку в этой таблице «docsintime», выбрав максимальный идентификатор с этим внешним ключом. Оператор выбора может быть что-то вроде:

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

При сохранении нового документа эта последняя сохраненная версия отображается в таблице ‘docsintime’. Вы сравниваете все соответствующие части с данными из этой записи. Если он не отличается, вы копируете отметку времени соответствующей части в новой записи, которая будет сохранена. Если это действительно отличается, тогда вы создаете новую метку времени для этой соответствующей части. После сравнения сохраните новую запись в обеих таблицах: «currentdocs» и «docsintime». Вы обновляете таблицу «currentdocs» и вставляете новую запись в таблицу «docsintime». Только с новым документом вы сделаете вставку в таблицу «currentdocs». При следующем запросе этого документа вам нужно будет только собрать информацию из таблицы «currentdocs». И процесс начинается заново.

Я сошел с ума? (Как) должен ли я создать редактор контента jQuery?

хорошо, поэтому я создал CMS, ориентированную в основном на начальные школы. Он становится довольно популярным в Новой Зеландии, но одна вещь, которую я ненавижу со страстью, — это в основном плохое качество в редакторах браузера WYSIWYG. Я использую KTML (сделанный InterAKT, который был приобретен Adobe несколько лет назад). На мой взгляд, этот редактор делает много замечательных вещей (редактирование/управление изображениями, миниатюры и довольно хорошее редактирование контента). К сожалению, time имеет свой неприятный путь с этим продуктом и новыми браузерами начинают ломать функции и вообще снижать производительность этого инструмента. Это также довольно страшно, основывая свои средства к существованию на несуществующем продукте!

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

правильно, поэтому традиционной моделью для редактирования, скажем, страницы в CMS, является вход в «задний конец» и нажмите «Редактировать» на странице. Затем он загрузит другой экран с редактором и, возможно, несколько других полей. Более продвинутые CMS, возможно, будут иметь несколько полей редактирования, которые предназначены для разных частей страницы. Во всяком случае, большая проблема с этим способом заключается в том, что пользователь редактирует документ за пределами окончательный контекст он появится. Проще говоря, это означает шаблон страницы. Многие вещи могут быть неправильными, например, область редактирования может отличаться от ширины фактической области шаблона. Высота почти всегда фиксирована, потому что существующие редакторы всегда используют IFRAMES для обратной совместимости. И есть много других рифов, о которых, я уверен, вы знаете, если вы находитесь в этой области развития.

вот мой редактор утопия:

нажать кнопку «Изменить страницу»: отображается фактическая страница (с ее фактическим шаблоном). Части страницы были помечены как редактируемые с помощью имени класса. Вы нажимаете на одну из этих областей (в моем случае это просто большая область «тела» в середине шаблона), и панель редактирования падает сверху экрана со всеми стандартными элементами управления (полужирный, курсив, вставка изображения и т. д. ). Iframes никогда не используются, вместо этого мы полагаемся на установку contentEditable в true на рассматриваемом DIV. Firefox 2 и IE6 могут уйти, давайте двигаться дальше. Вы можете редактировать страницу, точно зная, как она будет выглядеть при ее сохранении. Потому что все стили для этого шаблона загружены, ваши заголовки будут выглядеть правильно, все будет просто денди. Это такая радикальная концепция? Почему мы все еще довольствуемся TinyMCE и другим редактором, который слишком неудобно использовать, потому что это звучит как ругательство!?

давайте посмотрим фактам в лицо:

Я новичок в JavaScript. Я однажды играл в этой области, используя JavaScript антология из SitePoint в качестве руководства. Это был довольно классный опыт обучения, но они, конечно, использовали IFRAME, чтобы облегчить свою жизнь. Я попытался пойти другим путем и просто использовать contentEditable и даже попытался обойти собственные процедуры редактирования контента (execCommand) и вместо этого написал свой собственный. Они вроде как работали, но всегда были проблемы.

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

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

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

Топ-пост этого месяца:  Как воспользоваться тэгами HTML DL, DT и DD для создания списка данных (альтернатива табличных

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

обновление

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

обновление 2

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

обновление 3

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

обновление 4

хорошо,я достаточно далеко. Самые большие проблемы (как все всегда знают) — это как сохранить код, генерируемый в разумном положение дел. WYSIHAT, похоже, взял на борт всю не-IFRAME вещь, поэтому я держусь, чтобы посмотреть, как далеко это зайдет. Они используют подход просто очистки кода в конце цикла редактирования. Я думаю, что он должен быть очищен на лету, иначе вы можете отредактировать себя в трясину (я делал это несколько раз). Когда у меня будет время, я исследую какой-то двигатель гомогенизации, который можно подключить, чтобы процесс редактирования вел себя как можно более одинаково во всех современных броузеры.

7 ответов

Я полностью согласен с вашим предложением редактора разметки и iframes так 2001 🙂 мир заголовок семантики, поэтому нам нужны современные инструменты для редактирования контента. (смотрите мои слайды http://www.slideshare.net/draftkraft/aloha-editor-contenteditable-useable) я запустил редактор Aloha (http://aloha-editor.org) более или менее с той же интенсивностью, что и ваша выше позади. Утопия: -) в нашем случае стала более или менее реальностью, и у нас уже есть некоторое программное обеспечение, использующее это:

эти, как известно, используют Алоха редактор, как главный редактор

в TYPO3 (в следующей основной версии V5 http://latest.phoenix.demo.typo3.org/. Классные ребята, огромная открытым исходным кодом CMS в ЕС. Около 500.000 пользователей)

Содержание Gentics.Узел V5 (сначала узнайте большую производственную систему с помощью редактора Aloha. Клиент с 16.000 пользователей. http://gentics.com/Portal.Node/blog-detail/gentics/postings/company/Telekom-Austria-Group—communication-with-16-000-em.en.html)

эти системы, как известно, есть плагины

некоторые другие проекты, которые я слышал, но я не знаю

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

ОК, вау! Эти ребята делают именно то, о чем я думал:

Мне не нравится их панель инструментов, но они действительно отлично выглядят! Я буду следить за их прогрессом:)

У Джо Армстронга была почти такая же идея, как и у вас некоторое время назад, и он провел неделю или около того, играя с ContentEditable в паре с CouchDB для упорства. Он не закончил с полированным редактором, но это хорошая отправная точка для сворачивания вашего собственного (если это то, что вы хотите сделать). Кажется, было бы довольно просто взять то, что есть, и поместить его в солидный контекстный редактор.

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

прежде чем выйти и сделать редактор, хотя, это может заплатить, чтобы проверить, что ваши пользователи на самом деле делают. В корпоративном IT девять раз из десяти вы увидите, как люди объединяют свои страницы в Word или somesuch, а затем вставляют результаты в какой бы» редактор » у вас ни был. Я не думаю, что это будет работать слишком хорошо с ContentEditable методом. Кстати, именно поэтому мы все еще используем TinyMCE; у него есть половина приличной кнопки «вставить из слова». Вы нацеливаете инструмент на начальные школы, а не на корпоративную среду, поэтому там все может быть по-другому.

ты пробовал uEditor? Это твердое и простое решение Jquery, которое превращает textarea в Редакторы WYSIWYG

очевидно, что затем вы добавите параметры и обработчики событий в uEditor.

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

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

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

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

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

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

Сохранить изменения в contenteditable с отметкой времени

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

Теперь возникает вопрос: Как лучше всего сохранить информацию (какая часть изменилась, когда)?

Я рассмотрел следующие варианты, которые кажутся невероятными:

  1. Каждый раз, когда пользователь посещает сайт в конце документа, я вставляю флаг (например, диапазон emtpy с классом и атрибутом данных, в котором хранится начало редактирования). Этот флаг затем сохраняется в базе данных при вызове скрипта сохранения. Эта опция позволила бы очень легко показывать дату сбоку — я просто поместил бы их на той же высоте, что и пустой интервал, и интервал сообщает мне дату. Недостатки: пользователь может случайно удалить диапазон отметки времени, и если пользователь не закрывает окно в течение длительного времени, новые промежутки времени не вставляются (этого можно избежать, вставляя новые отрезки отметки времени каждые X минут, поэтому удаляемая часть более актуально)
  2. Попытка выполнить сравнение различий строк каждый раз, когда данные передаются в сценарий сохранения, и сохранять различие только с отметкой времени. Затем, когда страница загружена, соберите все части в правильном порядке и в Javascript поместите заметки с датами в нужное место. Для меня это звучит как чрезмерная нагрузка, хотя + при замене старых деталей две части могут стать одной и т. Д. В целом эти параметры звучат очень сложно.

Любой вклад /идеи /предложения высоко ценятся!

3 ответа

То, что вы пытаетесь реализовать, — это функция, называемая «аннотировать» или «обвинять» в мире контроля исходного кода (хотя вам просто нужна дата обновления, а не дата + автор или просто автор).

Чтобы сделать это правильно, вам нужен способ сделать diff ( php-diff может помочь задание) и получить варианты текста. Есть несколько стратегий:

хранит последнюю версию и сохраняет только дельты (такие как унифицированные различия, мои предпочтения)

сохраняйте все версии и вычисляйте дельты на лету

Если у вас есть текущая версия и список дельт (вы можете определенно сократить список, если скажете несколько десятков дельт, и позволить пользователю спросить больше, если это действительно важно). Вы составляете дельты вместе, здесь происходит фаза аннотации, так как вы можете сделать эту часть, помня, из какой версии идет каждая строка. На самом деле составление довольно простое (начните с самого последнего, все строки, добавленные в патч, ведущие к нему, относятся к последнему, остальные нужно объяснить, поэтому начните снова со следующего патча, пока не дойдете до самого древнего патча, который вы хотите обработать остальные строки взяты из этой версии или самой ранней, поэтому можно использовать флаг с надписью «на или перед»).

У Google есть библиотека diff для Javascript , поэтому можно сделать все тяжелая работа на машине пользователя. У них есть часть патча в этой библиотеке. Я не нашел библиотеку аннотаций /обвинений.

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

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

В бэкэнде вы создаете две таблицы. В одной таблице, назовем ее «currentdocs», вы всегда храните самую последнюю версию данных. Когда пользователь загружает документ, вся информация поступает из этой таблицы «currentdocs». В другой таблице, давайте назовем это «docsintime», вы сохраняете каждое новое сохранение. Он имеет внешний ключ к таблице «currentdocs», и вы можете найти последнюю строку в этой таблице «docsintime», выбрав максимальный идентификатор с этим внешним ключом. Оператор выбора может быть что-то вроде:

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

При сохранении нового документа эта последняя сохраненная версия отображается в таблице ‘docsintime’. Вы сравниваете все соответствующие части с данными из этой записи. Если он не отличается, вы копируете отметку времени соответствующей части в новой записи, которая будет сохранена. Если это действительно отличается, тогда вы создаете новую метку времени для этой соответствующей части. После сравнения сохраните новую запись в обеих таблицах: «currentdocs» и «docsintime». Вы обновляете таблицу «currentdocs» и вставляете новую запись в таблицу «docsintime». Только с новым документом вы сделаете вставку в таблицу «currentdocs». При следующем запросе этого документа вам нужно будет только собрать информацию из таблицы «currentdocs». И процесс начинается заново.

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

#1 Просто заработать хочу

  • Пользователи
  • 55 472 сообщений
  • 0 спасибо
  • Редактирование контента на лету. Урок 3

    Как создать сайт. Основы Самостоятельного Сайтостроения

    Опубликовано: 2 мая 2015 г.

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

    От автора: В этом уроке мы вернемся к урокам по работе с атрибутом HTML5 contenteditable. Ранее мы с вами реализовали задачу сохранения значения редактируемого поля. Однако, в примере мы с вами работали только с одним полем таблицы. В комментариях на сайте и форуме вы спрашивали, как можно работать с несколькими полями таблицы. В этом уроке вы найдете ответ на данный вопрос.

    ContentEditable div заменяет innerHTML на лету

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

    2 Solutions collect form web for “ContentEditable div заменяет innerHTML на лету”

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

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

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

    Редактирование контента на лету. Часть 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 ничего не добавляется и после обновления страницы все пропадает). Заранее благодарю.

    Добавить комментарий