Modul:character list

Dokumentasi untuk modul ini dapat dibuat di Modul:character list/doc

local m_unicode = require("Modul:Unicode data")
local m_uni_alias = require("Modul:Unicode data/aliases")
local general_category_data = require("Modul:Unicode data/category")
local process_params = require("Modul:parameters").process
local safe_require = require("Modul:utilities").safe_require
local script_data = require("Modul:Unicode data/scripts")
local Array = require("Modul:array")

local char_to_script = require("Modul:scripts").charToScript
local concat = table.concat
local insert = table.insert
local new_title = mw.title.new
local u = require("Modul:string utilities").char

local general_category_aliases = general_category_data.long_names

local export = {}

local Unicode_version = "16.0"

local function get_block_from_pagename()
	local title = mw.title.getCurrentTitle()
	if title.namespace == 100 and title.baseText == "Unicode" and m_unicode.get_block_range(title.subpageText) then
		return title.subpageText
	end
end

local function get_block_parameter(block, err)
	local block_start, block_end = m_unicode.get_block_range(block)
	if not (block_start and block_end) then
		err("Blok Unicode yang diberikan salah")
	end
	return {block, block_start, block_end}
end

local function get_data_for_code_point_range(block_start, block_end, filterer)
	local cps = {}
	for cp = block_start, block_end do
		if not filterer or filterer(cp) then
			local data = {}
			data.aliases = m_uni_alias[cp]
			for _, item in ipairs { "name", "script", "category", "image", "image_emoji" } do
				data[item] = m_unicode["lookup_" .. item](cp)
			end
			data.cp = cp
			insert(cps, data)
		end
	end
	return cps
end

-- Copied from [[Modul:Unicode data]].
local function binary_range_search(codepoint, ranges)
	local low, mid, high
	low, high = 1, ranges.length or require "Modul:table".length(ranges)
	while low <= high do
		mid = math.floor((low + high) / 2)
		local range = ranges[mid]
		if codepoint < range[1] then
			high = mid - 1
		elseif codepoint <= range[2] then
			return range, mid
		else
			low = mid + 1
		end
	end
	return nil, mid
end

-- The data_module argument must be a table
-- with the fields "ranges" and "singles".
-- If all code points in the inclusive range between start_code_point and
-- end_code_point have the same property value in the data module, or no value,
-- return this value.
local function get_shared_value(start_code_point, end_code_point, data_module)
	local code_point = start_code_point
	local previous_value
	local singles, ranges = data_module.singles, data_module.ranges
	while code_point <= end_code_point do
		local singles_value = singles[code_point]
		if singles_value then
			if previous_value then
				if singles_value ~= previous_value then
					return nil
				end
			else
				previous_value = singles_value
			end
			code_point = code_point + 1
		else
			local range = binary_range_search(code_point, ranges)
			if range then
				if previous_value then
					if range[3] ~= previous_value then
						return nil
					end
				else
					previous_value = range[3]
				end
				code_point = range[2] + 1
			else
				code_point = code_point + 1
			end
		end
	end
	return previous_value
end

function export.show_blocks(frame)
	local required_num_param = {required = true, type = "number", allow_hex = true}
	local args = process_params(frame:getParent().args, {
		[1] = required_num_param,
		[2] = required_num_param,
	})

	local result = {}
	local start_codepoint, end_codepoint = args[1], args[2]
	
	insert(result, '{| class="wikitable" style="width: 100%;"\n! width="10%;" | Poin kode pertama\n! width="10%;" | Poin kode terakhir\n ! Nama blok\n')
	for _, name, block_start, block_end in m_unicode.enum_blocks() do
		if (block_start >= start_codepoint) and (block_end <= end_codepoint) then
			insert(result, (
				'|-\n|U+%04X\n|U+%04X\n|[[Lampiran:Unicode/%s|%s]]\n'
			):format(block_start, block_end, name, name))
		end
	end
	insert(result, "|}")
	
	return concat(result)
end

function export.show_header(frame)
	local parent = frame:getParent()
	local default_block = get_block_from_pagename()
	
	local block = process_params((parent and parent:getTitle() ~= mw.title.getCurrentTitle().fullText and parent or frame).args, {
		block = {
			required = not default_block,
			convert = get_block_parameter,
			default = default_block,
		},
	}).block

	local block_name, block_start, block_end = unpack(block)
	local names, i = {}
	
	for j, name in m_unicode.enum_blocks() do
		names[j] = name
		if block_name == name then
			i = j
		elseif i and j == i + 1 then
			break
		end
	end
	
	local function appendix_link(block_name, left_arrow)
		return block_name
			and ("'''[[Lampiran:Unicode/%s|%s %s]]'''")
				:format(
					block_name,
					left_arrow and "⟵" or block_name,
					left_arrow and block_name or "⟶")
					 
			or ""
	end
	
	local general_category =
		get_shared_value(block_start, block_end, general_category_data)
	local script = get_shared_value(block_start, block_end, script_data)
	
	local text = (
		'{| style="width: 100%%;"\n' ..
		' | style="width: 30%%; text-align: left;"   | %s\n' ..
		' | style="text-align: center;" | <h2>%s</h2>\n' ..
		' | style="width: 30%%; text-align: right;"  | %s\n' ..
		' |}\nHalaman ini mencantumkan karakter di blok “[http://unicode.org/charts/PDF/U%04X.pdf %s]” dari standar Unicode, versi ' ..
		Unicode_version .. '. Blok ini mencakup poin kode dari U+%04X ke U+%04X.\n' ..
 	'[[Kategori:Blok Unicode|%s]]' ..
	'[[Kategori:Blok %s| ]]'):format(
			appendix_link(names[i - 1], true),
			names[i],
			appendix_link(names[i + 1], false),
			block_start, names[i], block_start, block_end,
			names[i],
			names[i]
		)
	if general_category or script then
		text = text .. (' Semua karakter di blok ini ')
		local items = {}
		if general_category then
			insert(items, ('adalah milik [[w:en:General Category|General Category]] %s (%s).')
			:format(general_category, general_category_aliases[general_category]:gsub('_', ' ')))
		end
		if script then
			local alias = script_data.aliases[script]
			local Wikipedia_article
			local script_obj = require "Modul:scripts".getByCode(script)
			if script_obj then
				Wikipedia_article = script_obj:getWikipediaArticle()
			else
				Wikipedia_article = alias .. ' script'
			end
			insert(items, ('punya nilai [[w:en:Unicode script|Aksara]] %s ([[w:en:%s|%s]])')
				:format(script, Wikipedia_article, alias))
		end
		text = text .. concat(items, " dan ") .. "."
	end
	
	return text
end

function export.show(frame)
	local parent = frame:getParent()
	local num_param = {type = "number", allow_hex = true}
	
	local args = process_params((parent and parent:getTitle() ~= mw.title.getCurrentTitle().fullText and parent or frame).args, {
		[1] = num_param,
		[2] = num_param,
		block = {convert = get_block_parameter},
	})

	local result = {}
	
	local block_start, block_end
	if args.block then
		block_start, block_end = unpack(args.block, 2)
	elseif args[1] and args[2] then
		block_start, block_end = args[1], args[2]
	else
		block_start, block_end = m_unicode.get_block_range(get_block_from_pagename())
		if not block_start then
			error("Harus dalam bentuk blok Unicode atau rentang karakter")
		end
	end
	
	local function present_codepoint(codepoint)
		if not m_unicode.is_printable(codepoint) then
			local character = u(codepoint)
			local text = '<small>(tidak dapat ditampilkan)</small>'
			if new_title(character) then
				return "[[" .. character .. "|" .. text .. "]]"
			else
				return text
			end
		end
		
		local link_target = m_unicode.get_entry_title(codepoint)

		local display = ("%s&#%u;"):format(m_unicode.is_combining(codepoint) and "&#x25cc;" or "", codepoint)
		if m_unicode.is_whitespace(codepoint) then
			display = "]" .. display .. "["	
		end

		return
			(link_target and '[[:%s|<span class="character-sample %s">%s</span>]]'
			or '<!-- %s --><span class="character-sample %s">%s</span>'):format(
				link_target or "", char_to_script(codepoint), display
			)
	end
	
	local cps = get_data_for_code_point_range(block_start, block_end, m_unicode.is_assigned)
	
	local emoji_image_exists = false
	
	local submodule = math.floor(block_start / 0x1000)
	local image_module = ("Modul:Unicode data/images/%03X"):format(submodule)
	local emoji_image_module = ("Modul:Unicode data/emoji images/%03X"):format(submodule)
	if safe_require(emoji_image_module) then
		for _, data in ipairs(cps) do
			if data.image_emoji then
				emoji_image_exists = true
				break
			end
		end
	end
	
	insert(result, [=[
{| class="wikitable sortable"
! width="12%" data-sort-type="number" | Poin kode
]=]
	)
	if emoji_image_exists then
		insert(result, [=[
! width="5%"  | Gambar bergaya teks<br><sup>[[Special:EditPage/]=] .. image_module .. [=[|sunting]]</sup>
! width="5%"  | Gambar bergaya emoji<br><sup>[[Special:EditPage/]=] .. emoji_image_module .. [=[|sunting]]</sup>
]=]
		)
	else
		insert(result, [=[
! width="5%"  | Gambar<br><sup>[[Special:EditPage/]=] .. image_module .. [=[|sunting]]</sup>
]=]
		)
	end
	insert(result, [=[
! width="5%"  | Karakter
]=]
	)
	local all_with_same_general_category = Array(cps)
		:all(function(data) return data.category == cps[1].category end)
	local all_with_same_script = Array(cps)
		:all(function(data) return data.script == cps[1].script end)
	if not all_with_same_general_category then
		insert(result, ' ! [[w:en:General Category|Kategori<br />Umum]]\n')
	end
	if not all_with_same_script then
		insert(result, ' ! [[w:Script (Unicode)|Aksara]]\n')
	end
	insert(result, ' ! Nama\n')
	
	for _, data in ipairs(cps) do
		local alt_names = ""
		local cp = data.cp
		
		if data.aliases then
			local aliases = {
				["correction"  ] = {},
				["control"     ] = {},
				["alternate"   ] = {},
				["figment"     ] = {},
				["abbreviation"] = {},
			}
			
			for _, info in ipairs(data.aliases) do
				insert(aliases[info[1]], "<small>" .. info[2] .. "</small>")
			end
			
			for _, name in ipairs(aliases.alternate) do
				alt_names = alt_names .. (' aka %s'):format(name)
			end

			if #aliases.control > 0 then
				alt_names = alt_names .. '; control character name: ' .. concat(aliases.control, " or ")
			end

			for _, name in ipairs(aliases.correction) do
				alt_names = alt_names .. ('<br/>Corrected name: %s'):format(name)
			end
			
			for _, name in ipairs(aliases.figment) do
				alt_names = alt_names .. ('<br/>Figment name: %s'):format(name)
			end

			if #aliases.abbreviation > 0 then
				alt_names = alt_names .. ' (' .. concat(aliases.abbreviation, ", ") .. ')'
			end
		end

		local current_image, current_image_emoji
		if data.image then
			current_image = ('[[File:%s|40x35px]]'):format(data.image)
		else
			current_image = ''
		end
		if emoji_image_exists then
			if data.image_emoji then
				current_image_emoji = ('[[File:%s|40x35px]]'):format(data.image_emoji)
			else
				current_image_emoji = ''
			end
		end
		
		insert(result, (
			' |- id="U-%04X"\n' ..
			' | data-sort-value="%u" | U+%04X <small>(%u)</small>\n' ..
			' | %s \n'
		):format(
			cp, cp, cp, cp,
			current_image
		))
		if emoji_image_exists then
			insert(result, (
				' | %s \n'
			):format(
				current_image_emoji
			))
		end
		insert(result, (
			' | %s \n'
		):format(
			present_codepoint(cp),
			data.category .. '<br />(' ..
				general_category_aliases[data.category]:gsub('_', ' ') ..
				')'
		))
		if not all_with_same_general_category then
			insert(result, (' | %s<br />(%s) \n')
				:format(
					data.category,
					general_category_aliases[data.category]:gsub('_', ' ')))
		end
		if not all_with_same_script then
			insert(result, (' | %s<br />(%s) \n')
				:format(
					data.script,
					script_data.aliases[data.script]))
		end
		insert(result, (' | <small>%s</small>%s\n')
			:format(
				mw.text.nowiki(data.name),
				alt_names))
			
	end
	
	insert(result,
		' |}'
	)
	
	insert(result, require("Modul:TemplateStyles")("Template:character info/style.css"))

	return concat(result)
end

return export