Merge "resources: Strip '$' and 'mw' from file closures"
[lhc/web/wiklou.git] / resources / src / mediawiki.widgets / MediaSearch / mw.widgets.MediaResultWidget.js
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 () {
8
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 || {};
26
27 // Parent constructor
28 mw.widgets.MediaResultWidget.super.call( this, config );
29
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;
35
36 this.imageDimensions = {};
37
38 this.isAudio = this.data.mediatype === 'AUDIO';
39
40 // Store the thumbnail url
41 this.thumbUrl = this.data.thumburl;
42 this.src = null;
43 this.row = null;
44
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' );
53
54 this.calculateSizing( this.data );
55
56 // Get wiki default thumbnail size
57 this.defaultThumbSize = mw.config.get( 'wgVisualEditorConfig' )
58 .defaultUserOptions.defaultthumbsize;
59
60 // Initialization
61 this.setLabel( new mw.Title( this.data.title ).getNameText() );
62 this.$label.addClass( 'mw-widget-mediaResultWidget-nameLabel' );
63
64 this.$element
65 .addClass( 'mw-widget-mediaResultWidget ve-ui-texture-pending' )
66 .prepend( this.$thumb, this.$overlay );
67 };
68
69 /* Inheritance */
70
71 OO.inheritClass( mw.widgets.MediaResultWidget, OO.ui.OptionWidget );
72
73 /* Static methods */
74
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 );
82
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 };
92
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 };
101
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 };
111
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 = {};
121
122 boundingBox = boundingBox || {};
123
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 );
149
150 // Set the box size
151 wrapperPadding = this.calculateWrapperPadding( this.imageDimensions );
152 this.$element.css( wrapperPadding );
153 };
154
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 };
165
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 };
174
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 ) );
186
187 boundingBox = {
188 width: Math.ceil( this.imageDimensions.width * resizeFactor ),
189 height: this.getRowHeight()
190 };
191
192 this.calculateSizing( this.data, boundingBox );
193
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 };
201
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 };
214
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 }
219
220 return css;
221 };
222
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 };
231
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 };
240
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 };
247
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 };
256
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 };
265
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 }() );