From f49e9a8890dfea0308b786544e59af37d9226c45 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sun, 25 Sep 2022 16:21:57 -0600 Subject: [PATCH 01/19] Initial work on implementing a RichEditor snippets button --- Plugin.php | 29 ++++++++ assets/js/froala-snippets.js | 132 +++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 assets/js/froala-snippets.js diff --git a/Plugin.php b/Plugin.php index 0db46e7..2e469f1 100644 --- a/Plugin.php +++ b/Plugin.php @@ -227,6 +227,35 @@ public function boot() Classes\Page::class, ]; }); + + BaseBackendController::extend(function ($controller) { + $user = BackendAuth::getUser(); + if (!$user || !$user->hasAccess('winter.pages.access_snippets')) { + return; + } + + // Add the AJAX handlers required for snippet inspector properties + // to function on all backend controllers + $controller->addDynamicMethod('onGetInspectorConfiguration', function() { + return (new StaticPage)->onGetInspectorConfiguration(); + }); + $controller->addDynamicMethod('onGetSnippetNames', function() { + return (new StaticPage)->onGetSnippetNames(); + }); + $controller->addDynamicMethod('onInspectableGetOptions', function() { + return (new StaticPage)->onInspectableGetOptions(); + }); + + FroalaFormWidget::extend(function ($widget) { + // Adds default base CSS/JS for snippets + $widget->addCss('/plugins/winter/pages/assets/css/pages.css', 'Winter.Pages'); + $widget->addJs('/plugins/winter/pages/assets/js/pages-page.js', 'Winter.Pages'); + $widget->addJs('/plugins/winter/pages/assets/js/pages-snippets.js', 'Winter.Pages'); + + // Adds custom assets for the Froala snippet button + $widget->addJs('/plugins/winter/pages/assets/js/froala-snippets.js', 'Winter.Pages'); + }); + }); } /** diff --git a/assets/js/froala-snippets.js b/assets/js/froala-snippets.js new file mode 100644 index 0000000..cf91511 --- /dev/null +++ b/assets/js/froala-snippets.js @@ -0,0 +1,132 @@ +(function ($) { + // Adds snippets to the default Froala buttons + // Places it after the quote button to keep dropdowns together + $.wn.richEditorButtons.splice(3, 0, 'snippets'); + + // Define a dropdown button. + $.FroalaEditor.RegisterCommand('snippets', { + // Button title. + title: 'Snippets', + + // Mark the button as a dropdown. + type: 'dropdown', + + // Specify the icon for the button. + // If this option is not specified, the button name will be used. + icon: '', + + // The dropdown HTML + html: function() { + if (!$.wn.snippets) { + return '
No snippets are currently defined.
'; + } + + var html = ''; + }, + + // Save the dropdown action into undo stack. + undo: true, + + // Focus inside the editor before callback. + focus: true, + + // Refresh the button state after the callback. + refreshAfterCallback: true, + + // Callback. + callback: function (cmd, val, params) { + var options = $.wn.snippets[val]; + + if (options) { + // Get editor element. OC2's richeditor has 2 nested data-control=richeditor, we want the outer one + var $editor = this.$el.parents('[data-control="richeditor"]:not([data-richeditor-vue])'); + + var $snippetNode = $('
 
'); + + if (options.component) { + $snippetNode.attr({ + 'data-component': options.component, + 'data-inspector-class': options.component + }) + + // If a component-based snippet was added, make sure that + // its code is unique, as it will be used as a component + // alias. + + /* + // Init a new snippet manager + + // Below code reattaches the inspector event, causing duplicate inspector options + // Until I can figure a solution, I have copied the code to this file... + + var snippetManager = new $.wn.pages.snippetManager; + options.snippet = snippetManager.generateUniqueComponentSnippetCode(options.component, options.snippet, $editor.parent()) + */ + + options.snippet = generateUniqueComponentSnippetCode(options.component, options.snippet, $editor.parent()); + } + + $snippetNode.attr({ + 'data-snippet': options.snippet, + 'data-name': options.name, + 'tabindex': '0', + 'draggable': 'true', + 'data-ui-block': 'true' + }) + + $snippetNode.addClass('fr-draggable'); + + // Insert the content + this.figures.insert($snippetNode); + } + + } + }); + + generateUniqueComponentSnippetCode = function(componentClass, originalCode, $pageForm) { + var updatedCode = originalCode, + counter = 1, + snippetFound = false + + do { + snippetFound = false + + $('[data-control="richeditor"] textarea', $pageForm).each(function() { + var $textarea = $(this), + $codeDom = $('
' + $textarea.val() + '
') + + if ($codeDom.find('[data-snippet="'+updatedCode+'"][data-component]').length > 0) { + snippetFound = true + updatedCode = originalCode + counter + counter++ + + return false + } + }) + + } while (snippetFound) + + return updatedCode + }; + + + /** + * Because the pages-snippets.js is injected after the richeditor script, it will register its + * initialization hooks too late. Here we need to force initialization in order to work with forms + * that are displayed on page load (i.e. Winter.Blog). + */ + $(document).ready(function() { + var $editor = $('[data-control="richeditor"]:not([data-richeditor-vue])'); + + if ($.wn.pagesPage && !window.location.pathname.includes('winter/pages')) { + $.wn.pagesPage.snippetManager.initSnippets($editor); + } + }); + +})(jQuery); \ No newline at end of file From a179118a5dc059171e5e7f76b1e8109a1aa61b99 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Wed, 15 Feb 2023 12:43:42 -0500 Subject: [PATCH 02/19] - Add SnippetLoader class - Add parser method to Snippet class --- classes/Snippet.php | 39 +++++++++ classes/SnippetLoader.php | 180 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+) create mode 100644 classes/SnippetLoader.php diff --git a/classes/Snippet.php b/classes/Snippet.php index cf16778..634f40c 100644 --- a/classes/Snippet.php +++ b/classes/Snippet.php @@ -4,6 +4,7 @@ use Cache; use Cms\Classes\ComponentHelpers; use Cms\Classes\Controller as CmsController; +use Cms\Classes\Theme; use Config; use Event; use Lang; @@ -464,6 +465,44 @@ protected static function dropDownOptionsToString($optionsArray) return implode(' | ', $result); } + /** + * Parse content to render snippets + * + * @param string $markup + * @param array $params + * @return string + * @throws ApplicationException + * @throws CmsException + * @throws SystemException + */ + public static function parse($markup, $params = []) + { + $theme = Theme::getActiveTheme(); + $controller = CmsController::getController(); + + $map = self::extractSnippetsFromMarkup($markup, $theme); + + foreach ($map as $snippetDeclaration => $snippetInfo) { + $snippetCode = $snippetInfo['code']; + + if (isset($snippetInfo['component'])) { + // The snippet is a component registered as a snippet + $snippetAlias = SnippetLoader::registerComponentSnippet($snippetInfo); + $generatedMarkup = $controller->renderComponent($snippetAlias, $params); + } + else { + // The snippet is a partial + $partialName = SnippetLoader::registerPartialSnippet($snippetInfo); + $generatedMarkup = $controller->renderPartial($partialName, array_merge($params, $snippetInfo['properties'])); + } + + $pattern = preg_quote($snippetDeclaration); + $markup = mb_ereg_replace($pattern, $generatedMarkup, $markup); + } + + return $markup; + } + protected static function extractSnippetsFromMarkup($markup, $theme) { $map = []; diff --git a/classes/SnippetLoader.php b/classes/SnippetLoader.php new file mode 100644 index 0000000..bdb16bd --- /dev/null +++ b/classes/SnippetLoader.php @@ -0,0 +1,180 @@ +getPartialSnippetMap($theme); + $snippetCode = $snippetInfo['code']; + + if (!array_key_exists($snippetCode, $partialSnippetMap)) { + throw new ApplicationException(sprintf('Partial for the snippet %s is not found', $snippetCode)); + } + + return $partialSnippetMap[$snippetCode]; + } + + /** + * Save to the cache the component snippets loaded for this page. + * Should be called once after all snippets are loaded to avoid multiple serializations. + * + * @param CmsPage $page The CMS Page to which the cache should be attached + */ + public static function saveCachedSnippets(CmsPage $page) + { + if (empty(self::$pageSnippetsCache)) { + return; + } + + Cache::put( + self::getMapCacheKey($page), + serialize(self::$pageSnippetsCache), + Carbon::now()->addDay() + ); + } + + /** + * Register back to the current controller all component snippets previously saved. + * This make AJAX handlers of these components available. + * + * @param CmsController $cmsController + * @param CmsPage $page The CMS page for which to load the cache + */ + public static function restoreComponentSnippetsFromCache($cmsController, CmsPage $page) + { + $componentSnippets = self::fetchCachedSnippets($page); + + foreach ($componentSnippets as $componentInfo) { + try { + self::attachComponentSnippetToController($componentInfo, $cmsController); + } catch (\Exception $e) { + } + } + } + + /** + * Attach a component-based snippet to a controller. + * + * Register the component if it is not defined yet. + * This is required because not all component snippets are registered as components, + * but it's safe to register them in render-time. + * + * If asked, the run lifecycle events of the component can be run. This is required for + * component that are added late in the page execution like with the twig filter. + * + * @param array $componentInfo + * @param CmsController $controller + * @param bool $triggerRun Should the run events of the component lifecycle be triggered? + * @throws SystemException + * @throws CmsException + */ + protected static function attachComponentSnippetToController($componentInfo, CmsController $controller, $triggerRun = false) + { + $componentManager = ComponentManager::instance(); + + if (!$componentManager->hasComponent($componentInfo['component'])) { + $componentManager->registerComponent($componentInfo['component'], $componentInfo['code']); + } + + $component = $controller->addComponent( + $componentInfo['component'], + $componentInfo['code'], + $componentInfo['properties'] + ); + + if ($triggerRun) { + if ($component->fireEvent('component.beforeRun', [], true)) { + return; + } + + if ($component->onRun()) { + return; + } + + if ($component->fireEvent('component.run', [], true)) { + return; + } + } + } + + /** + * Store a component snippet to the cache. + * The cache is not actually saved; saveCachedSnippets() must be called to persist the cache. + * + * @param string $alias The unique alias of the snippet + * @param array $snippetInfo The info of the snippet + */ + protected static function cacheSnippet($alias, $snippetInfo) + { + self::$pageSnippetsCache[$alias] = $snippetInfo; + } + + /** + * Get cached component snippets from the cache. + * + * @param CmsPage $page The CMS page for which to load the cache + */ + protected static function fetchCachedSnippets(CmsPage $page) + { + $cache = @unserialize(Cache::get(self::getMapCacheKey($page), serialize([]))); + + return is_array($cache) ? $cache : []; + } + + /** + * Get a cache key for the current page and the current user. + * + * @param CmsPage $page The CMS page for which to load the cache + * @return string + */ + protected static function getMapCacheKey(CmsPage $page) + { + $theme = Theme::getActiveTheme(); + + return 'dynamic-snippet-map-' . md5($theme->getPath() . $page['url'] . Session::getId()); + } +} From c8852f25c8041f69238674f0af7e262f79ae396a Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Wed, 15 Feb 2023 12:44:08 -0500 Subject: [PATCH 03/19] Add parseSnippets twig filter --- Plugin.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Plugin.php b/Plugin.php index 2e469f1..bb12ad6 100644 --- a/Plugin.php +++ b/Plugin.php @@ -265,7 +265,8 @@ public function registerMarkupTags(): array { return [ 'filters' => [ - 'staticPage' => ['Winter\Pages\Classes\Page', 'url'] + 'staticPage' => ['Winter\Pages\Classes\Page', 'url'], + 'parseSnippets' => ['Winter\Pages\Classes\Snippet', 'parse'], ] ]; } From ff8a10b88d4470d9bca666d84c496cc37288b8e5 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Wed, 15 Feb 2023 12:48:27 -0500 Subject: [PATCH 04/19] document why some code was commented out --- classes/SnippetLoader.php | 1 + 1 file changed, 1 insertion(+) diff --git a/classes/SnippetLoader.php b/classes/SnippetLoader.php index bdb16bd..ae073fc 100644 --- a/classes/SnippetLoader.php +++ b/classes/SnippetLoader.php @@ -31,6 +31,7 @@ public static function registerComponentSnippet($snippetInfo) // Make an unique alias for this snippet based on its name and parameters #$snippetInfo['code'] = uniqid($snippetInfo['code'] . '_' . md5(serialize($snippetInfo['properties'])) . '_'); + // the line above was commented out to allow the overriden partials in theme to be used for the component alias self::attachComponentSnippetToController($snippetInfo, $controller, true); self::cacheSnippet($snippetInfo['code'], $snippetInfo); From f8ef7ac8605a24131fd1a606ac5a9f06bca1b085 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 20 Feb 2023 08:01:22 -0500 Subject: [PATCH 05/19] fix namespace Co-authored-by: Ben Thomson --- classes/SnippetLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/SnippetLoader.php b/classes/SnippetLoader.php index ae073fc..68decf1 100644 --- a/classes/SnippetLoader.php +++ b/classes/SnippetLoader.php @@ -1,4 +1,4 @@ - Date: Mon, 20 Feb 2023 08:12:10 -0500 Subject: [PATCH 06/19] replace self:: with static:: --- classes/SnippetLoader.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/classes/SnippetLoader.php b/classes/SnippetLoader.php index 68decf1..94f16cc 100644 --- a/classes/SnippetLoader.php +++ b/classes/SnippetLoader.php @@ -33,8 +33,8 @@ public static function registerComponentSnippet($snippetInfo) #$snippetInfo['code'] = uniqid($snippetInfo['code'] . '_' . md5(serialize($snippetInfo['properties'])) . '_'); // the line above was commented out to allow the overriden partials in theme to be used for the component alias - self::attachComponentSnippetToController($snippetInfo, $controller, true); - self::cacheSnippet($snippetInfo['code'], $snippetInfo); + static::attachComponentSnippetToController($snippetInfo, $controller, true); + static::cacheSnippet($snippetInfo['code'], $snippetInfo); return $snippetInfo['code']; } @@ -67,13 +67,13 @@ public static function registerPartialSnippet($snippetInfo) */ public static function saveCachedSnippets(CmsPage $page) { - if (empty(self::$pageSnippetsCache)) { + if (empty(static::$pageSnippetsCache)) { return; } Cache::put( - self::getMapCacheKey($page), - serialize(self::$pageSnippetsCache), + static::getMapCacheKey($page), + serialize(static::$pageSnippetsCache), Carbon::now()->addDay() ); } @@ -87,11 +87,11 @@ public static function saveCachedSnippets(CmsPage $page) */ public static function restoreComponentSnippetsFromCache($cmsController, CmsPage $page) { - $componentSnippets = self::fetchCachedSnippets($page); + $componentSnippets = static::fetchCachedSnippets($page); foreach ($componentSnippets as $componentInfo) { try { - self::attachComponentSnippetToController($componentInfo, $cmsController); + static::attachComponentSnippetToController($componentInfo, $cmsController); } catch (\Exception $e) { } } @@ -151,7 +151,7 @@ protected static function attachComponentSnippetToController($componentInfo, Cms */ protected static function cacheSnippet($alias, $snippetInfo) { - self::$pageSnippetsCache[$alias] = $snippetInfo; + static::$pageSnippetsCache[$alias] = $snippetInfo; } /** @@ -161,7 +161,7 @@ protected static function cacheSnippet($alias, $snippetInfo) */ protected static function fetchCachedSnippets(CmsPage $page) { - $cache = @unserialize(Cache::get(self::getMapCacheKey($page), serialize([]))); + $cache = @unserialize(Cache::get(static::getMapCacheKey($page), serialize([]))); return is_array($cache) ? $cache : []; } From 6a8c6f563f7d27f22d97bae69ef73995a7b8d39d Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sat, 17 Jun 2023 15:38:41 -0400 Subject: [PATCH 07/19] remove error squelching --- classes/SnippetLoader.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/classes/SnippetLoader.php b/classes/SnippetLoader.php index 94f16cc..b665fbe 100644 --- a/classes/SnippetLoader.php +++ b/classes/SnippetLoader.php @@ -8,6 +8,8 @@ use Cms\Classes\Page as CmsPage; use Cms\Classes\Theme; use Cms\Classes\ComponentManager; +use Exception; +use Flash; use Session; use SystemException; @@ -161,7 +163,13 @@ protected static function cacheSnippet($alias, $snippetInfo) */ protected static function fetchCachedSnippets(CmsPage $page) { - $cache = @unserialize(Cache::get(static::getMapCacheKey($page), serialize([]))); + try { + $cache = unserialize(Cache::get(static::getMapCacheKey($page), serialize([]))); + } catch (Exception $e) { + $error = $e->getMessage(); + trace_log($error); + Flash::error($error); + } return is_array($cache) ? $cache : []; } From 56ee40a26f3db3518930f7c3fd0bc43636d65477 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sat, 17 Jun 2023 23:12:45 -0600 Subject: [PATCH 08/19] Add type hints --- classes/Snippet.php | 92 +++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 62 deletions(-) diff --git a/classes/Snippet.php b/classes/Snippet.php index 634f40c..e14c5d1 100644 --- a/classes/Snippet.php +++ b/classes/Snippet.php @@ -4,6 +4,7 @@ use Cache; use Cms\Classes\ComponentHelpers; use Cms\Classes\Controller as CmsController; +use Cms\Classes\Partial; use Cms\Classes\Theme; use Config; use Event; @@ -53,15 +54,10 @@ class Snippet */ protected $componentObj = null; - public function __construct() - { - } - /** * Initializes the snippet from a CMS partial. - * @param \Cms\Classes\Partial $parital A partial to load the configuration from. */ - public function initFromPartial($partial) + public function initFromPartial(Partial $partial): void { $viewBag = $partial->getViewBag(); @@ -73,10 +69,8 @@ public function initFromPartial($partial) /** * Initializes the snippet from a CMS component information. - * @param string $componentClass Specifies the component class. - * @param string $componentCode Specifies the component code. */ - public function initFromComponentInfo($componentClass, $componentCode) + public function initFromComponentInfo(string $componentClass, string $componentCode): void { $this->code = $componentCode; $this->componentClass = $componentClass; @@ -85,9 +79,8 @@ public function initFromComponentInfo($componentClass, $componentCode) /** * Returns the snippet name. * This method should not be used in the front-end request handling. - * @return string */ - public function getName() + public function getName(): ?string { if ($this->name !== null) { return $this->name; @@ -105,9 +98,8 @@ public function getName() /** * Returns the snippet description. * This method should not be used in the front-end request handling. - * @return string */ - public function getDescription() + public function getDescription(): ?string { if ($this->description !== null) { return $this->description; @@ -125,9 +117,8 @@ public function getDescription() /** * Returns the snippet component class name. * If the snippet is a partial snippet, returns NULL. - * @return string Returns the snippet component class name */ - public function getComponentClass() + public function getComponentClass(): ?string { return $this->componentClass; } @@ -139,19 +130,15 @@ public function getProperties() { if (!$this->componentClass) { return self::parseIniProperties($this->properties); - } - else { + } else { return ComponentHelpers::getComponentsPropertyConfig($this->getComponent(), false, true); } } /** * Returns a list of component definitions declared on the page. - * @param string $pageName Specifies the static page file name (the name of the corresponding content block file). - * @param \Cms\Classes\Theme $theme Specifies a parent theme. - * @return array Returns an array of component definitions */ - public static function listPageComponents($pageName, $theme, $markup) + public static function listPageComponents(string $pageName, Theme $theme, string $markup): array { $map = self::extractSnippetsFromMarkupCached($theme, $pageName, $markup); @@ -175,12 +162,11 @@ public static function listPageComponents($pageName, $theme, $markup) /** * Extends the partial form with Snippet fields. */ - public static function extendPartialForm($formWidget) + public static function extendPartialForm(\Backend\Widgets\Form $formWidget): void { /* * Snippet code field */ - $fieldConfig = [ 'tab' => 'winter.pages::lang.snippet.partialtab', 'type' => 'text', @@ -188,13 +174,11 @@ public static function extendPartialForm($formWidget) 'comment' => 'winter.pages::lang.snippet.code_comment', 'span' => 'left' ]; - $formWidget->tabs['fields']['viewBag[snippetCode]'] = $fieldConfig; /* * Snippet description field */ - $fieldConfig = [ 'tab' => 'winter.pages::lang.snippet.partialtab', 'type' => 'text', @@ -202,13 +186,11 @@ public static function extendPartialForm($formWidget) 'comment' => 'winter.pages::lang.snippet.name_comment', 'span' => 'right' ]; - $formWidget->tabs['fields']['viewBag[snippetName]'] = $fieldConfig; /* * Snippet properties field */ - $fieldConfig = [ 'tab' => 'winter.pages::lang.snippet.partialtab', 'type' => 'datatable', @@ -260,16 +242,14 @@ public static function extendPartialForm($formWidget) ] ] ]; - $formWidget->tabs['fields']['viewBag[snippetProperties]'] = $fieldConfig; } /** * Returns a component corresponding to the snippet. * This method should not be used in the front-end request handling code. - * @return \Cms\Classes\ComponentBase */ - protected function getComponent() + protected function getComponent(): ?\Cms\Classes\ComponentBase { if ($this->componentClass === null) { return null; @@ -290,12 +270,8 @@ protected function getComponent() /** * Parses the static page markup and renders snippets defined on the page. - * @param string $pageName Specifies the static page file name (the name of the corresponding content block file). - * @param \Cms\Classes\Theme $theme Specifies a parent theme. - * @param string $markup Specifies the markup string to process. - * @return string Returns the processed string. */ - public static function processPageMarkup($pageName, $theme, $markup) + public static function processPageMarkup(string $pageName, Theme $theme, string $markup): string { $map = self::extractSnippetsFromMarkupCached($theme, $pageName, $markup); @@ -312,8 +288,7 @@ public static function processPageMarkup($pageName, $theme, $markup) $partialName = $partialSnippetMap[$snippetCode]; $generatedMarkup = $controller->renderPartial($partialName, $snippetInfo['properties']); - } - else { + } else { $generatedMarkup = $controller->renderComponent($snippetCode); } @@ -324,7 +299,7 @@ public static function processPageMarkup($pageName, $theme, $markup) return $markup; } - public static function processTemplateSettingsArray($settingsArray) + public static function processTemplateSettingsArray(array $settingsArray): array { if (!isset($settingsArray['viewBag']['snippetProperties']['TableData'])) { return $settingsArray; @@ -353,7 +328,7 @@ public static function processTemplateSettingsArray($settingsArray) return $settingsArray; } - public static function processTemplateSettings($template) + public static function processTemplateSettings($template): void { if (!isset($template->viewBag['snippetProperties'])) { return; @@ -378,8 +353,10 @@ public static function processTemplateSettings($template) * As snippet properties are defined with data attributes, they are lower case, whereas * real property names are case sensitive. This method finds original property names defined * in snippet classes or partials and replaces property names defined in the static page markup. + * + * @throws ApplicationException if the provided snippet cannot be found */ - protected static function preprocessPropertyValues($theme, $snippetCode, $componentClass, $properties) + protected static function preprocessPropertyValues(Theme $theme, string $snippetCode, string $componentClass, array $properties): array { $snippet = SnippetManager::instance()->findByCodeOrComponent($theme, $snippetCode, $componentClass, true); if (!$snippet) { @@ -397,8 +374,7 @@ protected static function preprocessPropertyValues($theme, $snippetCode, $compon if (array_key_exists('default', $propertyInfo)) { $properties[$propertyCode] = $propertyInfo['default']; } - } - else { + } else { $markupPropertyInfo = $properties[$lowercaseCode]; unset($properties[$lowercaseCode]); $properties[$propertyCode] = $markupPropertyInfo; @@ -410,9 +386,8 @@ protected static function preprocessPropertyValues($theme, $snippetCode, $compon /** * Converts a keyed object to an array, converting the index to the "property" value. - * @return array */ - protected static function parseIniProperties($properties) + protected static function parseIniProperties(array $properties): array { foreach ($properties as $index => $value) { $properties[$index]['property'] = $index; @@ -421,7 +396,7 @@ protected static function parseIniProperties($properties) return array_values($properties); } - protected static function dropDownOptionsToArray($optionsString) + protected static function dropDownOptionsToArray(string $optionsString): array { $options = explode('|', $optionsString); @@ -434,16 +409,14 @@ protected static function dropDownOptionsToArray($optionsString) if (strlen($key)) { if (!preg_match('/^[0-9a-z-_]+$/i', $key)) { - throw new ValidationException(['snippetProperties' => Lang::get('winter.pages::lang.snippet.invalid_option_key', ['key'=>$key])]); + throw new ValidationException(['snippetProperties' => Lang::get('winter.pages::lang.snippet.invalid_option_key', ['key' => $key])]); } $result[$key] = trim($parts[1]); - } - else { + } else { $result[$index] = trim($optionStr); } - } - else { + } else { $result[$index] = trim($optionStr); } } @@ -451,7 +424,7 @@ protected static function dropDownOptionsToArray($optionsString) return $result; } - protected static function dropDownOptionsToString($optionsArray) + protected static function dropDownOptionsToString(array $optionsArray): string { $result = []; $isAssoc = (bool) count(array_filter(array_keys($optionsArray), 'is_string')); @@ -468,14 +441,11 @@ protected static function dropDownOptionsToString($optionsArray) /** * Parse content to render snippets * - * @param string $markup - * @param array $params - * @return string * @throws ApplicationException * @throws CmsException * @throws SystemException */ - public static function parse($markup, $params = []) + public static function parse(string $markup, array $params = []): string { $theme = Theme::getActiveTheme(); $controller = CmsController::getController(); @@ -489,8 +459,7 @@ public static function parse($markup, $params = []) // The snippet is a component registered as a snippet $snippetAlias = SnippetLoader::registerComponentSnippet($snippetInfo); $generatedMarkup = $controller->renderComponent($snippetAlias, $params); - } - else { + } else { // The snippet is a partial $partialName = SnippetLoader::registerPartialSnippet($snippetInfo); $generatedMarkup = $controller->renderPartial($partialName, array_merge($params, $snippetInfo['properties'])); @@ -503,7 +472,7 @@ public static function parse($markup, $params = []) return $markup; } - protected static function extractSnippetsFromMarkup($markup, $theme) + protected static function extractSnippetsFromMarkup(string $markup, Theme $theme): array { $map = []; $matches = []; @@ -549,7 +518,7 @@ protected static function extractSnippetsFromMarkup($markup, $theme) return $map; } - protected static function extractSnippetsFromMarkupCached($theme, $pageName, $markup) + protected static function extractSnippetsFromMarkupCached(Theme $theme, string $pageName, string $markup): array { if (array_key_exists($pageName, self::$pageSnippetMap)) { return self::$pageSnippetMap[$pageName]; @@ -586,7 +555,7 @@ protected static function extractSnippetsFromMarkupCached($theme, $pageName, $ma /** * Returns a cache key for this record. */ - protected static function getMapCacheKey($theme) + protected static function getMapCacheKey(Theme $theme): string { $key = crc32($theme->getPath()).'snippet-map'; /** @@ -606,9 +575,8 @@ protected static function getMapCacheKey($theme) /** * Clears the snippet map item cache - * @param \Cms\Classes\Theme $theme Specifies the current theme. */ - public static function clearMapCache($theme) + public static function clearMapCache(Theme $theme): void { Cache::forget(self::getMapCacheKey($theme)); } From 71cc21d8a6c1fcd186600e2a2de97df6063cc424 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sat, 17 Jun 2023 23:18:07 -0600 Subject: [PATCH 09/19] Add typehints --- classes/SnippetLoader.php | 41 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/classes/SnippetLoader.php b/classes/SnippetLoader.php index b665fbe..4402529 100644 --- a/classes/SnippetLoader.php +++ b/classes/SnippetLoader.php @@ -12,7 +12,6 @@ use Flash; use Session; use SystemException; - use Winter\Pages\Classes\SnippetManager; class SnippetLoader @@ -22,12 +21,10 @@ class SnippetLoader /** * Add a component registered as a snippet to the active controller. * - * @param array $snippetInfo The info of the snippet to register - * @return string The generated unique alias for this snippet * @throws SystemException * @throws CmsException */ - public static function registerComponentSnippet($snippetInfo) + public static function registerComponentSnippet(array $snippetInfo): string { $controller = CmsController::getController(); @@ -44,11 +41,9 @@ public static function registerComponentSnippet($snippetInfo) /** * Add a partial registered as a snippet to the active controller. * - * @param array $snippetInfo The info of the snippet to register - * @return string The generated unique alias for this snippet * @throws ApplicationException */ - public static function registerPartialSnippet($snippetInfo) + public static function registerPartialSnippet(array $snippetInfo): string { $theme = Theme::getActiveTheme(); $partialSnippetMap = SnippetManager::instance()->getPartialSnippetMap($theme); @@ -64,10 +59,8 @@ public static function registerPartialSnippet($snippetInfo) /** * Save to the cache the component snippets loaded for this page. * Should be called once after all snippets are loaded to avoid multiple serializations. - * - * @param CmsPage $page The CMS Page to which the cache should be attached */ - public static function saveCachedSnippets(CmsPage $page) + public static function saveCachedSnippets(CmsPage $page): void { if (empty(static::$pageSnippetsCache)) { return; @@ -83,17 +76,14 @@ public static function saveCachedSnippets(CmsPage $page) /** * Register back to the current controller all component snippets previously saved. * This make AJAX handlers of these components available. - * - * @param CmsController $cmsController - * @param CmsPage $page The CMS page for which to load the cache */ - public static function restoreComponentSnippetsFromCache($cmsController, CmsPage $page) + public static function restoreComponentSnippetsFromCache(CmsController $controller, CmsPage $page): void { $componentSnippets = static::fetchCachedSnippets($page); foreach ($componentSnippets as $componentInfo) { try { - static::attachComponentSnippetToController($componentInfo, $cmsController); + static::attachComponentSnippetToController($componentInfo, $controller); } catch (\Exception $e) { } } @@ -109,13 +99,10 @@ public static function restoreComponentSnippetsFromCache($cmsController, CmsPage * If asked, the run lifecycle events of the component can be run. This is required for * component that are added late in the page execution like with the twig filter. * - * @param array $componentInfo - * @param CmsController $controller - * @param bool $triggerRun Should the run events of the component lifecycle be triggered? * @throws SystemException * @throws CmsException */ - protected static function attachComponentSnippetToController($componentInfo, CmsController $controller, $triggerRun = false) + protected static function attachComponentSnippetToController(array $componentInfo, CmsController $controller, bool $triggerRunEvents = false): void { $componentManager = ComponentManager::instance(); @@ -129,7 +116,7 @@ protected static function attachComponentSnippetToController($componentInfo, Cms $componentInfo['properties'] ); - if ($triggerRun) { + if ($triggerRunEvents) { if ($component->fireEvent('component.beforeRun', [], true)) { return; } @@ -147,21 +134,16 @@ protected static function attachComponentSnippetToController($componentInfo, Cms /** * Store a component snippet to the cache. * The cache is not actually saved; saveCachedSnippets() must be called to persist the cache. - * - * @param string $alias The unique alias of the snippet - * @param array $snippetInfo The info of the snippet */ - protected static function cacheSnippet($alias, $snippetInfo) + protected static function cacheSnippet(string $alias, array $snippetInfo): void { static::$pageSnippetsCache[$alias] = $snippetInfo; } /** * Get cached component snippets from the cache. - * - * @param CmsPage $page The CMS page for which to load the cache */ - protected static function fetchCachedSnippets(CmsPage $page) + protected static function fetchCachedSnippets(CmsPage $page): void { try { $cache = unserialize(Cache::get(static::getMapCacheKey($page), serialize([]))); @@ -176,11 +158,8 @@ protected static function fetchCachedSnippets(CmsPage $page) /** * Get a cache key for the current page and the current user. - * - * @param CmsPage $page The CMS page for which to load the cache - * @return string */ - protected static function getMapCacheKey(CmsPage $page) + protected static function getMapCacheKey(CmsPage $page): string { $theme = Theme::getActiveTheme(); From 3b68d598a73bf5a503d7bf699c429911b09915ab Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sat, 17 Jun 2023 23:30:44 -0600 Subject: [PATCH 10/19] Apply suggestions from code review --- assets/js/froala-snippets.js | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/assets/js/froala-snippets.js b/assets/js/froala-snippets.js index cf91511..a3fb438 100644 --- a/assets/js/froala-snippets.js +++ b/assets/js/froala-snippets.js @@ -85,31 +85,29 @@ // Insert the content this.figures.insert($snippetNode); } - } }); generateUniqueComponentSnippetCode = function(componentClass, originalCode, $pageForm) { var updatedCode = originalCode, counter = 1, - snippetFound = false + snippetFound = false; do { - snippetFound = false + snippetFound = false; - $('[data-control="richeditor"] textarea', $pageForm).each(function() { + $('[data-control="richeditor"] textarea', $pageForm).each(function () { var $textarea = $(this), - $codeDom = $('
' + $textarea.val() + '
') + $codeDom = $('
' + $textarea.val() + '
'); if ($codeDom.find('[data-snippet="'+updatedCode+'"][data-component]').length > 0) { - snippetFound = true - updatedCode = originalCode + counter - counter++ + snippetFound = true; + updatedCode = originalCode + counter; + counter++; - return false + return false; } - }) - + }); } while (snippetFound) return updatedCode @@ -128,5 +126,4 @@ $.wn.pagesPage.snippetManager.initSnippets($editor); } }); - -})(jQuery); \ No newline at end of file +})(jQuery); From 7db20dc64abc8a37e46f4ca221eb2fc40f39be37 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sat, 17 Jun 2023 23:34:03 -0600 Subject: [PATCH 11/19] Update Plugin.php --- Plugin.php | 56 ++---------------------------------------------------- 1 file changed, 2 insertions(+), 54 deletions(-) diff --git a/Plugin.php b/Plugin.php index da9a5cc..ddc9dbc 100644 --- a/Plugin.php +++ b/Plugin.php @@ -146,7 +146,8 @@ public function registerMarkupTags(): array { return [ 'filters' => [ - 'staticPage' => ['Winter\Pages\Classes\Page', 'url'] + 'staticPage' => [StaticPage::class, 'url'] + 'parseSnippets' => [Snippet::class, 'parse'], ] ]; } @@ -390,57 +391,4 @@ protected function registerRichEditorLinkTypes(): void }); }); } - - /** - * Register new Twig variables - */ - public function registerMarkupTags(): array - { - return [ - 'filters' => [ - 'staticPage' => ['Winter\Pages\Classes\Page', 'url'], - 'parseSnippets' => ['Winter\Pages\Classes\Snippet', 'parse'], - ] - ]; - } - - public function registerClassAliases() - { - /** - * To allow compatibility with plugins that extend the original RainLab.Pages plugin, - * this will alias those classes to use the new Winter.Pages classes. - */ - return [ - \Winter\Pages\Plugin::class => \RainLab\Pages\Plugin::class, - \Winter\Pages\Classes\Content::class => \RainLab\Pages\Classes\Content::class, - \Winter\Pages\Classes\Controller::class => \RainLab\Pages\Classes\Controller::class, - \Winter\Pages\Classes\Menu::class => \RainLab\Pages\Classes\Menu::class, - \Winter\Pages\Classes\Page::class => \RainLab\Pages\Classes\Page::class, - \Winter\Pages\Classes\Router::class => \RainLab\Pages\Classes\Router::class, - \Winter\Pages\Classes\Snippet::class => \RainLab\Pages\Classes\Snippet::class, - \Winter\Pages\Classes\SnippetManager::class => \RainLab\Pages\Classes\SnippetManager::class, - \Winter\Pages\Components\ChildPages::class => \RainLab\Pages\Components\ChildPages::class, - \Winter\Pages\Components\StaticBreadcrumbs::class => \RainLab\Pages\Components\StaticBreadcrumbs::class, - \Winter\Pages\Components\StaticMenu::class => \RainLab\Pages\Components\StaticMenu::class, - \Winter\Pages\Components\StaticPage::class => \RainLab\Pages\Components\StaticPage::class, - \Winter\Pages\Controllers\Index::class => \RainLab\Pages\Controllers\Index::class, - \Winter\Pages\FormWidgets\MenuItems::class => \RainLab\Pages\FormWidgets\MenuItems::class, - \Winter\Pages\FormWidgets\MenuItemSearch::class => \RainLab\Pages\FormWidgets\MenuItemSearch::class, - \Winter\Pages\FormWidgets\PagePicker::class => \RainLab\Pages\FormWidgets\PagePicker::class, - \Winter\Pages\Widgets\MenuList::class => \RainLab\Pages\Widgets\MenuList::class, - \Winter\Pages\Widgets\PageList::class => \RainLab\Pages\Widgets\PageList::class, - \Winter\Pages\Widgets\SnippetList::class => \RainLab\Pages\Widgets\SnippetList::class, - ]; - } - - public static function clearCache() - { - $theme = Theme::getEditTheme(); - - $router = new Router($theme); - $router->clearCache(); - - StaticPage::clearMenuCache($theme); - SnippetManager::clearCache($theme); - } } From a98fe1d003b0deb68bc4fa0e34a136485bfea231 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sat, 17 Jun 2023 23:35:50 -0600 Subject: [PATCH 12/19] Update Plugin.php --- Plugin.php | 66 +++++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/Plugin.php b/Plugin.php index ddc9dbc..d771003 100644 --- a/Plugin.php +++ b/Plugin.php @@ -233,6 +233,36 @@ protected function extendBackendForms(): void ], ]); }, PHP_INT_MIN + 1); + + // Add support for the "snippets" button to all richeditor fields in the backend + BaseBackendController::extend(function ($controller) { + $user = BackendAuth::getUser(); + if (!$user || !$user->hasAccess('winter.pages.access_snippets')) { + return; + } + + // Add the AJAX handlers required for snippet inspector properties + // to function on all backend controllers + $controller->addDynamicMethod('onGetInspectorConfiguration', function() { + return (new StaticPage)->onGetInspectorConfiguration(); + }); + $controller->addDynamicMethod('onGetSnippetNames', function() { + return (new StaticPage)->onGetSnippetNames(); + }); + $controller->addDynamicMethod('onInspectableGetOptions', function() { + return (new StaticPage)->onInspectableGetOptions(); + }); + + FroalaFormWidget::extend(function ($widget) { + // Adds default base CSS/JS for snippets + $widget->addCss('/plugins/winter/pages/assets/css/pages.css', 'Winter.Pages'); + $widget->addJs('/plugins/winter/pages/assets/js/pages-page.js', 'Winter.Pages'); + $widget->addJs('/plugins/winter/pages/assets/js/pages-snippets.js', 'Winter.Pages'); + + // Adds custom assets for the Froala snippet button + $widget->addJs('/plugins/winter/pages/assets/js/froala-snippets.js', 'Winter.Pages'); + }); + }); } /** @@ -354,41 +384,5 @@ protected function registerRichEditorLinkTypes(): void return StaticPage::getRichEditorTypeInfo($type); } }); - - Event::listen('system.console.theme.sync.getAvailableModelClasses', function () { - return [ - Classes\Menu::class, - Classes\Page::class, - ]; - }); - - BaseBackendController::extend(function ($controller) { - $user = BackendAuth::getUser(); - if (!$user || !$user->hasAccess('winter.pages.access_snippets')) { - return; - } - - // Add the AJAX handlers required for snippet inspector properties - // to function on all backend controllers - $controller->addDynamicMethod('onGetInspectorConfiguration', function() { - return (new StaticPage)->onGetInspectorConfiguration(); - }); - $controller->addDynamicMethod('onGetSnippetNames', function() { - return (new StaticPage)->onGetSnippetNames(); - }); - $controller->addDynamicMethod('onInspectableGetOptions', function() { - return (new StaticPage)->onInspectableGetOptions(); - }); - - FroalaFormWidget::extend(function ($widget) { - // Adds default base CSS/JS for snippets - $widget->addCss('/plugins/winter/pages/assets/css/pages.css', 'Winter.Pages'); - $widget->addJs('/plugins/winter/pages/assets/js/pages-page.js', 'Winter.Pages'); - $widget->addJs('/plugins/winter/pages/assets/js/pages-snippets.js', 'Winter.Pages'); - - // Adds custom assets for the Froala snippet button - $widget->addJs('/plugins/winter/pages/assets/js/froala-snippets.js', 'Winter.Pages'); - }); - }); } } From fabd5bd9dbc0020c2e51f4c5781dd9f822483be8 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sat, 17 Jun 2023 23:37:09 -0600 Subject: [PATCH 13/19] Update Plugin.php --- Plugin.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Plugin.php b/Plugin.php index d771003..0febc43 100644 --- a/Plugin.php +++ b/Plugin.php @@ -1,6 +1,9 @@ Date: Sat, 17 Jun 2023 23:38:19 -0600 Subject: [PATCH 14/19] Missing comma --- Plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugin.php b/Plugin.php index 0febc43..f7e0740 100644 --- a/Plugin.php +++ b/Plugin.php @@ -149,7 +149,7 @@ public function registerMarkupTags(): array { return [ 'filters' => [ - 'staticPage' => [StaticPage::class, 'url'] + 'staticPage' => [StaticPage::class, 'url'], 'parseSnippets' => [Snippet::class, 'parse'], ] ]; From 202ad7660c867bbb66a3c02d9b5c1ee48633ce67 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sat, 17 Jun 2023 23:39:59 -0600 Subject: [PATCH 15/19] Update classes/SnippetLoader.php --- classes/SnippetLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/SnippetLoader.php b/classes/SnippetLoader.php index 4402529..6d45435 100644 --- a/classes/SnippetLoader.php +++ b/classes/SnippetLoader.php @@ -143,7 +143,7 @@ protected static function cacheSnippet(string $alias, array $snippetInfo): void /** * Get cached component snippets from the cache. */ - protected static function fetchCachedSnippets(CmsPage $page): void + protected static function fetchCachedSnippets(CmsPage $page): array { try { $cache = unserialize(Cache::get(static::getMapCacheKey($page), serialize([]))); From 417d42d9809aadaf070e9bf60ca8445b8a49c0e7 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sun, 18 Jun 2023 05:41:36 +0000 Subject: [PATCH 16/19] Test on 8.2 --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5bbdd8f..f13ba49 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: strategy: max-parallel: 6 matrix: - phpVersion: ['8.0', '8.1'] + phpVersion: ['8.0', '8.1', '8.2'] winterRelease: ['develop'] winterReleaseDir: ['develop'] include: From bb2278147fdeb0969f7ea2d304fe084f7ed86ab8 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 18 Jun 2023 13:04:43 -0400 Subject: [PATCH 17/19] add reason for thrown exceptions; remove CmsException --- classes/Snippet.php | 6 +++--- classes/SnippetLoader.php | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/classes/Snippet.php b/classes/Snippet.php index e14c5d1..c519a03 100644 --- a/classes/Snippet.php +++ b/classes/Snippet.php @@ -355,6 +355,7 @@ public static function processTemplateSettings($template): void * in snippet classes or partials and replaces property names defined in the static page markup. * * @throws ApplicationException if the provided snippet cannot be found + * @throws SystemException if the snippet component class cannot be found */ protected static function preprocessPropertyValues(Theme $theme, string $snippetCode, string $componentClass, array $properties): array { @@ -441,9 +442,8 @@ protected static function dropDownOptionsToString(array $optionsArray): string /** * Parse content to render snippets * - * @throws ApplicationException - * @throws CmsException - * @throws SystemException + * @throws ApplicationException if the provided snippet cannot be found + * @throws SystemException if the snippet component class cannot be found */ public static function parse(string $markup, array $params = []): string { diff --git a/classes/SnippetLoader.php b/classes/SnippetLoader.php index 6d45435..55d1423 100644 --- a/classes/SnippetLoader.php +++ b/classes/SnippetLoader.php @@ -21,8 +21,7 @@ class SnippetLoader /** * Add a component registered as a snippet to the active controller. * - * @throws SystemException - * @throws CmsException + * @throws SystemException if the snippet component class cannot be found */ public static function registerComponentSnippet(array $snippetInfo): string { @@ -41,7 +40,7 @@ public static function registerComponentSnippet(array $snippetInfo): string /** * Add a partial registered as a snippet to the active controller. * - * @throws ApplicationException + * @throws ApplicationException if the snippet partial is not found. */ public static function registerPartialSnippet(array $snippetInfo): string { @@ -99,8 +98,7 @@ public static function restoreComponentSnippetsFromCache(CmsController $controll * If asked, the run lifecycle events of the component can be run. This is required for * component that are added late in the page execution like with the twig filter. * - * @throws SystemException - * @throws CmsException + * @throws SystemException if component code is reserved. */ protected static function attachComponentSnippetToController(array $componentInfo, CmsController $controller, bool $triggerRunEvents = false): void { From be2c626ee7bbba24fa8149b38e6dbe07403f893c Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 19 Jun 2023 09:46:49 -0400 Subject: [PATCH 18/19] remove OC2 changes --- assets/js/froala-snippets.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/assets/js/froala-snippets.js b/assets/js/froala-snippets.js index a3fb438..8905cdc 100644 --- a/assets/js/froala-snippets.js +++ b/assets/js/froala-snippets.js @@ -44,8 +44,7 @@ var options = $.wn.snippets[val]; if (options) { - // Get editor element. OC2's richeditor has 2 nested data-control=richeditor, we want the outer one - var $editor = this.$el.parents('[data-control="richeditor"]:not([data-richeditor-vue])'); + var $editor = this.$el.parents('[data-control="richeditor"]'), var $snippetNode = $('
 
'); @@ -120,7 +119,7 @@ * that are displayed on page load (i.e. Winter.Blog). */ $(document).ready(function() { - var $editor = $('[data-control="richeditor"]:not([data-richeditor-vue])'); + var $editor = $('[data-control="richeditor"]'); if ($.wn.pagesPage && !window.location.pathname.includes('winter/pages')) { $.wn.pagesPage.snippetManager.initSnippets($editor); From 8aeb4b1990d1c58692cf5c8d814f0aaf03b257dd Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 19 Jun 2023 17:24:18 -0400 Subject: [PATCH 19/19] improve comment about snippet code --- classes/SnippetLoader.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/classes/SnippetLoader.php b/classes/SnippetLoader.php index 55d1423..702732b 100644 --- a/classes/SnippetLoader.php +++ b/classes/SnippetLoader.php @@ -29,7 +29,8 @@ public static function registerComponentSnippet(array $snippetInfo): string // Make an unique alias for this snippet based on its name and parameters #$snippetInfo['code'] = uniqid($snippetInfo['code'] . '_' . md5(serialize($snippetInfo['properties'])) . '_'); - // the line above was commented out to allow the overriden partials in theme to be used for the component alias + // the encoded snippet code line above is commented out because the snippet code must match the component alias, + // otherwise the overriden component markup in theme partials will not be found. static::attachComponentSnippetToController($snippetInfo, $controller, true); static::cacheSnippet($snippetInfo['code'], $snippetInfo);