You are here

function _lexicon_insertlink in Lexicon 7

Same name and namespace in other branches
  1. 6 lexicon.module \_lexicon_insertlink()

Insert lexicon links to $text after every matching $terms[i]['synonyms'] that is not inside a blocking tag. $terms[i]['ins_before'] is prepended to the matches, $terms[i]['ins_after'] is appended to them. Match type and replace mode all depend on user settings. The text is scanned once for all blocking tags and matches, then those 'events' are sorted and handled one by one.

1 call to _lexicon_insertlink()
_filter_lexicon_process in ./lexicon.module
Lexicon filter process callback function. Marks terms in the content of the website.

File

./lexicon.module, line 814
The Lexicon module is used to create lists of terms and definitions to use on a website and optionally mark those terms in the content of the website.

Code

function _lexicon_insertlink(&$text, &$terms_replace) {
  $multibyte_enabled = extension_loaded('mbstring');
  if ($multibyte_enabled) {
    $mb_prefix = 'mb_';
  }
  else {
    $mb_prefix = NULL;
  }
  $case_sensitive = variable_get('lexicon_case', '1');
  $findfunc = $mb_prefix . 'strpos';
  $findtagfunc = $mb_prefix . 'strpos';
  $replaceall = variable_get('lexicon_replace_all', 0);
  $replace_mode = variable_get('lexicon_replace', 'superscript');
  $events = array();

  // Find blocking tags.
  $open_tags = array(
    '[no-lexicon]',
    '<',
    '<a ',
    '[code',
  );
  $close_tags = array(
    '[/no-lexicon]',
    '>',
    '</a>',
    '[/code]',
  );
  $user_tags = explode(' ', variable_get('lexicon_blocking_tags', 'abbr acronym'));
  foreach ($user_tags as $tag) {
    if (!empty($tag)) {
      if (ctype_alnum($tag)) {
        $open_tags[] = '<' . $tag;
        $close_tags[] = '</' . $tag . '>';
      }
      elseif ($tag[0] == '.') {
        $open_tags[] = '<span class="' . drupal_substr($tag, 1);
        $close_tags[] = '</span>';
      }
    }
  }
  $searchtext = $case_sensitive ? $text : drupal_strtolower($text);
  foreach ($open_tags as $i => $tag) {
    $offset = 0;
    while (($offset = $findtagfunc($searchtext, $tag, $offset)) !== FALSE) {

      // Longer tags will override shorter '<' on the same offset.
      $events[$offset] = array(
        'type' => 'open',
        'which' => $i,
      );
      $offset += drupal_strlen($tag);
    }
  }

  // Find match candidates.
  foreach ($terms_replace as $i => $term) {
    $name = $term['term']->name;

    // Search for term name in content.
    if (!$case_sensitive) {
      $name = drupal_strtolower($name);
    }
    $offset = 0;
    $first_match_found = FALSE;
    while (($offset = $findfunc($searchtext, $name, $offset)) !== FALSE) {
      $len = drupal_strlen($name);
      $match = drupal_substr($text, $offset, $len);

      // Check if the match that was found is a proper match by the match
      // setting.
      $matchlen = drupal_strlen($match);
      $proper_match = FALSE;
      switch (variable_get('lexicon_match', 'b')) {

        // Require word break left or right.
        case 'lr':
          $proper_match = _lexicon_is_boundary(drupal_substr($text, $offset - 1, 1)) || _lexicon_is_boundary(drupal_substr($text, $offset + $matchlen, 1));
          break;

        // Require word break left and right.
        case 'b':
          $proper_match = _lexicon_is_boundary(drupal_substr($text, $offset - 1, 1)) && _lexicon_is_boundary(drupal_substr($text, $offset + $matchlen, 1));
          break;

        // Require word break left.
        case 'l':
          $proper_match = _lexicon_is_boundary(drupal_substr($text, $offset - 1, 1));
          break;

        // Require word break right.
        case 'r':
          $proper_match = _lexicon_is_boundary(drupal_substr($text, $offset + $matchlen, 1));
          break;

        // Match any substring.
        case 's':
        default:
          $proper_match = TRUE;
          break;
      }
      if ($proper_match) {

        // Only longer matches override shorter ones.
        if (!isset($events[$offset]) || drupal_strlen($events[$offset]['match']) < drupal_strlen($match)) {

          // Get synonym with case as in text.
          $events[$offset] = array(
            'type' => 'match',
            'which' => $i,
            'match' => $match,
          );
          if (!$replaceall) {
            $first_match_found = TRUE;
            break;
          }
        }
      }
      $offset += $len;
    }
    if (isset($term['term']->synonyms)) {
      foreach ($term['term']->synonyms as $synonym) {
        if (!$case_sensitive) {
          $synonym = drupal_strtolower($synonym);
        }
        $offset = 0;
        $first_match_found = FALSE;
        while (($offset = $findfunc($searchtext, $synonym, $offset)) !== FALSE) {
          $len = drupal_strlen($synonym);
          $match = drupal_substr($text, $offset, $len);

          // Check if the match that was found is a proper match according to
          // the match setting.
          $matchlen = drupal_strlen($match);
          $proper_match = FALSE;
          switch (variable_get('lexicon_match', 'b')) {

            // Require word break left or right.
            case 'lr':
              $proper_match = _lexicon_is_boundary(drupal_substr($text, $offset - 1, 1)) || _lexicon_is_boundary(drupal_substr($text, $offset + $matchlen, 1));
              break;

            // Require word break left and right.
            case 'b':
              $proper_match = _lexicon_is_boundary(drupal_substr($text, $offset - 1, 1)) && _lexicon_is_boundary(drupal_substr($text, $offset + $matchlen, 1));
              break;

            // Require word break left.
            case 'l':
              $proper_match = _lexicon_is_boundary(drupal_substr($text, $offset - 1, 1));
              break;

            // Require word break right.
            case 'r':
              $proper_match = _lexicon_is_boundary(drupal_substr($text, $offset + $matchlen, 1));
              break;

            // Match any substring.
            case 's':
            default:
              $proper_match = TRUE;
              break;
          }
          if ($proper_match) {

            // Only longer matches override shorter ones.
            if (!isset($events[$offset]) || drupal_strlen($events[$offset]['match']) < drupal_strlen($match)) {

              // Get synonym with case as in text.
              $events[$offset] = array(
                'type' => 'match',
                'which' => $i,
                'match' => $match,
              );
              if (!$replaceall) {
                $first_match_found = TRUE;
                break;
              }
            }
          }
          $offset += $len;
        }
        if ($first_match_found && !$replaceall) {
          break;
        }
      }
    }
  }
  ksort($events);
  $newtext = '';

  // Text was parsed from chars 0 to $parsed (exclusive).
  $parsed = 0;
  foreach ($events as $place => $event) {

    // Skip events inside blocking tag (they're already copied as is).
    if ($place < $parsed) {
      continue;
    }

    // Copy plain text (with no events).
    $newtext .= drupal_substr($text, $parsed, $place - $parsed);
    $parsed = $place;

    // If a blocking tag is opened, skip to closing tag.
    if ($event['type'] == 'open') {
      $skip = $findtagfunc($text, $close_tags[$event['which']], $place);
      if ($skip === FALSE) {
        $skip = drupal_strlen($text);
      }

      // If the tag is [no-lexicon] - remove it with the closing tag
      // (by incrementing $parsed without copying).
      if ($event['which'] == 0) {
        $parsed += drupal_strlen($open_tags[$event['which']]);
        $newtext .= drupal_substr($text, $parsed, $skip - $parsed);
        $parsed = $skip + drupal_strlen($close_tags[$event['which']]);
      }
      else {
        $newtext .= drupal_substr($text, $parsed, $skip - $parsed);
        $parsed = $skip;
      }
    }
    if ($event['type'] == 'match') {
      $matchlen = drupal_strlen($event['match']);
      if ($replace_mode == 'template') {
        $newtext .= theme('lexicon_mark_term', array(
          'term' => $terms_replace[$event['which']],
          'text' => $event['match'],
        ));
      }
      else {
        $newtext .= $terms_replace[$event['which']]['ins_before'] . $event['match'] . $terms_replace[$event['which']]['ins_after'];
      }
      $parsed += $matchlen;
    }
  }

  // Append remaining part.
  return $newtext . drupal_substr($text, $parsed);
}