mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-09-26 19:56:49 +00:00
Merge "Refactor MWMediaSearchWidget to use a queue and providers"
This commit is contained in:
commit
ac9f81cd2c
|
@ -14,6 +14,12 @@
|
|||
"classes": [
|
||||
"ve.ui.MW*Page"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data Model",
|
||||
"classes": [
|
||||
"ve.dm.MWMediaResource*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
"classes": [
|
||||
"ve.ui.MW*Page"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data Model",
|
||||
"classes": [
|
||||
"ve.dm.MWMediaResource*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -982,6 +982,8 @@ $wgResourceModules += array(
|
|||
'ext.visualEditor.mwimage' => $wgVisualEditorResourceTemplate + array(
|
||||
'scripts' => array(
|
||||
'modules/ve-mw/dm/models/ve.dm.MWImageModel.js',
|
||||
'modules/ve-mw/dm/models/ve.dm.MWMediaResourceProvider.js',
|
||||
'modules/ve-mw/dm/models/ve.dm.MWMediaResourceQueue.js',
|
||||
|
||||
'modules/ve-mw/ui/widgets/ve.ui.MWMediaSearchWidget.js',
|
||||
'modules/ve-mw/ui/widgets/ve.ui.MWMediaResultWidget.js',
|
||||
|
|
|
@ -963,6 +963,8 @@
|
|||
"remoteExtPath": "VisualEditor",
|
||||
"scripts": [
|
||||
"modules/ve-mw/dm/models/ve.dm.MWImageModel.js",
|
||||
"modules/ve-mw/dm/models/ve.dm.MWMediaResourceProvider.js",
|
||||
"modules/ve-mw/dm/models/ve.dm.MWMediaResourceQueue.js",
|
||||
"modules/ve-mw/ui/widgets/ve.ui.MWMediaSearchWidget.js",
|
||||
"modules/ve-mw/ui/widgets/ve.ui.MWMediaResultWidget.js",
|
||||
"modules/ve-mw/ui/widgets/ve.ui.MWMediaInfoFieldWidget.js",
|
||||
|
|
509
modules/ve-mw/dm/models/ve.dm.MWMediaResourceProvider.js
Normal file
509
modules/ve-mw/dm/models/ve.dm.MWMediaResourceProvider.js
Normal file
|
@ -0,0 +1,509 @@
|
|||
/*!
|
||||
* VisualEditor DataModel MWMediaResourceProvider class.
|
||||
*
|
||||
* @copyright 2011-2015 VisualEditor Team and others; see AUTHORS.txt
|
||||
* @license The MIT License (MIT); see LICENSE.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
* MediaWiki media resource provider.
|
||||
*
|
||||
* @class
|
||||
* @mixins OO.EventEmitter
|
||||
*
|
||||
* @constructor
|
||||
* @param {Object} [config] Configuration options
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider = function VeDmMWMediaResourceProvider( config ) {
|
||||
config = config || {};
|
||||
|
||||
// Source Configuration
|
||||
this.apiurl = this.setAPIurl( config.apiurl );
|
||||
this.name = config.name;
|
||||
this.displayName = config.displayName;
|
||||
this.local = config.local;
|
||||
this.scriptDirUrl = config.scriptDirUrl;
|
||||
|
||||
// ajaxOptions configuration
|
||||
this.dataType = config.dataType || 'jsonp';
|
||||
this.cached = config.cached || true;
|
||||
|
||||
// Fetching configuration
|
||||
this.fetchLimit = config.limit || 30;
|
||||
this.iiprop = config.iiprop || [ 'dimensions', 'url', 'mediatype', 'extmetadata', 'timestamp' ];
|
||||
this.fetchProp = config.fetchProp || 'imageinfo';
|
||||
this.lang = config.lang || 'en';
|
||||
|
||||
this.siteInfoPromise = null;
|
||||
this.thumbSizes = [];
|
||||
this.imageSizes = [];
|
||||
|
||||
this.depleted = false;
|
||||
this.offset = config.offset || 0;
|
||||
this.setQuery( config.query || '' );
|
||||
|
||||
// Mixin constructors
|
||||
OO.EventEmitter.call( this );
|
||||
};
|
||||
|
||||
/* Setup */
|
||||
OO.initClass( ve.dm.MWMediaResourceProvider );
|
||||
OO.mixinClass( ve.dm.MWMediaResourceProvider, OO.EventEmitter );
|
||||
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
* Initialize the source and get the site info.
|
||||
*
|
||||
* Connect to the api url and retrieve the siteinfo parameters
|
||||
* that are required for fetching results.
|
||||
*
|
||||
* @return {jQuery.Promise} Promise that resolves when the class
|
||||
* properties are set.
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.loadSiteInfo = function () {
|
||||
var provider = this;
|
||||
|
||||
if ( !this.siteInfoPromise ) {
|
||||
this.siteInfoPromise = ve.init.target.constructor.static.apiRequest( {
|
||||
action: 'query',
|
||||
meta: 'siteinfo'
|
||||
} )
|
||||
.then( function ( data ) {
|
||||
if ( data.error ) {
|
||||
return $.Deferred().reject();
|
||||
}
|
||||
provider.setImageSizes( ve.getProp( data, 'query', 'general', 'imagelimits' ) || [] );
|
||||
provider.setThumbSizes( ve.getProp( data, 'query', 'general', 'thumblimits' ) || [] );
|
||||
} );
|
||||
}
|
||||
return this.siteInfoPromise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get results from the source
|
||||
*
|
||||
* @return {jQuery.Promise} Promise that is resolved into an array
|
||||
* of available results, or is rejected if no results are available.
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getResults = function ( howMany ) {
|
||||
var xhr,
|
||||
aborted = false,
|
||||
provider = this;
|
||||
|
||||
return this.loadSiteInfo()
|
||||
.then( function () {
|
||||
if ( aborted ) {
|
||||
return $.Deferred().reject();
|
||||
}
|
||||
xhr = provider.fetchAPIresults( howMany );
|
||||
return xhr;
|
||||
} )
|
||||
.then(
|
||||
function ( results ) {
|
||||
if ( results.length === 0 ) {
|
||||
provider.toggleDepleted( true );
|
||||
}
|
||||
return results;
|
||||
},
|
||||
// Process failed, return an empty promise
|
||||
function () {
|
||||
provider.toggleDepleted( true );
|
||||
return $.Deferred().resolve( [] );
|
||||
}
|
||||
)
|
||||
.promise( { abort: function () {
|
||||
aborted = true;
|
||||
if ( xhr ) {
|
||||
xhr.abort();
|
||||
}
|
||||
} } );
|
||||
};
|
||||
|
||||
/**
|
||||
* Call the API for search results.
|
||||
*
|
||||
* @param {number} howMany The number of results to retrieve
|
||||
* @return {jQuery.Promise} Promise that resolves with an array of objects that contain
|
||||
* the fetched data.
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.fetchAPIresults = function ( howMany ) {
|
||||
var xhr,
|
||||
ajaxOptions = {},
|
||||
query = this.getQuery(),
|
||||
provider = this,
|
||||
apiCallConfig = {
|
||||
action: 'query',
|
||||
generator: 'search',
|
||||
gsrsearch: query,
|
||||
gsrnamespace: 6,
|
||||
continue: '',
|
||||
gsroffset: this.getOffset(),
|
||||
prop: this.getFetchProp(),
|
||||
// Language of the extmetadata details
|
||||
iiextmetadatalanguage: this.getLang(),
|
||||
iiprop: this.getIiProp().join( '|' ),
|
||||
iiurlheight: this.getMaxHeight(),
|
||||
// Standard width per resource
|
||||
iiurlwidth: this.getStandardWidth()
|
||||
};
|
||||
|
||||
howMany = howMany || 20;
|
||||
// Initial number of images
|
||||
apiCallConfig.gsrlimit = howMany;
|
||||
|
||||
if ( this.isValid() ) {
|
||||
if ( this.isLocal() ) {
|
||||
ajaxOptions = {
|
||||
url: mw.util.wikiScript( 'api' ),
|
||||
// If the url is local use json
|
||||
dataType: 'json'
|
||||
};
|
||||
} else {
|
||||
ajaxOptions = {
|
||||
// If 'apiurl' is set, use that. Otherwise, build the url
|
||||
// from scriptDirUrl and /api.php suffix
|
||||
url: this.apiurl || ( this.scriptDirUrl + '/api.php' ),
|
||||
// If the url is not the same origin use jsonp
|
||||
dataType: 'jsonp',
|
||||
// JSON-P requests are not cached by default and get a &_=random trail.
|
||||
// While setting cache=true will still bypass cache in most case due to the
|
||||
// callback parameter, at least drop the &_=random trail which triggers
|
||||
// an API warning (invalid parameter).
|
||||
cache: true
|
||||
};
|
||||
}
|
||||
|
||||
xhr = ve.init.target.constructor.static.apiRequest( apiCallConfig, ajaxOptions );
|
||||
return xhr
|
||||
.then( function ( data ) {
|
||||
var page, newObj,
|
||||
results = [],
|
||||
raw = ve.getProp( data, 'query', 'pages' );
|
||||
if ( data[ 'continue' ] ) {
|
||||
// Update the offset for next time
|
||||
provider.setOffset( data[ 'continue' ].gsroffset );
|
||||
} else {
|
||||
// This is the last available set of result. Mark as depleted!
|
||||
provider.toggleDepleted( true );
|
||||
}
|
||||
if ( raw ) {
|
||||
// Strip away the page ids
|
||||
for ( page in raw ) {
|
||||
newObj = raw[page].imageinfo[0];
|
||||
newObj.title = raw[page].title;
|
||||
results.push( newObj );
|
||||
}
|
||||
}
|
||||
return results;
|
||||
} )
|
||||
.promise( { abort: xhr.abort } );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get search query
|
||||
*
|
||||
* @return {string} search query
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getQuery = function () {
|
||||
return this.query;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set search query
|
||||
*
|
||||
* @param {string} value
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setQuery = function ( value ) {
|
||||
if ( this.query !== value ) {
|
||||
this.query = value;
|
||||
// Reset offset
|
||||
this.setOffset( 0 );
|
||||
// Reset depleted status
|
||||
this.toggleDepleted( false );
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Set api url
|
||||
*
|
||||
* @param {string} API url
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setAPIurl = function ( url ) {
|
||||
this.apiurl = url;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set api url
|
||||
*
|
||||
* @return {string} API url
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getAPIurl = function () {
|
||||
return this.apiurl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set name
|
||||
*
|
||||
* @param {string} name
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setName = function ( name ) {
|
||||
this.name = name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get name
|
||||
*
|
||||
* @returns {string} name
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getName = function () {
|
||||
return this.name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get displayName
|
||||
*
|
||||
* @return {string} displayName
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getDisplayName = function () {
|
||||
return this.displayName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set displayName
|
||||
*
|
||||
* @param {string} displayName
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setDisplayName = function ( displayName ) {
|
||||
this.displayName = displayName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get isLocal value
|
||||
*
|
||||
* @return {boolean} isLocal value
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.isLocal = function () {
|
||||
return this.local;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get ScriptDirUrl
|
||||
*
|
||||
* @return {string} ScriptDirUrl
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getScriptDirUrl = function () {
|
||||
return this.scriptDirUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set scriptDirUrl
|
||||
*
|
||||
* @param {string} scriptDirUrl
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setScriptDirUrl = function ( scriptDirUrl ) {
|
||||
this.scriptDirUrl = scriptDirUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get dataType
|
||||
*
|
||||
* @return {string} dataType
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getDataType = function () {
|
||||
return this.dataType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set dataType
|
||||
*
|
||||
* @param {string} dataType
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setDataType = function ( dataType ) {
|
||||
this.dataType = dataType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get cached
|
||||
*
|
||||
* @return {boolean} cached
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.isCached = function () {
|
||||
return this.cached;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get fetch limit or 'page' size. This is the number
|
||||
* of results per request.
|
||||
*
|
||||
* @return {number} limit
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getFetchLimit = function () {
|
||||
return this.limit;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set limit
|
||||
*
|
||||
* @param {number} limit
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setFetchLimit = function ( limit ) {
|
||||
this.limit = limit;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get properties
|
||||
*
|
||||
* @return {string[]} properties
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getIiProp = function () {
|
||||
return this.iiprop;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get max height
|
||||
*
|
||||
* @return {number|undefined} Maximum height
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getMaxHeight = function () {
|
||||
return this.maxHeight;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set maximum height
|
||||
*
|
||||
* @param {number} Maximum height
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setMaxHeight = function ( maxHeight ) {
|
||||
this.maxHeight = maxHeight;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get standard width, based on the provider source's thumb sizes.
|
||||
*
|
||||
* @return {number|undefined} fetchWidth
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getStandardWidth = function () {
|
||||
return this.thumbSizes && this.thumbSizes[ this.thumbSizes.length - 1 ];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get prop
|
||||
*
|
||||
* @return {string} prop
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getFetchProp = function () {
|
||||
return this.fetchProp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set prop
|
||||
*
|
||||
* @param {string} prop
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setFetchProp = function ( prop ) {
|
||||
this.fetchProp = prop;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get lang
|
||||
*
|
||||
* @return {string} lang
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getLang = function () {
|
||||
return this.lang;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set lang
|
||||
*
|
||||
* @param {string} lang
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setLang = function ( lang ) {
|
||||
this.lang = lang;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Offset
|
||||
*
|
||||
* @return {number} Offset
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getOffset = function () {
|
||||
return this.offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set Offset
|
||||
*
|
||||
* @param {number} Offset
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setOffset = function ( offset ) {
|
||||
this.offset = offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set thumb sizes
|
||||
*
|
||||
* @param {number[]} sizes Available thumbnail sizes
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setThumbSizes = function ( sizes ) {
|
||||
this.thumbSizes = sizes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set image sizes
|
||||
*
|
||||
* @param {number[]} sizes Available image sizes
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.setImageSizes = function ( sizes ) {
|
||||
this.imageSizes = sizes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get thumb sizes
|
||||
*
|
||||
* @returns {number[]} sizes Available thumbnail sizes
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getThumbSizes = function () {
|
||||
return this.thumbSizes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get image sizes
|
||||
*
|
||||
* @returns {number[]} sizes Available image sizes
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.getImageSizes = function () {
|
||||
return this.imageSizes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether the provider is depleted
|
||||
*
|
||||
* @return {boolean} depleted
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.isDepleted = function () {
|
||||
return this.depleted;
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle depleted state
|
||||
*
|
||||
* @param {boolean} depleted
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.toggleDepleted = function ( isDepleted ) {
|
||||
this.depleted = isDepleted !== undefined ? isDepleted : !this.depleted;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this source is valid and ready for search.
|
||||
* @return {boolean} Source is valid
|
||||
*/
|
||||
ve.dm.MWMediaResourceProvider.prototype.isValid = function () {
|
||||
return this.getQuery() &&
|
||||
(
|
||||
// If we don't have either 'apiurl' or 'scriptDirUrl'
|
||||
// the source is invalid, and we will skip it
|
||||
this.apiurl || this.scriptDirUrl !== undefined
|
||||
);
|
||||
};
|
174
modules/ve-mw/dm/models/ve.dm.MWMediaResourceQueue.js
Normal file
174
modules/ve-mw/dm/models/ve.dm.MWMediaResourceQueue.js
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*!
|
||||
* VisualEditor DataModel MWMediaResourceQueue class.
|
||||
*
|
||||
* @copyright 2011-2015 VisualEditor Team and others; see AUTHORS.txt
|
||||
* @license The MIT License (MIT); see LICENSE.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
* MediaWiki media resource queue.
|
||||
*
|
||||
* @class
|
||||
* @mixins OO.EventEmitter
|
||||
*
|
||||
* @constructor
|
||||
* @param {Object} [config] Configuration options
|
||||
*/
|
||||
ve.dm.MWMediaResourceQueue = function VeDmMWMediaResourceQueue( config ) {
|
||||
config = config || {};
|
||||
|
||||
this.fileRepoPromise = null;
|
||||
this.providers = [];
|
||||
this.providerPromises = [];
|
||||
|
||||
this.queue = [];
|
||||
|
||||
this.limit = config.limit || 20;
|
||||
this.threshhold = config.threshhold || 10;
|
||||
|
||||
// Mixin constructors
|
||||
OO.EventEmitter.call( this );
|
||||
};
|
||||
|
||||
/* Setup */
|
||||
OO.initClass( ve.dm.MWMediaResourceQueue );
|
||||
OO.mixinClass( ve.dm.MWMediaResourceQueue, OO.EventEmitter );
|
||||
|
||||
/**
|
||||
* Get items from the queue
|
||||
*
|
||||
* @param {number} [howMany] How many items to retrieve
|
||||
* @return {jQuery.Promise} Promise that resolves into an array of items
|
||||
*/
|
||||
ve.dm.MWMediaResourceQueue.prototype.get = function ( howMany ) {
|
||||
var me = this,
|
||||
prepared = [];
|
||||
|
||||
howMany = howMany || this.limit;
|
||||
|
||||
// Check if the queue has enough items
|
||||
if ( this.queue.length < howMany + this.threshhold ) {
|
||||
// Call for more results
|
||||
prepared.push(
|
||||
this.getResults( howMany + this.threshhold )
|
||||
.then( function ( items ) {
|
||||
// Add to the queue
|
||||
me.queue = me.queue.concat.apply( me.queue, items );
|
||||
} )
|
||||
);
|
||||
}
|
||||
|
||||
return $.when.apply( $, prepared )
|
||||
.then( function () {
|
||||
return me.queue.splice( 0, howMany );
|
||||
} );
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Get results from all providers
|
||||
* @return {jQuery.Promise} Promise that is resolved into an array of fetched items.
|
||||
*/
|
||||
ve.dm.MWMediaResourceQueue.prototype.getResults = function ( howMany ) {
|
||||
var i, len,
|
||||
queue = this;
|
||||
|
||||
// Make sure there are resources set up
|
||||
return this.setup()
|
||||
.then( function () {
|
||||
queue.providerPromises = [];
|
||||
// Set up the query to all providers
|
||||
for ( i = 0, len = queue.providers.length; i < len; i++ ) {
|
||||
queue.providers[i].setQuery( queue.getQuery() );
|
||||
if ( !queue.providers[i].isDepleted() ) {
|
||||
queue.providerPromises.push(
|
||||
queue.providers[i].getResults( howMany )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $.when.apply( $, queue.providerPromises )
|
||||
.then( Array.prototype.concat.bind( [] ) );
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* Set up the queue and its resources
|
||||
*
|
||||
* @return {jQuery.Promise} Promise that resolves when the resources are set up
|
||||
*/
|
||||
ve.dm.MWMediaResourceQueue.prototype.setup = function () {
|
||||
var i, len,
|
||||
queue = this;
|
||||
|
||||
return this.getFileRepos().then( function ( sources ) {
|
||||
if ( queue.providers.length === 0 ) {
|
||||
// Set up the providers
|
||||
for ( i = 0, len = sources.length; i < len; i++ ) {
|
||||
queue.providers.push( new ve.dm.MWMediaResourceProvider( {
|
||||
apiurl: sources[i].apiurl,
|
||||
name: sources[i].name,
|
||||
local: sources[i].local,
|
||||
scriptDirUrl: sources[i].scriptDirUrl
|
||||
} ) );
|
||||
}
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch the file repos.
|
||||
*
|
||||
* @return {jQuery.Promise} Promise that resolves when the resources are set up
|
||||
*/
|
||||
ve.dm.MWMediaResourceQueue.prototype.getFileRepos = function () {
|
||||
var defaultSource = [ {
|
||||
url: mw.util.wikiScript( 'api' ),
|
||||
local: true
|
||||
} ];
|
||||
|
||||
if ( !this.fileRepoPromise ) {
|
||||
this.fileRepoPromise = ve.init.target.constructor.static.apiRequest( {
|
||||
action: 'query',
|
||||
meta: 'filerepoinfo'
|
||||
} ).then(
|
||||
function ( resp ) {
|
||||
return resp.query && resp.query.repos || defaultSource;
|
||||
},
|
||||
function () {
|
||||
return $.Deferred().resolve( defaultSource );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return this.fileRepoPromise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the search query for all the providers.
|
||||
*
|
||||
* This also makes sure to abort any previous promises.
|
||||
*
|
||||
* @param {string} query Search query
|
||||
*/
|
||||
ve.dm.MWMediaResourceQueue.prototype.setQuery = function ( query ) {
|
||||
var i, len;
|
||||
if ( query !== this.query ) {
|
||||
this.query = query;
|
||||
// Reset queue
|
||||
this.queue = [];
|
||||
// Reset promises
|
||||
for ( i = 0, len = this.providerPromises.length; i < len; i++ ) {
|
||||
this.providerPromises[i].abort();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current search query.
|
||||
*
|
||||
* @param {string} query Search query
|
||||
*/
|
||||
ve.dm.MWMediaResourceQueue.prototype.getQuery = function () {
|
||||
return this.query;
|
||||
};
|
|
@ -410,15 +410,14 @@ ve.ui.MWMediaDialog.prototype.initialize = function () {
|
|||
* Note: Some information in the metadata object needs to be safely
|
||||
* stripped from its html wrappers.
|
||||
*
|
||||
* @param {Object} info Image info
|
||||
* @param {Object} imageinfo Image info
|
||||
*/
|
||||
ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( info ) {
|
||||
ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( imageinfo ) {
|
||||
var i, newDimensions, field, isPortrait, $info, $section, windowWidth,
|
||||
contentDirection = this.getFragment().getDocument().getDir(),
|
||||
imageinfo = info.imageinfo[0],
|
||||
imageTitle = new OO.ui.LabelWidget( {
|
||||
$: this.$,
|
||||
label: new mw.Title( info.title ).getNameText()
|
||||
label: new mw.Title( imageinfo.title ).getNameText()
|
||||
} ),
|
||||
metadata = imageinfo.extmetadata,
|
||||
// Field configuration (in order)
|
||||
|
@ -620,7 +619,7 @@ ve.ui.MWMediaDialog.prototype.buildMediaInfoPanel = function ( info ) {
|
|||
} );
|
||||
|
||||
// Call for a bigger image
|
||||
this.fetchThumbnail( info.title, newDimensions )
|
||||
this.fetchThumbnail( imageinfo.title, newDimensions )
|
||||
.done( function ( thumburl ) {
|
||||
if ( thumburl ) {
|
||||
$image.prop( 'src', thumburl );
|
||||
|
@ -779,21 +778,18 @@ ve.ui.MWMediaDialog.prototype.onSearchChoose = function ( info ) {
|
|||
* @param {ve.ui.MWMediaResultWidget|null} item Selected item
|
||||
*/
|
||||
ve.ui.MWMediaDialog.prototype.confirmSelectedImage = function () {
|
||||
var info,
|
||||
obj = {},
|
||||
item = this.selectedImageInfo;
|
||||
|
||||
if ( item ) {
|
||||
info = item.imageinfo[0];
|
||||
var obj = {},
|
||||
info = this.selectedImageInfo;
|
||||
|
||||
if ( info ) {
|
||||
if ( !this.imageModel ) {
|
||||
// Create a new image model based on default attributes
|
||||
this.imageModel = ve.dm.MWImageModel.static.newFromImageAttributes(
|
||||
{
|
||||
// Per https://www.mediawiki.org/w/?diff=931265&oldid=prev
|
||||
href: './' + item.title,
|
||||
href: './' + info.title,
|
||||
src: info.url,
|
||||
resource: './' + item.title,
|
||||
resource: './' + info.title,
|
||||
width: info.thumbwidth,
|
||||
height: info.thumbheight,
|
||||
mediaType: info.mediatype,
|
||||
|
@ -811,9 +807,9 @@ ve.ui.MWMediaDialog.prototype.confirmSelectedImage = function () {
|
|||
this.imageModel.changeImageSource(
|
||||
{
|
||||
mediaType: info.mediatype,
|
||||
href: './' + item.title,
|
||||
href: './' + info.title,
|
||||
src: info.url,
|
||||
resource: './' + item.title
|
||||
resource: './' + info.title
|
||||
},
|
||||
info
|
||||
);
|
||||
|
@ -824,7 +820,7 @@ ve.ui.MWMediaDialog.prototype.confirmSelectedImage = function () {
|
|||
}
|
||||
|
||||
// Cache
|
||||
obj[ item.title ] = info;
|
||||
obj[ info.title ] = info;
|
||||
ve.init.platform.imageInfoCache.set( obj );
|
||||
|
||||
this.checkChanged();
|
||||
|
@ -988,34 +984,6 @@ ve.ui.MWMediaDialog.prototype.checkChanged = function () {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the object of file repos to use for the media search
|
||||
*
|
||||
* @returns {jQuery.Promise}
|
||||
*/
|
||||
ve.ui.MWMediaDialog.prototype.getFileRepos = function () {
|
||||
var defaultSource = [ {
|
||||
url: mw.util.wikiScript( 'api' ),
|
||||
local: true
|
||||
} ];
|
||||
|
||||
if ( !this.fileRepoPromise ) {
|
||||
this.fileRepoPromise = ve.init.target.constructor.static.apiRequest( {
|
||||
action: 'query',
|
||||
meta: 'filerepoinfo'
|
||||
} ).then(
|
||||
function ( resp ) {
|
||||
return resp.query && resp.query.repos || defaultSource;
|
||||
},
|
||||
function () {
|
||||
return $.Deferred().resolve( defaultSource );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return this.fileRepoPromise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
@ -1093,31 +1061,8 @@ ve.ui.MWMediaDialog.prototype.switchPanels = function ( panel, stopSearchRequery
|
|||
this.setSize( 'larger' );
|
||||
this.selectedImageInfo = null;
|
||||
if ( !stopSearchRequery ) {
|
||||
// Show a spinner while we check for file repos.
|
||||
// this will only be done once per session.
|
||||
// The filerepo promise will be sent to the API
|
||||
// only once per session so this will be resolved
|
||||
// every time the search panel reloads
|
||||
this.$spinner.removeClass( 'oo-ui-element-hidden' );
|
||||
this.search.toggle( false );
|
||||
|
||||
// Get the repos from the API first
|
||||
// The ajax request will only be done once per session
|
||||
dialog.getFileRepos().done( function ( repos ) {
|
||||
dialog.search.setSources( repos );
|
||||
// Done, hide the spinner
|
||||
dialog.$spinner.addClass( 'oo-ui-element-hidden' );
|
||||
// Show the search and query the media sources
|
||||
dialog.search.toggle( true );
|
||||
dialog.search.query.setValue( dialog.pageTitle );
|
||||
dialog.search.queryMediaSources();
|
||||
// Initialization
|
||||
// This must be done only after there are proper
|
||||
// sources defined
|
||||
dialog.search.getQuery().focus().select();
|
||||
dialog.search.getResults().selectItem();
|
||||
dialog.search.getResults().highlightItem();
|
||||
} );
|
||||
this.search.query.setValue( dialog.pageTitle );
|
||||
this.search.query.focus().select();
|
||||
}
|
||||
|
||||
// Set the edit panel
|
||||
|
|
|
@ -24,14 +24,15 @@ ve.ui.MWMediaResultWidget = function VeUiMWMediaResultWidget( config ) {
|
|||
|
||||
// Properties
|
||||
this.initialSize = config.size || 150;
|
||||
this.maxSize = config.maxSize || this.initialSize * 2;
|
||||
this.maxWidth = config.maxWidth || this.initialSize * 2;
|
||||
this.expanded = false;
|
||||
this.dimensions = {};
|
||||
this.$thumb = this.buildThumbnail();
|
||||
this.$overlay = this.$( '<div>' );
|
||||
this.row = null;
|
||||
// Store the thumbnail url
|
||||
this.thumbUrl = ve.getProp( this.data.imageinfo, 0, 'thumburl' );
|
||||
this.thumbUrl = this.data.thumburl;
|
||||
this.src = null;
|
||||
|
||||
// Get wiki default thumbnail size
|
||||
this.defaultThumbSize = mw.config.get( 'wgVisualEditorConfig' )
|
||||
|
@ -48,15 +49,6 @@ ve.ui.MWMediaResultWidget = function VeUiMWMediaResultWidget( config ) {
|
|||
|
||||
// Adjust wrapper padding
|
||||
this.$element.css( $.extend( this.dimensions, this.calculateWrapperPadding( this.dimensions, this.initialSize ) ) );
|
||||
|
||||
// Select button
|
||||
this.selectButton = new OO.ui.ButtonWidget( {
|
||||
$: this.$,
|
||||
label: ve.msg( 'visualeditor-dialog-media-searchselect' ),
|
||||
icon: 'check'
|
||||
} );
|
||||
this.selectButton.toggle( false );
|
||||
this.$element.prepend( this.selectButton.$element );
|
||||
};
|
||||
|
||||
/* Inheritance */
|
||||
|
@ -90,7 +82,7 @@ ve.ui.MWMediaResultWidget.prototype.onThumbnailError = function () {
|
|||
*/
|
||||
ve.ui.MWMediaResultWidget.prototype.buildThumbnail = function () {
|
||||
var imageDimensions,
|
||||
info = this.data.imageinfo[0],
|
||||
info = this.data,
|
||||
$thumb = this.$( '<img>' );
|
||||
|
||||
// Preload image
|
||||
|
@ -109,7 +101,7 @@ ve.ui.MWMediaResultWidget.prototype.buildThumbnail = function () {
|
|||
height: this.initialSize
|
||||
};
|
||||
} else {
|
||||
if ( info.height < this.initialSize && info.width < this.maxSize ) {
|
||||
if ( info.height < this.initialSize && info.width < this.maxWidth ) {
|
||||
// Define dimensions with original size
|
||||
imageDimensions = {
|
||||
width: info.width,
|
||||
|
@ -137,7 +129,10 @@ ve.ui.MWMediaResultWidget.prototype.buildThumbnail = function () {
|
|||
* actual src.
|
||||
*/
|
||||
ve.ui.MWMediaResultWidget.prototype.lazyLoad = function () {
|
||||
this.$thumb.attr( 'src', this.thumbUrl );
|
||||
if ( !this.hasSrc() ) {
|
||||
this.src = this.thumbUrl;
|
||||
this.$thumb.attr( 'src', this.thumbUrl );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -176,7 +171,7 @@ ve.ui.MWMediaResultWidget.prototype.resizeThumb = function ( resizeFactor ) {
|
|||
*/
|
||||
ve.ui.MWMediaResultWidget.prototype.calculateThumbDimensions = function ( imageDimensions ) {
|
||||
var dimensions,
|
||||
maxWidth = this.maxSize,
|
||||
maxWidth = this.maxWidth,
|
||||
ratio = imageDimensions.width / imageDimensions.height;
|
||||
// Rules of resizing:
|
||||
// (1) Images must have height = this.initialSize
|
||||
|
@ -263,5 +258,5 @@ ve.ui.MWMediaResultWidget.prototype.getRow = function () {
|
|||
* @returns {boolean} Thumbnail has its source attribute set
|
||||
*/
|
||||
ve.ui.MWMediaResultWidget.prototype.hasSrc = function () {
|
||||
return !!this.$thumb.attr( 'src' );
|
||||
return !!this.src;
|
||||
};
|
||||
|
|
|
@ -25,29 +25,38 @@ ve.ui.MWMediaSearchWidget = function VeUiMWMediaSearchWidget( config ) {
|
|||
OO.ui.SearchWidget.call( this, config );
|
||||
|
||||
// Properties
|
||||
this.sources = {};
|
||||
this.providers = {};
|
||||
this.searchValue = '';
|
||||
this.rowHeight = config.rowHeight || 200;
|
||||
this.$panels = config.$panels;
|
||||
this.resourceQueue = new ve.dm.MWMediaResourceQueue( {
|
||||
limit: 20,
|
||||
threshhold: 10
|
||||
} );
|
||||
|
||||
this.queryTimeout = null;
|
||||
this.titles = {};
|
||||
this.queryMediaSourcesCallback = this.queryMediaSources.bind( this );
|
||||
this.itemCache = {};
|
||||
this.promises = [];
|
||||
this.lang = config.lang || 'en';
|
||||
this.$panels = config.$panels;
|
||||
|
||||
// Masonry fit properties
|
||||
this.rows = [];
|
||||
this.rowHeight = config.rowHeight || 200;
|
||||
this.queryMediaQueueCallback = this.queryMediaQueue.bind( this );
|
||||
this.layoutQueue = [];
|
||||
this.numItems = 0;
|
||||
this.lang = config.lang || 'en';
|
||||
|
||||
this.selected = null;
|
||||
|
||||
this.rows = [];
|
||||
|
||||
this.$noItemsMessage = this.$( '<div>' )
|
||||
.addClass( 've-ui-mwMediaSearchWidget-noresults oo-ui-element-hidden' )
|
||||
.text( ve.msg( 'visualeditor-dialog-media-noresults' ) )
|
||||
.appendTo( this.$query );
|
||||
this.noItemsMessage = new OO.ui.LabelWidget( {
|
||||
$: this.$,
|
||||
label: ve.msg( 'visualeditor-dialog-media-noresults' ),
|
||||
classes: [ 've-ui-mwMediaSearchWidget-noresults' ]
|
||||
} );
|
||||
this.noItemsMessage.toggle( false );
|
||||
|
||||
// Events
|
||||
this.$results.on( 'scroll', this.onResultsScroll.bind( this ) );
|
||||
this.$query.append( this.noItemsMessage.$element );
|
||||
this.results.connect( this, {
|
||||
choose: 'onResultsChoose',
|
||||
add: 'onResultsAdd',
|
||||
|
@ -65,29 +74,78 @@ OO.inheritClass( ve.ui.MWMediaSearchWidget, OO.ui.SearchWidget );
|
|||
/* Methods */
|
||||
|
||||
/**
|
||||
* Set the fileRepo sources for the media search
|
||||
* @param {Object} sources The sources object
|
||||
* Query all sources for media.
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
ve.ui.MWMediaSearchWidget.prototype.setSources = function ( sources ) {
|
||||
this.sources = sources;
|
||||
ve.ui.MWMediaSearchWidget.prototype.queryMediaQueue = function () {
|
||||
var search = this,
|
||||
value = this.query.getValue();
|
||||
|
||||
if ( value === '' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.query.pushPending();
|
||||
search.noItemsMessage.toggle( false );
|
||||
|
||||
this.resourceQueue.setQuery( value );
|
||||
this.resourceQueue.get( 20 )
|
||||
.then( function ( items ) {
|
||||
if ( items.length > 0 ) {
|
||||
search.processQueueResults( items, value );
|
||||
}
|
||||
|
||||
search.query.popPending();
|
||||
search.noItemsMessage.toggle( search.results.getItems().length === 0 );
|
||||
if ( search.results.getItems().length > 0 ) {
|
||||
search.lazyLoadResults();
|
||||
}
|
||||
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the fileRepo sources for the media search
|
||||
* @param {Object} sources The sources object
|
||||
* Process the media queue giving more items
|
||||
*
|
||||
* @method
|
||||
* @param {Object[]} items Given items by the media queue
|
||||
*/
|
||||
ve.ui.MWMediaSearchWidget.prototype.getSources = function () {
|
||||
return this.sources;
|
||||
ve.ui.MWMediaSearchWidget.prototype.processQueueResults = function ( items ) {
|
||||
var i, len, title,
|
||||
resultWidgets = [],
|
||||
value = this.resourceQueue.getQuery();
|
||||
|
||||
if ( value === '' || value !== this.query.getValue() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( i = 0, len = items.length; i < len; i++ ) {
|
||||
title = new mw.Title( items[i].title ).getMainText();
|
||||
// Do not insert duplicates
|
||||
if ( !Object.prototype.hasOwnProperty.call( this.itemCache, title ) ) {
|
||||
this.itemCache[title] = true;
|
||||
resultWidgets.push(
|
||||
new ve.ui.MWMediaResultWidget( {
|
||||
$: this.$,
|
||||
data: items[i],
|
||||
size: this.rowHeight,
|
||||
maxWidth: this.results.$element.width() / 3
|
||||
} )
|
||||
);
|
||||
}
|
||||
}
|
||||
this.results.addItems( resultWidgets );
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle select widget select events.
|
||||
* Handle search value change
|
||||
*
|
||||
* @param {string} value New value
|
||||
*/
|
||||
ve.ui.MWMediaSearchWidget.prototype.onQueryChange = function ( value ) {
|
||||
var i, len,
|
||||
trimmed = $.trim( value );
|
||||
var trimmed = $.trim( value );
|
||||
|
||||
if ( trimmed === this.searchValue ) {
|
||||
return;
|
||||
|
@ -98,14 +156,18 @@ ve.ui.MWMediaSearchWidget.prototype.onQueryChange = function ( value ) {
|
|||
OO.ui.SearchWidget.prototype.onQueryChange.apply( this, arguments );
|
||||
|
||||
// Reset
|
||||
this.titles = {};
|
||||
for ( i = 0, len = this.sources.length; i < len; i++ ) {
|
||||
delete this.sources[i].gsroffset;
|
||||
}
|
||||
this.itemCache = {};
|
||||
this.resetRows();
|
||||
|
||||
// Empty the results queue
|
||||
this.layoutQueue = [];
|
||||
|
||||
// Change resource queue query
|
||||
this.resourceQueue.setQuery( this.searchValue );
|
||||
|
||||
// Queue
|
||||
clearTimeout( this.queryTimeout );
|
||||
this.queryTimeout = setTimeout( this.queryMediaSourcesCallback, 250 );
|
||||
this.queryTimeout = setTimeout( this.queryMediaQueueCallback, 350 );
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -128,7 +190,7 @@ ve.ui.MWMediaSearchWidget.prototype.onResultsScroll = function () {
|
|||
|
||||
// Check if we need to ask for more results
|
||||
if ( !this.query.isPending() && position > threshold ) {
|
||||
this.queryMediaSources();
|
||||
this.queryMediaQueue();
|
||||
}
|
||||
|
||||
this.lazyLoadResults();
|
||||
|
@ -142,6 +204,7 @@ ve.ui.MWMediaSearchWidget.prototype.lazyLoadResults = function () {
|
|||
items = this.results.getItems(),
|
||||
resultsScrollTop = this.$results.scrollTop(),
|
||||
position = resultsScrollTop + this.$results.outerHeight();
|
||||
|
||||
// Lazy-load results
|
||||
for ( i = 0; i < items.length; i++ ) {
|
||||
elementTop = items[i].$element.position().top;
|
||||
|
@ -151,82 +214,6 @@ ve.ui.MWMediaSearchWidget.prototype.lazyLoadResults = function () {
|
|||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Query all sources for media.
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
ve.ui.MWMediaSearchWidget.prototype.queryMediaSources = function () {
|
||||
var i, len, source, request,
|
||||
lang = this.getLang(),
|
||||
ajaxOptions = {},
|
||||
value = this.query.getValue();
|
||||
|
||||
if ( value === '' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset message
|
||||
this.$noItemsMessage.addClass( 'oo-ui-element-hidden' );
|
||||
|
||||
// Abort previous promises if they are pending
|
||||
this.resetPromises();
|
||||
|
||||
for ( i = 0, len = this.sources.length; i < len; i++ ) {
|
||||
source = this.sources[i];
|
||||
// If we don't have either 'apiurl' or 'scriptDirUrl'
|
||||
// the source is invalid, and we will skip it
|
||||
if ( source.apiurl || source.scriptDirUrl !== undefined ) {
|
||||
if ( !source.gsroffset ) {
|
||||
source.gsroffset = 0;
|
||||
}
|
||||
if ( source.local ) {
|
||||
ajaxOptions = {
|
||||
url: mw.util.wikiScript( 'api' ),
|
||||
// If the url is local use json
|
||||
dataType: 'json'
|
||||
};
|
||||
} else {
|
||||
ajaxOptions = {
|
||||
// If 'apiurl' is set, use that. Otherwise, build the url
|
||||
// from scriptDirUrl and /api.php suffix
|
||||
url: source.apiurl || ( source.scriptDirUrl + '/api.php' ),
|
||||
// If the url is not the same origin use jsonp
|
||||
dataType: 'jsonp',
|
||||
// JSON-P requests are not cached by default and get a &_=random trail.
|
||||
// While setting cache=true will still bypass cache in most case due to the
|
||||
// callback parameter, at least drop the &_=random trail which triggers
|
||||
// an API warning (invalid parameter).
|
||||
cache: true
|
||||
};
|
||||
}
|
||||
this.query.pushPending();
|
||||
request = ve.init.target.constructor.static.apiRequest( {
|
||||
action: 'query',
|
||||
generator: 'search',
|
||||
gsrsearch: value,
|
||||
gsrnamespace: 6,
|
||||
// Initial number of images
|
||||
// NOTE: If this is too high, it triggers Common's bot prevention code
|
||||
gsrlimit: 30,
|
||||
gsroffset: source.gsroffset,
|
||||
prop: 'imageinfo',
|
||||
// Language of the extmetadata details
|
||||
iiextmetadatalanguage: lang,
|
||||
iiprop: 'dimensions|url|mediatype|extmetadata|timestamp',
|
||||
iiurlheight: this.rowHeight,
|
||||
// Width of the dialog
|
||||
iiurlwidth: 600 - 30 // Take off 30px for the margins
|
||||
}, ajaxOptions )
|
||||
.done( this.onMediaQueryDone.bind( this, source ) );
|
||||
source.value = value;
|
||||
this.promises.push( request );
|
||||
}
|
||||
|
||||
// When all sources are done, check to see if there are results
|
||||
$.when.apply( $, this.promises ).done( this.onAllMediaQueriesDone.bind( this ) );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset all the rows; destroy the jQuery elements and reset
|
||||
|
@ -242,44 +229,10 @@ ve.ui.MWMediaSearchWidget.prototype.resetRows = function () {
|
|||
this.rows = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Abort all api search query promises
|
||||
*/
|
||||
ve.ui.MWMediaSearchWidget.prototype.resetPromises = function () {
|
||||
var i;
|
||||
|
||||
for ( i = 0; i < this.promises.length; i++ ) {
|
||||
this.promises[i].abort();
|
||||
this.query.popPending();
|
||||
}
|
||||
|
||||
this.rowIndex = 0;
|
||||
// Empty the promise array
|
||||
this.promises = [];
|
||||
// Empty the results queue
|
||||
this.layoutQueue = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle media query response events.
|
||||
*
|
||||
* @method
|
||||
* @param {Object} source Media query source
|
||||
*/
|
||||
ve.ui.MWMediaSearchWidget.prototype.onAllMediaQueriesDone = function () {
|
||||
this.query.popPending();
|
||||
|
||||
if ( this.results.getItems().length === 0 ) {
|
||||
this.$noItemsMessage.removeClass( 'oo-ui-element-hidden' );
|
||||
} else {
|
||||
this.$noItemsMessage.addClass( 'oo-ui-element-hidden' );
|
||||
this.lazyLoadResults();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Find an available row at the end. Either we will need to create a new
|
||||
* row or use the last available row if it isn't full.
|
||||
*
|
||||
* @return {number} Row index
|
||||
*/
|
||||
ve.ui.MWMediaSearchWidget.prototype.getAvailableRow = function () {
|
||||
|
@ -377,7 +330,7 @@ ve.ui.MWMediaSearchWidget.prototype.onResultsAdd = function ( items ) {
|
|||
|
||||
// If we have less than 4 rows, call for more images
|
||||
if ( search.rows.length < 4 ) {
|
||||
search.queryMediaSources();
|
||||
search.queryMediaQueue();
|
||||
}
|
||||
} );
|
||||
this.runLayoutQueue();
|
||||
|
@ -409,54 +362,6 @@ ve.ui.MWMediaSearchWidget.prototype.onResultsRemove = function ( items ) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle media query load events.
|
||||
*
|
||||
* @method
|
||||
* @param {Object} source Media query source
|
||||
* @param {Object} data Media query response
|
||||
*/
|
||||
ve.ui.MWMediaSearchWidget.prototype.onMediaQueryDone = function ( source, data ) {
|
||||
if ( !data.query || !data.query.pages ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var page, title,
|
||||
items = [],
|
||||
pages = data.query.pages,
|
||||
value = this.query.getValue();
|
||||
|
||||
if ( value === '' || value !== source.value ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( data['query-continue'] && data['query-continue'].search ) {
|
||||
source.gsroffset = data['query-continue'].search.gsroffset;
|
||||
}
|
||||
|
||||
for ( page in pages ) {
|
||||
// Verify that imageinfo exists
|
||||
// In case it does not, skip the image to avoid errors in
|
||||
// ve.ui.MWMediaResultWidget
|
||||
if ( pages[page].imageinfo && pages[page].imageinfo.length > 0 ) {
|
||||
title = new mw.Title( pages[page].title ).getMainText();
|
||||
if ( !Object.prototype.hasOwnProperty.call( this.titles, title ) ) {
|
||||
this.titles[title] = true;
|
||||
items.push(
|
||||
new ve.ui.MWMediaResultWidget( {
|
||||
$: this.$,
|
||||
data: pages[page],
|
||||
size: this.rowHeight,
|
||||
maxSize: this.results.$element.width() / 3
|
||||
} )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.results.addItems( items );
|
||||
};
|
||||
|
||||
/**
|
||||
* Set language for the search results.
|
||||
* @param {string} lang Language
|
||||
|
|
Loading…
Reference in a new issue