Jump to content

MediaWiki:Gadget-GoodAndFeaturedClosure-main.vue

From Wikipedia

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
<template>
	<cdx-dialog 
	v-model:open="showDialog"
	title="Підбиття підсумку"
	close-button-label="Закрити"
	:primary-action="notRun ? primaryAction : null"
	:default-action="notRun ? defaultAction : null"
	style="min-width:700px"
	@primary="onPrimaryAction"
	@default="onDefaultAction"
	>
		<template v-if="notRun">		
			<cdx-radio			
			v-for="radio in radios"		
			:key="'radio-' + radio.value"		
			v-model="radioValue"		
			name="radio-group-descriptions"		
			:input-value="radio.value"		
			>			
			{{ radio.label }}
			</cdx-radio>
			<label for="gfc-reason">
				Причина (вікірозміткою, підпис згенерується автоматично):
			</label>
			<cdx-text-area
				autosize
				id="gfc-reason"
				v-model="reasonText"
			></cdx-text-area>
			<div v-if="prev"
			  class="gfc-preview"
			  v-html="previewHtml">
			</div>
		</template>
		<template v-else>
			<p style="font-weight:600">
				Будь ласка, зачекайте...
			</p>
			<p style="font-size: 120%; font-weight: bold;">{{ message }}</p>
			<cdx-progress-bar aria-label="Запуск скрипта"></cdx-progress-bar>
		</template>
	</cdx-dialog>
</template>

<script>
	const { CdxButton, CdxDialog, CdxTextArea, CdxRadio, CdxProgressBar } = require( '@wikimedia/codex' );
	const currentPage = mw.config.get("wgPageName").replace(/_/g," ");
	const date = new Date();
	var month = date.getMonth() + 1;
	if (month.toString().length == 1)
		month = '0' + month;
	const year = date.getFullYear();
	var day = date.getDate();
	if (day.toString().length == 1)
		day = '0' + day;
	module.exports = {
		data: function() {
			return {
				showDialog: false,
				notRun: true,
				prev: false,

				reasonText: "",
				previewHtml: "",
				message: null,
				radios: [
				{
					label: 'Статус надано',
					value: 'granted'
				},
				{
					label: 'Статус не надано',
					value: 'denied'
				}],
				radioValue: null,

				primaryAction: { label: 'Зберегти' },
	            defaultAction: { label: 'Попередній перегляд' },

				nominator: ""
			};
		},
		components: {
			CdxButton,
			CdxDialog,
			CdxTextArea,
			CdxRadio,
			CdxProgressBar
		},
		methods: {
			openDialog (title, section) {
				this.showDialog = true;
				this.pageName = title;
				this.sectionId =section;
			},
			closeDialog () {
				this.showDialog = false;
			},
			onPrimaryAction () {
				this.notRun = false;
				this.archiveSubpage()
			},
			onDefaultAction () {
				this.preview(this.reasonText)
			},
			preview (reason) {
				var param = {
					action: 'parse',
					format: 'json',
					prop: 'text',
					text: reason
				};
				this.prev = true;
				new mw.Api().get(param).done(function(data) {
					$('.gfc-preview').html(data.parse.text['*']);
				});
			},
			ukMonth () {
				var month_name = "";
				switch (month) {
					case "01":
						month_name = "січня";
						break;
					case "02":
						month_name = "лютого";
						break;
					case "03":
						month_name = "березня";
						break;
					case "04":
						month_name = "квітня";
						break;
					case "05":
						month_name = "травня";
						break;
					case "06":
						month_name = "червня";
						break;
					case "07":
						month_name = "липня";
						break;
					case "08":
						month_name = "серпня";
						break;
					case "09":
						month_name = "вересня";
						break;
					case 10:
						month_name = "жовтня";
						break;
					case 11:
						month_name = "листопада";
						break;
					case 12:
						month_name = "грудня";
						break;
				}
				return month_name
			},
			variable_names () {
				var gfc = this;
				switch (currentPage) {
					case 'Вікіпедія:Кандидати в добрі статті':
						return {
							stat_template: 'Шаблон:Статистика добрих статей',
							status_template: 'Добра стаття',
							nomination_template: 'Кандидат у добрі статті',
							talk_template: gfc.radioValue == 'granted' ? {
									type: "добра",
									status: "статус доброї надано"
								} : {
									type: "кандидат у добрі",
									status: "статус доброї не надано"
								},
							genitive: 'доброї',
							level: 'ДС',
							badge: 'Q17437798',
							authors_page: 'Вікіпедія:Добрі статті/Автори добрих статей'
						};
						break;
					case 'Вікіпедія:Кандидати у вибрані статті':
						return {
							stat_template: 'Шаблон:Статистика вибраних статей',
							status_template: 'Вибрана стаття',
							nomination_template: 'Кандидат у вибрані статті',
							talk_template: gfc.radioValue == 'granted' ? {
									type: "вибрана",
									status: "статус вибраної надано"
								} : {
									type: "кандидат у вибрані",
									status: "статус вибраної не надано"
								},
							genitive: 'вибраної',
							level: 'ВС',
							badge: 'Q17437796',
							authors_page: 'Вікіпедія:Добрі статті/Автори вибраних статей'
						};
					case 'Вікіпедія:Кандидати у вибрані списки':
						return {
							stat_template: 'Шаблон:Статистика вибраних статей',
							status_template: 'Вибрана стаття',
							nomination_template: 'Кандидат у вибрані статті',
							talk_template: gfc.radioValue == 'granted' ? {
									type: "вибрана",
									status: "статус вибраної надано"
								} : {
									type: "кандидат у вибрані",
									status: "статус вибраної не надано"
								},
							genitive: 'вибраного списку',
							level: 'ВСП',
							badge: 'Q17506997',
							authors_page: 'Вікіпедія:Добрі статті/Автори вибраних списків'
						};
						break;
					case 'Вікіпедія:Кандидати у вибрані портали':
						return {
							stat_template: 'Шаблон:Статистика вибраних статей',
							status_template: 'Вибрана стаття',
							nomination_template: 'Кандидат у вибрані статті',
							talk_template: gfc.radioValue == 'granted' ? {
									type: "вибрана",
									status: "статус вибраної надано"
								} : {
									type: "кандидат у вибрані",
									status: "статус вибраної не надано"
								},
							level: 'ВСП',
							badge: 'Q17580674'
						};
						break;
				}
			},
			sortEntries (arr) {
				return arr.sort((a, b) => {
					if (b.number !== a.number) {
					  return b.number - a.number;
					}
					return a.author.localeCompare(b.author, 'und', {
					  sensitivity: 'base'
					});
				});
			},
			incrementAuthor (arr, targetAuthor) {
				return this.sortEntries(
				    arr.map(e =>
				      e.author === targetAuthor
				        ? { ...e, number: e.number + 1 }
				        : e
				    )
				);
			},
			archiveSubpage () {
				var gfc = this;
				this.wait("Переноситься тема до підсторінки архіву")
				var params = {
					action: 'query',
					prop: 'revisions',
					titles: currentPage,
					rvprop: 'content',
					rvslots: 'main',
					rvsection: this.sectionId,
					formatversion: '2',
					format: 'json'
				}
				new mw.Api().get( params ).done( ( data ) => {
					var topic = data.query.pages[0].revisions[0].slots.main["content"];
					gfc.nominator = topic.match(/Взірцеві статті:Номінація.*?\[\[Користувач:(.*?)\|/s)[1]
					var params2 = {
						action: 'edit',
						title: currentPage + '/Архів/' + year + '-' + month + '-' + day,
						appendtext: "\n" + topic + "\n=== Підсумок ===\n" + gfc.reasonText + "--~~~~",
						format: 'json'
					}
					new mw.Api().postWithEditToken(params2).done(() => {
						new mw.Api().edit(currentPage, (revision) => {
							var content = revision.content;
							content = content.replace(RegExp("(Останній архів: \\[\\[" + mw.util.escapeRegExp(currentPage) + "/Архів/).*?\\]\\]"),"$1" + year + "-" + month + "-" + day + "|" + day + " " + gfc.ukMonth() +" року]]");
							return {
								text: content.replace("\n" + topic, ""),
								summary: "Архівування теми, оновлення посилання на останній архів",
								assert: "user"
							}
						}).then(() => {
							gfc.archive()
						}).fail((error) => {
							gfc.apiError(error)
						});
					});
				});
			},
			archive() {
				var gfc = this;
				this.wait("Редагується сторінка архіву")
				new mw.Api().edit(currentPage + '/Архів', (revision) => {
					var content = revision.content;
					if (content.match(RegExp('==\\s*' + year + ' рік\\s*=='))) {
						if (content.includes('/Архів/' + year + '-' + month + '-' + day))
							content = content.replace(RegExp("(\\|\\[\\["+ mw.util.escapeRegExp(currentPage) +"/Архів/"+ year +"-"+ month +"-"+ day + ".*?\\]\\])(\n\\|-)","s"), "$1, [["+ gfc.pageName +"]]$2");
						else
							content = content.replace(RegExp("(===\\s*" + year + " рік\\s*===\\n\\|-)"),"$1\n|[["+ currentPage +"/Архів/" + year + "-" + month + "-" + day + "|"+ day + " " + gfc.ukMonth() +"]]\n|[["+ gfc.pageName +"]]\n|-");
					}
					else {
						const previous_year = year - 1;
						content = content.replace(RegExp("(===\\s*" + previous_year + " рік\\s*===\\n\\|-)"),"=== " + year + " ===\n|[["+ currentPage +"/Архів/" + year + "-" + month + "-" + day + "|"+ day + " " + gfc.ukMonth() +"]]\n|[["+ gfc.pageName +"]]\n|-\n| colspan=2 |\n$1")
					}
					return {
						text: content,
						summary: "Оновлення архіву",
						assert: "user"
					}
				}).then(() => {
					gfc.update_statistics()
				}).fail((error) => {
					gfc.apiError(error)
				})
			},
			update_statistics () {
				var gfc = this;
				this.wait("Оновлюється статистика");
				new mw.Api().edit(gfc.variable_names().stat_template, (revision) => {
					var content = revision.content;
					switch (currentPage) {
						case 'Вікіпедія:Кандидати в добрі статті':
							if (content.match(RegExp("\\|Рік\\d+ = " + year))) {
								if(gfc.radioValue == 'granted')
									content = content.replace(RegExp("(\\|Рік\\d+ = " + year + "\\s+\\|Значення\\d+\\s+=\\s+)(\\d+)(\\s+\\|Мітка\\d+ = )\\d+", "g"), (match, g1, g2, g3) => g1 + (Number(g2)+1) + g3 + (Number(g2)+1));
								else
									content = content.replace(RegExp("(загальної кількості.*?\\|Рік\\d+ = " + year + "\\s+\\|Значення\\d+\\s+=\\s+)(\\d+)(\\s+\\|Мітка\\d+ = )\\d+", "s"), (match, g1, g2, g3) => g1 + (Number(g2)+1) + g3 + (Number(g2)+1));
							}
							else {
								if (gfc.radioValue == 'granted')
									content = content.replace(RegExp("(\\|Мітка)(\\d+)(\\s=\\s+\\d+)\\*","g"), (match, g1, g2, g3) => g1 + g2 + g3 + "\n|Рік" + (Number(g2)+1) + " = " + year + " |Значення" + (Number(g2)+1) + " = 1   |Мітка" + (Number(g2)+1) + " = 1*");
								else
									content = content.replace(RegExp("(загальної кількості.*?\\|Мітка)(\\d+)(\\s=\\s+\\d+)\\*(.*?)\\*","s"), (match, g1, g2, g3, g4) => g1 + g2 + g3 + "\n|Рік" + (Number(g2)+1) + " = " + year + " |Значення" + (Number(g2)+1) + " = 0   |Мітка" + (Number(g2)+1) + " = 0*" + g4 + "\n|Рік" + (Number(g2)+1) + " = " + year + " |Значення" + (Number(g2)+1) + " = 1   |Мітка" + (Number(g2)+1) + " = 1*");
							}
							break;
						case 'Вікіпедія:Кандидати у вибрані статті':
							return 'Статистика вибраних статей';
							break;
						case 'Вікіпедія:Кандидати у вибрані списки':
							return 'Статистика вибраних списків';
							break;
						case 'Вікіпедія:Кандидати у вибрані списки':
							return 'Статистика вибраних списків';
							break;
					}
					return {
						text: content,
						summary: "Оновлення статистики",
						assert: "user"
					}
				}).then(() => {
					gfc.change_status()
				}).fail((error) => {
					gfc.apiError(error)
				})
			},
			change_status () {
				var gfc = this;
				this.wait("Редагується номінована сторінка");
				new mw.Api().edit(gfc.pageName, (revision) => {
					var content = revision.content;
					content = content.replace(RegExp("{{" + gfc.variable_names().nomination_template + "}}\\s*"),"")
					if (content.includes("[[Категорія:"))
						content = content.replace(/\s*(\[\[Категорія:)/,"\n{{"+ gfc.variable_names().status_template +"}}\n\n$1");
					else
						content = content + "\n{{" + gfc.variable_names().status_template + "}}";
					return {
						text: content,
						summary: "Оновлення статусу сторінки",
						assert: "user"
					}
				}).then(() => {
					gfc.add_talk_template()
				}).fail((error) => {
					gfc.apiError(error);
				});
			},
			add_talk_template () {
				var gfc = this;
				this.wait("Редагується сторінка обговорення статті");
				var content = '';
				var params = {
					action: 'query',
					titles: 'talk:' + this.pageName,
					prop: 'revisions',
					rvprop: 'content',
					rvslots: 'main',
					format: 'json'
				}
				new mw.Api().get(params).done((data) => {
					if (Object.keys(data.query.pages)[0] == -1) {
						content = "{{Повідомлення ВЗВ|" + gfc.variable_names().talk_template.type + "|\n {{Повідомлення ВЗВ/Подія|" + gfc.variable_names().talk_template.status + "|" + day + " " + gfc.ukMonth() + " " + year + " року|" + currentPage + '/Архів/' + year + '-' + month + '-' + day + "}}\n}}";
						new mw.Api().create("talk:" + this.pageName, {summary: "Створення сторінки обговорення" }, content).then(() => {
							gfc.update_level(content);
						}).fail((error) => {
							gfc.apiError(error)
						});
					}
					else {
						content = data.query.pages[Object.keys(data.query.pages)[0]].revisions[0].slots.main["*"];
						new mw.Api().edit("talk:" + this.pageName, (revision) => {
							if (content.match(/{{Повідомлення ВЗВ/i))
								content = content.replace(/({{Повідомлення ВЗВ\|)(.*?)(\|.*?)(\n}}\n)/s, '$1' + gfc.variable_names().talk_template.type + '$3{{Повідомлення ВЗВ/Подія|' + gfc.variable_names().talk_template.status + '|' + day + ' ' + gfc.ukMonth() + ' ' + year + ' року|' + currentPage + '/Архів/' + year + '-' + month + '-' + day + '}}$4')
							else
								content = '{{Повідомлення ВЗВ|' + gfc.variable_names().talk_template.type + '|\n {{Повідомлення ВЗВ/Подія|' + gfc.variable_names().talk_template.status + '|' + day + ' ' + gfc.ukMonth() + ' ' + year + ' року|' + currentPage + '/Архів/' + year + '-' + month + '-' + day + '}}\n}}\n' + content;
							return {
								text: content,
								summary: "Оновлюються шаблони на сторінці обговорення статті",
								assert: "user"
							}
						}).then(() => {
							gfc.update_level(content)
						}).fail((error) => {
							gfc.apiError(error);
						});
					}
				});
			},
			update_level (content) {
				var gfc = this;
				if (content.match(/{{(Стаття )?(Вікі)?(проєкт)у?/gi))
					new mw.Api().edit("talk:" + this.pageName, (revision) => {
						var wikitext = revision.content.replace(/({{(Стаття )?(Вікі)?(проєкт)у?.*?\|рівень=\s*)..I?/gi, "$1" + gfc.variable_names.level);
						return {
							text: wikitext,
							summary: "",
							assert: 'user'
						}
					}).then(() => {
						//gfc.update_wikidata()
						gfc.stabilize()
					})
				else
					//gfc.update_wikidata()
					gfc.stabilize()
			},
			update_wikidata () {
				var gfc = this;
				new mw.ForeignApi('https://www.wikidata.org/w/api.php').postWithToken('csrf', {
					action: 'wbsetsitelink',
					site: mw.config.get("wgWikiID"),
					linksite: mw.config.get("wgWikiID"),
					title: gfc.pageName,
					badges: gfc.variable_names().badge,
					summary: 'assign badge via API',
					assert: 'user',
					format: 'json'
				}).then(() => {
					gfc.stabilize()
				}).fail((error) => {
					if (error == 'no-such-entity-link')
						console.log('skip');
				});
			},
			stabilize () {
				var gfc = this;
				if (mw.config.get("wgUserGroups").includes("sysop")) {
					this.wait("Стабілізовується сторінка");
					new mw.Api().postWithEditToken({
						action: 'stabilize',
						title: gfc.pageName,
						reason: 'Стабілізація доброї статті',
						default: 'stable'
					}).then(() => {
						gfc.update_author()
					}).fail((error) => {
						gfc.apiError(error)
					});
				}
				else {
					this.wait("Подається запит на стабілізацію сторінки");
					new mw.Api().edit('Вікіпедія:Захист сторінок', (revision) => {
						return {
							text: revision.content.replace("↓↓↓-->", "↓↓↓-->\n== Стабілізація статті " + gfc.pageName + " ==\nПрошу стабілізувати статтю [[" + gfc.pageName + "]] через отримання статусу " + gfc.variable_names().genitive + ".--~~~~"),
							summary: "",
							assert: "user"
						}
					}).then(() => {
						gfc.update_author()
					}).fail((error) => {
						gfc.apiError(error)
					});
				}
			},
			update_author () {
				var gfc = this;
				gfc.wait("Оновлюється статистика авторів добрих статей")
				new mw.Api().edit(gfc.variable_names().authors_page, (revision) => {
					var content = revision.content;
					var authors_arr, sorted_arr = [];
					if (content.includes(gfc.nominator)) {
						authors_arr = [...content.matchAll(/\[\[Користувач:(.*?)\|.*? \|\|\s*(\d+)/g)].map(m => ({
							author: m[1],
							number: Number(m[2])
						}));
						var prev_author_index = authors_arr.findIndex(e => e.author === gfc.nominator);
						sorted_arr = gfc.incrementAuthor(authors_arr, gfc.nominator);
						var author_index = sorted_arr.findIndex(e => e.author === gfc.nominator);
						content = content.replace(RegExp("(" + mw.util.escapeRegExp(gfc.nominator) + ".*?\\|\\|)\\s*(\\d+)(.*?)(\\n\\|[-}])", "s"), (match, g1, g2, g3, g4) => g1 + " " + (Number(g2)+1) + g3 + ", [[" + gfc.pageName + "]]" + g4);
						if (author_index != prev_author_index) {
							var prev_entity = author_index == 0 ? sorted_arr[author_index] : sorted_arr[author_index-1]
							var author_entity = sorted_arr[author_index]
							var after_entity = author_index == sorted_arr.length -1  ? sorted_arr[author_index] : sorted_arr[author_index+1];
							author_raw = content.match(RegExp("(\\|\\s*\\[\\[Користувач:" + mw.util.escapeRegExp(gfc.nominator) + "\n\\|.*?\n)(\\|)", "s"))[1];
							if ((author_entity.number < 5 && prev_entity.number >= 5) || (author_entity.number < 10 && prev_entity.number >= 10) || (author_entity.number < 20 && prev_entity.number >= 20) || (sorted_arr[0].author == gfc.nominator)) {
								content = content.replace(author_raw + "|-\n", "");
								content = content.replace(RegExp("(\\|\\s*\\[\\[Користувач:" + mw.util.escapeRegExp(after_entity.author) + ")"), author_raw + "$1");
							}
							else if ((after_entity.number < 5 && author_entity.number >= 5) || (after_entity.number < 10 && author_entity.number >= 10) || (after_entity.number < 20 && author_entity.number >= 20)) {
								content = content.replace(author_raw + "|-\n", "");
								content = content.replace(RegExp("(\\|\\s*\\[\\[Користувач:" + mw.util.escapeRegExp(prev_entity.author) + ".*?)(\\|})", "s"), "$1" + author_raw + "$2");
							}
							else {
								content = content.replace("|-\n" + author_raw, "");
								content = content.replace(RegExp("(\\|\\s*\\[\\[Користувач:" + mw.util.escapeRegExp(prev_entity.author), "s"),  author_raw + "|-\n$1");
							}
						}
					}
					else {
						authors_arr = [...content.matchAll(/\|\s*\[\[Користувач:(.*?)\|\D+?\n/g)].map(m => ({
							author: m[1],
							number: 1
						}));
						authors_arr.push({
							author: gfc.nominator,
							number: 0
						});
						sorted_arr = gfc.incrementAuthor(authors_arr, gfc.nominator)
						var author_index = sorted_arr.findIndex(e => e.author === gfc.nominator)
						if (author_index == 0)
							content = content.replace(RegExp("! Автор\\n! Стаття\\n\\|-"), "$&\n| [[Користувач:" + gfc.nominator + "|" + gfc.nominator + "]]\n| [[" + gfc.pageName + "]]\n");
						else {
							content = content.replace(RegExp("(\\| \\[\\[Користувач:" + mw.util.escapeRegExp(sorted_arr[author_index-1].author) + ".*?)(\\|-)", "s"), "$1|-\n| [[Користувач:" + gfc.nominator + "|" + gfc.nominator + "]]\n| [[" + gfc.pageName + "]]\n$2");
						}
					}
					return {
						text: content,
						summary: "Оновлення статистики авторів",
						assert: "user"
					}
				}).then(() => {
					gfc.success()
				}).fail((error) => {
					gfc.apiError(error);
				})
			},
			success() {
				this.wait('Перезавантаження сторінки');
				setTimeout(() => {
					this.closeDialog ();
					location.reload()
				}, 1000);
			},
			wait(message) {
				this.message = message;
			},
			apiError (code) {
				console.log(code);
			}
		},
		mounted() {
			$('.mw-heading2').each((index, element) => {
				if (index+1 < $('.mw-heading2').length-1) {
					const $heading = $( element );
					const title = $( element ).find( 'h2 a' ).attr( 'title' );
					const span = document.createElement( 'span' );
					const link = document.createElement( 'a' );
					span.className = 'mw-editsection mw-editsection-summary';
					link.href = '#';
					link.innerHTML = '[<span>Підбити підсумок</span>]';
					link.addEventListener( 'click', ( e ) => {
						e.preventDefault();
						this.openDialog( title, index+1 );
					} );
					$heading.find( '.mw-editsection' ).after(span);
					$heading.find( '.mw-editsection-summary' ).append(link)
				}
			});
		},
		unmounted() {
			//this.dialogTrigger.removeEventListener( this.openDialog );
		}
	};
</script>

<style>
.cdx-dialog__header__title {
	text-align: center;
}
</style>