This page was created by volunteers like you!
Help us make it even better. To learn more about contributing to MEpedia, click here.
Join the movement
Visit #MEAction to find support or take action. Donate today to help us improve and expand this project.
Congratulations!
MEpedia has got over 30 million views as of August 2022!

MediaWiki talk:Gadget-veReplace.js

From MEpedia, a crowd-sourced encyclopedia of ME and CFS science and history

How to use[edit source | reply | new]

From the Visual editor's menu

content hidden

Please create[edit source | reply | new]

Please create the page MediaWiki:Gadget-veReplace.js linked to this talk page, containing text below (without the "pre"):

Done! User:Kmdenmark (talk) 14:40, July 30, 2019 (EDT)

Code[edit source | reply | new]

/* Gadget to add a Replace text button to Visual editor's Insert menu */
if (!mw.messages.exists( 've-SearchAndReplaceDialog-title' )) {
	mw.messages.set({
		've-SearchAndReplaceDialog-title': 'Search and replace',
		've-SearchAndReplaceDialog-from-label': 'From:',
		've-SearchAndReplaceDialog-to-label': 'To:',
		've-SearchAndReplaceDialog-from-placeholder': 'From text',
		've-SearchAndReplaceDialog-to-placeholder': 'To text',
		've-SearchAndReplaceDialog-replaceAll': 'Replace all',
		've-SearchAndReplaceDialog-replace': 'Replace',
		've-SearchAndReplaceDialog-matchcase': 'Match case',
		've-SearchAndReplaceDialog-replace-complete': 'Found and replaced $1 occurrences',
		've-ReplaceTool-ToolbarButton': 'Replace text'
	});
}
/* end of translations */

/*!
 * VisualEditor replace gadget
 *
 * @copyright Wikipedia [[User:ערן|Eranroz]] and Wikipedia [[User:Ravid ziv|Ravid ziv]]
 * @license The MIT License (MIT)
 */
function extractText(){
	var nodes = [];
	var model = ve.init.target.getSurface().getModel();
	function getTextNodes( obj ) {
		var i;
		
		for ( i = 0; i < obj.children.length; i++ ) {
			if ( obj.children[i].type == 'text'){
				nodes.push(obj.children[i]);
			}

			if ( obj.children[i].children ) {
				getTextNodes( obj.children[i] );
			}
		}
	}
	getTextNodes(ve.init.target.getSurface().getModel().getDocument().getDocumentNode());
	return nodes;
}

function searchAndReplace( fromText, toText, replaceAll, matchCase ) {
	var textNodes = extractText();
	var model = ve.init.target.getSurface().getModel();
	var firstIndex = 0;
	var numReplacements = 0;
	for (var nodeI = 0; nodeI < textNodes.length; nodeI++) {
		var node = textNodes[nodeI];
		var nodeRange = node.getRange();
		var nodeText = model.getLinearFragment(nodeRange).getText();

		var fromIndex = matchCase? nodeText.toUpperCase().indexOf( fromText.toUpperCase(), firstIndex ) : nodeText.indexOf( fromText, firstIndex );
		if ( fromIndex == -1 ) {
			firstIndex = 0;
			continue;
		}
		var start = nodeRange.from+fromIndex;
		var end = start+fromText.length;
		if (!replaceAll && model.selection.start > start) {
			continue;//skip replacements before selection
		}
		var removeRange = new ve.Range( start, end );
		var transaction = ve.dm.Transaction.newFromReplacement(
			ve.init.target.getSurface().getView().getDocument().model, 
			removeRange, 
			toText
		);
		var newSelection = new ve.Range(0,0);
		if (!replaceAll) {
			newSelection = new ve.Range( start, start+toText.length );
		}
		ve.init.target.getSurface().getView().changeModel(transaction, newSelection);
		numReplacements++;
		if (!replaceAll) {
			break;
		}
		firstIndex = fromIndex + toText.length;
		nodeI = nodeI -1;
	}
	if (numReplacements==0 || replaceAll) {
		mw.notify( mw.msg( 've-SearchAndReplaceDialog-replace-complete', numReplacements ) );
	}
}

ve.ui.SearchAndReplaceDialog = function( manager, config ) {
	// Parent constructor
	ve.ui.SearchAndReplaceDialog.super.call( this, manager, config );

};
/* Inheritance */

OO.inheritClass( ve.ui.SearchAndReplaceDialog, ve.ui.FragmentDialog );

ve.ui.SearchAndReplaceDialog.prototype.getActionProcess  = function ( action ) {
	var fromVal = this.fromInput.getValue(),
		toVal = this.toInput.getValue(),
		matchCase = this.matchCaseCheckbox.getValue();

	if ( action === 'replace' ) {
		return new OO.ui.Process( function () {
			searchAndReplace( fromVal, toVal, false, matchCase );
		}, this );
	} else if ( action === 'replace-all' ) {
		return new OO.ui.Process( function () {
			searchAndReplace( fromVal, toVal, true, matchCase );
			this.close( );
		}, this );
	}
	return ve.ui.MWMediaDialog.super.prototype.getActionProcess.call( this, action );
}

ve.ui.SearchAndReplaceDialog.prototype.getBodyHeight = function () {
	return 200;
};

/* Static Properties */
ve.ui.SearchAndReplaceDialog.static.name = 'search';
ve.ui.SearchAndReplaceDialog.static.title = mw.msg( 've-SearchAndReplaceDialog-title' );
ve.ui.SearchAndReplaceDialog.static.size = 'medium';

ve.ui.SearchAndReplaceDialog.static.actions = [
	{
		'action': 'replace',
		'label': mw.msg( 've-SearchAndReplaceDialog-replace' ),
		'flags': [ 'constructive' ],
		'modes': 'insert'
	},
	{
		'label': OO.ui.deferMsg( 'visualeditor-dialog-action-cancel' ),
		'flags': 'safe',
		'modes': [ 'edit', 'insert', 'select' ]
	},
	{
		'action': 'replace-all',
		'label': mw.msg( 've-SearchAndReplaceDialog-replaceAll' ),
		'flags': [ 'constructive' ],
		'modes': 'insert'
	}
];

ve.ui.SearchAndReplaceDialog.prototype.initialize = function () {
	ve.ui.SearchAndReplaceDialog.super.prototype.initialize.call( this );
	this.panel = new OO.ui.PanelLayout( { '$': this.$, 'scrollable': true, 'padded': true } );
	this.inputsFieldset = new OO.ui.FieldsetLayout( {
		'$': this.$
	} );
	// input from
	this.fromInput = new OO.ui.TextInputWidget(
		{ '$': this.$, 'multiline': false, 'placeholder': mw.msg( 've-SearchAndReplaceDialog-from-placeholder' ) }
	);
	//input to
	this.toInput = new OO.ui.TextInputWidget(
		{ '$': this.$, 'multiline': false, 'placeholder': mw.msg( 've-SearchAndReplaceDialog-to-placeholder' ) }
	);
	this.fromField = new OO.ui.FieldLayout( this.fromInput, {
		'$': this.$,
		'label': mw.msg( 've-SearchAndReplaceDialog-from-label' )
	} );
	this.toField = new OO.ui.FieldLayout( this.toInput, {
		'$': this.$,
		'label': mw.msg( 've-SearchAndReplaceDialog-to-label' )
	} );


	this.matchCaseCheckbox = new OO.ui.CheckboxInputWidget( {
		'$': this.$
	} );
	var matchCaseField = new OO.ui.FieldLayout( this.matchCaseCheckbox, {
		'$': this.$,
		'align': 'inline',
		'label': mw.msg( 've-SearchAndReplaceDialog-matchcase' )
	} );

	this.inputsFieldset.$element.append(
		this.fromField.$element,
		this.toField.$element,
		matchCaseField.$element
	);
	this.panel.$element.append(	this.inputsFieldset.$element );
	this.$body.append( this.panel.$element );

}

ve.ui.windowFactory.register( ve.ui.SearchAndReplaceDialog );

//---------- replace tool ------------------
 
function ReplaceTool( toolGroup, config ) {
	OO.ui.Tool.call( this, toolGroup, config );
 
}
OO.inheritClass( ReplaceTool, OO.ui.Tool );
 
ReplaceTool.static.name = 'ReplaceTool';
ReplaceTool.static.title = mw.msg('ve-ReplaceTool-ToolbarButton');
 
ReplaceTool.prototype.onSelect = function () {
	this.toolbar.getSurface().execute( 'window', 'open', 'search', null );
};
 
ReplaceTool.prototype.onUpdateState = function () {
	this.setActive( false );
};
 
ve.ui.toolFactory.register( ReplaceTool );


End of code[edit source | reply | new]

Purpose: Creating a "Replace" / Replace "All" gadget for replacing text on the page being edited, which would be especially useful for mobile users and for fixing repeated typos. User:Kmdenmark documentation source with typos fixed User:Notjusttired (talk) 07:29, July 20, 2019 (EDT)

I have been looking for something like this! Smiley face Thanks!
Pyrrhus (talk) 14:05, July 20, 2019 (EDT)
Both MediaWiki and Wikipedia have a good number of gadgets. The autocorrect one might be handy for fixing common errors - you just pre-load it with what you want replacing. Hot cat might be very handy. more here notjusttired (talk) 20:57, July 20, 2019 (EDT)

Pages used by this gadget[edit source | reply | new]