Module:Quotations
Documentation for this module may be created at Module:Quotations/doc
local m_scriptutils = require("Module:script utilities")
local m_utilities = require("Module:utilities")
local date_validation = require("Module:Quotations/date validation")
local loadModule = nil -- essentially a forward-declaration
local export = {}
function export.create(frame)
local passed = true
local results = ''
passed, results = pcall(export.Create, frame)
if passed then
return results
else
return '<span class="wiktQuote" data-validation="red" style="display:none">'..results..'</span>'
end
end
function export.Create(frame)
--Set up our initial variables.
local args = frame:getParent().args
--Set empty tags to false
for k,v in pairs(args) do
if v == '' then
args[k] = false
end
end
local codedLangs = {['grc'] = true, ['la'] = true, ['xcl'] = true}
local lang = args[1]; if lang == "" then lang = nil end
lang = require("Module:languages").getLanguageByCode(lang)
local ante = {}
if codedLangs[lang:getCode()] then
local m_langModule = loadModule(lang)
ante = m_langModule.expand(args)
else
ante.author = args[2]
ante.work = args[3]
ante.ref = ''
local dot = false
for i=4, 10 do
if args[i] then
ante.ref = ante.ref..(dot and '.' or '')..args[i]
dot = true
else
break
end
end
for k,v in pairs(args) do
if type(k) ~= 'number' then
ante[k] = args[k]
end
end
end
local penult = {['year'] = '', ['author'] = '', ['work'] = '', ['ref'] = '',
['notes'] = '', ['otherLines'] = '', ['s1'] = '', ['s2'] = '',
['s3'] = '', ['s4'] = ''}
local comma = false
--Language specific modules are responsible for first line parameters.
--Base formatting module will poll for other parameters,
--pulling them only if the language module hasn't returned them.
local otherOtherLineStuff = {'quote', 'transyear', 'transauthor', 'trans'}
for i=1, 4 do
ante[otherOtherLineStuff[i]] = ante[otherOtherLineStuff[i]] or args[otherOtherLineStuff[i]]
end
if not ante.code then
penult.elAttr = ' class="wiktQuote" data-validation="white">'
else
penult.elAttr = ' class="wiktQuote" data-validation="'..ante.code..'">'
end
if ante.year then
penult.year = "'''"..date_validation.main(ante.year).."'''"
comma = true
end
if ante.author then
penult.s1 = (comma and ', ' or '')
penult.author = ante.author
comma = true
end
if ante.work then
penult.s2 = (comma and ', ' or '')
penult.work = "''"..ante.work.."''"
comma = true
end
if ante.ref then
penult.s3 = (comma and ' ' or '')
penult.ref = ante.ref
end
if ante.notes then
penult.s4 = (comma and', ' or '')
penult.notes = '('..ante.notes..')'
end
if ante.quote or ante.trans then
penult.otherLines = '<dl><dd>'
if ante.quote then
local sc, scFix = m_utilities.detect_script(ante.quote, lang)
penult.otherLines = penult.otherLines..m_scriptutils.tag_text(ante.quote, lang, sc)
end
if ante.trans then
if ante.transyear or ante.transauthor then
penult.otherLines = penult.otherLines..'<ul><li>'
if ante.transyear then
penult.otherLines = penult.otherLines.."'''"..ante.transyear.."''' translation"
else
penult.otherLines = penult.otherLines..'Translation'
end
if ante.transauthor then
penult.otherLines = penult.otherLines..' by '..ante.transauthor
end
penult.otherLines = penult.otherLines..'<dl><dd>'..ante.trans..'</dd></dl></li></ul>'
else
if not ante.quote then
penult.otherLines = penult.otherLines..ante.trans
else
penult.otherLines = penult.otherLines..'<dl><dd>'..ante.trans..'</dd></dl>'
end
end
end
penult.otherLines = penult.otherLines..'</dl></dd>'
end
local form = args['form'] or 'full'
if form == 'full' then
ultimate = '<div'..penult.elAttr..penult.year..penult.s1..penult.author..penult.s2..penult.work..penult.s3..penult.ref..penult.s4..penult.notes..penult.otherLines..'</div>'
elseif form == 'inline' then
ultimate = '<span'..penult.elAttr..penult.author..penult.s2..penult.work..penult.s3..penult.ref..'</span>'
elseif form == 'work' then
ultimate = '<span'..penult.elAttr..penult.work..penult.s3..penult.ref..'</span>'
elseif form == 'ref' then
ultimate = '<span'..penult.elAttr..penult.ref..'</span>'
end
return ultimate
end
function loadModule(lang)
local sema = require('Module:Quotations/' .. lang:getCode())
sema.library = sema.library or mw.loadData("Module:Quotations/" .. lang:getCode() .. "/data")
sema.changeCode = sema.changeCode or function(color)
if color == 'orange' then
sema.code = 'orange'
end
if (color == 'yellow') and (sema.code == 'green') then
sema.code = 'yellow'
end
end
sema.reroute = sema.reroute or function(route)
local temp = {}
local data = sema.library.data
for k,v in pairs(route) do
temp[k] = sema.interpret(v)
end
for k, v in pairs(temp) do
sema[k] = v
end
if sema.author and data[sema.author] then
sema.aData = data[sema.author]
if sema.work and sema.aData.works[sema.work] then
sema.wData = sema.aData.works[sema.work]
end
end
end
sema.choose = sema.choose or function(choice, optionA, optionB)
optionB = '' or optionB
choice = sema.interpret(choice)
if choice then
decision = optionA
else
decision = optionB
end
decision = sema.interpret(decision)
return decision
end
sema.isLetter = sema.isLetter or function(input)
local isit = not tonumber(input)
return isit
end
sema.lower = sema.lower or mw.ustring.lower
sema.roundDown = sema.roundDown or function(period, verse)
if not tonumber(verse) then
sema.changeCode('orange')
else
local rounded = math.floor(verse/period) * period
return rounded
end
end
sema.chapterSelect = sema.chapterSelect or function(rubric, verse)
verse = tonumber(verse)
for k,v in pairs(rubric) do
if v[1] <= verse and verse <= v[2] then
return k
end
end
sema.changeCode('orange')
end
sema.interpret = sema.interpret or function(item)
if type(item) == 'string' then
if string.sub(item, 1, 1) == '.' then
address = string.sub(item, 2)
local returnable = sema[address] or sema.library.data.Sundry and sema.library.data.Sundry[address]
return returnable
else
return item
end
elseif type(item) == 'table' then
--If it's a table, it's either a function call or a nested address.
local presumedFunction = sema.interpret(item[1])
if type(presumedFunction) == 'function' then
local parameters = {}
for i=2, 30 do
local expanded = sema.interpret(item[i])
if expanded then
table.insert(parameters, expanded)
else
break
end
end
local result = presumedFunction(unpack(parameters))
return result
else
local nested = sema
for i=1, 30 do
local address = item[i]
if address then
nested = nested[address]
else
break
end
end
return nested
end
else
return item
end
end
sema.convert = sema.convert or function(scheme, initiate)
if type(scheme) == "table" then
local initiate = tonumber(initiate) or initiate
local converted = scheme[initiate]
if converted == nil then
sema.changeCode('orange')
end
return converted
end
if type(scheme) == "function" then
local initiate = tonumber(initiate) or initiate
local converted = scheme(initiate)
if converted == nil then
sema.changeCode('orange')
end
return converted
end
sema.changeCode('orange')
end
sema.numToRoman = sema.numToRoman or function(item)
local j = tonumber(item)
if (j == nil) then
return item
end
if (j <= 0) then
return item
end
local ints = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}
local nums = {'M', 'CM', 'D', 'CD','C', 'XC','L','XL','X','IX','V','IV','I'}
local result = ""
for k = 1, #ints do
local count = math.floor(j / ints[k])
result = result .. string.rep(nums[k], count)
j = j - ints[k]*count
end
return result
end
sema.period = sema.period or '.'
sema.expand = sema.expand or function(args)
--Instantiate our variables.
local results = {}
sema.code = 'green'
local data = sema.library.data
local ultimate = ''
sema.author = args['author'] or args[2]
sema.work = args['work'] or args[3]
for i=1, 5 do
local refName = 'ref'..tostring(i)
local paramNumber = i + 3
sema[refName] = args[refName] or args[paramNumber]
end
--Check if we've been given an author alias.
if data.authorAliases[sema.author] then
sema.author = data.authorAliases[sema.author]
end
if not data[sema.author] then
sema.changeCode('yellow')
else
sema.aData = data[sema.author]
if sema.aData.reroute then
sema.reroute(sema.aData.reroute)
else
if sema.aData.aliases and sema.aData.aliases[sema.work] then
sema.work = sema.aData.aliases[sema.work]
end
if not sema.aData.works or not sema.aData.works[sema.work] then
sema.changeCode('yellow')
else
sema.wData = sema.aData.works[sema.work]
if sema.wData.reroute then
sema.reroute(sema.wData.reroute)
end
end
end
end
--Load all author-level data.
if sema.aData and sema.aData.aLink then
results.author = '[[w:'..sema.aData.aLink..'|'..sema.author..']]'
else
results.author = sema.author
end
if sema.aData and sema.aData.year then
results.year = sema.aData.year
end
--If the database has a link for the work, incorporate it.
if not sema.wData or not sema.wData['wLink'] then
results.work = sema.work
else
results.work = '[[w:'..sema.wData['wLink']..'|'..sema.work..']]'
end
--Some works have info which overrides the author-level info.
if sema.wData then
if sema.wData['year'] then
results.year = sema.wData.year
end
if sema.wData['author'] ~= nil then
results.author = sema.wData.author
end
end
--The displayed reference is simply all the ref argument(s) joined with a period.
sema.refDisplay = sema.ref1 and '' or false
for i=1, 5 do
local whichRef = 'ref'..tostring(i)
if sema[whichRef] then
if i > 1 then
sema.refDisplay = sema.refDisplay..'.'
end
sema.refDisplay = sema.refDisplay..sema[whichRef]
else
break
end
end
if args['through'] then
args['thru'] = args['through']
end
if args['thru'] then
sema.refDisplay = sema.refDisplay..'–'..args['thru']
end
--If the work is not in the database, or we don't have a source text link,
--the ref is simply the display.
--Otherwise, we have to create a reference link,
--easily the most challenging function of this script.
if sema.wData and sema.wData['rlFormat'] then
sema.rlFormat = sema.aData['rlFormat'..tostring(sema.wData.rlFormat)]
if sema.rlFormat then
sema.rlTitle = sema.wData['rlTitle']
sema.refLink = {}
for i=1, 30 do
local current = sema.rlFormat[i]
if current then
local results = sema.interpret(current)
table.insert(sema.refLink, results)
else
break
end
end
sema.refLink = table.concat(sema.refLink)
end
end
if sema.refLink then
results.ref = '[['..sema.refLink..'|'..sema.refDisplay..']]'
else
results.ref = sema.refDisplay
end
if args['notes'] then
results.notes = args.notes
end
results.code = sema.code
return results
end
return sema
end
return export