Merge "Update docs/hooks.txt for ShowSearchHitTitle"
[mediawiki.git] / resources / src / mediawiki.widgets / MediaSearch / mw.widgets.MediaResultWidget.js
blob7607e8425851a9eb3b1393d04edc8a56d24c1124
1 /*!
2  * MediaWiki Widgets - MediaResultWidget class.
3  *
4  * @copyright 2011-2016 VisualEditor Team and others; see AUTHORS.txt
5  * @license The MIT License (MIT); see LICENSE.txt
6  */
7 ( function ( $, mw ) {
9         /**
10          * Creates an mw.widgets.MediaResultWidget object.
11          *
12          * @class
13          * @extends OO.ui.OptionWidget
14          *
15          * @constructor
16          * @param {Object} [config] Configuration options
17          * @cfg {number} [rowHeight] Height of the row this result is part of
18          * @cfg {number} [maxRowWidth] A limit for the width of the row this
19          *  result is a part of.
20          * @cfg {number} [minWidth] Minimum width for the result
21          * @cfg {number} [maxWidth] Maximum width for the result
22          */
23         mw.widgets.MediaResultWidget = function MwWidgetsMediaResultWidget( config ) {
24                 // Configuration initialization
25                 config = config || {};
27                 // Parent constructor
28                 mw.widgets.MediaResultWidget.super.call( this, config );
30                 // Properties
31                 this.setRowHeight( config.rowHeight || 150 );
32                 this.maxRowWidth = config.maxRowWidth || 500;
33                 this.minWidth = config.minWidth || this.maxRowWidth / 5;
34                 this.maxWidth = config.maxWidth || this.maxRowWidth * 2 / 3;
36                 this.imageDimensions = {};
38                 this.isAudio = this.data.mediatype === 'AUDIO';
40                 // Store the thumbnail url
41                 this.thumbUrl = this.data.thumburl;
42                 this.src = null;
43                 this.row = null;
45                 this.$thumb = $( '<img>' )
46                         .addClass( 'mw-widget-mediaResultWidget-thumbnail' )
47                         .on( {
48                                 load: this.onThumbnailLoad.bind( this ),
49                                 error: this.onThumbnailError.bind( this )
50                         } );
51                 this.$overlay = $( '<div>' )
52                         .addClass( 'mw-widget-mediaResultWidget-overlay' );
54                 this.calculateSizing( this.data );
56                 // Get wiki default thumbnail size
57                 this.defaultThumbSize = mw.config.get( 'wgVisualEditorConfig' )
58                         .defaultUserOptions.defaultthumbsize;
60                 // Initialization
61                 this.setLabel( new mw.Title( this.data.title ).getNameText() );
62                 this.$label.addClass( 'mw-widget-mediaResultWidget-nameLabel' );
64                 this.$element
65                         .addClass( 'mw-widget-mediaResultWidget ve-ui-texture-pending' )
66                         .prepend( this.$thumb, this.$overlay );
67         };
69         /* Inheritance */
71         OO.inheritClass( mw.widgets.MediaResultWidget, OO.ui.OptionWidget );
73         /* Static methods */
75         // Copied from ve.dm.MWImageNode
76         mw.widgets.MediaResultWidget.static.resizeToBoundingBox = function ( imageDimensions, boundingBox ) {
77                 var newDimensions = OO.copy( imageDimensions ),
78                         scale = Math.min(
79                                 boundingBox.height / imageDimensions.height,
80                                 boundingBox.width / imageDimensions.width
81                         );
83                 if ( scale < 1 ) {
84                         // Scale down
85                         newDimensions = {
86                                 width: Math.floor( newDimensions.width * scale ),
87                                 height: Math.floor( newDimensions.height * scale )
88                         };
89                 }
90                 return newDimensions;
91         };
93         /* Methods */
94         /** */
95         mw.widgets.MediaResultWidget.prototype.onThumbnailLoad = function () {
96                 this.$thumb.first().addClass( 've-ui-texture-transparency' );
97                 this.$element
98                         .addClass( 'mw-widget-mediaResultWidget-done' )
99                         .removeClass( 've-ui-texture-pending' );
100         };
102         /** */
103         mw.widgets.MediaResultWidget.prototype.onThumbnailError = function () {
104                 this.$thumb.last()
105                         .css( 'background-image', '' )
106                         .addClass( 've-ui-texture-alert' );
107                 this.$element
108                         .addClass( 'mw-widget-mediaResultWidget-error' )
109                         .removeClass( 've-ui-texture-pending' );
110         };
112         /**
113          * Resize the thumbnail and wrapper according to row height and bounding boxes, if given.
114          *
115          * @param {Object} originalDimensions Original image dimensions with width and height values
116          * @param {Object} [boundingBox] Specific bounding box, if supplied
117          */
118         mw.widgets.MediaResultWidget.prototype.calculateSizing = function ( originalDimensions, boundingBox ) {
119                 var wrapperPadding,
120                         imageDimensions = {};
122                 boundingBox = boundingBox || {};
124                 if ( this.isAudio ) {
125                         // HACK: We are getting the wrong information from the
126                         // API about audio files. Set their thumbnail to square 120px
127                         imageDimensions = {
128                                 width: 120,
129                                 height: 120
130                         };
131                 } else {
132                         // Get the image within the bounding box
133                         imageDimensions = this.constructor.static.resizeToBoundingBox(
134                                 // Image original dimensions
135                                 {
136                                         width: originalDimensions.width || originalDimensions.thumbwidth,
137                                         height: originalDimensions.height || originalDimensions.thumbwidth
138                                 },
139                                 // Bounding box
140                                 {
141                                         width: boundingBox.width || this.getImageMaxWidth(),
142                                         height: boundingBox.height || this.getRowHeight()
143                                 }
144                         );
145                 }
146                 this.imageDimensions = imageDimensions;
147                 // Set the thumbnail size
148                 this.$thumb.css( this.imageDimensions );
150                 // Set the box size
151                 wrapperPadding = this.calculateWrapperPadding( this.imageDimensions );
152                 this.$element.css( wrapperPadding );
153         };
155         /**
156          * Replace the empty .src attribute of the image with the
157          * actual src.
158          */
159         mw.widgets.MediaResultWidget.prototype.lazyLoad = function () {
160                 if ( !this.hasSrc() ) {
161                         this.src = this.thumbUrl;
162                         this.$thumb.attr( 'src', this.thumbUrl );
163                 }
164         };
166         /**
167          * Retrieve the store dimensions object
168          *
169          * @return {Object} Thumb dimensions
170          */
171         mw.widgets.MediaResultWidget.prototype.getDimensions = function () {
172                 return this.dimensions;
173         };
175         /**
176          * Resize thumbnail and element according to the resize factor
177          *
178          * @param {number} resizeFactor The resizing factor for the image
179          */
180         mw.widgets.MediaResultWidget.prototype.resizeThumb = function ( resizeFactor ) {
181                 var boundingBox,
182                         imageOriginalWidth = this.imageDimensions.width,
183                         wrapperWidth = this.$element.width();
184                 // Set the new row height
185                 this.setRowHeight( Math.ceil( this.getRowHeight() * resizeFactor ) );
187                 boundingBox = {
188                         width: Math.ceil( this.imageDimensions.width * resizeFactor ),
189                         height: this.getRowHeight()
190                 };
192                 this.calculateSizing( this.data, boundingBox );
194                 // We need to adjust the wrapper this time to fit the "perfect"
195                 // dimensions, regardless of how small the image is
196                 if ( imageOriginalWidth < wrapperWidth ) {
197                         boundingBox.width = wrapperWidth * resizeFactor;
198                 }
199                 this.$element.css( this.calculateWrapperPadding( boundingBox ) );
200         };
202         /**
203          * Adjust the wrapper padding for small images
204          *
205          * @param {Object} thumbDimensions Thumbnail dimensions
206          * @return {Object} Css styling for the wrapper
207          */
208         mw.widgets.MediaResultWidget.prototype.calculateWrapperPadding = function ( thumbDimensions ) {
209                 var css = {
210                         height: this.rowHeight,
211                         width: thumbDimensions.width,
212                         lineHeight: this.getRowHeight() + 'px'
213                 };
215                 // Check if the image is too thin so we can make a bit of space around it
216                 if ( thumbDimensions.width < this.minWidth ) {
217                         css.width = this.minWidth;
218                 }
220                 return css;
221         };
223         /**
224          * Set the row height for all size calculations
225          *
226          * @return {number} rowHeight Row height
227          */
228         mw.widgets.MediaResultWidget.prototype.getRowHeight = function () {
229                 return this.rowHeight;
230         };
232         /**
233          * Set the row height for all size calculations
234          *
235          * @param {number} rowHeight Row height
236          */
237         mw.widgets.MediaResultWidget.prototype.setRowHeight = function ( rowHeight ) {
238                 this.rowHeight = rowHeight;
239         };
241         mw.widgets.MediaResultWidget.prototype.setImageMaxWidth = function ( width ) {
242                 this.maxWidth = width;
243         };
244         mw.widgets.MediaResultWidget.prototype.getImageMaxWidth = function () {
245                 return this.maxWidth;
246         };
248         /**
249          * Set the row this result is in.
250          *
251          * @param {number} row Row number
252          */
253         mw.widgets.MediaResultWidget.prototype.setRow = function ( row ) {
254                 this.row = row;
255         };
257         /**
258          * Get the row this result is in.
259          *
260          * @return {number} row Row number
261          */
262         mw.widgets.MediaResultWidget.prototype.getRow = function () {
263                 return this.row;
264         };
266         /**
267          * Check if the image has a src attribute already
268          *
269          * @return {boolean} Thumbnail has its source attribute set
270          */
271         mw.widgets.MediaResultWidget.prototype.hasSrc = function () {
272                 return !!this.src;
273         };
274 }( jQuery, mediaWiki ) );