jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/327233 )

Change subject: Load details divs on scroll
......................................................................


Load details divs on scroll

Speeds up the loading of details step significantly when there are many
uploads.

Bug: T153210
Change-Id: Ie178d8b7ec3c622d05b5648747d20deaf568f1e1
---
M resources/controller/uw.controller.Details.js
M resources/mw.UploadWizardDetails.js
2 files changed, 260 insertions(+), 203 deletions(-)

Approvals:
  Matthias Mullie: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/resources/controller/uw.controller.Details.js 
b/resources/controller/uw.controller.Details.js
index c64bede..9e99669 100644
--- a/resources/controller/uw.controller.Details.js
+++ b/resources/controller/uw.controller.Details.js
@@ -139,7 +139,6 @@
         */
        uw.controller.Details.prototype.createDetails = function ( upload ) {
                upload.details = new mw.UploadWizardDetails( upload, $( 
'#mwe-upwiz-macro-files' ) );
-               upload.details.populate();
                upload.details.attach();
        };
 
diff --git a/resources/mw.UploadWizardDetails.js 
b/resources/mw.UploadWizardDetails.js
index 262808a..b4cc851 100644
--- a/resources/mw.UploadWizardDetails.js
+++ b/resources/mw.UploadWizardDetails.js
@@ -10,11 +10,6 @@
         * @param {jQuery} containerDiv The `div` to put the interface into
         */
        mw.UploadWizardDetails = function ( upload, containerDiv ) {
-               var
-                       descriptionRequired, uri,
-                       $moreDetailsWrapperDiv, $moreDetailsDiv,
-                       details = this;
-
                this.upload = upload;
                this.containerDiv = containerDiv;
                this.api = upload.api;
@@ -22,208 +17,226 @@
                this.mainFields = [];
 
                this.div = $( '<div class="mwe-upwiz-info-file 
ui-helper-clearfix filled"></div>' );
-
-               this.thumbnailDiv = $( '<div class="mwe-upwiz-thumbnail 
mwe-upwiz-thumbnail-side"></div>' );
-
-               this.dataDiv = $( '<div class="mwe-upwiz-data"></div>' );
-
-               // descriptions
-               // Description is not required if a campaign provides 
alternative wikitext fields,
-               // which are assumed to function like a description
-               descriptionRequired = !(
-                       mw.UploadWizard.config.fields &&
-                       mw.UploadWizard.config.fields.length &&
-                       mw.UploadWizard.config.fields[ 0 ].wikitext
-               );
-               this.descriptionsDetails = new uw.DescriptionsDetailsWidget( {
-                       required: descriptionRequired
-               } );
-               this.descriptionsDetailsField = new uw.FieldLayout( 
this.descriptionsDetails, {
-                       label: mw.message( 'mwe-upwiz-desc' ).text(),
-                       help: mw.message( 'mwe-upwiz-tooltip-description' 
).text(),
-                       required: descriptionRequired
-               } );
-               this.mainFields.push( this.descriptionsDetailsField );
-
-               this.titleDetails = new uw.TitleDetailsWidget( {
-                       // Normalize file extension, e.g. 'JPEG' to 'jpg'
-                       extension: mw.Title.normalizeExtension( 
this.upload.title.getExtension() )
-               } );
-               this.titleDetailsField = new uw.FieldLayout( this.titleDetails, 
{
-                       label: mw.message( 'mwe-upwiz-title' ).text(),
-                       help: mw.message( 'mwe-upwiz-tooltip-title' ).text(),
-                       required: true
-               } );
-               this.mainFields.push( this.titleDetailsField );
-
-               this.deedChooserDetails = new uw.DeedChooserDetailsWidget();
-               this.deedChooserDetailsField = new uw.FieldLayout( 
this.deedChooserDetails, {
-                       label: mw.message( 'mwe-upwiz-copyright-info' ).text(),
-                       required: true
-               } );
-               this.deedChooserDetailsField.toggle( false ); // See 
useCustomDeedChooser()
-               this.mainFields.push( this.deedChooserDetailsField );
-
-               this.categoriesDetails = new uw.CategoriesDetailsWidget();
-               this.categoriesDetailsField = new uw.FieldLayout( 
this.categoriesDetails, {
-                       label: mw.message( 'mwe-upwiz-categories' ).text(),
-                       help: new OO.ui.HtmlSnippet(
-                               mw.message( 'mwe-upwiz-tooltip-categories', $( 
'<a>' ).attr( {
-                                       target: '_blank',
-                                       href: 
'https://commons.wikimedia.org/wiki/Commons:Categories'
-                               } ) ).parse()
-                       )
-               } );
-               this.mainFields.push( this.categoriesDetailsField );
-
-               this.dateDetails = new uw.DateDetailsWidget( { upload: 
this.upload } );
-               this.dateDetailsField = new uw.FieldLayout( this.dateDetails, {
-                       label: mw.message( 'mwe-upwiz-date-created' ).text(),
-                       help: mw.message( 'mwe-upwiz-tooltip-date' ).text(),
-                       required: true
-               } );
-               this.mainFields.push( this.dateDetailsField );
-
-               this.otherDetails = new uw.OtherDetailsWidget();
-               this.otherDetailsField = new uw.FieldLayout( this.otherDetails, 
{
-                       label: mw.message( 'mwe-upwiz-other' ).text(),
-                       help: mw.message( 'mwe-upwiz-tooltip-other' ).text()
-               } );
-               this.mainFields.push( this.otherDetailsField );
-
-               this.locationInput = new uw.LocationDetailsWidget( { 
showHeading: true } );
-               this.locationInputField = new uw.FieldLayout( 
this.locationInput, {
-                       // No 'label', labels are included in this widget
-                       help: new OO.ui.HtmlSnippet(
-                               mw.message( 'mwe-upwiz-tooltip-location', $( 
'<a>' ).attr( {
-                                       target: '_blank',
-                                       href: 
'//commons.wikimedia.org/wiki/Commons:Geocoding'
-                               } ) ).parse()
-                       )
-               } );
-               this.mainFields.push( this.locationInputField );
-
-               /* Build the form for the file upload */
-               this.$form = $( '<form id="mwe-upwiz-detailsform' + 
this.upload.index + '"></form>' ).addClass( 'detailsForm' );
-               this.$form.append(
-                       this.titleDetailsField.$element,
-                       this.descriptionsDetailsField.$element,
-                       this.deedChooserDetailsField.$element,
-                       this.dateDetailsField.$element,
-                       this.categoriesDetailsField.$element
-               );
-
-               this.$form.on( 'submit', function ( e ) {
-                       // Prevent actual form submission
-                       e.preventDefault();
-               } );
-
-               this.campaignDetailsFields = [];
-               $.each( mw.UploadWizard.config.fields, function ( i, field ) {
-                       var customDetails, customDetailsField;
-
-                       if ( field.wikitext ) {
-                               customDetails = new uw.CampaignDetailsWidget( 
field );
-                               customDetailsField = new uw.FieldLayout( 
customDetails, {
-                                       label: $( $.parseHTML( field.label ) ),
-                                       required: !!field.required
-                               } );
-
-                               if ( field.initialValue ) {
-                                       customDetails.setSerialized( { value: 
field.initialValue } );
-                               }
-
-                               details.$form.append( 
customDetailsField.$element );
-                               details.campaignDetailsFields.push( 
customDetailsField );
-                       }
-               } );
-
-               $moreDetailsWrapperDiv = $( '<div class="mwe-more-details">' );
-               $moreDetailsDiv = $( '<div>' );
-
-               $moreDetailsDiv.append(
-                       this.locationInputField.$element,
-                       this.otherDetailsField.$element
-               );
-
-               $moreDetailsWrapperDiv
-                       .append(
-                               $( '<a>' ).text( mw.msg( 
'mwe-upwiz-more-options' ) )
-                                       .addClass( 
'mwe-upwiz-details-more-options mw-collapsible-toggle mw-collapsible-arrow' ),
-                               $moreDetailsDiv.addClass( 
'mw-collapsible-content' )
-                       )
-                       .makeCollapsible( { collapsed: true } );
-
-               // Expand collapsed sections if the fields within were changed 
(e.g. by metadata copier)
-               this.locationInput.on( 'change', function () {
-                       $moreDetailsWrapperDiv.data( 'mw-collapsible' 
).expand();
-               } );
-               this.otherDetails.on( 'change', function () {
-                       $moreDetailsWrapperDiv.data( 'mw-collapsible' 
).expand();
-               } );
-
-               this.$form.append(
-                       $moreDetailsWrapperDiv
-               );
-
-               // Add in remove control to form
-               this.removeCtrl = new OO.ui.ButtonWidget( {
-                       label: mw.message( 'mwe-upwiz-remove' ).text(),
-                       title: mw.message( 'mwe-upwiz-remove-upload' ).text(),
-                       classes: [ 'mwe-upwiz-remove-upload' ],
-                       flags: 'destructive',
-                       icon: 'remove',
-                       framed: false
-               } ).on( 'click', function () {
-                       OO.ui.confirm( mw.message( 
'mwe-upwiz-license-confirm-remove' ).text(), {
-                               title: mw.message( 
'mwe-upwiz-license-confirm-remove-title' ).text()
-                       } ).done( function ( confirmed ) {
-                               if ( confirmed ) {
-                                       details.upload.emit( 'remove-upload' );
-                               }
-                       } );
-               } );
-
-               this.$form.append( this.removeCtrl.$element );
-
-               this.submittingDiv = $( '<div>' ).addClass( 
'mwe-upwiz-submitting' )
-                       .append(
-                               $( '<div>' ).addClass( 
'mwe-upwiz-file-indicator' ),
-                               $( '<div>' ).addClass( 
'mwe-upwiz-details-texts' ).append(
-                                       $( '<div>' ).addClass( 
'mwe-upwiz-visible-file-filename-text' ),
-                                       $( '<div>' ).addClass( 
'mwe-upwiz-file-status-line' )
-                               )
-                       );
-
-               $( this.dataDiv ).append(
-                       this.$form,
-                       this.submittingDiv
-               ).morphCrossfader();
-
-               $( this.div ).append(
-                       this.thumbnailDiv,
-                       this.dataDiv
-               );
-
-               uri = new mw.Uri( location.href, { overrideKeys: true } );
-               if ( mw.UploadWizard.config.defaults.description || 
uri.query.descriptionlang ) {
-                       this.descriptionsDetails.setSerialized( {
-                               descriptions: [
-                                       {
-                                               language: 
uri.query.descriptionlang ?
-                                                       
uw.DescriptionDetailsWidget.static.getClosestAllowedLanguage( 
uri.query.descriptionlang ) :
-                                                       
uw.DescriptionDetailsWidget.static.getDefaultLanguage(),
-                                               description: 
mw.UploadWizard.config.defaults.description || ''
-                                       }
-                               ]
-                       } );
-               }
        };
 
        mw.UploadWizardDetails.prototype = {
 
                // Has this details object been attached to the DOM already?
                isAttached: false,
+
+               /**
+                * Build the interface and attach all elements - do this on 
demand.
+                */
+               buildInterface: function () {
+                       var descriptionRequired, uri,
+                               $moreDetailsWrapperDiv, $moreDetailsDiv,
+                               details = this;
+
+                       this.thumbnailDiv = $( '<div class="mwe-upwiz-thumbnail 
mwe-upwiz-thumbnail-side"></div>' );
+
+                       this.dataDiv = $( '<div class="mwe-upwiz-data"></div>' 
);
+
+                       // descriptions
+                       // Description is not required if a campaign provides 
alternative wikitext fields,
+                       // which are assumed to function like a description
+                       descriptionRequired = !(
+                               mw.UploadWizard.config.fields &&
+                               mw.UploadWizard.config.fields.length &&
+                               mw.UploadWizard.config.fields[ 0 ].wikitext
+                       );
+                       this.descriptionsDetails = new 
uw.DescriptionsDetailsWidget( {
+                               required: descriptionRequired
+                       } );
+                       this.descriptionsDetailsField = new uw.FieldLayout( 
this.descriptionsDetails, {
+                               label: mw.message( 'mwe-upwiz-desc' ).text(),
+                               help: mw.message( 
'mwe-upwiz-tooltip-description' ).text(),
+                               required: descriptionRequired
+                       } );
+                       this.mainFields.push( this.descriptionsDetailsField );
+
+                       this.titleDetails = new uw.TitleDetailsWidget( {
+                               // Normalize file extension, e.g. 'JPEG' to 
'jpg'
+                               extension: mw.Title.normalizeExtension( 
this.upload.title.getExtension() )
+                       } );
+                       this.titleDetailsField = new uw.FieldLayout( 
this.titleDetails, {
+                               label: mw.message( 'mwe-upwiz-title' ).text(),
+                               help: mw.message( 'mwe-upwiz-tooltip-title' 
).text(),
+                               required: true
+                       } );
+                       this.mainFields.push( this.titleDetailsField );
+
+                       this.deedChooserDetails = new 
uw.DeedChooserDetailsWidget();
+                       this.deedChooserDetailsField = new uw.FieldLayout( 
this.deedChooserDetails, {
+                               label: mw.message( 'mwe-upwiz-copyright-info' 
).text(),
+                               required: true
+                       } );
+                       this.deedChooserDetailsField.toggle( false ); // See 
useCustomDeedChooser()
+                       this.mainFields.push( this.deedChooserDetailsField );
+
+                       this.categoriesDetails = new 
uw.CategoriesDetailsWidget();
+                       this.categoriesDetailsField = new uw.FieldLayout( 
this.categoriesDetails, {
+                               label: mw.message( 'mwe-upwiz-categories' 
).text(),
+                               help: new OO.ui.HtmlSnippet(
+                                       mw.message( 
'mwe-upwiz-tooltip-categories', $( '<a>' ).attr( {
+                                               target: '_blank',
+                                               href: 
'https://commons.wikimedia.org/wiki/Commons:Categories'
+                                       } ) ).parse()
+                               )
+                       } );
+                       this.mainFields.push( this.categoriesDetailsField );
+
+                       this.dateDetails = new uw.DateDetailsWidget( { upload: 
this.upload } );
+                       this.dateDetailsField = new uw.FieldLayout( 
this.dateDetails, {
+                               label: mw.message( 'mwe-upwiz-date-created' 
).text(),
+                               help: mw.message( 'mwe-upwiz-tooltip-date' 
).text(),
+                               required: true
+                       } );
+                       this.mainFields.push( this.dateDetailsField );
+
+                       this.otherDetails = new uw.OtherDetailsWidget();
+                       this.otherDetailsField = new uw.FieldLayout( 
this.otherDetails, {
+                               label: mw.message( 'mwe-upwiz-other' ).text(),
+                               help: mw.message( 'mwe-upwiz-tooltip-other' 
).text()
+                       } );
+                       this.mainFields.push( this.otherDetailsField );
+
+                       this.locationInput = new uw.LocationDetailsWidget( { 
showHeading: true } );
+                       this.locationInputField = new uw.FieldLayout( 
this.locationInput, {
+                               // No 'label', labels are included in this 
widget
+                               help: new OO.ui.HtmlSnippet(
+                                       mw.message( 
'mwe-upwiz-tooltip-location', $( '<a>' ).attr( {
+                                               target: '_blank',
+                                               href: 
'//commons.wikimedia.org/wiki/Commons:Geocoding'
+                                       } ) ).parse()
+                               )
+                       } );
+                       this.mainFields.push( this.locationInputField );
+
+                       /* Build the form for the file upload */
+                       this.$form = $( '<form id="mwe-upwiz-detailsform' + 
this.upload.index + '"></form>' ).addClass( 'detailsForm' );
+                       this.$form.append(
+                               this.titleDetailsField.$element,
+                               this.descriptionsDetailsField.$element,
+                               this.deedChooserDetailsField.$element,
+                               this.dateDetailsField.$element,
+                               this.categoriesDetailsField.$element
+                       );
+
+                       this.$form.on( 'submit', function ( e ) {
+                               // Prevent actual form submission
+                               e.preventDefault();
+                       } );
+
+                       this.campaignDetailsFields = [];
+                       $.each( mw.UploadWizard.config.fields, function ( i, 
field ) {
+                               var customDetails, customDetailsField;
+
+                               if ( field.wikitext ) {
+                                       customDetails = new 
uw.CampaignDetailsWidget( field );
+                                       customDetailsField = new 
uw.FieldLayout( customDetails, {
+                                               label: $( $.parseHTML( 
field.label ) ),
+                                               required: !!field.required
+                                       } );
+
+                                       if ( field.initialValue ) {
+                                               customDetails.setSerialized( { 
value: field.initialValue } );
+                                       }
+
+                                       details.$form.append( 
customDetailsField.$element );
+                                       details.campaignDetailsFields.push( 
customDetailsField );
+                               }
+                       } );
+
+                       $moreDetailsWrapperDiv = $( '<div 
class="mwe-more-details">' );
+                       $moreDetailsDiv = $( '<div>' );
+
+                       $moreDetailsDiv.append(
+                               this.locationInputField.$element,
+                               this.otherDetailsField.$element
+                       );
+
+                       $moreDetailsWrapperDiv
+                               .append(
+                                       $( '<a>' ).text( mw.msg( 
'mwe-upwiz-more-options' ) )
+                                               .addClass( 
'mwe-upwiz-details-more-options mw-collapsible-toggle mw-collapsible-arrow' ),
+                                       $moreDetailsDiv.addClass( 
'mw-collapsible-content' )
+                               )
+                               .makeCollapsible( { collapsed: true } );
+
+                       // Expand collapsed sections if the fields within were 
changed (e.g. by metadata copier)
+                       this.locationInput.on( 'change', function () {
+                               $moreDetailsWrapperDiv.data( 'mw-collapsible' 
).expand();
+                       } );
+                       this.otherDetails.on( 'change', function () {
+                               $moreDetailsWrapperDiv.data( 'mw-collapsible' 
).expand();
+                       } );
+
+                       this.$form.append(
+                               $moreDetailsWrapperDiv
+                       );
+
+                       // Add in remove control to form
+                       this.removeCtrl = new OO.ui.ButtonWidget( {
+                               label: mw.message( 'mwe-upwiz-remove' ).text(),
+                               title: mw.message( 'mwe-upwiz-remove-upload' 
).text(),
+                               classes: [ 'mwe-upwiz-remove-upload' ],
+                               flags: 'destructive',
+                               icon: 'remove',
+                               framed: false
+                       } ).on( 'click', function () {
+                               OO.ui.confirm( mw.message( 
'mwe-upwiz-license-confirm-remove' ).text(), {
+                                       title: mw.message( 
'mwe-upwiz-license-confirm-remove-title' ).text()
+                               } ).done( function ( confirmed ) {
+                                       if ( confirmed ) {
+                                               details.upload.emit( 
'remove-upload' );
+                                       }
+                               } );
+                       } );
+
+                       this.$form.append( this.removeCtrl.$element );
+
+                       this.submittingDiv = $( '<div>' ).addClass( 
'mwe-upwiz-submitting' )
+                               .append(
+                                       $( '<div>' ).addClass( 
'mwe-upwiz-file-indicator' ),
+                                       $( '<div>' ).addClass( 
'mwe-upwiz-details-texts' ).append(
+                                               $( '<div>' ).addClass( 
'mwe-upwiz-visible-file-filename-text' ),
+                                               $( '<div>' ).addClass( 
'mwe-upwiz-file-status-line' )
+                                       )
+                               );
+
+                       $( this.dataDiv ).append(
+                               this.$form,
+                               this.submittingDiv
+                       ).morphCrossfader();
+
+                       $( this.div ).append(
+                               this.thumbnailDiv,
+                               this.dataDiv
+                       );
+
+                       uri = new mw.Uri( location.href, { overrideKeys: true } 
);
+                       if ( mw.UploadWizard.config.defaults.description || 
uri.query.descriptionlang ) {
+                               this.descriptionsDetails.setSerialized( {
+                                       descriptions: [
+                                               {
+                                                       language: 
uri.query.descriptionlang ?
+                                                               
uw.DescriptionDetailsWidget.static.getClosestAllowedLanguage( 
uri.query.descriptionlang ) :
+                                                               
uw.DescriptionDetailsWidget.static.getDefaultLanguage(),
+                                                       description: 
mw.UploadWizard.config.defaults.description || ''
+                                               }
+                                       ]
+                               } );
+                       }
+
+                       this.populate();
+
+                       this.interfaceBuilt = true;
+
+                       if ( this.savedSerialData ) {
+                               this.setSerialized( this.savedSerialData );
+                               this.savedSerialData = undefined;
+                       }
+               },
 
                /*
                 * Append the div for this details object to the DOM.
@@ -233,8 +246,25 @@
                 * Will only append once.
                 */
                attach: function () {
+                       var $window = $( window ),
+                               details = this;
+
+                       function maybeBuild() {
+                               if ( !this.interfaceBuilt && 
$window.scrollTop() + $window.height() + 1000 >= details.div.offset().top ) {
+                                       details.buildInterface();
+                                       $window.off( 'scroll', maybeBuild );
+                               }
+                       }
+
                        if ( !this.isAttached ) {
                                $( this.containerDiv ).append( this.div );
+
+                               if ( $window.scrollTop() + $window.height() + 
1000 >= this.div.offset().top ) {
+                                       this.buildInterface();
+                               } else {
+                                       $window.on( 'scroll', maybeBuild );
+                               }
+
                                this.isAttached = true;
                        }
                },
@@ -573,6 +603,12 @@
                 * @return {Object.<string,Object>}
                 */
                getSerialized: function () {
+                       if ( !this.interfaceBuilt ) {
+                               // We don't have the interface yet, but it'll 
get filled out as
+                               // needed.
+                               return;
+                       }
+
                        return {
                                title: this.titleDetails.getSerialized(),
                                description: 
this.descriptionsDetails.getSerialized(),
@@ -593,10 +629,32 @@
                 *
                 * Fields from the representation can be omitted to keep the 
current value.
                 *
-                * @param {Object.<string,Object>} serialized
+                * @param {Object.<string,Object>} [serialized]
                 */
                setSerialized: function ( serialized ) {
                        var i;
+
+                       if ( !this.interfaceBuilt ) {
+                               // There's no interface yet! Don't load the 
data, just keep it
+                               // around.
+                               if ( serialized === undefined ) {
+                                       // Note: This will happen if we "undo" 
a copy operation while
+                                       // some of the details interfaces 
aren't loaded.
+                                       this.savedSerialData = undefined;
+                               } else {
+                                       this.savedSerialData = $.extend( true,
+                                               this.savedSerialData || {},
+                                               serialized
+                                       );
+                               }
+                               return;
+                       }
+
+                       if ( serialized === undefined ) {
+                               // This is meaningless if the interface is 
already built.
+                               return;
+                       }
+
                        if ( serialized.title ) {
                                this.titleDetails.setSerialized( 
serialized.title );
                        }

-- 
To view, visit https://gerrit.wikimedia.org/r/327233
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ie178d8b7ec3c622d05b5648747d20deaf568f1e1
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/extensions/UploadWizard
Gerrit-Branch: master
Gerrit-Owner: MarkTraceur <[email protected]>
Gerrit-Reviewer: Matthias Mullie <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to