মিডিয়াউইকি:Gadget-Adiutor-CSD.js

লক্ষ্য করুন: প্রকাশ করার পর, পরিবর্তনগুলো দেখতে আপনাকে আপনার ব্রাউজারের ক্যাশে পরিষ্কার করার প্রয়োজন হতে পারে।

  • ফায়ারফক্স / সাফারি: পুনরায় লোড-এ ক্লিক করার সময় শিফট টিপে ধরে রাখুন, অথবা হয় Ctrl-F5 বা Ctrl-R টিপুন (ম্যাকে ⌘-R টিপুন)
  • গুগল ক্রোম: Ctrl-Shift-R (ম্যাকে ⌘-Shift-R) টিপুন
  • ইন্টারনেট এক্সপ্লোরার / এজ: Ctrl ধরে রাখা অবস্থায় Refresh-এ ক্লিক করুন, অথবা Ctrl-F5 টিপুন
  • অপেরা: Ctrl-F5 টিপুন।
/* Adiutor: Enhancing Wikipedia Editing Through a Comprehensive Set of Versatile Tools and Modules.
 * Author: Vikipolimer
 * Learn more at: https://meta.wikimedia.org/wiki/Adiutor
 * License: Licensed under Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
<nowiki> */
var api = new mw.Api();
var mwConfig = mw.config.get(["wgArticleId", "wgPageName", "wgNamespaceNumber", "wgUserName"]);
var wikiId = mw.config.get('wgWikiID');
var adiutorUserOptions = JSON.parse(mw.user.options.get('userjs-adiutor-' + wikiId));
var csdReason, csdSummary, notificationMessage, articleAuthor;
var csdOptions = [];
var csdReasons = [];
var saltCsdSummary = '';
var pageTitle = mw.config.get("wgPageName").replace(/_/g, " ");

function fetchApiData(callback) {
	api.get({
		action: "query",
		prop: "revisions",
		titles: "MediaWiki:Gadget-Adiutor-CSD.json",
		rvprop: "content",
		formatversion: 2
	}).done(function(data) {
		var content = data.query.pages[0].revisions[0].content;
		try {
			var jsonData = JSON.parse(content);
			callback(jsonData);
		} catch(error) {
			// Handle JSON parsing error
			mw.notify('Failed to parse JSON data from API.', {
				title: mw.msg('operation-failed'),
				type: 'error'
			});
		}
	}).fail(function() {
		// Handle API request failure
		mw.notify('Failed to fetch data from the API.', {
			title: mw.msg('operation-failed'),
			type: 'error'
		});
		// You may choose to stop code execution here
	});
}
fetchApiData(function(jsonData) {
	if(!jsonData) {
		// Handle a case where jsonData is empty or undefined
		mw.notify('MediaWiki:Gadget-Adiutor-CSD.json data is empty or undefined.', {
			title: mw.msg('operation-failed'),
			type: 'error'
		});
		// You may choose to stop code execution here
		return;
	}
	api.get({
		action: 'query',
		list: 'logevents',
		leaction: 'delete/delete',
		letprop: 'delete',
		letitle: pageTitle
	}).done(function(data) {
		if(data.query.logevents) {
			revDelCount = data.query.logevents.length;
		} else {
			revDelCount = 0;
		}
		var speedyDeletionReasons = jsonData.speedyDeletionReasons;
		var csdTemplateStartSingleReason = jsonData.csdTemplateStartSingleReason;
		var csdTemplateStartMultipleReason = jsonData.csdTemplateStartMultipleReason;
		var reasonAndSeperator = jsonData.reasonAndSeperator;
		var speedyDeletionPolicyLink = jsonData.speedyDeletionPolicyLink;
		var speedyDeletionPolicyPageShorcut = jsonData.speedyDeletionPolicyPageShorcut;
		var apiPostSummaryforLog = jsonData.apiPostSummaryforLog;
		var apiPostSummary = jsonData.apiPostSummary;
		var csdNotificationTemplate = jsonData.csdNotificationTemplate;
		var userPagePrefix = jsonData.userPagePrefix;
		var userTalkPagePrefix = jsonData.userTalkPagePrefix;
		var localLangCode = jsonData.localLangCode;
		var singleReasonSummary = jsonData.singleReasonSummary;
		var multipleReasonSummary = jsonData.multipleReasonSummary;
		var copyVioReasonValue = jsonData.copyVioReasonValue;
		var csdTemplatePostfixReasonData = jsonData.csdTemplatePostfixReasonData;
		var csdTemplatePostfixReasonValue = jsonData.csdTemplatePostfixReasonValue;
		var useVerticalVarForSeparatingMultipleReasons = jsonData.useVerticalVarForSeparatingMultipleReasons;

		function SpeedyDeletionRequestDialog(config) {
			SpeedyDeletionRequestDialog.super.call(this, config);
		}
		OO.inheritClass(SpeedyDeletionRequestDialog, OO.ui.ProcessDialog);
		// Specify a name for .addWindows()
		SpeedyDeletionRequestDialog.static.name = 'myDialog';
		// Specify a title and an action set that uses modes ('edit' and 'help' mode, in this example).
		SpeedyDeletionRequestDialog.static.title = new OO.ui.deferMsg('csd-module-title');
		SpeedyDeletionRequestDialog.static.actions = [{
			action: 'continue',
			modes: 'edit',
			label: new OO.ui.deferMsg('tag-page'),
			flags: ['primary', 'progressive']
		}, {
			action: 'policy',
			modes: 'edit',
			label: mw.msg('speedy-deletion-policy'),
			framed: false,
		}, {
			modes: 'edit',
			label: new OO.ui.deferMsg('cancel'),
			flags: ['safe', 'close']
		}, {
			action: 'back',
			modes: 'help',
			label: new OO.ui.deferMsg('back'),
			flags: ['safe', 'back']
		}];
		// Customize the initialize() method to add content and set up event handlers. 
		// This example uses a stack layout with two panels: one displayed for 
		// edit mode and one for help mode.
		SpeedyDeletionRequestDialog.prototype.initialize = function() {
			SpeedyDeletionRequestDialog.super.prototype.initialize.apply(this, arguments);
			var i, reason, checkboxWidget, fieldLayout;
			var selectedNamespace = null;
			if(mw.config.get('wgIsRedirect')) {
				selectedNamespace = speedyDeletionReasons.find(reason => reason.namespace === 'redirect');
				nameSpaceDeletionReasons = new OO.ui.FieldsetLayout({
					label: selectedNamespace.name
				});
				for(i = 0; i < selectedNamespace.reasons.length; i++) {
					reason = selectedNamespace.reasons[i];
					checkboxWidget = new OO.ui.CheckboxInputWidget({
						value: reason.value,
						data: reason.data,
						selected: false
					});
					fieldLayout = new OO.ui.FieldLayout(checkboxWidget, {
						label: reason.label,
						align: 'inline',
						help: reason.help
					});
					nameSpaceDeletionReasons.addItems([fieldLayout]);
				}
			} else {
				var NS_MAIN = 0,
					NS_USER = 2,
					NS_USER_TALK = 3,
					NS_FILE = 6,
					NS_TEMPLATE = 10,
					NS_CATEGORY = 14;
				switch(mwConfig.wgNamespaceNumber) {
					case NS_MAIN:
					case NS_FILE:
					case NS_CATEGORY:
					case NS_USER:
					case NS_USER_TALK:
					case NS_TEMPLATE:
						selectedNamespace;
						if(mwConfig.wgNamespaceNumber === NS_USER || mwConfig.wgNamespaceNumber === NS_USER_TALK) {
							selectedNamespace = speedyDeletionReasons.find(reason => reason.namespace === NS_USER);
						} else {
							selectedNamespace = speedyDeletionReasons.find(reason => reason.namespace === mwConfig.wgNamespaceNumber);
						}
						if(selectedNamespace) {
							nameSpaceDeletionReasons = new OO.ui.FieldsetLayout({
								label: selectedNamespace.name
							});
							for(i = 0; i < selectedNamespace.reasons.length; i++) {
								reason = selectedNamespace.reasons[i];
								checkboxWidget = new OO.ui.CheckboxInputWidget({
									value: reason.value,
									data: reason.data,
									selected: false
								});
								fieldLayout = new OO.ui.FieldLayout(checkboxWidget, {
									label: reason.label,
									align: 'inline',
									help: reason.help
								});
								nameSpaceDeletionReasons.addItems([fieldLayout]);
							}
						} else {
							nameSpaceDeletionReasons = new OO.ui.FieldsetLayout({});
							nameSpaceDeletionReasons.addItems([
								new OO.ui.FieldLayout(new OO.ui.MessageWidget({
									type: 'warning',
									inline: true,
									label: new OO.ui.HtmlSnippet('<strong>' + mw.msg('no-namespace-reason-for-csd-title') + '</strong><br><small>' + mw.msg('no-namespace-reason-for-csd') + '</small>')
								})),
							]);
						}
						break;
					default:
						nameSpaceDeletionReasons = new OO.ui.FieldsetLayout({});
						nameSpaceDeletionReasons.addItems([
							new OO.ui.FieldLayout(new OO.ui.MessageWidget({
								type: 'warning',
								inline: true,
								label: new OO.ui.HtmlSnippet('<strong>' + mw.msg('no-namespace-reason-for-csd-title') + '</strong><br><small>' + mw.msg('no-namespace-reason-for-csd') + '</small>')
							})),
						]);
						break;
				}
			}
			selectedNamespaceForGeneral = null;
			for(i = 0; i < speedyDeletionReasons.length; i++) {
				if(speedyDeletionReasons[i].namespace === 'general') {
					selectedNamespaceForGeneral = {
						name: speedyDeletionReasons[i].name,
						reasons: speedyDeletionReasons[i].reasons
					};
					break;
				}
			}
			copyVioInput = new OO.ui.TextInputWidget({
				placeholder: mw.msg('copyright-infringing-page'),
				value: '',
				icon: 'link',
				data: 'COV',
				classes: ['adiutor-copvio-input'],
			});
			copyVioInput.$element.css({
				'margin-top': '10px',
				'margin-bottom': '10px'
			});
			copyVioInput.$element.hide();
			isCopyVio = false;
			generalReasons = new OO.ui.FieldsetLayout({
				label: selectedNamespaceForGeneral.name
			});
			for(i = 0; i < selectedNamespaceForGeneral.reasons.length; i++) {
				reason = selectedNamespaceForGeneral.reasons[i];
				checkboxWidget = new OO.ui.CheckboxInputWidget({
					value: reason.value,
					data: reason.data,
					selected: false
				});
				if(reason.value === copyVioReasonValue) {
					fieldLayout = new OO.ui.FieldLayout(checkboxWidget, {
						label: reason.label,
						align: 'inline',
						help: reason.help
					});
					fieldLayout.$element.append(copyVioInput.$element);
					copyVioInput.$element.hide(); // Hide it initially
				} else {
					fieldLayout = new OO.ui.FieldLayout(checkboxWidget, {
						label: reason.label,
						align: 'inline',
						help: reason.help
					});
				}
				generalReasons.addItems([fieldLayout]);
			}
			selectedNamespaceForOthers = null;
			for(i = 0; i < speedyDeletionReasons.length; i++) {
				if(speedyDeletionReasons[i].namespace === 'other') {
					selectedNamespaceForOthers = {
						name: speedyDeletionReasons[i].name,
						reasons: speedyDeletionReasons[i].reasons
					};
					break;
				}
			}
			otherReasons = new OO.ui.FieldsetLayout({
				label: selectedNamespaceForOthers.name
			});
			for(i = 0; i < selectedNamespaceForOthers.reasons.length; i++) {
				reason = selectedNamespaceForOthers.reasons[i];
				checkboxWidget = new OO.ui.CheckboxInputWidget({
					value: reason.value,
					data: reason.data,
					selected: false
				});
				fieldLayout = new OO.ui.FieldLayout(checkboxWidget, {
					label: reason.label,
					align: 'inline',
					help: reason.help
				});
				otherReasons.addItems([fieldLayout]);
			}
			generalReasons.$element.on('click', function(item) {
				if(item.target.value === copyVioReasonValue) {
					copyVioInput.$element.show();
				}
			});
			deletionOptions = new OO.ui.FieldsetLayout({
				label: mw.msg('other-options'),
			});
			deletionOptions.addItems([
				new OO.ui.FieldLayout(new OO.ui.CheckboxInputWidget({
					selected: false,
					value: 'recreationProrection'
				}), {
					label: new OO.ui.deferMsg('protect-against-rebuilding'),
					help: new OO.ui.deferMsg('protect-against-rebuilding-help'),
					align: 'inline'
				}),
				new OO.ui.FieldLayout(new OO.ui.CheckboxInputWidget({
					selected: adiutorUserOptions.speedyDeletion.csdSendMessageToCreator,
					value: 'informCreator'
				}), {
					label: new OO.ui.deferMsg('afd-inform-creator'),
					help: new OO.ui.deferMsg('afd-inform-creator-help'),
					align: 'inline'
				})
			]);
			var headerTitle = new OO.ui.MessageWidget({
				type: 'notice',
				inline: true,
				label: new OO.ui.deferMsg('csd-header-title')
			});
			var headerTitleDescription = new OO.ui.LabelWidget({
				label: new OO.ui.deferMsg('csd-header-description')
			});
			headerTitleDescription.$element.css({
				'margin-top': '10px',
				'padding-left': '30px',
				'margin-bottom': '10px'
			});
			var left_panel = new OO.ui.PanelLayout({
				$content: [nameSpaceDeletionReasons.$element, deletionOptions.$element],
				classes: ['one'],
				scrollable: false,
			});
			var right_panel = new OO.ui.PanelLayout({
				$content: generalReasons.$element,
				classes: ['two'],
				scrollable: false,
			});
			var stack = new OO.ui.StackLayout({
				items: [left_panel, right_panel],
				continuous: true,
				classes: ['adiutor-csd-modal-container']
			});
			stack.$element.css({
				'margin-top': '20px',
			});
			this.panel1 = new OO.ui.PanelLayout({
				padded: true,
				expanded: false,
				classes: ['adiutor-csd-modal-container-panel-1']
			});
			if(revDelCount >= "1") {
				var deletionMessage = mw.msg('page-deletion-count-warning', revDelCount);
				var deletionMessageWithLink = deletionMessage.replace(/\$2/g, '<a href="/wiki/Special:Log?type=delete&user=&page=' + mwConfig.wgPageName + '">' + mw.msg('log') + '</a>');
				var headerBarRevDel = new OO.ui.MessageWidget({
					type: 'warning',
					label: new OO.ui.HtmlSnippet(deletionMessageWithLink)
				});
				this.panel1.$element.append(headerTitle.$element, headerTitleDescription.$element, headerBarRevDel.$element, stack.$element);
			} else {
				this.panel1.$element.append(headerTitle.$element, headerTitleDescription.$element, stack.$element);
			}
			this.stackLayout = new OO.ui.StackLayout({
				items: [this.panel1]
			});
			this.$body.append(this.stackLayout.$element);
		};
		// Set up the initial mode of the window ('edit', in this example.)  
		SpeedyDeletionRequestDialog.prototype.getSetupProcess = function(data) {
			return SpeedyDeletionRequestDialog.super.prototype.getSetupProcess.call(this, data).next(function() {
				this.actions.setMode('edit');
			}, this);
		};
		// Use the getActionProcess() method to set the modes and displayed item.
		SpeedyDeletionRequestDialog.prototype.getActionProcess = function(action) {
			if(action === 'policy') {
				window.open('/wiki/' + speedyDeletionPolicyLink + '', '_blank');
			} else if(action === 'back') {
				// Set the mode to edit.
				this.actions.setMode('edit');
				// Show the edit panel.
				this.stackLayout.setItem(this.panel1);
			} else if(action === 'continue') {
				var dialog = this;
				return new OO.ui.Process(function() {
					nameSpaceDeletionReasons.items.forEach(function(Reason) {
						if(Reason.fieldWidget.selected) {
							csdReasons.push({
								value: Reason.fieldWidget.value,
								data: Reason.fieldWidget.data,
								selected: Reason.fieldWidget.selected
							});
						}
					});
					generalReasons.items.forEach(function(Reason) {
						if(Reason.fieldWidget.selected) {
							csdReasons.push({
								value: Reason.fieldWidget.value,
								data: Reason.fieldWidget.data,
								selected: Reason.fieldWidget.selected
							});
						}
					});
					if(csdReasons.length > 0) {
						var saltCSDSummary = '';
						if(copyVioInput.value != "") {
							copyVioURL = '|url=' + copyVioInput.value;
						} else {
							copyVioURL = "";
						}
						if(csdReasons.length > 1) {
							if(useVerticalVarForSeparatingMultipleReasons) {
								var saltCSDReason = csdTemplateStartMultipleReason;
								var i = 0;
								var keys = Object.keys(csdReasons);
								for(i = 0; i < keys.length; i++) {
									saltCSDReason += '|' + csdReasons[keys[i]].value;
								}
								for(i = 0; i < keys.length; i++) {
									if(i > 0) saltCSDSummary += (i < keys.length - 1) ? ', ' : ' ' + reasonAndSeperator + ' ';
									saltCSDSummary += '[[' + speedyDeletionPolicyPageShorcut + '#' + csdReasons[keys[i]].value + ']]';
								}
								csdReason = saltCSDReason + '}}';
								csdSummary = replaceParameter(multipleReasonSummary, '2', saltCSDSummary);
							} else {
								var saltCSDReason = csdTemplateStartMultipleReason;
								var i = 0;
								var keys = Object.keys(csdReasons);
								for(i = 0; i < keys.length; i++) {
									if(i > 0) saltCSDReason += (i < keys.length - 1) ? ', ' : ' ' + reasonAndSeperator + ' ';
									saltCSDReason += '[[' + speedyDeletionPolicyPageShorcut + '#' + csdReasons[keys[i]].value + ']]';
								}
								for(i = 0; i < keys.length; i++) {
									if(i > 0) saltCSDSummary += (i < keys.length - 1) ? ', ' : ' ' + reasonAndSeperator + ' ';
									saltCSDSummary += '[[' + speedyDeletionPolicyPageShorcut + '#' + csdReasons[keys[i]].value + ']]';
								}
								csdReason = saltCSDReason + copyVioURL + '}}';
								csdSummary = replaceParameter(multipleReasonSummary, '2', saltCSDSummary);
							}
						} else {
							var reasonPlaceholder = csdTemplateStartSingleReason + copyVioURL + '}}';
							if(csdTemplatePostfixReasonData) {
								csdReason = replaceParameter(reasonPlaceholder, '3', csdReasons[0].data);
							} else if(csdTemplatePostfixReasonValue) {
								csdReason = replaceParameter(reasonPlaceholder, '3', csdReasons[0].value);
							}
							csdSummary = replaceParameter(singleReasonSummary, '2', csdReasons[0].data);
							saltCSDSummary = replaceParameter(singleReasonSummary, '2', csdReasons[0].data);
						}
						deletionOptions.items.forEach(function(Option) {
							if(Option.fieldWidget.selected) {
								csdOptions.push({
									value: Option.fieldWidget.value,
									selected: Option.fieldWidget.selected
								});
							}
						});
						csdOptions.forEach(function(Option) {
							if(Option.value === "recreationProrection") {
								csdReason = csdReason + "\n" + '{{Salt}}';
							}
							if(Option.value === "informCreator") {
								getCreator().then(function(data) {
									var articleAuthor = data.query.pages[mw.config.get('wgArticleId')].revisions[0].user;
									if(!mw.util.isIPAddress(articleAuthor)) {
										var placeholdersForNotification = {
											$1: pageTitle,
											$2: saltCSDSummary,
											$3: csdReason,
										};
										var message = replacePlaceholders(placeholdersForNotification, placeholders);
										sendMessageToAuthor(articleAuthor, message);
									}
								});
							}
						});
						putCSDTemplate(csdReason, csdSummary);
						logCsdRequest(saltCSDSummary, adiutorUserOptions);
						showProgress();
						dialog.close();
					} else {
						mw.notify(mw.message('select-speedy-deletion-reason').text(), {
							title: mw.msg('warning'),
							type: 'error'
						});
					}
				});
			}
			return SpeedyDeletionRequestDialog.super.prototype.getActionProcess.call(this, action);
		};
		// Create and append the window manager.
		var windowManager = new OO.ui.WindowManager({
			classes: ['adiutor-csd-modal-dialog-container-sub']
		});
		$(document.body).append(windowManager.$element);
		// Create a new dialog window.
		var speedyDeletionRequestDialog = new SpeedyDeletionRequestDialog({
			size: 'larger',
			classes: ['adiutor-csd-modal-dialog-container']
		});
		// Add windows to window manager using the addWindows() method.
		windowManager.addWindows([speedyDeletionRequestDialog]);
		// Open the window.
		windowManager.openWindow(speedyDeletionRequestDialog);
		// Define functions below as needed
		function putCSDTemplate(csdReason, csdSummary) {
			api.postWithToken('csrf', {
				action: 'edit',
				title: mwConfig.wgPageName,
				prependtext: csdReason + "\n",
				summary: csdSummary,
				tags: 'Adiutor',
				format: 'json'
			}).done(function() {
				adiutorUserOptions.stats.csdRequests++;
				api.postWithEditToken({
					action: 'globalpreferences',
					format: 'json',
					optionname: 'userjs-adiutor-' + mw.config.get('wgWikiID'),
					optionvalue: JSON.stringify(adiutorUserOptions),
					formatversion: 2,
				}, function() {});
				location.reload();
			});
		}

		function logCsdRequest() {
			if(adiutorUserOptions.speedyDeletion.csdLogNominatedPages === true) {
				// Get the current date and format it as "Month Year"
				var currentDate = new Date();
				var currentMonthYear = currentDate.toLocaleString(localLangCode, {
					month: 'long',
					year: 'numeric'
				});
				// Define the section title using the current month and year
				var sectionTitle = "== " + currentMonthYear + " ==";
				var newContent; // Define newContent here in a higher scope
				// Fetch the content of the page
				api.get({
					action: 'parse',
					page: userPagePrefix.concat(mwConfig.wgUserName, '/' + adiutorUserOptions.speedyDeletion.csdLogPageName + '').split(' ').join('_'),
					format: 'json',
					prop: 'wikitext'
				}).then(function(data) {
					var pageContent = data.parse.wikitext['*'];
					// Check if the section title exists in the page content
					if(pageContent.includes(sectionTitle)) {
						// Append the log entry just below the section
						newContent = pageContent.replace(sectionTitle, sectionTitle + "\n" + "# '''[[:" + pageTitle + "|" + pageTitle + "]]''' " + csdSummary + " ~~~~~");
					} else {
						// Create the section and append the log entry
						newContent = pageContent + "\n\n" + sectionTitle + "\n" + "# '''[[:" + pageTitle + "|" + pageTitle + "]]''' " + csdSummary + " ~~~~~";
					}
					// Perform the edit to update the page content
					return api.postWithToken('csrf', {
						action: 'edit',
						title: userPagePrefix.concat(mwConfig.wgUserName, '/' + adiutorUserOptions.speedyDeletion.csdLogPageName + '').split(' ').join('_'),
						text: newContent,
						summary: replaceParameter(apiPostSummaryforLog, '1', pageTitle),
						tags: 'Adiutor',
						format: 'json'
					});
				}).catch(function(error) {
					// Handle the error here
					console.error('Error:', error);
					// If you want to retry the edit in the catch block, you can do so
					api.postWithToken('csrf', {
						action: 'edit',
						title: userPagePrefix.concat(mwConfig.wgUserName, '/' + adiutorUserOptions.speedyDeletion.csdLogPageName + '').split(' ').join('_'),
						section: 'new',
						sectiontitle: sectionTitle,
						text: "# '''[[:" + pageTitle + "]]''' " + csdSummary + " ~~~~~",
						summary: replaceParameter(apiPostSummaryforLog, '1', pageTitle),
						format: 'json',
					}).done(function() {});
				});
			}
		}

		function getCreator() {
			return api.get({
				action: 'query',
				prop: 'revisions',
				rvlimit: 1,
				rvprop: ['user'],
				rvdir: 'newer',
				titles: mwConfig.wgPageName
			});
		}

		function sendMessageToAuthor(articleAuthor, notificationMessage) {
			api.postWithToken('csrf', {
				action: 'edit',
				title: userTalkPagePrefix + articleAuthor,
				appendtext: '\n' + notificationMessage,
				summary: replaceParameter(apiPostSummary, '1', pageTitle),
				tags: 'Adiutor',
				format: 'json'
			}).done(function() {});
		}

		function showProgress() {
			var processStartedDialog = new OO.ui.MessageDialog();
			var progressBar = new OO.ui.ProgressBarWidget();
			var windowManager = new OO.ui.WindowManager();
			$(document.body).append(windowManager.$element);
			windowManager.addWindows([processStartedDialog]);
			windowManager.openWindow(processStartedDialog, {
				title: mw.msg('processing'),
				notificationMessage: progressBar.$element
			});
		}

		function replacePlaceholders(input, replacements) {
			return input.replace(/\$(\d+)/g, function(match, group) {
				var replacement = replacements['$' + group];
				return replacement !== undefined ? replacement : match;
			});
		}

		function replaceParameter(input, parameterName, newValue) {
			const regex = new RegExp('\\$' + parameterName, 'g');
			if(input.includes('$' + parameterName)) {
				return input.replace(regex, newValue);
			} else {
				return input;
			}
		}
	});
});
/* </nowiki> */