diff --git a/assets/scripts/admin-cms.js b/assets/scripts/admin-cms.js index 594a8470..daf9ea57 100644 --- a/assets/scripts/admin-cms.js +++ b/assets/scripts/admin-cms.js @@ -14,6 +14,7 @@ import './admin/content-edit/preview-background-color'; import './admin/content-edit/preview-block'; import './admin/content-edit/preview-class'; import './admin/content-edit/preview-collection-node-class'; +import './admin/content-edit/preview-color-attribute'; import './admin/content-edit/contenteditable'; import './admin/content-edit/contenteditable-focus'; import './admin/content-edit/preview-fill'; @@ -30,7 +31,7 @@ import './admin/content-forms'; import './admin/routes-forms'; import './admin/fields-visibility'; import './admin/locales-widgets'; -import './admin/versions-diff'; +import './admin/versions-diff'; import './types/block-type'; import './types/color-type'; diff --git a/assets/scripts/admin/content-edit/preview-color-attribute.js b/assets/scripts/admin/content-edit/preview-color-attribute.js new file mode 100644 index 00000000..8b062640 --- /dev/null +++ b/assets/scripts/admin/content-edit/preview-color-attribute.js @@ -0,0 +1,73 @@ +import {registerFeature} from '@softspring/cms-bundle/scripts/tools'; + +registerFeature('admin_content_edit_preview_color_attribute', _init); + +/** + * Init behaviour + * @private + */ +function _init() { + document.addEventListener('input', onEditColorAttribute); + document.addEventListener('change', onEditColorAttribute); +} + +/** + * Sets a color field to target element attribute + * + * The preview target element must have the "data-edit-color-attribute-{attributeName}-target" attribute + * The input field must have the "data-edit-color-attribute-{attributeName}-input" + * Both data attributes must have the same value (as identifier) + */ +function onEditColorAttribute(event) { + if (!event.target) { + return; + } + + let moduleEdit = event.target.closest('.cms-module-edit'); + if (!moduleEdit) { + return; + } + + let preview = moduleEdit.querySelector('.module-preview'); + if (!preview) { + return; + } + + const kebabize = (str) => str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? "-" : "") + $.toLowerCase()); + const escapeAttrValue = (value) => typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(value) : value.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); + + Object.keys(event.target.dataset).forEach((dataAttribute) => { + if (!dataAttribute.startsWith('editColorAttribute') || !dataAttribute.endsWith('Input')) { + return; + } + + const targetHashes = event.target.dataset[dataAttribute] + .split(',') + .map((hash) => hash.trim()) + .filter(Boolean); + + if (!targetHashes.length) { + return; + } + + const targetAttributeName = dataAttribute + .replace(/^editColorAttribute/, '') + .replace(/Input$/, ''); + + if (!targetAttributeName) { + return; + } + + const attributeName = kebabize(targetAttributeName); + targetHashes.forEach((targetHash) => { + const htmlTargetElements = preview.querySelectorAll("[data-edit-color-attribute-" + attributeName + "-target=\"" + escapeAttrValue(targetHash) + "\"]"); + if (!htmlTargetElements.length) { + return; + } + + htmlTargetElements.forEach((htmlTargetElement) => { + htmlTargetElement.setAttribute(attributeName, event.target.value); + }); + }); + }); +} diff --git a/assets/scripts/types/color-type.js b/assets/scripts/types/color-type.js index 6a29a555..c979aa03 100644 --- a/assets/scripts/types/color-type.js +++ b/assets/scripts/types/color-type.js @@ -25,7 +25,12 @@ function _init() { } let widget = event.target; - let toggler = widget.closest('.input-group').querySelector('[data-color-type=toggler]'); + let inputGroup = widget.closest('.input-group'); + if (!inputGroup) { + return; + } + + let toggler = inputGroup.querySelector('[data-color-type=toggler]'); if (!toggler) { return; @@ -40,7 +45,16 @@ function _init() { } function colorDatePicker(toggler) { - let widget = toggler.closest('.input-group').querySelector('[data-color-type=widget]'); + if (!toggler) { + return; + } + + let inputGroup = toggler.closest('.input-group'); + if (!inputGroup) { + return; + } + + let widget = inputGroup.querySelector('[data-color-type=widget]'); if (!widget) { return; @@ -56,7 +70,16 @@ function colorDatePicker(toggler) { if (!widget.hasAttribute('data-edit-bgcolor-input')) return; - let modulePreview = widget.closest('.cms-module-edit').querySelector('.module-preview'); + let moduleEdit = widget.closest('.cms-module-edit'); + if (!moduleEdit) { + return; + } + + let modulePreview = moduleEdit.querySelector('.module-preview'); + if (!modulePreview) { + return; + } + let htmlTargetElements = modulePreview.querySelectorAll("[data-edit-bgcolor-target='" + widget.dataset.editBgcolorInput + "']"); if (htmlTargetElements.length) { @@ -66,4 +89,4 @@ function colorDatePicker(toggler) { htmlTargetElements.forEach((htmlTargetElement) => htmlTargetElement.style.backgroundColor = widget.value); } } -} \ No newline at end of file +} diff --git a/src/Form/Type/ColorType.php b/src/Form/Type/ColorType.php index 9b901cae..84d87775 100644 --- a/src/Form/Type/ColorType.php +++ b/src/Form/Type/ColorType.php @@ -4,6 +4,9 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ColorType as SymfonyColorType; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; +use Symfony\Component\OptionsResolver\OptionsResolver; class ColorType extends AbstractType { @@ -12,8 +15,21 @@ public function getBlockPrefix(): string return 'cms_color'; } + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'show_toggler' => true, + ]); + $resolver->setAllowedTypes('show_toggler', 'bool'); + } + public function getParent(): string { return SymfonyColorType::class; } + + public function buildView(FormView $view, FormInterface $form, array $options): void + { + $view->vars['show_toggler'] = $options['show_toggler']; + } } diff --git a/src/Twig/Extension/EditFormExtension.php b/src/Twig/Extension/EditFormExtension.php index 27797680..b1862033 100644 --- a/src/Twig/Extension/EditFormExtension.php +++ b/src/Twig/Extension/EditFormExtension.php @@ -23,9 +23,22 @@ public function getFilters(): array ]; } - public function formViewSetAttr(FormView $formView, string $name, string $value): void + public function formViewSetAttr(FormView $formView, string $name, string $value, bool $allowMultiple = false): void { - $formView->vars['attr'][$name] = $value; + $current = (string) ($formView->vars['attr'][$name] ?? ''); + + if (!$allowMultiple || '' === $current) { + $formView->vars['attr'][$name] = $value; + + return; + } + + $values = array_filter(array_map('trim', explode(',', $current))); + if (!in_array($value, $values, true)) { + $values[] = $value; + } + + $formView->vars['attr'][$name] = implode(',', $values); } public function sha1($value): string diff --git a/templates/forms/types_theme.html.twig b/templates/forms/types_theme.html.twig index f78e3b6f..678ca6e5 100644 --- a/templates/forms/types_theme.html.twig +++ b/templates/forms/types_theme.html.twig @@ -37,14 +37,18 @@ {% endblock html_class_widget %} {% block cms_color_widget %} -