Module:New texts/sandbox

From Wikisource
Jump to navigation Jump to search
-- This is a module to implement listings of new texts

local p = {} --p stands for package

local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local error_function = require('Module:Error')['error']

local DEFAULTS = {
	data_source = "Template:New texts/data",
	currentyear = tonumber(os.date("%Y")),
	frame = mw.getCurrentFrame()
}

function get_data(src, year)
	local data
	
	if not src or src == '' then
		src = DEFAULTS["data_source"]
	end
	year = tonumber(year) or DEFAULTS["currentyear"]
	src = src .. "/" .. year .. ".json"
	
	local data
	if pcall(function()
		local jsondata = mw.title.new(tostring(src)):getContent()
		data = mw.text.jsonDecode(jsondata)
	end) then
      -- no errors while loading
    else
    	error("Failed to load new text data from [[" .. src .. "]]")
    end
	
	return data
end

--[=[
Construct creator link/nonlink
]=]
function construct_author(str, nowiki)
	str = mw.text.trim(str)
	
	-- strip "Portal:" prefixes if not piped
	str = string.gsub(str, "%[%[%s*[Pp]ortal:([^|]-)|?%]%]", function (target)
		return "[[Portal:" .. target .. "|" .. target .. "]]"
	end)
	-- plain portal syntax
	str = string.gsub(str, "^[Pp]ortal:(.*)$", function (target)
		if nowiki then
			return target
		else
			return "[[Portal:" .. target .. "|" .. target .. "]]"
		end
	end)
	
	-- strip "Author:" prefixes if not piped
	str = string.gsub(str, "%[%[%s*[Aa]uthor:([^|]-)|?%]%]", function (target)
		return "[[Author:" .. target .. "|" .. target .. "]]"
	end)
	-- plain author syntax
	str = string.gsub(str, "^[Aa]uthor:(.*)$", function (target)
		if nowiki then
			return target
		else
			return "[[Author:" .. target .. "|" .. target .. "]]"
		end
	end)
	
	-- auto-strip bracketed dates
	if not nowiki then
		str = string.gsub(str, "^((.*) +%([0-9]+[-–][0-9]+%))$", function (full_target, no_date)
			return "[[Author:" .. full_target .. "|" .. no_date .. "]]"
		end, 1)
	end
	
	-- if the string has its own links, return it now
	if string.match(str, "%[%[") then
		return str
	end
	
	-- if the author is anonymous
	if string.match(str, "[uU]nknown") or string.match(str, "[aA]non") or string.match(str, "[aA]nonymous") then
		if nowiki then
			return "Anonymous"
		else
			return "[[Portal:Anonymous texts|Anonymous]]"
		end
	end
	
	if string.match(str, "[Vv]arious") then
		return "Various authors"
	end
	
	-- if nowiki then don't make link
	if nowiki then
		return str
	end
	
	-- if a pipe is provided
	if string.match(str, "|") then
		return "[[Author:" .. str .. "]]"
	end
	
	-- make our own piped link
	return "[[Author:" .. str .. "|" .. str .. "]]"
end

--[=[
Format new items
]=]
function p._new_texts_item(args)
	-- parse args
	local image_name = args.image_name
	local image_size = mw.text.trim(args.image_size or '100px')
	
	local title = args.title or args[1]
	local display = args.display or title
	local edition = args.edition
	
	local work_date = args['date'] or args[3]
	local work_type = args['type']
	
	local nowiki = yesno(mw.text.trim(args.nowiki or 'no'))
	local author = args.author or args[2]
	local translator = args.translator
	local translation_date = args.translation_date
	local editor = args.editor
	local illustrator = args.illustrator
	
	-- image
	local image = ""
	if image_name then
		image = "[[File:" .. mw.text.trim(image_name) .. "|right|" .. image_size .. "|link=]]" -- no link to image's page in the File namespace
	end
	
	-- title
	local text
	if title then
		text = "<span style='font-style:italic; font-weight:bold;'>[[" .. mw.text.trim(title) .. "|" .. mw.text.trim(display) .. "]]</span>"
	else
		text = error_function({"Error: No title entered"})
	end
	
	-- edition
	if edition then
		text = text .. ", " .. mw.text.trim(edition)
	end
	
	-- date/type
	if work_date or work_type then
		text = text .. " ("
		if work_date then
			text = text .. mw.text.trim(work_date)
			if translation_date then
				text = text .. ', '
			end
		end
		if translation_date then
			text = text .. 'tr. ' .. mw.text.trim(translation_date)
		end
		if work_type then
			if mw.text.trim(work_type) == "film" then
				local type_indicator = DEFAULTS["frame"]:expandTemplate {
					title = "media",
					args = {
						15,
						['type'] = "film"
					}
				}
				if work_date then
					text = text .. " "
				end
				text = text .. type_indicator
			end
		end
		text = text .. ")"
	end
	
	-- creators
	if author or translator or editor or illustrator then
		text = text .. '<div style="margin-left:1em; font-size:83%;" class="creators">' -- list name(s) in their own paragraph
		
		local creators = {}
		if author then
			creators[1] = 'by ' .. construct_author(author, nowiki)
		end
		if translator then
			creators[2] = 'translated by ' .. construct_author(translator, nowiki)
		end
		if editor then
			creators[3] = 'edited by ' .. construct_author(editor, nowiki)
		end
		if illustrator then
			creators[4] = 'illustrated by ' .. construct_author(illustrator, nowiki)
		end
		
		text = text .. table.concat(creators, ', ') .. '</div>'
	end
	
	return image .. text
end
function p.new_texts_item(frame)
	return p._new_texts_item(getArgs(frame))
end

--[=[
Construct an author link for the given key (e.g "author" or "translator")
]=]
function construct_author_from_item(item, key, nowiki)
	if not item or not item[key] then
		return nil
	end

    -- explicit nowiki
	if item[key .. "_nowiki"] then
		return item[key]	
	end
	
	local tab = item[key]
	
	if type(tab) ~= 'table' then
		tab = {tab}
	end
	
	entries = {}
	for k, v in pairs(tab) do
		table.insert(entries, construct_author(v, nowiki))
	end
	
	return table.concat({table.concat(entries, ", ", 1, #entries - 1), entries[#entries]}, " and ")
end

--[=[
Construct an entry using new_texts_item with the data from item
]=]
function item_to_new_texts_item(item)
	-- suppress auto links for the authors, etc
	local nowiki = yesno(item.nowiki)
	
	args = {
		["nowiki"] = "yes", -- we always construct this ourselves
		
		["image_name"] = item["image_name"],
		["image_size"] = item["image_size"],
		
		["title"] = item["title"],
		
		["author"] = construct_author_from_item(item, "author", nowiki),
		["edition"] = item["edition"],
		["editor"] = construct_author_from_item(item, "editor", nowiki),
		["illustrator"] = construct_author_from_item(item, "editor", nowiki),
		["translator"] = construct_author_from_item(item, "translator", nowiki),
		["translation_date"] = item["translation_year"],
		
		["date"] = item["year"],
	}
	
	if item["display"] then
		args["display"] = item["display"]
	else
		-- if title is a subpage of some other title, use subpage as display title
		mwt = mw.title.new(tostring(title))
		if mwt and mwt.isSubpage then
			args["display"] = mwt.subpageText
		end
	end
	
	return p._new_texts_item(args)
end

function table_len(data)
	-- count the items (#data doesn't work because keys are non-numeric)
	local count = 0
	for k, _ in pairs(data) do
		count = count + 1
	end
	return count
end

--[=[
Construct the new texts list from instances of new_texts_item

Arguments:
* limit: how many items to display
* offset: how many items to skip the display of

not in use AFAICT
]=]
function p._new_texts(args)
	-- pull in the data from the data module at [[Template:New texts/data(/YEAR).json]]
	local data = get_data(args["data_source"], nil)
	
	-- how many items to show
	local offset = tonumber(args["offset"]) or 0
	local limit = tonumber(args["limit"]) or 7
	
	-- count the months
	local months = table_len(data)
	
	s = ""
	count = 0 
	-- iterate in reverse, because we want the most recent months
	for i = months, 1, -1 do
		
		local month = data[i]
		
		local broken = false
		
		for k, v in pairs(month) do
	
			if count >= offset then
				s = s .. item_to_new_texts_item(v) .. "\n"
			end
			
			count = count + 1

			if count >= limit + offset then
				broken = true
				break
			end
		end
		
		if broken then
			break
		end
	end
	return s
end
function p.new_texts(frame)
	return p._new_texts(getArgs(frame))
end

function construct_month_list(items, start_num)
	local s = ""
	local count = 0
	local first_in_month = true
	for i=table_len(items), 1, -1 do
		
		local v = items[i]
		
		s = s .. "#"
		
		if first_in_month then
			s = s .. "<li value=\"" .. (start_num + 1) .. "\">"
		end
		
		s = s .. " " .. item_to_new_texts_item(v) .. "\n"
		
		count = count + 1
		-- reset
		first_in_month = false
	end
	
	return s, count
end

--[=[
Construct the list of archived items for the given month

Arguments:
* month: the month to show (nil to show whole year)
* year: the year to show
]=]
function p._archive_list(args)
	local month = tonumber(args["month"])
	local year = tonumber(args["year"]) or DEFAULTS["currentyear"]
	
	-- pull in the data from the relevant archive
	local data = get_data(args["data_source"], year)

	local s = ""
	
	local count = 1
	
	local months
	if month then
		months = {}
		months[month] = data[month]
	else
		months = data
	end
	
	local count = 0
	
	local max_m = table_len(months)
	for k, m in pairs(months) do
		local numeric_anchor = string.format("%02d", k)
		s = s .. tostring(mw.html.create("span"):attr("id", numeric_anchor)) .. "\n"
		s = s .. "==" .. os.date("%B", os.time({year=2000, month=k, day=1})) .. "==\n\n"
		
		--mw.logObject(m)
		content, m_count = construct_month_list(m, count)
		
		s = s .. content
		count = count + m_count
	end

	return s
end
function p.archive_list(frame)
	return p._archive_list(getArgs(frame))
end

--[=[
Construct the process header for the list of archived items for the given year

Arguments:
* year: the year to show
]=]
function p._archive_list_header(args)
	local year = tonumber(args["year"] or args[1] or mw.title.getCurrentTitle().subpageText)
	
	local nextlink
	if year < DEFAULTS["currentyear"] then
		nextlink = "[[Wikisource:Works/" .. year + 1 .. "|" .. year + 1 .. "]]"
	end
	
	return DEFAULTS["frame"]:expandTemplate {
		['title'] = 'Process header',
		['args'] = {
			['title'] = 'Proofread works added in ' .. year,
			['previous'] = "[[Wikisource:Works/" .. year - 1 .. "|" .. year - 1 .. "]]",
			['next'] = nextlink,
			['notes'] = 'These works are from [[Help:DjVu files|scanned texts]] and have been [[Help:proofread|proofread]] at least once, if not fully validated.'
		}
	}
end
function p.archive_list_header(frame)
	return p._archive_list_header(getArgs(frame))
end

--[=[
Combine archive_list and archive_list_header to implement Template:New texts archive

Arguments:
* year: the year to show
]=]

function p.new_texts_archive(frame)
	local args = getArgs(frame)
	args.year = args.year or args[1]
	
	local header = p._archive_list_header(args)
	local toc = frame:expandTemplate {
		['title'] = 'Right block',
		['args'] = {
			frame:preprocess('__TOC__')
		}
	}
	local list = p._archive_list(args)
	return header .. toc .. list
end

return p