diff --git a/css/overview.css b/css/overview.css new file mode 100644 index 0000000..f53c610 --- /dev/null +++ b/css/overview.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/js/overview.js b/js/overview.js new file mode 100644 index 0000000..a11712f --- /dev/null +++ b/js/overview.js @@ -0,0 +1,67 @@ +/** + * @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/paragraphs_collection.libraries.yml b/paragraphs_collection.libraries.yml index bddd5ea..298bdec 100644 --- a/paragraphs_collection.libraries.yml +++ b/paragraphs_collection.libraries.yml @@ -1,3 +1,14 @@ +overview: + css: + component: + css/overview.css: {} + js: + js/overview.js: {} + dependencies: + - core/drupal + - core/jquery + - core/jquery.once + grid_layout: css: theme: diff --git a/paragraphs_collection.links.menu.yml b/paragraphs_collection.links.menu.yml new file mode 100644 index 0000000..70aeea3 --- /dev/null +++ b/paragraphs_collection.links.menu.yml @@ -0,0 +1,6 @@ +paragraphs_collection.layouts: + title: 'Paragraphs Collection' + parent: system.admin_reports + description: 'Overviews of items discoverable by behavior plugins.' + route_name: paragraphs_collection.layouts + menu_name: admin diff --git a/paragraphs_collection.links.task.yml b/paragraphs_collection.links.task.yml new file mode 100644 index 0000000..a7742b7 --- /dev/null +++ b/paragraphs_collection.links.task.yml @@ -0,0 +1,10 @@ +paragraphs_collection.layouts: + title: Layouts + route_name: paragraphs_collection.layouts + base_route: paragraphs_collection.layouts + +paragraphs_collection.styles: + title: Styles + route_name: paragraphs_collection.styles + base_route: paragraphs_collection.layouts + diff --git a/paragraphs_collection.routing.yml b/paragraphs_collection.routing.yml new file mode 100644 index 0000000..6a87acf --- /dev/null +++ b/paragraphs_collection.routing.yml @@ -0,0 +1,15 @@ +paragraphs_collection.layouts: + path: '/admin/reports/paragraphs_collection/layouts' + defaults: + _controller: '\Drupal\paragraphs_collection\Controller\OverviewController::layouts' + _title: 'Available grid layouts' + requirements: + _permission: 'administer paragraphs types' + +paragraphs_collection.styles: + path: '/admin/reports/paragraphs_collection/styles' + defaults: + _controller: '\Drupal\paragraphs_collection\Controller\OverviewController::styles' + _title: 'Available styles' + requirements: + _permission: 'administer paragraphs types' diff --git a/src/Controller/OverviewController.php b/src/Controller/OverviewController.php new file mode 100644 index 0000000..7d7be15 --- /dev/null +++ b/src/Controller/OverviewController.php @@ -0,0 +1,427 @@ +gridLayoutDiscovery = $grid_layout_discovery; + $this->styleDiscovery = $style_discovery; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('paragraphs_collection.grid_layout_discovery'), + $container->get('paragraphs_collection.style_discovery') + ); + } + + /** + * Lists Paragraphs Types with the grid layouts they allow. + * + * @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. + */ + protected function getGridLayoutsOrderedByParagraphsTypes() { + if (isset($this->gridLayoutsOrderedByParagraphsTypes)) { + return $this->gridLayoutsOrderedByParagraphsTypes; + } + + $paragraph_type_ids = \Drupal::entityQuery('paragraphs_type')->execute(); + $paragraphs_types_enabled = []; + foreach ($paragraph_type_ids as $paragraph_type_id) { + /** @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] = []; + foreach ($configuration['available_grid_layouts'] as $key => $value) { + if ($value) { + $paragraphs_types_enabled[$paragraph_type_id][] = $key; + } + } + } + } + return $this->gridLayoutsOrderedByParagraphsTypes = $paragraphs_types_enabled; + } + + /** + * Lists Paragraphs Types with the style groups they use. + * + * @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. + */ + protected function getStyleGroupsOrderedByParagraphsTypes() { + if (isset($this->styleGroupsOrderedByParagraphsTypes)) { + return $this->styleGroupsOrderedByParagraphsTypes; + } + + $paragraph_type_ids = \Drupal::entityQuery('paragraphs_type')->execute(); + $paragraphs_types_enabled = []; + foreach ($paragraph_type_ids as $paragraph_type_id) { + /** @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']; + } + } + 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; + } + + /** + * 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; + } + } + + return $paragraphs_types; + } + + /** + * Generates an overview page of available layouts for the grid layout plugin. + * + * @return array + * The output render array. + */ + public function layouts() { + $header = [ + 'label' => $this->t('Grid layout'), + 'details' => $this->t('Details'), + 'use' => $this->t('Used in'), + ]; + + $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); + + $paragraphs_type_link_list = []; + foreach ($paragraphs_type_ids as $paragraphs_type_id) { + $paragraphs_type = ParagraphsType::load($paragraphs_type_id); + + if($paragraphs_type_link_list != []) { + $paragraphs_type_link_list[] = ['#plain_text' => ', ']; + } + + $paragraphs_type_link_list[] = [ + '#type' => 'link', + '#title' => $paragraphs_type->label(), + '#url' => $paragraphs_type->toUrl(), + '#attributes' => [ + 'class' => ['table-filter-paragraphs-type-source'], + ], + ]; + } + + $row['label'] = [ + '#type' => 'markup', + '#markup' => Html::escape($layout['title']), + '#prefix' => '', + '#suffix' => '', + ]; + $row['details'] = [ + '#type' => 'details', + '#title' => $this->t($layout['description']) ?: $this->t('Details'), + '#open' => FALSE, + '#attributes' => ['class' => ['overview-details']], + ]; + $row['details']['id'] = [ + '#type' => 'item', + '#title' => $this->t('ID'), + '#markup' => ''. Html::escape($layout_id) . '', + '#prefix' => '