You are here

abstract class GlossifyBase in Glossify 8

Base implementation of tooltip filter type plugin.

Hierarchy

Expanded class hierarchy of GlossifyBase

3 files declare their use of GlossifyBase
GlossifyBaseTest.php in tests/src/Unit/GlossifyBaseTest.php
NodeTooltip.php in modules/glossify_node/src/Plugin/Filter/NodeTooltip.php
TaxonomyTooltip.php in modules/glossify_taxonomy/src/Plugin/Filter/TaxonomyTooltip.php

File

src/GlossifyBase.php, line 15

Namespace

Drupal\glossify
View source
abstract class GlossifyBase extends FilterBase {

  /**
   * Convert terms in text to links.
   *
   * @param string $text
   *   The HTML text upon which the filter is acting.
   * @param array $terms
   *   The terms (array) to be replaced with links.
   *   structure: [$termname_lower => [
   *     ['id' => $id],
   *     ['name' => $term],
   *     ['name_norm' => $termname_lower],
   *     ['tip' => $tooltip],
   *   ]].
   * @param bool $case_sensitivity
   *   Case sensitive replace.
   * @param bool $first_only
   *   Replace only first match.
   * @param string $displaytype
   *   Type of tooltip/link.
   * @param string $urlpattern
   *   URL pattern to create links.
   *
   * @return string
   *   The original HTML with the term string replaced by links.
   */
  protected function parseTooltipMatch($text, array $terms, $case_sensitivity, $first_only, $displaytype, $urlpattern) {

    // Create dom document.
    $html_dom = Html::load($text);
    $xpath = new DOMXPath($html_dom);
    $pattern_parts = $replaced = [];

    // Transform terms into normalized search pattern.
    foreach ($terms as $term) {
      $term_norm = preg_replace('/\\s+/', ' ', preg_quote(trim($term->name_norm)));
      $term_norm = preg_replace('#/#', '\\/', $term_norm);
      $pattern_parts[] = preg_replace('/ /', '\\s+', $term_norm);
    }

    // Process HTML.
    $text_nodes = $xpath
      ->query('//text()[not(ancestor::a) and not(ancestor::span[@class="glossify-exclude"])]');
    foreach ($text_nodes as $original_node) {
      $text = $original_node->nodeValue;
      $matches = [];
      foreach ($pattern_parts as $pattern_part) {
        $pattern = '/\\b(' . $pattern_part . ')\\b/';
        if (!$case_sensitivity) {
          $pattern .= 'i';
        }
        preg_match_all($pattern, $text, $matches_part, PREG_OFFSET_CAPTURE);
        if (count($matches_part[0])) {
          foreach ($matches_part[0] as $match_part) {
            $matches[$match_part[1]] = $match_part[0];
          }
        }
      }

      // Sort by position in text.
      ksort($matches);
      if (count($matches) > 0) {
        $offset = $loop_count = 0;
        $parent = $original_node->parentNode;
        $refnode = $original_node->nextSibling;
        $current_path = $this
          ->currentPath();
        $parent
          ->removeChild($original_node);
        foreach ($matches as $term_pos => $term_txt) {
          $loop_count += 1;
          $term_txt = preg_replace('/\\s+/', ' ', $term_txt);
          $terms_key = $case_sensitivity ? $term_txt : strtolower($term_txt);

          // Insert any text before the term instance.
          $prefix = substr($text, $offset, $term_pos - $offset);
          $parent
            ->insertBefore($html_dom
            ->createTextNode($prefix), $refnode);
          $dom_fragment = $html_dom
            ->createDocumentFragment();
          if ($current_path == str_replace('[id]', $terms[$terms_key]->id, $urlpattern)) {

            // Reinsert the found match if whe are on the page
            // this match points to.
            $dom_fragment
              ->appendXML($term_txt);
          }
          elseif ($first_only && in_array($term_txt, $replaced)) {

            // Reinsert the found match if only first match must be parsed.
            $dom_fragment
              ->appendXML($term_txt);
          }
          else {
            $tip = '';
            if ($displaytype == 'links' || $displaytype == 'tooltips_links') {

              // Insert the matched term instance as link.
              if ($displaytype == 'tooltips_links') {
                $tip = $this
                  ->sanitizeTip($terms[$terms_key]->tip);
              }
              if (\Drupal::hasContainer()) {
                $tipurl = Url::fromUri('internal:' . str_replace('[id]', $terms[$terms_key]->id, $urlpattern));
              }
              else {
                $tipurl = str_replace('[id]', $terms[$terms_key]->id, $urlpattern);
              }
              $word_link = [
                '#theme' => 'glossify_link',
                '#word' => $term_txt,
                '#tip' => $tip,
                '#tipurl' => $tipurl,
              ];
              $word = $this
                ->renderLink($word_link);
            }
            else {

              // Has to be 'tooltips'.
              // Insert the matched term instance as tooltip.
              $tip = $this
                ->sanitizeTip($terms[$terms_key]->tip);
              $word_tip = [
                '#theme' => 'glossify_tooltip',
                '#word' => $term_txt,
                '#tip' => $tip,
              ];
              $word = $this
                ->renderTip($word_tip);
            }
            $dom_fragment
              ->appendXML($word);
            $replaced[] = $term_txt;
          }
          $parent
            ->insertBefore($dom_fragment, $refnode);
          $offset = $term_pos + strlen($term_txt);

          // Last match, append remaining text.
          if ($loop_count == count($matches)) {
            $suffix = substr($text, $offset);
            $parent
              ->insertBefore($html_dom
              ->createTextNode($suffix), $refnode);
          }
        }
      }
    }
    return Html::serialize($html_dom);
  }

  /**
   * Render tip for found match.
   */
  protected function renderTip($word_tip) {
    return trim(render($word_tip));
  }

  /**
   * Render link for found match.
   */
  protected function renderLink($word_link) {
    return trim(render($word_link));
  }

  /**
   * Get current path.
   */
  protected function currentPath() {
    return \Drupal::service('path.current')
      ->getPath();
  }

  /**
   * Cleanup and truncate tip text.
   */
  private function sanitizeTip($tip) {

    // Get rid of HTML.
    $tip = strip_tags($tip);

    // Maximise tooltip text length.
    $tip = Unicode::truncate($tip, 300, TRUE, TRUE);
    return $tip;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
FilterBase::$provider public property The name of the provider that owns this filter.
FilterBase::$settings public property An associative array containing the configured settings of this filter.
FilterBase::$status public property A Boolean indicating whether this filter is enabled.
FilterBase::$weight public property The weight of this filter compared to others in a filter collection.
FilterBase::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides DependentPluginInterface::calculateDependencies 1
FilterBase::defaultConfiguration public function Gets default configuration for this plugin. Overrides ConfigurableInterface::defaultConfiguration
FilterBase::getConfiguration public function Gets this plugin's configuration. Overrides ConfigurableInterface::getConfiguration
FilterBase::getDescription public function Returns the administrative description for this filter plugin. Overrides FilterInterface::getDescription
FilterBase::getHTMLRestrictions public function Returns HTML allowed by this filter's configuration. Overrides FilterInterface::getHTMLRestrictions 4
FilterBase::getLabel public function Returns the administrative label for this filter plugin. Overrides FilterInterface::getLabel
FilterBase::getType public function Returns the processing type of this filter plugin. Overrides FilterInterface::getType
FilterBase::prepare public function Prepares the text for processing. Overrides FilterInterface::prepare
FilterBase::setConfiguration public function Sets the configuration for this plugin instance. Overrides ConfigurableInterface::setConfiguration 1
FilterBase::settingsForm public function Generates a filter's settings form. Overrides FilterInterface::settingsForm 3
FilterBase::tips public function Generates a filter's tip. Overrides FilterInterface::tips 9
FilterBase::__construct public function Constructs a \Drupal\Component\Plugin\PluginBase object. Overrides PluginBase::__construct 4
FilterInterface::process public function Performs the filter processing. 21
FilterInterface::TYPE_HTML_RESTRICTOR constant HTML tag and attribute restricting filters to prevent XSS attacks.
FilterInterface::TYPE_MARKUP_LANGUAGE constant Non-HTML markup language filters that generate HTML.
FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE constant Irreversible transformation filters.
FilterInterface::TYPE_TRANSFORM_REVERSIBLE constant Reversible transformation filters.
GlossifyBase::currentPath protected function Get current path. 1
GlossifyBase::parseTooltipMatch protected function Convert terms in text to links.
GlossifyBase::renderLink protected function Render link for found match. 1
GlossifyBase::renderTip protected function Render tip for found match. 1
GlossifyBase::sanitizeTip private function Cleanup and truncate tip text.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.