2017-02-17 04:10:15 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace MediaWiki\Tidy;
|
|
|
|
|
|
2021-02-18 15:51:57 +00:00
|
|
|
use Sanitizer;
|
2021-08-08 20:50:34 +00:00
|
|
|
use Wikimedia\RemexHtml\HTMLData;
|
|
|
|
|
use Wikimedia\RemexHtml\Serializer\HtmlFormatter;
|
|
|
|
|
use Wikimedia\RemexHtml\Serializer\SerializerNode;
|
2017-02-17 04:10:15 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
class RemexCompatFormatter extends HtmlFormatter {
|
|
|
|
|
private static $markedEmptyElements = [
|
|
|
|
|
'li' => true,
|
|
|
|
|
'p' => true,
|
|
|
|
|
'tr' => true,
|
|
|
|
|
];
|
|
|
|
|
|
2021-04-29 22:40:40 +00:00
|
|
|
/** @var ?callable */
|
2021-02-10 15:42:26 +00:00
|
|
|
private $textProcessor;
|
|
|
|
|
|
2017-02-17 04:10:15 +00:00
|
|
|
public function __construct( $options = [] ) {
|
|
|
|
|
parent::__construct( $options );
|
2017-10-07 00:26:23 +00:00
|
|
|
$this->attributeEscapes["\u{00A0}"] = ' ';
|
2017-02-17 04:10:15 +00:00
|
|
|
unset( $this->attributeEscapes["&"] );
|
2017-10-07 00:26:23 +00:00
|
|
|
$this->textEscapes["\u{00A0}"] = ' ';
|
2017-02-17 04:10:15 +00:00
|
|
|
unset( $this->textEscapes["&"] );
|
2021-02-10 15:42:26 +00:00
|
|
|
$this->textProcessor = $options['textProcessor'] ?? null;
|
2017-02-17 04:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function startDocument( $fragmentNamespace, $fragmentName ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-10 15:42:26 +00:00
|
|
|
public function characters( SerializerNode $parent, $text, $start, $length ) {
|
|
|
|
|
$text = parent::characters( $parent, $text, $start, $length );
|
2021-02-18 15:51:57 +00:00
|
|
|
|
2021-02-10 15:42:26 +00:00
|
|
|
if ( $parent->namespace !== HTMLData::NS_HTML
|
|
|
|
|
|| !isset( $this->rawTextElements[$parent->name] )
|
|
|
|
|
) {
|
|
|
|
|
if ( $this->textProcessor !== null ) {
|
|
|
|
|
$text = call_user_func( $this->textProcessor, $text );
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-18 15:51:57 +00:00
|
|
|
|
|
|
|
|
// Ensure a consistent representation for all entities
|
|
|
|
|
$text = Sanitizer::normalizeCharReferences( $text );
|
2021-02-10 15:42:26 +00:00
|
|
|
return $text;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-17 04:10:15 +00:00
|
|
|
public function element( SerializerNode $parent, SerializerNode $node, $contents ) {
|
|
|
|
|
$data = $node->snData;
|
|
|
|
|
if ( $data && $data->isPWrapper ) {
|
|
|
|
|
if ( $data->nonblankNodeCount ) {
|
|
|
|
|
return "<p>$contents</p>";
|
|
|
|
|
} else {
|
|
|
|
|
return $contents;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$name = $node->name;
|
|
|
|
|
$attrs = $node->attrs;
|
2019-03-29 20:12:24 +00:00
|
|
|
if ( isset( self::$markedEmptyElements[$name] ) && $attrs->count() === 0
|
|
|
|
|
&& strspn( $contents, "\t\n\f\r " ) === strlen( $contents )
|
|
|
|
|
) {
|
|
|
|
|
return "<{$name} class=\"mw-empty-elt\">$contents</{$name}>";
|
2017-02-17 04:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$s = "<$name";
|
|
|
|
|
foreach ( $attrs->getValues() as $attrName => $attrValue ) {
|
|
|
|
|
$encValue = strtr( $attrValue, $this->attributeEscapes );
|
2021-02-18 15:51:57 +00:00
|
|
|
$encValue = Sanitizer::normalizeCharReferences( $encValue );
|
2017-02-17 04:10:15 +00:00
|
|
|
$s .= " $attrName=\"$encValue\"";
|
|
|
|
|
}
|
|
|
|
|
if ( $node->namespace === HTMLData::NS_HTML && isset( $this->voidElements[$name] ) ) {
|
|
|
|
|
$s .= ' />';
|
|
|
|
|
return $s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$s .= '>';
|
|
|
|
|
if ( $node->namespace === HTMLData::NS_HTML
|
|
|
|
|
&& isset( $contents[0] ) && $contents[0] === "\n"
|
|
|
|
|
&& isset( $this->prefixLfElements[$name] )
|
|
|
|
|
) {
|
|
|
|
|
$s .= "\n$contents</$name>";
|
|
|
|
|
} else {
|
|
|
|
|
$s .= "$contents</$name>";
|
|
|
|
|
}
|
|
|
|
|
return $s;
|
|
|
|
|
}
|
|
|
|
|
}
|