bricks-2.x-dev/bricks.module
bricks.module
<?php use Drupal\bricks\Bricks; use Drupal\bricks\BricksFieldItemInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element; /** * Prepares variables for `field.html.twig`. */ function bricks_preprocess_field(&$variables) { $element = $variables['element']; if (substr($element['#formatter'], 0, 7) === 'bricks_') { $variables['items'] = [ [ 'content' => Bricks::nestItems($variables['items'], $variables['element']['#items']), ], ]; } } /* BRICKS EDITING */ /** * Implements hook_field_widget_info_alter(). */ function bricks_field_widget_info_alter(array &$info) { // Let Bricks to re-use ANY Entity Reference -compatible widgets: foreach ($info as $widget_id => &$widget_info) { if (in_array('entity_reference', $widget_info['field_types'])) { $widget_info['field_types'][] = 'bricks'; } if (in_array('entity_reference_revisions', $widget_info['field_types'])) { $widget_info['field_types'][] = 'bricks_revisioned'; } } } /** * Implements hook_field_widget_WIDGET_TYPE_form_alter() for * `entity_reference_autocomplete`. */ function bricks_field_widget_entity_reference_autocomplete_form_alter(&$element, FormStateInterface $form_state, $context) { $field_type = $context['items']->getFieldDefinition()->getType(); // @TODO: Replace by 'Nested bricks' widget setting. if (in_array($field_type, ['bricks'])) { // @TODO: Find a better way to be used in _bricks_preprocess_tabledrag_form(). $element['#widget'] = 'entity_reference_autocomplete'; // #default_value is en Entity or NULL. _bricks_form_element_alter($element, $context['items'][$context['delta']], $element['target_id']['#default_value']); hide($element['depth']); } } /** * Implements hook_field_widget_WIDGET_TYPE_form_alter() for * `bricks_tree_autocomplete`. */ function bricks_field_widget_bricks_tree_autocomplete_form_alter(&$element, FormStateInterface $form_state, $context) { bricks_field_widget_entity_reference_autocomplete_form_alter($element, $form_state, $context); } /** * Prepares variables for `field-multiple-value-form.html.twig`. */ function bricks_preprocess_field_multiple_value_form(&$variables) { _bricks_preprocess_tabledrag_form($variables, 'element', 'entity_reference_autocomplete', $variables['element']['#field_name'] . '-delta-order'); } /** * Helper function for hook_preprocess_field_multiple_value_form(). */ function _bricks_preprocess_tabledrag_form(&$variables, $element_key, $widget, $order_class, $render_options = FALSE) { $element = $variables[$element_key]; $operation_key = NULL; // @TODO: Replace by 'Nested bricks' widget setting. if (isset($element['#widget']) && $element['#widget'] == $widget || isset($element[0]['#widget']) && $element[0]['#widget'] == $widget) { // @TODO: Tmp hack for the proper indent width calculation. $variables['table']['#header'][0]['style'] = 'min-width: 150px'; $variables['table']['#header'][] = ['data' => t('Depth'), 'class' => ['bricks-depth-header']]; if ($render_options) { // Find Operations column $operation_key = array_filter($variables['table']['#header'], function($item) { return isset($item['is_operation']); }); if (!empty($operation_key) && is_array($operation_key)) { $operation_key = array_keys($operation_key); $operation_key = array_pop($operation_key); // Insert new options column before operations. array_splice($variables['table']['#header'], $operation_key, 0, [['data' => t('Options')]]); } } $row = 0; foreach (Element::children($element) as $i => $key) { if ($key !== 'add_more' && $key !== 'header_actions') { $depth = $element[$key]['depth']['#value']; $indentation = []; if ($depth > 0) { $indentation = [ '#theme' => 'indentation', '#size' => $depth, ]; } $drag_cell = &$variables['table']['#rows'][$row]['data'][0]; $drag_cell['data'] = !empty($indentation) ? \Drupal::service('renderer')->render($indentation) : '' . $drag_cell['data']; // @TODO $drag_cell['style'] = 'width: auto; min-width: 150px'; show($element[$key]['depth']); $variables['table']['#rows'][$row]['data'][] = \Drupal::service('renderer')->render($element[$key]['depth']); if ($render_options && !is_null($operation_key)) { // Insert data row in options column. array_splice($variables['table']['#rows'][$row]['data'], $operation_key, 0,[['data' => \Drupal::service('renderer')->render($element[$key]['options']), 'class' => 'inline-entity-form-brick-options']]); } } if ($key !== 'add_more') { $row++; } } $tabledrag_options = &$variables['table']['#tabledrag']; $tabledrag_options[0]['relationship'] = 'all'; $tabledrag_options[] = [ 'action' => 'depth', 'relationship' => 'group', 'group' => 'bricks-depth', ]; // Fake option to enable indentation: $tabledrag_options[] = [ 'action' => 'match', 'relationship' => 'parent', 'group' => $order_class, ]; $variables['table']['#attached']['library'][] = 'bricks/tabledrag.relationship-all'; } } /** * Helper function for widget's formElement(). */ function _bricks_form_element_alter(&$element, $item, $entity) { $element['depth'] = [ // @TODO: Other types break the correct indentations. '#type' => 'hidden', '#default_value' => !empty($item->depth) ? $item->depth : 0, '#weight' => 10, '#attributes' => [ 'class' => ['bricks-depth'], ], ]; $element['options'] = [ '#type' => 'container', '#weight' => 100, '#attributes' => [ 'class' => ['container-inline'], ], ]; if ($entity) { if ($entity->bundle() == 'layout' && \Drupal::service('module_handler')->moduleExists('layout_discovery')) { $element['options']['layout'] = [ '#type' => 'select', '#options' => \Drupal::service('plugin.manager.core.layout')->getLayoutOptions(), '#default_value' => !empty($item->options['layout']) ? $item->options['layout'] : NULL, ]; } if ($entity->bundle() != 'layout') { $element['options']['view_mode'] = [ '#type' => 'select', '#options' => \Drupal::service('entity_display.repository')->getViewModeOptionsByBundle($entity->getEntityTypeId(), $entity->bundle()), '#default_value' => !empty($item->options['view_mode']) ? $item->options['view_mode'] : NULL, ]; } } $element['options']['css_class'] = [ '#type' => 'textfield', '#default_value' => !empty($item->options['css_class']) ? $item->options['css_class'] : '', '#size' => 10, '#attributes' => [ 'placeholder' => t('CSS class(-es)'), ], ]; $element['options']['css_id'] = [ '#type' => 'textfield', '#default_value' => !empty($item->options['css_id']) ? $item->options['css_id'] : '', '#size' => 10, '#attributes' => [ 'placeholder' => t('CSS ID'), ], ]; } /* MISC */ /** * Prepares variables for `block.html.twig` for `system_powered_by_block`. */ function bricks_preprocess_block__system_powered_by_block(&$variables) { $bricks_link = '<a href="https://uibricks.com">Bricks</a>'; $variables['content']['#markup'] = str_replace('>Drupal</a>', '>Drupal</a> & ' . $bricks_link, $variables['content']['#markup']); } /** * Implements hook_entity_presave(). */ function bricks_entity_presave(EntityInterface $entity) { if ($entity instanceof FieldableEntityInterface) { foreach ($entity->getFields() as $field_item_list) { if ($field_item_list->get(0) instanceof BricksFieldItemInterface) { Bricks::correctDepths($field_item_list); } } } }