Bmansurov has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/327697 )

Change subject: WIP: Add reading depth
......................................................................

WIP: Add reading depth

Use schema revision 16159206.

Add the 'checkin' action, which is accompanied by
the 'pageVisibility' property. The action is logged
at the following seconds (Fibonacci numbers) after
the page loads: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,
144, 233, 377, 610, 987, 1597, 2584, 4181, 6765.

Bug: T147314
Change-Id: Ib9ec7bd0e60aa34a04e32222b025347f6ee31794
---
M extension.json
M resources/ext.popups/actions.js
M resources/ext.popups/boot.js
A resources/ext.popups/checkin.js
M resources/ext.popups/reducers.js
A tests/qunit/ext.popups/checkins.test.js
6 files changed, 188 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Popups 
refs/changes/97/327697/1

diff --git a/extension.json b/extension.json
index bf05854..71827c7 100644
--- a/extension.json
+++ b/extension.json
@@ -37,7 +37,7 @@
                ]
        },
        "EventLoggingSchemas": {
-               "Popups": 16112163
+               "Popups": 16163887
        },
        "config": {
                "@PopupsBetaFeature": "@var bool: Whether the extension should 
be enabled as an opt-in beta feature. If true, the BetaFeatures extension must 
be installed. False by default.",
@@ -76,6 +76,7 @@
                                
"resources/ext.popups/changeListeners/previewCount.js",
                                
"resources/ext.popups/changeListeners/settings.js",
                                "resources/ext.popups/settingsDialog.js",
+                               "resources/ext.popups/checkin.js",
                                "resources/ext.popups/boot.js"
                        ],
                        "templates": {
diff --git a/resources/ext.popups/actions.js b/resources/ext.popups/actions.js
index aa71472..298818c 100644
--- a/resources/ext.popups/actions.js
+++ b/resources/ext.popups/actions.js
@@ -3,6 +3,7 @@
        var actions = {},
                types = {
                        BOOT: 'BOOT',
+                       CHECKIN: 'CHECKIN',
                        LINK_DWELL: 'LINK_DWELL',
                        LINK_ABANDON_START: 'LINK_ABANDON_START',
                        LINK_ABANDON_END: 'LINK_ABANDON_END',
@@ -87,6 +88,13 @@
                };
        };
 
+       actions.checkin = function ( time ) {
+               return {
+                       type: types.CHECKIN,
+                       time: time
+               };
+       };
+
        /**
         * Represents Page Previews fetching data via the 
[gateway](./gateway.js).
         *
diff --git a/resources/ext.popups/boot.js b/resources/ext.popups/boot.js
index 5c8ae30..b3f499e 100644
--- a/resources/ext.popups/boot.js
+++ b/resources/ext.popups/boot.js
@@ -74,6 +74,7 @@
         * 2. Binding the actions to such store
         * 3. Trigger the boot action to bootstrap the system
         * 4. When the page content is ready:
+        *   - Setup `checkin` actions
         *   - Process the eligible links for page previews
         *   - Initialize the renderer
         *   - Bind hover and click events to the eligible links to trigger 
actions
@@ -126,6 +127,8 @@
                                        mw.config
                                );
 
+                       mw.popups.checkin.setupActions( actions.checkin );
+
                        mw.popups.renderer.init();
 
                        previewLinks
diff --git a/resources/ext.popups/checkin.js b/resources/ext.popups/checkin.js
new file mode 100644
index 0000000..f511301
--- /dev/null
+++ b/resources/ext.popups/checkin.js
@@ -0,0 +1,115 @@
+( function ( mw, $ ) {
+       var CHECKIN_TIMES = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,
+                       377, 610, 987, 1597, 2584, 4181, 6765],  // Fibonacci 
numbers
+               // Have checkin actions been setup already?
+               haveCheckinActionsBeenSetup = false;
+
+
+       /**
+        * Return the browser specific property and event names
+        *
+        * Unless returned `undefined`, the returned values are the
+        * `document.hidden` property and `visibilitychange` event names in
+        * this order.
+        *
+        * @see https://www.w3.org/TR/page-visibility/#dom-document-hidden
+        * @return {string[]|undefined}
+        */
+       function getBrowserSpecificPropertyAndEventNames () {
+               if ( document.hidden !== undefined ) {
+                       return ['hidden', 'visibilitychange'];
+               } else if ( document.mozHidden !== undefined ) {
+                       return ['mozHidden', 'mozvisibilitychange'];
+               } else if ( document.msHidden !== undefined ) {
+                       return ['msHidden', 'msvisibilitychange'];
+               } else if ( document.webkitHidden !== undefined ) {
+                       return ['webkitHidden', 'webkitvisibilitychange'];
+               }
+       }
+
+       function setVisibleTimeout ( callback, delay ) {
+               var propertyAndEvent = 
getBrowserSpecificPropertyAndEventNames(),
+                       hiddenPropertyName,
+                       visibilityChangeEventName,
+                       timeoutId,
+                       lastStartedAt;
+
+               if ( !propertyAndEvent ) {
+                       return;
+               }
+
+               hiddenPropertyName = propertyAndEvent[0];
+               visibilityChangeEventName = propertyAndEvent[1];
+
+               /**
+                * `delay` milliseconds have passed
+                */
+               function done () {
+                       callback();
+                       $( document ).off( visibilityChangeEventName, 
visibilityChangeHandler );
+               }
+               /**
+                * Pause or resume the timer depending on the page visibility 
state
+                */
+               function visibilityChangeHandler() {
+                       var millisecondsPassed;
+
+                       // Pause the timer if the page is hidden.
+                       if ( document[ hiddenPropertyName ] ) {
+                               // only if the timer has started
+                               if ( lastStartedAt ) {
+                                       millisecondsPassed = new 
Date().getTime() - lastStartedAt;
+                                       delay = Math.max( 0, delay - 
millisecondsPassed );
+                                       clearTimeout( timeoutId );
+                               }
+                       } else {
+                               lastStartedAt = new Date().getTime();
+                               // otherwise, resume
+                               timeoutId = setTimeout( done, delay );
+                       }
+               }
+
+               visibilityChangeHandler();
+
+               $( document ).on( visibilityChangeEventName, 
visibilityChangeHandler );
+       }
+
+       /**
+        * Perform an the passed `checkin` action at the predefined times
+        *
+        * Actions are setup only once no matter how many times this function is
+        * called.
+        *
+        * @see CHECKIN_TIMES
+        * @param checkinAction
+        */
+       function setupActions( checkinAction ) {
+               var timeIndex = 0,
+                       timesLength = CHECKIN_TIMES.length,
+                       time;
+
+               if ( haveCheckinActionsBeenSetup ) return;
+
+               function setup () {
+                       time = CHECKIN_TIMES[timeIndex];
+                       checkinAction( time );
+
+                       timeIndex += 1;
+                       if ( timeIndex < timesLength ) {
+                               setVisibleTimeout( setup, ( CHECKIN_TIMES[ 
timeIndex ] - time ) * 1000 );
+                       }
+               }
+
+               setVisibleTimeout( setup, CHECKIN_TIMES[ timeIndex ] * 1000 );
+
+               haveCheckinActionsBeenSetup = true;
+       }
+
+       mw.popups.checkin = {
+               CHECKIN_TIMES: CHECKIN_TIMES,
+               getBrowserSpecificPropertyAndEventNames: 
getBrowserSpecificPropertyAndEventNames,
+               setVisibleTimeout: setVisibleTimeout,
+               setupActions: setupActions
+       };
+
+}( mediaWiki, jQuery ) );
diff --git a/resources/ext.popups/reducers.js b/resources/ext.popups/reducers.js
index 6f1bf39..f09d1bd 100644
--- a/resources/ext.popups/reducers.js
+++ b/resources/ext.popups/reducers.js
@@ -176,6 +176,15 @@
                                        }
                                } );
 
+                       case mw.popups.actionTypes.CHECKIN:
+                               return nextState( state, {
+                                       event: {
+                                               action: 'checkin',
+                                               checkin: action.time,
+                                               pageVisibility: 
action.pageVisibility
+                                       }
+                               } );
+
                        case mw.popups.actionTypes.EVENT_LOGGED:
                                return nextState( state, {
                                        event: undefined
diff --git a/tests/qunit/ext.popups/checkins.test.js 
b/tests/qunit/ext.popups/checkins.test.js
new file mode 100644
index 0000000..d5f7c56
--- /dev/null
+++ b/tests/qunit/ext.popups/checkins.test.js
@@ -0,0 +1,51 @@
+( function ( mw, $ ) {
+       QUnit.module( 'ext.popups/checkin', {
+               setup: function () {
+                       this.CHECKIN_TIMES = [1, 2, 3, 5, 8, 13, 21, 34, 55, 
89, 144, 233,
+                               377, 610, 987, 1597, 2584, 4181, 6765];
+               }
+       } );
+
+       QUnit.test( 'checkin times are correct', function ( assert ) {
+               assert.expect( 1 );
+               assert.deepEqual( mw.popups.checkin.CHECKIN_TIMES, 
this.CHECKIN_TIMES );
+       } );
+
+       QUnit.test( 'document visibility state is correctly identified', 
function ( assert ) {
+               assert.expect( 5 );
+
+               var self = this,
+                       cases = [
+                               ['visible', 'visible'],
+                               ['hidden', 'hidden'],
+                               ['prerender', 'hidden'],
+                               ['unloaded', 'unknown'],
+                               [undefined, 'unknown']
+                       ],
+                       checkin = mw.popups.checkin;
+
+               $.each( cases, function ( i, testCase ) {
+                       assert.equal( checkin.getPageVisibilityState( 
testCase[0] ), testCase[1] );
+               } );
+       } );
+
+       QUnit.test( 'checkin actions are setup correctly', function ( assert ) {
+               assert.expect( 1 + this.CHECKIN_TIMES.length );
+
+               var timeoutSpy = this.sandbox.spy( window, 'setTimeout' ),
+                       checkinStub = this.sandbox.stub();
+
+               mw.popups.checkin.setupActions( checkinStub );
+
+               assert.equal( timeoutSpy.callCount, this.CHECKIN_TIMES.length );
+
+               $.each( this.CHECKIN_TIMES, function ( i, checkinTime ) {
+                       assert.ok( timeoutSpy.calledWith(
+                               checkinStub,
+                               checkinTime * 1000,
+                               checkinTime,
+                               mw.popups.checkin.getPageVisibilityState( 
document.visibilityState )
+                       ) );
+               } );
+       } );
+}( mediaWiki, jQuery ) );

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib9ec7bd0e60aa34a04e32222b025347f6ee31794
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Popups
Gerrit-Branch: master
Gerrit-Owner: Bmansurov <[email protected]>

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

Reply via email to