mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-25 23:05:35 +00:00
aa9eb95455
Change the media search widget to work with resource queues and providers. Create providers based on the user's filerepo settings and aggregate their responses with the media queue. Stop asking for more results from providers that are depleted. Also fixes a rather nasty infinite-loop bug where the API returns only very few images, and the UI keeps asking for more. Bug: T78161 Bug: T88764 Change-Id: I65aed3446cd1f056476c56e6e04522c70e49e595
263 lines
7.3 KiB
JavaScript
263 lines
7.3 KiB
JavaScript
/*!
|
|
* VisualEditor UserInterface MWMediaResultWidget class.
|
|
*
|
|
* @copyright 2011-2015 VisualEditor Team and others; see AUTHORS.txt
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
*/
|
|
|
|
/**
|
|
* Creates an ve.ui.MWMediaResultWidget object.
|
|
*
|
|
* @class
|
|
* @extends OO.ui.OptionWidget
|
|
*
|
|
* @constructor
|
|
* @param {Object} [config] Configuration options
|
|
* @cfg {number} [size] Media thumbnail size
|
|
*/
|
|
ve.ui.MWMediaResultWidget = function VeUiMWMediaResultWidget( config ) {
|
|
// Configuration initialization
|
|
config = config || {};
|
|
|
|
// Parent constructor
|
|
OO.ui.OptionWidget.call( this, config );
|
|
|
|
// Properties
|
|
this.initialSize = config.size || 150;
|
|
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 = this.data.thumburl;
|
|
this.src = null;
|
|
|
|
// Get wiki default thumbnail size
|
|
this.defaultThumbSize = mw.config.get( 'wgVisualEditorConfig' )
|
|
.defaultUserOptions.defaultthumbsize;
|
|
|
|
// Initialization
|
|
this.setLabel( new mw.Title( this.data.title ).getNameText() );
|
|
this.$label.addClass( 've-ui-mwMediaResultWidget-nameLabel' );
|
|
this.$overlay.addClass( 've-ui-mwMediaResultWidget-overlay' );
|
|
|
|
this.$element
|
|
.addClass( 've-ui-mwMediaResultWidget ve-ui-texture-pending' )
|
|
.prepend( this.$thumb, this.$overlay );
|
|
|
|
// Adjust wrapper padding
|
|
this.$element.css( $.extend( this.dimensions, this.calculateWrapperPadding( this.dimensions, this.initialSize ) ) );
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
OO.inheritClass( ve.ui.MWMediaResultWidget, OO.ui.OptionWidget );
|
|
|
|
/* Methods */
|
|
/** */
|
|
ve.ui.MWMediaResultWidget.prototype.onThumbnailLoad = function () {
|
|
this.$thumb.first().addClass( 've-ui-texture-transparency' );
|
|
this.$element
|
|
.addClass( 've-ui-mwMediaResultWidget-done' )
|
|
.removeClass( 've-ui-texture-pending' );
|
|
};
|
|
|
|
/** */
|
|
ve.ui.MWMediaResultWidget.prototype.onThumbnailError = function () {
|
|
this.$thumb.last()
|
|
.css( 'background-image', '' )
|
|
.addClass( 've-ui-texture-alert' );
|
|
this.$element
|
|
.addClass( 've-ui-mwMediaResultWidget-error' )
|
|
.removeClass( 've-ui-texture-pending' );
|
|
};
|
|
|
|
/**
|
|
* Build a thumbnail.
|
|
*
|
|
* @method
|
|
* @returns {jQuery} Thumbnail element
|
|
*/
|
|
ve.ui.MWMediaResultWidget.prototype.buildThumbnail = function () {
|
|
var imageDimensions,
|
|
info = this.data,
|
|
$thumb = this.$( '<img>' );
|
|
|
|
// Preload image
|
|
$thumb
|
|
.addClass( 've-ui-mwMediaResultWidget-thumbnail' )
|
|
.on( {
|
|
load: this.onThumbnailLoad.bind( this ),
|
|
error: this.onThumbnailError.bind( this )
|
|
} );
|
|
|
|
if ( info.mediatype === 'AUDIO' ) {
|
|
// HACK: We are getting the wrong information from the
|
|
// API about audio files. Set their thumbnail to square
|
|
imageDimensions = {
|
|
width: this.initialSize,
|
|
height: this.initialSize
|
|
};
|
|
} else {
|
|
if ( info.height < this.initialSize && info.width < this.maxWidth ) {
|
|
// Define dimensions with original size
|
|
imageDimensions = {
|
|
width: info.width,
|
|
height: info.height
|
|
};
|
|
} else {
|
|
// Resize dimensions to be a fixed height
|
|
imageDimensions = ve.dm.Scalable.static.getDimensionsFromValue(
|
|
{ height: this.initialSize },
|
|
info.thumbwidth / info.thumbheight
|
|
);
|
|
}
|
|
}
|
|
// Resize the wrapper
|
|
this.dimensions = this.calculateThumbDimensions( imageDimensions );
|
|
|
|
// Resize the image
|
|
$thumb.css( this.dimensions );
|
|
|
|
return $thumb;
|
|
};
|
|
|
|
/**
|
|
* Replace the empty .src attribute of the image with the
|
|
* actual src.
|
|
*/
|
|
ve.ui.MWMediaResultWidget.prototype.lazyLoad = function () {
|
|
if ( !this.hasSrc() ) {
|
|
this.src = this.thumbUrl;
|
|
this.$thumb.attr( 'src', this.thumbUrl );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Retrieve the store dimensions object
|
|
* @return {Object} Thumb dimensions
|
|
*/
|
|
ve.ui.MWMediaResultWidget.prototype.getDimensions = function () {
|
|
return this.dimensions;
|
|
};
|
|
|
|
/**
|
|
* Resize thumbnail and element according to the resize factor
|
|
* @param {number} resizeFactor New resizing factor, multiplying the
|
|
* current dimensions of the thumbnail
|
|
*/
|
|
ve.ui.MWMediaResultWidget.prototype.resizeThumb = function ( resizeFactor ) {
|
|
var wrapperCss, imageDimensions,
|
|
currWidth = this.$thumb.width(),
|
|
currHeight = this.$thumb.height();
|
|
|
|
imageDimensions = {
|
|
width: currWidth * resizeFactor,
|
|
height: currHeight * resizeFactor
|
|
};
|
|
// Resize thumb wrapper
|
|
this.$thumb.css( imageDimensions );
|
|
// Adjust wrapper padding - this is done so the image is placed in the center
|
|
wrapperCss = $.extend( imageDimensions, this.calculateWrapperPadding( imageDimensions, imageDimensions.height ) );
|
|
this.$element.css( wrapperCss );
|
|
};
|
|
|
|
/**
|
|
* Calculate thumbnail dimensions
|
|
* @param {Object} imageDimensions Image dimensions
|
|
* @return {Object} Thumbnail dimensions
|
|
*/
|
|
ve.ui.MWMediaResultWidget.prototype.calculateThumbDimensions = function ( imageDimensions ) {
|
|
var dimensions,
|
|
maxWidth = this.maxWidth,
|
|
ratio = imageDimensions.width / imageDimensions.height;
|
|
// Rules of resizing:
|
|
// (1) Images must have height = this.initialSize
|
|
// (2) If after resize image width is larger than maxWidth
|
|
// the image is scaled down to width = 3*this.width
|
|
// (3) Smaller images do not scale up
|
|
// * If image height < this.initialSize, add padding and center
|
|
// the image vertically
|
|
// * If image width < this.initialSize, add a fixed padding to both
|
|
// sides.
|
|
// This is done in 'calculateWrapperPadding'
|
|
// First scale all images based on height = this.initialSize
|
|
dimensions = ve.dm.MWImageNode.static.resizeToBoundingBox(
|
|
// Image thumb size
|
|
imageDimensions,
|
|
// Bounding box
|
|
{
|
|
width: maxWidth,
|
|
height: this.initialSize
|
|
}
|
|
);
|
|
|
|
// Check if image width is larger than maxWidth
|
|
if ( dimensions.width > maxWidth ) {
|
|
// Resize again to fit maxWidth
|
|
dimensions = ve.dm.Scalable.static.getDimensionsFromValue( { width: maxWidth }, ratio );
|
|
}
|
|
|
|
return dimensions;
|
|
};
|
|
|
|
/**
|
|
* Adjust the wrapper padding for small images
|
|
* @param {Object} thumbDimensions Thumbnail dimensions
|
|
* @return {Object} Left and right padding
|
|
*/
|
|
ve.ui.MWMediaResultWidget.prototype.calculateWrapperPadding = function ( thumbDimensions, rowHeight ) {
|
|
var padding,
|
|
minWidthRatioForPadding = 2 / 3 * rowHeight,
|
|
paddingWidth = {},
|
|
paddingHeight = {},
|
|
minWidth = 0.5 * rowHeight;
|
|
|
|
// Check if the image fits the row height
|
|
if ( thumbDimensions.height < rowHeight ) {
|
|
// Set up top/bottom padding
|
|
paddingHeight = {
|
|
'padding-top': ( rowHeight - thumbDimensions.height ) / 2,
|
|
'padding-bottom': ( rowHeight - thumbDimensions.height ) / 2
|
|
};
|
|
}
|
|
|
|
// Check if the image is too thin so we can make a bit of space around it
|
|
if ( thumbDimensions.width < minWidth ) {
|
|
// Make the padding so that the total width is a 1/3 of the line height
|
|
padding = rowHeight - minWidthRatioForPadding - thumbDimensions.width;
|
|
paddingWidth = {
|
|
'padding-left': padding / 2,
|
|
'padding-right': padding / 2
|
|
};
|
|
}
|
|
|
|
return $.extend( {}, paddingWidth, paddingHeight );
|
|
};
|
|
|
|
/**
|
|
* Set the row this result is in.
|
|
* @param {number} row Row number
|
|
*/
|
|
ve.ui.MWMediaResultWidget.prototype.setRow = function ( row ) {
|
|
this.row = row;
|
|
};
|
|
|
|
/**
|
|
* Get the row this result is in.
|
|
* @return {number} row Row number
|
|
*/
|
|
ve.ui.MWMediaResultWidget.prototype.getRow = function () {
|
|
return this.row;
|
|
};
|
|
|
|
/**
|
|
* Check if the image has a src attribute already
|
|
* @returns {boolean} Thumbnail has its source attribute set
|
|
*/
|
|
ve.ui.MWMediaResultWidget.prototype.hasSrc = function () {
|
|
return !!this.src;
|
|
};
|