text($md); if ($no_paragraph) $html = preg_replace('/

(.*?)<\/p>/', '$1', $html); else { // collect references $re = '/^

(\[([io]?\d{1,2})]) (.*?)<\/p>/m'; $result = preg_match_all($re, $html, $matches); if (pcre_no_error($result)) { $reftitles_map = []; foreach ($matches[2] as $i => $refname) { $reftitles_map[$refname] = trim(strip_tags($matches[3][$i])); } $span_opening_tag = ''; $html = preg_replace($re, '

'.$span_opening_tag.'$1 $3

', $html); $re = '/'.implode('|', array_map(fn($m) => '(?:'.$span_opening_tag.')?'.preg_quote($m, '/'), $matches[1])).'/'; $html = preg_replace_callback($re, function($match) use ($span_opening_tag, $reftitles_map) { if (str_starts_with($match[0], $span_opening_tag)) return $match[0]; if (!preg_match('/\[([io]?\d{1,2})]/', $match[0], $refmatch)) return $match[0]; $refname = $refmatch[1]; $reftitle = $reftitles_map[$refname]; return ''.$match[0].''; }, $html); } } return $html; } public static function toc(string $md): string { $pd = new MyParsedown([ 'toc' => [ 'lowercase' => true, 'transliterate' => true, 'urlencode' => false, 'headings' => ['h1', 'h2', 'h3'] ] ]); $pd->text($md); return $pd->contentsList(); } public static function htmlToText(string $html): string { $text = html_entity_decode(strip_tags($html)); $lines = explode("\n", $text); $lines = array_map('trim', $lines); $text = implode("\n", $lines); $text = preg_replace("/(\r?\n){2,}/", "\n\n", $text); return $text; } public static function htmlImagesFix(string $html, bool $is_retina, string $user_theme): string { global $config; $is_dark_theme = $user_theme === 'dark'; return preg_replace_callback( '/('.preg_quote($config['uploads_path'], '/').'\/\w{8}\/)([ap])(\d+)x(\d+)(\.jpg)/', function($match) use ($is_retina, $is_dark_theme) { $mult = $is_retina ? 2 : 1; $is_alpha = $match[2] == 'a'; return $match[1].$match[2].(intval($match[3])*$mult).'x'.(intval($match[4])*$mult).($is_alpha && $is_dark_theme ? '_dark' : '').$match[5]; }, $html ); } }