author | Dan |
Thu, 13 May 2010 09:15:42 -0400 | |
changeset 5 | 030635a70d61 |
parent 4 | a803741a5fc0 |
child 6 | 63539b03fa5f |
permissions | -rw-r--r-- |
0 | 1 |
<?php |
2 |
/* |
|
4 | 3 |
Plugin Name: Wikulator |
4 |
Plugin URI: http://enanocms.org/plugin/wikulator |
|
0 | 5 |
Description: Several parser extensions that provide MediaWiki-like support for references, search highlighting, and a table of contents to Enano |
6 |
Author: Dan Fuhry |
|
7 |
Version: 0.1 beta 1 |
|
8 |
Author URI: http://enanocms.org/ |
|
9 |
*/ |
|
10 |
||
11 |
/* |
|
12 |
* This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License |
|
13 |
* as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. |
|
14 |
* |
|
15 |
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied |
|
16 |
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. |
|
17 |
*/ |
|
18 |
||
2 | 19 |
$plugins->attachHook('render_wikiformat_posttemplates', 'mediafier_draw_toc($text);'); |
0 | 20 |
$plugins->attachHook('render_wikiformat_post', 'mediafy($result);'); |
21 |
$plugins->attachHook('compile_template', 'mediafier_add_headers();'); |
|
22 |
$plugins->attachHook('html_attribute_whitelist', '$whitelist["ref"] = array(); $whitelist["references"] = array("/");'); |
|
23 |
||
24 |
function mediafy(&$text) |
|
25 |
{ |
|
26 |
global $db, $session, $paths, $template, $plugins; // Common objects |
|
27 |
mediafy_highlight_search_words($text); |
|
28 |
mediafy_process_references($text); |
|
29 |
} |
|
30 |
||
1 | 31 |
function mediafier_draw_toc(&$text) |
32 |
{ |
|
33 |
if ( strstr($text, '__NOTOC__') ) |
|
34 |
return true; |
|
35 |
||
36 |
if ( !preg_match_all('/^\s*([=]{1,6})([^\r\n]+)\\1\s*$/m', $text, $matches) ) |
|
37 |
return true; |
|
38 |
||
39 |
$heading_map = array(); |
|
40 |
foreach ( $matches[1] as $heading ) |
|
41 |
{ |
|
42 |
$heading_map[] = strlen($heading); |
|
43 |
} |
|
44 |
||
45 |
if ( count($heading_map) < 4 && !strstr($text, '__TOC__') ) |
|
46 |
return true; |
|
47 |
||
48 |
$prev = 0; |
|
49 |
$levels = 0; |
|
50 |
$treenum = array(); |
|
51 |
$toc = ''; |
|
52 |
foreach ( $heading_map as $i => $head ) |
|
53 |
{ |
|
54 |
if ( $head > $prev ) |
|
55 |
{ |
|
56 |
$treenum[] = 0; |
|
57 |
$levels++; |
|
58 |
$toc .= '<dl>'; |
|
59 |
} |
|
60 |
else if ( $head < $prev ) |
|
61 |
{ |
|
62 |
if ( $levels > 1 ) |
|
63 |
{ |
|
64 |
$toc .= '</dl>'; |
|
65 |
$levels--; |
|
66 |
unset($treenum[count($treenum)-1]); |
|
67 |
} |
|
68 |
} |
|
3
98ccd8815a02
Fixed a few tree construction + relative jump (1.1.7 parser) bugs in TOC
Dan
parents:
2
diff
changeset
|
69 |
$treenum = array_values($treenum); |
2 | 70 |
if ( isset($treenum[count($treenum)-1]) ) |
71 |
$treenum[count($treenum)-1]++; |
|
1 | 72 |
if ( $i > 0 ) |
73 |
$toc .= '</dd>'; |
|
4 | 74 |
if ( version_compare(enano_version(), '1.1.7', '>=') ) |
75 |
{ |
|
76 |
$tocid = sanitize_page_id(trim($matches[2][$i])); |
|
77 |
$tocid = str_replace(array('[', ']'), '', $tocid); |
|
78 |
} |
|
79 |
else |
|
80 |
{ |
|
81 |
$tocid = "$i"; |
|
82 |
} |
|
83 |
$toc .= '<dd><a href="#head:' . $tocid . '">' . implode('.', $treenum) . ' ' . htmlspecialchars($matches[2][$i]) . '</a>'; |
|
1 | 84 |
$prev = $head; |
85 |
} |
|
86 |
while ( $levels > 0 ) |
|
87 |
{ |
|
88 |
$toc .= '</dd></dl>'; |
|
89 |
$levels--; |
|
90 |
} |
|
91 |
$toc_body = "<nowiki><div class=\"toc mdg-comment\"> |
|
92 |
<dl><dd><b>Contents</b> <small>[<a href=\"#\" onclick=\"collapseTOC(this); return false;\">hide</a>]</small></dd></dl> |
|
93 |
<div>$toc</div> |
|
94 |
</div></nowiki>"; |
|
2 | 95 |
|
1 | 96 |
if ( strstr($text, '__TOC__') ) |
2 | 97 |
{ |
1 | 98 |
$text = str_replace_once('__TOC__', $toc_body, $text); |
2 | 99 |
} |
100 |
else if ( $text === ($rtext = preg_replace('/^=/', "$toc_body\n\n=", $text)) ) |
|
101 |
{ |
|
1 | 102 |
$text = str_replace_once("\n=", "\n$toc_body\n=", $text); |
2 | 103 |
} |
104 |
else |
|
105 |
{ |
|
106 |
$text = $rtext; |
|
107 |
unset($rtext); |
|
108 |
} |
|
1 | 109 |
} |
110 |
||
0 | 111 |
function mediafier_add_headers() |
112 |
{ |
|
113 |
global $db, $session, $paths, $template, $plugins; // Common objects |
|
114 |
$template->add_header("<style type=\"text/css\"> |
|
115 |
.highlight { background-color: #FFFFC0; font-weight: bold; } |
|
116 |
.refbak { background-color: #E0E0FF; font-weight: bold; } |
|
117 |
.references { font-size: smaller; } |
|
118 |
</style>"); |
|
119 |
$ref_script = <<<EOF |
|
120 |
<enano:no-opt> |
|
1 | 121 |
<style type="text/css"> |
122 |
div.toc { |
|
123 |
display: table; |
|
124 |
max-width: 70%; |
|
125 |
padding: 0.7em 1.7em 0.7em 0.7em; |
|
126 |
margin: 10px 0 0 0; |
|
127 |
} |
|
128 |
div.toc dl { |
|
129 |
margin: 2px 0; |
|
130 |
} |
|
131 |
div.toc dd { |
|
132 |
margin-left: 1em; |
|
133 |
} |
|
134 |
</style> |
|
0 | 135 |
<script type="text/javascript"> |
136 |
// <![CDATA[ |
|
137 |
function refsOff() |
|
138 |
{ |
|
139 |
var divs = getElementsByClassName(document, '*', 'refbottom'); |
|
140 |
for ( var i in divs ) |
|
141 |
{ |
|
1 | 142 |
\$dynano(divs[i]).rmClass('refbak'); |
0 | 143 |
} |
144 |
divs = getElementsByClassName(document, '*', 'reftop'); |
|
145 |
for ( var i in divs ) |
|
146 |
{ |
|
1 | 147 |
\$dynano(divs[i]).rmClass('refbak'); |
0 | 148 |
} |
149 |
} |
|
150 |
function refToBottom(id) |
|
151 |
{ |
|
152 |
refsOff(); |
|
1 | 153 |
\$dynano('ref_'+id+'_b').addClass('refbak'); |
0 | 154 |
} |
155 |
function refToTop(id) |
|
156 |
{ |
|
157 |
refsOff(); |
|
1 | 158 |
\$dynano('cite_'+id).addClass('refbak'); |
159 |
} |
|
160 |
function collapseTOC(el) |
|
161 |
{ |
|
162 |
var toc_inner = el.parentNode.parentNode.parentNode.parentNode.getElementsByTagName('div')[0]; |
|
163 |
if ( toc_inner.style.display == 'none' ) |
|
164 |
{ |
|
165 |
el.innerHTML = 'hide'; |
|
166 |
toc_inner.style.display = 'block'; |
|
167 |
} |
|
168 |
else |
|
169 |
{ |
|
170 |
el.innerHTML = 'show'; |
|
171 |
toc_inner.style.display = 'none'; |
|
172 |
} |
|
0 | 173 |
} |
174 |
// ]]> |
|
175 |
</script> |
|
176 |
</enano:no-opt> |
|
177 |
||
178 |
EOF; |
|
179 |
$template->add_header($ref_script); |
|
180 |
} |
|
181 |
||
182 |
function mediafy_highlight_search_words(&$result) |
|
183 |
{ |
|
184 |
global $db, $session, $paths, $template, $plugins; // Common objects |
|
185 |
||
186 |
if ( !isset($_SERVER['HTTP_REFERER']) && !isset($_GET['highlight']) ) |
|
187 |
return false; |
|
188 |
||
189 |
$referer = ( isset($_GET['highlight']) ) ? $_SERVER['REQUEST_URI'] : $_SERVER['HTTP_REFERER']; |
|
190 |
$term = ( isset($_GET['highlight']) ) ? 'highlight' : 'q'; |
|
191 |
||
192 |
preg_match('/(\?|&)'.$term.'=(.+?)(&|$)/', $referer, $match); |
|
193 |
if ( !isset($match[2]) ) |
|
194 |
{ |
|
195 |
return false; |
|
196 |
} |
|
197 |
||
198 |
$words = $match[2]; |
|
199 |
$words = urldecode($words); |
|
200 |
if ( $term == 'q' ) |
|
201 |
{ |
|
202 |
// it's from a search query - extract terms |
|
203 |
require_once(ENANO_ROOT . '/includes/search.php'); |
|
204 |
$words = parse_search_query($words, $warnings); |
|
205 |
$words = array_merge($words['any'], $words['req']); |
|
206 |
} |
|
207 |
else |
|
208 |
{ |
|
209 |
$words = explode(' ', $words); |
|
210 |
} |
|
211 |
||
212 |
// strip HTML out of the rendered text |
|
213 |
$rand_seed = $session->dss_rand(); |
|
214 |
preg_match_all('/<.+?>/', $result, $html_matches); |
|
215 |
$i = 0; |
|
216 |
foreach ( $html_matches[0] as $match ) |
|
217 |
{ |
|
218 |
$i++; |
|
219 |
$result = str_replace($match, "{HIGHLIGHT_PLACEHOLDER:$i:$rand_seed}", $result); |
|
220 |
} |
|
221 |
||
222 |
// highlight matches |
|
223 |
foreach ( $words as $word ) |
|
224 |
{ |
|
2 | 225 |
$result = preg_replace('/([\W]|^)(' . str_replace('/', '\/', preg_quote($word)) . ')([\W])/i', "\\1<span class=\"highlight\">\\2</span>\\3", $result); |
0 | 226 |
} |
227 |
||
228 |
// restore HTML |
|
229 |
$i = 0; |
|
230 |
foreach ( $html_matches[0] as $match ) |
|
231 |
{ |
|
232 |
$i++; |
|
233 |
$result = str_replace("{HIGHLIGHT_PLACEHOLDER:$i:$rand_seed}", $match, $result); |
|
234 |
} |
|
235 |
||
236 |
// add "remove highlighting" link |
|
237 |
$result = '<div style="float: right; text-align: right;"><a href="' . makeUrl($paths->page) . '" onclick="ajaxReset(); return false;">Turn off <span class="highlight">highlighting</span></a></div>' . |
|
238 |
$result; |
|
239 |
||
240 |
} |
|
241 |
||
242 |
function mediafy_process_references(&$text) |
|
243 |
{ |
|
244 |
global $db, $session, $paths, $template, $plugins; // Common objects |
|
245 |
||
246 |
// Is there a <references /> in the wikitext? If not, just return out to avoid empty processing |
|
247 |
if ( !preg_match('#<references(([ ]*)/)?>#', $text) ) |
|
248 |
{ |
|
249 |
//die('no match'); |
|
250 |
return false; |
|
251 |
} |
|
252 |
||
253 |
// Retrieve references |
|
254 |
preg_match_all('#<ref>(.+?)</ref>#s', $text, $matches); |
|
255 |
||
256 |
// Init counter |
|
257 |
$i = 0; |
|
258 |
||
259 |
// Init refs array |
|
260 |
$refs = array(); |
|
261 |
||
262 |
// main parser loop |
|
263 |
foreach ( $matches[0] as $j => $match ) |
|
264 |
{ |
|
265 |
$i++; |
|
266 |
$inner =& $matches[1][$j]; |
|
267 |
$refs[$i] = $inner; |
|
268 |
$reflink = '<sup><a class="reftop" id="cite_' . $i . '" name="cite_' . $i . '" href="#ref_' . $i . '" onclick="refToBottom(\'' . $i . '\');">[' . $i . ']</a></sup>'; |
|
269 |
$text = str_replace($match, $reflink, $text); |
|
270 |
} |
|
271 |
||
272 |
// compile refs div |
|
273 |
$refsdiv = '<div class="references">'; |
|
274 |
$refsdiv .= '<table border="0" width="100%"><tr><td valign="top">'; |
|
275 |
$count = ( count($refs) >= 20 ) ? floor(count($refs) / 2) : 99; |
|
276 |
foreach ( $refs as $i => $ref ) |
|
277 |
{ |
|
278 |
$reflink = '<span id="ref_' . $i . '" name="ref_' . $i . '"><sup><b><a onclick="refToTop(\'' . $i . '\');" href="#cite_' . $i . '">^</a></b></sup> </span>'; |
|
2 | 279 |
$ref = trim($ref); |
0 | 280 |
$refsdiv .= "<div class=\"refbottom\" id=\"ref_{$i}_b\">$reflink $i. $ref</div>"; |
281 |
if ( $i == $count ) |
|
282 |
$refsdiv .= '</td><td valign="top">'; |
|
283 |
} |
|
284 |
$refsdiv .= '</td></tr></table>'; |
|
285 |
$refsdiv .= '</div>'; |
|
286 |
||
287 |
preg_match('#<references(([ ]*)/)?>#', $text, $match); |
|
288 |
$text = str_replace_once($match[0], $refsdiv, $text); |
|
289 |
} |
|
290 |
||
291 |
?> |