diff --git a/css/overview.admin.css b/css/overview.admin.css new file mode 100644 index 0000000..f53c610 --- /dev/null +++ b/css/overview.admin.css @@ -0,0 +1,10 @@ +.overview-details { + border: 0; + margin: 0; +} + +.overview-details summary { + font-weight: normal; + text-transform: none; + padding: 0; +} diff --git a/css/overview.css b/css/overview.css deleted file mode 100644 index f53c610..0000000 --- a/css/overview.css +++ /dev/null @@ -1,10 +0,0 @@ -.overview-details { - border: 0; - margin: 0; -} - -.overview-details summary { - font-weight: normal; - text-transform: none; - padding: 0; -} diff --git a/js/overview.admin.js b/js/overview.admin.js new file mode 100644 index 0000000..81a8cf6 --- /dev/null +++ b/js/overview.admin.js @@ -0,0 +1,66 @@ +/** + * @file + * Paragraphs Collection overview behaviors. + */ + +(function ($, Drupal) { + + "use strict"; + + /** + * Filters the overview table by input search filters. + * + * Target table: .table-filter[data-table] + * Text search input: input.table-filter-text + * Group search select: select.table-filter-group-select + * Source text: .table-filter-text-source + * Source group: .table-filter-group-source + * + * @type {Drupal~behavior} + */ + Drupal.behaviors.tableFilterByText = { + attach: function (context, settings) { + var $filters = $('.table-filter').once('table-filter'); + var $table = $($filters.attr('data-table')); + var $text_input = $('input.table-filter-text').once('table-filter-text'); + var $group_select = $('select.table-filter-group-select').once('table-filter-group-select'); + var $rows; + + function filterItemList() { + var group_value; + if (typeof $group_select.val() !== 'undefined') { + group_value = $group_select.val().toLowerCase(); + } + var text_value = $text_input.val().toLowerCase(); + + function showItemRow(index, row) { + var $row = $(row); + var $group_sources = $row.find('.table-filter-group-source'); + var $text_sources = $row.find('.table-filter-text-source'); + var group_array = $group_sources.map(function() { + return $(this).text().toLowerCase(); + }).get(); + + if (group_value && group_array.indexOf(group_value) == -1) { + $row.hide(); + return; + } + if (text_value && $text_sources.text().toLowerCase().indexOf(text_value) == -1) { + $row.hide(); + return; + } + $row.show(); + } + + $rows.each(showItemRow); + } + + if ($table.length) { + $rows = $table.find('tbody tr'); + $text_input.on('keyup', filterItemList); + $group_select.on('change', filterItemList); + } + } + }; + +}(jQuery, Drupal)); diff --git a/js/overview.js b/js/overview.js deleted file mode 100644 index a11712f..0000000 --- a/js/overview.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file - * Paragraphs Collection overview behaviors. - */ - -(function ($, Drupal) { - - "use strict"; - - /** - * Filters the overview table by input search filters. - * - * Target table: .table-filter[data-table] - * Text search input: input.table-filter-text - * Group search select: select.table-filter-group-select - * Source text: .table-filter-text-source - * Source group: .table-filter-group-source - * - * @type {Drupal~behavior} - */ - Drupal.behaviors.tableFilterByText = { - attach: function (context, settings) { - var $filters = $('.table-filter').once('table-filter'); - var $table = $($filters.attr('data-table')); - // var $selects = $ - var $text_input = $('input.table-filter-text').once('table-filter-text'); - var $group_select = $('select.table-filter-group-select').once('table-filter-group-select'); - var $rows; - - function filterItemList() { - var group_value; - if (typeof $group_select.val() !== 'undefined') { - group_value = $group_select.val().toLowerCase(); - } - var text_value = $text_input.val().toLowerCase(); - - function showItemRow(index, row) { - var $row = $(row); - var $group_sources = $row.find('.table-filter-group-source'); - var $text_sources = $row.find('.table-filter-text-source'); - var group_array = $group_sources.map(function() { - return $(this).text().toLowerCase(); - }).get(); - - if (group_value && group_array.indexOf(group_value) == -1) { - $row.hide(); - return; - } - if (text_value && $text_sources.text().toLowerCase().indexOf(text_value) == -1) { - $row.hide(); - return; - } - $row.show(); - } - - $rows.each(showItemRow); - } - - if ($table.length) { - $rows = $table.find('tbody tr'); - $text_input.on('keyup', filterItemList); - $group_select.on('change', filterItemList); - } - } - }; - -}(jQuery, Drupal)); diff --git a/modules/paragraphs_library/paragraphs_library.module b/modules/paragraphs_library/paragraphs_library.module index e2ea38d..fefaa4b 100644 --- a/modules/paragraphs_library/paragraphs_library.module +++ b/modules/paragraphs_library/paragraphs_library.module @@ -6,7 +6,84 @@ */ use Drupal\Core\Form\FormStateInterface; +use Drupal\paragraphs\Plugin\Field\FieldWidget\ParagraphsWidget; use Drupal\views\ViewExecutable; +use \Drupal\paragraphs_library\Entity\LibraryItem; +use \Drupal\Component\Utility\NestedArray; +use \Drupal\Core\Field\WidgetBase; +use \Drupal\paragraphs\Entity\Paragraph; + +/** + * Implements hook_paragraph_widget_dropbutton_alter(). + */ +function paragraphs_library_paragraph_widget_dropbutton_alter(&$links, &$context) { + $field_definition = $context['items']->getFieldDefinition(); + $parents = $context['element']['#field_parents']; + $field_name = $field_definition->getName(); + $widget_state = $context['widget']; + // Don't allow conversion of library items. + $bundle = isset($context['widget']['selected_bundle']) ? $context['widget']['selected_bundle'] : FALSE; + if ($bundle != 'from_library') { + $id_prefix = implode('_', array_merge($parents, array($field_name, $context['delta']))); + $links['add_to_library'] = [ + '#type' => 'submit', + '#value' => t('Add to library'), + '#name' => $id_prefix . '_add_to_library', + '#weight' => 503, + '#submit' => ['paragraphs_collection_make_library_item_submit'], + '#limit_validation_errors' => [ + array_merge($parents, [$field_name, 'add_to_library']), + ], + '#delta' => $context['delta'], + '#ajax' => [ + 'callback' => [ + ParagraphsWidget::class, + 'itemAjax', + ], + 'wrapper' => $widget_state['ajax_wrapper_id'], + 'effect' => 'fade', + ], + '#prefix' => '
  • ', + '#suffix' => '
  • ', + ]; + } +} + +/** + * Make library item submit callback. + * + * @param array $form + * The element form array. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state object. + */ +function paragraphs_collection_make_library_item_submit(array $form, FormStateInterface $form_state) { + $button = $form_state->getTriggeringElement(); + // Go one level up in the form, to the widgets container. + $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -4)); + $field_name = $element['#field_name']; + $parents = $element['#field_parents']; + + // Replacing element in the array. + $widget_state = WidgetBase::getWidgetState($parents, $field_name, $form_state); + $delta = $button['#delta']; + $library_item = LibraryItem::createFromParagraph($widget_state['paragraphs'][$delta]['entity']); + $library_item->save(); + + // Replace this paragraph with a library reference one. + $paragraph_item = [ + 'entity' => Paragraph::create([ + 'type' => 'from_library', + 'field_reusable_paragraph' => $library_item, + ]), + 'display' => $widget_state['paragraphs'][$delta]['display'], + 'mode' => 'edit', + ]; + + $widget_state['paragraphs'][$delta] = $paragraph_item; + WidgetBase::setWidgetState($parents, $field_name, $form_state, $widget_state); + $form_state->setRebuild(); +} /** * Implements hook_preprocess_HOOK(). diff --git a/modules/paragraphs_library/src/Entity/LibraryItem.php b/modules/paragraphs_library/src/Entity/LibraryItem.php index 116c580..eb32cb4 100644 --- a/modules/paragraphs_library/src/Entity/LibraryItem.php +++ b/modules/paragraphs_library/src/Entity/LibraryItem.php @@ -2,9 +2,12 @@ namespace Drupal\paragraphs_library\Entity; +use Drupal\Component\Utility\Unicode; +use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\paragraphs\ParagraphInterface; use Drupal\paragraphs_library\LibraryItemInterface; /** @@ -95,4 +98,20 @@ class LibraryItem extends ContentEntityBase implements LibraryItemInterface { return $fields; } + /** + * {@inheritdoc} + */ + public static function createFromParagraph(ParagraphInterface $paragraph) { + $summary = $paragraph->getSummary(); + $summary = Unicode::truncate($summary, 50); + + $label = $paragraph->getParagraphType()->label() . ': ' . $summary; + $library_item = static::create([ + 'label' => $label, + 'paragraphs' => $paragraph, + ]); + + return $library_item; + } + } diff --git a/modules/paragraphs_library/src/LibraryItemInterface.php b/modules/paragraphs_library/src/LibraryItemInterface.php index 97e8277..099b25e 100644 --- a/modules/paragraphs_library/src/LibraryItemInterface.php +++ b/modules/paragraphs_library/src/LibraryItemInterface.php @@ -3,8 +3,22 @@ namespace Drupal\paragraphs_library; use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\paragraphs\ParagraphInterface; /** * Provides an interface defining a paragraphs entity. */ -interface LibraryItemInterface extends ContentEntityInterface { } +interface LibraryItemInterface extends ContentEntityInterface { + + /** + * Creates a library entity from a paragraph entity. + * + * @param \Drupal\paragraphs\ParagraphInterface $paragraph + * The paragraph entity. + * + * @return \Drupal\paragraphs_library\LibraryItemInterface + * The library item entity. + */ + public static function createFromParagraph(ParagraphInterface $paragraph); + +} diff --git a/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php b/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php index ca15958..1557bc4 100644 --- a/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php +++ b/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php @@ -20,13 +20,25 @@ class ParagraphsLibraryItemTest extends ParagraphsExperimentalTestBase { * * @var array */ - public static $modules = ['views', 'paragraphs_library']; + public static $modules = [ + 'views', + 'paragraphs_library', + 'paragraphs_collection_test', + 'link', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $this->addParagraphedContentType('paragraphed_test', 'field_paragraphs'); + } /** * Tests the library items workflow for paragraphs. */ public function testLibraryItems() { - $this->addParagraphedContentType('paragraphed_test', 'field_paragraphs'); $this->loginAsAdmin(['create paragraphed_test content', 'edit any paragraphed_test content', 'administer paragraphs library']); // Add a Paragraph type with a text field. @@ -138,4 +150,44 @@ class ParagraphsLibraryItemTest extends ParagraphsExperimentalTestBase { $this->assertEqual($element[0]->p->__toString(), 're_usable_text_new', 'Paragraphs summary available.'); } + /** + * Tests converting paragraph item into library. + */ + public function testConvertParagraphIntoLibrary() { + $this->loginAsAdmin([ + 'create paragraphed_test content', + 'edit any paragraphed_test content', + 'administer paragraphs library', + ]); + $this->drupalGet('node/add/paragraphed_test'); + $this->drupalPostForm(NULL, NULL, 'Add Text'); + $edit = [ + 'field_paragraphs[0][subform][paragraphs_text][0][value]' => 'Random text for testing converting into library.', + ]; + $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_add_to_library'); + $this->assertText('From library'); + $this->assertText('Reusable paragraph'); + $edit = [ + 'title[0][value]' => 'TextParagraphs', + ]; + $this->drupalPostForm(NULL, $edit, 'Save and publish'); + $this->drupalGet('node/1'); + $this->assertText('Random text for testing converting into library.'); + + // Create library item from existing paragraph item. + $this->drupalGet('node/add/paragraphed_test'); + $this->drupalPostForm(NULL, NULL, 'Add Text'); + $edit = [ + 'title[0][value]' => 'NodeTitle', + 'field_paragraphs[0][subform][paragraphs_text][0][value]' => 'Random text for testing converting into library.', + ]; + $this->drupalPostForm(NULL, $edit, t('Save and publish')); + $node = $this->getNodeByTitle('NodeTitle'); + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_add_to_library'); + $this->drupalGet('/admin/content/paragraphs'); + $this->assertText('Text'); + $this->assertText('Random text for testing converting into library.'); + } + } diff --git a/paragraphs_collection.libraries.yml b/paragraphs_collection.libraries.yml index 298bdec..0542477 100644 --- a/paragraphs_collection.libraries.yml +++ b/paragraphs_collection.libraries.yml @@ -1,9 +1,9 @@ overview: css: component: - css/overview.css: {} + css/overview.admin.css: {} js: - js/overview.js: {} + js/overview.admin.js: {} dependencies: - core/drupal - core/jquery diff --git a/src/Controller/OverviewController.php b/src/Controller/OverviewController.php index 7d7be15..8ebda6b 100644 --- a/src/Controller/OverviewController.php +++ b/src/Controller/OverviewController.php @@ -40,29 +40,46 @@ class OverviewController extends ControllerBase { protected $styleDiscovery; /** - * A nested array of grid layout machine names. + * A nested array of Paragraphs Type objects. * - * The first level is keyed by Paragraphs Type IDs. The second-level keys have - * no meaning. The second-level values are machine names of the grid layouts - * that the first-level key Paragraphs Type has enabled. - * Exception: An empty second-level array means that all layouts are enabled - * for that Paragraphs Type. + * A nested array. The first level is keyed by grid layout machine names. The + * second level is keyed Paragraphs Type IDs. The second-level values are + * Paragraphs Type objects that allow the respective grid layout. Grid layouts + * are ordered by name. + * + * Example: + * @code + * [ + * '1_2_1_column_layout' => [ + * 'grid_pt' => $grid_paragraphs_type_object, + * ] + * ] + * @endcode * * @var array */ - protected $gridLayoutsOrderedByParagraphsTypes; + protected $paragraphsTypesGroupedByGridLayouts; /** - * An array of style group machine names keyed by Paragraphs Type IDs. + * A nested array of Paragraphs Type objects. + * + * A nested array. The first level is keyed by style machine names. The second + * level is keyed Paragraphs Type IDs. The second-level values are Paragraphs + * Type objects that allow the respective grid layout. Styles are ordered by + * name. * - * Each Paragraph Type has the style group is uses as the value. - * Exception: An empty string as the value means that all style groups are - * enabled for that Paragraphs Type. + * Example: + * @code + * [ + * 'blue_style' => [ + * 'style_pt' => $style_paragraphs_type_object, + * ] + * ] + * @endcode * * @var array */ - protected $styleGroupsOrderedByParagraphsTypes; - + protected $paragraphsTypesGroupedByStyles; /** * Constructs a \Drupal\paragraphs_collection\Controller\OverviewController object. @@ -88,105 +105,121 @@ class OverviewController extends ControllerBase { } /** - * Lists Paragraphs Types with the grid layouts they allow. + * Lists grid layouts with the Paragraphs Types that allow them. * * @return array - * A nested array. The first level is keyed by Paragraphs Type IDs. The - * second-level keys have no meaning. The second-level values are machine - * names of the grid layouts that the first-level key Paragraphs Type has - * enabled. - * Exception: An empty second-level array means that all layouts are enabled - * for that Paragraphs Type. + * A nested array. The first level is keyed by grid layout machine names. + * The second level is keyed Paragraphs Type IDs. The second-level values + * are Paragraphs Type objects that allow the respective grid layout. Grid + * layouts are ordered by name. + * Example: + * @code + * [ + * '1_2_1_column_layout' => [ + * 'grid_pt' => $grid_paragraphs_type_object, + * ] + * ] + * @endcode */ - protected function getGridLayoutsOrderedByParagraphsTypes() { - if (isset($this->gridLayoutsOrderedByParagraphsTypes)) { - return $this->gridLayoutsOrderedByParagraphsTypes; + public function getParagraphsTypesGroupedByGridLayouts() { + if (isset($this->paragraphsTypesGroupedByGridLayouts)) { + return $this->paragraphsTypesGroupedByGridLayouts; } $paragraph_type_ids = \Drupal::entityQuery('paragraphs_type')->execute(); - $paragraphs_types_enabled = []; - foreach ($paragraph_type_ids as $paragraph_type_id) { + $paragraphs_types = ParagraphsType::loadMultiple($paragraph_type_ids); + + // Find all enabled grid layouts for each Paragraphs Type. + // An empty array as the second-level value means that all grid layouts are + // enabled for that Paragraphs type. + $grid_layouts_grouped_by_paragraphs_types = []; + foreach ($paragraphs_types as $paragraph_type_id => $paragraphs_type) { /** @var ParagraphsType $paragraphs_type */ - $paragraphs_type = ParagraphsType::load($paragraph_type_id); $configuration = $paragraphs_type->getBehaviorPlugin('grid_layout')->getConfiguration(); if (isset($configuration['enabled']) && $configuration['enabled']) { - $paragraphs_types_enabled[$paragraph_type_id] = []; + $grid_layouts_grouped_by_paragraphs_types[$paragraph_type_id] = []; foreach ($configuration['available_grid_layouts'] as $key => $value) { if ($value) { - $paragraphs_types_enabled[$paragraph_type_id][] = $key; + $grid_layouts_grouped_by_paragraphs_types[$paragraph_type_id][] = $key; } } } } - return $this->gridLayoutsOrderedByParagraphsTypes = $paragraphs_types_enabled; + + //Get all grid layouts ordered by title. + $layouts = $this->gridLayoutDiscovery->getGridLayouts(); + uasort($layouts, function ($layout1, $layout2) { + return strcasecmp($layout1['title'], $layout2['title']); + }); + + // Group Paragraphs Types by grid layouts. + $paragraphs_types_grouped_by_grid_layouts = []; + foreach ($layouts as $layout_id => $layout) { + foreach ($grid_layouts_grouped_by_paragraphs_types as $paragraphs_type_id => $enabled_layouts) { + if ($enabled_layouts == [] || in_array($layout_id, $enabled_layouts)) { + $paragraphs_types_grouped_by_grid_layouts[$layout_id][$paragraphs_type_id] = $paragraphs_types[$paragraphs_type_id]; + } + } + } + + return $this->paragraphsTypesGroupedByGridLayouts = $paragraphs_types_grouped_by_grid_layouts; } /** - * Lists Paragraphs Types with the style groups they use. + * Lists styles with the Paragraphs Types that allow them. * * @return array - * An array of style group machine names keyed by Paragraphs Type IDs. Each - * Paragraph Type has the style group is uses as the value. - * Exception: An empty string as the value means that all style groups are - * enabled for that Paragraphs Type. + * A nested array. The first level is keyed by style machine names. The + * second level is keyed Paragraphs Type IDs. The second-level values are + * Paragraphs Type objects that allow the respective grid layout. Styles + * are ordered by name. + * Example: + * @code + * [ + * 'blue_style' => [ + * 'style_pt' => $style_paragraphs_type_object, + * ] + * ] + * @endcode */ - protected function getStyleGroupsOrderedByParagraphsTypes() { - if (isset($this->styleGroupsOrderedByParagraphsTypes)) { - return $this->styleGroupsOrderedByParagraphsTypes; + public function getParagraphsTypesGroupedByStyles() { + if (isset($this->paragraphsTypesGroupedByStyles)) { + return $this->paragraphsTypesGroupedByStyles; } $paragraph_type_ids = \Drupal::entityQuery('paragraphs_type')->execute(); - $paragraphs_types_enabled = []; - foreach ($paragraph_type_ids as $paragraph_type_id) { + $paragraphs_types = ParagraphsType::loadMultiple($paragraph_type_ids); + + // Find the used style group for each Paragraphs Type. + // An as empty string as the second-level value means that the Paragraphs + // Type uses all style groups. + $styles_grouped_by_paragraphs_types = []; + foreach ($paragraphs_types as $paragraph_type_id => $paragraphs_type) { /** @var ParagraphsType $paragraphs_type */ - $paragraphs_type = ParagraphsType::load($paragraph_type_id); $configuration = $paragraphs_type->getBehaviorPlugin('style')->getConfiguration(); if (isset($configuration['enabled']) && $configuration['enabled']) { - $paragraphs_types_enabled[$paragraph_type_id] = $configuration['group']; + $styles_grouped_by_paragraphs_types[$paragraph_type_id] = $configuration['group']; } } - return $this->styleGroupsOrderedByParagraphsTypes = $paragraphs_types_enabled; - } - /** - * Finds all Paragraphs Types which allow a particular grid layout behaviour. - * - * @param string $layout - * The machine name of the grid layout. - * - * @return array - * Array of IDs of Paragraphs Types that use the grid layout. - */ - public function getParagraphsTypesPerLayout($layout) { - $paragraphs_types = []; - foreach ($this->getGridLayoutsOrderedByParagraphsTypes() as $paragraphs_type => $enabled_layouts) { - if ($enabled_layouts == [] || in_array($layout, $enabled_layouts)) { - $paragraphs_types[] = $paragraphs_type; - } - } - - return $paragraphs_types; - } + //Get all styles ordered by title. + $styles = $this->styleDiscovery->getStyles(); + uasort($styles, function ($style1, $style2) { + return strcasecmp($style1['title'], $style2['title']); + }); - /** - * Finds all Paragraphs Types which allow a particular style behaviour. - * - * @param string $style - * The machine name of the style. - * - * @return array - * Array of IDs of Paragraphs Types that use the style. - */ - public function getParagraphsTypesPerStyle($style) { - $paragraphs_types = []; - foreach ($this->getStyleGroupsOrderedByParagraphsTypes() as $paragraphs_type => $used_style_group) { - $enabled_styles = array_keys($this->styleDiscovery->getStyleOptions($used_style_group)); - if (in_array($style, $enabled_styles)) { - $paragraphs_types[] = $paragraphs_type; + // Group Paragraphs Types by styles. + $paragraphs_types_grouped_by_styles = []; + foreach ($styles as $style_id => $style) { + foreach ($styles_grouped_by_paragraphs_types as $paragraphs_type_id => $used_style_group) { + $enabled_styles = array_keys($this->styleDiscovery->getStyleOptions($used_style_group)); + if (in_array($style_id, $enabled_styles)) { + $paragraphs_types_grouped_by_styles[$style_id][$paragraphs_type_id] = $paragraphs_types[$paragraphs_type_id]; + } } } - return $paragraphs_types; + return $this->paragraphsTypesGroupedByStyles = $paragraphs_types_grouped_by_styles; } /** @@ -196,6 +229,25 @@ class OverviewController extends ControllerBase { * The output render array. */ public function layouts() { + $filters = [ + '#type' => 'fieldset', + '#attributes' => [ + 'class' => ['table-filter', 'js-show', 'form--inline'], + 'data-table' => '.paragraphs-collection-overview-table', + ], + '#title' => $this->t('Filter'), + ]; + $filters['text'] = [ + '#type' => 'search', + '#title' => $this->t('Grid layout label or ID'), + '#size' => 40, + '#attributes' => [ + 'class' => ['table-filter-text'], + 'autocomplete' => 'off', + 'title' => $this->t('Enter a part of the style label or ID to filter by.'), + ], + ]; + $header = [ 'label' => $this->t('Grid layout'), 'details' => $this->t('Details'), @@ -203,17 +255,14 @@ class OverviewController extends ControllerBase { ]; $layouts = $this->gridLayoutDiscovery->getGridLayouts(); - uasort($layouts, function ($layout1, $layout2) { - return strcasecmp($layout1['title'], $layout2['title']); - }); - $rows =[]; - foreach ($layouts as $layout_id => $layout) { - $paragraphs_type_ids = $this->getParagraphsTypesPerLayout($layout_id); + $rows = []; + foreach ($this->getParagraphsTypesGroupedByGridLayouts() as $layout_id => $value) { + $layout = $layouts[$layout_id]; $paragraphs_type_link_list = []; - foreach ($paragraphs_type_ids as $paragraphs_type_id) { - $paragraphs_type = ParagraphsType::load($paragraphs_type_id); + foreach ($value as $paragraphs_type_id => $paragraphs_type) { + /** @var ParagraphsType $paragraphs_type */ if($paragraphs_type_link_list != []) { $paragraphs_type_link_list[] = ['#plain_text' => ', ']; @@ -230,23 +279,26 @@ class OverviewController extends ControllerBase { } $row['label'] = [ - '#type' => 'markup', - '#markup' => Html::escape($layout['title']), - '#prefix' => '', - '#suffix' => '', + '#type' => 'container', + '#plain_text' => $layout['title'], + '#attributes' => ['class' => ['table-filter-text-source']], ]; $row['details'] = [ '#type' => 'details', - '#title' => $this->t($layout['description']) ?: $this->t('Details'), + '#title' => $layout['description'] ?: $this->t('Description not available.'), '#open' => FALSE, '#attributes' => ['class' => ['overview-details']], ]; $row['details']['id'] = [ '#type' => 'item', '#title' => $this->t('ID'), - '#markup' => ''. Html::escape($layout_id) . '', - '#prefix' => '
    ', - '#suffix' => '
    ', + '#prefix' => '', + '#suffix' => '', + 'item' => [ + '#type' => 'container', + '#plain_text' => $layout_id, + '#attributes' => ['class' => ['table-filter-text-source']], + ], ]; $row['use'] = $paragraphs_type_link_list; @@ -263,18 +315,43 @@ class OverviewController extends ControllerBase { ]; $table += $rows; + $build['filters'] = $filters; + $build['table'] = $table; + $build['#attached']['library'] = ['paragraphs_collection/overview']; + + return $build; + } + + /** + * Generates an overview page of available styles for the styles plugin. + * + * @return array + * The output render array. + */ + public function styles() { + $group_options = $this->styleDiscovery->getStyleGroups(); + asort($group_options); + $empty_option = ['' => '- All -']; + $filters = [ '#type' => 'fieldset', '#attributes' => [ 'class' => ['table-filter', 'js-show', 'form--inline'], 'data-table' => '.paragraphs-collection-overview-table', ], - '#weight' => -10, '#title' => $this->t('Filter'), ]; + $filters['group'] = [ + '#type' => 'select', + '#title' => $this->t('Group'), + '#options' => $empty_option + $group_options, + '#attributes' => [ + 'class' => ['table-filter-group-select'], + ], + ]; $filters['text'] = [ '#type' => 'search', - '#title' => $this->t('Grid layout label or ID'), + '#title' => $this->t('Style label or ID'), '#size' => 40, '#attributes' => [ 'class' => ['table-filter-text'], @@ -283,21 +360,6 @@ class OverviewController extends ControllerBase { ], ]; - $build['table'] = $table; - $build['filters'] = $filters; - $build['#attached']['library'] = ['paragraphs_collection/overview']; - - return $build; - } - - - /** - * Generates an overview page of available styles for the styles plugin. - * - * @return array - * The output render array. - */ - public function styles() { $header = [ 'label' => $this->t('Style'), 'details' => $this->t('Details'), @@ -305,17 +367,14 @@ class OverviewController extends ControllerBase { ]; $styles = $this->styleDiscovery->getStyles(); - uasort($styles, function ($style1, $style2) { - return strcasecmp($style1['title'], $style2['title']); - }); - $rows =[]; - foreach ($styles as $style_id => $style) { - $paragraphs_type_ids = $this->getParagraphsTypesPerStyle($style_id); + $rows = []; + foreach ($this->getParagraphsTypesGroupedByStyles() as $style_id => $value) { + $style = $styles[$style_id]; $paragraphs_type_link_list = []; - foreach ($paragraphs_type_ids as $paragraphs_type_id) { - $paragraphs_type = ParagraphsType::load($paragraphs_type_id); + foreach ($value as $paragraphs_type_id => $paragraphs_type) { + /** @var ParagraphsType $paragraphs_type */ if($paragraphs_type_link_list != []) { $paragraphs_type_link_list[] = ['#plain_text' => ', ']; @@ -337,31 +396,33 @@ class OverviewController extends ControllerBase { $group_list[] = ['#plain_text' => ', ']; } $group_list[] = [ - '#type' => 'markup', - '#markup' => Html::escape($group), - '#prefix' => '', - '#suffix' => '', + '#type' => 'container', + '#plain_text' => $group, + '#attributes' => ['class' => ['table-filter-group-source']], ]; } $row['label'] = [ - '#type' => 'markup', - '#markup' => Html::escape($style['title']), - '#prefix' => '', - '#suffix' => '', + '#type' => 'container', + '#plain_text' => $style['title'], + '#attributes' => ['class' => ['table-filter-text-source']], ]; $row['details'] = [ '#type' => 'details', - '#title' => $this->t($style['description']) ?: $this->t('Details'), + '#title' => $style['description'] ?: $this->t('Description not available.'), '#open' => FALSE, '#attributes' => ['class' => ['overview-details']], ]; $row['details']['id'] = [ '#type' => 'item', '#title' => $this->t('ID'), - '#markup' => ''. Html::escape($style_id) . '', - '#prefix' => '
    ', - '#suffix' => '
    ', + '#prefix' => '', + '#suffix' => '', + 'item' => [ + '#type' => 'container', + '#plain_text' => $style_id, + '#attributes' => ['class' => ['table-filter-text-source']], + ], ]; $row['details']['groups'] = [ '#type' => 'item', @@ -385,40 +446,8 @@ class OverviewController extends ControllerBase { ]; $table += $rows; - $group_options = $this->styleDiscovery->getStyleGroups(); - asort($group_options); - $empty_option = ['' => '- All -']; - - $filters = [ - '#type' => 'fieldset', - '#attributes' => [ - 'class' => ['table-filter', 'js-show', 'form--inline'], - 'data-table' => '.paragraphs-collection-overview-table', - ], - '#weight' => -10, - '#title' => $this->t('Filter'), - ]; - $filters['group'] = [ - '#type' => 'select', - '#title' => $this->t('Group'), - '#options' => $empty_option + $group_options, - '#attributes' => [ - 'class' => ['table-filter-group-select'], - ], - ]; - $filters['text'] = [ - '#type' => 'search', - '#title' => $this->t('Style label or ID'), - '#size' => 40, - '#attributes' => [ - 'class' => ['table-filter-text'], - 'autocomplete' => 'off', - 'title' => $this->t('Enter a part of the style label or ID to filter by.'), - ], - ]; - - $build['table'] = $table; $build['filters'] = $filters; + $build['table'] = $table; $build['#attached']['library'] = ['paragraphs_collection/overview']; return $build;