jenkins-bot has submitted this change and it was merged.

Change subject: EventEmitter tweaks
......................................................................


EventEmitter tweaks

* Prevent accidental object's function calling when emitting events.
* Add #one for callbacks that should be fired only once.
* Don't use $.extend( obj.prototype, EventEmitter.prorotype ), can be
  bug prone (name clashes).

Change-Id: I11de9760fa7e6fe5a0ef57204321689e6fcc6a0b
---
M javascripts/common/eventemitter.js
M javascripts/common/mf-api.js
M javascripts/modules/mf-photo.js
M tests/javascripts/common/test_eventemitter.js
4 files changed, 55 insertions(+), 24 deletions(-)

Approvals:
  Jdlrobson: Verified; Looks good to me, approved
  jenkins-bot: Verified



diff --git a/javascripts/common/eventemitter.js 
b/javascripts/common/eventemitter.js
index 783e580..33226b6 100644
--- a/javascripts/common/eventemitter.js
+++ b/javascripts/common/eventemitter.js
@@ -1,5 +1,12 @@
 ( function( M, $ ) {
 
+       function callbackProxy( callback ) {
+               return function() {
+                       var args = Array.prototype.slice.call( arguments, 1 );
+                       callback.apply( callback, args );
+               };
+       }
+
        function EventEmitter() {}
 
        /**
@@ -9,10 +16,18 @@
         * @param {Function} callback Callback to be bound.
         */
        EventEmitter.prototype.on = function( event, callback ) {
-               $( this ).on( event, function() {
-                       var args = Array.prototype.slice.call( arguments, 1 );
-                       callback.apply( callback, args );
-               } );
+               $( this ).on( event, callbackProxy( callback ) );
+               return this;
+       };
+
+       /**
+        * Bind a callback to the event and run it only once.
+        *
+        * @param {string} event Event name.
+        * @param {Function} callback Callback to be bound.
+        */
+       EventEmitter.prototype.one = function( event, callback ) {
+               $( this ).one( event, callbackProxy( callback ) );
                return this;
        };
 
@@ -24,7 +39,10 @@
         */
        EventEmitter.prototype.emit = function( event /* , arg1, arg2, ... */ ) 
{
                var args = Array.prototype.slice.call( arguments, 1 );
-               $( this ).trigger( event, args );
+               // use .triggerHandler() for emitting events to avoid 
accidentally
+               // invoking object's functions, e.g. don't call obj.something() 
when
+               // doing obj.emit( 'something' )
+               $( this ).triggerHandler( event, args );
                return this;
        };
 
diff --git a/javascripts/common/mf-api.js b/javascripts/common/mf-api.js
index d6958fc..4e772e1 100644
--- a/javascripts/common/mf-api.js
+++ b/javascripts/common/mf-api.js
@@ -20,6 +20,8 @@
                this.initialize( options );
        }
 
+       Api.prototype = new EventEmitter();
+
        // FIXME: make Api and View inherit from an abstract Class object
        /**
         * Constructor that can be overriden.
@@ -74,7 +76,9 @@
                                // need to bind this event before we open the 
connection (see note at
                                // 
https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress)
                                xhr.upload.addEventListener( 'progress', 
function( ev ) {
-                                       request.emit( 'progress', ev );
+                                       if ( ev.lengthComputable ) {
+                                               self.emit( 'progress', request, 
ev.loaded / ev.total );
+                                       }
                                } );
                        }
                        return xhr;
@@ -82,7 +86,6 @@
                */
 
                request = $.ajax( options );
-               $.extend( request, EventEmitter.prototype );
                this.requests.push( request );
                return request;
        };
diff --git a/javascripts/modules/mf-photo.js b/javascripts/modules/mf-photo.js
index 09c81e7..c52c07f 100644
--- a/javascripts/modules/mf-photo.js
+++ b/javascripts/modules/mf-photo.js
@@ -5,7 +5,6 @@
                CtaDrawer = M.require( 'CtaDrawer' ),
                funnel = $.cookie( 'mwUploadsFunnel' ) || 'article',
                showCta = mw.config.get( 'wgMFEnablePhotoUploadCTA' ) || funnel 
=== 'nearby',
-               EventEmitter = M.require( 'eventemitter' ),
                ProgressBar = M.require( 'widgets/progress-bar' ),
                Overlay = M.require( 'Overlay' ),
                ownershipMessage = mw.msg( 'mobile-frontend-photo-ownership', 
mw.config.get( 'wgUserName' ), mw.user ),
@@ -179,7 +178,8 @@
 
                        function doUpload( token ) {
                                var formData = new FormData(),
-                                       ext = options.file.name.slice( 
options.file.name.lastIndexOf( '.' ) + 1 );
+                                       ext = options.file.name.slice( 
options.file.name.lastIndexOf( '.' ) + 1 ),
+                                       request;
 
                                options.fileName = generateFileName( 
options.description, '.' + ext );
 
@@ -201,7 +201,7 @@
                                        } )
                                );
 
-                               self.post( formData, {
+                               request = self.post( formData, {
                                        // iOS seems to ignore the cache 
parameter so sending r parameter
                                        // send useformat=mobile for sites 
where endpoint is a desktop url so that they are mobile edit tagged
                                        url: apiUrl + '?useformat=mobile&r=' + 
Math.random(),
@@ -209,10 +209,6 @@
                                        cache: false,
                                        contentType: false,
                                        processData: false
-                               } ).on( 'progress', function( ev ) {
-                                       if ( ev.lengthComputable ) {
-                                               self.emit( 'progress', 
ev.loaded / ev.total );
-                                       }
                                } ).done( function( data ) {
                                        var descriptionUrl = '',
                                                warnings = data.upload ? 
data.upload.warnings : false;
@@ -253,7 +249,14 @@
                                                result.reject( status + ': ' + 
error );
                                        }
                                } );
+
+                               self.on( 'progress', function( req, progress ) {
+                                       if ( req === request ) {
+                                               self.emit( 'uploadProgress', 
progress );
+                                       }
+                               } );
                        }
+
                        self.getToken( 'edit', endpoint ).done( function( token 
) {
                                doUpload( token );
                        } ).fail( function( err ) {
@@ -263,8 +266,6 @@
                        return result;
                }
        } );
-
-       $.extend( PhotoApi.prototype, EventEmitter.prototype );
 
        LearnMoreOverlay = Overlay.extend( {
                defaults: {
@@ -666,7 +667,7 @@
                                self.emit( 'error' );
                        } );
 
-                       api.on( 'progress', function( value ) {
+                       api.on( 'uploadProgress', function( value ) {
                                progressPopup.setValue( value );
                        } );
                }
diff --git a/tests/javascripts/common/test_eventemitter.js 
b/tests/javascripts/common/test_eventemitter.js
index 1193daf..a59bc61 100644
--- a/tests/javascripts/common/test_eventemitter.js
+++ b/tests/javascripts/common/test_eventemitter.js
@@ -1,14 +1,23 @@
 ( function( M ) {
 
-  var EventEmitter = M.require( 'eventemitter' );
+       var EventEmitter = M.require( 'eventemitter' );
 
        QUnit.module( 'MobileFrontend EventEmitter' );
 
-       QUnit.test( '#on', 1, function() {
-    var e = new EventEmitter(), spy = sinon.spy();
-    e.on( 'testEvent', spy );
-    e.emit( 'testEvent', 'first', 2 );
-    ok( spy.calledWith( 'first', 2 ), 'run callback when event runs' );
-  } );
+       QUnit.test( '#on', 1, function( assert ) {
+               var e = new EventEmitter(), spy = sinon.spy();
+               e.on( 'testEvent', spy );
+               e.emit( 'testEvent', 'first', 2 );
+               assert.ok( spy.calledWith( 'first', 2 ), 'run callback when 
event runs' );
+       } );
+
+       QUnit.test( '#one', 2, function( assert ) {
+               var e = new EventEmitter(), spy = sinon.spy();
+               e.one( 'testEvent', spy );
+               e.emit( 'testEvent', 'first', 2 );
+               e.emit( 'testEvent', 'second', 2 );
+               assert.ok( spy.calledWith( 'first', 2 ), 'run callback when 
event runs' );
+               assert.ok( spy.calledOnce, 'run callback once' );
+       } );
 
 }( mw.mobileFrontend) );

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I11de9760fa7e6fe5a0ef57204321689e6fcc6a0b
Gerrit-PatchSet: 5
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: JGonera <[email protected]>
Gerrit-Reviewer: Jdlrobson <[email protected]>
Gerrit-Reviewer: jenkins-bot

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

Reply via email to