collapse_text.module in Collapse Text 6
Same filename and directory in other branches
collapse_text is an input filter that allows text to be collapsible
File
collapse_text.moduleView source
<?php
/**
* @file
* collapse_text is an input filter that allows text to be collapsible
*/
/**
* Implementation of hook_filter_tips().
*/
function collapse_text_filter_tips($delta, $format, $long = false) {
if ($long) {
return t('Enclose sections of text in [collapse] and [/collapse] to ' + 'turn them into collapsible sections. If you use [collapse collapsed] ' + 'and [/collapse], the section will start out collapsed. You may ' + 'specify a title with [collapse title=some title] ' + '(or [collapse collapsed title=some title]). If no title is specified, ' + 'the title will be taken from the first header ' + '(<h1>, <h2>, <h3>, ...) found. In the absence of a ' + 'header, a default title is used.');
}
else {
return t('Make collapsible text blocks using [collapse] and [/collapse].');
}
}
/**
* Implementation of hook_filter().
*/
function collapse_text_filter($op, $delta = 0, $format = -1, $text = '') {
switch ($op) {
case 'list':
return array(
0 => t('Collapse text'),
);
break;
case 'description':
return t('Make collapsing text sections');
break;
case 'settings':
// This filter has no user settings.
break;
case 'no cache':
return FALSE;
break;
case 'prepare':
return $text;
break;
case 'process':
return collapse_text_process($text);
break;
default:
return $text;
break;
}
}
function collapse_text_process($text) {
$text = collapse_text_process_recurs($text);
// remove non-escaped collapse open tags
$text = preg_replace('/(?<!\\\\)
\\[
collapse
(\\ collapsed)?
(?:\\ style=([^\\] ]*))?
(?:\\ title=([^\\]]*))?
\\]/smx', "", $text);
// remove non-escaped collapse close tags
$text = preg_replace('/(?<!\\\\)\\[\\/collapse\\]/smx', "", $text);
// remove backslash on escaped open tags
$text = preg_replace('/\\\\
(\\[
collapse
(?:\\ collapsed)?
(?:\\ style=([^\\] ]*))?
(?:\\ title=[^\\]]*)?
\\])/smx', '$1', $text);
// remove backslash on escaped close tags
$text = preg_replace('/\\\\(\\[\\/collapse\\])/smx', "\$1", $text);
return $text;
}
/**
* Provides a layer of encapsulation for the regex call.
*/
function collapse_text_process_recurs($text) {
// Per #259535 and #233877, add ability to specify title
// in collapse text. Thanks rivena, Justyn
// Per #233877, add ability to have nested sections.
$text = preg_replace_callback('/
(?:<p(?:\\s[^>]*)?>)? # (remove paragraph if right before)
(?<!\\\\) # make sure the tag is not escaped with a backslash
\\[ # look for an opening bracket
collapse # followed by the word `collapse`
(\\ collapsed)? # followed by (optionally) a space and the word `collapsed` (captured)
(?:\\ style=([^\\] ]*))? # followed by (optionally) a space and a style, consisting of any
# characters except a close bracket (captured)
(?:\\ title=([^\\]]*))? # followed by (optionally) a space and a title, consisting of any
\\] # followed by a closing bracket
(?:<\\/p\\s*>)? # (remove paragraph if right after)
( (?: [^[] # followed by either a non open bracket,
| \\\\\\[ # or an escaped open bracket
| \\[(?!\\/?collapse) # or a non collapse tag
| (?R) )+ ) # or the expression recursively run.
(?:<p(?:\\s[^>]*)?>)? # (remove paragraph if right before)
(?<!\\\\) # make sure the tag is not escaped with a backslash
\\[\\/collapse\\] # a closing "tag", which is a slash followed by `collapse` in brackets
(?:<\\/p\\s*>)? # (remove paragraph if right after)
/smx', "_collapse_text_replace_callback", $text);
return $text;
}
function _collapse_text_replace_callback($matches) {
global $base_url;
// 2008-12-15 REMorse (no issue number) added space to make
// $collapsed work
$collapsed = $matches[1] == ' collapsed';
$style = trim($matches[2]);
$title = trim($matches[3]);
$interior = $matches[4];
if (empty($title)) {
// If a title is not supplied, look for a header (<h1>, <h2> ...)
// and use it as the title.
$h_matches = array();
preg_match('/(<h\\d[^>]*>(.+?)<\\/h\\d>)/smi', $interior, $h_matches);
$title = strip_tags($h_matches[2]);
// If we get the title from the first header tag,
// then we should remove the header tag so it's not repeated
if (!empty($title)) {
$replacement = "";
$occ = 1;
$interior = str_replace($h_matches[0], $replacement, $interior, $occ);
}
}
if (empty($title)) {
// If there is still no title, provide some default text.
// Added call to t() per #256176 yngens
$title = t('Use the arrow to expand or collapse this section');
}
$form = array(
'#prefix' => '<form action="' . $base_url . '/">',
'#suffix' => '</form>',
'#theme' => 'collapse_text_fieldset',
);
$form['fieldset'] = array(
'#type' => 'fieldset',
'#title' => $title,
'#collapsible' => true,
'#collapsed' => $collapsed,
);
if (!empty($style)) {
$form['fieldset']['#attributes'] = array(
'class' => collapse_text_id_safe($style),
);
}
$form['fieldset']['text_contents'] = array(
'#type' => 'markup',
'#prefix' => '<div class="collapse-text">',
'#value' => collapse_text_process_recurs($interior),
'#suffix' => '</div>',
);
return drupal_render($form);
}
function collapse_text_preprocess_page(&$variables) {
global $theme;
// Add collapse.js if a collapsible fieldset is found in a region or the main content.
if (strpos($variables['scripts'], 'misc/collapse.js') === FALSE) {
$regions = array_keys(system_region_list($theme));
$regions[] = 'content';
foreach ($regions as $region) {
// Using stripos() is much faster then executing preg_match() on every page.
if (stripos($variables[$region], '<fieldset') !== FALSE && stripos($variables[$region], 'collapsible') !== FALSE) {
drupal_add_js('misc/collapse.js', 'core');
$variables['scripts'] = drupal_get_js();
return;
}
}
}
}
/**
* Implementation of hook_theme().
*/
function collapse_text_theme($existing, $type, $theme, $path) {
return array(
'collapse_text_fieldset' => array(
'arguments' => array(
'element',
),
),
);
}
/**
* Theme a section of collapsible text. By default, this function calls the
* default 'theme_fieldset' implementation, but this function can be overridden
* to implement a custom theme just for collapsed text.
*
* @param $element
* An associative array containing the properties of the element.
* Properties used: attributes, title, value, description, children, collapsible, collapsed
* @return
* A themed HTML string representing the collapsed text.
*
* @ingroup themeable
*/
function theme_collapse_text_fieldset($element) {
return drupal_render($element);
}
/**
* Converts a string to a suitable html ID attribute.
* Copied from zen_id_safe() in the Zen theme.
*
* http://www.w3.org/TR/html4/struct/global.html#h-7.5.2 specifies what makes a
* valid ID attribute in HTML. This function:
*
* - Ensure an ID starts with an alpha character by optionally adding an 'id'.
* - Replaces any character except alphanumeric characters with dashes.
* - Converts entire string to lowercase.
*
* @param $string
* The string
* @return
* The converted string
*/
function collapse_text_id_safe($string) {
// Replace with dashes anything that isn't A-Z, numbers, dashes, or underscores.
$string = strtolower(preg_replace('/[^a-zA-Z0-9-]+/', '-', $string));
// If the first character is not a-z, add 'id' in front.
if (!ctype_lower($string[0])) {
// Don't use ctype_alpha since its locale aware.
$string = 'id' . $string;
}
return $string;
}
Functions
Name | Description |
---|---|
collapse_text_filter | Implementation of hook_filter(). |
collapse_text_filter_tips | Implementation of hook_filter_tips(). |
collapse_text_id_safe | Converts a string to a suitable html ID attribute. Copied from zen_id_safe() in the Zen theme. |
collapse_text_preprocess_page | |
collapse_text_process | |
collapse_text_process_recurs | Provides a layer of encapsulation for the regex call. |
collapse_text_theme | Implementation of hook_theme(). |
theme_collapse_text_fieldset | Theme a section of collapsible text. By default, this function calls the default 'theme_fieldset' implementation, but this function can be overridden to implement a custom theme just for collapsed text. |
_collapse_text_replace_callback |