15use InvalidArgumentException;
28 private const SIDE_DELETED =
'deleted';
29 private const SIDE_ADDED =
'added';
30 private const SIDE_CLASSES = [
31 self::SIDE_DELETED =>
'diff-side-deleted',
32 self::SIDE_ADDED =>
'diff-side-added'
36 $this->leadingContextLines = 2;
37 $this->trailingContextLines = 2;
46 $msg = preg_replace(
'/^ /m',
"\u{00A0} ", $msg );
47 $msg = preg_replace(
'/ $/m',
" \u{00A0}", $msg );
48 $msg = preg_replace(
'/ /',
"\u{00A0} ", $msg );
61 protected function blockHeader( $xbeg, $xlen, $ybeg, $ylen ) {
64 return $this->rawElement(
69 [
'colspan' =>
'2',
'class' =>
'diff-lineno',
'id' =>
'mw-diff-left-l' . $xbeg ],
70 '<!--LINE ' . $xbeg .
'-->'
75 [
'colspan' =>
'2',
'class' =>
'diff-lineno' ],
76 '<!--LINE ' . $ybeg .
'-->'
95 protected function lines( $lines, $prefix =
' ', $color =
'white' ) {
106 return $this->
wrapLine(
'+', [
'diff-addedline', $this->getClassForSide( self::SIDE_ADDED ) ], $line );
117 return $this->
wrapLine(
'−', [
'diff-deletedline', $this->getClassForSide( self::SIDE_DELETED ) ], $line );
129 return $this->
wrapLine(
'', [
'diff-context', $this->getClassForSide( $side ) ], $line );
139 protected function wrapLine( $marker, $class, $line ) {
140 if ( $line !==
'' ) {
147 $markerAttrs = [
'class' =>
'diff-marker' ];
149 $markerAttrs[
'data-marker'] = $marker;
152 if ( is_array( $class ) ) {
153 $class = implode(
' ', $class );
156 return $this->element(
'td', $markerAttrs ) .
157 $this->rawElement(
'td', [
'class' => $class ], $line );
165 return $this->element(
'td', [
'colspan' =>
'2',
'class' => $this->getClassForSide( $side ) ] );
173 protected function added( $lines ) {
174 foreach ( $lines as $line ) {
183 [
'class' =>
'diffchange' ],
199 foreach ( $lines as $line ) {
207 [
'class' =>
'diffchange' ],
224 foreach ( $lines as $line ) {
229 $this->
contextLine( htmlspecialchars( $line ), self::SIDE_DELETED ) .
230 $this->
contextLine( htmlspecialchars( $line ), self::SIDE_ADDED )
243 protected function changed( $orig, $closing ) {
245 $del = $diff->orig();
246 $add = $diff->closing();
248 # Notice that WordLevelDiff returns HTML-escaped output.
249 # Hence, we will be calling addedLine/deletedLine without HTML-escaping.
251 $ndel = count( $del );
252 $nadd = count( $add );
253 $n = max( $ndel, $nadd );
254 for ( $i = 0; $i < $n; $i++ ) {
255 $delLine = $i < $ndel ? $this->
deletedLine( $del[$i] ) : $this->
emptyLine( self::SIDE_DELETED );
256 $addLine = $i < $nadd ? $this->
addedLine( $add[$i] ) : $this->
emptyLine( self::SIDE_ADDED );
275 private function getClassForSide(
string $side ): string {
276 if ( !isset( self::SIDE_CLASSES[$side] ) ) {
277 throw new InvalidArgumentException(
"Invalid diff side: $side" );
279 return self::SIDE_CLASSES[$side];
290 private function rawElement( $element, $attribs = [], $contents =
'' ) {
292 foreach ( $attribs as $name => $value ) {
293 $ret .=
" $name=\"" . htmlspecialchars( $value, ENT_QUOTES ) .
'"';
295 $ret .=
">$contents</$element>";
307 private function element( $element, $attribs = [], $contents =
'' ) {
308 return $this->rawElement( $element, $attribs, htmlspecialchars( $contents, ENT_NOQUOTES ) );
313class_alias( TableDiffFormatter::class,
'TableDiffFormatter' );
if(!defined('MW_SETUP_CALLBACK'))