Adds a live updates button that refreshes the changes list every 3 seconds.
For now this is pretty dumb in that it re-requests the entire list every time;
the next step would be to make it only load new changes using the &from=
query parameter.
Bug: T167743
Change-Id: Ic2ddea840e5c46f42b32ae4fff91138cacc28ec0
*/
$wgStructuredChangeFiltersEnableExperimentalViews = false;
+/**
+ * Whether to allow users to use the experimental live update feature in the new RecentChanges UI
+ */
+$wgStructuredChangeFiltersEnableLiveUpdate = false;
+
/**
* Use new page patrolling to check new pages on Special:Newpages
*/
*/
public function execute( $subpage ) {
global $wgStructuredChangeFiltersEnableSaving,
- $wgStructuredChangeFiltersEnableExperimentalViews;
+ $wgStructuredChangeFiltersEnableExperimentalViews,
+ $wgStructuredChangeFiltersEnableLiveUpdate;
// Backwards-compatibility: redirect to new feed URLs
$feedFormat = $this->getRequest()->getVal( 'feed' );
'wgStructuredChangeFiltersEnableExperimentalViews',
$wgStructuredChangeFiltersEnableExperimentalViews
);
+ $out->addJsConfigVars(
+ 'wgStructuredChangeFiltersEnableLiveUpdate',
+ $wgStructuredChangeFiltersEnableLiveUpdate
+ );
$out->addJsConfigVars(
'wgRCFiltersChangeTags',
$this->buildChangeTagList()
"rcfilters-view-namespaces-tooltip": "Filter results by namespace",
"rcfilters-view-tags-tooltip": "Filter results using edit tags",
"rcfilters-view-return-to-default-tooltip": "Return to main filter menu",
+ "rcfilters-liveupdates-button": "Live updates",
"rcnotefrom": "Below {{PLURAL:$5|is the change|are the changes}} since <strong>$3, $4</strong> (up to <strong>$1</strong> shown).",
"rclistfromreset": "Reset date selection",
"rclistfrom": "Show new changes starting from $2, $3",
"rcfilters-view-namespaces-tooltip": "Tooltip for the button that loads the namespace view in [[Special:RecentChanges]]",
"rcfilters-view-tags-tooltip": "Tooltip for the button that loads the tags view in [[Special:RecentChanges]]",
"rcfilters-view-return-to-default-tooltip": "Tooltip for the button that returns to the default filter view in [[Special:RecentChanges]]",
+ "rcfilters-liveupdates-button": "Label for the button to enable or disable live updates on [[Special:RecentChanges]]",
"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}}.",
'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js',
'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/mw.rcfilters.HighlightColors.js',
'resources/src/mediawiki.rcfilters/mw.rcfilters.init.js',
],
'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.SavedLinksListWidget.less',
'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.SavedLinksListItemWidget.less',
'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.SaveFiltersPopupButtonWidget.less',
+ 'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.LiveUpdateButtonWidget.less',
],
'skinStyles' => [
'monobook' => [
'rcfilters-view-namespaces-tooltip',
'rcfilters-view-tags-tooltip',
'rcfilters-view-return-to-default-tooltip',
+ 'rcfilters-liveupdates-button',
'blanknamespace',
'namespaces',
'invert',
'oojs-ui.styles.icons-interactions',
'oojs-ui.styles.icons-content',
'oojs-ui.styles.icons-layout',
+ 'oojs-ui.styles.icons-media',
],
],
'mediawiki.special' => [
/**
* @event update
* @param {jQuery|string} changesListContent
+ * @param {jQuery} $fieldset
*
* The list of change is now up to date
*/
this._trackHighlight( 'clear', filterName );
};
+ /**
+ * Enable or disable live updates.
+ * @param {boolean} enable True to enable, false to disable
+ */
+ mw.rcfilters.Controller.prototype.toggleLiveUpdate = function ( enable ) {
+ if ( enable && !this.liveUpdateTimeout ) {
+ this._scheduleLiveUpdate();
+ } else if ( !enable && this.liveUpdateTimeout ) {
+ clearTimeout( this.liveUpdateTimeout );
+ this.liveUpdateTimeout = null;
+ }
+ };
+
+ /**
+ * Set a timeout for the next live update.
+ * @private
+ */
+ mw.rcfilters.Controller.prototype._scheduleLiveUpdate = function () {
+ this.liveUpdateTimeout = setTimeout( this._doLiveUpdate.bind( this ), 3000 );
+ };
+
+ /**
+ * Perform a live update.
+ * @private
+ */
+ mw.rcfilters.Controller.prototype._doLiveUpdate = function () {
+ var controller = this;
+ this.updateChangesList( {}, true )
+ .always( function () {
+ if ( controller.liveUpdateTimeout ) {
+ // Live update was not disabled in the meantime
+ controller._scheduleLiveUpdate();
+ }
+ } );
+ };
+
/**
* Save the current model state as a saved query
*
* Update the list of changes and notify the model
*
* @param {Object} [params] Extra parameters to add to the API call
+ * @param {boolean} [isLiveUpdate] Don't update the URL or invalidate the changes list
+ * @return {jQuery.Promise} Promise that is resolved when the update is complete
*/
- mw.rcfilters.Controller.prototype.updateChangesList = function ( params ) {
- this._updateURL( params );
- this.changesListModel.invalidate();
- this._fetchChangesList()
+ mw.rcfilters.Controller.prototype.updateChangesList = function ( params, isLiveUpdate ) {
+ if ( !isLiveUpdate ) {
+ this._updateURL( params );
+ this.changesListModel.invalidate();
+ }
+ return this._fetchChangesList()
.then(
// Success
function ( pieces ) {
&-viewToggleButtons {
margin-top: 1em;
}
+
+ &-bottom {
+ margin-top: 1em;
+ }
}
--- /dev/null
+.mw-rcfilters-ui-liveUpdateButtonWidget {
+ &.oo-ui-toggleWidget-on {
+ position: relative;
+ overflow: hidden;
+ &:after {
+ content: '';
+ mix-blend-mode: screen;
+ position: absolute;
+ width: 1.875em;
+ height: 1.875em;
+ top: 1.875em / 4;
+ left: 0.46875em;
+ background: rgba( 51, 102, 204, 0.5 );
+ border-radius: 100%;
+ transform-origin: 50% 50%;
+ opacity: 0;
+ animation: ripple 1.2s ease-out infinite;
+ animation-delay: 1s;
+ }
+ }
+}
+
+@keyframes ripple {
+ 0%,
+ 35% {
+ transform: scale( 0 );
+ opacity: 1;
+ }
+ 50% {
+ transform: scale( 1.5 );
+ opacity: 0.8;
+ }
+ 100% {
+ opacity: 0;
+ transform: scale( 4 );
+ }
+}
* @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
*/
mw.rcfilters.ui.FilterWrapperWidget = function MwRcfiltersUiFilterWrapperWidget( controller, model, savedQueriesModel, config ) {
+ var $bottom;
config = config || {};
// Parent
{ $overlay: this.$overlay }
);
+ this.liveUpdateButton = new mw.rcfilters.ui.LiveUpdateButtonWidget(
+ this.controller
+ );
+
// Initialize
this.$element
.addClass( 'mw-rcfilters-ui-filterWrapperWidget' );
}
+ $bottom = $( '<div>' )
+ .addClass( 'mw-rcfilters-ui-filterWrapperWidget-bottom' );
+
+ if ( mw.config.get( 'wgStructuredChangeFiltersEnableLiveUpdate' ) ) {
+ $bottom.append( this.liveUpdateButton.$element );
+ }
+
this.$element.append(
- this.filterTagWidget.$element
+ this.filterTagWidget.$element,
+ $bottom
);
};
--- /dev/null
+( function ( mw ) {
+ /**
+ * Widget for toggling live updates
+ *
+ * @extends OO.ui.ToggleButtonWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller
+ * @param {Object} config Configuration object
+ */
+ mw.rcfilters.ui.LiveUpdateButtonWidget = function MwRcfiltersUiLiveUpdateButtonWidget( controller, config ) {
+ config = config || {};
+
+ // Parent
+ mw.rcfilters.ui.LiveUpdateButtonWidget.parent.call( this, $.extend( {
+ icon: 'play',
+ label: mw.message( 'rcfilters-liveupdates-button' ).text()
+ } ), config );
+
+ this.controller = controller;
+
+ // Events
+ this.connect( this, { change: 'onChange' } );
+
+ this.$element.addClass( 'mw-rcfilters-ui-liveUpdateButtonWidget' );
+ };
+
+ /* Initialization */
+
+ OO.inheritClass( mw.rcfilters.ui.LiveUpdateButtonWidget, OO.ui.ToggleButtonWidget );
+
+ /* Methods */
+
+ /**
+ * Respond to the button being toggled.
+ * @param {boolean} enable Whether the button is now pressed/enabled
+ */
+ mw.rcfilters.ui.LiveUpdateButtonWidget.prototype.onChange = function ( enable ) {
+ this.controller.toggleLiveUpdate( enable );
+ };
+
+}( mediaWiki ) );