PageRenderTime 47ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/mediawiki-extensions-fckeditor/usr/share/mediawiki-extensions/fckeditor/FCKeditorParser.body.php

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