MediaWiki:Gadget-Search.js

From Wikidata
Jump to navigation Jump to search

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.
//<nowiki>
( function () {
	var wb = wikibase;
	var i18nData = require( './Search-i18n.json' );

	if ( $( 'body' ).hasClass( 'rtl' ) ) {
		i18nData.en.dir = 'rtl';
		i18nData.en.left = 'right';
		i18nData.en.right = 'left';
	} else {
		i18nData.en.dir = 'ltr';
		i18nData.en.left = 'left';
		i18nData.en.right = 'right';
	}

	var i18nLang = mw.config.get( 'wgUserLanguage' );
	while ( i18nLang ) {
		if ( i18nLang in i18nData ) {
			break;
		}
		i18nLang = i18nLang.substr( 0, i18nLang.lastIndexOf( '-' ) );
	}
	if ( !i18nLang ) {
		i18nLang = 'en';
	}

	/**
	 * Returns the localized version of a message.
	 */
	function i18n( key ) {
		if ( i18nData[ i18nLang ].hasOwnProperty( key ) ) {
			return i18nData[ i18nLang ][ key ];
		}
		return i18nData.en[ key ];
	}

	/**
	 * Get the wikipedia site from a language code.
	 *
	 * @param {String} language code
	 * @return wikibase.Site|null
	 *
	 * required modules: wikibase
	 */
	function getSiteByLang( lang ) {
		var langs = {
			// workaround for T59706
			// source: https://noc.wikimedia.org/conf/InitialiseSettings.php.txt
			'crh-latn': wb.sites.getSite( 'crhwiki' ),
			'nb': wb.sites.getSite( 'nowiki' ),
			'gsw': wb.sites.getSite( 'alswiki' ),
			'sgs': wb.sites.getSite( 'bat_smgwiki' ),
			'be-tarask': wb.sites.getSite( 'be_x_oldwiki' ),
			'bho': wb.sites.getSite( 'bhwiki' ),
			'vro': wb.sites.getSite( 'fiu_vrowiki' ),
			'rup': wb.sites.getSite( 'roa_rupwiki' ),
			'lzh': wb.sites.getSite( 'zh_classicalwiki' ),
			'nan': wb.sites.getSite( 'zh_min_nanwiki' ),
			'yue': wb.sites.getSite( 'zh_yuewiki' )
		};
		var sites = wb.sites.getSitesOfGroup( 'wikipedia' );
		$.each( sites, function ( index, site ) {
			// ignore 'simplewiki' to get the mapping from 'en' to 'enwiki'
			if ( site.getId() === 'simplewiki' ) {
				// continue
				return;
			}
			langs[site.getLanguageCode()] = site;
		} );

		while ( lang ) {
			if ( langs.hasOwnProperty( lang ) ) {
				return langs[lang];
			}
			// substr() ignores a possible negative -1 from indexOf,
			// and will return empty string in that case.
			lang = lang.substr( 0, lang.lastIndexOf( '-' ) );
		}
		return null;
	}

	var site = getSiteByLang( mw.config.get( 'wgUserLanguage' ) );
	if ( !site ) {
		// no site found. unknown language.
		return;
	}

	function toggle() {
		$( '#improvedsearch' ).toggle( 'fast' );
		$( '.improvedsearch-page' ).focus();
	}

	function getSuggestions( search ) {
		$( '.suggestions' ).eq( 1 ).remove();
		if ( $( '.improvedsearch-page' ).val() === '' ) {
			$( '.suggestions' ).eq( 0 ).hide();
			return;
		}
		// Optimization: Avoid $.ajax() or 'jsonp' which involve uncacheable
		// API requests with callbacks and cross-site JavaScript execution.
		// Prefer mw.ForeignApi, which makes a pure JSON CORS request, and sets
		// the correct 'origin=' parameter automatically.
		var api = new mw.ForeignApi( site.getApi() );
		api.get( {
				formatversion: 2,
				action: 'opensearch',
				search: search
		} )
		.then( function ( data ) {
			$( '.suggestions:eq(0) .suggestions-results' ).html( '' );
			$( '.suggestions:eq(0) a.mw-searchSuggest-link' )
				.attr( 'href', mw.config.get( 'wgScript' ) + '?title=Special%3AItemByTitle&site=' + site.getId() + '&page=' + mw.util.wikiUrlencode( data[0] ) )
				.find( '.special-query > span' )
				.text( data[0] );
			$( '.suggestions:eq(0) a.mw-searchSuggest-link' )
				.find( '.special-label > span' )
				.text( i18n( 'placeholder' ) + '...' );
			$( '.suggestions:eq(0) a.mw-searchSuggest-link' )
				.find( '.suggestions-special' )
				.hover( function () {
					$( this ).addClass( 'suggestions-result-current' );
				}, function () {
					$( this ).removeClass( 'suggestions-result-current' );
				} );

			for ( var i in data[1] ) {
				$( '.suggestions:eq(0) .suggestions-results' ).append(
					getSuggestionLink( data[1][i], data[0].length, i )
				);
			}

			var style = {
				'font-size': '13px',
				width: '226px',
				top: '109px',
				bottom: 'auto',
				height: 'auto'
			};
			style[i18n( 'right' )] = '29px';
			style[i18n( 'left' )] = 'auto';

			$( '.suggestions' )
				.eq( 0 )
				.css( style )
				.show();
		} );
	}

	function getSuggestionLink( page, length, index ) {
		return $( '<a>' )
		.attr( {
			href: mw.config.get( 'wgScript' ) + '?title=Special%3AItemByTitle&site=' + site.getId() + '&page=' + mw.util.wikiUrlencode( page ),
			'class': 'mw-searchSuggest-link'
		} )
		.append(
			$( '<div>' )
			.attr( {
				'class': 'suggestions-result',
				rel: index,
				title: page
			} )
			.hover( function () {
				$( this ).addClass( 'suggestions-result-current' );
				$( '.improvedsearch-page' ).val( page );
			}, function () {
				$( this ).removeClass( 'suggestions-result-current' );
			} )
			.append(
				$( '<span>' )
				.css( 'white-space', 'nowrap' )
				.append(
					$( '<span>' )
					.attr( 'class', 'highlight' )
					.text( page.substr( 0, length ) )
				)
				.append( page.substr( length ) )
			)
		);
	}

	function init() {
		var $improvedSearch = $( '<form>' )
		.attr( {
			id: 'improvedsearch',
			action: mw.config.get( 'wgScript' )
		} )
		.append(
			$( '<div>' )
			.attr( 'id', 'simpleSearch' ) // This is a hack.
			.append(
				$( '<input>' )
				.attr( {
					type: 'hidden',
					name: 'title',
					value: 'Special:ItemByTitle'
				} )
			)
			.append(
				$( '<input>' )
				.attr( {
					type: 'hidden',
					name: 'site',
					value: site.getId()
				} )
			)
			.append(
				$( '<input>' )
				.attr( {
					id: 'searchInput', // This is a hack.
					'class': 'improvedsearch-page',
					type: 'text',
					accesskey: 'g',
					title: i18n( 'title' ),
					name: 'page',
					autocomplete: 'off',
					placeholder: i18n( 'placeholder' )
				} )
				.updateTooltipAccessKeys()
			)
			.append(
				$( '<input>' )
				.attr( {
					id: 'searchButton', // This is a hack.
					'class': 'searchButton',
					type: 'submit',
					title: i18n( 'description' ),
					value: i18n( 'title' )
				} )
			)
		);
			var isVectorSkin = mw.config.get( "skin" ) === "vector"  || mw.config.get( "skin" ) === "vector-2022" ; if ( isVectorSkin  ) {
			$( '#p-search' ).append( $improvedSearch );
			$( '#improvedsearch' ).hide( 0 );
			var oldVal;
			$( '.improvedsearch-page' )
			.off( 'keyup' )
			.off( 'keydown' )
			.off( 'keypress' )
			.on( 'keyup', function () {
				if ( oldVal != $( '.improvedsearch-page' ).val() ) {
					getSuggestions( $( '.improvedsearch-page' ).val() );
					oldVal = $( '.improvedsearch-page' ).val();
				}
			} )
			.on( 'focusout', function () {
				if ( $( '.suggestions-result-current' ).length === 0 ) {
					$( '.suggestions' ).eq( 0 ).hide();
				}
			} );
			var toggleCss = {
				cursor: 'pointer',
				width: '20px',
				height: '20px',
				'margin-top': '-24px',
				'background-image': 'url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjIyIiBoZWlnaHQ9IjE2Ij48cGF0aCBkPSJNMTUuNTAyIDYuMDAxbC01IDUuMDAxLTUtNS4wMDF6IiBmaWxsPSIjNzk3OTc5Ii8+PC9zdmc+")',
				'background-position': 'center',
				'background-repeat': 'no-repeat',
			};
			toggleCss['margin-' + i18n( 'left' )] = 'calc(20vw + 8px)';

			$( '#searchform' ).after(
				$( '<div>' )
				.attr( {
					id: 'improvedsearch-toggle',
					'class': 'vectorMenu',
					title: i18n( 'title' )
				} )
				.css( toggleCss )
				.on( 'click', toggle )
			);
		} else if ( $( '#searchBody' ).length ) {
			$( '#searchBody' ).append( '<br>', $improvedSearch );
		}
	}

	$( init );
}() );
//</nowiki>