コンテンツにスキップ

モジュール:分註

提供: Wikisource
モジュールの解説[表示] [編集] [履歴] [キャッシュを破棄]

テンプレート {{分註}} の表示処理を担当する Lua モジュールです。

上段・下段の文字列をもとに、分注または組み文字HTML 構造を生成します。


type の正規化、括弧生成、ARIA 属性付与、|type = unknown の警告処理など表示ロジックは本モジュールが担当します。

設定値は Module:分註/config に分離しています。

-- Module:分註
-- 
-- 本モジュールは、分注(上下に並べた注記)および組み文字を統一した形式で描画
-- するための処理を提供します。
-- 主にテンプレートから {{#invoke:分註|main}} として呼び出され、HTML を構築し
-- て返します。
-- 
-- 設定値は Module:分註/config に集約されています。

require('strict')

local cfg     = require('Module:分註/config')
local yesno   = require('Module:Yesno')
local getArgs = require('Module:Arguments').getArgs

local p = {}

----------------------------------------------------------------------
-- Bunchu "class"
----------------------------------------------------------------------
local Bunchu = {}
Bunchu.__index = Bunchu

----------------------------------------------------------------------
-- 名前空間名を ID に変換するヘルパー
-- (canonicalName または name でマッチ)
----------------------------------------------------------------------
local function resolveNamespaceId(key)
	if type(key) ~= "string" then
		return nil
	end

	local lower = mw.ustring.lower(mw.text.trim(key))

	-- Main 名前空間だけ 0 扱いにする
	if lower == "main" then
		return 0
	end

	-- それ以外は name / canonicalName で総当たり
	for id, info in pairs(mw.site.namespaces) do
		local name  = info.name
		local canon = info.canonicalName

		if name and mw.ustring.lower(name) == lower then
			return id
		end
		if canon and mw.ustring.lower(canon) == lower then
			return id
		end
	end

	return nil
end

----------------------------------------------------------------------
-- 名前空間名リストを ID の集合に変換するヘルパー
-- (canonicalName または name でマッチ)
----------------------------------------------------------------------
local allowedNamespaceIds

local function getAllowedNamespaceIds()
	if allowedNamespaceIds then
		return allowedNamespaceIds
	end

	local resolved = {}
	local list = cfg.allowedNamespaces

	if type(list) == "table" then
		for _, key in ipairs(list) do
			local id = resolveNamespaceId(key)
			if id then
				resolved[id] = true
			else
				mw.addWarning(cfg.warningUnknownNamespace .. tostring(key))
			end
		end
	end

	allowedNamespaceIds = resolved
	return resolved
end


----------------------------------------------------------------------
-- normalizeType
----------------------------------------------------------------------
--[[
	正規化された type 名を返す関数。
	ユーザー入力のゆらぎ(大文字混在、表記揺れ、和名など)を cfg.typeAliases
	に基づいて吸収する。

	@param raw string|nil
	@return string  canonical type ("bunchu", "kumimoji", "unknown")
]]
function Bunchu.normalizeType(raw)
	if not raw or raw == "" then
		return "unknown"
	end

	local v = mw.ustring.lower(tostring(raw))
	v = mw.text.trim(v)
	v = v:gsub("[_%-/]", "")
	v = v:gsub("%s+", "")

	for canonical, aliases in pairs(cfg.typeAliases) do
		for _, alias in ipairs(aliases) do
			if v == alias then
				return canonical
			end
		end
	end

	return "unknown"
end

----------------------------------------------------------------------
-- Constructor
----------------------------------------------------------------------
--[[
	インスタンス生成。

	@param args table Module:Arguments により取得した引数テーブル
	@return Bunchu インスタンス
]]
function Bunchu.new(args)
	local self = setmetatable({}, Bunchu)

	self.text1 = args[1] or ""
	self.text2 = args[2] or ""

	self.rawType = args.type
	self.type = Bunchu.normalizeType(self.rawType)

	-- bracket の明示指定判定
	self.bracketRaw = args.bracket
	local bracketGiven = self.bracketRaw ~= nil

	-- 明示指定があればそれを優先、ないときは、type == "bunchu"だけ
	-- デフォルトで括弧あり
	if bracketGiven then
		self.bracket = yesno(self.bracketRaw) or false
	else
		self.bracket = (self.type == "bunchu")
	end
	-- 括弧は分注 (type = bunchu) のみ使用する仕様。
	-- 他のtypeでは bracket = yes と指定されても括弧は表示しない。
	self.bracketEffective = self.bracket and (self.type == "bunchu")

	self.size       = args.size
	self.extraStyle = args.style

	return self
end

----------------------------------------------------------------------
-- HTML build methods
----------------------------------------------------------------------

-- span wrapper
function Bunchu:buildRoot()
	self.root = mw.html.create("span")
	self.root:addClass("wst-bunchu")
	return self.root
end

-- data-* と aria-* 属性設定
function Bunchu:applySemanticAttributes()
	self.root:attr("data-wst-bunchu-type", self.type)

	-- ARIA label
	local aria = cfg.ariaLabels[self.type]
	if aria then
		self.root:attr("aria-label", aria)
	end
	
	-- ARIA role
	local role = cfg.ariaRole[self.type]
	if role then
		self.root:attr("role", role)
	end
end

-- style 属性構築
function Bunchu:applyStyle()
	local parts = {}

	if self.size then
		table.insert(parts, "font-size:" .. self.size .. ";")
	end
	if self.extraStyle then
		table.insert(parts, self.extraStyle)
	end

	if #parts > 0 then
		self.root:cssText(table.concat(parts, " "))
	end
end

-- 括弧(左)
function Bunchu:addInlineStartBracketIfNeeded()
	if not self.bracketEffective then return end
	local inlineStart = self.root:tag("span")
	inlineStart:addClass("wst-bunchu-col wst-bunchu-bracket-inline-start")
	inlineStart:attr("role", "none")
	inlineStart:tag("span"):wikitext("⎛")
	inlineStart:tag("span"):wikitext("⎝")
end

-- 上下テキスト
function Bunchu:addText()
	local col = self.root:tag("span")
	col:addClass("wst-bunchu-col wst-bunchu-text")
	col:tag("span"):wikitext(self.text1)
	col:tag("span"):wikitext(self.text2)
end

-- 括弧(右)
function Bunchu:addInlineEndBracketIfNeeded()
	if not self.bracketEffective then return end
	local inlineEnd = self.root:tag("span")
	inlineEnd:addClass("wst-bunchu-col wst-bunchu-bracket-inline-end")
	inlineEnd:attr("role", "none")
	inlineEnd:tag("span"):wikitext("⎞")
	inlineEnd:tag("span"):wikitext("⎠")
end

----------------------------------------------------------------------
-- finalizeOutput
----------------------------------------------------------------------
--[[
	unknown の場合の警告表示と追跡カテゴリ付加。

	@param html string
	@return string
]]
function Bunchu:finalizeOutput(html)
	if self.type == "unknown" then
		-- プレビュー時にのみ表示される警告
		mw.addWarning(cfg.warningUnknownType)

		-- 許可された名前空間でのみ追跡カテゴリを付与
		local title = mw.title.getCurrentTitle()
		local allowed = getAllowedNamespaceIds()
		if allowed[title.namespace] then
			html = html .. "[[Category:" .. cfg.trackingCategoryUnknown .. "]]"
		end
	end

	return html
end

----------------------------------------------------------------------
-- render
----------------------------------------------------------------------
--[[
	最終的な HTML を構築する。
	TemplateStyles の読み込みもここで行う。

	@return string HTML
]]
function Bunchu:render()
	self:buildRoot()
	self:applySemanticAttributes()
	self:applyStyle()
	self:addInlineStartBracketIfNeeded()
	self:addText()
	self:addInlineEndBracketIfNeeded()

	local html = tostring(self.root)

	local styleTag = mw.getCurrentFrame():extensionTag(
		'templatestyles',
		'',
		{ src = cfg.styles }
	)

	html = styleTag .. html
	return self:finalizeOutput(html)
end

----------------------------------------------------------------------
-- Entry point
----------------------------------------------------------------------
--[[
	#invoke から呼び出されるエントリポイント。

	@param frame table
	@return string
]]
function p.main(frame)
	local args = getArgs(frame)
	local obj  = Bunchu.new(args)
	return obj:render()
end

return p