Skip to content
Snippets Groups Projects
Commit c07368d0 authored by Radoslav Terezka's avatar Radoslav Terezka
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
{
"name": "drunomics/custom_elements",
"description": "Render fields as custom elements.",
"type": "drupal-module",
"authors": [
{
"name": "drunomics GmbH",
"email": "hello@drunomics.com"
}
],
"license": "GPL-2.0-or-later",
"repositories": [
{
"type": "composer",
"url": "https://packages.drupal.org/8"
}
],
"extra": {
"branch-alias": {
"dev-8.x-1.x": "1.0.x-dev"
}
},
"require": {
},
"require-dev": {
}
}
name: Custom Elements
description: Render fields as custom elements.
package: Other
type: module
core: 8.x
main:
version: 1.0.0
css: []
js: []
<?php
/**
* @file
* Custom elements hooks.
*/
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Template\Attribute;
/**
* Implements hook_theme().
*/
function custom_elements_theme() {
return [
'custom_elements' => [
'tag' => NULL,
'name' => NULL,
'type' => NULL,
'data_attributes' => [],
'fields' => [],
],
];
}
/**
* Implements hook_theme_suggestions_alter().
*
* Use custom elements template for every content entity which is using
* view mode prefixed with `custom_elements`.
*/
function custom_elements_theme_suggestions_alter(array &$suggestions, array &$variables, $hook) {
// Applies if view mode is prefixed with 'custom_elements'.
if (isset($variables['elements']['#view_mode']) && strpos($variables['elements']['#view_mode'], 'custom_elements') === 0) {
// Suggests that hook is entity type, so entity object is placed on #{hook}.
$entity = $variables['elements']['#' . $hook] ?? NULL;
// Check if entity was found.
if (!$entity) {
/** @var \Drupal\Core\Logger\LoggerChannel $logger */
$logger = \Drupal::service('logger.channel.custom_elements');
$logger->warning(t('Cannot obtain entity @entity for element with custom elements view mode.', ['@entity' => $hook]));
return;
}
// Check if entity is content entity, exit if not.
if (!$entity instanceof ContentEntityBase) {
return;
}
$variables['elements']['#entity'] = $entity;
$suggestions[] = 'custom_elements';
}
}
/**
* Prepares variables for content entity.
*
* Default template: custom-elements.twig.html.
*/
function template_preprocess_custom_elements(&$variables) {
/** @var \Drupal\Core\Entity\ContentEntityBase $entity */
$entity = $variables['elements']['#entity'];
$variables['#attached']['library'][] = 'custom_elements/main';
$variables['type'] = $entity->bundle();
$variables['name'] = $entity->bundle();
$view_mode = $variables['elements']['#view_mode'];
/** @var \Drupal\custom_elements\Service\VariablePreprocessor $variable_preprocessor */
$variable_preprocessor = \Drupal::service('custom_elements.variable_preprocessor');
$entity_values = $variable_preprocessor->preprocessVariables($entity, $view_mode);
$variables['data_attributes'] = new Attribute($entity_values->getDataAttributes());
$variables['fields'] = $entity_values->getFieldValues();
$variables['tag'] = $entity_values->getHtmlTag();
}
services:
logger.channel.custom_elements:
parent: logger.channel_base
arguments: ['custom_elements']
custom_elements.variable_preprocessor:
class: Drupal\custom_elements\Service\VariablePreprocessor
arguments: ['@renderer']
<?php
namespace Drupal\custom_elements;
/**
* Entity values data model.
*/
class EntityValues {
/**
* HTML tag.
*
* @var string
*/
protected $tag;
/**
* Prefix for data attribute.
*
* @var string
*/
protected $dataAttributePrefix = 'data-';
/**
* List of data attributes.
*
* @var array
*/
protected $dataAttributes = [];
/**
* List of field values.
*
* @var \Drupal\Core\Render\Markup[]|string[]
*/
protected $fieldValues = [];
/**
* Sanitizes data attribute value - strip html tags.
*
* @param string $value
* Data attribute value.
*
* @return string
* Sanitized data attribute value.
*/
protected function sanitizeDataAttribute($value) {
return strip_tags($value);
}
/**
* Gets HTML tag.
*
* @return string
*/
public function getHtmlTag() {
return $this->tag;
}
/**
* Sets HTML tag.
*
* @param string $tag
* HTML tag.
*/
public function setHtmlTag($tag) {
$this->tag = $tag;
}
/**
* Gets data attributes.
*
* @return array
*/
public function getDataAttributes() {
return $this->dataAttributes;
}
/**
* Gets value for given data attribute.
*
* @param string $key
* Name of the data attribute to get value for.
*
* @return string
*/
public function getDataAttribute($key) {
return $this->dataAttributes[$this->dataAttributePrefix . $key] ?? NULL;
}
/**
* Sets value for given data attribute.
*
* @param string $key
* Name of the data attribute to set value for.
* @param string $value
* Data attribute value.
*/
public function setDataAttribute($key, $value) {
$this->dataAttributes[$this->dataAttributePrefix . $key] = $this->sanitizeDataAttribute($value);
}
/**
* Gets field values.
*
* @return \Drupal\Core\Render\Markup[]|string[]
*/
public function getFieldValues() {
return $this->fieldValues;
}
/**
* Gets value for given field.
*
* @param string $key
* Name of the field to get value for.
*
* @return \Drupal\Core\Render\Markup|string
*/
public function getFieldValue($key) {
return $this->fieldValues[$key] ?? NULL;
}
/**
* Sets value for given field.
*
* @param string $key
* Name of the field to set value for.
* @param \Drupal\Core\Render\Markup|string $value
* Field value markup.
*/
public function setFieldValue($key, $value) {
$this->fieldValues[$key] = $value;
}
}
<?php
namespace Drupal\custom_elements\Service;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\custom_elements\EntityValues;
use Drupal\field\Entity\FieldConfig;
/**
* Service to preprocess template variables for custom elements.
*/
class VariablePreprocessor {
/**
* List of field types considered scalar.
*
* @var array
*/
protected $scalarFieldTypes = [
// General fields.
'boolean',
'datetime',
'email',
'timestamp',
// Text fields.
'string',
'list_string',
'string_long',
// Numeric fields.
'float',
'list_integer',
'list_float',
'decimal',
'integer',
];
/**
* The renderer service.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* Constructs a new VariablePreprocessor object.
*
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer service.
*/
public function __construct(RendererInterface $renderer) {
$this->renderer = $renderer;
}
/**
* Get html tag based on entity type.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* Entity to get tag for.
*
* @return string
* HTML tag.
*/
protected function getHtmlTag(ContentEntityInterface $entity) {
$entityType = $entity->getEntityTypeId();
switch ($entityType) {
case 'paragraph':
return 'pg';
}
return $entityType;
}
/**
* Preprocess entity to extract data attributes and field values.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* Entity to preprocess.
* @param string $viewMode
* View mode used for rendering field values.
*
* @return \Drupal\custom_elements\EntityValues
* Extracted entity values containing data attributes and field values.
*/
public function preprocessVariables(ContentEntityInterface $entity, $viewMode) {
$entityValues = new EntityValues();
$entityValues->setHtmlTag($this->getHtmlTag($entity));
/** @var \Drupal\Core\Field\FieldItemListInterface[] $fields */
$fields = $entity->getFields();
foreach ($fields as $field) {
$fieldDefinition = $field->getFieldDefinition();
// Handle custom fields only.
if ($fieldDefinition instanceof FieldConfig) {
$fieldName = $field->getName();
// Simple fields considered to be data attributes.
$fieldType = $fieldDefinition->getType();
if (in_array($fieldType, $this->scalarFieldTypes)) {
$entityValues->setDataAttribute($fieldName, $field->value);
}
// Complex fields.
else {
$fieldBuild = $entity->{$fieldName}->view(['view_mode' => $viewMode]);
/** @var \Drupal\Core\Render\Markup $fieldRendered */
$fieldRendered = $this->renderer->renderPlain($fieldBuild);
$entityValues->setFieldValue($fieldName, $fieldRendered);
}
}
}
return $entityValues;
}
}
{#
/**
* @file
* Default theme implementation for displaying an custom elements entity.
*
* Available variables:
* - tag: HTML tag for current entity.
* - name: Label of paragraph type turned to lowercase.
* - type: Type of paragraph.
* - data-attributes: Scalar field values.
* - fields: Rendered field values.
*
* @ingroup themeable
*/
#}
<{{ tag }}-{{ name }} type="{{ type }}" {{ data_attributes }}>
{% for field_name,field_value in fields %}
<section name="{{ field_name }}">{{ field_value }}</section>
{% endfor %}
</{{ tag }}-{{ name }}>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment