Extension:TransformChanges.php
<? /**
* TransformChanges extension - Makes recent-changes and watchlists render in nice columns for easier reading * Template:Php
* See http://www.mediawiki.org/wiki/Extension:TransformChanges for installation and usage details * * @package MediaWiki * @subpackage Extensions * @author Aran Dunkley User:Nad * @copyright © 2007 Aran Dunkley * @licence GNU General Public Licence 2.0 or later */
if (!defined('MEDIAWIKI')) die('Not an entry point.');
define('TRANSFORMCHANGES_VERSION', '1.1.3, 2009-01-29');
$wgExtensionCredits['other'][] = array( 'name' => 'TransformChanges', 'author' => 'User:Nad, User:Fish1203', 'description' => 'Makes recent-changes and watchlists render in nice columns for easier reading.', 'url' => 'http://www.organicdesign.co.nz/Extension:TransformChanges', 'version' => TRANSFORMCHANGES_VERSION );
- Disable enhanced recent changes
$wgExtensionFunctions[] = 'wfSetupTransformChanges'; function wfSetupTransformChanges() { global $wgUser; $wgUser->setOption('usenewrc', false); }
- A hack for 1.12+ to ensure the SpecialPageExecuteAfterPage hook gets called
$wgHooks['ChangesListInsertArticleLink'][] = 'wfRunSpecialPageExecuteAfterPageHook'; function wfRunSpecialPageExecuteAfterPageHook() {
# Bail if already done static $done = 0; if ($done++) return true;
# Create a replica of the OutputPage class which calls the SpecialPageExecuteAfterPage after recentchanges rendered class OutputPage2 extends OutputPage { function addHTML($text) { parent::addHTML($text);
if (ereg('^
', $text)) wfRunHooks('SpecialPageExecuteAfterPage', array());
}
}
# Replace the global $wgOut object with an identical instance of the new OutputPage2 class
global $wgOut;
$oldOut = $wgOut;
$wgOut = new OutputPage2();
foreach (array_keys(get_class_vars('OutputPage')) as $k) $wgOut->$k = $oldOut->$k;
return true;
}
$wgHooks['SpecialPageExecuteAfterPage'][] = 'wfTransformChanges';
function wfTransformChanges() {
global $wgOut;
$title = $wgOut->getPageTitle();
if ($title != wfMsgForContent('recentchanges') && $title != wfMsgForContent('watchlist')) return true;
$text =& $wgOut->mBodytext;
$text = preg_replace('|(\\s*)?(.+?)
\\s*()- |s', '$3
- ', $text);
# Edits by Fish1203
# (http://www.mediawiki.org/wiki/User:Fish1203)
# solving the PHP preg_replace_callback() pcre.backtrack_limit problem
# splitting in days
$parts = explode("", $text);
$first = 1;
$nbedits = 50;
$text = $parts[0] . "";
foreach ($parts as $part) {
# skipping first part (= Special:RecentChanges "header")
if ($first == 1) $first = 0;
else {
$nbsubparts = (substr_count($part, "")-1); # how many edits for this day ?
# if more than $nbedits edits for this day
if ($nbsubparts > $nbedits) {
$divide = intval(abs($nbsubparts/$nbedits));
# splits each day in parts containing $nbedits edits (max.)
$start = 0;
$parts2 = array();
for ($lp=0; $lp<$divide; $lp++) {
$parts2[$lp] = substr($part, $start, (strposn($part, "", ($lp+1)*$nbedits))-$start );
$start = (strposn($part, "", ($lp+1)*$nbedits));
}
# last part for the day
$parts2[$divide] = substr($part, $start, strlen($part));
foreach($parts2 as $part2) {
$part2 = "$part2
";
$text .= preg_replace_callback("|(.+?)
|s", 'wfTransformChangesUL', $part2);
}
}
else {
$part = "$part
";
$text .= preg_replace_callback("|(.+?)
|s", 'wfTransformChangesUL', $part);
}
}
}
# there may be one last tag remaining... just remove it... :-)
$text = str_replace("", "", $text);
$text .= "
";
return true;
}
function wfTransformChangesUL($match) {
global $wgTransformChangesRow;
$wgTransformChangesRow = 'odd';
$rows = preg_replace_callback('|<li\\s*(.*?)>(.+?)|s', 'wfTransformChangesLI', $match[1]);
return $rows;
}
function wfTransformChangesLI($match) {
global $wgTransformChangesRow, $wgSimpleSecurity;
$wgTransformChangesRow = $wgTransformChangesRow == 'even' ? 'odd' : 'even';
$talk = ;
list(, $date, $text) = $match;
$cols = array('time', 'title', 'user', 'talk', 'info', 'comment', 'diff');
# OrganicDesign has different columns and order
#$cols = array('time','diff','title','comment','user','info');
$ncols = count($cols);
$row = ;
$error = 'Error: match failed!';
if ($date) {
$row = "$date\n";
$wgTransformChangesRow = 'even';
# OrganicDesign's table header
#static $head = "TimeActionsItem changedDescription of changeChanged byDetails";
#$row .= $head;
#$head = ;
}
$row .= "";
if (preg_match('|^(.*?); (\\d+:\\d+)(.+?)(<a.+?</a>\\))\\s*(.*?)$|', $text, $m)) {
list(, $diff, $time, $bytes, $user, $comment) = $m;
if (preg_match('|^(.+\\)).*?\\. \\.\\s*(.*?)\\s*(<a.+)$|', $diff, $m)) list(, $diff, $info, $title) = $m; else $info = $title = ;
if (preg_match('|(\\(.+?\\))|', $bytes, $m)) $info .= "$m[1]";
# Remove talk for email or IP users and make user lowercase
if (preg_match('|(<a.+?</a>).+?(\\(.+?</a>\\))|', $user, $m)) {
list(, $user, $talk) = $m;
if (ereg('@', $user) || !eregi('[a-z]',$user)) { $talk = ; $user = strtolower($user); }
}
if (preg_match('|\\((.+)\\)|', $comment, $m)) $comment = $m[1];
# Only show row if ok by SimpleSecurity extension
$allowed = true;
if (preg_match('|title="(.+?)"|', $title, $m) && is_object($wgSimpleSecurity)) {
global $wgUser;
$t = Title::newFromText($m[1]);
$allowed = version_compare(SIMPLESECURITY_VERSION, '4.0.0') < 0
? $wgSimpleSecurity->validateTitle('view', $t)
: $wgSimpleSecurity->userCanReadTitle($wgUser, $t, $error);
}
# OrganicDesign has an edit link instead of talk and hist
#$talk = preg_replace('| \\|.+</a>|',,$talk);
#$diff = preg_replace('|curid=[0-9]+&(amp;)?action=history|','action=edit',$diff);
#$diff = preg_replace('|>hist<|','>edit<',$diff);
#$user .= " $talk";
if ($allowed) foreach ($cols as $col) {
$val = isset($$col) ? $$col : ;
$row .= "$val";
}
} else $row = $error;
$row .= "\n";
return $row;
}
- Returns the position of the $n-th $c token (string) in $haystack (= position at the end of the token)
function strposn($haystack, $c, $n) {
$a = explode($c, $haystack, $n+1);
if ($n <= 0 || count($a) <= $n) return false;
return strlen($haystack)-strlen($a[$n]);
}
# Edits by Fish1203 # (http://www.mediawiki.org/wiki/User:Fish1203) # solving the PHP preg_replace_callback() pcre.backtrack_limit problem
# splitting in days
$parts = explode("- ", $text);
$first = 1;
$nbedits = 50;
$text = $parts[0] . "";
foreach ($parts as $part) {
# skipping first part (= Special:RecentChanges "header")
if ($first == 1) $first = 0;
else {
$nbsubparts = (substr_count($part, "")-1); # how many edits for this day ?
- Returns the position of the $n-th $c token (string) in $haystack (= position at the end of the token)
# if more than $nbedits edits for this day if ($nbsubparts > $nbedits) { $divide = intval(abs($nbsubparts/$nbedits));
# splits each day in parts containing $nbedits edits (max.) $start = 0; $parts2 = array(); for ($lp=0; $lp<$divide; $lp++) {
$parts2[$lp] = substr($part, $start, (strposn($part, "", ($lp+1)*$nbedits))-$start ); $start = (strposn($part, "", ($lp+1)*$nbedits));}
# last part for the day $parts2[$divide] = substr($part, $start, strlen($part));
foreach($parts2 as $part2) {
$part2 = "- $part2
- (.+?)
} } else {
$part = "- $part
- (.+?)
} } }
# there may be one last tag remaining... just remove it... :-) $text = str_replace("", "", $text); $text .= "return true; }
function wfTransformChangesUL($match) { global $wgTransformChangesRow; $wgTransformChangesRow = 'odd';
$rows = preg_replace_callback('|<li\\s*(.*?)>(.+?)|s', 'wfTransformChangesLI', $match[1]);return $rows; }
function wfTransformChangesLI($match) { global $wgTransformChangesRow, $wgSimpleSecurity; $wgTransformChangesRow = $wgTransformChangesRow == 'even' ? 'odd' : 'even'; $talk = ; list(, $date, $text) = $match; $cols = array('time', 'title', 'user', 'talk', 'info', 'comment', 'diff');
# OrganicDesign has different columns and order #$cols = array('time','diff','title','comment','user','info');
$ncols = count($cols); $row = ;
$error = 'Error: match failed!';if ($date) {
$row = "$date\n";$wgTransformChangesRow = 'even';
# OrganicDesign's table header
#static $head = "TimeActionsItem changedDescription of changeChanged byDetails";#$row .= $head; #$head = ; }
$row .= ""; if (preg_match('|^(.*?); (\\d+:\\d+)(.+?)(<a.+?</a>\\))\\s*(.*?)$|', $text, $m)) { list(, $diff, $time, $bytes, $user, $comment) = $m; if (preg_match('|^(.+\\)).*?\\. \\.\\s*(.*?)\\s*(<a.+)$|', $diff, $m)) list(, $diff, $info, $title) = $m; else $info = $title = ; if (preg_match('|(\\(.+?\\))|', $bytes, $m)) $info .= "$m[1]"; # Remove talk for email or IP users and make user lowercase if (preg_match('|(<a.+?</a>).+?(\\(.+?</a>\\))|', $user, $m)) { list(, $user, $talk) = $m; if (ereg('@', $user) || !eregi('[a-z]',$user)) { $talk = ; $user = strtolower($user); } } if (preg_match('|\\((.+)\\)|', $comment, $m)) $comment = $m[1]; # Only show row if ok by SimpleSecurity extension $allowed = true; if (preg_match('|title="(.+?)"|', $title, $m) && is_object($wgSimpleSecurity)) { global $wgUser; $t = Title::newFromText($m[1]); $allowed = version_compare(SIMPLESECURITY_VERSION, '4.0.0') < 0 ? $wgSimpleSecurity->validateTitle('view', $t) : $wgSimpleSecurity->userCanReadTitle($wgUser, $t, $error); } # OrganicDesign has an edit link instead of talk and hist #$talk = preg_replace('| \\|.+</a>|',,$talk); #$diff = preg_replace('|curid=[0-9]+&(amp;)?action=history|','action=edit',$diff); #$diff = preg_replace('|>hist<|','>edit<',$diff); #$user .= " $talk"; if ($allowed) foreach ($cols as $col) { $val = isset($$col) ? $$col : ; $row .= "$val";} } else $row = $error;
$row .= "\n"; return $row; }