From eb6386bb5b2f9a32ff25449b73fcad64aa3dea9c Mon Sep 17 00:00:00 2001 From: Gilles Dubuc Date: Fri, 11 Apr 2014 16:05:58 +0200 Subject: [PATCH] Load oojs-ui on demand when "use this file" is clicked Change-Id: Ia3b6b91c7ff0cb223f5f312eb901726fb6adcf35 Mingle: https://wikimedia.mingle.thoughtworks.com/projects/multimedia/cards/426 --- MultimediaViewer.php | 4 - MultimediaViewerHooks.php | 3 + resources/mmv/mmv.js | 10 +- resources/mmv/ui/mmv.ui.reuse.dialog.js | 112 ++++++++++++++---- .../qunit/mmv/ui/mmv.ui.reuse.dialog.test.js | 11 +- 5 files changed, 107 insertions(+), 33 deletions(-) diff --git a/MultimediaViewer.php b/MultimediaViewer.php index 0af11da0d..4404a14b6 100644 --- a/MultimediaViewer.php +++ b/MultimediaViewer.php @@ -485,10 +485,6 @@ $wgResourceModules += array( 'dependencies' => array( 'mmv.ui', 'oojs', - 'oojs-ui', - 'mmv.ui.reuse.share', - 'mmv.ui.reuse.embed', - 'mmv.ui.reuse.download', ), ), diff --git a/MultimediaViewerHooks.php b/MultimediaViewerHooks.php index 82b0b7480..45daec769 100644 --- a/MultimediaViewerHooks.php +++ b/MultimediaViewerHooks.php @@ -222,6 +222,9 @@ class MultimediaViewerHooks { 'dependencies' => array( 'mmv', 'mmv.bootstrap', + 'mmv.ui.reuse.share', + 'mmv.ui.reuse.embed', + 'mmv.ui.reuse.download', ), 'localBasePath' => __DIR__, 'remoteExtPath' => 'MultimediaViewer', diff --git a/resources/mmv/mmv.js b/resources/mmv/mmv.js index e003fcab6..cb5681522 100755 --- a/resources/mmv/mmv.js +++ b/resources/mmv/mmv.js @@ -310,6 +310,7 @@ } viewer.ui.panel.animateMetadataOnce(); + viewer.preloadDependencies(); } ); this.comingFromHashChange = false; @@ -706,9 +707,16 @@ /** * Unregisters all event handlers. Currently only used in tests. */ - MMVP.cleanupEventHandlers = function () { + MMVP.cleanupEventHandlers = function () { $( document ).off( 'mmv-close.mmvp mmv-next.mmvp mmv-prev.mmvp mmv-resize.mmvp' ); }; + /** + * Preloads JS and CSS dependencies that aren't needed to display the first image, but could be needed later + */ + MMVP.preloadDependencies = function () { + mw.loader.load( [ 'mmv.ui.reuse.share', 'mmv.ui.reuse.embed', 'mmv.ui.reuse.download' ] ); + }; + mw.mmv.MultimediaViewer = MultimediaViewer; }( mediaWiki, jQuery ) ); diff --git a/resources/mmv/ui/mmv.ui.reuse.dialog.js b/resources/mmv/ui/mmv.ui.reuse.dialog.js index 9d03bec8c..c52693993 100644 --- a/resources/mmv/ui/mmv.ui.reuse.dialog.js +++ b/resources/mmv/ui/mmv.ui.reuse.dialog.js @@ -34,13 +34,6 @@ this.$reuseDialog = $( '
' ) .addClass( 'mw-mmv-reuse-dialog' ); - this.reuseTabs = new oo.ui.MenuWidget( { - classes: [ 'mw-mmv-reuse-tabs' ] - } ); - // MenuWidget has a nasty tendency to hide itself, maybe we're not using it right? - this.reuseTabs.hide = $.noop; - this.reuseTabs.$element.show().appendTo( this.$reuseDialog ); - this.$downArrow = $( '
' ) .addClass( 'mw-mmv-reuse-down-arrow' ) .appendTo( this.$reuseDialog ); @@ -54,8 +47,6 @@ * @property {Object.} List of tab ui objects. */ this.tabs = null; - - this.initTabs(); } oo.inheritClass( Dialog, mw.mmv.ui.Element ); DP = Dialog.prototype; @@ -64,6 +55,14 @@ DP.initTabs = function () { var shareTab, embedTab, downloadTab; + this.reuseTabs = new oo.ui.MenuWidget( { + classes: [ 'mw-mmv-reuse-tabs' ] + } ); + + // MenuWidget has a nasty tendency to hide itself, maybe we're not using it right? + this.reuseTabs.hide = $.noop; + this.reuseTabs.$element.show().appendTo( this.$reuseDialog ); + this.tabs = { share: new mw.mmv.ui.reuse.Share( this.$reuseDialog ), download: new mw.mmv.ui.reuse.Download( this.$reuseDialog ), @@ -86,20 +85,52 @@ // Default to 'share' tab this.selectedTab = 'share'; this.reuseTabs.selectItem( shareTab ); + + if ( this.dependenciesNeedToBeAttached ) { + this.attachDependencies(); + } + + if ( this.tabsSetValues ) { + // This is a delayed set() for the elements we've just created on demand + this.tabs.share.set.apply( this.tabs.share, this.tabsSetValues.share ); + this.tabs.download.set.apply( this.tabs.download, this.tabsSetValues.download ); + this.tabs.embed.set.apply( this.tabs.embed, this.tabsSetValues.embed ); + this.tabsSetValues = undefined; + } }; /** * Handles click on link that opens/closes the dialog. */ - DP.handleOpenCloseClick = function() { + DP.handleOpenCloseClick = function () { + var dialog = this, + $deferred = $.Deferred(); + mw.mmv.logger.log( 'use-this-file-link-click' ); - if ( this.isOpen ) { - this.closeDialog(); + if ( this.tabs === null ) { + // initTabs() needs to have these dependencies loaded in order to run + mw.loader.using( [ 'mmv.ui.reuse.share', 'mmv.ui.reuse.embed', 'mmv.ui.reuse.download' ], function () { + dialog.initTabs(); + $deferred.resolve(); + }, function (error) { + $deferred.reject( error ); + if ( window.console && window.console.error ) { + window.console.error( 'mw.loader.using error when trying to load reuse dependencies', error ); + } + } ); } else { - this.openDialog(); + $deferred.resolve(); } + $deferred.then( function() { + if ( dialog.isOpen ) { + dialog.closeDialog(); + } else { + dialog.openDialog(); + } + } ); + return false; }; @@ -123,31 +154,52 @@ /** * Registers listeners. */ - DP.attach = function() { - var dialog = this, - tab; + DP.attach = function () { + var dialog = this; this.handleEvent( 'mmv-reuse-open', $.proxy( dialog.handleOpenCloseClick, dialog ) ); - this.reuseTabs.on( 'select', $.proxy( dialog.handleTabSelection, dialog ) ); - for ( tab in this.tabs ) { - this.tabs[tab].attach(); + this.attachDependencies(); + }; + + /** + * Registrers listeners for dependencies loaded on demand + */ + DP.attachDependencies = function () { + var tab, dialog = this; + + if ( this.reuseTabs && this.tabs ) { + // This is a delayed attach() for the elements we've just created on demand + this.reuseTabs.on( 'select', $.proxy( dialog.handleTabSelection, dialog ) ); + + for ( tab in this.tabs ) { + this.tabs[tab].attach(); + } + + this.dependenciesNeedToBeAttached = false; + } else { + this.dependenciesNeedToBeAttached = true; } }; /** * Clears listeners. */ - DP.unattach = function() { + DP.unattach = function () { var tab; this.constructor['super'].prototype.unattach.call( this ); this.stopListeningToOutsideClick(); - this.reuseTabs.off( 'select' ); - for ( tab in this.tabs ) { - this.tabs[tab].unattach(); + if ( this.reuseTabs ) { + this.reuseTabs.off( 'select' ); + } + + if ( this.tabs ) { + for ( tab in this.tabs ) { + this.tabs[tab].unattach(); + } } }; @@ -159,9 +211,17 @@ * @param {string} caption */ DP.set = function ( image, repo, caption) { - this.tabs.share.set( image ); - this.tabs.download.set( image ); - this.tabs.embed.set( image, repo, caption ); + if ( this.tabs !== null ) { + this.tabs.share.set( image ); + this.tabs.download.set( image ); + this.tabs.embed.set( image, repo, caption ); + } else { + this.tabsSetValues = { + share : [ image ], + download : [ image ], + embed : [ image, repo, caption ] + }; + } }; /** diff --git a/tests/qunit/mmv/ui/mmv.ui.reuse.dialog.test.js b/tests/qunit/mmv/ui/mmv.ui.reuse.dialog.test.js index 6bdb4e169..a9fab308e 100644 --- a/tests/qunit/mmv/ui/mmv.ui.reuse.dialog.test.js +++ b/tests/qunit/mmv/ui/mmv.ui.reuse.dialog.test.js @@ -23,12 +23,11 @@ QUnit.module( 'mmv.ui.reuse.Dialog', QUnit.newMwEnvironment() ); - QUnit.test( 'Sanity test, object creation and UI construction', 3, function ( assert ) { + QUnit.test( 'Sanity test, object creation and UI construction', 2, function ( assert ) { var reuseDialog = makeReuseDialog(); assert.ok( reuseDialog, 'Reuse UI element is created.' ); assert.strictEqual( reuseDialog.$reuseDialog.length, 1, 'Reuse dialog div created.' ); - assert.ok( reuseDialog.reuseTabs, 'Reuse tabs created.' ); } ); QUnit.test( 'handleOpenCloseClick():', 2, function ( assert ) { @@ -59,6 +58,8 @@ QUnit.test( 'handleTabSelection():', 4, function ( assert ) { var reuseDialog = makeReuseDialog(); + reuseDialog.initTabs(); + reuseDialog.tabs.share.show = function () { assert.ok( true, 'Share tab shown.' ); }; @@ -83,6 +84,8 @@ QUnit.test( 'attach()/unattach():', 2, function ( assert ) { var reuseDialog = makeReuseDialog(); + reuseDialog.initTabs(); + reuseDialog.handleOpenCloseClick = function() { assert.ok( false, 'handleOpenCloseClick should not have been called.' ); }; @@ -126,6 +129,8 @@ var reuseDialog = makeReuseDialog(), realCloseDialog = reuseDialog.closeDialog; + reuseDialog.initTabs(); + function clickOutsideDialog() { var event = new $.Event( 'click', { target: reuseDialog.$container[0] } ); reuseDialog.$container.trigger( event ); @@ -200,6 +205,8 @@ }, embedFileInfo = new mw.mmv.model.EmbedFileInfo( title, src, url ); + reuseDialog.initTabs(); + reuseDialog.set( image, embedFileInfo ); assert.ok( ! reuseDialog.isOpen, 'Dialog closed by default.' );