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
) );