پرش به محتوا

پودمان:AlborzInfoBox

از ویکی البرز

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

--------------------------------------------------------------------------------
-- Module:AlborzInfoBox
-- Wiki Alborz Information System
-- Core Engine
-- Version 2.0
--------------------------------------------------------------------------------

local p = {}

--------------------------------------------------------------------------------
-- DATA
--------------------------------------------------------------------------------

local data = mw.loadData("Module:AlborzInfoBox/Data/Geography")

--------------------------------------------------------------------------------
-- NORMALIZE
--------------------------------------------------------------------------------

local function norm(value)

	if value == nil then
		return nil
	end

	value = tostring(value)

	value = mw.text.trim(value)

	-- حذف نیم‌فاصله و کاراکترهای نامرئی
	value = mw.ustring.gsub(value, "[\u200C\u200D\uFEFF]", "")

	-- یکسان‌سازی فاصله‌ها
	value = mw.ustring.gsub(value, "%s+", " ")

	-- حروف عربی → فارسی
	value = mw.ustring.gsub(value, "ي", "ی")
	value = mw.ustring.gsub(value, "ى", "ی")
	value = mw.ustring.gsub(value, "ك", "ک")

	return mw.text.trim(value)
end

--------------------------------------------------------------------------------
-- ARGUMENT HANDLING
--------------------------------------------------------------------------------

local function collectArgs(frame)

	local args = {}

	local function push(source)

		if not source then
			return
		end

		for key, value in pairs(source) do

			if value ~= nil then

				local normalizedKey = norm(key)
				local normalizedValue = mw.text.trim(tostring(value))

				if normalizedKey ~= "" and normalizedValue ~= "" then
					args[normalizedKey] = normalizedValue
				end

			end

		end

	end

	-- اول آرگومان‌های مستقیم invoke
	push(frame.args)

	-- سپس آرگومان‌های الگو
	local parent = frame:getParent()

	if parent then
		push(parent.args)
	end

	return args
end

--------------------------------------------------------------------------------
-- FIELD VALUE
--------------------------------------------------------------------------------

local function getValue(args, field)

	if not field then
		return nil
	end

	local names = {}

	-- arg اصلی
	if field.arg then
		table.insert(names, field.arg)
	end

	-- نام‌های جایگزین
	if field.args then

		for _, name in ipairs(field.args) do
			table.insert(names, name)
		end

	end

	-- جست‌وجوی مقدار
	for _, name in ipairs(names) do

		local key = norm(name)
		local value = args[key]

		if value and value ~= "" then
			return value
		end

	end

	-- مقدار پیش‌فرض
	if field.default ~= nil then
		return field.default
	end

	return nil
end

--------------------------------------------------------------------------------
-- SAFE WIKITEXT
--------------------------------------------------------------------------------

local function cleanText(value)

	if value == nil then
		return nil
	end

	value = tostring(value)

	value = mw.text.trim(value)

	if value == "" then
		return nil
	end

	return value
end

--------------------------------------------------------------------------------
-- ADD ROW
--------------------------------------------------------------------------------

local function addRow(root, label, value, raw)

	value = cleanText(value)

	if not value then
		return
	end

	local tr = root:tag("tr")

	-- Label
	local th = tr:tag("th")

	th
		:attr("scope", "row")
		:addClass("infobox-label")
		:wikitext(label)

	-- Value
	local td = tr:tag("td")

	td:addClass("infobox-value")

	if raw then
		td:wikitext(value)
	else
		td:wikitext(mw.text.encode(value))
	end
end

--------------------------------------------------------------------------------
-- TYPE BADGE
--------------------------------------------------------------------------------

local badgeMap = {

	city = "شهر",
	village = "روستا",
	county = "شهرستان",
	district = "بخش",
	ruraldistrict = "دهستان",

	neighborhood = "محله",

	mountain = "کوه",
	cave = "غار",
	river = "رودخانه",
	waterfall = "آبشار",
	park = "پارک",
	historic = "بنای تاریخی"

}

local function addBadge(root, typeKey)

	local label = badgeMap[typeKey] or "مکان"

	local tr = root:tag("tr")

	local td = tr:tag("td")

	td
		:attr("colspan", "2")
		:addClass("infobox-badge-row")

	local span = td:tag("span")

	span
		:addClass("infobox-badge")
		:wikitext(label)

end

--------------------------------------------------------------------------------
-- IMAGE
--------------------------------------------------------------------------------

local function isSimpleFilename(value)

	if not value or value == "" then
		return false
	end

	value = mw.text.trim(value)

	-- اگر خود مقدار شامل ویکی‌متن یا HTML باشد
	if value:find("{", 1, true)
		or value:find("<", 1, true)
		or value:find("|", 1, true)
		or value:find("[[", 1, true)
	then
		return false
	end

	return true
end

--------------------------------------------------------------------------------
-- IMAGE RENDERER
--------------------------------------------------------------------------------

local function addImage(root, args)

	local content =
		args[norm("تصویر")]
		or args[norm("پرونده")]
		or args[norm("image")]

	if not content or content == "" then
		return
	end

	content = mw.text.trim(content)

	local tr = root:tag("tr")

	local td = tr:tag("td")

	td
		:attr("colspan", "2")
		:addClass("infobox-image")

	if isSimpleFilename(content) then

		local filename = content

		filename = mw.ustring.gsub(
			filename,
			"^[Ff]ile:",
			""
		)

		filename = mw.ustring.gsub(
			filename,
			"^پرونده:",
			""
		)

		td:wikitext(
			"[[File:" .. filename .. "|250px]]"
		)

	else

		td:wikitext(content)

	end

end

--------------------------------------------------------------------------------
-- IMAGE CAPTION
--------------------------------------------------------------------------------

local function addCaption(root, args)

	local caption =
		args[norm("توضیح تصویر")]
		or args[norm("عنوان تصویر")]
		or args[norm("زیرنویس")]
		or args[norm("برچسب تصویر")]

	if not caption or caption == "" then
		return
	end

	local tr = root:tag("tr")

	local td = tr:tag("td")

	td
		:attr("colspan", "2")
		:addClass("infobox-caption")
		:wikitext(mw.text.encode(caption))

end

--------------------------------------------------------------------------------
-- TITLE
--------------------------------------------------------------------------------

local function getTitle(args)

	return
		args[norm("نام‌رسمی")]
		or args[norm("نام رسمی")]
		or args[norm("نام")]
		or mw.title.getCurrentTitle().text

end

local function addTitle(root, args)

	local title = getTitle(args)

	if not title or title == "" then
		return
	end

	local tr = root:tag("tr")

	local th = tr:tag("th")

	th
		:attr("colspan", "2")
		:addClass("infobox-title")
		:wikitext(mw.text.encode(title))

end

--------------------------------------------------------------------------------
-- TABLE
--------------------------------------------------------------------------------

local function newTable(typeKey)

	local root = mw.html.create("table")

	root
		:addClass("infobox")
		:addClass("alborz-infobox")
		:addClass("infobox-geography")
		:addClass("infobox-type-" .. typeKey)
		:attr("role", "presentation")

	return root
end

--------------------------------------------------------------------------------
-- TYPE ALIASES
--------------------------------------------------------------------------------

local typeAliases = {

	["شهرستان"] = "county",
	["county"] = "county",

	["شهر"] = "city",
	["city"] = "city",

	["روستا"] = "village",
	["village"] = "village",

	["بخش"] = "district",
	["district"] = "district",

	["دهستان"] = "ruraldistrict",
	["ruraldistrict"] = "ruraldistrict",

	["محله"] = "neighborhood",
	["neighborhood"] = "neighborhood",

	["کوه"] = "mountain",
	["mountain"] = "mountain",

	["غار"] = "cave",
	["cave"] = "cave",

	["رودخانه"] = "river",
	["river"] = "river",

	["آبشار"] = "waterfall",
	["waterfall"] = "waterfall",

	["پارک"] = "park",
	["park"] = "park",

	["بنای تاریخی"] = "historic",
	["historic"] = "historic"

}

--------------------------------------------------------------------------------
-- TYPE RESOLUTION
--------------------------------------------------------------------------------

local function resolveType(value)

	if not value or value == "" then
		return "city"
	end

	value = norm(value)

	return typeAliases[value] or value

end

--------------------------------------------------------------------------------
-- LAYOUT
--------------------------------------------------------------------------------

local function getLayout(typeKey)

	if not data or not data.layouts then
		return {}
	end

	return
		data.layouts[typeKey]
		or data.layouts.city
		or {}

end

--------------------------------------------------------------------------------
-- RENDER ROWS
--------------------------------------------------------------------------------

local function renderRows(root, args, layout)

	if not layout then
		return
	end

	for _, key in ipairs(layout) do

		local field = data.fields[key]

		if field then

			local value = getValue(args, field)

			if value and value ~= "" then

				addRow(
					root,
					field.label,
					value,
					field.raw
				)

			end

		end

	end

end

--------------------------------------------------------------------------------
-- MAIN RENDER
--------------------------------------------------------------------------------

local function render(args)

	if not data then
		return "Infobox data not found"
	end

	if not data.fields then
		return "Infobox fields not found"
	end

	----------------------------------------------------------------
	-- Resolve type
	----------------------------------------------------------------

	local requestedType =
		args[norm("نوع")]
		or args[norm("type")]

	local typeKey =
		resolveType(requestedType)

	----------------------------------------------------------------
	-- Data type map
	----------------------------------------------------------------

	local internalType = typeKey

	if data.typeMap and data.typeMap[typeKey] then
		internalType = data.typeMap[typeKey]
	end

	----------------------------------------------------------------
	-- Layout
	----------------------------------------------------------------

	local layout =
		getLayout(internalType)

	----------------------------------------------------------------
	-- Table
	----------------------------------------------------------------

	local root =
		newTable(internalType)

	----------------------------------------------------------------
	-- Title
	----------------------------------------------------------------

	addTitle(root, args)

	----------------------------------------------------------------
	-- Type badge
	----------------------------------------------------------------

	addBadge(root, internalType)

	----------------------------------------------------------------
	-- Image
	----------------------------------------------------------------

	addImage(root, args)

	----------------------------------------------------------------
	-- Caption
	----------------------------------------------------------------

	addCaption(root, args)

	----------------------------------------------------------------
	-- Rows
	----------------------------------------------------------------

	renderRows(
		root,
		args,
		layout
	)

	return tostring(root)

end

--------------------------------------------------------------------------------
-- PUBLIC ENTRY POINT
--------------------------------------------------------------------------------

function p.main(frame)

	local args =
		collectArgs(frame)

	return render(args)

end

--------------------------------------------------------------------------------
-- RETURN
--------------------------------------------------------------------------------

return p