* @file
* @ingroup Parser
*/
+
class ParserOutput extends CacheTime {
/**
- * Feature flag to indicate to extensions that MediaWiki core supports and
+ * Feature flags to indicate to extensions that MediaWiki core supports and
* uses getText() stateless transforms.
*/
const SUPPORTS_STATELESS_TRANSFORMS = 1;
+ const SUPPORTS_UNWRAP_TRANSFORM = 1;
/**
* @var string $mText The output text
*/
public $mSections = [];
- /**
- * @deprecated since 1.31 Use getText() options.
- * @var bool $mEditSectionTokens prefix/suffix markers if edit sections were output as tokens.
- */
- public $mEditSectionTokens = true;
-
/**
* @var array $mProperties Name/value pairs to be cached in the DB.
*/
*/
public $mTimestamp;
- /**
- * @deprecated since 1.31 Use getText() options.
- * @var bool $mTOCEnabled Whether TOC should be shown, can't override __NOTOC__.
- */
- public $mTOCEnabled = true;
-
/**
* @var bool $mEnableOOUI Whether OOUI should be enabled.
*/
private $mIndexPolicy = '';
/**
- * @var array $mAccessedOptions List of ParserOptions (stored in the keys).
+ * @var true[] $mAccessedOptions List of ParserOptions (stored in the keys).
*/
private $mAccessedOptions = [];
* to generate one and `__NOTOC__` wasn't used. Default is true,
* but might be statefully overridden.
* - enableSectionEditLinks: (bool) Include section edit links, assuming
- * section edit link tokens are present in the HTML. Default is true,
+ * section edit link tokens are present in the HTML. Default is true,
* but might be statefully overridden.
+ * - unwrap: (bool) Remove a wrapping mw-parser-output div. Default is false.
+ * - deduplicateStyles: (bool) When true, which is the default, `<style>`
+ * tags with the `data-mw-deduplicate` attribute set are deduplicated by
+ * value of the attribute: all but the first will be replaced by `<link
+ * rel="mw-deduplicated-inline-style" href="mw-data:..."/>` tags, where
+ * the scheme-specific-part of the href is the (percent-encoded) value
+ * of the `data-mw-deduplicate` attribute.
* @return string HTML
*/
public function getText( $options = [] ) {
- // @todo Warn if !array_key_exists( 'allowTOC', $options ) && empty( $this->mTOCEnabled )
-
- // @todo Warn if !array_key_exists( 'enableSectionEditLinks', $options )
- // && !$this->mEditSectionTokens
- // Note that while $this->mEditSectionTokens formerly defaulted to false,
- // ParserOptions->getEditSection() defaults to true and Parser copies
- // that to us so true makes more sense as the stateless default.
-
$options += [
- // empty() here because old cached versions might lack the field somehow.
- // In that situation, the historical behavior (possibly buggy) is to remove the TOC.
- 'allowTOC' => !empty( $this->mTOCEnabled ),
- 'enableSectionEditLinks' => $this->mEditSectionTokens,
+ 'allowTOC' => true,
+ 'enableSectionEditLinks' => true,
+ 'unwrap' => false,
+ 'deduplicateStyles' => true,
];
$text = $this->mText;
Hooks::runWithoutAbort( 'ParserOutputPostCacheTransform', [ $this, &$text, &$options ] );
+ if ( $options['unwrap'] !== false ) {
+ $start = Html::openElement( 'div', [
+ 'class' => 'mw-parser-output'
+ ] );
+ $startLen = strlen( $start );
+ $end = Html::closeElement( 'div' );
+ $endPos = strrpos( $text, $end );
+ $endLen = strlen( $end );
+
+ if ( substr( $text, 0, $startLen ) === $start && $endPos !== false
+ // if the closing div is followed by real content, bail out of unwrapping
+ && preg_match( '/^(?>\s*<!--.*?-->)*\s*$/s', substr( $text, $endPos + $endLen ) )
+ ) {
+ $text = substr( $text, $startLen );
+ $text = substr( $text, 0, $endPos - $startLen )
+ . substr( $text, $endPos - $startLen + $endLen );
+ }
+ }
+
if ( $options['enableSectionEditLinks'] ) {
$text = preg_replace_callback(
self::EDITSECTION_REGEX,
);
}
+ if ( $options['deduplicateStyles'] ) {
+ $seen = [];
+ $text = preg_replace_callback(
+ '#<style\s+([^>]*data-mw-deduplicate\s*=[^>]*)>.*?</style>#s',
+ function ( $m ) use ( &$seen ) {
+ $attr = Sanitizer::decodeTagAttributes( $m[1] );
+ if ( !isset( $attr['data-mw-deduplicate'] ) ) {
+ return $m[0];
+ }
+
+ $key = $attr['data-mw-deduplicate'];
+ if ( !isset( $seen[$key] ) ) {
+ $seen[$key] = true;
+ return $m[0];
+ }
+
+ // We were going to use an empty <style> here, but there
+ // was concern that would be too much overhead for browsers.
+ // So let's hope a <link> with a non-standard rel and href isn't
+ // going to be misinterpreted or mangled by any subsequent processing.
+ return Html::element( 'link', [
+ 'rel' => 'mw-deduplicated-inline-style',
+ 'href' => "mw-data:" . wfUrlencode( $key ),
+ ] );
+ },
+ $text
+ );
+ }
+
return $text;
}
* @deprecated since 1.31 Use getText() options.
*/
public function getEditSectionTokens() {
- return $this->mEditSectionTokens;
+ wfDeprecated( __METHOD__, '1.31' );
+ return true;
}
public function &getLinks() {
* @deprecated since 1.31 Use getText() options.
*/
public function getTOCEnabled() {
- return $this->mTOCEnabled;
+ wfDeprecated( __METHOD__, '1.31' );
+ return true;
}
public function getEnableOOUI() {
* @deprecated since 1.31 Use getText() options.
*/
public function setEditSectionTokens( $t ) {
- return wfSetVar( $this->mEditSectionTokens, $t );
+ wfDeprecated( __METHOD__, '1.31' );
+ return true;
}
public function setIndexPolicy( $policy ) {
* @deprecated since 1.31 Use getText() options.
*/
public function setTOCEnabled( $flag ) {
- return wfSetVar( $this->mTOCEnabled, $flag );
+ wfDeprecated( __METHOD__, '1.31' );
+ return true;
}
public function addCategory( $c, $sort ) {
/**
* Register a file dependency for this output
* @param string $name Title dbKey
- * @param string $timestamp MW timestamp of file creation (or false if non-existing)
- * @param string $sha1 Base 36 SHA-1 of file (or false if non-existing)
- * @return void
+ * @param string|false|null $timestamp MW timestamp of file creation (or false if non-existing)
+ * @param string|false|null $sha1 Base 36 SHA-1 of file (or false if non-existing)
*/
public function addImage( $name, $timestamp = null, $sha1 = null ) {
$this->mImages[$name] = 1;
* @param Title $title
* @param int $page_id
* @param int $rev_id
- * @return void
*/
public function addTemplate( $title, $page_id, $rev_id ) {
$ns = $title->getNamespace();
/**
* Returns the options from its ParserOptions which have been taken
- * into account to produce this output or false if not available.
- * @return array
+ * into account to produce this output.
+ * @return string[]
*/
public function getUsedOptions() {
if ( !isset( $this->mAccessedOptions ) ) {