پودمان:IranByProvinceCatNav

از اسلامیکال
پرش به ناوبری پرش به جستجو

توضیحات این پودمان می‌تواند در پودمان:IranByProvinceCatNav/توضیحات قرار گیرد.

--[[
	v01.18: fix handling of definite article (e.g. for 'the Northwest Territories') 

 each title consists of 3 parts
    * prefix
    * province name
    * suffix
 e.g. "فلان در تهران"
    * prefix = "فلان در "
    * province name = "تهران"
    * suffix = ""
 e.g. "تهران در دهه ۱۳۹۰"
    * prefix = ""
    * province name = "تهران"
    * suffix = "در دهه ۱۳۹۰"
]]

-- config
local textSize = '90%'
local tableClass="toc"
local evenRowStyle = "vertical-align:top; background-color:#f3f3f3;"
local oddRowStyle = "vertical-align:top;"
local labelStyle = "text-align:left; font-weight: bold; padding: 0.25em 0.5em 0.25em 0.5em;"
local listStyle = "text-align:right; font-weight: normal; padding: 0.25em 0.5em 0.25em 0.5em;"
local greyLinkColor = "#888"
--[[ Note that the table styles are designed to ensure that the navbox is as wide as possible, while still leaving
     enough enough space on the right for portal boxes, commons links, and GeoGroup templates.
     A lot of fiddling was needed to make it work, so please test any chnages very carfully in the sandbox.
]]
local tableFallbackMaxWidth="auto"
local tableMaxWidth="calc(100% - 25em)" -- Template:GeoGroup has width: 23em<
-- local tableStyle="margin-left:0; margin-right:auto; clear:left !important; margin-top:0 !important; float:left; width:auto;"
local tableStyle="margin-right:0; margin-left:auto; clear:right !important; margin-top:0 !important; width:auto;"

-- Templates which are allowed to call this module
local callingTemplates = {
	'الگو:IranByProvinceCatNav',
	'الگو:ناوبری رده استان‌های ایران',
}

-- globals for this module
local debugging = false
local debugmsg = ""
local tableRowNum = 0
local title_prefix = ""
local title_suffix = ""
local title_prefix
local title_suffix
local thisPageProvince
local greyLinkCount = 0
local blueLinkCount = 0
local parentname = ""
local templateName

local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local p = {}

--[[
	Plain text list of provinces and territories
	* Each entry exactly as it appears in running text in category titles, with any prefix (e.g. "the")
	* Be sure to avoid hidden characters and duplicate spaces.  They break the pattern-matching on which this module relies
]]
local IranProvinces = {
	'استان آذربایجان شرقی',
	'استان آذربایجان غربی',
	'استان اردبیل',
	'استان اصفهان',
	'استان البرز',
	'استان ایلام',
	'استان بوشهر',
	'استان تهران',
	'استان چهارمحال و بختیاری',
	'استان خراسان جنوبی',
	'استان خراسان رضوی',
	'استان خراسان شمالی',
	'استان خوزستان',
	'استان زنجان',
	'استان سمنان',
	'استان سیستان و بلوچستان',
	'استان فارس',
	'استان قزوین',
	'استان قم',
	'استان کردستان',
	'استان کرمان',
	'استان کرمانشاه',
	'استان کهگیلویه و بویراحمد',
	'استان گلستان',
	'استان گیلان',
	'استان لرستان',
	'استان مازندران',
	'استان مرکزی',
	'استان هرمزگان',
	'استان همدان',
	'استان یزد'
}

-- If the page title matches any of these Lua patterns, treat it as a false positive 
local falsePositiveChecks = {
	"کرج",
	"استان کرج",
}

function makeTrackingCategory()
	-- discount the current page, which will always be coded as a blue link, but rendered as bold un-navigable
	blueLinkCount = blueLinkCount - 1
	if greyLinkCount == 0 then
		return "[[رده:" .. templateName .. " بدون پیوند خاکستری]]"
	end
	if blueLinkCount == 0 then
		return "[[رده:" .. templateName .. " فقط دارای پیوند خاکستری]]"
	end
	if  greyLinkCount <= 10 then
		return "[[رده:" .. templateName .. " با کمتر از ۱۰ پیوند خاکستری]]"
	end
	if  greyLinkCount >= 25 then
		return "[[رده:" .. templateName .. " با بیش از ۲۵ پیوند خاکستری]]"
	end
	if  greyLinkCount > 10 then
		return "[[رده:" .. templateName .. " با بیش از ۱۰ پیوند خاکستری]]"
	end
	return ""
end

function makeTableRow(rowLabel, provinceList)
	debugLog(2, "ساخت ردیف جدول, برچسب: ")
	if (rowLabel == nil) then
		rowLabel = "بر&nbsp;پایه<br/>استان"
		debugLog(nil, rowLabel)
	else
		rowLabel = mw.text.trim(rowLabel)
		debugLog(nil, " [" .. rowLabel .. "]")
	end
	tableRowNum = tableRowNum + 1
	local thisRow
	if (tableRowNum % 2) == 0 then
		debugLog(3, "با شمارهٔ زوج")
		thisRow = '<tr style="' .. evenRowStyle .. '">\n'
	else
		debugLog(3, "با شمارهٔ فرد")
		thisRow = '<tr style="' .. oddRowStyle .. '">\n'
	end
	if not ((rowLabel == nil) or (rowLabel =="")) then
		thisRow = thisRow .. '<td style="' .. labelStyle .. '">' .. rowLabel .. '</td>\n'
	end
	-- now begin making the row contents
	thisRow = thisRow .. '<td style="' .. listStyle .. ';"><div class="hlist">\n'
	local i, aProvince
		debugLog(3, "پردازش فهرست استان‌ها")
	for i, aProvince in ipairs(provinceList) do
		debugLog(4, "شمارهٔ " .. tostring(i) .. ": [" .. aProvince .. "]")
		myCatName = makeCatName(aProvince, title_prefix, title_suffix)
		thisRow = thisRow .. "* " .. makeCatLink(myCatName, aProvince) .. "\n"
	end
	thisRow = thisRow .. '</div></td>\n</tr>'
	return thisRow
end


function makeTable()
	debugLog(1, "ساخت جدول")
	tableRowNum = 0
	local myTable = '<table class="' .. tableClass .. '"'
	myTable = myTable .. ' style="' .. tableStyle .. '; font-size:' .. textSize .. '; max-width:' .. tableFallbackMaxWidth .. '; max-width:' .. tableMaxWidth ..'">\n'

	myTable = myTable .. makeTableRow(nil, IranProvinces)
	myTable = myTable .. "</table>\n"
	return myTable
end


-- Make a piped link to a category, if it exists
-- If it doesn't exist, just display the greyed link title without linking
function makeCatLink(catname, disp)
	local displaytext
	if (disp ~= "") and (disp ~= nil) then
		-- use 'disp' parameter, but strip any leading word "استان"
		displaytext = mw.ustring.gsub(disp, "استان%s+", "");
	else
		displaytext = catname
	end
	local fmtlink
	local catPage = mw.title.new( catname, "رده" )
	if (catPage.exists) then
		fmtlink = "[[:رده:" .. catname .. "|" .. displaytext .. "]]"
		blueLinkCount = blueLinkCount + 1
	else
		fmtlink = '<span style="color:' .. greyLinkColor .. '">' .. displaytext .. "</span>"
		greyLinkCount = greyLinkCount + 1
	end

	return fmtlink
end


function makeCatName(provinceName, prefix, suffix)
	local thisCatName = prefix .. provinceName .. suffix
	debugLog(5, "نام این رده = [" .. thisCatName .. "]")
	--[[
		Now check whether the all following conditions are true
			1/ the provinceName begins with "استان"
			2/ the category does NOT exist if we use "استان "
			3/ the category does exist if we strip "استان "
		 If those conditions are all true, them strip "استان" 
	]] 
	if (mw.ustring.match(provinceName, "استان ") ~= nil) then
		debugLog(6, "نام استان با «استان» آغاز می‌شود")
		local provinceNameStripped = mw.ustring.gsub(provinceName, "استان ", "", 1)
		local thisCatNameStripped = prefix .. provinceNameStripped .. suffix
		debugLog(6, "نام این رده به‌صورت جدا جدا = [" .. thisCatNameStripped .. "]")
		local testCatPage = mw.title.new(thisCatName, "رده" )
		local testCatPageStripped = mw.title.new(thisCatNameStripped, "رده" )
		if not testCatPage.exists then
			debugLog(7, "[" .. testCatPage.fullText .. "] .. موجود نیست") 
			if (testCatPageStripped.exists) then
				debugLog(7, "[" .. testCatPageStripped.fullText .. "] .. موجود است، پس از آن استفاده می‌شود") 
				return thisCatNameStripped
			end
		end
	end
	return thisCatName
end


function patternSearchEncode(s)
	return mw.ustring.gsub(s, "([%W])", "%%%1")
end

-- Does the pagename include a province name?
function findprovinceNameInPagename(pn, provinceList, description)
	local i, aProvince, testProvince
	debugLog(2, "بررسی [" .. pn .."] برای نام استان در مجموعهٔ استان‌ها: " .. description)
	for i, aProvince in ipairs(provinceList) do
		testProvince = aProvince
		debugLog(3, "آزمایش: ["  .. testProvince .. "]")
		local testProvinceEncoded = patternSearchEncode(testProvince)
		-- For efficiency, the first test is a simple match as a a screening test
		-- If the bare county name is nowhere in the pagename, then no need for
		-- more precise checks
		-- This check would be one line in regex, but Lua pattern matching is cruder,
		-- so we need several passes to ensure that any match is of a complete word
		debugLog(4, "انطباق ساده؟ ")
		if (not mw.ustring.match(pn, testProvinceEncoded)) then
			debugLog(nil, "ناموفق")
		else
			debugLog(nil, "موفق")

			-- test for false positives
			local j, aFalsePositiveTest
			for j, aFalsePositiveTest in ipairs(falsePositiveChecks) do
				debugLog(5, "الگوی آزمایش «" .. aFalsePositiveTest .. "» مثبت کاذب است؟ ")
				if (mw.ustring.match(pn, aFalsePositiveTest)) then
					debugLog(nil, "منطبق است، پس ناموفق")
					return nil
				end
				debugLog(nil, "منطبق نیست، پس درست است")
			end

			debugLog(4, "انطباق کل مام؟ ")
			if (pn == testProvince) then
				debugLog(nil, "بله")
				return testProvince
			end
			debugLog(nil, "خیر")

			debugLog(4, "انطباق در ابتدا پیش از جداکننده؟ ")
			if mw.ustring.match(pn, "^" .. testProvinceEncoded .. "[^%w]") then
				debugLog(nil, "بله")
				return testProvince
			end
			debugLog(nil, "خیر")
			
			debugLog(4, "انطباق در انتها پس از جداکننده؟ ")
			if mw.ustring.match(pn, "[^%w]" .. testProvinceEncoded .. "$") then
				debugLog(nil, "بله")
				return testProvince
			end
			debugLog(nil, "خیر")

			debugLog(4, "انطباق در هر جا پس یا پیش از جداکننده؟ ")
			if mw.ustring.match(pn, "[^%w]" .. testProvinceEncoded .. "[^%w]") then
				debugLog(nil, "بله")
				return testProvince
			end
			debugLog(nil, "خیر")

		end
		-- Special case: if the province name we are testing begins with a prefixed "استان"
		debugLog(4, "آزمایش استان با «استان» آغاز می‌شود؟ ")
		if (mw.ustring.match(testProvince, "استان ") == nil) then
			debugLog(nil, "خیر")
		else
			debugLog(nil, "بله")
		end
		if (mw.ustring.match(testProvince, "استان ") ~= nil) then
			local testProvinceStripped = mw.ustring.gsub(testProvince, "استان ", "", 1)
			local testProvinceStrippedEncoded = patternSearchEncode(testProvinceStripped)
			debugLog(4, "الگوی آزمایش بدون مقالهٔ اصلی، مثلاً «" .. testProvinceStrippedEncoded .. "»؟ ")
			if (mw.ustring.match(pn, "[^%w]" .. testProvinceStrippedEncoded .. "[^%w]")  ~= nil)
			or (mw.ustring.match(pn, "^" .. testProvinceStrippedEncoded .. "[^%w]")  ~= nil)
			or (mw.ustring.match(pn, "[^%w]" .. testProvinceStrippedEncoded .. "$")  ~= nil)
			or (mw.ustring.match(pn, "^" .. testProvinceStrippedEncoded .. "$")  ~= nil) then
				debugLog(nil, "بله")
				return testProvinceStripped
			end
			debugLog(nil, "خیر")
		end
	end
	return nil
end

-- parse the pagename to find 3 parts: prefix, province name, suffix
function parsePagename(pn)
	debugLog(1, "تجزیهٔ نام صفحه: [" .. pn .. "]")
	local validprovinceName
	validprovinceName = findprovinceNameInPagename(pn, IranProvinces, "provincelst")
	if validprovinceName == nil then
		return false
	end
	
	-- if we get here, the page name "pn" includes a validprovinceName
	-- so now we need to split the string
	
	debugLog(2, "تفکیک نام صفحه پیرامون [" .. validprovinceName .. "]")
	local validProvinceEncoded = mw.ustring.gsub(validprovinceName, "([%W])", "%%%1")
	match_prefix, match_province, match_suffix = mw.ustring.match(pn, "^(.*)(" .. validProvinceEncoded .. ")(.*)$")
	
	title_prefix = match_prefix
	title_suffix = match_suffix
	debugLog(2, "تجزیه موفق")
	debugLog(3, "پیشوند عنوان = [" .. title_prefix .. "]")
	debugLog(3, "استان در این صفححه = [" .. match_province .. "]")
	debugLog(3, "پسوند عنوان = [" .. title_suffix .. "]")
	return true
end


function publishDebugLog()
	if not debugging then
		return ""
	end
	return "== خرفسترزدایی ==\n\n" .. debugmsg .. "\n== خروجی ==\n"
end


-- debugLog builds a log which can be output if debuging is enabled
-- each log entry is given a level, so that the output is not simply a flat list
-- a debug msg may be appended to the previous msg by setting the level to nil
function debugLog(level, msg)

	if (debugmsg == nil) then
		debugmsg = ""
	end

	if (level ~= nil) then
		-- not appending, so make a new line
		debugmsg = debugmsg .. "\n"
		-- then add the level
		local i
		for i = 1, level do
			if (i % 2) == 1 then
				debugmsg = debugmsg .. "#"
			else
				debugmsg = debugmsg .. "*"
			end
		end 
	end
	debugmsg = debugmsg .. " " .. msg
	return true
end


function getYesNoParam(args, thisParamName, defaultVal)
	local paramVal = args[thisParamName]
	if paramVal == nil then
		paramVal = ""
	end

	debugLog(2, "برآورد پارامتر بله/خیر: [" .. thisParamName .. "] = [" .. paramVal .. "]")
	debugLog(3, "پیش‌فرض = " .. ((defaultVal and "بله") or "خیر"))
	debugLog(3, "برآورد به‌عنوان: ")
	local returnValue
	if paramVal == "" then
		returnValue = defaultVal
	else
		returnValue = yesno(args[thisParamName], defaultVal)
	end
	if (returnValue) then
		debugLog(nil, "بله")
	else
		debugLog(nil, "خیر")
	end
	return returnValue
end

function makeErrorMsg(s)
	return '<p class="error">خطای [[' .. parentname .. ']]: ' .. s .. '</p>\n'
end

function isValidParent(p)
	local i, aParent
	for i, aParent in ipairs(callingTemplates) do
		if p == aParent then
			return true
		end
	end
	return false
end

function p.main(frame)
	local parent = frame:getParent()
	if parent then
		 parentname = parent:getTitle():gsub('/صفحه تمرین$', '')
	end

	if (parentname == nil) or not isValidParent(parentname) then
		local errormsg = '<p class="error"> خطا: ' .. parentname .. ' داده‌پوش معتبری برای [[' .. frame:getTitle() .. ']] نیست\n'
		errormsg = errormsg .. '<br><br>داده‌پوش‌های معتبر: '
		local i, aParent
		for i, aParent in ipairs(callingTemplates) do
			errormsg = errormsg .. '[[' .. aParent  .. ']]'
		end
		errormsg = errormsg .. '</p>'
		return errormsg
	end
	templateName = mw.ustring.gsub(parentname, "^الگو:", "")
	
	debugLog(1, "بررسی پارامترها")
	debugging = getYesNoParam(frame.args, "debug", false)

	-- get the page title
	thispage = mw.title.getCurrentTitle()
	thispagename = thispage.text;
	
	debugLog(1, "mw.title.getCurrentTitle()")
	debugLog(2, "thispage.text = [" .. thispage.text .."]")
	debugLog(2, "thispage.namespace = [" .. thispage.namespace .."]")
	debugLog(2, "thispage.nsText = [" .. thispage.nsText .."]")
	debugLog(2, "این صفحه یک رده است؟ با استفاده از (thispage:inNamespace(14)): ")
	if not (thispage:inNamespace(14)) then
		debugLog(nil, "خیر، رده نیست")
		debugLog(1, "رده نیست، پس خروجی ارائه نمی‌شود")
		return makeErrorMsg("تنها برای استفاده در صفحه‌های رده") .. publishDebugLog()
	end
	debugLog(nil, "بله، رده است")

	if not parsePagename(thispagename) then
		-- some error parsing the title, so don't proceed to output
		local trackingCatInvalid = "[[رده:" .. templateName .. " در رده نامعتبر]]"
		return makeErrorMsg('نام این رده شامل نام معتبر یکی از استان‌های ایران نیست') .. publishDebugLog() .. trackingCatInvalid
	end
	
	debugLog(1, "تجزیه کامل شد")
	debugLog(2, "پیشوند عنوان = [" .. title_prefix .. "]")
	debugLog(2, "پسوند عنوان = [" .. title_suffix .. "]")
	
	local myNavTable = makeTable()
	debugLog(2, "تعداد پیوندهای آبی = [" .. blueLinkCount .. "]. &nbsp; (دقت کنید که صفحهٔ کنونی همواره به‌عنوان پیوند آبی شمارش می‌شود، اما قابل ناوبری نخواهد بود)")
	debugLog(2, "تعداد پیوندهای خاکستری = [" .. greyLinkCount .. "]")
	
	if (blueLinkCount <= 1) then
		-- This is a navbar to nowhere, so suppress display
		myNavTable = ""
		debugLog(1, "صفر پیوند آبی (به‌جز صفحهٔ کنونی) باعث می‌شود که این ناوبری کاربردی نداشته‌باشد؛ پس جعبهٔ ناوبری نمایش نخواهد یافت")
	end
	
	local myTrackingCat = makeTrackingCategory()

	return publishDebugLog() .. myNavTable .. myTrackingCat

end

return p