function _glossary_insertlink in Glossary 5.2
Same name and namespace in other branches
- 5 glossary.module \_glossary_insertlink()
- 6 glossary.module \_glossary_insertlink()
- 7 glossary.module \_glossary_insertlink()
Insert glossary 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 _glossary_insertlink()
File
- ./
glossary.module, line 602 - Glossary terms will be automatically marked with links to their descriptions.
Code
function _glossary_insertlink($format, &$text, &$terms) {
$multibyte_enabled = extension_loaded('mbstring');
if ($multibyte_enabled) {
$mb_prefix = 'mb_';
$drupal_prefix = 'mb_';
}
else {
$mb_prefix = NULL;
$drupal_prefix = NULL;
}
$case_sensitive = variable_get("glossary_case_{$format}", '1');
// $findfunc = $mb_prefix . ($case_sensitive ? 'strpos' : 'stripos');
$findfunc = $mb_prefix . 'strpos';
$findtagfunc = $mb_prefix . 'strpos';
$substrfunc = $drupal_prefix . 'substr';
$strlenfunc = $drupal_prefix . 'strlen';
$replaceall = variable_get("glossary_replace_all_{$format}", 0);
$events = array();
// Find blocking tags.
$open_tags = array(
'[no-glossary]',
'<',
'<a ',
'[code',
);
$close_tags = array(
'[/no-glossary]',
'>',
'</a>',
'[/code]',
);
// use these always/when Codefilter module is on?
// array('< ?php ', '[?php ', '<% ', '[% ', '[codefilter_');
// array('?'.'>', '?]', '%'.'>', '%]', '[/codefilter_');
$user_tags = explode(' ', variable_get("glossary_blocking_tags_{$format}", 'abbr acronym'));
foreach ($user_tags as $tag) {
if (!empty($tag)) {
if (ctype_alnum($tag)) {
$open_tags[] = "<{$tag}";
$close_tags[] = "</{$tag}>";
}
else {
if ($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 += $strlenfunc($tag);
}
}
// Find match candidates.
foreach ($terms as $i => $term) {
foreach ($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 = $strlenfunc($synonym);
$match = $substrfunc($text, $offset, $len);
// Only longer matches override shorter ones.
if (!isset($events[$offset]) || $strlenfunc($events[$offset]['match']) < $strlenfunc($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;
}
//TODO: remove this if we want different synonyms of the same term to be matched independently as 'first matches'
if ($first_match_found && !$replaceall) {
break;
}
}
}
ksort($events);
$newtext = '';
$parsed = 0;
// Text was parsed from chars 0 to $parsed (exclusive).
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 .= $substrfunc($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 = $strlenfunc($text);
}
// If the tag is [no-glossary] - remove it with the closing tag (by incrementing $parsed without copying).
if ($event['which'] == 0) {
$parsed += $strlenfunc($open_tags[$event['which']]);
$newtext .= $substrfunc($text, $parsed, $skip - $parsed);
$parsed = $skip + $strlenfunc($close_tags[$event['which']]);
}
else {
$newtext .= $substrfunc($text, $parsed, $skip - $parsed);
$parsed = $skip;
}
}
if ($event['type'] == 'match') {
$matchlen = $strlenfunc($event['match']);
$proper_match = FALSE;
switch (variable_get("glossary_match_{$format}", 'b')) {
case 'lr':
// Require word break left or right.
// $proper_match = (_glossary_is_boundary($text {$next - 1}) || _glossary_is_boundary($text {$next + $matchlen}));
$proper_match = _glossary_is_boundary($substrfunc($text, $place - 1, 1)) || _glossary_is_boundary($substrfunc($text, $place + $matchlen, 1));
break;
case 'b':
// Require word break left and right.
// $proper_match = (_glossary_is_boundary($text {$next - 1}) && _glossary_is_boundary($text {$next + $matchlen}));
$proper_match = _glossary_is_boundary($substrfunc($text, $place - 1, 1)) && _glossary_is_boundary($substrfunc($text, $place + $matchlen, 1));
break;
case 'l':
// Require word break left.
// $proper_match = _glossary_is_boundary($text {$next - 1});
$proper_match = _glossary_is_boundary($substrfunc($text, $place - 1, 1));
break;
case 'r':
// Require word break right.
// $proper_match = _glossary_is_boundary($text {$next + $matchlen});
$proper_match = _glossary_is_boundary($substrfunc($text, $place + $matchlen, 1));
break;
case 's':
// Match any substring.
default:
$proper_match = TRUE;
break;
}
if ($proper_match) {
$newtext .= $terms[$event['which']]['ins_before'] . $event['match'] . $terms[$event['which']]['ins_after'];
$parsed += $matchlen;
}
}
}
// Append remaining part.
return $newtext . $substrfunc($text, $parsed);
}