Benutzer:Karl Gruber/ARreplace.js

Aus Regiowiki
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
  • Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
  • Opera: Strg+F5
/**
 * 
 * Original stammt von [[Benutzer:TMg/autoFormatter]]
 * 
 * Blendet eine „Auto-Format“-Funktion in der Werkzeugleiste ein, die viele typische Wikifizierungs-Fehler
 * automatisch korrigiert. Eine ausführliche Beschreibung ist auf der Diskussionsseite zu finden.
 * (<nowiki> zur Umgehung von [[bugzilla:8761]].)
 */
( function( $, mw ) {
	if ( typeof $ !== 'function' || typeof mw !== 'object'
		|| ( mw.config.get( 'wgAction' ) !== 'edit' && mw.config.get( 'wgAction' ) !== 'submit' )
	) {
		return;
	}
	if ( !mw.libs ) {
		mw.libs = {};
	}

	mw.libs.ARreplace = {
		click: function( a ) {
			var e = document.forms['editform'].elements,
				textbox = e['wpTextbox1'],
				summary = e['wpSummary'];
			if ( !textbox ) {
				return false;
			}

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

			if ( !a || !a.nodeType || a.rel === 'ARreplace' ) {
				$( a && a.nodeType ? a : '[rel=ARreplace]' ).css( {
					backgroundColor: '',
					opacity: ''
				} );
			}

			this.clickedElement = a;
			this.isAll = false;
			this.isDisambiguation = /\{\{\s*[Bb]egriffsklärung\s*[|}]/.test( textbox.value );
			this.lang = mw.config.get( 'wgContentLanguage' );
			this.localisation = typeof window.autoFormatLocalisation === 'undefined' ||
				window.autoFormatLocalisation === true ? this.lang : window.autoFormatLocalisation;

			this.cleanElement( textbox );
			summary.value = summary.value + 'Ersetzungen ';

			if ( window.wikEd && window.wikEd.useWikEd ) {
				wikEd.UpdateFrame();
			}
			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, '' );

				s += 'Ersetzungen';
				
				summary.value = s, summary.selectionStart = s0, summary.selectionEnd = s.length;
			}
			if ( window.wikEd && window.wikEd.useWikEd ) wikEd.UpdateFrame();
			return false;
		},
		isChanged: function( oldValue, newValue ) {
			/* Entfernte Leerräume am Textende zählen nie als Änderung */
			oldValue = oldValue.replace( /\s+$/, '' );
			newValue = newValue.replace( /\s+$/, '' );
			/* Entfernte Leerräume am Zeilenende nicht als Änderung anzeigen, aber trotzdem ersetzen */
			var changed = oldValue.replace( /[\r ]+\n/g, '\n' ) !== newValue.replace( /[\r ]+\n/g, '\n' );

			var a = this.clickedElement;
			if ( !a || !a.nodeType || a.rel === 'ARreplace' ) {
				$( a && a.nodeType ? a : '[rel=ARreplace]' ).css( {
					backgroundColor: changed ? '#DEF740' : '',
					borderRadius: changed ? '3px' : '',
					opacity: changed ? '' : '.4'
				} );
			} else if ( a && a.style ) {
				a.style.color = changed ? 'green' : 'silver';
			}
			/* Normalisierte Zeilenumbrüche nie als Änderung werten, das vermeidet Flackern */
			return changed || oldValue.replace( /\r+$/gm, '' ) !== newValue;
		},
		cleanElement: function( e ) {
			var t;

			e.focus();
			if ( typeof e.selectionStart === 'number' ) {
				var scroll = e.scrollTop,
					s1 = e.selectionStart,
					s2 = e.selectionEnd;

				if ( s2 > s1 && ( s1 > 0 || s2 < e.value.length ) ) {
					t = this.cleanText( e.value.substring( s1, s2 ) );
					if ( t === false ) {
						return;
					}
					var newValue = e.value.substr( 0, s1 ) + t + e.value.substr( s2 );
					e.value = newValue;
					/* Fix for Opera */
					s2 = s1 + t.length + ( e.value.length - newValue.length );
				} else if ( !this.cleanAll( e ) ) {
					return;
				}
				e.selectionStart = s1;
				e.selectionEnd = s2;
				e.scrollTop = scroll;
			} else if ( typeof document.selection === 'object' ) {
				var range = document.selection.createRange();
				if ( range.text.length ) {
					t = this.cleanText( range.text );
					if ( t !== false ) {
						range.text = t;
					}
				} else {
					this.cleanAll( e );
				}
			} else {
				this.cleanAll( e );
			}
		},
		cleanAll: function( e ) {
			this.isAll = true;
			var t = this.cleanText( e.value );
			if ( t !== false ) {
				e.value = t.replace( /^\s*\n/, '' );
			}
			return t !== false;
		},
		cleanText: function( t ) {
			var oldValue = t;
			t = this.backupFilenames( t );
			t = this.backupNowikis( t );

			t = this.executeUserReplacements( t );

			t = this.restoreFilenames( t );
			t = this.restoreNowikis( t );
			return this.isChanged( oldValue, t ) ? t : false;
		},






		executeUserReplacements: function( t ) {
			var from,
				replacements = window.autoRegexpReplacements || {};

			for ( from in replacements ) {
				var to = replacements[from];
				/* Wenn die Ersetzungen kein assoziatives Objekt sondern ein 2-dimensionales Array sind */
				if ( typeof to === 'object' && to.length > 1 ) {
					from = to[0];
					to = to[1];
				}
				/* If the search pattern is a regular expression already, 'function' is for older Chrome */
				if ( typeof from === 'object' || typeof from === 'function' ) {
					/*if there is a ^ or a $ in regexp, perform linewise replace */
					if(/\/[\^]|[$]\/\w*/.test(from.toString())){
						lines = t.split('\n');
						for (var i=0; i<lines.length; i++) {
							lines[i] = lines[i].replace( from, to );
						}
					   	res=lines.join('\n');
					   	t= res;
					   	continue;
					} else {
						t=t.replace( from, to );
						continue;
					}	   
				}
				/* Leere Suchmuster sicherheitshalber nicht zulassen */
				if ( /^\s*$/.test( from ) || typeof to !== 'string' ) {
					continue;
				}

				/* Die meisten Regex-Zeichen maskieren, außer Zeichenklassen */
				from = from.replace( /([$()*+.?^{|}])/g, '\\$1' );
				to = to.replace( /\$/g, '$$$$' );
				/* Wortgrenzen beachten */
				from = from.replace( /^(?=\w|\\d)/, '\\b' ).replace( /(\w)$/, '$1\\b' );
				var a = [];
				for ( var re = /\\[dw]/g, m, i = 1; m = re.exec( from ); a.push( m ) ) {
					to = to.replace( m[0], '$' + i++ );
				}
				for ( i = a.length; i--; ) {
					from = from.slice( 0, a[i].index ) + ( a[i][0] === '\\d' ? '(\\d+)' :
						'([A-Za-z\xB5\xC0-\xD6\xD8-\xF6\xF8-\u024F]+)' ) +
						from.slice( a[i].index + 2 );
				}
				/* Look-ahead verwenden, wenn ein Platzhalter in Suchmuster und Ersatz am Ende steht */
				if ( /\+\)\\b$/.test( from ) && new RegExp( '\\$' + a.length + '$' ).test( to ) ) {
					from = from.replace( /([^()]+)\)\\b$/, '?=$1\\b)' );
					to = to.replace( /\$\d+$/, '' );
				}
				/* Allow optional spaces after dots in the search pattern */
				from = from.replace( /\\\.(?=[(\w\xC0-\u024F])/g, '\\.(?:[ \xA0]|&nbsp;)*' );
				t = t.replace( new RegExp( from, 'g' ), to );
			}
			return t;
		},
		backupNowikis: function( t ) {
			this.nowikis = [];
			var re = /<(nowiki|includeonly|syntaxhighlight|source|html|pre|code|score|timeline|hiero|math)\b(?!\s*\/>)[\s\S]*?<\/\1\s*>/gi;
			var m;
			while ( m = re.exec( t ) ) {
				delete m.input;
				this.nowikis.push( m );
			}
			for ( var i = this.nowikis.length; i--; ) {
				var placeholder = '<nowiki>' + i + '<\/nowiki>';
				t = t.slice( 0, this.nowikis[i].index ) + placeholder +
					t.slice( this.nowikis[i].index + this.nowikis[i][0].length );
				if ( /^<\w+\s*>\s*<\/\w+\s*>$/.test( this.nowikis[i][0] ) ) {
					this.nowikis[i][0] = /^no/i.test( this.nowikis[i][1] ) ? '<nowiki />' : '';
				} else if ( /^s[oy]/i.test( this.nowikis[i][1] ) ) {
					this.nowikis[i][0] = this.nowikis[i][0].replace( /^(<)\w+|\w+\s*(?=>$)/g, '$1syntaxhighlight' );
				}
				this.nowikis[i][1] = placeholder;
				delete this.nowikis[i].index;
			}
			return t;
		},
		restoreNowikis: function( t ) {
			for ( var i = 0, len = this.nowikis.length, index = 0; i < len; i++ ) {
				index = t.indexOf( this.nowikis[i][1], index );
				if ( index >= 0 ) {
					t = t.slice( 0, index ) + this.nowikis[i][0] +
						t.slice( index + this.nowikis[i][1].length );
				}
			}
			delete this.nowikis;
			return t;
		},
		backupFilenames: function( t ) {
			/* Dateinamen retten incl. Vereinheitlichung als "Datei:" */
			this.files = [];
			var ns = mw.config.get( 'wgFormattedNamespaces' )[6],
				ext = mw.config.get( 'wgFileExtensions' ) || ['png', 'gif', 'jpg', 'jpeg', 'tiff',
				'tif', 'xcf', 'pdf', 'mid', 'ogg', 'ogv', 'svg', 'djvu', 'oga', 'flac', 'wav', 'webm'];
			/* Match <gallery> lines, [[File:Thumbnails]] and {{Template|Parameters.jpg}} */
			var m,
				re = new RegExp(
				'(^ *|\\[\\[:?)\\s*(' + ns + '|Bild|File|Image) *: *([^\\n[\\]|]*?) *(?=[\\n\\]|])|'
					+ '(^ *|\\|\\n?(?:[^=[\\]{|}]*=)? *)\\s*([^\\n/[\\]{|}]*\\.(?:'
					+ ext.join( '|' ) + '))(?= *[\\n|}])',
				'gim'
			);
			while ( m = re.exec( t ) ) {
				var o = ( m[5] ? m[4] : m[1] ).length;
				m.index += o;
				m.l = m[0].length - o;
				/* Multiple underscores and spaces never have a meaning in filenames */
				m[3] = ( m[5] || m[3] ).replace( /(?:[ _\xA0]|%20|%5F|%C2%A0|&nbsp;)+/gi, ' ' );
				this.files.push( m );
			}
			var r = '',
				p = 0;
			for ( var i = 0; i < this.files.length; i++ ) {
				this.files[i][0] = '<file>' + i + '<\/file>';
				/* Einheitliche Schreibweise und Leerzeichenausgleich */
				r += t.slice( p, this.files[i].index )
					+ ( this.files[i][2] ? ( this.localisation ? ns : this.files[i][2] ) + ':' : '' )
					+ this.files[i][0];
				p = this.files[i].index + this.files[i].l;
			}
			return p ? r + t.slice( p ) : t;
		},
		restoreFilenames: function( t ) {
			/* Gerettete Dateinamen wieder einsetzen */
			var r = '',
				p = 0;

			for ( var index, i = 0; i < this.files.length; i++ ) {
				if ( ( index = t.indexOf( this.files[i][0], p ) ) < 0 ) {
					continue;
				}
				r += t.slice( p, index ) + this.files[i][3];
				p = index + this.files[i][0].length;
				delete this.files[i];
			}
			if ( p ) {
				t = r + t.slice( p );
			}
			/* Fehlschläge nochmal versuchen, passiert bspw. bei umsortierten Galeriezeilen */
			for ( i = this.files.length; i--; ) {
				if ( this.files[i] ) {
					t = t.replace( this.files[i][0], this.files[i][3] );
				}
			}
			delete this.files;
			return t;
		}
	};

	if ( mw.user.options.get( 'usebetatoolbar' ) ) {
		mw.loader.using( 'ext.wikiEditor.toolbar', function() {
			$( document ).ready( function() {
				$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
					'section': 'main',
					'group': 'format',
					'tools': {
						'ARreplace': {
							'label': 'Auto-Regexp',
							'type': 'button',
							'icon': '//upload.wikimedia.org/wikipedia/commons/thumb/3/34/Gnome-colors-edit-find-replace.svg/22px-Gnome-colors-edit-find-replace.svg.png',
							'action': {
								'type': 'callback',
								'execute': function() { return mw.libs.ARreplace.click( this ); }
							}
						}
					}
				} );
			} );
		} );
	} else if ( mw.user.options.get( 'showtoolbar' ) ) {
		mw.loader.using( 'mediawiki.action.edit', function() {
			mw.toolbar.addButton( '//upload.wikimedia.org/wikipedia/commons/2/2e/Button_broom.png',
				'Auto-Regexp', '', '', '', 'mw-customeditbutton-ARreplace' );
			$( document ).ready( function() {
				$( '#mw-customeditbutton-ARreplace' ).click(
					function() { return mw.libs.ARreplace.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="#">Auto-Regexp<\/a>' );
			a.click( function() { return mw.libs.ARreplace.click( this ); } );
			b.append( a );
		} );
	}
} )( jQuery, mediaWiki );