Module:Dialogue
Jump to navigation
Jump to search
This module implements {{Dialogue}}.
local p = {}
function p.formatBlock(frame)
local lines = mw.text.split(frame.args[1] or "", "\n")
local output = ""
local lastSpeaker = nil
local inContainer = false
local inOptionResponse = false
local inSpeakerBlock = false
for _, line in ipairs(lines) do
line = mw.text.trim(line)
-- Skip empty lines
if line == "" then
-- Do nothing
-- Check if this is an end-of-option delimiter
elseif line == "---" or line == "–––" or line == "—" then
-- Close any open containers
if inContainer then
output = output .. "</div>\n"
inContainer = false
end
if inSpeakerBlock then
output = output .. "</div>\n"
inSpeakerBlock = false
end
-- Reset state
lastSpeaker = nil
inOptionResponse = false
-- Check if this is a wikitext header (skip processing, pass through)
elseif line:match("^==+.+==+$") then
-- Close any open containers before the header
if inContainer then
output = output .. "</div>\n"
inContainer = false
end
if inSpeakerBlock then
output = output .. "</div>\n"
inSpeakerBlock = false
end
-- Pass the header through as-is
output = output .. line .. "\n"
-- Reset state
lastSpeaker = nil
inOptionResponse = false
-- Check if this is a dialogue option (starts with >)
elseif line:match("^>%s*(.+)$") then
local optionText = line:match("^>%s*(.+)$")
-- Close any open speaker containers before showing options
if inContainer then
output = output .. "</div>\n"
inContainer = false
end
if inSpeakerBlock then
output = output .. "</div>\n"
inSpeakerBlock = false
end
-- Add the dialogue option with visible >
output = output .. "<div class='dialogue-option'>'''>''' " .. optionText .. "</div>\n"
-- Reset last speaker and mark that we're now in option response mode
lastSpeaker = nil
inOptionResponse = true
else
-- Match "Speaker: text" format
local speaker, text = line:match("^(.-):%s*(.+)$")
if speaker and text then
speaker = mw.text.trim(speaker)
text = mw.text.trim(text)
-- Remove bold markup (''') from speaker name
speaker = speaker:gsub("'''", "")
speaker = mw.text.trim(speaker)
-- Check if we have a new speaker
if speaker ~= lastSpeaker then
-- Close previous speaker's containers if they exist
if inContainer then
output = output .. "</div>\n"
inContainer = false
end
if inSpeakerBlock then
output = output .. "</div>\n"
inSpeakerBlock = false
end
-- Determine if this should be indented (response to option)
local blockClass = inOptionResponse and "dialogue-speaker-block dialogue-speaker-block-indented" or "dialogue-speaker-block"
-- Start new speaker block
output = output .. "<div class='" .. blockClass .. "'>\n"
inSpeakerBlock = true
-- Add new speaker name
output = output .. "<div class='dialogue-speaker'>'''" .. speaker .. "'''</div>\n"
-- Start new dialogue container
output = output .. "<div class='dialogue-container'>\n"
lastSpeaker = speaker
inContainer = true
-- Reset option response flag after first response
inOptionResponse = false
end
-- Add the dialogue line
output = output .. "<div class='dialogue-line'>" .. text .. "</div>\n"
else
-- Line without a speaker - close any open containers first
if inContainer then
output = output .. "</div>\n"
inContainer = false
end
if inSpeakerBlock then
output = output .. "</div>\n"
inSpeakerBlock = false
end
-- Display as a standalone dialogue line
output = output .. "<div class='dialogue-line dialogue-line-standalone'>" .. line .. "</div>\n"
-- Reset state
lastSpeaker = nil
inOptionResponse = false
end
end
end
-- Close any open containers
if inContainer then
output = output .. "</div>\n"
end
if inSpeakerBlock then
output = output .. "</div>\n"
end
return output
end
return p