function XBBCodeFilter::process in Extensible BBCode 7
Same name and namespace in other branches
- 5 xbbcode-filter.php \XBBCodeFilter::process()
- 6 xbbcode.filter.inc \XBBCodeFilter::process()
Execute the filter on a particular text.
Note: This function makes use of substr() and strlen() instead of Drupal wrappers. This is the correct approach as all offsets are calculated by the PREG_OFFSET_CAPTURE setting of preg_match_all(), which returns byte offsets rather than character offsets.
Parameters
$text: The text to be filtered.
Return value
HTML code.
File
- ./
xbbcode.filter.inc, line 40 - The filtering class. This will be instanced for each filter, and then called to process a piece of text.
Class
- XBBCodeFilter
- @file The filtering class. This will be instanced for each filter, and then called to process a piece of text.
Code
function process($text) {
// Find all opening and closing tags in the text.
preg_match_all(XBBCODE_RE_TAG, $text, $tags, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
if (!$tags) {
return $text;
}
// Initialize the stack with a root tag, and the name tracker.
$stack = array(
new XBBCodeTagMatch(),
);
$open_by_name = array();
foreach ($tags as $i => $tag) {
$tag = $tags[$i] = new XBBCodeTagMatch($tag, $this);
$open_by_name[$tag->name] = 0;
}
foreach ($tags as $tag) {
// Case 1: The tag is opening, and known to the filter.
if (!$tag->closing && isset($this->tags[$tag->name])) {
// Add text before the new tag to the parent, then stack the new tag.
end($stack)
->advance($text, $tag->start);
// Stack the newly opened tag, or render it if it's selfclosing.
if ($this->tags[$tag->name]->options->selfclosing) {
$rendered = $this
->render_tag($tag);
if ($rendered === NULL) {
$rendered = $tag->element;
}
end($stack)
->append($rendered, $tag->end);
}
else {
array_push($stack, $tag);
$open_by_name[$tag->name]++;
}
}
elseif ($tag->closing && !empty($open_by_name[$tag->name])) {
// Find the last matching opening tag, breaking any unclosed tag since then.
while (end($stack)->name != $tag->name) {
$dangling = array_pop($stack);
end($stack)
->break_tag($dangling);
$open_by_name[$dangling->name]--;
}
end($stack)
->advance($text, $tag->start);
$open_by_name[$tag->name]--;
// If the tag forbids rendering its content, revert to the unrendered text.
if ($this->tags[$tag->name]->options->nocode) {
end($stack)
->revert($text);
}
if ($this->tags[$tag->name]->options->plain) {
// We will double-encode entities only if non-encoded chars exist.
if (end($stack)->content != htmlspecialchars(end($stack)->content, ENT_QUOTES, 'UTF-8', FALSE)) {
end($stack)->content = check_plain(end($stack)->content);
}
}
// Append the rendered HTML to the content of its parent tag.
$current = array_pop($stack);
$rendered = $this
->render_tag($current);
if ($rendered === NULL) {
$rendered = $current->element . $current->content . $tag->element;
}
end($stack)
->append($rendered, $tag->end);
}
}
end($stack)->content .= substr($text, end($stack)->offset);
if ($this->autoclose_tags) {
while (count($stack) > 1) {
// Render the unclosed tag and pop it off the stack
$output = $this
->render_tag(array_pop($stack));
end($stack)->content .= $output;
}
}
else {
while (count($stack) > 1) {
$current = array_pop($stack);
$content = $current->element . $current->content;
end($stack)->content .= $content;
}
}
return end($stack)->content;
}