Merge "Use image sources from the fileRepo API"

This commit is contained in:
jenkins-bot 2014-01-05 05:47:17 +00:00 committed by Gerrit Code Review
commit 6e21afb908
3 changed files with 142 additions and 58 deletions

View file

@ -23,11 +23,6 @@ ve.init.mw.Platform = function VeInitMwPlatform() {
this.externalLinkUrlProtocolsRegExp = new RegExp( '^' + mw.config.get( 'wgUrlProtocols' ) );
this.modulesUrl = mw.config.get( 'wgExtensionAssetsPath' ) + '/VisualEditor/modules';
this.parsedMessages = {};
this.mediaSources = [
//TODO: Bug 50673
{ 'url': mw.util.wikiScript( 'api' ) },
{ 'url': '//commons.wikimedia.org/w/api.php' }
];
};
/* Inheritance */
@ -92,16 +87,6 @@ ve.init.mw.Platform.prototype.getUserLanguages = function () {
return langs;
};
/**
* Get a list of URLs to MediaWiki API entry points where media can be found.
*
* @method
* @returns {string[]} API URLs
*/
ve.init.mw.Platform.prototype.getMediaSources = function () {
return this.mediaSources;
};
/* Initialization */
ve.init.platform = new ve.init.mw.Platform();

View file

@ -5,6 +5,8 @@
* @license The MIT License (MIT); see LICENSE.txt
*/
/*global mw */
/**
* Dialog for inserting MediaWiki media objects.
*
@ -24,6 +26,7 @@ ve.ui.MWMediaInsertDialog = function VeUiMWMediaInsertDialog( windowSet, config
// Properties
this.item = null;
this.sources = {};
};
/* Inheritance */
@ -59,15 +62,21 @@ ve.ui.MWMediaInsertDialog.prototype.initialize = function () {
// Parent method
ve.ui.MWDialog.prototype.initialize.call( this );
// Properties
this.search = new ve.ui.MWMediaSearchWidget( { '$': this.$ } );
// Widget
this.search = new ve.ui.MWMediaSearchWidget( {
'$': this.$
} );
// Initialization
this.search.$element.addClass( 've-ui-mwMediaInsertDialog-select' );
// Events
this.search.connect( this, { 'select': 'onSearchSelect' } );
// Initialization
this.search.$element.addClass( 've-ui-mwMediaInsertDialog-select' );
this.$spinner = this.$( '<div>' ).addClass( 've-specialchar-spinner' );
this.$body.append( this.$spinner );
this.$body.append( this.search.$element );
};
/**
@ -77,10 +86,82 @@ ve.ui.MWMediaInsertDialog.prototype.setup = function ( data ) {
// Parent method
ve.ui.MWDialog.prototype.setup.call( this, data );
// Initialization
this.search.getQuery().$input.focus().select();
this.search.getResults().selectItem();
this.search.getResults().highlightItem();
// Show a spinner while we check for file repos.
// this will only be done once per session.
//
// This is in .setup rather than .initialize so that
// the user has visual indication (spinner) during the
// ajax request
this.$spinner.show();
this.search.$element.hide();
// Get the repos from the API first
// The ajax request will only be done once per session
this.getFileRepos().done( ve.bind( function ( repos ) {
if ( repos ) {
this.sources = repos;
this.search.setSources( this.sources );
}
// Done, hide the spinner
this.$spinner.hide();
// Show the search and query the media sources
this.search.$element.show();
this.search.queryMediaSources();
// Initialization
// This must be done only after there are proper
// sources defined
this.search.getQuery().$input.focus().select();
this.search.getResults().selectItem();
this.search.getResults().highlightItem();
}, this ) );
};
/**
* Get the object of file repos to use for the media search
* @returns {jQuery.Promise}
*/
ve.ui.MWMediaInsertDialog.prototype.getFileRepos = function () {
var deferred = $.Deferred();
// We will only ask for the ajax call if this.sources
// isn't already set up
if ( $.isEmptyObject( this.sources ) ) {
// Take sources from api.php?action=query&meta=filerepoinfo&format=jsonfm
// The decision whether to take 'url' or 'apiurl' per each repository is made
// in the MWMediaSearchWidget depending on whether it is local and has apiurl
// defined at all.
$.ajax( {
'url': mw.util.wikiScript( 'api' ),
'data': {
'action': 'query',
'meta': 'filerepoinfo',
'format': 'json'
},
'dataType': 'json',
'type': 'POST',
// Wait up to 100 seconds before giving up
'timeout': 100000,
'cache': false
} )
.done( function ( resp ) {
deferred.resolve( resp.query.repos );
} )
.fail( function () {
deferred.resolve( [ {
'url': mw.util.wikiScript( 'api' ),
'local': true }
] );
} );
} else {
// There was no need to ask for the resources again
// return false so we can skip setting the sources
deferred.resolve( false );
}
return deferred.promise();
};
/**

View file

@ -28,7 +28,7 @@ ve.ui.MWMediaSearchWidget = function VeUiMWMediaSearchWidget( config ) {
OO.ui.SearchWidget.call( this, config );
// Properties
this.sources = ve.copy( ve.init.platform.getMediaSources() );
this.sources = {};
this.size = config.size || 150;
this.queryTimeout = null;
this.titles = {};
@ -39,7 +39,6 @@ ve.ui.MWMediaSearchWidget = function VeUiMWMediaSearchWidget( config ) {
// Initialization
this.$element.addClass( 've-ui-mwMediaSearchWidget' );
this.queryMediaSources();
};
/* Inheritance */
@ -48,6 +47,14 @@ OO.inheritClass( ve.ui.MWMediaSearchWidget, OO.ui.SearchWidget );
/* Methods */
/**
* Set the fileRepo sources for the media search
* @param {Object} sources The sources object
*/
ve.ui.MWMediaSearchWidget.prototype.setSources = function ( sources ) {
this.sources = sources;
};
/**
* Handle select widget select events.
*
@ -89,7 +96,7 @@ ve.ui.MWMediaSearchWidget.prototype.onResultsScroll = function () {
* @method
*/
ve.ui.MWMediaSearchWidget.prototype.queryMediaSources = function () {
var i, len, source,
var i, len, source, url,
value = this.query.getValue();
if ( value === '' ) {
@ -98,39 +105,50 @@ ve.ui.MWMediaSearchWidget.prototype.queryMediaSources = function () {
for ( i = 0, len = this.sources.length; i < len; i++ ) {
source = this.sources[i];
if ( source.request ) {
source.request.abort();
// If we don't have either 'apiurl' or 'scriptDirUrl'
// the source is invalid, and we will skip it
if ( source.apiurl || source.scriptDirUrl ) {
if ( source.request ) {
source.request.abort();
}
if ( !source.gsroffset ) {
source.gsroffset = 0;
}
if ( source.local ) {
url = mw.util.wikiScript( 'api' );
} else {
// If 'apiurl' is set, use that. Otherwise, build the url
// from scriptDirUrl and /api.php suffix
url = source.apiurl || ( source.scriptDirUrl + '/api.php' );
}
this.query.pushPending();
source.request = $.ajax( {
'url': url,
'data': {
'format': 'json',
'action': 'query',
'generator': 'search',
'gsrsearch': value,
'gsrnamespace': 6,
'gsrlimit': 15,
'gsroffset': source.gsroffset,
'prop': 'imageinfo',
'iiprop': 'dimensions|url',
'iiurlheight': this.size
},
// This request won't be cached since the JSON-P callback is unique. However make sure
// to allow jQuery to cache otherwise so it won't e.g. add "&_=(random)" which will
// trigger a MediaWiki API error for invalid parameter "_".
'cache': true,
// TODO: Only use JSON-P for cross-domain.
// jQuery has this logic built-in (if url is not same-origin ..)
// but isn't working for some reason.
'dataType': 'jsonp'
} )
.done( ve.bind( this.onMediaQueryDone, this, source ) )
.always( ve.bind( this.onMediaQueryAlways, this, source ) );
source.value = value;
}
if ( !source.gsroffset ) {
source.gsroffset = 0;
}
this.query.pushPending();
source.request = $.ajax( {
'url': source.url,
'data': {
'format': 'json',
'action': 'query',
'generator': 'search',
'gsrsearch': value,
'gsrnamespace': 6,
'gsrlimit': 15,
'gsroffset': source.gsroffset,
'prop': 'imageinfo',
'iiprop': 'dimensions|url',
'iiurlheight': this.size
},
// This request won't be cached since the JSON-P callback is unique. However make sure
// to allow jQuery to cache otherwise so it won't e.g. add "&_=(random)" which will
// trigger a MediaWiki API error for invalid parameter "_".
'cache': true,
// TODO: Only use JSON-P for cross-domain.
// jQuery has this logic built-in (if url is not same-origin ..)
// but isn't working for some reason.
'dataType': 'jsonp'
} )
.done( ve.bind( this.onMediaQueryDone, this, source ) )
.always( ve.bind( this.onMediaQueryAlways, this, source ) );
source.value = value;
}
};