function _tableofcontents_replace_headers in Table of Contents 6.3
Same name and namespace in other branches
- 7.2 tableofcontents.inc \_tableofcontents_replace_headers()
- 7 tableofcontents.pages.inc \_tableofcontents_replace_headers()
This function changes a header attributes. It adds an identifier in case there are none. It registers the identifier if there is already one.
\note Note that the attributes (2nd match) always starts with a space if it exists.
@param[in] $matches The matches (level, attributes and title)
Return value
The header with an identifier.
1 string reference to '_tableofcontents_replace_headers'
- _tableofcontents_headers in ./
tableofcontents.pages.inc - This function goes through all the headers found in the text.
File
- ./
tableofcontents.pages.inc, line 43 - Applies the filter functions.
Code
function _tableofcontents_replace_headers($matches) {
global $_tableofcontents_toc;
static $toc_translations, $duplicates_error;
$h = new TOC_Header();
$h->level = $matches[2];
$h->attributes = $matches[3];
$h->title = $matches[4];
// increase this level and reset all the sub-levels
++$_tableofcontents_toc->counters[$h->level];
for ($l = $h->level + 1; $l <= 6; ++$l) {
$_tableofcontents_toc->counters[$l] = 0;
}
if ($_tableofcontents_toc->level_from > $h->level) {
$_tableofcontents_toc->level_from = $h->level;
}
$_tableofcontents_toc->level_to = $h->level;
// determine the min./max. on the spot
if ($_tableofcontents_toc->header_min) {
if ($_tableofcontents_toc->header_min > $h->level) {
$_tableofcontents_toc->header_min = $h->level;
}
}
else {
$_tableofcontents_toc->header_min = $h->level;
}
if ($_tableofcontents_toc->header_max) {
if ($_tableofcontents_toc->header_max < $h->level) {
$_tableofcontents_toc->header_max = $h->level;
}
}
else {
$_tableofcontents_toc->header_max = $h->level;
}
// check for existing id and use that if found
if (preg_match('/\\sid=(?:"([^"]*?)"|\'([^\']*?)\'|([^\\s"\'>]))/i', $h->attributes, $id)) {
// id[1] is with "
// id[2] is with '
// id[3] is without any quotes
$h->identifier = $id[1] ? $id[1] : ($id[2] ? $id[2] : $id[3]);
// check for unicity
foreach ($_tableofcontents_toc->headers as $header) {
if ($header->identifier == $h->identifier) {
if (!isset($duplicates_error)) {
$duplicates_error = TRUE;
drupal_set_message(t('Two or more anchor identifiers match each others. One of them will be modified. This error happens when some anchor identifiers are generated automatically and others are predefined. Or both are predefined and the operator made a mistake (maybe a copy & paste?)'), 'warning');
}
// make it unique anyway
$h->identifier .= $_tableofcontents_toc->id_separator . $_tableofcontents_toc->header_id++;
$h->attributes = preg_replace('/\\sid=(?:"([^"]*?)"|\'([^\']*?)\'|([^\\s"\'>]))/i', ' id="' . $h->identifier . '"', $h->attributes);
break;
}
}
}
else {
switch ($_tableofcontents_toc->id_generator) {
case 'random':
// generate a random ID and then ensure unicity
do {
$id = user_password(8);
// system function to generate a password from letters/digits
$found = FALSE;
foreach ($_tableofcontents_toc->headers as $header) {
if ($header->identifier == $id) {
$found = TRUE;
break;
}
}
} while ($found);
break;
case 'increment':
$id = $_tableofcontents_toc->identifier_introducer . $_tableofcontents_toc->id_separator . $_tableofcontents_toc->header_id++;
break;
case 'sections':
$id = $_tableofcontents_toc->identifier_introducer;
for ($idx = $_tableofcontents_toc->level_from; $idx <= $_tableofcontents_toc->level_to; ++$idx) {
$id .= $_tableofcontents_toc->id_separator . $_tableofcontents_toc->counters[$idx];
}
break;
case 'custom':
// the callee has to edit the $h->identifier and $h->attributes fields
module_invoke_all('anchor_identifier', $_tableofcontents_toc, $h);
$id = '';
break;
default:
// case 'title'
// no existing identifier, create one using the header title
//
// HTML 4.01
//
// http://www.w3.org/TR/html4/types.html#h-6.2
//
// ID and NAME tokens must begin with a letter ([A-Za-z]) and
// may be followed by any number of letters, digits ([0-9]),
// hyphens ("-"), underscores ("_"), colons (":"), and periods (".").
//
// 1. convert and other spaces into underscores
// 2. convert — or – to '--'
// 3. convert & to 'and'
// 4. remove any other entities
// 5. remove any incompatible character
// 6. remove digits at the start of the name (we could also add a letter?)
//
// thanks to pathauto module for i18n-ascii.txt file
if (!isset($toc_translations)) {
$path = drupal_get_path('module', 'tableofcontents');
$toc_translations = parse_ini_file($path . '/i18n-ascii.txt');
}
$title = strtr(strip_tags($h->title, $_tableofcontents_toc->allowed_tags), $toc_translations);
$allowed_chars = '';
if (empty($_tableofcontents_toc->id_stripping['dashes'])) {
$allowed_chars = '-';
}
$allowed_chars .= 'A-Za-z';
if (empty($_tableofcontents_toc->id_stripping['digits'])) {
$allowed_chars .= '0-9';
}
if (empty($_tableofcontents_toc->id_stripping['periods'])) {
$allowed_chars .= '.';
}
if (empty($_tableofcontents_toc->id_stripping['underscores'])) {
$allowed_chars .= '_';
}
if (empty($_tableofcontents_toc->id_stripping['colons'])) {
$allowed_chars .= ':';
}
$id = preg_replace(array(
'/ |\\s/',
'/\'/',
'/—/',
'/–/',
'/&/',
'/&[a-z]+;/',
'/[^' . $allowed_chars . ']/',
'/^[-0-9._:]+/',
'/__+/',
), array(
'_',
// and spaces
'-',
// apostrophe, so it makes things slightly more readable
'--',
// —
'--',
// –
'and',
// &
'',
// any other entity
'',
// any character that is invalid as an ID name
'',
// any digits at the start of the name
'_',
), strip_tags($title));
if (!$id) {
// no identifier (i.e. title is composed exclusively of digits, entities, etc.)
$id = $_tableofcontents_toc->identifier_introducer . $_tableofcontents_toc->id_separator . $_tableofcontents_toc->header_id++;
}
break;
}
if ($id != '') {
// ensure unicity
foreach ($_tableofcontents_toc->headers as $header) {
if ($header->identifier == $id) {
$id .= $_tableofcontents_toc->id_separator . $_tableofcontents_toc->header_id++;
break;
}
}
$h->identifier = $id;
// create a new header including the generated identifier
$h->attributes .= ' id="' . $id . '"';
}
}
$h->number = theme('tableofcontents_number', $_tableofcontents_toc);
if ($_tableofcontents_toc->number_headers) {
$number = $h->number;
}
else {
$number = '';
}
$result = $matches[1] . '<h' . $h->level . $h->attributes . '>' . $number . $h->title . '</h' . $h->level . '>';
// save that header
$_tableofcontents_toc->headers[] = $h;
// Add a back to top before the header?
if ($_tableofcontents_toc->back_to_top && $h->level >= $_tableofcontents_toc->back_to_top_minlevel && $h->level <= $_tableofcontents_toc->back_to_top_maxlevel) {
switch ($_tableofcontents_toc->back_to_top_location) {
case 'header':
$result .= $_tableofcontents_toc->back_to_top_link;
break;
default:
//case 'bottom':
if (!$_tableofcontents_toc->first_header) {
$result = $_tableofcontents_toc->back_to_top_link . $result;
}
break;
}
}
$_tableofcontents_toc->first_header = FALSE;
return $result;
}