* @since 2.0 */ class ApiMarkdown extends GithubMarkdown { use ApiMarkdownTrait; /** * @var BaseRenderer */ public static $renderer; /** * @var array translation for guide block types * @since 2.0.5 */ public static $blockTranslations = []; protected $renderingContext; protected $headings = []; /** * @return array the headlines of this document * @since 2.0.5 */ public function getHeadings() { return $this->headings; } /** * @inheritDoc */ protected function prepare() { parent::prepare(); $this->headings = []; } public function parse($text) { $markup = parent::parse($text); $markup = $this->applyToc($markup); return $markup; } /** * @since 2.0.5 */ protected function applyToc($content) { // generate TOC if (!empty($this->headings)) { $toc = []; foreach ($this->headings as $heading) $toc[] = '
  • ' . Html::a(strip_tags($heading['title']), '#' . $heading['id']) . '
  • '; $toc = '
      ' . implode("\n", $toc) . "
    \n"; if (strpos($content, '') !== false) $content = str_replace('', "\n" . $toc, $content); else $content = $toc . $content; } return $content; } /** * @var Highlighter */ private static $highlighter; /** * @inheritdoc */ protected function renderCode($block) { if (self::$highlighter === null) { self::$highlighter = new Highlighter(); self::$highlighter->setAutodetectLanguages([ 'apache', 'nginx', 'bash', 'dockerfile', 'http', 'css', 'less', 'scss', 'javascript', 'json', 'markdown', 'php', 'sql', 'twig', 'xml', ]); } try { if (isset($block['language'])) { $result = self::$highlighter->highlight($block['language'], $block['content'] . "\n"); return "
    language} language-{$block['language']}\">{$result->value}
    \n"; } else { $result = self::$highlighter->highlightAuto($block['content'] . "\n"); return "
    language}\">{$result->value}
    \n"; } } catch (DomainException $e) { echo $e; return parent::renderCode($block); } } /** * Highlights code * * @param string $code code to highlight * @param string $language language of the code to highlight * @return string HTML of highlighted code * @deprecated since 2.0.5 this method is not used anymore, highlight.php is used for highlighting */ public static function highlight($code, $language) { if ($language !== 'php') { return htmlspecialchars($code, ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8'); } if (strncmp($code, '\n and tags added by php $text = substr(trim($text), 36, -16); return $text; } /** * @inheritDoc */ protected function renderHeadline($block) { $content = $this->renderAbsy($block['content']); if (preg_match('~~', $content, $matches)) { $hash = $matches[1]; $content = preg_replace('~~', '', $content); } else { $hash = Inflector::slug(strip_tags($content)); } $hashLink = ""; if ($block['level'] == 2) { $this->headings[] = [ 'title' => trim($content), 'id' => $hash, ]; } elseif ($block['level'] > 2) { if (end($this->headings)) { $this->headings[key($this->headings)]['sub'][] = [ 'title' => trim($content), 'id' => $hash, ]; } } $tag = 'h' . $block['level']; return "<$tag>$content $hashLink"; } /** * @inheritdoc */ protected function renderLink($block) { $result = parent::renderLink($block); // add special syntax for linking to the guide $result = preg_replace_callback('/href="guide:([A-z0-9-.#]+)"/i', function($match) { return 'href="' . static::$renderer->generateGuideUrl($match[1]) . '"'; }, $result, 1); return $result; } /** * @inheritdoc * @since 2.0.5 */ protected function translateBlockType($type) { $key = ucfirst($type) . ':'; if (isset(static::$blockTranslations[$key])) { $translation = static::$blockTranslations[$key]; } else { $translation = $key; } return "$translation "; } /** * Converts markdown into HTML * * @param string $content * @param TypeDoc $context * @param bool $paragraph * @return string */ public static function process($content, $context = null, $paragraph = false) { if (!isset(Markdown::$flavors['api'])) { Markdown::$flavors['api'] = new static; } if (is_string($context)) { $context = static::$renderer->apiContext->getType($context); } Markdown::$flavors['api']->renderingContext = $context; if ($paragraph) { return Markdown::processParagraph($content, 'api'); } else { return Markdown::process($content, 'api'); } } /** * Add bootstrap classes to tables. * @inheritdoc */ public function renderTable($block) { return str_replace('', '
    ', parent::renderTable($block)); } }