Implement extension registration from an extension.json file
[mediawiki.git] / resources / src / mediawiki.page / mediawiki.page.gallery.js
blobe3ffbdacb353b90c9c4f3b8ba181d80ed79f5e7b
1 /*!
2  * Show gallery captions when focused. Copied directly from jquery.mw-jump.js.
3  * Also Dynamically resize images to justify them.
4  */
5 ( function ( $ ) {
6         $( function () {
7                 var isTouchScreen,
8                         gettingFocus,
9                         galleries = 'ul.mw-gallery-packed-overlay, ul.mw-gallery-packed-hover, ul.mw-gallery-packed';
11                 // Is there a better way to detect a touchscreen? Current check taken from stack overflow.
12                 isTouchScreen = !!( window.ontouchstart !== undefined || window.DocumentTouch !== undefined && document instanceof window.DocumentTouch );
14                 if ( isTouchScreen ) {
15                         // Always show the caption for a touch screen.
16                         $( 'ul.mw-gallery-packed-hover' )
17                                 .addClass( 'mw-gallery-packed-overlay' )
18                                 .removeClass( 'mw-gallery-packed-hover' );
19                 } else {
20                         // Note use of just "a", not a.image, since we want this to trigger if a link in
21                         // the caption receives focus
22                         $( 'ul.mw-gallery-packed-hover li.gallerybox' ).on( 'focus blur', 'a', function ( e ) {
23                                 // Confusingly jQuery leaves e.type as focusout for delegated blur events
24                                 gettingFocus = e.type !== 'blur' && e.type !== 'focusout';
25                                 $( this ).closest( 'li.gallerybox' ).toggleClass( 'mw-gallery-focused', gettingFocus );
26                         } );
27                 }
29                 // Now on to justification.
30                 function justify() {
31                         var lastTop,
32                                 $img,
33                                 imgWidth,
34                                 imgHeight,
35                                 captionWidth,
36                                 rows = [],
37                                 $gallery = $( this );
39                         $gallery.children( 'li' ).each( function () {
40                                 // Math.floor to be paranoid if things are off by 0.00000000001
41                                 var top = Math.floor( $( this ).position().top ),
42                                         $this = $( this );
44                                 if ( top !== lastTop ) {
45                                         rows[rows.length] = [];
46                                         lastTop = top;
47                                 }
49                                 $img = $this.find( 'div.thumb a.image img' );
50                                 if ( $img.length && $img[0].height ) {
51                                         imgHeight = $img[0].height;
52                                         imgWidth = $img[0].width;
53                                 } else {
54                                         // If we don't have a real image, get the containing divs width/height.
55                                         // Note that if we do have a real image, using this method will generally
56                                         // give the same answer, but can be different in the case of a very
57                                         // narrow image where extra padding is added.
58                                         imgHeight = $this.children().children( 'div:first' ).height();
59                                         imgWidth = $this.children().children( 'div:first' ).width();
60                                 }
62                                 // Hack to make an edge case work ok
63                                 if ( imgHeight < 30 ) {
64                                         // Don't try and resize this item.
65                                         imgHeight = 0;
66                                 }
68                                 captionWidth = $this.children().children( 'div.gallerytextwrapper' ).width();
69                                 rows[rows.length - 1][rows[rows.length - 1].length] = {
70                                         $elm: $this,
71                                         width: $this.outerWidth(),
72                                         imgWidth: imgWidth,
73                                         // XXX: can divide by 0 ever happen?
74                                         aspect: imgWidth / imgHeight,
75                                         captionWidth: captionWidth,
76                                         height: imgHeight
77                                 };
79                                 // Save all boundaries so we can restore them on window resize
80                                 $this.data( 'imgWidth', imgWidth );
81                                 $this.data( 'imgHeight', imgHeight );
82                                 $this.data( 'width', $this.outerWidth() );
83                                 $this.data( 'captionWidth', captionWidth );
84                         } );
86                         ( function () {
87                                 var maxWidth,
88                                         combinedAspect,
89                                         combinedPadding,
90                                         curRow,
91                                         curRowHeight,
92                                         wantedWidth,
93                                         preferredHeight,
94                                         newWidth,
95                                         padding,
96                                         $outerDiv,
97                                         $innerDiv,
98                                         $imageDiv,
99                                         $imageElm,
100                                         imageElm,
101                                         $caption,
102                                         i,
103                                         j,
104                                         avgZoom,
105                                         totalZoom = 0;
107                                 for ( i = 0; i < rows.length; i++ ) {
108                                         maxWidth = $gallery.width();
109                                         combinedAspect = 0;
110                                         combinedPadding = 0;
111                                         curRow = rows[i];
112                                         curRowHeight = 0;
114                                         for ( j = 0; j < curRow.length; j++ ) {
115                                                 if ( curRowHeight === 0 ) {
116                                                         if ( isFinite( curRow[j].height ) ) {
117                                                                 // Get the height of this row, by taking the first
118                                                                 // non-out of bounds height
119                                                                 curRowHeight = curRow[j].height;
120                                                         }
121                                                 }
123                                                 if ( curRow[j].aspect === 0 || !isFinite( curRow[j].aspect ) ) {
124                                                         // One of the dimensions are 0. Probably should
125                                                         // not try to resize.
126                                                         combinedPadding += curRow[j].width;
127                                                 } else {
128                                                         combinedAspect += curRow[j].aspect;
129                                                         combinedPadding += curRow[j].width - curRow[j].imgWidth;
130                                                 }
131                                         }
133                                         // Add some padding for inter-element spacing.
134                                         combinedPadding += 5 * curRow.length;
135                                         wantedWidth = maxWidth - combinedPadding;
136                                         preferredHeight = wantedWidth / combinedAspect;
138                                         if ( preferredHeight > curRowHeight * 1.5 ) {
139                                                 // Only expand at most 1.5 times current size
140                                                 // As that's as high a resolution as we have.
141                                                 // Also on the off chance there is a bug in this
142                                                 // code, would prevent accidentally expanding to
143                                                 // be 10 billion pixels wide.
144                                                 if ( i === rows.length - 1 ) {
145                                                         // If its the last row, and we can't fit it,
146                                                         // don't make the entire row huge.
147                                                         avgZoom = ( totalZoom / ( rows.length - 1 ) ) * curRowHeight;
148                                                         if ( isFinite( avgZoom ) && avgZoom >= 1 && avgZoom <= 1.5 ) {
149                                                                 preferredHeight = avgZoom;
150                                                         } else {
151                                                                 // Probably a single row gallery
152                                                                 preferredHeight = curRowHeight;
153                                                         }
154                                                 } else {
155                                                         preferredHeight = 1.5 * curRowHeight;
156                                                 }
157                                         }
158                                         if ( !isFinite( preferredHeight ) ) {
159                                                 // This *definitely* should not happen.
160                                                 // Skip this row.
161                                                 continue;
162                                         }
163                                         if ( preferredHeight < 5 ) {
164                                                 // Well something clearly went wrong...
165                                                 // Skip this row.
166                                                 continue;
167                                         }
169                                         if ( preferredHeight / curRowHeight > 1 ) {
170                                                 totalZoom += preferredHeight / curRowHeight;
171                                         } else {
172                                                 // If we shrink, still consider that a zoom of 1
173                                                 totalZoom += 1;
174                                         }
176                                         for ( j = 0; j < curRow.length; j++ ) {
177                                                 newWidth = preferredHeight * curRow[j].aspect;
178                                                 padding = curRow[j].width - curRow[j].imgWidth;
179                                                 $outerDiv = curRow[j].$elm;
180                                                 $innerDiv = $outerDiv.children( 'div' ).first();
181                                                 $imageDiv = $innerDiv.children( 'div.thumb' );
182                                                 $imageElm = $imageDiv.find( 'img' ).first();
183                                                 imageElm = $imageElm.length ? $imageElm[0] : null;
184                                                 $caption = $outerDiv.find( 'div.gallerytextwrapper' );
186                                                 // Since we are going to re-adjust the height, the vertical
187                                                 // centering margins need to be reset.
188                                                 $imageDiv.children( 'div' ).css( 'margin', '0px auto' );
190                                                 if ( newWidth < 60 || !isFinite( newWidth ) ) {
191                                                         // Making something skinnier than this will mess up captions,
192                                                         if ( newWidth < 1 || !isFinite( newWidth ) ) {
193                                                                 $innerDiv.height( preferredHeight );
194                                                                 // Don't even try and touch the image size if it could mean
195                                                                 // making it disappear.
196                                                                 continue;
197                                                         }
198                                                 } else {
199                                                         $outerDiv.width( newWidth + padding );
200                                                         $innerDiv.width( newWidth + padding );
201                                                         $imageDiv.width( newWidth );
202                                                         $caption.width( curRow[j].captionWidth + ( newWidth - curRow[j].imgWidth ) );
203                                                 }
205                                                 if ( imageElm ) {
206                                                         // We don't always have an img, e.g. in the case of an invalid file.
207                                                         imageElm.width = newWidth;
208                                                         imageElm.height = preferredHeight;
209                                                 } else {
210                                                         // Not a file box.
211                                                         $imageDiv.height( preferredHeight );
212                                                 }
213                                         }
214                                 }
215                         }() );
216                 }
218                 $( galleries ).each( justify );
219                 $( window ).resize( $.debounce( 300, true, function () {
220                         $( galleries ).children( 'li' ).each( function () {
221                                 var imgWidth = $( this ).data( 'imgWidth' ),
222                                         imgHeight = $( this ).data( 'imgHeight' ),
223                                         width = $( this ).data( 'width' ),
224                                         captionWidth = $( this ).data( 'captionWidth' ),
225                                         $imageElm, imageElm;
227                                 // Restore original sizes so we can arrange the elements as on freshly loaded page
228                                 $( this ).width( width );
229                                 $( this ).children( 'div' ).first().width( width );
230                                 $( this ).children( 'div' ).first().children( 'div.thumb' ).width( imgWidth );
231                                 $( this ).find( 'div.gallerytextwrapper' ).width( captionWidth );
233                                 $imageElm = $( this ).find( 'img' ).first();
234                                 imageElm = $imageElm.length ? $imageElm[0] : null;
235                                 if ( imageElm ) {
236                                         imageElm.width = imgWidth;
237                                         imageElm.height = imgHeight;
238                                 }
239                         } );
240                 } ) );
241                 $( window ).resize( $.debounce( 300, function () {
242                         $( galleries ).each( justify );
243                 } ) );
244         } );
245 }( jQuery ) );