Implement ability to select and save watch temporarily.
Add functionality that allows users to select a watch period via a drop-down in the pop-up that shows up when a user watches a page via star. Update the expiry dropdown when user is in a page edit-form. Bug: T249262 Change-Id: I9a7dfcaf84be8083e0319789dc95f2d15cee245a
This commit is contained in:
parent
08eb0dbc33
commit
68d81806ca
9 changed files with 160 additions and 23 deletions
|
|
@ -117,22 +117,22 @@ class WatchAction extends FormAction {
|
|||
* @since 1.35
|
||||
* @todo Move this somewhere better when it's being used in more than just this action.
|
||||
*
|
||||
* @param IContextSource $context
|
||||
* @param MessageLocalizer $msgLocalizer
|
||||
* @param WatchedItem|bool $watchedItem
|
||||
*
|
||||
* @return mixed[] With keys `options` (string[]) and `default` (string).
|
||||
*/
|
||||
public static function getExpiryOptions( IContextSource $context, $watchedItem ) {
|
||||
$expiryOptionsMsg = $context->msg( 'watchlist-expiry-options' )->text();
|
||||
$expiryOptions = XmlSelect::parseOptionsMessage( $expiryOptionsMsg );
|
||||
public static function getExpiryOptions( MessageLocalizer $msgLocalizer, $watchedItem ) {
|
||||
$expiryOptionsMsg = $msgLocalizer->msg( 'watchlist-expiry-options' );
|
||||
$expiryOptionsMsgText = $expiryOptionsMsg->text();
|
||||
$expiryOptions = XmlSelect::parseOptionsMessage( $expiryOptionsMsgText );
|
||||
$default = 'infinite';
|
||||
if ( $watchedItem instanceof WatchedItem && $watchedItem->getExpiry() ) {
|
||||
// If it's already being temporarily watched,
|
||||
// add the existing expiry as the default option in the dropdown.
|
||||
|
||||
$expiry = MWTimestamp::getInstance( $watchedItem->getExpiry() );
|
||||
$diffInDays = $watchedItem->getExpiryInDays();
|
||||
$daysLeft = $context->msg( 'watchlist-expiry-days-left', [ $diffInDays ] )->text();
|
||||
$daysLeft = $msgLocalizer->msg( 'watchlist-expiry-days-left', [ $diffInDays ] )->text();
|
||||
$expiryOptions = array_merge(
|
||||
[ $daysLeft => $expiry->getTimestamp( TS_MW ) ],
|
||||
$expiryOptions
|
||||
|
|
|
|||
|
|
@ -2383,6 +2383,11 @@
|
|||
"addedwatchtext": "\"[[:$1]]\" and its discussion page have been added to your [[Special:Watchlist|watchlist]].",
|
||||
"addedwatchtext-talk": "\"[[:$1]]\" and its associated page have been added to your [[Special:Watchlist|watchlist]].",
|
||||
"addedwatchtext-short": "The page \"$1\" has been added to your watchlist.",
|
||||
"addedwatchexpiry-options-label": "Watchlist time period:",
|
||||
"addedwatchexpirytext": "\"[[:$1]]\" and its discussion page have been added to your [[Special:Watchlist|watchlist]] for $2.",
|
||||
"addedwatchexpirytext-talk": "\"[[:$1]]\" and its associated page have been added to your [[Special:Watchlist|watchlist]] for $2.",
|
||||
"addedwatchindefinitelytext": "\"[[:$1]]\" and its discussion page have been added to your [[Special:Watchlist|watchlist]] permanently.",
|
||||
"addedwatchindefinitelytext-talk": "\"[[:$1]]\" and its associated page have been added to your [[Special:Watchlist|watchlist]] permanently.",
|
||||
"removewatch": "Remove from watchlist",
|
||||
"removedwatchtext": "\"[[:$1]]\" and its discussion page have been removed from your [[Special:Watchlist|watchlist]].",
|
||||
"removedwatchtext-talk": "\"[[:$1]]\" and its associated page have been removed from your [[Special:Watchlist|watchlist]].",
|
||||
|
|
|
|||
|
|
@ -2599,6 +2599,11 @@
|
|||
"addedwatchtext": "Message shown after clicking on the {{msg-mw|Watch}} tab in a content namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Removedwatchtext}}\n* {{msg-mw|Addedwatchtext-talk}}",
|
||||
"addedwatchtext-talk": "Message shown after clicking on the {{msg-mw|Watch}} tab in a talk namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Removedwatchtext-talk}}\n* {{msg-mw|Addedwatchtext}}",
|
||||
"addedwatchtext-short": "Explanation shown when watching item from [[Special:UnwatchedPages]].\n\nSee also:\n* {{msg-mw|Removedwatchtext-short}}\n* {{msg-mw|Addedwatchtext}}",
|
||||
"addedwatchexpiry-options-label": "Text for watchlist expiry dropdown shown after clicking on the {{msg-mw|Watch}} tab in a content namespace page.",
|
||||
"addedwatchexpirytext": "Message shown after selecting to watch a page temporarily. A selection is made from the watchlist expiry dropdown options in the pop up. Parameters:\n* $1 - page title\n* $2 - the expiry selected",
|
||||
"addedwatchexpirytext-talk": "Message shown after selecting to watch a talk page temporarily. A selection is made from the watchlist expiry dropdown options in the pop up. Parameters:\n* $1 - page title\n* $2 - the expiry selected",
|
||||
"addedwatchindefinitelytext": "Message shown after selecting to watch a page indefinitely. The selection is made from the watchlist expiry dropdown options in the pop up. Parameters:\n* $1 - page title",
|
||||
"addedwatchindefinitelytext-talk": "Message shown after selecting to watch a talk page indefinitely. The selection is made from the watchlist expiry dropdown options in the pop up. Parameters:\n* $1 - page title",
|
||||
"removewatch": "A confirmation message that is shown after a user clicks the watchlist star icon if the JavaScript does not or cannot load, or if they visit the \"action=\" link directly, e.g. https://translatewiki.net/w/i.php?title=MediaWiki:Removewatch/qqq&action=unwatch\n\nSee also:\n* {{msg-mw|Addwatch}}\n* {{msg-mw|Confirm-unwatch-top}}\n* {{msg-mw|Confirm-unwatch-button}}",
|
||||
"removedwatchtext": "Message shown after clicking on the {{msg-mw|Unwatch}} tab in a content namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Addedwatchtext}}\n* {{msg-mw|Removedwatchtext-talk}}",
|
||||
"removedwatchtext-talk": "Message shown after clicking on the {{msg-mw|Unwatch}} tab in a talk namespace page. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Addedwatchtext-talk}}\n* {{msg-mw|Removedwatchtext}}",
|
||||
|
|
|
|||
|
|
@ -2682,12 +2682,25 @@ return [
|
|||
],
|
||||
],
|
||||
'mediawiki.watchstar.widgets' => [
|
||||
'localBasePath' => "$IP/resources/src/mediawiki.watchstar.widgets",
|
||||
'remoteBasePath' => "$wgResourceBasePath/resources/src/mediawiki.watchstar.widgets",
|
||||
'packageFiles' => [
|
||||
'resources/src/mediawiki.watchstar.widgets/WatchlistExpiryWidget.js',
|
||||
'WatchlistExpiryWidget.js',
|
||||
[ 'name' => 'data.json', 'callback' => function ( MessageLocalizer $messageLocalizer ) {
|
||||
return WatchAction::getExpiryOptions( $messageLocalizer, false );
|
||||
} ]
|
||||
],
|
||||
'styles' => 'WatchlistExpiryWidget.css',
|
||||
'dependencies' => [
|
||||
'oojs-ui'
|
||||
],
|
||||
'messages' => [
|
||||
'addedwatchexpiry-options-label',
|
||||
'addedwatchexpirytext',
|
||||
'addedwatchexpirytext-talk',
|
||||
'addedwatchindefinitelytext',
|
||||
'addedwatchindefinitelytext-talk'
|
||||
],
|
||||
'targets' => [ 'desktop', 'mobile' ],
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,11 @@
|
|||
// Change state on every change of the watchthis checkbox.
|
||||
watchThisWidget.on( 'change', function ( enabled ) {
|
||||
watchlistExpiryWidget.setDisabled( !enabled );
|
||||
|
||||
// Reset the watchlist-expiry dropdown to the 'infinite' value
|
||||
if ( watchlistExpiryWidget.isDisabled() ) {
|
||||
watchlistExpiryWidget.setValue( 'infinite' );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
|
|
|
|||
|
|
@ -47,9 +47,11 @@
|
|||
* Convenience method for `action=watch`.
|
||||
*
|
||||
* @inheritdoc #doWatchInternal
|
||||
* @since 1.35 - expiry parameter can be passed when
|
||||
* Watchlist Expiry is enabled
|
||||
*/
|
||||
watch: function ( pages ) {
|
||||
return doWatchInternal.call( this, pages );
|
||||
watch: function ( pages, expiry ) {
|
||||
return doWatchInternal.call( this, pages, { expiry: expiry } );
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@
|
|||
*/
|
||||
( function () {
|
||||
// The name of the page to watch or unwatch
|
||||
var pageTitle = mw.config.get( 'wgRelevantPageName' );
|
||||
var pageTitle = mw.config.get( 'wgRelevantPageName' ),
|
||||
isWatchlistExpiryEnabled = require( './config.json' ).WatchlistExpiry;
|
||||
|
||||
/**
|
||||
* Update the link text, link href attribute and (if applicable)
|
||||
|
|
@ -183,7 +184,6 @@
|
|||
.done( function ( watchResponse ) {
|
||||
var message,
|
||||
watchlistPopup = null,
|
||||
isWatchlistExpiryEnabled = require( './config.json' ).WatchlistExpiry,
|
||||
otherAction = action === 'watch' ? 'unwatch' : 'watch';
|
||||
|
||||
if ( mwTitle.isTalkPage() ) {
|
||||
|
|
@ -195,22 +195,33 @@
|
|||
// @since 1.35 - pop up notification will be loaded with OOUI
|
||||
// only if Watchlist Expiry is enabled
|
||||
if ( isWatchlistExpiryEnabled ) {
|
||||
|
||||
if ( action === 'watch' ) { // The message should include `infinite` watch period
|
||||
message = mwTitle.isTalkPage() ? 'addedwatchindefinitelytext-talk' : 'addedwatchindefinitelytext';
|
||||
}
|
||||
|
||||
mw.loader.using( 'mediawiki.watchstar.widgets' ).done( function ( require ) {
|
||||
var WatchlistExpiryWidget = require( 'mediawiki.watchstar.widgets' );
|
||||
|
||||
if ( !watchlistPopup ) {
|
||||
watchlistPopup = new WatchlistExpiryWidget( {
|
||||
// The following messages can be used here:
|
||||
// * addedwatchtext-talk
|
||||
// * addedwatchtext
|
||||
// * removedwatchtext-talk
|
||||
// * removedwatchtext
|
||||
message: mw.message( message, mwTitle.getPrefixedText() ).parseDom()
|
||||
} );
|
||||
watchlistPopup = new WatchlistExpiryWidget(
|
||||
action,
|
||||
title,
|
||||
{
|
||||
// The following messages can be used here:
|
||||
// * addedwatchindefinitelytext-talk
|
||||
// * addedwatchindefinitelytext
|
||||
// * removedwatchtext-talk
|
||||
// * removedwatchtext
|
||||
message: mw.message( message, mwTitle.getPrefixedText() ).parseDom(),
|
||||
$link: $link,
|
||||
$li: $link.closest( 'li' )
|
||||
} );
|
||||
}
|
||||
|
||||
mw.notify( watchlistPopup.$element, {
|
||||
tag: 'watch-self',
|
||||
autoHideSeconds: 'long',
|
||||
autoHide: true
|
||||
} );
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
.mw-WatchlistExpiryWidgetwatchlist-dropdown-label {
|
||||
margin-top: 0.8em;
|
||||
}
|
||||
|
|
@ -1,23 +1,116 @@
|
|||
/* eslint-disable no-implicit-globals */
|
||||
/**
|
||||
* A special widget that displays a message that a page is being watched/unwatched
|
||||
* with a selection widget that can determine how long the page will be watched
|
||||
* with a selection widget that can determine how long the page will be watched.
|
||||
* If a page is being watched then a dropdown with expiry options is included.
|
||||
*
|
||||
* @class
|
||||
* @extends OO.ui.Widget
|
||||
* @param {string} action One of 'watch', 'unwatch'
|
||||
* @param {string} pageTitle Title of page that this widget will watch or unwatch
|
||||
* @param {Object} config Configuration object
|
||||
*/
|
||||
var WatchlistExpiryWidget = function ( config ) {
|
||||
|
||||
var WatchlistExpiryWidget = function ( action, pageTitle, config ) {
|
||||
var dataExpiryOptions = require( './data.json' ).options,
|
||||
messageLabel, dropdownLabel,
|
||||
expiryDropdown, onDropdownChange, api, $link, $li,
|
||||
expiryOptions = [];
|
||||
|
||||
config = config || {};
|
||||
$link = config.$link;
|
||||
$li = config.$li;
|
||||
|
||||
WatchlistExpiryWidget.parent.call( this, config );
|
||||
|
||||
this.message = new OO.ui.LabelWidget( {
|
||||
messageLabel = new OO.ui.LabelWidget( {
|
||||
label: config.message
|
||||
} );
|
||||
|
||||
this.$element
|
||||
.addClass( 'mw-watchstar-WatchlistExpiryWidget' )
|
||||
.append( this.message.$element );
|
||||
.append( messageLabel.$element );
|
||||
|
||||
if ( action === 'watch' ) {
|
||||
Object.keys( dataExpiryOptions ).forEach( function ( key ) {
|
||||
expiryOptions.push( { data: dataExpiryOptions[ key ], label: key } );
|
||||
} );
|
||||
|
||||
dropdownLabel = new OO.ui.LabelWidget( {
|
||||
label: mw.message( 'addedwatchexpiry-options-label' ).parseDom(),
|
||||
classes: [ 'mw-WatchlistExpiryWidgetwatchlist-dropdown-label' ]
|
||||
} );
|
||||
expiryDropdown = new OO.ui.DropdownInputWidget( {
|
||||
options: expiryOptions,
|
||||
classes: [ 'mw-watchexpiry' ]
|
||||
} );
|
||||
onDropdownChange = function ( value ) {
|
||||
var notif = mw.notification;
|
||||
|
||||
if ( typeof $link !== 'undefined' ) {
|
||||
$link.addClass( 'loading' )
|
||||
.text( mw.msg( 'watching' ) );
|
||||
}
|
||||
// Pause the mw.notify so that we can wait for watch request to finish
|
||||
notif.pause();
|
||||
api = new mw.Api();
|
||||
api.watch( pageTitle, value )
|
||||
.done( function () {
|
||||
var message,
|
||||
mwTitle = mw.Title.newFromText( pageTitle );
|
||||
if ( mwTitle.isTalkPage() ) {
|
||||
message = value === 'infinite' ? 'addedwatchindefinitelytext-talk' : 'addedwatchexpirytext-talk';
|
||||
} else {
|
||||
message = value === 'infinite' ? 'addedwatchindefinitelytext' : 'addedwatchexpirytext';
|
||||
}
|
||||
|
||||
// The following messages can be used here:
|
||||
// * addedwatchindefinitelytext-talk
|
||||
// * addedwatchindefinitelytext
|
||||
// * addedwatchexpirytext-talk
|
||||
// * addedwatchexpirytext
|
||||
messageLabel.setLabel(
|
||||
mw.message( message, mwTitle.getPrefixedText(), value ).parseDom()
|
||||
);
|
||||
// Resume the mw.notify once the label has been updated
|
||||
notif.resume();
|
||||
|
||||
if ( typeof $link !== 'undefined' ) {
|
||||
$link.removeClass( 'loading' );
|
||||
}
|
||||
|
||||
if ( typeof $li !== 'undefined' ) {
|
||||
if ( value === 'infinite' ) {
|
||||
$li.removeClass( 'mw-watchlink-temp' );
|
||||
} else {
|
||||
$li.addClass( 'mw-watchlink-temp' );
|
||||
}
|
||||
$link.text( mw.msg( 'unwatch' ) );
|
||||
}
|
||||
|
||||
// Update the "Watch this page" checkbox on action=edit when the
|
||||
// page is watched or unwatched via the tab.
|
||||
if ( document.getElementById( 'wpWatchlistExpiryWidget' ) ) {
|
||||
OO.ui.infuse( '#wpWatchlistExpiryWidget' ).setValue( value );
|
||||
}
|
||||
} )
|
||||
.fail( function ( code, data ) {
|
||||
// Format error message
|
||||
var $msg = api.getErrorMessage( data );
|
||||
|
||||
// Report to user about the error
|
||||
mw.notify( $msg, {
|
||||
tag: 'watch-self',
|
||||
type: 'error'
|
||||
} );
|
||||
// Resume the mw.notify once the error has been reported
|
||||
notif.resume();
|
||||
} );
|
||||
};
|
||||
|
||||
expiryDropdown.on( 'change', onDropdownChange );
|
||||
this.$element.append( dropdownLabel.$element, expiryDropdown.$element );
|
||||
}
|
||||
};
|
||||
|
||||
OO.inheritClass( WatchlistExpiryWidget, OO.ui.Widget );
|
||||
|
|
|
|||
Loading…
Reference in a new issue