MediaWiki:Gadget-Preview.js

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
// -------------------------------------------------------------------------------------------------------------
// Shows a "preview" button next to each linked article to get a preview of the article right next to the table.
// Much thanks to User:Denny/articlePreview.js, from which I got the idea.
//
// Usage: Enable the gadget Preview in your preferences.
// -------------------------------------------------------------------------------------------------------------

( function ( mw, $, wb ) {
	"use strict";

	if ( mw.config.get( 'wgNamespaceNumber' ) !== 0 ||
		!mw.config.exists( 'wbEntityId' )
	) {
		return;
	}

	var translations = require( './Preview-i18n.json' );
	$.i18n().load( translations );

	var html = '\
<div class="articlepreview mw-body-content">\
	<div class="toggler"></div>\
	<div class="container">\
		<h2 class="title"></h2>\
		<div class="content">\
			\
		</div>\
	</div>\
</div>';

	var sitelinks;

	/**
	 * The cached previews.
	 */
	var cache = {};

	/**
	 * The html elements.
	 */
	var $articlepreview, $title, $content, $container, $toggler;

	/**
	 * The wikimedia commons site.
	 */
	var commons = wb.sites.getSite( 'commonswiki' );

	function updatePosition () {
		if ( $( window ).scrollTop() < 90 ) {
			$articlepreview.removeClass( 'fixed' );
		} else {
			$articlepreview.addClass( 'fixed' );
		}
	}

	function show() {
		if ( $articlepreview.hasClass( 'open' ) ) {
			return;
		}
		$toggler.attr( 'title', $.i18n( 'gadget-preview-title' ) + ' — ' + $.i18n( 'gadget-preview-hide' ) );
		var width = Math.max( $( window ).width() - 1300, 400 );
		$articlepreview.addClass( 'open' ).animate( {
			width: width + 'px'
		} );
		$container.width( ( width - 40 ) + 'px' );
	}

	function hide() {
		$articlepreview.animate( {
			width: '0px'
		}, function () {
			$articlepreview.removeClass( 'open' );
			$toggler.attr( 'title', $.i18n( 'gadget-preview-title' ) + ' — ' + $.i18n( 'gadget-preview-show' ) );
		} );
	}

	/**
	 * Adds the html to the preview widget.
	 *
	 * @param wiki the wiki to show
	 */
	function showPreview( site ) {
		var data = cache[ site.getId() ];

		$title
		.attr( 'dir', data.dir )
		.attr( 'lang', data.lang )
		.html( ( data.displaytitle || mw.html.escape( data.title ) ) + ' — ' + site.getName() + ' ' )
		.append(
			$( '<span>' )
			.attr( 'dir', 'ltr' )
			.attr( 'lang', 'en' )
			.text( '(' + site.getId() + ')' )
		);

		$content
		.attr( {
			'class': data.dir ? 'mw-content-' + data.dir : undefined,
			'dir': data.dir,
			'lang': data.lang
		} )
		.html( data.content )
		.append(
			$( '<p>' )
			.append(
				$( '<a>' )
				.attr( {
					'href': site.getUrlTo( data.title ),
					'title': site.getId() + ':' + data.title
				} )
				.text( $.i18n( 'gadget-preview-readmore' ) )
			) // </a>
		); // </p>

		if ( data.image ) {
			$content.prepend(
				$( '<a>' )
				.attr( 'href', data.image.url )
				.append(
					$( '<img>' )
					.attr( {
						'src': data.image.source,
						'width': data.image.width,
						'height': data.image.height,
						'class': 'thumbnail',
						'title': data.image.name,
						'alt': data.image.name
					} )
				)
			);
		}
	}

	/**
	 * Showing the preview got by an http request. Requests are cached.
	 *
	 * @param site the current site object
	 */
	function preview( site ) {
		var wiki = site.getId(),
			sitelink = sitelinks[ wiki ];

		show(); // show the widget

		if ( !sitelink ) {
			return;
		}

		if ( cache.hasOwnProperty( wiki ) ) {
			showPreview( site );
		} else {
			$.createSpinner( {
				size: 'small',
				type: 'block'
			} ).appendTo( $content.empty() );
			var api = new mw.Api( {
				ajax: {
					url: site.getApi(),
					dataType: 'jsonp',
					cache: true
				},
				parameters: {
					formatversion: 2
				}
			} );
			api.get( {
				action: 'query',
				prop: 'extracts|info|pageprops|pageimages',
				exintro: true,
				exchars: 1000,
				piprop: 'thumbnail',
				pithumbsize: Math.floor( $container.width() / 2 ),
				titles: sitelink.title,
			} )
			.done( function ( data ) {
				var page = data.query.pages[ Object.keys( data.query.pages )[ 0 ] ];
				if ( page.missing ) {
					cache[ wiki ] = {
						content: '<p class="error">' + mw.html.escape( $.i18n( 'gadget-preview-missing' ) ) + '</p>',
						title: sitelink.title
					};
				} else {
					cache[ wiki ] = {
						content: page.extract.replace( /<\/p>(…|...)/, '…</p>' ),
						dir: page.pagelanguagedir,
						lang: page.pagelanguagehtmlcode,
						title: sitelink.title,
						displaytitle: page.pageprops && page.pageprops.displaytitle
					};
					if ( page.pageprops && page.pageprops.page_image && page.thumbnail ) {
						cache[ wiki ].image = {
							source: page.thumbnail.source,
							width: page.thumbnail.width,
							height: page.thumbnail.height,
							url: commons.getUrlTo( 'File:' + page.pageprops.page_image ),
							name: page.pageprops.page_image
						};
					}
				}
				showPreview( site );
			} );
		}
	}

	/**
	 * Initialising the links.
	 */
	function init() {
		var lang = mw.config.get( 'wgUserLanguage' );
		var wiki = lang + 'wiki'; // guess default wiki
		var site = wb.sites.getSite( wiki );

		mw.util.$content.append( html );

		$articlepreview = $( '.articlepreview' );
		$title = $articlepreview.find( '.title' ).text( $.i18n( 'gadget-preview-title' ) );
		$content = $articlepreview.find( '.content' ).text( $.i18n( 'gadget-preview-noarticle' ) );
		$container = $articlepreview.find( '.container' )
		// 100px is the top position of the container set on the css page
		.css( 'max-height', ( $( window ).height() - 100 ) + 'px' );

		$toggler = $articlepreview.find( '.toggler' )
		.attr( 'title', $.i18n( 'gadget-preview-title' ) + ' — ' + $.i18n( 'gadget-preview-show' ) )
		.click( function () {
			if ( $articlepreview.hasClass( 'open' ) ) {
				hide();
			} else {
				show();
			}
		} );

		$( window ).scroll( updatePosition );
		updatePosition();

		if ( sitelinks[ wiki ] ) {
			if ( $( window ).width() > 1600 && !$( 'body' ).hasClass( 'wb-diffpage' ) ) {
				preview( site );
			} else {
				$content
				.append( '<br>&nbsp;&rarr;&nbsp;' )
				.append(
					site.getLinkTo( sitelinks[ wiki ].title )
					.click( function ( e ) {
						e.preventDefault();
						preview( site );
					} ) // </a>
				);
			}
		}

		$( '.wikibase-sitelinkview' ).each( function () {
			var wiki = $( this ).data( 'wbSiteid' ),
				site = wb.sites.getSite( wiki );

			$( this ).prepend(
				$( '<a>' )
				.attr( {
					'class': 'articlepreview-button',
					title: $.i18n( 'gadget-preview-preview' ),
					href: site.getUrlTo( sitelinks[ wiki ].title )
				} )
				.click( function ( e ) {
					e.preventDefault();
					preview( site );
				} )
			);
		} );
	}

	var entityLoaded = $.Deferred();

	$.when(
		entityLoaded,
		$.ready
	).done( init );

	mw.hook( 'wikibase.entityPage.entityLoaded' ).add( function ( entity ) {
		sitelinks = entity.sitelinks;
		if ( sitelinks ) {
			entityLoaded.resolve();
		} else {
			entityLoaded.reject();
		}
	} );

}( mediaWiki, jQuery, wikibase ) );