navigation_plus-1.0.5/src/NavigationPlusUi.php

src/NavigationPlusUi.php
<?php

declare(strict_types=1);

namespace Drupal\navigation_plus;

use Drupal\block\Entity\Block;
use Drupal\Core\Routing\AdminContext;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ExtensionPathResolver;
use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\navigation_plus\Event\EditableFieldAttributes;
use Drupal\layout_builder\OverridesSectionStorageInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
 * Navigation + UI.
 */
final class NavigationPlusUi {

  use StringTranslationTrait;

  /**
   * @var \Drupal\Core\Entity\EntityInterface|NULL
   *   The entity derived from the route.
   *   @see deriveEntityFromRoute.
   */
  private ?EntityInterface $entity = NULL;

  public function __construct(
    private readonly RequestStack $requestStack,
    private readonly ModePluginManager $modeManager,
    private readonly RouteMatchInterface $routeMatch,
    private readonly AdminContext $routerAdminContext,
    private readonly AccountProxyInterface $currentUser,
    private readonly ConfigFactoryInterface $configFactory,
    private readonly EventDispatcherInterface  $eventDispatcher,
    private readonly ExtensionPathResolver $extensionPathResolver,
    private readonly EntityTypeManagerInterface $entityTypeManager,
    private readonly EntityDisplayRepositoryInterface $entityDisplayRepository,
  ) {}

  /**
   * Add toolbars.
   *
   * Add mode toolbars to the navigation module's left sidebar.
   *
   * @param array $variables
   *   The navigation sidebar render array.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   */
  public function buildToolbars(&$variables) {
    $mode_state = $this->getMode();
    // Hide the standard navigation items if any modes are enabled.
    if ($mode_state !== 'none') {
      foreach ($variables['content']['content'] as &$navigation_item) {
        $navigation_item['#attributes']['class'][] = 'navigation-plus-hidden';
      }
    }
    $modes = $this->modeManager->getModePlugins();
    if (!empty($modes)) {
      $variables['#attached']['library'][] = 'navigation_plus/modes';
      $this->setThemeColors($variables);
    }
    foreach ($modes as $mode_id => $mode) {
      $mode->addAttachments($variables['#attached']);
      $variables['#cache']['contexts'][] = 'user.permissions';
      $variables['#cache']['contexts'][] = "cookies:navigationMode";

      // Add a button to toggle into the mode.
      $variables['content']['footer']["navigation_plus_{$mode_id}_mode"]['content']["navigation_plus_toggle_{$mode_id}_mode"] = $mode->buildModeButton();

      // Add a toolbar for this mode.
      $toolbar_classes = ['toolbar-block', 'navigation-plus-mode'];
      if ($mode_state !== $mode_id) {
        $toolbar_classes[] = 'navigation-plus-hidden';
      }
      $variables['content']['content']["navigation_plus_$mode_id"] = [
        '#type' => 'container',
        '#attributes' => [
          'id' => "navigation-plus-$mode_id",
          'class' => $toolbar_classes,
        ],
        // Match the navigation module markup.
        'admin_toolbar_item' => [
          '#type' => 'container',
          '#attributes' => [
            'class' => ['admin-toolbar__item'],
          ],
        ],
        'toolbar' => $mode->buildToolbar($variables),
        '#weight' => 99,
      ];
    }
  }

  /**
   * Wrap and attribute fields for editing.
   *
   * We add a wrapper around the field and let tools add the attributes needed
   * to make the tools work.
   *
   * @param $variables
   *   The variables from hook_preprocess_field.
   *
   * @return void
   */
  public function wrapAndAttributeFieldsForEditing(&$variables) {
    // Only attribute the page elements when in edit mode.
    $variables['#cache']['contexts'][] = 'cookies:navigationMode';
    $mode = $this->getMode();
    if ($mode !== 'edit') {
      return;
    }

    if (!empty($variables['items'])) {
      foreach ($variables['items'] as &$item) {
        $item['content'] = [
          'edit_mode_wrapper' => [
            '#type' => 'container',
            '#attributes' => [
              'class' => ['edit-plus-field-value'],
            ],
            'content' => $item['content'],
          ],
        ];
      }
    }

    $this->eventDispatcher->dispatch(new EditableFieldAttributes($variables), EditableFieldAttributes::class);
  }

  /**
   * Build page top.
   *
   * Let modes add top and side bars.
   *
   * @param array $page_top
   *   The page_top render array.
   *
   * @return void
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   */
  public function buildPageTop(array &$page_top) {
    foreach ($this->modeManager->getModePlugins() as $mode_id => $mode) {
      $mode->buildBars($page_top, $mode);
    }
  }

  /**
   * Preprocess top bar.
   */
  public function preprocessTopBar(&$variables) {
    $variables['#cache']['contexts'][] = 'cookies:navigationMode';
    // Hide the navigation top bar when in a mode.
    if ($this->getMode() !== 'none') {
      $variables['attributes']['class'][] = 'navigation-plus-hidden';
    }
  }


  /**
   * Get mode.
   *
   * Many UI state items are stored in JS's Local and Session storage. Edit mode
   * is stored as a cookie so that the server can conditionally render the page
   * elements with attributes used for the editing UI. Rendering this server
   * side prevents a flashing that would occur if we waited till the JS was
   * loaded to enable the editing UI.
   *
   * @param string $cookie_name
   *   The name of the cookie.
   *
   * @return string
   *   Whether edit mode is enabled (Whether the toolbar is open or closed).
   */
  public function getMode(string $cookie_name = 'navigationMode'): string {
    // Query parameters are for js requests like /lb-plus/place-block/overrides/node.16
    return $this->requestStack->getCurrentRequest()->get($cookie_name) ??
    // Cookies are for pages like /node/10
    $this->requestStack->getCurrentRequest()->cookies->get($cookie_name) ??
      'none';
  }

  /**
   * Is valid view mode.
   *
   * @return bool
   *   Whether the view_mode is a valid view mode.
   */
  public function isValidViewMode(EntityInterface $entity, string $view_mode): bool {
    $valid_view_modes = $this->entityDisplayRepository->getViewModes($entity->getEntityTypeId());
    $valid_view_modes['default'] = TRUE;
    return !empty($valid_view_modes[$view_mode]);
  }

  /**
   * Derive entity from route.
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   *   Returns the entity for this route or NULL if there isn't one or there is
   *   more than one.
   */
  public function deriveEntityFromRoute() {
    if (empty($this->entity)) {
      $parameters = $this->routeMatch->getParameters()->all();
      $top_level_entity = NULL;
      foreach ($parameters as $parameter) {
        $entity = NULL;
        if ($parameter instanceof EntityInterface) {
          $entity = $parameter;
        }
        if ($parameter instanceof OverridesSectionStorageInterface) {
          $entity = $parameter->getContextValue('entity');
        }
        if (!empty($entity) && is_null($top_level_entity)) {
          $top_level_entity = $entity;
        } elseif (!empty($entity) && !is_null($top_level_entity)) {
          if (
            $top_level_entity instanceof EntityInterface &&
            $entity instanceof EntityInterface &&
            $entity->bundle() === $top_level_entity->bundle() &&
            $entity->id() === $top_level_entity->id()
          ) {
            // These are the same entity. That's okay
            continue;
          }
          // If there is more than one entity it's not obvious which one is the parent,
          // so we should probably not try to edit.
          return NULL;
        }
      }
      if (!empty($top_level_entity)) {
        $this->entity = $top_level_entity;
      }
    }

    // If the entity is a Block Config Entity, load its Block Content Entity.
    if ($this->entity instanceof Block) {
      $plugin_id = $this->entity->getPluginId();
      if (str_contains($plugin_id, ':')) {
        [$entity_type, $uuid] = explode(':', $plugin_id);
        if ($this->entityTypeManager->hasDefinition($entity_type)) {
          $entities = $this->entityTypeManager->getStorage($entity_type)->loadByProperties(['uuid' => $uuid]);
          if (!empty($entities)) {
            $this->entity = reset($entities);
          }
        }
      }
    }

    return $this->entity;
  }

  public function clearDerivedEntity() {
    $this->entity = NULL;
  }

  /**
   * Add theme colors.
   *
   * @param array $element
   *   The layout builder element.
   */
  private function setThemeColors(array &$element) {
    // Add theme specific colors.
    $colors = $this->configFactory->get('navigation_plus.settings')->get('colors');
    $rules = '';
    if (!empty($colors)) {
      foreach($colors as $color => $hex) {
        $rules .= "--navigation-plus-$color-color: {$hex};\n";
      }
    }
    else {
      $rules = "--navigation-plus-main-color: #4b9ae4;\n";
    }
    if (!empty($rules)){
      $element['content']['content']['navigation_plus_ui'] = [
        '#type' => 'html_tag',
        '#tag' => 'style',
        '#value' => ":root {\n$rules}\n",
      ];
    }
  }

}

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

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