vvjf-1.0.3/vvjf.module

vvjf.module
<?php

/**
 * @file
 * Provides the module implementation for vvjf.
 *
 * Contains template preprocessing and theme definitions for Views.
 *
 * Filename:     vvjf.module
 * Website:      https://www.flashwebcenter.com
 * Description:  template.
 * Developer:    Alaa Haddad https://www.alaahaddad.com.
 */

declare(strict_types=1);

use Drupal\Component\Utility\Html;
use Drupal\Core\Render\Markup;
use Drupal\views\ViewExecutable;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Template\Attribute;
use Drupal\vvjf\Plugin\views\style\ViewsVanillaJavascriptFlipbox;

/**
 * Implements hook_help().
 */
function vvjf_help(string $route_name, RouteMatchInterface $route_match): ?string {
  if ($route_name === 'help.page.vvjf') {
    return _vvjf_helper_render_readme();
  }
  return NULL;
}

/**
 * Helper function to render README.md.
 */
function _vvjf_helper_render_readme(): string {
  $readme_path = __DIR__ . '/README.md';
  $text = file_get_contents($readme_path);

  if ($text === FALSE) {
    return (string) t('README.md file not found.');
  }

  if (!\Drupal::moduleHandler()->moduleExists('markdown')) {
    return '<pre>' . htmlspecialchars($text) . '</pre>';
  }

  $filter_manager = \Drupal::service('plugin.manager.filter');
  $settings = \Drupal::config('markdown.settings')->getRawData();
  $filter = $filter_manager->createInstance('markdown', ['settings' => $settings]);
  return $filter->process($text, 'en')->getProcessedText();
}

/**
 * Implements hook_theme().
 */
function vvjf_theme(array $existing, string $type, string $theme, string $path): array {
  return [
    'views_view_vvjf_fields' => [
      'variables' => [
        'view' => NULL,
        'options' => [],
        'row' => NULL,
        'field_alias' => NULL,
        'attributes' => [],
        'title_attributes' => [],
        'content_attributes' => [],
        'title_prefix' => [],
        'title_suffix' => [],
        'fields' => [],
      ],
      'template' => 'views-view-vvjf-fields',
      'path' => $path . '/templates',
    ],
    'views_view_vvjf' => [
      'variables' => [
        'view' => NULL,
        'rows' => [],
        'options' => [],
      ],
      'template' => 'views-view-vvjf',
      'path' => $path . '/templates',
    ],
  ];
}

/**
 * Implements hook_preprocess_HOOK() for views_view_vvjf.
 */
function template_preprocess_views_view_vvjf(array &$variables): void {
  static $views_theme_loaded = FALSE;
  if (!$views_theme_loaded) {
    \Drupal::moduleHandler()->loadInclude('views', 'inc', 'views.theme');
    $views_theme_loaded = TRUE;
  }

  /** @var \Drupal\vvjf\Plugin\views\style\ViewsVanillaJavascriptFlipbox $handler */
  $handler = $variables['view']->style_plugin;

  $list_attributes = [];

  if (!empty($handler->options['flip_trigger'])) {
    $list_attributes['data-flip-trigger'] = $handler->options['flip_trigger'];
  }

  if (!empty($handler->options['flip_direction'])) {
    $list_attributes['data-flip-direction'] = $handler->options['flip_direction'];
  }

  if (!empty($handler->options['flip_speed'])) {
    $list_attributes['data-flip-speed'] = $handler->options['flip_speed'];
  }

  if (!empty($handler->options['front_bg_color'])) {
    $list_attributes['data-front-bg-color'] = $handler->options['front_bg_color'];
  }

  if (!empty($handler->options['back_bg_color'])) {
    $list_attributes['data-back-bg-color'] = $handler->options['back_bg_color'];
  }

  if (!empty($handler->options['perspective'])) {
    $list_attributes['data-perspective'] = $handler->options['perspective'];
  }

  if (!empty($handler->options['available_breakpoints'])) {
    $list_attributes['data-available-breakpoints'] = $handler->options['available_breakpoints'];
  }

  if (!empty($handler->options['animation_easing'])) {
    $list_attributes['data-animation-easing'] = $handler->options['animation_easing'];
  }

  if (!empty($handler->options['grid_gap'])) {
    $list_attributes['data-grid-gap'] = $handler->options['grid_gap'];
  }

  if (!empty($handler->options['box_height'])) {
    $list_attributes['data-box-height'] = $handler->options['box_height'];
  }

  if (!empty($handler->options['box_width'])) {
    $list_attributes['data-box-width'] = $handler->options['box_width'];
  }

  if (isset($handler->options['enable_css'])) {
    $list_attributes['data-enable-css'] = $handler->options['enable_css'] ? 'true' : 'false';
  }

  if (!empty($handler->options['unique_id'])) {
    $list_attributes['data-unique-id'] = $handler->options['unique_id'];
  }

  $variables['list_attributes'] = new Attribute($list_attributes);

  $variables['options'] = $handler->options;

  $variables['settings'] = [
    'view_id' => $variables['view']->dom_id,
    'flip_trigger' => $handler->options['flip_trigger'],
    'flip_direction' => $handler->options['flip_direction'],
    'flip_speed' => $handler->options['flip_speed'],
    'front_bg_color' => $handler->options['front_bg_color'],
    'back_bg_color' => $handler->options['back_bg_color'],
    'perspective' => $handler->options['perspective'],
    'available_breakpoints' => $handler->options['available_breakpoints'],
    'animation_easing' => $handler->options['animation_easing'],
    'grid_gap' => $handler->options['grid_gap'],
    'box_height' => $handler->options['box_height'],
    'box_width' => $handler->options['box_width'],
    'enable_css' => $handler->options['enable_css'],
    'unique_id' => $handler->options['unique_id'],
  ];

  if (!empty($variables['rows'])) {
    foreach ($variables['rows'] as $key => $row) {
      if (isset($row['#theme']) && is_array($row['#theme'])) {
        foreach ($row['#theme'] as $idx => $theme_hook_suggestion) {
          $variables['rows'][$key]['#theme'][$idx] = str_replace('views_view_fields', 'views_view_vvjf_fields', $theme_hook_suggestion);
        }
      }
    }
  }

  template_preprocess_views_view_unformatted($variables);
}

/**
 * Prepares variables for views_view_vvjf_fields template.
 */
function template_preprocess_views_view_vvjf_fields(array &$variables): void {
  static $views_theme_loaded = FALSE;
  if (!$views_theme_loaded) {
    \Drupal::moduleHandler()->loadInclude('views', 'inc', 'views.theme');
    $views_theme_loaded = TRUE;
  }
  $fields = &$variables['fields'];

  if (!empty($fields)) {
    $field_keys = array_keys($fields);

    if (isset($field_keys[0])) {
      $first_field_key = $field_keys[0];
      if (isset($fields[$first_field_key])) {
        $fields[$first_field_key]->wrapper_prefix = '<div class="vvjf-front-card">';
        $fields[$first_field_key]->wrapper_suffix = '</div>';
      }
    }

    if (count($field_keys) > 1) {
      $back_card_html = '<div class="vvjf-back-card">';
      for ($i = 1; $i < count($field_keys); $i++) {
        $field_key = $field_keys[$i];
        if (isset($fields[$field_key])) {
          $back_card_html .= (string) $fields[$field_key]->content;
          unset($fields[$field_key]);
        }
      }
      $back_card_html .= '</div>';

      $fields['vvjf_back_card'] = (object) [
        'content' => Markup::create($back_card_html),
        'wrapper_prefix' => '',
        'wrapper_suffix' => '',
        'label_html' => '',
        'separator' => '',
      ];
    }
  }

  template_preprocess_views_view_fields($variables);
}

/**
 * Implements hook_preprocess_views_view().
 */
function vvjf_preprocess_views_view(array &$variables): void {
  if ($variables['view']->style_plugin instanceof ViewsVanillaJavascriptFlipbox) {
    $variables['attributes']['class'][] = 'vvj-flipbox';
  }
}

/**
 * Implements hook_token_info().
 */
function vvjf_token_info(): array {
  return [
    'tokens' => [
      'view' => [
        'vvjf' => [
          'name' => t('VVJF field output'),
          'description' => t("Use these tokens when you enable 'Use replacement tokens from the first row' in Views text areas such as the header, footer, or empty text. Use [vvjf:field_name] for rendered output, or [vvjf:field_name:plain] to strip HTML and return plain text. These tokens pull values from the first row of the View result."),
        ],
      ],
    ],
  ];
}

/**
 * Implements hook_tokens().
 */
function vvjf_tokens(string $type, array $tokens, array $data = [], array $options = []): array {
  $replacements = [];

  if (!in_array($type, ['vvjf', 'global'])) {
    return $replacements;
  }

  if (!isset($data['view']) || !($data['view'] instanceof ViewExecutable)) {
    return $replacements;
  }

  $view = $data['view'];

  if (!($view->style_plugin instanceof ViewsVanillaJavascriptFlipbox)) {
    return $replacements;
  }

  if (empty($view->result)) {
    return $replacements;
  }

  $first_row = $view->result[0];
  $field_handlers = $view->display_handler->getHandlers('field');

  /** @var \Drupal\Core\Render\RendererInterface $renderer */
  $renderer = \Drupal::service('renderer');

  foreach ($tokens as $token => $name) {
    if (!preg_match('/^[a-zA-Z0-9_]+(:plain)?$/', $token)) {
      \Drupal::logger('vvjf')->warning('Invalid token format: @token', ['@token' => $token]);
      continue;
    }

    $plain = FALSE;
    $field_id = $token;

    if (str_ends_with($token, ':plain')) {
      $plain = TRUE;
      $field_id = substr($token, 0, -6);
    }

    if (!isset($field_handlers[$field_id])) {
      continue;
    }

    try {
      $handler = $field_handlers[$field_id];
      $value = $plain && method_exists($handler, 'advancedRenderText')
        ? $handler->advancedRenderText($first_row)
        : $handler->advancedRender($first_row);

      if (is_array($value)) {
        $rendered = $renderer->renderPlain($value);
      }
      else {
        $rendered = (string) $value;
      }

      $replacements["[vvjf:$token]"] = $plain
        ? Html::decodeEntities(strip_tags($rendered))
        : Markup::create($rendered);
    }
    catch (\Throwable $e) {
      \Drupal::logger('vvjf')->error('Token replacement failed for @token: @message', [
        '@token' => $token,
        '@message' => $e->getMessage(),
      ]);
      $replacements["[vvjf:$token]"] = '';
    }
  }

  return $replacements;
}

/**
 * Implements hook_views_data_alter().
 */
function vvjf_views_data_alter(array &$data): void {
  $data['views_style_plugin']['views_vvjf'] = [
    'type' => 'views_style',
    'label' => t('Views Vanilla JavaScript 3D Flipbox'),
    'mapping' => [
      'unique_id' => [
        'type' => 'string',
        'label' => t('Unique ID for the view display'),
      ],
      'flip_trigger' => [
        'type' => 'string',
        'label' => t('Flip Trigger'),
        'description' => t('Trigger method for flipping (hover or click).'),
      ],
      'flip_direction' => [
        'type' => 'string',
        'label' => t('Flip Direction'),
        'description' => t('Direction of the flip animation.'),
      ],
      'flip_speed' => [
        'type' => 'float',
        'label' => t('Flip Speed'),
        'description' => t('Duration of the flip animation in seconds.'),
      ],
      'front_bg_color' => [
        'type' => 'string',
        'label' => t('Front Background Color'),
        'description' => t('Background color for the front side.'),
      ],
      'back_bg_color' => [
        'type' => 'string',
        'label' => t('Back Background Color'),
        'description' => t('Background color for the back side.'),
      ],
      'perspective' => [
        'type' => 'integer',
        'label' => t('Perspective'),
        'description' => t('3D perspective value.'),
      ],
      'available_breakpoints' => [
        'type' => 'string',
        'label' => t('Available Breakpoints'),
        'description' => t('Responsive breakpoint settings.'),
      ],
      'animation_easing' => [
        'type' => 'string',
        'label' => t('Animation Easing'),
        'description' => t('Easing function for the flip animation.'),
      ],
      'grid_gap' => [
        'type' => 'integer',
        'label' => t('Grid Gap'),
        'description' => t('Gap between grid items in pixels.'),
      ],
      'box_height' => [
        'type' => 'integer',
        'label' => t('Box Height'),
        'description' => t('Height of the flip box in pixels.'),
      ],
      'box_width' => [
        'type' => 'integer',
        'label' => t('Box Width'),
        'description' => t('Minimum width of the flip box in pixels.'),
      ],
      'enable_css' => [
        'type' => 'boolean',
        'label' => t('Enable CSS'),
        'description' => t('Include the default CSS library.'),
      ],
    ],
  ];
}

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

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