Module:Cite source

local util_vars = require('Module:VarsUtil') --originally from https://thealchemistcode.fandom.com/wiki/Module:VarsUtil local util_link = require('Module:LinkUtil') local util_text = require('Module:TextUtil') local util_smw = require('Module:SMW') local cache = require('mw.ext.LuaCache') local PREFIX = 'SC_STORE_01-' local p = {} --p stands for package local h = {} --h stands for helper

-- from https://stackoverflow.com/a/7927877 under CC-BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/) - written by lhf (https://stackoverflow.com/users/107090/lhf) function h.tableInvert(t) local s={} for k,v in pairs(t) do    s[v]=k end return s end

--==========================================	Generating and saving citations	==========================================

function h.getAndFormatUnlinkedItems(args) --gets and formats data for items that are unlinked	in the infobox local data = {["anthology"] = "", ["writer"] = "", ["publisher"] = "", ["adapted from"] = "", ["network"] = ""} for key, val in pairs(data) do		if args[key] and args[key] ~= "" then local current = util_text.split(args[key], args["separator"]) if #current > 4 then data[key] = "" .. util_link.stripPipe(util_link.stripDab(current[1])) .. "" .. ", et al. " else for i = 1, #current do data[key] = data[key] .. "" .. util_link.stripPipe(util_link.stripDab(current[i])) .. "" if i == #current-1 then data[key] = data[key] .. " and " elseif i == #current then data[key] = data[key] else data[key] = data[key] .. ", "					end end end end end return data end

--not currently in use function h.getAndFormatIssuesText(args)	--formats issues text (similar concept as above but doesn't add links)	local issues = ""	if args["publication"] then		local current = util_text.split(args["publication"], args["separator"])		for i = 1, --

function h.getAndFormatSeriesText(args) -- making series text local series = "" if args["citation series"] then series = args["citation series"] elseif args["range"] then series = "" .. util_link.stripPipe(util_link.stripDab(args["range"])) .. "" elseif args["series"] then local overrides = mw.loadData("Module:Cite source/series overrides") if overrides[args["series"]] then series = overrides[args["series"]] else series = args["series"] end if args["season number"] then series = series .. " " .. "" .. string.lower(util_link.stripPipe(util_link.stripDab(args["season number"]))) .. "" end end return series end

function h.getReleaseYearText(args) -- get and format release year local releaseYearText = "" if args["release date"] or args["broadcast date"] or args["premiere"] or args["beta release date"] or args["cover date"] then args["release date"] = util_text.split(util_link.stripDab(args["release date"] or args["broadcast date"] or args["premiere"] or args["beta release date"] or args["cover date"]), "-") local releaseYear local releaseEndYear if #args["release date"] >= 2 then releaseYear = args["release date"][1]:gsub("%s+", ""):sub(-4) releaseEndYear = args["release date"][2]:gsub("%s+", ""):sub(-4) if tonumber(releaseEndYear) == nil then releaseEndYear = nil end if tonumber(releaseYear) == nil then releaseYear = releaseEndYear releaseEndYear = nil end else releaseYear = args["release date"][1]:gsub("%s+", ""):sub(-4) end if releaseEndYear and releaseYear and (releaseEndYear ~= releaseYear) then releaseYearText = releaseYearText .. "" .. releaseYear .."-" .. releaseEndYear .. "" else releaseYearText = "" .. releaseYear .."" end end return releaseYearText end

function h.makeOutput(data, args) -- making outputText local outputText = "" if data["writer"] ~= "" then outputText = outputText .. data["writer"] .. ", "		if data["adapted from"] ~= "" then outputText = outputText .. "adapted from ''" .. data["adapted from"] .. "''"			local originalWriter = mw.smw.ask( "" .. util_link.stripPipe(args["adapted from"]) .. "" .. "\n|?Writer")[1]["Writer"] or "" if originalWriter ~= "" then outputText = outputText .. " (" .. originalWriter .. ")" end outputText = outputText .. ", "		end elseif data["adapted from"] ~= "" then outputText = outputText .. "adapted from ''" .. data["adapted from"] .. "''"		local originalWriter = mw.smw.ask( "" .. util_link.stripPipe(args["adapted from"]) .. "" .. "\n|?Writer")[1]["Writer"] or "" if originalWriter ~= "" then outputText = outputText .. " (" .. originalWriter .. ")" end outputText = outputText .. ", "	end local KEYS = {"series", "anthology", "publisher", "network", "release year"} local loopData = {} for _, key in pairs(KEYS) do		if data[key] and data[key] ~= "" then if key == "anthology" then table.insert(loopData, ""..data[key].."") else table.insert(loopData, data[key]) end end end if loopData[1] then outputText = outputText .. loopData[1] if loopData[2] then outputText = outputText .. " (" .. loopData[2]			if loopData[3] then				outputText = outputText .. ", " .. loopData[3]				if loopData[4] then					outputText = outputText .. ", " .. loopData[4]					if loopData[5] then						outputText = outputText .. ", " .. loopData[5]					end				end			end			outputText = outputText ..")" end end --fallback in case of an error if outputText == "" or outputText == nil then outputText = "Error: code 1 - data table empty." else outputText = outputText .. "."	end return outputText end

function h.storeText(outputText, name) util_vars.setVar(PREFIX .. name, outputText) cache.delete(PREFIX .. name) cache.set(PREFIX .. name, outputText) mw.smw.set({["Story info"] = outputText}) end

function p.infoboxStore( frame ) local args = frame:getParent.args local name = frame.args[1] if args["citation text"] then outputText = args["citation text"] else if not args["separator"] then args["separator"] = "," end -- combines and if args["anthology"] and args["audio anthology"] then args["anthology"] = args["anthology"] .. ", " .. args["audio anthology"] elseif (not args["anthology"]) and args["audio anthology"] then args["anthology"] = args["audio anthology"] end -- combines and if args["adapted from"] and args["novelisation of"] then args["adapted from"] = args["adapted from"] .. ", " .. args["novelisation of"] elseif (not args["adapted from"]) and args["novelisation of"] then args["adapted from"] = args["novelisation of"] end local data = h.getAndFormatUnlinkedItems(args) --data["issues"] = h.getAndFormatIssuesText(args) not currently in use data["series"] = h.getAndFormatSeriesText(args) data["release year"] = h.getReleaseYearText(args) for key, val in pairs(data) do util_vars.setVar(PREFIX .. name .. "-" .. key, val) end if args["adapted from"] and args["adapted from"] ~= "" then util_vars.setVar(PREFIX .. name .. "-adapted from arg", args["adapted from"]) end local outputText = h.makeOutput(data, args) --outputText = util_smw.dump(data) --for testing h.storeText(outputText, name) end end

function p.variantStore(frame) local args = frame:getParent.args local name = frame.args[1] if args["citation text"] then outputText = args["citation text"] else if not args["separator"] then args["separator"] = "," end -- combines and if args["anthology"] and args["audio anthology"] then args["anthology"] = args["anthology"] .. ", " .. args["audio anthology"] elseif (not args["anthology"]) and args["audio anthology"] then args["anthology"] = args["audio anthology"] end -- combines and if args["adapted from"] and args["novelisation of"] then args["adapted from"] = args["adapted from"] .. ", " .. args["novelisation of"] elseif (not args["adapted from"]) and args["novelisation of"] then args["adapted from"] = args["novelisation of"] end -- combines and if args["release year"] and args["release year"] ~= "" then args["release date"] = args["release year"] end local variantData = h.getAndFormatUnlinkedItems(args) --variantData["issues"] = h.getAndFormatIssuesText(args) not currently in use variantData["series"] = h.getAndFormatSeriesText(args) variantData["release year"] = h.getReleaseYearText(args) local data = {["anthology"] = "", ["writer"] = "", ["publisher"] = "", ["adapted from"] = "", ["network"] = "", ["series"] = "", ["release year"] = ""} for key, val in pairs(data) do data[key] = util_vars.getVar(PREFIX .. name .. "-" .. key) or "" end local origArgs = {} if util_vars.getVar(PREFIX .. name .. "-adapted from arg") then origArgs["adapted from"] = util_vars.getVar(PREFIX .. name .. "-adapted from arg") end data["variant"] = args["variant"] or "variant" --data["original"] = args["original"] or ("" .. util_link.stripPipe(util_link.stripDab(name)) .. "") local outputText = string.upper(string.sub(data["variant"], 1, 1)) .. string.sub(data["variant"], 2) if variantData["release year"] and variantData["release year"] ~= "" then outputText = outputText .. " from " .. variantData["release year"] end -- maybe add other variant data here? outputText = outputText .. ", " .. h.makeOutput(data, origArgs) h.storeText(outputText, name .. "-" .. data["variant"]) end end

--==========================================	Displaying citations	==========================================

function h.generatePreciseCite(args) local preciseCite = "" if args["precisecite"] and args["precisecite"] ~= "" then preciseCite = " " .. args["precisecite"] else local info = {["edition"] = "", ["chapter"] = "", ["page"] = "", ["timestamp"] = ""} if args["ed"] and args["ed"] ~= "" then info["edition"] = " Edition: " .. args["ed"] end if args["chapt"] and args["chapt"] ~= "" then info["chapter"] = " Chapter: " .. args["chapt"] elseif args["chaptnum"] and args["chaptnum"] ~= "" then if string.match(args["chaptnum"], "-") or string.match(args["chaptnum"], ",") or string.match(args["chaptnum"], "&") or string.match(args["chaptnum"], "and") then info["chapter"] = " Chapters " .. args["chaptnum"] else info["chapter"] = " Chapter " .. args["chaptnum"] end if args["chaptname"] and args["chaptname"] ~= "" then info["chapter"] = info["chapter"] .. ", \"" .. args["chaptname"] .. "\"" end end if args["page"] and args["page"] ~= "" then if string.match(args["page"], "-") or string.match(args["page"], ",") or string.match(args["page"], "&") or string.match(args["page"], "and") then info["page"] = " Pages " .. args["page"] else info["page"] = " Page " .. args["page"] end end if args["timestamp"] and args["timestamp"] ~= "" then info["timestamp"] = " Timestamp " .. args["timestamp"] else local timestamp = {["hour"] = "", ["minute"] = "", ["second"] = ""} if args["hour"] and args["hour"] ~= "" then timestamp["hour"] = args["hour"] end if args["minute"] and args["minute"] ~= "" then timestamp["minute"] = args["minute"] end if args["second"] and args["second"] ~= "" then timestamp["second"] = args["second"] end if timestamp["second"] ~= "" or timestamp["minute"] ~= "" or timestamp["hour"] ~= "" then info["timestamp"] = " Timestamp" for key, val in pairs(timestamp) do					if val ~= "" then info["timestamp"] = info["timestamp"] .. " " .. val:lower .. " " .. key if not(val:lower == "1" or val:lower == "one") then info["timestamp"] = info["timestamp"] .. "s" end end end end end for _, val in pairs(info) do			if val ~= "" then preciseCite = preciseCite .. val .. ";"			end end preciseCite = preciseCite:sub(1, -2) end return preciseCite end

function h.getInfo(story, variant) local info local dataStore = story if variant and variant ~= "" then dataStore = story .. "-" .. variant end if util_vars.getVar(PREFIX .. dataStore) then info = util_vars.getVar(PREFIX .. dataStore) elseif cache.get(PREFIX .. dataStore) then info = cache.get(PREFIX .. dataStore) util_vars.setVar(PREFIX .. dataStore, info) elseif mw.smw.ask( "" .. story .. "" .. "\n|?Story info")[1]["Story info"] then smwResult = mw.smw.ask( "" .. story .. "" .. "\n|?Story info")[1]["Story info"] if type(smwResult) == "table" then if variant and variant ~= "" then if #smwResult == 2 then info = smwResult[2] util_vars.setVar(PREFIX .. dataStore, info) cache.set(PREFIX .. dataStore, info) else info = "Error: Code 4 - no data in variables or cache and SMW returned information for multiple variants, the one required here not being clear." -- at the moment, this code is being a bit lazy. It is theoretically possible to get an actual output here, but it would require trying to find the correct story info value for the requested variant which is hard. It is believed that this situation will not come up commonly enough for this to be an issue. end else info = smwResult[1] util_vars.setVar(PREFIX .. dataStore, info) cache.set(PREFIX .. dataStore, info) end elseif type(smwResult) == "string" and not(variant and variant ~= "") then info = smwResult util_vars.setVar(PREFIX .. dataStore, info) cache.set(PREFIX .. dataStore, info) else info = "Error: Code 2 - no data stored in variables, cache or SMW." end else info = "Error: Code 2 - no data stored in variables, cache or SMW." end return info end

function p.displayCitation(frame) local args = frame:getParent.args local finishedCitation = "" local usingNamedPageCitation = false if args["name"] and args["name"] ~= "" then if util_vars.getVar(PREFIX .. "NAMED-PAGE-CITATION" .. args["name"]) then finishedCitation = util_vars.getVar(PREFIX .. "NAMED-PAGE-CITATION" .. args["name"]) usingNamedPageCitation = true end end if usingNamedPageCitation == false then if not args[1] or args[1] == "" then return "Error: code 3 - no story given in template transclusion." end local story = args[1] local additionalDisplay = "" local section = "" local variant = "" if args["var"] and args["var"] ~= "" then variant = args["var"] additionalDisplay = additionalDisplay .. " (" .. args["var"]			if args["sect"] and args["sect"] ~= "" then				section = "#" .. args["sect"]				if args["part"] and args["part"] ~= "" then					additionalDisplay = additionalDisplay .. ", part " .. string.lower(args["part"]) 				elseif args["ep"] and args["ep"] ~= "" then					additionalDisplay = additionalDisplay .. ", episode  " .. string.lower(args["ep"])				end				additionalDisplay = additionalDisplay .. ")" elseif args["namedep"] and args["namedep"] ~= "" then section = "#" .. args["namedep"] additionalDisplay = additionalDisplay .. ")"			elseif args["part"] and args["part"] ~= "" then				section = "#Part " .. args["part"]				additionalDisplay = additionalDisplay .. ", part " .. string.lower(args["part"]) .. ")" elseif args["ep"] and args["ep"] ~= "" then section = "#Episode " .. args["ep"] additionalDisplay = additionalDisplay .. ", episode " .. string.lower(args["ep"]) .. ")"			else				additionalDisplay = additionalDisplay .. ")" end else if args["sect"] and args["sect"] ~= "" then section = "#" .. args["sect"] if args["part"] and args["part"] ~= "" then additionalDisplay = additionalDisplay .. " (part " .. string.lower(args["part"]) .. ")" elseif args["ep"] and args["ep"] ~= "" then additionalDisplay = additionalDisplay .. " (episode " .. string.lower(args["ep"]) .. ")" end elseif args["namedep"] and args["namedep"] ~= "" then section = "#" .. args["namedep"] elseif args["part"] and args["part"] ~= "" then section = "#Part " .. args["part"] additionalDisplay = additionalDisplay .. " (part " .. string.lower(args["part"]) .. ")" elseif args["ep"] and args["ep"] ~= "" then section = "#Episode " .. args["ep"] additionalDisplay = additionalDisplay .. " (episode " .. string.lower(args["ep"]) .. ")" elseif args["marker"] and args["marker"] ~= "" then section = "#Marker " .. args["marker"] if not args["notital"] or args["notital"] == "" then additionalDisplay = additionalDisplay .. ": "				end additionalDisplay = additionalDisplay .. "Marker " .. string.lower(args["marker"]) end end local preciseCite = h.generatePreciseCite(args) local display = "" local quote = "" local ital = "''" local pretext = "" if args["noital"] and args["noital"] ~= "" then ital = "" end if args["notital"] and args["notital"] ~= "" then display = additionalDisplay elseif args["namedep"] and args["namedep"] ~= "" then display = util_link.stripDab(args["namedep"]) quote = "\""			pretext = pretext .. "Part of " .. ital .. util_link.stripDab(story) .. ital .. additionalDisplay .. ", "		elseif args["namedpart"] and args["namedpart"] ~= "" then			display = util_link.stripDab(args["namedpart"])			quote = "\"" pretext = pretext .. "Part of " .. ital .. util_link.stripDab(story) .. ital .. additionalDisplay .. ", " elseif args[2] and args[2] ~= "" then display = ital .. args[2] .. ital else display = ital .. util_link.stripDab(story) .. ital .. additionalDisplay end if args["quote"] and args["quote"] ~= "" then quote = "\""		end		local collapsibleText = ""		if args["citationtext"] and args["citationtext"] ~= "" then			collapsibleText = args["citationtext"]		else			local main = ""			if not(args["noinfo"] and args["noinfo"] ~= "") then				local overideArgs = {["anthology"] = "", ["writer"] = "", ["publisher"] = "", ["adapted from"] = "", ["network"] = "", ["release date"] = "", ["series"] = ""}				args["release date"] = args["release year"] or ""				local overides = false				for key, val in pairs(overideArgs) do					if args[key] and args[key] ~= "" then						overideArgs[key] = args[key]						overides = true					end				end				if overides then					overideArgs["separator"] = args["separator"] or ","					local smwQuery = "\[\[" .. args[1] .. "\]\]"					local SMWPROPS = {["anthology"] = "Anthology", ["writer"] = "Writer", ["publisher"] = "Publisher", ["adapted from"] = "Adapted from", ["network"] = "Premiere network", ["release date"] = "Release date", ["series"] = "Series"} local SMWPROPSINVERSE = h.tableInvert(SMWPROPS) for key, val in pairs(overideArgs) do						if val == "" then smwQuery = smwQuery .. "\n|?" .. SMWPROPS[key] if key == "release date" then smwQuery = smwQuery .. "\n|?Release end date" end end end local smwResult = mw.smw.ask(smwQuery)[1] table.remove(smwResult, 1) local UNLINKEDVALUES = {["Anthology"] = true, ["Writer"] = true, ["Publisher"] = true, ["Adapted from"] = true, ["Premiere network"] = true} for key, val in pairs(smwResult) do						if type(val) == "table" then local list = "" for _, item in pairs(smwResult) do								if UNLINKEDVALUES[key] then if util_link.stripLink(item):sub(1,1) == ":" then list = list .. overideArgs["separator"] .. util_link.stripLink(item):sub(2) else list = list .. overideArgs["separator"] .. util_link.stripLink(item) end else list = list .. overideArgs["separator"] .. item end end overideArgs[SMWPROPSINVERSE[key]] = list or "" else if UNLINKEDVALUES[key] then if util_link.stripLink(val):sub(1,1) == ":" then overideArgs[SMWPROPSINVERSE[key]] = util_link.stripLink(val):sub(2) or "" else overideArgs[SMWPROPSINVERSE[key]] = util_link.stripLink(val) or "" end elseif key == "Release date" then overideArgs["release date"] = util_text.split(val, "-")[1] elseif key == "Release end date" then overideArgs["release date"] = overideArgs["release date"] .. " - " .. util_text.split(val, "-")[1] else overideArgs[SMWPROPSINVERSE[key]] = val or "" end end end local data = h.getAndFormatUnlinkedItems(overideArgs) --data["issues"] = h.getAndFormatIssuesText(overideArgs) not currently in use data["series"] = h.getAndFormatSeriesText(overideArgs) data["release year"] = h.getReleaseYearText(overideArgs) main = h.makeOutput(data, overideArgs) else -- this is what happens in the majority of cases main = h.getInfo(story, variant) end collapsibleText = pretext .. main .. preciseCite else collapsibleText = preciseCite end end if collapsibleText ~= "" then if collapsibleText:sub(-1) ~= "." then collapsibleText = collapsibleText .. "."			end finishedCitation = quote .. "" .. display .. "" .. quote .. " [+] " .. collapsibleText .. " "		else finishedCitation = quote .. "" .. display .. "" .. quote end if args["name"] and args["name"] ~= "" then util_vars.setVar(PREFIX .. "NAMED-PAGE-CITATION" .. args["name"], finishedCitation) end if args["wikitextoutput"] and args["wikitextoutput"] ~= "" then finishedCitation = frame:preprocess(" " .. finishedCitation .. " ") end end return finishedCitation end

return p