X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FDifferenceEngine.php;h=52bf654d7795b086c249ef8449704f4d61f68017;hb=a91c84bc1c23c2827aa9946036bbdb12e1e01a7e;hp=8b80c27e8b74cecb14d6d8f7210f8f3c7ba0447d;hpb=61c6f0b22368a9edca5c74fc30984f7ac3f8e525;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/DifferenceEngine.php b/includes/DifferenceEngine.php index 8b80c27e8b..52bf654d77 100644 --- a/includes/DifferenceEngine.php +++ b/includes/DifferenceEngine.php @@ -1,49 +1,99 @@ mOldid = $old; - $this->mNewid = $new; + global $wgTitle; + if ( 'prev' == $new ) { + # Show diff between revision $old and the previous one. + # Get previous one from DB. + # + $this->mNewid = intval($old); + $dbr =& wfGetDB( DB_SLAVE ); + $this->mOldid = $dbr->selectField( 'old', 'old_id', + "old_title='" . $wgTitle->getDBkey() . "'" . + ' AND old_namespace=' . $wgTitle->getNamespace() . + " AND old_id<{$this->mNewid} ORDER BY old_id DESC" ); + + } elseif ( 'next' == $new ) { + + # Show diff between revision $old and the previous one. + # Get previous one from DB. + # + $this->mOldid = intval($old); + $dbr =& wfGetDB( DB_SLAVE ); + $this->mNewid = $dbr->selectField( 'old', 'old_id', + "old_title='" . $wgTitle->getDBkey() . "'" . + ' AND old_namespace=' . $wgTitle->getNamespace() . + " AND old_id>{$this->mOldid} ORDER BY old_id " ); + if ( false === $this->mNewid ) { + # if no result, NewId points to the newest old revision. The only newer + # revision is cur, which is "0". + $this->mNewid = 0; + } + + } else { + + $this->mOldid = intval($old); + $this->mNewid = intval($new); + } + $this->mRcidMarkPatrolled = intval($rcid); # force it to be an integer } function showDiffPage() { - global $wgUser, $wgTitle, $wgOut, $wgLang; - $fname = "DifferenceEngine::showDiffPage"; + global $wgUser, $wgTitle, $wgOut, $wgLang, $wgOnlySysopsCanPatrol, $wgUseRCPatrol; + $fname = 'DifferenceEngine::showDiffPage'; wfProfileIn( $fname ); - + + # mOldid is false if the difference engine is called with a "vague" query for + # a diff between a version V and its previous version V' AND the version V + # is the first version of that article. In that case, V' does not exist. + if ( $this->mOldid === false ) { + $this->showFirstRevision(); + wfProfileOut( $fname ); + return; + } + $t = $wgTitle->getPrefixedText() . " (Diff: {$this->mOldid}, " . "{$this->mNewid})"; - $mtext = wfMsg( "missingarticle", $t ); + $mtext = wfMsg( 'missingarticle', $t ); $wgOut->setArticleFlag( false ); if ( ! $this->loadText() ) { - $wgOut->setPagetitle( wfMsg( "errorpagetitle" ) ); + $wgOut->setPagetitle( wfMsg( 'errorpagetitle' ) ); $wgOut->addHTML( $mtext ); wfProfileOut( $fname ); return; } $wgOut->suppressQuickbar(); - + $oldTitle = $this->mOldPage->getPrefixedText(); $newTitle = $this->mNewPage->getPrefixedText(); if( $oldTitle == $newTitle ) { $wgOut->setPageTitle( $newTitle ); } else { - $wgOut->setPageTitle( $oldTitle . ", " . $newTitle ); + $wgOut->setPageTitle( $oldTitle . ', ' . $newTitle ); } - $wgOut->setSubtitle( wfMsg( "difference" ) ); - $wgOut->setRobotpolicy( "noindex,follow" ); - + $wgOut->setSubtitle( wfMsg( 'difference' ) ); + $wgOut->setRobotpolicy( 'noindex,follow' ); + if ( !( $this->mOldPage->userCanRead() && $this->mNewPage->userCanRead() ) ) { $wgOut->loginToUse(); $wgOut->output(); @@ -53,38 +103,114 @@ class DifferenceEngine { $sk = $wgUser->getSkin(); $talk = $wgLang->getNsText( NS_TALK ); - $contribs = wfMsg( "contribslink" ); - + $contribs = wfMsg( 'contribslink' ); $this->mOldComment = $sk->formatComment($this->mOldComment); $this->mNewComment = $sk->formatComment($this->mNewComment); - - $oldUserLink = $sk->makeLinkObj( Title::makeTitle( NS_USER, $this->mOldUser ), $this->mOldUser ); - $newUserLink = $sk->makeLinkObj( Title::makeTitle( NS_USER, $this->mNewUser ), $this->mNewUser ); - $oldUTLink = $sk->makeLinkObj( Title::makeTitle( NS_USER_TALK, $this->mOldUser ), $talk ); - $newUTLink = $sk->makeLinkObj( Title::makeTitle( NS_USER_TALK, $this->mNewUser ), $talk ); - $oldContribs = $sk->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, "Contributions" ), $contribs, - "target=" . urlencode($this->mOldUser) ); - $newContribs = $sk->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, "Contributions" ), $contribs, - "target=" . urlencode($this->mNewUser) ); + $oldUserLink = $sk->makeLinkObj( Title::makeTitleSafe( NS_USER, $this->mOldUser ), $this->mOldUser ); + $newUserLink = $sk->makeLinkObj( Title::makeTitleSafe( NS_USER, $this->mNewUser ), $this->mNewUser ); + $oldUTLink = $sk->makeLinkObj( Title::makeTitleSafe( NS_USER_TALK, $this->mOldUser ), $talk ); + $newUTLink = $sk->makeLinkObj( Title::makeTitleSafe( NS_USER_TALK, $this->mNewUser ), $talk ); + $oldContribs = $sk->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Contributions' ), $contribs, + 'target=' . urlencode($this->mOldUser) ); + $newContribs = $sk->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Contributions' ), $contribs, + 'target=' . urlencode($this->mNewUser) ); if ( !$this->mNewid && $wgUser->isSysop() ) { - $rollback = "   [" . $sk->makeKnownLinkObj( $wgTitle, wfMsg( "rollbacklink" ), - "action=rollback&from=" . urlencode($this->mNewUser) ) . "]"; + $rollback = '   [' . $sk->makeKnownLinkObj( $wgTitle, wfMsg( 'rollbacklink' ), + 'action=rollback&from=' . urlencode($this->mNewUser) ) . ']'; + } else { + $rollback = ''; + } + if ( $wgUseRCPatrol && $this->mRcidMarkPatrolled != 0 && $wgUser->getID() != 0 && + ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) ) + { + $patrol = ' [' . $sk->makeKnownLinkObj( $wgTitle, wfMsg( 'markaspatrolleddiff' ), + "action=markpatrolled&rcid={$this->mRcidMarkPatrolled}" ) . ']'; + } else { + $patrol = ''; + } + + $prevlink = $sk->makeKnownLinkObj( $wgTitle, wfMsg( 'previousdiff' ), 'diff=prev&oldid='.$this->mOldid ); + if ( $this->mNewid == 0 ) { + $nextlink = ''; } else { - $rollback = ""; + $nextlink = $sk->makeKnownLinkObj( $wgTitle, wfMsg( 'nextdiff' ), 'diff=next&oldid='.$this->mNewid ); } - $oldHeader = "{$this->mOldtitle}
$oldUserLink ($oldUTLink | $oldContribs)
". - $this->mOldComment; - $newHeader = "{$this->mNewtitle}
$newUserLink ($newUTLink | $newContribs) $rollback
". - $this->mNewComment; + $oldHeader = "{$this->mOldtitle}
$oldUserLink " . + "($oldUTLink | $oldContribs)
" . $this->mOldComment . + '
' . $prevlink; + $newHeader = "{$this->mNewtitle}
$newUserLink " . + "($newUTLink | $newContribs) $rollback
" . $this->mNewComment . + '
' . $nextlink . $patrol; DifferenceEngine::showDiff( $this->mOldtext, $this->mNewtext, $oldHeader, $newHeader ); - $wgOut->addHTML( "

{$this->mNewtitle}

\n" ); + $wgOut->addHTML( "

{$this->mPagetitle}

\n" ); $wgOut->addWikiText( $this->mNewtext ); - + + wfProfileOut( $fname ); + } + + # Show the first revision of an article. Uses normal diff headers in contrast to normal + # "old revision" display style. + # + function showFirstRevision() + { + global $wgOut, $wgTitle, $wgUser, $wgLang; + + $fname = 'DifferenceEngine::showFirstRevision'; + wfProfileIn( $fname ); + + + $this->mOldid = $this->mNewid; # hack to make loadText() work. + + # Get article text from the DB + # + if ( ! $this->loadText() ) { + $t = $wgTitle->getPrefixedText() . " (Diff: {$this->mOldid}, " . + "{$this->mNewid})"; + $mtext = wfMsg( 'missingarticle', $t ); + $wgOut->setPagetitle( wfMsg( 'errorpagetitle' ) ); + $wgOut->addHTML( $mtext ); + wfProfileOut( $fname ); + return; + } + + # Check if user is allowed to look at this page. If not, bail out. + # + if ( !( $this->mOldPage->userCanRead() ) ) { + $wgOut->loginToUse(); + $wgOut->output(); + wfProfileOut( $fname ); + exit; + } + + # Prepare the header box + # + $sk = $wgUser->getSkin(); + + $uTLink = $sk->makeLinkObj( Title::makeTitleSafe( NS_USER_TALK, $this->mOldUser ), $wgLang->getNsText( NS_TALK ) ); + $userLink = $sk->makeLinkObj( Title::makeTitleSafe( NS_USER, $this->mOldUser ), $this->mOldUser ); + $contribs = $sk->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Contributions' ), wfMsg( 'contribslink' ), + 'target=' . urlencode($this->mOldUser) ); + $nextlink = $sk->makeKnownLinkObj( $wgTitle, wfMsg( 'nextdiff' ), 'diff=next&oldid='.$this->mNewid ); + $header = "
{$this->mOldtitle}
$userLink " . + "($uTLink | $contribs)
" . $this->mOldComment . + '
' . $nextlink. "
\n"; + + $wgOut->addHTML( $header ); + + $wgOut->setSubtitle( wfMsg( 'difference' ) ); + $wgOut->setRobotpolicy( 'noindex,follow' ); + + + # Show current revision + # + $wgOut->addHTML( "

{$this->mPagetitle}

\n" ); + $wgOut->addWikiText( $this->mNewtext ); + wfProfileOut( $fname ); } @@ -92,23 +218,24 @@ class DifferenceEngine { { global $wgOut, $wgUseExternalDiffEngine; - $otext = str_replace( "\r\n", "\n", htmlspecialchars( $otext ) ); - $ntext = str_replace( "\r\n", "\n", htmlspecialchars( $ntext ) ); + $wgOut->addHTML( " + + + + + + " ); - - $wgOut->addHTML( "
{$otitle}{$ntitle}
- - -\n" ); if ( $wgUseExternalDiffEngine ) { - dl("php_wikidiff.so"); + # For historical reasons, external diff engine expects + # input text to be HTML-escaped already + $otext = str_replace( "\r\n", "\n", htmlspecialchars ( $otext ) ); + $ntext = str_replace( "\r\n", "\n", htmlspecialchars ( $ntext ) ); + dl('php_wikidiff.so'); $wgOut->addHTML( wikidiff_do_diff( $otext, $ntext, 2) ); } else { - $ota = explode( "\n", $otext); - $nta = explode( "\n", $ntext); + $ota = explode( "\n", str_replace( "\r\n", "\n", $otext ) ); + $nta = explode( "\n", str_replace( "\r\n", "\n", $ntext ) ); $diffs = new Diff( $ota, $nta ); $formatter = new TableDiffFormatter(); $formatter->format( $diffs ); @@ -124,18 +251,21 @@ cellpadding='0' cellspacing='4px' class='diff'> function loadText() { global $wgTitle, $wgOut, $wgLang; - $fname = "DifferenceEngine::loadText"; - + $fname = 'DifferenceEngine::loadText'; + $dbr =& wfGetDB( DB_SLAVE ); if ( 0 == $this->mNewid || 0 == $this->mOldid ) { $wgOut->setArticleFlag( true ); - $this->mNewtitle = wfMsg( "currentrev" ); + $newLink = $wgTitle->getLocalUrl(); + $this->mPagetitle = wfMsg( 'currentrev' ); + $this->mNewtitle = "{$this->mPagetitle}"; $id = $wgTitle->getArticleID(); - - $s = $dbr->getArray( 'cur', array( 'cur_text', 'cur_user_text', 'cur_comment' ), + + $s = $dbr->getArray( 'cur', array( 'cur_text', 'cur_user_text', 'cur_comment' ), array( 'cur_id' => $id ), $fname ); - if ( $s === false ) { - return false; + if ( $s === false ) { + wfDebug( "Unable to load cur_id $id\n" ); + return false; } $this->mNewPage = &$wgTitle; @@ -146,44 +276,53 @@ cellpadding='0' cellspacing='4px' class='diff'> $s = $dbr->getArray( 'old', array( 'old_namespace','old_title','old_timestamp', 'old_text', 'old_flags','old_user_text','old_comment' ), array( 'old_id' => $this->mNewid ), $fname ); - if ( $s === false ) { - return false; + if ( $s === false ) { + wfDebug( "Unable to load old_id {$this->mNewid}\n" ); + return false; } $this->mNewtext = Article::getRevisionText( $s ); $t = $wgLang->timeanddate( $s->old_timestamp, true ); $this->mNewPage = Title::MakeTitle( $s->old_namespace, $s->old_title ); - $this->mNewtitle = wfMsg( "revisionasof", $t ); + $newLink = $wgTitle->getLocalUrl ('oldid=' . $this->mNewid); + $this->mPagetitle = wfMsg( 'revisionasof', $t ); + $this->mNewtitle = "{$this->mPagetitle}"; $this->mNewUser = $s->old_user_text; $this->mNewComment = $s->old_comment; } if ( 0 == $this->mOldid ) { - $s = $dbr->getArray( 'old', - array( 'old_namespace','old_title','old_timestamp','old_text', 'old_flags','old_user_text','old_comment' ), + $s = $dbr->getArray( 'old', + array( 'old_namespace','old_title','old_timestamp','old_text', 'old_flags','old_user_text','old_comment' ), array( /* WHERE */ - 'old_namespace' => $this->mNewPage->getNamespace(), - 'old_title' => $this->mNewPage->getDBkey() + 'old_namespace' => $this->mNewPage->getNamespace(), + 'old_title' => $this->mNewPage->getDBkey() ), $fname, array( 'ORDER BY' => 'inverse_timestamp', 'USE INDEX' => 'name_title_timestamp' ) ); + if ( $s === false ) { + wfDebug( 'Unable to load ' . $this->mNewPage->getPrefixedDBkey . " from old\n" ); + return false; + } } else { - $s = $dbr->getArray( 'old', + $s = $dbr->getArray( 'old', array( 'old_namespace','old_title','old_timestamp','old_text','old_flags','old_user_text','old_comment'), - array( 'old_id' => $this->mOldid ), + array( 'old_id' => $this->mOldid ), $fname ); - } - if ( $s === false ) { - return false; + if ( $s === false ) { + wfDebug( "Unable to load old_id {$this->mOldid}\n" ); + return false; + } } $this->mOldPage = Title::MakeTitle( $s->old_namespace, $s->old_title ); $this->mOldtext = Article::getRevisionText( $s ); $t = $wgLang->timeanddate( $s->old_timestamp, true ); - $this->mOldtitle = wfMsg( "revisionasof", $t ); + $oldLink = $this->mOldPage->getLocalUrl ('oldid=' . $this->mOldid); + $this->mOldtitle = "" . wfMsg( 'revisionasof', $t ) . ''; $this->mOldUser = $s->old_user_text; $this->mOldComment = $s->old_comment; - + return true; } } @@ -196,13 +335,17 @@ cellpadding='0' cellspacing='4px' class='diff'> define('USE_ASSERTS', function_exists('assert')); +/** + * @todo document + * @package MediaWiki + */ class _DiffOp { var $type; var $orig; var $closing; - + function reverse() { - trigger_error("pure virtual", E_USER_ERROR); + trigger_error('pure virtual', E_USER_ERROR); } function norig() { @@ -214,9 +357,13 @@ class _DiffOp { } } +/** + * @todo document + * @package MediaWiki + */ class _DiffOp_Copy extends _DiffOp { var $type = 'copy'; - + function _DiffOp_Copy ($orig, $closing = false) { if (!is_array($closing)) $closing = $orig; @@ -229,9 +376,13 @@ class _DiffOp_Copy extends _DiffOp { } } +/** + * @todo document + * @package MediaWiki + */ class _DiffOp_Delete extends _DiffOp { var $type = 'delete'; - + function _DiffOp_Delete ($lines) { $this->orig = $lines; $this->closing = false; @@ -242,9 +393,13 @@ class _DiffOp_Delete extends _DiffOp { } } +/** + * @todo document + * @package MediaWiki + */ class _DiffOp_Add extends _DiffOp { var $type = 'add'; - + function _DiffOp_Add ($lines) { $this->closing = $lines; $this->orig = false; @@ -255,9 +410,13 @@ class _DiffOp_Add extends _DiffOp { } } +/** + * @todo document + * @package MediaWiki + */ class _DiffOp_Change extends _DiffOp { var $type = 'change'; - + function _DiffOp_Change ($orig, $closing) { $this->orig = $orig; $this->closing = $closing; @@ -267,8 +426,8 @@ class _DiffOp_Change extends _DiffOp { return new _DiffOp_Change($this->closing, $this->orig); } } - - + + /** * Class used internally by Diff to actually compute the diffs. * @@ -287,6 +446,7 @@ class _DiffOp_Change extends _DiffOp { * are my own. * * @author Geoffrey T. Dairiki + * @package MediaWiki * @access private */ class _DiffEngine @@ -301,7 +461,7 @@ class _DiffEngine unset($this->seq); unset($this->in_seq); unset($this->lcs); - + // Skip leading common lines. for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) { if ($from_lines[$skip] != $to_lines[$skip]) @@ -315,7 +475,7 @@ class _DiffEngine break; $this->xchanged[$xi] = $this->ychanged[$yi] = false; } - + // Ignore lines which do not exist in both files. for ($xi = $skip; $xi < $n_from - $endskip; $xi++) $xhash[$from_lines[$xi]] = 1; @@ -367,7 +527,7 @@ class _DiffEngine $add = array(); while ($yi < $n_to && $this->ychanged[$yi]) $add[] = $to_lines[$yi++]; - + if ($delete && $add) $edits[] = new _DiffOp_Change($delete, $add); elseif ($delete) @@ -377,7 +537,7 @@ class _DiffEngine } return $edits; } - + /* Divide the Largest Common Subsequence (LCS) of the sequences * [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally @@ -397,7 +557,7 @@ class _DiffEngine */ function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks) { $flip = false; - + if ($xlim - $xoff > $ylim - $yoff) { // Things seems faster (I'm not sure I understand why) // when the shortest sequence in X. @@ -417,7 +577,7 @@ class _DiffEngine $this->seq[0]= $yoff - 1; $this->in_seq = array(); $ymids[0] = array(); - + $numer = $xlim - $xoff + $nchunks - 1; $x = $xoff; for ($chunk = 0; $chunk < $nchunks; $chunk++) { @@ -584,14 +744,14 @@ class _DiffEngine */ while ($j < $other_len && $other_changed[$j]) $j++; - + while ($i < $len && ! $changed[$i]) { USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]'); $i++; $j++; while ($j < $other_len && $other_changed[$j]) $j++; } - + if ($i == $len) break; @@ -672,8 +832,10 @@ class _DiffEngine /** * Class representing a 'diff' between two sequences of strings. + * @todo document + * @package MediaWiki */ -class Diff +class Diff { var $edits; @@ -722,7 +884,7 @@ class Diff } return true; } - + /** * Compute the length of the Longest Common Subsequence (LCS). * @@ -749,7 +911,7 @@ class Diff */ function orig() { $lines = array(); - + foreach ($this->edits as $edit) { if ($edit->orig) array_splice($lines, sizeof($lines), 0, $edit->orig); @@ -767,7 +929,7 @@ class Diff */ function closing() { $lines = array(); - + foreach ($this->edits as $edit) { if ($edit->closing) array_splice($lines, sizeof($lines), 0, $edit->closing); @@ -776,7 +938,7 @@ class Diff } /** - * Check a Diff for validity. + * Check a Diff for validity. * * This is here only for debugging purposes. */ @@ -801,15 +963,16 @@ class Diff } $lcs = $this->lcs(); - trigger_error("Diff okay: LCS = $lcs", E_USER_NOTICE); + trigger_error('Diff okay: LCS = '.$lcs, E_USER_NOTICE); } } - + /** * FIXME: bad name. + * @todo document + * @package MediaWiki */ -class MappedDiff -extends Diff +class MappedDiff extends Diff { /** * Constructor. @@ -839,7 +1002,7 @@ extends Diff assert(sizeof($from_lines) == sizeof($mapped_from_lines)); assert(sizeof($to_lines) == sizeof($mapped_to_lines)); - + $this->Diff($mapped_from_lines, $mapped_to_lines); $xi = $yi = 0; @@ -849,7 +1012,7 @@ extends Diff $orig = array_slice($from_lines, $xi, sizeof($orig)); $xi += sizeof($orig); } - + $closing = &$this->edits[$i]->closing; if (is_array($closing)) { $closing = array_slice($to_lines, $yi, sizeof($closing)); @@ -865,6 +1028,8 @@ extends Diff * This class formats the diff in classic diff format. * It is intended that this class be customized via inheritance, * to obtain fancier outputs. + * @todo document + * @package MediaWiki */ class DiffFormatter { @@ -958,7 +1123,7 @@ class DiffFormatter elseif ($edit->type == 'change') $this->_changed($edit->orig, $edit->closing); else - trigger_error("Unknown edit type", E_USER_ERROR); + trigger_error('Unknown edit type', E_USER_ERROR); } $this->_end_block(); } @@ -981,11 +1146,11 @@ class DiffFormatter return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg; } - + function _start_block($header) { echo $header; } - + function _end_block() { } @@ -993,16 +1158,16 @@ class DiffFormatter foreach ($lines as $line) echo "$prefix $line\n"; } - + function _context($lines) { $this->_lines($lines); } function _added($lines) { - $this->_lines($lines, ">"); + $this->_lines($lines, '>'); } function _deleted($lines) { - $this->_lines($lines, "<"); + $this->_lines($lines, '<'); } function _changed($orig, $closing) { @@ -1015,11 +1180,15 @@ class DiffFormatter /** * Additions by Axel Boldt follow, partly taken from diff.php, phpwiki-1.3.3 - * + * */ define('NBSP', ' '); // iso-8859-x non-breaking space. +/** + * @todo document + * @package MediaWiki + */ class _HWLDF_WordAccumulator { function _HWLDF_WordAccumulator () { $this->_lines = array(); @@ -1030,22 +1199,26 @@ class _HWLDF_WordAccumulator { function _flushGroup ($new_tag) { if ($this->_group !== '') { - if ($this->_tag == 'mark') - $this->_line .= ''.$this->_group.''; - else - $this->_line .= $this->_group; - } + if ($this->_tag == 'mark') + $this->_line .= '' . + htmlspecialchars ( $this->_group ) . ''; + else + $this->_line .= htmlspecialchars ( $this->_group ); + } $this->_group = ''; $this->_tag = $new_tag; } - + function _flushLine ($new_tag) { $this->_flushGroup($new_tag); if ($this->_line != '') - $this->_lines[] = $this->_line; + array_push ( $this->_lines, $this->_line ); + else + # make empty lines visible by inserting an NBSP + array_push ( $this->_lines, NBSP ); $this->_line = ''; } - + function addWords ($words, $tag = '') { if ($tag != $this->_tag) $this->_flushGroup($tag); @@ -1055,7 +1228,6 @@ class _HWLDF_WordAccumulator { if ($word == '') continue; if ($word[0] == "\n") { - $this->_group .= NBSP; $this->_flushLine($tag); $word = substr($word, 1); } @@ -1070,20 +1242,22 @@ class _HWLDF_WordAccumulator { } } +/** + * @todo document + * @package MediaWiki + */ class WordLevelDiff extends MappedDiff { function WordLevelDiff ($orig_lines, $closing_lines) { list ($orig_words, $orig_stripped) = $this->_split($orig_lines); list ($closing_words, $closing_stripped) = $this->_split($closing_lines); - + $this->MappedDiff($orig_words, $closing_words, $orig_stripped, $closing_stripped); } function _split($lines) { - // FIXME: fix POSIX char class. -# if (!preg_match_all('/ ( [^\S\n]+ | [[:alnum:]]+ | . ) (?: (?!< \n) [^\S\n])? /xs', if (!preg_match_all('/ ( [^\S\n]+ | [0-9_A-Za-z\x80-\xff]+ | . ) (?: (?!< \n) [^\S\n])? /xs', implode("\n", $lines), $m)) { @@ -1094,7 +1268,7 @@ class WordLevelDiff extends MappedDiff function orig () { $orig = new _HWLDF_WordAccumulator; - + foreach ($this->edits as $edit) { if ($edit->type == 'copy') $orig->addWords($edit->orig); @@ -1106,7 +1280,7 @@ class WordLevelDiff extends MappedDiff function closing () { $closing = new _HWLDF_WordAccumulator; - + foreach ($this->edits as $edit) { if ($edit->type == 'copy') $closing->addWords($edit->closing); @@ -1119,7 +1293,8 @@ class WordLevelDiff extends MappedDiff /** * Wikipedia Table style diff formatter. - * + * @todo document + * @package MediaWiki */ class TableDiffFormatter extends DiffFormatter { @@ -1127,10 +1302,10 @@ class TableDiffFormatter extends DiffFormatter $this->leading_context_lines = 2; $this->trailing_context_lines = 2; } - + function _block_header( $xbeg, $xlen, $ybeg, $ylen ) { - $l1 = wfMsg( "lineno", $xbeg ); - $l2 = wfMsg( "lineno", $ybeg ); + $l1 = wfMsg( 'lineno', $xbeg ); + $l2 = wfMsg( 'lineno', $ybeg ); $r = '\n" . '\n"; @@ -1145,39 +1320,40 @@ class TableDiffFormatter extends DiffFormatter function _end_block() { } - function _lines( $lines, $prefix=' ', $color="white" ) { + function _lines( $lines, $prefix=' ', $color='white' ) { } + # HTML-escape parameter before calling this function addedLine( $line ) { - return ''; + return ""; } + # HTML-escape parameter before calling this function deletedLine( $line ) { - return ''; + return ""; + } + + # HTML-escape parameter before calling this + function contextLine( $line ) { + return ""; } function emptyLine() { return ''; } - function contextLine( $line ) { - return ''; - } - - function _added($lines) { + function _added( $lines ) { global $wgOut; foreach ($lines as $line) { $wgOut->addHTML( '' . $this->emptyLine() . - $this->addedLine( $line ) . "\n" ); + $this->addedLine( htmlspecialchars ( $line ) ) . "\n" ); } } function _deleted($lines) { global $wgOut; foreach ($lines as $line) { - $wgOut->addHTML( '' . $this->deletedLine( $line ) . + $wgOut->addHTML( '' . $this->deletedLine( htmlspecialchars ( $line ) ) . $this->emptyLine() . "\n" ); } } @@ -1185,8 +1361,9 @@ class TableDiffFormatter extends DiffFormatter function _context( $lines ) { global $wgOut; foreach ($lines as $line) { - $wgOut->addHTML( '' . $this->contextLine( $line ) . - $this->contextLine( $line ) . "\n" ); + $wgOut->addHTML( '' . + $this->contextLine( htmlspecialchars ( $line ) ) . + $this->contextLine( htmlspecialchars ( $line ) ) . "\n" ); } } @@ -1196,12 +1373,18 @@ class TableDiffFormatter extends DiffFormatter $del = $diff->orig(); $add = $diff->closing(); + # Notice that WordLevelDiff returns HTML-escaped output. + # Hence, we will be calling addedLine/deletedLine without HTML-escaping. + while ( $line = array_shift( $del ) ) { $aline = array_shift( $add ); $wgOut->addHTML( '' . $this->deletedLine( $line ) . - $this->addedLine( $aline ) . "\n" ); + $this->addedLine( $aline ) . "\n" ); + } + foreach ($add as $line) { # If any leftovers + $wgOut->addHTML( '' . $this->emptyLine() . + $this->addedLine( $line ) . "\n" ); } - $this->_added( $add ); # If any leftovers } }
-{$otitle} -{$ntitle}
'.$l1."'.$l2."
+' . - $line.'+{$line}-' . - $line.'-{$line} {$line}  '.$line.'