From 7da24265c85a694823403fc97b13d4d40b79c92b Mon Sep 17 00:00:00 2001 From: Stephane Bisson Date: Fri, 18 Aug 2017 10:52:24 -0400 Subject: [PATCH] WLFilters: convert mark as seen button to new style Bug: T171121 Change-Id: I52b3c318fe8270c857d9afebdfd7f440d56131c9 --- languages/i18n/en.json | 1 + languages/i18n/qqq.json | 1 + resources/Resources.php | 2 + .../mw.rcfilters.dm.ChangesListViewModel.js | 18 ++++++ .../mw.rcfilters.Controller.js | 16 ++++- .../mediawiki.rcfilters/mw.rcfilters.init.js | 62 +++++++++++-------- .../ui/mw.rcfilters.ui.FilterWrapperWidget.js | 23 +++++-- .../mw.rcfilters.ui.MarkSeenButtonWidget.js | 55 ++++++++++++++++ 8 files changed, 148 insertions(+), 30 deletions(-) create mode 100644 resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MarkSeenButtonWidget.js diff --git a/languages/i18n/en.json b/languages/i18n/en.json index 3497d80f97..69b134a627 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -1461,6 +1461,7 @@ "rcfilters-liveupdates-button": "Live updates", "rcfilters-liveupdates-button-title-on": "Turn off live updates", "rcfilters-liveupdates-button-title-off": "Display new changes as they happen", + "rcfilters-watchlist-markSeen-button": "Mark all changes as seen", "rcnotefrom": "Below {{PLURAL:$5|is the change|are the changes}} since $3, $4 (up to $1 shown).", "rclistfromreset": "Reset date selection", "rclistfrom": "Show new changes starting from $2, $3", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index eeb0e7a65f..20b018261d 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -1651,6 +1651,7 @@ "rcfilters-liveupdates-button": "Label for the button to enable or disable live updates on [[Special:RecentChanges]]", "rcfilters-liveupdates-button-title-on": "Title for the button to enable or disable live updates on [[Special:RecentChanges]] when the feature is ON.", "rcfilters-liveupdates-button-title-off": "Title for the button to enable or disable live updates on [[Special:RecentChanges]] when the feature is OFF.", + "rcfilters-watchlist-markSeen-button": "Label for the button to mark all changes as seen on [[Special:Watchlist]] when using the structured filters interface.", "rcnotefrom": "This message is displayed at [[Special:RecentChanges]] when viewing recentchanges from some specific time.\n\nThe corresponding message is {{msg-mw|Rclistfrom}}.\n\nParameters:\n* $1 - the maximum number of changes that are displayed\n* $2 - (Optional) a date and time\n* $3 - a date\n* $4 - a time\n* $5 - Number of changes are displayed, for use with PLURAL", "rclistfromreset": "Used on [[Special:RecentChanges]] to reset a selection of a certain date range.", "rclistfrom": "Used on [[Special:RecentChanges]]. Parameters:\n* $1 - (Currently not use) date and time. The date and the time adds to the rclistfrom description.\n* $2 - time. The time adds to the rclistfrom link description (with split of date and time).\n* $3 - date. The date adds to the rclistfrom link description (with split of date and time).\n\nThe corresponding message is {{msg-mw|Rcnotefrom}}.", diff --git a/resources/Resources.php b/resources/Resources.php index 09bd4dc762..d504e60808 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -1799,6 +1799,7 @@ return [ 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterItemHighlightButton.js', 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.HighlightColorPickerWidget.js', 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.LiveUpdateButtonWidget.js', + 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MarkSeenButtonWidget.js', 'resources/src/mediawiki.rcfilters/mw.rcfilters.HighlightColors.js', 'resources/src/mediawiki.rcfilters/mw.rcfilters.init.js', ], @@ -1889,6 +1890,7 @@ return [ 'rcfilters-liveupdates-button', 'rcfilters-liveupdates-button-title-on', 'rcfilters-liveupdates-button-title-off', + 'rcfilters-watchlist-markSeen-button', 'rcfilters-other-review-tools', 'blanknamespace', 'namespaces', diff --git a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js index 65943989f1..d7042ff3c6 100644 --- a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js +++ b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js @@ -14,6 +14,7 @@ this.newChangesExist = false; this.nextFrom = null; this.liveUpdate = false; + this.unseenWatchedChanges = false; }; /* Initialization */ @@ -81,6 +82,7 @@ if ( mw.rcfilters.featureFlags.liveUpdate ) { this.extractNextFrom( $fieldset ); } + this.checkForUnseenWatchedChanges( changesListContent ); this.emit( 'update', changesListContent, $fieldset, isInitialDOM, separateOldAndNew ? from : null ); }; @@ -140,4 +142,20 @@ return this.liveUpdate; }; + /** + * Check if some of the given changes watched and unseen + * + * @param {jQuery|string} changeslistContent + */ + mw.rcfilters.dm.ChangesListViewModel.prototype.checkForUnseenWatchedChanges = function ( changeslistContent ) { + this.unseenWatchedChanges = changeslistContent !== 'NO_RESULTS' && + changeslistContent.find( '.mw-changeslist-line-watched' ).length > 0; + }; + + /** + * @return {boolean} Whether some of the current changes are watched and unseen + */ + mw.rcfilters.dm.ChangesListViewModel.prototype.hasUnseenWatchedChanges = function () { + return this.unseenWatchedChanges; + }; }( mediaWiki ) ); diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js index 98a628167e..c24e6c67d3 100644 --- a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js +++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js @@ -996,7 +996,7 @@ * Update the list of changes and notify the model * * @param {Object} [params] Extra parameters to add to the API call - * @param {string} [updateMode='filterChange'] One of 'filterChange', 'liveUpdate', 'showNewChanges' + * @param {string} [updateMode='filterChange'] One of 'filterChange', 'liveUpdate', 'showNewChanges', 'markSeen' * @return {jQuery.Promise} Promise that is resolved when the update is complete */ mw.rcfilters.Controller.prototype.updateChangesList = function ( params, updateMode ) { @@ -1263,4 +1263,18 @@ this.prevLoggedItems = filters; } }; + + /** + * Mark all changes as seen on Watchlist + */ + mw.rcfilters.Controller.prototype.markAllChangesAsSeen = function () { + var api = new mw.Api(); + api.postWithToken( 'csrf', { + formatversion: 2, + action: 'setnotificationtimestamp', + entirewatchlist: true + } ).then( function () { + this.updateChangesList( null, 'markSeen' ); + }.bind( this ) ); + }; }( mediaWiki, jQuery ) ); diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js index dba8fe060e..a6bce1434e 100644 --- a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js +++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js @@ -25,7 +25,11 @@ $overlay = $( '
' ) .addClass( 'mw-rcfilters-ui-overlay' ), filtersWidget = new mw.rcfilters.ui.FilterWrapperWidget( - controller, filtersModel, savedQueriesModel, changesListModel, { $overlay: $overlay } ); + controller, filtersModel, savedQueriesModel, changesListModel, { $overlay: $overlay } ), + markSeenButton, + currentPage = mw.config.get( 'wgCanonicalNamespace' ) + + ':' + + mw.config.get( 'wgCanonicalSpecialPageName' ); // TODO: The changesListWrapperWidget should be able to initialize // after the model is ready. @@ -54,30 +58,38 @@ controller.replaceUrl(); - toplinksTitle = new OO.ui.ButtonWidget( { - framed: false, - indicator: topLinksCookieValue === 'collapsed' ? 'down' : 'up', - flags: [ 'progressive' ], - label: $( '' ).append( mw.message( 'rcfilters-other-review-tools' ).parse() ).contents() - } ); - $( '.mw-recentchanges-toplinks-title' ).replaceWith( toplinksTitle.$element ); - // Move the top links to a designated area so it's near the - // 'saved filters' button and make it collapsible - $( '.mw-recentchanges-toplinks' ) - .addClass( 'mw-rcfilters-ui-ready' ) - .makeCollapsible( { - collapsed: topLinksCookieValue === 'collapsed', - $customTogglers: toplinksTitle.$element - } ) - .on( 'beforeExpand.mw-collapsible', function () { - mw.cookie.set( topLinksCookieName, 'expanded' ); - toplinksTitle.setIndicator( 'up' ); - } ) - .on( 'beforeCollapse.mw-collapsible', function () { - mw.cookie.set( topLinksCookieName, 'collapsed' ); - toplinksTitle.setIndicator( 'down' ); - } ) - .appendTo( '.mw-rcfilters-ui-filterWrapperWidget-top-placeholder' ); + if ( currentPage === 'Special:Recentchanges' ) { + toplinksTitle = new OO.ui.ButtonWidget( { + framed: false, + indicator: topLinksCookieValue === 'collapsed' ? 'down' : 'up', + flags: [ 'progressive' ], + label: $( '' ).append( mw.message( 'rcfilters-other-review-tools' ).parse() ).contents() + } ); + $( '.mw-recentchanges-toplinks-title' ).replaceWith( toplinksTitle.$element ); + // Move the top links to a designated area so it's near the + // 'saved filters' button and make it collapsible + $( '.mw-recentchanges-toplinks' ) + .addClass( 'mw-rcfilters-ui-ready' ) + .makeCollapsible( { + collapsed: topLinksCookieValue === 'collapsed', + $customTogglers: toplinksTitle.$element + } ) + .on( 'beforeExpand.mw-collapsible', function () { + mw.cookie.set( topLinksCookieName, 'expanded' ); + toplinksTitle.setIndicator( 'up' ); + } ) + .on( 'beforeCollapse.mw-collapsible', function () { + mw.cookie.set( topLinksCookieName, 'collapsed' ); + toplinksTitle.setIndicator( 'down' ); + } ) + .appendTo( '.mw-rcfilters-ui-filterWrapperWidget-top-placeholder' ); + } // end Special:RC + + if ( currentPage === 'Special:Watchlist' ) { + markSeenButton = new mw.rcfilters.ui.MarkSeenButtonWidget( controller, changesListModel ); + $( 'form#mw-watchlist-resetbutton' ).detach(); + filtersWidget.prependToTopRow( markSeenButton ); + } // end Special:WL } }; diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js index 8f8ca38a42..c3af7c5bd8 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js @@ -17,7 +17,7 @@ mw.rcfilters.ui.FilterWrapperWidget = function MwRcfiltersUiFilterWrapperWidget( controller, model, savedQueriesModel, changesListModel, config ) { - var $top, $topRow, $bottom; + var $top, $bottom; config = config || {}; // Parent @@ -59,7 +59,7 @@ ); // Initialize - $topRow = $( '
' ) + this.$topRow = $( '
' ) .addClass( 'mw-rcfilters-ui-row' ) .append( $( '
' ) @@ -69,7 +69,7 @@ $top = $( '
' ) .addClass( 'mw-rcfilters-ui-filterWrapperWidget-top' ) .addClass( 'mw-rcfilters-ui-table' ) - .append( $topRow ); + .append( this.$topRow ); $bottom = $( '
' ) .addClass( 'mw-rcfilters-ui-filterWrapperWidget-bottom' ) @@ -84,7 +84,7 @@ { $overlay: this.$overlay } ); - $topRow.append( + this.$topRow.append( $( '
' ) .addClass( 'mw-rcfilters-ui-cell' ) .addClass( 'mw-rcfilters-ui-filterWrapperWidget-top-savedLinks' ) @@ -108,4 +108,19 @@ OO.inheritClass( mw.rcfilters.ui.FilterWrapperWidget, OO.ui.Widget ); OO.mixinClass( mw.rcfilters.ui.FilterWrapperWidget, OO.ui.mixin.PendingElement ); + + /* Methods */ + + /** + * Add a widget at the beginning of the top row + * + * @param {OO.ui.Widget} widget Any widget + */ + mw.rcfilters.ui.FilterWrapperWidget.prototype.prependToTopRow = function ( widget ) { + this.$topRow.prepend( + widget.$element + .addClass( 'mw-rcfilters-ui-cell' ) + ); + }; + }( mediaWiki ) ); diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MarkSeenButtonWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MarkSeenButtonWidget.js new file mode 100644 index 0000000000..073cd1ea7a --- /dev/null +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MarkSeenButtonWidget.js @@ -0,0 +1,55 @@ +( function ( mw ) { + /** + * Button for marking all changes as seen on the Watchlist + * + * @extends OO.ui.ButtonWidget + * + * @constructor + * @param {mw.rcfilters.Controller} controller + * @param {mw.rcfilters.dm.ChangesListViewModel} model Changes list view model + * @param {Object} [config] Configuration object + */ + mw.rcfilters.ui.MarkSeenButtonWidget = function MwRcfiltersUiMarkSeenButtonWidget( controller, model, config ) { + config = config || {}; + + // Parent + mw.rcfilters.ui.MarkSeenButtonWidget.parent.call( this, $.extend( { + label: mw.message( 'rcfilters-watchlist-markSeen-button' ).text(), + icon: 'doubleCheck' + }, config ) ); + + this.controller = controller; + this.model = model; + + // Events + this.connect( this, { click: 'onClick' } ); + this.model.connect( this, { update: 'onModelUpdate' } ); + + this.$element.addClass( 'mw-rcfilters-ui-markSeenButtonWidget' ); + + this.onModelUpdate(); + }; + + /* Initialization */ + + OO.inheritClass( mw.rcfilters.ui.MarkSeenButtonWidget, OO.ui.ButtonWidget ); + + /* Methods */ + + /** + * Respond to the button being clicked + */ + mw.rcfilters.ui.MarkSeenButtonWidget.prototype.onClick = function () { + this.controller.markAllChangesAsSeen(); + // assume there's no more unseen changes until the next model update + this.setDisabled( true ); + }; + + /** + * Respond to the model being updated with new changes + */ + mw.rcfilters.ui.MarkSeenButtonWidget.prototype.onModelUpdate = function () { + this.setDisabled( !this.model.hasUnseenWatchedChanges() ); + }; + +}( mediaWiki ) ); -- 2.20.1