Skip to content
Snippets Groups Projects

ISTWCMS-4866: moving the heading selector for ec outside the individual ec...

1 file
+ 1
1
Compare changes
  • Side-by-side
  • Inline
+ 588
0
<?php
namespace Drupal\uw_custom_blocks\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* UW custom block expand collapse.
*
* @Block(
* id = "uw_cbl_expand_collapse",
* admin_label = @Translation("Expand Collapse"),
* )
*/
class UwCblExpandCollapse extends BlockBase implements ContainerFactoryPluginInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The variable for current path.
*
* @var \Drupal\Core\Path\CurrentPathStack
*/
protected $currentPath;
/**
* Constructs a BlockComponentRenderArray object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin ID for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Path\CurrentPathStack $currentPath
* The currentPath.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, CurrentPathStack $currentPath) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
$this->currentPath = $currentPath;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity_type.manager'), $container->get('path.current'));
}
/**
* {@inheritdoc}
*/
public function build() {
// Get the ecs from configuration.
$ecs = $this->configuration['ecs'];
// Step through each of the e/c sections and get out the
// layout builder from the e/c section node.
foreach ($ecs as $ec) {
if (isset($ec['group'])) {
// Load the node.
$node = $this->entityTypeManager->getStorage('node')->load($ec['group']);
// Ensure that we have a node that is loaded, this check
// is here in case someone deletes a E/C node.
if ($node && $node->isPublished()) {
// Get the sections from the layout builder.
$sections = $node->get('layout_builder__layout')->getSections();
// Reset the render array so that we do not get duplicates.
$render = [];
// Step through each of the sections and get the
// render arrays.
foreach ($sections as $section) {
$render[] = $section->toRenderArray();
}
// Set the variables to be used in the template.
$exp_col['items'][] = [
'groups' => $render,
'heading_text' => $node->label(),
];
}
}
}
// Set the flag to show the exp/col all buttons.
if (count($ecs) > 1) {
$exp_col['show_exp_col_all'] = TRUE;
}
else {
$exp_col['show_exp_col_all'] = FALSE;
}
// Set the uuid so that we can handle multiple E/C.
$exp_col['uuid'] = uniqid();
// Get the heading selector from the block configuration.
$exp_col['heading_selector'] = $this->configuration['heading_selector'];
return [
'#theme' => 'uw_block_expand_collapse',
'#exp_col' => $exp_col,
];
}
/**
* {@inheritdoc}
*/
public function blockForm($form, FormStateInterface $form_state) {
// Adding the ability to do ajax forms.
$form['#tree'] = TRUE;
// Setup the add_more_called flag, so that we know
// which of the items to load.
// If we even do one add or remove, we set this flag
// so that the form will load the values from the
// form_state, if flag is not set, it will load
// from the block config.
if (empty($form_state->get('add_more_called'))) {
$add_more_called = FALSE;
$form_state->set('add_more_called', $add_more_called);
}
else {
$add_more_called = $form_state->get('add_more_called');
}
// If the add_more_flag is not set, we load from the
// block config. If it is set, we load from the form_state.
if (!$add_more_called) {
$ecs = $this->configuration['ecs'] ?? NULL;
$form_state->set('ecs', $ecs);
}
else {
$ecs = $form_state->get('ecs');
}
// Get the num_of_rows from the form_state.
$num_of_rows = $form_state->get('num_of_rows');
// If the num_of_rows is not set, we first look at
// the block config and see if we have ecs, and if
// so set num_of_rows to the number of ecs. If we
// do not have num_of_rows set, default to 1 (this is
// the first load of the form).
if (empty($num_of_rows)) {
if (isset($ecs)) {
$num_of_rows = count($ecs);
}
else {
$num_of_rows = 1;
}
}
// Reset the node since we used it above and if we don't
// we get a node loaded in the e/c section on first form load.
$node = NULL;
// Set the num_of_rows to the form_state so that we
// can use it in the ajax calls.
$form_state->set('num_of_rows', $num_of_rows);
// The class to be used for groups.
$group_class = 'group-order-weight';
// The field set for the E/C groups.
$form['items_fieldset'] = [
'#type' => 'fieldset',
'#title' => $this->t('Expand/collapse groups'),
'#prefix' => '<div id="items-wrapper">',
'#suffix' => '</div>',
];
// The heading selector element.
$form['items_fieldset']['heading_selector'] = [
'#title' => $this->t('Heading selector'),
'#type' => 'select',
'#options' => [
'h2' => $this->t('h2'),
'h3' => $this->t('h3'),
'h4' => $this->t('h4'),
'h5' => $this->t('h5'),
'h6' => $this->t('h6'),
],
'#default_value' => $this->configuration['heading_selector'] ?? '',
'#required' => TRUE,
];
// Build the table.
$form['items_fieldset']['items'] = [
'#type' => 'table',
'#header' => [
'',
$this->t('Group'),
'',
$this->t('Weight'),
],
'#empty' => $this->t('No items.'),
'#tableselect' => FALSE,
'#tabledrag' => [
[
'action' => 'order',
'relationship' => 'sibling',
'group' => $group_class,
],
],
'#prefix' => '<div class="uw-exp-col__table">',
'#suffix' => '</div>',
];
for ($i = 0; $i < $num_of_rows; $i++) {
// Reset the settings array.
$settings = [];
// Set the table to be draggable.
$settings['#attributes']['class'][] = 'draggable';
// Set the weight.
$settings['#weight'] = $i;
// Reset null so that we dont get a value if there is a
// blank row in the table.
$node = NULL;
// If there is an e/c group, load in the node. If
// there is not, we are on a add more call with no group
// set yet.
if (isset($ecs[$i]['group']) && $ecs[$i]['group'] !== NULL) {
// Load the node based on the nid.
$node = $this->entityTypeManager->getStorage('node')->load($ecs[$i]['group']);
}
// The first column of the table, that will house the arrows
// for rearranging e/c groups.
$settings['arrow'] = [
'#type' => 'markup',
'#markup' => '',
'#title_display' => 'invisible',
];
// Container for the group.
$settings['group_info'] = [
'#type' => 'container',
'#prefix' => '<div class="uw-exp-col__group-info">',
'#suffix' => '</div>',
];
// Wrapper id for the operations links.
$wrapper_id = 'operations-wrapper-' . $i;
// The group element, which is an autocomplete using the nid
// of a uw_ct_expand_collapse_group content type.
$settings['group_info']['group'] = [
'#type' => 'entity_autocomplete',
'#target_type' => 'node',
'#tags' => TRUE,
'#default_value' => $node ?? '',
'#selection_settings' => [
'target_bundles' => ['uw_ct_expand_collapse_group'],
],
'#title' => '',
'#attributes' => [
'class' => ['uw-exp-col__group'],
],
'#ajax' => [
'callback' => [$this, 'updateOperationsLinks'],
'disable-refocus' => FALSE,
'event' => 'change',
'wrapper' => $wrapper_id,
'element_id' => $i,
],
'#prefix' => '<div class="form-required">',
'#suffix' => '</div>',
];
// The container for the operations.
$settings['group_info']['operations_wrapper'] = [
'#type' => 'container',
'#prefix' => '<div id="' . $wrapper_id . '">',
'#suffix' => '</div>',
];
// Get the operations links based on if this has a group.
if (isset($ecs[$i]['group'])) {
$links = $this->uwExpandCollapseGetOperationsLinks($ecs[$i]['group']);
}
else {
$links = $this->uwExpandCollapseGetOperationsLinks();
}
// The operations links.
$settings['group_info']['operations_wrapper']['operations'] = [
'#type' => 'markup',
'#markup' => $links,
];
// The add expand/collapse remove group button.
$settings['button'] = [
'#type' => 'submit',
'#value' => $this->t('Remove'),
'#submit' => [[$this, 'expandCollapseRemoveOne']],
'#ajax' => [
'callback' => [$this, 'expandCollapseCallback'],
'wrapper' => 'items-wrapper',
'element_id' => $i,
],
'#attributes' => [
'class' => ['button--small'],
],
];
// The weight element.
$settings['weight'] = [
'#type' => 'weight',
'#title_display' => 'invisible',
'#default_value' => $i,
'#attributes' => ['class' => [$group_class]],
];
// Add the settings to the items array, which is full row
// in the table.
$form['items_fieldset']['items'][] = $settings;
}
// The add expand/collapse group button.
$form['add_group'] = [
'#type' => 'submit',
'#value' => $this->t('Add expand/collapse group'),
'#submit' => [[$this, 'expandCollapseAddOne']],
'#ajax' => [
'callback' => [$this, 'expandCollapseCallback'],
'wrapper' => 'items-wrapper',
],
'#attributes' => [
'class' => ['button--large'],
],
];
return $form;
}
/**
* Ajax callback to update the operations links.
*
* @param array $form
* The form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @return mixed
* Array of elements to be used for replacement.
*/
public function updateOperationsLinks(array &$form, FormStateInterface $form_state) {
// Get the triggering element.
$triggering_element = $triggering_element = $form_state->getTriggeringElement();
// From the triggering element, get the element id, which
// allow us to get the nid.
$element_id = $triggering_element['#ajax']['element_id'];
// Get the values from the form state.
$values = $form_state->getValues();
$nid = $values['settings']['items_fieldset']['items'][$element_id]['group_info']['group'][0]['target_id'];
$form['settings']['items_fieldset']['items'][$element_id]['group_info']['operations_wrapper']['operations']['#markup'] = $this->uwExpandCollapseGetOperationsLinks($nid);
return $form['settings']['items_fieldset']['items'][$element_id]['group_info']['operations_wrapper'];
}
/**
* Add one more e/c section to the form.
*
* @param array $form
* The form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
public function expandCollapseAddOne(array &$form, FormStateInterface $form_state) {
// Increase by 1 the number of rows and set it in
// the form_state.
$num_of_rows = $form_state->get('num_of_rows');
$num_of_rows++;
$form_state->set('num_of_rows', $num_of_rows);
// Set the add_more_called flag, so that we will load
// the items by form_state, rather than block config.
$form_state->set('add_more_called', TRUE);
// Get the current values of the form_state.
$values = $form_state->getValues();
// Get the items from the form state, which will contain
// the e/c settings.
$items = $values['settings']['items_fieldset']['items'];
// Step through each of the items and set values to be used
// in the ecs block config.
foreach ($items as $item) {
$ecs[] = [
'heading_selector' => $item['heading_selector'],
'group' => $item['group_info']['group'][0]['target_id'],
];
}
// Set the ecs from the items in the form_state, so that we
// will load newly added values.
$form_state->set('ecs', $ecs);
// Rebuild form with 1 extra row.
$form_state->setRebuild();
}
/**
* Remove one e/c section from the form.
*
* @param array $form
* The form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
public function expandCollapseRemoveOne(array &$form, FormStateInterface $form_state) {
// Get the triggering element, so that we can get
// which element we need to remove.
$triggering_element = $form_state->getTriggeringElement();
// Get the element id from the triggering element.
$element_id = $triggering_element['#ajax']['element_id'];
// Get the current values of the form_state.
$values = $form_state->getValues();
$ecs = $values['settings']['items_fieldset']['items'];
unset($ecs[$element_id]);
// Set the ecs from the items in the form_state, so that we
// will load newly added values.
$form_state->set('ecs', $ecs);
// Decrement the num_of_rows, since we are removing one.
$num_of_rows = $form_state->get('num_of_rows');
$num_of_rows--;
$form_state->set('num_of_rows', $num_of_rows);
// Set the add_more_called flag, so that we will load
// the items by form_state, rather than block config.
$form_state->set('add_more_called', TRUE);
// Rebuild form with 1 extra row.
$form_state->setRebuild();
}
/**
* The ajax call back for expand/collapse remove one.
*
* @param array $form
* The form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @return mixed
* The form element to be overwritten.
*/
public function expandCollapseCallback(array &$form, FormStateInterface $form_state) {
return $form['settings']['items_fieldset'];
}
/**
* {@inheritdoc}
*/
public function blockSubmit($form, FormStateInterface $form_state) {
// Load in the values from the form_sate.
$values = $form_state->getValues();
// Get the items from the form_state.
$items = $values['items_fieldset']['items'];
// Set the heading selector.
$this->configuration['heading_selector'] = $values['items_fieldset']['heading_selector'];
// Setup ecs array, we need to default to null in case
// nothing is submitted in the form.
$ecs = [];
// Step through each of the items and set values to be used
// in the ecs block config.
foreach ($items as $item) {
$ecs[] = [
'group' => $item['group_info']['group'][0]['target_id'],
];
}
// Save the ecs in the block config.
$this->configuration['ecs'] = $ecs;
}
/**
* Function to get the links for the operations of e/c.
*
* @param int|null $nid
* The nid of the section, if there is one.
*
* @return string
* The HTML string containing the links.
*/
public function uwExpandCollapseGetOperationsLinks(int $nid = NULL): string {
// Start the HTML for the operations links.
$links = '<ul class="uw-exp-col__operations">';
// If we have a nid, then add edit and view links.
// If there is no nid, only use add link.
if ($nid) {
// Get the correct URL to the node, no matter where we are.
$url = Url::fromRoute('entity.node.canonical', ['node' => $nid])->toString();
// The URL to the pencil icon.
$pencil_icon = '/' . drupal_get_path('module', 'uw_custom_blocks') . '/images/pencil.png';
$pencil_icon = Url::fromUri('internal:' . $pencil_icon, ['absolute' => TRUE])->toString();
// The URL for the view icon.
$view_icon = '/' . drupal_get_path('module', 'uw_custom_blocks') . '/images/view.png';
$view_icon = Url::fromUri('internal:' . $view_icon, ['absolute' => TRUE])->toString();
$links .= '<li>';
$links .= '<a href="' . $url . '/layout" target="_blank">';
$links .= '<img src="' . $pencil_icon . '" alt="edit expand/collapse group" />';
$links .= '</a>';
$links .= '</li>';
$links .= '<li>';
$links .= '<a class="use-ajax" data-dialog-options="{&quot;width&quot;:800}" data-dialog-type="modal" href="' . $url . '">';
$links .= '<img src="' . $view_icon . '" alt="add new expand/collapse group" />';
$links .= '</a>';
$links .= '</li>';
}
else {
// The URL for the plus icon.
$plus_icon = '/' . drupal_get_path('module', 'uw_custom_blocks') . '/images/plus.png';
$plus_icon = Url::fromUri('internal:' . $plus_icon, ['absolute' => TRUE])->toString();
// Get the correct URL to the add node, no matter where we are.
$url = Url::fromRoute('node.add', ['node_type' => 'uw_ct_expand_collapse_group'])->toString();
$links .= '<li>';
$links .= '<a href="' . $url . '" target="_blank">';
$links .= '<img src="' . $plus_icon . '" alt="add new expand/collapse group" />';
$links .= '</a>';
$links .= '</li>';
}
// Close the ul in the HTML.
$links .= '</ul>';
// Return the HTML for the operations links.
return $links;
}
}
Loading