Teaser met html support > nog een Regex update (met dank aan Kurt)
<?php
/**
* @file
*
* Main module file for The AIM User Interface
*/
/**
* Implements hook_menu()
*/
function the_aim_ui_menu() {
$items = array();
$items['admin/config/the-aim'] = array(
'title' => 'The AIM',
'description' => 'Configure The AIM modules',
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array('access administration pages'),
'type' => MENU_NORMAL_ITEM,
'weight' => 50,
'file path' => drupal_get_path('module', 'system'),
'file' => 'system.admin.inc',
);
return $items;
}
/**
* Implements hook_field_formatter_info()
*/
function the_aim_ui_field_formatter_info() {
return array(
'trim_to_char' => array(
'label' => t('Trim to # chars'),
'field types' => array('text_long', 'text_with_summary'),
'description' => t('Trim the output of a field to a specific number of characters.'),
'settings' => array(
'number_of_chars' => 300,
'wordsafe' => (int) FALSE,
'min_wordsafe_length' => 4,
'add_ellipsis' => (int) TRUE,
'ellipsis' => '',
'clean_cbox' => (int) FALSE,
'clean_tables' => (int) FALSE,
'allowed_tags' => '',
'break_tags' => '',
),
),
);
}
/**
* Implements hook_field_formatter_view().
*/
function the_aim_ui_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
switch ($display['type']) {
case 'trim_to_char':
$max_length = max((int) $display['settings']['number_of_chars'], 0);
$wordsafe = (!empty($display['settings']['wordsafe'])) ? (bool) $display['settings']['wordsafe'] : FALSE ;
$min_wordsafe_length = (!empty($display['settings']['min_wordsafe_length'])) ? (int) $display['settings']['min_wordsafe_length'] : 1 ;
$add_ellipsis = (!empty($display['settings']['add_ellipsis'])) ? (bool) $display['settings']['add_ellipsis'] : FALSE ;
$options = array();
if (!empty($display['settings']['ellipsis'])) $options['ellipsis'] = $display['settings']['ellipsis'];
if (!empty($display['settings']['allowed_tags'])) $options['allowed_tags'] = $display['settings']['allowed_tags'];
if (!empty($display['settings']['break_tags'])) $options['break_tags'] = $display['settings']['break_tags'];
if (!empty($display['settings']['clean_cbox'])) $options['clean_cbox'] = $display['settings']['clean_cbox'];
if (!empty($display['settings']['clean_tables'])) $options['clean_tables'] = $display['settings']['clean_tables'];
$element = array();
foreach ($items as $delta => $item) {
$string = (!empty($item['summary'])) ? $item['summary'] : $item['value'];
$string = _truncate_utf8_xml($string, $max_length, $wordsafe, $add_ellipsis, $min_wordsafe_length, $options);
$element[] = array(
'#type' => 'markup',
'#markup' => $string,
);
}
break;
}
return $element;
}
/**
* Truncates a UTF-8-encoded XML string
*
* @param string $string
* @param int $max_length
* @param bool $wordsafe
* @param bool $add_ellipsis
* @param int $min_wordsafe_length
* @param array $options
*
* @return string Returns a valid truncated XML string.
*/
function _truncate_utf8_xml($string, $max_length, $wordsafe = FALSE, $add_ellipsis = FALSE, $min_wordsafe_length = 1, $options = array()) {
// Define defaults
$ellipsis = '…';
$allowed_tags = '';
$break_tags = '';
$clean_cbox = FALSE;
$clean_tables = FALSE;
// Set the defined field formatter options
extract($options);
// Get the ellipsis length
if ($add_ellipsis) {
// Truncate ellipsis in case $max_length is small.
$ellipsis = drupal_substr(html_entity_decode($ellipsis), 0, $max_length);
$max_length -= drupal_strlen($ellipsis);
$max_length = max($max_length, 0);
}
if ($max_length <= $min_wordsafe_length) {
// Do not attempt word-safe if lengths are bad.
$wordsafe = FALSE;
}
// Add a break after some tags
if (!empty($break_tags)) {
preg_match_all('/[a-z]+/i', $break_tags, $break_tags);
$break_tags = reset($break_tags);
foreach ($break_tags as $tag) {
$string = preg_replace('/<\/' . $tag . '>/im', '<br>$0', $string);
}
}
// Strip colorbox links
if ((bool)$clean_cbox) {
$string = preg_replace('/(<a class="cboxElement".*?>)(.+)(<\/a>)/ims', '$2', $string);
}
// Strip any (nested) tables
if ((bool)$clean_tables) {
$string = preg_replace('%<table\b[^>]*+>(?:(?R)|[^<]*+(?:(?!</?table\b)<[^<]*+)*+)*+</table>%im', '', $string);
}
// Strip the string from tags, keeping the allowed tags
$string = trim(strip_tags($string, $allowed_tags));
// Strip empty links
$string = preg_replace('/<a[^>]*>(\s|<\/?\s*br\s*\/?>)*<\/a>/im', '', $string);
// Strip empty paragraph
$string = preg_replace('/<p[^>]*>(\s|<\/?\s*br\s*\/?>)*<\/p>/im', '', $string);
// Replace tabs, newlines and carriage returns with a regular space.
$string = preg_replace('~[[:cntrl:]]~', ' ', $string);
// Replace multiple spaces with a single one
$string = preg_replace('!\s+!', ' ', $string);
// If the length without tags is less than our target we are done
if (strlen(strip_tags($string)) < $max_length)
return $string;
// Get the validated xml string
$string = _valid_xml($string);
// Get each single word / tag
preg_match_all('/<[^>]++>|[^<>\s]++/', $string, $tokens);
// Loop over the words / tags
$counter = 0;
$newtext = array();
foreach ($tokens[0] as $i => $token) {
// Ignore tags in the string length
if (mb_substr($token, 0, 1, 'utf-8') === '<') {
$newtext[] = $token;
continue;
}
// Get the token length
$token_length = mb_strlen(html_entity_decode($token));
// Set the string length till this word (count in the leading space)
$counter += $token_length + 1;
// Adding the word would exceed the allowed string length
if ($counter > $max_length) {
// Add a word fragment if allowed
if (!$wordsafe) {
$delta = $counter - $max_length;
$fragment = mb_substr($token, 0, $delta);
$newtext[] = $fragment;
}
else {
// Check if the last word respects the minimum wordsafe length
while (mb_strlen(end($newtext)) < $min_wordsafe_length) {
array_pop($newtext);
}
}
// Prevent to add the word
break;
}
$newtext[] = $token;
}
// Build the new string
$string = implode(' ', $newtext);
// Get the validated xml string
$string = _valid_xml($string);
// Add the ellipsis at the end
if ($add_ellipsis)
$string .= $ellipsis;
// Return the processed string
return $string;
}
/**
* Generate a valid XML string
*
* @param string $text
*
* @return string Return a valid XML string.
*/
function _valid_xml($text) {
// Create a new xml document object
$document = new DOMDocument();
// Disable libxml errors
libxml_use_internal_errors(true);
// Load HTML from a string
$document->loadHTML('<?xml version="1.0" encoding="UTF-8"?><body>' . $text . '</body>');
// Clear libxml error buffer
libxml_clear_errors();
// Get the body from the xml document
$text = substr($document->saveXML($document->getElementsByTagName('body')->item(0)), strlen('<body>'), -strlen('</body>'));
// Return the text
return $text;
}
/**
* Implements hook_field_formatter_settings_form().
*/
function the_aim_ui_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$element = array();
$element['number_of_chars'] = array(
'#type' => 'textfield',
'#title' => t('Number of characters'),
// '#description' => t('The maximum number of characters'),
'#default_value' => $settings['number_of_chars'],
);
$element['wordsafe'] = array(
'#type' => 'checkbox',
'#title' => t('Wordsafe'),
'#description' => t('Don\'t cut words while shortening text'),
'#default_value' => $settings['wordsafe'],
);
$element['min_wordsafe_length'] = array(
'#type' => 'textfield',
'#title' => t('Wordsafe length'),
'#description' => t('Make sure the latest word, from a shortened text, has a certain length'),
'#default_value' => $settings['min_wordsafe_length'],
);
$element['add_ellipsis'] = array(
'#type' => 'checkbox',
'#title' => t('Add ellipsis'),
// '#description' => t('Add an ellipsis to the end of a shortened text'),
'#default_value' => $settings['add_ellipsis'],
);
$element['ellipsis'] = array(
'#type' => 'textfield',
'#title' => t('Ellipsis substitution'),
// '#description' => t('Sign or signs to indicate the text was shortened'),
'#default_value' => $settings['ellipsis'],
);
$element['clean_cbox'] = array(
'#type' => 'checkbox',
'#title' => t('Remove colorboxes'),
'#description' => t('Remove colorbox links even though links are allowed'),
'#default_value' => $settings['clean_cbox'],
);
$element['clean_tables'] = array(
'#type' => 'checkbox',
'#title' => t('Remove tables'),
// '#description' => t('Remove tables from the output'),
'#default_value' => $settings['clean_tables'],
);
$element['allowed_tags'] = array(
'#type' => 'textfield',
'#title' => t('Allowed tags'),
'#description' => t('Don\'t strip the above tags. For example: %example', array('%example' => '<a><b><i><strong><em><br><br/>')),
'#default_value' => $settings['allowed_tags'],
);
$element['break_tags'] = array(
'#type' => 'textfield',
'#title' => t('Break tags'),
'#description' => t('Add a break tag at the end of the above tags. For example: %example', array('%example' => '</p></li>')),
'#default_value' => $settings['break_tags'],
);
return $element;
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function the_aim_ui_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$summary = t('Maximum number of chars: @number_of_chars', array(
'@number_of_chars' => $settings['number_of_chars'],
));
return $summary;
}