custom_elements-8.x-2.x-dev/custom_elements.module

custom_elements.module
<?php

/**
 * @file
 * Custom elements hooks.
 */

use Drupal\Component\Render\MarkupInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\Markup;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Update\UpdateHookRegistry;
use Drupal\custom_elements\CustomElement;
use Drupal\custom_elements\CustomElementsEntityViewDisplay;
use Drupal\custom_elements\CustomElementsLayoutBuilderEntityViewDisplay;
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;

/**
 * Implements hook_theme().
 */
function custom_elements_theme() {
  return [
    'custom_element' => [
      'variables' => ['custom_element' => NULL],
    ],
    'custom_element__renderless_container' => [
      'base hook' => 'custom_element',
    ],
  ];
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function custom_elements_theme_suggestions_custom_element(array $variables) {
  $suggestions = [];
  /** @var \Drupal\custom_elements\CustomElement $custom_element */
  $custom_element = $variables['custom_element'];

  // Add suggestion based on tag name.
  $tag = str_replace('-', '_', $custom_element->getTag());
  $suggestions[] = 'custom_element__' . $tag;

  return $suggestions;
}

/**
 * Prepares variables when an entity is rendered as custom element.
 *
 * Default template: custom-element.twig.html.
 */
function template_preprocess_custom_element(&$variables) {
  // Attach custom-elements libraries.
  $variables['#attached']['library'][] = 'custom_elements/main';

  // Generate variables for easier usage in the template.
  /** @var \Drupal\custom_elements\CustomElement $custom_element */
  $custom_element = $variables['custom_element'];

  $config = \Drupal::config('custom_elements.settings');
  $markup_style = $config->get('markup_style');

  // Add config as cacheable dependency so markup is invalidated when settings
  // change.
  $cache_metadata = BubbleableMetadata::createFromRenderArray($variables);
  $cache_metadata->addCacheableDependency($config);
  $cache_metadata->applyTo($variables);
  $variables['attributes'] = new Attribute();
  foreach ($custom_element->getAttributes() as $key => $value) {
    // Take care of struct values and json-encode them as necessary.
    if (is_array($value)) {
      $value = json_encode($value);
      // For vue mark-up style let vue evaluate the json to an object.
      // See https://vuejs.org/v2/guide/components-props.html#Passing-an-Object
      if ($markup_style == 'vue-3') {
        $key = ":$key";
      }
    }
    // Attributes with html markup get html stripped, so we convert to string.
    if ($value instanceof MarkupInterface) {
      $value = (string) $value;
    }
    $variables['attributes'][$key] = $value;
  }
  $variables['tag_prefix'] = $custom_element->getTagPrefix() ? $custom_element->getTagPrefix() . '-' : '';
  $variables['tag'] = $custom_element->getTag();

  if ($markup_style == 'vue-3') {
    $variables['slots'] = custom_elements_prepare_slots_as_vue_3($custom_element);
  }
  else {
    $variables['slots'] = custom_elements_prepare_slots_as_web_component($custom_element);
  }

  BubbleableMetadata::createFromObject($custom_element)
    ->applyTo($variables);
}

/**
 * Prepares custom elements slots for rendering.
 *
 * @param \Drupal\custom_elements\CustomElement $custom_element
 *   The custom element.
 *
 * @return array
 *   A list of renderable slots to be passed to the template.
 */
function custom_elements_prepare_slots_as_web_component(CustomElement $custom_element) {
  $slots = [];
  $slot_entries = $custom_element->getSortedSlots();
  foreach ($slot_entries as $slot_entry) {
    if ($slot_entry['content'] instanceof CustomElement) {
      $element = $slot_entry['content'];
      $element->setAttribute('slot', $slot_entry['key']);
      $slots[] = $element->toRenderArray();
    }
    elseif ($slot_entry['key'] == 'default' && count($slot_entries) == 1) {
      // No need for a wrapping div if there is only one default slot entry.
      $slots[] = [
        '#type' => 'markup',
        '#markup' => $slot_entry['content'],
      ];
    }
    else {
      $slots[] = [
        '#prefix' => '<div slot=' . $slot_entry['key'] . '>',
        '#type' => 'markup',
        '#markup' => $slot_entry['content'],
        '#suffix' => '</div>',
      ];
    }
  }
  return $slots;
}

/**
 * Prepares custom elements slots for rendering in vue style.
 *
 * @param \Drupal\custom_elements\CustomElement $custom_element
 *   The custom element.
 *
 * @return array
 *   A list of renderable slots to be passed to the template.
 */
function custom_elements_prepare_slots_as_vue_3(CustomElement $custom_element) {
  $slots = [];
  $slots_by_name = $custom_element->getSortedSlotsByName();
  // If there is only the default slot, skip the wrapping template tag.
  $skip_wrapper = count($slots_by_name) == 1 && isset($slots_by_name['default']);

  foreach ($slots_by_name as $key => $slot_entries) {
    $render = [];
    if (!$skip_wrapper) {
      $render['#prefix'] = Markup::create('<template #' . $key . '>' . "\n");
      $render['#suffix'] = Markup::create('</template>' . "\n");
    }
    foreach ($slot_entries as $slot_entry) {
      if ($slot_entry['content'] instanceof CustomElement) {
        $element = $slot_entry['content'];
        $render[] = $element->toRenderArray();
      }
      else {
        $render[] = [
          '#markup' => $slot_entry['content'],
        ];
      }
    }
    $slots[$key] = $render;
  }
  return $slots;
}

/**
 * Implements hook_entity_type_alter().
 *
 * @see custom_elements_module_implements_alter()
 */
function custom_elements_entity_type_alter(array &$entity_types) {
  // Check if this call is made during layout_builder installation; changing
  // the entity class would make the loadMultiple() call in
  // layout_builder_install() fail fatally in that case. This check depends on
  // ModuleInstaller implementation details, i.e. entity info is
  // - (re)built before the module (version) is registered
  // - not rebuilt between registering the module and invoking hook_install.
  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
  $layout_builder_module_install_in_progress =
    $entity_types['entity_view_display']->getClass() === LayoutBuilderEntityViewDisplay::class
    && \Drupal::service('update.update_hook_registry')->getInstalledVersion('layout_builder')
       == UpdateHookRegistry::SCHEMA_UNINSTALLED;

  if (!$layout_builder_module_install_in_progress) {
    // Use the right class depending on layout builder being used.
    $class = \Drupal::moduleHandler()->moduleExists('layout_builder') ? CustomElementsLayoutBuilderEntityViewDisplay::class : CustomElementsEntityViewDisplay::class;
    $entity_types['entity_view_display']
      ->setClass($class);
  }
}

/**
 * Implements hook_module_implements_alter().
 */
function custom_elements_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'entity_type_alter') {
    // Make sure this runs after layout builder.
    // Move custom_elements_entity_type_alter() to the end of the list.
    // \Drupal::moduleHandler()->getImplementations()
    // iterates through $implementations with a foreach loop which PHP iterates
    // in the order that the items were added, so to move an item to the end of
    // the array, we remove it and then add it.
    $group = $implementations['custom_elements'];
    unset($implementations['custom_elements']);
    $implementations['custom_elements'] = $group;
  }
  // Be sure our entity_view_alter hook comes last, even after layout builder
  // which also tries to make it come last.
  // @see custom_elements_install().
  if ($hook === 'entity_view_alter') {
    $group = $implementations['custom_elements'];
    unset($implementations['custom_elements']);
    $implementations['custom_elements'] = $group;
  }
}

/**
 * Implements hook_modules_installed().
 *
 * @see custom_elements_entity_type_alter()
 */
function custom_elements_modules_installed($modules, $is_syncing) {
  if (in_array('layout_builder', $modules, TRUE)) {
    // Rebuild info that was not changed yet during installation.
    \Drupal::entityTypeManager()->clearCachedDefinitions();
  }
}

/**
 * Implements hook_entity_view_display_alter().
 */
function custom_elements_entity_view_display_alter(EntityViewDisplayInterface $display, array $context) {
  // Enable for all view-modes named appropriately by default.
  if (strpos($context['view_mode'], 'custom_elements') === 0) {
    $display->setThirdPartySetting('custom_elements', 'enabled', TRUE);
  }
}

/**
 * Implements hook_entity_view_alter().
 */
function custom_elements_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  // Alter the build array to apply custom elements rendering.
  if (!empty($build['#custom_elements_enabled'])) {
    $build['#theme'] = 'custom_element';
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc