|
1
|
|
|
<?php |
|
2
|
|
|
/* |
|
3
|
|
|
* This file is part of the trefoil application. |
|
4
|
|
|
* |
|
5
|
|
|
* (c) Miguel Angel Gabriel <[email protected]> |
|
6
|
|
|
* |
|
7
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
8
|
|
|
* file that was distributed with this source code. |
|
9
|
|
|
*/ |
|
10
|
|
|
namespace Trefoil\Plugins\Optional; |
|
11
|
|
|
|
|
12
|
|
|
use Easybook\Events\BaseEvent; |
|
13
|
|
|
use Easybook\Events\EasybookEvents; |
|
14
|
|
|
use Easybook\Events\ParseEvent; |
|
15
|
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
|
16
|
|
|
use Trefoil\Plugins\BasePlugin; |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* This plugin transforms Markdown footnotes markup into inline footnotes. |
|
20
|
|
|
* |
|
21
|
|
|
* @deprecated |
|
22
|
|
|
* |
|
23
|
|
|
* PrinceXMl manages footnotes as: |
|
24
|
|
|
* |
|
25
|
|
|
* "text<span class="fn">Text of the footnote</span> more text" |
|
26
|
|
|
* |
|
27
|
|
|
* This plugin transforms the Markdown-generated footnotes to the PrinceXML |
|
28
|
|
|
* format. |
|
29
|
|
|
* |
|
30
|
|
|
* Note that one limitation is that the footnote text cannot contain block |
|
31
|
|
|
* elements (as paragraphs, tables, lists). The plugin overcomes this |
|
32
|
|
|
* partially by replacing paragraph tags with <br/> tags. |
|
33
|
|
|
* |
|
34
|
|
|
*/ |
|
35
|
|
|
class FootnotesInlinePlugin extends BasePlugin implements EventSubscriberInterface |
|
36
|
|
|
{ |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* The footnotes |
|
40
|
|
|
* |
|
41
|
|
|
* @var array |
|
42
|
|
|
*/ |
|
43
|
|
|
protected $footnotes = array(); |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* @param array $footnotes |
|
47
|
|
|
* |
|
48
|
|
|
* @internal Should be protected but made public for PHP 5.3 compat |
|
49
|
|
|
*/ |
|
50
|
|
|
public function setFootnotes($footnotes) |
|
51
|
|
|
{ |
|
52
|
|
|
$this->footnotes = $footnotes; |
|
53
|
|
|
} |
|
54
|
|
|
|
|
55
|
|
|
/** |
|
56
|
|
|
* @return array |
|
57
|
|
|
* |
|
58
|
|
|
* @internal Should be protected but made public for PHP 5.3 compat |
|
59
|
|
|
*/ |
|
60
|
|
|
public function getFootnotes() |
|
61
|
|
|
{ |
|
62
|
|
|
return $this->footnotes; |
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
|
|
66
|
|
|
/* ******************************************************************************** |
|
67
|
|
|
* Event handlers |
|
68
|
|
|
* ******************************************************************************** |
|
69
|
|
|
*/ |
|
70
|
|
View Code Duplication |
public static function getSubscribedEvents() |
|
71
|
|
|
{ |
|
72
|
|
|
return array( |
|
73
|
|
|
EasybookEvents::PRE_PARSE => array('onItemPreParse', +100), |
|
74
|
|
|
EasybookEvents::POST_PARSE => array('onItemPostParse'), |
|
75
|
|
|
EasybookEvents::POST_PUBLISH => 'onPostPublish' |
|
76
|
|
|
); |
|
77
|
|
|
} |
|
78
|
|
|
|
|
79
|
|
|
public function onItemPreParse(ParseEvent $event) |
|
80
|
|
|
{ |
|
81
|
|
|
$this->init($event); |
|
82
|
|
|
|
|
83
|
|
|
if ($this->item['config']['element'] === 'footnotes') { |
|
84
|
|
|
|
|
85
|
|
|
$this->app['publishing.footnotes.items'] = array(); |
|
86
|
|
|
|
|
87
|
|
|
return; |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
$this->saveFootnotes(); |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
public function onItemPostParse(ParseEvent $event) |
|
94
|
|
|
{ |
|
95
|
|
|
$this->init($event); |
|
96
|
|
|
|
|
97
|
|
|
$this->processItem(); |
|
98
|
|
|
|
|
99
|
|
|
// reload changed item |
|
100
|
|
|
$event->setItem($this->item); |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
public function onPostPublish(BaseEvent $event) |
|
104
|
|
|
{ |
|
105
|
|
|
$this->init($event); |
|
106
|
|
|
|
|
107
|
|
|
$this->deprecationNotice(); |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
/* ******************************************************************************** |
|
111
|
|
|
* Implementation |
|
112
|
|
|
* ******************************************************************************** |
|
113
|
|
|
*/ |
|
114
|
|
|
|
|
115
|
|
|
/** |
|
116
|
|
|
* For a content item to be processed, extract generated footnotes. |
|
117
|
|
|
*/ |
|
118
|
|
|
protected function processItem() |
|
119
|
|
|
{ |
|
120
|
|
|
$this->extractFootnotes(); |
|
121
|
|
|
$this->inlineFootnotes(); |
|
122
|
|
|
} |
|
123
|
|
|
|
|
124
|
|
|
protected function extractFootnotes() |
|
125
|
|
|
{ |
|
126
|
|
|
$content = $this->item['content']; |
|
127
|
|
|
|
|
128
|
|
|
$regExp = '/'; |
|
129
|
|
|
$regExp .= '<div class="footnotes">.*<ol>(?<fns>.*)<\/ol>.*<\/div>'; |
|
130
|
|
|
$regExp .= '/Ums'; // Ungreedy, multiline, dotall |
|
131
|
|
|
|
|
132
|
|
|
// PHP 5.3 compat |
|
133
|
|
|
$me = $this; |
|
134
|
|
|
|
|
135
|
|
|
$content = preg_replace_callback( |
|
136
|
|
|
$regExp, |
|
137
|
|
|
function ($matches) use ($me) { |
|
138
|
|
|
|
|
139
|
|
|
$regExp2 = '/'; |
|
140
|
|
|
$regExp2 .= '<li.*id="(?<id>.*)">.*'; |
|
141
|
|
|
$regExp2 .= '<p>(?<text>.*) <a .*href="#(?<backref>.*)"'; |
|
142
|
|
|
$regExp2 .= '/Ums'; // Ungreedy, multiline, dotall |
|
143
|
|
|
|
|
144
|
|
|
preg_match_all($regExp2, $matches[0], $matches2, PREG_SET_ORDER); |
|
145
|
|
|
|
|
146
|
|
|
if ($matches2) { |
|
147
|
|
|
foreach ($matches2 as $match2) { |
|
148
|
|
|
$footnotes = $me->getFootnotes(); |
|
149
|
|
|
$footnotes[$match2['id']] = array( |
|
150
|
|
|
'text' => $match2['text'] |
|
151
|
|
|
); |
|
152
|
|
|
$me->setFootnotes($footnotes); |
|
153
|
|
|
} |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
return ''; |
|
157
|
|
|
}, |
|
158
|
|
|
$content |
|
159
|
|
|
); |
|
160
|
|
|
|
|
161
|
|
|
$this->item['content'] = $content; |
|
162
|
|
|
} |
|
163
|
|
|
|
|
164
|
|
View Code Duplication |
protected function inlineFootnotes() |
|
|
|
|
|
|
165
|
|
|
{ |
|
166
|
|
|
$content = $this->item['content']; |
|
167
|
|
|
|
|
168
|
|
|
$regExp = '/'; |
|
169
|
|
|
$regExp .= '<sup id="(?<supid>fnref.?:.*)">'; |
|
170
|
|
|
$regExp .= '<a(?<prev>.*)href="#(?<href>fn:.*)"(?<post>.*)>(?<number>.*)<\/a><\/sup>'; |
|
171
|
|
|
$regExp .= '/Ums'; // Ungreedy, multiline, dotall |
|
172
|
|
|
|
|
173
|
|
|
// PHP 5.3 compat |
|
174
|
|
|
$me = $this; |
|
175
|
|
|
|
|
176
|
|
|
$content = preg_replace_callback( |
|
177
|
|
|
$regExp, |
|
178
|
|
|
function ($matches) use ($me) { |
|
179
|
|
|
$footnotes = $me->getFootnotes(); |
|
180
|
|
|
$footnote = $footnotes[$matches['href']]; |
|
181
|
|
|
$text = $footnote['text']; |
|
182
|
|
|
|
|
183
|
|
|
// replace <p>...</p> with <br/> because no block elements are |
|
184
|
|
|
// allowed inside a <span>. |
|
185
|
|
|
// The paragraph contents are also put inside a fake paragraph <span> |
|
186
|
|
|
// so they can be styled. |
|
187
|
|
|
|
|
188
|
|
|
$text = str_replace( |
|
189
|
|
|
['<p>', '</p>'], |
|
190
|
|
|
['<span class="p">', '<br/></span>'], |
|
191
|
|
|
$text |
|
192
|
|
|
); |
|
193
|
|
|
$text = '<span class="p" >' . $text . '</span>'; |
|
194
|
|
|
|
|
195
|
|
|
$html = sprintf( |
|
196
|
|
|
'<span class="fn">%s</span>', |
|
197
|
|
|
$text |
|
198
|
|
|
); |
|
199
|
|
|
|
|
200
|
|
|
return $html; |
|
201
|
|
|
}, |
|
202
|
|
|
$content |
|
203
|
|
|
); |
|
204
|
|
|
|
|
205
|
|
|
$this->item['content'] = $content; |
|
206
|
|
|
} |
|
207
|
|
|
|
|
208
|
|
|
protected function saveFootnotes() |
|
209
|
|
|
{ |
|
210
|
|
|
$this->app['publishing.footnotes.items'] = $this->footnotes; |
|
211
|
|
|
} |
|
212
|
|
|
} |
|
213
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.