From dd4b3d9ebb85c9bc8138212fd7cb207ab154f626 Mon Sep 17 00:00:00 2001 From: Thomas Lange Date: Mon, 19 Jul 2021 17:50:21 +0200 Subject: Add and use new parser/transformer classes Classes: * Parsers\ArgumentParser * Parsers\EmoticonParser * Parsers\MarkdownParser Interfaces: * Parsers\ParserInterface --- core/functions.php | 108 +++++++---------------------- core/namespace/Parsers/ArgumentParser.php | 30 ++++++++ core/namespace/Parsers/EmoticonParser.php | 72 +++++++++++++++++++ core/namespace/Parsers/MarkdownParser.php | 37 ++++++++++ core/namespace/Parsers/ParserInterface.php | 7 ++ 5 files changed, 171 insertions(+), 83 deletions(-) create mode 100644 core/namespace/Parsers/ArgumentParser.php create mode 100644 core/namespace/Parsers/EmoticonParser.php create mode 100644 core/namespace/Parsers/MarkdownParser.php create mode 100644 core/namespace/Parsers/ParserInterface.php diff --git a/core/functions.php b/core/functions.php index ff52e0c..547f84a 100644 --- a/core/functions.php +++ b/core/functions.php @@ -8,6 +8,10 @@ use ORM\Entities\User; use Template\Template as Template; use Template\Factory as TemplateFactory; +use Parsers\ArgumentParser; +use Parsers\EmoticonParser; +use Parsers\MarkdownParser; + #=============================================================================== # Create generic pagination template #=============================================================================== @@ -89,28 +93,34 @@ function generateUserItemTemplate(User $User): Template { # Helper function to reduce duplicate code #=============================================================================== function generateItemTemplateData(EntityInterface $Entity): array { - $ATTR = $Entity->getAll(['password']); - $ATTR = array_change_key_case($ATTR, CASE_UPPER); + $ArgumentParser = new ArgumentParser; + $MarkdownParser = new MarkdownParser; + + $attribute = $Entity->getAll(['password']); + $attribute = array_change_key_case($attribute, CASE_UPPER); + + $text = parseContentTags($Entity->get('body')); + $arguments = $ArgumentParser->parse($Entity->get('argv') ?? ''); - $preparsed = parseContentTags($Entity->get('body')); + $images = $MarkdownParser->parse($text)['img']['src'] ?? []; + $images = array_map('htmlentities', $images); return [ 'URL' => Application::getEntityURL($Entity), 'GUID' => generatePseudoGUID($Entity), - 'ARGV' => parseArguments($Entity->get('argv')), - - 'ATTR' => $ATTR, + 'ARGV' => $arguments, + 'ATTR' => $attribute, 'PREV' => FALSE, 'NEXT' => FALSE, 'FILE' => [ - 'LIST' => getMarkdownImageURLs($preparsed), + 'LIST' => $images, ], 'BODY' => [ - 'TEXT' => function() use($preparsed) { - return $preparsed; + 'TEXT' => function() use($text) { + return $text; }, 'HTML' => function() use($Entity) { return parseEntityContent($Entity); @@ -188,50 +198,15 @@ function parseContentTags(string $text): string { # Parse entity content #=============================================================================== function parseEntityContent(EntityInterface $Entity): string { - $Parsedown = new Parsedown(); - $Parsedown->setUrlsLinked(FALSE); - $text = parseContentTags($Entity->get('body')); if(Application::get('WRAP_EMOTICONS')) { - $text = parseUnicodeEmoticons($text); - } - - return $Parsedown->text($text); -} - -#=============================================================================== -# Extract Markdown formatted image URLs -#=============================================================================== -function getMarkdownImageURLs(string $text): array { - $pattern = '#\!\[(.*)\][ ]?(?:\n[ ]*)?\((.*)(\s[\'"](.*)[\'"])?\)#U'; - $content = parseContentTags($text); - - if(preg_match_all($pattern, $content, $matches)) { - return array_map('htmlentities', $matches[2]); - } - - return []; -} - -#=============================================================================== -# Parse argument string to array -#=============================================================================== -function parseArguments(?string $argv): array { - if($argv) { - foreach(explode('|', $argv) as $delimeter) { - $part = explode('=', $delimeter); - - $argumentK = $part[0] ?? NULL; - $argumentV = $part[1] ?? TRUE; - - if(preg_match('#^[[:word:]]+$#', $argumentK)) { - $arguments[strtoupper($argumentK)] = $argumentV; - } - } + $EmoticonParser = new EmoticonParser; + $text = $EmoticonParser->transform($text); } - return $arguments ?? []; + $MarkdownParser = new MarkdownParser; + return $MarkdownParser->transform($text); } #=============================================================================== @@ -261,43 +236,10 @@ function parseDatetime($datetime, $format): string { } #=============================================================================== -# Get unicode emoticons with their corresponding explanation +# Get emoticons with their explanations #=============================================================================== function getUnicodeEmoticons(): array { - $Language = Application::getLanguage(); - - return [ - html_entity_decode('😊') => $Language->text('emoticon_1F60A'), - html_entity_decode('😞') => $Language->text('emoticon_1F61E'), - html_entity_decode('😃') => $Language->text('emoticon_1F603'), - html_entity_decode('😛') => $Language->text('emoticon_1F61B'), - html_entity_decode('😲') => $Language->text('emoticon_1F632'), - html_entity_decode('😉') => $Language->text('emoticon_1F609'), - html_entity_decode('😢') => $Language->text('emoticon_1F622'), - html_entity_decode('😐') => $Language->text('emoticon_1F610'), - html_entity_decode('😵') => $Language->text('emoticon_1F635'), - html_entity_decode('😒') => $Language->text('emoticon_1F612'), - html_entity_decode('😎') => $Language->text('emoticon_1F60E'), - html_entity_decode('😟') => $Language->text('emoticon_1F61F'), - html_entity_decode('😂') => $Language->text('emoticon_1F602'), - html_entity_decode('😄') => $Language->text('emoticon_1F604'), - ]; -} - -#=============================================================================== -# Wrap emoticons in element with "title" attribute for explanation -#=============================================================================== -function parseUnicodeEmoticons($string): string { - $emoticon_data = getUnicodeEmoticons(); - $emoticon_list = array_keys($emoticon_data); - $emoticon_list = implode('|', $emoticon_list); - - return preg_replace_callback("#($emoticon_list)#", function($matches) - use($emoticon_data) { - $emoticon = $matches[1]; - $explanation = $emoticon_data[$emoticon]; - return sprintf('%s', $explanation, $emoticon); - }, $string); + return (new EmoticonParser)->getEmoticons(); } #=============================================================================== diff --git a/core/namespace/Parsers/ArgumentParser.php b/core/namespace/Parsers/ArgumentParser.php new file mode 100644 index 0000000..ab32fe1 --- /dev/null +++ b/core/namespace/Parsers/ArgumentParser.php @@ -0,0 +1,30 @@ +Language = Application::getLanguage(); + } + + #=========================================================================== + # Get emoticons with their explanations + #=========================================================================== + public function getEmoticons(): array { + $Language = $this->Language; + + return [ + html_entity_decode('😊') => $Language->text('emoticon_1F60A'), + html_entity_decode('😞') => $Language->text('emoticon_1F61E'), + html_entity_decode('😃') => $Language->text('emoticon_1F603'), + html_entity_decode('😛') => $Language->text('emoticon_1F61B'), + html_entity_decode('😲') => $Language->text('emoticon_1F632'), + html_entity_decode('😉') => $Language->text('emoticon_1F609'), + html_entity_decode('😢') => $Language->text('emoticon_1F622'), + html_entity_decode('😐') => $Language->text('emoticon_1F610'), + html_entity_decode('😵') => $Language->text('emoticon_1F635'), + html_entity_decode('😒') => $Language->text('emoticon_1F612'), + html_entity_decode('😎') => $Language->text('emoticon_1F60E'), + html_entity_decode('😟') => $Language->text('emoticon_1F61F'), + html_entity_decode('😂') => $Language->text('emoticon_1F602'), + html_entity_decode('😄') => $Language->text('emoticon_1F604'), + ]; + } + + #=========================================================================== + # Parse occurring emoticons (*without* duplicates) + #=========================================================================== + public function parse(string $text): array { + $emoticon_data = $this->getEmoticons(); + $emoticon_list = array_keys($emoticon_data); + $emoticon_list = implode('|', $emoticon_list); + + preg_match_all("#($emoticon_list)#", $text, $matches); + + foreach($matches[1] as $emoticon) { + $emoticons[$emoticon] = $emoticon_data[$emoticon]; + } + + return $emoticons ?? []; + } + + #=========================================================================== + # Wrap emoticons inside a titled span element + #=========================================================================== + public function transform(string $text): string { + $emoticon_data = $this->getEmoticons(); + $emoticon_list = array_keys($emoticon_data); + $emoticon_list = implode('|', $emoticon_list); + + # TODO: Do not wrap emoticons if they occur inside a code block + return preg_replace_callback("#($emoticon_list)#", function($matches) + use($emoticon_data) { + $emoticon = $matches[1]; + $explanation = $emoticon_data[$emoticon]; + return sprintf('%s', $explanation, $emoticon); + }, $text); + } +} diff --git a/core/namespace/Parsers/MarkdownParser.php b/core/namespace/Parsers/MarkdownParser.php new file mode 100644 index 0000000..27a18ad --- /dev/null +++ b/core/namespace/Parsers/MarkdownParser.php @@ -0,0 +1,37 @@ +Parsedown = new Parsedown(); + $this->Parsedown->setUrlsLinked(FALSE); + } + + #=========================================================================== + # Parse Markdown (currently only images) + #=========================================================================== + public function parse(string $text): array { + $image = '#\!\[(.*)\]\((.*)(?:\s[\'"](.*)[\'"])?\)#U'; + + if(preg_match_all($image, $text, $matches)) { + $data['img']['src'] = $matches[2]; + $data['img']['alt'] = $matches[1]; + $data['img']['title'] = $matches[3]; + } + + return $data ?? []; + } + + #=========================================================================== + # Transform Markdown to HTML + #=========================================================================== + public function transform(string $text): string { + return $this->Parsedown->text($text); + } +} diff --git a/core/namespace/Parsers/ParserInterface.php b/core/namespace/Parsers/ParserInterface.php new file mode 100644 index 0000000..8dd94e2 --- /dev/null +++ b/core/namespace/Parsers/ParserInterface.php @@ -0,0 +1,7 @@ +