From 0e01796a3c0774fdd1626854ad638c66f5caf97b Mon Sep 17 00:00:00 2001 From: Gilles Dubuc Date: Fri, 21 Nov 2014 00:39:29 +0100 Subject: [PATCH] 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 --- MultimediaViewer.php | 20 ++ MultimediaViewerHooks.php | 6 +- .../mmv/logging/mmv.logging.ViewLogger.js | 172 ++++++++++++++++++ resources/mmv/mmv.bootstrap.js | 2 +- resources/mmv/mmv.js | 45 ++--- .../logging/mmv.logging.ViewLogger.test.js | 75 ++++++++ tests/qunit/mmv/mmv.bootstrap.test.js | 2 +- tests/qunit/mmv/mmv.lightboxinterface.test.js | 4 +- tests/qunit/mmv/mmv.test.js | 38 ++-- .../qunit/mmv/ui/mmv.ui.canvasButtons.test.js | 2 +- 10 files changed, 314 insertions(+), 52 deletions(-) create mode 100644 resources/mmv/logging/mmv.logging.ViewLogger.js create mode 100644 tests/qunit/mmv/logging/mmv.logging.ViewLogger.test.js diff --git a/MultimediaViewer.php b/MultimediaViewer.php index fbb449265..d6aea6f18 100644 --- a/MultimediaViewer.php +++ b/MultimediaViewer.php @@ -117,6 +117,14 @@ if ( !isset( $wgMediaViewerImageQueryParameter ) ) { $wgMediaViewerImageQueryParameter = false; } +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'; @@ -898,6 +906,7 @@ $wgResourceModules += array( 'mmv.routing', 'mmv.logging.DurationLogger', 'mmv.logging.DimensionLogger', + 'mmv.logging.ViewLogger', 'jquery.fullscreen', 'jquery.hidpi', 'jquery.scrollTo', @@ -1003,6 +1012,17 @@ $wgResourceModules += array( ), ), + 'mmv.logging.ViewLogger' => $wgMediaViewerResourceTemplate + array( + 'scripts' => array( + 'mmv/logging/mmv.logging.ViewLogger.js', + ), + + 'dependencies' => array( + 'mediawiki.Uri', + 'mmv.base', + ), + ), + 'mmv.head' => $wgMediaViewerResourceTemplate + array( 'scripts' => array( 'mmv/mmv.head.js', diff --git a/MultimediaViewerHooks.php b/MultimediaViewerHooks.php index 5e87291be..55a906799 100644 --- a/MultimediaViewerHooks.php +++ b/MultimediaViewerHooks.php @@ -142,7 +142,9 @@ class MultimediaViewerHooks { global $wgMediaViewerActionLoggingSamplingFactorMap, $wgNetworkPerformanceSamplingFactor, $wgMediaViewerDurationLoggingSamplingFactor, $wgMediaViewerDurationLoggingLoggedinSamplingFactor, $wgMediaViewerAttributionLoggingSamplingFactor, $wgMediaViewerDimensionLoggingSamplingFactor, - $wgMediaViewerIsInBeta, $wgMediaViewerUseThumbnailGuessing, $wgMediaViewerImageQueryParameter; + $wgMediaViewerIsInBeta, $wgMediaViewerUseThumbnailGuessing, $wgMediaViewerImageQueryParameter, + $wgMediaViewerRecordViewDuration; + $vars['wgMultimediaViewer'] = array( 'infoLink' => self::$infoLink, 'discussionLink' => self::$discussionLink, @@ -155,6 +157,7 @@ class MultimediaViewerHooks { 'attributionSamplingFactor' => $wgMediaViewerAttributionLoggingSamplingFactor, 'dimensionSamplingFactor' => $wgMediaViewerDimensionLoggingSamplingFactor, 'imageQueryParameter' => $wgMediaViewerImageQueryParameter, + 'recordViewDuration' => $wgMediaViewerRecordViewDuration, 'tooltipDelay' => 1000, ); $vars['wgMediaViewer'] = true; @@ -199,6 +202,7 @@ class MultimediaViewerHooks { 'tests/qunit/mmv/logging/mmv.logging.ActionLogger.test.js', 'tests/qunit/mmv/logging/mmv.logging.AttributionLogger.test.js', 'tests/qunit/mmv/logging/mmv.logging.DimensionLogger.test.js', + 'tests/qunit/mmv/logging/mmv.logging.ViewLogger.test.js', 'tests/qunit/mmv/model/mmv.model.test.js', 'tests/qunit/mmv/model/mmv.model.IwTitle.test.js', 'tests/qunit/mmv/model/mmv.model.TaskQueue.test.js', diff --git a/resources/mmv/logging/mmv.logging.ViewLogger.js b/resources/mmv/logging/mmv.logging.ViewLogger.js new file mode 100644 index 000000000..2c48d2078 --- /dev/null +++ b/resources/mmv/logging/mmv.logging.ViewLogger.js @@ -0,0 +1,172 @@ +/* + * 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 . + */ + +( function ( mw, $ ) { + var VL; + + /** + * Tracks how long users are viewing images for + * @class mw.mmv.logging.ViewLogger + * @extends mw.Api + * @constructor + * @param {mw.Map} mwConfig mw.config + * @param {Object} window Browser window object + * @param {mw.mmv.logging.ActionLogger} actionLogger ActionLogger object + */ + function ViewLogger( mwConfig, windowObject, actionLogger ) { + var config = mwConfig && mwConfig.get ? mwConfig.get( 'wgMultimediaViewer' ) : false; + + /** + * 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 = config ? config.recordViewDuration : false; + + /** + * Browser window + * @property {Object} + */ + this.window = windowObject; + + /** + * Action logger + * @property {mw.mmv.logging.ActionLogger} + */ + this.actionLogger = actionLogger; + } + + VL = ViewLogger.prototype; + + /** + * Tracks the unview event of the current image if appropriate + */ + VL.unview = function () { + if ( !this.wasLastViewLogged ) { + return; + } + + this.wasLastViewLogged = false; + this.actionLogger.log( 'image-unview', true ); + }; + + /** + * Starts recording a viewing window for the current image + */ + VL.startViewDuration = function () { + this.viewStartTime = $.now(); + }; + + /** + * Stops recording the viewing window for the current image + */ + VL.stopViewDuration = function () { + if ( this.viewStartTime ) { + this.viewDuration += $.now() - this.viewStartTime; + this.viewStartTime = 0; + } + }; + + /** + * Records the amount of time the current image has been viewed + */ + VL.recordViewDuration = function () { + var uri; + + this.stopViewDuration(); + + if ( this.shouldRecordViewDuration && this.viewDuration > 0 ) { + uri = new mw.Uri( this.url ); + uri.extend( { viewDuration: this.viewDuration } ); + + $.ajax( { + type: 'HEAD', + url: uri.toString() + } ); + + 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 + */ + VL.attach = function ( url ) { + var view = this; + + this.url = url; + this.startViewDuration(); + + $( this.window ) + .off( '.mmv-view-logger' ) + .on( 'beforeunload.mmv-view-logger', function() { + view.recordViewDuration(); + } ) + .on( 'focus.mmv-view-logger', function() { + view.startViewDuration(); + } ) + .on( 'blur.mmv-view-logger', function() { + view.stopViewDuration(); + } ); + }; + + /* + * Stops listening to events + */ + VL.unattach = function() { + $( this.window ).off( '.mmv-view-logger' ); + this.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 + */ + VL.setLastViewLogged = function ( wasEventLogged ) { + this.wasLastViewLogged = wasEventLogged; + }; + + mw.mmv.logging.ViewLogger = ViewLogger; +}( mediaWiki, jQuery ) ); diff --git a/resources/mmv/mmv.bootstrap.js b/resources/mmv/mmv.bootstrap.js index ad51921ed..053c66b0e 100644 --- a/resources/mmv/mmv.bootstrap.js +++ b/resources/mmv/mmv.bootstrap.js @@ -467,7 +467,7 @@ */ MMVB.getViewer = function () { if ( this.viewer === undefined ) { - this.viewer = new mw.mmv.MultimediaViewer(); + this.viewer = new mw.mmv.MultimediaViewer( mw.config ); this.viewer.setupEventHandlers(); } diff --git a/resources/mmv/mmv.js b/resources/mmv/mmv.js index 11392a351..99ebb9207 100644 --- a/resources/mmv/mmv.js +++ b/resources/mmv/mmv.js @@ -24,10 +24,17 @@ * to manage the viewing experience of such content. * @class mw.mmv.MultimediaViewer * @constructor + * @param {mw.Map} mwConfig mw.config */ - function MultimediaViewer() { + function MultimediaViewer( mwConfig ) { var apiCacheMaxAge = 86400; // one day + /** + * @property {mw.Map} + * @private + */ + this.mwConfig = mwConfig; + /** * @property {mw.mmv.provider.Image} * @private @@ -40,7 +47,7 @@ */ this.imageInfoProvider = new mw.mmv.provider.ImageInfo( new mw.mmv.logging.Api( 'imageinfo' ), // Short-circuit, don't fallback, to save some tiny amount of time - { language: mw.config.get( 'wgUserLanguage', false ) || mw.config.get( 'wgContentLanguage', 'en' ) } + { language: this.mwConfig.get( 'wgUserLanguage', false ) || this.mwConfig.get( 'wgContentLanguage', 'en' ) } ); /** @@ -106,10 +113,9 @@ this.documentTitle = document.title; /** - * Was the last image view logged or was logging skipped? - * @property {boolean} + * @property {mw.mmv.logging.ViewLogger} view - */ - this.wasLastViewLogged = false; + this.viewLogger = new mw.mmv.logging.ViewLogger( this.mwConfig, window, mw.mmv.actionLogger ); } MMVP = MultimediaViewer.prototype; @@ -424,14 +430,10 @@ this.ui.canvas.unblur(); } - mw.mmv.actionLogger.log( 'image-view' ).then( function ( wasEventLogged ) { - viewer.wasLastViewLogged = wasEventLogged; + this.viewLogger.attach( 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.viewLogger.setLastViewLogged( wasEventLogged ); } ); }; @@ -797,6 +799,8 @@ var thumb; if ( index < this.thumbs.length && index >= 0 ) { + this.viewLogger.recordViewDuration(); + thumb = this.thumbs[ index ]; this.loadImage( thumb.image, thumb.$thumb.clone()[0] ); } @@ -806,7 +810,6 @@ * Opens the next image */ MMVP.nextImage = function () { - this.unview(); mw.mmv.actionLogger.log( 'next-image' ); this.loadIndex( this.currentIndex + 1 ); }; @@ -815,7 +818,6 @@ * Opens the previous image */ MMVP.prevImage = function () { - this.unview(); mw.mmv.actionLogger.log( 'prev-image' ); this.loadIndex( this.currentIndex - 1 ); }; @@ -826,7 +828,8 @@ MMVP.close = function () { var windowTitle; - this.unview(); + this.viewLogger.recordViewDuration(); + this.viewLogger.unattach(); windowTitle = this.createDocumentTitle( null ); @@ -951,17 +954,5 @@ 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; }( mediaWiki, jQuery ) ); diff --git a/tests/qunit/mmv/logging/mmv.logging.ViewLogger.test.js b/tests/qunit/mmv/logging/mmv.logging.ViewLogger.test.js new file mode 100644 index 000000000..fefff6909 --- /dev/null +++ b/tests/qunit/mmv/logging/mmv.logging.ViewLogger.test.js @@ -0,0 +1,75 @@ +( function ( mw, $ ) { + QUnit.module( 'mmv.logging.ViewLogger', QUnit.newMwEnvironment( { + setup: function () { + this.clock = this.sandbox.useFakeTimers(); + } + } ) ); + + QUnit.test( 'unview()', 4, function ( assert ) { + var logger = { log : $.noop }, + viewLogger = new mw.mmv.logging.ViewLogger( {}, {}, logger ); + + this.sandbox.stub( logger, 'log' ); + + viewLogger.unview(); + + assert.ok( !logger.log.called, 'action logger not called' ); + + viewLogger.setLastViewLogged( false ); + viewLogger.unview(); + + assert.ok( !logger.log.called, 'action logger not called' ); + + viewLogger.setLastViewLogged( true ); + viewLogger.unview(); + + assert.ok( logger.log.calledOnce, 'action logger called' ); + + viewLogger.unview(); + + assert.ok( logger.log.calledOnce, 'action logger not called again' ); + } ); + + QUnit.test( 'focus and blur', 1, function ( assert ) { + var fakeWindow = $( '
' ), + viewLogger = new mw.mmv.logging.ViewLogger( {}, fakeWindow, { log : $.noop } ); + + this.clock.tick( 1 ); // This is just so that $.now() > 0 in the fake timer environment + + viewLogger.attach(); + + this.clock.tick( 5 ); + + fakeWindow.triggerHandler( 'blur' ); + + this.clock.tick( 2 ); + + fakeWindow.triggerHandler( 'focus' ); + + this.clock.tick( 3 ); + + fakeWindow.triggerHandler( 'blur' ); + + this.clock.tick( 4 ); + + assert.strictEqual( viewLogger.viewDuration, 8, 'Only focus duration was logged' ); + } ); + + QUnit.test( 'stopViewDuration before startViewDuration', 1, function ( assert ) { + var viewLogger = new mw.mmv.logging.ViewLogger( {}, {}, { log : $.noop } ); + + this.clock.tick( 1 ); // This is just so that $.now() > 0 in the fake timer environment + + viewLogger.stopViewDuration(); + + this.clock.tick( 2 ); + + viewLogger.startViewDuration(); + + this.clock.tick( 3 ); + + viewLogger.stopViewDuration(); + + assert.strictEqual( viewLogger.viewDuration, 3, 'Only last timeframe was logged' ); + } ); +}( mediaWiki, jQuery ) ); diff --git a/tests/qunit/mmv/mmv.bootstrap.test.js b/tests/qunit/mmv/mmv.bootstrap.test.js index 53dda695d..2be14f9d4 100644 --- a/tests/qunit/mmv/mmv.bootstrap.test.js +++ b/tests/qunit/mmv/mmv.bootstrap.test.js @@ -275,7 +275,7 @@ var bootstrap, $div, $link, - viewer = new mw.mmv.MultimediaViewer(), + viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ), fname = 'valid', imgSrc = '/' + fname + '.jpg/300px-' + fname + '.jpg', imgRegex = new RegExp( imgSrc + '$' ); diff --git a/tests/qunit/mmv/mmv.lightboxinterface.test.js b/tests/qunit/mmv/mmv.lightboxinterface.test.js index 1a61748f5..b79152b0c 100644 --- a/tests/qunit/mmv/mmv.lightboxinterface.test.js +++ b/tests/qunit/mmv/mmv.lightboxinterface.test.js @@ -136,7 +136,7 @@ var buttonOffset, panelBottom, oldRevealButtonsAndFadeIfNeeded, lightbox = new mw.mmv.LightboxInterface(), - viewer = new mw.mmv.MultimediaViewer(), + viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ), oldFnEnterFullscreen = $.fn.enterFullscreen, oldFnExitFullscreen = $.fn.exitFullscreen; @@ -245,7 +245,7 @@ } ); QUnit.test( 'Keyboard prev/next', 2, function ( assert ) { - var viewer = new mw.mmv.MultimediaViewer(), + var viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ), lightbox = new mw.mmv.LightboxInterface(); viewer.setupEventHandlers(); diff --git a/tests/qunit/mmv/mmv.test.js b/tests/qunit/mmv/mmv.test.js index 14eb36f51..50b1e091e 100644 --- a/tests/qunit/mmv/mmv.test.js +++ b/tests/qunit/mmv/mmv.test.js @@ -2,7 +2,7 @@ QUnit.module( 'mmv', QUnit.newMwEnvironment() ); QUnit.test( 'eachPrealoadableLightboxIndex()', 11, function ( assert ) { - var viewer = new mw.mmv.MultimediaViewer(), + var viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ), expectedIndices, i; @@ -31,7 +31,7 @@ QUnit.test( 'Hash handling', 7, function ( assert ) { var oldUnattach, - viewer = new mw.mmv.MultimediaViewer(), + viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ), ui = new mw.mmv.LightboxInterface(), imageSrc = 'Foo bar.jpg', image = { filePageTitle: new mw.Title( 'File:' + imageSrc ) }; @@ -102,7 +102,7 @@ QUnit.test( 'Progress', 4, function ( assert ) { var imageDeferred = $.Deferred(), - viewer = new mw.mmv.MultimediaViewer(); + viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ); viewer.thumbs = []; viewer.displayPlaceholderThumbnail = $.noop; @@ -158,7 +158,7 @@ secondImageDeferred = $.Deferred(), firstImage = { index: 1, filePageTitle : new mw.Title( 'File:First.jpg' ) }, secondImage = { index: 2, filePageTitle : new mw.Title( 'File:Second.jpg' ) }, - viewer = new mw.mmv.MultimediaViewer(); + viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ); viewer.thumbs = []; viewer.displayPlaceholderThumbnail = $.noop; @@ -256,7 +256,7 @@ } ); QUnit.test( 'resetBlurredThumbnailStates', 4, function ( assert ) { - var viewer = new mw.mmv.MultimediaViewer(); + var viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ); assert.ok( !viewer.realThumbnailShown, 'Real thumbnail state is correct' ); assert.ok( !viewer.blurredThumbnailShown, 'Placeholder state is correct' ); @@ -271,7 +271,7 @@ } ); QUnit.test( 'Placeholder first, then real thumbnail', 4, function ( assert ) { - var viewer = new mw.mmv.MultimediaViewer(); + var viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ); viewer.setImage = $.noop; viewer.ui = { canvas : { @@ -286,14 +286,14 @@ assert.ok( viewer.blurredThumbnailShown, 'Placeholder state is correct' ); assert.ok( !viewer.realThumbnailShown, 'Real thumbnail state is correct' ); - viewer.displayRealThumbnail(); + viewer.displayRealThumbnail( { url : undefined } ); assert.ok( viewer.realThumbnailShown, 'Real thumbnail state is correct' ); assert.ok( viewer.blurredThumbnailShown, 'Placeholder state is correct' ); } ); QUnit.test( 'Placeholder first, then real thumbnail - missing size', 4, function ( assert ) { - var viewer = new mw.mmv.MultimediaViewer(); + var viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ); viewer.currentIndex = 1; viewer.setImage = $.noop; @@ -309,14 +309,14 @@ assert.ok( viewer.blurredThumbnailShown, 'Placeholder state is correct' ); assert.ok( !viewer.realThumbnailShown, 'Real thumbnail state is correct' ); - viewer.displayRealThumbnail(); + viewer.displayRealThumbnail( { url : undefined } ); assert.ok( viewer.realThumbnailShown, 'Real thumbnail state is correct' ); assert.ok( viewer.blurredThumbnailShown, 'Placeholder state is correct' ); } ); QUnit.test( 'Real thumbnail first, then placeholder', 4, function ( assert ) { - var viewer = new mw.mmv.MultimediaViewer(); + var viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ); viewer.setImage = $.noop; viewer.ui = { @@ -326,7 +326,7 @@ unblur: $.noop } }; - viewer.displayRealThumbnail(); + viewer.displayRealThumbnail( { url : undefined } ); assert.ok( viewer.realThumbnailShown, 'Real thumbnail state is correct' ); assert.ok( !viewer.blurredThumbnailShown, 'Placeholder state is correct' ); @@ -338,7 +338,7 @@ } ); QUnit.test( 'displayRealThumbnail', 2, function ( assert ) { - var viewer = new mw.mmv.MultimediaViewer(); + var viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ); viewer.setImage = $.noop; viewer.ui = { canvas : { @@ -348,16 +348,16 @@ viewer.blurredThumbnailShown = true; // Should not result in an unblurWithAnimation animation (image cache from cache) - viewer.displayRealThumbnail( undefined, undefined, undefined, 5 ); + viewer.displayRealThumbnail( { url : undefined }, undefined, undefined, 5 ); assert.ok( !viewer.ui.canvas.unblurWithAnimation.called, 'There should not be an unblurWithAnimation animation' ); // Should result in an unblurWithAnimation (image didn't come from cache) - viewer.displayRealThumbnail( undefined, undefined, undefined, 1000 ); + viewer.displayRealThumbnail( { url : undefined }, undefined, undefined, 1000 ); assert.ok( viewer.ui.canvas.unblurWithAnimation.called, 'There should be an unblurWithAnimation animation' ); } ); QUnit.test( 'New image loaded while another one is loading', 5, function ( assert ) { - var viewer = new mw.mmv.MultimediaViewer(), + var viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ), firstImageDeferred = $.Deferred(), secondImageDeferred = $.Deferred(), firstLigthboxInfoDeferred = $.Deferred(), @@ -419,7 +419,7 @@ QUnit.test( 'Events are not trapped after the viewer is closed', 0, function( assert ) { var i, j, k, eventParameters, - viewer = new mw.mmv.MultimediaViewer(), + viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ), $document = $( document ), $qf = $( '#qunit-fixture' ), eventTypes = [ 'keydown', 'keyup', 'keypress', 'click', 'mousedown', 'mouseup' ], @@ -490,7 +490,7 @@ } ); QUnit.test( 'Refuse to load too-big thumbnails', 1, function ( assert ) { - var viewer = new mw.mmv.MultimediaViewer(), + var viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ), intendedWidth = 50, title = mw.Title.newFromText( 'File:Foobar.svg' ); @@ -507,7 +507,7 @@ thumbnailInfoStub, imageStub, promise, - viewer = new mw.mmv.MultimediaViewer(), + viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ), sandbox = this.sandbox, oldUseThumbnailGuessing = mw.config.get( 'wgMultimediaViewer' ).useThumbnailGuessing, file = new mw.Title( 'File:Copyleft.svg' ), @@ -607,7 +607,7 @@ } ); QUnit.test( 'document.title', 2, function ( assert ) { - var viewer = new mw.mmv.MultimediaViewer(), + var viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ), bootstrap = new mw.mmv.MultimediaViewerBootstrap(), title = new mw.Title( 'File:This_should_show_up_in_document_title.png'), oldDocumentTitle = document.title; diff --git a/tests/qunit/mmv/ui/mmv.ui.canvasButtons.test.js b/tests/qunit/mmv/ui/mmv.ui.canvasButtons.test.js index c94fff073..e3b1ecf25 100644 --- a/tests/qunit/mmv/ui/mmv.ui.canvasButtons.test.js +++ b/tests/qunit/mmv/ui/mmv.ui.canvasButtons.test.js @@ -22,7 +22,7 @@ var i = 0, $qf = $( '#qunit-fixture' ), buttons = new mw.mmv.ui.CanvasButtons( $qf, $( '
' ), $( '
' ) ), - viewer = new mw.mmv.MultimediaViewer(); + viewer = new mw.mmv.MultimediaViewer( { get : $.noop } ); viewer.ui = {};