Module:New texts/sandbox
Appearance
![]() | This is the module sandbox page for Module:New texts (diff). |
Functions to provide lists of new works shown at {{new texts}} (and therefore also the Main page)
Add work data to Template:New texts/data/2025.json.
Archived data is pulled from Template:New texts/data/YYYY.json
.
Functions
[edit]new_texts
: function called by {{new texts}} for a list of recent new text- limit: how many items to show
- skip: how many items to skip
- data_source: alternative source base title for data (default is
Template:New texts/data
. Year and.json
are appended.
archive_list
: function called by {{new texts archive}} for a list of new texts by year- year: the year to show, omit for current year
- month: the month to show, omit for entire year
- data_source: alternative source base title for data (default is
Template:New texts/data
. Year and.json
are appended.
Archives
[edit]Archives of New Texts ( ) | |
---|---|
2025: | |
2024: | |
2023: | |
2022: | |
2021: | |
2020: | |
2019: | |
2018: | |
2017: | |
2016: | |
2015: | |
2014: | |
2013: | |
2012: | |
2011: | |
2010: |
-- This is a module to implement listings of new texts
require('strict')
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"))
}
local 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
]=]
local function construct_author(str, nowiki)
-- 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 = 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(args.nowiki) or false
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
local text_item = {}
-- image
if image_name then
-- no link to image's page in the File namespace
table.insert(text_item, "[[File:" .. image_name .. "|right|" .. image_size .. "|link=]]")
end
-- title
if title then
local title_text = mw.html.create('span')
:css({['font-style'] = 'italic', ['font-weight'] = 'bold'})
:wikitext('[[' .. title .. '|' .. display .. ']]')
table.insert(text_item, tostring(title_text))
else
table.insert(text_item, error_function({"Error: No title entered"}))
end
-- edition
if edition then
table.insert(text_item, ', ' .. edition)
end
-- date/type
local work_info = {}
if work_date then
table.insert(work_info, work_date)
end
if work_date and translation_date then
table.insert(work_info, ',')
end
if translation_date then
table.insert(work_info, 'tr. ' .. translation_date)
end
if work_type == 'film' then
table.insert(work_info, require('Module:Media')._media({[1] = 15, ['type'] = 'film'}))
end
if #work_info > 0 then
table.insert(text_item, ' (' .. table.concat(work_info, ' ') .. ')')
end
-- creators
local creators = {}
if author then
table.insert(creators, 'by ' .. construct_author(author, nowiki))
end
if translator then
table.insert(creators, 'translated by ' .. construct_author(translator, nowiki))
end
if editor then
table.insert(creators, 'edited by ' .. construct_author(editor, nowiki))
end
if illustrator then
table.insert(creators, 'illustrated by ' .. construct_author(illustrator, nowiki))
end
if #creators > 0 then
local creators_div = mw.html.create('div')
:css({['margin-left'] = '1em', ['font-size'] = '83%'})
:addClass('creators')
:wikitext(table.concat(creators, ', '))
table.insert(text_item, tostring(creators_div))
end
return table.concat(text_item)
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")
]=]
local 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 author_data = item[key]
if type(author_data) ~= 'table' then
author_data = {author_data}
end
local entries = {}
for k, v in pairs(author_data) do
table.insert(entries, construct_author(v, nowiki))
end
if #entries == 0 then
return nil
elseif #entries == 1 then
return entries[1]
else
return table.concat(entries, ', ', 1, #entries - 1) .. ' and ' .. entries[#entries]
end
end
--[=[
Construct an entry using new_texts_item with the data from item
]=]
local function item_to_new_texts_item(item)
-- suppress auto links for the authors, etc
local nowiki = yesno(item.nowiki)
local 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"],
["display"] = item["display"]
}
if not args["display"] then
-- if title is a subpage of some other title, use subpage as display title
local mwt = mw.title.new(tostring(args["title"]))
if mwt and mwt.isSubpage then
args["display"] = mwt.subpageText
end
end
return p._new_texts_item(args)
end
local 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)
local texts = {}
local count = 0
local broken = false
-- iterate in reverse, because we want the most recent months
for i = months, 1, -1 do
local month = data[i]
for k, v in pairs(month) do
if count >= offset then
table.insert(texts, item_to_new_texts_item(v))
end
count = count + 1
if count >= limit + offset then
broken = true
break
end
end
if broken then
break
end
end
return table.concat(texts, '\n')
end
function p.new_texts(frame)
return p._new_texts(getArgs(frame))
end
local function construct_month_list(items, start_num)
local count = 0
local first_in_month = true
local items_len = table_len(items)
if items_len == 0 then
return '', count
end
local ol = mw.html.create('ol')
for i = items_len, 1, -1 do
local li = ol:tag('li')
if i == items_len then
li:attr('value', start_num + 1)
end
li:wikitext(item_to_new_texts_item(items[i]))
count = count + 1
end
return ol, 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 a_list = mw.html.create('div')
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
a_list:tag('span')
:attr('id', string.format("%02d", k))
a_list:tag('h2')
:wikitext(os.date("%B", os.time({year = year, month = k, day = 1})))
local content, m_count = construct_month_list(m, count)
a_list:node(content)
count = count + m_count
end
return a_list
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 tonumber(args[1]) or tonumber(mw.title.getCurrentTitle().subpageText)
if not year then
return error_function({"[[Module:New texts]] error: No year provided"})
end
local nextlink
if year < DEFAULTS["currentyear"] then
nextlink = "[[Wikisource:Works/" .. year + 1 .. "|" .. year + 1 .. "]]"
end
return require('Module:Process header')._process_header({
['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 styles = frame:extensionTag('templatestyles', '', {src = 'Template:Block right/styles.css'})
local toc = mw.html.create('div')
:addClass('wst-block-right')
:wikitext(frame:preprocess('__TOC__'))
local clear = mw.html.create('div'):css({['clear'] = 'both'})
local list = p._archive_list(args)
return styles .. header .. tostring(toc) .. tostring(clear) .. tostring(list)
end
return p