Pergi ke kandungan

Modul:get IDs

Daripada Wikikamus
local export = {}

local require_when_needed = require("Module:require when needed")

local parameters_module = "Module:parameters"
local string_nowiki_module = "Module:string/nowiki"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local template_parser_module = "Module:template parser"

local anchor_encode = mw.uri.anchorEncode
local byte = string.byte
local class_else_type = require_when_needed(template_parser_module, "class_else_type")
local concat = table.concat
local decode_entities = require_when_needed(string_utilities_module, "decode_entities")
local format = string.format
local get -- Defined below.
local gsub = string.gsub
local load_data = mw.loadData
local lower = string.lower
local new_title = mw.title.new
local normalize_anchor -- Defined below.
local nowiki = require_when_needed(string_nowiki_module)
local pairs = pairs
local parse = require_when_needed(template_parser_module, "parse")
local pcall = pcall
local process_params = require_when_needed(parameters_module, "process")

local frame
local templates = require(table_module).listToSet{
	"anchor",
	"etymid",
	"etymon",
	"senseid",
	"ter-lihat",
	"ter-atas",
	"ter-atas-juga"
}

function export.normalize_anchor(str)
	return decode_entities(anchor_encode(str))
end
normalize_anchor = export.normalize_anchor

local function handle_heading(name, seen, ids)
	-- Repeated IDs are disambiguated by appending _N, where N is an
	-- incremented integer. When determining this, ASCII characters are case-
	-- insensitive, but all other characters are case-sensitive.
	local check = lower(name)
	if seen[check] then
		local i, name_lower = 1, check
		repeat
			i = i + 1
			check = name_lower .. "_" .. i
		until not seen[check]
		name = name .. "_" .. i
	end
	seen[check] = true
	ids[#ids + 1] = name
end

local function pseudo_percent_encode(ch)
	return format(".%02X", byte(ch))
end

local function handle_template(name, node, ids)
	if not frame then
		frame = mw.getCurrentFrame()
	end
	local args, success = node:get_arguments()
	for k, v in pairs(args) do
		args[k] = frame:preprocess(v)
	end
	success, args = pcall(process_params, args, load_data("Module:parameters/data")[name])
	if not success then
		return
	elseif name == "anchor" then
		args = args[1]
		for i = 1, #args do
			ids[#ids + 1] = normalize_anchor(args[i])
		end
		return
	end
	local id1, id2
	if name == "ter-atas" or name == "ter-atas" or name == "ter-atas-juga" then
		id1 = "Terjemahan-"
		if name == "ter-atas" then
			id2 = args.id or args[1]
		else
			id2 = args.id.default or args[1]
		end
	else
		id1 = args[1]:getCanonicalName() .. ": "
		id2 = args[name == "etymon" and "id" or 2]
	end
	if id2 then
		ids[#ids + 1] = normalize_anchor(id1 .. id2)
	end
end

function export.get(pagename, force_transclusion)
	local page, seen, ids = new_title(pagename), {}, {}
	
	for node in parse((page.redirectTarget or page):getContent()):__pairs("next_node") do
		local node_class = class_else_type(node)
		if node_class == "heading" then
			local name = normalize_anchor(node:get_name())
			handle_heading(name, seen, ids)
			-- Headings get a fallback ID, which uses pseudo-percent-encoding
			-- where "%" is replaced by "." (e.g. "!" is ".21").
			local name2 = gsub(name, "[^%w%-.:_]", pseudo_percent_encode)
			if name2 ~= name then
				handle_heading(name2, seen, ids)
			end
		elseif node_class == "template" then
			local name = node:get_name(nil, force_transclusion)
			if templates[name] then
				handle_template(name, node, ids)
			end
		end
	end
	
	return ids
end
get = export.get

-- Used by [[MediaWiki:Gadget-OrangeLinks.js]].
function export.show(frame)
	local output = {}
	
	for i, pagename in ipairs(frame.args) do
		output[i] = nowiki(concat(get(pagename, true), " "))
	end
	
	return concat(output, "\n\n")
end

return export