From: Stephen Cameron Date: Thu, 21 Apr 2022 16:19:23 +0000 (+0200) Subject: Add automatic YouTube embeds to markdown fields. Done #5024 X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;h=810e4b9a1db1edacb451a962804347f45087e53e;p=pmi.git Add automatic YouTube embeds to markdown fields. Done #5024 --- diff --git a/app/Markdown/YouTube/Element.php b/app/Markdown/YouTube/Element.php new file mode 100644 index 0000000..1423a0e --- /dev/null +++ b/app/Markdown/YouTube/Element.php @@ -0,0 +1,54 @@ +URL = $URL; + } + + public function getURL() { + return $this->URL; + } + + public function getVideoID() { + + // Extract the video ID from the URLs. This should support all the main YouTube URL formats + // Instead of regex, we could use parse_url() here - it's more readable / maintainable but also harder + // to support multiple URL formats. See example: + // https://github.com/zoonru/commonmark-ext-youtube-iframe/blob/master/src/YouTubeLongUrlParser.php + preg_match("/(?:https?:\/\/)?(?:www\.)?youtu\.?be(?:\.com)?\/?.*(?:watch|embed)?(?:.*v=|v\/|\/)([\w\-_]+)/", $this->URL, $matches); + if ($matches[1]) { + return $matches[1]; + } + return null; + } + + public function canContain(AbstractBlock $block): bool { + return false; + } + + public function acceptsLines(): bool { + return false; + } + + public function isCode(): bool { + return false; + } + + public function shouldLastLineBeBlank(Cursor $cursor, $currentLineNumber): bool { + return false; + } + + public function matchesNextLine(Cursor $cursor): bool { + return false; + } + +} diff --git a/app/Markdown/YouTube/Extension.php b/app/Markdown/YouTube/Extension.php new file mode 100644 index 0000000..1a8fbe2 --- /dev/null +++ b/app/Markdown/YouTube/Extension.php @@ -0,0 +1,24 @@ +addBlockParser(new Parser()) + ->addBlockRenderer(Element::class, new Renderer( + (string) $environment->getConfig('youtube_iframe_width', 560), + (string) $environment->getConfig('youtube_iframe_height', 315), + (bool) $environment->getConfig('youtube_iframe_allowfullscreen', true) + )); + } +} diff --git a/app/Markdown/YouTube/Parser.php b/app/Markdown/YouTube/Parser.php new file mode 100644 index 0000000..ea1044b --- /dev/null +++ b/app/Markdown/YouTube/Parser.php @@ -0,0 +1,26 @@ +isIndented()) { + return false; + } + + // Make sure that we have a valid YouTube video URL to work with + $matched = $cursor->match("~(?:https?://)?(?:www\.)?youtu\.?be(?:\.com)?/?.*(?:watch|embed)?(?:.*v=|v/|/)([\w\-_]+)~"); + if (!$matched) { + return false; // No match, let this line be handled by another parser + } + $context->addBlock(new Element($matched)); + + return true; + } + +} diff --git a/app/Markdown/YouTube/Renderer.php b/app/Markdown/YouTube/Renderer.php new file mode 100644 index 0000000..37ad7b2 --- /dev/null +++ b/app/Markdown/YouTube/Renderer.php @@ -0,0 +1,61 @@ +width = $width; + $this->height = $height; + $this->allowFullScreen = $allowFullScreen; + } + + public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, $inTightList = false): HtmlElement { + + // Make sure we're rendering a YouTube Element + if (!($block instanceof Element)) { + throw new \InvalidArgumentException('Incompatible block type: ' . get_class($block)); + } + + /* @var $block Element */ + $video_ID = $block->getVideoID(); + + // Javascript to ensure the lite-youtube script is only loaded once... + // Note: This is problematic for sites with Vue wrappers (eg. PMI) because a raw