پرش به محتوا

پودمان:Protected edit request/active/آزمایشی

از ویکی‌پدیا، دانشنامهٔ آزاد
-- بعضی قسمت‌های این پودمان برای فارسی‌سازی بهتر تغییر یافته‌است، لطفاً هنگام به‌روزرسانی دقت کنید.
require('strict')

local yesno, makeMessageBox -- passed in from Module:Protected edit request
local makeToolbar = require('Module:Toolbar')._main
local getPagetype = require('Module:Pagetype')._main
local effectiveProtectionLevel = require('Module:Effective protection level')._main

----------------------------------------------------------------------
-- Helper functions
----------------------------------------------------------------------

local function makeWikilink(page, display)
	if display then
		return mw.ustring.format('[[%s|%s]]', page, display)
	else
		return mw.ustring.format('[[%s]]', page)
	end
end

----------------------------------------------------------------------
-- Title class
----------------------------------------------------------------------

-- This is basically the mw.title class with some extras thrown in.

local title = {}
title.__index = title

function title.getProtectionLevelText(protectionLevel)
	-- Gets the text to use in anchors and urn links.
	local levels = {unprotected = 'editunprotected', autoconfirmed = 'editsemiprotected', extendedconfirmed = 'editextendedprotected', templateeditor = 'edittemplateprotected', sysop = 'editprotected'}
	return levels[protectionLevel]
end

function title.new(...)
	local success, obj = pcall(mw.title.new, ...)
	if not (success and obj) then return end

	-- Add a protectionLevel property.
	obj.protectionLevel = effectiveProtectionLevel(obj.exists and 'edit' or 'create', obj)
	if obj.protectionLevel == '*' then
		-- Make unprotected pages return "unprotected".
		obj.protectionLevel = 'unprotected'
	elseif obj.protectionLevel == 'user' then
		-- If we just need to be registered, pretend we need to be autoconfirmed, since it's the closest thing we have.
		obj.protectionLevel = 'autoconfirmed'
	elseif obj.protectionLevel == 'accountcreator' then
		-- Lump titleblacklisted pages in with template-protected pages, since templateeditors can do both.
		obj.protectionLevel = 'templateeditor'
	end

	-- Add a pagetype property.
	obj.pagetype = getPagetype{page = obj.prefixedText, defaultns = 'all'}
	
	-- Add link-making methods.
	function obj:makeUrlLink(query, display)
		return mw.ustring.format('[%s %s]', self:fullUrl(query), display)
	end

	function obj:makeViewLink(display)
		return self:makeUrlLink({redirect = 'no'}, display)
	end

	function obj:makeEditLink(display)
		return self:makeUrlLink({action = 'edit'}, display)
	end

	function obj:makeHistoryLink(display)
		return self:makeUrlLink({action = 'history'}, display)
	end

	function obj:makeLastEditLink(display)
		return self:makeUrlLink({diff = 'cur', oldid = 'prev'}, display)
	end

	function obj:makeWhatLinksHereLink(display)
		return makeWikilink('ویژه:پیوند به این صفحه/' .. self.prefixedText, display)
	end

	function obj:makeCompareLink(otherTitle, display)
		display = display or 'تفاوت'
		local comparePagesTitle = title.new('ویژه:مقایسه صفحات')
		return comparePagesTitle:makeUrlLink({page1 = self.prefixedText, page2 = otherTitle.prefixedText}, display)
	end

	function obj:makeLogLink(logType, display)
		local logTitle = title.new('ویژه:سیاهه‌ها')
		return logTitle:makeUrlLink({type = logType, page = self.prefixedText}, display)
	end

	function obj:urlEncode()
		return mw.uri.encode(self.prefixedText, 'WIKI')
	end

	function obj:makeUrnLink(boxProtectionLevel)
		-- Outputs a urn link. The protection level is taken from the template, rather than detected from page itself,
		-- as the detection may be inaccurate for cascade-protected and title-blacklisted pages as of Nov 2013.
		local protectionLinkText = title.getProtectionLevelText(boxProtectionLevel)
		return mw.ustring.format('[urn:x-wp-%s:%s <span></span>]', protectionLinkText, self:urlEncode())
	end

	-- Get a subpage title object, but go through pcall rather than use the unprotected mw.title:subPageTitle.
	function obj:getSubpageTitle(subpage)
		return title.new(self.prefixedText .. '/' .. subpage)
	end
	
	return obj
end

----------------------------------------------------------------------
-- TitleTable class
----------------------------------------------------------------------

local titleTable = {}
titleTable.__index = titleTable

function titleTable.new(args)
	-- Get numerical arguments and make title objects for each of them. 
	local nums = {}
	for k, v in pairs(args) do
		if type(k) == 'number' then
			table.insert(nums, k)
		end
	end
	table.sort(nums)
	local titles = {}
	for _, num in ipairs(nums) do
		local title = title.new(args[num])
		table.insert(titles, title)
	end
	-- Get the current title, and get the subject title if no titles were specified.
	titles.currentTitle = mw.title.getCurrentTitle()
	if #titles < 1 then
		local subjectNs = titles.currentTitle.subjectNsText
		if subjectNs ~= '' then
			subjectNs = subjectNs .. ':'
		end
		table.insert(titles, title.new(subjectNs .. titles.currentTitle.text))
	end
	-- Set the metatable.
	setmetatable(titles, titleTable)
	return titles
end

function titleTable:memoize(memoField, func, ...)
	if self[memoField] ~= nil then
		return self[memoField]
	else
		self[memoField] = func(...)
		return self[memoField]
	end
end

function titleTable:titleIterator()
	local i = 0
	local n = #self
	return function()
		i = i + 1
		if i <= n then
			return self[i]
		end
	end
end

function titleTable:hasSameProperty(memoField, getPropertyFunc)
	-- If the titles table has more than one title in it, check if they have the same property.
	-- The property is found using the getPropertyFunc function, which takes a title object as its single argument.
	
	local function hasSameProperty(getPropertyFunc)
		local property
		for i, obj in ipairs(self) do
			if i == 1 then
				property = getPropertyFunc(obj)
			elseif getPropertyFunc(obj) ~= property then
				return false
			end
		end
		return true
	end

	return self:memoize(memoField, hasSameProperty, getPropertyFunc)
end	

function titleTable:hasSameExistenceStatus()
	-- Returns true if all the titles exist, or if they all don't exist. Returns false if there is a mixture of existence statuses.
	return self:hasSameProperty('sameExistenceStatus', function (title) return title.exists end)
end

function titleTable:hasSameProtectionStatus()
	-- Checks if all the titles have the same protection status (either for creation protection or for edit-protection - the two are not mixed).
	local sameExistenceStatus = self:hasSameExistenceStatus()
	if sameExistenceStatus then
		return self:hasSameProperty('sameProtectionStatus', function (title) return title.protectionLevel end)
	else
		return sameExistenceStatus
	end
end

function titleTable:hasSamePagetype()
	-- Checks if all the titles have the same pagetype.
	return self:hasSameProperty('samePagetype', function (title) return title.pagetype end)
end

function titleTable:propertyExists(memoField, getPropertyFunc)
	-- Checks if a title with a certain property exists.
	-- The property is found using the getPropertyFunc function, which takes a title object as its single argument
	-- and should return a boolean value.
	local function propertyExists(getPropertyFunc)
		for titleObj in self:titleIterator() do
			if getPropertyFunc(titleObj) then
				return true
			end
		end
		return false
	end
	return self:memoize(memoField, propertyExists, getPropertyFunc)
end

function titleTable:hasNonInterfacePage()
	return self:propertyExists('nonInterfacePage', function (titleObj) return titleObj.namespace ~= 8 end)
end

function titleTable:hasTemplateOrModule()
	return self:propertyExists('templateOrModule', function (titleObj) return titleObj.namespace == 10 or titleObj.namespace == 828 end)
end

function titleTable:hasNonTemplateOrModule()
	return self:propertyExists('nontemplateormodule', function (titleobj) return titleobj.namespace ~= 10 and titleobj.namespace ~= 828 end)
end

function titleTable:hasOtherProtectionLevel(level)
	for titleObj in self:titleIterator() do
		if titleObj.protectionLevel ~= level then
			return true
		end
	end
	return false
end

function titleTable:getProtectionLevels()
	local function getProtectionLevels()
		local levels = {}
		for titleObj in self:titleIterator() do
			local level = titleObj.protectionLevel
			levels[level] = true
		end
		return levels
	end
	return self:memoize('protectionLevels', getProtectionLevels)
end

----------------------------------------------------------------------
-- Blurb class definition
----------------------------------------------------------------------

local blurb = {}
blurb.__index = blurb

function blurb.new(titleTable, boxProtectionLevel)
	local obj = {}
	obj.titles = titleTable
	obj.boxProtectionLevel = boxProtectionLevel
	obj.linkCount = 0 -- Counter for the number of total items in the object's link lists. 
	setmetatable(obj, blurb)
	return obj
end

-- Static methods --

function blurb.makeParaText(name, val)
	local pipe = mw.text.nowiki('|')
	local equals = mw.text.nowiki('=')
	val = val and ("''" .. val .. "''") or ''
	return mw.ustring.format('<code style="white-space: nowrap;">%s%s%s%s</code>', pipe, name, equals, val)
end

function blurb.makeTemplateLink(s)
	return mw.ustring.format('%s[[الگو:%s|%s]]%s', mw.text.nowiki('{{'), s,	s, mw.text.nowiki('}}'))
end

function blurb:makeProtectionText()
	local boxProtectionLevel = self.boxProtectionLevel
	local levels = {['*'] = 'حفاظت‌نشده', autoconfirmed = 'نیمه‌حفاظت‌شده', extendedconfirmed ='حفاظت تأییدشده پایدار' , templateeditor = 'الگوحفاظت‌شده', sysop = 'کاملاً حفاظت‌شده'}
	for level, protectionText in pairs(levels) do
		if level == boxProtectionLevel then
			return mw.ustring.format('[[راهنما:حفاظت|%s]]', protectionText)
		end
	end
	error('سطح حفاظت ناشناخته ' .. boxProtectionLevel)
end
-- برای فارسی‌سازی بهتر، شروط تابع زیر را تغییر دادم
function blurb.getPagetypePlural(title)
	local pagetype = title.pagetype
	if pagetype == 'pages' then
		return 'صفحه‌های'
	elseif pagetype == 'templates' then
		return 'الگوها'
	else
		return pagetype .. '‌ها'
	end
end

-- Normal methods --

function blurb:makeLinkList(title)
	local tbargs = {} -- The argument list to pass to Module:Toolbar
	tbargs.style = 'font-size: smaller;'
	tbargs.separator = 'dot'
	-- Page links.
	table.insert(tbargs, title:makeEditLink('ویرایش'))
	table.insert(tbargs, title:makeHistoryLink('تاریخچه'))
	table.insert(tbargs, title:makeLastEditLink('ویرایش آخر'))
	table.insert(tbargs, title:makeWhatLinksHereLink('پیوندها'))
	-- Sandbox links.
	local sandboxTitle = title:getSubpageTitle('تمرین')
	if sandboxTitle and sandboxTitle.exists then
		table.insert(tbargs, sandboxTitle:makeViewLink('صفحه تمرین'))
		table.insert(tbargs, sandboxTitle:makeEditLink('ویرایش صفحه تمرین'))
		table.insert(tbargs, sandboxTitle:makeHistoryLink('تاریخچه صفحه تمرین'))
		table.insert(tbargs, sandboxTitle:makeLastEditLink('ویرایش آخر صفحه تمرین'))
		table.insert(tbargs, title:makeCompareLink(sandboxTitle, 'تفاوت با صفحه تمرین'))
	end
	-- Test cases links.
	local testcasesTitle = title:getSubpageTitle('آزمایشی')
	if testcasesTitle and testcasesTitle.exists then
		table.insert(tbargs, testcasesTitle:makeViewLink('صفحه آزمایشی'))
	end
	-- Transclusion count link.
	if title.namespace == 10 or title.namespace == 828 then -- Only add the transclusion count link for templates and modules.
		local tclink = mw.uri.new{
			host = 'tools.wmflabs.org',
			path = '/templatecount/index.php',
			query = {
				lang = 'fa',
				name = title.text,
				namespace = title.namespace,
			},
			fragment = 'bottom'
		}
		tclink = string.format('[%s شمار تراگنجانش]', tostring(tclink))
		table.insert(tbargs, tclink)
	end
	-- Protection log link.
	if title.namespace ~= 8 then -- MediaWiki pages don't have protection log entries.
		table.insert(tbargs, title:makeLogLink('protect', 'سیاهه محافظت'))
	end
	self.linkCount = self.linkCount + #tbargs -- Keep track of the number of total links created by the object.
	return makeToolbar(tbargs)
end

function blurb:makeLinkLists()
	local titles = self.titles
	if #titles == 1 then
		return self:makeLinkList(titles[1])
	else
		local ret = {}
		table.insert(ret, '<ul>')
		for i, titleObj in ipairs(titles) do
			table.insert(ret, mw.ustring.format('<li>%s %s</li>', titleObj:makeViewLink(titleObj.prefixedText), self:makeLinkList(titleObj)))
		end
		table.insert(ret, '</ul>')
		return table.concat(ret)
	end
end

function blurb:makeIntro()
	local titles = self.titles
	local requested = '[[ویکی‌پدیا:درخواست‌های ویرایش|درخواست شده‌است]] که'
	local protectionText
	if titles:hasNonInterfacePage() then
		protectionText = ' ' .. self:makeProtectionText()
	else
		protectionText = '' -- Interface pages cannot be unprotected, so we don't need to explicitly say they are protected.
	end
	-- Deal with cases where we are passed multiple titles.
	if #titles > 1 then
		local pagetype
		if titles:hasSamePagetype() then
			pagetype = blurb.getPagetypePlural(titles[1])
		else
			pagetype = 'pages'
		end
		-- برای فارسی‌سازی بهتر، جای پارامتر pagetype را با protectionText عوض کردم
		return mw.ustring.format("'''%s ویرایش‌ها در %s %s صورت گیرد''':", requested, pagetype, protectionText)
	end
	-- Deal with cases where we are passed only one title.
	local title = titles[1]
	local stringToFormat
	if title.exists then
		stringToFormat = '%s ویرایشی در %s %sٔ %s انجام شود.'
	else
		stringToFormat = '%s %s %s در %s ساخته شود.'
	end
	stringToFormat = "'''" .. stringToFormat .. "'''"
	-- برای فارسی‌سازی بهتر، جای پارامتر title.pagetype را با protectionText عوض کردم
	return mw.ustring.format(stringToFormat, requested, title.pagetype, protectionText, title:makeViewLink(title.prefixedText))
end

function blurb:makeBody()
	local titles = self.titles
	local protectionLevels = titles:getProtectionLevels()
	local boxProtectionLevel = self.boxProtectionLevel
	local hasNonInterfacePage = titles:hasNonInterfacePage()
	local isPlural = false
	if #titles > 1 then
		isPlural = true
	end

	local descriptionText = "این الگو باید به‌دنبال یک '''توضیح کامل و مشخص''' از درخواست باشد، "
	if boxProtectionLevel == 'sysop' or boxProtectionLevel == 'templateeditor' then
		local editText = 'ویرایش'
		if isPlural then
			editText = editText .. '‌ها'
		end
		local descriptionCompleteText = mw.ustring.format('به‌گونه‌ای که یک ویرایشگر ناآشنا به موضوع اصلی بتواند %s درخواست‌شده را فوراً انجام دهد.', editText)
		descriptionText = descriptionText .. descriptionCompleteText
	else
		descriptionText = descriptionText .. 'بنابراین، مشخص کنید کدام متن باید حذف شود و یک نسخه دقیق از آن‌چه که باید جایگزینش شود ارائه کنید. '
			.. [[«لطفاً ''الف'' را تغییر دهید» '''پذیرفتنی نیست''' و رد خواهد خواهد شد؛ درخواست '''باید''' به شکل «لطفاً ''الف'' را به ''ب'' تغییر دهید» باشد.]]
	end

	local smallText = ''
	if boxProtectionLevel == 'sysop' or boxProtectionLevel == 'templateeditor' then
		local templateFullText
		if boxProtectionLevel == 'sysop' then
			templateFullText = 'به‌طور کامل حفاظت‌شده'
		elseif boxProtectionLevel == 'templateeditor' then
			templateFullText = 'الگوحفاظت‌شده'
		end
		smallText =	'درخواست‌های ویرایش برای صفحه‌های ' .. templateFullText	.. " باید فقط برای ویرایش‌هایی که یا '''بحث برانگیز نیستند''' یا توسط [[ویکی‌پدیا:اجماع|اجماع]] حمایت می‌شود به‌کار رود."
			.. " اگر ویرایش مطرح‌شده ممکن است بحث برانگیز باشد، آن را در صفحه بحث صفحه حفاظت‌شده به بحث بگذارید '''پیش از''' آنکه از این الگو استفاده کنید."
	else
		local userText
		if boxProtectionLevel == 'autoconfirmed' then
			userText = 'کاربر [[ویکی‌پدیا:اختیارات گروه‌های کاربری#کاربران تأییدشدهٔ خودکار|خودکار تأییدشده]]'
		elseif boxProtectionLevel == 'extendedconfirmed' then
			userText = 'کاربر [[ویکی‌پدیا:اختیارات_گروه‌های_کاربری#کاربران_تأییدشدهٔ_پایدار|تأییدشدهٔ پایدار]]'
		else
			userText = 'کاربر'
		end
		local answeredPara = blurb.makeParaText('پاسخ', 'خیر')
		local stringToFormat =	'هر %s می‌تواند ویرایشِ درخواست‌شده را انجام دهد. '
			.. [[به‌خاطر داشته‌باشید زمانی که که درخواست پذیرفته شد، رد شد یا در انتظار ورودی کاربر است، مقدار پارامتر %s را به «'''بله'''» تغییر دهید، ]]
			.. "در غیر اینصورت درخواست‌های غیرفعال‌شده یا انجام‌شده بیهوده رده درخواست‌های ویرایش را پر می‌کند. "
			.. '<!-- همچنین می‌توانید از الگوی %s در پاسخ استفاده کنید. -->'
		smallText = mw.ustring.format(stringToFormat, userText, answeredPara, blurb.makeTemplateLink('ESp'))
	end
	if hasNonInterfacePage then
		smallText = smallText .. ' اگر می‌خواهید صفحه محافظت شود یا از محافظت خارج گردد درخواستتان را در [[ویکی‌پدیا:درخواست محافظت صفحه]] بنویسید.'
	end
	if boxProtectionLevel == 'sysop' or boxProtectionLevel == 'templateeditor' then
		smallText = smallText .. ' زمانی که درخواست انجام شد یا رد شد، لطفاً پارامتر ' .. blurb.makeParaText('پاسخ‌داده‌شده', 'بله') .. 'را این‌چنین تنظیم کنید تا الگو را غیرفعال کنید.'
	end
	return mw.ustring.format('%s\n<p style="font-size:smaller; line-height:1.3em;">\n%s\n</p>', descriptionText, smallText)
end

function blurb:export()
	local intro = self:makeIntro()
	local linkLists = self:makeLinkLists()
	local body = self:makeBody()
	-- Start long links lists on a new line.
	local linkListSep = ' '
	if self.linkCount > 5 then
		linkListSep = '<br />'
	end
	return mw.ustring.format('%s%s%s\n\n%s', intro, linkListSep, linkLists, body)
end

----------------------------------------------------------------------
-- Subclass of Module:Protected edit request's box class for active boxes
----------------------------------------------------------------------

local box = {}
box.__index = box

function box.new(protectionType, args)
	-- In the inheritance system used here, an object's metatable is its class, and a class's metatable is its superclass
	local obj = getmetatable(box).new(protectionType, args)
	setmetatable(obj, box)
	local boxProtectionLevels = {semi = 'autoconfirmed', extended = 'extendedconfirmed', template = 'templateeditor', full = 'sysop'}
	obj.boxProtectionLevel = boxProtectionLevels[protectionType]
	obj.demo = yesno(args.demo)
	-- Set dependent objects.
	obj.titles = titleTable.new(args)
	if not yesno(args.force) and obj.titles:hasSameProperty('sameProtectionStatus', function (title) return title.protectionLevel end) and obj.titles[1].protectionLevel ~= 'unprotected' then
		obj.boxProtectionLevel = obj.titles[1].protectionLevel
	end
	obj.blurb = blurb.new(obj.titles, obj.boxProtectionLevel)
	return obj
end

function box:setImage()
	local titles = self.titles
	local boxProtectionLevel = self.boxProtectionLevel
	local padlock
	if boxProtectionLevel == 'sysop' and not titles:hasNonTemplateOrModule() then
		padlock = 'Padlock-red.svg'
	elseif boxProtectionLevel == 'sysop' then
		padlock = 'Padlock.svg'
	elseif boxProtectionLevel == 'templateeditor' then
		padlock = 'Padlock-pink.svg'
	elseif boxProtectionLevel == 'autoconfirmed' then
		padlock = 'Padlock-silver.svg'
	elseif boxProtectionLevel == 'extendedconfirmed' then
		padlock = 'Padlock-blue.svg'
	else
		padlock = 'Padlock-bronze-open.svg'
	end
	local stringToFormat = '[[پرونده:%s|%dpx|جایگزین=|پیوند=]]'
	local smallPadlock = mw.ustring.format(stringToFormat, padlock, 25)
	local largePadlock = mw.ustring.format(stringToFormat, padlock, 60)
	self:setArg('smallimage', smallPadlock)
	self:setArg('image', largePadlock)
end

function box:buildUrnLinks()
	local ret = {}
	local boxProtectionLevel = self.boxProtectionLevel
	for titleObj in self.titles:titleIterator() do
		table.insert(ret, titleObj:makeUrnLink(boxProtectionLevel))
	end
	return mw.ustring.format('<span class="plainlinks" style="display:none">%s</span>', table.concat(ret))
end

function box:setBlurbText()
	self:setArg('text', self.blurb:export() .. self:buildUrnLinks())
end

function box:exportRequestTmbox()
	self:setImage()
	self:setBlurbText()
	self:setArg('class', 'editrequest')
	self:setArg('id', title.getProtectionLevelText(self.boxProtectionLevel)) -- for anchor. yes, this leads to multiple elements with the same ID. we should probably fix this at some point
	return makeMessageBox('tmbox', self.tmboxArgs)
end

function box:exportRequestCategories()
	local cats = {}
	local boxProtectionLevel = self.boxProtectionLevel
	local function addCat(cat)
		table.insert(cats, mw.ustring.format('[[رده:%s]]', cat))
	end
	local protectionCats = {
		autoconfirmed = 'درخواست‌های ویرایش صفحه‌های نیمه‌حفاظت‌شده',
		extendedconfirmed = 'درخواست‌های ویرایش صفحه‌های حفاظت‌شده تأییدشده پایدار',
		templateeditor = 'درخواست‌های ویرایش الگوهای الگوحفاظت‌شده',
		sysop = 'درخواست‌های ویرایش صفحه‌های کاملاً حفاظت‌شده'
	}
	addCat(protectionCats[boxProtectionLevel])
	if self.titles:hasOtherProtectionLevel(boxProtectionLevel) then
		addCat('درخواست‌های ویرایش با الگوی احتمالاً اشتباه')
	end
	return table.concat(cats)
end

function box:export()
	if not self.titles.currentTitle.isTalkPage and not self.demo then
		return '<span class="error">خطا: درخواست‌های ویرایش حفاظت‌شده فقط می‌توانند در صفحه بحث ایجاد شوند.</span>[[رده:صفحه‌های غیر بحثی که درخواست ویرایش در صفحه حفاظت‌شده دارند]]'
	end
	local ret = {}
	table.insert(ret, self:exportRequestTmbox())
	if not self.demo then
		table.insert(ret, self:exportRequestCategories())
	end
	return table.concat(ret)
end

----------------------------------------------------------------------
-- Function exported to Module:Protected edit request
----------------------------------------------------------------------

return function(superclass, yn, mb)
	yesno = yn
	makeMessageBox = mb
	return setmetatable(box, superclass)
end