mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Echo
synced 2024-11-24 07:54:13 +00:00
Merge "Add mark-as-read button to notifications in Special:Notifications"
This commit is contained in:
commit
4331c30993
|
@ -13,6 +13,7 @@ $specialPageAliases = array();
|
|||
$specialPageAliases['en'] = array(
|
||||
'Notifications' => array( 'Notifications' ),
|
||||
'DisplayNotificationsConfiguration' => array( 'DisplayNotificationsConfiguration' ),
|
||||
'NotificationsMarkRead' => array( 'NotificationsMarkRead' ),
|
||||
);
|
||||
|
||||
/** Arabic (العربية) */
|
||||
|
@ -258,4 +259,4 @@ $specialPageAliases['zh-hans'] = array(
|
|||
/** Traditional Chinese (中文(繁體)) */
|
||||
$specialPageAliases['zh-hant'] = array(
|
||||
'Notifications' => array( '通知' ),
|
||||
);
|
||||
);
|
||||
|
|
1
Echo.php
1
Echo.php
|
@ -63,6 +63,7 @@ $wgAPIModules['echomarkseen'] = 'ApiEchoMarkSeen';
|
|||
// Special page
|
||||
$wgSpecialPages['Notifications'] = 'SpecialNotifications';
|
||||
$wgSpecialPages['DisplayNotificationsConfiguration'] = 'SpecialDisplayNotificationsConfiguration';
|
||||
$wgSpecialPages['NotificationsMarkRead'] = 'SpecialNotificationsMarkRead';
|
||||
|
||||
// Housekeeping hooks
|
||||
$wgHooks['LoadExtensionSchemaUpdates'][] = 'EchoHooks::onLoadExtensionSchemaUpdates';
|
||||
|
|
|
@ -257,22 +257,6 @@ $wgResourceModules += array(
|
|||
),
|
||||
'targets' => array( 'desktop', 'mobile' ),
|
||||
),
|
||||
'ext.echo.special' => $echoResourceTemplate + array(
|
||||
'scripts' => array(
|
||||
'special/ext.echo.special.js',
|
||||
),
|
||||
'dependencies' => array(
|
||||
'mediawiki.ui.button',
|
||||
'mediawiki.api',
|
||||
'ext.echo.ui',
|
||||
),
|
||||
'messages' => array(
|
||||
'echo-load-more-error',
|
||||
'echo-more-info',
|
||||
'echo-feedback',
|
||||
),
|
||||
),
|
||||
|
||||
// HACK: OOUI has an icon pack for these, but it's unhelpfully large and we don't
|
||||
// want to load more as render-blocking CSS than we have to (T112401)
|
||||
'ext.echo.badgeicons' => $echoResourceTemplate + array(
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// @codingStandardsIgnoreFile
|
||||
global $wgAutoloadClasses;
|
||||
|
||||
$wgAutoloadClasses += array(
|
||||
$wgAutoloadClasses += [
|
||||
'ApiEchoMarkRead' => __DIR__ . '/includes/api/ApiEchoMarkRead.php',
|
||||
'ApiEchoMarkReadTest' => __DIR__ . '/tests/phpunit/api/ApiEchoMarkReadTest.php',
|
||||
'ApiEchoMarkSeen' => __DIR__ . '/includes/api/ApiEchoMarkSeen.php',
|
||||
|
@ -114,5 +114,6 @@ $wgAutoloadClasses += array(
|
|||
'SpecialDisplayNotificationsConfiguration' => __DIR__ . '/includes/special/SpecialDisplayNotificationsConfiguration.php',
|
||||
'SpecialNotifications' => __DIR__ . '/includes/special/SpecialNotifications.php',
|
||||
'SpecialNotificationsFormatter' => __DIR__ . '/includes/formatters/SpecialNotificationsFormatter.php',
|
||||
'SpecialNotificationsMarkRead' => __DIR__ . '/includes/special/SpecialNotificationsMarkRead.php',
|
||||
'SuppressionMaintenanceTest' => __DIR__ . '/tests/phpunit/maintenance/SupressionMaintenanceTest.php',
|
||||
);
|
||||
];
|
||||
|
|
|
@ -94,6 +94,9 @@
|
|||
"echo-displaynotificationsconfiguration-mandatory-notification-methods-header": "Required notification methods",
|
||||
"echo-displaynotificationsconfiguration-mandatory-notification-methods-by-category-legend": "Which notification methods are mandatory for each category",
|
||||
"echo-specialpage": "Notifications",
|
||||
"echo-specialpage-markasread": "Notification: Mark as read",
|
||||
"echo-specialpage-markasread-invalid-id": "Invalid event ID",
|
||||
"notificationsmarkread-legend": "Mark notification as read",
|
||||
"echo-anon": "To receive notifications, [$1 create an account] or [$2 log in].",
|
||||
"echo-none": "You have no notifications.",
|
||||
"echo-more-info": "More info",
|
||||
|
|
|
@ -85,6 +85,9 @@
|
|||
"echo-displaynotificationsconfiguration-mandatory-notification-methods-header": "Header on DisplayNotificationsConfiguration for section about which notification methods are required",
|
||||
"echo-displaynotificationsconfiguration-mandatory-notification-methods-by-category-legend": "Explanatory text on DisplayNotificationsConfiguration regarding which notification methods are mandatory for each category",
|
||||
"echo-specialpage": "Special page title for Special:Notifications.\n{{Identical|Notification}}",
|
||||
"echo-specialpage-markasread": "Special page title for Special:NotificationsMarkRead for marking specific notification as read.",
|
||||
"echo-specialpage-markasread-invalid-id": "Error message shown to users who try to mark a notification as read with an invalid event ID.",
|
||||
"notificationsmarkread-legend": "Title for the form that marks a notification as read in [[Special:NotificationsMarkAsRead]]",
|
||||
"echo-anon": "Error message shown to users who try to visit [[Special:Notifications]] as an anon.\n\nParameters:\n* $1 - URL of signup page, with returnto pointing to Special:Notifications\n* $2 - URL of login page, with returnto pointing to Special:Notifications",
|
||||
"echo-none": "Message shown to users who have no notifications. Also shown in the overlay.",
|
||||
"echo-more-info": "This is used for the title (mouseover text) of an icon that links to a page with more information about the Echo extension.\n{{Identical|More information}}",
|
||||
|
|
|
@ -422,6 +422,14 @@ abstract class EchoEventPresentationModel implements JsonSerializable {
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the associated event
|
||||
* @return int Event id
|
||||
*/
|
||||
public function getEventId() {
|
||||
return $this->event->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws TimestampException
|
||||
|
|
|
@ -2,9 +2,15 @@
|
|||
|
||||
/**
|
||||
* A formatter for Special:Notifications
|
||||
*
|
||||
* This formatter uses OOUI libraries. Any calls to this formatter must
|
||||
* also call OutputPage::enableOOUI() before calling this formatter.
|
||||
*/
|
||||
class SpecialNotificationsFormatter extends EchoEventFormatter {
|
||||
protected function formatModel( EchoEventPresentationModel $model ) {
|
||||
$markReadSpecialPage = SpecialPage::getTitleFor( 'NotificationsMarkRead' );
|
||||
$id = $model->getEventId();
|
||||
|
||||
$icon = Html::element(
|
||||
'img',
|
||||
array(
|
||||
|
@ -13,6 +19,15 @@ class SpecialNotificationsFormatter extends EchoEventFormatter {
|
|||
)
|
||||
);
|
||||
|
||||
OutputPage::setupOOUI();
|
||||
$markAsReadButton = new OOUI\ButtonWidget( array(
|
||||
'icon' => 'close',
|
||||
'framed' => false,
|
||||
'href' => $markReadSpecialPage->getLocalUrl() . '/' . $id,
|
||||
'classes' => array( 'mw-echo-markAsReadButton' ),
|
||||
'title' => wfMessage( 'echo-notification-markasread' )
|
||||
) );
|
||||
|
||||
$html = Xml::tags(
|
||||
'div',
|
||||
array( 'class' => 'mw-echo-title' ),
|
||||
|
@ -70,8 +85,10 @@ class SpecialNotificationsFormatter extends EchoEventFormatter {
|
|||
// Wrap everything in mw-echo-content class
|
||||
$html = Xml::tags( 'div', array( 'class' => 'mw-echo-content' ), $html );
|
||||
|
||||
// And then add the icon in front and wrap with mw-echo-state class.
|
||||
$html = Xml::tags( 'div', array( 'class' => 'mw-echo-state' ), $icon . $html );
|
||||
// And then add the mark as read button
|
||||
// and the icon in front and wrap with
|
||||
// mw-echo-state class.
|
||||
$html = Xml::tags( 'div', array( 'class' => 'mw-echo-state' ), $markAsReadButton . $icon . $html );
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ class SpecialNotifications extends SpecialPage {
|
|||
|
||||
$out->addSubtitle( $this->buildSubtitle() );
|
||||
|
||||
$out->enableOOUI();
|
||||
|
||||
// The continue parameter to pull current set of data from, this
|
||||
// would be used for browsers with javascript disabled
|
||||
$continue = $this->getRequest()->getVal( 'continue', null );
|
||||
|
@ -67,34 +69,41 @@ class SpecialNotifications extends SpecialPage {
|
|||
|
||||
// Add the notifications to the page (interspersed with date headers)
|
||||
$dateHeader = '';
|
||||
$notices = '';
|
||||
$unread = array();
|
||||
$echoSeenTime = EchoSeenTime::newFromUser( $user );
|
||||
$seenTime = $echoSeenTime->getTime();
|
||||
$notifArray = array();
|
||||
foreach ( $notif as $row ) {
|
||||
$class = 'mw-echo-notification';
|
||||
|
||||
if ( !isset( $row['read'] ) ) {
|
||||
$class .= ' mw-echo-unread';
|
||||
$class .= ' mw-echo-notification-unread';
|
||||
if ( !$row['targetpages'] ) {
|
||||
$unread[] = $row['id'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( $seenTime !== null && $row['timestamp']['mw'] > $seenTime ) {
|
||||
$class .= ' mw-echo-unseen';
|
||||
$class .= ' mw-echo-notification-unseen';
|
||||
}
|
||||
|
||||
if ( !$row['*'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Output the date header if it has not been displayed
|
||||
if ( $dateHeader !== $row['timestamp']['date'] ) {
|
||||
$dateHeader = $row['timestamp']['date'];
|
||||
$notices .= Html::rawElement( 'li', array( 'class' => 'mw-echo-date-section' ), $dateHeader );
|
||||
$notifArray[ $dateHeader ] = array(
|
||||
'notices' => array()
|
||||
);
|
||||
}
|
||||
|
||||
$notices .= Html::rawElement(
|
||||
// Collect unread IDs
|
||||
if ( !isset( $row['read'] ) ) {
|
||||
$notifArray[ $dateHeader ][ 'unread' ][] = $row['id'];
|
||||
}
|
||||
|
||||
$notifArray[ $dateHeader ][ 'notices' ][] = Html::rawElement(
|
||||
'li',
|
||||
array(
|
||||
'class' => $class,
|
||||
|
@ -105,6 +114,19 @@ class SpecialNotifications extends SpecialPage {
|
|||
$row['*']
|
||||
);
|
||||
}
|
||||
|
||||
// Build the HTML
|
||||
$notices = '';
|
||||
foreach ( $notifArray as $section => $data ) {
|
||||
$sectionTitle = Html::element( 'span', array( 'class' => 'mw-echo-date-section-text' ), $section );
|
||||
|
||||
// Heading
|
||||
$notices .= Html::rawElement( 'li', array( 'class' => 'mw-echo-date-section' ), $sectionTitle );
|
||||
|
||||
// Notices
|
||||
$notices .= join( "\n", $data[ 'notices' ] );
|
||||
}
|
||||
|
||||
$html = Html::rawElement( 'ul', array( 'id' => 'mw-echo-special-container' ), $notices );
|
||||
|
||||
// Build the more link
|
||||
|
@ -123,7 +145,6 @@ class SpecialNotifications extends SpecialPage {
|
|||
}
|
||||
|
||||
$out->addHTML( $html );
|
||||
$out->addModules( 'ext.echo.special' );
|
||||
$out->addJsConfigVars(
|
||||
array(
|
||||
'wgEchoDisplayNum' => self::DISPLAY_NUM,
|
||||
|
@ -133,15 +154,6 @@ class SpecialNotifications extends SpecialPage {
|
|||
);
|
||||
// For no-js support
|
||||
$out->addModuleStyles( array( 'ext.echo.styles.notifications', 'ext.echo.styles.special' ) );
|
||||
|
||||
DeferredUpdates::addCallableUpdate( function () use ( $user, $echoSeenTime, $unread ) {
|
||||
// Mark items as read
|
||||
if ( $unread ) {
|
||||
MWEchoNotifUser::newFromUser( $user )->markRead( $unread );
|
||||
}
|
||||
// Record time notifications have been seen
|
||||
$echoSeenTime->setTime( wfTimestamp( TS_MW ) );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,7 +165,7 @@ class SpecialNotifications extends SpecialPage {
|
|||
$lang = $this->getLanguage();
|
||||
$subtitleLinks = array();
|
||||
// More info link
|
||||
$subtitleLinks[] = Html::rawElement(
|
||||
$subtitleLinks[] = Html::element(
|
||||
'a',
|
||||
array(
|
||||
'href' => $wgEchoHelpPage,
|
||||
|
@ -165,7 +177,7 @@ class SpecialNotifications extends SpecialPage {
|
|||
$this->msg( 'echo-more-info' )->text()
|
||||
);
|
||||
// Preferences link
|
||||
$subtitleLinks[] = Html::rawElement(
|
||||
$subtitleLinks[] = Html::element(
|
||||
'a',
|
||||
array(
|
||||
'href' => SpecialPage::getTitleFor( 'Preferences' )->getLinkURL() . '#mw-prefsection-echo',
|
||||
|
|
76
includes/special/SpecialNotificationsMarkRead.php
Normal file
76
includes/special/SpecialNotificationsMarkRead.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
class SpecialNotificationsMarkRead extends FormSpecialPage {
|
||||
protected $eventId;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct( 'NotificationsMarkRead' );
|
||||
}
|
||||
|
||||
public function execute( $par ) {
|
||||
parent::execute( $par );
|
||||
|
||||
$out = $this->getOutput();
|
||||
$out->setPageTitle( $this->msg( 'echo-specialpage-markasread' )->text() );
|
||||
|
||||
// Redirect to login page and inform user of the need to login
|
||||
$this->requireLogin( 'echo-notification-loginrequired' );
|
||||
}
|
||||
|
||||
public function isListed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an HTMLForm descriptor array
|
||||
* @return array
|
||||
*/
|
||||
protected function getFormFields() {
|
||||
return array(
|
||||
'id' => array(
|
||||
'type' => 'hidden',
|
||||
'required' => true,
|
||||
'default' => $this->par,
|
||||
'filter-callback' => function ( $value, $alldata ) {
|
||||
// Allow for a single value or a set of values
|
||||
$result = explode( ',', $value );
|
||||
return $result;
|
||||
},
|
||||
'validation-callback' => function ( $value, $alldata ) {
|
||||
if ( (int)$value <= 0 ) {
|
||||
return $this->msg( 'echo-specialpage-markasread-invalid-id' );
|
||||
}
|
||||
foreach ( $value as $val ) {
|
||||
if ( (int)( $val ) <= 0 ) {
|
||||
return $this->msg( 'echo-specialpage-markasread-invalid-id' );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function alterForm( HTMLForm $form ) {
|
||||
$form->setSubmitText( $this->msg( 'echo-notification-markasread' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the form on POST submission.
|
||||
* @param array $data
|
||||
* @param HTMLForm $form
|
||||
* @return bool|string|array|Status As documented for HTMLForm::trySubmit.
|
||||
*/
|
||||
public function onSubmit( array $data /* $form = null */ ) {
|
||||
// Allow for multiple IDs or a single ID
|
||||
$ids = $data['id'];
|
||||
|
||||
$notifUser = MWEchoNotifUser::newFromUser( $this->getUser() );
|
||||
return $notifUser->markRead( $ids );
|
||||
}
|
||||
|
||||
public function onSuccess() {
|
||||
$page = SpecialPage::getTitleFor( 'Notifications' );
|
||||
$this->getOutput()->redirect( $page->getFullUrl() );
|
||||
}
|
||||
}
|
|
@ -7,7 +7,8 @@
|
|||
// not wrapped with a NotificationItemWidget.
|
||||
.mw-echo-state {
|
||||
display: block;
|
||||
padding: 15px 40px 10px 10px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
.mw-echo-notification-primary-link {
|
||||
display: none;
|
||||
|
@ -35,10 +36,6 @@
|
|||
overflow: hidden;
|
||||
zoom: 1;
|
||||
|
||||
&.mw-echo-unread {
|
||||
color: #252525;
|
||||
}
|
||||
|
||||
span.autocomment {
|
||||
color: inherit;
|
||||
font-style: normal;
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
font-size: 1.1em;
|
||||
text-transform: uppercase;
|
||||
border-bottom: 1px solid #C9C9C9;
|
||||
margin: 30px 0 5px 50px;
|
||||
margin: 30px 0 5px 0;
|
||||
color: #686868;
|
||||
max-width: 550px;
|
||||
}
|
||||
|
@ -72,12 +72,17 @@ ul#mw-echo-special-container {
|
|||
}
|
||||
|
||||
.mw-echo-notification {
|
||||
padding: 15px 35px 10px 0;
|
||||
padding: 30px 40px 15px 10px;
|
||||
margin-right: 40px;
|
||||
|
||||
.mw-echo-markAsReadButton {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#mw-echo-special-container {
|
||||
.mw-echo-notification {
|
||||
background-color: transparent;
|
||||
background-color: #F1F1F1;
|
||||
|
||||
&:hover {
|
||||
/* Fallback for IE<=8 */
|
||||
|
@ -85,10 +90,25 @@ ul#mw-echo-special-container {
|
|||
background-color: rgba(0, 0, 0, 0.035);
|
||||
}
|
||||
|
||||
&.mw-echo-unread {
|
||||
&-unread {
|
||||
color: #252525;
|
||||
background-color: transparent;
|
||||
padding-right: 0;
|
||||
|
||||
.mw-echo-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mw-echo-markAsReadButton {
|
||||
float: right;
|
||||
display: inline-block;
|
||||
margin-left: 1em;
|
||||
|
||||
opacity: 0.5;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue