Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OEL-477: Create User profile card pattern, and field group custom form… #48

Open
wants to merge 11 commits into
base: 1.x
Choose a base branch
from
59 changes: 59 additions & 0 deletions modules/oe_whitelabel_helper/oe_whitelabel_helper.module
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,68 @@

declare(strict_types = 1);

use Drupal\Core\Template\Attribute;

/**
* Implements hook_locale_translation_projects_alter().
*/
function oe_whitelabel_helper_locale_translation_projects_alter(&$projects) {
$projects['oe_whitelabel_helper']['info']['interface translation server pattern'] = drupal_get_path('module', 'oe_whitelabel_helper') . '/translations/%project-%language.po';
}

/**
* Theme preprocess function for grid_field_formatter.
*
* This function essentially extends the core field module theming methods, in
* particular template_preprocess_field. It also introduces new field template
* suggestions such as:
* - field--two-column.tpl.php
* - field--two-column--[FIELD_TYPE].tpl.php
* - field--two-column--[FIELD_NAME].tpl.php
* - field--two-column--[FIELD_NAME]--[BUNDLE].tpl.php.
*
* @see field--two-column.tpl.php
*/
function oe_whitelabel_helper_field_formatter(&$variables, $hook) {
// Extend the core field module theming functions.
template_preprocess_field($variables, $hook);

// Add colummns number.
$number_of_columns = $variables['element']['#columns'];
$variables['columns'] = $number_of_columns;

// Build row attributes.
$variables['row_attributes'] = new Attribute([
'class' => ['row'],
]);

// Build column layout number.
$variables['column_layout'] = floor(12 / $number_of_columns);
}

/**
* Implements hook_theme_suggestions_HOOK().
*/
function oe_whitelabel_helper_theme_suggestions_field__two_column(array $variables) {
$suggestions = [];
$element = $variables['element'];

$suggestions[] = 'field__two_column' . $element['#field_type'];
$suggestions[] = 'field__two_column' . $element['#field_name'];
$suggestions[] = 'field__two_column' . $element['#entity_type'] . '__' . $element['#bundle'];
$suggestions[] = 'field__two_column' . $element['#entity_type'] . '__' . $element['#field_name'];
$suggestions[] = 'field__two_column' . $element['#entity_type'] . '__' . $element['#field_name'] . '__' . $element['#bundle'];

return $suggestions;
}

/**
* Implements hook_theme().
*/
function oe_whitelabel_helper_theme() {
return [
'field_oe_whitelabel_double_column_formatter' => [
'render element' => 'element',
],
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
<?php

declare(strict_types = 1);

namespace Drupal\oe_whitelabel_helper\Plugin\field_group\FieldGroupFormatter;

use Drupal\Component\Utility\Xss;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\Element;
use Drupal\field\FieldConfigInterface;
use Drupal\field_group\FieldGroupFormatterBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Plugin implementation of the 'multicolumn' formatter.
*
* @FieldGroupFormatter(
* id = "multicolumn",
* label = @Translation("Multicolumn formatter"),
* description = @Translation("Breaks fields evenly into two columns."),
* supported_contexts = {
* "view",
* }
* )
*/
class MultiColumn extends FieldGroupFormatterBase implements ContainerFactoryPluginInterface {
/**
* Module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;

/**
* The Entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;

/**
* Render API properties.
*
* @var array
*/
protected $renderApiProperties = [
'#theme',
'#markup',
'#prefix',
'#suffix',
'#type',
'widget',
];

/**
* Constructs a Popup object.
*
* @param string $plugin_id
* The plugin_id for the formatter.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param object $group
* The group object.
* @param array $settings
* The formatter settings.
* @param string $label
* The formatter label.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler service.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The Entity field manager.
*/
public function __construct($plugin_id, $plugin_definition, $group, array $settings, $label, ModuleHandlerInterface $module_handler, EntityFieldManagerInterface $entity_field_manager) {
parent::__construct($plugin_id, $plugin_definition, $group, $settings, $label);
$this->moduleHandler = $module_handler;
$this->entityFieldManager = $entity_field_manager;
}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$plugin_id,
$plugin_definition,
$configuration['group'],
$configuration['settings'],
$configuration['label'],
$container->get('module_handler'),
$container->get('entity_field.manager')
);
}

/**
* {@inheritdoc}
*/
public static function defaultContextSettings($context): array {
return [
'first_column' => '',
'second_column' => '',
'hide_table_if_empty' => FALSE,
] + parent::defaultSettings();
}

/**
* {@inheritdoc}
*/
public function settingsForm(): array {
$form = parent::settingsForm();

$form['first_column'] = [
'#title' => $this->t('First column classes'),
'#description' => $this->t('Add custom classes to the first column.'),
'#type' => 'textfield',
'#default_value' => $this->getSetting('first_column'),
];
$form['second_column'] = [
'#title' => $this->t('Second column classes'),
'#description' => $this->t('Add custom classes to the second column.'),
'#type' => 'textfield',
'#default_value' => $this->getSetting('second_column'),
];

$form['hide_table_if_empty'] = [
'#title' => $this->t('Hide the table if empty'),
'#description' => $this->t('Do not output any table or container markup if there are no rows with values.'),
'#type' => 'checkbox',
'#default_value' => $this->getSetting('hide_table_if_empty'),
];

return $form;
}

/**
* {@inheritdoc}
*/
public function settingsSummary(): array {
$summary = parent::settingsSummary();
$summary[] = $this->t('Display results as a 2 column table.');

return $summary;
}

/**
* {@inheritdoc}
*/
public function preRender(&$element, $rendering_object): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an issue with this according to the complexity, please have a look at https://drone.fpfis.eu/openeuropa/oe_whitelabel/483/20

parent::preRender($element, $rendering_object);

$element['#mode'] = $this->context;
// Allow modules to alter the rows, useful for removing empty rows.
$children = Element::children($element, TRUE);
$this->moduleHandler->alter('field_group_table_rows', $element, $children);

if ($this->getSetting('hide_table_if_empty')) {
field_group_remove_empty_display_groups($element, []);
if ($element == []) {
return;
}
}

// Elements wrapper.
$element['#type'] = 'container';
$element['#attributes']['class'][] = 'my-3';

// Print the fieldset title.
$element['fieldset_title']['#type'] = 'markup';
$element['fieldset_title']['#markup'] = '<h4 class="fw-bold mb-4">' . $this->group->label . '</h4>';

// Fieldset data container.
$element['fieldset']['data']['#type'] = 'container';
$element['fieldset']['data']['#attributes']['class'][] = 'row';

// Set additional classes per column.
$classes = ['col-12', 'col-md-6'];
if ($this->getSetting('first_column')) {
$first_column_classes = array_merge($classes, [$this->getSetting('first_column')]);
}

if ($this->getSetting('second_column')) {
$second_column_classes = array_merge($classes, [$this->getSetting('second_column')]);
}
// Columns container.
$element['fieldset']['data']['first_column']['#type'] = 'container';
$element['fieldset']['data']['first_column']['#attributes'] = [
'class' => $this->getSetting('first_column') ? $first_column_classes : $classes,
];
$element['fieldset']['data']['second_column']['#type'] = 'container';
$element['fieldset']['data']['second_column']['#attributes'] = [
'class' => $this->getSetting('second_column') ? $second_column_classes : $classes,
];

$this->buildFieldsetColumns($element, $children);
}

/**
* Build the columns of the fieldset.
*/
protected function buildFieldsetColumns(array &$element, array $children): void {
// Number of items in the first columns.
$first_column_elements = array_slice($children, 0, ceil(count($children) / 2));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ceil is waiting for a float not an int

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact ceil can receive both int and floats, but in this case ceil is rounding up for then we have un-even elements.

// Build fieldset column(s).
foreach ($children as $key => $field_name) {
$column = in_array($field_name, $first_column_elements) ? 'first_column' : 'second_column';
if ($row = $this->buildRow($element, $field_name)) {
$element['fieldset']['data'][$column][$field_name] = $row;
}
unset($element[$field_name]);
}
}

/**
* Build the row for requested element.
*
* @param array $element
* Rendering array of an element.
* @param string $field_name
* The name of currently handling field.
*
* @return array
* Table row definition on success or an empty array otherwise.
*/
protected function buildRow(array $element, string $field_name): array {
$item = $this->getRowItem($element, $field_name);
$build = [];

if (!$item) {
return $build;
}
$item['#attributes'] = ['class' => 'col-12 col-md-6'];
$build = $item;

return $build;
}

/**
* Return item definition array.
*
* @param array $element
* Rendering array.
* @param string $field_name
* Item field machine name.
*
* @return array
* Item definition array on success or empty array otherwise.
*/
protected function getRowItem(array $element, string $field_name): array {
$item = $element[$field_name] ?? [];
$is_empty = !is_array($item) || !array_intersect($this->renderApiProperties, array_keys($item));

if ($is_empty && $this->getSetting('always_show_field_value') && isset($element['#entity_type'], $element['#bundle'])) {
$field_definitions = $this->entityFieldManager->getFieldDefinitions($element['#entity_type'], $element['#bundle']);
$field_definition = $field_definitions[$field_name] ?? NULL;

if ($field_definition instanceof FieldConfigInterface) {
$is_empty = FALSE;

$item = [
'#title' => $field_definition->label(),
'#label_display' => 'above',
'#markup' => Xss::filter($this->getSetting('empty_field_placeholder')),
];
}
}

$item['#attributes']['class'] = ['row'];
return $is_empty ? [] : $item;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{#
/**
* @file
* Default template for a field.
*/
#}
{%
set classes = [
bundle|clean_class ~ '__' ~ field_name_clean|clean_class,
label_display == 'inline' ? 'd-flex',
]
%}
{%
set title_classes = [
'field__label',
'col-12',
'col-md-6',
label_display == 'visually_hidden' ? 'visually-hidden',
]
%}

{% if label_hidden %}
{% if multiple %}
<div{{ attributes.addClass(classes) }}>
{% for item in items %}
<div{{ item.attributes.addClass('field__item col-12 col-md-6') }}>{{ item.content }}</div>
{% endfor %}
</div>
{% else %}
{% for item in items %}
<div{{ attributes.addClass(classes) }}>{{ item.content }}</div>
{% endfor %}
{% endif %}
{% else %}
<div{{ attributes.addClass(classes) }}>
<div{{ title_attributes.addClass(title_classes) }}>
{{ label }}{% if label_display == 'inline' %}<span class="me-1">:</span>{% endif %}
</div>
{% if multiple %}
<div class="field__items col-12 col-md-6">
{% endif %}
{% for item in items %}
<div{{ item.attributes.addClass('field__item col-12 col-md-6') }}>{{ item.content }}</div>
{% endfor %}
{% if multiple %}
</div>
{% endif %}
</div>
{% endif %}
Loading