*/
protected $description;
- /**
- * Callable used to check whether this filter is allowed to take effect
- *
- * @var callable $isAllowedCallable
- */
- protected $isAllowedCallable;
-
/**
* List of conflicting groups
*
* $filterDefinition['label'] string i18n key of label for structured UI.
* $filterDefinition['description'] string i18n key of description for structured
* UI.
- * $filterDefinition['isAllowedCallable'] callable Callable taking two parameters,
- * the class name of the special page and an IContextSource, and returning true
- * if and only if the current user is permitted to use this filter on the current
- * wiki. If it returns false, it will both hide the UI (in all UIs) and prevent
- * the DB query modification from taking effect. (optional, defaults to allowed)
* $filterDefinition['priority'] int Priority integer. Higher value means higher
* up in the group's filter list.
*/
$this->description = $filterDefinition['description'];
}
- if ( isset( $filterDefinition['isAllowedCallable'] ) ) {
- $this->isAllowedCallable = $filterDefinition['isAllowedCallable'];
- }
-
$this->priority = $filterDefinition['priority'];
$this->group->registerFilter( $this );
/**
* Checks whether the filter should display on the unstructured UI
*
- * @param ChangesListSpecialPage $specialPage Current special page
* @return bool Whether to display
*/
- abstract public function displaysOnUnstructuredUi( ChangesListSpecialPage $specialPage );
+ abstract public function displaysOnUnstructuredUi();
/**
* Checks whether the filter should display on the structured UI
* This refers to the exact filter. See also isFeatureAvailableOnStructuredUi.
*
- * @param ChangesListSpecialPage $specialPage Current special page
* @return bool Whether to display
*/
- public function displaysOnStructuredUi( ChangesListSpecialPage $specialPage ) {
- return $this->label !== null && $this->isAllowed( $specialPage );
+ public function displaysOnStructuredUi() {
+ return $this->label !== null;
}
/**
*
* This can either be the exact filter, or a new filter that replaces it.
*/
- public function isFeatureAvailableOnStructuredUi( ChangesListSpecialPage $specialPage ) {
- return $this->displaysOnStructuredUi( $specialPage );
+ public function isFeatureAvailableOnStructuredUi() {
+ return $this->displaysOnStructuredUi();
}
/**
return $this->priority;
}
- /**
- * Checks whether the filter is allowed for the current context
- *
- * @param ChangesListSpecialPage $specialPage Current special page
- * @return bool Whether it is allowed
- */
- public function isAllowed( ChangesListSpecialPage $specialPage ) {
- if ( $this->isAllowedCallable === null ) {
- return true;
- } else {
- return call_user_func(
- $this->isAllowedCallable,
- get_class( $specialPage ),
- $specialPage->getContext()
- );
- }
- }
-
/**
* Gets the CSS class
*
*/
private $filterGroupDefinitions;
+ // Same format as filterGroupDefinitions, but for a single group (reviewStatus)
+ // that is registered conditionally.
+ private $reviewStatusFilterGroupDefinition;
+
+ // Single filter registered conditionally
+ private $hideCategorizationFilterDefinition;
+
/**
* Filter groups, and their contained filters
* This is an associative array (with group name as key) of ChangesListFilterGroup objects.
]
],
- [
- 'name' => 'reviewStatus',
- 'title' => 'rcfilters-filtergroup-reviewstatus',
- 'class' => ChangesListBooleanFilterGroup::class,
- 'filters' => [
- [
- 'name' => 'hidepatrolled',
- 'label' => 'rcfilters-filter-patrolled-label',
- 'description' => 'rcfilters-filter-patrolled-description',
- // rcshowhidepatr-show, rcshowhidepatr-hide
- // wlshowhidepatr
- 'showHideSuffix' => 'showhidepatr',
- 'default' => false,
- 'isAllowedCallable' => function ( $pageClassName, $context ) {
- return $context->getUser()->useRCPatrol();
- },
- 'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
- &$query_options, &$join_conds ) {
-
- $conds[] = 'rc_patrolled = 0';
- },
- 'cssClassSuffix' => 'patrolled',
- 'isRowApplicableCallable' => function ( $ctx, $rc ) {
- return $rc->getAttribute( 'rc_patrolled' );
- },
- ],
- [
- 'name' => 'hideunpatrolled',
- 'label' => 'rcfilters-filter-unpatrolled-label',
- 'description' => 'rcfilters-filter-unpatrolled-description',
- 'default' => false,
- 'isAllowedCallable' => function ( $pageClassName, $context ) {
- return $context->getUser()->useRCPatrol();
- },
- 'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
- &$query_options, &$join_conds ) {
-
- $conds[] = 'rc_patrolled = 1';
- },
- 'cssClassSuffix' => 'unpatrolled',
- 'isRowApplicableCallable' => function ( $ctx, $rc ) {
- return !$rc->getAttribute( 'rc_patrolled' );
- },
- ],
- ],
- ],
+ // reviewStatus (conditional)
[
'name' => 'significance',
'title' => 'rcfilters-filtergroup-significance',
'class' => ChangesListBooleanFilterGroup::class,
+ 'priority' => -6,
'filters' => [
[
'name' => 'hideminor',
'label' => 'rcfilters-filter-pageedits-label',
'description' => 'rcfilters-filter-pageedits-description',
'default' => false,
+ 'priority' => -2,
'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
&$query_options, &$join_conds ) {
'label' => 'rcfilters-filter-newpages-label',
'description' => 'rcfilters-filter-newpages-description',
'default' => false,
+ 'priority' => -3,
'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
&$query_options, &$join_conds ) {
return $rc->getAttribute( 'rc_source' ) === RecentChange::SRC_NEW;
},
],
+
+ // hidecategorization
+
[
- 'name' => 'hidecategorization',
- 'label' => 'rcfilters-filter-categorization-label',
- 'description' => 'rcfilters-filter-categorization-description',
- // rcshowhidecategorization-show, rcshowhidecategorization-hide.
- // wlshowhidecategorization
- 'showHideSuffix' => 'showhidecategorization',
- 'isAllowedCallable' => function ( $pageClassName, $context ) {
- return $context->getConfig()->get( 'RCWatchCategoryMembership' );
+ 'name' => 'hidelog',
+ 'label' => 'rcfilters-filter-logactions-label',
+ 'description' => 'rcfilters-filter-logactions-description',
+ 'default' => false,
+ 'priority' => -5,
+ 'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
+ &$query_options, &$join_conds ) {
+
+ $conds[] = 'rc_type != ' . $dbr->addQuotes( RC_LOG );
},
+ 'cssClassSuffix' => 'src-mw-log',
+ 'isRowApplicableCallable' => function ( $ctx, $rc ) {
+ return $rc->getAttribute( 'rc_source' ) === RecentChange::SRC_LOG;
+ }
+ ],
+ ],
+ ],
+ ];
+
+ $this->reviewStatusFilterGroupDefinition = [
+ [
+ 'name' => 'reviewStatus',
+ 'title' => 'rcfilters-filtergroup-reviewstatus',
+ 'class' => ChangesListBooleanFilterGroup::class,
+ 'priority' => -5,
+ 'filters' => [
+ [
+ 'name' => 'hidepatrolled',
+ 'label' => 'rcfilters-filter-patrolled-label',
+ 'description' => 'rcfilters-filter-patrolled-description',
+ // rcshowhidepatr-show, rcshowhidepatr-hide
+ // wlshowhidepatr
+ 'showHideSuffix' => 'showhidepatr',
'default' => false,
'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
&$query_options, &$join_conds ) {
- $conds[] = 'rc_type != ' . $dbr->addQuotes( RC_CATEGORIZE );
+ $conds[] = 'rc_patrolled = 0';
},
- 'cssClassSuffix' => 'src-mw-categorize',
+ 'cssClassSuffix' => 'patrolled',
'isRowApplicableCallable' => function ( $ctx, $rc ) {
- return $rc->getAttribute( 'rc_source' ) === RecentChange::SRC_CATEGORIZE;
+ return $rc->getAttribute( 'rc_patrolled' );
},
],
[
- 'name' => 'hidelog',
- 'label' => 'rcfilters-filter-logactions-label',
- 'description' => 'rcfilters-filter-logactions-description',
+ 'name' => 'hideunpatrolled',
+ 'label' => 'rcfilters-filter-unpatrolled-label',
+ 'description' => 'rcfilters-filter-unpatrolled-description',
'default' => false,
'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
&$query_options, &$join_conds ) {
- $conds[] = 'rc_type != ' . $dbr->addQuotes( RC_LOG );
+ $conds[] = 'rc_patrolled = 1';
},
- 'cssClassSuffix' => 'src-mw-log',
+ 'cssClassSuffix' => 'unpatrolled',
'isRowApplicableCallable' => function ( $ctx, $rc ) {
- return $rc->getAttribute( 'rc_source' ) === RecentChange::SRC_LOG;
- }
+ return !$rc->getAttribute( 'rc_patrolled' );
+ },
],
],
- ],
+ ]
+ ];
+
+ $this->hideCategorizationFilterDefinition = [
+ 'name' => 'hidecategorization',
+ 'label' => 'rcfilters-filter-categorization-label',
+ 'description' => 'rcfilters-filter-categorization-description',
+ // rcshowhidecategorization-show, rcshowhidecategorization-hide.
+ // wlshowhidecategorization
+ 'showHideSuffix' => 'showhidecategorization',
+ 'default' => false,
+ 'priority' => -4,
+ 'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables, &$fields, &$conds,
+ &$query_options, &$join_conds ) {
+
+ $conds[] = 'rc_type != ' . $dbr->addQuotes( RC_CATEGORIZE );
+ },
+ 'cssClassSuffix' => 'src-mw-categorize',
+ 'isRowApplicableCallable' => function ( $ctx, $rc ) {
+ return $rc->getAttribute( 'rc_source' ) === RecentChange::SRC_CATEGORIZE;
+ },
];
}
}
/**
- * Register all filters and their groups, plus conflicts
+ * Register all filters and their groups (including those from hooks), plus handle
+ * conflicts and defaults.
*
* You might want to customize these in the same method, in subclasses. You can
* call getFilterGroup to access a group, and (on the group) getFilter to access a
protected function registerFilters() {
$this->registerFiltersFromDefinitions( $this->filterGroupDefinitions );
+ // Make sure this is not being transcluded (we don't want to show this
+ // information to all users just because the user that saves the edit can
+ // patrol)
+ if ( !$this->including() && $this->getUser()->useRCPatrol() ) {
+ $this->registerFiltersFromDefinitions( $this->reviewStatusFilterGroupDefinition );
+ }
+
+ $changeTypeGroup = $this->getFilterGroup( 'changeType' );
+
+ if ( $this->getConfig()->get( 'RCWatchCategoryMembership' ) ) {
+ $transformedHideCategorizationDef = $this->transformFilterDefinition(
+ $this->hideCategorizationFilterDefinition
+ );
+
+ $transformedHideCategorizationDef['group'] = $changeTypeGroup;
+
+ $hideCategorization = new ChangesListBooleanFilter(
+ $transformedHideCategorizationDef
+ );
+ }
+
Hooks::run( 'ChangesListSpecialPageStructuredFilters', [ $this ] );
$unstructuredGroupDefinition =
'rcfilters-filter-unregistered-conflicts-user-experience-level'
);
- $changeTypeGroup = $this->getFilterGroup( 'changeType' );
$categoryFilter = $changeTypeGroup->getFilter( 'hidecategorization' );
$logactionsFilter = $changeTypeGroup->getFilter( 'hidelog' );
$pagecreationFilter = $changeTypeGroup->getFilter( 'hidenewpages' );
$significanceTypeGroup = $this->getFilterGroup( 'significance' );
$hideMinorFilter = $significanceTypeGroup->getFilter( 'hideminor' );
- $hideMinorFilter->conflictsWith(
- $categoryFilter,
- 'rcfilters-hideminor-conflicts-typeofchange-global',
- 'rcfilters-hideminor-conflicts-typeofchange',
- 'rcfilters-typeofchange-conflicts-hideminor'
- );
+ // categoryFilter is conditional; see registerFilters
+ if ( $categoryFilter !== null ) {
+ $hideMinorFilter->conflictsWith(
+ $categoryFilter,
+ 'rcfilters-hideminor-conflicts-typeofchange-global',
+ 'rcfilters-hideminor-conflicts-typeofchange',
+ 'rcfilters-typeofchange-conflicts-hideminor'
+ );
+ }
$hideMinorFilter->conflictsWith(
$logactionsFilter,
'rcfilters-hideminor-conflicts-typeofchange-global',
);
}
+ /**
+ * Transforms filter definition to prepare it for constructor.
+ *
+ * See overrides of this method as well.
+ *
+ * @param array $filterDefinition Original filter definition
+ *
+ * @return array Transformed definition
+ */
+ protected function transformFilterDefinition( array $filterDefinition ) {
+ return $filterDefinition;
+ }
+
/**
* Register filters from a definition object
*
* Array specifying groups and their filters; see Filter and
* ChangesListFilterGroup constructors.
*
- * There is light processing to simplify core maintenance. See overrides
- * of this method as well.
+ * There is light processing to simplify core maintenance.
*/
protected function registerFiltersFromDefinitions( array $definition ) {
- $priority = -1;
+ $autoFillPriority = -1;
foreach ( $definition as $groupDefinition ) {
- $groupDefinition['priority'] = $priority;
- $priority--;
+ if ( !isset( $groupDefinition['priority'] ) ) {
+ $groupDefinition['priority'] = $autoFillPriority;
+ } else {
+ // If it's explicitly specified, start over the auto-fill
+ $autoFillPriority = $groupDefinition['priority'];
+ }
+
+ $autoFillPriority--;
$className = $groupDefinition['class'];
unset( $groupDefinition['class'] );
+
+ foreach ( $groupDefinition['filters'] as &$filterDefinition ) {
+ $filterDefinition = $this->transformFilterDefinition( $filterDefinition );
+ }
+
$this->registerFilterGroup( new $className( $groupDefinition ) );
}
}
$query_options, $join_conds, $opts[$filterGroup->getName()] );
} else {
foreach ( $filterGroup->getFilters() as $filter ) {
- if ( $opts[$filter->getName()] && $filter->isAllowed( $this ) ) {
+ if ( $opts[$filter->getName()] ) {
$filter->modifyQuery( $dbr, $this, $tables, $fields, $conds,
$query_options, $join_conds );
}