Phuedx has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/207762

Change subject: Hygiene: Generalise the futureLog mechanism
......................................................................

Hygiene: Generalise the futureLog mechanism

Add the Schema#logBeacon method, which logs the event on the next page
load. Events logged with the #logBeacon event are referred to as
"beacons" throughout.

Also, fix documentation of optional parameters in settings#get and

Bug: T96326
Change-Id: I312adb5ca9665c388d5c1766252f326789cd0d3f
---
M includes/Resources.php
M javascripts/settings.js
M resources/mobile.startup/Schema.js
A resources/mobile.startup/beacons.js
M resources/mobile.startup/init.js
M tests/qunit/mobile.startup/test_Schema.js
A tests/qunit/mobile.startup/test_beacons.js
7 files changed, 188 insertions(+), 13 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend 
refs/changes/62/207762/1

diff --git a/includes/Resources.php b/includes/Resources.php
index 61a301f..99782af 100644
--- a/includes/Resources.php
+++ b/includes/Resources.php
@@ -359,6 +359,7 @@
                        'resources/mobile.startup/Thumbnail.js',
                        'resources/mobile.startup/Page.js',
                        'resources/mobile.startup/Skin.js',
+                       'resources/mobile.startup/beacons.js',
                        'resources/mobile.startup/Schema.js',
                        'resources/mobile.startup/util.js',
                        'resources/mobile.startup/init.js',
diff --git a/javascripts/settings.js b/javascripts/settings.js
index fb7f548..f5f5438 100644
--- a/javascripts/settings.js
+++ b/javascripts/settings.js
@@ -32,7 +32,7 @@
                         * @method
                         * @param {String} name The key to refer to this value
                         * @param {String} value The value to store alongside 
the key
-                        * @param {Boolean} useCookieFallback Optional: When 
set this will use
+                        * @param {Boolean} [useCookieFallback] When set this 
will use
                         * cookies when local storage not available.
                         * @returns {Boolean} Whether the save was successful 
or not
                         */
@@ -49,7 +49,7 @@
                         * Retrieves a user setting from a previous browser 
setting
                         * @method
                         * @param {String} name The key to refer to this value
-                        * @param {Boolean} useCookieFallback Optional: When 
set this will use cookies
+                        * @param {Boolean} [useCookieFallback] When set this 
will use cookies
                         * when local storage not available.
                         * @returns {String|Boolean} Returns the associated 
value or False if nothing
                         * is found
diff --git a/resources/mobile.startup/Schema.js 
b/resources/mobile.startup/Schema.js
index f471e70..b2976cb 100644
--- a/resources/mobile.startup/Schema.js
+++ b/resources/mobile.startup/Schema.js
@@ -1,7 +1,8 @@
 ( function ( M, $ ) {
        var Schema,
                Class = M.require( 'Class' ),
-               user = M.require( 'user' );
+               user = M.require( 'user' ),
+               beacons = M.require( 'beacons' );
 
        /**
         * @class Schema
@@ -59,6 +60,17 @@
                        } else {
                                return $.Deferred().reject( 'EventLogging not 
installed.' );
                        }
+               },
+
+               /**
+                * Try to log an event after the next page load.
+                *
+                * @method
+                *
+                * @param {Object} data to log
+                */
+               logBeacon: function ( data ) {
+                       beacons.add( this.name, data );
                }
        } );
 
diff --git a/resources/mobile.startup/beacons.js 
b/resources/mobile.startup/beacons.js
new file mode 100644
index 0000000..160f68b
--- /dev/null
+++ b/resources/mobile.startup/beacons.js
@@ -0,0 +1,92 @@
+( function ( M ) {
+
+       var settings = M.require( 'settings' );
+
+       /**
+        * Loads the beacons from local storage.
+        *
+        * @returns {Array}
+        */
+       function load() {
+               return JSON.parse( settings.get( 'mobileFrontend/beacons' ) ) 
|| [];
+       }
+
+       /**
+        * Saves the beacons to local storage.
+        *
+        * @param {Object[]} beacons
+        */
+       function save( beacons ) {
+               settings.save( 'mobileFrontend/beacons', JSON.stringify( 
beacons ) );
+       }
+
+       // FIXME: [EL] This could be made more general if we decide to move the
+       // schema class to their respective modules.
+       /**
+        * Creates an instance of a schema in the `loggingSchemas` group, e.g.
+        * `factorySchema( 'MobileWebSearch' )` would return an instance of the
+        * `SchemaMobileWebSearch` class.
+        *
+        * @param {String} name
+        * @returns {Schema}
+        * @throws Error If the schema isn't defined
+        */
+       function factorySchema( name ) {
+               var klass = M.require( 'loggingSchemas/Schema' + name );
+
+               return new klass;
+       }
+
+       /**
+        * @singleton
+        */
+       M.define( 'beacons', {
+
+               /**
+                * Adds a beacon to be logged.
+                *
+                * @method
+                *
+                * @param {Object} event
+                */
+               add: function ( schema, data ) {
+                       var beacons = load();
+
+                       beacons.push( {
+                               schema: schema,
+                               data: data
+                       } );
+
+                       save( beacons );
+               },
+
+               /**
+                * Deletes all beacons without logging them.
+                *
+                * @method
+                */
+               clear: function () {
+                       save( [] );
+               },
+
+               /**
+                * Logs all beacons in parallel.
+                *
+                * Once all of the logging requests have been started, then the 
beacons are deleted, and if
+                * a beacon fails, then it isn't retried.
+                *
+                * @method
+                */
+               flush: function () {
+                       var beacons = load(),
+                               beacon;
+
+                       while ( beacon = beacons.shift() ) {
+                               factorySchema( beacon.schema ).log( beacon.data 
)
+                       }
+
+                       this.clear();
+               }
+       } );
+
+} ( mw.mobileFrontend ) );
\ No newline at end of file
diff --git a/resources/mobile.startup/init.js b/resources/mobile.startup/init.js
index 2f65dbb..3daee2b 100644
--- a/resources/mobile.startup/init.js
+++ b/resources/mobile.startup/init.js
@@ -5,7 +5,7 @@
  * @class mw.mobileFrontend
  * @singleton
  */
-( function ( M, $ ) {
+( function ( M, $, mw ) {
        var currentPage, skin,
                $cachedIcons = $( '#page-actions' ).find( '.icon' ),
                PageApi = M.require( 'PageApi' ),
@@ -86,4 +86,9 @@
                $cachedIcons.addClass( 'mw-ui-icon mw-ui-icon-element' 
).removeClass( 'icon' );
                $cachedIcons.filter( '.icon-text' ).addClass( 
'mw-ui-icon-before' ).removeClass( 'icon-text mw-ui-icon-element' );
        }
-}( mw.mobileFrontend, jQuery ) );
+
+       mw.loader.using( 'mobile.loggingSchemas' ).done( function () {
+               M.require( 'beacons' ).flush();
+       } );
+
+}( mw.mobileFrontend, jQuery, mw ) );
diff --git a/tests/qunit/mobile.startup/test_Schema.js 
b/tests/qunit/mobile.startup/test_Schema.js
index 65dbf7b..dfaf0fb 100644
--- a/tests/qunit/mobile.startup/test_Schema.js
+++ b/tests/qunit/mobile.startup/test_Schema.js
@@ -1,10 +1,18 @@
 ( function ( $, M ) {
-       var Schema = M.require( 'Schema' );
+       var Schema = M.require( 'Schema' ),
+               beacons = M.require( 'beacons' );
 
-       QUnit.module( 'Schema' );
+       QUnit.module( 'Schema', {
+               setup: function () {
+                       this.TestSchema = Schema.extend( {
+                               name: 'test'
+                       } );
+                       this.stub( beacons, 'add' ).returns( null );
+               }
+       } );
 
        QUnit.test( '#initialize', 3, function ( assert ) {
-               var s1, s2, s3, SubSchema;
+               var s1, s2, s3;
                // Creating a schema without name throws
                try {
                        s1 = new Schema();
@@ -15,11 +23,19 @@
                s2 = new Schema( {}, 'aname' );
                assert.strictEqual( s2.name, 'aname', 'explicit name gets set' 
);
 
-               SubSchema = Schema.extend( {
-                       name: 'subname'
-               } );
-               s3 = new SubSchema( {} );
-               assert.strictEqual( s3.name, 'subname', 'subclassed name works' 
);
+               s3 = new this.TestSchema( {} );
+               assert.strictEqual( s3.name, 'test', 'subclassed name works' );
+       } );
+
+       QUnit.test( '#logBeacon', 1, function ( assert ) {
+               var test = new this.TestSchema(),
+                       data = {
+                               foo: 'bar'
+                       };
+
+               test.logBeacon( data );
+
+               assert.deepEqual( [ 'test', data ], beacons.add.firstCall.args, 
'#logBeacon calls beacons.add' );
        } );
 
 }( jQuery, mw.mobileFrontend ) );
diff --git a/tests/qunit/mobile.startup/test_beacons.js 
b/tests/qunit/mobile.startup/test_beacons.js
new file mode 100644
index 0000000..e7f81d0
--- /dev/null
+++ b/tests/qunit/mobile.startup/test_beacons.js
@@ -0,0 +1,49 @@
+( function ( M ) {
+
+       var Schema = M.require( 'Schema' ),
+               TestSchema = Schema.extend( {
+                       name: 'test'
+               } ),
+               beacons = M.require( 'beacons' );
+
+       // Because these can't be undefined, we have to do this in the module 
preamble (not setup and
+       // teardown).
+       M.define( 'loggingSchemas/SchemaTest', TestSchema );
+       M.define( 'loggingSchemas/SchemaTest2', TestSchema );
+
+       QUnit.module( 'MobileFrontend: beacons', {
+               setup: function () {
+                       this.stub( TestSchema.prototype, 'log' );
+                       this.logStub = TestSchema.prototype.log;
+               }
+       } );
+
+       QUnit.test( '#flush should log the beacon', 1, function ( assert ) {
+               var data = {
+                       foo: 'bar'
+               };
+
+               beacons.add( 'Test', data );
+               beacons.flush();
+
+               assert.deepEqual( [ data ], this.logStub.firstCall.args );
+       } );
+
+       QUnit.test( '#flush should log all the beacons that have been added', 
1, function ( assert ) {
+               beacons.add( 'Test', {} );
+               beacons.add( 'Test2', {} );
+               beacons.flush();
+
+               assert.strictEqual( 2, this.logStub.callCount );
+       } );
+
+       QUnit.test( '#clear shouldn\'t log the beacons that have been added', 
1, function ( assert ) {
+               beacons.add( 'Test', {} );
+               beacons.add( 'Test2', {} );
+               beacons.clear();
+               beacons.flush();
+
+               assert.strictEqual( 0, this.logStub.callCount );
+       } );
+
+} ( mw.mobileFrontend ) );

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I312adb5ca9665c388d5c1766252f326789cd0d3f
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Phuedx <g...@samsmith.io>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to