View source
<?php
namespace Drupal\glossify;
use Drupal\filter\Plugin\FilterBase;
use Drupal\Component\Utility\Html;
use Drupal\Core\Url;
use DOMXPath;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Render;
abstract class GlossifyBase extends FilterBase {
protected function parseTooltipMatch($text, array $terms, $case_sensitivity, $first_only, $displaytype, $urlpattern) {
$html_dom = Html::load($text);
$xpath = new DOMXPath($html_dom);
$pattern_parts = $replaced = [];
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);
}
$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];
}
}
}
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);
$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)) {
$dom_fragment
->appendXML($term_txt);
}
elseif ($first_only && in_array($term_txt, $replaced)) {
$dom_fragment
->appendXML($term_txt);
}
else {
$tip = '';
if ($displaytype == 'links' || $displaytype == 'tooltips_links') {
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 {
$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);
if ($loop_count == count($matches)) {
$suffix = substr($text, $offset);
$parent
->insertBefore($html_dom
->createTextNode($suffix), $refnode);
}
}
}
}
return Html::serialize($html_dom);
}
protected function renderTip($word_tip) {
return trim(render($word_tip));
}
protected function renderLink($word_link) {
return trim(render($word_link));
}
protected function currentPath() {
return \Drupal::service('path.current')
->getPath();
}
private function sanitizeTip($tip) {
$tip = strip_tags($tip);
$tip = Unicode::truncate($tip, 300, TRUE, TRUE);
return $tip;
}
}