[ 'tablespan' => true ] ]; if (!is_null($opts)) { $parsedown_opts = array_merge($parsedown_opts, $opts); } parent::__construct($parsedown_opts); $this->InlineTypes['{'][] = 'FileAttach'; $this->InlineTypes['{'][] = 'Image'; $this->InlineTypes['{'][] = 'Video'; $this->inlineMarkerList .= '{'; } protected function inlineFileAttach($excerpt) { if (preg_match('/^{fileAttach:([\w]{8})}{\/fileAttach}/', $excerpt['text'], $matches)) { $random_id = $matches[1]; $upload = uploads::getUploadByRandomId($random_id); $result = [ 'extent' => strlen($matches[0]), 'element' => [ 'name' => 'span', 'text' => '', ], 'type' => '' ]; if (!$upload) { return $result; } unset($result['element']['text']); $ctx = self::getSkinContext(); $result['element']['rawHtml'] = $ctx->fileupload($upload->name, $upload->getDirectUrl(), $upload->note, $upload->getSize()); return $result; } } protected function inlineImage($excerpt) { global $config; if (preg_match('/^{image:([\w]{8}),(.*?)}{\/image}/', $excerpt['text'], $matches)) { $random_id = $matches[1]; $opts = [ 'w' => 'auto', 'h' => 'auto', 'align' => 'left', 'nolabel' => false, ]; $inputopts = explode(',', $matches[2]); foreach ($inputopts as $opt) { if ($opt == 'nolabel') $opts[$opt] = true; else { list($k, $v) = explode('=', $opt); if (!isset($opts[$k])) continue; $opts[$k] = $v; } } $image = uploads::getUploadByRandomId($random_id); $result = [ 'extent' => strlen($matches[0]), 'element' => [ 'name' => 'span', 'text' => '', ], 'type' => '' ]; if (!$image) { return $result; } list($w, $h) = $image->getImagePreviewSize( $opts['w'] == 'auto' ? null : $opts['w'], $opts['h'] == 'auto' ? null : $opts['h'] ); $opts['w'] = $w; // $opts['h'] = $h; if (!$this->useImagePreviews) $image_url = $image->getDirectUrl(); else $image_url = $image->getDirectPreviewUrl($w, $h); unset($result['element']['text']); $ctx = self::getSkinContext(); $result['element']['rawHtml'] = $ctx->image( w: $opts['w'], nolabel: $opts['nolabel'], align: $opts['align'], padding_top: round($h / $w * 100, 4), may_have_alpha: $image->imageMayHaveAlphaChannel(), url: $image_url, direct_url: $image->getDirectUrl(), note: $image->note ); return $result; } } protected function inlineVideo($excerpt) { if (preg_match('/^{video:([\w]{8})(?:,(.*?))?}{\/video}/', $excerpt['text'], $matches)) { $random_id = $matches[1]; $opts = [ 'w' => 'auto', 'h' => 'auto', 'align' => 'left', 'nolabel' => false, ]; $inputopts = !empty($matches[2]) ? explode(',', $matches[2]) : []; foreach ($inputopts as $opt) { if ($opt == 'nolabel') $opts[$opt] = true; else { list($k, $v) = explode('=', $opt); if (!isset($opts[$k])) continue; $opts[$k] = $v; } } $video = uploads::getUploadByRandomId($random_id); $result = [ 'extent' => strlen($matches[0]), 'element' => [ 'name' => 'span', 'text' => '', ], 'type' => '' ]; if (!$video) { return $result; } $video_url = $video->getDirectUrl(); unset($result['element']['text']); $ctx = self::getSkinContext(); $result['element']['rawHtml'] = $ctx->video( url: $video_url, w: $opts['w'], h: $opts['h'] ); return $result; } } protected function paragraph($line) { if (preg_match('/^{fileAttach:([\w]{8})}{\/fileAttach}$/', $line['text'])) { return $this->inlineFileAttach($line); } if (preg_match('/^{image:([\w]{8}),(?:.*?)}{\/image}/', $line['text'])) { return $this->inlineImage($line); } if (preg_match('/^{video:([\w]{8})(?:,(?:.*?))?}{\/video}/', $line['text'])) { return $this->inlineVideo($line); } return parent::paragraph($line); } protected function blockFencedCodeComplete($block) { if (!isset($block['element']['element']['attributes'])) { return $block; } $code = $block['element']['element']['text']; $languageClass = $block['element']['element']['attributes']['class']; $language = explode('-', $languageClass); if ($language[1] == 'term') { $lines = explode("\n", $code); for ($i = 0; $i < count($lines); $i++) { $line = $lines[$i]; if (str_starts_with($line, '$ ') || str_starts_with($line, '# ')) { $lines[$i] = ''.substr($line, 0, 2).''.htmlspecialchars(substr($line, 2), ENT_NOQUOTES, 'UTF-8'); } else { $lines[$i] = htmlspecialchars($line, ENT_NOQUOTES, 'UTF-8'); } } $block['element']['element']['rawHtml'] = implode("\n", $lines); unset($block['element']['element']['text']); return $block; } return parent::blockFencedCodeComplete($block); } protected static function getSkinContext(): SkinContext { return new SkinContext('\\skin\\markdown'); } protected function blockTableComplete(array $Block) { if ( ! isset($Block)) { return null; } $HeaderElements =& $Block['element']['elements'][0]['elements'][0]['elements']; for ($index = count($HeaderElements) - 1; $index >= 0; --$index) { $colspan = 1; $HeaderElement =& $HeaderElements[$index]; while ($index && $HeaderElements[$index - 1]['handler']['argument'] === '>') { $colspan++; $PreviousHeaderElement =& $HeaderElements[--$index]; $PreviousHeaderElement['merged'] = true; if (isset($PreviousHeaderElement['attributes'])) { $HeaderElement['attributes'] = $PreviousHeaderElement['attributes']; } } if ($colspan > 1) { if ( ! isset($HeaderElement['attributes'])) { $HeaderElement['attributes'] = array(); } $HeaderElement['attributes']['colspan'] = $colspan; } } for ($index = count($HeaderElements) - 1; $index >= 0; --$index) { if (isset($HeaderElements[$index]['merged'])) { array_splice($HeaderElements, $index, 1); } } $Rows =& $Block['element']['elements'][1]['elements']; foreach ($Rows as $RowNo => &$Row) { $Elements =& $Row['elements']; for ($index = count($Elements) - 1; $index >= 0; --$index) { $colspan = 1; $Element =& $Elements[$index]; while ($index && $Elements[$index - 1]['handler']['argument'] === '>') { $colspan++; $PreviousElement =& $Elements[--$index]; $PreviousElement['merged'] = true; if (isset($PreviousElement['attributes'])) { $Element['attributes'] = $PreviousElement['attributes']; } } if ($colspan > 1) { if ( ! isset($Element['attributes'])) { $Element['attributes'] = array(); } $Element['attributes']['colspan'] = $colspan; } } } foreach ($Rows as $RowNo => &$Row) { $Elements =& $Row['elements']; foreach ($Elements as $index => &$Element) { $rowspan = 1; if (isset($Element['merged'])) { continue; } while ($RowNo + $rowspan < count($Rows) && $index < count($Rows[$RowNo + $rowspan]['elements']) && $Rows[$RowNo + $rowspan]['elements'][$index]['handler']['argument'] === '^' && (@$Element['attributes']['colspan'] ?: null) === (@$Rows[$RowNo + $rowspan]['elements'][$index]['attributes']['colspan'] ?: null)) { $Rows[$RowNo + $rowspan]['elements'][$index]['merged'] = true; $rowspan++; } if ($rowspan > 1) { if ( ! isset($Element['attributes'])) { $Element['attributes'] = array(); } $Element['attributes']['rowspan'] = $rowspan; } } } foreach ($Rows as $RowNo => &$Row) { $Elements =& $Row['elements']; for ($index = count($Elements) - 1; $index >= 0; --$index) { if (isset($Elements[$index]['merged'])) { array_splice($Elements, $index, 1); } } } return $Block; } }