Как следует обрабатывать символы новой строки в bbcode?

Я использую расширение bbcode PECL для определения набора тегов, которые я разрешаю для форума. Я реализовал почти все теги, описанные на http://www.bbcode.org.

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

Путь nl2br()

nl2br() отлично подходит для того, чтобы заставить браузер принимать новые строки, когда пользователь их вводит, поскольку он находит новые строки и вставляет там теги <br />, чтобы браузер также принимал новую строку. Но это бросает вызов некоторым более сложным разметкам.

Например:

[ul]
[li]list item 1[/li]
[li]list item 2[/li]
[/ul]

приводит к

<ul><br />
<li>list item 1</li><br />
<li>list item 2</li><br />
<ul>

который разбрасывает пробелы повсюду. Таблицы имеют похожие проблемы по той же причине. Кроме того, любой тег, который фактически отображает пробелы (например, <pre><code>code goes here</code></pre>), получает двойной интервал. Ики.

Метод CSS

В CSS есть white-space правил, которые могут пригодиться в таких ситуациях. Если мы поместим все сообщения форума в элемент .bbcode, а затем просто включим правило таблицы стилей

.bbcode {
    white-space: pre-line;
}

тогда браузер сохранит символы новой строки, свернет другие пробелы и перенесет слова. Звучит довольно идеально. Однако элементы списка и т. Д. По-прежнему сталкиваются с этой проблемой двойного интервала, потому что браузер отображает новую строку после каждого </li>.

Мы можем обойти некоторые из этого, определив:

.bbcode {
    white-space: pre-line;
}
.bbcode * {
    white-space: normal;
}

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

Как-мне-сделать-это? способ

На самом деле я бы хотел, чтобы комбинация двух эффектов:

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

В идеале, я думаю, что [li]some\ntext[/li] должно давать две строки, [li]sometext[/li]\n должно давать только одну строку, а [i]sometext[/i]\n должно давать две строки.

Как это делается? Или, скорее, что люди обычно делают на форумах, использующих bbcode? Я, вероятно, мог бы написать функцию, в которой я определил бы все случаи, в которых должен быть вставлен <br />, это сильно пахнет изобретением множества колес.


person Mala    schedule 28.02.2015    source источник


Ответы (2)


Сейчас я остановился на

Путь nl2br-str_replace

$html = nl2br(bbcode_parse($handler, htmlentities($bbcode_string)));
$html = str_replace(
    array('</div><br />', '<tr><br />', '</tr><br />', '<th><br />', '</th><br />', '<td><br />', '</td><br />', '<ul><br />', '</ul><br />', '<ol><br />', '</ol><br />', '<li><br />', '</li><br />', '</pre><br />'),
    array('</div>', '<tr>', '</tr>', '<th>', '</th>', '<td>', '</td>', '<ul>', '</ul>', '<ol>', '</ol>', '<li>', '</li>', '</pre>'), $html);
return $html;

И CSS:

.bbcode pre br {
    display: none;
}

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

CSS предотвращает двойной интервал в pre элементах (и вам нужно будет добавить любые другие элементы, которые берут новые строки из пробелов). PHP избавляется от символов новой строки, вызванных тем, что пользователь помещает символы новой строки между ними, например. [li]stuff[/li] элементов.

Это непросто: если пользователь вводит пробел после [/ li] и перед новой строкой, <br /> не удаляется. Возможно, я мог бы использовать регулярные выражения для поиска [tag][whitespace]<br />, но я не вижу в этом большой проблемы.


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

person Mala    schedule 01.03.2015

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

Подлый (но недействительный HTML) способ CSS

Просто используйте функцию PHP nl2br(), оставьте white-space: normal, но добавьте следующие правила CSS:

.bbcode ul > br,
.bbcode ol > br,
.bbcode table > br,
.bbcode tr > br,
.bbcode pre br {
    display: none;
}

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

Затем нам нужно скрыть конечные разрывы строк из элементов уровня блока:

.bbcode table + br,
.bbcode ul + br,
.bbcode ol + br,
.bbcode div + br,
.bbcode iframe + br,
.bbcode pre + br,
.bbcode blockquote + br {
    display: none;
}

Вот и все! Мы могли бы обойтись одним правилом с множеством elem + br правил, но, поскольку я никогда не слышал о таком селекторе, прежде чем я перестраховался, где могу, используя нотацию селектора, которая, как я знаю, является (довольно) перекрестной. совместим с браузером, где я могу.

Я надеюсь, что это помогает кому-то!

person Mala    schedule 28.02.2015
comment
Если br просто не отображается, это еще не улучшает недопустимую разметку, которую они создают внутри списка или таблицы. Это не «хитрость», это просто борьба с симптомами, а не с тем, что на самом деле неправильно. - person CBroe; 28.02.2015
comment
Хорошая мысль, я изменил название. Я все еще надеюсь услышать о лучшем способе, но до тех пор я буду работать с ним. - person Mala; 28.02.2015
comment
Еще одно замечание: это не чисто удаляет разрывы строк между элементами таблицы, поскольку браузеры (ну, по крайней мере, хром) исправят плохую разметку, переместив теги <br> перед таблицей, прежде чем таблица стилей получит шанс чтобы скрыть их. - person Mala; 28.02.2015