2 * Show gallery captions when focused. Copied directly from jquery.mw-jump.js.
3 * Also Dynamically resize images to justify them.
8 // Is there a better way to detect a touchscreen? Current check taken from stack overflow.
9 isTouchScreen = !!( window.ontouchstart !== undefined ||
10 window.DocumentTouch !== undefined && document instanceof window.DocumentTouch
14 * Perform the layout justification.
17 * @context {HTMLElement} A `ul.mw-gallery-*` element
28 $gallery.children( 'li.gallerybox' ).each( function () {
29 // Math.floor to be paranoid if things are off by 0.00000000001
30 var top = Math.floor( $( this ).position().top ),
33 if ( top !== lastTop ) {
34 rows[ rows.length ] = [];
38 $img = $this.find( 'div.thumb a.image img' );
39 if ( $img.length && $img[ 0 ].height ) {
40 imgHeight = $img[ 0 ].height;
41 imgWidth = $img[ 0 ].width;
43 // If we don't have a real image, get the containing divs width/height.
44 // Note that if we do have a real image, using this method will generally
45 // give the same answer, but can be different in the case of a very
46 // narrow image where extra padding is added.
47 imgHeight = $this.children().children( 'div:first' ).height();
48 imgWidth = $this.children().children( 'div:first' ).width();
51 // Hack to make an edge case work ok
52 if ( imgHeight < 30 ) {
53 // Don't try and resize this item.
57 captionWidth = $this.children().children( 'div.gallerytextwrapper' ).width();
58 rows[ rows.length - 1 ][ rows[ rows.length - 1 ].length ] = {
60 width: $this.outerWidth(),
62 // XXX: can divide by 0 ever happen?
63 aspect: imgWidth / imgHeight,
64 captionWidth: captionWidth,
68 // Save all boundaries so we can restore them on window resize
69 $this.data( 'imgWidth', imgWidth );
70 $this.data( 'imgHeight', imgHeight );
71 $this.data( 'width', $this.outerWidth() );
72 $this.data( 'captionWidth', captionWidth );
96 for ( i = 0; i < rows.length; i++ ) {
97 maxWidth = $gallery.width();
103 for ( j = 0; j < curRow.length; j++ ) {
104 if ( curRowHeight === 0 ) {
105 if ( isFinite( curRow[ j ].height ) ) {
106 // Get the height of this row, by taking the first
107 // non-out of bounds height
108 curRowHeight = curRow[ j ].height;
112 if ( curRow[ j ].aspect === 0 || !isFinite( curRow[ j ].aspect ) ) {
113 // One of the dimensions are 0. Probably should
114 // not try to resize.
115 combinedPadding += curRow[ j ].width;
117 combinedAspect += curRow[ j ].aspect;
118 combinedPadding += curRow[ j ].width - curRow[ j ].imgWidth;
122 // Add some padding for inter-element spacing.
123 combinedPadding += 5 * curRow.length;
124 wantedWidth = maxWidth - combinedPadding;
125 preferredHeight = wantedWidth / combinedAspect;
127 if ( preferredHeight > curRowHeight * 1.5 ) {
128 // Only expand at most 1.5 times current size
129 // As that's as high a resolution as we have.
130 // Also on the off chance there is a bug in this
131 // code, would prevent accidentally expanding to
132 // be 10 billion pixels wide.
133 if ( i === rows.length - 1 ) {
134 // If its the last row, and we can't fit it,
135 // don't make the entire row huge.
136 avgZoom = ( totalZoom / ( rows.length - 1 ) ) * curRowHeight;
137 if ( isFinite( avgZoom ) && avgZoom >= 1 && avgZoom <= 1.5 ) {
138 preferredHeight = avgZoom;
140 // Probably a single row gallery
141 preferredHeight = curRowHeight;
144 preferredHeight = 1.5 * curRowHeight;
147 if ( !isFinite( preferredHeight ) ) {
148 // This *definitely* should not happen.
152 if ( preferredHeight < 5 ) {
153 // Well something clearly went wrong...
158 if ( preferredHeight / curRowHeight > 1 ) {
159 totalZoom += preferredHeight / curRowHeight;
161 // If we shrink, still consider that a zoom of 1
165 for ( j = 0; j < curRow.length; j++ ) {
166 newWidth = preferredHeight * curRow[ j ].aspect;
167 padding = curRow[ j ].width - curRow[ j ].imgWidth;
168 $outerDiv = curRow[ j ].$elm;
169 $innerDiv = $outerDiv.children( 'div' ).first();
170 $imageDiv = $innerDiv.children( 'div.thumb' );
171 $imageElm = $imageDiv.find( 'img' ).first();
172 imageElm = $imageElm.length ? $imageElm[ 0 ] : null;
173 $caption = $outerDiv.find( 'div.gallerytextwrapper' );
175 // Since we are going to re-adjust the height, the vertical
176 // centering margins need to be reset.
177 $imageDiv.children( 'div' ).css( 'margin', '0px auto' );
179 if ( newWidth < 60 || !isFinite( newWidth ) ) {
180 // Making something skinnier than this will mess up captions,
181 if ( newWidth < 1 || !isFinite( newWidth ) ) {
182 $innerDiv.height( preferredHeight );
183 // Don't even try and touch the image size if it could mean
184 // making it disappear.
188 $outerDiv.width( newWidth + padding );
189 $innerDiv.width( newWidth + padding );
190 $imageDiv.width( newWidth );
191 $caption.width( curRow[ j ].captionWidth + ( newWidth - curRow[ j ].imgWidth ) );
195 // We don't always have an img, e.g. in the case of an invalid file.
196 imageElm.width = newWidth;
197 imageElm.height = preferredHeight;
200 $imageDiv.height( preferredHeight );
207 function handleResizeStart() {
208 $galleries.children( 'li.gallerybox' ).each( function () {
209 var imgWidth = $( this ).data( 'imgWidth' ),
210 imgHeight = $( this ).data( 'imgHeight' ),
211 width = $( this ).data( 'width' ),
212 captionWidth = $( this ).data( 'captionWidth' ),
213 $innerDiv = $( this ).children( 'div' ).first(),
214 $imageDiv = $innerDiv.children( 'div.thumb' ),
217 // Restore original sizes so we can arrange the elements as on freshly loaded page
218 $( this ).width( width );
219 $innerDiv.width( width );
220 $imageDiv.width( imgWidth );
221 $( this ).find( 'div.gallerytextwrapper' ).width( captionWidth );
223 $imageElm = $( this ).find( 'img' ).first();
224 imageElm = $imageElm.length ? $imageElm[ 0 ] : null;
226 imageElm.width = imgWidth;
227 imageElm.height = imgHeight;
229 $imageDiv.height( imgHeight );
234 function handleResizeEnd() {
235 $galleries.each( justify );
238 mw.hook( 'wikipage.content' ).add( function ( $content ) {
239 if ( isTouchScreen ) {
240 // Always show the caption for a touch screen.
241 $content.find( 'ul.mw-gallery-packed-hover' )
242 .addClass( 'mw-gallery-packed-overlay' )
243 .removeClass( 'mw-gallery-packed-hover' );
245 // Note use of just "a", not a.image, since we want this to trigger if a link in
246 // the caption receives focus
247 $content.find( 'ul.mw-gallery-packed-hover li.gallerybox' ).on( 'focus blur', 'a', function ( e ) {
248 // Confusingly jQuery leaves e.type as focusout for delegated blur events
249 var gettingFocus = e.type !== 'blur' && e.type !== 'focusout';
250 $( this ).closest( 'li.gallerybox' ).toggleClass( 'mw-gallery-focused', gettingFocus );
254 $galleries = $content.find( 'ul.mw-gallery-packed-overlay, ul.mw-gallery-packed-hover, ul.mw-gallery-packed' );
255 // Call the justification asynchronous because live preview fires the hook with detached $content.
256 setTimeout( function () {
257 $galleries.each( justify );
259 // Bind here instead of in the top scope as the callbacks use $galleries.
263 .resize( $.debounce( 300, true, handleResizeStart ) )
264 .resize( $.debounce( 300, handleResizeEnd ) );
268 }( mediaWiki, jQuery ) );