r58267 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r58266‎ | r58267 | r58268 >
Date:18:18, 28 October 2009
Author:demon
Status:ok (Comments)
Tags:
Comment:
(bug 19859) Remove HTMLDiff. Could possibly be salvaged as an extension one day, but not today. DifferenceEngine and friends will need some refactoring to allow spinning this off. In the meantime, removing the mostly-broken experimental feature. Its always in the logs if anyone wants to reuse the code somewhere else one day
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/includes/Article.php (modified) (history)
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/HistoryPage.php (modified) (history)
  • /trunk/phase3/includes/diff/DifferenceInterface.php (modified) (history)
  • /trunk/phase3/includes/diff/HTMLDiff.php (deleted) (history)
  • /trunk/phase3/includes/diff/Nodes.php (deleted) (history)
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/maintenance/language/messageTypes.inc (modified) (history)
  • /trunk/phase3/maintenance/language/messages.inc (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/AutoLoader.php
@@ -376,13 +376,7 @@
377377 'IBM_DB2Field' => 'includes/db/DatabaseIbm_db2.php',
378378
379379 # includes/diff
380 - 'AncestorComparator' => 'includes/diff/HTMLDiff.php',
381 - 'AnchorToString' => 'includes/diff/HTMLDiff.php',
382380 'ArrayDiffFormatter' => 'includes/diff/DifferenceEngine.php',
383 - 'BodyNode' => 'includes/diff/Nodes.php',
384 - 'ChangeText' => 'includes/diff/HTMLDiff.php',
385 - 'ChangeTextGenerator' => 'includes/diff/HTMLDiff.php',
386 - 'DelegatingContentHandler' => 'includes/diff/HTMLDiff.php',
387381 '_DiffEngine' => 'includes/diff/DifferenceEngine.php',
388382 'DifferenceEngine' => 'includes/diff/DifferenceInterface.php',
389383 'DiffFormatter' => 'includes/diff/DifferenceEngine.php',
@@ -392,27 +386,11 @@
393387 '_DiffOp_Copy' => 'includes/diff/DifferenceEngine.php',
394388 '_DiffOp_Delete' => 'includes/diff/DifferenceEngine.php',
395389 '_DiffOp' => 'includes/diff/DifferenceEngine.php',
396 - 'DomTreeBuilder' => 'includes/diff/HTMLDiff.php',
397 - 'DummyNode' => 'includes/diff/Nodes.php',
398 - 'HTMLDiffer' => 'includes/diff/HTMLDiff.php',
399 - 'HTMLOutput' => 'includes/diff/HTMLDiff.php',
400390 '_HWLDF_WordAccumulator' => 'includes/diff/DifferenceEngine.php',
401 - 'ImageNode' => 'includes/diff/Nodes.php',
402 - 'LastCommonParentResult' => 'includes/diff/HTMLDiff.php',
403391 'MappedDiff' => 'includes/diff/DifferenceEngine.php',
404 - 'Modification' => 'includes/diff/HTMLDiff.php',
405 - 'NoContentTagToString' => 'includes/diff/HTMLDiff.php',
406 - 'Node' => 'includes/diff/Nodes.php',
407392 'RangeDifference' => 'includes/diff/Diff.php',
408393 'TableDiffFormatter' => 'includes/diff/DifferenceEngine.php',
409 - 'TagNode' => 'includes/diff/Nodes.php',
410 - 'TagToString' => 'includes/diff/HTMLDiff.php',
411 - 'TagToStringFactory' => 'includes/diff/HTMLDiff.php',
412 - 'TextNode' => 'includes/diff/Nodes.php',
413 - 'TextNodeDiffer' => 'includes/diff/HTMLDiff.php',
414 - 'TextOnlyComparator' => 'includes/diff/HTMLDiff.php',
415394 'UnifiedDiffFormatter' => 'includes/diff/DifferenceEngine.php',
416 - 'WhiteSpaceNode' => 'includes/diff/Nodes.php',
417395 'WikiDiff3' => 'includes/diff/Diff.php',
418396 'WordLevelDiff' => 'includes/diff/DifferenceEngine.php',
419397
Index: trunk/phase3/includes/DefaultSettings.php
@@ -2892,9 +2892,6 @@
28932893 /** Name of the external diff engine to use */
28942894 $wgExternalDiffEngine = false;
28952895
2896 -/** Whether to use inline diff */
2897 -$wgEnableHtmlDiff = false;
2898 -
28992896 /** Use RC Patrolling to check for vandalism */
29002897 $wgUseRCPatrol = true;
29012898
Index: trunk/phase3/includes/diff/Nodes.php
@@ -1,439 +0,0 @@
2 -<?php
3 -
4 -/** Copyright (C) 2008 Guy Van den Broeck <guy@guyvdb.eu>
5 - *
6 - * This program is free software; you can redistribute it and/or modify
7 - * it under the terms of the GNU General Public License as published by
8 - * the Free Software Foundation; either version 2 of the License, or
9 - * (at your option) any later version.
10 - *
11 - * This program is distributed in the hope that it will be useful,
12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 - * GNU General Public License for more details.
15 - *
16 - * You should have received a copy of the GNU General Public License
17 - * along with this program; if not, write to the Free Software
18 - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 - * or see http://www.gnu.org/
20 - *
21 - */
22 -
23 -/**
24 - * Any element in the DOM tree of an HTML document.
25 - * @ingroup DifferenceEngine
26 - */
27 -class Node {
28 -
29 - public $parent;
30 -
31 - protected $parentTree;
32 -
33 - public $whiteBefore = false;
34 -
35 - public $whiteAfter = false;
36 -
37 - function __construct($parent) {
38 - $this->parent = $parent;
39 - }
40 -
41 - public function getParentTree() {
42 - if (!isset($this->parentTree)) {
43 - if (!is_null($this->parent)) {
44 - $this->parentTree = $this->parent->getParentTree();
45 - $this->parentTree[] = $this->parent;
46 - } else {
47 - $this->parentTree = array();
48 - }
49 - }
50 - return $this->parentTree;
51 - }
52 -
53 - public function getLastCommonParent(Node $other) {
54 - $result = new LastCommonParentResult();
55 -
56 - $myParents = $this->getParentTree();
57 - $otherParents = $other->getParentTree();
58 -
59 - $i = 1;
60 - $isSame = true;
61 - $nbMyParents = count($myParents);
62 - $nbOtherParents = count($otherParents);
63 - while ($isSame && $i < $nbMyParents && $i < $nbOtherParents) {
64 - if (!$myParents[$i]->openingTag === $otherParents[$i]->openingTag) {
65 - $isSame = false;
66 - } else {
67 - // After a while, the index i-1 must be the last common parent
68 - $i++;
69 - }
70 - }
71 -
72 - $result->lastCommonParentDepth = $i - 1;
73 - $result->parent = $myParents[$i - 1];
74 -
75 - if (!$isSame || $nbMyParents > $nbOtherParents) {
76 - // Not all tags matched, or all tags matched but
77 - // there are tags left in this tree
78 - $result->indexInLastCommonParent = $myParents[$i - 1]->getIndexOf($myParents[$i]);
79 - $result->splittingNeeded = true;
80 - } else if ($nbMyParents <= $nbOtherParents) {
81 - $result->indexInLastCommonParent = $myParents[$i - 1]->getIndexOf($this);
82 - }
83 - return $result;
84 - }
85 -
86 - public function setParent($parent) {
87 - $this->parent = $parent;
88 - unset($this->parentTree);
89 - }
90 -
91 - public function inPre() {
92 - $tree = $this->getParentTree();
93 - foreach ($tree as &$ancestor) {
94 - if ($ancestor->isPre()) {
95 - return true;
96 - }
97 - }
98 - return false;
99 - }
100 -}
101 -
102 -/**
103 - * Node that can contain other nodes. Represents an HTML tag.
104 - * @ingroup DifferenceEngine
105 - */
106 -class TagNode extends Node {
107 -
108 - public $children = array();
109 -
110 - public $qName;
111 -
112 - public $attributes = array();
113 -
114 - public $openingTag;
115 -
116 - function __construct($parent, $qName, /*array*/ $attributes) {
117 - parent::__construct($parent);
118 - $this->qName = strtolower($qName);
119 - foreach($attributes as $key => &$value){
120 - $this->attributes[strtolower($key)] = $value;
121 - }
122 - return $this->openingTag = Xml::openElement($this->qName, $this->attributes);
123 - }
124 -
125 - public function addChildAbsolute(Node $node, $index) {
126 - array_splice($this->children, $index, 0, array($node));
127 - }
128 -
129 - public function getIndexOf(Node $child) {
130 - // don't trust array_search with objects
131 - foreach ($this->children as $key => &$value){
132 - if ($value === $child) {
133 - return $key;
134 - }
135 - }
136 - return null;
137 - }
138 -
139 - public function getNbChildren() {
140 - return count($this->children);
141 - }
142 -
143 - public function getMinimalDeletedSet($id, &$allDeleted, &$somethingDeleted) {
144 - $nodes = array();
145 -
146 - $allDeleted = false;
147 - $somethingDeleted = false;
148 - $hasNonDeletedDescendant = false;
149 -
150 - if (empty($this->children)) {
151 - return $nodes;
152 - }
153 -
154 - foreach ($this->children as &$child) {
155 - $allDeleted_local = false;
156 - $somethingDeleted_local = false;
157 - $childrenChildren = $child->getMinimalDeletedSet($id, $allDeleted_local, $somethingDeleted_local);
158 - if ($somethingDeleted_local) {
159 - $nodes = array_merge($nodes, $childrenChildren);
160 - $somethingDeleted = true;
161 - }
162 - if (!$allDeleted_local) {
163 - $hasNonDeletedDescendant = true;
164 - }
165 - }
166 - if (!$hasNonDeletedDescendant) {
167 - $nodes = array($this);
168 - $allDeleted = true;
169 - }
170 - return $nodes;
171 - }
172 -
173 - public function splitUntil(TagNode $parent, Node $split, $includeLeft) {
174 - $splitOccured = false;
175 - if ($parent !== $this) {
176 - $part1 = new TagNode(null, $this->qName, $this->attributes);
177 - $part2 = new TagNode(null, $this->qName, $this->attributes);
178 - $part1->setParent($this->parent);
179 - $part2->setParent($this->parent);
180 -
181 - $onSplit = false;
182 - $pastSplit = false;
183 - foreach ($this->children as &$child)
184 - {
185 - if ($child === $split) {
186 - $onSplit = true;
187 - }
188 - if(!$pastSplit || ($onSplit && $includeLeft)) {
189 - $child->setParent($part1);
190 - $part1->children[] = $child;
191 - } else {
192 - $child->setParent($part2);
193 - $part2->children[] = $child;
194 - }
195 - if ($onSplit) {
196 - $onSplit = false;
197 - $pastSplit = true;
198 - }
199 - }
200 - $myindexinparent = $this->parent->getIndexOf($this);
201 - if (!empty($part1->children)) {
202 - $this->parent->addChildAbsolute($part1, $myindexinparent);
203 - }
204 - if (!empty($part2->children)) {
205 - $this->parent->addChildAbsolute($part2, $myindexinparent);
206 - }
207 - if (!empty($part1->children) && !empty($part2->children)) {
208 - $splitOccured = true;
209 - }
210 -
211 - $this->parent->removeChild($myindexinparent);
212 -
213 - if ($includeLeft) {
214 - $this->parent->splitUntil($parent, $part1, $includeLeft);
215 - } else {
216 - $this->parent->splitUntil($parent, $part2, $includeLeft);
217 - }
218 - }
219 - return $splitOccured;
220 -
221 - }
222 -
223 - private function removeChild($index) {
224 - unset($this->children[$index]);
225 - $this->children = array_values($this->children);
226 - }
227 -
228 - public static $blocks = array('html', 'body','p','blockquote', 'h1',
229 - 'h2', 'h3', 'h4', 'h5', 'pre', 'div', 'ul', 'ol', 'li', 'table',
230 - 'tbody', 'tr', 'td', 'th', 'br');
231 -
232 - public function copyTree() {
233 - $newThis = new TagNode(null, $this->qName, $this->attributes);
234 - $newThis->whiteBefore = $this->whiteBefore;
235 - $newThis->whiteAfter = $this->whiteAfter;
236 - foreach ($this->children as &$child) {
237 - $newChild = $child->copyTree();
238 - $newChild->setParent($newThis);
239 - $newThis->children[] = $newChild;
240 - }
241 - return $newThis;
242 - }
243 -
244 - public function getMatchRatio(TagNode $other) {
245 - $txtComp = new TextOnlyComparator($other);
246 - return $txtComp->getMatchRatio(new TextOnlyComparator($this));
247 - }
248 -
249 - public function expandWhiteSpace() {
250 - $shift = 0;
251 - $spaceAdded = false;
252 -
253 - $nbOriginalChildren = $this->getNbChildren();
254 - for ($i = 0; $i < $nbOriginalChildren; ++$i) {
255 - $child = $this->children[$i + $shift];
256 -
257 - if ($child instanceof TagNode) {
258 - if (!$child->isPre()) {
259 - $child->expandWhiteSpace();
260 - }
261 - }
262 - if (!$spaceAdded && $child->whiteBefore) {
263 - $ws = new WhiteSpaceNode(null, ' ', $child->getLeftMostChild());
264 - $ws->setParent($this);
265 - $this->addChildAbsolute($ws,$i + ($shift++));
266 - }
267 - if ($child->whiteAfter) {
268 - $ws = new WhiteSpaceNode(null, ' ', $child->getRightMostChild());
269 - $ws->setParent($this);
270 - $this->addChildAbsolute($ws,$i + 1 + ($shift++));
271 - $spaceAdded = true;
272 - } else {
273 - $spaceAdded = false;
274 - }
275 -
276 - }
277 - }
278 -
279 - public function getLeftMostChild() {
280 - if (empty($this->children)) {
281 - return $this;
282 - }
283 - return $this->children[0]->getLeftMostChild();
284 - }
285 -
286 - public function getRightMostChild() {
287 - if (empty($this->children)) {
288 - return $this;
289 - }
290 - return $this->children[$this->getNbChildren() - 1]->getRightMostChild();
291 - }
292 -
293 - public function isPre() {
294 - return 0 == strcasecmp($this->qName,'pre');
295 - }
296 -
297 - public static function toDiffLine(TagNode $node) {
298 - return $node->openingTag;
299 - }
300 -}
301 -
302 -/**
303 - * Represents a piece of text in the HTML file.
304 - * @ingroup DifferenceEngine
305 - */
306 -class TextNode extends Node {
307 -
308 - public $text;
309 -
310 - public $modification;
311 -
312 - function __construct($parent, $text) {
313 - parent::__construct($parent);
314 - $this->modification = new Modification(Modification::NONE);
315 - $this->text = $text;
316 - }
317 -
318 - public function copyTree() {
319 - $clone = clone $this;
320 - $clone->setParent(null);
321 - return $clone;
322 - }
323 -
324 - public function getLeftMostChild() {
325 - return $this;
326 - }
327 -
328 - public function getRightMostChild() {
329 - return $this;
330 - }
331 -
332 - public function getMinimalDeletedSet($id, &$allDeleted, &$somethingDeleted) {
333 - if ($this->modification->type == Modification::REMOVED
334 - && $this->modification->id == $id){
335 - $somethingDeleted = true;
336 - $allDeleted = true;
337 - return array($this);
338 - }
339 - return array();
340 - }
341 -
342 - public function isSameText($other) {
343 - if (is_null($other) || ! $other instanceof TextNode) {
344 - return false;
345 - }
346 - return str_replace('\n', ' ',$this->text) === str_replace('\n', ' ',$other->text);
347 - }
348 -
349 - public static function toDiffLine(TextNode $node) {
350 - return str_replace('\n', ' ',$node->text);
351 - }
352 -}
353 -
354 -/**
355 - * @todo Document
356 - * @ingroup DifferenceEngine
357 - */
358 -class WhiteSpaceNode extends TextNode {
359 -
360 - function __construct($parent, $s, Node $like = null) {
361 - parent::__construct($parent, $s);
362 - if(!is_null($like) && $like instanceof TextNode) {
363 - $newModification = clone $like->modification;
364 - $newModification->firstOfID = false;
365 - $this->modification = $newModification;
366 - }
367 - }
368 -}
369 -
370 -/**
371 - * Represents the root of a HTML document.
372 - * @ingroup DifferenceEngine
373 - */
374 -class BodyNode extends TagNode {
375 -
376 - function __construct() {
377 - parent::__construct(null, 'body', array());
378 - }
379 -
380 - public function copyTree() {
381 - $newThis = new BodyNode();
382 - foreach ($this->children as &$child) {
383 - $newChild = $child->copyTree();
384 - $newChild->setParent($newThis);
385 - $newThis->children[] = $newChild;
386 - }
387 - return $newThis;
388 - }
389 -
390 - public function getMinimalDeletedSet($id, &$allDeleted, &$somethingDeleted) {
391 - $nodes = array();
392 - foreach ($this->children as &$child) {
393 - $childrenChildren = $child->getMinimalDeletedSet($id,
394 - $allDeleted, $somethingDeleted);
395 - $nodes = array_merge($nodes, $childrenChildren);
396 - }
397 - return $nodes;
398 - }
399 -
400 -}
401 -
402 -/**
403 - * Represents an image in HTML. Even though images do not contain any text they
404 - * are independent visible objects on the page. They are logically a TextNode.
405 - * @ingroup DifferenceEngine
406 - */
407 -class ImageNode extends TextNode {
408 -
409 - public $attributes;
410 -
411 - function __construct(TagNode $parent, /*array*/ $attrs) {
412 - if(!array_key_exists('src', $attrs)) {
413 - HTMLDiffer::diffDebug( "Image without a source\n" );
414 - parent::__construct($parent, '<img></img>');
415 - }else{
416 - parent::__construct($parent, '<img>' . strtolower($attrs['src']) . '</img>');
417 - }
418 - $this->attributes = $attrs;
419 - }
420 -
421 - public function isSameText($other) {
422 - if (is_null($other) || ! $other instanceof ImageNode) {
423 - return false;
424 - }
425 - return $this->text === $other->text;
426 - }
427 -
428 -}
429 -
430 -/**
431 - * No-op node
432 - * @ingroup DifferenceEngine
433 - */
434 -class DummyNode extends Node {
435 -
436 - function __construct() {
437 - // no op
438 - }
439 -
440 -}
Index: trunk/phase3/includes/diff/HTMLDiff.php
@@ -1,1009 +0,0 @@
2 -<?php
3 -
4 -/** Copyright (C) 2008 Guy Van den Broeck <guy@guyvdb.eu>
5 - *
6 - * This program is free software; you can redistribute it and/or modify
7 - * it under the terms of the GNU General Public License as published by
8 - * the Free Software Foundation; either version 2 of the License, or
9 - * (at your option) any later version.
10 - *
11 - * This program is distributed in the hope that it will be useful,
12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 - * GNU General Public License for more details.
15 - *
16 - * You should have received a copy of the GNU General Public License
17 - * along with this program; if not, write to the Free Software
18 - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 - * or see http://www.gnu.org/
20 - *
21 - * @ingroup DifferenceEngine
22 - */
23 -
24 -/**
25 - * When detecting the last common parent of two nodes, all results are stored as
26 - * a LastCommonParentResult.
27 - */
28 -class LastCommonParentResult {
29 -
30 - // Parent
31 - public $parent;
32 -
33 - // Splitting
34 - public $splittingNeeded = false;
35 -
36 - // Depth
37 - public $lastCommonParentDepth = -1;
38 -
39 - // Index
40 - public $indexInLastCommonParent = -1;
41 -}
42 -
43 -class Modification{
44 -
45 - const NONE = 1;
46 - const REMOVED = 2;
47 - const ADDED = 4;
48 - const CHANGED = 8;
49 -
50 - public $type;
51 -
52 - public $id = -1;
53 -
54 - public $firstOfID = false;
55 -
56 - public $changes;
57 -
58 - function __construct($type) {
59 - $this->type = $type;
60 - }
61 -
62 - public static function typeToString($type) {
63 - switch($type) {
64 - case self::NONE: return 'none';
65 - case self::REMOVED: return 'removed';
66 - case self::ADDED: return 'added';
67 - case self::CHANGED: return 'changed';
68 - }
69 - }
70 -}
71 -
72 -class DomTreeBuilder {
73 -
74 - public $textNodes = array();
75 -
76 - public $bodyNode;
77 -
78 - private $currentParent;
79 -
80 - private $newWord = '';
81 -
82 - protected $bodyStarted = false;
83 -
84 - protected $bodyEnded = false;
85 -
86 - private $whiteSpaceBeforeThis = false;
87 -
88 - private $lastSibling;
89 -
90 - private $notInPre = true;
91 -
92 - function __construct() {
93 - $this->bodyNode = $this->currentParent = new BodyNode();
94 - $this->lastSibling = new DummyNode();
95 - }
96 -
97 - /**
98 - * Must be called manually
99 - */
100 - public function endDocument() {
101 - $this->endWord();
102 - HTMLDiffer::diffDebug( count($this->textNodes) . " text nodes in document.\n" );
103 - }
104 -
105 - public function startElement($parser, $name, /*array*/ $attributes) {
106 - if (strcasecmp($name, 'body') != 0) {
107 - HTMLDiffer::diffDebug( "Starting $name node.\n" );
108 - $this->endWord();
109 -
110 - $newNode = new TagNode($this->currentParent, $name, $attributes);
111 - $this->currentParent->children[] = $newNode;
112 - $this->currentParent = $newNode;
113 - $this->lastSibling = new DummyNode();
114 - if ($this->whiteSpaceBeforeThis && !in_array(strtolower($this->currentParent->qName),TagNode::$blocks)) {
115 - $this->currentParent->whiteBefore = true;
116 - }
117 - $this->whiteSpaceBeforeThis = false;
118 - if(strcasecmp($name, 'pre') == 0) {
119 - $this->notInPre = false;
120 - }
121 - }
122 - }
123 -
124 - public function endElement($parser, $name) {
125 - if(strcasecmp($name, 'body') != 0) {
126 - HTMLDiffer::diffDebug( "Ending $name node.\n");
127 - if (0 == strcasecmp($name,'img')) {
128 - // Insert a dummy leaf for the image
129 - $img = new ImageNode($this->currentParent, $this->currentParent->attributes);
130 - $this->currentParent->children[] = $img;
131 - $img->whiteBefore = $this->whiteSpaceBeforeThis;
132 - $this->lastSibling = $img;
133 - $this->textNodes[] = $img;
134 - }
135 - $this->endWord();
136 - if (!in_array(strtolower($this->currentParent->qName),TagNode::$blocks)) {
137 - $this->lastSibling = $this->currentParent;
138 - } else {
139 - $this->lastSibling = new DummyNode();
140 - }
141 - $this->currentParent = $this->currentParent->parent;
142 - $this->whiteSpaceBeforeThis = false;
143 - if (!$this->notInPre && strcasecmp($name, 'pre') == 0) {
144 - $this->notInPre = true;
145 - }
146 - } else {
147 - $this->endDocument();
148 - }
149 - }
150 -
151 - const regex = '/([\s\.\,\"\\\'\(\)\?\:\;\!\{\}\-\+\*\=\_\[\]\&\|\$]{1})/';
152 - const whitespace = '/^[\s]{1}$/';
153 - const delimiter = '/^[\s\.\,\"\\\'\(\)\?\:\;\!\{\}\-\+\*\=\_\[\]\&\|\$]{1}$/';
154 -
155 - public function characters($parser, $data) {
156 - $matches = preg_split(self::regex, $data, -1, PREG_SPLIT_DELIM_CAPTURE);
157 -
158 - foreach($matches as &$word) {
159 - if (preg_match(self::whitespace, $word) && $this->notInPre) {
160 - $this->endWord();
161 - $this->lastSibling->whiteAfter = true;
162 - $this->whiteSpaceBeforeThis = true;
163 - } else if (preg_match(self::delimiter, $word)) {
164 - $this->endWord();
165 - $textNode = new TextNode($this->currentParent, $word);
166 - $this->currentParent->children[] = $textNode;
167 - $textNode->whiteBefore = $this->whiteSpaceBeforeThis;
168 - $this->whiteSpaceBeforeThis = false;
169 - $this->lastSibling = $textNode;
170 - $this->textNodes[] = $textNode;
171 - } else {
172 - $this->newWord .= $word;
173 - }
174 - }
175 - }
176 -
177 - private function endWord() {
178 - if ($this->newWord !== '') {
179 - $node = new TextNode($this->currentParent, $this->newWord);
180 - $this->currentParent->children[] = $node;
181 - $node->whiteBefore = $this->whiteSpaceBeforeThis;
182 - $this->whiteSpaceBeforeThis = false;
183 - $this->lastSibling = $node;
184 - $this->textNodes[] = $node;
185 - $this->newWord = "";
186 - }
187 - }
188 -
189 - public function getDiffLines() {
190 - return array_map(array('TextNode','toDiffLine'), $this->textNodes);
191 - }
192 -}
193 -
194 -class TextNodeDiffer {
195 -
196 - private $textNodes;
197 - public $bodyNode;
198 -
199 - private $oldTextNodes;
200 - private $oldBodyNode;
201 -
202 - private $newID = 0;
203 -
204 - private $changedID = 0;
205 -
206 - private $changedIDUsed = false;
207 -
208 - // used to remove the whitespace between a red and green block
209 - private $whiteAfterLastChangedPart = false;
210 -
211 - private $deletedID = 0;
212 -
213 - function __construct(DomTreeBuilder $tree, DomTreeBuilder $oldTree) {
214 - $this->textNodes = $tree->textNodes;
215 - $this->bodyNode = $tree->bodyNode;
216 - $this->oldTextNodes = $oldTree->textNodes;
217 - $this->oldBodyNode = $oldTree->bodyNode;
218 - }
219 -
220 - public function markAsNew($start, $end) {
221 - if ($end <= $start) {
222 - return;
223 - }
224 -
225 - if ($this->whiteAfterLastChangedPart) {
226 - $this->textNodes[$start]->whiteBefore = false;
227 - }
228 -
229 - for ($i = $start; $i < $end; ++$i) {
230 - $mod = new Modification(Modification::ADDED);
231 - $mod->id = $this->newID;
232 - $this->textNodes[$i]->modification = $mod;
233 - }
234 - if ($start < $end) {
235 - $this->textNodes[$start]->modification->firstOfID = true;
236 - }
237 - ++$this->newID;
238 - }
239 -
240 - public function handlePossibleChangedPart($leftstart, $leftend, $rightstart, $rightend) {
241 - $i = $rightstart;
242 - $j = $leftstart;
243 -
244 - if ($this->changedIDUsed) {
245 - ++$this->changedID;
246 - $this->changedIDUsed = false;
247 - }
248 -
249 - $changes;
250 - while ($i < $rightend) {
251 - $acthis = new AncestorComparator($this->textNodes[$i]->getParentTree());
252 - $acother = new AncestorComparator($this->oldTextNodes[$j]->getParentTree());
253 - $result = $acthis->getResult($acother);
254 - unset($acthis, $acother);
255 -
256 - if ( $result ) {
257 - $mod = new Modification(Modification::CHANGED);
258 -
259 - if (!$this->changedIDUsed) {
260 - $mod->firstOfID = true;
261 - } else if (!is_null( $result ) && $result !== $this->changes) {
262 - ++$this->changedID;
263 - $mod->firstOfID = true;
264 - }
265 -
266 - $mod->changes = $result;
267 - $mod->id = $this->changedID;
268 -
269 - $this->textNodes[$i]->modification = $mod;
270 - $this->changes = $result;
271 - $this->changedIDUsed = true;
272 - } else if ($this->changedIDUsed) {
273 - ++$this->changedID;
274 - $this->changedIDUsed = false;
275 - }
276 - ++$i;
277 - ++$j;
278 - }
279 - }
280 -
281 - public function markAsDeleted($start, $end, $before) {
282 -
283 - if ($end <= $start) {
284 - return;
285 - }
286 -
287 - if ($before > 0 && $this->textNodes[$before - 1]->whiteAfter) {
288 - $this->whiteAfterLastChangedPart = true;
289 - } else {
290 - $this->whiteAfterLastChangedPart = false;
291 - }
292 -
293 - for ($i = $start; $i < $end; ++$i) {
294 - $mod = new Modification(Modification::REMOVED);
295 - $mod->id = $this->deletedID;
296 -
297 - // oldTextNodes is used here because we're going to move its deleted
298 - // elements to this tree!
299 - $this->oldTextNodes[$i]->modification = $mod;
300 - }
301 - $this->oldTextNodes[$start]->modification->firstOfID = true;
302 -
303 - $root = $this->oldTextNodes[$start]->getLastCommonParent($this->oldTextNodes[$end-1])->parent;
304 -
305 - $junk1 = $junk2 = null;
306 - $deletedNodes = $root->getMinimalDeletedSet($this->deletedID, $junk1, $junk2);
307 -
308 - HTMLDiffer::diffDebug( "Minimal set of deleted nodes of size " . count($deletedNodes) . "\n" );
309 -
310 - // Set prevLeaf to the leaf after which the old HTML needs to be
311 - // inserted
312 - if ($before > 0) {
313 - $prevLeaf = $this->textNodes[$before - 1];
314 - }
315 - // Set nextLeaf to the leaf before which the old HTML needs to be
316 - // inserted
317 - if ($before < count($this->textNodes)) {
318 - $nextLeaf = $this->textNodes[$before];
319 - }
320 -
321 - while (count($deletedNodes) > 0) {
322 - if (isset($prevLeaf)) {
323 - $prevResult = $prevLeaf->getLastCommonParent($deletedNodes[0]);
324 - } else {
325 - $prevResult = new LastCommonParentResult();
326 - $prevResult->parent = $this->bodyNode;
327 - $prevResult->indexInLastCommonParent = -1;
328 - }
329 - if (isset($nextleaf)) {
330 - $nextResult = $nextLeaf->getLastCommonParent($deletedNodes[count($deletedNodes) - 1]);
331 - } else {
332 - $nextResult = new LastCommonParentResult();
333 - $nextResult->parent = $this->bodyNode;
334 - $nextResult->indexInLastCommonParent = $this->bodyNode->getNbChildren();
335 - }
336 -
337 - if ($prevResult->lastCommonParentDepth == $nextResult->lastCommonParentDepth) {
338 - // We need some metric to choose which way to add-...
339 - if ($deletedNodes[0]->parent === $deletedNodes[count($deletedNodes) - 1]->parent
340 - && $prevResult->parent === $nextResult->parent) {
341 - // The difference is not in the parent
342 - $prevResult->lastCommonParentDepth = $prevResult->lastCommonParentDepth + 1;
343 - } else {
344 - // The difference is in the parent, so compare them
345 - // now THIS is tricky
346 - $distancePrev = $deletedNodes[0]->parent->getMatchRatio($prevResult->parent);
347 - $distanceNext = $deletedNodes[count($deletedNodes) - 1]->parent->getMatchRatio($nextResult->parent);
348 -
349 - if ($distancePrev <= $distanceNext) {
350 - $prevResult->lastCommonParentDepth = $prevResult->lastCommonParentDepth + 1;
351 - } else {
352 - $nextResult->lastCommonParentDepth = $nextResult->lastCommonParentDepth + 1;
353 - }
354 - }
355 -
356 - }
357 -
358 - if ($prevResult->lastCommonParentDepth > $nextResult->lastCommonParentDepth) {
359 - // Inserting at the front
360 - if ($prevResult->splittingNeeded) {
361 - $prevLeaf->parent->splitUntil($prevResult->parent, $prevLeaf, true);
362 - }
363 - $prevLeaf = $deletedNodes[0]->copyTree();
364 - unset($deletedNodes[0]);
365 - $deletedNodes = array_values($deletedNodes);
366 - $prevLeaf->setParent($prevResult->parent);
367 - $prevResult->parent->addChildAbsolute($prevLeaf,$prevResult->indexInLastCommonParent + 1);
368 - } else if ($prevResult->lastCommonParentDepth < $nextResult->lastCommonParentDepth) {
369 - // Inserting at the back
370 - if ($nextResult->splittingNeeded) {
371 - $splitOccured = $nextLeaf->parent->splitUntil($nextResult->parent, $nextLeaf, false);
372 - if ($splitOccured) {
373 - // The place where to insert is shifted one place to the
374 - // right
375 - $nextResult->indexInLastCommonParent = $nextResult->indexInLastCommonParent + 1;
376 - }
377 - }
378 - $nextLeaf = $deletedNodes[count(deletedNodes) - 1]->copyTree();
379 - unset($deletedNodes[count(deletedNodes) - 1]);
380 - $deletedNodes = array_values($deletedNodes);
381 - $nextLeaf->setParent($nextResult->parent);
382 - $nextResult->parent->addChildAbsolute($nextLeaf,$nextResult->indexInLastCommonParent);
383 - }
384 - }
385 - ++$this->deletedID;
386 - }
387 -
388 - public function expandWhiteSpace() {
389 - $this->bodyNode->expandWhiteSpace();
390 - }
391 -
392 - public function lengthNew(){
393 - return count($this->textNodes);
394 - }
395 -
396 - public function lengthOld(){
397 - return count($this->oldTextNodes);
398 - }
399 -}
400 -
401 -class HTMLDiffer {
402 -
403 - private $output;
404 - private static $debug = '';
405 -
406 - function __construct($output) {
407 - $this->output = $output;
408 - }
409 -
410 - function htmlDiff($from, $to) {
411 - wfProfileIn( __METHOD__ );
412 - // Create an XML parser
413 - $xml_parser = xml_parser_create('');
414 -
415 - $domfrom = new DomTreeBuilder();
416 -
417 - // Set the functions to handle opening and closing tags
418 - xml_set_element_handler($xml_parser, array($domfrom, "startElement"), array($domfrom, "endElement"));
419 -
420 - // Set the function to handle blocks of character data
421 - xml_set_character_data_handler($xml_parser, array($domfrom, "characters"));
422 -
423 - HTMLDiffer::diffDebug( "Parsing " . strlen($from) . " characters worth of HTML\n" );
424 - if (!xml_parse($xml_parser, '<?xml version="1.0" encoding="UTF-8"?>'.Sanitizer::hackDocType().'<body>', false)
425 - || !xml_parse($xml_parser, $from, false)
426 - || !xml_parse($xml_parser, '</body>', true)){
427 - $error = xml_error_string(xml_get_error_code($xml_parser));
428 - $line = xml_get_current_line_number($xml_parser);
429 - HTMLDiffer::diffDebug( "XML error: $error at line $line\n" );
430 - }
431 - xml_parser_free($xml_parser);
432 - unset($from);
433 -
434 - $xml_parser = xml_parser_create('');
435 -
436 - $domto = new DomTreeBuilder();
437 -
438 - // Set the functions to handle opening and closing tags
439 - xml_set_element_handler($xml_parser, array($domto, "startElement"), array($domto, "endElement"));
440 -
441 - // Set the function to handle blocks of character data
442 - xml_set_character_data_handler($xml_parser, array($domto, "characters"));
443 -
444 - HTMLDiffer::diffDebug( "Parsing " . strlen($to) . " characters worth of HTML\n" );
445 - if (!xml_parse($xml_parser, '<?xml version="1.0" encoding="UTF-8"?>'.Sanitizer::hackDocType().'<body>', false)
446 - || !xml_parse($xml_parser, $to, false)
447 - || !xml_parse($xml_parser, '</body>', true)){
448 - $error = xml_error_string(xml_get_error_code($xml_parser));
449 - $line = xml_get_current_line_number($xml_parser);
450 - HTMLDiffer::diffDebug( "XML error: $error at line $line\n" );
451 - }
452 - xml_parser_free($xml_parser);
453 - unset($to);
454 -
455 - $diffengine = new WikiDiff3();
456 - $differences = $this->preProcess($diffengine->diff_range($domfrom->getDiffLines(), $domto->getDiffLines()));
457 - unset($xml_parser, $diffengine);
458 -
459 - $domdiffer = new TextNodeDiffer($domto, $domfrom);
460 -
461 - $currentIndexLeft = 0;
462 - $currentIndexRight = 0;
463 - foreach ($differences as &$d) {
464 - if ($d->leftstart > $currentIndexLeft) {
465 - $domdiffer->handlePossibleChangedPart($currentIndexLeft, $d->leftstart,
466 - $currentIndexRight, $d->rightstart);
467 - }
468 - if ($d->leftlength > 0) {
469 - $domdiffer->markAsDeleted($d->leftstart, $d->leftend, $d->rightstart);
470 - }
471 - $domdiffer->markAsNew($d->rightstart, $d->rightend);
472 -
473 - $currentIndexLeft = $d->leftend;
474 - $currentIndexRight = $d->rightend;
475 - }
476 - $oldLength = $domdiffer->lengthOld();
477 - if ($currentIndexLeft < $oldLength) {
478 - $domdiffer->handlePossibleChangedPart($currentIndexLeft, $oldLength, $currentIndexRight, $domdiffer->lengthNew());
479 - }
480 - $domdiffer->expandWhiteSpace();
481 - $output = new HTMLOutput('htmldiff', $this->output);
482 - $output->parse($domdiffer->bodyNode);
483 - wfProfileOut( __METHOD__ );
484 - }
485 -
486 - private function preProcess(/*array*/ $differences) {
487 - $newRanges = array();
488 -
489 - $nbDifferences = count($differences);
490 - for ($i = 0; $i < $nbDifferences; ++$i) {
491 - $leftStart = $differences[$i]->leftstart;
492 - $leftEnd = $differences[$i]->leftend;
493 - $rightStart = $differences[$i]->rightstart;
494 - $rightEnd = $differences[$i]->rightend;
495 -
496 - $leftLength = $leftEnd - $leftStart;
497 - $rightLength = $rightEnd - $rightStart;
498 -
499 - while ($i + 1 < $nbDifferences && self::score($leftLength,
500 - $differences[$i + 1]->leftlength,
501 - $rightLength,
502 - $differences[$i + 1]->rightlength)
503 - > ($differences[$i + 1]->leftstart - $leftEnd)) {
504 - $leftEnd = $differences[$i + 1]->leftend;
505 - $rightEnd = $differences[$i + 1]->rightend;
506 - $leftLength = $leftEnd - $leftStart;
507 - $rightLength = $rightEnd - $rightStart;
508 - ++$i;
509 - }
510 - $newRanges[] = new RangeDifference($leftStart, $leftEnd, $rightStart, $rightEnd);
511 - }
512 - return $newRanges;
513 - }
514 -
515 - /**
516 - * Heuristic to merge differences for readability.
517 - */
518 - public static function score($ll, $nll, $rl, $nrl) {
519 - if (($ll == 0 && $nll == 0)
520 - || ($rl == 0 && $nrl == 0)) {
521 - return 0;
522 - }
523 - $numbers = array($ll, $nll, $rl, $nrl);
524 - $d = 0;
525 - foreach ($numbers as &$number) {
526 - while ($number > 3) {
527 - $d += 3;
528 - $number -= 3;
529 - $number *= 0.5;
530 - }
531 - $d += $number;
532 -
533 - }
534 - return $d / (1.5 * count($numbers));
535 - }
536 -
537 - /**
538 - * Add to debug output
539 - * @param string $str Debug output
540 - */
541 - public static function diffDebug( $str ) {
542 - self :: $debug .= $str;
543 - }
544 -
545 - /**
546 - * Get debug output
547 - * @return string
548 - */
549 - public static function getDebugOutput() {
550 - return self :: $debug;
551 - }
552 -
553 -}
554 -
555 -class TextOnlyComparator {
556 -
557 - public $leafs = array();
558 -
559 - function _construct(TagNode $tree) {
560 - $this->addRecursive($tree);
561 - $this->leafs = array_map(array('TextNode','toDiffLine'), $this->leafs);
562 - }
563 -
564 - private function addRecursive(TagNode $tree) {
565 - foreach ($tree->children as &$child) {
566 - if ($child instanceof TagNode) {
567 - $this->addRecursive($child);
568 - } else if ($child instanceof TextNode) {
569 - $this->leafs[] = $node;
570 - }
571 - }
572 - }
573 -
574 - public function getMatchRatio(TextOnlyComparator $other) {
575 - $nbOthers = count($other->leafs);
576 - $nbThis = count($this->leafs);
577 - if($nbOthers == 0 || $nbThis == 0){
578 - return -log(0);
579 - }
580 -
581 - $diffengine = new WikiDiff3(25000, 1.35);
582 - $diffengine->diff($this->leafs, $other->leafs);
583 -
584 - $lcsLength = $diffengine->getLcsLength();
585 -
586 - $distanceThis = $nbThis-$lcsLength;
587 -
588 - return (2.0 - $lcsLength/$nbOthers - $lcsLength/$nbThis) / 2.0;
589 - }
590 -}
591 -
592 -/**
593 - * A comparator used when calculating the difference in ancestry of two Nodes.
594 - */
595 -class AncestorComparator {
596 -
597 - public $ancestors;
598 - public $ancestorsText;
599 -
600 - function __construct(/*array*/ $ancestors) {
601 - $this->ancestors = $ancestors;
602 - $this->ancestorsText = array_map(array('TagNode','toDiffLine'), $ancestors);
603 - }
604 -
605 - public $compareTxt = "";
606 -
607 - public function getResult(AncestorComparator $other) {
608 -
609 - $diffengine = new WikiDiff3(10000, 1.35);
610 - $differences = $diffengine->diff_range($other->ancestorsText,$this->ancestorsText);
611 -
612 - if (count($differences) == 0){
613 - return null;
614 - }
615 - $changeTxt = new ChangeTextGenerator($this, $other);
616 -
617 - return $changeTxt->getChanged($differences)->toString();;
618 - }
619 -}
620 -
621 -class ChangeTextGenerator {
622 -
623 - private $ancestorComparator;
624 - private $other;
625 -
626 - private $factory;
627 -
628 - function __construct(AncestorComparator $ancestorComparator, AncestorComparator $other) {
629 - $this->ancestorComparator = $ancestorComparator;
630 - $this->other = $other;
631 - $this->factory = new TagToStringFactory();
632 - }
633 -
634 - public function getChanged(/*array*/ $differences) {
635 - $txt = new ChangeText;
636 - $rootlistopened = false;
637 - if (count($differences) > 1) {
638 - $txt->addHtml('<ul class="changelist">');
639 - $rootlistopened = true;
640 - }
641 - $nbDifferences = count($differences);
642 - for ($j = 0; $j < $nbDifferences; ++$j) {
643 - $d = $differences[$j];
644 - $lvl1listopened = false;
645 - if ($rootlistopened) {
646 - $txt->addHtml('<li>');
647 - }
648 - if ($d->leftlength + $d->rightlength > 1) {
649 - $txt->addHtml('<ul class="changelist">');
650 - $lvl1listopened = true;
651 - }
652 - // left are the old ones
653 - for ($i = $d->leftstart; $i < $d->leftend; ++$i) {
654 - if ($lvl1listopened){
655 - $txt->addHtml('<li>');
656 - }
657 - // add a bullet for a old tag
658 - $this->addTagOld($txt, $this->other->ancestors[$i]);
659 - if ($lvl1listopened){
660 - $txt->addHtml('</li>');
661 - }
662 - }
663 - // right are the new ones
664 - for ($i = $d->rightstart; $i < $d->rightend; ++$i) {
665 - if ($lvl1listopened){
666 - $txt->addHtml('<li>');
667 - }
668 - // add a bullet for a new tag
669 - $this->addTagNew($txt, $this->ancestorComparator->ancestors[$i]);
670 -
671 - if ($lvl1listopened){
672 - $txt->addHtml('</li>');
673 - }
674 - }
675 - if ($lvl1listopened) {
676 - $txt->addHtml('</ul>');
677 - }
678 - if ($rootlistopened) {
679 - $txt->addHtml('</li>');
680 - }
681 - }
682 - if ($rootlistopened) {
683 - $txt->addHtml('</ul>');
684 - }
685 - return $txt;
686 - }
687 -
688 - private function addTagOld(ChangeText $txt, TagNode $ancestor) {
689 - $this->factory->create($ancestor)->getRemovedDescription($txt);
690 - }
691 -
692 - private function addTagNew(ChangeText $txt, TagNode $ancestor) {
693 - $this->factory->create($ancestor)->getAddedDescription($txt);
694 - }
695 -}
696 -
697 -class ChangeText {
698 -
699 - private $txt = "";
700 -
701 - public function addHtml($s) {
702 - $this->txt .= $s;
703 - }
704 -
705 - public function toString() {
706 - return $this->txt;
707 - }
708 -}
709 -
710 -class TagToStringFactory {
711 -
712 - private static $containerTags = array('html', 'body', 'p', 'blockquote',
713 - 'h1', 'h2', 'h3', 'h4', 'h5', 'pre', 'div', 'ul', 'ol', 'li',
714 - 'table', 'tbody', 'tr', 'td', 'th', 'br', 'hr', 'code', 'dl',
715 - 'dt', 'dd', 'input', 'form', 'img', 'span', 'a');
716 -
717 - private static $styleTags = array('i', 'b', 'strong', 'em', 'font',
718 - 'big', 'del', 'tt', 'sub', 'sup', 'strike');
719 -
720 - const MOVED = 1;
721 - const STYLE = 2;
722 - const UNKNOWN = 4;
723 -
724 - public function create(TagNode $node) {
725 - $sem = $this->getChangeSemantic($node->qName);
726 - if (strcasecmp($node->qName,'a') == 0) {
727 - return new AnchorToString($node, $sem);
728 - }
729 - if (strcasecmp($node->qName,'img') == 0) {
730 - return new NoContentTagToString($node, $sem);
731 - }
732 - return new TagToString($node, $sem);
733 - }
734 -
735 - protected function getChangeSemantic($qname) {
736 - if (in_array(strtolower($qname),self::$containerTags)) {
737 - return self::MOVED;
738 - }
739 - if (in_array(strtolower($qname),self::$styleTags)) {
740 - return self::STYLE;
741 - }
742 - return self::UNKNOWN;
743 - }
744 -}
745 -
746 -class TagToString {
747 -
748 - protected $node;
749 -
750 - protected $sem;
751 -
752 - function __construct(TagNode $node, $sem) {
753 - $this->node = $node;
754 - $this->sem = $sem;
755 - }
756 -
757 - public function getRemovedDescription(ChangeText $txt) {
758 - $tagDescription = wfMsgExt('diff-' . $this->node->qName, 'parseinline' );
759 - if( wfEmptyMsg( 'diff-' . $this->node->qName, $tagDescription ) ){
760 - $tagDescription = "&lt;" . $this->node->qName . "&gt;";
761 - }
762 - if ($this->sem == TagToStringFactory::MOVED) {
763 - $txt->addHtml( wfMsgExt( 'diff-movedoutof', 'parseinline', $tagDescription ) );
764 - } else if ($this->sem == TagToStringFactory::STYLE) {
765 - $txt->addHtml( wfMsgExt( 'diff-styleremoved' , 'parseinline', $tagDescription ) );
766 - } else {
767 - $txt->addHtml( wfMsgExt( 'diff-removed' , 'parseinline', $tagDescription ) );
768 - }
769 - $this->addAttributes($txt, $this->node->attributes);
770 - $txt->addHtml('.');
771 - }
772 -
773 - public function getAddedDescription(ChangeText $txt) {
774 - $tagDescription = wfMsgExt('diff-' . $this->node->qName, 'parseinline' );
775 - if( wfEmptyMsg( 'diff-' . $this->node->qName, $tagDescription ) ){
776 - $tagDescription = "&lt;" . $this->node->qName . "&gt;";
777 - }
778 - if ($this->sem == TagToStringFactory::MOVED) {
779 - $txt->addHtml( wfMsgExt( 'diff-movedto' , 'parseinline', $tagDescription) );
780 - } else if ($this->sem == TagToStringFactory::STYLE) {
781 - $txt->addHtml( wfMsgExt( 'diff-styleadded', 'parseinline', $tagDescription ) );
782 - } else {
783 - $txt->addHtml( wfMsgExt( 'diff-added', 'parseinline', $tagDescription ) );
784 - }
785 - $this->addAttributes($txt, $this->node->attributes);
786 - $txt->addHtml('.');
787 - }
788 -
789 - protected function addAttributes(ChangeText $txt, array $attributes) {
790 - if (count($attributes) < 1) {
791 - return;
792 - }
793 - $firstOne = true;
794 - $nbAttributes_min_1 = count($attributes)-1;
795 - $keys = array_keys($attributes);
796 - for ($i=0;$i<$nbAttributes_min_1;$i++) {
797 - $key = $keys[$i];
798 - $attr = $attributes[$key];
799 - if($firstOne) {
800 - $firstOne = false;
801 - $txt->addHtml( wfMsgExt('diff-with', 'escapenoentities', $this->translateArgument($key), htmlspecialchars($attr) ) );
802 - continue;
803 - }
804 - $txt->addHtml( wfMsgExt( 'comma-separator', 'escapenoentities' ) .
805 - wfMsgExt( 'diff-with-additional', 'escapenoentities',
806 - $this->translateArgument( $key ), htmlspecialchars( $attr ) )
807 - );
808 - }
809 -
810 - if ($nbAttributes_min_1 > 0) {
811 - $txt->addHtml( wfMsgExt( 'diff-with-final', 'escapenoentities',
812 - $this->translateArgument($keys[$nbAttributes_min_1]),
813 - htmlspecialchars($attributes[$keys[$nbAttributes_min_1]]) ) );
814 - }
815 - }
816 -
817 - protected function translateArgument($name) {
818 - $translation = wfMsgExt('diff-' . $name, 'parseinline' );
819 - if ( wfEmptyMsg( 'diff-' . $name, $translation ) ) {
820 - $translation = "&lt;" . $name . "&gt;";;
821 - }
822 - return htmlspecialchars( $translation );
823 - }
824 -}
825 -
826 -class NoContentTagToString extends TagToString {
827 -
828 - function __construct(TagNode $node, $sem) {
829 - parent::__construct($node, $sem);
830 - }
831 -
832 - public function getAddedDescription(ChangeText $txt) {
833 - $tagDescription = wfMsgExt('diff-' . $this->node->qName, 'parseinline' );
834 - if( wfEmptyMsg( 'diff-' . $this->node->qName, $tagDescription ) ){
835 - $tagDescription = "&lt;" . $this->node->qName . "&gt;";
836 - }
837 - $txt->addHtml( wfMsgExt('diff-changedto', 'parseinline', $tagDescription ) );
838 - $this->addAttributes($txt, $this->node->attributes);
839 - $txt->addHtml('.');
840 - }
841 -
842 - public function getRemovedDescription(ChangeText $txt) {
843 - $tagDescription = wfMsgExt('diff-' . $this->node->qName, 'parseinline' );
844 - if( wfEmptyMsg( 'diff-' . $this->node->qName, $tagDescription ) ){
845 - $tagDescription = "&lt;" . $this->node->qName . "&gt;";
846 - }
847 - $txt->addHtml( wfMsgExt('diff-changedfrom', 'parseinline', $tagDescription ) );
848 - $this->addAttributes($txt, $this->node->attributes);
849 - $txt->addHtml('.');
850 - }
851 -}
852 -
853 -class AnchorToString extends TagToString {
854 -
855 - function __construct(TagNode $node, $sem) {
856 - parent::__construct($node, $sem);
857 - }
858 -
859 - protected function addAttributes(ChangeText $txt, array $attributes) {
860 - if (array_key_exists('href', $attributes)) {
861 - $txt->addHtml(' ' . wfMsgExt( 'diff-withdestination', 'parseinline', htmlspecialchars($attributes['href']) ) );
862 - unset($attributes['href']);
863 - }
864 - parent::addAttributes($txt, $attributes);
865 - }
866 -}
867 -
868 -/**
869 - * Takes a branch root and creates an HTML file for it.
870 - */
871 -class HTMLOutput{
872 -
873 - private $prefix;
874 - private $handler;
875 -
876 - function __construct($prefix, $handler) {
877 - $this->prefix = $prefix;
878 - $this->handler = $handler;
879 - }
880 -
881 - public function parse(TagNode $node) {
882 - $handler = &$this->handler;
883 -
884 - if (strcasecmp($node->qName, 'img') != 0 && strcasecmp($node->qName, 'body') != 0) {
885 - $handler->startElement($node->qName, $node->attributes);
886 - }
887 -
888 - $newStarted = false;
889 - $remStarted = false;
890 - $changeStarted = false;
891 - $changeTXT = '';
892 -
893 - foreach ($node->children as &$child) {
894 - if ($child instanceof TagNode) {
895 - if ($newStarted) {
896 - $handler->endElement('span');
897 - $newStarted = false;
898 - } else if ($changeStarted) {
899 - $handler->endElement('span');
900 - $changeStarted = false;
901 - } else if ($remStarted) {
902 - $handler->endElement('span');
903 - $remStarted = false;
904 - }
905 - $this->parse($child);
906 - } else if ($child instanceof TextNode) {
907 - $mod = $child->modification;
908 -
909 - if ($newStarted && ($mod->type != Modification::ADDED || $mod->firstOfID)) {
910 - $handler->endElement('span');
911 - $newStarted = false;
912 - } else if ($changeStarted && ($mod->type != Modification::CHANGED
913 - || $mod->changes != $changeTXT || $mod->firstOfID)) {
914 - $handler->endElement('span');
915 - $changeStarted = false;
916 - } else if ($remStarted && ($mod->type != Modification::REMOVED || $mod ->firstOfID)) {
917 - $handler->endElement('span');
918 - $remStarted = false;
919 - }
920 -
921 - // no else because a removed part can just be closed and a new
922 - // part can start
923 - if (!$newStarted && $mod->type == Modification::ADDED) {
924 - $attrs = array('class' => 'diff-html-added');
925 - if ($mod->firstOfID) {
926 - $attrs['id'] = "added-{$this->prefix}-{$mod->id}";
927 - }
928 - $handler->startElement('span', $attrs);
929 - $newStarted = true;
930 - } else if (!$changeStarted && $mod->type == Modification::CHANGED) {
931 - $attrs = array('class' => 'diff-html-changed');
932 - if ($mod->firstOfID) {
933 - $attrs['id'] = "changed-{$this->prefix}-{$mod->id}";
934 - }
935 - $handler->startElement('span', $attrs);
936 -
937 - //tooltip
938 - $handler->startElement('span', array('class' => 'tip'));
939 - $handler->html($mod->changes);
940 - $handler->endElement('span');
941 -
942 - $changeStarted = true;
943 - $changeTXT = $mod->changes;
944 - } else if (!$remStarted && $mod->type == Modification::REMOVED) {
945 - $attrs = array('class'=>'diff-html-removed');
946 - if ($mod->firstOfID) {
947 - $attrs['id'] = "removed-{$this->prefix}-{$mod->id}";
948 - }
949 - $handler->startElement('span', $attrs);
950 - $remStarted = true;
951 - }
952 -
953 - $chars = $child->text;
954 -
955 - if ($child instanceof ImageNode) {
956 - $this->writeImage($child);
957 - } else {
958 - $handler->characters($chars);
959 - }
960 - }
961 - }
962 -
963 - if ($newStarted) {
964 - $handler->endElement('span');
965 - $newStarted = false;
966 - } else if ($changeStarted) {
967 - $handler->endElement('span');
968 - $changeStarted = false;
969 - } else if ($remStarted) {
970 - $handler->endElement('span');
971 - $remStarted = false;
972 - }
973 -
974 - if (strcasecmp($node->qName, 'img') != 0
975 - && strcasecmp($node->qName, 'body') != 0) {
976 - $handler->endElement($node->qName);
977 - }
978 - }
979 -
980 - private function writeImage(ImageNode $imgNode) {
981 - $attrs = $imgNode->attributes;
982 - $this->handler->startElement('img', $attrs);
983 - $this->handler->endElement('img');
984 - }
985 -}
986 -
987 -class DelegatingContentHandler {
988 -
989 - private $delegate;
990 -
991 - function __construct($delegate) {
992 - $this->delegate = $delegate;
993 - }
994 -
995 - function startElement($qname, /*array*/ $arguments) {
996 - $this->delegate->addHtml(Xml::openElement($qname, $arguments));
997 - }
998 -
999 - function endElement($qname){
1000 - $this->delegate->addHtml(Xml::closeElement($qname));
1001 - }
1002 -
1003 - function characters($chars){
1004 - $this->delegate->addHtml(htmlspecialchars($chars));
1005 - }
1006 -
1007 - function html($html){
1008 - $this->delegate->addHtml($html);
1009 - }
1010 -}
Index: trunk/phase3/includes/diff/DifferenceInterface.php
@@ -28,7 +28,6 @@
2929 var $mRevisionsLoaded = false; // Have the revisions been loaded
3030 var $mTextLoaded = 0; // How many text blobs have been loaded, 0, 1 or 2?
3131 var $mCacheHit = false; // Was the diff fetched from cache?
32 - var $htmldiff;
3332
3433 /**
3534 * Set this to true to add debug info to the HTML output.
@@ -51,11 +50,10 @@
5251 * @param $new String: either 'prev' or 'next'.
5352 * @param $rcid Integer: ??? FIXME (default 0)
5453 * @param $refreshCache boolean If set, refreshes the diff cache
55 - * @param $htmldiff boolean If set, output using HTMLDiff instead of raw wikicode diff
5654 * @param $unhide boolean If set, allow viewing deleted revs
5755 */
5856 function __construct( $titleObj = null, $old = 0, $new = 0, $rcid = 0,
59 - $refreshCache = false, $htmldiff = false, $unhide = false )
 57+ $refreshCache = false, $unhide = false )
6058 {
6159 if ( $titleObj ) {
6260 $this->mTitle = $titleObj;
@@ -87,7 +85,6 @@
8886 }
8987 $this->mRcidMarkPatrolled = intval($rcid); # force it to be an integer
9088 $this->mRefreshCache = $refreshCache;
91 - $this->htmldiff = $htmldiff;
9289 $this->unhide = $unhide;
9390 }
9491
@@ -112,7 +109,7 @@
113110 }
114111
115112 function showDiffPage( $diffOnly = false ) {
116 - global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol, $wgEnableHtmlDiff;
 113+ global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol;
117114 wfProfileIn( __METHOD__ );
118115
119116
@@ -264,12 +261,6 @@
265262 $query['diffonly'] = $diffOnly;
266263 }
267264
268 - $htmldiffarg = $this->htmlDiffArgument();
269 -
270 - if( $htmldiffarg ) {
271 - $query['htmldiff'] = $htmldiffarg['htmldiff'];
272 - }
273 -
274265 # Make "previous revision link"
275266 $query['diff'] = 'prev';
276267 $query['oldid'] = $this->mOldid;
@@ -401,47 +392,8 @@
402393 $msg = $suppressed ? 'rev-suppressed-unhide-diff' : 'rev-deleted-unhide-diff';
403394 $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1</div>\n", array( $msg, $link ) );
404395 }
405 - # Otherwise, output the HTML diff if requested...
406 - } else if( $wgEnableHtmlDiff && $this->htmldiff ) {
407 - $multi = $this->getMultiNotice();
408 - $wgOut->addHTML( '<div class="diff-switchtype">' . $sk->link(
409 - $this->mTitle,
410 - wfMsgHtml( 'wikicodecomparison' ),
411 - array(
412 - 'id' => 'differences-switchtype'
413 - ),
414 - array(
415 - 'diff' => $this->mNewid,
416 - 'oldid' => $this->mOldid,
417 - 'htmldiff' => 0
418 - ),
419 - array(
420 - 'known',
421 - 'noclasses'
422 - )
423 - ) . '</div>');
424 - $wgOut->addHTML( $this->addHeader( '', $oldHeader, $newHeader, $multi ) );
425 - # Add deletion notice if the user is viewing deleted content
426 - if( $deleted ) {
427 - $msg = $suppressed ? 'rev-suppressed-diff-view' : 'rev-deleted-diff-view';
428 - $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1</div>\n", $msg );
429 - }
430 - $this->renderHtmlDiff();
431396 # Otherwise, output a regular diff...
432397 } else {
433 - if( $wgEnableHtmlDiff ) {
434 - $wgOut->addHTML( '<div class="diff-switchtype">' . $sk->link(
435 - $this->mTitle,
436 - wfMsgHtml( 'visualcomparison' ),
437 - array( 'id' => 'differences-switchtype' ),
438 - array(
439 - 'diff' => $this->mNewid,
440 - 'oldid' => $this->mOldid,
441 - 'htmldiff' => 1
442 - ),
443 - array( 'known', 'noclasses' )
444 - ) . '</div>');
445 - }
446398 # Add deletion notice if the user is viewing deleted content
447399 $notice = '';
448400 if( $deleted ) {
@@ -517,70 +469,6 @@
518470 wfProfileOut( __METHOD__ );
519471 }
520472
521 -
522 - function renderHtmlDiff() {
523 - global $wgOut, $wgParser, $wgDebugComments;
524 - wfProfileIn( __METHOD__ );
525 -
526 - $this->showDiffStyle();
527 -
528 - $wgOut->addHTML( '<h2>'.wfMsgHtml( 'visual-comparison' )."</h2>\n" );
529 - #add deleted rev tag if needed
530 - if( !$this->mNewRev->userCan(Revision::DELETED_TEXT) ) {
531 - $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1</div>\n", 'rev-deleted-text-permission' );
532 - } else if( $this->mNewRev->isDeleted(Revision::DELETED_TEXT) ) {
533 - $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1</div>\n", 'rev-deleted-text-view' );
534 - }
535 -
536 - if( !$this->mNewRev->isCurrent() ) {
537 - $oldEditSectionSetting = $wgOut->parserOptions()->setEditSection( false );
538 - }
539 -
540 - $this->loadText();
541 -
542 - // Old revision
543 - if( is_object( $this->mOldRev ) ) {
544 - $wgOut->setRevisionId( $this->mOldRev->getId() );
545 - }
546 -
547 - $popts = $wgOut->parserOptions();
548 - $oldTidy = $popts->setTidy( true );
549 - $popts->setEditSection( false );
550 -
551 - $parserOutput = $wgParser->parse( $this->mOldtext, $this->getTitle(), $popts, true, true, $wgOut->getRevisionId() );
552 - $popts->setTidy( $oldTidy );
553 -
554 - //only for new?
555 - //$wgOut->addParserOutputNoText( $parserOutput );
556 - $oldHtml = $parserOutput->getText();
557 - wfRunHooks( 'OutputPageBeforeHTML', array( &$wgOut, &$oldHtml ) );
558 -
559 - // New revision
560 - if( is_object( $this->mNewRev ) ) {
561 - $wgOut->setRevisionId( $this->mNewRev->getId() );
562 - }
563 -
564 - $popts = $wgOut->parserOptions();
565 - $oldTidy = $popts->setTidy( true );
566 -
567 - $parserOutput = $wgParser->parse( $this->mNewtext, $this->getTitle(), $popts, true, true, $wgOut->getRevisionId() );
568 - $popts->setTidy( $oldTidy );
569 -
570 - $wgOut->addParserOutputNoText( $parserOutput );
571 - $newHtml = $parserOutput->getText();
572 - wfRunHooks( 'OutputPageBeforeHTML', array( &$wgOut, &$newHtml ) );
573 -
574 - unset($parserOutput, $popts);
575 -
576 - $differ = new HTMLDiffer(new DelegatingContentHandler($wgOut));
577 - $differ->htmlDiff($oldHtml, $newHtml);
578 - if ( $wgDebugComments ) {
579 - $wgOut->addHTML( "\n<!-- HtmlDiff Debug Output:\n" . HTMLDiffer::getDebugOutput() . " End Debug -->" );
580 - }
581 -
582 - wfProfileOut( __METHOD__ );
583 - }
584 -
585473 /**
586474 * Show the first revision of an article. Uses normal diff headers in
587475 * contrast to normal "old revision" display style.
@@ -629,7 +517,6 @@
630518 array(
631519 'diff' => 'next',
632520 'oldid' => $this->mNewid,
633 - $this->htmlDiffArgument()
634521 ),
635522 array(
636523 'known',
@@ -648,19 +535,6 @@
649536 wfProfileOut( __METHOD__ );
650537 }
651538
652 - function htmlDiffArgument(){
653 - global $wgEnableHtmlDiff;
654 - if($wgEnableHtmlDiff){
655 - if($this->htmldiff){
656 - return array( 'htmldiff' => 1 );
657 - }else{
658 - return array( 'htmldiff' => 0 );
659 - }
660 - }else{
661 - return array();
662 - }
663 - }
664 -
665539 /**
666540 * Get the diff text, send it to $wgOut
667541 * Returns false if the diff could not be generated, otherwise returns true
Index: trunk/phase3/includes/HistoryPage.php
@@ -359,7 +359,7 @@
360360 * @return string HTML output
361361 */
362362 function getStartBody() {
363 - global $wgScript, $wgEnableHtmlDiff, $wgUser, $wgOut, $wgContLang;
 363+ global $wgScript, $wgUser, $wgOut, $wgContLang;
364364 $this->lastRow = false;
365365 $this->counter = 1;
366366 $this->oldIdChecked = 0;
@@ -385,34 +385,13 @@
386386 wfMsg( 'showhideselectedversions' )
387387 ) . "\n";
388388 }
389 - if( $wgEnableHtmlDiff ) {
390 - $this->buttons .= Xml::element( 'button',
391 - array(
392 - 'type' => 'submit',
393 - 'name' => 'htmldiff',
394 - 'value' => '1',
395 - 'class' => 'historysubmit',
396 - 'accesskey' => wfMsg( 'accesskey-visualcomparison' ),
397 - 'title' => wfMsg( 'tooltip-compareselectedversions' ),
398 - ),
399 - wfMsg( 'visualcomparison')
400 - ) . "\n";
401 - $this->buttons .= $this->submitButton( wfMsg( 'wikicodecomparison'),
402 - array(
403 - 'class' => 'historysubmit',
404 - 'accesskey' => wfMsg( 'accesskey-compareselectedversions' ),
405 - 'title' => wfMsg( 'tooltip-compareselectedversions' ),
406 - )
407 - ) . "\n";
408 - } else {
409 - $this->buttons .= $this->submitButton( wfMsg( 'compareselectedversions'),
410 - array(
411 - 'class' => 'historysubmit',
412 - 'accesskey' => wfMsg( 'accesskey-compareselectedversions' ),
413 - 'title' => wfMsg( 'tooltip-compareselectedversions' ),
414 - )
415 - ) . "\n";
416 - }
 389+ $this->buttons .= $this->submitButton( wfMsg( 'compareselectedversions'),
 390+ array(
 391+ 'class' => 'historysubmit',
 392+ 'accesskey' => wfMsg( 'accesskey-compareselectedversions' ),
 393+ 'title' => wfMsg( 'tooltip-compareselectedversions' ),
 394+ )
 395+ ) . "\n";
417396 $this->buttons .= '</div>';
418397 $s .= $this->buttons . '<ul id="pagehistory">' . "\n";
419398 return $s;
Index: trunk/phase3/includes/Article.php
@@ -943,11 +943,10 @@
944944 $rcid = $wgRequest->getVal( 'rcid' );
945945 $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) );
946946 $purge = $wgRequest->getVal( 'action' ) == 'purge';
947 - $htmldiff = $wgRequest->getBool( 'htmldiff' );
948947 $unhide = $wgRequest->getInt('unhide') == 1;
949948 $oldid = $this->getOldID();
950949
951 - $de = new DifferenceEngine( $this->mTitle, $oldid, $diff, $rcid, $purge, $htmldiff, $unhide );
 950+ $de = new DifferenceEngine( $this->mTitle, $oldid, $diff, $rcid, $purge, $unhide );
952951 // DifferenceEngine directly fetched the revision:
953952 $this->mRevIdFetched = $de->mNewid;
954953 $de->showDiffPage( $diffOnly );
Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -1563,64 +1563,8 @@
15641564 'lineno' => 'Line $1:',
15651565 'compareselectedversions' => 'Compare selected revisions',
15661566 'showhideselectedversions' => 'Show/hide selected revisions',
1567 -'visualcomparison' => 'Visual comparison',
1568 -'wikicodecomparison' => 'Wikitext comparison',
15691567 'editundo' => 'undo',
15701568 'diff-multi' => '({{PLURAL:$1|One intermediate revision|$1 intermediate revisions}} not shown)',
1571 -'diff-movedto' => 'moved to $1',
1572 -'diff-styleadded' => '$1 style added',
1573 -'diff-added' => '$1 added',
1574 -'diff-changedto' => 'changed to $1',
1575 -'diff-movedoutof' => 'moved out of $1',
1576 -'diff-styleremoved' => '$1 style removed',
1577 -'diff-removed' => '$1 removed',
1578 -'diff-changedfrom' => 'changed from $1',
1579 -'diff-src' => 'source',
1580 -'diff-withdestination' => 'with destination $1',
1581 -'diff-with' => '&#32;with $1 $2',
1582 -'diff-with-additional' => '$1 $2', # only translate this message to other languages if you have to change it
1583 -'diff-with-final' => '&#32;and $1 $2',
1584 -'diff-width' => 'width',
1585 -'diff-height' => 'height',
1586 -'diff-p' => "a '''paragraph'''",
1587 -'diff-blockquote' => "a '''quote'''",
1588 -'diff-h1' => "a '''heading (level 1)'''",
1589 -'diff-h2' => "a '''heading (level 2)'''",
1590 -'diff-h3' => "a '''heading (level 3)'''",
1591 -'diff-h4' => "a '''heading (level 4)'''",
1592 -'diff-h5' => "a '''heading (level 5)'''",
1593 -'diff-pre' => "a '''preformatted block'''",
1594 -'diff-div' => "a '''division'''",
1595 -'diff-ul' => "an '''unordered list'''",
1596 -'diff-ol' => "an '''ordered list'''",
1597 -'diff-li' => "a '''list item'''",
1598 -'diff-table' => "a '''table'''",
1599 -'diff-tbody' => "a '''table's content'''",
1600 -'diff-tr' => "a '''row'''",
1601 -'diff-td' => "a '''cell'''",
1602 -'diff-th' => "a '''header'''",
1603 -'diff-br' => "a '''break'''",
1604 -'diff-hr' => "a '''horizontal rule'''",
1605 -'diff-code' => "a '''computer code block'''",
1606 -'diff-dl' => "a '''definition list'''",
1607 -'diff-dt' => "a '''definition term'''",
1608 -'diff-dd' => "a '''definition'''",
1609 -'diff-input' => "an '''input'''",
1610 -'diff-form' => "a '''form'''",
1611 -'diff-img' => "an '''image'''",
1612 -'diff-span' => "a '''span'''",
1613 -'diff-a' => "a '''link'''",
1614 -'diff-i' => "'''italics'''",
1615 -'diff-b' => "'''bold'''",
1616 -'diff-strong' => "'''strong'''",
1617 -'diff-em' => "'''emphasis'''",
1618 -'diff-font' => "'''font'''",
1619 -'diff-big' => "'''big'''",
1620 -'diff-del' => "'''deleted'''",
1621 -'diff-tt' => "'''fixed width'''",
1622 -'diff-sub' => "'''subscript'''",
1623 -'diff-sup' => "'''superscript'''",
1624 -'diff-strike' => "'''strikethrough'''",
16251569
16261570 # Search results
16271571 'searchresults' => 'Search results',
@@ -3276,7 +3220,6 @@
32773221 'accesskey-preview' => 'p', # do not translate or duplicate this message to other languages
32783222 'accesskey-diff' => 'v', # do not translate or duplicate this message to other languages
32793223 'accesskey-compareselectedversions' => 'v', # do not translate or duplicate this message to other languages
3280 -'accesskey-visualcomparison' => 'b', # do not translate or duplicate this message to other languages
32813224 'accesskey-watch' => 'w', # do not translate or duplicate this message to other languages
32823225 'accesskey-upload' => 's', # do not translate or duplicate this message to other languages
32833226
@@ -3475,9 +3418,6 @@
34763419 'previousdiff' => '← Older edit',
34773420 'nextdiff' => 'Newer edit →',
34783421
3479 -# Visual comparison
3480 -'visual-comparison' => 'Visual comparison',
3481 -
34823422 # Media information
34833423 'mediawarning' => "'''Warning''': This file may contain malicious code, by executing it your system may be compromised.<hr />",
34843424 'imagemaxsize' => "Image size limit:<br />''(for file description pages)''",
Index: trunk/phase3/RELEASE-NOTES
@@ -89,6 +89,7 @@
9090 maintenance
9191 * $wgCapitalLinkOverrides added to configure per-namespace capitalization
9292 * (bug 21172) $wgSorbsUrl can now be an array with multiple DNSBL
 93+* $wgEnableHtmlDiff has been removed
9394
9495 === New features in 1.16 ===
9596
@@ -604,6 +605,7 @@
605606 * User::isValidPassword now only returns boolean results, User::getPasswordValidity
606607 can be used to get an error message string
607608 * The error message shown in Special:ChangePassword now parses wiki markup
 609+* (bug 19859) Removed experimental HTMLDiff feature
608610
609611 == API changes in 1.16 ==
610612
Index: trunk/phase3/maintenance/language/messages.inc
@@ -766,64 +766,7 @@
767767 'lineno',
768768 'compareselectedversions',
769769 'showhideselectedversions',
770 - 'visualcomparison',
771 - 'wikicodecomparison',
772770 'editundo',
773 - 'diff-multi',
774 - 'diff-movedto',
775 - 'diff-styleadded',
776 - 'diff-added',
777 - 'diff-changedto',
778 - 'diff-movedoutof',
779 - 'diff-styleremoved',
780 - 'diff-removed',
781 - 'diff-changedfrom',
782 - 'diff-src',
783 - 'diff-withdestination',
784 - 'diff-with',
785 - 'diff-with-additional',
786 - 'diff-with-final',
787 - 'diff-width',
788 - 'diff-height',
789 - 'diff-p',
790 - 'diff-blockquote',
791 - 'diff-h1',
792 - 'diff-h2',
793 - 'diff-h3',
794 - 'diff-h4',
795 - 'diff-h5',
796 - 'diff-pre',
797 - 'diff-div',
798 - 'diff-ul',
799 - 'diff-ol',
800 - 'diff-li',
801 - 'diff-table',
802 - 'diff-tbody',
803 - 'diff-tr',
804 - 'diff-td',
805 - 'diff-th',
806 - 'diff-br',
807 - 'diff-hr',
808 - 'diff-code',
809 - 'diff-dl',
810 - 'diff-dt',
811 - 'diff-dd',
812 - 'diff-input',
813 - 'diff-form',
814 - 'diff-img',
815 - 'diff-span',
816 - 'diff-a',
817 - 'diff-i',
818 - 'diff-b',
819 - 'diff-strong',
820 - 'diff-em',
821 - 'diff-font',
822 - 'diff-big',
823 - 'diff-del',
824 - 'diff-tt',
825 - 'diff-sub',
826 - 'diff-sup',
827 - 'diff-strike',
828771 ),
829772 'search' => array(
830773 'searchresults',
@@ -2262,7 +2205,6 @@
22632206 'accesskey-preview',
22642207 'accesskey-diff',
22652208 'accesskey-compareselectedversions',
2266 - 'accesskey-visualcomparison',
22672209 'accesskey-watch',
22682210 'accesskey-upload',
22692211 ),
@@ -2454,9 +2396,6 @@
24552397 'previousdiff',
24562398 'nextdiff',
24572399 ),
2458 - 'visual-comparison' => array(
2459 - 'visual-comparison',
2460 - ),
24612400 'media-info' => array(
24622401 'mediawarning',
24632402 'imagemaxsize',
@@ -3304,7 +3243,6 @@
33053244 'variantname-kk' => 'Variants for Kazakh language',
33063245 'variantname-ku' => 'Variants for Kurdish language',
33073246 'variantname-tg' => 'Variants for Tajiki language',
3308 - 'visual-comparison' => 'Visual comparison',
33093247 'media-info' => 'Media information',
33103248 'metadata' => 'Metadata',
33113249 'exif' => 'EXIF tags',
Index: trunk/phase3/maintenance/language/messageTypes.inc
@@ -67,7 +67,6 @@
6868 'accesskey-preview',
6969 'accesskey-diff',
7070 'accesskey-compareselectedversions',
71 - 'accesskey-visualcomparison',
7271 'accesskey-watch',
7372 'accesskey-upload',
7473 'addsection',

Follow-up revisions

RevisionCommit summaryAuthorDate
r58270Follow-up to r58267: rebuild all language filessiebrand18:40, 28 October 2009
r58732Restore message accidently removed with r58267.raymond21:08, 7 November 2009
r76003(bug 25783) Remove leftover HTMLDiff CSS, followup to incomplete r58267demon13:53, 4 November 2010

Comments

#Comment by Tim Starling (talk | contribs)   09:47, 30 December 2009

/me sheds a tear

Status & tagging log