/*!
* MediaWiki Widgets - MediaResultWidget class.
*
* @copyright 2011-2016 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
( function () {
/**
* @classdesc Media result widget.
*
* @class
* @extends OO.ui.OptionWidget
*
* @constructor
* @description Creates an mw.widgets.MediaResultWidget object.
* @param {Object} [config] Configuration options
* @param {number} [config.rowHeight] Height of the row this result is part of
* @param {number} [config.maxRowWidth] A limit for the width of the row this
* result is a part of.
* @param {number} [config.minWidth] Minimum width for the result
* @param {number} [config.maxWidth] Maximum width for the result
*/
mw.widgets.MediaResultWidget = function MwWidgetsMediaResultWidget( config ) {
// Configuration initialization
config = config || {};
// Parent constructor
mw.widgets.MediaResultWidget.super.call( this, config );
// Properties
this.setRowHeight( config.rowHeight || 150 );
this.maxRowWidth = config.maxRowWidth || 500;
this.minWidth = config.minWidth || this.maxRowWidth / 5;
this.maxWidth = config.maxWidth || this.maxRowWidth * 2 / 3;
this.imageDimensions = {};
this.isAudio = this.data.mediatype === 'AUDIO';
// Store the thumbnail url
this.thumbUrl = this.data.thumburl;
this.src = null;
this.row = null;
this.$thumb = $( '<img>' )
.addClass( 'mw-widget-mediaResultWidget-thumbnail' )
.attr( 'alt', '' )
.on( {
load: this.onThumbnailLoad.bind( this ),
error: this.onThumbnailError.bind( this )
} );
this.$overlay = $( '<div>' )
.addClass( 'mw-widget-mediaResultWidget-overlay' );
this.calculateSizing( this.data );
// Initialization
this.setLabel( new mw.Title( this.data.title ).getNameText() );
this.$label.addClass( 'mw-widget-mediaResultWidget-nameLabel' );
this.$element
.addClass( 'mw-widget-mediaResultWidget ve-ui-texture-pending' )
.prepend( this.$thumb, this.$overlay );
};
/* Inheritance */
OO.inheritClass( mw.widgets.MediaResultWidget, OO.ui.OptionWidget );
/* Static methods */
// Copied from ve.dm.MWImageNode
mw.widgets.MediaResultWidget.static.resizeToBoundingBox = function ( imageDimensions, boundingBox ) {
let newDimensions = OO.copy( imageDimensions );
const scale = Math.min(
boundingBox.height / imageDimensions.height,
boundingBox.width / imageDimensions.width
);
if ( scale < 1 ) {
// Scale down
newDimensions = {
width: Math.floor( newDimensions.width * scale ),
height: Math.floor( newDimensions.height * scale )
};
}
return newDimensions;
};
/* Methods */
mw.widgets.MediaResultWidget.prototype.onThumbnailLoad = function () {
this.$thumb.first().addClass( 've-ui-texture-transparency' );
this.$element
.addClass( 'mw-widget-mediaResultWidget-done' )
.removeClass( 've-ui-texture-pending' );
};
mw.widgets.MediaResultWidget.prototype.onThumbnailError = function () {
this.$thumb.last()
.css( 'background-image', '' )
.addClass( 've-ui-texture-alert' );
this.$element
.addClass( 'mw-widget-mediaResultWidget-error' )
.removeClass( 've-ui-texture-pending' );
};
/**
* Resize the thumbnail and wrapper according to row height and bounding boxes, if given.
*
* @param {Object} originalDimensions Original image dimensions with width and height values
* @param {Object} [boundingBox] Specific bounding box, if supplied
*/
mw.widgets.MediaResultWidget.prototype.calculateSizing = function ( originalDimensions, boundingBox ) {
boundingBox = boundingBox || {};
let imageDimensions;
if ( this.isAudio ) {
// HACK: We are getting the wrong information from the
// API about audio files. Set their thumbnail to square 120px
imageDimensions = {
width: 120,
height: 120
};
} else {
// Get the image within the bounding box
imageDimensions = this.constructor.static.resizeToBoundingBox(
// Image original dimensions
{
width: originalDimensions.width || originalDimensions.thumbwidth,
height: originalDimensions.height || originalDimensions.thumbwidth
},
// Bounding box
{
width: boundingBox.width || this.getImageMaxWidth(),
height: boundingBox.height || this.getRowHeight()
}
);
}
this.imageDimensions = imageDimensions;
// Set the thumbnail size
this.$thumb.css( this.imageDimensions );
// Set the box size
const wrapperPadding = this.calculateWrapperPadding( this.imageDimensions );
this.$element.css( wrapperPadding );
};
/**
* Replace the empty .src attribute of the image with the
* actual src.
*/
mw.widgets.MediaResultWidget.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
*/
mw.widgets.MediaResultWidget.prototype.getDimensions = function () {
return this.dimensions;
};
/**
* Resize thumbnail and element according to the resize factor.
*
* @param {number} resizeFactor The resizing factor for the image
*/
mw.widgets.MediaResultWidget.prototype.resizeThumb = function ( resizeFactor ) {
const imageOriginalWidth = this.imageDimensions.width,
wrapperWidth = this.$element.width();
// Set the new row height
this.setRowHeight( Math.ceil( this.getRowHeight() * resizeFactor ) );
const boundingBox = {
width: Math.ceil( this.imageDimensions.width * resizeFactor ),
height: this.getRowHeight()
};
this.calculateSizing( this.data, boundingBox );
// We need to adjust the wrapper this time to fit the "perfect"
// dimensions, regardless of how small the image is
if ( imageOriginalWidth < wrapperWidth ) {
boundingBox.width = wrapperWidth * resizeFactor;
}
this.$element.css( this.calculateWrapperPadding( boundingBox ) );
};
/**
* Adjust the wrapper padding for small images.
*
* @param {Object} thumbDimensions Thumbnail dimensions
* @return {Object} Css styling for the wrapper
*/
mw.widgets.MediaResultWidget.prototype.calculateWrapperPadding = function ( thumbDimensions ) {
const css = {
height: this.rowHeight,
width: thumbDimensions.width,
lineHeight: this.getRowHeight() + 'px'
};
// Check if the image is too thin so we can make a bit of space around it
if ( thumbDimensions.width < this.minWidth ) {
css.width = this.minWidth;
}
return css;
};
/**
* Set the row height for all size calculations.
*
* @return {number} rowHeight Row height
*/
mw.widgets.MediaResultWidget.prototype.getRowHeight = function () {
return this.rowHeight;
};
/**
* Set the row height for all size calculations.
*
* @param {number} rowHeight Row height
*/
mw.widgets.MediaResultWidget.prototype.setRowHeight = function ( rowHeight ) {
this.rowHeight = rowHeight;
};
mw.widgets.MediaResultWidget.prototype.setImageMaxWidth = function ( width ) {
this.maxWidth = width;
};
mw.widgets.MediaResultWidget.prototype.getImageMaxWidth = function () {
return this.maxWidth;
};
/**
* Set the row this result is in.
*
* @param {number} row Row number
*/
mw.widgets.MediaResultWidget.prototype.setRow = function ( row ) {
this.row = row;
};
/**
* Get the row this result is in.
*
* @return {number} row Row number
*/
mw.widgets.MediaResultWidget.prototype.getRow = function () {
return this.row;
};
/**
* Check if the image has a src attribute already.
*
* @return {boolean} Thumbnail has its source attribute set
*/
mw.widgets.MediaResultWidget.prototype.hasSrc = function () {
return !!this.src;
};
}() );