Module:Person
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Person/doc
-- ================================================================================
-- Module dependencies
-- ================================================================================
local cargo = mw.ext.cargo
local getArgs = require('Module:Arguments').getArgs -- for processing arguments
local cf = require("Module:Custom_functions")
local ibf = require("Module:Infobox_functions")
local tf = require("Module:Table_functions")
-- ================================================================================
-- Main table
-- ================================================================================
local p = {}
function p.get_person_gallery_new(frame)
-- ========================================
-- Parameters from frame object
-- ========================================
local args = getArgs(frame) -- Use the globally configured getArgs
local gallery_mode = args.gallery_mode or "packed"
local name_string = args.names
-- Treat the presence of the parameter as true regardless of its value
local show_organization = false
local show_occupation_title = false
-- Converts the user-entered comma-delimited name list to an array
local name_array = {}
for value in string.gmatch(name_string, '([^,]+)') do
table.insert(name_array, mw.text.trim(value))
end
-- ========================================
-- Parameters set here
-- ========================================
local placeholder_image = 'Face silhouette for no photo profiles.png' -- Define a default placeholder image
-- ========================================
-- Function to build Cargo where statement
-- ========================================
local function build_or_conditions(name_array)
local conditions = {}
for _, name in ipairs(name_array) do
local sanitized_name = mw.text.trim(name):gsub('"', '\\"'):gsub("'", "\\'")
table.insert(conditions, string.format('Full_name="%s"', sanitized_name))
end
return table.concat(conditions, ' OR ')
end
-- ========================================
-- Set Cargo variables
-- ========================================
local cargo_table = "Person"
local backup_table = "Person_extra"
local fields = "Full_name, Image, Organizations, Position_titles"
local where_condition = build_or_conditions(name_array)
local cargo_args = {
where = where_condition
}
-- ========================================
-- Get results from primary cargo table results
-- ========================================
local primary_results = cargo.query(cargo_table, fields, cargo_args)
local primary_names_found = {}
for _, entry in ipairs(primary_results) do
primary_names_found[entry.Full_name] = true
end
-- ========================================
-- Identify missing names and query backup table if necessary
-- ========================================
local missing_names = {}
for _, name in ipairs(name_array) do
if not primary_names_found[name] then
table.insert(missing_names, name)
end
end
local backup_results = {}
if #missing_names > 0 then
local backup_where_condition = build_or_conditions(missing_names)
local backup_cargo_args = {
where = backup_where_condition
}
backup_results = cargo.query(backup_table, fields, backup_cargo_args)
end
-- ========================================
-- Combine results from both tables
-- ========================================
local combined_results = {}
for _, result in ipairs(primary_results) do
combined_results[result.Full_name] = {result, "primary"}
end
for _, result in ipairs(backup_results) do
combined_results[result.Full_name] = {result, "backup"}
end
-- Overwrite cargo_results with combined results from both tables
cargo_results = combined_results
-- ========================================
-- Map results to person name vector
-- ========================================
local function get_person_file_names(cargo_results, name_array)
local file_name_array = {}
for _, name in ipairs(name_array) do
local result_info = cargo_results[name]
local result = result_info and result_info[1] or nil
local table_type = result_info and result_info[2] or "backup"
if result and result.Image and result.Image ~= '' then
result.Image = cf.remove_file_prefix(result.Image)
file_name_array[name] = {
Image = cf.add_file_prefix_gentle(result.Image),
Organizations = result.Organizations or "Unknown organization",
Position_titles = result.Position_titles or "Unknown position",
table_type = table_type
}
else
file_name_array[name] = {
Image = placeholder_image,
Organizations = result and result.Organizations or "Unknown organization",
Position_titles = result and result.Position_titles or "Unknown position",
table_type = table_type
}
end
end
return file_name_array
end
local file_name_array = get_person_file_names(cargo_results, name_array)
if next(file_name_array) == nil then
return '<span class="person-gallery-error">No images found for the provided names!</span>'
end
-- ========================================
-- Build the gallery
-- ========================================
local gallery_wikitext = '<gallery heights=200 mode="' .. gallery_mode .. '">\n'
for _, name in ipairs(name_array) do
local person_info = file_name_array[name]
if person_info and person_info.Image then
local caption = name -- Start with just the name
local link_to_page = name -- Default link is to the page with the same name
-- If the name is from the "Person" table, make it a link
if person_info.table_type == "primary" then
caption = string.format("[[%s|%s]]", link_to_page, name)
end
-- Append organization if required
if show_organization then
caption = caption .. "<br>" .. person_info.Organizations
end
-- Append position titles if required
if show_occupation_title then
caption = caption .. "<br>" .. person_info.Position_titles
end
-- Add the image with the link to the same page
gallery_wikitext = gallery_wikitext .. string.format('%s|link=%s|%s\n', person_info.Image, link_to_page, caption)
else
gallery_wikitext = gallery_wikitext .. "File:Face silhouette for no photo profiles.png|No image available for " .. name .. '<br><br>\n'
end
end
gallery_wikitext = gallery_wikitext .. '</gallery>'
return frame:preprocess(gallery_wikitext)
end
-- ================================================================================
-- Get person gallery
-- ================================================================================
function p.get_person_gallery(frame)
-- ========================================
-- Parameters from frame object
-- ========================================
local args = getArgs(frame) -- Ensure getArgs is correctly referenced
local gallery_mode = args.gallery_mode or "packed"
local name_string = args.names
-- Converts the user-entered comma-delimited name list to an array
local name_array = {}
for value in string.gmatch(name_string, '([^,]+)') do
table.insert(name_array, mw.text.trim(value))
end
-- ========================================
-- Parameters set here
-- ========================================
local placeholder_image = 'Face silhouette for no photo profiles.png' -- Define a default placeholder image
-- ========================================
-- Function to build Cargo where statment
-- ========================================
-- Takes the array of names and builds an "or" conditional statement for the Cargo query in the correct syntax
local function build_or_conditions(name_array)
local conditions = {}
for _, name in ipairs(name_array) do
-- Trim whitespace and escape single and double quotes
local sanitized_name = mw.text.trim(name):gsub('"', '\\"'):gsub("'", "\\'")
table.insert(conditions, string.format('Full_name="%s"', sanitized_name))
end
return table.concat(conditions, ' OR ')
end
-- ========================================
-- Set Cargo variables
-- ========================================
local cargo_table = "Person"
local backup_table = "Person_extra"
local fields = "Full_name, Image, Organizations, Position_titles"
local where_condition = build_or_conditions(name_array)
local cargo_args = {
where = where_condition
}
-- ========================================
-- Get results from primary cargo table results
-- ========================================
local primary_results = cargo.query(cargo_table, fields, cargo_args)
local primary_names_found = {}
for _, entry in ipairs(primary_results) do
primary_names_found[entry.Full_name] = true
end
-- ========================================
-- Identify missing names and query backup table if necessary
-- ========================================
local missing_names = {}
for _, name in ipairs(name_array) do
if not primary_names_found[name] then
table.insert(missing_names, name)
end
end
-- Get results from backup cargo table for only for missing names
local backup_results = {}
if #missing_names > 0 then
local backup_where_condition = build_or_conditions(missing_names)
local backup_cargo_args = {
where = backup_where_condition
}
backup_results = cargo.query(backup_table, fields, backup_cargo_args)
end
-- ========================================
-- Combine results from both tables
-- ========================================
local combined_results = {}
for _, result in ipairs(primary_results) do
combined_results[result.Full_name] = result
end
for _, result in ipairs(backup_results) do
combined_results[result.Full_name] = result
end
-- Overwrite cargo_results with combined results from both tables
cargo_results = combined_results
-- ========================================
-- Map results to person name vector
-- ========================================
-- Function that extracts Cargo results and maps them onto the user-provided name array
local function get_person_file_names(cargo_results, name_array)
-- Use a table to map names to their images, organizations, and positions
local file_name_array = {}
-- Iterate over the ordered name array
for _, name in ipairs(name_array) do
local result = cargo_results[name]
if result and result.Image and result.Image ~= '' then
-- remove File prefix if it already exists
result.Image = cf.remove_file_prefix(result.Image)
-- Only add entries to file_name_array if an image is available
file_name_array[name] = {
Image = cf.add_file_prefix_gentle(result.Image),
Organizations = result.Organizations or "Unknown organization",
Position_titles = result.Position_titles or "Unknown position"
}
else
-- Handle cases where no results are found or no image is available
-- Use the default placeholder image if no image is found
file_name_array[name] = {
Image = placeholder_image,
Organizations = result and result.Organizations or "Unknown organization",
Position_titles = result and result.Position_titles or "Unknown position"
}
end
end
return file_name_array
end
-- Takes the array of names and returns a table mapping each name to its corresponding image file
local file_name_array = get_person_file_names(cargo_results, name_array)
-- Check if the mapping table is empty (indicating no images were found)
if next(file_name_array) == nil then
return '<span class="person-gallery-error">No images found for the provided names!</span>'
end
-- ========================================
-- Build the gallery
-- ========================================
-- Adjust the gallery_wikitext appending to include organization and position titles
local gallery_wikitext = '<gallery heights=200 mode="' .. gallery_mode .. '">\n'
for _, name in ipairs(name_array) do
local person_info = file_name_array[name]
if person_info and person_info.Image then
-- Use <br> instead of \n for line breaks in captions
local caption = string.format("%s<br>%s<br>%s", name, person_info.Organizations, person_info.Position_titles)
gallery_wikitext = gallery_wikitext .. person_info.Image .. '|' .. caption .. '\n'
else
-- Handle names without associated images or data with a placeholder
gallery_wikitext = gallery_wikitext .. "File:Face silhouette for no photo profiles.png|No image available for " .. name .. '<br><br>\n'
end
end
gallery_wikitext = gallery_wikitext .. '</gallery>'
return frame:preprocess(gallery_wikitext)
end
-- ================================================================================
-- Create a person bio box
-- ================================================================================
function p.get_person_bio_box(frame)
-- get args passed through the frame
local args = getArgs(frame)
local title = mw.title.getCurrentTitle().text
local name = args.name or title
local position_title = args.position_title
-- Cargo query to retrieve user image and description
local tables = "Person"
local fields = "Full_name, Image, Position_titles, Bio"
-- local where = string.format('Full_name = "%s"', mw.text.trim(name))
local where = string.format('Full_name = "%s"', name)
local cargo_results = mw.ext.cargo.query(tables, fields, {where = where})
if #cargo_results < 1 then
return string.format('<span style="color: red;">%s</span>', "Can't find this name in the Cargo database!")
end
-- control loop for image file name
local image = cargo_results[1].Image and cargo_results[1].Image ~= "" and cargo_results[1].Image or "Face silhouette for no photo profiles.png"
-- add file prefix if needed
image = cf.add_file_prefix_gentle(image)
-- control loop for position titles
local position_titles = args.position_title or cargo_results[1].Position_titles
-- begin create html container
local container = mw.html.create('div')
:addClass('person-photo-box')
-- Header with the person's name and title
container:tag('div')
:addClass('person-photo-header')
:wikitext(string.format('[[%s|%s%s%s]]', name, name, " - ", position_titles))
if cargo_results and #cargo_results > 0 then
local contentWrapper = mw.html.create('div')
:addClass('content-wrapper')
local imageDiv = mw.html.create('div')
:addClass('person-photo-content')
:wikitext(string.format('[[%s%s%s]]', image, '|link=', name))
local textDiv = mw.html.create('div')
:addClass('person-photo-text')
:wikitext(cargo_results[1].Bio or "")
-- Append image and text divs to the content wrapper
contentWrapper
:node(imageDiv)
:node(textDiv)
-- Append content wrapper to the container
container:node(contentWrapper)
else
container:tag('div')
:addClass('error-message')
:wikitext(string.format('<span style="color: red;">%s</span>', "Can't find this name in the Cargo database!"))
end
return tostring(container)
end
-- ================================================================================
-- Get person photo
-- ================================================================================
local function get_person_photo(frame)
local args = getArgs(frame)
local title = mw.title.getCurrentTitle().text
local name = args.name or title
-- cargo query to retrieve user image
local tables = "Person"
local fields = "Full_name, Image"
local cargo_args = {
where = string.format('Full_name = "%s"', name)
}
local cargo_results = cargo.query(tables, fields, cargo_args)
-- extract image name
local image = cargo_results[1].Image
-- add file prefix if needed
image = cf.add_file_prefix_gentle(image)
if cargo_results and #cargo_results > 0 then
-- return user bio
return "[[" .. image .. "]]"
else
-- return error message in red
return string.format('<span style="color: red;">%s</span>', "Can't find this name in the Cargo database!")
end
end
p.get_person_photo = get_person_photo
-- ================================================================================
-- Infobox
-- ================================================================================
function p.infobox(frame)
local args = getArgs(frame)
local title = mw.title.getCurrentTitle().text
--[[ this is important to escape single and double quotes in titles for Cargo queries and text display but I need an
un-escaped version for the create_infobox() function below because that function escapes apostrophes in names in a different way
for html rendering.
--]]
local escaped_title = title:gsub("'", "''"):gsub('"', '""')
args.Image = args.Image or "Face silhouette for no photo profiles.png"
-- ========================================
-- Cargo query for User page connection
-- ========================================
-- This Cargo query is necessary to get the connection to the mediawiki user page for a given person
local tables = "User_to_person"
local fields = "Full_name"
local cargo_args = {
where = string.format("%s = '%s'", "Full_name", escaped_title)
}
local cargo_results = cargo.query(tables, fields, cargo_args)
-- ========================================
-- Build HTML
-- ========================================
local link_text = "URL"
local root = ""
local html_theme_class = '-user'
root = ibf.create_infobox(root, title, html_theme_class)
root = ibf.add_image(root, args.Image, html_theme_class)
root = ibf.add_row(root, 'Country', args.Base_country, html_theme_class, "page")
root = ibf.add_row(root, 'Organizations:', args.Organizations, html_theme_class, "")
root = ibf.add_row(root, 'Departments', args.Departments, html_theme_class)
root = ibf.add_row(root, 'Titles:', args.Position_titles, html_theme_class)
root = ibf.add_row(root, 'Focal areas:', args.Focal_areas, html_theme_class)
root = ibf.add_row(root, 'Focal species:', args.Focal_species, html_theme_class, "page")
root = ibf.add_row(root, 'Website:', args.Other_websites, html_theme_class, "ext_link", link_text)
root = ibf.add_row(root, 'LinkedIn:', args.Linkedin, html_theme_class, "ext_link", link_text)
root = ibf.add_row(root, 'Twitter:', args.Twitter, html_theme_class, "ext_link", link_text)
return root
end
-- ================================================================================
-- Retrieve a Person biography
-- ================================================================================
local function biography(frame)
local args = getArgs(frame)
local title = mw.title.getCurrentTitle().text
local name = args.name or title
-- cargo query to retrieve user bio
local tables = "Person"
local fields = "Full_name, Bio"
local cargo_args = {
where = string.format('Full_name = "%s"', name)
}
local cargo_results = cargo.query(tables, fields, cargo_args)
if cargo_results and #cargo_results > 0 then
-- return user bio
return cargo_results[1]["Bio"]
else
-- return error message in red
return string.format('<span style="color: red;">%s</span>', "Can't find this name in the Cargo database!")
end
end
p.biography = biography
return p