Замечания и предложения по нему, а также их обсуждение. Предыдущий тред >>1000000.
>>/b/1003098 Раньше не было возможности escape-ить символы разметки, теперь есть. Раньше на ***%%You are a buggy fork!%%*** Кусаба выводила ломаный HTML, <b><i><spoiler></spoiler></b></i>, ибо ** имеет приоритет над *, и возник вопрос, что делать в ситуации, когда встречаем тэг, закрывающий блок верхнего уровня, а внутренние блоки ещё не закрыты. A. Закрывать все внутренние блоки по тэгу закрытия блока верхнего уровня. ***%%*** => <b><i><spoiler></spoiler></i></b><i>; A++. По закрытию, восстанавливать незакрытый внутри закрываемого блока контекст. ***%%*** => <b><i><spoiler></spoiler></b><i></i>; B. Сделать приоритет тэгов разметки контекстно-зависимым, чтобы ***%%You are a buggy fork!%%*** интерпретировалось как [b][i]%%You are a buggy fork!%%[/i][/b]. Или ***%%*** => <b><i><spoiler></spoiler></i></b> Вариант A позволяет написать You are a buggy fork! как ***%%You are a buggy fork!**, что короче и потенциально удобнее. Варианты A++ и B имитируют, как было раньше. Вариант A было меньше кодить, потому и был реализован. Но, если нужно, могу к началу января взяться сделать совместимость. Который из вариантов больше по душе?
***%%You are a buggy fork!%%***
<b><i><spoiler></spoiler></b></i>
**
*
A.
***%%*** => <b><i><spoiler></spoiler></i></b><i>
A++.
***%%*** => <b><i><spoiler></spoiler></b><i></i>
B.
[b][i]%%You are a buggy fork!%%[/i][/b]
***%%*** => <b><i><spoiler></spoiler></i></b>
***%%You are a buggy fork!**
>>1000358 Поспав на этом два дня, думаю, что можно, технически, просто добавить пример со спойлером в раздел Markdown->Особенности (и поставить туда якорь, чтобы ссылаться удобнее). Но я думал над тем как сделать Совусу кодоподсветку, и знаете, было бы неплохо внести наши изменения в апстрим. И тогда Совусу наверное захочется совместимость, и чтобы теги не закрывались по концу сообщения а игнорировались наверное? Я попробую потыкать до рождества и сам и его что кому надо. Но если говорить про фичи, можно придумать вообще кнопку текстового превью поста? Решает вообще все текущие и будущие проблемы с разметкой, если пользователь может починить всё сам. Ещё можно заморочиться и аж в постформе это делать по ходу заполнения текста, но это или часто дёргать движок, или переписывать то же самое по второму разу на жс.
>>1000368 > И тогда Совусу наверное захочется совместимость Скорее всего. A++ вариант к нему ближе всего. Кусаба parse'ит ***Жирный**Курсив* как ЖирныйКурсив, after all. Хотя не идентичен: скажем, **text* Кусаба распарсит как *text, но не текущий алгоритм. Чтобы, как Кусаба, нужно вводить lookahead до закрывающего тэга. Который ещё может оказаться в [nofmt] блоке, и который должен будет игнорироваться поэтому. И который если не найдётся, должен будет привести к reparsing'у того would-be открывающего ** как *. > и чтобы теги не закрывались по концу сообщения а игнорировались наверное И это тоже. И тут тоже нужно искать закрывающий тэг. В любом случае, похоже, стоит отказаться от parsing'а в один проход. Скажем, можно разбить ввод на токены, инактивировать незакрытые тэги, убрать пустые блоки, и уже потом делать HTML. Можно сделать и lookahead-зависимый **/* parsing, но это куда муторнее.
***Жирный**Курсив*
**text*
> можно придумать вообще кнопку текстового превью поста? Why not. Если силы есть. > или переписывать то же самое по второму разу Даёшь Flower Bus на Node.js!
>>/b/1003427 > 300x100 Поднимаем баннер?
>>1000377 Сначала пусть кто-то нарисует.
>>1000378 ??
>>1000377 Миленько, но кто это там на самолёте?
>>1000380 Pea Ace (Горошина-Ас) же!
Пытались что-нибудь трогать? > И который если не найдётся, должен будет привести к reparsing'у того would-be открывающего ** как * Любопытная циклическая лабуда в оригинальной Кусабе. '' => ''; '*' => '*'; '**' => '**'; '***' => '*'; '****' => '**'; '*****' => '*'; '******' => ''; // <b><i></b></i> Если приставлять звёздочки к 'text*' и 'text**' период тоже 6, но свой. Наверное, нет смысла такое поведение копировать? А то как бы не получилось, что последовательное применение регулякок со strtr-ом выйдет не только на несколько сотен строк кода меньше, но и быстрее. Пускай, наверное, будет '****' => '', то бишь <b></b>. В конце концов, оригинальный parser не убирает возможность отправить пустое сообщение, either. Тогда, пусть будет '***' => '***', '***t*' => '**t' '***t**' => '*t' и '***t***' => 't'. Пустые же блоки дополнительным проходом поубирать.
Стоит сделать обновление RSSа по удалению поста. >>/b/1003583
>>1000385 Что там обновлять? Если такое сообщение попало в кеш твоего ридера то сервер с ним уже ничего не сделает.
>>1000385 Done. >>1000386 RSS обновлялся только по постингу новых постов.
>>1000370 Силы на это нашлись, прикрутить перевод после нескольких попыток не нашлись. >>1000377 Done.
>>1000383 Если '****' это <b></b>, то почему *** не <i>*</i>? Алсо, '***t**' => '<b>*t</b>' или *<b>t</b>? По идее наверное первое?
'****'
<b></b>
***
<i>*</i>
'***t**' => '<b>*t</b>'
*<b>t</b>
> Done. Cool. >>1000389 > почему *** не <i>*</i>? У позиции 0 распознаётся **, поскольку имеет приоритет над *, и parsing идёт дальше. У позиции 2 * распознаётся как *, но ни для раннего **, ни для * не находится закрытие. Поэтому оба инактивируются и печатаются, как есть. Reparsing'а у позиции 0 не происходит. Если бы происходило, было бы <i></i>*, и было бы '**' => ''. > По идее наверное первое? Да. Если саму систему parsing-а пока не трогали, напишу новый BBCode() тогда. Где-то к началу января будет готово. Как-то так пока вижу. Оставляем continue-проверки только для кода/nofmt и для \n\r-тэга закрытия списка, а также для открывающего BB-тэга, если ровно тот же тэг пока не был закрыт, i.e. в '[i] [i] [/i]' второе [i] вызывает continue, '[i] [i] [/i]' => ' [i] '. Встречаем тэг? Добавляем его в список, а также простой текст между ним и предыдущим тэгом. Вместо true в $states пишем ссылку на свежедобавленный элемент списка. Встречаем закрывающий тэг? Из $states, если есть, по ссылке достаём соответствующий открывающему тэгу элемент списка, и прописываем туда ссылку на закрывающий элемент. Вторым проходом инактивируем незакрытые тэги, третьим делаем HTML, следя, чтобы '* [i] test * [/i]' и подобное не приводило к некорректному HTML: '* test0 [i] test1 * test2 [/i]' => ' test0 test1 test2 '.
> к началу января Или к середине.
>>1000391 Да это я думаю пока не критично, хоть и хорошо было бы. Я сам-то в разъездах до 12го.
Всё-таки течёт оно у меня невероятно. И без раскрытых картинок. И наверно, получается, проблема уникальная для этой конфигурации, раз больше никот. Какая-то несовместимость может. Ои на месте, а версия с sw всё поднимается и поднимается.
>>1000402 Не совсем понимаю, как это читать. Это всё местное, и заодно течёт не только воркер? Ну и на всякий случай тот же вопрос про 410. Так-то я могу себе вернуть/поставить тоже рикай и помониторить.
>>1000403 Я тоже не понимаю, как это читать, лол. Эото скриншоты с девтулсов, открытых на вкладке именно тут. Просто тыкнул что-то с надписью memory как очевидное, а там почему-то экстеншоны. Воркера не видно было, но единственное отличие 0141 от 014 в нём, поэтому на него и грешу. Вот сейчас рикая нет, а вкладка опять 200,000 K и растёт дальше пока пишу этот пост. Открыл /b/ 410 сейчас, прокрутил сверху донизу, открыл quick reply, попечатал, развернул картинку на 4000×4000, подождал. Около 70,000 K, стабильно, (норма). Быстрый тест булки (поставил sleep 5m) - так же. Попробовал Clear site data в Devtools (и Unregister service workers которая там). Всё равно отъелась до 400,000K просто постояв открытая. В общем, мистика. Сделать тут мало что можно, так как подозреваю всё-таки какую-то непонятную несовместимость с моей уникальной конфигурацией. Но мне хотелось бы узнать, сколько у вас вкладка потребляет просто постояв. Может, у вас много памяти свободно и вам просто незаметно. А я тут постоянно на границе OOM сижу. Месяц непрерывно запущенного хрома это не шутки, собсно, там сам Browser утекает, а кнопки Minimize mem usage, как в Firefox, не завезли.
Как-то так на моей лисе. Наверное, действительно течёт где-то. >>1000404 > но единственное отличие 0141 от 014 в нём Не единственное же. Есть изменения в kusaba.js.
>>1000405 Это очень долгий замер! У меня за пять минут все улетает. Ну и в "лисе", а надо на хромиум-подобных!
>>1000406 Или не течёт. Проверю в хромиуме чуть позже.
На TaskManager-е в Хромиуме memory footprint действительно растёт, но и периодически сбрасывается. Наверное, дело в сборке мусора.
Memory Snapshot за 5 минут, однако, ничего интересного не показывает.
>>1000391 Новости. У меня депрессия. tokenize → fix_integrity → print почти готово, оставалось бы только отдебажить, но поскольку [nofmt] и [code] сами по себе являются escaper'ами, для них нужно будет делать предобработку отдельным циклом и таки с lookahead'ом, и уже потом дотокенезировать гарантированно непокрытый активными [nofmt] или [code] блоками текст. Завис пока на этом. Иначе, как пока сейчас у меня в черновике, будет вывод «every mark after unclosed ` is **ignored** ». А должно быть «every mark after unclosed ` is ignored"». Also, погодя возник вопрос, что делать, если, скажем, для незакрытого [code] встречаются за-escape'ленные и escape-блоком другого типа, и тильдою [/code], например «[code] This is `NOW ~[/code]`». Думаю резолвить такой ввод как «[code] This is NOW ~[/code]» всё-таки. Другие заметки по надвигающемуся. Будет пофикшена ситуация (±костыльно, но можно будет включить и цитирование в обобщённую обработку)List end.> Citation Будет пофикшена ситуация %% - Bug. %% ↓↓↓↓↓↓↓ Bug.
NOW ~[/code]
>>1000410 Поправляйтесь. Ради развлечения, попробовал чисто теоретически сформулировать грамматикой. Выходит как-то не очень: Message => List\nMessage|Quote\nMessage|Paragraph\nMessage|EOF List => OrderedList|UnorderedList OrderedList => OLElement\nOrderedListContinuation|OLElement OrderedListContinuation => OLElement\nOrderedListContinuation|OLElement OLElement => +InlineParagraph|#InlineParagraph UnrderedList => ULElement\nUnorderedListContinuation|ULElement UnorderedListContinuation => ULElement\nUnorderedListContinuation|ULElement ULElement => -InlineParagraph|*InlineParagraph InlineParagraph => Line|Line~\nInlineParagraph Line => NoFmtLine,Line|CodeLine,Line|BoldLine,Line|ItalicLine,Line|UnderscoreLine,Line|StrikethroughLine,Line|AsciiLine,Line|SpoilerLine,Line|URL,Line|Text,Line|<empty> NoFmtLine => [nofmt]Text,NoEscape[/nofmt]|``Text,NoEscape`` CodeLine => [code]Text,NoEscape[/code]|`Text,NoEscape` BoldLine => [b]Line,NoEscape[/b]|**Line,NoEscape** ItalicLine => [i]Line,NoEscape[/i]|**Line,NoEscape** UnderscoreLine => [u]Line,NoEscape[/u] StrikethroughLine => [s]Line,NoEscape[/s]|^^Line,NoEscape^^ AsciiLine => [aa]Line,NoEscape[/aa] SpoilerLine => [spoiler]Line,NoEscape[/spoiler]|%%Line,NoEscape%% NoEscape => (~~)*|Text,(~~)* Text => [^\n]*? URL => (http|https|ftp|sftp|mailto)://[^, \n]+ Paragraph => NoFmtParagraph,Paragraph|CodeParagraph,Paragraph|BoldParagraph,Paragraph|ItalicParagraph,Paragraph|UnderscoreParagraph,Paragraph|StrikethroughParagraph,Paragraph|AsciiParagraph,Paragraph|SpoilerParagraph,Paragraph|Line,Paragraph|<empty> NoFmtParagraph => [nofmt]MLText,NoEscape[/nofmt]\n? CodeParagraph => [code]MLText,NoEscape[/code]\n? BoldParagraph => [b]\n?Paragraph\n?,NoEscape[/b]\n? ItalicParagraph => [i]\n?Paragraph\n?,NoEscape[/i]\n? UnderscoreParagraph => [u]\n?Paragraph\n?,NoEscape[/u]\n? StrikethroughParagraph => [s]\n?Paragraph\n?,NoEscape[/s]\n? AsciiParagraph => [aa]\n?Paragraph\n?,NoEscape[/aa]\n? SpoilerParagraph => [spoiler]\n?Paragraph\n?,NoEscape[/spoiler]\n? MLText => Text\nMLText|Text|\n|<empty> Хорошо что мы вложенные списки пока не даём.
>>1000411 А, ну и >>ссылки забыл добавить на одном уровне с урл и определить Quote как >Line. (или InlineParagraph?)
>>1000410 Готово. parse.class.php и markdown.html в архиве. Запилено, как оговорено, Кусаба-подобное поведение, пофикшено упомянутое в >>1000410 и >>/b/1004023 пофикшено тоже. Обработка (">", "\r\n") обобщённым токенизатором привела к конфликту с >>post_id, который был решён запихиванием обработки этого >>post_id в общий же токенизатор: как следствие, внутренние ссылки теперь подлежат escape-у. Возможно, стоит запихать в него же и обработку внешних ссылок, что может быть удобно, если хочется поместить ссылку под спойлер. InterboardQuoteCheck и InterthreadQuoteCheck я не трогал. Наверное, можно как-то красиво сжать определения констант, но я не стал заморачиваться. Часть debug_* функций я не стал удалять. Вдруг пригодятся.
> Поправляйтесь Спасибо. > чисто теоретически сформулировать грамматикой Тоже вот думалось, можно ли как-то это дело формально определить и скормить Bison-у, и чтобы оно само всё сгенерировало. Но у нас, вполне возможно, не context-free grammar. > Хорошо что мы вложенные списки пока не даём Scary.
>>1000413 It's up!
>>1000410 Мужик сказал — мужик сделал. Круто и ответственно!
Добавил URLы в обобщённую обработку. Теперь можно escape-ить начало URLа по ~. Условия, по которым терминируется URL, отличаются от оригинала.Пробельный символ;~ (поглощается);.,:;?!«»“”’… перед пробельным символом или в конце строки;Текст, соответствующий любому из тэгов разметки.То бишь, нет терминации по скобкам: чтобы отправить "Автобус (https://410chan.org/b/)" нужно будет набрать "Автобус (https://410chan.org/b/~)". Убрал возможность делать ссылки с ftp://-дескриптором, потому что FTP выпилен из современных браузеров, но там легко в url_start_subregex и в mark_to_mark_type по аналогии добавить. >> у >>post_link теперь тоже опознаётся через mark_to_mark_type, и токенизируется тем же, что и внешние ссылки, кодом. На будущее, должно быть легко g://here_goes_gelbooru_hash и p://pixiv_artwork_id добавить. Можно даже без префиксов-дескрипторов сделать. [nofmt] и `` теперь не превращают пробелы в неразрывные. Файлы в архиве.
.,:;?!«»“”’…
Also, надо бы поменять тип message столбца с text, на mediumtext. И на Чио тоже. Когда длина сообщения будет считаться по mb_strlen, вызвать переполнение будет даже проще, чем сейчас.
>>1000417>Firefox 90 will no longer support the FTP protocolОднако.
>>1000419 https://kb.mozillazine.org/Register_protocol Но есть такое вот. Так что, наверное, стоит поддержку ftp:// вернуть. Заодно ftps и sftp добавить. Может, ещё что-то? Также, если есть возможность как-то проверять, есть у протокола handler или нет, можно будет добавить в kusaba.js, чтобы по клику на ссылку происходило её копирование в случае, если нет.
>>1000417 Добавлено, но: 1. Оставил mailto, ftp, news 2. Оставил декодирование ссылок как было чтобы не нарваться на XSS из прошлого года >>1000418 TODO. Как и обновить код на кодберге. Ещё надо наверное проверить есть ли изменения в рендере от смены пробелов неразрывных на обычные в коде.
>>1000423 2. Я там убрал htmlspecialchars decode, потому что теперь не вызывается htmlspecialchars encode перед parsing-ом, prettify_url оставив тем же. Иначе получается, как на приложенной картинке. > есть ли изменения в рендере от смены пробелов неразрывных на обычные в коде.Я только для [nofmt] и для `` убрал. Не для [code] и `. Если убрать их и для [code], оно съест отступы.
BTW, если по запилу кодоподсветки оформлять развод, то, наверное, стоит и [nbsp] добавить.
Перетащу сюда всякое в видный пост чтобы не терялось. >>1000340 якорь добавить-перекрасить. >>1000344 sodane отдельным скриптом(?) >>1000402 попробовать это отладить. При желании можно костыль-версию добавить и включать или одно или другое по каким настройкам... Было бы ещё неплохо для модерки какой экран просмотра анимапчи...
>>1000418>>1000425 Done.
>>1000428 Gut. >>1000427> Было бы ещё неплохо для модерки какой экран просмотра анимапчиСписок, где слева картинка, справа — имена, и можно редактировать? > При желании можно костыль-версию добавить и включать или одно или другое по каким настройкам...Есть версия, которая не использует SharedWorker, поскольку тот не реализован в мобильном Хроме. Можно if(!!window.SharedWorker) поменять на if(false) и посмотреть, в нём ли дело.
if(!!window.SharedWorker)
if(false)
>>1000429 И кнопочку аплоада/разрешения для какой доски. Или два разных экрана, один для алиасов, один для доскопринадлежности. Так можно избавиться от текстофайлов и их в БД держать.>Можно if(!!window.SharedWorker) поменять на if(false) и посмотреть, в нём ли дело.А я пожалуй так и сделаю.
> $catalog_page .= '<span class="catalogmsg">' . closeOpenTags(mb_substr(strip_tags(stripslashes($line['message'])), 0, 40)) .'</span><br />';> closeOpenTags(mb_substr(strip_tags(stripslashes($line['message'])), 0, 40))С учётом HTML Entities, получать catalogmsg можно вот так, наверное. function get_catalog_msg($msg, $max_catalog_msg_length){ $catalog_msg = ''; $msg_id = 0; $catalog_msg_len = 0; $brs = ['<br>' => 1, '<br/>' => 1, '<br />' => 1]; while($msg_id < strlen($msg) && $catalog_msg_len < $max_catalog_msg_length){ $c = $msg[$msg_id]; if($c === '<'){ $html_tag_term_id = strpos($msg, '>', $msg_id); if($html_tag_term_id === false) break; if($html_tag_term_id - $msg_id + 1 <= strlen("<br />")){ $maybe_br = substr($msg, $msg_id, $html_tag_term_id - $msg_id + 1); if(array_key_exists($maybe_br, $brs)){ $catalog_msg .= ' '; $catalog_msg++; } } $msg_id = $html_tag_term_id + 1; } else if($c === '&'){ $html_entity_term_id = strpos($msg, ';', $msg_id); if($html_entity_term_id === false) break; $html_entity = substr($msg, $msg_id, $html_entity_term_id - $msg_id + 1); $decoded = html_entity_decode($html_entity, ENT_QUOTES | ENT_HTML5); if($html_entity != $decoded){ $catalog_msg .= $html_entity; $catalog_msg_len++; } $msg_id = $html_entity_term_id + 1; } else{ $o = ord($c); // we're at the start of some UTF-8 symbol if($o > 0xDF) $bytes = $o > 0xEF ? 4 : 3; else $bytes = $o > 0x7F ? 2 : 1; $catalog_msg .= substr($msg, $msg_id, $bytes); $catalog_msg_len += 1; $msg_id += $bytes; } } return $catalog_msg; }
function get_catalog_msg($msg, $max_catalog_msg_length){ $catalog_msg = ''; $msg_id = 0; $catalog_msg_len = 0; $brs = ['<br>' => 1, '<br/>' => 1, '<br />' => 1]; while($msg_id < strlen($msg) && $catalog_msg_len < $max_catalog_msg_length){ $c = $msg[$msg_id]; if($c === '<'){ $html_tag_term_id = strpos($msg, '>', $msg_id); if($html_tag_term_id === false) break; if($html_tag_term_id - $msg_id + 1 <= strlen("<br />")){ $maybe_br = substr($msg, $msg_id, $html_tag_term_id - $msg_id + 1); if(array_key_exists($maybe_br, $brs)){ $catalog_msg .= ' '; $catalog_msg++; } } $msg_id = $html_tag_term_id + 1; } else if($c === '&'){ $html_entity_term_id = strpos($msg, ';', $msg_id); if($html_entity_term_id === false) break; $html_entity = substr($msg, $msg_id, $html_entity_term_id - $msg_id + 1); $decoded = html_entity_decode($html_entity, ENT_QUOTES | ENT_HTML5); if($html_entity != $decoded){ $catalog_msg .= $html_entity; $catalog_msg_len++; } $msg_id = $html_entity_term_id + 1; } else{ $o = ord($c); // we're at the start of some UTF-8 symbol if($o > 0xDF) $bytes = $o > 0xEF ? 4 : 3; else $bytes = $o > 0x7F ? 2 : 1; $catalog_msg .= substr($msg, $msg_id, $bytes); $catalog_msg_len += 1; $msg_id += $bytes; } } return $catalog_msg; }
キタ━━━(゚∀゚)━━━!!
>>1000434 Ахаха ох вау.
>>1000435> $to_append = strtr($to_append, [" " => " ", "\t" => " "]); Забыл ; добавить.
>>1000436 Поправлено. >>1000433 Хммм. Вообще, было бы неплохо это через formatLongMessage сделать что уже делает примерно то же самое. И парсер хтмл заново писать не надо, потому что он либу использует.
formatLongMessage
>>1000437 Теперь там просто DomDocument->loadHTML->getNode->textContent, и всё в mb_substr. Алсо, оказывается всё время с ввода нового formatLongMessage оно выводило лишние <!DOCTYPE><html><body></body></html>, лол. >>1000430 Так и сделано. >>1000402 прожмите F5 и проверьте, пожалуйста.
DomDocument->loadHTML->getNode->textContent
mb_substr
>>1000437 Стоит, думаю, и посты поправить. update posts_b set message=regexp_replace(message, ' (?!;)', '\\1 ') where postedat > unix_timestamp('2025-02-17 08:23:40') and postedat < unix_timestamp('2025-03-04 08:47:55'); update posts_d set message=regexp_replace(message, ' (?!;)', '\\1 ') where postedat > unix_timestamp('2025-02-17 08:23:40') and postedat < unix_timestamp('2025-03-04 08:47:55'); >>1000438> Теперь там просто DomDocument->loadHTML->getNode->textContent, и всё в mb_substr.В formatLongMessage или вместо closeOpenTags(...)?
update posts_b set message=regexp_replace(message, ' (?!;)', '\\1 ') where postedat > unix_timestamp('2025-02-17 08:23:40') and postedat < unix_timestamp('2025-03-04 08:47:55'); update posts_d set message=regexp_replace(message, ' (?!;)', '\\1 ') where postedat > unix_timestamp('2025-02-17 08:23:40') and postedat < unix_timestamp('2025-03-04 08:47:55');
closeOpenTags(...)
>>1000439 Не особо любо менять посты, но так как это был баг, то ладно. И да, в closeOpenTags. То есть там теперь не мешанина из striptags()stripslashes()closeopentags() а просто берётся текстовая часть хтмл и обрезается до 40 символов.