From d1d7d61b4e115918203b3f1954055fd708dccab1 Mon Sep 17 00:00:00 2001 From: trendschau Date: Tue, 19 Oct 2021 22:30:18 +0200 Subject: [PATCH] Version 1.5.1: Shortcodes, public form generator, improved textarea for code --- .../ControllerAuthorArticleApi.php | 2 +- .../Controllers/ControllerAuthorBlockApi.php | 4 +- .../Controllers/ControllerFrontendWebsite.php | 2 +- system/Events/OnShortcodeFound.php | 14 + system/Extensions/ParsedownExtension.php | 285 +++++++++++------- system/Models/Fields.php | 13 +- system/Plugin.php | 9 +- system/author/css/style.css | 9 +- system/author/css/visiblecontrol.woff | Bin 0 -> 980 bytes system/author/css/visiblecontrol.woff2 | Bin 0 -> 536 bytes system/author/partials/fields.twig | 11 +- system/author/settings/themes.twig | 2 + 12 files changed, 238 insertions(+), 113 deletions(-) create mode 100644 system/Events/OnShortcodeFound.php create mode 100644 system/author/css/visiblecontrol.woff create mode 100644 system/author/css/visiblecontrol.woff2 diff --git a/system/Controllers/ControllerAuthorArticleApi.php b/system/Controllers/ControllerAuthorArticleApi.php index 9e9c432..52e9e4f 100644 --- a/system/Controllers/ControllerAuthorArticleApi.php +++ b/system/Controllers/ControllerAuthorArticleApi.php @@ -1076,7 +1076,7 @@ class ControllerAuthorArticleApi extends ControllerAuthor } # initialize parsedown extension - $parsedown = new ParsedownExtension($this->uri->getBaseUrl()); + $parsedown = new ParsedownExtension($this->uri->getBaseUrl(), $settings = false, $this->c->dispatcher); # fix footnotes in parsedown, might break with complicated footnotes $parsedown->setVisualMode(); diff --git a/system/Controllers/ControllerAuthorBlockApi.php b/system/Controllers/ControllerAuthorBlockApi.php index 163c10f..8ce7faf 100644 --- a/system/Controllers/ControllerAuthorBlockApi.php +++ b/system/Controllers/ControllerAuthorBlockApi.php @@ -67,7 +67,7 @@ class ControllerAuthorBlockApi extends ControllerAuthor } # initialize parsedown extension - $parsedown = new ParsedownExtension($this->uri->getBaseUrl()); + $parsedown = new ParsedownExtension($this->uri->getBaseUrl(), $settings = false, $this->c->dispatcher); # if content is not an array, then transform it if(!is_array($pageMarkdown)) @@ -265,7 +265,7 @@ class ControllerAuthorBlockApi extends ControllerAuthor } # initialize parsedown extension - $parsedown = new ParsedownExtension($this->uri->getBaseUrl()); + $parsedown = new ParsedownExtension($this->uri->getBaseUrl(), $settings = false, $this->c->dispatcher); $parsedown->setVisualMode(); # if content is not an array, then transform it diff --git a/system/Controllers/ControllerFrontendWebsite.php b/system/Controllers/ControllerFrontendWebsite.php index 553de55..427d49e 100644 --- a/system/Controllers/ControllerFrontendWebsite.php +++ b/system/Controllers/ControllerFrontendWebsite.php @@ -220,7 +220,7 @@ class ControllerFrontendWebsite extends ControllerShared $itemUrl = isset($item->urlRel) ? $item->urlRel : false; /* initialize parsedown */ - $parsedown = new ParsedownExtension($this->base_url, $this->settings); + $parsedown = new ParsedownExtension($this->base_url, $this->settings, $this->c->dispatcher); /* set safe mode to escape javascript and html in markdown */ $parsedown->setSafeMode(true); diff --git a/system/Events/OnShortcodeFound.php b/system/Events/OnShortcodeFound.php new file mode 100644 index 0000000..5767c2f --- /dev/null +++ b/system/Events/OnShortcodeFound.php @@ -0,0 +1,14 @@ +settings = $settings; + $this->dispatcher = $dispatcher; + # show anchor next to headline? $this->showAnchor = isset($settings['headlineanchors']) ? $settings['headlineanchors'] : false; @@ -34,6 +38,7 @@ class ParsedownExtension extends \ParsedownExtra $this->InlineTypes['\\'][] = 'Math'; $this->InlineTypes['$'][] = 'Math'; + $this->InlineTypes['['][] = 'Shortcode'; $this->inlineMarkerList .= '\\'; $this->inlineMarkerList .= '$'; @@ -42,7 +47,10 @@ class ParsedownExtension extends \ParsedownExtra $this->visualMode = false; - # identify Table Of contents after footnotes and links + # identify Shortcodes after footnotes and links + array_unshift($this->BlockTypes['['], 'Shortcode'); + + # identify Table Of contents after footnotes and links and shortcodes array_unshift($this->BlockTypes['['], 'TableOfContents'); } @@ -715,6 +723,176 @@ class ParsedownExtension extends \ParsedownExtra { return $Block; } + + protected function blockShortcode($Line) + { + if ($this->dispatcher && preg_match('/^\[:.*:\]/', $Line['text'], $matches)) + { + return $this->createShortcodeArray($matches); + } + else + { + return; + } + } + + protected function inlineShortcode($Excerpt) + { + $remainder = $Excerpt['text']; + + if ($this->dispatcher && preg_match('/\[:.*:\]/', $remainder, $matches)) + { + return $this->createShortcodeArray($matches); + } + else + { + return; + } + } + + protected function createShortcodeArray($matches) + { + $shortcodeString = substr($matches[0], 2, -2); + $shortcodeArray = explode(' ', $shortcodeString, 2); + $shortcode = []; + + $shortcode['name'] = $shortcodeArray[0]; + $shortcode['params'] = false; + + # are there params? + if(isset($shortcodeArray[1])) + { + $shortcode['params'] = []; + + # see: https://www.thetopsites.net/article/58136180.shtml + $pattern = '/(\\w+)\s*=\\s*("[^"]*"|\'[^\']*\'|[^"\'\\s>]*)/'; + preg_match_all($pattern, $shortcodeArray[1], $attributes, PREG_SET_ORDER); + + foreach($attributes as $attribute) + { + if(isset($attribute[1]) && isset($attribute[2])) + { + $shortcode['params'][$attribute[1]] = trim($attribute[2], " \""); + } + } + } + + $html = $this->dispatcher->dispatch('onShortcodeFound', new OnShortcodeFound($shortcode))->getData(); + + # if no shortcode has been processed, add the original string + if(is_array($html) OR is_object($html)) + { + $html = 'No shortcode found.'; + } + + return array( + 'element' => array( + 'rawHtml' => $html, + 'allowRawHtmlInSafeMode' => true, + ), + 'extent' => strlen($matches[0]), + ); + } + + protected function inlineLink($Excerpt) + { + $Element = array( + 'name' => 'a', + 'handler' => array( + 'function' => 'lineElements', + 'argument' => null, + 'destination' => 'elements', + ), + 'nonNestables' => array('Url', 'Link'), + 'attributes' => array( + 'href' => null, + 'title' => null, + ), + ); + + $extent = 0; + + $remainder = $Excerpt['text']; + + if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) + { + $Element['handler']['argument'] = $matches[1]; + + $extent += strlen($matches[0]); + + $remainder = substr($remainder, $extent); + } + else + { + return; + } + + if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) + { + # start typemill: if relative link or media-link + $href = $matches[1]; + if($href[0] == '/') + { + $href = $this->baseUrl . $href; + } + elseif(substr( $href, 0, 6 ) === "media/") + { + $href = $this->baseUrl . '/' . $href; + } + # end typemill + + $Element['attributes']['href'] = $href; + + if (isset($matches[2])) + { + $Element['attributes']['title'] = substr($matches[2], 1, - 1); + } + + $extent += strlen($matches[0]); + } + else + { + if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) + { + $definition = strlen($matches[1]) ? $matches[1] : $Element['handler']['argument']; + $definition = strtolower($definition); + + $extent += strlen($matches[0]); + } + else + { + $definition = strtolower($Element['handler']['argument']); + } + + if ( ! isset($this->DefinitionData['Reference'][$definition])) + { + return; + } + + $Definition = $this->DefinitionData['Reference'][$definition]; + + $Element['attributes']['href'] = $Definition['url']; + $Element['attributes']['title'] = $Definition['title']; + } + + $Link = array( + 'extent' => $extent, + 'element' => $Element, + ); + + # Parsedown Extra + $remainder = $Link !== null ? substr($Excerpt['text'], $Link['extent']) : ''; + + if (preg_match('/^[ ]*{('.$this->regexAttribute.'+)}/', $remainder, $matches)) + { + $Link['element']['attributes'] += $this->parseAttributeData($matches[1]); + + $Link['extent'] += strlen($matches[0]); + } + + return $Link; + + } # advanced attribute data, check parsedown extra plugin: https://github.com/tovic/parsedown-extra-plugin protected function parseAttributeData($text) { @@ -771,8 +949,6 @@ class ParsedownExtension extends \ParsedownExtra protected $regexAttribute = '(?:[#.][-\w:\\\]+[ ]*|[-\w:\\\]+(?:=(?:["\'][^\n]*?["\']|[^\s]+)?)?[ ]*)'; - - # ++ # blocks that belong to a "magneticType" would "merge" if they are next to each other protected $magneticTypes = array('DefinitionList', 'Footnote'); @@ -1050,105 +1226,4 @@ class ParsedownExtension extends \ParsedownExtra } return false; } - - - protected function inlineLink($Excerpt) - { - $Element = array( - 'name' => 'a', - 'handler' => array( - 'function' => 'lineElements', - 'argument' => null, - 'destination' => 'elements', - ), - 'nonNestables' => array('Url', 'Link'), - 'attributes' => array( - 'href' => null, - 'title' => null, - ), - ); - - $extent = 0; - - $remainder = $Excerpt['text']; - - if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) - { - $Element['handler']['argument'] = $matches[1]; - - $extent += strlen($matches[0]); - - $remainder = substr($remainder, $extent); - } - else - { - return; - } - - if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) - { - # start typemill: if relative link or media-link - $href = $matches[1]; - if($href[0] == '/') - { - $href = $this->baseUrl . $href; - } - elseif(substr( $href, 0, 6 ) === "media/") - { - $href = $this->baseUrl . '/' . $href; - } - # end typemill - - $Element['attributes']['href'] = $href; - - if (isset($matches[2])) - { - $Element['attributes']['title'] = substr($matches[2], 1, - 1); - } - - $extent += strlen($matches[0]); - } - else - { - if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) - { - $definition = strlen($matches[1]) ? $matches[1] : $Element['handler']['argument']; - $definition = strtolower($definition); - - $extent += strlen($matches[0]); - } - else - { - $definition = strtolower($Element['handler']['argument']); - } - - if ( ! isset($this->DefinitionData['Reference'][$definition])) - { - return; - } - - $Definition = $this->DefinitionData['Reference'][$definition]; - - $Element['attributes']['href'] = $Definition['url']; - $Element['attributes']['title'] = $Definition['title']; - } - - $Link = array( - 'extent' => $extent, - 'element' => $Element, - ); - - # Parsedown Extra - $remainder = $Link !== null ? substr($Excerpt['text'], $Link['extent']) : ''; - - if (preg_match('/^[ ]*{('.$this->regexAttribute.'+)}/', $remainder, $matches)) - { - $Link['element']['attributes'] += $this->parseAttributeData($matches[1]); - - $Link['extent'] += strlen($matches[0]); - } - - return $Link; - - } } \ No newline at end of file diff --git a/system/Models/Fields.php b/system/Models/Fields.php index 7bfeb8c..0f7b36d 100644 --- a/system/Models/Fields.php +++ b/system/Models/Fields.php @@ -89,13 +89,24 @@ class Fields } # Now prepopulate the field object with the value */ - if($field->getType() == "textarea" || $field->getType() == "paragraph") + if($field->getType() == "textarea") { if($userValue) { $field->setContent($userValue); } } + elseif($field->getType() == 'paragraph') + { + if(isset($fieldConfigurations['value'])) + { + $field->setContent($fieldConfigurations['value']); + } + if($userValue) + { + $field->setContent($userValue); + } + } elseif($field->getType() == "checkbox") { # checkboxes need a special treatment, because field does not exist in settings if unchecked by user diff --git a/system/Plugin.php b/system/Plugin.php index 933177b..c13ad28 100644 --- a/system/Plugin.php +++ b/system/Plugin.php @@ -202,9 +202,10 @@ abstract class Plugin implements EventSubscriberInterface $fieldsModel = new Fields(); $settings = $this->getSettings(); + $form = false; $pluginDefinitions = \Typemill\Settings::getObjectSettings('plugins', $pluginName); - if(isset($settings['plugins'][$pluginName]['publicformdefinitions'])) + if(isset($settings['plugins'][$pluginName]['publicformdefinitions']) && $settings['plugins'][$pluginName]['publicformdefinitions'] != '') { $arrayFromYaml = \Symfony\Component\Yaml\Yaml::parse($settings['plugins'][$pluginName]['publicformdefinitions']); $pluginDefinitions['public']['fields'] = $arrayFromYaml; @@ -214,6 +215,12 @@ abstract class Plugin implements EventSubscriberInterface $captchaoptions = isset($settings['plugins'][$pluginName]['captchaoptions']) ? $settings['plugins'][$pluginName]['captchaoptions'] : false; $recaptcha = isset($settings['plugins'][$pluginName]['recaptcha']) ? $settings['plugins'][$pluginName]['recaptcha_webkey'] : false; + if($captchaoptions == 'disabled') + { + # in case a captcha has failed on another page like login, the captcha-session must be deleted, otherwise it will not pass the security middleware + unset($_SESSION['captcha']); + } + $fieldsModel = new Fields(); if(isset($pluginDefinitions['public']['fields'])) diff --git a/system/author/css/style.css b/system/author/css/style.css index cb41b45..abc6512 100644 --- a/system/author/css/style.css +++ b/system/author/css/style.css @@ -1,3 +1,10 @@ +@font-face { + font-family: 'visiblecontrol'; + src: url('visiblecontrol.woff') format('woff'), + url('visiblecontrol.woff2') format('woff2'); + unicode-range: U+0020; +} + /********************** * TRANSITION * **********************/ @@ -1349,7 +1356,7 @@ ul.cardInfo{ background-color: #FFF; } textarea.codearea, .cardField textarea.codearea{ - font-family: monospace; + font-family: visiblecontrol,monospace; background: #333; color: #fff; } diff --git a/system/author/css/visiblecontrol.woff b/system/author/css/visiblecontrol.woff new file mode 100644 index 0000000000000000000000000000000000000000..f338a985ea3262cb9afeefd005e45ea5665da7fd GIT binary patch literal 980 zcmXT-cXMN4WB>x@D-66Knsoz+#0K2lLVSVhb^zt1fmmk3(Zgl#F0O7su^B+V92jdd zaQO%88!<32E&=jwfH*8cII%7{H?aUH_5sLu2GU*(L2UEV6N`aj%oBiO93cGvKLc}m zPGuSc1Cs-g9|FQF|Gc!#NKH%u>M;QFf#x!p$v%5_Ape4uA>qcsJt7`P2GliBm?snhESlzVEtj~2?+_TO3Bw|^6>N&3C#LwfSFmC zSt!Bf8OxHL%NR6S*;ubd)~6f3N$_=E!N_2Kki&<0DT5}^2nMEAK)jOSA;_$RgtUeP zNj5h&fda-)5(jI<*mxDrvMrI6oYA1u`v3nytpi{F9}oEIaNxu-hUW%NAx4G^nA|!< z4@)vI%y`1~5oDYg7;1qG2AR)X$C}2#%)rjTAgm~;Xb!}h%%Oi)Co}c`Eo4pmH7l8A zAxIY^!$YQQ#%0U~;P^HY6Jb+UQZr$c4zRY;)UaYUunw@Y3IO?cYM*b`VFLlT`9juP zwy^Aasm1cXJN9HZi_>*W$B&FcK1v2=Clu8+ZTfP{GPk`N?gI0UE5FgSr!D;I{LPT z-qZN^y4F-i`|X>Mz*U#D=G@A*_bTy!DLdS^a>i3KSPf2lyizW=w4CYy^hxI&cnT1m*)KaGvA=hcqaR k8G)h83?x~=Ar2%U@tDHUwA%ZMrNb9!`eSe`VC!W70AKDaDgXcg literal 0 HcmV?d00001 diff --git a/system/author/css/visiblecontrol.woff2 b/system/author/css/visiblecontrol.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..f097521c2982cd4379bf7958e6f9fe7cd0eb9f06 GIT binary patch literal 536 zcmXT-cQayOWB>vt2?kye&ANesf$=Cr48%tT_HJ$=zA{pBY+(#dUV zD$D{b3arf`>{`;tSp=`nDm+oAHskr6>CzdWo27*hPvTg$wZ6LSy5lbjts*u|N149r4I^8*67u zW>(|W41ofX#1)+BZ}+_XUH3yrE%js9CuJ|AOs500UmwnT@b}^J#asU~HL{f`az=`A zskq3sO)3hiY?J7D`N?|f6*r~^hKAIss{{ field.getContent() }} + {% if field.name == 'publicformdefinitions' %} + + + + + {% else %} + + + + {% endif %} {% elseif field.type == 'paragraph' %} diff --git a/system/author/settings/themes.twig b/system/author/settings/themes.twig index 69b165f..c2189c5 100644 --- a/system/author/settings/themes.twig +++ b/system/author/settings/themes.twig @@ -85,6 +85,8 @@ {% endfor %} + +