Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?php
/**
* @file
* Contains \Drupal\filter\Plugin\Filter\FilterCaption.
*/
namespace Drupal\filter\Plugin\Filter;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Annotation\Translation;
use Drupal\filter\Annotation\Filter;
use Drupal\filter\Plugin\FilterBase;
/**
* Provides a filter to display image captions and align images.
*
* @Filter(
* id = "filter_caption",
* module = "filter",
* title = @Translation("Display image captions and align images"),
* description = @Translation("Uses data-caption and data-align attributes on <img> tags to caption and align images."),
* type = FILTER_TYPE_TRANSFORM_REVERSIBLE
* )
*/
class FilterCaption extends FilterBase {
/**
* {@inheritdoc}
*/
public function process($text, $langcode, $cache, $cache_id) {
if (stristr($text, 'data-caption') !== FALSE || stristr($text, 'data-align') !== FALSE) {
$dom = filter_dom_load($text);
$xpath = new \DOMXPath($dom);
foreach ($xpath->query('//*[@data-caption or @data-align]') as $node) {
$caption = NULL;
$align = NULL;
// Retrieve, then remove the data-caption and data-align attributes.
if ($node->hasAttribute('data-caption')) {
$caption = String::checkPlain($node->getAttribute('data-caption'));
$node->removeAttribute('data-caption');
// Sanitize caption: decode HTML encoding, limit allowed HTML tags.
$caption = String::decodeEntities($caption);
$caption = Xss::filter($caption);
// The caption must be non-empty.
if (Unicode::strlen($caption) === 0) {
$caption = NULL;
}
}
if ($node->hasAttribute('data-align')) {
$align = $node->getAttribute('data-align');
$node->removeAttribute('data-align');
// Only allow 3 values: 'left', 'center' and 'right'.
if (!in_array($align, array('left', 'center', 'right'))) {
$align = NULL;
}
}
// If neither attribute has a value after validation, then don't
// transform the HTML.
if ($caption === NULL && $align === NULL) {
continue;
}
// Given the updated node, caption and alignment: re-render it with a
// caption.
$filter_caption = array(
'#theme' => 'filter_caption',
'#node' => $node->C14N(),
'#tag' => $node->tagName,
'#caption' => $caption,
'#align' => $align,
);
$altered_html = drupal_render($filter_caption);
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Load the altered HTML into a new DOMDocument and retrieve the element.
$updated_node = filter_dom_load($altered_html)->getElementsByTagName('body')
->item(0)
->childNodes
->item(0);
// Import the updated node from the new DOMDocument into the original
// one, importing also the child nodes of the updated node.
$updated_node = $dom->importNode($updated_node, TRUE);
// Finally, replace the original image node with the new image node!
$node->parentNode->replaceChild($updated_node, $node);
}
return filter_dom_serialize($dom);
}
return $text;
}
/**
* {@inheritdoc}
*/
public function tips($long = FALSE) {
if ($long) {
return t('
<p>You can add image captions and align images left, right or centered. Examples:</p>
<ul>
<li>Caption an image: <code><img src="" data-caption="This is a caption" /></code></li>
<li>Align an image: <code><img src="" data-align="center" /></code></li>
<li>Caption & align an image: <code><img src="" data-caption="Alpaca" data-align="right" /></code></li>
</ul>');
}
else {
return t('You can caption (data-caption="Text") and align images (data-align="center"), but also video, blockquotes, and so on.');
}
}
}