summaryrefslogtreecommitdiff
path: root/resources/src/mediawiki.page/mediawiki.page.gallery.js
diff options
context:
space:
mode:
Diffstat (limited to 'resources/src/mediawiki.page/mediawiki.page.gallery.js')
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.gallery.js425
1 files changed, 240 insertions, 185 deletions
diff --git a/resources/src/mediawiki.page/mediawiki.page.gallery.js b/resources/src/mediawiki.page/mediawiki.page.gallery.js
index 1892967a..95140704 100644
--- a/resources/src/mediawiki.page/mediawiki.page.gallery.js
+++ b/resources/src/mediawiki.page/mediawiki.page.gallery.js
@@ -2,211 +2,266 @@
* Show gallery captions when focused. Copied directly from jquery.mw-jump.js.
* Also Dynamically resize images to justify them.
*/
-( function ( $ ) {
- $( function () {
- var isTouchScreen,
- gettingFocus,
- galleries = 'ul.mw-gallery-packed-overlay, ul.mw-gallery-packed-hover, ul.mw-gallery-packed';
-
+( function ( mw, $ ) {
+ var $galleries,
+ bound = false,
// Is there a better way to detect a touchscreen? Current check taken from stack overflow.
- isTouchScreen = !!( window.ontouchstart !== undefined || window.DocumentTouch !== undefined && document instanceof window.DocumentTouch );
+ isTouchScreen = !!( window.ontouchstart !== undefined ||
+ window.DocumentTouch !== undefined && document instanceof window.DocumentTouch
+ );
- if ( isTouchScreen ) {
- // Always show the caption for a touch screen.
- $( 'ul.mw-gallery-packed-hover' )
- .addClass( 'mw-gallery-packed-overlay' )
- .removeClass( 'mw-gallery-packed-hover' );
- } else {
- // Note use of just "a", not a.image, since we want this to trigger if a link in
- // the caption receives focus
- $( 'ul.mw-gallery-packed-hover li.gallerybox' ).on( 'focus blur', 'a', function ( e ) {
- // Confusingly jQuery leaves e.type as focusout for delegated blur events
- gettingFocus = e.type !== 'blur' && e.type !== 'focusout';
- $( this ).closest( 'li.gallerybox' ).toggleClass( 'mw-gallery-focused', gettingFocus );
- } );
- }
+ /**
+ * Perform the layout justification.
+ * @ignore
+ * @context {HTMLElement} A `ul.mw-gallery-*` element
+ */
+ function justify() {
+ var lastTop,
+ $img,
+ imgWidth,
+ imgHeight,
+ captionWidth,
+ rows = [],
+ $gallery = $( this );
- // Now on to justification.
- // We may still get ragged edges if someone resizes their window. Could bind to
- // that event, otoh do we really want to constantly be resizing galleries?
- $( galleries ).each( function () {
- var lastTop,
- $img,
- imgWidth,
- imgHeight,
- rows = [],
- $gallery = $( this );
-
- $gallery.children( 'li' ).each( function () {
- // Math.floor to be paranoid if things are off by 0.00000000001
- var top = Math.floor( $( this ).position().top ),
- $this = $( this );
-
- if ( top !== lastTop ) {
- rows[rows.length] = [];
- lastTop = top;
- }
+ $gallery.children( 'li' ).each( function () {
+ // Math.floor to be paranoid if things are off by 0.00000000001
+ var top = Math.floor( $( this ).position().top ),
+ $this = $( this );
- $img = $this.find( 'div.thumb a.image img' );
- if ( $img.length && $img[0].height ) {
- imgHeight = $img[0].height;
- imgWidth = $img[0].width;
- } else {
- // If we don't have a real image, get the containing divs width/height.
- // Note that if we do have a real image, using this method will generally
- // give the same answer, but can be different in the case of a very
- // narrow image where extra padding is added.
- imgHeight = $this.children().children( 'div:first' ).height();
- imgWidth = $this.children().children( 'div:first' ).width();
- }
+ if ( top !== lastTop ) {
+ rows[rows.length] = [];
+ lastTop = top;
+ }
- // Hack to make an edge case work ok
- if ( imgHeight < 30 ) {
- // Don't try and resize this item.
- imgHeight = 0;
- }
+ $img = $this.find( 'div.thumb a.image img' );
+ if ( $img.length && $img[0].height ) {
+ imgHeight = $img[0].height;
+ imgWidth = $img[0].width;
+ } else {
+ // If we don't have a real image, get the containing divs width/height.
+ // Note that if we do have a real image, using this method will generally
+ // give the same answer, but can be different in the case of a very
+ // narrow image where extra padding is added.
+ imgHeight = $this.children().children( 'div:first' ).height();
+ imgWidth = $this.children().children( 'div:first' ).width();
+ }
- rows[rows.length - 1][rows[rows.length - 1].length] = {
- $elm: $this,
- width: $this.outerWidth(),
- imgWidth: imgWidth,
- // XXX: can divide by 0 ever happen?
- aspect: imgWidth / imgHeight,
- captionWidth: $this.children().children( 'div.gallerytextwrapper' ).width(),
- height: imgHeight
- };
- } );
+ // Hack to make an edge case work ok
+ if ( imgHeight < 30 ) {
+ // Don't try and resize this item.
+ imgHeight = 0;
+ }
- ( function () {
- var maxWidth,
- combinedAspect,
- combinedPadding,
- curRow,
- curRowHeight,
- wantedWidth,
- preferredHeight,
- newWidth,
- padding,
- $outerDiv,
- $innerDiv,
- $imageDiv,
- $imageElm,
- imageElm,
- $caption,
- i,
- j,
- avgZoom,
- totalZoom = 0;
-
- for ( i = 0; i < rows.length; i++ ) {
- maxWidth = $gallery.width();
- combinedAspect = 0;
- combinedPadding = 0;
- curRow = rows[i];
- curRowHeight = 0;
-
- for ( j = 0; j < curRow.length; j++ ) {
- if ( curRowHeight === 0 ) {
- if ( isFinite( curRow[j].height ) ) {
- // Get the height of this row, by taking the first
- // non-out of bounds height
- curRowHeight = curRow[j].height;
- }
- }
+ captionWidth = $this.children().children( 'div.gallerytextwrapper' ).width();
+ rows[rows.length - 1][rows[rows.length - 1].length] = {
+ $elm: $this,
+ width: $this.outerWidth(),
+ imgWidth: imgWidth,
+ // XXX: can divide by 0 ever happen?
+ aspect: imgWidth / imgHeight,
+ captionWidth: captionWidth,
+ height: imgHeight
+ };
- if ( curRow[j].aspect === 0 || !isFinite( curRow[j].aspect ) ) {
- // One of the dimensions are 0. Probably should
- // not try to resize.
- combinedPadding += curRow[j].width;
- } else {
- combinedAspect += curRow[j].aspect;
- combinedPadding += curRow[j].width - curRow[j].imgWidth;
- }
- }
+ // Save all boundaries so we can restore them on window resize
+ $this.data( 'imgWidth', imgWidth );
+ $this.data( 'imgHeight', imgHeight );
+ $this.data( 'width', $this.outerWidth() );
+ $this.data( 'captionWidth', captionWidth );
+ } );
- // Add some padding for inter-element spacing.
- combinedPadding += 5 * curRow.length;
- wantedWidth = maxWidth - combinedPadding;
- preferredHeight = wantedWidth / combinedAspect;
-
- if ( preferredHeight > curRowHeight * 1.5 ) {
- // Only expand at most 1.5 times current size
- // As that's as high a resolution as we have.
- // Also on the off chance there is a bug in this
- // code, would prevent accidentally expanding to
- // be 10 billion pixels wide.
- if ( i === rows.length - 1 ) {
- // If its the last row, and we can't fit it,
- // don't make the entire row huge.
- avgZoom = ( totalZoom / ( rows.length - 1 ) ) * curRowHeight;
- if ( isFinite( avgZoom ) && avgZoom >= 1 && avgZoom <= 1.5 ) {
- preferredHeight = avgZoom;
- } else {
- // Probably a single row gallery
- preferredHeight = curRowHeight;
- }
- } else {
- preferredHeight = 1.5 * curRowHeight;
+ ( function () {
+ var maxWidth,
+ combinedAspect,
+ combinedPadding,
+ curRow,
+ curRowHeight,
+ wantedWidth,
+ preferredHeight,
+ newWidth,
+ padding,
+ $outerDiv,
+ $innerDiv,
+ $imageDiv,
+ $imageElm,
+ imageElm,
+ $caption,
+ i,
+ j,
+ avgZoom,
+ totalZoom = 0;
+
+ for ( i = 0; i < rows.length; i++ ) {
+ maxWidth = $gallery.width();
+ combinedAspect = 0;
+ combinedPadding = 0;
+ curRow = rows[i];
+ curRowHeight = 0;
+
+ for ( j = 0; j < curRow.length; j++ ) {
+ if ( curRowHeight === 0 ) {
+ if ( isFinite( curRow[j].height ) ) {
+ // Get the height of this row, by taking the first
+ // non-out of bounds height
+ curRowHeight = curRow[j].height;
}
}
- if ( !isFinite( preferredHeight ) ) {
- // This *definitely* should not happen.
- // Skip this row.
- continue;
- }
- if ( preferredHeight < 5 ) {
- // Well something clearly went wrong...
- // Skip this row.
- continue;
- }
- if ( preferredHeight / curRowHeight > 1 ) {
- totalZoom += preferredHeight / curRowHeight;
+ if ( curRow[j].aspect === 0 || !isFinite( curRow[j].aspect ) ) {
+ // One of the dimensions are 0. Probably should
+ // not try to resize.
+ combinedPadding += curRow[j].width;
} else {
- // If we shrink, still consider that a zoom of 1
- totalZoom += 1;
+ combinedAspect += curRow[j].aspect;
+ combinedPadding += curRow[j].width - curRow[j].imgWidth;
}
+ }
- for ( j = 0; j < curRow.length; j++ ) {
- newWidth = preferredHeight * curRow[j].aspect;
- padding = curRow[j].width - curRow[j].imgWidth;
- $outerDiv = curRow[j].$elm;
- $innerDiv = $outerDiv.children( 'div' ).first();
- $imageDiv = $innerDiv.children( 'div.thumb' );
- $imageElm = $imageDiv.find( 'img' ).first();
- imageElm = $imageElm.length ? $imageElm[0] : null;
- $caption = $outerDiv.find( 'div.gallerytextwrapper' );
-
- // Since we are going to re-adjust the height, the vertical
- // centering margins need to be reset.
- $imageDiv.children( 'div' ).css( 'margin', '0px auto' );
-
- if ( newWidth < 60 || !isFinite( newWidth ) ) {
- // Making something skinnier than this will mess up captions,
- if ( newWidth < 1 || !isFinite( newWidth ) ) {
- $innerDiv.height( preferredHeight );
- // Don't even try and touch the image size if it could mean
- // making it disappear.
- continue;
- }
+ // Add some padding for inter-element spacing.
+ combinedPadding += 5 * curRow.length;
+ wantedWidth = maxWidth - combinedPadding;
+ preferredHeight = wantedWidth / combinedAspect;
+
+ if ( preferredHeight > curRowHeight * 1.5 ) {
+ // Only expand at most 1.5 times current size
+ // As that's as high a resolution as we have.
+ // Also on the off chance there is a bug in this
+ // code, would prevent accidentally expanding to
+ // be 10 billion pixels wide.
+ if ( i === rows.length - 1 ) {
+ // If its the last row, and we can't fit it,
+ // don't make the entire row huge.
+ avgZoom = ( totalZoom / ( rows.length - 1 ) ) * curRowHeight;
+ if ( isFinite( avgZoom ) && avgZoom >= 1 && avgZoom <= 1.5 ) {
+ preferredHeight = avgZoom;
} else {
- $outerDiv.width( newWidth + padding );
- $innerDiv.width( newWidth + padding );
- $imageDiv.width( newWidth );
- $caption.width( curRow[j].captionWidth + ( newWidth - curRow[j].imgWidth ) );
+ // Probably a single row gallery
+ preferredHeight = curRowHeight;
}
+ } else {
+ preferredHeight = 1.5 * curRowHeight;
+ }
+ }
+ if ( !isFinite( preferredHeight ) ) {
+ // This *definitely* should not happen.
+ // Skip this row.
+ continue;
+ }
+ if ( preferredHeight < 5 ) {
+ // Well something clearly went wrong...
+ // Skip this row.
+ continue;
+ }
- if ( imageElm ) {
- // We don't always have an img, e.g. in the case of an invalid file.
- imageElm.width = newWidth;
- imageElm.height = preferredHeight;
- } else {
- // Not a file box.
- $imageDiv.height( preferredHeight );
+ if ( preferredHeight / curRowHeight > 1 ) {
+ totalZoom += preferredHeight / curRowHeight;
+ } else {
+ // If we shrink, still consider that a zoom of 1
+ totalZoom += 1;
+ }
+
+ for ( j = 0; j < curRow.length; j++ ) {
+ newWidth = preferredHeight * curRow[j].aspect;
+ padding = curRow[j].width - curRow[j].imgWidth;
+ $outerDiv = curRow[j].$elm;
+ $innerDiv = $outerDiv.children( 'div' ).first();
+ $imageDiv = $innerDiv.children( 'div.thumb' );
+ $imageElm = $imageDiv.find( 'img' ).first();
+ imageElm = $imageElm.length ? $imageElm[0] : null;
+ $caption = $outerDiv.find( 'div.gallerytextwrapper' );
+
+ // Since we are going to re-adjust the height, the vertical
+ // centering margins need to be reset.
+ $imageDiv.children( 'div' ).css( 'margin', '0px auto' );
+
+ if ( newWidth < 60 || !isFinite( newWidth ) ) {
+ // Making something skinnier than this will mess up captions,
+ if ( newWidth < 1 || !isFinite( newWidth ) ) {
+ $innerDiv.height( preferredHeight );
+ // Don't even try and touch the image size if it could mean
+ // making it disappear.
+ continue;
}
+ } else {
+ $outerDiv.width( newWidth + padding );
+ $innerDiv.width( newWidth + padding );
+ $imageDiv.width( newWidth );
+ $caption.width( curRow[j].captionWidth + ( newWidth - curRow[j].imgWidth ) );
+ }
+
+ if ( imageElm ) {
+ // We don't always have an img, e.g. in the case of an invalid file.
+ imageElm.width = newWidth;
+ imageElm.height = preferredHeight;
+ } else {
+ // Not a file box.
+ $imageDiv.height( preferredHeight );
}
}
- }() );
+ }
+ }() );
+ }
+
+ function handleResizeStart() {
+ $galleries.children( 'li' ).each( function () {
+ var imgWidth = $( this ).data( 'imgWidth' ),
+ imgHeight = $( this ).data( 'imgHeight' ),
+ width = $( this ).data( 'width' ),
+ captionWidth = $( this ).data( 'captionWidth' ),
+ $innerDiv = $( this ).children( 'div' ).first(),
+ $imageDiv = $innerDiv.children( 'div.thumb' ),
+ $imageElm, imageElm;
+
+ // Restore original sizes so we can arrange the elements as on freshly loaded page
+ $( this ).width( width );
+ $innerDiv.width( width );
+ $imageDiv.width( imgWidth );
+ $( this ).find( 'div.gallerytextwrapper' ).width( captionWidth );
+
+ $imageElm = $( this ).find( 'img' ).first();
+ imageElm = $imageElm.length ? $imageElm[0] : null;
+ if ( imageElm ) {
+ imageElm.width = imgWidth;
+ imageElm.height = imgHeight;
+ } else {
+ $imageDiv.height( imgHeight );
+ }
+ } );
+ }
+
+ function handleResizeEnd() {
+ $galleries.each( justify );
+ }
+
+ mw.hook( 'wikipage.content' ).add( function ( $content ) {
+ if ( isTouchScreen ) {
+ // Always show the caption for a touch screen.
+ $content.find( 'ul.mw-gallery-packed-hover' )
+ .addClass( 'mw-gallery-packed-overlay' )
+ .removeClass( 'mw-gallery-packed-hover' );
+ } else {
+ // Note use of just "a", not a.image, since we want this to trigger if a link in
+ // the caption receives focus
+ $content.find( 'ul.mw-gallery-packed-hover li.gallerybox' ).on( 'focus blur', 'a', function ( e ) {
+ // Confusingly jQuery leaves e.type as focusout for delegated blur events
+ var gettingFocus = e.type !== 'blur' && e.type !== 'focusout';
+ $( this ).closest( 'li.gallerybox' ).toggleClass( 'mw-gallery-focused', gettingFocus );
+ } );
+ }
+
+ $galleries = $content.find( 'ul.mw-gallery-packed-overlay, ul.mw-gallery-packed-hover, ul.mw-gallery-packed' );
+ // Call the justification asynchronous because live preview fires the hook with detached $content.
+ setTimeout( function () {
+ $galleries.each( justify );
+
+ // Bind here instead of in the top scope as the callbacks use $galleries.
+ if ( !bound ) {
+ bound = true;
+ $( window )
+ .resize( $.debounce( 300, true, handleResizeStart ) )
+ .resize( $.debounce( 300, handleResizeEnd ) );
+ }
} );
} );
-}( jQuery ) );
+}( mediaWiki, jQuery ) );