diff --git a/css/_summary.scss b/css/_summary.scss index b08472f..8026dae 100644 --- a/css/_summary.scss +++ b/css/_summary.scss @@ -18,6 +18,7 @@ text-align: center; white-space: nowrap; vertical-align: baseline; + margin: 3px 0; // Empty badges collapse automatically &:empty { @@ -26,33 +27,55 @@ } } -.paragraph-info { - display: flex; - // Needed not just because of centering but also to prevent span child to - // stretch vertically. - align-items: center; -} - // We are using .js prefix here mainly because we want to apply this style rules // only for JS version of the element. .js { - .paragraphs-collapsed-description { - position: relative; - height: 1.538em; - overflow: hidden; - color: #777; - word-break: break-all; - line-height: 1.538em; - - // Fade out text element. - &::after { - display: block; - position: absolute; - top: 0; - right: 0; - width: 3em; - background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, #fff 100%); - content: "\00a0"; + .paragraphs-description { + .paragraphs-content-wrapper, + .paragraphs-plugin-wrapper { + position: relative; + height: 1.538em; + overflow: hidden; + word-break: break-all; + line-height: 1.538em; + + // Fade out text element. + &::after { + display: block; + position: absolute; + top: 0; + right: 0; + width: 3em; + background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, #fff 100%); + content: "\00a0"; + } + } + + .summary-plugin-label { + text-transform: uppercase; + } + + .summary-plugin { + padding-right: 5px; + font-size: 0.7rem; + color: $behavior-summary-color; + + &:not(:last-child) { + border-right: 2px solid $light-grey; + } + &:not(:first-child) { + padding: 0 5px; + } } } + + // Hide plugin summary when on behavior tab and paragraph is collapsed. + .behavior-active .paragraphs-expanded-description .paragraphs-plugin-wrapper { + display: none; + } + + // Hide content summary when on content tab and paragraph is collapsed. + .content-active .paragraphs-expanded-description .paragraphs-content-wrapper { + display: none; + } } diff --git a/css/_variables.scss b/css/_variables.scss index 47660ad..3416c85 100644 --- a/css/_variables.scss +++ b/css/_variables.scss @@ -1,6 +1,7 @@ // Colours. $grey-dark: #999999 !default; +$light-grey: #e5e3de !default; // Layout. @@ -35,3 +36,4 @@ $info-icon-size: 16px !default; $badge-padding-y: .15em !default; $badge-padding-x: .3em !default; $badge-color: #787878 !default; +$behavior-summary-color: #777 !default; diff --git a/css/paragraphs.dragdrop.css b/css/paragraphs.dragdrop.css index e743f21..a8abdc8 100644 --- a/css/paragraphs.dragdrop.css +++ b/css/paragraphs.dragdrop.css @@ -176,14 +176,6 @@ line-height: 1.538em; } -.paragraphs-dragdrop__item .paragraphs-summary-wrapper > .paragraphs-collapsed-description { - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - -ms-flex-positive: 1; - flex-grow: 1; - font-style: italic; -} - .paragraphs-dragdrop__handle { display: -webkit-box; display: -webkit-flex; diff --git a/css/paragraphs.dragdrop.scss b/css/paragraphs.dragdrop.scss index 09cd3f7..a451bbd 100644 --- a/css/paragraphs.dragdrop.scss +++ b/css/paragraphs.dragdrop.scss @@ -171,18 +171,13 @@ width: calc(100% - var(--dnd-icon-size)); } - // Collapsed summary container. + // Closed summary container. .paragraphs-summary-wrapper { display: flex; align-items: center; height: 1.538em; margin: 5px 0; line-height: 1.538em; - - > .paragraphs-collapsed-description { - flex-grow: 1; - font-style: italic; - } } } diff --git a/css/paragraphs.formatter.css b/css/paragraphs.formatter.css index af9d1a8..602e276 100644 --- a/css/paragraphs.formatter.css +++ b/css/paragraphs.formatter.css @@ -10,33 +10,24 @@ text-align: center; white-space: nowrap; vertical-align: baseline; + margin: 3px 0; } .paragraphs-badge:empty { display: none; } -.paragraph-info { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; -} - -.js .paragraphs-collapsed-description { +.js .paragraphs-description .paragraphs-content-wrapper, +.js .paragraphs-description .paragraphs-plugin-wrapper { position: relative; height: 1.538em; overflow: hidden; - color: #777; word-break: break-all; line-height: 1.538em; } -.js .paragraphs-collapsed-description::after { +.js .paragraphs-description .paragraphs-content-wrapper::after, +.js .paragraphs-description .paragraphs-plugin-wrapper::after { display: block; position: absolute; top: 0; @@ -47,6 +38,32 @@ content: "\00a0"; } +.js .paragraphs-description .summary-plugin-label { + text-transform: uppercase; +} + +.js .paragraphs-description .summary-plugin { + padding-right: 5px; + font-size: 0.7rem; + color: #777; +} + +.js .paragraphs-description .summary-plugin:not(:last-child) { + border-right: 2px solid #e5e3de; +} + +.js .paragraphs-description .summary-plugin:not(:first-child) { + padding: 0 5px; +} + +.js .behavior-active .paragraphs-expanded-description .paragraphs-plugin-wrapper { + display: none; +} + +.js .content-active .paragraphs-expanded-description .paragraphs-content-wrapper { + display: none; +} + .paragraph-formatter { display: -ms-grid; display: grid; diff --git a/css/paragraphs.widget.css b/css/paragraphs.widget.css index 566564b..a9eb0f3 100644 --- a/css/paragraphs.widget.css +++ b/css/paragraphs.widget.css @@ -10,33 +10,24 @@ text-align: center; white-space: nowrap; vertical-align: baseline; + margin: 3px 0; } .paragraphs-badge:empty { display: none; } -.paragraph-info { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; -} - -.js .paragraphs-collapsed-description { +.js .paragraphs-description .paragraphs-content-wrapper, +.js .paragraphs-description .paragraphs-plugin-wrapper { position: relative; height: 1.538em; overflow: hidden; - color: #777; word-break: break-all; line-height: 1.538em; } -.js .paragraphs-collapsed-description::after { +.js .paragraphs-description .paragraphs-content-wrapper::after, +.js .paragraphs-description .paragraphs-plugin-wrapper::after { display: block; position: absolute; top: 0; @@ -47,12 +38,39 @@ content: "\00a0"; } +.js .paragraphs-description .summary-plugin-label { + text-transform: uppercase; +} + +.js .paragraphs-description .summary-plugin { + padding-right: 5px; + font-size: 0.7rem; + color: #777; +} + +.js .paragraphs-description .summary-plugin:not(:last-child) { + border-right: 2px solid #e5e3de; +} + +.js .paragraphs-description .summary-plugin:not(:first-child) { + padding: 0 5px; +} + +.js .behavior-active .paragraphs-expanded-description .paragraphs-plugin-wrapper { + display: none; +} + +.js .content-active .paragraphs-expanded-description .paragraphs-content-wrapper { + display: none; +} + .paragraphs-icon { display: inline-block; height: 20px; width: 20px; background: no-repeat center; background-size: 16px 16px; + vertical-align: middle; } .paragraphs-icon-view { @@ -194,13 +212,13 @@ display: grid; -ms-grid-columns: 100px auto 1fr auto; grid-template-columns: 100px auto 1fr auto; - -ms-grid-rows: auto; - grid-template-rows: auto; - grid-gap: 5px 5px; - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; + -ms-grid-rows: auto auto; + grid-template-rows: auto auto; + grid-gap: 0 5px; + -webkit-box-align: baseline; + -webkit-align-items: baseline; + -ms-flex-align: baseline; + align-items: baseline; } @media (min-width: 992px) { @@ -241,8 +259,8 @@ -ms-grid-column: 3; -ms-grid-column-span: 1; -ms-grid-row: 1; - -ms-grid-row-span: 1; - grid-row: 1 / span 1; + -ms-grid-row-span: 2; + grid-row: 1 / span 2; } } @@ -269,17 +287,17 @@ margin-top: 5px; } -.draggable:hover .paragraphs-collapsed-description::after { +.draggable:hover .paragraphs-description::after { background: -webkit-gradient(linear, left top, right top, from(rgba(247, 252, 255, 0)), to(#f7fcff)); background: linear-gradient(to right, rgba(247, 252, 255, 0) 0%, #f7fcff 100%); } -.drag-previous .paragraphs-collapsed-description::after { +.drag-previous .paragraphs-description::after { background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 221, 0)), to(#ffd)); background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #ffd 100%); } -tr:hover .paragraphs-collapsed-description::after { +tr:hover .paragraphs-description::after { background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 221, 0)), to(#f7fcff)); background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #f7fcff 100%); } @@ -305,6 +323,7 @@ tr:hover .paragraphs-collapsed-description::after { padding-right: 5px; height: 16px; width: 16px; + vertical-align: middle; } .js .paragraph-type-label { diff --git a/css/paragraphs.widget.scss b/css/paragraphs.widget.scss index 37d6401..cc794ce 100644 --- a/css/paragraphs.widget.scss +++ b/css/paragraphs.widget.scss @@ -14,6 +14,7 @@ width: $info-size; background: no-repeat center; background-size: $info-icon-size $info-icon-size; + vertical-align: middle; $icons: view edit-info edit-disabled delete delete-disabled lock changed collapse warning error; @each $icon in $icons { @@ -141,9 +142,9 @@ .paragraph-top { display: grid; grid-template-columns: 100px auto 1fr auto; - grid-template-rows: auto; - grid-gap: $gutter-top $gutter-top; - align-items: center; + grid-template-rows: auto auto; + grid-gap: 0 $gutter-top; + align-items: baseline; @media (min-width: map-get($grid-breakpoints, 'lg')) { grid-template-columns: 150px auto 1fr auto; @@ -174,7 +175,7 @@ grid-column: 3 / 4; -ms-grid-column: 3; -ms-grid-column-span: 1; - grid-row: 1 / span 1; + grid-row: 1 / span 2; } } @@ -198,20 +199,20 @@ margin-top: 5px; } - .paragraphs-collapsed-description { - @at-root .draggable:hover .paragraphs-collapsed-description { + .paragraphs-description { + @at-root .draggable:hover .paragraphs-description { &::after { background: linear-gradient(to right, rgba(247, 252, 255, 0) 0%, #f7fcff 100%); } } - @at-root .drag-previous .paragraphs-collapsed-description { + @at-root .drag-previous .paragraphs-description { &::after { background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #ffd 100%); } } - @at-root tr:hover .paragraphs-collapsed-description { + @at-root tr:hover .paragraphs-description { &::after { background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #f7fcff 100%); } @@ -232,6 +233,7 @@ padding-right: $gutter-top; height: $info-icon-size; width: $info-icon-size; + vertical-align: middle; } &-label { diff --git a/js/paragraphs.admin.js b/js/paragraphs.admin.js index 968d334..d391499 100644 --- a/js/paragraphs.admin.js +++ b/js/paragraphs.admin.js @@ -33,7 +33,7 @@ if (!($mainRegion.hasClass('content-active')) && !($mainRegion.hasClass('behavior-active'))) { $tabContent.addClass('is-active'); - $mainRegion.addClass('content-active'); + $parWidget.addClass('content-active'); } $parContent.show(); @@ -62,13 +62,13 @@ $($parWidget).find($clickedTab.attr('href')).addClass('is-active'); if ($parWidget.find('#content').hasClass('is-active')) { - $parWidget.find('.layout-region-node-main').addClass('content-active'); + $parWidget.addClass('content-active'); $parWidget.find('.paragraphs-content').show(); $parWidget.find('.paragraphs-behavior').hide(); } if ($parWidget.find('#behavior').hasClass('is-active')) { - $parWidget.find('.layout-region-node-main').addClass('behavior-active'); + $parWidget.addClass('behavior-active'); $parWidget.find('.paragraphs-content').hide(); $parWidget.find('.paragraphs-behavior').show(); } diff --git a/modules/paragraphs_library/src/Entity/LibraryItem.php b/modules/paragraphs_library/src/Entity/LibraryItem.php index f064163..6669e0d 100644 --- a/modules/paragraphs_library/src/Entity/LibraryItem.php +++ b/modules/paragraphs_library/src/Entity/LibraryItem.php @@ -283,7 +283,7 @@ class LibraryItem extends EditorialContentEntityBase implements LibraryItemInter */ protected static function buildLabel(ParagraphInterface $paragraph) { $summary = $paragraph->getSummary(['show_behavior_summary' => FALSE]); - $summary = Unicode::truncate($summary, 50); + $summary = Unicode::truncate(strip_tags($summary), 50); return $paragraph->getParagraphType()->label() . ': ' . $summary; } diff --git a/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php b/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php index 6b4ffa6..25f3a55 100644 --- a/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php +++ b/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php @@ -201,7 +201,7 @@ class ParagraphsLibraryItemTest extends ParagraphsExperimentalTestBase { $element = $this->cssSelect('th.views-field-paragraphs__target-id'); $this->assertEqual($element[0]->__toString(), 'Paragraphs', 'Paragraphs column is available.'); - $element = $this->cssSelect('.paragraphs-collapsed-description'); + $element = $this->cssSelect('.paragraphs-description .paragraphs-summary-wrapper'); $this->assertEqual(trim($element[0]->__toString()), 're_usable_text_new', 'Paragraphs summary available.'); // Check that the deletion of library items does not cause errors. diff --git a/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php b/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php index 20f05dc..875a9e4 100644 --- a/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php +++ b/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php @@ -167,12 +167,12 @@ JS; $save_button = $this->assertSession()->elementExists('css', '.ui-dialog .ui-dialog-buttonset button'); $save_button->press(); $this->waitForAjaxToFinish(); - $this->assertRaw('class="paragraphs-collapsed-description">This is a reusable text UPDATED.'); + $this->assertRaw('class="paragraphs-description">
This is a reusable text UPDATED.'); $this->submitForm([], 'Save'); // Edit the outside library item. $this->getSession()->getPage()->clickLink('Outside library item'); $this->getSession()->getPage()->clickLink('Edit'); - $this->assertRaw('class="paragraphs-collapsed-description">This is a reusable text UPDATED.'); + $this->assertRaw('class="paragraphs-description">
This is a reusable text UPDATED.'); // Edit the inner library item and assert the fields and values. $this->getSession()->getPage()->pressButton('Edit'); $this->waitForAjaxToFinish(); @@ -198,7 +198,7 @@ JS; $this->getSession()->evaluateScript($drop); sleep(1); $this->waitForAjaxToFinish(); - $this->assertRaw('class="paragraphs-collapsed-description">Inner library item'); + $this->assertRaw('class="paragraphs-description">
Inner library item'); $this->submitForm([], 'Save'); $this->assertText('paragraphed_test Overlay node has been created.'); // Edit the node. diff --git a/paragraphs.module b/paragraphs.module index bfa09bf..c8e2c1c 100644 --- a/paragraphs.module +++ b/paragraphs.module @@ -78,6 +78,10 @@ function paragraphs_theme() { 'render element' => 'element', 'template' => 'paragraphs-actions', ], + 'paragraphs_summary' => [ + 'render element' => 'element', + 'template' => 'paragraphs-summary', + ], ); } @@ -590,3 +594,18 @@ function _paragraphs_migration_entity_type_adjust(array &$migration, $destinatio ]; $migration['process'][$destination] = $entity_type_process; } + +/** + * Prepares variables for. + * + * Default template: paragraphs-summary.html.twig + * + * @param array $variables + * An associative array containing: + * - buttons: An array of buttons to display in the modal form. + */ +function template_preprocess_paragraphs_summary(&$variables) { + $variables['contents'] = $variables['element']['#summary']['contents']; + $variables['behaviors'] = $variables['element']['#summary']['behaviors']; + $variables['expanded'] = isset($variables['element']['#expanded']) ? $variables['element']['#expanded'] : FALSE; +} diff --git a/src/Entity/Paragraph.php b/src/Entity/Paragraph.php index 078756d..c3f02dc 100644 --- a/src/Entity/Paragraph.php +++ b/src/Entity/Paragraph.php @@ -411,7 +411,7 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface { $show_behavior_summary = isset($options['show_behavior_summary']) ? $options['show_behavior_summary'] : TRUE; $depth_limit = isset($options['depth_limit']) ? $options['depth_limit'] : 1; $this->summaryCount = 0; - $summary = []; + $summary = ['contents' => [], 'behaviors' => []]; $components = entity_get_form_display('paragraph', $this->getType(), 'default')->getComponents(); uasort($components, 'Drupal\Component\Utility\SortArray::sortByWeightElement'); foreach (array_keys($components) as $field_name) { @@ -429,23 +429,23 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface { if ($field_definition->getType() == 'image' || $field_definition->getType() == 'file') { $file_summary = $this->getFileSummary($field_name); if ($file_summary != '') { - $summary[] = $file_summary; + $summary['contents'][] = $file_summary; } } $text_summary = $this->getTextSummary($field_name, $field_definition); if ($text_summary != '') { - $summary[] = $text_summary; + $summary['contents'][] = $text_summary; } if ($field_definition->getType() == 'entity_reference_revisions') { // Decrease the depth, since we are entering a nested paragraph. $nested_summary = $this->getNestedSummary($field_name, [ - 'show_behavior_summary' => $show_behavior_summary, + 'show_behavior_summary' => FALSE, 'depth_limit' => $depth_limit - 1 ]); if ($nested_summary != '') { - $summary[] = $nested_summary; + $summary = array_merge($summary, $nested_summary); } } @@ -454,7 +454,7 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface { $entity = $this->get($field_name)->entity; // Switch to the entity translation in the current context if exists. $entity = \Drupal::service('entity.repository')->getTranslationFromContext($entity, $this->activeLangcode); - $summary[] = $entity->label(); + $summary['contents'][] = $entity->label(); } } @@ -464,7 +464,7 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface { if ($block = $block_admin_label = $this->get($field_name)->first()->getBlock()) { $block_admin_label = $block->getPluginDefinition()['admin_label']; } - $summary[] = $block_admin_label; + $summary['contents'][] = $block_admin_label; } } @@ -472,10 +472,10 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface { if (!empty($this->get($field_name)->first())) { // If title is not set, fallback to the uri. if ($title = $this->get($field_name)->title) { - $summary[] = $title; + $summary['contents'][] = $title; } else { - $summary[] = $this->get($field_name)->uri; + $summary['contents'][] = $this->get($field_name)->uri; } } } @@ -485,13 +485,17 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface { $paragraphs_type = $this->getParagraphType(); foreach ($paragraphs_type->getEnabledBehaviorPlugins() as $plugin_id => $plugin) { if ($plugin_summary = $plugin->settingsSummary($this)) { - $summary = array_merge($summary, $plugin_summary); + foreach ($plugin_summary as $plugin_summary_element) { + if (!is_array($plugin_summary_element)) { + $plugin_summary_element = ['value' => $plugin_summary_element]; + } + $summary['behaviors'][] = $plugin_summary_element; + } } } } - $collapsed_summary_text = implode(', ', $summary); - return strip_tags($collapsed_summary_text); + return $summary; } /** @@ -613,7 +617,7 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface { elseif ($file_value->alt != '') { $text = $file_value->alt; } - elseif ($file_value->entity->getFileName()) { + elseif ($file_value->entity && $file_value->entity->getFileName()) { $text = $file_value->entity->getFileName(); } @@ -638,32 +642,31 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface { * See \Drupal\paragraphs\ParagraphInterface::getSummary() for all of the * available options. * - * @return string + * @return array * Short summary for nested Paragraphs type * or NULL if the summary is empty. */ protected function getNestedSummary($field_name, array $options) { - $summary = []; + $summary = ['contents' => [], 'behaviors' => []]; if ($options['depth_limit'] >= 0) { foreach ($this->get($field_name) as $item) { $entity = $item->entity; if ($entity instanceof ParagraphInterface) { // Switch to the entity translation in the current context if exists. $entity = \Drupal::service('entity.repository')->getTranslationFromContext($entity, $this->activeLangcode); - $summary[] = $entity->getSummary($options); + $entity_summary = $entity->getSummary($options); + foreach ($entity_summary['contents'] as $content) { + $summary['contents'][] = $content; + } + foreach ($entity_summary['behaviors'] as $behaviors) { + $summary['behaviors'][] = $behaviors; + } $this->summaryCount++; } } } - $summary = array_filter($summary); - - if (empty($summary)) { - return NULL; - } - - $paragraph_summary = implode(', ', $summary); - return $paragraph_summary; + return $summary; } /** diff --git a/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php b/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php index 6111ff2..bdabf7e 100644 --- a/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php +++ b/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php @@ -48,9 +48,9 @@ class ParagraphsSummaryFormatter extends EntityReferenceFormatterBase { ] ]; $elements[$delta]['summary']['description'] = [ - '#markup' => $summary, - '#prefix' => '
', - '#suffix' => '
', + '#theme' => 'paragraphs_summary', + '#summary' => $summary, + '#expanded' => FALSE, ]; } } diff --git a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php index 9d87d3b..feb1b60 100644 --- a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php +++ b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php @@ -697,7 +697,7 @@ class InlineParagraphsWidget extends WidgetBase { $summary = $paragraphs_entity->getSummary(); $element['top']['paragraph_summary']['fields_info'] = [ '#markup' => $summary, - '#prefix' => '
', + '#prefix' => '
', '#suffix' => '
', ]; } diff --git a/src/Plugin/Field/FieldWidget/ParagraphsWidget.php b/src/Plugin/Field/FieldWidget/ParagraphsWidget.php index e9f10d6..095c023 100644 --- a/src/Plugin/Field/FieldWidget/ParagraphsWidget.php +++ b/src/Plugin/Field/FieldWidget/ParagraphsWidget.php @@ -759,6 +759,17 @@ class ParagraphsWidget extends WidgetBase { if ($item_mode == 'edit') { $display->buildForm($paragraphs_entity, $element['subform'], $form_state); $hide_untranslatable_fields = $paragraphs_entity->isDefaultTranslationAffectedOnly(); + $summary = $paragraphs_entity->getSummary(); + + if (!empty($summary)) { + $element['top']['summary']['fields_info'] = [ + '#theme' => 'paragraphs_summary', + '#summary' => $summary, + '#expanded' => TRUE, + '#access' => $paragraphs_entity->access('update') || $paragraphs_entity->access('view'), + ]; + } + $info = array_merge($info, $paragraphs_entity->getIcons()); foreach (Element::children($element['subform']) as $field) { if ($paragraphs_entity->hasField($field)) { @@ -780,6 +791,12 @@ class ParagraphsWidget extends WidgetBase { if (!$is_paragraph_field) { $element['subform'][$field]['#attributes']['class'][] = 'paragraphs-content'; + $element['top']['summary']['fields_info'] = [ + '#theme' => 'paragraphs_summary', + '#summary' => $summary, + '#expanded' => TRUE, + '#access' => $paragraphs_entity->access('update') || $paragraphs_entity->access('view'), + ]; } $translatable = $field_definition->isTranslatable(); // Hide untranslatable fields when configured to do so except @@ -834,9 +851,9 @@ class ParagraphsWidget extends WidgetBase { $summary = $paragraphs_entity->getSummary(); if (!empty($summary)) { $element['top']['summary']['fields_info'] = [ - '#markup' => $summary, - '#prefix' => '
', - '#suffix' => '
', + '#theme' => 'paragraphs_summary', + '#summary' => $summary, + '#expanded' => FALSE, '#access' => $paragraphs_entity->access('update') || $paragraphs_entity->access('view'), ]; } @@ -1339,9 +1356,9 @@ class ParagraphsWidget extends WidgetBase { } $element['top']['summary']['fields_info'] = [ - '#markup' => $child_paragraph->getSummary($summary_options), - '#prefix' => '
', - '#suffix' => '
', + '#theme' => 'paragraphs_summary', + '#summary' => $child_paragraph->getSummary($summary_options), + '#expanded' => FALSE, '#access' => $child_paragraph->access('update') || $child_paragraph->access('view'), ]; diff --git a/src/Tests/Classic/ParagraphsAdministrationTest.php b/src/Tests/Classic/ParagraphsAdministrationTest.php index 482b1e9..f1a8db1 100644 --- a/src/Tests/Classic/ParagraphsAdministrationTest.php +++ b/src/Tests/Classic/ParagraphsAdministrationTest.php @@ -277,8 +277,8 @@ class ParagraphsAdministrationTest extends ParagraphsTestBase { // The textareas for paragraphs should not be visible. $this->assertNoRaw('field_paragraphs[0][subform][field_text][0][value]'); $this->assertNoRaw('field_paragraphs[1][subform][field_text][0][value]'); - $this->assertRaw('
Test text 1, ' . $files[0]->filename); - $this->assertRaw('
Test text 2, ' . $files[1]->filename); + $this->assertRaw('
Test text 1, ' . $files[0]->filename); + $this->assertRaw('
Test text 2, ' . $files[1]->filename); // Test for preview option. $this->drupalGet('admin/structure/types/manage/article/form-display'); diff --git a/src/Tests/Classic/ParagraphsEditModesTest.php b/src/Tests/Classic/ParagraphsEditModesTest.php index 821f026..b015eea 100644 --- a/src/Tests/Classic/ParagraphsEditModesTest.php +++ b/src/Tests/Classic/ParagraphsEditModesTest.php @@ -64,8 +64,8 @@ class ParagraphsEditModesTest extends ParagraphsTestBase { // Assert the summary is correctly generated. $this->clickLink(t('Edit')); - $this->assertRaw('
' . $files[0]->filename . ', text_summary'); - $this->assertRaw('
Title example'); + $this->assertRaw('
' . $files[0]->filename . ', text_summary'); + $this->assertRaw('
Title example'); // Edit and remove alternative text. $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); @@ -76,7 +76,7 @@ class ParagraphsEditModesTest extends ParagraphsTestBase { ]; $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); // Assert the summary is correctly generated. - $this->assertRaw('
alternative_text_summary, text_summary'); + $this->assertRaw('
alternative_text_summary, text_summary'); // Remove image. $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); @@ -85,7 +85,7 @@ class ParagraphsEditModesTest extends ParagraphsTestBase { // Assert the summary is correctly generated. $this->clickLink(t('Edit')); - $this->assertRaw('
text_summary'); + $this->assertRaw('
text_summary'); // Add a Block Paragraphs type. $this->addParagraphsType('block_paragraph'); @@ -100,7 +100,7 @@ class ParagraphsEditModesTest extends ParagraphsTestBase { ]; $this->drupalPostForm(NULL, $edit, t('Save')); $this->clickLink(t('Edit')); - $this->assertRaw('
Breadcrumbs'); + $this->assertRaw('
Breadcrumbs'); } } diff --git a/src/Tests/Classic/ParagraphsWidgetButtonsTest.php b/src/Tests/Classic/ParagraphsWidgetButtonsTest.php index 6917bdb..2783f08 100644 --- a/src/Tests/Classic/ParagraphsWidgetButtonsTest.php +++ b/src/Tests/Classic/ParagraphsWidgetButtonsTest.php @@ -60,7 +60,7 @@ class ParagraphsWidgetButtonsTest extends ParagraphsTestBase { $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_1_collapse'); // Verify that we have warning message for each paragraph. $this->assertNoUniqueText('You have unsaved changes on this Paragraph item.'); - $this->assertRaw('
' . $closed_mode_text); + $this->assertRaw('
' . $closed_mode_text); $this->drupalPostForm(NULL, [], t('Save')); $this->assertText('paragraphed_test ' . $node->label() . ' has been updated.'); $this->assertText($closed_mode_text); diff --git a/src/Tests/Experimental/ParagraphsExperimentalAdministrationTest.php b/src/Tests/Experimental/ParagraphsExperimentalAdministrationTest.php index 18bbc64..a64f7ba 100644 --- a/src/Tests/Experimental/ParagraphsExperimentalAdministrationTest.php +++ b/src/Tests/Experimental/ParagraphsExperimentalAdministrationTest.php @@ -275,8 +275,8 @@ class ParagraphsExperimentalAdministrationTest extends ParagraphsExperimentalTes // The textareas for paragraphs should not be visible. $this->assertNoRaw('field_paragraphs[0][subform][field_text][0][value]'); $this->assertNoRaw('field_paragraphs[1][subform][field_text][0][value]'); - $this->assertRaw('
Test text 1, ' . $files[0]->filename); - $this->assertRaw('
Test text 2, ' . $files[1]->filename); + $this->assertRaw('
Test text 1, ' . $files[0]->filename); + $this->assertRaw('
Test text 2, ' . $files[1]->filename); // Test for preview option. $this->drupalGet('admin/structure/types/manage/article/form-display'); diff --git a/src/Tests/Experimental/ParagraphsExperimentalBehaviorsTest.php b/src/Tests/Experimental/ParagraphsExperimentalBehaviorsTest.php index 27e3fdd..9b7fdcf 100644 --- a/src/Tests/Experimental/ParagraphsExperimentalBehaviorsTest.php +++ b/src/Tests/Experimental/ParagraphsExperimentalBehaviorsTest.php @@ -200,7 +200,7 @@ class ParagraphsExperimentalBehaviorsTest extends ParagraphsExperimentalTestBase // Check that the summary does not have the user displayed. $node = $this->getNodeByTitle('field_override_test'); $this->drupalPostAjaxForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_collapse'); - $this->assertRaw('paragraphs-collapsed-description">This is a test'); + $this->assertRaw('class="paragraphs-description paragraphs-collapsed-description">
This is a test'); } /** @@ -260,8 +260,8 @@ class ParagraphsExperimentalBehaviorsTest extends ParagraphsExperimentalTestBase $this->assertFieldByXPath('//*[@id="edit-field-paragraphs-1-top-icons"]/span[@class="paragraphs-icon paragraphs-icon-bold"]'); // Assert that the summary includes the text of the behavior plugins. - $this->assertRaw('class="paragraphs-collapsed-description">first_paragraph, Bold: Yes, Text color: blue'); - $this->assertRaw('class="paragraphs-collapsed-description">nested_paragraph, Bold: No, Text color: blue, Bold: Yes'); + $this->assertRaw('class="paragraphs-description paragraphs-collapsed-description">
first_paragraph
Bold Yes Text color blue
'); + $this->assertRaw('class="paragraphs-description paragraphs-collapsed-description">
nested_paragraph
Bold Yes
'); // Add an empty nested paragraph. $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); @@ -272,7 +272,7 @@ class ParagraphsExperimentalBehaviorsTest extends ParagraphsExperimentalTestBase // Check an empty nested paragraph summary. $this->clickLink('Edit'); - $this->assertRaw('class="paragraphs-collapsed-description">'); + $this->assertRaw('class="paragraphs-description paragraphs-collapsed-description">'); } diff --git a/src/Tests/Experimental/ParagraphsExperimentalEditModesTest.php b/src/Tests/Experimental/ParagraphsExperimentalEditModesTest.php index 58a9bcc..9e60918 100644 --- a/src/Tests/Experimental/ParagraphsExperimentalEditModesTest.php +++ b/src/Tests/Experimental/ParagraphsExperimentalEditModesTest.php @@ -78,9 +78,9 @@ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase // Assert the summary is correctly generated. $this->clickLink(t('Edit')); - $this->assertRaw('
' . $files[0]->filename . ', text_summary'); - $this->assertRaw('
' . $this->admin_user->label()); - $this->assertRaw('
Title example'); + $this->assertRaw('
' . $files[0]->filename . ', text_summary'); + $this->assertRaw('
' . $this->admin_user->label()); + $this->assertRaw('
Title example'); // Edit and remove alternative text. $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); @@ -91,7 +91,7 @@ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase ]; $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); // Assert the summary is correctly generated. - $this->assertRaw('
alternative_text_summary, text_summary'); + $this->assertRaw('
alternative_text_summary, text_summary'); // Remove image. $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); @@ -100,7 +100,7 @@ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase // Assert the summary is correctly generated. $this->clickLink(t('Edit')); - $this->assertRaw('
text_summary'); + $this->assertRaw('
text_summary'); $this->addParagraphsType('nested_paragraph'); static::fieldUIAddNewField('admin/structure/paragraphs_type/nested_paragraph', 'nested_content', 'Nested Content', 'entity_reference_revisions', ['settings[target_type]' => 'paragraph'], []); @@ -146,7 +146,7 @@ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase 'field_paragraphs[0][subform][field_block][0][plugin_id]' => 'block_content:' . $after_block2->uuid(), ]; $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse'); - $this->assertRaw('
Llama custom block'); + $this->assertRaw('
Llama custom block'); $edit = ['title[0][value]' => 'Test llama block']; $this->drupalPostForm(NULL, $edit, t('Save')); // Delete the block. @@ -169,7 +169,7 @@ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase $this->drupalPostForm(NULL, $edit, t('Save')); // Check the summary when no link title is provided. $this->clickLink(t('Edit')); - $this->assertRaw('
http://www.google.com'); + $this->assertRaw('
http://www.google.com'); // Set a link title. $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_0_edit'); $edit = [ @@ -178,7 +178,7 @@ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase $this->drupalPostForm(NULL, $edit, t('Save')); // Check the summary when the link title is set. $this->clickLink(t('Edit')); - $this->assertRaw('
Link title'); + $this->assertRaw('
Link title'); // Allow the user to select if the paragraphs is published or not. $edit = [ @@ -204,7 +204,7 @@ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase $this->assertNoText('memorable_summary_title'); $node = $this->getNodeByTitle('Access summary test'); $this->drupalGet('node/' . $node->id() . '/edit'); - $this->assertRaw('
memorable_summary_title'); + $this->assertRaw('
memorable_summary_title'); $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more'); $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_title_add_more'); @@ -221,10 +221,10 @@ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase $this->assertNoText('memorable_nested_summary_title'); $node = $this->getNodeByTitle('Access nested summary test'); $this->drupalGet('node/' . $node->id() . '/edit'); - $this->assertRaw('
memorable_nested_summary_title'); + $this->assertRaw('
memorable_nested_summary_title'); $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit'); $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_0_collapse'); - $this->assertRaw('
memorable_nested_summary_title'); + $this->assertRaw('
memorable_nested_summary_title'); } } diff --git a/src/Tests/Experimental/ParagraphsExperimentalTranslationTest.php b/src/Tests/Experimental/ParagraphsExperimentalTranslationTest.php index 6689979..e42b0b3 100644 --- a/src/Tests/Experimental/ParagraphsExperimentalTranslationTest.php +++ b/src/Tests/Experimental/ParagraphsExperimentalTranslationTest.php @@ -444,8 +444,8 @@ class ParagraphsExperimentalTranslationTest extends ParagraphsExperimentalTestBa // Assert that the summary is displayed in the current language. $this->drupalGet('de/node/' . $node->id() . '/edit'); $this->assertFieldByName('title[0][value]', 'DE llama'); - $this->assertRaw('
DE text llama'); - $this->assertRaw('
DE nested text llama'); + $this->assertRaw('
DE text llama
'); + $this->assertRaw('
DE nested text llama
'); // Case 2: Referenced entities. $this->addParagraphsType('node_reference'); @@ -473,7 +473,7 @@ class ParagraphsExperimentalTranslationTest extends ParagraphsExperimentalTestBa $this->drupalPostForm(NULL, $edit, t('Save (this translation)')); // Edit the node again and check the paragraph summary. $this->drupalGet('de/node/' . $referencing_node->id() . '/edit'); - $this->assertRaw('
DE llama'); + $this->assertRaw('
DE llama
'); } /** diff --git a/src/Tests/Experimental/ParagraphsExperimentalWidgetButtonsTest.php b/src/Tests/Experimental/ParagraphsExperimentalWidgetButtonsTest.php index 45ec337..0358bce 100644 --- a/src/Tests/Experimental/ParagraphsExperimentalWidgetButtonsTest.php +++ b/src/Tests/Experimental/ParagraphsExperimentalWidgetButtonsTest.php @@ -81,7 +81,7 @@ class ParagraphsExperimentalWidgetButtonsTest extends ParagraphsExperimentalTest $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_1_collapse'); // Verify that we have warning message for each paragraph. $this->assertEqual(2, count($this->xpath("//*[contains(@class, 'paragraphs-icon-changed')]"))); - $this->assertRaw('
' . $closed_mode_text); + $this->assertRaw('
' . $closed_mode_text); $this->drupalPostForm(NULL, [], t('Save')); $this->assertText('paragraphed_test ' . $node->label() . ' has been updated.'); $this->assertText($closed_mode_text); diff --git a/templates/paragraphs-summary.html.twig b/templates/paragraphs-summary.html.twig new file mode 100644 index 0000000..eb228e2 --- /dev/null +++ b/templates/paragraphs-summary.html.twig @@ -0,0 +1,42 @@ +{# +/** + * @file + * Default theme implementation for a paragraphs summary. + * + * Available variables: + * - expanded: Whether the summary is expanded or not. + * - contents: Array of content summary. + * - behaviors: Array of behavior summary. + * + * @see template_preprocess() + * + * @ingroup themeable + */ +#} +{% + set classes = [ + 'paragraphs-description', + expanded ? 'paragraphs-expanded-description' : 'paragraphs-collapsed-description' +] +%} +
+ {% if contents is not empty %} +
+ {% for content in contents %} + {{ content }} + {% endfor %} +
+ {% endif %} + {% if behaviors is not empty %} +
+ {% for behavior in behaviors %} + + {% if behavior.label is not null %} + {{ behavior.label }} + {% endif %} + {{ behavior.value }} + + {% endfor %} +
+ {% endif %} +
diff --git a/tests/src/Functional/ParagraphsExperimentalTranslationsTest.php b/tests/src/Functional/ParagraphsExperimentalTranslationsTest.php index 8257a1a..c392b2c 100644 --- a/tests/src/Functional/ParagraphsExperimentalTranslationsTest.php +++ b/tests/src/Functional/ParagraphsExperimentalTranslationsTest.php @@ -151,13 +151,13 @@ class ParagraphsExperimentalTranslationsTest extends BrowserTestBase { $assert_session->fieldNotExists('field_paragraphs[2][subform][field_text_untranslatable_hide][0][value]'); $assert_session->buttonNotExists('field_paragraphs_2_collapse'); $assert_session->buttonNotExists('field_paragraphs_2_edit'); - $assert_session->responseContains('
Do not translate me CLOSED EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Do not translate me CLOSED EN'); $assert_session->buttonExists('field_paragraphs_1_collapse'); $assert_session->fieldExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]'); $page->pressButton('field_paragraphs_1_collapse'); $assert_session->fieldNotExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]'); - $assert_session->responseContains('
Do not translate me EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Do not translate me EN'); $assert_session->buttonExists('field_paragraphs_1_edit'); $assert_session->buttonExists('field_paragraphs_3_collapse'); @@ -178,17 +178,17 @@ class ParagraphsExperimentalTranslationsTest extends BrowserTestBase { $this->drupalGet("/de/node/{$host_node_id}/translations/add/en/de"); $assert_session->fieldExists('field_paragraphs[0][subform][field_text_translatable][0][value]'); $assert_session->fieldExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]'); - $assert_session->responseContains('
Do not translate me CLOSED EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Do not translate me CLOSED EN'); $assert_session->fieldExists('field_paragraphs[3][subform][field_paragraphs][0][subform][field_text_translatable][0][value]'); // Translate the content of the translatable fields. $page->fillField('field_paragraphs[0][subform][field_text_translatable][0][value]', 'Translate me DE'); $page->fillField('field_paragraphs[3][subform][field_paragraphs][0][subform][field_text_translatable][0][value]', 'Nested translate me DE'); // Close all Paragraphs with the new values. $page->pressButton('field_paragraphs_collapse_all'); - $assert_session->responseContains('
Translate me DE'); - $assert_session->responseContains('
Do not translate me EN'); - $assert_session->responseContains('
Do not translate me CLOSED EN'); - $assert_session->responseContains('
Nested translate me DE'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Translate me DE'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Do not translate me EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Do not translate me CLOSED EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Nested translate me DE'); // Edit the first Paragraph and update its value. $page->pressButton('field_paragraphs_0_edit'); $page->fillField('field_paragraphs[0][subform][field_text_translatable][0][value]', 'Translate me UPDATE DE'); @@ -200,16 +200,16 @@ class ParagraphsExperimentalTranslationsTest extends BrowserTestBase { // Edit the translation, assert that the Paragraphs are closed by default. $this->drupalGet('de/node/' . $host_node_id . '/edit'); - $assert_session->responseContains('
Translate me UPDATE DE'); - $assert_session->responseContains('
Do not translate me EN'); - $assert_session->responseContains('
Do not translate me CLOSED EN'); - $assert_session->responseContains('
Nested translate me DE'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Translate me UPDATE DE'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Do not translate me EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Do not translate me CLOSED EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Nested translate me DE'); // Open all paragraphs. $page->pressButton('field_paragraphs_edit_all'); $assert_session->fieldExists('field_paragraphs[0][subform][field_text_translatable][0][value]'); $assert_session->fieldExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]'); - $assert_session->responseContains('
Do not translate me CLOSED EN'); - $assert_session->responseContains('
Nested translate me DE'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Do not translate me CLOSED EN'); + $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description">
Nested translate me DE'); $assert_session->fieldNotExists('field_paragraphs[3][subform][field_paragraphs][0][subform][field_text_translatable][0][value]'); // When editing a nested container, all children should follow the widget // settings when editing the translation. diff --git a/tests/src/Functional/ParagraphsExperimentalUiTest.php b/tests/src/Functional/ParagraphsExperimentalUiTest.php index 39b2536..b2207ab 100644 --- a/tests/src/Functional/ParagraphsExperimentalUiTest.php +++ b/tests/src/Functional/ParagraphsExperimentalUiTest.php @@ -74,7 +74,7 @@ class ParagraphsExperimentalUiTest extends BrowserTestBase { $node = $this->getNodeByTitle('Llama test'); $this->drupalGet('node/' . $node->id() . '/edit'); $this->assertSession()->pageTextContains('