mediawiki-extensions-Discus.../includes/Notifications/DiscussionToolsEventTrait.php
Bartosz Dziewoński 435b0c65c7 Enhance Echo user talk edit and mention notifications
If the user talk edit or mention coincides with exactly one new comment:
* Change the primary link to be a direct link to the comment
* Add a text snippet to notifications that don't already include one
  (user talk edits that are not new sections).

This is done for all such notifications, regardless of whether anyone
has topic subscriptions enabled.

Bug: T281590
Bug: T253082
Change-Id: I98fbca8e57845cd7c82ad533c393db953e4e5643
2021-09-20 15:05:42 +02:00

108 lines
3.3 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;
/**
* This trait must be only used on EchoEventPresentationModel subclasses.
*
* @property \EchoEvent $event
* @property \Language $language
*/
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();
/**
* Get a link to the individual comment, if available.
*
* @return string Full URL linking to the comment
*/
protected function getCommentLink() {
if ( !$this->userCan( RevisionRecord::DELETED_TEXT ) ) {
return null;
}
$title = $this->event->getTitle();
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;
}
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.
$sectionTitles = [ $this->event->getExtraParam( 'section-title' ) ];
$commentIds = [ $this->event->getExtraParam( 'comment-id' ) ];
foreach ( $this->getBundledEvents() as $event ) {
$sectionTitles[] = $event->getExtraParam( 'section-title' );
$commentIds[] = $event->getExtraParam( 'comment-id' );
}
$commentIds = array_values( array_filter( $commentIds ) );
$sectionTitles = array_values( array_unique( array_filter( $sectionTitles ) ) );
if ( !$commentIds ) {
return null;
}
$params = [ 'dtnewcomments' => implode( '|', $commentIds ) ];
if ( count( $sectionTitles ) === 1 ) {
return $title->createFragmentTarget( $sectionTitles[0] )->getFullURL( $params );
} else {
return $title->getFullURL( $params );
}
}
}
/**
* Get a snippet of the individual comment, if available.
*
* @return string The snippet, as plain text (may be empty)
*/
protected function getContentSnippet() {
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 );
}
}