diff --git a/AbuseFilter.class.php b/AbuseFilter.class.php
index def6e57c7..0989fdeaf 100644
--- a/AbuseFilter.class.php
+++ b/AbuseFilter.class.php
@@ -2200,4 +2200,29 @@ class AbuseFilter {
return $text;
}
+ /*
+ * Get the history ID of the first change to a given filter
+ *
+ * @param $filterId integer: Filter id
+ * @return integer|bool
+ */
+ public static function getFirstFilterChange( $filterID ) {
+ static $firstChanges = array();
+
+ if ( !isset( $firstChanges[ $filterID ] ) ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $row = $dbr->selectRow(
+ 'abuse_filter_history',
+ 'afh_id',
+ array(
+ 'afh_filter' => $filterID,
+ ),
+ __METHOD__,
+ array( 'ORDER BY' => 'afh_timestamp ASC' )
+ );
+ $firstChanges[$filterID] = $row->afh_id;
+ }
+
+ return $firstChanges[$filterID];
+ }
}
diff --git a/AbuseFilter.i18n.php b/AbuseFilter.i18n.php
index 636c4685c..589221a51 100644
--- a/AbuseFilter.i18n.php
+++ b/AbuseFilter.i18n.php
@@ -478,6 +478,8 @@ For full details, see [[Special:AbuseFilter/history|the list]] of recent filter
'abusefilter-diff-pattern' => 'Filter conditions',
'abusefilter-diff-invalid' => 'Unable to fetch the requested versions',
'abusefilter-diff-backhistory' => 'Back to filter history',
+ 'abusefilter-diff-prev' => 'Older change',
+ 'abusefilter-diff-next' => 'Newer change',
// Import interface
'abusefilter-import-intro' => 'You can use this interface to import filters from other wikis.
@@ -929,6 +931,8 @@ This is also used in {{msg-mw|Abusefilter-revert-preview-intro}}. When changing
* $2 is a link to a username.
* $3 is a raw username, which can be used for GENDER.',
'abusefilter-diff-info' => "Header for the box containing the basic information about a user account, displayed on the 'user profile' tab of the [[Special:Preferences|user preferences]] special page.",
+ 'abusefilter-diff-prev' => 'Link to the diff view for the previous change to this filter',
+ 'abusefilter-diff-next' => 'Link to the diff view for the next change to this filter',
'abusefilter-import-intro' => "Do not ''translate'' {{int:abusefilter-edit-export}}, {{int:abusefilter-tools-subtitle}}, and {{int:abusefilter-import-submit}} unless you absolute must substitute any of them.",
'abusefilter-group-default' => 'The name for the default filter group. Most filters will be in this group.',
);
diff --git a/Views/AbuseFilterViewDiff.php b/Views/AbuseFilterViewDiff.php
index 0195e22d2..6382dba2b 100644
--- a/Views/AbuseFilterViewDiff.php
+++ b/Views/AbuseFilterViewDiff.php
@@ -3,6 +3,7 @@
class AbuseFilterViewDiff extends AbuseFilterView {
var $mOldVersion = null;
var $mNewVersion = null;
+ var $mNextHistoryId = null;
var $mFilter = null;
function show() {
@@ -16,7 +17,7 @@ class AbuseFilterViewDiff extends AbuseFilterView {
}
foreach ( $links as $msg => $title ) {
- $links[$msg] = Linker::link( $title, $this->msg( $msg )->parse() );
+ $links[$msg] = Linker::link( $title, $this->msg( $msg )->escaped() );
}
$backlinks = $this->getLanguage()->pipeList( $links );
@@ -24,6 +25,33 @@ class AbuseFilterViewDiff extends AbuseFilterView {
if ( $show ) {
$out->addHTML( $this->formatDiff() );
+
+ // Next and previous change links
+ $links = array();
+ if ( AbuseFilter::getFirstFilterChange( $this->mFilter ) != $this->mOldVersion['meta']['history_id'] ) {
+ // Create a "previous change" link if this isn't the first change of the given filter
+ $links[] = Linker::link(
+ $this->getTitle(
+ 'history/' . $this->mFilter . '/diff/prev/' . $this->mOldVersion['meta']['history_id']
+ ),
+ $this->getLanguage()->getArrow( 'backwards' ) . ' ' . $this->msg( 'abusefilter-diff-prev' )->escaped()
+ );
+ }
+
+ if ( !is_null( $this->mNextHistoryId ) ) {
+ // Create a "next change" link if this isn't the last change of the given filter
+ $links[] = Linker::link(
+ $this->getTitle(
+ 'history/' . $this->mFilter . '/diff/prev/' . $this->mNextHistoryId
+ ),
+ $this->msg( 'abusefilter-diff-next' )->escaped() . ' ' . $this->getLanguage()->getArrow( 'forwards' )
+ );
+ }
+
+ if ( count( $links ) > 0 ) {
+ $backlinks = $this->getLanguage()->pipeList( $links );
+ $out->addHTML( Xml::tags( 'p', null, $backlinks ) );
+ }
}
}
@@ -47,9 +75,35 @@ class AbuseFilterViewDiff extends AbuseFilterView {
return false;
}
+ $this->mNextHistoryId = $this->getNextHistoryId( $this->mNewVersion['meta']['history_id'] , 'next' );
+
return true;
}
+ /**
+ * Get the history ID of the next change
+ *
+ * @param $historyId Integer: History id to find next change of
+ * @return Integer|Null: Id of the next change or null if there isn't one
+ */
+ function getNextHistoryId( $historyId ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $row = $dbr->selectRow(
+ 'abuse_filter_history',
+ 'afh_id',
+ array(
+ 'afh_filter' => $this->mFilter,
+ 'afh_id > ' . $dbr->addQuotes( $historyId ),
+ ),
+ __METHOD__,
+ array( 'ORDER BY' => 'afh_timestamp ASC' )
+ );
+ if ( $row ) {
+ return $row->afh_id;
+ }
+ return null;
+ }
+
function loadSpec( $spec, $otherSpec ) {
static $dependentSpecs = array( 'prev', 'next' );
static $cache = array();
@@ -106,7 +160,7 @@ class AbuseFilterViewDiff extends AbuseFilterView {
'afh_id>' . $dbr->addQuotes( $other['meta']['history_id'] ),
),
__METHOD__,
- array( 'ORDER BY' => 'afh_timestamp DESC' )
+ array( 'ORDER BY' => 'afh_timestamp ASC' )
);
if ( $other && !$row ) {
diff --git a/Views/AbuseFilterViewHistory.php b/Views/AbuseFilterViewHistory.php
index 07d68d382..05adad9e8 100644
--- a/Views/AbuseFilterViewHistory.php
+++ b/Views/AbuseFilterViewHistory.php
@@ -158,9 +158,13 @@ class AbuseFilterHistoryPager extends TablePager {
$formatted = Linker::link( $title, $value );
break;
case 'afh_id':
- $title = $this->mPage->getTitle(
- 'history/' . $row->afh_filter . "/diff/prev/$value" );
- $formatted = Linker::link( $title, $this->msg( 'abusefilter-history-diff' )->parse() );
+ $formatted = '';
+ if ( AbuseFilter::getFirstFilterChange( $row->afh_filter ) != $value ) {
+ // Set a link to a diff with the previous version if this isn't the first edit to the filter
+ $title = $this->mPage->getTitle(
+ 'history/' . $row->afh_filter . "/diff/prev/$value" );
+ $formatted = Linker::link( $title, $this->msg( 'abusefilter-history-diff' )->parse() );
+ }
break;
default:
$formatted = "Unable to format $name";