class XBBCodeFilter in Extensible BBCode 8.2
Same name and namespace in other branches
- 8.3 src/Plugin/Filter/XBBCodeFilter.php \Drupal\xbbcode\Plugin\Filter\XBBCodeFilter
- 4.0.x src/Plugin/Filter/XBBCodeFilter.php \Drupal\xbbcode\Plugin\Filter\XBBCodeFilter
Provides a filter that converts BBCode to HTML.
Plugin annotation
@Filter(
id = "xbbcode",
title = @Translation("Convert BBCode into HTML."),
type = Drupal\filter\Plugin\FilterInterface::TYPE_MARKUP_LANGUAGE,
settings = {
"override" = FALSE,
"linebreaks" = TRUE,
"tags" = {}
}
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\filter\Plugin\FilterBase implements FilterInterface
- class \Drupal\xbbcode\Plugin\Filter\XBBCodeFilter
- class \Drupal\filter\Plugin\FilterBase implements FilterInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of XBBCodeFilter
File
- src/
Plugin/ Filter/ XBBCodeFilter.php, line 33 - Contains Drupal\xbbcode\Plugin\Filter\XBBCodeFilter.
Namespace
Drupal\xbbcode\Plugin\FilterView source
class XBBCodeFilter extends FilterBase {
private $tags;
/**
* Construct a filter object from a bundle of tags, and the format ID.
*
* @param $tags
* Tag array.
* @param $format
* Text format ID.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
module_load_include('inc', 'xbbcode');
$this->tag_settings = $this->settings['override'] ? $this->settings['tags'] : Drupal::config('xbbcode.settings')
->get('tags');
$this->tags = _xbbcode_build_tags($this->tag_settings ? $this->tag_settings : []);
}
/**
* Settings callback for the filter settings of xbbcode.
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$form['linebreaks'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Convert linebreaks to HTML.'),
'#default_value' => $this->settings['linebreaks'],
'#description' => $this
->t('Newline <code>\\n</code> characters will become <code><br /></code> characters.'),
];
$form['override'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Override the <a href="@url">global settings</a> with specific settings for this format.', [
'@url' => Drupal::url('xbbcode.admin_handlers'),
]),
'#default_value' => $this->settings['override'],
'#description' => $this
->t('Overriding the global settings allows you to disallow or allow certain special tags for this format, while other formats will not be affected by the change.'),
'#attributes' => [
'onchange' => 'Drupal.toggleFieldset(jQuery("#edit-filters-xbbcode-settings-tags"))',
],
];
$form = XBBCodeHandlerForm::buildFormHandlers($form, $this->tag_settings);
$form['handlers']['#type'] = 'details';
$form['handlers']['#open'] = $this->settings['override'];
$parents = $form['#parents'];
$parents[] = 'tags';
$form['handlers']['tags']['#parents'] = $parents;
$form['handlers']['extra']['tags']['#parents'] = $parents;
return $form;
}
public function tips($long = FALSE) {
if (!$this->tags) {
return $this
->t('BBCode is enabled, but no tags are defined.');
}
if ($long) {
$table = [
'#type' => 'table',
'#caption' => $this
->t('Allowed BBCode tags:'),
'#header' => [
$this
->t('Tag Description'),
$this
->t('You Type'),
$this
->t('You Get'),
],
];
foreach ($this->tags as $name => $tag) {
$table[$name] = [
[
'#markup' => "<strong>[{$name}]</strong><br />" . $tag->description,
'#attributes' => [
'class' => [
'description',
],
],
],
[
'#markup' => '<code>' . str_replace("\n", '<br />', SafeMarkup::checkPlain($tag->sample)) . '</code>',
'#attributes' => [
'class' => [
'type',
],
],
],
[
'#markup' => $this
->process($tag->sample, NULL)
->getProcessedText(),
'#attributes' => [
'class' => [
'get',
],
],
],
];
}
return Drupal::service('renderer')
->render($table);
}
else {
foreach ($this->tags as $name => $tag) {
$tags[$name] = '<abbr title="' . $tag->description . '">[' . $name . ']</abbr>';
}
return $this
->t('You may use these tags: !tags', [
'!tags' => implode(', ', $tags),
]);
}
}
/**
* {@inheritdoc}
*/
public function process($text, $langcode) {
$tree = $this
->buildTree($text);
$output = $this
->renderTree($tree->content);
// The core AutoP filter breaks inline tags that span multiple paragraphs.
// Since there is no advantage in using <p></p> tags, this filter uses
// ordinary <br /> tags which are usable inside inline tags.
if ($this->settings['linebreaks']) {
$output = nl2br($output);
}
return new FilterProcessResult($output);
}
private function buildTree($text) {
// Find all opening and closing tags in the text.
preg_match_all(XBBCODE_RE_TAG, $text, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
// Initialize the name tracker, and the list of valid tags.
$open_by_name = [];
$tags = [];
foreach ($matches as $match) {
$tag = new XBBCodeTagMatch($match);
if (isset($this->tags[$tag->name])) {
$tag->selfclosing = $this->tags[$tag->name]->options->selfclosing;
$tags[] = $tag;
$open_by_name[$tag->name] = 0;
}
}
// Initialize the stack with a root element.
$stack = [
new XBBCodeRootElement(),
];
foreach ($tags as $tag) {
// Add text before the new tag to the parent
end($stack)
->advance($text, $tag->start);
// Case 1: The tag is opening and not self-closing.
if (!$tag->closing && !$tag->selfclosing) {
// Stack the open tag, and increment the tracker.
array_push($stack, $tag);
$open_by_name[$tag->name]++;
}
elseif ($tag->selfclosing) {
end($stack)
->append($tag, $tag->end);
}
elseif ($open_by_name[$tag->name]) {
$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)
->breakTag($dangling);
$open_by_name[$dangling->name]--;
}
$current = array_pop($stack);
$current
->advance($text, $tag->start);
$current->source = substr($text, $current->end, $current->offset - $current->end);
$current->closer = $tag;
end($stack)
->append($current, $tag->end);
}
}
// Add the remainder of the text, and then break any tags still open.
end($stack)
->advance($text, strlen($text));
while (count($stack) > 1) {
$dangling = array_pop($stack);
end($stack)
->breakTag($dangling);
}
return end($stack);
}
private function renderTree($tree) {
$output = '';
foreach ($tree as $root) {
if (is_object($root)) {
$root->content = $this
->renderTree($root->content);
$rendered = $this
->renderTag($root);
$root = $rendered !== NULL ? $rendered : $root
->getOuterText();
}
$output .= $root;
}
return $output;
}
/**
* Render a single tag.
*
* @param $tag
* The complete match object, including its name, content and attributes.
*
* @return
* HTML code to insert in place of the tag and its content.
*/
private function renderTag(XBBCodeTagMatch $tag) {
if ($callback = $this->tags[$tag->name]->callback) {
return $callback($tag);
}
else {
$replace['{content}'] = $tag->content;
$replace['{source}'] = $tag->source;
$replace['{option}'] = $tag->option;
foreach ($tag->attrs as $name => $value) {
$replace['{' . $name . '}'] = $value;
}
$markup = str_replace(array_keys($replace), array_values($replace), $this->tags[$tag->name]->markup);
// Make sure that unset placeholders are replaced with empty strings.
$markup = preg_replace('/{\\w+}/', '', $markup);
return $markup;
}
}
}
Members
Name![]() |
Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
DependencySerializationTrait:: |
public | function | 1 | |
DependencySerializationTrait:: |
public | function | 2 | |
FilterBase:: |
public | property | The name of the provider that owns this filter. | |
FilterBase:: |
public | property | An associative array containing the configured settings of this filter. | |
FilterBase:: |
public | property | A Boolean indicating whether this filter is enabled. | |
FilterBase:: |
public | property | The weight of this filter compared to others in a filter collection. | |
FilterBase:: |
public | function |
Calculates dependencies for the configured plugin. Overrides DependentPluginInterface:: |
1 |
FilterBase:: |
public | function |
Gets default configuration for this plugin. Overrides ConfigurableInterface:: |
|
FilterBase:: |
public | function |
Gets this plugin's configuration. Overrides ConfigurableInterface:: |
|
FilterBase:: |
public | function |
Returns the administrative description for this filter plugin. Overrides FilterInterface:: |
|
FilterBase:: |
public | function |
Returns HTML allowed by this filter's configuration. Overrides FilterInterface:: |
4 |
FilterBase:: |
public | function |
Returns the administrative label for this filter plugin. Overrides FilterInterface:: |
|
FilterBase:: |
public | function |
Returns the processing type of this filter plugin. Overrides FilterInterface:: |
|
FilterBase:: |
public | function |
Prepares the text for processing. Overrides FilterInterface:: |
|
FilterBase:: |
public | function |
Sets the configuration for this plugin instance. Overrides ConfigurableInterface:: |
1 |
FilterInterface:: |
constant | HTML tag and attribute restricting filters to prevent XSS attacks. | ||
FilterInterface:: |
constant | Non-HTML markup language filters that generate HTML. | ||
FilterInterface:: |
constant | Irreversible transformation filters. | ||
FilterInterface:: |
constant | Reversible transformation filters. | ||
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
3 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
XBBCodeFilter:: |
private | property | ||
XBBCodeFilter:: |
private | function | ||
XBBCodeFilter:: |
public | function |
Performs the filter processing. Overrides FilterInterface:: |
|
XBBCodeFilter:: |
private | function | Render a single tag. | |
XBBCodeFilter:: |
private | function | ||
XBBCodeFilter:: |
public | function |
Settings callback for the filter settings of xbbcode. Overrides FilterBase:: |
|
XBBCodeFilter:: |
public | function |
Generates a filter's tip. Overrides FilterBase:: |
|
XBBCodeFilter:: |
public | function |
Construct a filter object from a bundle of tags, and the format ID. Overrides FilterBase:: |