模組:雙拉丁字組合

模組解[]
-- vi:set sw=4 ts=4 ai sm:
---- This module reimplements Template:雙拉丁字組合 and
---- Template:兩個拉丁字母搞清楚 so that directions
---- are synchronized and what appears at the four
---- directions will be automatically determined

require ('strict');
local p = {};

local alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

local exceptions = {
	['CD'] = 'CD (搞清楚)';
	['CG'] = 'CG (搞清楚)';
	['DJ'] = 'DJ (搞清楚)';
	['EQ'] = 'EQ (搞清楚)';
	['ET'] = 'ET (搞清楚)';
	['EX'] = 'EX (搞清楚)';
	['IC'] = 'IC (搞清楚)';
	['IQ'] = 'IQ (搞清楚)';
	['IT'] = 'IT (搞清楚)';
	['IU'] = 'IU (搞清楚)';
	['IZ'] = 'IZ (搞清楚)';
	['KG'] = 'KG (搞清楚)';
	['KN'] = 'KN (搞清楚)';
	['MD'] = 'MD (搞清楚)';
	['NY'] = 'NY (搞清楚)';
	['OT'] = 'OT (搞清楚)';
	['PE'] = 'PE (搞清楚)';
	['QQ'] = 'QQ (搞清楚)';
	['RT'] = 'RT (搞清楚)';
	['SF'] = 'SF (搞清楚)';
	['TV'] = 'TV (搞清楚)';
	['UK'] = 'UK (搞清楚)';
	['UN'] = 'UN (搞清楚)';
	['VK'] = 'VK (搞清楚)';
	['VW'] = 'VW (搞清楚)';
};

local function parse_combination( base )
	local it1, it2;
	if base then
		local a, b = base:upper():match('^([' .. alphabet .. '])([' .. alphabet .. '])$');
		if a and b then
			it1 = alphabet:find(a);
			it2 = alphabet:find(b);
		end
	end
	return it1, it2;
end

local function combination( a, b )
	local it = '';
	if a > 0 and a <= alphabet:len() and b > 0 and b <= alphabet:len() then
		it = alphabet:sub(a, a) .. alphabet:sub(b, b);
	end
	return it;
end

local function make_link( s )
	local it = s;
	if it and it ~= '' then
		local target;
		if exceptions[it] then
			target = exceptions[it];
		else
			-- In theory nothing needs to be done, but if we expect
			-- PB, which doesn't exist, but we have a page Pb, we
			-- should link to Pb instead of PB
			local det = mw.title.new(it);
			if not det:getContent() then
				local candidate = it:lower();
				det = mw.title.new(candidate);
				if det:getContent() then
					target = candidate;
				end
			end
		end
		if target then
			it = '[[' .. target .. '|' .. s .. ']]';
		else
			it = '[[' .. s .. ']]';
		end
	end
	return it;
end

local function remove_comments( s )
	return s:gsub('%s*%(.*%)$', '');
end

local function detect_base_from_page_name()
	local this_page = mw.title.getCurrentTitle();
	local candidate = this_page.text;				-- 齋版名,冇 namespace
	candidate = remove_comments(candidate);			-- 鏟括弧
	local it;
	local a, b;
	a, b = parse_combination(candidate);
	if a and b then
		it = candidate;
	end
	return it;
end

local function emit_navbox_real( base )
	local a, b = parse_combination(base);
	
	-- 原格式抄自舊模 Template:雙拉丁字組合
	local it = '\n{| class="infobox soeng1laai1ding1"\n';
	it = it .. '! colspan="3"| 一覽\n';
	it = it .. '|-\n';
	it = it .. '|\n';
	it = it .. '|' .. make_link(combination(a -1, b)) .. '\n';
	it = it .. '|\n';
	it = it .. '|-\n';
	it = it .. '|' .. make_link(combination(a, b -1)) .. '\n';
	it = it .. '|' .. combination(a, b) .. '\n';
	it = it .. '|' .. make_link(combination(a, b + 1)) .. '\n';
	it = it .. '|-\n';
	it = it .. '|\n';
	it = it .. '|' .. make_link(combination(a + 1, b)) .. '\n';
	it = it .. '|\n';
	it = it .. '|}';
	return it;
end

local function emit_footer_real( base )
	local a, b = parse_combination(base);
	local it = '';

	-- 原格式抄自舊模 Template:兩個拉丁字母搞清楚
	it = it .. '\n{| class="wikitable soeng1laai1ding1"\n';
	for i = 1, alphabet:len(), 1 do
		it = it .. '|-\n';
		for j = 1, alphabet:len(), 1 do
			local elem = combination(i, j);
			local in_minimap_p;
			it = it .. '|';
			if a and b then
				-- CSS table handling is very hard to work with, cells at the
				-- N and W directions can’t have their borders set the normal
				-- way so we have to work around the problem by marking also
				-- the cell left of the W cell and above the N cell
				local classes = {};
				if i == a - 2 and j == b then
					table.insert(classes, 'soeng6soeng6');
				elseif i == a - 1 and j == b - 1 then
					table.insert(classes, 'zo2soeng6');
				elseif i == a - 1 and j == b then
					in_minimap_p = true;
					table.insert(classes, 'soeng6');
				elseif i == a - 1 and j == b + 1 then
					table.insert(classes, 'jau6soeng6');
				elseif i == a + 1 and j == b - 1 then
					table.insert(classes, 'zo2haa6');
				elseif i == a + 1 and j == b then
					in_minimap_p = true;
					table.insert(classes, 'haa6');
				elseif i == a + 1 and j == b + 1 then
					table.insert(classes, 'jau6haa6');
				elseif i == a and j == b - 2 then
					table.insert(classes, 'zo2zo2');
				elseif i == a and j == b - 1 then
					in_minimap_p = true;
					table.insert(classes, 'zo2');
				elseif i == a and j == b + 1 then
					in_minimap_p = true;
					table.insert(classes, 'jau6');
				elseif i == a and j == b then
					in_minimap_p = true;
					table.insert(classes, 'zung1');
				end
				if i == 1 then
					table.insert(classes, 'zeoi3soeng6');
				elseif i == alphabet:len() then
					table.insert(classes, 'zeoi3haa6');
				end
				if j == 1 then
					table.insert(classes, 'zeoi3zo2');
				elseif j == alphabet:len() then
					table.insert(classes, 'zeoi3jau6');
				end
				if in_minimap_p then
					table.insert(classes, 1, 'siu2dei6tou4faan6wai4');
				end
				if #classes > 0 then
					it = it .. 'class="' .. table.concat(classes, ' ') .. '"|';
				end
			end
			if it then
				local fragment = elem;
				if not (a and b and i == a and j == b) then
					fragment = make_link(fragment);
				end
				if in_minimap_p then
					fragment = '<b>' .. fragment .. '</b>';
				end
				it = it .. fragment;
			end
			it = it .. '\n';
		end
	end
	it = it .. '|}';
	return it;
end

--- Exported, invocable functions ---------------------------------------------

-- Entry point
p.main = function( frame )
	local parent = frame:getParent();
	local it;
	local styles = '模組:雙拉丁字組合/styles.css';
	local style2 = '模:搞清楚/styles.css';

	local base;
	local mode = frame.args.mode;
	it = ''
	for k, v in pairs(parent.args) do
		if type(k) == 'number' then
			base = v;	-- 原模參數5先係 base
		elseif k == 'base' then
			if base then
				error('遇到參數' .. k .. ' 「' .. v .. '」,但係已經指定咗字母組合係 「' .. base .. '」');
			end
			base = v;
		else
			error('雙拉丁字組合: 模遇到不明參數 「' .. k .. '」');
		end
	end
	local detected_base = detect_base_from_page_name();
	if not base then
		base = detected_base;
	end
	if not base then
		if mode == 'navbox' then
			error('雙拉丁字組合: 冇指定字母組合係乜');
		end
	elseif base:len() ~= 2 then
		error('雙拉丁字組合: 「' .. base .. '」 唔係雙字母組合');
	end

	-- build it
	if mode == 'navbox' then
		it = emit_navbox_real(base);
	elseif mode == 'footer' then
		it = emit_footer_real(base);
	else
		error('雙拉丁字組合: #invoke 冇指定 mode=navbox 定 mode=footer');
	end

	-- track potential problems
	if detected_base then
		local a, b;
		a, b = parse_combination(detected_base);
		local expected_base = combination(a, b);
		local page_name = mw.title.getCurrentTitle().text;
		if page_name == expected_base or page_name == exceptions[expected_base] then
			--
		elseif expected_base == remove_comments(detected_base) then
			it = it .. '[[Category:雙拉丁字組合版括弧搞清楚版冇列例外]]';
		elseif expected_base == detected_base:upper() then
			it = it .. '[[Category:雙拉丁字組合版名唔啱大細楷]]';
		else
			it = it .. '[[Category:雙拉丁字組合版名唔啱名]]';
		end
	end

	-- request our style sheet
	it = table.concat ({
			frame:extensionTag ('templatestyles', '', {src=styles}),
			frame:extensionTag ('templatestyles', '', {src=style2}),
			it
		});
	return it;
end

p.emit_navbox_real = emit_navbox_real;
p.emit_footer_real = emit_footer_real;
p.parse_combination = parse_combination;
p.combination = combination;
p.make_link = make_link;
p.detect_base_from_page_name = detect_base_from_page_name;
return p;