Подтвердить что ты не робот

Предотвратите обход содержимого Chrome из присоединенного <p>с помощью <span>

Я наблюдал нежелательное поведение в Chrome, которое происходит, когда один соединяет два <p>, удаляя разделение между ними. Несмотря на то, что теги <p> соединены должным образом, Chrome обрезает содержимое тега <p> с правом наименьшего значения <span>.

Изменить: это происходит для всех элементов блока, а не только тегов p.

Пример:

Например, когда разделительный </p><p> удаляется из следующего блока:

<div contenteditable="true"><p>p one.</p><p>p two.</p></div>

Это будет:

<div contenteditable="true"><p>p one.<span style="font-size: 16px; line-height: 1.44;">p two.</span></p>

Пример в скрипте: Содержимое обертки Chrome, объединенное в <p> с <span>.

Вопрос

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

4b9b3361

Ответ 1

Есть способ, но вам нужно активно устанавливать несколько стилей. Идея состоит в том, чтобы сообщить Chrome, что стили уже позаботились, поэтому нет необходимости добавлять SPAN для удовлетворения требований стилей. в основном, вам нужно добавить хром добавленные стили в класс span под вашим contenteditable div (см. пример ниже).

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

Для примера:

  • Я добавил класс "edit" в контентный DIV
  • Я добавил класс .edit p, span в стиле

Это будет:

.edit {
  border: 1px solid gray;
  padding: 10px;
}
.edit p, span {
  line-height: 1.44; font-size: 16px;
}

И DIV:

<div contenteditable="true" class="edit">...</div>

Обратите внимание, что вам обычно не нужен font-size: 16px;. Мне нужно было добавить это, потому что скрипта определяет некоторый размер шрифта в contenteditable. На отдельной странице мне это не нужно.

Вам нужно применить этот "патч" Chrome к любым элементам, где это происходит (так что если вам нужно UL, OL... а затем добавить то, что необходимо после моей логики выше)

Ответ 2

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

в общем, вы могли бы проверить, когда такие ошибки могут произойти. для случая создания span вы должны прослушивать все события keydown и keypress и проверять, является ли ключ ключом backspace/delete или для каждого ключа, который вставляет символы, если это реальный выбор.

если это так, тогда вам нужно проверить текущий выбор (либо позицию метки вставки, либо реальный выбор), тогда вы знаете, что следующий следующий текстовый элемент или node. то вам нужно проверить следующее в следующих keypress и keyup, если есть span, созданный непосредственно после метки вставки. в зависимости от ошибки браузера вам потребуется дополнительная проверка. если есть один, снова разворачивайте его содержимое. addale Mutation могут использоваться события и вспомогательные атрибуты.

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

ИЗМЕНИТЬ Здесь обновляется скрипт js, который показывает идею с событием Mutable: http://jsfiddle.net/THPmr/6/

Но это не пуленепробино, это просто показать, как это можно было бы достичь (проверено только в chrome 27.0.1422.0 и, вероятно, не будет работать, если более чем один текстовый элемент содержится во втором p)

Ответ 3

CSS влияет на то, как разметка создается внутри contenteditable:

div, pre {   граница: 1px сплошной серый;   padding: 10px;   высота линии: 1,44; }

Удалите строку линии линии, и проблема больше не возникает.

В целом существует несколько ошибок с contenteditable, связанных с стилем по умолчанию: Как избежать WebKit contentEditable copy-paste, приводящий к нежелательному CSS?

EDIT JsFiddle косвенно влияет на это (tinkerbin ведет себя по-разному) из-за своего CSS (normalize.css). Попробуйте следующее:

  • Запустите скрипт
  • Осмотреть <p>
  • Отключить все объявления font-size в стеке CSS - включая высоту строки
  • выполнить обратное пространство
  • нет встроенного диапазона

Решение 1. Используйте классы и идентификаторы.

Не объявляйте размер шрифта для p или div, но для p.main-content или, проще говоря, .main-content. Если размер шрифта ваших элементов внутри contenteditable поступает из внутреннего CSS-браузера браузера, то Chrome не добавит дополнительный стиль разметки/вставки.

Решение 2: используйте санирующий аппарат.

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

Ответ 4

Лучшим способом, который я нашел до сих пор, является прослушивание DOMNodeInserted и проверка имени tagName. Если это диапазон, вы можете удалить тег и оставить содержимое. Это также держит курсор в нужном месте.

function unwrap(el, target) {
    if ( !target ) {
        target = el.parentNode;
    }
    while (el.firstChild) {
        target.appendChild(el.firstChild);
    }
    el.parentNode.removeChild(el);
}

var AutoFix = true;

document.getElementById('editable')
.addEventListener('DOMNodeInserted', function(ev) {
    if ( !AutoFix ) {
        return;
    }
    if ( ev.target.tagName=='SPAN' ) {
        unwrap(ev.target);
    }
});

Я добавил логический "AutoFix", чтобы вы могли отключить автоматические изменения dom, когда вам нужно вставить span, так как это событие срабатывает при любом изменении dom. Например. если у вас есть панель инструментов, которая позволяет пользователю вставлять что-то вроде < span class= "highlight" > ... </span> .

Код не имеет побочных эффектов в IE или FireFox, насколько я могу видеть.

Ответ 5

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

document.querySelector('[contenteditable=true]')
  .addEventListener('DOMNodeInserted', function(event) {
    if (event.target.tagName == 'SPAN') {
      event.target.outerHTML = event.target.innerHTML;
    }
  });

Ответ 6

Это тоже меня раздражало, но я нашел решение, которое сейчас достаточно хорошо работает.

$('#container span').filter(function() {
    $(this).removeAttr("style");
    return $(this).html().trim().length == 0;
}).remove();

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

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

Это не идеальный, но быстрый и лаконичный.