Замечание: Возможно, после публикации вам придётся очистить кэш своего браузера, чтобы увидеть изменения.

  • Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
  • Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
  • Internet Explorer / Edge: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl+F5
  • Opera: Нажмите Ctrl+F5.
/*
* В данный момент хорошо работает (проверял) подбор отдельного существительного, пары прил+сущ, предл+прил+сущ.
* Из замеченных недоработок - не определяет обратный порядок сущ+прил, а также составные названия из сущ-х (пример: князь Владимир)
*/

	var url = '//astafiev.me/WikiLinker/links/';

// Toolbar buttons

var addOldToolbarButton = function() {
	var $toolbar = $( '#gadget-toolbar' );
	if ( !$toolbar.length ) {
		$toolbar = $( '#toolbar' );
	}
	$( '<div>' )
		.addClass( 'mw-toolbar-editbutton' )
		.attr( 'id', 'mw-editbutton-gadget-wikilinker' )
		.attr( 'alt', 'МорфоСсыльщик' )
		.attr( 'title', 'МорфоСсыльщик — подбирает вики-ссылку для выделенного слова или словосочетания, учитывая словоизменение' )
		.css( 'background-image', 'url(//upload.wikimedia.org/wikipedia/commons/a/ad/Wikilinker_toolbar.png) ' )
		.appendTo( $toolbar )
		.on( 'click', main );
};

var addNewToolbarButton = function() {
	$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
		'section': 'main',
		'group': 'format',
		'tools': {
			'morphlinker': {
				label: 'МорфоСсыльщик — подбирает вики-ссылку для выделенного слова или словосочетания, учитывая словоизменение',
				type: 'button',
				icon: '//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Glagoljica_Az.svg/13px-Glagoljica_Az.svg.png',
				action: {
					type: 'callback',
					execute: function() {
						main();
					}
				}
			}
		}
	} );
};

if ( $.inArray( mw.config.get( 'wgAction' ), [ 'edit', 'submit' ] ) !== -1 ) {
	mw.loader.using( [ 'user.options', 'jquery.textSelection' ], function () {
		if ( mw.user.options.get( 'usebetatoolbar' ) === 1 ) {
			if ( mw.user.options.get( 'showtoolbar' ) === 1 ) {
				$.when(
					mw.loader.using( ['ext.wikiEditor', 'schema.Edit'] ),
					$.ready
				).then( addNewToolbarButton );
			}
		} else {
			mw.loader.using( 'mediawiki.toolbar', function() {
				$( addOldToolbarButton );
			} );
		}
	} );
}

function main(){
	var xmlhttp;
	var CantWork = 'Сначала нужно выделить слово или словосочетание';
 	var requestTokens = 0;
 	var $wpTextbox1 = $( '#wpTextbox1' );
 
	var txt = $wpTextbox1.textSelection( 'getSelection' );
	var startEndPos = $( '#wpTextbox1' ).textSelection( 'getCaretPosition', {
			startAndEnd: true
		} ),
		startPos = startEndPos[0],
		endPos = startEndPos[1];

	// Trim selected text
	while ( txt.slice( 0, 1 ) === ' ' ) {
		txt = txt.slice( 1 );
		startPos = startPos + 1;
	}
	while ( txt.slice( -1 ) === ' ' ) {
		txt = txt.slice( 0, -1 );
		endPos = endPos - 1;
	}
	if ( txt === '' ) {
		mw.notify( CantWork );
		return;
	}
	if ( startEndPos[0] !== startPos || startEndPos[1] !== endPos ) {
		$wpTextbox1.textSelection( 'setSelection', {
			start: startPos,
			end: endPos 
		} );
	}
	
	loadXMLDoc( url + txt );
}


	function loadXMLDoc ( url ) {
		xmlhttp = GetXmlHttpObject();
		if ( xmlhttp === null ) {
			mw.notify( 'Your browser does not support XMLHTTP!' );
			return;
		}
		xmlhttp.onreadystatechange = stateChanged;
		xmlhttp.open( 'GET', url, true );
		xmlhttp.send( null );
	}

	function GetXmlHttpObject() {
		if ( window.XMLHttpRequest ) {
			// code for IE7+, Firefox, Chrome, Opera, Safari
			return new XMLHttpRequest();
		}
		if ( window.ActiveXObject ) {
			// code for IE6, IE5
			return new ActiveXObject( 'Microsoft.XMLHTTP' );
		}
		return null;
	}
	
	function stateChanged() {
		if ( xmlhttp.readyState === 4 ) {
			if ( xmlhttp.status === 200 ) {
				var resp = JSON.parse( xmlhttp.responseText );
				
				var список = [];
				var морфол = "";
				
				for (i=0; i<resp.части.length; i++){
					var часть = resp.части[i];
					var найденноеСлово;
					var норма = false;
					var noun = false, adj = false;
					var узел = { исход: часть.слово, норма:null  };
					for (j=0; j<часть.варианты.length; j++){
						var вариант = часть.варианты[j];
						var noun_cand = вариант.частьРечи == 'существительное';
						if (!noun && noun_cand){
							noun = true;
							найденноеСлово = вариант.базоваяФорма;
						}
						var adj_cand = вариант.частьРечи == 'прилагательное';
						if (!noun && !adj && adj_cand){
							adj = true;
							найденноеСлово = вариант.базоваяФорма;
						}
						var норма_cand = false;
						for (k=0; k<вариант.граммемы.length; k++){
							if (вариант.граммемы[k] == 'именительный'){
								норма_cand = true;
								break;
							}
						}
						if (норма_cand && (noun_cand||adj_cand) ){
							noun = noun || noun_cand;
							adj = adj || adj_cand;
							норма = true;
							найденноеСлово = вариант.базоваяФорма;
							узел.формы = унифФормы(вариант.формы);
							break;
						}
					}
					// сохраняем слово в исходном виде, если не прил или сущ
					if (!noun && !adj){
						найденноеСлово = часть.слово;
						морфол += "`";
					} else {
						морфол += noun? "с" : "п";
					}
					узел.норма = найденноеСлово;
					список.push(узел);
				}
				
				// постобработка полученных норм
				список = синтаксОбработка(морфол, список);
				if (список.length < 1){
					return;
				}

				var подстановка;
				if (список.length > 1){
					var ориг = список[0].слово.исход;
					var нормФ = список[0].форма;
					for (i=1; i<список.length; i++){
						ориг  =  ориг + ' ' + список[i].слово.исход;
						нормФ = нормФ + ' ' + список[i].форма;
					}
					подстановка = '[[' + нормФ + '|' + ориг + ']]';
				} else {
					var ориг = список[0].слово.исход;
					var нормФ = список[0].форма;
					if (нормФ.length <= ориг.length && ориг.substr(0, нормФ.length) == нормФ ){
						подстановка = "[[" + нормФ + "]]" + ориг.substr(нормФ.length);
					} else {
						подстановка = "[[" + нормФ + "|" + ориг + "]]";
					}
				}
				
				захватРезультата(подстановка);
	
			}
		}
	}
	
	function унифФормы(формы){
		var карта = {};
		формы.forEach ( function(форма) {
			карта[форма.граммема] = форма.форма;
		});
		return карта;
	}

	function синтаксОбработка(морфология, слова){
		// постобработка полученных норм
		var синтСписок = [];

//		var patt = /^((?:\:?пс)|(?:\:?п?с\:с))+$/;
//		var patt = /((?:\:?пс)|(?:\:?п?с\:с))(?=(?:\:?пс)|(?:\:?п?с\:с)|$)/g;
		var оснШаблон = /(?:^с)|(?:`?[уп]+с)|(?:`?п*с`с)/.source;
		var шаблон = new RegExp( '('+оснШаблон+')(?='+оснШаблон+'|$)', 'g' );
		while ( (res=шаблон.exec(морфология)) !== null ){
			var фраза = res[1];
		    var начало = res.index;
		    if (фраза[0]=='`'){
			    var словоФорма = {слово:слова[начало], форма: слова[начало].исход };
			    синтСписок.push(словоФорма);
		    	фраза = фраза.substr(1);
		    	начало++;
		    }
			var позСущ = фраза.indexOf('с');
		    if(фраза.length>1 && фраза[0]=='п' && 0 < позСущ && позСущ < фраза.search(/[`у]|$/)  ){
		    	var сущ = слова[позСущ];
		    	var фс = сущ.формы;
				// перебор определений
				for (var i=начало; i<позСущ; i++){
			    	var прил = слова[i];
					var форма_прил = {слово: прил, форма: прил.норма };
					{	// подбор рода/числа для слова-определения
						var фп = прил.формы;
						if (фс['множественное'] !== null && фп['множественное'] !== null){
							форма_прил.форма = фп['множественное'];
						}
						delete фс.множественное;
						for (var ключ in фс){
							if (фп[ключ] !== null)
							форма_прил.форма = фп[ключ];
						}
					}
					синтСписок.push( форма_прил );
				}
			    синтСписок.push( {слово: сущ, форма: сущ.норма } );
			    начало = позСущ+1;
		    }
		    if (фраза.length>0 && фраза[0]==='с' ){
			    синтСписок.push( {слово: слова[начало], форма: слова[начало].норма } );
			    начало++;
		    }
		    var форма = (начало<шаблон.lastIndex) && (фраза[начало]==='`');
		    for (и=начало; и<шаблон.lastIndex; и++){
		    	var слово = слова[и];
			    синтСписок.push( {слово: слово, форма: форма? слово.исход : слово.норма } );
		    }
		}
		return синтСписок;
	}
	var захватРезультата = function (результат){
		$( '#wpTextbox1' )
			.textSelection( 'encapsulateSelection', {
				peri: результат,
				replace: true
			} )
			.textSelection( 'scrollToCaretPosition' )
	 		.focus();
	}