Butun axtardiqlarinizi tapmaq ucun buraya: DAXIL OLUN
  Mp4 Mp3 Axtar Yukle
  Video Axtar Yukle
  Shekil Axtar Yukle
  Informasiya Melumat Axtar
  Hazir Inshalar Toplusu
  AZERI CHAT + Tanishliq
  1-11 Sinif Derslikler Yukle
  Saglamliq Tibbi Melumat
  Whatsapp Plus Yukle(Yeni)

  • Ana səhifə
  • Təsadüfi
  • Yaxınlıqdakılar
  • Daxil ol
  • Nizamlamalar
İndi ianə et Əgər Vikipediya sizin üçün faydalıdırsa, bu gün ianə edin.

MediaViki:Gadget-toolbox-tag.js

  • İnterfeys
  • Müzakirə
  • Mənbəyə bax

Qeyd: Dəyişiklikləri yayımladıqdan sonra etdiyiniz dəyişikliklərin görünməsi üçün brauzerinizin keşinin təmizlənməsi lazım ola bilər.

  • Firefox / Safari: Reload düyməsinə basılı tutarkən Shift düyməsinə basın, və ya Ctrl+F5 və ya Ctrl+R (Mac üçün ⌘-R )
  • Google Chrome: Ctrl-Shift-R (Mac üçün ⌘-Shift-R)
  • Edge: Ctrl düyməsini basılı tutarkən Refresh düyməsinə basın, və ya sadəcə Ctrl+F5.
/* <nowiki> */

mw.loader.using(['mediawiki.api', 'mediawiki.util', '@wikimedia/codex'], require => {
	const { createMwApp } = require('vue');
	const { CdxDialog, CdxCheckbox, CdxField, CdxSearchInput, CdxTabs, CdxTab } = require('@wikimedia/codex');
	const api = new mw.Api();
	const ns = mw.config.get('wgNamespaceNumber');
	const pageTitle = mw.config.get('wgPageName').replaceAll('_', ' ');
	if (![0, 4].includes(ns)) return;

	const tagList = {
		'Formatlaşdırma və vikiləşdirmə': {
			'Ümumi': [ 
				{ tag: 'Vikiləşdirmək', description: "bu məqaləni vikiləşdirmək lazımdır" },
				{ tag: 'Qaralama', description: 'məqalə qaralama halındadır' },
				{ tag: 'Təkmilləşdirmə', description: 'məqalə Vikipediya meyarlarına uyğunlaşdırılmalıdır' },
				{ tag: 'Daxili keçid azlığı', description: 'məqalədə daxili keçidlərin artırılmasına ehtiyac var', alias: 'Underlinked' },
				{ tag: 'Stil kitabçasına uyğun olmayan', description: 'məqalə stil kitabçasına uyğun deyil' },
				{ tag: 'Yarımçıq', description: 'məqalə yarımçıqdır və genişləndirilməlidir' },
				{ tag: 'Preambulasız', description: 'məqalənin giriş hissəsi yoxdur' },
				{ tag: 'Qısa preambula', description: 'məqalənin giriş hissəsi çox qısadır' },
				{ tag: 'Uzun preambula', description: 'məqalənin giriş hissəsi çox uzundur' }
			],
			'Texniki': [ 
				{ tag: 'İş gedir', description: 'məqalədə iş davam etməkdədir' },
				{ tag: 'Silinməyə namizəd', description: 'səhifə silinməyə namizəddir' }
			]
		},
		'Ümumi məzmun': {
			'Əhəmiyyət və ensiklopediklik': [
				{ tag: 'Əhəmiyyət', description: 'məqalənin ensiklopedik tələblərə cavab vermədiyinə dair şübhələr var' }
			],
			'Yazı üslubu': [
				{ tag: 'Reklam', description: 'bu məqalə reklam xarakteri daşıyır.' },
				{ tag: 'Üslub', description: 'bu məqalənin üslubu və ya stili Vikipediyada istifadə olunan ensiklopedik tərzdə olmaya bilər.' }
			],
			'Məlumat və detallar': [
				{ tag: 'Mütəxəssis', description: 'məqalənin təkmilləşdirilməsi üçün mütəxəssislərə ehtiyac var' },
				{ tag: 'Qloballaşdır', description: 'məqalədəki nümunələr və perspektivlər mövzuya dünya miqyasında baxışı əks etdirmir'},
			],
			'Aktuallıq': [
				{ tag: 'Aktual', description: 'məqalədə davam edən aktual hadisələrlə bağlı məlumat var' },
				{ tag: 'Yeniləmə', description: 'məqalədəki məlumatlar köhnədir' },
				{ tag: 'Güncəl əlaqəli', description: 'məzmun başqa məqalədəki hadisələr ilə əlaqəli olduğu üçün tez-tez dəyişə bilər' },
				{ tag: 'Yaxınlarda ölən', description: 'məqalə son vaxtlarda vəfat etmiş insan haqqındadır' },
				{ tag: 'Davam edən döyüş', description: 'hadisələr davam etdiyi üçün məqalə tez-tez dəyişikliyə məruz qala bilər' },
				{ tag: 'Gözlənilən oyun', description: 'məqalə istehsal prosesində olan və buraxılması gözlənilən video oyun haqqındadır' },
			],
			'Neytrallıq, qərəzlilik və faktiki dəqiqlik': [
				{ tag: 'Tərəfli', description: 'məqalənin neytrallığı şübhə doğurur' },
				{ tag: 'Faktları yoxla', description: 'məqalədə verilən faktların dəqiqliyini yoxlamaq lazımdır' },
				{ tag: 'Maraq toqquşması', description: 'məqalənin əsas müəllifinin mövzu ilə sıx əlaqəsi var' },
			],
			'Mənbələr və istinadlar': [
				{ tag: 'Mənbə azlığı', description: 'məlumatların yoxlanıla bilməsi üçün əlavə mənbələrə ehtiyac var' },
				{ tag: 'Mənbəsiz', description: 'məqalədəki heç bir məlumatın mənbəsi göstərilməyib' },
				{ tag: 'İlkin mənbələr', description: 'yalnız ilkin və ya onunla əlaqəli mənbələrdən istifadə olunur)' },
				{ tag: 'İstinadsız', description: 'mənbələr göstərilsə də, mətndaxili istinadlar yoxdur' },
				{ tag: 'Tək mənbə', description: 'məqalə böyük ölçüdə və ya tamamilə tək mənbəyə əsaslanır' },
				{ tag: 'Orijinal tədqiqat', description: 'məqalədə orijinal tədqiqata yer verilib' },
				{ tag: 'Müəllif mənbələri', description: 'məqalənin müəllifi tərəfindən yayımlanan mənbələrdən istifadə edilib' },
			],
			'Layihələrə köçürmələr': [
				{ tag: 'Vikimənbəyə köçür', description: 'məqaləni Vikimənbəyə köçürmək lazımdır)' },
				{ tag: 'Vikisitata köçür', description: 'məqaləni Vikisitata köçürmək lazımdır' },
				{ tag: 'Vikikitaba köçür', description: 'məqaləni Vikikitaba köçürmək lazımdır' },
				{ tag: 'Vikilüğətə köçür', description: 'məqaləni Vikilüğətə köçürmək lazımdır' },
			]
		},
		'Spesifik məzmun problemləri': {
			'Dil': [
				{ tag: 'Azərbaycanca deyil', description: 'məqalə Azərbaycan dilində yazılmayıb və tərcüməyə ehtiyac var' },
				{ tag: 'Yanlış transliterasiyalar', description: 'Azərbaycan dilinə yanlış şəkildə transliterasiya edilmiş xüsusi adlar var' },
				{ tag: 'Yanlış adlandırma', description: 'Azərbaycan dilində düzgün verilməmiş məqalə adı' }
			],
			'Kateqoriyalar': [
				{ tag: 'Kateqoriyasız', description: 'səhifəyə hansısa kateqoriya əlavə edilməyib' },
				{ tag: 'Kateqoriya əlavə et', description: 'əlavə və ya daha spesifik kateqoriyalara ehtiyac var' },
				{ tag: 'Kateqoriya çıxar', description: 'səhifə həm əsas, həm də alt kateqoriyalara əlavə edilib' }
			],
			'Keçidlər': [
				{ tag: 'Tənha', description: 'hansısa məqalədən bu məqaləyə verilmiş keçid yoxdur', 	alias: ['Orphan', 'Tənha məqalə', 'Tənha səhifə'] }
			],
			'İstinad formaları': [
				{ tag: 'İstinad stili', description: 'istinadlar müvafiq istinad şablonları ilə göstərilməlidir' },
			],
		}
	};

	const portletLink = mw.util.addPortletLink(
		'p-ap',
		'javascript:void(0);',
		'Bildiriş',
		't-ap-tag',
		'Bildiriş şablonu əlavə və ya çıxar'
	);

	const app = createMwApp({
	data: () => ({
		tagList,
		monthNames: [
			'yanvar', 'fevral', 'mart', 'aprel', 'may', 'iyun',
			'iyul', 'avqust', 'sentyabr', 'oktyabr', 'noyabr', 'dekabr'
		],
		dialogShown: false,
		selectedTags: [],
		existingTags: [],
		searchQuery: '',
		status: 'form',
		progressText: '',
		summary: 'Səhifəyə bildiriş şablonu əlavə olunur',
		tabsData: [
			{ name: 'add', label: 'Şablon əlavə et' },
			{ name: 'remove', label: 'Şablon çıxar' }
		]
	}),
	computed: {
		filteredTagList() {
			if (!this.searchQuery.trim()) return this.tagList;
	
			const query = this.searchQuery.toLowerCase();
			const result = {};
	
			for (const [categoryName, groups] of Object.entries(this.tagList)) {
				const filteredGroups = {};
				for (const [groupName, tags] of Object.entries(groups)) {
				const matchedTags = tags.filter(tag =>
					!this.existingTags.includes(tag.tag) && (
						tag.tag.toLowerCase().includes(query) ||
						tag.description.toLowerCase().includes(query)
					)
				);
					if (matchedTags.length > 0) {
						filteredGroups[groupName] = matchedTags;
					}
				}
				if (Object.keys(filteredGroups).length > 0) {
					result[categoryName] = filteredGroups;
				}
			}
			return result;
		},
		existingTagList() {
			const query = this.searchQuery.toLowerCase();
			const existing = this.existingTags.map(tag => {
				const tagObj = Object.values(this.tagList)
					.flatMap(group => Object.values(group).flat())
					.find(t => t.tag === tag);
				return tagObj && (
					!query || tagObj.tag.toLowerCase().includes(query) || tagObj.description.toLowerCase().includes(query)
				) ? tagObj : null;
			}).filter(Boolean);
			return existing;
		},
		selectedMode() {
			const selected = this.selectedTags;
			const allExisting = selected.length > 0 && selected.every(tag => this.existingTags.includes(tag));
			const allNew = selected.length > 0 && selected.every(tag => !this.existingTags.includes(tag));
			if (allExisting) return 'remove';
			if (allNew) return 'add';
			if (selected.length > 0) return 'update';
			return 'none';
		},
		highlightedText() {
			const query = this.searchQuery.toLowerCase();
			if (!query) return t => t;
			return text =>
				text.replace(
					new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi'),
					'<span style="text-decoration: underline;">$1</span>'
				)
		}
	},
	methods: {
		async toggleDialog() {
			this.dialogShown = !this.dialogShown;
			if (this.dialogShown) {
				await this.fetchExistingTags();
			} else {
				this.status = 'form';
				this.selectedTags = [];
				this.searchQuery = '';
			}
		},
		async fetchExistingTags() {
			const response = await api.get({
				action: 'query',
				prop: 'revisions',
				titles: pageTitle,
				rvprop: 'content',
				format: 'json',
				formatversion: 2
			});
		
			const content =
				response.query &&
				response.query.pages &&
				response.query.pages[0] &&
				response.query.pages[0].revisions &&
				response.query.pages[0].revisions[0] &&
				response.query.pages[0].revisions[0].content || '';
		
			const allTags = Object.values(this.tagList)
				.flatMap(groups => Object.values(groups).flat());
			
			const tagTitles = allTags.flatMap(tag => {
				const aliases = Array.isArray(tag.alias) ? tag.alias : tag.alias ? [tag.alias] : [];
				return [tag.tag, ...aliases].map(name => `Şablon:${name}`);
			});
		
			const redirectsRes = await api.get({
				action: 'query',
				titles: tagTitles.join('|'),
				redirects: 1,
				format: 'json'
			});
		
			const redirectMap = {};
			if (redirectsRes.query && redirectsRes.query.redirects) {
				for (const redir of redirectsRes.query.redirects) {
					const from = redir.from.replace(/^Şablon:/, '').trim();
					const to = redir.to.replace(/^Şablon:/, '').trim();
					redirectMap[from] = to;
				}
			}
		
			const tagNameMap = {};
			this.aliasMap = {};
			
			for (const t of allTags) {
				const aliases = Array.isArray(t.alias) ? t.alias : t.alias ? [t.alias] : [];
				tagNameMap[t.tag] = t.tag;
				this.aliasMap[t.tag] = [t.tag, ...aliases];
			
				for (const alias of aliases) {
					tagNameMap[alias] = t.tag;
				}
			}
		
			const detectionTags = Object.keys(tagNameMap);
		
			this.existingTags = detectionTags
				.filter(name => new RegExp(`{{\\s*${name}(\\s*\\||\\s*}})`, 'i').test(content))
				.map(name => tagNameMap[name]);
		
			this.selectedTags = [];
			this.searchQuery = this.searchQuery;
		},
		
		addProgressLog(tag, action) {
			this.progressText = `"${tag} şablonu" ${action}…`;
		},
		
		async onSubmit() {
		this.status = 'sending';
		if (this.selectedMode === 'update') {
			this.progressText = 'Şablonlar yenilənir…';
		
			const response = await api.get({
				action: 'query',
				prop: 'revisions',
				titles: pageTitle,
				rvprop: 'content',
				format: 'json',
				formatversion: 2
			});
		
			let content = (
				response.query &&
				response.query.pages &&
				response.query.pages[0] &&
				response.query.pages[0].revisions &&
				response.query.pages[0].revisions[0] &&
				response.query.pages[0].revisions[0].content
			) || '';
		
			const now = new Date();
			const monthYear = `${this.monthNames[now.getMonth()]} ${now.getFullYear()}`;
		
			for (const tag of this.selectedTags.filter(t => this.existingTags.includes(t))) {
				this.addProgressLog(tag, 'çıxarılır');
				await new Promise(r => setTimeout(r, 250));
			
				const aliases = (this.aliasMap && this.aliasMap[tag]) ? this.aliasMap[tag] : [tag];
				for (const alias of aliases) {
					const regex = new RegExp(`\\s*{{\\s*${alias}(\\|[^}]*)?}}\\s*\\n?`, 'gi');
					content = content.replace(regex, '');
				}
			}
			
			const addedTags = this.selectedTags.filter(t => !this.existingTags.includes(t));
			
			for (const tag of addedTags) {
				this.addProgressLog(tag, 'əlavə edilir');
				await new Promise(r => setTimeout(r, 250));
			}

			const prependText = addedTags.map(t => `{{${t}|tarix=${monthYear}}}`).join('\n');
			if (prependText) content = prependText + '\n' + content;
		
			const removedTags = this.selectedTags.filter(t => this.existingTags.includes(t));
			
			const linkify = tag => `{{[[Şablon:${tag}|${tag}]]}}`;
			const removedLinked = removedTags.map(linkify);
			const addedLinked = addedTags.map(linkify);
			
			const joinTags = arr => {
				if (arr.length === 1) return arr[0];
				if (arr.length === 2) return `${arr[0]} və ${arr[1]}`;
				return arr.slice(0, -1).join(', ') + ' və ' + arr.slice(-1);
			};
			
			let summaryParts = [];
			if (removedLinked.length) summaryParts.push(`${joinTags(removedLinked)} çıxarıldı`);
			if (addedLinked.length) summaryParts.push(`${joinTags(addedLinked)} əlavə edildi`);
			const summaryText = summaryParts.join(', ') + '.';
			
			await api.postWithEditToken({
				action: 'edit',
				title: pageTitle,
				text: content,
				summary: summaryText,
				format: 'json'
			});
		
			this.status = 'done';
			setTimeout(() => location.reload(), 2000);
			return;
		}
		if (this.selectedMode === 'remove') {
			this.progressText = 'Şablonlar çıxarılır…';
		
			const response = await api.get({
				action: 'query',
				prop: 'revisions',
				titles: pageTitle,
				rvprop: 'content',
				format: 'json',
				formatversion: 2
			});
		
			let content = (
				response.query &&
				response.query.pages &&
				response.query.pages[0] &&
				response.query.pages[0].revisions &&
				response.query.pages[0].revisions[0] &&
				response.query.pages[0].revisions[0].content
			) || '';
		
			for (const tag of this.selectedTags) {
				this.addProgressLog(tag, 'çıxarılır');
				await new Promise(r => setTimeout(r, 250));
			
				const aliases = (this.aliasMap && this.aliasMap[tag]) ? this.aliasMap[tag] : [tag];
				for (const alias of aliases) {
					const regex = new RegExp(`\\s*{{\\s*${alias}(\\|[^}]*)?}}\\s*\\n?`, 'gi');
					content = content.replace(regex, '');
				}
			}
			
			const linked = this.selectedTags.map(tag =>
				`{{[[Şablon:${tag}|${tag}]]}}`
			);
			
			let summaryText = '';
			if (linked.length === 1) {
				summaryText = `${linked[0]} çıxarıldı.`;
			} else if (linked.length === 2) {
				summaryText = `${linked[0]} və ${linked[1]} çıxarıldı.`;
			} else {
				summaryText = linked.slice(0, -1).join(', ') + ' və ' + linked.slice(-1) + ' çıxarıldı.';
			}
		
			await api.postWithEditToken({
				action: 'edit',
				title: pageTitle,
				text: content,
				summary: summaryText,
				format: 'json'
			});
		
			this.status = 'done';
			setTimeout(() => location.reload(), 2000);
			return;
		}
		
			const now = new Date();
			const monthYear = `${this.monthNames[now.getMonth()]} ${now.getFullYear()}`;
		
			const response = await api.get({
				action: 'query',
				prop: 'revisions',
				titles: pageTitle,
				rvprop: 'content',
				format: 'json',
				formatversion: 2
			});
		
			const currentWikitext = (
				response.query &&
				response.query.pages &&
				response.query.pages[0] &&
				response.query.pages[0].revisions &&
				response.query.pages[0].revisions[0] &&
				response.query.pages[0].revisions[0].content
			) || '';
		
			const newTags = this.selectedTags.filter(t => {
				const regex = new RegExp(`{{\\s*${t}\\b`, 'i');
				return !regex.test(currentWikitext);
			});
		
			if (newTags.length === 0) {
				this.progressText = 'Seçilmiş şablonlar artıq mövcuddur!';
				setTimeout(() => { this.status = 'form'; }, 2500);
				return;
			}
			
			for (const tag of newTags) {
				this.addProgressLog(tag, 'əlavə edilir');
				await new Promise(r => setTimeout(r, 250));
			}
					
			const tagsWikitext = newTags.map(t => `{{${t}|tarix=${monthYear}}}`).join('\n');
		
			const linked = newTags.map(tag =>
				`{{[[Şablon:${tag}|${tag}]]}}`
			);
		
			let summaryText = '';
			if (linked.length === 1) {
				summaryText = `${linked[0]} əlavə edildi.`;
			} else if (linked.length === 2) {
				summaryText = `${linked[0]} və ${linked[1]} əlavə edildi.`;
			} else {
				summaryText = linked.slice(0, -1).join(', ') + ' və ' + linked.slice(-1) + ' əlavə edildi.';
			}
		
			await api.postWithEditToken({
				action: 'edit',
				title: pageTitle,
				prependtext: tagsWikitext + '\n',
				summary: summaryText,
				format: 'json'
			});
		
			this.status = 'done';
			setTimeout(() => location.reload(), 2000);
		}
	},
		template: `
		<cdx-dialog
			v-model:open="dialogShown"
			title="Şablon əlavə et"
			:subtitle="''"
			use-close-button
			close-button-label="Bağla"
			:primary-action="status === 'form' ? {
				label:
					selectedMode === 'remove'
						? (selectedTags.length === 1 ? 'Şablonu çıxar' : 'Şablonları çıxar')
						: selectedMode === 'add'
							? 'Əlavə et'
							: 'Yenilə',
				actionType:
					selectedMode === 'remove'
						? 'destructive'
						: selectedMode === 'add'
							? 'progressive'
							: 'default',
				disabled: selectedTags.length === 0
			} : undefined"
			@primary="onSubmit"
		>
			<template #default>
				<div v-if="status === 'form'" style="padding-top: 0.5em;">
					<cdx-tabs v-model="activeTab">
						<cdx-tab
							v-for="tab in tabsData"
							:key="tab.name"
							:name="tab.name"
							:label="tab.label"
						>
							<div v-if="tab.name === 'remove'">
								<div style="margin: 1em 0;">
									<cdx-field :is-fieldset="true" v-if="existingTagList.length">
										<cdx-checkbox
											v-for="tag in existingTagList"
											:key="'existing-' + tag.tag"
											v-model="selectedTags"
											:input-value="tag.tag"
										>
											{{ tag.tag }} – {{ tag.description }}
										</cdx-checkbox>
									</cdx-field>
									<p v-else style="padding: 1em; font-style: italic; color: #555;">
										Səhifədə yerləşdirilmiş bildiriş şablonu tapılmadı.
									</p>
								</div>
							</div>
					
							<div v-else>
								<cdx-search-input
									v-model="searchQuery"
									aria-label="Şablon axtar"
									placeholder="Şablon və ya təsvir axtar…"
									style="margin: 0.75em 0 1em; width: 100%;"
								/>
					
								<div v-for="(groups, categoryName) in filteredTagList" :key="categoryName">
									<h4>{{ categoryName }}</h4>
									<cdx-field :is-fieldset="true">
										<cdx-checkbox
											v-for="tag in Object.values(groups).flat()"
											:key="tag.tag"
											v-model="selectedTags"
											:input-value="tag.tag"
											:disabled="existingTags.includes(tag.tag)"
										>
											<span v-html="highlightedText(tag.tag)"></span> – <span v-html="highlightedText(tag.description)"></span>
										</cdx-checkbox>
									</cdx-field>
								</div>
							</div>
						</cdx-tab>
					</cdx-tabs>
				</div>
			
				<div v-else style="padding: 1em 1.5em; font-size: 90%;">
					<div class="cdx-progress-indicator">
						<div class="cdx-progress-indicator__indicator">
							<progress
								class="cdx-progress-indicator__indicator__progress"
								id="cdx-template-progress"
								v-if="status === 'sending'"
							></progress>
						</div>
						<div class="cdx-label cdx-progress-indicator__label">
							<label class="cdx-label__label" for="cdx-template-progress">
								<span class="cdx-label__label__text">
									{{ status === 'sending' ? progressText : (selectedMode === 'remove' ? 'Şablonlar çıxarıldı!' : (selectedMode === 'update' ? 'Şablonlar yeniləndi!' : 'Şablonlar əlavə olundu!')) }}
								</span>
							</label>
						</div>
					</div>
				</div>
			</template>
		</cdx-dialog>
		`,
		mounted() {
			portletLink.addEventListener('click', this.toggleDialog);
		},
		unmounted() {
			portletLink.removeEventListener('click', this.toggleDialog);
		}
	});

	app.component('cdx-dialog', CdxDialog)
		.component('cdx-checkbox', CdxCheckbox)
		.component('cdx-field', CdxField)
		.component('cdx-search-input', CdxSearchInput)
		.component('cdx-tabs', CdxTabs)
		.component('cdx-tab', CdxTab)
		.mount(document.body.appendChild(document.createElement('div')));
});

/* </nowiki> */
Mənbə — "https://az.wikipedia.org/w/index.php?title=MediaViki:Gadget-toolbox-tag.js&oldid=8190018"
Informasiya Melumat Axtar