1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
<?php
/**
* Renders a diff for a single slot.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup DifferenceEngine
*/
use MediaWiki\Context\IContextSource;
use MediaWiki\Output\OutputPage;
use MediaWiki\Title\Title;
use Wikimedia\Assert\Assert;
/**
* Renders a diff for a single slot (that is, a diff between two content objects).
*
* Callers should obtain instances of this class by invoking ContentHandler::getSlotDiffRenderer
* on the content handler of the new content object (ie. the one shown on the right side
* of the diff), or of the old one if the new one does not exist.
*
* The default implementation just does a text diff on the native text representation.
* Content handler extensions can subclass this to provide a more appropriate diff method by
* overriding ContentHandler::getSlotDiffRendererInternal. Other extensions that want to interfere
* with diff generation in some way can use the GetSlotDiffRenderer hook.
*
* @stable to extend
* @ingroup DifferenceEngine
*/
abstract class SlotDiffRenderer {
/**
* Get a diff between two content objects. One of them might be null (meaning a slot was
* created or removed), but both cannot be. $newContent (or if it's null then $oldContent)
* must have the same content model that was used to obtain this diff renderer.
* @param Content|null $oldContent
* @param Content|null $newContent
* @return string HTML. One or more <tr> tags, or an empty string if the inputs are identical.
* @throws IncompatibleDiffTypesException
*/
abstract public function getDiff( Content $oldContent = null, Content $newContent = null );
/**
* Localize language-independent text returned by getDiff(), making it
* suitable for display. Subclasses overriding this should arrange for
* injection of a MessageLocalizer.
*
* @param string $diff
* @param array $options Associative array of options:
* - reducedLineNumbers: If true, remove "line 1" but allow other line numbers
* @return string
*/
public function localizeDiff( string $diff, array $options = [] ) {
return $diff;
}
/**
* Get the content to add above the main diff table.
*
* @since 1.41
* @param IContextSource $context
* @param Title $newTitle
* @return (string|null)[] An array of HTML fragments to assemble into the prefix
* area. They will be deduplicated and sorted by key.
*/
public function getTablePrefix( IContextSource $context, Title $newTitle ): array {
return [];
}
/**
* Add modules needed for correct styling/behavior of the diff.
* @stable to override
* @param OutputPage $output
*/
public function addModules( OutputPage $output ) {
}
/**
* Return any extra keys to split the diff cache by.
* @stable to override
* @return string[]
*/
public function getExtraCacheKeys() {
return [];
}
/**
* Helper method to normalize the input of getDiff().
* Verifies that at least one of $oldContent and $newContent is not null, verifies that
* they are instances of one of the allowed classes (if provided), and replaces null with
* empty content.
* @param Content|null &$oldContent
* @param Content|null &$newContent
* @param string|array|null $allowedClasses
* @throws IncompatibleDiffTypesException
*/
protected function normalizeContents(
Content &$oldContent = null, Content &$newContent = null, $allowedClasses = null
) {
if ( !$oldContent && !$newContent ) {
throw new InvalidArgumentException( '$oldContent and $newContent cannot both be null' );
}
if ( $allowedClasses ) {
if ( is_string( $allowedClasses ) ) {
$allowedClasses = explode( '|', $allowedClasses );
}
$allowedClassesOrNull = array_merge( $allowedClasses, [ 'null' ] );
// The new content (or the old one if the new one is null) must always match the renderer
// since the ContentHandler of that model should be used to create it
Assert::parameterType( $allowedClassesOrNull, $newContent, '$newContent' );
if ( !$newContent ) {
Assert::parameterType( $allowedClassesOrNull, $oldContent, '$oldContent' );
}
// If there are two content objects, the old one can be arbitrary as it is possible
// to generate a diff between any two revisions; so an incompatible model should be
// handled as a user error, not a logic error.
if ( $oldContent && $newContent ) {
$allowed = false;
foreach ( $allowedClasses as $class ) {
if ( $oldContent instanceof $class ) {
$allowed = true;
break;
}
}
if ( !$allowed ) {
throw new IncompatibleDiffTypesException( $oldContent->getModel(), $newContent->getModel() );
}
}
}
if ( !$oldContent ) {
$oldContent = $newContent->getContentHandler()->makeEmptyContent();
} elseif ( !$newContent ) {
$newContent = $oldContent->getContentHandler()->makeEmptyContent();
}
}
}
|