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)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
 * Citoid for Bharatpedia / BharatpediaNeo
 * Wikitext-safe: no raw HTML tag literals in this file.
 *
 * common.js:
 *   importScript('User:WikiDwarf/Citoid.js');
 */
( function ( $, mw ) {
	'use strict';

	var CITOID_ENDPOINT = 'https://en.wikipedia.org/api/rest_v1/data/citation/mediawiki/';
	var LT = String.fromCharCode( 60 );
	var GT = String.fromCharCode( 62 );
	var lastUrl = '';
	var msg = {
		'toolbox-label': 'Citoid',
		'toolbox-tooltip': 'Generate a Bharatpedia reference from a URL',
		title: 'Citoid - Bharatpedia',
		close: 'Close',
		generate: 'Generate citation',
		urlLabel: 'URL',
		dateLabel: 'Date format',
		codeLabel: 'Template code',
		rawLabel: 'Raw Citoid data',
		monthnames: [
			'January', 'February', 'March', 'April', 'May', 'June',
			'July', 'August', 'September', 'October', 'November', 'December'
		]
	};

	function el( tag, attrs, text ) {
		var node = document.createElement( tag );
		var k;
		attrs = attrs || {};
		for ( k in attrs ) {
			if ( Object.prototype.hasOwnProperty.call( attrs, k ) ) {
				node.setAttribute( k, attrs[ k ] );
			}
		}
		if ( text ) {
			node.textContent = text;
		}
		return node;
	}

	function escapePipes( val ) {
		if ( val === undefined || val === null ) {
			return '';
		}
		return String( val ).replace( /\|/g, '-' );
	}

	function formatCS1Date( isodate ) {
		if ( !isodate ) {
			return '';
		}
		var style = $( 'input[name=citoid-datestyle]:checked' ).val() || 'DMY';
		var raw = String( isodate );
		var test1 = raw.match( /(\d{4})-(\d{2})-(\d{2})/ );
		var test2 = raw.match( /([A-Z][a-z]+) (\d+), (\d{4})/ );
		var test3 = raw.match( /(\d{4})-(\d{2})(?:$|[^\d])/ );
		var day, month, year, daynum, monthnum, index;

		if ( test1 ) {
			year = test1[ 1 ];
			monthnum = test1[ 2 ];
			daynum = test1[ 3 ];
			day = parseInt( daynum, 10 );
			month = parseInt( monthnum, 10 ) - 1;
		} else if ( test2 ) {
			year = test2[ 3 ];
			day = parseInt( test2[ 2 ], 10 );
			daynum = day < 10 ? '0' + day : String( day );
			index = msg.monthnames.indexOf( test2[ 1 ] ) + 1;
			if ( index < 1 ) {
				return raw;
			}
			monthnum = index < 10 ? '0' + index : String( index );
			month = index - 1;
		} else if ( test3 ) {
			year = test3[ 1 ];
			monthnum = test3[ 2 ];
			month = parseInt( monthnum, 10 ) - 1;
			if ( style === 'MDY' ) {
				return msg.monthnames[ month ] + ', ' + year;
			}
			if ( style === 'YMD' ) {
				return year + '-' + monthnum;
			}
			return msg.monthnames[ month ] + ' ' + year;
		} else {
			return raw;
		}

		if ( style === 'MDY' ) {
			return msg.monthnames[ month ] + ' ' + day + ', ' + year;
		}
		if ( style === 'YMD' ) {
			return year + '-' + monthnum + '-' + daynum;
		}
		return day + ' ' + msg.monthnames[ month ] + ' ' + year;
	}

	var templateTypeMap = {
		book: 'Cite book',
		bookSection: 'Cite book',
		journalArticle: 'Cite journal',
		magazineArticle: 'Cite news',
		newspaperArticle: 'Cite news',
		thesis: 'Cite journal',
		webpage: 'Cite web',
		blogPost: 'Cite web',
		forumPost: 'Cite web',
		email: 'Cite web',
		report: 'Cite journal',
		conferencePaper: 'Cite journal',
		encyclopediaArticle: 'Cite journal',
		dictionaryEntry: 'Cite journal',
		presentation: 'Cite journal',
		manuscript: 'Cite book'
	};

	var webParams = {
		first1: 'author1-first', last1: 'author1-last',
		first2: 'author2-first', last2: 'author2-last',
		first3: 'author3-first', last3: 'author3-last',
		first4: 'author4-first', last4: 'author4-last',
		'access-date': 'accessDate',
		title: 'title', url: 'url', date: 'date',
		publisher: 'publisher', via: 'libraryCatalog',
		website: 'publicationTitle'
	};

	var newsParams = {
		first1: 'author1-first', last1: 'author1-last',
		first2: 'author2-first', last2: 'author2-last',
		first3: 'author3-first', last3: 'author3-last',
		first4: 'author4-first', last4: 'author4-last',
		'access-date': 'accessDate',
		title: 'title', url: 'url', publisher: 'publisher',
		newspaper: 'publicationTitle', date: 'date', location: 'place',
		issn: 'ISSN', pages: 'pages', volume: 'volume',
		issue: 'issue', via: 'libraryCatalog', doi: 'DOI'
	};

	var journalParams = {
		first1: 'author1-first', last1: 'author1-last',
		first2: 'author2-first', last2: 'author2-last',
		first3: 'author3-first', last3: 'author3-last',
		first4: 'author4-first', last4: 'author4-last',
		title: 'title', url: 'url', publisher: 'publisher',
		journal: 'publicationTitle', date: 'date', location: 'place',
		issn: 'ISSN', isbn: 'ISBN', pages: 'pages', volume: 'volume',
		issue: 'issue', pmid: 'PMID', pmc: 'PMCID', doi: 'DOI'
	};

	var bookParams = {
		first1: 'author1-first', last1: 'author1-last',
		first2: 'author2-first', last2: 'author2-last',
		first3: 'author3-first', last3: 'author3-last',
		first4: 'author4-first', last4: 'author4-last',
		title: 'title', url: 'url', publisher: 'publisher',
		journal: 'publicationTitle', date: 'date', location: 'place',
		issn: 'ISSN', isbn: 'ISBN', pages: 'pages', volume: 'volume',
		series: 'series', via: 'libraryCatalog', doi: 'DOI'
	};

	var templateParamMap = {
		'Cite web': webParams,
		'Cite news': newsParams,
		'Cite journal': journalParams,
		'Cite book': bookParams,
		Citation: journalParams
	};

	function getPlainObject( url, searchResults ) {
		var citation = ( searchResults && searchResults[ 0 ] ) ? searchResults[ 0 ] : {};
		var templateName = templateTypeMap[ citation.itemType ] || 'Cite web';
		var paramMap = templateParamMap[ templateName ] || webParams;
		var paramObj = {};
		var authors, i, n, pair;

		if ( !citation.url ) {
			citation.url = url;
		}
		if ( citation.PMCID ) {
			citation.url = null;
		}
		if ( citation.websiteTitle ) {
			citation.publicationTitle = citation.websiteTitle;
		}

		$.each( paramMap, function ( key, value ) {
			paramObj[ key ] = { wt: escapePipes( citation[ value ] ) };
		} );

		authors = citation.author;
		if ( $.isArray( authors ) ) {
			for ( i = 0; i < authors.length; i++ ) {
				n = i + 1;
				pair = authors[ i ] || [];
				paramObj[ 'first' + n ] = { wt: escapePipes( pair[ 0 ] ) };
				paramObj[ 'last' + n ] = { wt: escapePipes( pair[ 1 ] ) };
			}
		}

		if ( paramObj.date && paramObj.date.wt ) {
			paramObj.date.wt = formatCS1Date( paramObj.date.wt );
		}
		if ( paramObj[ 'access-date' ] && paramObj[ 'access-date' ].wt ) {
			paramObj[ 'access-date' ].wt = formatCS1Date( paramObj[ 'access-date' ].wt );
		}

		return {
			templateName: templateName.toLowerCase(),
			params: paramObj
		};
	}

	function buildTemplateCode( obj ) {
		var res = LT + 'ref' + GT + '{{' + obj.templateName;
		$.each( obj.params, function ( key, value ) {
			if ( value && value.wt ) {
				res += '|' + key + '=' + value.wt;
			}
		} );
		res += '}}' + LT + '/ref' + GT;
		return res;
	}

	function callCitoid() {
		var url = $.trim( $( '#citoid-url' ).val() );
		if ( !url ) {
			mw.notify( 'Enter a URL first.' );
			return;
		}
		lastUrl = url;
		$( '#citoid-code' ).val( 'Loading...' );
		$( '#citoid-full' ).val( '' );

		$.ajax( {
			url: CITOID_ENDPOINT + encodeURIComponent( url ),
			type: 'GET',
			dataType: 'json',
			success: function ( result ) {
				$( '#citoid-code' ).val( buildTemplateCode( getPlainObject( lastUrl, result ) ) );
				$( '#citoid-full' ).val( JSON.stringify( result, null, 2 ) );
			},
			error: function ( xhr, textStatus, errorThrown ) {
				var detail = textStatus + ( errorThrown ? ': ' + errorThrown : '' );
				mw.notify( 'Citoid failed - ' + detail );
				$( '#citoid-code' ).val( '' );
				$( '#citoid-full' ).val( detail );
			}
		} );
	}

	function openDialog() {
		$( '#citoid-cont' ).fadeIn( 'fast' );
		$( '#citoid-url' ).trigger( 'focus' );
	}

	function injectCSS() {
		mw.util.addCSS(
			'#citoid-cont{position:fixed;z-index:2000;inset:8% 10%;background:#fff;color:#202122;border:1px solid #a2a9b1;box-shadow:0 2px 16px rgba(0,0,0,.25);padding:12px 16px;overflow:auto;}' +
			'#citoid-dialog h2{margin:0 32px 8px 0;font-size:1.25em;}' +
			'#citoid-close{position:absolute;top:10px;right:12px;font-size:22px;text-decoration:none;}' +
			'#citoid-url,#citoid-code,#citoid-full{width:98%;}' +
			'#citoid-code,#citoid-full{min-height:8em;font-family:monospace;font-size:12px;}' +
			'#citoid-button{margin:8px 0;}' +
			'#citoid-floating{position:fixed;right:16px;bottom:16px;z-index:2001;}'
		);
	}

	function radio( value, label, checked ) {
		var wrap = el( 'label' );
		var input = el( 'input', { type: 'radio', name: 'citoid-datestyle', value: value } );
		if ( checked ) {
			input.checked = true;
		}
		wrap.appendChild( input );
		wrap.appendChild( document.createTextNode( ' ' + label ) );
		return wrap;
	}

	function buildHTML() {
		var cont = el( 'div', { id: 'citoid-cont' } );
		var dialog = el( 'div', { id: 'citoid-dialog' } );
		var close = el( 'a', { id: 'citoid-close', href: '#' }, 'x' );
		var body = el( 'div', { id: 'citoid-body' } );
		var urlP = el( 'p' );
		var dateP = el( 'p' );
		var gen = el( 'button', { id: 'citoid-button', type: 'button' }, msg.generate );
		var code = el( 'textarea', { id: 'citoid-code' } );
		var full = el( 'textarea', { id: 'citoid-full' } );

		cont.style.display = 'none';
		close.onclick = function ( e ) {
			e.preventDefault();
			$( cont ).fadeOut( 'fast' );
		};
		gen.onclick = callCitoid;

		urlP.appendChild( document.createTextNode( msg.urlLabel + ': ' ) );
		urlP.appendChild( el( 'input', { type: 'text', id: 'citoid-url', size: '80' } ) );

		dateP.appendChild( document.createTextNode( msg.dateLabel + ': ' ) );
		dateP.appendChild( radio( 'DMY', '1 September 2014', true ) );
		dateP.appendChild( document.createTextNode( '  ' ) );
		dateP.appendChild( radio( 'MDY', 'September 1, 2014', false ) );
		dateP.appendChild( document.createTextNode( '  ' ) );
		dateP.appendChild( radio( 'YMD', '2014-09-01', false ) );

		dialog.appendChild( el( 'h2', {}, msg.title ) );
		dialog.appendChild( close );
		body.appendChild( urlP );
		body.appendChild( dateP );
		body.appendChild( gen );
		body.appendChild( el( 'p', {}, msg.codeLabel ) );
		body.appendChild( code );
		body.appendChild( el( 'p', {}, msg.rawLabel ) );
		body.appendChild( full );
		dialog.appendChild( body );
		cont.appendChild( dialog );
		document.body.appendChild( cont );
	}

	function bindOpener( node ) {
		if ( !node ) {
			return;
		}
		$( node ).on( 'click', function ( e ) {
			e.preventDefault();
			openDialog();
		} );
	}

	function addEntryPoint() {
		var node, i, portlets, btn, slot;
		portlets = [ 'p-cactions', 'p-views', 'p-tb' ];
		slot = document.getElementById( 'antivandal-slot' );

		btn = el( 'button', {
			type: 'button',
			id: 't-citoid',
			title: msg[ 'toolbox-tooltip' ]
		}, msg[ 'toolbox-label' ] );

		if ( slot && !document.getElementById( 't-citoid' ) ) {
			slot.appendChild( btn );
			bindOpener( btn );
			return;
		}

		node = null;
		for ( i = 0; i < portlets.length; i++ ) {
			node = mw.util.addPortletLink(
				portlets[ i ],
				'#',
				msg[ 'toolbox-label' ],
				't-citoid',
				msg[ 'toolbox-tooltip' ]
			);
			if ( node ) {
				break;
			}
		}

		if ( !node ) {
			btn.id = 'citoid-floating';
			document.body.appendChild( btn );
			node = btn;
		}
		bindOpener( node );
	}

	mw.loader.using( 'mediawiki.util' ).then( function () {
		$( function () {
			injectCSS();
			buildHTML();
			addEntryPoint();
		} );
	} );

}( jQuery, mediaWiki ) );