Fix enhanced RC data attribute sanitizing
[lhc/web/wiklou.git] / includes / changes / EnhancedChangesList.php
index 3aad60e..d977457 100644 (file)
@@ -32,11 +32,17 @@ class EnhancedChangesList extends ChangesList {
         */
        protected $rc_cache;
 
+       /**
+        * @var TemplateParser
+        */
+       protected $templateParser;
+
        /**
         * @param IContextSource|Skin $obj
+        * @param array $filterGroups Array of ChangesListFilterGroup objects (currently optional)
         * @throws MWException
         */
-       public function __construct( $obj ) {
+       public function __construct( $obj, array $filterGroups = [] ) {
                if ( $obj instanceof Skin ) {
                        // @todo: deprecate constructing with Skin
                        $context = $obj->getContext();
@@ -49,7 +55,7 @@ class EnhancedChangesList extends ChangesList {
                        $context = $obj;
                }
 
-               parent::__construct( $context );
+               parent::__construct( $context, $filterGroups );
 
                // message is set by the parent ChangesList class
                $this->cacheEntryFactory = new RCCacheEntryFactory(
@@ -57,6 +63,7 @@ class EnhancedChangesList extends ChangesList {
                        $this->message,
                        $this->linkRenderer
                );
+               $this->templateParser = new TemplateParser();
        }
 
        /**
@@ -339,8 +346,7 @@ class EnhancedChangesList extends ChangesList {
 
                $this->rcCacheIndex++;
 
-               $templateParser = new TemplateParser();
-               return $templateParser->processTemplate(
+               return $this->templateParser->processTemplate(
                        'EnhancedChangesListGroup',
                        $templateParams
                );
@@ -441,13 +447,16 @@ class EnhancedChangesList extends ChangesList {
                # Tags
                $data['tags'] = $this->getTags( $rcObj, $classes );
 
+               $attribs = $this->getDataAttributes( $rcObj );
+
                // give the hook a chance to modify the data
                $success = Hooks::run( 'EnhancedChangesListModifyLineData',
-                       [ $this, &$data, $block, $rcObj, &$classes ] );
+                       [ $this, &$data, $block, $rcObj, &$classes, &$attribs ] );
                if ( !$success ) {
                        // skip entry if hook aborted it
                        return [];
                }
+               $attribs = wfArrayFilterByKey( $attribs, [ Sanitizer::class, 'isReservedDataAttribute' ] );
 
                $lineParams['recentChangesFlagsRaw'] = [];
                if ( isset( $data['recentChangesFlags'] ) ) {
@@ -463,6 +472,7 @@ class EnhancedChangesList extends ChangesList {
                }
 
                $lineParams['classes'] = array_values( $classes );
+               $lineParams['attribs'] = Html::expandAttributes( $attribs );
 
                // everything else: makes it easier for extensions to add or remove data
                $lineParams['data'] = array_values( $data );
@@ -665,6 +675,8 @@ class EnhancedChangesList extends ChangesList {
                # Show how many people are watching this if enabled
                $data['watchingUsers'] = $this->numberofWatchingusers( $rcObj->numberofWatchingusers );
 
+               $data['attribs'] = array_merge( $this->getDataAttributes( $rcObj ), [ 'class' => $classes ] );
+
                // give the hook a chance to modify the data
                $success = Hooks::run( 'EnhancedChangesListModifyBlockLineData',
                        [ $this, &$data, $rcObj ] );
@@ -672,9 +684,13 @@ class EnhancedChangesList extends ChangesList {
                        // skip entry if hook aborted it
                        return '';
                }
+               $attribs = $data['attribs'];
+               unset( $data['attribs'] );
+               $attribs = wfArrayFilterByKey( $attribs, function( $key ) {
+                       return $key === 'class' || Sanitizer::isReservedDataAttribute( $key );
+               } );
 
-               $line = Html::openElement( 'table', [ 'class' => $classes ] ) .
-                       Html::openElement( 'tr' );
+               $line = Html::openElement( 'table', $attribs ) . Html::openElement( 'tr' );
                $line .= '<td class="mw-enhanced-rc"><span class="mw-enhancedchanges-arrow-space"></span>';
 
                if ( isset( $data['recentChangesFlags'] ) ) {
@@ -711,6 +727,11 @@ class EnhancedChangesList extends ChangesList {
                if ( $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) {
                        // For categorizations we must swap the category title with the page title!
                        $pageTitle = Title::newFromID( $rc->getAttribute( 'rc_cur_id' ) );
+                       if ( !$pageTitle ) {
+                               // The page has been deleted, but the RC entry
+                               // deletion job has not run yet. Just skip.
+                               return '';
+                       }
                }
 
                $retVal = ' ' . $this->msg( 'parentheses' )