Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
function findHeading( $el ) {
	while( !$el.is( '#bodyContent' ) ) {
		var $prev = $el.prevAll( 'h1,h2,h3,h4,h5,h6' );
		if ( $prev.length ) {
			return $prev.first();
		}
		$el = $el.parent();
	}

	return $();
}

function getSectionNumber( $el ) {
	var editLink = findHeading( $el ).find( '.mw-editsection a' ).attr( 'href' ),
		matches = editLink ? editLink.match( /&section=([^&]+)/ ) : null;
	return $.isArray( matches ) ? parseInt( matches[1] ) : 0;
}

function ucfirst( s ) {
	var ch = s.charAt( 0 ).toUpperCase();
	return ch + s.substr( 1 );
}

function normalizeTitle( title ) {
	return ucfirst( decodeURIComponent( title )
		.replace( '_', ' ' )
		.replace( / +/, ' ' )
		.trim()
	);
}

function findDabLink( text, faceText, dest ) {
	var matches,
		match,
		i,
		template,
		link,
		linkFace,
		result = {};

	dest = dest.trim();
	matches = text.match( /\[\[[^\[\]]*?\]\][^\[\]]{0,20}\s*\{\{.*?\}\}/g );
	if ( !matches ) {
		return false;
	}
	for ( i = 0; i < matches.length; i++ ) {
		match = matches[i];
		var linkMatches = match.match( /\[\[\s*(.+?)\s*(?:|\|\s*(.+?))\s*\]\]/ );
		var templateMatches = match.match( /\s*\{\{\s*(.+?)\s*(?:|\|\s*(.+?))\s*\}\}/ );
		if ( linkMatches && templateMatches ) {
			link = normalizeTitle( linkMatches[1] );
			template = normalizeTitle( templateMatches[1] );
			linkFace = linkMatches[2] === undefined ? linkMatches[1] : linkMatches[2]; 
			if ( link == dest
				&& linkFace == faceText
				&& template.match( /Dn|Disambiguation needed/ )
			) {
				return {
					match: match,
					linkText: linkMatches[0],
					link: link,
					rawLink: linkMatches[1],
					face: faceText,
					template: templateMatches[0]
				};
			}
		}
	}
	return false;
}

function getDabVariants( title ) {
	var api = new mw.Api();

	return api.get( {
		action: 'query',
		prop: 'links',
		plnamespace: 0,
		pllimit: 'max',
		titles: title,
		redirects: 1
	} ).then(
		function( data ) {
			var links = [];
			$.each( data.query.pages, function( i, page ) {
				$.each( page.links, function( i, link ) {
					links.push( link.title );
				} );
			} );
			return links.sort();
		}
	);
}

function getWikiText( page, section ) {
	var api = new mw.Api();

	return api.get( {
		action: 'parse',
		page: page,
		prop: 'wikitext',
		section: section
	} ).then( function( data ) {
		return data.parse.wikitext['*'];
	} );
}

function doDabDialog( section, faceText, dest ) {
	var disambiguationResult,
		buttons = {
			Cancel: function() {
				$( this ).dialog( 'close' );
			},
		},
		saveButton = function() {
			var api = new mw.Api();

			api.postWithToken( 'edit', {
				action: 'edit',
				title: mw.config.get( 'wgPageName' ),
				section: section,
				text: $( '#dabtext' ).val(),
				summary: 'Disambiguated [[' + dest + ']] to [[' + disambiguationResult + ']]'
			} ).done( function() {
				location.reload();
			} );
			$( this )
				.text( 'Saving...' )
				.dialog( { buttons: {} } );
		},
		$content = $( '<div>' )
			.append( $( '<div id="dab-dialog">' ).append(
				$.createSpinner().after( $( '<span>Loading...</span>' ) )
			) )
			.dialog( {
				modal: true,
				buttons: buttons,
				width: '80%',
				height: 400
			} );
	
	$.when(
		getWikiText( mw.config.get( 'wgPageName' ), section ),
		getDabVariants( dest )
	).done( function( wikitext, links ) {
			var $select,
				dab = findDabLink( wikitext, faceText, dest ),
				newWikitext;

			if ( !dab ) {
				$content.text( 'Could not find a link to correct. Edit manually?' );
				return;
			}
			$select = $( '<select>' )
				.append(
					$( '<option>' )
						.attr( 'value', '' )
						.text( 'Select a destination article...' )
				)
				.on( 'change', function() {
					var val = $select.val(),
						newLink;
					if ( val === '' ) {
						return;
					}
					disambiguationResult = val;
					newLink = dab.match
						.replace( dab.linkText, '[[' + val + '|' + dab.face + ']]' )
						.replace( dab.template, '' );
					newWikitext = wikitext.replace( dab.match, newLink );
					$( '#dabtext' )
						.val( newWikitext )
						.show();
					if ( !window.find( newLink, false, true ) ) {
						window.find( newLink, false, false );
				    }
				} );
			$.each( links, function( i, link ) {
				$select.append(
					$( '<option>' )
						.attr( 'value', link )
						.text( link )
				);
			} );
			buttons.Save = saveButton;
			
			$content.html( '' )
				.append(
					$( '<div>' )
						.append( $( '<textarea rows="20" id="dabtext" style="display: none">' )
							.val( wikitext )
						)
						.append( $select )
				).dialog( {	buttons: buttons } );
		} )
		.fail( function() {
			$content.text( 'zomgfailed' );
		} );
}

$( 'sup.Inline-Template a' ).each( function() {
	var href = this.getAttribute( 'href' ) || '',
		$link = $( this );
	if ( !href.indexOf( 'editintro=Template:Disambiguation_needed/editintro' ) ) {
		return;
	}
	$link.on( 'click.dab', function( e ) {
		e.preventDefault();
		mw.loader.using( [ 'jquery.ui', 'jquery.spinner' ], function() {
			var section = getSectionNumber( $link ),
				$dabLink = $link.parents( 'sup' ).prev( 'a' ),
				faceText = $dabLink.text(),
				dest = $dabLink.attr( 'href' );
			if ( $dabLink.length != 1
				|| $dabLink.is( '.external' )
				|| !dest.match( /^\/wiki\// ) )
			{
				return;
			}
			dest = normalizeTitle( dest.replace( /^\/wiki\//, '' ) );
			doDabDialog( section, faceText, dest );
		} );
	} );
} );