RCFilters: Redo the way spinners and ready/loading states are managed
authorRoan Kattouw <roan.kattouw@gmail.com>
Wed, 20 Sep 2017 00:00:24 +0000 (17:00 -0700)
committerRoan Kattouw <roan.kattouw@gmail.com>
Wed, 20 Sep 2017 00:07:31 +0000 (17:07 -0700)
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 <body>.
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

resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RcTopSectionWidget.less
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RcTopSectionWidget.js

index 83e5796..13da97f 100644 (file)
@@ -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',
index cc5ecd4..0ab2c01 100644 (file)
@@ -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 {
        }
 
        .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;
                }
        }
 
                        // 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,
                        .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,
index 9d1cc23..aca3ea6 100644 (file)
@@ -37,7 +37,7 @@
                        border: 1px solid #ddd;
                }
 
-               &:not( .mw-rcfilters-ui-ready ) {
+               body:not( .mw-rcfilters-ui-initialized ) & {
                        display: none;
                }
        }
index f331f75..429def4 100644 (file)
         * 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' );
        };
 
        /**
                                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' );
                } );
        };
 
index cfcdf35..83905d5 100644 (file)
@@ -87,7 +87,6 @@
         */
        mw.rcfilters.ui.FormWrapperWidget.prototype.onChangesModelInvalidate = function () {
                this.$submitButton.prop( 'disabled', true );
-               this.$element.removeClass( 'mw-rcfilters-ui-ready' );
        };
 
        /**
         */
        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() );
index f0e1241..95a4e59 100644 (file)
@@ -33,7 +33,6 @@
                } );
 
                this.$topLinks
-                       .addClass( 'mw-rcfilters-ui-ready' )
                        .makeCollapsible( {
                                collapsed: topLinksCookieValue === 'collapsed',
                                $customTogglers: toplinksTitle.$element