mediawiki-extensions-Discus.../includes/Notifications/DiscussionToolsEventTrait.php
Bartosz Dziewoński d2405cc11c Simplify handling of sections in bundled notification links
This code previously ensured that the fragment identifier linking
to a section was only included if all events had the same section.
It doesn't actually seem worth the effort, since we handle scrolling
to the highlighted comments client-side anyway.

And the links were not quite correct, because we didn't parse and
strip the section title as expected by built-in Echo events. Just
use Echo's code for this.

Depends-On: Idb3a87fd18330f90a8cdc1276994d54288e17b28
Change-Id: Icae0d3654dd02109337ff8737b16f55bbd514f43
2022-01-21 00:06:36 +01:00

140 lines
4.2 KiB
PHP

<?php
/**
* Common code for all Echo event presentation models for DiscussionTools events.
*
* @file
* @ingroup Extensions
* @license MIT
*/
namespace MediaWiki\Extension\DiscussionTools\Notifications;
use EchoDiscussionParser;
use MediaWiki\Revision\RevisionRecord;
use WikiMap;
/**
* This trait must be only used on EchoEventPresentationModel subclasses.
*
* @property \EchoEvent $event
* @property \Language $language
* @property \EchoPresentationModelSection $section
*/
trait DiscussionToolsEventTrait {
/**
* @param int $type RevisionRecord::DELETED_* constant
* @return bool
*/
abstract protected function userCan( $type );
/**
* @return bool
*/
abstract protected function isBundled();
/**
* @return \EchoEvent[]
*/
abstract protected function getBundledEvents();
/**
* @return int[]|false
*/
abstract protected function getBundledIds();
/**
* Get a link to the individual comment, if available.
*
* @return string|null Full URL linking to the comment, null if not available
*/
protected function getCommentLink(): ?string {
if ( !$this->userCan( RevisionRecord::DELETED_TEXT ) ) {
return null;
}
if ( !$this->isBundled() ) {
// For a single-comment notification, make a pretty(ish) direct link to the comment.
// The browser scrolls and we highlight it client-side.
$commentId = $this->event->getExtraParam( 'comment-id' );
if ( !$commentId ) {
return null;
}
$title = $this->event->getTitle();
return $title->createFragmentTarget( $commentId )->getFullURL();
} else {
// For a multi-comment notification, we can't make a direct link, because we don't know
// which comment appears first on the page; the best we can do is a link to the section.
// We handle both scrolling and highlighting client-side, using the ugly parameter
// listing all comments.
// Bundling works differently for different notification types:
// * Subscribed topic notifications are bundled per-section.
// * User talk page notifications are bundled per-page (so basically, always bundled).
// * Mention notifications are *never* bundled.
// Code below tries to avoid assumptions in case this behavior changes.
$commentIds = [ $this->event->getExtraParam( 'comment-id' ) ];
foreach ( $this->getBundledEvents() as $event ) {
$commentIds[] = $event->getExtraParam( 'comment-id' );
}
$commentIds = array_values( array_filter( $commentIds ) );
if ( !$commentIds ) {
return null;
}
$params = [ 'dtnewcomments' => implode( '|', $commentIds ) ];
// This may or may not have a fragment identifier, depending on whether it was recorded for
// the first one of the bundled events. It's usually not needed because we handle scrolling
// client-side, but we can keep it for no-JS users, and to reduce the jump when scrolling.
$titleWithOptionalSection = $this->section->getTitleWithSection();
return $titleWithOptionalSection->getFullURL( $params );
}
}
/**
* Get a snippet of the individual comment, if available.
*
* @return string The snippet, as plain text (may be empty)
*/
protected function getContentSnippet(): string {
if ( !$this->userCan( RevisionRecord::DELETED_TEXT ) ) {
return '';
}
// Note that we store plain text in the 'content' param.
// Echo also has a 'content' param (for mention notifications), but it contains wikitext.
$content = $this->event->getExtraParam( 'content' );
if ( !$content ) {
return '';
}
return $this->language->truncateForVisual( $content, EchoDiscussionParser::DEFAULT_SNIPPET_LENGTH );
}
/**
* Add mark-as-read params to a link array
*
* Taken from EchoEventPresentationModel::getPrimaryLinkWithMarkAsRead
* TODO: Upstream to Echo?
*
* @param array $link Link
* @return array
*/
protected function addMarkAsRead( $link ) {
global $wgEchoCrossWikiNotifications;
if ( $link ) {
$eventIds = [ $this->event->getId() ];
if ( $this->getBundledIds() ) {
$eventIds = array_merge( $eventIds, $this->getBundledIds() );
}
$queryParams = [ 'markasread' => implode( '|', $eventIds ) ];
if ( $wgEchoCrossWikiNotifications ) {
$queryParams['markasreadwiki'] = WikiMap::getCurrentWikiId();
}
$link['url'] = wfAppendQuery( $link['url'], $queryParams );
}
return $link;
}
}