@@ -553,6 +553,105 @@ public function execute( $subpage ) {
553553LoggerFactory::getInstance ( 'objectcache ' )
554554) );
555555}
556+
557+ $ this ->includeRcFiltersApp ();
558+ }
559+
560+ /**
561+ * Include the modules and configuration for the RCFilters app.
562+ * Conditional on the user having the feature enabled.
563+ */
564+ protected function includeRcFiltersApp () {
565+ if ( $ this ->isStructuredFilterUiEnabled () ) {
566+ $ out = $ this ->getOutput ();
567+ $ jsData = $ this ->getStructuredFilterJsData ();
568+
569+ $ messages = [];
570+ foreach ( $ jsData ['messageKeys ' ] as $ key ) {
571+ $ messages [$ key ] = $ this ->msg ( $ key )->plain ();
572+ }
573+
574+ $ out ->addHTML (
575+ ResourceLoader::makeInlineScript (
576+ ResourceLoader::makeMessageSetScript ( $ messages )
577+ )
578+ );
579+
580+ $ experimentalStructuredChangeFilters =
581+ $ this ->getConfig ()->get ( 'StructuredChangeFiltersEnableExperimentalViews ' );
582+
583+ $ out ->addJsConfigVars ( 'wgStructuredChangeFilters ' , $ jsData ['groups ' ] );
584+ $ out ->addJsConfigVars (
585+ 'wgStructuredChangeFiltersEnableExperimentalViews ' ,
586+ $ experimentalStructuredChangeFilters
587+ );
588+ $ out ->addJsConfigVars (
589+ 'wgStructuredChangeFiltersEnableLiveUpdate ' ,
590+ $ this ->getConfig ()->get ( 'StructuredChangeFiltersEnableLiveUpdate ' )
591+ );
592+ $ out ->addJsConfigVars (
593+ 'wgRCFiltersChangeTags ' ,
594+ $ this ->buildChangeTagList ()
595+ );
596+ $ out ->addJsConfigVars (
597+ 'StructuredChangeFiltersDisplayConfig ' ,
598+ [
599+ 'maxDays ' => (int )$ this ->getConfig ()->get ( 'RCMaxAge ' ) / ( 24 * 3600 ), // Translate to days
600+ 'limitArray ' => $ this ->getConfig ()->get ( 'RCLinkLimits ' ),
601+ 'daysArray ' => $ this ->getConfig ()->get ( 'RCLinkDays ' ),
602+ ]
603+ );
604+ }
605+ }
606+
607+ /**
608+ * Fetch the change tags list for the front end
609+ *
610+ * @return Array Tag data
611+ */
612+ protected function buildChangeTagList () {
613+ $ explicitlyDefinedTags = array_fill_keys ( ChangeTags::listExplicitlyDefinedTags (), 0 );
614+ $ softwareActivatedTags = array_fill_keys ( ChangeTags::listSoftwareActivatedTags (), 0 );
615+
616+ // Hit counts disabled for perf reasons, see T169997
617+ /*
618+ $tagStats = ChangeTags::tagUsageStatistics();
619+ $tagHitCounts = array_merge( $explicitlyDefinedTags, $softwareActivatedTags, $tagStats );
620+
621+ // Sort by hits
622+ arsort( $tagHitCounts );
623+ */
624+ $ tagHitCounts = array_merge ( $ explicitlyDefinedTags , $ softwareActivatedTags );
625+
626+ // Build the list and data
627+ $ result = [];
628+ foreach ( $ tagHitCounts as $ tagName => $ hits ) {
629+ if (
630+ // Only get active tags
631+ isset ( $ explicitlyDefinedTags [ $ tagName ] ) ||
632+ isset ( $ softwareActivatedTags [ $ tagName ] )
633+ ) {
634+ // Parse description
635+ $ desc = ChangeTags::tagLongDescriptionMessage ( $ tagName , $ this ->getContext () );
636+
637+ $ result [] = [
638+ 'name ' => $ tagName ,
639+ 'label ' => Sanitizer::stripAllTags (
640+ ChangeTags::tagDescription ( $ tagName , $ this ->getContext () )
641+ ),
642+ 'description ' => $ desc ? Sanitizer::stripAllTags ( $ desc ->parse () ) : '' ,
643+ 'cssClass ' => Sanitizer::escapeClass ( 'mw-tag- ' . $ tagName ),
644+ 'hits ' => $ hits ,
645+ ];
646+ }
647+ }
648+
649+ // Instead of sorting by hit count (disabled, see above), sort by display name
650+ usort ( $ result , function ( $ a , $ b ) {
651+ return strcasecmp ( $ a ['label ' ], $ b ['label ' ] );
652+ } );
653+
654+ return $ result ;
556655}
557656
558657/**
@@ -779,19 +878,20 @@ public function setup( $parameters ) {
779878 * @return FormOptions
780879 */
781880public function getDefaultOptions () {
782- $ config = $ this ->getConfig ();
783881$ opts = new FormOptions ();
784- $ structuredUI = $ this ->getUser ()-> getOption ( ' rcenhancedfilters ' );
882+ $ structuredUI = $ this ->isStructuredFilterUiEnabled ( );
785883// If urlversion=2 is set, ignore the filter defaults and set them all to false/empty
786884$ useDefaults = $ this ->getRequest ()->getInt ( 'urlversion ' ) !== 2 ;
787885
788886// Add all filters
887+ /** @var ChangesListFilterGroup $filterGroup */
789888foreach ( $ this ->filterGroups as $ filterGroup ) {
790889// URL parameters can be per-group, like 'userExpLevel',
791890// or per-filter, like 'hideminor'.
792891if ( $ filterGroup ->isPerGroupRequestParameter () ) {
793892$ opts ->add ( $ filterGroup ->getName (), $ useDefaults ? $ filterGroup ->getDefault () : '' );
794893} else {
894+ /** @var ChangesListBooleanFilter $filter */
795895foreach ( $ filterGroup ->getFilters () as $ filter ) {
796896$ opts ->add ( $ filter ->getName (), $ useDefaults ? $ filter ->getDefault ( $ structuredUI ) : false );
797897}
@@ -857,8 +957,6 @@ public function getStructuredFilterJsData() {
857957'messageKeys ' => [],
858958];
859959
860- $ context = $ this ->getContext ();
861-
862960usort ( $ this ->filterGroups , function ( $ a , $ b ) {
863961return $ b ->getPriority () - $ a ->getPriority ();
864962} );
@@ -1055,9 +1153,7 @@ protected function buildQuery( &$tables, &$fields, &$conds, &$query_options,
10551153&$ join_conds , FormOptions $ opts
10561154) {
10571155$ dbr = $ this ->getDB ();
1058- $ user = $ this ->getUser ();
10591156
1060- $ context = $ this ->getContext ();
10611157foreach ( $ this ->filterGroups as $ filterGroup ) {
10621158// URL parameters can be per-group, like 'userExpLevel',
10631159// or per-filter, like 'hideminor'.
@@ -1279,12 +1375,11 @@ public function makeLegend() {
12791375) . "\n" ;
12801376$ legend .= Html::closeElement ( 'dl ' ) . "\n" ;
12811377
1282- # Collapsibility
1283- $ legendHeading = $ this ->getUser ()->getOption (
1284- 'rcenhancedfilters '
1285- ) ?
1378+ $ legendHeading = $ this ->isStructuredFilterUiEnabled () ?
12861379$ context ->msg ( 'rcfilters-legend-heading ' )->parse () :
12871380$ context ->msg ( 'recentchanges-legend-heading ' )->parse ();
1381+
1382+ # Collapsible
12881383$ legend =
12891384'<div class="mw-changeslist-legend"> ' .
12901385$ legendHeading .
@@ -1305,6 +1400,11 @@ protected function addModules() {
13051400'mediawiki.special.changeslist ' ,
13061401] );
13071402$ out ->addModules ( 'mediawiki.special.changeslist.legend.js ' );
1403+
1404+ if ( $ this ->isStructuredFilterUiEnabled () ) {
1405+ $ out ->addModules ( 'mediawiki.rcfilters.filters.ui ' );
1406+ $ out ->addModuleStyles ( 'mediawiki.rcfilters.filters.base.styles ' );
1407+ }
13081408}
13091409
13101410protected function getGroupName () {
@@ -1426,4 +1526,13 @@ public function filterOnUserExperienceLevel( $specialPageClassName, $context, $d
14261526$ conds [] = reset ( $ conditions );
14271527}
14281528}
1529+
1530+ /**
1531+ * Check whether the structured filter UI is enabled
1532+ *
1533+ * @return bool
1534+ */
1535+ protected function isStructuredFilterUiEnabled () {
1536+ return $ this ->getUser ()->getOption ( 'rcenhancedfilters ' );
1537+ }
14291538}
0 commit comments