From be99787e5b216247ffbc26a7f90e27ac985fff4f Mon Sep 17 00:00:00 2001 From: Roan Kattouw Date: Tue, 19 Sep 2017 17:00:24 -0700 Subject: [PATCH] RCFilters: Redo the way spinners and ready/loading states are managed The mw-rcfilters-ui-ready class was being set on no fewer than 4 elements, all with different meanings, and some with no relevant styling at all. It also did not distinguish between "the UI is initializing" and "we are loading new results". Remove mw-rcfilters-ui-ready completely (and remove some code that added or removed it pointlessly), and create two new CSS classes on the . mw-rcfilters-ui-initialized is added when the UI has initialized, and is used to hide the old UI and display a spinner while the UI loads. mw-rcfilters-ui-loading is added when we start loading new results and removed when they arrive; it's used to grey out the results area and add a spinner. Bonus: make the spinner appear in a different place depending on why it's being shown: when initializing, it's shown in the place where the UI will soon appear; when loading, it's shown near the top of the changes list. Change-Id: Ib5c8a36654ba44880823fdade8cad52ffa59ed69 --- .../mediawiki.rcfilters/mw.rcfilters.init.js | 5 +- .../styles/mw.rcfilters.less | 49 ++++++++++++------- .../mw.rcfilters.ui.RcTopSectionWidget.less | 2 +- ...w.rcfilters.ui.ChangesListWrapperWidget.js | 6 +-- .../ui/mw.rcfilters.ui.FormWrapperWidget.js | 2 - .../ui/mw.rcfilters.ui.RcTopSectionWidget.js | 1 - 6 files changed, 37 insertions(+), 28 deletions(-) diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js index 83e5796353..13da97f1b9 100644 --- a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js +++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js @@ -50,8 +50,9 @@ filtersModel, changesListModel, controller, $( 'fieldset.cloptions' ) ); $( '.rcfilters-container' ).append( filtersWidget.$element ); - $( 'body' ).append( $overlay ); - $( '.rcfilters-head' ).addClass( 'mw-rcfilters-ui-ready' ); + $( 'body' ) + .append( $overlay ) + .addClass( 'mw-rcfilters-ui-initialized' ); $( 'a.mw-helplink' ).attr( 'href', diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less index cc5ecd4e70..0ab2c01f63 100644 --- a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less +++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less @@ -1,6 +1,9 @@ @import 'mediawiki.mixins.animation'; @import 'mw.rcfilters.mixins'; +@rcfilters-spinner-width: 70px; +@rcfilters-head-min-height: 200px; + // Corrections for the standard special page .client-js { .cloptions { @@ -8,15 +11,14 @@ } .rcfilters-head { - min-height: 200px; - - &:not( .mw-rcfilters-ui-ready ) { - opacity: 0.5; - pointer-events: none; + min-height: @rcfilters-head-min-height; + } + body:not( .mw-rcfilters-ui-initialized ) .rcfilters-head { + opacity: 0.5; + pointer-events: none; - .cloptions { - display: none; - } + .cloptions { + display: none; } } @@ -32,22 +34,23 @@ // message of our own display: none; } + } - &:not( .mw-rcfilters-ui-ready ) { - opacity: 0.5; - } + body:not( .mw-rcfilters-ui-initialized ) .mw-changeslist, + body.mw-rcfilters-ui-loading .mw-changeslist { + opacity: 0.5; } .rcfilters-spinner { - margin: -2em auto 0; - width: 70px; - opacity: 0.8; display: none; - white-space: nowrap; + position: absolute; + left: 50%; + width: @rcfilters-spinner-width; + // Make sure the middle of the spinner is centered, rather than its left edge + margin-left: -@rcfilters-spinner-width/2; - &:not( .mw-rcfilters-ui-ready ) { - display: block; - } + opacity: 0.8; + white-space: nowrap; & .rcfilters-spinner-bounce, &:before, @@ -69,6 +72,16 @@ .animation-delay( 0s ); } } + body:not( .mw-rcfilters-ui-initialized ) .rcfilters-spinner { + display: block; + // When initializing, display the spinner on top of the area where the UI will appear + margin-top: -@rcfilters-head-min-height/2; + } + body.mw-rcfilters-ui-loading .rcfilters-spinner { + display: block; + // When loading new results, display the spinner on top of the results area + margin-top: 4em; + } #contentSub, .watchlistDetails, diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RcTopSectionWidget.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RcTopSectionWidget.less index 9d1cc23801..aca3ea68a5 100644 --- a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RcTopSectionWidget.less +++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RcTopSectionWidget.less @@ -37,7 +37,7 @@ border: 1px solid #ddd; } - &:not( .mw-rcfilters-ui-ready ) { + body:not( .mw-rcfilters-ui-initialized ) & { display: none; } } diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js index f331f75edb..429def4ec2 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js @@ -109,8 +109,7 @@ * Respond to changes list model invalidate */ mw.rcfilters.ui.ChangesListWrapperWidget.prototype.onModelInvalidate = function () { - $( '.rcfilters-spinner' ).removeClass( 'mw-rcfilters-ui-ready' ); - this.$element.removeClass( 'mw-rcfilters-ui-ready' ); + $( 'body' ).addClass( 'mw-rcfilters-ui-loading' ); }; /** @@ -184,8 +183,7 @@ mw.hook( 'wikipage.content' ).fire( widget.$element ); } - $( '.rcfilters-spinner' ).addClass( 'mw-rcfilters-ui-ready' ); - widget.$element.addClass( 'mw-rcfilters-ui-ready' ); + $( 'body' ).removeClass( 'mw-rcfilters-ui-loading' ); } ); }; diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js index cfcdf353a9..83905d5be9 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js @@ -87,7 +87,6 @@ */ mw.rcfilters.ui.FormWrapperWidget.prototype.onChangesModelInvalidate = function () { this.$submitButton.prop( 'disabled', true ); - this.$element.removeClass( 'mw-rcfilters-ui-ready' ); }; /** @@ -100,7 +99,6 @@ */ mw.rcfilters.ui.FormWrapperWidget.prototype.onChangesModelUpdate = function ( $changesList, $fieldset, isInitialDOM ) { this.$submitButton.prop( 'disabled', false ); - this.$element.removeClass( 'mw-rcfilters-ui-ready' ); // Replace the entire fieldset this.$element.empty().append( $fieldset.contents() ); diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RcTopSectionWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RcTopSectionWidget.js index f0e1241241..95a4e592d8 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RcTopSectionWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RcTopSectionWidget.js @@ -33,7 +33,6 @@ } ); this.$topLinks - .addClass( 'mw-rcfilters-ui-ready' ) .makeCollapsible( { collapsed: topLinksCookieValue === 'collapsed', $customTogglers: toplinksTitle.$element -- 2.20.1