Module:Story: Difference between revisions

From FictionBase
Links to genres, collections, and tags
Link author, publication, and year
Line 56: Line 56:
end
end


local function addField(meta, label, value, full)
local function addField(meta, label, value, full, ns)
value = trim(value)
value = trim(value)
if not value then return end
if not value then return end
if ns then
value = makeNsLink(ns, value) or value
end
local field = meta:tag("div"):addClass("story-field")
local field = meta:tag("div"):addClass("story-field")
if full then field:addClass("story-field-full") end
if full then field:addClass("story-field-full") end
Line 147: Line 152:


local meta = root:tag("div"):addClass("story-meta")
local meta = root:tag("div"):addClass("story-meta")
addField(meta, "Author", author)
addField(meta, "Author", author, false, "Author")
addField(meta, "Published in", publication)
addField(meta, "Published in", publication, false, "Publication")
addField(meta, "Year", year)
addField(meta, "Year", year, false, "Year")
addField(meta, "Words", words)
addField(meta, "Words", words)
addReadOnline(meta, args)
addReadOnline(meta, args)

Revision as of 08:35, 3 March 2026

Documentation for this module may be created at Module:Story/doc

local p = {}

local function trim(s)
	if s == nil then return nil end
	s = tostring(s)
	s = mw.text.trim(s)
	if s == "" then return nil end
	return s
end

local function split_semicolons(s)
	s = trim(s)
	if not s then return {} end
	local parts = mw.text.split(s, "%s*;%s*", false)
	local out = {}
	for _, part in ipairs(parts) do
		part = trim(part)
		if part then
			table.insert(out, part)
		end
	end
	return out
end

local function storeCargo(args)
	if not mw.ext.cargo then return end

	mw.ext.cargo.store("Stories", {
		Title = args.title,
		Author = args.author,
		Publication = args.publication,
		Year = tonumber(args.year),
		Words = tonumber((args.words or ""):gsub(",", ""):match(".*")),
		Logline = args.logline,
		Read1Site = args.read1_site,
		Read1URL = args.read1_url,
		Read1Access = args.read1_access,
		Read2Site = args.read2_site,
		Read2URL = args.read2_url,
		Read2Access = args.read2_access,
		Read3Site = args.read3_site,
		Read3URL = args.read3_url,
		Read3Access = args.read3_access,
		Genres = args.genres,
		Collections = args.collections,
		Tags = args.tags,
		Notes = args.notes
	})
end

local function makeNsLink(ns, label)
	label = trim(label)
	if not label then return nil end
	local target = mw.ustring.gsub(label, "%s+", "_")
	return string.format("[[%s:%s|%s]]", ns, target, label)
end

local function addField(meta, label, value, full, ns)
	value = trim(value)
	if not value then return end

	if ns then
		value = makeNsLink(ns, value) or value
	end

	local field = meta:tag("div"):addClass("story-field")
	if full then field:addClass("story-field-full") end
	field:tag("div"):addClass("story-label"):wikitext(label)
	field:tag("div"):addClass("story-value"):wikitext(value)
end

local function addMultiField(meta, label, raw, full, ns)
	local items = split_semicolons(raw)
	if #items == 0 then return end
	local field = meta:tag("div"):addClass("story-field")
	if full then field:addClass("story-field-full") end
	field:tag("div"):addClass("story-label"):wikitext(label)
	local val = field:tag("div"):addClass("story-value")
	for _, item in ipairs(items) do
		local wikitext = item
		if ns then
			wikitext = makeNsLink(ns, item) or item
		end
		val:tag("span"):addClass("story-chip"):wikitext(wikitext)
	end
end

local function normalizeAccess(access)
	access = trim(access)
	if not access then return nil end
	access = mw.ustring.lower(access)
	if access ~= "free" and access ~= "paid" then return nil end
	return access
end

local function addReadOnline(meta, args)
	local links = {}
	for i = 1, 3 do
		local url = trim(args["read" .. i .. "_url"])
		if url then
			local site = trim(args["read" .. i .. "_site"]) or ("Link " .. i)
			local access = normalizeAccess(args["read" .. i .. "_access"])
			table.insert(links, { url = url, site = site, access = access })
		end
	end
	if #links == 0 then return end

	local field = meta:tag("div"):addClass("story-field"):addClass("story-field-full")
	field:tag("div"):addClass("story-label"):wikitext("Read online")
	local val = field:tag("div"):addClass("story-value")
	for _, l in ipairs(links) do
		local row = val:tag("div"):addClass("story-link")
		row:wikitext("[" .. l.url .. " " .. l.site .. "]")
		if l.access then
			row:wikitext(" ")
			row:tag("span")
				:addClass("story-badge")
				:addClass("story-badge-" .. l.access)
				:wikitext(mw.language.getContentLanguage():ucfirst(l.access))
		end
	end
end

function p.main(frame)
	local args = frame:getParent() and frame:getParent().args or frame.args

	local title = trim(args.title) or ""
	local author = trim(args.author)
	local publication = trim(args.publication)
	local year = trim(args.year)
	local words = trim(args.words)
	local logline = trim(args.logline)
	local plot_summary = trim(args.plot_summary)
	local notes = trim(args.notes)

	local root = mw.html.create("div"):addClass("story-card")

	local header = root:tag("div"):addClass("story-header")
	header:tag("div"):addClass("story-title"):wikitext(title ~= "" and title or "Untitled")

	if author then
		local byline = "By " .. author
		if publication then
			byline = byline .. ", first published in " .. publication
		end
		header:tag("div"):addClass("story-byline"):wikitext(byline)
	end

	if logline then
		header:tag("div"):addClass("story-logline"):wikitext(logline)
	end

	local meta = root:tag("div"):addClass("story-meta")
	addField(meta, "Author", author, false, "Author")
	addField(meta, "Published in", publication, false, "Publication")
	addField(meta, "Year", year, false, "Year")
	addField(meta, "Words", words)
	addReadOnline(meta, args)

	-- Split-capable multi-value fields (semicolon-separated)
	addMultiField(meta, "Genres", args.genres, false, "Genre")
	addMultiField(meta, "Collections", args.collections, false, "Collection")
	addMultiField(meta, "Tags", args.tags, true, "Tag")

	if plot_summary then
		local section = root:tag("div"):addClass("story-section")
		section:tag("div"):addClass("story-section-title"):wikitext("Plot Summary")
		section:tag("div"):addClass("story-section-body"):wikitext(plot_summary)
	end

	if notes then
		local section = root:tag("div"):addClass("story-section")
		section:tag("div"):addClass("story-section-title"):wikitext("Notes")
		section:tag("div"):addClass("story-section-body"):wikitext(notes)
	end
	
	storeCargo(args)

	return tostring(root)
end

return p