jenkins-bot has submitted this change and it was merged.
Change subject: Refactor to a data model
......................................................................
Refactor to a data model
Image information and repo information are now both stored somewhere
else entirely, so we don't need to keep accessing weird API return
values to sort things out. fetchImageInfo now uses those classes to
an extent, and we now cache thumbnail URLs for different sizes.
Change-Id: Ife8293c86683ea914b1a5a60000584b501d92e55
---
M MultimediaViewer.php
M MultimediaViewerHooks.php
A resources/ext.multimediaViewer/ext.multimediaViewer.dataModel.js
M resources/ext.multimediaViewer/ext.multimediaViewer.js
M resources/ext.multimediaViewer/ext.multimediaViewer.lightboxinterface.js
A resources/ext.multimediaViewer/mmv.js
A tests/qunit/ext.multimediaViewer.dataModel.test.js
M tests/qunit/ext.multimediaViewer.lightboxinterface.test.js
8 files changed, 575 insertions(+), 218 deletions(-)
Approvals:
Gergő Tisza: Looks good to me, approved
jenkins-bot: Verified
diff --git a/MultimediaViewer.php b/MultimediaViewer.php
index 6df2b66..a7f6a08 100644
--- a/MultimediaViewer.php
+++ b/MultimediaViewer.php
@@ -86,6 +86,23 @@
),
), $moduleInfoMMV );
+$wgResourceModules['ext.multimediaViewer.dataModel'] = array_merge( array(
+ 'scripts' => array(
+ 'ext.multimediaViewer.dataModel.js',
+ ),
+
+ 'dependencies' => array(
+ 'ext.multimediaViewer.base',
+ 'oojs',
+ ),
+), $moduleInfoMMV );
+
+$wgResourceModules['ext.multimediaViewer.base'] = array_merge( array(
+ 'scripts' => array(
+ 'mmv.js',
+ ),
+), $moduleInfoMMV );
+
$wgResourceModules['ext.multimediaViewer'] = array_merge( array(
'scripts' => array(
'ext.multimediaViewer.js',
@@ -102,6 +119,7 @@
'mediawiki.Title',
'jquery.ui.dialog',
'jquery.hidpi',
+ 'ext.multimediaViewer.dataModel',
),
'messages' => array(
diff --git a/MultimediaViewerHooks.php b/MultimediaViewerHooks.php
index 3fa971a..1c2e2b8 100644
--- a/MultimediaViewerHooks.php
+++ b/MultimediaViewerHooks.php
@@ -118,6 +118,7 @@
$testModules['qunit']['ext.multimediaViewer.tests'] = array(
'scripts' => array(
'tests/qunit/ext.multimediaViewer.test.js',
+
'tests/qunit/ext.multimediaViewer.dataModel.test.js',
'tests/qunit/ext.multimediaViewer.lightboxinterface.test.js',
'tests/qunit/lightboximage.test.js',
'tests/qunit/lightboxinterface.test.js',
diff --git a/resources/ext.multimediaViewer/ext.multimediaViewer.dataModel.js
b/resources/ext.multimediaViewer/ext.multimediaViewer.dataModel.js
new file mode 100644
index 0000000..5753e95
--- /dev/null
+++ b/resources/ext.multimediaViewer/ext.multimediaViewer.dataModel.js
@@ -0,0 +1,303 @@
+/*
+ * 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, oo ) {
+ /**
+ * @class mw.mmv.model.Image
+ * Represents information about a single image
+ * @constructor
+ * @param {mw.Title} title
+ * @param {number} size Filesize in bytes of the original image
+ * @param {number} width Width of the original image
+ * @param {number} height Height of the original image
+ * @param {string} mimeType
+ * @param {string} url URL to the image itself (original version)
+ * @param {string} descriptionUrl URL to the image description page
+ * @param {string} repo The repository this image belongs to
+ * @param {string} lastUploader The last person to upload a version of
this image.
+ * @param {string} lastUploadDateTime The time and date the last upload
occurred
+ * @param {string} originalUploadDateTime The time and date the
original upload occurred
+ * @param {string} description
+ * @param {string} source
+ * @param {string} author
+ * @param {string} license
+ */
+ function Image(
+ title,
+ size,
+ width,
+ height,
+ mimeType,
+ url,
+ descriptionUrl,
+ repo,
+ lastUploader,
+ uploadDateTime,
+ creationDateTime,
+ description,
+ source,
+ author,
+ license
+ ) {
+ /** @property {mw.Title} title */
+ this.title = title;
+
+ /** @property {number} size */
+ this.size = size;
+
+ /** @property {number} width */
+ this.width = width;
+
+ /** @property {number} height */
+ this.height = height;
+
+ /** @property {string} mimeType */
+ this.mimeType = mimeType;
+
+ /** @property {string} url */
+ this.url = url;
+
+ /** @property {string} descriptionUrl */
+ this.descriptionUrl = descriptionUrl;
+
+ /** @property {string} repo */
+ this.repo = repo;
+
+ /** @property {string} lastUploader */
+ this.lastUploader = lastUploader;
+
+ /** @property {string} uploadDateTime */
+ this.uploadDateTime = uploadDateTime;
+
+ /** @property {string} creationDateTime */
+ this.creationDateTime = creationDateTime;
+
+ /** @property {string} description */
+ this.description = description;
+
+ /** @property {string} source */
+ this.source = source;
+
+ /** @property {string} author */
+ this.author = author;
+
+ /** @property {string} license */
+ this.license = license;
+
+ /**
+ * @property {object} thumbUrls
+ * An object indexed by image widths
+ * with URLs to appropriately sized thumbnails
+ */
+ this.thumbUrls = {};
+ }
+
+ /**
+ * @method
+ * @static
+ * Constructs a new Image object out of an object containing
+ * imageinfo data from an API response.
+ * @param {mw.Title} title
+ * @param {object} imageInfo
+ * @returns {mw.mmv.model.Image}
+ */
+ Image.newFromImageInfo = function ( title, imageInfo ) {
+ var uploadDateTime, creationDateTime, imageData,
+ description, source, author, license,
+ innerInfo = imageInfo.imageinfo[0],
+ extmeta = innerInfo.extmetadata;
+
+ if ( extmeta ) {
+ creationDateTime = extmeta.DateTimeOriginal;
+ uploadDateTime = extmeta.DateTime;
+
+ if ( uploadDateTime ) {
+ uploadDateTime = uploadDateTime.value.replace(
/<.*?>/g, '' );
+ }
+
+ if ( creationDateTime ) {
+ creationDateTime =
creationDateTime.value.replace( /<.*?>/g, '' );
+ }
+
+ description = extmeta.ImageDescription &&
extmeta.ImageDescription.value;
+ source = extmeta.Credit && extmeta.Credit.value;
+ author = extmeta.Artist && extmeta.Artist.value;
+ license = extmeta.License && extmeta.License.value;
+ }
+
+ imageData = new Image(
+ title,
+ innerInfo.size,
+ innerInfo.width,
+ innerInfo.height,
+ innerInfo.mime,
+ innerInfo.url,
+ innerInfo.descriptionurl,
+ imageInfo.imagerepository,
+ innerInfo.user,
+ uploadDateTime,
+ creationDateTime,
+ description,
+ source,
+ author,
+ license
+ );
+
+ if ( innerInfo.thumburl ) {
+ imageData.addThumbUrl(
+ innerInfo.thumbwidth,
+ innerInfo.thumburl
+ );
+ }
+
+ return imageData;
+ };
+
+ /**
+ * @method
+ * Add a thumb URL
+ * @param {number} width
+ * @param {string} url
+ */
+ Image.prototype.addThumbUrl = function ( width, url ) {
+ this.thumbUrls[width] = url;
+ };
+
+ /**
+ * @method
+ * Get a thumb URL if we have it.
+ * @param {number} width
+ * @returns {string|undefined}
+ */
+ Image.prototype.getThumbUrl = function ( width ) {
+ return this.thumbUrls[width];
+ };
+
+ /**
+ * @method
+ * Check whether the image is CC-licensed.
+ * @returns {boolean}
+ */
+ Image.prototype.isCcLicensed = function () {
+ return this.license && this.license.substr( 0, 2 ) === 'cc';
+ };
+
+ /**
+ * @class mw.mmv.model.Repo
+ * Represents information about a single image repository
+ * @constructor
+ * @param {string} displayName
+ * @param {boolean} isLocal
+ */
+ function Repo(
+ displayName,
+ isLocal
+ ) {
+ /** @property {string} displayName */
+ this.displayName = displayName;
+
+ /** @property {boolean} isLocal */
+ this.isLocal = isLocal;
+ }
+
+ /**
+ * @method
+ * @static
+ * Creates a new object from repoInfo we found in an API response.
+ * @param {object} repoInfo
+ * @returns {mw.mmv.model.Repo}
+ */
+ Repo.newFromRepoInfo = function ( repoInfo ) {
+ if ( repoInfo.apiurl ) {
+ return new ForeignApiRepo(
+ repoInfo.displayname,
+ false,
+ repoInfo.apiurl,
+ repoInfo.server,
+ repoInfo.articlepath
+ );
+ } else if ( repoInfo.descBaseUrl ) {
+ return new ForeignDbRepo(
+ repoInfo.displayname,
+ false,
+ repoInfo.descBaseUrl
+ );
+ } else {
+ return new Repo( repoInfo.displayname, repoInfo.local );
+ }
+ };
+
+ /**
+ * @class mw.mmv.model.ForeignApiRepo
+ * Represents information about a foreign API repository
+ * @extends Repo
+ * @constructor
+ * @inheritdoc
+ * @param {string} apiUrl URL to the wiki's api.php
+ * @param {string} server Hostname for the wiki
+ * @param {string} articlePath Path to articles on the wiki, relative
to the hostname.
+ */
+ function ForeignApiRepo(
+ displayName,
+ isLocal,
+ apiUrl,
+ server,
+ articlePath
+ ) {
+ Repo.call( this, displayName, isLocal );
+
+ /** @property {string} apiUrl */
+ this.apiUrl = apiUrl;
+
+ /** @property {string} server */
+ this.server = server;
+
+ /** @property {string} articlePath */
+ this.articlePath = articlePath;
+
+ /** @property {string} absoluteArticlePath */
+ this.absoluteArticlePath = server + articlePath;
+ }
+
+ oo.inheritClass( ForeignApiRepo, Repo );
+
+ /**
+ * @class mw.mmv.model.ForeignDbRepo
+ * Represents information about a foreign, shared DB repository
+ * @extends Repo
+ * @constructor
+ * @inheritdoc
+ */
+ function ForeignDbRepo(
+ displayName,
+ isLocal,
+ descBaseUrl
+ ) {
+ Repo.call( this, displayName, isLocal );
+
+ /** @property {string} descBaseUrl */
+ this.descBaseUrl = descBaseUrl;
+ }
+
+ oo.inheritClass( ForeignDbRepo, Repo );
+
+ mw.mmv.model = {};
+ mw.mmv.model.Image = Image;
+ mw.mmv.model.Repo = Repo;
+ mw.mmv.model.ForeignApiRepo = ForeignApiRepo;
+ mw.mmv.model.ForeignDbRepo = ForeignDbRepo;
+}( mediaWiki, OO ) );
diff --git a/resources/ext.multimediaViewer/ext.multimediaViewer.js
b/resources/ext.multimediaViewer/ext.multimediaViewer.js
index 09ff6d1..d1c4ece 100755
--- a/resources/ext.multimediaViewer/ext.multimediaViewer.js
+++ b/resources/ext.multimediaViewer/ext.multimediaViewer.js
@@ -115,8 +115,11 @@
this.api = new mw.Api();
/**
- * imageInfo object. TODO: Describe structure and valid states.
- * @property {Object}
+ * imageInfo object, used for caching - promises will resolve
with
+ * an mw.mmv.model.Image object, a repoInfo object, the best
width for
+ * the current screen configuration, and the width requested
from
+ * the server (if any).
+ * @property {jQuery.Promise[]}
* @private
*/
this.imageInfo = {};
@@ -317,8 +320,8 @@
var viewer = this,
fileTitle = this.currentImageFileTitle;
- this.fetchImageInfo( fileTitle, [ 'url' ] ).done( function (
imageInfo, repoInfo, targetWidth ) {
- viewer.loadResizedImage( ui, imageInfo, targetWidth );
+ this.fetchImageInfo( fileTitle, [ 'url' ] ).done( function (
imageData, repoInfo, targetWidth ) {
+ viewer.loadResizedImage( ui, imageData, targetWidth );
} );
};
@@ -328,31 +331,30 @@
* @protected
*
* @param {LightboxInterface} ui lightbox that got resized
- * @param {Object} imageInfo information regarding the new resized image
+ * @param {mw.mmv.model.Image} imageData information regarding the new
resized image
* @param {number} targetWidth
*/
- MMVP.loadResizedImage = function ( ui, imageInfo, targetWidth ) {
- var innerInfo, rpid, viewer, image;
+ MMVP.loadResizedImage = function ( ui, imageData, targetWidth,
requestedWidth ) {
+ var rpid, viewer, image, maybeThumb;
// Replace image only if data was returned.
- if ( imageInfo ) {
+ if ( imageData ) {
viewer = this;
image = new Image();
-
- innerInfo = imageInfo.imageinfo[0];
image.onload = function () {
viewer.profileEnd( rpid );
};
rpid = this.profileStart( 'image-resize', {
- width: innerInfo.width,
- height: innerInfo.height,
- fileSize: innerInfo.size
- }, innerInfo.mime );
+ width: imageData.width,
+ height: imageData.height,
+ fileSize: imageData.size
+ }, imageData.mimeType );
- image.src = innerInfo.thumburl || innerInfo.url;
- if ( innerInfo.thumbwidth > targetWidth ) {
+ maybeThumb = imageData.getThumbUrl( requestedWidth );
+ image.src = maybeThumb || imageData.url;
+ if ( maybeThumb && requestedWidth > targetWidth ||
!maybeThumb && imageData.width > targetWidth ) {
image.width = targetWidth;
}
ui.replaceImageWith( image );
@@ -463,24 +465,32 @@
};
/**
- * Get image information out of an API response.
- * @param {Object[]} images The query.pages member of the API response.
- * @returns {Object} Representing image information.
+ * @method
+ * Get first (hopefully only) member of an object.
+ * @param {Array|Object} things
+ * @returns {Mixed}
*/
- MMVP.getImageInfo = function ( images ) {
- var imageInfo;
+ MMVP.getFirst = function ( things ) {
+ var thing;
- if ( images ) {
- $.each( images, function ( i, page ) {
- imageInfo = page;
+ if ( things ) {
+ $.each( things, function ( i, thisone ) {
+ thing = thisone;
return false;
} );
}
- return imageInfo;
+ return thing;
};
- MMVP.setImageInfo = function ( fileTitle, imageInfo ) {
+ /**
+ * @method
+ * Set the image information in the UI.
+ * @param {mw.Title} fileTitle
+ * @param {mw.mmv.model.Image} imageData
+ * @param {mw.mmv.model.Repo} repoData
+ */
+ MMVP.setImageInfo = function ( fileTitle, imageData, repoData ) {
function whitelistHtml( $el ) {
var child, $prev, $child = $el.children().first();
@@ -508,37 +518,22 @@
}
}
- var extmeta, gfpid,
- repoInfo,
- desc,
- datetime, dtmsg,
- license, msgname,
- username,
- source, author,
+ var gfpid,
+ msgname,
viewer = this,
- ui = this.lightbox.iface,
- innerInfo = imageInfo.imageinfo[0] || {};
+ ui = this.lightbox.iface;
ui.$title.text( fileTitle.getNameText() );
- ui.$useFile.data( 'title', fileTitle );
- ui.$useFile.data( 'src', innerInfo.url );
+ ui.initUseFileData( fileTitle, imageData.url, repoData.isLocal
);
ui.$useFileLi.removeClass( 'empty' );
- if ( this.repoInfo ) {
- repoInfo = this.repoInfo[imageInfo.imagerepository];
- }
+ ui.setRepoDisplayName( repoData.displayname, repoData.isLocal );
+ ui.setFilePageLink( imageData.descriptionUrl );
- if ( repoInfo ) {
- ui.setRepoDisplayName( repoInfo.displayname,
repoInfo.local );
- ui.setFilePageLink( repoInfo, fileTitle );
- }
+ ui.$repoLi.removeClass( 'empty' );
- ui.$repoLi.toggleClass( 'empty', !repoInfo );
-
- username = innerInfo.user;
-
- if ( username ) {
+ if ( imageData.lastUploader ) {
gfpid = this.profileStart( 'gender-fetch' );
// TODO: Reuse the api member, fix everywhere.
@@ -546,115 +541,98 @@
// TODO this is ugly as hell, let's fix this in core.
new mw.Api( {
ajax: {
- url: repoInfo.apiurl ||
mw.util.wikiScript( 'api' )
+ url: repoData.apiUrl ||
mw.util.wikiScript( 'api' )
}
} ).get( {
action: 'query',
list: 'users',
- ususers: username,
+ ususers: imageData.lastUploader,
usprop: 'gender'
} ).done( function ( data ) {
- var gender = data.query.users[0].gender;
+ var gender = 'unknown';
viewer.profileEnd( gfpid );
- ui.setUserPageLink( repoInfo, username, gender
);
+ if ( data && data.query && data.query.users &&
+ data.query.users[0] &&
data.query.users[0].gender ) {
+ gender = data.query.users[0].gender;
+ }
+
+ ui.setUserPageLink( repoData,
imageData.lastUploader, gender );
} ).fail( function () {
mw.log( 'Gender fetch with ID ' + gfpid + '
failed, probably due to cross-domain API request.' );
- ui.setUserPageLink( repoInfo, username,
'unknown' );
+ ui.setUserPageLink( repoData,
imageData.lastUploader, 'unknown' );
} );
}
- extmeta = innerInfo.extmetadata;
-
- if ( extmeta ) {
- desc = extmeta.ImageDescription;
-
- ui.$imageDescDiv.toggleClass( 'empty', !desc );
-
- if ( desc ) {
- desc = desc.value;
- whitelistHtml( ui.$imageDesc.append(
$.parseHTML( desc ) ) );
- } else {
- ui.$imageDesc.append( mw.message(
'multimediaviewer-desc-nil' ).text() );
- }
-
- datetime = extmeta.DateTimeOriginal || extmeta.DateTime;
-
- if ( datetime ) {
- // get rid of HTML tags
- datetime = datetime.value.replace( /<.*?>/g, ''
);
- datetime = this.formatDate( datetime );
-
- dtmsg = (
- 'multimediaviewer-datetime-' +
- ( extmeta.DateTimeOriginal ? 'created'
: 'uploaded' )
- );
-
- ui.$datetime.text(
- mw.message( dtmsg, datetime ).text()
- );
- }
-
- ui.$datetimeLi.toggleClass( 'empty', !datetime );
-
- source = extmeta.Credit;
- author = extmeta.Artist;
-
- if ( source ) {
- source = source.value;
- whitelistHtml( ui.$source.empty().append(
$.parseHTML( source ) ) );
- }
-
- if ( author ) {
- author = author.value;
- whitelistHtml( ui.$author.empty().append(
$.parseHTML( author ) ) );
- }
-
- if ( source && author ) {
- ui.$credit.html(
- mw.message(
- 'multimediaviewer-credit',
- ui.$author.get( 0 ).outerHTML,
- ui.$source.get( 0 ).outerHTML
- ).plain()
- );
- } else {
- // Clobber the contents and only have one of
the fields
- if ( source ) {
- ui.$credit.html( ui.$source );
- } else if ( author ) {
- ui.$credit.html( ui.$author );
- }
- }
-
- ui.$credit.toggleClass( 'empty', !source && !author );
-
- license = extmeta.License;
+ if ( imageData.creationDateTime ) {
+ ui.$datetime.text(
+ mw.message(
+ 'multimediaviewer-datetime-created',
+ this.formatDate(
imageData.creationDateTime )
+ ).text()
+ );
+ } else if ( imageData.uploadDateTime ) {
+ ui.$datetime.text(
+ mw.message(
+ 'multimediaviewer-datetime-uploaded',
+ this.formatDate(
imageData.uploadDateTime )
+ ).text()
+ );
}
- if ( license ) {
- license = license.value;
+ ui.$datetimeLi.toggleClass( 'empty', !imageData.uploadDateTime
&& !imageData.creationDateTime );
+
+ if ( imageData.description ) {
+ whitelistHtml( ui.$imageDesc.empty().append(
$.parseHTML( imageData.description ) ) );
+ } else {
+ ui.$imageDesc.append( mw.message(
'multimediaviewer-desc-nil' ).text() );
}
- msgname = 'multimediaviewer-license-' + ( license || '' );
+ ui.$imageDescDiv.toggleClass( 'empty', !imageData.description );
- if ( !license || !mw.messages.exists( msgname ) ) {
+ if ( imageData.source ) {
+ whitelistHtml( ui.$source.empty().append( $.parseHTML(
imageData.source ) ) );
+ }
+
+ if ( imageData.author ) {
+ whitelistHtml( ui.$author.empty().append( $.parseHTML(
imageData.author ) ) );
+ }
+
+ if ( imageData.source && imageData.author ) {
+ ui.$credit.html(
+ mw.message(
+ 'multimediaviewer-credit',
+ ui.$author.get( 0 ).outerHTML,
+ ui.$source.get( 0 ).outerHTML
+ ).plain()
+ );
+ } else {
+ // Clobber the contents and only have one of the fields
+ if ( imageData.source ) {
+ ui.$credit.empty().append( ui.$source );
+ } else if ( imageData.author ) {
+ ui.$credit.empty().append( ui.$author );
+ }
+ }
+
+ ui.$credit.toggleClass( 'empty', !imageData.source &&
!imageData.author );
+
+ msgname = 'multimediaviewer-license-' + ( imageData.license ||
'' );
+
+ if ( !imageData.license || !mw.messages.exists( msgname ) ) {
// Cannot display, fallback or fail
- license = 'default';
msgname = 'multimediaviewer-license-default';
} else {
// License found, store the license data
ui.$license.data( 'license', mw.message( msgname
).text() );
}
- if ( license ) {
- ui.$license
- .text( mw.message( msgname ).text() )
- .toggleClass( 'cc-license', license.substr( 0,
2 ) === 'cc' );
- }
+ ui.$license
+ .text( mw.message( msgname ).text() )
+ .toggleClass( 'cc-license', imageData.isCcLicensed() );
- ui.$license.toggleClass( 'empty', !license );
+ ui.$license.toggleClass( 'empty', !imageData.license );
};
MMVP.loadImage = function ( image, initialSrc ) {
@@ -676,9 +654,9 @@
mdpid = this.profileStart( 'metadata-fetch' );
- this.fetchImageInfo( image.filePageTitle ).done( function (
imageInfo, res, size ) {
+ this.fetchImageInfo( image.filePageTitle ).done( function (
imageData, repoInfo, size, requestedWidth ) {
var pid,
- innerInfo = imageInfo.imageinfo[0],
+ repoData = mw.mmv.model.Repo.newFromRepoInfo(
repoInfo[imageData.repo] ),
imageEle = new Image(),
targetWidth = size;
@@ -698,16 +676,16 @@
viewer.profileEnd( mdpid );
pid = viewer.profileStart( 'image-load', {
- width: innerInfo.width,
- height: innerInfo.height,
- fileSize: innerInfo.size
- }, innerInfo.mime );
+ width: imageData.width,
+ height: imageData.height,
+ fileSize: imageData.size
+ }, imageData.mimeType );
- imageEle.src = imageInfo.imageinfo[0].thumburl ||
imageInfo.imageinfo[0].url;
+ imageEle.src = imageData.getThumbUrl( requestedWidth )
|| imageData.url;
viewer.lightbox.iface.$imageDiv.removeClass( 'empty' );
viewer.lightbox.iface.replaceImageWith( imageEle );
- viewer.setImageInfo( image.filePageTitle, imageInfo );
+ viewer.setImageInfo( image.filePageTitle, imageData,
repoData );
} );
comingFromPopstate = false;
@@ -729,9 +707,13 @@
* @method
* Fetches image information from the API.
*
- * Will resolve the promise with two objects (imageInfo and repoInfo)
and the
+ * Will resolve the promise with two objects (imageData and repoData),
the
* target width - basically the screen size - that the caller should
resize
- * the image to eventually.
+ * the image to eventually, and the requested width - that is, what we
asked
+ * for from the API - that should be used to fetch the thumbnail URL
from
+ * the imageData object.
+ *
+ * The target
* @param {mw.Title} fileTitle Title of the file page for the image.
* @param {string[]} [props] List of properties to get from imageinfo
* @returns {jQuery.Promise}
@@ -753,7 +735,7 @@
requestedWidth = widths.requested;
function handleApiData( data ) {
- var imageInfo;
+ var imageInfo, imageData;
if ( !data || !data.query ) {
// No information, oh well
@@ -761,17 +743,13 @@
}
viewer.cacheRepoInfo( data.query.repos );
- imageInfo = viewer.getImageInfo( data.query.pages );
+ imageInfo = viewer.getFirst( data.query.pages );
if ( imageInfo ) {
- if ( !imageInfo.imageinfo ||
- imageInfo.imageinfo.length ===
0 ) {
- // No data, fail.
- $.Deferred().reject();
- }
+ imageData =
mw.mmv.model.Image.newFromImageInfo( fileTitle, imageInfo );
// Give back the information we have
- return $.Deferred().resolve( imageInfo,
viewer.repoInfo, targetWidth );
+ return $.Deferred().resolve( imageData,
viewer.repoInfo, targetWidth, requestedWidth );
} else {
return $.Deferred().reject();
}
@@ -802,20 +780,25 @@
// Fetch the new thumb url but nothing else, because
it's
// the only non-cacheable thing
apiArgs.iiprop = 'url';
- return this.imageInfo[filename].then( function (
cachedInfo ) {
- return makeImageInfoRequest( apiArgs ).then(
function ( imageInfo, repoInfo, targetWidth ) {
- var innerInfo,
- newInfo = $.extend( true, {},
cachedInfo );
- $.each( imageInfo.imageinfo, function (
i, item ) {
- innerInfo = item;
- return false;
- } );
- $.each( newInfo.imageinfo, function (
i, item ) {
- item.thumburl =
innerInfo.thumburl;
- item.thumbwidth =
innerInfo.thumbwidth;
- item.thumbheight =
innerInfo.thumbheight;
- } );
- return $.Deferred().resolve( newInfo,
repoInfo, targetWidth );
+ return this.imageInfo[filename].then( function (
imageData, repoInfo ) {
+ var maybeThumb = imageData.getThumbUrl(
requestedWidth );
+
+ // Thumbnail caching! Woo!
+ if ( maybeThumb ) {
+ return $.Deferred().resolve( imageData,
repoInfo, targetWidth, requestedWidth );
+ }
+
+ return viewer.api.get( apiArgs ).then( function
( data ) {
+ var imageInfo, innerInfo;
+
+ imageInfo = viewer.getFirst(
data.query.pages );
+ innerInfo = viewer.getFirst(
imageInfo.imageinfo );
+
+ if ( innerInfo.thumburl ) {
+ imageData.addThumbUrl(
innerInfo.thumbwidth, innerInfo.thumburl );
+ }
+
+ return $.Deferred().resolve( imageData,
repoInfo, targetWidth, requestedWidth );
} );
} );
}
diff --git
a/resources/ext.multimediaViewer/ext.multimediaViewer.lightboxinterface.js
b/resources/ext.multimediaViewer/ext.multimediaViewer.lightboxinterface.js
index d0d3bcd..7e6cd6b 100644
--- a/resources/ext.multimediaViewer/ext.multimediaViewer.lightboxinterface.js
+++ b/resources/ext.multimediaViewer/ext.multimediaViewer.lightboxinterface.js
@@ -524,54 +524,43 @@
/**
* @method
* Sets the URL for the File: page of the image
- * @param {Object} repoInfo
- * @param {mw.Title} fileTitle
+ * @param {string} url
*/
- LIP.setFilePageLink = function ( repoInfo, fileTitle ) {
- var linkpath;
+ LIP.setFilePageLink = function ( url ) {
+ this.$repo.prop( 'href', url );
+ this.$license.prop( 'href', url );
+ };
- if ( repoInfo.descBaseUrl ) {
- linkpath = repoInfo.descBaseUrl +
fileTitle.getMainText();
- } else {
- if ( repoInfo.server && repoInfo.articlepath ) {
- linkpath = repoInfo.server +
repoInfo.articlepath;
- } else {
- linkpath = mw.config.get( 'wgArticlePath' );
- }
- linkpath = linkpath.replace( '$1',
fileTitle.getPrefixedText() );
- }
-
- if ( repoInfo.local ) {
- this.$useFile.data( 'isLocal', repoInfo.local );
- }
-
- if ( !/^(https?:)?\/\//.test( linkpath ) ) {
- this.$useFile.data( 'link', mw.config.get( 'wgServer' )
+ linkpath );
- } else {
- this.$useFile.data( 'link', linkpath );
- }
-
- this.$repo.prop( 'href', linkpath );
- this.$license.prop( 'href', linkpath );
+ /**
+ * @method
+ * Saves some data about the image on the $useFile element for later
setup.
+ * @param {mw.Title} title
+ * @param {string} src The URL for the full-size image
+ * @param {boolean} isLocal Whether the file is on this wiki or not
+ */
+ LIP.initUseFileData = function ( title, src, isLocal ) {
+ this.$useFile.data( 'title', title );
+ this.$useFile.data( 'src', src );
+ this.$useFile.data( 'isLocal', isLocal );
};
/**
* @method
* Sets the link to the user page where possible
- * @param {Object} repoInfo
+ * @param {mw.mmv.model.Repo} repoData
* @param {string} username
* @param {string} gender
*/
- LIP.setUserPageLink = function ( repoInfo, username, gender ) {
+ LIP.setUserPageLink = function ( repoData, username, gender ) {
var userlink,
userpage = 'User:' + username;
- if ( repoInfo.descBaseUrl ) {
+ if ( repoData instanceof mw.mmv.model.ForeignDbRepo ) {
// We basically can't do anything about this; fail
this.$username.addClass( 'empty' );
} else {
- if ( repoInfo.server && repoInfo.articlepath ) {
- userlink = repoInfo.server +
repoInfo.articlepath;
+ if ( repoData.absoluteArticlePath ) {
+ userlink = repoData.absoluteArticlePath;
} else {
userlink = mw.config.get( 'wgArticlePath' );
}
diff --git a/resources/ext.multimediaViewer/mmv.js
b/resources/ext.multimediaViewer/mmv.js
new file mode 100644
index 0000000..87f5930
--- /dev/null
+++ b/resources/ext.multimediaViewer/mmv.js
@@ -0,0 +1,22 @@
+/*
+ * 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/>.
+ */
+
+// This will just set up various objects for the main
+// MultimediaViewer load.
+( function ( mw ) {
+ mw.mmv = {};
+}( mediaWiki ) );
diff --git a/tests/qunit/ext.multimediaViewer.dataModel.test.js
b/tests/qunit/ext.multimediaViewer.dataModel.test.js
new file mode 100644
index 0000000..e290426
--- /dev/null
+++ b/tests/qunit/ext.multimediaViewer.dataModel.test.js
@@ -0,0 +1,60 @@
+/*
+ * 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 ) {
+ QUnit.module( 'ext.multimediaViewer.dataModel',
QUnit.newMwEnvironment() );
+
+ QUnit.test( 'Image model constructor sanity check', 16, function (
assert ) {
+ var
+ title = mw.Title.newFromText( 'File:Foobar.jpg' ),
+ size = 100,
+ width = 10,
+ height = 15,
+ mime = 'image/jpeg',
+ url =
'https://upload.wikimedia.org/wikipedia/commons/3/3a/Foobar.jpg',
+ descurl =
'https://commons.wikimedia.org/wiki/File:Foobar.jpg',
+ repo = 'wikimediacommons',
+ user = 'Kaldari',
+ datetime = '2011-07-04T23:31:14Z',
+ origdatetime = '2010-07-04T23:31:14Z',
+ description = 'This is a test file.',
+ source = 'WMF',
+ author = 'Ryan Kaldari',
+ license = 'cc0',
+ imageData = new mw.mmv.model.Image(
+ title, size, width, height, mime, url,
+ descurl, repo, user, datetime, origdatetime,
+ description, source, author, license );
+
+ assert.strictEqual( imageData.title, title, 'Title is set
correctly' );
+ assert.strictEqual( imageData.size, size, 'Size is set
correctly' );
+ assert.strictEqual( imageData.width, width, 'Width is set
correctly' );
+ assert.strictEqual( imageData.height, height, 'Height is set
correctly' );
+ assert.strictEqual( imageData.mimeType, mime, 'MIME type is set
correctly' );
+ assert.strictEqual( imageData.url, url, 'URL for original image
is set correctly' );
+ assert.strictEqual( imageData.descriptionUrl, descurl, 'URL for
image description page is set correctly' );
+ assert.strictEqual( imageData.repo, repo, 'Repository name is
set correctly' );
+ assert.strictEqual( imageData.lastUploader, user, 'Name of last
uploader is set correctly' );
+ assert.strictEqual( imageData.uploadDateTime, datetime, 'Date
and time of last upload is set correctly' );
+ assert.strictEqual( imageData.creationDateTime, origdatetime,
'Date and time of original upload is set correctly' );
+ assert.strictEqual( imageData.description, description,
'Description is set correctly' );
+ assert.strictEqual( imageData.source, source, 'Source is set
correctly' );
+ assert.strictEqual( imageData.author, author, 'Author is set
correctly' );
+ assert.strictEqual( imageData.license, license, 'License is set
correctly' );
+ assert.ok( imageData.thumbUrls, 'Thumb URL cache is set up
properly' );
+ } );
+}( mediaWiki ) );
diff --git a/tests/qunit/ext.multimediaViewer.lightboxinterface.test.js
b/tests/qunit/ext.multimediaViewer.lightboxinterface.test.js
index 3e87ed4..52e5a5e 100644
--- a/tests/qunit/ext.multimediaViewer.lightboxinterface.test.js
+++ b/tests/qunit/ext.multimediaViewer.lightboxinterface.test.js
@@ -123,21 +123,8 @@
assert.strictEqual( handlerCalls, 1, 'The handler was not
called after calling lightbox.clearEvents().' );
} );
- QUnit.test( 'Setting repository information in the UI works as
expected', 5, function ( assert ) {
- var lightbox = new mw.LightboxInterface(),
-
- localRepoInfo = {
- local: true
- },
-
- remoteDBRepoInfo = {
- descBaseUrl: 'http://example.com/wiki/File:'
- },
-
- remoteAPIRepoInfo = {
- server: 'http://commons.example.org',
- articlepath: '/wiki/$1'
- };
+ QUnit.test( 'Setting repository information in the UI works as
expected', 3, function ( assert ) {
+ var lightbox = new mw.LightboxInterface();
lightbox.setRepoDisplayName( 'Example Wiki' );
assert.strictEqual( lightbox.$repo.text(), 'Learn more on
Example Wiki', 'Text set to something useful for remote wiki - if this fails it
might be because of localisation' );
@@ -145,13 +132,7 @@
lightbox.setRepoDisplayName();
assert.strictEqual( lightbox.$repo.text(), 'Learn more on ' +
mw.config.get( 'wgSiteName' ), 'Text set to something useful for local wiki -
if this fails it might be because of localisation' );
- lightbox.setFilePageLink( localRepoInfo, mw.Title.newFromText(
'File:Foobar.jpg' ) );
- assert.strictEqual( lightbox.$repo.prop( 'href' ),
mw.config.get( 'wgServer' ) + mw.config.get( 'wgArticlePath' ).replace( '$1',
'File:Foobar.jpg' ), 'The file link was set to a local page successfully.' );
-
- lightbox.setFilePageLink( remoteDBRepoInfo,
mw.Title.newFromText( 'File:Foobar.jpg' ) );
- assert.strictEqual( lightbox.$repo.prop( 'href' ),
'http://example.com/wiki/File:Foobar.jpg', 'The file link was set to a remote
shared DB page successfully.' );
-
- lightbox.setFilePageLink( remoteAPIRepoInfo,
mw.Title.newFromText( 'File:Foobar.jpg' ) );
- assert.strictEqual( lightbox.$repo.prop( 'href' ),
'http://commons.example.org/wiki/File:Foobar.jpg', 'The file link was set to a
remote API page successfully.' );
+ lightbox.setFilePageLink(
'https://commons.wikimedia.org/wiki/File:Foobar.jpg' );
+ assert.strictEqual( lightbox.$repo.prop( 'href' ),
'https://commons.wikimedia.org/wiki/File:Foobar.jpg', 'The file link was set
successfully.' );
} );
}( mediaWiki, jQuery ) );
--
To view, visit https://gerrit.wikimedia.org/r/106846
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ife8293c86683ea914b1a5a60000584b501d92e55
Gerrit-PatchSet: 6
Gerrit-Project: mediawiki/extensions/MultimediaViewer
Gerrit-Branch: master
Gerrit-Owner: MarkTraceur <[email protected]>
Gerrit-Reviewer: Gergő Tisza <[email protected]>
Gerrit-Reviewer: MarkTraceur <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits