Benutzer:TMg/weblinkChecker.js

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen

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
/**
 * (<nowiki> zur Umgehung von [[bugzilla:8761]].)
 */
( function( $, mw ) {
	if ( !document.forms['editform']
		|| ( mw.config.get( 'wgAction' ) !== 'edit' && mw.config.get( 'wgAction' ) !== 'submit' )
	) {
		return;
	}

	mw.util.addCSS( '#linkCheckerBox table a { padding: .2em 1px; }' +
		'#linkCheckerBox table a:hover { background: #0645AD; border-radius: 2px; color: #FFF; text-decoration: none; }' +
		'#linkCheckerBox tr:hover { background: #DFE7F4; }' +
		'#linkCheckerBox tr.hintergrundfarbe5:hover { background: #D1D1D1; }' +
		'#linkCheckerBox tr.hintergrundfarbe7:hover { background: #FFB1B1; }' +
		'#linkCheckerBox tr.hintergrundfarbe8:hover { background: #FFE184; }' +
		'#linkCheckerBox td input { -moz-box-sizing: border-box; box-sizing: border-box; width: 100%; }' );

	function click( a ) {
		mw.loader.using( 'jquery.tablesorter', loadLinkChecker );
		return false;
	}

	function loadLinkChecker() {
		if ( window.wikEd && window.wikEd.useWikEd ) {
			wikEd.UpdateTextarea();
		}

		var elements = document.forms['editform'].elements,
			textbox = elements['wpTextbox1'], summary = elements['wpSummary'];
		if ( !textbox ) {
			return;
		}

		var t = textbox.value;
		/* See includes/parser/Parser.php */
		var re = /\bhttps?:\/\/[^\][<>"\x00-\x20\x7F|]*[^\][<>"\x00-\x20\x7F,;\\.:!?)|}]/gi,
			m,
			a = [];
		while ( m = re.exec(t) ) {
			m.number = -1;
			for ( var p = m.index; p >= 0; m.number++ ) {
				p = p < m[0].length ? -1 : t.lastIndexOf( m[0], p - m[0].length );
			}
			a.push( m );
		}

		var html = '<div id="linkCheckerBox" style="padding:1em 0"><form action="#">' +
			'<div style="border:solid silver;border-width:1px 0;clear:both;max-height:23.1em;overflow:auto">' +
			'<table class="wikitable sortable" style="margin:-1px 0;width:100%">' +
			'<tr><th width="40%">Original</th>';
		if ( option( 'context' ) ) {
			html += '<th width="10%">Kontext</th>';
		}
		html += '<th width="10%">Recherche</th>' +
			'<th class="unsortable" width="10%"><acronym title="Archivlinks einfach komplett einfügen">Ersatz</acronym></th>' +
			'<th width="30%">Beschriftung</th></tr>';
		for ( var i = 0; i < a.length; i++ ) {
			var tree = createContextTree(t, a[i].index, a[i].index + a[i][0].length);
			if ( !tree ) {
				continue;
			}

			if ( tree.parent && tree.parent.uri ) {
				a[i][0] = tree.parent.uri;
			}
			var webarchiv = parseWebarchiv( a[i][0] ),
				timestamp = ( tree.archive && tree.archive.timestamp ) || ( webarchiv && webarchiv.timestamp ),
				is = ( tree.archive && tree.archive.is ) || ( webarchiv && webarchiv.is ),
				uri = webarchiv && webarchiv.url || a[i][0];

			html += '<tr class="uri' + i;
			if ( tree.parent && ( /^(?:Toter|Dead) Link$/i.test( tree.parent.type ) ||
				findParameter( tree.parent.parameters, 'offline', '\\S.*' ) >= 0 ) )
				html += ' hintergrundfarbe8';
			else if ( is && !/^\d{4}-?\d\d-?\d\d/.test( is ) )
				html += ' hintergrundfarbe7';
			else if ( tree.archive || webarchiv )
				html += ' hintergrundfarbe5';
			html += '"><td><a class="goto" data-number="' + a[i].number + '" data-uri="' + uri +
				'" href="' + uri + '" title="Gehe zu' + ( a[i].i > 0 ?
				'm ' + (a[i].i + 1) + '. Vorkommen dieses externen Links' : ' diesem externen Link' ) + '">↓</a> ';
			var dirs = uri.split(/(^[^\/?]+\/+[^\/?]+\/*|\?[^?]+|[^\/?]+\/*)/);
			if ( dirs.length <= 0 ) {
				dirs = [uri];
			}
			for ( var d = 0; d < dirs.length; d++ ) {
				if ( !dirs[d] )
					continue;
				var href = dirs.slice(0, d + 1).join('');
				html += '<a href="' + mw.html.escape(href) + '" target="_blank">';
				if (dirs[d].length > 3 && href.indexOf('?') >= 0)
					html += mw.html.escape(dirs[d].charAt()) + '…';
				else
					html += mw.html.escape(dirs[d]
						.replace(/^(?:\w+:\/+|www\.)*/, '')
						.replace(/#...+/, '#…'))
						.replace(/\B_\B/g, '_<wbr>');
				html += '</a>';
			}
			var context = '', text = tree.text || '', node = tree.parent;
			while ( node ) {
				if ( context )
					context = ' → ' + context;
				context = ( node.type === 'LINK' ? 'Link' : node.type === 'REF' ? 'Ref.' :
					node.type.replace( /^Infobox.*/, 'Infobox' ) ) + context;
				if ( !text ) {
					text = node.text || '';
				}
				node = node.parent;
			}
			var site = uri.replace( /^[^\/]*\/+(?:www\.)?/i, '' ).replace( /\/.*$/, '' );
			var euquery = uri.replace( /[^\/]+$/, '' ).replace( /^[^\/]*\/+/, '' ).replace( /^www\./i, '*.' );
			html += '</td>';
			if ( option( 'context' ) ) {
				html += '<td>' + context + '</td>';
			}
			html += '<td data-sort-value="0">'
				+ '<a href="' + mw.html.escape( option( 'search' ).replace( /%s/g,
					'site:' + encodeURIComponent( site + ( text ? ' ' + text : '' ) ) ) )
				+ '" target="_blank" title="Websuche">Web</a>&nbsp;'
				+ '<a href="https://wayback.archive.org/web/' + ( timestamp || '*' ) + '/' + uri + '" target="_blank"'
				+ ' title="Wayback Machine beim Internet Archive (archive.org)">Wayb.</a>&nbsp;';
			if ( is )
				html += '<a href="https://archive.is/' + is + ( /^\d{4}\w?\d\d\w?\d\d/.test( is ) ? '/' + uri : '' ) +
					'" target="_blank" title="archive.is">.is</a>';
			else
				html += '<a href="https://www.webcitation.org/query.php?url=' + uri + '" target="_blank"' +
					' title="WebCite (webcitation.org)">WebC.</a>';
			html += '&nbsp;<a class="exturlusage" href="/wiki/Special:LinkSearch/' + euquery + '" target="_blank"' +
				' title="Weblinksuche innerhalb der Wikipedia">Wikip.</a>' +
				'</td><td><input autocomplete="off" name="r' + i + '" type="url" value="';
			if ( webarchiv && webarchiv.url )
				html += webarchiv.archive;
			else if (/^\w*:\/+[^\/]+\.\w+$/.test(a[i][0]))
				html += a[i][0].toLowerCase() + '/';
			else if ( /^\w*:\/+[^\/]*[A-Z]/.test( a[i][0] ) )
				html += a[i][0].replace( /^\w*:\/+[^\/]*/, function( $0 ) { return $0.toLowerCase(); } );
			else if ( /<!--.*?-->/.test( a[i][0] ) )
				html += a[i][0].replace( /<!--.*?-->/g, '' );
			html += '"></td><td data-sort-value="' + mw.html.escape( text.replace( /^[^\w\xC0-\u1FFF]+/, '' ) ) +
				'"><input name="t' + i + '" type="text" value="' + mw.html.escape( text.replace( /[\n\r\t ]+/g, ' ' ) ) + '"></td></tr>';

			if ( euquery && a.length <= option( 'autoLimit' ) ) {
				( function( i ) {
					$.ajax( '//de.wikipedia.org/w/api.php?action=query&format=xml&list=exturlusage&euprop=&euquery=' + euquery, {
						dataType: 'html',
						error: function( o, s, e ) { alert( e ); },
						success: function( data, s, o ) {
							var c = data.indexOf( 'euoffset' ) > 0 ? '10+' :
								Math.round( ( data.indexOf( '/exturlusage' ) - 47 ) / 6 );
							if ( typeof c === 'string' || c > 0 ) {
								var a = $( '.uri' + i + ' .exturlusage' );
								a.text( c );
								a.parent().attr( 'data-sort-value', typeof c === 'number' ? c : 10 );
							}
						}
					} );
				} )( i );
			}
		}
		html += '</table></div>' +
			'<div class="buttons editOptions" style="margin:0;padding-bottom:.5em;padding-top:.5em;">' +
			'<input type="submit" value="Änderungen übernehmen"> ' +
			'<a class="cancelLink" href="#">Abbrechen</a><span class="mw-editButtons-pipe-separator"> | </span>' +
			'<a class="pref" href="#">Einstellungen</a>' +
			'</div></form>' +
			'<form action="#" class="pref" style="display:none"><fieldset><legend>Einstellungen</legend>' +
			'<input id="prefContext" type="checkbox" value="1"' + (option('context') ? ' checked="checked"' : '') + '>' +
			'<label for="prefContext"> Kontextinformationen für die Fundstellen anzeigen</label><br />' +
			'Websuchmaschine: <input id="prefSearch" size="40" type="text" value="' + mw.html.escape(option('search')) + '"> <small>alternativ z.&thinsp;B. https://www.google.de/search?q=%s</small><br />' +
			'Obergrenze für die Anzeige der Verwendungshäufigkeit: ' +
			'<input id="prefAutoLimit" min="0" size="4" type="number" value="' + mw.html.escape(option('autoLimit')) + '"> externe Links im Artikel<br />' +
			//'Automatische Ersetzungen (z.&thinsp;B. <code>www.alt.de/ www.neu.de/</code>):<br /><textarea rows="5"></textarea>' +
			'<input type="submit" value="Einstellungen speichern"> ' +
			'<a class="cancelLink" href="#">Abbrechen</a>' +
			'</fieldset></form>' +
			'</div>';
		$( '#editform' ).before( html );
		var t = $( '#linkCheckerBox table' );
		if ( t.tablesorter ) {
			t.tablesorter();
		}

		$( '#linkCheckerBox a.goto' ).on( 'click', function() {
			if ( window.wikEd && window.wikEd.useWikEd ) {
				wikEd.UpdateTextarea();
			}

			var t = textbox.value,
				p = -1;
			for (var n = this.getAttribute('data-number'); n >= 0; n--)
				p = t.indexOf(this.getAttribute('data-uri'), p + 1);
			if (p < 0) return false;
			textbox.focus();
			if ( typeof textbox.selectionStart === 'number' ) {
				textbox.selectionStart = p;
				textbox.selectionEnd = p + this.getAttribute('data-uri').length;
			} else if ( typeof textbox.selection === 'object' ) {
				var range = textbox.selection.createRange();
				range.move('character', p);
				range.moveEnd('character', this.getAttribute('data-uri').length);
			}
			return false;
		} );
		$( '#linkCheckerBox form:first-child' ).on( 'submit', function() {
			if ( window.wikEd && window.wikEd.useWikEd ) {
				wikEd.UpdateTextarea();
			}

			var t = textbox.value,
				count = 0;
			for ( var i = a.length; i--; ) {
				var p = -a[i][0].length;
				for ( var n = a[i].number; n >= 0; n-- ) {
					p = t.indexOf( a[i][0], p + a[i][0].length );
				}
				if ( p < 0 ) continue;
				if ( !this.elements['r' + i] ) continue;
				var r = this.elements['r' + i].value.replace( /^\s+|\s+$/g, '' ) || a[i][0];
				var text = this.elements['t' + i].value.replace( /^\s+|\s+$/g, '' );

				var tree = createContextTree( t, p, p + a[i][0].length ),
					node = tree;
				if ( !tree ) continue;
				if ( tree.archive && r && r !== a[i][0] ) tree.archive = false;
				var archive = tree.archive || parseWebarchiv( r );

				if ( /^W(?:aybackarchiv|BA)$/i.test( node.parent.type )
					|| ( /^(?:Toter|Dead) Link$/i.test( node.parent.type ) && r !== a[i][0] )
				) {
					node = node.parent;
				}
				var de = node.parent.type === 'Internetquelle';
				var isCite = de || /^(?:Internetquelle|Cite (?:book|journal|news|web))$/.test( node.parent.type );
				if ( isCite ) {
					/* Drop misspelled parameters */
					deleteParameter( node.parent.parameters, ['archivurl', 'archivdate', 'archivdatum',
						'archive-url', 'archive-date', 'archive-datum', 'archvieurl', 'archviedate',
						'web-archiv', 'webarchiv', 'https?:\\/\\/[^=|]*'] );
				}

				if ( archive ) {
					if ( isCite ) {
						node = node.parent;
						deleteParameter( node.parameters, 'offline' );
						putParameter( node.parameters, node.parameter || 'url', archive.url || a[i][0], 0 );
						putParameter( node.parameters, de ? 'titel' : 'title', text, 1 );
						var where = de ? ['url', 'titel', 'titelerg', 'werk', 'seiten', 'datum', 'archiv-url'] :
							['url', 'title', 'accessdate', 'last', 'first', 'authorlink', 'coauthors',
							'date', 'format', 'work', 'publisher', 'pages', 'language', 'archiveurl'];
						putParameter( node.parameters, de ? 'archiv-url' : 'archiveurl', archive.archive || '', where );
						putParameter( node.parameters, de ? 'archiv-datum' : 'archivedate', archive.date || '', where );
						r = node.parameters.join( '' );
					} else {
						if ( node.parent.type === 'LINK' || node.parent.type === 'Webarchiv' )
							node = node.parent;
						r = '{{Webarchiv | url=' + ( archive.url || a[i][0] ) + ' | ' + ( archive.id
							? 'webciteID=' + archive.id : archive.is
							? 'archive-is=' + archive.is
							: 'wayback=' + archive.timestamp ) + ' | text=' + text.replace( /\|+(?![^{}]*\}\})/g, '–' ) + '}}';
					}
				} else if ( isCite ) {
					node = node.parent;
					deleteParameter( node.parameters, ['archiv-url', 'archiv-datum', 'archiveurl', 'archivedate'] );
					if ( r !== a[i][0] ) deleteParameter( node.parameters, 'offline' );
					putParameter( node.parameters, node.parameter || 'url', r, 0 );
					putParameter( node.parameters, de ? 'titel' : 'title', text, 1 );
					r = node.parameters.join( '' );
				} else if ( node.parent.type === 'LINK'
					|| node.parent.type === 'Webarchiv'
					|| ( text && ( !node.parent || node.parent.type === 'REF' ) )
				) {
					r = '[' + r + (text ? ' ' + text : '') + ']';
					if ( node.parent && node.parent.type !== 'REF' ) node = node.parent;
				}
				if ( r === t.slice( node.start, node.end ) ) continue;
				t = t.slice( 0, node.start ) + r + t.slice( node.end );
				count++;
			}
			textbox.focus();
			if ( t !== textbox.value ) {
				var s = textbox.scrollTop, s0 = textbox.selectionStart, s1 = textbox.selectionEnd;
				textbox.value = t;
				textbox.selectionStart = s0, textbox.selectionEnd = s1, textbox.scrollTop = s;

				s = summary.value,
					s0 = s.length;
				s = s.replace( /^\s+|\s+$/g, '' );
				if ( /\d+\W*externer? Links?\s+geändert$/.test( s ) ) {
					s = s.replace( /(\d)+\W*(?=externer? Links?\s+geändert$)/,
						function( $0, $1 ) { return Math.max( $1, count ) + '+ '; } );
				} else {
					if ( /[^!,./:;?]$/.test( s ) ) s += ';';
					if ( /\S$/.test( s ) ) s += ' ';
					s += count + ' externe' + ( count > 1 ? ' Links' : 'r Link' ) + ' geändert';
				}
				summary.value = s, summary.selectionStart = s0, summary.selectionEnd = s.length;
			}
			$( '#linkCheckerBox' ).remove();
			if ( window.wikEd && window.wikEd.useWikEd ) wikEd.UpdateFrame();
			return false;
		} );
		$( '#linkCheckerBox .buttons a.cancelLink' ).on( 'click', function() {
			$( '#linkCheckerBox' ).remove();
			return false;
		} );
		$( '#linkCheckerBox a.pref' ).on( 'click', function() {
			$( '#linkCheckerBox form.pref' ).show();
			$( '#linkCheckerBox .buttons' ).hide();
			return false;
		} );
		$( '#linkCheckerBox .pref' ).on( 'submit', function() {
			option( 'autoLimit', $( '#prefAutoLimit' )[0].value );
			option( 'context', $( '#prefContext' )[0].checked );
			option( 'search', $( '#prefSearch' )[0].value );
			$( '#linkCheckerBox form.pref' ).hide();
			$( '#linkCheckerBox .buttons' ).show();
			return false;
		} );
		$( '#linkCheckerBox .pref a.cancelLink' ).on( 'click', function() {
			$( '#linkCheckerBox form.pref' ).hide();
			$( '#linkCheckerBox .buttons' ).show();
			return false;
		} );
	}

	function createContextTree( t, uriStart, uriEnd ) {
		var tree = { type: 'URI', start: uriStart, end: uriEnd }, node = tree;
		while ( node && node.type !== 'REF' ) {
			node.parent = findParent( t, node.start, node.end );
			node = node.parent;
		}
		if ( tree.parent.parameters ) {
			var m = /\|\s*archiv[e-]url\s*=\s*(https?:\/\/[^\s|}]+)/.exec(t.slice(tree.parent.start, tree.parent.end));
			if ( m ) {
				/* Bei Vorlagen mit zwei externen Links den Archivlink nicht als eigenständig behandeln */
				if (tree.parent.start + m.index + m[0].length - m[1].length !== tree.start) return false;
				/* Archivlink statt dessen als Parameter beim Originallink mitführen */
				tree.archive = parseWebarchiv(m[1]) || { archive: m[1] };
				/* Original-URL retten, wenn sie sich nicht aus dem Archivlink ergibt */
				m = /\|\s*url\s*=\s*(https?:\/\/[^\s|}]+)/.exec(t.slice(tree.parent.start, tree.parent.end));
				if (!tree.archive.url && m) tree.archive.url = m[1];
				if (/url$/.test(tree.parent.parameter)) tree.parent.parameter = 'url';
			} else if ( tree.parent.type === 'Webarchiv' ) {
				if ( m = /\|\s*(?:wayback|1)\s*=\s*([\d*]+)/.exec( t.slice( tree.parent.start, tree.parent.end ) ) )
					tree.archive = { timestamp: m[1] };
				else if ( m = /\|\s*webciteID\s*=\s*(\w+)/.exec( t.slice( tree.parent.start, tree.parent.end ) ) )
					tree.archive = { id: m[1] };
				else if ( m = /\|\s*archive-(?:is|today)\s*=\s*([^\s{|}]+)/.exec( t.slice( tree.parent.start, tree.parent.end ) ) )
					tree.archive = { is: m[1] };
				else if ( m = /^[^|]*\|\s*([\d*]+)/.exec( t.slice( tree.parent.start, tree.parent.end ) ) )
					tree.archive = { timestamp: m[1] };
			}
		}
		return tree;
	}

	function findParent( t, parsedStart, parsedEnd ) {
		var i = parsedStart,
			skipSquare = 0,
			skipCurly = 0,
			parameter = undefined;

		while ( --i >= 0 ) {
			if ( t.charAt( i ) === '|' && skipCurly <= 0 && !parameter && parameter !== false ) {
				var a = /^\s*([^={|}]*?)\s*=\s*$/.exec( t.slice( i + 1, parsedStart ) );
				parameter = a ? a[1] : false;
			} else if ( t.charAt( i ) === '}' ) {
				skipCurly++;
			} else if ( t.charAt( i ) === '{' && skipCurly-- <= 0 ) {
				i--;
				/* Schachtelung am Anfang ist geklärt, am Ende noch nicht */
				var a = /^\{\s*([^{|}]*?)\s*\|/.exec( t.slice( i + 1, parsedStart ) ),
					b = /^(?:[^{}]|\{+[^{}]*\}\})*\}\}/.exec( t.slice( parsedEnd ) );
				if ( !a || !b ) {
					return false;
				}

				var node = {
					type: a[1].charAt( 0 ).toUpperCase() + a[1].slice( 1 ).replace( /_/g, ' ' ),
					start: i,
					end: parsedEnd + b[0].length,
					parameter: parameter,
					parameters: ( t.slice( i, parsedEnd ) + b[0] ).split( /(\|(?:[^{|}]|\{+[^{}]*\}\})*)/ )
				};
				if ( !node.text && ( a = /\|\s*(?:Text|Titel|Title|3)\s*=\s*((?:[^{|}]|\{+[^{}]*\}\})*?)\s*[|}]/i.exec( t.slice( node.start, node.end ) ) ) ) {
					node.text = a[1];
				}
				if ( !node.text && node.type === 'Webarchiv' && node.parameters.length > 5
					&& ( a = /^\|\s*([^=]*?)\s*$/.exec( node.parameters[5] ) )
				) {
					node.text = a[1];
				}
				return node;
			} else if ( t.charAt( i ) === ']' ) {
				skipSquare++;
			} else if ( t.charAt( i ) === '[' && skipSquare-- <= 0 ) {
				var a = /^\s*$/.test( t.slice( i + 1, parsedStart ) );
				/* Einfache Schachtelung akzeptieren, aber sofort verwerfen */
				var b = /^((?:<!--[^>]*-->|[^\s[\]])*)(?:\s+((?:[^[\]]|\[\[[^[\]]*\]\])*))?\]/.exec(t.slice(parsedEnd));
				if ( !a || !b ) {
					return false;
				}
				return { type: 'LINK', start: i, end: parsedEnd + b[0].length,
					uri: t.slice( parsedStart, parsedEnd + b[1].length ),
					text: b[2] ? b[2].replace( /[[\]]+/g, '' ) : '' };
			} else if ( t.charAt( i ) === '\n' && skipCurly <= 0 ) {
				var a = /^\* *$/.test( t.slice( i + 1, parsedStart ) ),
					b = /^ +([^\r\n<>[\]{|}]*[^\s<>[\]{|}])/.exec( t.slice( parsedEnd ) );
				if ( a && b ) {
					var t = b[1].replace(/^[\s:–-]+/, '');
					if ( t ) {
						return { type: 'LINK', start: parsedStart, end: parsedEnd + b[0].length, text: t };
					}
				}
			} else if ( t.charAt( i ) === '<' ) {
				var slice = t.slice( i + 1, parsedStart ),
					b;
				if ( /^ref\b(?![^<>]*\/>)[^<>]*>[^<>]*$/i.test( slice ) ) {
					b = /^(?:[^<>]|<!--[^<>]*-->|<(?!\w)|<(abbr|[biq]|bd[io]|em|nowiki|small|strong|su[bp])\b[^<>]*>[^<>]*<\/\1\s*>)*<\/ref\s*>/i.exec( t.slice( parsedEnd ) );
				}
				if ( b ) {
					return { type: 'REF', start: i, end: parsedEnd + b[0].length };
				} else if ( !/^(?:\W|\/?(?:abbr|[biq]|bd[io]|em|nowiki|small|strong|su[bp])\b)/i.test( slice ) ) {
					return false;
				}
			}
		}
		return false;
	}

	function parseWebarchiv( uri ) {
		return parseWayback( uri ) || parseWebCite( uri ) || parseArchiveIs( uri );
	}

	function parseWayback( uri ) {
		var m = /\barchive\.org\b.*(\b(\d{4})(\d\d)(\d\d)\d{6}|\/\*)\/(\S*)/i.exec( uri );
		if ( !m ) {
			return false;
		}
		if ( m[2] && ( m[2] < 1970 || m[2] > new Date().getFullYear() || m[3] < 1 || m[3] > 12 || m[4] < 1 || m[4] > 31 ) ) {
			return false;
		}
		var t = m[2] ? m[1] : '*';
		var url = /^\w+:\/\//.test(m[5]) ? m[5] : m[5].replace(/^(?:http(s?):)?\/*/, 'http$1://');
		return { archive: 'https://web.archive.org/web/' + t + '/' + url,
			url: url, timestamp: t, date: m[2] ? m[2] + '-' + m[3] + '-' + m[4] : '' };
	}

	function webCiteBase62ToDate( id ) {
		if ( /^\w{1,9}$/.test( id ) ) {
			for ( var i = 0, s = 0; c = id.charCodeAt( i ); i++ ) {
				s *= 62;
				s += c - [ , 48, 55, 61][c >> 5];
			}
			id = s;
		}
		if ( id > 0 ) {
			return new Date( id / 1000 ).toISOString().substring( 0, 10 );
		}
	}

	function parseWebCite( uri ) {
		var m = /\bwebcitation\.org\/(.*\bid=(\d+)|\w{1,9}$)/i.exec( uri );
		if ( !m ) {
			return false;
		}
		var id = m[2] ? m[2] : m[1];
		m = /\bdate=(\d{4}-\d\d-\d\d)/i.exec( uri );
		var date = m && m[1] || webCiteBase62ToDate( id );
		return { archive: 'https://www.webcitation.org/' + id, id: id, date: date };
	}

	function parseArchiveIs( uri ) {
		var m;
		uri = uri.replace( /^https?:\/\/archive\.(?:fo|is|li|md|ph|today|vn|ec)\//, 'https://archive.is/' );
		if ( m = /\barchive\.(?:fo|is|li|md|ph|today|vn|ec)\/((\d{4})\W*(\d\d)\W*(\d\d)\S*)\/(https?:\/\/\S+)/.exec( uri ) ) {
			return { archive: uri, is: m[1].replace(/\D+/g, ''), url: m[5], date: m[2] + '-' + m[3] + '-' + m[4] };
		}
		if ( m = /\barchive\.(?:fo|is|li|md|ph|today|vn|ec)\/(\S+)/.exec( uri ) ) {
			return { archive: uri, is: m[1] };
		}
		return false;
	}

	function findParameter( a, name, value ) {
		var r = -1;
		if (!a) return r;
		var re = new RegExp('^\\s*\\|\\s*' + name + '\\s*=' + (value ? '\\s*' + value + '\\s*$' : ''));
		for (var i = a.length; i--; )
		{
			if (re.test(a[i]))
				if (r < 0) r = i;
				/* Drop duplicate parameters */
				else a[i] = '';
		}
		return r;
	}

	function putParameter( a, name, value, where ) {
		value = ( value || '' ).replace( /\|+(?![^{}]*\}\})/g, '–' ).replace( /\$/g, '$$$$' );
		var i = findParameter( a, name );
		if ( i >= 0 ) {
			if ( value )
				a[i] = a[i].replace(/^([^=]*=\s*)(?:[^{}]|\{+[^{}]*\}\})*?(\s*\}*)$/, '$1' + value + '$2');
			return a;
		}
		var p = where;
		if ( typeof p !== 'number' ) {
			var p = a.length - 1;
			if (where)
			{
				var re = new RegExp('^\\|\\s*(?:' + where.join('|') + ')\\s*=');
				for (var i = a.length; i--; ) if (re.test(a[i])) { p = i; break; }
			}
		}
		name = name.replace(/\$/g, '$$$$');
		if (p <= 0)
			a[p] = a[p].replace(/(\s*)$/, ' | ' + name + '=' + value + '$1');
		else
			a[p] = a[p].replace(/^((\|\s*)[\s\S]*?(\s*))(\}*)$/, '$1$2' + name + '=' + value + '$3$4');
		return a;
	}

	function deleteParameter( a, name ) {
		if (!a) return a;
		var re = new RegExp('^\\|\\s*(?:' + (typeof name === 'string' ? name : name.join('|')) + ')\\s*=[^|]*(?=\\}\\}$|$)');
		for (var i = a.length; i--; )
			a[i] = a[i].replace(re, '');
		return a;
	}

	function option( key, value ) {
		var a = 'weblinkChecker' + key.charAt(0).toUpperCase() + key.slice(1);
		if (typeof value === 'boolean') value = value ? '1' : '';
		if (typeof value !== 'undefined' && localStorage)
			localStorage[a] = value;
		value = localStorage && localStorage[a];
		if (typeof value === 'undefined') value = window[a];
		switch (key.toLowerCase())
		{
			case 'autolimit': value = value || 8; break;
			case 'search': value = value || 'https://duckduckgo.com/?q=%s'; break;
		}
		return '' + value;
	}

	if ( mw.user.options.get( 'usebetatoolbar' ) ) {
		mw.loader.using( 'ext.wikiEditor', function() {
			$( document ).ready( function() {
				$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
					'section': 'main',
					'group': 'insert',
					'tools': {
						'weblinkChecker': {
							'label': 'Weblink-Checker',
							'type': 'button',
							'icon': '//upload.wikimedia.org/wikipedia/commons/thumb/7/72/Crystal_wp.png/22px-Crystal_wp.png',
							'action': {
								'type': 'callback',
								'execute': function() { return click(this); }
							}
						}
					}
				} );
			} );
		} );
	} else if ( mw.user.options.get( 'showtoolbar' ) ) {
		mw.loader.using( 'mediawiki.action.edit', function() {
			mw.toolbar.addButton( '//upload.wikimedia.org/wikipedia/commons/thumb/7/72/Crystal_wp.png/22px-Crystal_wp.png',
				'Weblink-Checker', '', '', '', 'mw-customeditbutton-weblinkChecker' );
			$( function() {
				$( '#mw-customeditbutton-weblinkChecker' ).click( function() { return click( this ); } );
			} );
		} );
	} else {
		$( document ).ready( function() {
			/* Notfalls als Link unter dem Bearbeitungsfenster */
			var b = $( '.editButtons' ), c = b.children().last();
			( c.is( 'span' ) ? c : b ).append( $( '.mw-editButtons-pipe-separator', b ).first().clone() );
			var a = $( '<a href="#">Weblink-Checker</a>' );
			a.click( function() { return click( this ); } );
			b.append( a );
		} );
	}
} )( jQuery, mediaWiki );
// </nowiki>