29use InvalidArgumentException;
42 private const SIDE_DELETED =
'deleted';
43 private const SIDE_ADDED =
'added';
44 private const SIDE_CLASSES = [
45 self::SIDE_DELETED =>
'diff-side-deleted',
46 self::SIDE_ADDED =>
'diff-side-added'
50 $this->leadingContextLines = 2;
51 $this->trailingContextLines = 2;
60 $msg = preg_replace(
'/^ /m',
"\u{00A0} ", $msg );
61 $msg = preg_replace(
'/ $/m',
" \u{00A0}", $msg );
62 $msg = preg_replace(
'/ /',
"\u{00A0} ", $msg );
75 protected function blockHeader( $xbeg, $xlen, $ybeg, $ylen ) {
78 return $this->rawElement(
83 [
'colspan' =>
'2',
'class' =>
'diff-lineno',
'id' =>
'mw-diff-left-l' . $xbeg ],
84 '<!--LINE ' . $xbeg .
'-->'
89 [
'colspan' =>
'2',
'class' =>
'diff-lineno' ],
90 '<!--LINE ' . $ybeg .
'-->'
109 protected function lines(
$lines, $prefix =
' ', $color =
'white' ) {
120 return $this->
wrapLine(
'+', [
'diff-addedline', $this->getClassForSide( self::SIDE_ADDED ) ], $line );
131 return $this->
wrapLine(
'−', [
'diff-deletedline', $this->getClassForSide( self::SIDE_DELETED ) ], $line );
143 return $this->
wrapLine(
'', [
'diff-context', $this->getClassForSide( $side ) ], $line );
153 protected function wrapLine( $marker, $class, $line ) {
154 if ( $line !==
'' ) {
161 $markerAttrs = [
'class' =>
'diff-marker' ];
163 $markerAttrs[
'data-marker'] = $marker;
166 if ( is_array( $class ) ) {
167 $class = implode(
' ', $class );
170 return $this->element(
'td', $markerAttrs ) .
171 $this->rawElement(
'td', [
'class' => $class ], $line );
179 return $this->element(
'td', [
'colspan' =>
'2',
'class' => $this->getClassForSide( $side ) ] );
188 foreach (
$lines as $line ) {
197 [
'class' =>
'diffchange' ],
213 foreach (
$lines as $line ) {
221 [
'class' =>
'diffchange' ],
238 foreach (
$lines as $line ) {
243 $this->
contextLine( htmlspecialchars( $line ), self::SIDE_DELETED ) .
244 $this->
contextLine( htmlspecialchars( $line ), self::SIDE_ADDED )
257 protected function changed( $orig, $closing ) {
259 $del = $diff->orig();
260 $add = $diff->closing();
262 # Notice that WordLevelDiff returns HTML-escaped output.
263 # Hence, we will be calling addedLine/deletedLine without HTML-escaping.
265 $ndel = count( $del );
266 $nadd = count( $add );
267 $n = max( $ndel, $nadd );
268 for ( $i = 0; $i < $n; $i++ ) {
269 $delLine = $i < $ndel ? $this->
deletedLine( $del[$i] ) : $this->
emptyLine( self::SIDE_DELETED );
270 $addLine = $i < $nadd ? $this->
addedLine( $add[$i] ) : $this->
emptyLine( self::SIDE_ADDED );
289 private function getClassForSide(
string $side ): string {
290 if ( !isset( self::SIDE_CLASSES[$side] ) ) {
291 throw new InvalidArgumentException(
"Invalid diff side: $side" );
293 return self::SIDE_CLASSES[$side];
304 private function rawElement( $element, $attribs = [], $contents =
'' ) {
306 foreach ( $attribs as $name => $value ) {
307 $ret .=
" $name=\"" . htmlspecialchars( $value, ENT_QUOTES ) .
'"';
309 $ret .=
">$contents</$element>";
321 private function element( $element, $attribs = [], $contents =
'' ) {
322 return $this->rawElement( $element, $attribs, htmlspecialchars( $contents, ENT_NOQUOTES ) );
327class_alias( TableDiffFormatter::class,
'TableDiffFormatter' );
if(!defined('MW_SETUP_CALLBACK'))
if(!file_exists( $CREDITS)) $lines