public static function convertDataToAttributes($data) { // get ID of current CK instance $instance = RTE::getInstanceId(); // properly encode JSON $encoded = RTEReverseParser::encodeRTEData($data); $encoded = Sanitizer::encodeAttribute($encoded); return " data-rte-meta=\"{$encoded}\" data-rte-instance=\"{$instance}\" "; }
/** * Make lists from lines starting with ':', '*', '#', etc. (DBL) * * @param $text String * @param $linestart Boolean: whether or not this is at the start of a line. * @private * @return string the lists rendered as HTML */ function doBlockLevels($text, $linestart) { wfProfileIn(__METHOD__); # Parsing through the text line by line. The main thing # happening here is handling of block-level elements p, pre, # and making lists from lines starting with * # : etc. # $textLines = StringUtils::explode("\n", $text); $lastPrefix = $output = ''; $this->mDTopen = $inBlockElem = false; $prefixLength = 0; $paragraphStack = false; $comment = $prefixType = false; # wikia change foreach ($textLines as $oLine) { # Fix up $linestart if (!$linestart) { $output .= $oLine; $linestart = true; continue; } # * = ul # # = ol # ; = dt # : = dd # RTE (Rich Text Editor) - begin # @author: Macbre $this->doBlockLevelsLineStart($oLine, $output); # RTE - end $lastPrefixLength = strlen($lastPrefix); $preCloseMatch = preg_match('/<\\/pre/i', $oLine); $preOpenMatch = preg_match('/<pre/i', $oLine); # If not in a <pre> element, scan for and figure out what prefixes are there. if (!$this->mInPre) { # Multiple prefixes may abut each other for nested lists. $prefixLength = strspn($oLine, '*#:;'); $prefix = substr($oLine, 0, $prefixLength); # eh? # ; and : are both from definition-lists, so they're equivalent # for the purposes of determining whether or not we need to open/close # elements. $prefix2 = str_replace(';', ':', $prefix); $t = substr($oLine, $prefixLength); $this->mInPre = (bool) $preOpenMatch; } else { # Don't interpret any other prefixes in preformatted text $prefixLength = 0; $prefix = $prefix2 = ''; $t = $oLine; } # RTE (Rich Text Editor) - begin # @author: Macbre $this->mCurrentPrefix = $prefix; # RTE - end # List generation if ($prefixLength && $lastPrefix === $prefix2) { # Same as the last item, so no need to deal with nesting or opening stuff $output .= $this->nextItem(substr($prefix, -1)); $paragraphStack = false; if (substr($prefix, -1) === ';') { # The one nasty exception: definition lists work like this: # ; title : definition text # So we check for : in the remainder text to split up the # title and definition, without b0rking links. $term = $t2 = ''; if ($this->findColonNoLinks($t, $term, $t2) !== false) { $t = $t2; $output .= $term . $this->nextItem(':'); } } } elseif ($prefixLength || $lastPrefixLength) { # We need to open or close prefixes, or both. # Either open or close a level... $commonPrefixLength = $this->getCommon($prefix, $lastPrefix); $paragraphStack = false; # Close all the prefixes which aren't shared. while ($commonPrefixLength < $lastPrefixLength) { $output .= $this->closeList($lastPrefix[$lastPrefixLength - 1]); --$lastPrefixLength; } # Continue the current prefix if appropriate. if ($prefixLength <= $commonPrefixLength && $commonPrefixLength > 0) { $output .= $this->nextItem($prefix[$commonPrefixLength - 1]); } # Open prefixes where appropriate. while ($prefixLength > $commonPrefixLength) { $char = substr($prefix, $commonPrefixLength, 1); /* Wikia change begin - @author: Macbre */ $this->mLastCommonPrefix = $prefixLength == $commonPrefixLength + 1; /* Wikia change end */ $output .= $this->openList($char); if (';' === $char) { # @todo FIXME: This is dupe of code above if ($this->findColonNoLinks($t, $term, $t2) !== false) { $t = $t2; $output .= $term . $this->nextItem(':'); } } ++$commonPrefixLength; } $lastPrefix = $prefix2; } # If we have no prefixes, go to paragraph mode. if (0 == $prefixLength) { wfProfileIn(__METHOD__ . "-paragraph"); # No prefix (not in list)--go to paragraph mode # XXX: use a stack for nestable elements like span, table and div $openmatch = preg_match('/(?:<aside|<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|<p|<ul|<ol|<li|<\\/tr|<\\/td|<\\/th)/iS', $t); /** * Wikia change start * @author Federico "Lox" Lucignano * * Stop the parser from wrapping figure tags in paragraphs */ $closematch = preg_match('/(?:<\\/?aside|<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|' . '<td|<th|<\\/?div|<\\/?figure|<hr|<\\/pre|<\\/p|' . $this->mUniqPrefix . '-pre|' . $this->mUniqPrefix . '-bloglist|' . $this->mUniqPrefix . '-infobox|<\\/li|<\\/ul|<\\/ol|<\\/?center)/iS', $t); /** * Wikia change end */ # RTE (Rich Text Editor) - begin # @author: Macbre $this->doOpenCloseMatch($t, $openmatch, $closematch); # RTE - end if ($openmatch or $closematch) { $paragraphStack = false; # TODO bug 5718: paragraph closed $output .= $this->closeParagraph(); if ($preOpenMatch and !$preCloseMatch) { $this->mInPre = true; } $inBlockElem = !$closematch; } elseif (!$inBlockElem && !$this->mInPre) { if (' ' == substr($t, 0, 1) and $this->mLastSection === 'pre' || trim($t) != '') { # pre if ($this->mLastSection !== 'pre') { $paragraphStack = false; $output .= $this->closeParagraph() . '<pre>'; $this->mLastSection = 'pre'; } $t = substr($t, 1); } else { # paragraph if (trim($t) === '') { if ($paragraphStack) { $output .= $paragraphStack . '<br />'; $paragraphStack = false; $this->mLastSection = 'p'; } else { if ($this->mLastSection !== 'p') { $output .= $this->closeParagraph(); $this->mLastSection = ''; $paragraphStack = '<p>'; } else { $paragraphStack = '</p><p>'; } } } else { if ($paragraphStack) { $output .= $paragraphStack; $paragraphStack = false; $this->mLastSection = 'p'; } elseif ($this->mLastSection !== 'p') { $output .= $this->closeParagraph() . '<p>'; $this->mLastSection = 'p'; } else { # RTE (Rich Text Editor) - begin # @author: Macbre global $wgRTEParserEnabled; if (!empty($wgRTEParserEnabled)) { // count trailing spaces $text = ltrim(strrev($output), "\n"); $spaces = strspn($text, ' '); $output .= RTEReverseParser::buildComment('LINE_BREAK', array('spaces' => $spaces)); } # RTE - end } } } } wfProfileOut(__METHOD__ . "-paragraph"); } # somewhere above we forget to get out of pre block (bug 785) if ($preCloseMatch && $this->mInPre) { $this->mInPre = false; } if ($paragraphStack === false) { $output .= $t . "\n"; } # RTE (Rich Text Editor) - begin # @author: Macbre $this->doBlockLevelsLineEnd($oLine, $output); # RTE - end } while ($prefixLength) { $output .= $this->closeList($prefix2[$prefixLength - 1]); --$prefixLength; } if ($this->mLastSection != '') { $output .= '</' . $this->mLastSection . '>'; $this->mLastSection = ''; } wfProfileOut(__METHOD__); return $output; }
/** * Convert wikitext to HTML and add extra HTML attributes for RTE * * @param $text String: text we want to parse * @param $title A title object * @param $options ParserOptions * @param $linestart boolean * @param $clearState boolean * @param $revid Int: number to pass in {{REVISIONID}} * @return ParserOutput a ParserOutput */ public function parse($text, Title $title, ParserOptions $options, $linestart = true, $clearState = true, $revid = null) { wfProfileIn(__METHOD__); // get rid of all \r in wikitext $text = str_replace("\r\n", "\n", $text); // count newlines at the beginning of the wikitext $emptyLinesAtStart = strspn($text, "\n"); if ($emptyLinesAtStart > 0) { // don't double count empty lines at the beginning of wikitext $this->emptyLinesBefore = $emptyLinesAtStart * -1; } // mark HTML entities from wikitext (& : _) $text = self::markEntities($text); // set flag indicating parsing for CK global $wgRTEParserEnabled; $wgRTEParserEnabled = true; // don't use XML cache in preprocessor global $wgPreprocessorCacheThreshold; $wgPreprocessorCacheThreshold = 1000000; //RTE::log(__METHOD__ . '::beforeParse', $text); // parse to HTML $output = parent::parse($text, $title, $options, $linestart, $clearState, $revid); $wgRTEParserEnabled = false; // add extra RTE attributes to HTML elements (for correct handling of spaces and newlines when parsing back to wikitext) $html = $output->getText(); // add RTE_EMPTY_LINES_BEFORE comment if ($emptyLinesAtStart > 0) { $html = RTEReverseParser::addEmptyLinesBeforeComment($emptyLinesAtStart) . $html; } //RTE::log(__METHOD__ . '::beforeReplace', $html); // wrap HTML entities inside span "placeholders" (& : _) $html = self::wrapEntities($html); wfProfileIn(__METHOD__ . '::regexp'); // remove EMPTY_LINES_BEFORE comments which are before closing tags - refs RT#38889 // <!-- RTE_EMPTY_LINES_BEFORE_1 --></td></tr></table> <= remove this one // <!-- RTE_EMPTY_LINES_BEFORE_1 --><p> $html = preg_replace('%<!-- RTE_EMPTY_LINES_BEFORE_(\\d+) -->(</[^>]+></)%s', '\\2', $html); // move empty lines counter data from comment to next opening tag attribute (thx to Marooned) $html = preg_replace('%<!-- RTE_EMPTY_LINES_BEFORE_(\\d+) -->(?!<!)(.*?)(<[^/][^>]*)>%s', '\\2\\3 data-rte-empty-lines-before="\\1">', $html); // remove not replaced EMPTY_LINES_BEFORE comments // <!-- RTE_EMPTY_LINES_BEFORE_1 -- data-rte-empty-lines-before="1"> $html = preg_replace('%<!-- RTE_EMPTY_LINES_BEFORE_(\\d+) [^>]+>%s', '', $html); // add data-rte-spaces-before for list items and table cells $html = preg_replace_callback("/<(li|dd|dt|td|th)([^>]*)>( +)/", 'RTEParser::spacesBeforeCallback', $html); // replace placeholder markers with placeholders $html = preg_replace_callback("/-01-(\\d{4})/", 'RTE::replacePlaceholder', $html); // replace dataidx attribute with data-rte-meta attribute storing JSON encoded meta data $html = preg_replace_callback('/ _rte_dataidx="(\\d{4})" /', 'RTEData::replaceIdxByData', $html); $html = preg_replace("/-(?:" . RTEMarker::INTERNAL_WIKITEXT . "|" . RTEMarker::EXTERNAL_WIKITEXT . ")-\\d{4}/", '', $html); // RT#40786: add empty paragraphs between headings (</h3>\n<h3 ...) $html = preg_replace("%(</h\\d>\\s)(<h\\d)%s", '$1<p data-rte-filler="true"></p>$2', $html); wfProfileOut(__METHOD__ . '::regexp'); // add extra attribute for p tags coming from parser $html = strtr($html, array('<p>' => '<p data-rte-fromparser="true">', '<p ' => '<p data-rte-fromparser="true" ')); // add empty paragraph for new / empty pages if ($html == '') { $html = Xml::element('p'); } // update parser output RTE::log(__METHOD__, $html); $output->setText($html); wfProfileOut(__METHOD__); return $output; }
function parseInternal() { $parser = new RTEReverseParser(); return $parser->parse($this->mText); }
/** * Parse given HTML from CK back to wikitext */ public static function HtmlToWikitext($html) { wfProfileIn(__METHOD__); $RTEReverseParser = new RTEReverseParser(); $wikitext = $RTEReverseParser->parse($html); wfProfileOut(__METHOD__); return $wikitext; }