User:Maxim Masiutin/RefRenamer-core.js

// This is a fork from User:Nardog/RefRenamer-core.js by User:Nardog // The fork adds support the pmid (PubMed ID) attribute.

(function refRenamerCore {	let messages = Object.assign({ loadingSource: 'Loading the source...', loadingHtml: 'Loading HTML...', parsing: 'Parsing wikitext...', opening: 'Opening the diff...', continue: 'Continue', main: 'Main fallback stack:', pmid: 'pmid', lastName: 'Last name', firstName: 'First name', author: 'Author', periodical: 'Periodical/website', publisher: 'Publisher', article: 'Article', book: 'Book', domain: 'Domain', firstPhrase: 'First phrase', lowercase: 'Lowercase', removeDia: 'Remove diacritics', removePunct: 'Remove punctuation', replaceSpace: 'Replace space with:', year: 'Year', yearFallback: 'Fall back on any 4-digit number', yearConvert: 'Convert to ASCII', latinIncrement: 'Use Latin letters for increments', latinStart: 'Start with:', increment: 'Numeric increments start at:', forceIncrement: 'Always insert increments', delimiter: 'Delimiter:', delimitConditional: 'Insert delimiters only after numerals', removeUnreused: 'Remove unreused names', apply: 'Apply', reset: 'Reset', tableName: 'Name', tableCaption: 'References to rename', tableRef: 'Reference', tableNewName: 'New name', tableAddRemove: '+/−', keepTooltip: 'Uncheck to remove', tableRemove: '(Remove)', removeTooltip: 'Remove from references to rename', otherTableCaption: 'Other named references', notReused: '(not reused)', addTooltip: 'Add to references to rename', addAll: 'Add all', resetSelection: 'Reset selection', noNamesAlert: 'The source does not contain ref names to rename.', noChangesError: 'No names have been modified.', duplicatesError: 'The following names are already used or input more than once:', summary: 'Replaced VE ref names using RefRenamer', genericSummary: 'Renamed references using RefRenamer' }, window.refrenamerMessages);	let getMsg = (key, ...args) => ( messages.hasOwnProperty(key) ? mw.format(messages[key], ...args) : key );	let notify = key => {		mw.notify(getMsg(key), { autoHideSeconds: 'long', tag: 'refrenamer' });	};	let dialog;	let encodedPn = encodeURIComponent(mw.config.get('wgPageName'));	let headers = {		'Api-User-Agent': 'RefRenamer (https://en.wikipedia.org/wiki/User:Maxim_Masiutin/RefRenamer)'	};	window.refRenamer = => {		let data = {			isEdit: document.getElementById('wpTextbox1') &&				!$('input[name=wpSection]').val,			refs: []		};		let promise;		let dependencies = [			'oojs-ui-windows', 'oojs-ui-widgets', 'jquery.makeCollapsible',			'oojs-ui.styles.icons-interactions', 'mediawiki.storage'		];		if (data.isEdit) {			dependencies.push('jquery.textSelection');		} else {			dependencies.push('mediawiki.api', 'user.options');			data.started = performance.now;			notify('loadingSource');			promise = $.ajax('/w/rest.php/v1/page/' + encodedPn, { headers }).then(response => { data.wikitext = response.source; data.revId = response.latest.id; data.editTime = response.latest.timestamp.replace(/\D/g, ''); });		}		$.when(mw.loader.using(dependencies), promise).then( => { if (data.isEdit) { data.wikitext = $('#wpTextbox1').textSelection('getContents'); }			let sources = []; let wikitext = data.wikitext.replace(//g, ''); let match; let re = /]+?))\s*(?:>([^]+?)<\/ref|\/)>/gi;			while ((match = re.exec(wikitext))) {				let name = match[1] || match[2] || match[3];				let ref = data.refs.find(r => r.name === name);				if (ref) {					ref.reused = true;				} else {					data.refs.push({						name: name,						normalized: normalize(name),						isVe: /^:\d+$/.test(name)					});				}				if (data.isEdit && match[4]) {					sources.push(match[0]);				}			}			if (!data.refs.length) throw 'nonames';			if (data.isEdit) {				notify('parsing');				return $.ajax('/api/rest_v1/transform/wikitext/to/html/' + encodedPn, {					type: 'POST',					data: { wikitext: sources.join(''), body_only: true },					headers: headers				});			} else {				notify('loadingHtml');				return $.ajax('/api/rest_v1/page/html/' + encodedPn, { headers });			}		}).then(response => {			let $page = $($.parseHTML(response)); let $refs = $page.find('.mw-references:not([data-mw-group]) .mw-reference-text'); $refs.each(function (i) {				let match = this.id.match(/^mw-reference-text-cite_note-(.+)-\d+$/);				if (!match) return;				let ref = data.refs.find(r => r.normalized === match[1]);				if (!ref) return;				ref.coins = {};				ref.$ref = $refs.eq(i).clone;				ref.$ref.find('[id], [about]').addBack.removeAttr('id about');				ref.$ref.find('a').attr('target', '_blank')					.filter('[href^="./"]').attr('href', function { return mw.format(							mw.config.get('wgArticlePath'),							this.getAttribute('href').slice(2)						); });				let coinsSpan = this.querySelector('.Z3988');				if (coinsSpan) {					new URLSearchParams(coinsSpan.title).forEach((v, k) => { if (k.startsWith('rft.')) { ref.coins[k.slice(4)] = v;						} else if (k === 'rft_id') { try { if (v.startsWith('http')) { ref.coins.domain = new URL(v).hostname; } else {                              let infore = /^info:([A-Za-z0-9]+)\/(.+)$/; let infomatch; if ((infomatch = infore.exec(v)) !== null) {                                let infokey   = infomatch[1]; let infovalue = infomatch[2]; if (infokey === 'pmid') {                                   ref.coins[infokey] = infokey + infovalue; }                              }                             }						 } catch (e) {} }					});				}				let text = this.textContent;				if (ref.coins.date) {					let numbers = ref.coins.date.match(/\p{Nd}+/gu);					if (numbers) {						let converted = numbers.map(n => toAscii(n));						ref.coins.year = numbers[							converted.indexOf(String(Math.max(...converted)))						];						data.hasNonAsciiYear = data.hasNonAsciiYear || isNaN(ref.coins.year);					}				} else {					let yearMarch = text.match(/(?:^|\P{Nd})(\p{Nd}{4})(?!\p{Nd})/u);					if (yearMarch) {						ref.year = yearMarch[1];						data.hasNonAsciiYear = data.hasNonAsciiYear || isNaN(ref.year);					}				}				if (!ref.coins.domain) {					let link = this.querySelector('a.external');					if (link) ref.domain = link.hostname;				}				ref.phrase = (text.match(/[^\s\p{P}].*?(?=\s*(?:\p{P}|$))/u) || [])[0];			}); data.refs = data.refs.filter(ref => ref.$ref); if (!data.refs.length) throw 'nonames'; let collator; try { collator = Intl.Collator(mw.config.get('wgContentLanguage') + '-u-kn-true'); } catch (e) { collator = Intl.Collator('en-u-kn-true'); }			data.refs.sort((a, b) => collator.compare(a.name, b.name)); if (!dialog) initDialog; dialog.open(data); }).catch(e => { OO.ui.alert(e === 'nonames' ? getMsg('noNamesAlert') : e.message); }).always( => { mw.requestIdleCallback( => {				let notif = $('.mw-notification-tag-refrenamer').data('mw-notification');				if (notif) notif.close;			}); });	};	let initDialog = => {		let rtl = document.dir === 'rtl';		let left = rtl ? 'right' : 'left';		let right = rtl ? 'left' : 'right';		mw.loader.addStyleTag(`.refrenamer .oo-ui-window-body{padding:1em} .refrenamer .oo-ui-layout.oo-ui-labelElement.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline{margin:4px 0} .refrenamer-subinput{padding-${left}:2em} .refrenamer-dropdown .oo-ui-fieldLayout-header{flex-grow:0 !important} .refrenamer-dropdown .oo-ui-fieldLayout-field{width:min-content !important} .refrenamer-name, .refrenamer-ref{vertical-align:top} .refrenamer-name{max-width:6em} .refrenamer-name, .refrenamer-ref .mw-reference-text{font-size:90%;overflow-wrap:break-word} .refrenamer-newname{height:3em;position:relative;width:12em} .refrenamer-newname > .oo-ui-textInputWidget{position:absolute;top:0;${left}:0;height:100%} .refrenamer-newname .oo-ui-inputWidget-input{height:100%;resize:none;scrollbar-width:none} .refrenamer-newname .oo-ui-textInputWidget-type-text > .oo-ui-inputWidget-input{font-family:monospace,monospace;font-size:90%} .refrenamer-newname > .oo-ui-checkboxInputWidget{float:${right};margin-${right}:0;z-index:1} .refrenamer-newname .oo-ui-checkboxInputWidget ~ .oo-ui-textInputWidget > .oo-ui-inputWidget-input{padding-${right}:30px} .refrenamer-newname .oo-ui-textInputWidget:not(.oo-ui-element-hidden) + span{display:none} .refrenamer .refrenamer-addremove{padding:0;position:relative;width:32px;height:32px} .refrenamer-addremove > .oo-ui-buttonElement-frameless.oo-ui-iconElement{margin:0;position:absolute;top:0;bottom:0;left:0;right:0} .refrenamer-addremove .oo-ui-buttonElement-button{height:100%} .refrenamer-othername{max-width:32em;overflow-wrap:break-word} .refrenamer-table-wide .refrenamer-othername{max-width:16em}`); function RefRenamerDialog(config) { RefRenamerDialog.parent.call(this, config); this.$element.addClass('refrenamer'); }		OO.inheritClass(RefRenamerDialog, OO.ui.ProcessDialog); RefRenamerDialog.static.name = 'refRenamerDialog'; RefRenamerDialog.static.title = 'RefRenamer'; RefRenamerDialog.static.size = 'large'; RefRenamerDialog.static.actions = [ {				flags: ['safe', 'close'] },			{				action: 'continue', label: getMsg('continue'), flags: ['primary', 'progressive'] }		];		RefRenamerDialog.prototype.initialize = function { RefRenamerDialog.parent.prototype.initialize.apply(this, arguments); this.mainSelect = new OO.ui.MenuTagMultiselectWidget({				options: [                   { data: 'pmid', label: getMsg('pmid') },                    { data: 'aulast', label: getMsg('lastName') },					{ data: 'aufirst', label: getMsg('firstName') },					{ data: 'au', label: getMsg('author') },					{ data: 'jtitle', label: getMsg('periodical') },					{ data: 'pub|inst', label: getMsg('publisher') },					{ data: 'atitle|title', label: getMsg('article') },					{ data: 'btitle', label: getMsg('book') },					{ data: 'domain', label: getMsg('domain') },					{ data: 'phrase', label: getMsg('firstPhrase') }				]			}).connect(this, { change: 'updateSize', reorder: 'updateSize' }); this.lowercaseCheck = new OO.ui.CheckboxInputWidget; this.removeDiaCheck = new OO.ui.CheckboxInputWidget; this.removePunctCheck = new OO.ui.CheckboxInputWidget; this.replaceSpaceCheck = new OO.ui.CheckboxInputWidget.on('change', selected => {				this.replaceSpaceInput.toggle(selected);				this.updateSize;			}); this.replaceSpaceInput = new OO.ui.TextInputWidget({				classes: ['refrenamer-subinput']			}).toggle; this.yearCheck = new OO.ui.CheckboxInputWidget.on('change', selected => {				this.yearFallbackLayout.toggle(selected);				this.yearConvertLayout.toggle(selected && this.hasNonAsciiYear);				this.latinIncrementLayout.toggle(selected);				this.updateSize;			}); this.yearFallbackCheck = new OO.ui.CheckboxInputWidget; this.yearFallbackLayout = new OO.ui.FieldLayout(this.yearFallbackCheck, {				label: getMsg('yearFallback'),				align: 'inline',				classes: ['refrenamer-subinput']			}); this.yearConvertCheck = new OO.ui.CheckboxInputWidget; this.yearConvertLayout = new OO.ui.FieldLayout(this.yearConvertCheck, {				label: getMsg('yearConvert'),				align: 'inline',				classes: ['refrenamer-subinput']			}); this.latinIncrementCheck = new OO.ui.CheckboxInputWidget.on('change', selected => {				this.latinStartLayout.toggle(selected);				this.updateSize;			}); this.latinIncrementLayout = new OO.ui.FieldLayout(this.latinIncrementCheck, {				label: getMsg('latinIncrement'),				align: 'inline',				classes: ['refrenamer-subinput']			}); this.latinIncrementDropdown = new OO.ui.DropdownWidget({				menu: {					items: [						new OO.ui.MenuOptionWidget({ data: 0, label: 'a' }),						new OO.ui.MenuOptionWidget({ data: 1, label: 'b' })					]				}			}); this.latinStartLayout = new OO.ui.FieldLayout(this.latinIncrementDropdown, {				label: getMsg('latinStart'),				classes: ['refrenamer-subinput', 'refrenamer-dropdown']			}).toggle; this.latinIncrementLayout.$element.append(this.latinStartLayout.$element); this.incrementDropdown = new OO.ui.DropdownWidget({				menu: {					items: [						new OO.ui.MenuOptionWidget({ data: 0, label: '0' }),						new OO.ui.MenuOptionWidget({ data: 1, label: '1' }),						new OO.ui.MenuOptionWidget({ data: 2, label: '2' })					]				}			}); this.forceIncrementCheck = new OO.ui.CheckboxInputWidget; this.delimiterInput = new OO.ui.TextInputWidget; this.delimitConditionalCheck = new OO.ui.CheckboxInputWidget; this.removeUnreusedCheck = new OO.ui.CheckboxInputWidget; this.applyButton = new OO.ui.ButtonInputWidget({				label: getMsg('apply'),				flags: ['progressive'],				type: 'submit'			}).connect(this, { click: 'applyConfig' }); this.resetButton = new OO.ui.ButtonWidget({				label: getMsg('reset')			}).connect(this, { click: 'setConfig' }); this.form = new OO.ui.FormLayout({				items: [					new OO.ui.FieldLayout(this.mainSelect, { label: getMsg('main'), align: 'top' }),					new OO.ui.FieldLayout(this.lowercaseCheck, { label: getMsg('lowercase'), align: 'inline' }),					new OO.ui.FieldLayout(this.removeDiaCheck, { label: getMsg('removeDia'), align: 'inline' }),					new OO.ui.FieldLayout(this.removePunctCheck, { label: getMsg('removePunct'), align: 'inline' }),					new OO.ui.FieldLayout(this.replaceSpaceCheck, { label: getMsg('replaceSpace'), align: 'inline' }),					this.replaceSpaceInput,					new OO.ui.FieldLayout(this.yearCheck, { label: getMsg('year'), align: 'inline' }),					this.yearFallbackLayout,					this.yearConvertLayout,					this.latinIncrementLayout,					new OO.ui.FieldLayout(this.incrementDropdown, { label: getMsg('increment'), classes: ['refrenamer-dropdown'] }),					new OO.ui.FieldLayout(this.forceIncrementCheck, { label: getMsg('forceIncrement'), align: 'inline' }),					new OO.ui.FieldLayout(this.delimiterInput, { label: getMsg('delimiter'), align: 'top' }),					new OO.ui.FieldLayout(this.delimitConditionalCheck, { label: getMsg('delimitConditional'), align: 'inline' }),					new OO.ui.FieldLayout(this.removeUnreusedCheck, { label: getMsg('removeUnreused'), align: 'inline' }),					this.applyButton,					this.resetButton				]			}); this.$tbody = $(' '); this.$otherTbody = $(' '); this.$otherTable = $(' ').addClass('wikitable').append(				$(' ').text(getMsg('otherTableCaption')),				$(' ').append( $(' ').append(						$(' ').text(getMsg('tableName')),						$(' ').text(getMsg('tableRef')),						$(' ').text(getMsg('tableAddRemove'))					) ),				this.$otherTbody			).on('afterExpand.mw-collapsible', function {				this.classList.add('refrenamer-table-wide');			}).on('afterCollapse.mw-collapsible', function  {				this.classList.toggle( 'refrenamer-table-wide', !!this.querySelector('.mw-collapsible:not(.mw-collapsed)') );			});			this.addAllButton = new OO.ui.ButtonWidget({				flags: ['progressive'],				label: getMsg('addAll')			}).on('click', => {				this.refs.forEach(ref => { if (!ref.renamable) { this.addCandidate(ref, true); }				});			});			this.resetSelectionButton = new OO.ui.ButtonWidget({				label: getMsg('resetSelection')			}).on('click', => {				this.refs.forEach(ref => { if (ref.renamable) { if (!ref.isVe) this.removeCandidate(ref); } else { if (ref.isVe) this.addCandidate(ref, true); }				});			});			this.$body.append(				this.form.$element,				$(' ').addClass('wikitable').append( $(' ').text(getMsg('tableCaption')), $(' ').append(						$(' ').append( $(' ').text(getMsg('tableName')), $(' ').text(getMsg('tableRef')), $(' ').text(getMsg('tableNewName')), $(' ').text(getMsg('tableAddRemove')) )					),					this.$tbody ),				this.$otherTable,				this.addAllButton.$element,				this.resetSelectionButton.$element			); this.defaults = { main: ['aulast', 'aufirst', 'au', 'jtitle', 'pub|inst', 'phrase'], lowercase: false, removeDia: false, removePunct: false, replaceSpace: false, year: true, yearFallback: false, yearConvert: true, latinIncrement: false, increment: 2, forceIncrement: false, delimiter: '-', delimitConditional: false, removeUnreused: true };		};		RefRenamerDialog.prototype.getConfig = function { return { main: this.mainSelect.getValue, lowercase: this.lowercaseCheck.isSelected, removeDia: this.removeDiaCheck.isSelected, removePunct: this.removePunctCheck.isSelected, replaceSpace: this.replaceSpaceCheck.isSelected && this.replaceSpaceInput.getValue, year: this.yearCheck.isSelected, yearFallback: this.yearFallbackCheck.isSelected, yearConvert: this.yearConvertCheck.isSelected, latinIncrement: this.latinIncrementCheck.isSelected && this.latinIncrementDropdown.getMenu.findSelectedItem.getData, increment: this.incrementDropdown.getMenu.findSelectedItem.getData, forceIncrement: this.forceIncrementCheck.isSelected, delimiter: this.delimiterInput.getValue, delimitConditional: this.delimitConditionalCheck.isSelected, removeUnreused: this.removeUnreusedCheck.isSelected };		};		RefRenamerDialog.prototype.setConfig = function (config) { config = Object.assign({}, this.defaults, config); this.mainSelect.setValue(config.main); this.lowercaseCheck.setSelected(config.lowercase); this.removeDiaCheck.setSelected(config.removeDia); this.removePunctCheck.setSelected(config.removePunct); this.replaceSpaceCheck.setSelected(typeof config.replaceSpace === 'string'); this.replaceSpaceInput.setValue(				this.replaceSpaceCheck.isSelected ? config.replaceSpace : '-'			); this.yearCheck.setSelected(config.year); this.yearFallbackCheck.setSelected(config.yearFallback); this.yearConvertCheck.setSelected(config.yearConvert); this.latinIncrementCheck.setSelected(typeof config.latinIncrement === 'number'); this.latinIncrementDropdown.getMenu.selectItemByData(				this.latinIncrementCheck.isSelected ? config.latinIncrement : 0			); this.incrementDropdown.getMenu.selectItemByData(config.increment); this.forceIncrementCheck.setSelected(config.forceIncrement); this.delimiterInput.setValue(config.delimiter); this.delimitConditionalCheck.setSelected(config.delimitConditional); this.removeUnreusedCheck.setSelected(config.removeUnreused); };		RefRenamerDialog.prototype.applyConfig = function { let config = this.getConfig; config.processed = this.refs.filter(ref => !ref.renamable) .map(ref => ref.normalized); this.refs.forEach(ref => {				if (ref.renamable) {					this.applyConfigTo(ref, config);				}			}); };		RefRenamerDialog.prototype.applyConfigTo = function (ref, config) { config = config || this.getConfig; if (!config.processed) { config.processed = this.refs.filter(r => r !== ref).map(r => ( r.renamable ? normalize(r.input.getValue) || r.normalized : r.normalized ));			}			ref.input.setValue(''); if (!ref.reused) { ref.keepCheck.setSelected(!config.removeUnreused); if (config.removeUnreused) return; }			let s;			config.main.some(key => key.split('|').some(subkey => { s = ref.coins[subkey] || ref[subkey]; return s;			})); if (!s) { config.processed.push(ref.normalized); return; }			if (config.lowercase) { s = s.toLowerCase; }			if (config.removeDia) { s = s.normalize('NFD').replace(/\p{Mn}/gu, ''); }			if (config.removePunct) { s = s.replace(/\p{P}/gu, ''); }			if (typeof config.replaceSpace === 'string') { s = s.replace(/\s+/g, config.replaceSpace); }			let useLatin; let year; if (!s.startsWith('pmid')) {             year = config.year && (ref.coins.year || config.yearFallback && ref.year); }			if (year) { if (config.yearConvert) year = toAscii(year); let delimiter = config.delimitConditional && /\P{Nd}$/u.test(s) ? ''					: config.delimiter; s += delimiter + year; useLatin = typeof config.latinIncrement === 'number'; }			let unsuffixed = s;			let normalized = normalize(s); let delimiter = useLatin || (				config.delimitConditional && /\P{Nd}$/u.test(unsuffixed)			) ? '' : config.delimiter; let increment = useLatin ? config.latinIncrement : config.increment; let incrementStr = useLatin ? toLatin(increment) : increment; let forceIncrement = config.forceIncrement; while (forceIncrement || config.processed.includes(normalized)) { s = unsuffixed + delimiter + incrementStr; normalized = normalize(s); increment++; incrementStr = useLatin ? toLatin(increment) : increment; forceIncrement = false; }			config.processed.push(normalized); ref.input.setValue(s); };		RefRenamerDialog.prototype.addCandidate = function (ref, isMove) { ref.renamable = true; if (this.refs.every(r => r.renamable)) { this.$otherTable.hide; this.addAllButton.toggle(false); } else { this.$otherTable.show; this.addAllButton.toggle(true); }			ref.$otherRow.hide; if (isMove) { ref.$otherRow.find('.mw-collapsible') .data('mw-collapsible').collapse; }			if (ref.removeButton) { this.applyConfigTo(ref); ref.$row.children('.refrenamer-ref').append(ref.$ref); ref.$row.show; return; }			ref.input = new OO.ui.MultilineTextInputWidget({				allowLinebreaks: false,				placeholder: ref.name			}).connect(this, { enter: ['executeAction', 'continue'] }); ref.input.$input.on({ focus: onFocus, blur: onBlur }); if (!ref.reused) { ref.keepCheck = new OO.ui.CheckboxInputWidget({					selected: true,					title: getMsg('keepTooltip')				}).connect(ref.input, { change: 'toggle' }); ref.keepCheck.$input.on({ focus: onFocus, blur: onBlur }); }			if (isMove) this.applyConfigTo(ref); ref.removeButton = new OO.ui.ButtonWidget({				flags: ['destructive'],				framed: false,				icon: 'subtract',				title: getMsg('removeTooltip')			}).connect(this, { click: ['removeCandidate', ref] }); ref.$row.append(				$(' ').addClass('refrenamer-name').text(ref.name),				$(' ').addClass('refrenamer-ref mw-parser-output').append(ref.$ref),				$(' ').addClass('refrenamer-newname').append( ref.keepCheck && ref.keepCheck.$element, ref.input.$element, ref.keepCheck && $(' ').text(getMsg('tableRemove')) ),				$(' ').addClass('refrenamer-addremove').append(ref.removeButton.$element)			).show; };		RefRenamerDialog.prototype.removeCandidate = function (ref) { ref.renamable = false; this.$otherTable.show; this.addAllButton.toggle(true); ref.$row.hide; if (ref.addButton) { ref.$otherRow.find('.mw-collapsible-content').append(ref.$ref); ref.$otherRow.show; return; }			ref.addButton = new OO.ui.ButtonWidget({				flags: ['progressive'],				framed: false,				icon: 'add',				title: getMsg('addTooltip')			}).connect(this, { click: ['addCandidate', ref, true] }); ref.$otherRow.append(				$(' ').addClass('refrenamer-othername').text(ref.name).append(!ref.reused && [ ' ',					$(' ').text(getMsg('notReused')) ]),				$(' ').addClass('refrenamer-ref mw-parser-output').append( $(' ').addClass('mw-collapsible mw-collapsed') .append(ref.$ref).makeCollapsible ),				$(' ').addClass('refrenamer-addremove').append(ref.addButton.$element)			).show; };		RefRenamerDialog.prototype.getSetupProcess = function (data) { Object.assign(this, data); this.$tbody.empty; this.$otherTbody.empty; this.refs.forEach(ref => {				ref.$row = $(' ').appendTo(this.$tbody);				ref.$otherRow = $(' ').appendTo(this.$otherTbody);				this[ref.isVe ? 'addCandidate' : 'removeCandidate'](ref);			}); this.resetSelectionButton.toggle(this.refs.some(ref => !ref.isVe)); this.setConfig(mw.storage.getObject('refrenamer')); this.applyConfig; this.$body.scrollTop(0); return RefRenamerDialog.super.prototype.getSetupProcess.call(this, data); };		RefRenamerDialog.prototype.getActionProcess = function (action) { return RefRenamerDialog.super.prototype.getActionProcess.call(this, action).next(function {				if (action !== 'continue') return;				let removed = [];				let modified = this.refs.filter(ref => { if (!ref.renamable) return; if (ref.keepCheck && !ref.keepCheck.isSelected) { removed.push(ref); return; }					ref.newName = ref.input.getValue.replace(/^[\s_]+|[\s_]+$/g, ''); ref.newNormalized = normalize(ref.newName); return ref.newNormalized; });				if (!modified.length && !removed.length) {					return new OO.ui.Error(getMsg('noChangesError'), { recoverable: false });				}				let duplicates = new Set( this.refs.map(ref => ( ref.renamable ? ref.newNormalized || ref.normalized : ref.normalized )).filter((name, i, arr) => arr.indexOf(name) !== i)				);				if (duplicates.size) {					return new OO.ui.Error($([						document.createTextNode(getMsg('duplicatesError')),						$('').append([...duplicates].map(n => $('').text(n)))[0]					]), { recoverable: false });				}				this.close;				let subs = {};				[...modified, ...removed].forEach(ref => { subs[ref.name] = ref.newName; });				let newText = replace(this.wikitext, subs);				let iw = mw.config.get('wgWikiID') === 'enwiki' ? '' : 'w:en:';				let summary = [...modified, ...removed].every(ref => ref.isVe) ? getMsg( 'summary', iw + 'Wikipedia:VisualEditor/Named references', iw + 'User:Maxim Masiutin/RefRenamer' ) : getMsg('genericSummary', iw + 'User:Maxim Masiutin/RefRenamer');				if (this.isEdit) {					$('#wpTextbox1').textSelection('setContents', newText);					if (document.documentElement.classList.contains('ve-active')) {						ve.init.target.once('showChanges', => { ve.init.target.saveDialog.reviewModeButtonSelect.selectItemByData('source'); ve.init.target.saveDialog.setEditSummary(summary); });						ve.init.target.showSaveDialog('review');					} else {						$('#wpSummary').textSelection('setContents', summary);						$('#wpDiff').trigger('click');					}				} else {					new mw.Api.get({ action: 'query', titles: mw.config.get('wgPageName'), prop: 'info', inprop: 'watched', curtimestamp: 1, formatversion: 2 }).always(response => { let formData = []; let timestamp = response && response.curtimestamp; if (timestamp) { let elapsed = performance.now - this.started; let time = new Date(new Date(timestamp).getTime - elapsed) .toISOString.slice(0, -5).replace(/\D/g, ''); formData.push(['wpStarttime', time]); }						formData.push(							['wpEdittime', this.editTime],							['editRevId', this.revId],							['wpTextbox1', newText],							['wpSummary', summary],							['wpMinoredit', '']						); let page = (((response || {}).query || {}).pages || [])[0] || {}; if (page.watched ||							Number(mw.user.options.get('watchdefault')) === 1						) { formData.push(['wpWatchthis', '']); if (page.watchlistexpiry) { formData.push(['wpWatchlistExpiry', page.watchlistexpiry]); }						}						formData.push(['wpDiff', ''], ['wpUltimateParam', 1]); $(' ').attr({							method: 'post',							action: mw.util.getUrl(null, { action: 'submit' }),							enctype: 'multipart/form-data'						}).append(							formData.map(([n, v]) => $(' ').attr({								name: n,								type: 'hidden'							}).val(v))						).appendTo(document.body).trigger('submit').remove; });					notify('opening');				}				mw.requestIdleCallback( => { let customized = Object.entries(this.getConfig) .filter(([k, v]) => String(v) !== String(this.defaults[k])); if (customized.length) { mw.storage.setObject('refrenamer', Object.fromEntries(customized), 7776000); } else { mw.storage.remove('refrenamer'); }				});			}, this); };		RefRenamerDialog.prototype.hideErrors = function { RefRenamerDialog.super.prototype.hideErrors.call(this); this.actions.setAbilities({ continue: true }); };		dialog = new RefRenamerDialog; let winMan = new OO.ui.WindowManager; winMan.addWindows([dialog]); winMan.$element.appendTo(OO.ui.getTeleportTarget); };	let replace = (text, subs) => text.replace(		/<(ref)\s+(name)\s*=\s*(?:"\s*([^\n"]+?)\s*"|'\s*([^\n']+?)\s*'|([^\s>]+?))(\s*\/?)>/gi,		(s, ref, attr, name1, name2, name3, slash) => {			let name = name1 || name2 || name3;			return subs.hasOwnProperty(name)				? subs[name]					? `<${ref} ${attr}="${subs[name]}"${slash}>`					: `<${ref}>`				: s;		}	);	let normalize = s => s.replace(/[\s_]+/g, '_').replace(/^_+|_+$/g, );	let toAscii = s => s.replace(/\D/g, c => {		let cp = c.codePointAt(0);		let zero = cp;		while (/\p{Nd}/u.test(String.fromCodePoint(zero - 1))) {			zero--;		}		return (cp - zero) % 10;	});	let toLatin = n => {		let s = ;		do {			s = String.fromCharCode(97 + (n % 26)) + s;			n = Math.floor(n / 26) - 1;		} while (n >= 0);		return s;	};	let onFocus = => {		dialog.refs.forEach(ref => {			if (ref.renamable) {				ref.input.setTabIndex(1);				if (ref.keepCheck) ref.keepCheck.setTabIndex(1); }		});	};	let onBlur = => {		dialog.refs.forEach(ref => { if (ref.renamable) { ref.input.setTabIndex(0); if (ref.keepCheck) ref.keepCheck.setTabIndex(0); }		});	};	window.refRenamer; });