local export = {}
local tag_text = require("Module:script utilities").tag_text
local get_lang = require("Module:languages").getByCode
local utils = require("Module:bibliography/utils")
-- understands if a number refers to one or multiple instances of something (e.g. pages, sections) and pluralises it accordingly
local function format_number_label(number, singular, plural)
return ((number:find("–") or number:find("f%.$") or number:find(", ")) and plural or singular)..number
end
-- handles page_url, entry_url, etc.
local function param_url(source, input_data, param_name)
if not input_data then return nil end
local url_config, link_node
if input_data.volume and source.volumes and source.volumes then
local current_volume = source.volumes
if current_volume then
url_config = current_volume
link_node = current_volume.link
end
end
url_config = url_config or source
link_node = link_node or source.link
if not url_config then return nil end
-- handles the node
if type(url_config) ~= "table" then
url_config = { url = url_config }
else
for set_arg, set_value in pairs(url_config) do
if set_arg:match("^set_") then
set_arg = set_arg:gsub("^set_", "")
-- simple addition or subtraction
if type(set_value) == "number" and input_data then
input_data = input_data + set_value
-- operations as strings
-- TODO: needs to be stricter with invalid inputs
elseif type(set_value) == "string" and input_data then
local num = input_data
-- separating operations
local function esc(text) return text:gsub("()", "%%%1") end
local prefix = set_value:match("^*")
local operations = set_value:match(esc(prefix).."(*)")
local before_alterations = esc(prefix..operations)
local alterations = set_value:match(before_alterations.."(>+)")
assert(alterations or not set_value:match(before_alterations.."."), "Invalid string as set_page: "..set_value)
-- enforcing operations
local function calculate_operation(num, operations)
assert(operations:gsub("() *(%d+)", function(operation, operation_num)
num = ({
= function(a, b) return a + b end,
= function(a, b) return a - b end,
= function(a, b) return a * b end,
= function(a, b) return math.floor(a / b) end,
})(num, tonumber(operation_num))
return ""
end):match("^ *$"), "Invalid operation in set_page: "..set_value)
return num
end
num = calculate_operation(num, operations)
if alterations then
assert(alterations:gsub("> *(%d+) *(*)", function(alteration_from, alteration_operation)
if input_data > tonumber(alteration_from) then
num = calculate_operation(num, alteration_operation)
end
return ""
end):match("^ *$"), "Invalid alteration in set_page: "..set_value)
end
input_data = prefix..num
-- full function for complex operation
elseif type(set_value) == "function" then
input_data = set_value(input_data)
end
end
end
end
-- percent encodes entry name
if input_data.entry then
input_data.entry = mw.uri.encode(input_data.entry)
end
-- formats the URL
local function resolve_value(site_key)
local value = url_config
-- recycle data from stable links
if value == true then
value = link_node
end
if not value then error("Could not retrieve the "..site_key.." data for "..param_name) end
-- if a function, runs it
if type(value) == "string" then
return value
elseif type(value) == "function" then
return value(input_data)
end
error("Could not define "..param_name.." URL from the site "..site_key)
end
if url_config.ia then
return "https://archive.org/details/"..resolve_value("ia")
..(url_config.n and "/page/n" or "/page/")
..input_data.page.."/mode/1up?view=theater"
elseif url_config.gb then
return "https://books.google.com/?id="..resolve_value("gb").."&pg="..(url_config.pref or "PA")..input_data.page
elseif url_config.url then
local do_break = false
local ret = resolve_value("url"):gsub("%$(*)%$", function (wanted_param)
local param_ret = input_data
if not param_ret then do_break = true end
return param_ret
end)
if do_break then return end
return ret
end
error("No URL could be made")
end
function export.show(frame)
-- universal parameters
local list_allow_holes = { list = true, allow_holes = true }
local list_entry_alias = { list = true, alias_of = "entry" }
local list_page_alias = { list = true, alias_of = "page" }
local list_section_alias = { list = true, alias_of = "section" }
local volume_alias = { alias_of = "volume" }
local params = {
-- language
= true,
-- source id
= true,
-- headword
= list_allow_holes,
= list_entry_alias,
= list_entry_alias,
= list_entry_alias,
= list_entry_alias,
-- page
= list_allow_holes,
= list_page_alias,
= list_page_alias,
-- section
= list_allow_holes,
= list_section_alias,
= list_section_alias,
-- volume
= true,
= volume_alias,
= volume_alias,
-- sub entries
= list_allow_holes,
-- entry ID
= list_allow_holes,
}
-- load sources data from submodule
local function get_source_data(input_lang, input_sid)
local data = require("Module:bibliography/data/"..input_lang)
-- find the source in among data
local source, sid = (function ()
local sources = data.sources
-- simply return the source if easily accessible
if sources then
return sources, input_sid
end
for iter_sid, iter_source in pairs(sources) do
-- maybe if stripped it is the same
if utils.is_abbrev(iter_sid) then
if utils.strip_markup(iter_sid) == input_sid then
return iter_source, iter_sid
end
end
-- try with the aliases
local alias = iter_source.alias
if alias then
if type(alias) == "string" then
if alias == input_sid then
return iter_source, iter_sid
end
elseif type(alias) == "table" then
for _, v in ipairs(alias) do
if v == input_sid then
return iter_source, iter_sid
end
end
end
end
end
error("could not find the source with the ID "..input_sid.." in the database ]")
end)()
-- handle importing
if source.import_from then source, sid, input_lang = get_source_data(source.import_from, sid) end
return source, sid, input_lang, data.bib_page
end
local args = frame:getParent().args
local source, sid, tracking_lang, bib_page = get_source_data(args, args)
-- source specific parameters
if source.own_args then
for i, v in pairs(source.own_args) do params = v end
end
args = require("Module:parameters").process(frame:getParent().args, params)
args, args = nil, nil
args.pagename = mw.title.getCurrentTitle().text
-- display the source, and handle arguments if different
args.sid_display = utils.format(sid)
args.sid = utils.strip_markup(sid)
if source.default_pagename then
if #args.entry == 0 then
args.entry = args.pagename
args.entry.maxindex = 1
elseif #args.entry == 1 and args.entry == "-" then
args.entry = nil
args.entry.maxindex = 0
end
end
if source.set_args then
local function apply_setter(setter)
if type(setter) == "function" then
setter(args)
elseif type(setter) == "string" then
require("Module:bibliography/presets")(args)
elseif type(setter) == "table" then
if #setter > 0 then
for _, setter_child in ipairs(setter) do
apply_setter(setter_child)
end
elseif setter.from and setter.to and setter.setter then
for index, from in ipairs(args) do
if not args then
args = setter.setter(from)
elseif args == "-" then
args = nil
end
end
end
end
end
apply_setter(source.set_args)
end
local ret = "]"
-- tracks the source being cited
require("Module:debug/track")("bibref/"..tracking_lang.."/"..args.sid)
-- handle parameters
-- TODO: multiple volumes may be given
if args.volume then
ret = ret..", vol. "..args.volume
if args.volume:match("^%d+") then
args.volume = tonumber(args.volume:match("^%d+"))
end
end
local i = 0
while true do
i = i + 1
local section, page, entry = args.section, args.page, args.entry
if not (page or entry or section) then
break;
end
-- loads the data
local url_data
if source.page_url or source.entry_url or source.section_url or source.volumes then
url_data = {}
for arg_name, arg in pairs(args) do
if type(arg) == "table" then
if arg then
if arg:match("^%d+") and arg_name == "page" or arg_name == "section" then
url_data = tonumber(arg:match("^%d+"))
else
url_data = arg
end
end
else
url_data = arg
end
end
end
-- format sections
ret = ret..", "
if section then
section = format_number_label(section, "§", "§§")
local section_url = param_url(source, url_data, "section")
if section_url then section = "" end
ret = ret..section
end
-- format pages
if page then
if section then ret = ret.." " end
page = format_number_label(page, "page ", "pages ")
-- make the page a link if we have information
local page_url = param_url(source, url_data, "page")
if page_url then page = "" end
ret = ret..page
end
-- format headwords
if entry then
if page or section then ret = ret..": " end
local entry_url = param_url(source, url_data, "entry")
if entry_url then entry = "" end
local sub = args.sub
if source.entry_lang then
entry = tag_text(entry, get_lang(source.entry_lang))
if sub then sub = tag_text(sub, get_lang(source.entry_lang)) end
end
if sub then entry = entry.."” → “"..sub end
entry = entry:gsub("()%^(%d+)", "%1<sup>%2</sup>")
ret = ret.."“"..entry.."”"
end
end
return ret
end
return export