recogito_integration-1.0.x-dev/recogito_integration.module

recogito_integration.module
<?php

/**
 * @file
 * Contains hooks and functions for the Recogito Integration module.
 *
 * This module integrates the Recogito annotation tool with Drupal. It provides
 * functionality to attach Recogito to certain node types and manage permissions
 * for viewing, creating, editing, and deleting annotations.
 */

use Drupal\Core\Form\FormStateInterface;
use Drupal\node\NodeInterface;
use Drupal\taxonomy\TermInterface;

/**
 * Implements hook_page_attachments().
 */
function recogito_integration_page_attachments(array &$attachments) {
  $routeName = \Drupal::routeMatch()->getRouteName();
  if (!in_array($routeName, ['entity.node.canonical', 'recogito_annotate_node'])) {
    return;
  }
  $currentUser = \Drupal::currentUser();
  $viewPerm = $currentUser->hasPermission('recogito view annotations');
  if (!$viewPerm) {
    return;
  }
  $createPerm = $currentUser->hasPermission('recogito create annotations');
  $config = \Drupal::config('recogito_integration.settings');
  $annotatables = $config->get('recogito_integration.annotatables') ?? [];
  $node = \Drupal::routeMatch()->getParameter('node');
  if (!isset($annotatables[$node->getType()])) {
    return;
  }
  if (!$annotatables[$node->getType()]['enabled']) {
    return;
  }
  $attached = [];
  if ($routeName === 'recogito_annotate_node' && $createPerm) {
    $perms = [
      'view' => $viewPerm,
      'create' => $createPerm,
      'edit' => $currentUser->hasPermission('recogito edit annotations'),
      'delete' => $currentUser->hasPermission('recogito delete annotations'),
      'edit-own' => $currentUser->hasPermission('recogito edit own annotations'),
      'delete-own' => $currentUser->hasPermission('recogito delete own annotations'),
    ];
    $attached = [
      'permissions' => $perms,
      'userData' => [
        'id' => $currentUser->id(),
        'displayName' => $currentUser->getDisplayName(),
      ],
      'admin' => $currentUser->isAuthenticated(),
      'nodeId' => $node->id(),
    ];
    $vocab = $config->get('recogito_integration.vocabulary_name');
    $termList = [];
    if ($vocab) {
      $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('taxonomy_term', $vocab);
      $style_field = '';
      if ($config->get('recogito_integration.preview_tag_selector')) {
        foreach ($field_definitions as $field_name => $field_definition) {
          if ($field_definition->getType() === 'annotation_profile') {
            $style_field = $field_name;
            break;
          }
        }
      }
      $terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree($vocab);
      $term_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
      $termList = [];
      $termStyleList = [];
      foreach ($terms as $term) {
        $termList[] = $term->name;
        $result = ['name' => $term->name, 'hasStyle' => 0];
        $term = $term_storage->load($term->tid);
        if (!$style_field) {
          $termStyleList[] = $result;
          continue;
        }
        $style = $term->get($style_field)->getValue();
        if (empty($style) || !$style[0]['styling_choice']) {
          $termStyleList[] = $result;
          continue;
        }
        $result['hasStyle'] = 1;
        $result['style'] = [
          'text_color' => $style[0]['text_color'],
          'background_color' => $style[0]['background_color'],
          'underline_style' => $style[0]['underline_style'],
          'underline_stroke' => $style[0]['underline_stroke'],
          'underline_color' => $style[0]['underline_color'],
          'background_transparency' => $style[0]['background_transparency'],
        ];
        $result['style'] = recogito_integration_validate_style($result['style']);
        $termStyleList[] = $result;
      }
    }
    $defaultTagIds = $config->get('recogito_integration.default_tag') ?? [];
    $defaultTags = [];
    if ($defaultTagIds) {
      $tags = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadMultiple($defaultTagIds);
      $defaultTags = array_map(function ($term) {
        return $term->getName();
      }, $tags);
      $defaultTags = array_values($defaultTags);
    }
    $attached['tagOptions'] = [
      'defaultTags' => $defaultTags,
      'tagList' => $termList,
      'tagStyleList' => $termStyleList,
      'selector' => $config->get('recogito_integration.tag_selector') ?? 0,
      'textInput' => $config->get('recogito_integration.tag_text_input') ?? 1,
      'createNewTag' => $config->get('recogito_integration.create_nonexistent_tag') ?? 1,
    ];
  }
  else {
    $attached = [
      'permissions' => ['view' => $viewPerm],
      'nodeId' => $node->id(),
    ];
  }

  $attached['annotatable_fields'] = $annotatables[$node->getType()]['fields'];

  if ($config->get('recogito_integration.custom_annotations')) {
    $attached['custom_elements'] = preg_split("/\r?\n/", $config->get('recogito_integration.custom_annotations_elements') ?? '');
  }
  else {
    $attached['custom_elements'] = [];
  }

  $attachments['#attached']['drupalSettings']['recogito_integration'] = $attached;
  switch ($routeName) {
    case 'entity.node.canonical':
      $attachments['#attached']['library'][] = 'recogito_integration/recogito_user';
      break;

    case 'recogito_annotate_node':
      if ($createPerm && $currentUser->isAuthenticated()) {
        $attachments['#attached']['library'][] = 'recogito_integration/recogito_admin';
      }
      break;
  }
}

/**
 * Implements hook_node_predelete().
 */
function recogito_integration_node_predelete(NodeInterface $node) {
  if ($node->getType() == 'annotation') {
    $textualbodies = $node->get('field_annotation_textualbody')->referencedEntities();
    foreach ($textualbodies as $textualbody) {
      $textualbody->delete();
    }
    return;
  }
  $annotations = recogito_integration_get_annotations_for_node($node->id());
  foreach ($annotations as $annotation) {
    $annotation->delete();
  }
}

/**
 * Implements hook_taxonomy_term_predelete().
 */
function recogito_integration_taxonomy_term_predelete(TermInterface $term) {
  $vocabularyId = $term->bundle();
  $config = \Drupal::config('recogito_integration.settings');
  $selectedVocab = $config->get('recogito_integration.vocabulary_name') ?? '';
  if ($vocabularyId !== $selectedVocab) {
    return;
  }
  $textualBodies = recogito_integration_get_tag_textualbody($term->id());
  foreach ($textualBodies as $textualBody) {
    $textualBody->delete();
  }
}

/**
 * Implements hook_form_alter().
 */
function recogito_integration_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  if (preg_match('/^node_.*_(edit|delete)_form$/', $form_id, $matches)) {
    $form_type = $matches[1];
    $nid = $form_state->getFormObject()->getEntity()->id();
    if (!$nid) {
      return;
    }
    $node = $form_state->getFormObject()->getEntity();
    if (!$node instanceof NodeInterface) {
      return;
    }
    if ($node->getType() == 'annotation') {
      return;
    }
    if (recogito_integration_get_annotations_for_node($nid)) {
      switch ($form_type) {
        case 'edit':
          $msg = 'IMPORTANT INFORMATION:\n\nThis page contains annotations. Updating this node may affect '
          . 'the positioning of existing annotations.\n\nPlease double check the existing annotations after '
          . 'updating this page.';
          $form['actions']['submit'] = [
            '#type' => 'submit',
            '#value' => 'Save',
            '#attributes' => [
              'onclick' => 'if(!confirm("' . $msg . '")){return false;}',
            ],
            '#submit' => [
              '::submitForm',
              '::save',
              'menu_ui_form_node_form_submit',
            ],
            '#access' => TRUE,
            '#button_type' => 'primary',
            '#weight' => 5,
          ];
          break;

        case 'delete':
          $form['description']['#markup'] = '<strong><u>Warning:</u></strong><br>
          This page contains annotations. Deleting this page will also delete all 
          associated annotations.<br>
          <strong>This action cannot be undone!</strong>';
          break;
      }
    }
  }
  elseif (preg_match('/^taxonomy_term_(.*)_delete_form$/', $form_id, $matches)) {
    $config = \Drupal::config('recogito_integration.settings');
    $vocab = $config->get('recogito_integration.vocabulary_name') ?? '';
    if ($vocab && $matches[1] === $vocab) {
      $term = $form_state->getFormObject()->getEntity();
      if (recogito_integration_get_tag_textualbody($term->id())) {
        $form['description']['#markup'] = '<strong><u>Warning:</u></strong><br>
        This term is used for tagging annotations. Deleting this term will
        remove the tag from annotations.<br>
        <strong>This action cannot be undone!</strong>';
      }
    }
  }
}

/**
 * Implements hook_preprocess_field().
 */
function recogito_integration_preprocess_field(array &$variables) {
  $config = \Drupal::config('recogito_integration.settings');
  $annotatables = $config->get('recogito_integration.annotatables') ?? [];
  $contentType = $variables['element']['#bundle'];
  if (!isset($annotatables[$contentType]) || !$annotatables[$contentType]['enabled']) {
    return;
  }
  $fieldsAnnotate = $annotatables[$contentType]['fields'] ?? [];
  if (in_array($variables['element']['#field_name'], $fieldsAnnotate)) {
    $variables['attributes']['annotatable-field-id'] = $variables['element']['#field_name'];
    $variables['attributes']['annotatable-type'] = 'field';
  }
}

/**
 * Implements hook_preprocess_views_view_field().
 */
function recogito_integration_preprocess_views_view_field(array &$variables) {
  $field = $variables['field'];
  $config = \Drupal::config('recogito_integration.settings');
  $annotatables = $config->get('recogito_integration.annotatables') ?? [];
  $node = $variables['row']->_entity;
  if (!$node instanceof NodeInterface) {
    return;
  }
  $contentType = $node->getType();
  if (!isset($annotatables[$contentType]) || !$annotatables[$contentType]['enabled']) {
    return;
  }
  $fieldsAnnotate = $annotatables[$contentType]['fields'] ?? [];
  if (in_array($field->field, $fieldsAnnotate)) {
    $variables['output'] = [
      '#prefix' => '<div annotatable-field-id="' . $field->field . '" annotatable-type="view_field">',
      '#suffix' => '</div>',
      '#markup' => $variables['output'],
    ];
  }
}

/**
 * Validate the style for an annotation.
 *
 * @param array $style
 *   The style to validate.
 *
 * @return array
 *   The validated style.
 */
function recogito_integration_validate_style(array $style) {
  $colorRegex = '/^#(?:[0-9a-fA-F]{3}){1,2}$/';
  $lineStyles = ['dotted', 'dashed', 'double', 'solid', 'groove', 'ridge', 'inset', 'outset', 'none'];
  $config = \Drupal::config('recogito_integration.settings');
  $style['text_color'] = preg_match($colorRegex, $style['text_color']) ? $style['text_color'] : ($config->get('recogito_integration.text_color') ?? '#000000');
  $style['background_color'] = preg_match($colorRegex, $style['background_color']) ? $style['background_color'] : ($config->get('recogito_integration.background_color') ?? '#000000');
  $style['underline_color'] = preg_match($colorRegex, $style['underline_color']) ? $style['underline_color'] : ($config->get('recogito_integration.underline_color') ?? '#000000');
  $style['underline_style'] = in_array($style['underline_style'], $lineStyles) ? $style['underline_style'] : ($config->get('recogito_integration.underline_style') ?? 'none');
  $style['underline_stroke'] = is_numeric($style['underline_stroke']) ? $style['underline_stroke'] : ($config->get('recogito_integration.underline_stroke') ?? '0');
  $style['background_transparency'] = is_numeric($style['background_transparency']) ? $style['background_transparency'] : ($config->get('recogito_integration.background_transparency') ?? '0');
  return $style;
}

/**
 * Query Annotation Collection based on URL.
 *
 * @param int $nodeId
 *   The node ID.
 */
function recogito_integration_get_annotations_for_node(int $nodeId) {
  return \Drupal::entityTypeManager()
    ->getStorage('node')
    ->loadByProperties([
      'type' => 'annotation',
      'field_annotation_node_reference' => $nodeId,
      'status' => 1,
    ]);
}

/**
 * Query Textualbody Tags by Taxonomy Term.
 *
 * @param int $termId
 *   The term name.
 */
function recogito_integration_get_tag_textualbody(int $termId) {
  return \Drupal::entityTypeManager()
    ->getStorage('paragraph')
    ->loadByProperties([
      'type' => 'annotation_textualbody',
      'field_annotation_tag_reference' => $termId,
      'field_annotation_purpose' => 'tagging',
    ]);

}

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

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