, * @link https://getkirby.com * @copyright Bastian Allgeier * @license https://getkirby.com/license */ class Blocks extends Plain { public function blockquote(Element $node): array { $text = []; // get all the text for the quote foreach ($node->children() as $child) { if ($child instanceof DOMText) { $text[] = trim($child->textContent); } if ( $child instanceof DOMElement && $child->tagName !== 'footer' ) { $element = new Element($child); $text[] = $element->innerHTML($this->marks()); } } // filter empty blocks and separate text blocks with breaks $text = implode('', array_filter($text)); // get the citation from the footer $citation = $node->find('footer')?->innerHTML($this->marks()); return [ 'content' => [ 'citation' => $citation, 'text' => $text ], 'type' => 'quote', ]; } /** * Creates the fallback block type * if no other block can be found */ public function fallback(Element|string $element): array|null { if ($element instanceof Element) { $html = $element->innerHtml(); // wrap the inner HTML in a p tag if it doesn't // contain one yet. if (Str::contains($html, '
') === false) { $html = '
' . $html . '
'; } } elseif (is_string($element) === true) { $html = trim($element); if (Str::length($html) === 0) { return null; } $html = '' . $html . '
'; } else { return null; } return [ 'content' => [ 'text' => $html, ], 'type' => 'text', ]; } /** * Converts a heading element to a heading block */ public function heading(Element $node): array { $content = [ 'level' => strtolower($node->tagName()), 'text' => $node->innerHTML() ]; if ($id = $node->attr('id')) { $content['id'] = $id; } ksort($content); return [ 'content' => $content, 'type' => 'heading', ]; } public function iframe(Element $node): array { $src = $node->attr('src'); $figcaption = $node->find('ancestor::figure[1]//figcaption'); $caption = $figcaption?->innerHTML($this->marks()); // avoid parsing the caption twice $figcaption?->remove(); // reverse engineer video URLs if (preg_match('!player.vimeo.com\/video\/([0-9]+)!i', $src, $array) === 1) { $src = 'https://vimeo.com/' . $array[1]; } elseif (preg_match('!youtube.com\/embed\/([a-zA-Z0-9_-]+)!', $src, $array) === 1) { $src = 'https://youtube.com/watch?v=' . $array[1]; } elseif (preg_match('!youtube-nocookie.com\/embed\/([a-zA-Z0-9_-]+)!', $src, $array) === 1) { $src = 'https://youtube.com/watch?v=' . $array[1]; } else { $src = false; } // correct video URL if ($src) { return [ 'content' => [ 'caption' => $caption, 'url' => $src ], 'type' => 'video', ]; } return [ 'content' => [ 'text' => $node->outerHTML() ], 'type' => 'markdown', ]; } public function img(Element $node): array { $link = $node->find('ancestor::a')?->attr('href'); $figcaption = $node->find('ancestor::figure[1]//figcaption'); $caption = $figcaption?->innerHTML($this->marks()); // avoid parsing the caption twice $figcaption?->remove(); return [ 'content' => [ 'alt' => $node->attr('alt'), 'caption' => $caption, 'link' => $link, 'location' => 'web', 'src' => $node->attr('src'), ], 'type' => 'image', ]; } /** * Converts a list element to HTML */ public function list(Element $node): string { $html = []; foreach ($node->filter('li') as $li) { $innerHtml = ''; foreach ($li->children() as $child) { if ($child instanceof DOMText) { $innerHtml .= $child->textContent; } elseif ($child instanceof DOMElement) { $child = new Element($child); $list = ['ul', 'ol']; $innerHtml .= match (in_array($child->tagName(), $list)) { true => $this->list($child), default => $child->innerHTML($this->marks()) }; } } $html[] = '