Skip to content

Commit

Permalink
Merge pull request #1785 from tomudding/feature/improved-markdown-sup…
Browse files Browse the repository at this point in the history
…port-for-companies

Improved markdown support for companies
  • Loading branch information
tomudding authored Feb 6, 2024
2 parents 9a4d146 + 08d09c1 commit 637a3da
Show file tree
Hide file tree
Showing 40 changed files with 863 additions and 131 deletions.
4 changes: 2 additions & 2 deletions config/autoload/global.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
],

/*
* Exam and Summary upload directory configration.
* Exam and Summary upload directory configuration.
*/
'education' => [
'upload_dir' => 'public/data/education',
Expand All @@ -86,7 +86,7 @@
],

/*
* Exam and Summary temporary upload directory configration.
* Exam and Summary temporary upload directory configuration.
*/
'education_temp' => [
'upload_exam_dir' => 'public/data/education_temp_exams',
Expand Down
2 changes: 0 additions & 2 deletions module/Activity/view/partial/create.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ $lang = $this->plugin('translate')->getTranslator()->getLocale();
$description = $form->get('description')
->setAttribute('class', 'form-control form-control-dutch')
->setAttribute('style', 'width:100%; height:10em; resize:none')
->setAttribute('data-provide', 'markdown')
->setAttribute('id', 'description-nl');
$description->setValue($this->localisedTextElement($description));
?>
Expand Down Expand Up @@ -154,7 +153,6 @@ $lang = $this->plugin('translate')->getTranslator()->getLocale();
$descriptionEn = $form->get('descriptionEn')
->setAttribute('class', 'form-control form-control-english')
->setAttribute('style', 'width:100%; height:10em; resize:none')
->setAttribute('data-provide', 'markdown')
->setAttribute('id', 'description-en');
$descriptionEn->setValue($this->localisedTextElement($descriptionEn));
?>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\CompanyImage;

use Application\View\Helper\GlideUrl;
use League\CommonMark\Environment\EnvironmentBuilderInterface;
use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
use League\CommonMark\Extension\CommonMark\Renderer\Inline\ImageRenderer;
use League\CommonMark\Extension\ExtensionInterface;
use Override;

class CompanyImageExtension implements ExtensionInterface
{
public function __construct(private readonly GlideUrl $glideUrl)
{
}

#[Override]
public function register(EnvironmentBuilderInterface $environment): void
{
$environment->addRenderer(
Image::class,
new CompanyImageRenderer($environment->getConfiguration(), new ImageRenderer(), $this->glideUrl),
10,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\CompanyImage;

use Application\View\Helper\GlideUrl;
use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
use League\CommonMark\Extension\CommonMark\Renderer\Inline\ImageRenderer;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;
use League\CommonMark\Util\HtmlElement;
use League\Config\ConfigurationInterface;
use Stringable;

use function str_starts_with;
use function substr;

class CompanyImageRenderer implements NodeRendererInterface
{
public function __construct(
private readonly ConfigurationInterface $config,
private readonly ImageRenderer $baseImageRenderer,
private readonly GlideUrl $glideUrl,
) {
}

public function render(
Node $node,
ChildNodeRendererInterface $childRenderer,
): Stringable|string {
Image::assertInstanceOf($node);

// phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable
/** @var Image $node */

// Check if we have a valid image, only accept images that were uploaded specifically for companies.
if (!str_starts_with($node->getUrl(), '/data/company/')) {
return '';
}

$this->baseImageRenderer->setConfiguration($this->config);
/** @var HtmlElement $imageElement */
$imageElement = $this->baseImageRenderer->render($node, $childRenderer);

$imageElement->setAttribute('style', 'max-width: 100%');
$imageElement->setAttribute('src', $this->glideUrl->getUrl(substr($node->getUrl(), 5), []));

return $imageElement;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\NoImage;

use League\CommonMark\Environment\EnvironmentBuilderInterface;
use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
use League\CommonMark\Extension\ExtensionInterface;
use Override;

class NoImageExtension implements ExtensionInterface
{
#[Override]
public function register(EnvironmentBuilderInterface $environment): void
{
$environment->addRenderer(Image::class, new NoImageRenderer(), 10);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\NoImage;

use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;

use function sprintf;

class NoImageRenderer implements NodeRendererInterface
{
public function render(
Node $node,
ChildNodeRendererInterface $childRenderer,
): string {
Image::assertInstanceOf($node);

// phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable
/** @var Image $node */

return sprintf(
'![%s](%s)',
$node->getTitle() ?? '',
$node->getUrl(),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\VideoIframe\Parsers;

use Application\Extensions\CommonMark\VideoIframe\Video;
use Application\Extensions\CommonMark\VideoIframe\VideoPlatforms;
use Application\Extensions\CommonMark\VideoIframe\VideoUrlParserInterface;
use Override;

use function preg_match;

class VimeoUrlParser implements VideoUrlParserInterface
{
private const REGEX = '/(?:vimeo\.com\/(?:\d+|[^\/]+\/[^\/]+\/video\/|album\/[^\/]+\/video\/|channels\/[^\/]+\/|groups\/[^\/]+\/videos\/|ondemand\/[^\/]+\/)|player\.vimeo\.com\/video\/)(\d+)/';

Check warning on line 16 in module/Application/src/Extensions/CommonMark/VideoIframe/Parsers/VimeoUrlParser.php

View workflow job for this annotation

GitHub Actions / php-codesniffer / PHP_CodeSniffer (8.3)

Line exceeds 120 characters; contains 197 characters

#[Override]
public function parse(string $url): ?Video
{
if (preg_match(self::REGEX, $url, $matches)) {
return new Video(VideoPlatforms::Vimeo, $matches[1]);
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\VideoIframe\Parsers;

use Application\Extensions\CommonMark\VideoIframe\Video;
use Application\Extensions\CommonMark\VideoIframe\VideoPlatforms;
use Application\Extensions\CommonMark\VideoIframe\VideoUrlParserInterface;
use Override;

use function preg_match;

class YouTubeUrlParser implements VideoUrlParserInterface
{
private const REGEX = '/(?:m\.)?(?:youtube\.com\/(?:watch\?v=|v\/|embed\/)|youtu\.be\/|youtube-nocookie\.com\/embed\/)([\w-]+)/';

Check warning on line 16 in module/Application/src/Extensions/CommonMark/VideoIframe/Parsers/YouTubeUrlParser.php

View workflow job for this annotation

GitHub Actions / php-codesniffer / PHP_CodeSniffer (8.3)

Line exceeds 120 characters; contains 133 characters

#[Override]
public function parse(string $url): ?Video
{
if (preg_match(self::REGEX, $url, $matches)) {
return new Video(VideoPlatforms::YouTube, $matches[1]);
}

return null;
}
}
24 changes: 24 additions & 0 deletions module/Application/src/Extensions/CommonMark/VideoIframe/Video.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\VideoIframe;

class Video
{
public function __construct(
private readonly VideoPlatforms $platform,
private readonly string $identifier,
) {
}

public function getPlatform(): VideoPlatforms
{
return $this->platform;
}

public function getIdentifier(): string
{
return $this->identifier;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\VideoIframe;

use League\CommonMark\Node\Node;

class VideoIframe extends Node
{
public function __construct(private readonly Video $video)
{
parent::__construct();
}

public function getVideo(): Video
{
return $this->video;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\VideoIframe;

use Application\Extensions\CommonMark\VideoIframe\Parsers\VimeoUrlParser;
use Application\Extensions\CommonMark\VideoIframe\Parsers\YouTubeUrlParser;
use League\CommonMark\Environment\EnvironmentBuilderInterface;
use League\CommonMark\Event\DocumentParsedEvent;
use League\CommonMark\Extension\ExtensionInterface;
use Override;

class VideoIframeExtension implements ExtensionInterface
{
#[Override]
public function register(EnvironmentBuilderInterface $environment): void
{
$environment->addEventListener(
DocumentParsedEvent::class,
new VideoIframeProcessor([
new VimeoUrlParser(),
new YouTubeUrlParser(),
]),
)
->addRenderer(VideoIframe::class, new VideoIframeRenderer(), 10);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\VideoIframe;

use League\CommonMark\Event\DocumentParsedEvent;
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;

class VideoIframeProcessor
{
/**
* @param VideoUrlParserInterface[] $parsers
*/
public function __construct(private readonly array $parsers)
{
}

public function __invoke(DocumentParsedEvent $event): void
{
$walker = $event->getDocument()->walker();

while ($item = $walker->next()) {
$link = $item->getNode();

if (!($link instanceof Link)) {
continue;
}

foreach ($this->parsers as $parser) {
$video = $parser->parse($link->getUrl());

if (null === $video) {
continue;
}

$link->replaceWith(new VideoIframe($video));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\VideoIframe;

use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;
use League\CommonMark\Util\HtmlElement;
use Override;
use Stringable;

class VideoIframeRenderer implements NodeRendererInterface
{
#[Override]
public function render(
Node $node,
ChildNodeRendererInterface $childRenderer,
): Stringable {
VideoIframe::assertInstanceOf($node);

// phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable
/** @var VideoIframe $node */
$video = $node->getVideo();

return new HtmlElement(
'div',
['style' => 'position: relative; height: 0; padding-bottom: 56.2493%;'],
new HtmlElement('iframe', [
'allowfullscreen' => '1',
'src' => $video->getPlatform()->getUrl($video->getIdentifier()),
'style' => 'position: absolute; width: 100%; height: 100%; top: 0; left: 0; border: 0;',
]),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Application\Extensions\CommonMark\VideoIframe;

enum VideoPlatforms: string
{
case Vimeo = 'vimeo';
case YouTube = 'youtube';

public function getUrl(string $identifier): string
{
return match ($this) {
self::Vimeo => 'https://player.vimeo.com/video/' . $identifier,
self::YouTube => 'https://www.youtube-nocookie.com/embed/' . $identifier,
};
}
}
Loading

0 comments on commit 637a3da

Please sign in to comment.