Skip to content

Commit

Permalink
Work in progress, display emojis
Browse files Browse the repository at this point in the history
  • Loading branch information
danon committed Nov 22, 2023
1 parent 2a9a17e commit c0a0776
Show file tree
Hide file tree
Showing 10 changed files with 1,958 additions and 24 deletions.
29 changes: 29 additions & 0 deletions app/Services/Parser/Extensions/Emoji.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
namespace Coyote\Services\Parser\Extensions;

use League\CommonMark\Node\Block\AbstractBlock;

class Emoji extends AbstractBlock
{
private static ?array $resourceFile = null;

public string $code;
public string $unified;
public string $name;

public function __construct(string $code)
{
parent::__construct();
$this->code = $code;

if (self::$resourceFile === null) {
self::$resourceFile = \json_decode(\file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'emoji.json'), true);
}
$resourceFile = self::$resourceFile;

$emoji = $resourceFile['emoticons'][$code];

$this->unified = $emoji['unified'];
$this->name = $emoji['name'];
}
}
46 changes: 46 additions & 0 deletions app/Services/Parser/Extensions/EmojiParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php
namespace Coyote\Services\Parser\Extensions;

use League\CommonMark\Parser\Cursor;
use League\CommonMark\Parser\Inline\InlineParserInterface;
use League\CommonMark\Parser\Inline\InlineParserMatch;
use League\CommonMark\Parser\InlineParserContext;

class EmojiParser implements InlineParserInterface
{
public function getMatchDefinition(): InlineParserMatch
{
return InlineParserMatch::join(
InlineParserMatch::string(':'),
InlineParserMatch::regex('\w+'),
InlineParserMatch::string(':'));
}

public function parse(InlineParserContext $inlineContext): bool
{
$cursor = $inlineContext->getCursor();
$previous = $cursor->peek(-1);
if ($previous === null || $previous === ' ') {
return $this->appendEmoji($cursor, $inlineContext);
}
return false;
}

private function appendEmoji(Cursor $cursor, InlineParserContext $context): bool
{
$previousState = $cursor->saveState();
$emoji = $cursor->match('/^:[\w+-]+:/i');
if ($emoji === null) {
$cursor->restoreState($previousState);
return false;
}
$emoji = \subStr($emoji, 1, -1);
if (\array_key_exists($emoji, Emojis::$codes)) {
$container = $context->getContainer();
$container->appendChild(new Emoji($emoji));
return true;
}
$cursor->restoreState($previousState);
return false;
}
}
34 changes: 34 additions & 0 deletions app/Services/Parser/Extensions/EmojiRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
namespace Coyote\Services\Parser\Extensions;

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

class EmojiRenderer implements NodeRendererInterface
{
public function render(Node $node, ChildNodeRendererInterface $childRenderer): HtmlElement
{
if ($node instanceof Emoji) {
return $this->renderEmoji($node);
}
throw new \LogicException('Failed to parse markdown emoticons');
}

private function renderEmoji(Emoji $emoji): HtmlElement
{
return new HtmlElement('img', [
'class' => 'img-smile',
'src' => $this->cdnUrl($emoji),
'alt' => ":$emoji->code:, $emoji->name",
'title' => $emoji->name,
'style' => 'width:16px',
]);
}

private function cdnUrl(Emoji $emoji): string
{
return "https://cdn.jsdelivr.net/gh/twitter/[email protected]/assets/svg/$emoji->unified.svg";
}
}
1,788 changes: 1,788 additions & 0 deletions app/Services/Parser/Extensions/Emojis.php

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions app/Services/Parser/Extensions/emoji.json

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion app/Services/Parser/Parsers/Markdown.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

use Coyote\Repositories\Contracts\PageRepositoryInterface as PageRepository;
use Coyote\Repositories\Contracts\UserRepositoryInterface as UserRepository;
use Coyote\Services\Parser\Extensions\Emoji;
use Coyote\Services\Parser\Extensions\EmojiParser;
use Coyote\Services\Parser\Extensions\EmojiRenderer;
use Coyote\Services\Parser\Extensions\InternalLinkExtension;
use Coyote\Services\Parser\Extensions\MentionExtension;
use Coyote\Services\Parser\Extensions\YoutubeLinkExtension;
Expand All @@ -26,7 +29,15 @@ public function __construct(

public function parse(string $text): string
{
$environment = new Environment(['renderer' => ['soft_break' => "<br>\n"]]);
$environment = new Environment([
'renderer' => ['soft_break' => "<br>\n"],
'default_attributes' => [
Emoji::class => [
'class' => 'table',
'alt' => 'new',
],
],
]);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new StrikethroughExtension());
Expand All @@ -36,6 +47,9 @@ public function parse(string $text): string
$environment->addExtension(new InternalLinkExtension($this->page, $this->host));
$environment->addInlineParser(new WikiLinksInlineParser($this->page), 100);
$environment->addExtension(new YoutubeLinkExtension());

$environment->addInlineParser(new EmojiParser());
$environment->addRenderer(Emoji::class, new EmojiRenderer());

$converter = new MarkdownConverter($environment);

Expand Down
1 change: 1 addition & 0 deletions app/Services/Parser/Parsers/Purifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public function __construct(array $overrideAllowedHtml = null)

$def = $config->getHTMLDefinition(true);
$def->addAttribute('a', 'data-user-id', 'Number');
$def->addAttribute('img', 'data-emoji', 'Text');
$def->addAttribute('iframe', 'allowfullscreen', 'Bool');

$mark = $def->addElement('mark', 'Inline', 'Inline', 'Common');
Expand Down
64 changes: 42 additions & 22 deletions app/Services/Parser/Parsers/Smilies.php
Original file line number Diff line number Diff line change
@@ -1,42 +1,62 @@
<?php
namespace Coyote\Services\Parser\Parsers;

use Coyote\Services\Parser\Extensions\Emoji;
use TRegx\CleanRegex\Match\Details\Detail;
use TRegx\CleanRegex\Pattern;

class Smilies extends HashParser
{
private array $smilies = [
':)' => 'smile.gif',
':-)' => 'smile.gif',
';)' => 'wink.gif',
';-)' => 'wink.gif',
':-|' => 'neutral.gif',
':D' => 'laugh.gif',
':-D' => 'laugh.gif',
':(' => 'sad.gif',
':-(' => 'sad.gif',
':P' => 'tongue1.gif',
':p' => 'tongue1.gif',
':-P' => 'tongue1.gif',
':-/' => 'confused.gif',
':/' => 'damn.gif',
':[' => 'mad.gif',
':-[' => 'mad.gif',
':|' => 'zonk.gif',
':]' => 'squared.gif',
':d' => 'teeth.gif',
':)' => 'smile',
':-)' => 'twinkle',

';)' => 'wink',
';-)' => 'wink',

':|' => 'neutral',
':-|' => 'neutral',

':D' => 'laugh',
':-D' => 'laugh',

':(' => 'frown',
':-(' => 'frown',

':P' => 'tongue',
':p' => 'tongue',
':-P' => 'tongue',
':-p' => 'tongue',

';P' => 'tongue_wink',
';p' => 'tongue_wink',
';-P' => 'tongue_wink',
';-p' => 'tongue_wink',

':/' => 'confused',
':-/' => 'confused',

':[' => 'angry',
':-[' => 'angry',

':]' => 'squared.gif',

':d' => 'grimacing',
];

public function hashedParse(string $text): string
{
return Pattern::template('(?<=^|[\n \>]|\.)(@)')
->alteration(array_keys($this->smilies))
->replace($text)
->callback(function (Detail $match) {
->callback(function (Detail $match): string {
$smiley = $match->get(1);
$link = $this->smilies[$smiley];
return '<img class="img-smile" alt="' . $smiley . '" title="' . $smiley . '" src="/img/smilies/' . $link . '">';
$emojiCode = $this->smilies[$smiley];

$emo = new Emoji($emojiCode);

$src = "https://cdn.jsdelivr.net/gh/twitter/[email protected]/assets/svg/$emo->unified.svg";
return "<img class=\"img-smile\" alt=\"{$emo->name}\" title=\"{$emo->name}\" src=\"{$src}\" style=\"width:16px\">";
});
}
}
2 changes: 1 addition & 1 deletion config/purifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

// 'HTML.Doctype' => 'XHTML 1.0 Strict', // przez ta linie usuwana byla zawartosc znacznika <blockquote>

'HTML.Allowed' => 'b,strong,i,em,u,a[href|title|data-user-id|class],p,br,ul,ol[start],li,span[style|title|class],img[width|height|alt|src|title],sub,sup,pre,code[class],div[class],kbd,mark,h1,h2,h3,h4,h5,h6,blockquote,del,table[summary|class],thead,tbody,tr,th[abbr],td[abbr],hr,dfn,var,samp,iframe[src|class|allowfullscreen]',
'HTML.Allowed' => 'b,strong,i,em,u,a[href|title|data-user-id|class],p,br,ul,ol[start],li,span[style|title|class],img[width|height|alt|src|title|class],sub,sup,pre,code[class],div[class],kbd,mark,h1,h2,h3,h4,h5,h6,blockquote,del,table[summary|class],thead,tbody,tr,th[abbr],td[abbr],hr,dfn,var,samp,iframe[src|class|allowfullscreen]',
'CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,font-family,text-decoration,color,background-color,background-image,text-align',
'AutoFormat.AutoParagraph' => false,
'AutoFormat.RemoveEmpty' => false, // nie usuwaj pustych atrybutow typu <a></a>
Expand Down
1 change: 1 addition & 0 deletions resources/views/emails/layout.twig
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
.img-smile {
display: inline;
width: 16px;
}
h1, h2, h3, h4, h5, h6 {
Expand Down

0 comments on commit c0a0776

Please sign in to comment.