Benutzer:TMg/advancedSearch.js

Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 26. Januar 2017 um 17:39 Uhr durch TMg (Diskussion | Beiträge) (Test to parse phrases ending in ~). Sie kann sich erheblich von der aktuellen Version unterscheiden.

Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
( function ( mw, $ ) {
	'use strict';

	if ( mw.config.get( 'wgCanonicalSpecialPageName' ) !== 'Search' ) {
		return;
	}

	/**
	 * @param {string} val
	 * @return {string}
	 */
	function trimQuotes( val ) {
		return val.replace( /^"([^"]+)"$/, '$1' );
	}

	/**
	 * @param {string} val
	 * @return {string}
	 */
	function addQuotes( val ) {
		return trimQuotes( val ).replace( /^([^"]*\s[^"]*)$/, '"$1"' );
	}

	var advancedOptions = [
		// Text
		{
			group: 'Text',
			id: 'phrase',
			label: 'Genau diese Wortgruppe:',
			formatter: function ( val ) {
				return addQuotes( val );
			}
		},
		{
			group: 'Text',
			id: 'fuzzy',
			label: 'Ungefähr dieses Wort:',
			formatter: function ( val ) {
				return val + '~';
			},
			parser: /(?:^| +)("[^"]+"|\S+)~(?= |$)/gi
		},
		{
			group: 'Text',
			id: 'not',
			label: 'Nicht dieses Wort:',
			formatter: function ( val ) {
				return '-' + val;
			}
		},
		{
			group: 'Text',
			id: 'hastemplate',
			label: 'Nur Seiten mit dieser Vorlage:',
			formatter: function ( val ) {
				return 'hastemplate:' + addQuotes( val );
			},
			parser: /\bhastemplate:("[^"]+"|\S+)\s*/gi
		},
		{
			group: 'Text',
			id: 'insource',
			label: 'Suche im Wikitext:',
			formatter: function ( val ) {
				return 'insource:' + ( /^\/.*\/$/.test( val ) ? val : addQuotes( val ) );
			},
			parser: /\binsource:(\/\S+\/|"[^"]+"|\S+)\s*/gi
		},

		// Titles and headlines
		// local:
		{
			group: 'Titel',
			id: 'prefix',
			label: 'Seitentitel beginnt mit:',
			formatter: function ( val ) {
				return 'prefix:' + addQuotes( val );
			},
			parser: /\bprefix:("[^"]+"|\S+)\s*/gi
		},
		{
			group: 'Titel',
			id: 'intitle',
			label: 'Seitentitel enthält:',
			formatter: function ( val ) {
				return 'intitle:' + val;
			},
			parser: /\bintitle:("[^"]+"|\S+)\s*/gi
		},

		// Categories
		{
			group: 'Kategorien',
			id: 'deepcat',
			label: 'In dieser oder tieferer Kategorie:',
			enabled: function () {
				return !!mw.libs.deepCat;
			},
			formatter: function ( val ) {
				return 'deepcat:' + addQuotes( val );
			},
			parser: /\bdeepcat:("[^"]+"|\S+)\s*/gi
		},
		{
			group: 'Kategorien',
			id: 'incategory',
			label: 'Nur direkt in dieser Kategorie:',
			formatter: function ( val ) {
				return 'incategory:' + addQuotes( val );
			},
			parser: /\bincategory:("[^"]+"|\S+)\s*/gi
		},

		// Files
		// filebits
		// filesize
		{
			group: 'Dateien',
			id: 'filetype',
			label: 'Dateien dieses Typs:',
			formatter: function ( val ) {
				var types = '';
				val.split( ',' ).forEach( function ( type ) {
					type = $.trim( type ).replace( /^\w*\W+(?=\w)/, '' ).toLowerCase();
					switch ( type ) {
						case '':
							break;

						// Individual file types with non-standard alternatives
						case 'bitmap':
						case 'image':
						case 'bild':
							types += 'filetype:bitmap';
							break;
						case 'audio':
						case 'music':
						case 'musik':
							types += 'filetype:audio';
							break;
						case 'drawing':
						case 'vector':
						case 'vektor':
						case 'zeichnung':
							types += 'filetype:drawing';
							break;

						// Other known file types
						case 'multimedia':
						case 'office':
						case 'video':
							types += 'filetype:' + type;
							break;

						// Individual MIME types with non-standard alternatives
						case 'flac':
							types += 'filemime:audio/flac';
							break;
						case 'midi':
						case 'mid':
							types += 'filemime:audio/midi';
							break;
						case 'wav':
						case 'wave':
							types += 'filemime:audio/wav';
							break;
						case 'jpg':
							types += 'filemime:image/jpeg';
							break;
						case 'tif':
							types += 'filemime:image/tiff';
							break;
						case 'svg':
						case 'xml':
							types += 'filemime:xml/svg';
							break;

						// Other known MIME types
						case 'ogg':
						case 'pdf':
							types += 'filemime:application/' + type;
							break;
						default:
							types += 'filemime:image/' + type;
							break;
					}
				} );
				return types;
			},
			parser: /\bfile(?:mime|type):(?:\w+\/)?(\w+)/gi
		},
		{
			group: 'Dateien',
			id: 'filew',
			label: 'Dateibreite in Pixel:',
			formatter: function ( val ) {
				return 'filew:' + val;
			},
			parser: /\bfilew(?:idth)?\b:?([<>\d.,]+)\s*/gi
		},
		{
			group: 'Dateien',
			id: 'fileh',
			label: 'Dateihöhe in Pixel:',
			formatter: function ( val ) {
				return 'fileh:' + val;
			},
			parser: /\bfileh(?:eight)?\b:?([<>\d.,]+)\s*/gi
		},
		{
			group: 'Dateien',
			id: 'fileres',
			label: 'Diagonalauflösung in Pixel:',
			formatter: function ( val ) {
				return 'fileres:' + val;
			},
			parser: /\bfileres\b:?([<>\d.,]+)\s*/gi
		}

		// Ordering
		// prefer-recent:
		// boost-templates:

		// Meta
		// linksto:
		// neartitle:
		// morelike:
	];

	/**
	 * @param {RegExp|undefined} regexp
	 * @param {string} val
	 * @return {Array|boolean}
	 */
	function lastMatch( regexp, val ) {
		var match,
			lastMatch = false;

		while ( regexp && ( match = regexp.exec( val ) ) ) {
			lastMatch = match;
		};

		return lastMatch;
	}

	/**
	 * @param {string} val
	 * @returns {string}
	 */
	function parseSearchOptions( val ) {
		for ( var i = advancedOptions.length; i--; ) {
			var option = advancedOptions[i],
				$field = $( '#advancedSearchOption-' + option.id );

			if ( !$field.length || $.trim( $field.val() ) !== '' ) {
				continue;
			}

			var match = lastMatch( option.parser, val );

			if ( match ) {
				val = val.slice( 0, match.index ) + val.slice( match.index + match[0].length );
				$field.val( trimQuotes( match[1] ) );
			}
		}

		return $.trim( val );
	}

	/**
	 * @param {string} allValues
	 * @returns {string}
	 */
	function formatSearchOptions( allValues ) {
		advancedOptions.forEach( function ( option ) {
			var $field = $( '#advancedSearchOption-' + option.id );

			if ( !$field.length ) {
				return;
			}

			var val = $.trim( $field.val() );

			if ( val !== '' ) {
				allValues += ' ' + option.formatter( val );
				$field.val( '' );
			}
		} );

		return $.trim( allValues );
	}

	mw.loader.using( [ 'oojs-ui' ], function () {
		var $search =  $( 'form#search, form#powersearch' ),
			optionSets = {};

		advancedOptions.forEach( function ( option ) {
			if ( option.enabled && !option.enabled() ) {
				return;
			}

			var id = 'advancedSearchOption-' + option.id;

			if ( !optionSets[option.group] ) {
				optionSets[option.group] = [];
			}

			optionSets[option.group].push(
				$( '<div>' )
					.css( { display: 'table-row' } )
					.append(
						$( '<label>' )
							.prop( { 'for': id } )
							.css( {
								display: 'table-cell',
								'text-align': 'right',
								'padding-right': '0.5em',
								width: '20em'
							} )
							.text( option.label ),
						$( '<input>' )
							.prop( { id: id } )
							.css( { display: 'table-cell' } )
					)
			);
		} );

		var $allOptions = $( '<fieldset>' )
			.css( { clear: 'both' } )
			.append( $( '<legend>' ).text( 'Erweiterte Suchoptionen' ) )
			.hide();

		for ( var group in optionSets ) {
			var $optionSet = $( '<fieldset>' )
				.css( {
					border: 'none',
					'border-top': 'solid 1px #ccc',
					margin: 0
				} )
				.append( $( '<legend>' )
					.css( { color: '#666' } )
					.text( group )
				);

			optionSets[group].forEach( function ( $option ) {
				$optionSet.append( $option );
			} );

			$allOptions.append( $optionSet );
		}

		var advancedButton = new OO.ui.ButtonWidget( {
			icon: 'advanced',
			title: 'Erweiterte Suchoptionen'
		} ).on( 'click', function () {
			$allOptions.toggle();

			if ( $allOptions.is(':visible') ) {
				var $field = $search.find( 'input[name="search"]' );
				$field.val( parseSearchOptions( $field.val() ) );
			}
		} );

		var $advancedButton = advancedButton.$element.css( {
			display: 'table-cell',
			'padding-right': '0.2em',
			width: '1%'
		} );
		$( '#searchText' ).parent().before( $advancedButton );
		$( '#mw-search-top-table').after( $allOptions );

		$search.on( 'submit', function () {
			var $field = $( this ).find( 'input[name="search"]' );
			$field.val( formatSearchOptions( $field.val() ) );
		} );
	} );
} )( mediaWiki, jQuery );