Gilles has uploaded a new change for review. https://gerrit.wikimedia.org/r/173640
Change subject: Track how long users are viewing images for ...................................................................... Track how long users are viewing images for This is complete, but it would be better if the HEAD request was actually aborted by Varnish when the viewDuration parameter is present, or if the hit pointed to a script that does that. Change-Id: I66cafd97427756411e967de1901324af2215e3ae Mingle: https://wikimedia.mingle.thoughtworks.com/projects/multimedia/cards/1001 --- M MultimediaViewer.php M MultimediaViewerHooks.php A resources/mmv/logging/mmv.logging.View.js M resources/mmv/mmv.js 4 files changed, 173 insertions(+), 26 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MultimediaViewer refs/changes/40/173640/1 diff --git a/MultimediaViewer.php b/MultimediaViewer.php index a9abc28..a7a0d9c 100644 --- a/MultimediaViewer.php +++ b/MultimediaViewer.php @@ -109,6 +109,14 @@ $wgMediaViewerEnableByDefaultForAnonymous = $wgMediaViewerEnableByDefault; } +if ( !isset( $wgMediaViewerRecordViewDuration ) ) { + /** + * If set, record the view duration via a HEAD request. + * @var bool + */ + $wgMediaViewerRecordViewDuration = false; +} + $wgMessagesDirs['MultimediaViewer'] = __DIR__ . '/i18n'; $wgExtensionMessagesFiles['MultimediaViewer'] = __DIR__ . '/MultimediaViewer.i18n.php'; @@ -889,6 +897,7 @@ 'mmv.routing', 'mmv.logging.DurationLogger', 'mmv.logging.DimensionLogger', + 'mmv.logging.View', 'jquery.fullscreen', 'jquery.hidpi', 'jquery.scrollTo', @@ -994,6 +1003,17 @@ ), ), + 'mmv.logging.View' => $wgMediaViewerResourceTemplate + array( + 'scripts' => array( + 'mmv/logging/mmv.logging.View.js', + ), + + 'dependencies' => array( + 'mmv.base', + 'mmv.logging.ActionLogger', + ), + ), + 'mmv.head' => $wgMediaViewerResourceTemplate + array( 'scripts' => array( 'mmv/mmv.head.js', diff --git a/MultimediaViewerHooks.php b/MultimediaViewerHooks.php index bf6d36f..a8d9c43 100644 --- a/MultimediaViewerHooks.php +++ b/MultimediaViewerHooks.php @@ -142,7 +142,7 @@ global $wgMediaViewerActionLoggingSamplingFactorMap, $wgNetworkPerformanceSamplingFactor, $wgMediaViewerDurationLoggingSamplingFactor, $wgMediaViewerDurationLoggingLoggedinSamplingFactor, $wgMediaViewerAttributionLoggingSamplingFactor, $wgMediaViewerDimensionLoggingSamplingFactor, - $wgMediaViewerIsInBeta, $wgMediaViewerUseThumbnailGuessing; + $wgMediaViewerIsInBeta, $wgMediaViewerUseThumbnailGuessing, $wgMediaViewerRecordViewDuration; $vars['wgMultimediaViewer'] = array( 'infoLink' => self::$infoLink, 'discussionLink' => self::$discussionLink, @@ -154,6 +154,7 @@ 'actionLoggingSamplingFactorMap' => $wgMediaViewerActionLoggingSamplingFactorMap, 'attributionSamplingFactor' => $wgMediaViewerAttributionLoggingSamplingFactor, 'dimensionSamplingFactor' => $wgMediaViewerDimensionLoggingSamplingFactor, + 'recordViewDuration' => $wgMediaViewerRecordViewDuration, 'tooltipDelay' => 1000, ); $vars['wgMediaViewer'] = true; diff --git a/resources/mmv/logging/mmv.logging.View.js b/resources/mmv/logging/mmv.logging.View.js new file mode 100644 index 0000000..d38ed94 --- /dev/null +++ b/resources/mmv/logging/mmv.logging.View.js @@ -0,0 +1,143 @@ +/* + * This file is part of the MediaWiki extension MultimediaViewer. + * + * MultimediaViewer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * MultimediaViewer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MultimediaViewer. If not, see <http://www.gnu.org/licenses/>. + */ + +( function ( mw, $ ) { + var V; + + /** + * Tracks how long users are viewing images for + * @class mw.mmv.logging.View + * @extends mw.Api + * @constructor + */ + function View( mwConfig ) { + /** + * Was the last image view logged or was logging skipped? + * @property {boolean} + */ + this.wasLastViewLogged = false; + + /** + * Record when the user started looking at the current image + * @property {number} + */ + this.viewStartTime = 0; + + /** + * How long the user has been looking at the current image + * @property {number} + */ + this.viewDuration = 0; + + /** + * The image URL to hit with a HEAD request + * @property {string} + */ + this.url = ''; + + /** + * Should the view duration be recorded through a HEAD request + * @property {boolean} + */ + this.shouldRecordViewDuration = mwConfig.get( 'wgMultimediaViewer' ).recordViewDuration; + } + + V = View.prototype; + + /** + * Tracks the unview event of the current image if appropriate + */ + V.unview = function () { + if ( !this.wasLastViewLogged ) { + return; + } + + this.wasLastViewLogged = false; + mw.mmv.actionLogger.log( 'image-unview', true ); + }; + + /** + * Starts recording a viewing window for the current image + */ + V.startViewDuration = function () { + this.viewStartTime = $.now(); + }; + + /** + * Stops recording the viewing window for the current image + */ + V.stopViewDuration = function () { + if ( this.viewStartTime ) { + this.viewDuration += $.now() - this.viewStartTime; + this.viewStartTime = 0; + } + }; + + /** + * Records the amount of time the current image has been viewed + */ + V.recordViewDuration = function () { + this.stopViewDuration(); + + if ( this.shouldRecordViewDuration && this.viewDuration > 0 ) { + $.ajax( { + type: 'HEAD', + async: true, + url: this.url + '?viewDuration=' + this.viewDuration + } ); + + mw.log( 'Image has been viewed for ', this.viewDuration ); + } + + this.viewDuration = 0; + + this.unview(); + }; + + /** + * Sets up the view tracking for the current image + * @param {string} url URL of the image to send a HEAD request to + */ + V.setupViewTracking = function ( url ) { + var view = this; + + this.url = url; + this.startViewDuration(); + + $( window ) + .off( '.view' ) + .on( 'beforeunload.view', function() { + view.recordViewDuration(); + } ) + .on( 'focus.view', function() { + view.startViewDuration(); + } ) + .on( 'blur.view', function() { + view.stopViewDuration(); + } ); + }; + + /** + * Tracks whether or not the image view event was logged or not (i.e. was it in the logging sample) + * @param {boolean} wasEventLogged Whether the image view event was logged + */ + V.setLastViewLogged = function ( wasEventLogged ) { + this.wasLastViewLogged = wasEventLogged; + }; + + mw.mmv.logging.View = View; +}( mediaWiki, jQuery ) ); diff --git a/resources/mmv/mmv.js b/resources/mmv/mmv.js index 4125619..67e67b3 100644 --- a/resources/mmv/mmv.js +++ b/resources/mmv/mmv.js @@ -106,10 +106,9 @@ this.documentTitle = document.title; /** - * Was the last image view logged or was logging skipped? - * @property {boolean} + * @property {mw.mmv.logging.View} view - */ - this.wasLastViewLogged = false; + this.view = new mw.mmv.logging.View( mw.config ); } MMVP = MultimediaViewer.prototype; @@ -405,14 +404,10 @@ this.ui.canvas.unblur(); } - mw.mmv.actionLogger.log( 'image-view' ).then( function ( wasEventLogged ) { - viewer.wasLastViewLogged = wasEventLogged; + this.view.setupViewTracking( thumbnail.url ); - if ( viewer.wasLastViewLogged ) { - $( window ).on( 'beforeunload.unview', function() { viewer.unview(); } ); - } else { - $( window ).off( 'beforeunload.unview' ); - } + mw.mmv.actionLogger.log( 'image-view' ).then( function ( wasEventLogged ) { + viewer.view.setLastViewLogged( wasEventLogged ); } ); }; @@ -787,7 +782,7 @@ * Opens the next image */ MMVP.nextImage = function () { - this.unview(); + this.view.recordViewDuration(); mw.mmv.actionLogger.log( 'next-image' ); this.loadIndex( this.currentIndex + 1 ); }; @@ -796,7 +791,7 @@ * Opens the previous image */ MMVP.prevImage = function () { - this.unview(); + this.view.recordViewDuration(); mw.mmv.actionLogger.log( 'prev-image' ); this.loadIndex( this.currentIndex - 1 ); }; @@ -807,7 +802,7 @@ MMVP.close = function () { var windowTitle; - this.unview(); + this.view.recordViewDuration(); windowTitle = this.createDocumentTitle( null ); @@ -930,18 +925,6 @@ */ MMVP.preloadDependencies = function () { mw.loader.load( [ 'mmv.ui.reuse.share', 'mmv.ui.reuse.embed', 'mmv.ui.reuse.download', 'moment' ] ); - }; - - /** - * Tracks the unview event of the current image if appropriate - */ - MMVP.unview = function () { - if ( !this.wasLastViewLogged ) { - return; - } - - this.wasLastViewLogged = false; - mw.mmv.actionLogger.log( 'image-unview', true ); }; mw.mmv.MultimediaViewer = MultimediaViewer; -- To view, visit https://gerrit.wikimedia.org/r/173640 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I66cafd97427756411e967de1901324af2215e3ae Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/MultimediaViewer Gerrit-Branch: master Gerrit-Owner: Gilles <gdu...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits