1 | <?php |
---|
2 | |
---|
3 | class FCKeditorParser extends FCKeditorParserWrapper |
---|
4 | { |
---|
5 | public static $fkc_mw_makeImage_options; |
---|
6 | protected $fck_mw_strtr_span; |
---|
7 | protected $fck_mw_strtr_span_counter=1; |
---|
8 | protected $fck_mw_taghook; |
---|
9 | protected $fck_internal_parse_text; |
---|
10 | protected $fck_matches = array(); |
---|
11 | |
---|
12 | private $FCKeditorMagicWords = array( |
---|
13 | '__NOTOC__', |
---|
14 | '__FORCETOC__', |
---|
15 | '__NOEDITSECTION__', |
---|
16 | '__START__', |
---|
17 | '__NOTITLECONVERT__', |
---|
18 | '__NOCONTENTCONVERT__', |
---|
19 | '__END__', |
---|
20 | '__TOC__', |
---|
21 | '__NOTC__', |
---|
22 | '__NOCC__', |
---|
23 | "__FORCETOC__", |
---|
24 | "__NEWSECTIONLINK__", |
---|
25 | "__NOGALLERY__", |
---|
26 | ); |
---|
27 | |
---|
28 | /** |
---|
29 | * Add special string (that would be changed by Parser) to array and return simple unique string |
---|
30 | * that will remain unchanged during whole parsing operation. |
---|
31 | * At the end we'll replace all this unique strings with original content |
---|
32 | * |
---|
33 | * @param string $text |
---|
34 | * @return string |
---|
35 | */ |
---|
36 | private function fck_addToStrtr($text, $replaceLineBreaks = true) { |
---|
37 | $key = 'Fckmw'.$this->fck_mw_strtr_span_counter.'fckmw'; |
---|
38 | $this->fck_mw_strtr_span_counter++; |
---|
39 | if ($replaceLineBreaks) { |
---|
40 | $this->fck_mw_strtr_span[$key] = str_replace(array("\r\n", "\n", "\r"),"fckLR",$text); |
---|
41 | } |
---|
42 | else { |
---|
43 | $this->fck_mw_strtr_span[$key] = $text; |
---|
44 | } |
---|
45 | return $key; |
---|
46 | } |
---|
47 | |
---|
48 | /** |
---|
49 | * Handle link to subpage if necessary |
---|
50 | * @param string $target the source of the link |
---|
51 | * @param string &$text the link text, modified as necessary |
---|
52 | * @return string the full name of the link |
---|
53 | * @private |
---|
54 | */ |
---|
55 | function maybeDoSubpageLink($target, &$text) { |
---|
56 | return $target; |
---|
57 | } |
---|
58 | |
---|
59 | /** |
---|
60 | * DO NOT Replace special strings like "ISBN xxx" and "RFC xxx" with |
---|
61 | * magic external links. |
---|
62 | * |
---|
63 | * DML |
---|
64 | * @private |
---|
65 | */ |
---|
66 | function doMagicLinks( $text ) { |
---|
67 | return $text; |
---|
68 | } |
---|
69 | |
---|
70 | /** |
---|
71 | * Callback function for custom tags: feed, ref, references etc. |
---|
72 | * |
---|
73 | * @param string $str Input |
---|
74 | * @param array $argv Arguments |
---|
75 | * @return string |
---|
76 | */ |
---|
77 | function fck_genericTagHook( $str, $argv, $parser ) { |
---|
78 | if (in_array($this->fck_mw_taghook, array("ref", "math", "references", "source"))) { |
---|
79 | $class = $this->fck_mw_taghook; |
---|
80 | } |
---|
81 | else { |
---|
82 | $class = "special"; |
---|
83 | } |
---|
84 | |
---|
85 | if (empty($argv)) { |
---|
86 | $ret = "<span class=\"fck_mw_".$class."\" _fck_mw_customtag=\"true\" _fck_mw_tagname=\"".$this->fck_mw_taghook."\">"; |
---|
87 | } |
---|
88 | else { |
---|
89 | $ret = "<span class=\"fck_mw_".$class."\" _fck_mw_customtag=\"true\" _fck_mw_tagname=\"".$this->fck_mw_taghook."\""; |
---|
90 | foreach ($argv as $key=>$value) { |
---|
91 | $ret .= " ".$key."=\"".$value."\""; |
---|
92 | } |
---|
93 | $ret .=">"; |
---|
94 | } |
---|
95 | if (is_null($str)) { |
---|
96 | $ret = substr($ret, 0, -1) . " />"; |
---|
97 | } |
---|
98 | else { |
---|
99 | $ret .= htmlspecialchars($str); |
---|
100 | $ret .= "</span>"; |
---|
101 | } |
---|
102 | |
---|
103 | $replacement = $this->fck_addToStrtr($ret); |
---|
104 | return $replacement; |
---|
105 | } |
---|
106 | |
---|
107 | /** |
---|
108 | * Callback function for wiki tags: nowiki, includeonly, noinclude |
---|
109 | * |
---|
110 | * @param string $tagName tag name, eg. nowiki, math |
---|
111 | * @param string $str Input |
---|
112 | * @param array $argv Arguments |
---|
113 | * @return string |
---|
114 | */ |
---|
115 | function fck_wikiTag( $tagName, $str, $argv = array()) { |
---|
116 | if (empty($argv)) { |
---|
117 | $ret = "<span class=\"fck_mw_".$tagName."\" _fck_mw_customtag=\"true\" _fck_mw_tagname=\"".$tagName."\">"; |
---|
118 | } |
---|
119 | else { |
---|
120 | $ret = "<span class=\"fck_mw_".$tagName."\" _fck_mw_customtag=\"true\" _fck_mw_tagname=\"".$tagName."\""; |
---|
121 | foreach ($argv as $key=>$value) { |
---|
122 | $ret .= " ".$key."=\"".$value."\""; |
---|
123 | } |
---|
124 | $ret .=">"; |
---|
125 | } |
---|
126 | if (is_null($str)) { |
---|
127 | $ret = substr($ret, 0, -1) . " />"; |
---|
128 | } |
---|
129 | else { |
---|
130 | $ret .= htmlspecialchars($str); |
---|
131 | $ret .= "</span>"; |
---|
132 | } |
---|
133 | |
---|
134 | $replacement = $this->fck_addToStrtr($ret); |
---|
135 | |
---|
136 | return $replacement; |
---|
137 | } |
---|
138 | |
---|
139 | /** |
---|
140 | * Strips and renders nowiki, pre, math, hiero |
---|
141 | * If $render is set, performs necessary rendering operations on plugins |
---|
142 | * Returns the text, and fills an array with data needed in unstrip() |
---|
143 | * |
---|
144 | * @param StripState $state |
---|
145 | * |
---|
146 | * @param bool $stripcomments when set, HTML comments <!-- like this --> |
---|
147 | * will be stripped in addition to other tags. This is important |
---|
148 | * for section editing, where these comments cause confusion when |
---|
149 | * counting the sections in the wikisource |
---|
150 | * |
---|
151 | * @param array dontstrip contains tags which should not be stripped; |
---|
152 | * used to prevent stipping of <gallery> when saving (fixes bug 2700) |
---|
153 | * |
---|
154 | * @private |
---|
155 | */ |
---|
156 | function strip( $text, $state, $stripcomments = false , $dontstrip = array () ) { |
---|
157 | global $wgContLang, $wgUseTeX, $wgScriptPath, $wgVersion, $wgHooks, $wgExtensionFunctions; |
---|
158 | |
---|
159 | wfProfileIn( __METHOD__ ); |
---|
160 | $render = ($this->mOutputType == OT_HTML); |
---|
161 | |
---|
162 | $uniq_prefix = $this->mUniqPrefix; |
---|
163 | $commentState = new ReplacementArray; |
---|
164 | $nowikiItems = array(); |
---|
165 | $generalItems = array(); |
---|
166 | |
---|
167 | $elements = array_merge( array( 'nowiki', 'gallery', 'math' ), array_keys( $this->mTagHooks ) ); |
---|
168 | if ( (isset($wgHooks['ParserFirstCallInit']) && in_array('efSyntaxHighlight_GeSHiSetup', $wgHooks['ParserFirstCallInit'])) |
---|
169 | || (isset($wgExtensionFunctions) && in_array('efSyntaxHighlight_GeSHiSetup', $wgExtensionFunctions)) ) { |
---|
170 | $elements = array_merge( $elements, array( 'source' ) ); |
---|
171 | } |
---|
172 | if ( (isset($wgHooks['ParserFirstCallInit']) && in_array('wfCite', $wgHooks['ParserFirstCallInit'])) |
---|
173 | || (isset($wgExtensionFunctions) && in_array('wfCite', $wgExtensionFunctions)) ) { |
---|
174 | $elements = array_merge( $elements, array( 'ref', 'references' ) ); |
---|
175 | } |
---|
176 | global $wgRawHtml; |
---|
177 | if( $wgRawHtml ) { |
---|
178 | $elements[] = 'html'; |
---|
179 | } |
---|
180 | |
---|
181 | # Removing $dontstrip tags from $elements list (currently only 'gallery', fixing bug 2700) |
---|
182 | foreach ( $elements AS $k => $v ) { |
---|
183 | if ( !in_array ( $v , $dontstrip ) ) continue; |
---|
184 | unset ( $elements[$k] ); |
---|
185 | } |
---|
186 | |
---|
187 | $elements = array_unique($elements); |
---|
188 | $matches = array(); |
---|
189 | if (version_compare("1.12", $wgVersion, ">")) { |
---|
190 | $text = Parser::extractTagsAndParams( $elements, $text, $matches, $uniq_prefix ); |
---|
191 | } |
---|
192 | else { |
---|
193 | $text = self::extractTagsAndParams( $elements, $text, $matches, $uniq_prefix ); |
---|
194 | } |
---|
195 | |
---|
196 | foreach( $matches as $marker => $data ) { |
---|
197 | list( $element, $content, $params, $tag ) = $data; |
---|
198 | if( $render ) { |
---|
199 | $tagName = strtolower( $element ); |
---|
200 | wfProfileIn( __METHOD__."-render-$tagName" ); |
---|
201 | switch( $tagName ) { |
---|
202 | case '!--': |
---|
203 | // Comment |
---|
204 | if( substr( $tag, -3 ) == '-->' ) { |
---|
205 | $output = $tag; |
---|
206 | } else { |
---|
207 | // Unclosed comment in input. |
---|
208 | // Close it so later stripping can remove it |
---|
209 | $output = "$tag-->"; |
---|
210 | } |
---|
211 | break; |
---|
212 | case 'references': |
---|
213 | $output = $this->fck_wikiTag('references', $content, $params); |
---|
214 | break; |
---|
215 | case 'ref': |
---|
216 | $output = $this->fck_wikiTag('ref', $content, $params); |
---|
217 | break; |
---|
218 | case 'syntaxhighlight': |
---|
219 | case 'source': |
---|
220 | $output = $this->fck_wikiTag('source', $content, $params); |
---|
221 | break; |
---|
222 | case 'html': |
---|
223 | if( $wgRawHtml ) { |
---|
224 | $output = $this->fck_wikiTag('html', $content, $params); |
---|
225 | } |
---|
226 | break; |
---|
227 | case 'nowiki': |
---|
228 | $output = $this->fck_wikiTag('nowiki', $content, $params); //required by FCKeditor |
---|
229 | break; |
---|
230 | case 'math': |
---|
231 | if($wgUseTeX){ //normal render |
---|
232 | $output = $wgContLang->armourMath( MathRenderer::renderMath( $content ) ); |
---|
233 | }else //show fakeimage |
---|
234 | $output = '<img _fckfakelement="true" class="FCK__MWMath" _fck_mw_math="'.$content.'" src="'.$wgScriptPath.'/skins/common/images/button_math.png" />'; |
---|
235 | break; |
---|
236 | case 'gallery': |
---|
237 | $output = $this->fck_wikiTag('gallery', $content, $params); //required by FCKeditor |
---|
238 | //$output = $this->renderImageGallery( $content, $params ); |
---|
239 | break; |
---|
240 | default: |
---|
241 | if( isset( $this->mTagHooks[$tagName] ) ) { |
---|
242 | $this->fck_mw_taghook = $tagName; //required by FCKeditor |
---|
243 | $output = call_user_func_array( $this->mTagHooks[$tagName], |
---|
244 | array( $content, $params, $this ) ); |
---|
245 | } else { |
---|
246 | throw new MWException( "Invalid call hook $element" ); |
---|
247 | } |
---|
248 | } |
---|
249 | wfProfileOut( __METHOD__."-render-$tagName" ); |
---|
250 | } else { |
---|
251 | // Just stripping tags; keep the source |
---|
252 | $output = $tag; |
---|
253 | } |
---|
254 | |
---|
255 | // Unstrip the output, to support recursive strip() calls |
---|
256 | $output = $state->unstripBoth( $output ); |
---|
257 | |
---|
258 | if( !$stripcomments && $element == '!--' ) { |
---|
259 | $commentState->setPair( $marker, $output ); |
---|
260 | } elseif ( $element == 'html' || $element == 'nowiki' ) { |
---|
261 | $nowikiItems[$marker] = $output; |
---|
262 | } else { |
---|
263 | $generalItems[$marker] = $output; |
---|
264 | } |
---|
265 | } |
---|
266 | # Add the new items to the state |
---|
267 | # We do this after the loop instead of during it to avoid slowing |
---|
268 | # down the recursive unstrip |
---|
269 | $state->nowiki->mergeArray( $nowikiItems ); |
---|
270 | $state->general->mergeArray( $generalItems ); |
---|
271 | |
---|
272 | # Unstrip comments unless explicitly told otherwise. |
---|
273 | # (The comments are always stripped prior to this point, so as to |
---|
274 | # not invoke any extension tags / parser hooks contained within |
---|
275 | # a comment.) |
---|
276 | if ( !$stripcomments ) { |
---|
277 | // Put them all back and forget them |
---|
278 | $text = $commentState->replace( $text ); |
---|
279 | } |
---|
280 | |
---|
281 | $this->fck_matches = $matches; |
---|
282 | wfProfileOut( __METHOD__ ); |
---|
283 | return $text; |
---|
284 | } |
---|
285 | |
---|
286 | /** Replace HTML comments with unique text using fck_addToStrtr function |
---|
287 | * |
---|
288 | * @private |
---|
289 | * @param string $text |
---|
290 | * @return string |
---|
291 | */ |
---|
292 | private function fck_replaceHTMLcomments( $text ) { |
---|
293 | wfProfileIn( __METHOD__ ); |
---|
294 | while (($start = strpos($text, '<!--')) !== false) { |
---|
295 | $end = strpos($text, '-->', $start + 4); |
---|
296 | if ($end === false) { |
---|
297 | # Unterminated comment; bail out |
---|
298 | break; |
---|
299 | } |
---|
300 | |
---|
301 | $end += 3; |
---|
302 | |
---|
303 | # Trim space and newline if the comment is both |
---|
304 | # preceded and followed by a newline |
---|
305 | $spaceStart = max($start - 1, 0); |
---|
306 | $spaceLen = $end - $spaceStart; |
---|
307 | while (substr($text, $spaceStart, 1) === ' ' && $spaceStart > 0) { |
---|
308 | $spaceStart--; |
---|
309 | $spaceLen++; |
---|
310 | } |
---|
311 | while (substr($text, $spaceStart + $spaceLen, 1) === ' ') |
---|
312 | $spaceLen++; |
---|
313 | if (substr($text, $spaceStart, 1) === "\n" and substr($text, $spaceStart + $spaceLen, 1) === "\n") { |
---|
314 | # Remove the comment, leading and trailing |
---|
315 | # spaces, and leave only one newline. |
---|
316 | $replacement = $this->fck_addToStrtr(substr($text, $spaceStart, $spaceLen+1), false); |
---|
317 | $text = substr_replace($text, $replacement."\n", $spaceStart, $spaceLen + 1); |
---|
318 | } |
---|
319 | else { |
---|
320 | # Remove just the comment. |
---|
321 | $replacement = $this->fck_addToStrtr(substr($text, $start, $end - $start), false); |
---|
322 | $text = substr_replace($text, $replacement, $start, $end - $start); |
---|
323 | } |
---|
324 | } |
---|
325 | wfProfileOut( __METHOD__ ); |
---|
326 | |
---|
327 | return $text; |
---|
328 | } |
---|
329 | |
---|
330 | function replaceInternalLinks( $text ) { |
---|
331 | $text = preg_replace("/\[\[([^|\[\]]*?)\]\]/", "[[$1|RTENOTITLE]]", $text); //#2223: [[()]] => [[%1|RTENOTITLE]] |
---|
332 | $text = preg_replace("/\[\[:(.*?)\]\]/", "[[RTECOLON$1]]", $text); //change ':' => 'RTECOLON' in links |
---|
333 | $text = parent::replaceInternalLinks($text); |
---|
334 | $text = preg_replace("/\|RTENOTITLE\]\]/", "]]", $text); // remove unused RTENOTITLE |
---|
335 | |
---|
336 | return $text; |
---|
337 | } |
---|
338 | |
---|
339 | function makeImage( $nt, $options ) { |
---|
340 | FCKeditorParser::$fkc_mw_makeImage_options = $options; |
---|
341 | return parent::makeImage( $nt, $options ); |
---|
342 | } |
---|
343 | |
---|
344 | /** |
---|
345 | * Replace templates with unique text to preserve them from parsing |
---|
346 | * |
---|
347 | * @todo if {{template}} is inside string that also must be returned unparsed, |
---|
348 | * e.g. <noinclude>{{template}}</noinclude> |
---|
349 | * {{template}} replaced with Fckmw[n]fckmw which is wrong... |
---|
350 | * |
---|
351 | * @param string $text |
---|
352 | * @return string |
---|
353 | */ |
---|
354 | private function fck_replaceTemplates( $text ) { |
---|
355 | |
---|
356 | $callback = array('{' => |
---|
357 | array( |
---|
358 | 'end'=>'}', |
---|
359 | 'cb' => array( |
---|
360 | 2=>array('FCKeditorParser', 'fck_leaveTemplatesAlone'), |
---|
361 | 3=>array('FCKeditorParser', 'fck_leaveTemplatesAlone'), |
---|
362 | ), |
---|
363 | 'min' =>2, |
---|
364 | 'max' =>3, |
---|
365 | ) |
---|
366 | ); |
---|
367 | |
---|
368 | $text = $this->replace_callback($text, $callback); |
---|
369 | |
---|
370 | $tags = array(); |
---|
371 | $offset=0; |
---|
372 | $textTmp = $text; |
---|
373 | while (false !== ($pos = strpos($textTmp, "<!--FCK_SKIP_START-->"))) |
---|
374 | { |
---|
375 | $tags[abs($pos + $offset)] = 1; |
---|
376 | $textTmp = substr($textTmp, $pos+21); |
---|
377 | $offset += $pos + 21; |
---|
378 | } |
---|
379 | |
---|
380 | $offset=0; |
---|
381 | $textTmp = $text; |
---|
382 | while (false !== ($pos = strpos($textTmp, "<!--FCK_SKIP_END-->"))) |
---|
383 | { |
---|
384 | $tags[abs($pos + $offset)] = -1; |
---|
385 | $textTmp = substr($textTmp, $pos+19); |
---|
386 | $offset += $pos + 19; |
---|
387 | } |
---|
388 | |
---|
389 | if (!empty($tags)) { |
---|
390 | ksort($tags); |
---|
391 | |
---|
392 | $strtr = array("<!--FCK_SKIP_START-->" => "", "<!--FCK_SKIP_END-->" => ""); |
---|
393 | |
---|
394 | $sum=0; |
---|
395 | $lastSum=0; |
---|
396 | $finalString = ""; |
---|
397 | $stringToParse = ""; |
---|
398 | $startingPos = 0; |
---|
399 | $inner = ""; |
---|
400 | $strtr_span = array(); |
---|
401 | foreach ($tags as $pos=>$type) { |
---|
402 | $sum += $type; |
---|
403 | if (!$pos) { |
---|
404 | $opened = 0; |
---|
405 | $closed = 0; |
---|
406 | } |
---|
407 | else { |
---|
408 | $opened = substr_count($text, '[', 0, $pos); //count [ |
---|
409 | $closed = substr_count($text, ']', 0, $pos); //count ] |
---|
410 | } |
---|
411 | if ($sum == 1 && $lastSum == 0) { |
---|
412 | $stringToParse .= strtr(substr($text, $startingPos, $pos - $startingPos), $strtr); |
---|
413 | $startingPos = $pos; |
---|
414 | } |
---|
415 | else if ($sum == 0) { |
---|
416 | $stringToParse .= 'Fckmw'.$this->fck_mw_strtr_span_counter.'fckmw'; |
---|
417 | $inner = htmlspecialchars(strtr(substr($text, $startingPos, $pos - $startingPos + 19), $strtr)); |
---|
418 | $this->fck_mw_strtr_span['href="Fckmw'.$this->fck_mw_strtr_span_counter.'fckmw"'] = 'href="'.$inner.'"'; |
---|
419 | if($opened <= $closed) { // {{template}} is NOT in [] or [[]] |
---|
420 | $this->fck_mw_strtr_span['Fckmw'.$this->fck_mw_strtr_span_counter.'fckmw'] = '<span class="fck_mw_template">'.str_replace(array("\r\n", "\n", "\r"),"fckLR",$inner).'</span>'; |
---|
421 | }else{ |
---|
422 | $this->fck_mw_strtr_span['Fckmw'.$this->fck_mw_strtr_span_counter.'fckmw'] = str_replace(array("\r\n", "\n", "\r"),"fckLR",$inner); |
---|
423 | } |
---|
424 | $startingPos = $pos + 19; |
---|
425 | $this->fck_mw_strtr_span_counter++; |
---|
426 | } |
---|
427 | $lastSum = $sum; |
---|
428 | } |
---|
429 | $stringToParse .= substr($text, $startingPos); |
---|
430 | $text = &$stringToParse; |
---|
431 | } |
---|
432 | |
---|
433 | return $text; |
---|
434 | } |
---|
435 | |
---|
436 | function internalParse ( $text ) { |
---|
437 | |
---|
438 | $this->fck_internal_parse_text =& $text; |
---|
439 | |
---|
440 | //these three tags should remain unchanged |
---|
441 | $text = StringUtils::delimiterReplaceCallback( '<includeonly>', '</includeonly>', array($this, 'fck_includeonly'), $text ); |
---|
442 | $text = StringUtils::delimiterReplaceCallback( '<noinclude>', '</noinclude>', array($this, 'fck_noinclude'), $text ); |
---|
443 | $text = StringUtils::delimiterReplaceCallback( '<onlyinclude>', '</onlyinclude>', array($this, 'fck_onlyinclude'), $text ); |
---|
444 | |
---|
445 | //html comments shouldn't be stripped |
---|
446 | $text = $this->fck_replaceHTMLcomments( $text ); |
---|
447 | //as well as templates |
---|
448 | $text = $this->fck_replaceTemplates( $text ); |
---|
449 | |
---|
450 | $finalString = parent::internalParse($text); |
---|
451 | |
---|
452 | return $finalString; |
---|
453 | } |
---|
454 | function fck_includeonly( $matches ) { |
---|
455 | return $this->fck_wikiTag('includeonly', $matches[1]); |
---|
456 | } |
---|
457 | function fck_noinclude( $matches ) { |
---|
458 | return $this->fck_wikiTag('noinclude', $matches[1]); |
---|
459 | } |
---|
460 | function fck_onlyinclude( $matches ) { |
---|
461 | return $this->fck_wikiTag('onlyinclude', $matches[1]); |
---|
462 | } |
---|
463 | function fck_leaveTemplatesAlone( $matches ) { |
---|
464 | return "<!--FCK_SKIP_START-->".$matches['text']."<!--FCK_SKIP_END-->"; |
---|
465 | } |
---|
466 | function formatHeadings( $text, $isMain=true ) { |
---|
467 | return $text; |
---|
468 | } |
---|
469 | function replaceFreeExternalLinks( $text ) { return $text; } |
---|
470 | function stripNoGallery(&$text) {} |
---|
471 | function stripToc( $text ) { |
---|
472 | //$prefix = '<span class="fck_mw_magic">'; |
---|
473 | //$suffix = '</span>'; |
---|
474 | $prefix = ''; |
---|
475 | $suffix = ''; |
---|
476 | |
---|
477 | $strtr = array(); |
---|
478 | foreach ($this->FCKeditorMagicWords as $word) { |
---|
479 | $strtr[$word] = $prefix . $word . $suffix; |
---|
480 | } |
---|
481 | |
---|
482 | return strtr( $text, $strtr ); |
---|
483 | } |
---|
484 | |
---|
485 | function doDoubleUnderscore( $text ) { |
---|
486 | return $text; |
---|
487 | } |
---|
488 | |
---|
489 | function parse( $text, &$title, $options, $linestart = true, $clearState = true, $revid = null ) { |
---|
490 | $text = preg_replace("/^#REDIRECT/", "<!--FCK_REDIRECT-->", $text); |
---|
491 | $parserOutput = parent::parse($text, $title, $options, $linestart , $clearState , $revid ); |
---|
492 | |
---|
493 | $categories = $parserOutput->getCategories(); |
---|
494 | if ($categories) { |
---|
495 | $appendString = ""; |
---|
496 | foreach ($categories as $cat=>$val) { |
---|
497 | $args = ''; |
---|
498 | if( $val == 'RTENOTITLE' ){ |
---|
499 | $args .= '_fcknotitle="true" '; |
---|
500 | $val = $cat; |
---|
501 | } |
---|
502 | if ($val != $title->mTextform) { |
---|
503 | $appendString .= "<a ".$args."href=\"Category:" . $cat ."\">" . $val ."</a> "; |
---|
504 | } |
---|
505 | else { |
---|
506 | $appendString .= "<a ".$args."href=\"Category:" . $cat ."\">Category:" . $cat ."</a> "; |
---|
507 | } |
---|
508 | } |
---|
509 | $parserOutput->setText($parserOutput->getText() . $appendString); |
---|
510 | } |
---|
511 | |
---|
512 | if (!empty($this->fck_mw_strtr_span)) { |
---|
513 | global $leaveRawTemplates; |
---|
514 | if (!empty($leaveRawTemplates)) { |
---|
515 | foreach ($leaveRawTemplates as $l) { |
---|
516 | $this->fck_mw_strtr_span[$l] = substr($this->fck_mw_strtr_span[$l], 30, -7); |
---|
517 | } |
---|
518 | } |
---|
519 | $text = strtr($parserOutput->getText(), $this->fck_mw_strtr_span); |
---|
520 | $parserOutput->setText(strtr($text, $this->fck_mw_strtr_span)); |
---|
521 | } |
---|
522 | if (!empty($this->fck_matches)) { |
---|
523 | $text = $parserOutput->getText() ; |
---|
524 | foreach ($this->fck_matches as $key => $m) { |
---|
525 | $text = str_replace( $key, $m[3], $text); |
---|
526 | } |
---|
527 | $parserOutput->setText($text); |
---|
528 | } |
---|
529 | |
---|
530 | if (!empty($parserOutput->mLanguageLinks)) { |
---|
531 | foreach ($parserOutput->mLanguageLinks as $l) { |
---|
532 | $parserOutput->setText($parserOutput->getText() . "\n" . "<a href=\"".$l."\">".$l."</a>") ; |
---|
533 | } |
---|
534 | } |
---|
535 | |
---|
536 | $parserOutput->setText(str_replace("<!--FCK_REDIRECT-->", "#REDIRECT", $parserOutput->getText())); |
---|
537 | |
---|
538 | return $parserOutput; |
---|
539 | } |
---|
540 | |
---|
541 | /** |
---|
542 | * Make lists from lines starting with ':', '*', '#', etc. |
---|
543 | * |
---|
544 | * @private |
---|
545 | * @return string the lists rendered as HTML |
---|
546 | */ |
---|
547 | function doBlockLevels( $text, $linestart ) { |
---|
548 | $fname = 'Parser::doBlockLevels'; |
---|
549 | wfProfileIn( $fname ); |
---|
550 | |
---|
551 | # Parsing through the text line by line. The main thing |
---|
552 | # happening here is handling of block-level elements p, pre, |
---|
553 | # and making lists from lines starting with * # : etc. |
---|
554 | # |
---|
555 | $textLines = explode( "\n", $text ); |
---|
556 | |
---|
557 | $lastPrefix = $output = ''; |
---|
558 | $this->mDTopen = $inBlockElem = false; |
---|
559 | $prefixLength = 0; |
---|
560 | $paragraphStack = false; |
---|
561 | |
---|
562 | if ( !$linestart ) { |
---|
563 | $output .= array_shift( $textLines ); |
---|
564 | } |
---|
565 | foreach ( $textLines as $oLine ) { |
---|
566 | $lastPrefixLength = strlen( $lastPrefix ); |
---|
567 | $preCloseMatch = preg_match('/<\\/pre/i', $oLine ); |
---|
568 | $preOpenMatch = preg_match('/<pre/i', $oLine ); |
---|
569 | if ( !$this->mInPre ) { |
---|
570 | # Multiple prefixes may abut each other for nested lists. |
---|
571 | $prefixLength = strspn( $oLine, '*#:;' ); |
---|
572 | $pref = substr( $oLine, 0, $prefixLength ); |
---|
573 | |
---|
574 | # eh? |
---|
575 | $pref2 = str_replace( ';', ':', $pref ); |
---|
576 | $t = substr( $oLine, $prefixLength ); |
---|
577 | $this->mInPre = !empty($preOpenMatch); |
---|
578 | } else { |
---|
579 | # Don't interpret any other prefixes in preformatted text |
---|
580 | $prefixLength = 0; |
---|
581 | $pref = $pref2 = ''; |
---|
582 | $t = $oLine; |
---|
583 | } |
---|
584 | |
---|
585 | # List generation |
---|
586 | if( $prefixLength && 0 == strcmp( $lastPrefix, $pref2 ) ) { |
---|
587 | # Same as the last item, so no need to deal with nesting or opening stuff |
---|
588 | $output .= $this->nextItem( substr( $pref, -1 ) ); |
---|
589 | $paragraphStack = false; |
---|
590 | |
---|
591 | if ( substr( $pref, -1 ) == ';') { |
---|
592 | # The one nasty exception: definition lists work like this: |
---|
593 | # ; title : definition text |
---|
594 | # So we check for : in the remainder text to split up the |
---|
595 | # title and definition, without b0rking links. |
---|
596 | $term = $t2 = ''; |
---|
597 | if ($this->findColonNoLinks($t, $term, $t2) !== false) { |
---|
598 | $t = $t2; |
---|
599 | $output .= $term . $this->nextItem( ':' ); |
---|
600 | } |
---|
601 | } |
---|
602 | } elseif( $prefixLength || $lastPrefixLength ) { |
---|
603 | # Either open or close a level... |
---|
604 | $commonPrefixLength = $this->getCommon( $pref, $lastPrefix ); |
---|
605 | $paragraphStack = false; |
---|
606 | |
---|
607 | while( $commonPrefixLength < $lastPrefixLength ) { |
---|
608 | $output .= $this->closeList( $lastPrefix{$lastPrefixLength-1} ); |
---|
609 | --$lastPrefixLength; |
---|
610 | } |
---|
611 | if ( $prefixLength <= $commonPrefixLength && $commonPrefixLength > 0 ) { |
---|
612 | $output .= $this->nextItem( $pref{$commonPrefixLength-1} ); |
---|
613 | } |
---|
614 | while ( $prefixLength > $commonPrefixLength ) { |
---|
615 | $char = substr( $pref, $commonPrefixLength, 1 ); |
---|
616 | $output .= $this->openList( $char ); |
---|
617 | |
---|
618 | if ( ';' == $char ) { |
---|
619 | # FIXME: This is dupe of code above |
---|
620 | if ($this->findColonNoLinks($t, $term, $t2) !== false) { |
---|
621 | $t = $t2; |
---|
622 | $output .= $term . $this->nextItem( ':' ); |
---|
623 | } |
---|
624 | } |
---|
625 | ++$commonPrefixLength; |
---|
626 | } |
---|
627 | $lastPrefix = $pref2; |
---|
628 | } |
---|
629 | if( 0 == $prefixLength ) { |
---|
630 | wfProfileIn( "$fname-paragraph" ); |
---|
631 | # No prefix (not in list)--go to paragraph mode |
---|
632 | // XXX: use a stack for nestable elements like span, table and div |
---|
633 | $openmatch = preg_match('/(?:<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|<p|<ul|<ol|<li|<\\/tr|<\\/td|<\\/th)/iS', $t ); |
---|
634 | $closematch = preg_match( |
---|
635 | '/(?:<\\/table|<\\/blockquote|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'. |
---|
636 | '<td|<th|<\\/?div|<hr|<\\/pre|<\\/p|'.$this->mUniqPrefix.'-pre|<\\/li|<\\/ul|<\\/ol|<\\/?center)/iS', $t ); |
---|
637 | if ( $openmatch or $closematch ) { |
---|
638 | $paragraphStack = false; |
---|
639 | # TODO bug 5718: paragraph closed |
---|
640 | $output .= $this->closeParagraph(); |
---|
641 | if ( $preOpenMatch and !$preCloseMatch ) { |
---|
642 | $this->mInPre = true; |
---|
643 | } |
---|
644 | if ( $closematch ) { |
---|
645 | $inBlockElem = false; |
---|
646 | } else { |
---|
647 | $inBlockElem = true; |
---|
648 | } |
---|
649 | } else if ( !$inBlockElem && !$this->mInPre ) { |
---|
650 | if ( ' ' == $t{0} and ( $this->mLastSection == 'pre' or trim($t) != '' ) ) { |
---|
651 | // pre |
---|
652 | if ($this->mLastSection != 'pre') { |
---|
653 | $paragraphStack = false; |
---|
654 | $output .= $this->closeParagraph().'<pre class="_fck_mw_lspace">'; |
---|
655 | $this->mLastSection = 'pre'; |
---|
656 | } |
---|
657 | $t = substr( $t, 1 ); |
---|
658 | } else { |
---|
659 | // paragraph |
---|
660 | if ( '' == trim($t) ) { |
---|
661 | if ( $paragraphStack ) { |
---|
662 | $output .= $paragraphStack.'<br />'; |
---|
663 | $paragraphStack = false; |
---|
664 | $this->mLastSection = 'p'; |
---|
665 | } else { |
---|
666 | if ($this->mLastSection != 'p' ) { |
---|
667 | $output .= $this->closeParagraph(); |
---|
668 | $this->mLastSection = ''; |
---|
669 | $paragraphStack = '<p>'; |
---|
670 | } else { |
---|
671 | $paragraphStack = '</p><p>'; |
---|
672 | } |
---|
673 | } |
---|
674 | } else { |
---|
675 | if ( $paragraphStack ) { |
---|
676 | $output .= $paragraphStack; |
---|
677 | $paragraphStack = false; |
---|
678 | $this->mLastSection = 'p'; |
---|
679 | } else if ($this->mLastSection != 'p') { |
---|
680 | $output .= $this->closeParagraph().'<p>'; |
---|
681 | $this->mLastSection = 'p'; |
---|
682 | } |
---|
683 | } |
---|
684 | } |
---|
685 | } |
---|
686 | wfProfileOut( "$fname-paragraph" ); |
---|
687 | } |
---|
688 | // somewhere above we forget to get out of pre block (bug 785) |
---|
689 | if($preCloseMatch && $this->mInPre) { |
---|
690 | $this->mInPre = false; |
---|
691 | } |
---|
692 | if ($paragraphStack === false) { |
---|
693 | $output .= $t."\n"; |
---|
694 | } |
---|
695 | } |
---|
696 | while ( $prefixLength ) { |
---|
697 | $output .= $this->closeList( $pref2{$prefixLength-1} ); |
---|
698 | --$prefixLength; |
---|
699 | } |
---|
700 | if ( '' != $this->mLastSection ) { |
---|
701 | $output .= '</' . $this->mLastSection . '>'; |
---|
702 | $this->mLastSection = ''; |
---|
703 | } |
---|
704 | |
---|
705 | wfProfileOut( $fname ); |
---|
706 | return $output; |
---|
707 | } |
---|
708 | } |
---|