Module:Information: Difference between revisions

From Research Realm
No edit summary
(i hate this god i hate this)
Tag: Manual revert
 
(One intermediate revision by the same user not shown)
Line 2: Line 2:
   __  __          _      _        ___        __                            _  _             
   __  __          _      _        ___        __                            _  _             
  |  \/  | ___  __| |_  _| | ___ _|_ _|_ __  / _| ___  _ __ _ __ ___  __ _| |_(_) ___  _ __   
  |  \/  | ___  __| |_  _| | ___ _|_ _|_ __  / _| ___  _ __ _ __ ___  __ _| |_(_) ___  _ __   
  | |\/| |/ _ \ / _` | | | | |/ _ (_)| || '_ \| |_ / _ \| '__| m'_ ` _ \ / _` | __| |/ _ \| '_ \  
  | |\/| |/ _ \ / _` | | | | |/ _ (_)| || '_ \| |_ / _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \  
  | |  | | (_) | (_| | |_| | |  __/_ | || | | |  _| (_) | |  | | | | | | (_| | |_| | (_) | | | |
  | |  | | (_) | (_| | |_| | |  __/_ | || | | |  _| (_) | |  | | | | | | (_| | |_| | (_) | | | |
  |_|  |_|\___/ \__,_|\__,_|_|\___(_)___|_| |_|_|  \___/|_|  |_| |_| |_|\__,_|\__|_|\___/|_| |_|
  |_|  |_|\___/ \__,_|\__,_|_|\___(_)___|_| |_|_|  \___/|_|  |_| |_| |_|\__,_|\__|_|\___/|_| |_|
Line 21: Line 21:
local core    = require('Module:Core')
local core    = require('Module:Core')


-- ====================================================================
-- ==================================================
local function langWrapper(text, textLang, userLang)  
-- === Internal functions ===========================
-- ==================================================
 
local function langWrapper(text, textLang)  
-- code equivalent to https://commons.wikimedia.org/wiki/Template:Description
-- code equivalent to https://commons.wikimedia.org/wiki/Template:Description
local dir = mw.language.new( textLang ):isRTL() and 'rtl' or 'ltr' 
local language = mw.language.new( textLang )
local str = string.format('<span class="language %s"><b>%s:</b></span>', textLang, mw.language.fetchLanguageName( userLang, textLang  ))
local dir      = language:getDir() 
     return string.format('<div class="description mw-content-%s" dir="%s" lang="%s">%s %s</div>', dir, dir, textLang, str, text)
local LangName = language:ucfirst(mw.language.fetchLanguageName( textLang, textLang))
local str = mw.ustring.format('<span class="language %s"><b>%s:</b></span>', textLang, LangName)
     return mw.ustring.format('<div class="description mw-content-%s" dir="%s" lang="%s">%s %s</div>', dir, dir, textLang, str, text)
end
 
-------------------------------------------------------------------------------
local function getBareLabel(id, userLang)
-- code equivalent to require("Module:Wikidata label")._getLabel with Wikidata=- option
local label, link
-- build language fallback list
local langList = mw.language.getFallbacksFor(userLang)
table.insert(langList, 1, userLang)
for _, lang in ipairs(langList) do  -- loop over language fallback list looking for label in the specific language
label = mw.wikibase.getLabelByLang(id, lang)
if label then break end                    -- label found and we are done
end
return label or id
end
 
-------------------------------------------------------------------------------
local function message(name, lang)
return mw.message.new( 'wm-license-information-'..name ):inLanguage(lang):plain()
end
end


Line 34: Line 58:
-- ====================================================================
-- ====================================================================
local function Build_html(args)
local function Build_html(args)
-- Permissions tag
local lang = args.lang -- user's language
local tag1 = mw.message.new( "wm-license-information-permission" ):inLanguage(args.lang):plain()
local dir  = mw.language.new( lang ):getDir()    -- get text direction
local tag2 = mw.message.new( "wm-license-information-permission-reusing-link" ):inLanguage(args.lang):plain()
local desTag = mw.ustring.format('<span class="summary fn" style="display:none">%s</span>', args.pagename)
local tag3 = mw.message.new( "wm-license-information-permission-reusing-text" ):inLanguage(args.lang):plain()
local prmTag = mw.ustring.format("<br /><small>([[%s|%s]])</small>", message('permission-reusing-link', lang),
local permission_tag  = string.format("%s<br /><small>([[%s|%s]])</small>", tag1, tag2, tag3)
message('permission-reusing-text', lang))
local dir  = mw.language.new( args.lang ):isRTL() and 'rtl' or 'ltr'   -- get text direction
tag1 = mw.message.new( "wm-license-information-description" ):inLanguage(args.lang):plain()
tag2 = mw.title.getCurrentTitle().text -- pagename
local description_tag = string.format('%s<span class="summary fn" style="display:none">%s</span>', tag1, tag2)
tag3 = string.format(' lang="%s"', args.lang)


-- add other fields
-- field specific preferences
local params = {
local params = {
{field='description'    , id='fileinfotpl_desc' , tag=description_tag,                  alt=true, wrapper='\n%s', td=' class="description"'},
{field='description'    , id='fileinfotpl_desc', tag2=desTag, td='class="description"'},
{field='other_fields_1'},
{field='other_fields_1'},
{field='date'          , id='fileinfotpl_date' , tag='wm-license-information-date',              wrapper='\n%s', td=tag3},
{field='date'          , id='fileinfotpl_date', td=mw.ustring.format('lang="%s"', lang)},
{field='source'        , id='fileinfotpl_src'  , tag='wm-license-information-source',  alt=true, wrapper='\n%s'},  
{field='source'        , id='fileinfotpl_src'},  
{field='author'        , id='fileinfotpl_aut'  , tag='wm-license-information-author',  alt=true, wrapper='\n%s'},
{field='author'        , id='fileinfotpl_aut'},
{field='permission'    , id='fileinfotpl_perm' , tag=permission_tag,                            wrapper='\n%s'},
{field='permission'    , id='fileinfotpl_perm', tag2=prmTag },
{field='other_versions' , id='fileinfotpl_ver'   , tag='wm-license-information-other-versions',    wrapper='\n%s'},  
{field='other_versions' , id='fileinfotpl_ver', tag='other-versions'},  
{field='other_fields'}
{field='other_fields'},
}
}
local results = {}
local results = {}
Line 60: Line 79:
local field, tag, cell1, cell2, id
local field, tag, cell1, cell2, id
field = args[param.field]
field = args[param.field]
if field and mw.ustring.match(field,"^[%s%p]+$") then field=nul; end -- ignore punctuation only fields
if param.id then -- skip "other fields" parameter
if param.id then -- skip "other fields" parameter
if field then  -- add "id" to first <td> cell only if the field is present
if type(field) == 'string' then  -- add "id" to first <td> cell only if the field is present
id = string.format('id="%s" ', param.id)
id = mw.ustring.format('id="%s" ', param.id)
elseif param.alt then -- Some field have "Missing" message if field is not provided
elseif type(field) == 'table' then
-- code equivalent to Template:Source missing, Template:Author missing, Template:Description missing
-- the field was initially not present, it contains only our
tag1  = 'class="boilerplate metadata" id="cleanup" style="text-align: center; background: #ffe; '..
-- warning text; flatten it so that mw.ustring.format() gets a string
'margin: .75em 15%; padding: .5em; border: 1px solid #e3e3b0;'
field = field.missing
tag2  = mw.message.new( 'wm-license-information-'..param.field..'-missing' ):inLanguage(args.lang):plain()
tag3  = mw.message.new( 'wm-license-information-'..param.field..'-missing-request' ):inLanguage(args.lang):plain()
field = string.format('<div %s direction: %s;" lang="%s">%s\n%s\n</div>', tag1, dir, args.lang, tag2, tag3)
end
end
if field or args.demo then  -- skip the row if still no field
if field or (args.demo and param.tag) then  -- skip the row if still no field
tag = param.tag
tag   = message(param.tag or param.field, lang) .. (param.tag2 or '')
if string.sub(tag,1,10) == 'wm-license' then
cell1 = mw.ustring.format('<td %sclass="fileinfo-paramfield" lang="%s">%s</td>\n', id or '', lang, tag)
tag = mw.message.new( tag ):inLanguage(args.lang):plain() -- label message in args.lang language
cell2 = mw.ustring.format('<td %s>\n%s</td>', param.td or '', field or '')
end
field = mw.ustring.format('<tr style="vertical-align: top">\n%s%s\n</tr>\n\n', cell1, cell2)
cell1 = string.format('<td %sclass="fileinfo-paramfield" lang="%s">%s</td>\n', id or '', args.lang, tag)
cell2 = string.format('<td%s>'.. param.wrapper ..'</td>', param.td or '', field or '')
field = string.format('<tr style="vertical-align: top">\n%s%s\n</tr>\n\n', cell1, cell2)
end
end
end
end
Line 87: Line 98:


-- add table and outer layers
-- add table and outer layers
local style = string.format('class="fileinfotpl-type-information toccolours vevent '..
local style = mw.ustring.format('class="fileinfotpl-type-information toccolours vevent '..
'mw-content-%s" style="width: 100%%; direction: %s;" cellpadding="4"', dir, dir)
'mw-content-%s" style="width: 100%%; direction: %s;" cellpadding="4"', dir, dir)
results = string.format('<table %s>\n\n%s\n</table>\n', style, table.concat(results))
results = mw.ustring.format('<table %s>\n\n%s\n</table>\n', style, table.concat(results))
results = string.format('<div class="hproduct commons-file-information-table">\n%s\n</div>', results)
results = mw.ustring.format('<div class="hproduct commons-file-information-table">\n%s\n</div>', results)
return results
return results
end
end
Line 102: Line 113:
-- === Version of the function to be called from other LUA codes
-- === Version of the function to be called from other LUA codes
-- ===========================================================================
-- ===========================================================================
-------------------------------------------------------------------------------
-- _information function creates a wikicode for {{Information}} template based on
-- passed arguments (through "args") and data extracted from SDC. Allowed fields of
-- "args" are : 'description', 'date', 'permission', 'author', 'other_versions', 
-- 'source','other_fields', 'other_fields_1', 'demo' and 'lang'
-------------------------------------------------------------------------------
-- Dependencies: p._SDC_Description, p._SDC_Source, p._SDC_Author, p._SDC_Date,
--    Build_html, Module:ISOdate (_date)
-------------------------------------------------------------------------------
function p._information(args)
function p._information(args)


Line 110: Line 131:
-- ============================================================================================
-- ============================================================================================
local page = mw.title.getCurrentTitle()
local page = mw.title.getCurrentTitle()
local lang = args.lang
local namespace = page.namespace  -- get page namespace
local namespace = page.namespace  -- get page namespace
if namespace==6 or namespace==10 then
if namespace==6 or namespace==10 then
local allowedFields = {'description', 'date', 'permission', 'author', 'other_versions',   
local allowedFields = {'description', 'date', 'permission', 'author', 'other_versions',   
'source','other_fields', 'other_fields_1', 'demo', 'lang', 'mid', 'pageid'}
'source','other_fields', 'other_fields_1', 'demo', 'lang', 'strict'}
local set, badField = {}, {}
local set, badField = {}, {}
for _, field in ipairs(allowedFields) do set[field] = true end
for _, field in ipairs(allowedFields) do set[field] = true end
Line 122: Line 144:
end
end
if #badField>0 then
if #badField>0 then
cats = string.format('\n;<span style="color:red">Error in [[Template:Information|{{Information}}'..
cats = mw.ustring.format('\n;<span style="color:red">Error in [[Template:Information|{{Information}}'..
' template]]: unknown parameter "%s".</span>',  table.concat(badField,'", "'))
' template]]: unknown parameter "%s".</span>',  table.concat(badField,'", "'))
cats = cats .. '\n[[Category:Pages using Information template with incorrect parameter]]'
cats = cats .. '\n[[Category:Pages using Information template with incorrect parameter]]'
end
end
end
end
if namespace==6  then -- files are required to have at least the 3 fields below
if args.date then
-- apply ISODate to function to date string to convert date in ISO format to translated date string
args.date = ISOdate(args.date, lang, '', 'dtstart', '100-999')     
end
args.pagename = page.text
 
-- ====================================================
-- === harvest structured data                      ===
-- ====================================================
local entity = mw.wikibase.getEntity()
if namespace==6 and entity then -- file namespace
-- call SDC functions only when needed
local icon = true
-- local field is missing -> get it from SDC
args.description = args.description or p._SDC_Description(entity, lang, icon)  
args.source      = args.source      or p._SDC_Source(entity, lang, icon)
args.author      = args.author      or p._SDC_Author(entity, lang, icon)
args.date        = args.date        or p._SDC_Date(entity, lang, icon)
end
-- ====================================================
-- === add tracking templates and categories        ===
-- ====================================================
-- add the template tag (all official infoboxes transclude {{Infobox template tag}} so files without that tag do not have an infobox
mw.getCurrentFrame():expandTemplate{ title = 'Infobox template tag' }
 
-- files are required to have at least the 3 fields below
if args.strict~=false then
local reqFields = {description='Media lacking a description', author='Media lacking author information', source='Images without source'}
local reqFields = {description='Media lacking a description', author='Media lacking author information', source='Images without source'}
for field, errCat in pairs(reqFields) do  
for field, errCat in pairs(reqFields) do  
if args[field] and mw.ustring.match(args[field],"^[%s%p]+$") then
args[field]=nil;
end -- ignore punctuation only fields
if not args[field] then
if not args[field] then
cats = cats .. '\n[[Category:'.. errCat ..']]'
-- code equivalent to Template:Source missing, Template:Author missing, Template:Description missing
local tag1 = 'class="boilerplate metadata" id="cleanup" style="text-align: center; background: #ffe; '..
'margin: .75em 15%; padding: .5em; border: 1px solid #e3e3b0;'
local tag2 = message(field..'-missing', lang)
local tag3 = message(field..'-missing-request', lang)
local dir  = mw.language.new( lang ):getDir()    -- get text direction
args[field] = {missing =  mw.ustring.format('<div %s direction: %s;" lang="%s">%s\n%s\n</div>', tag1, dir, lang, tag2, tag3)}
cats = cats .. '\n[[Category:'.. errCat ..']]'
end
end
end
end
end
if namespace~=6  then
cats = '' -- categories are added only to files
end
end


return Build_html(args) .. cats
end


-- ====================================================
-------------------------------------------------------------------------------
-- === harvest structured data                      ===
-- interface for other Lua codes to 5 functions for extracting description, source,
-- ====================================================
-- author, date and location information from SDC.
-- at the moment we only harvest caption from SDC to use in case description is missing
-- INPUTS:
if namespace==6 and not args.description then -- file namespace
--  - "entity" - structure created by mw.wikibase.getEntity function
local entity = nil
--  - "lang"  - users language
if page.id>0 then -- some pages sometimes have pageid = 0
-------------------------------------------------------------------------------
entity = mw.wikibase.getEntity("M" .. page.id)
-- Dependencies: langWrapper
-------------------------------------------------------------------------------
function p._SDC_Description(entity, lang, icon)
-- create {{en|1=...}} template with SDC's caption
local description, _
if entity and entity.labels then -- get label in users language or one of that language fallback list
local label = core.langSwitch(entity.labels, lang)
local labels, D = {}, {}
if label then -- show either matching language
labels[lang] = label
else -- or if missing then show all
labels = entity.labels
end
end
if entity then  
for _, label in pairs(labels) do -- add {{en|1=....}} like wrapper
-- build language fallback list (snipit borrowed from (Module:Wikidata label]])
if icon and #D==0 then -- add editAtSDC icon to the first description
args.lang = string.lower(args.lang) or 'en'
label.value = label.value .. core.editAtSDC('ooui-php-4', lang)
local langList = mw.language.getFallbacksFor(args.lang)
end
table.insert(langList, 1, args.lang)
table.insert(D, langWrapper(label.value, label.language, lang))
end
-- get label in users language or one of that language fallback list
description = table.concat(D, '\n')
for _, language in ipairs(langList) do  -- loop over language fallback list looking for label in the specific language
end
args.description = entity:getLabel(language)  
return description
--args.description = langWrapper(args.description, language, args.lang) -- disable for time being as labels sometimes have wrong language codes
end
if args.description then  
 
break -- label found and we are done
-------------------------------------------------------------------------------
end
-- Dependencies: Module:Wikidata_date "_date" function, Module:ISOdate "_ISOdate" function
-------------------------------------------------------------------------------
function p._SDC_Date(entity, lang, icon)
-- get creation date from P571 (inception)
-- Code can handle YYYY-MM-DD, YYYY-MM, and YYYY dates without any additional resources
-- But can load [[Module:Wikidata date]] if needed
local Date
if entity and entity.claims and entity.claims.P571 then
local snak = entity.claims.P571[1].mainsnak
if (snak.snaktype == "value") then
local v = snak.datavalue.value
if v and (v.calendarmodel=='http://www.wikidata.org/entity/Q1985727') and (mw.ustring.sub(v.time,1,1)=='+') then
if v.precision >= 11 then            -- day
Date = mw.ustring.sub(v.time,2,11)   -- date in YYYY-MM-DD format
elseif v.precision == 10 then        -- month
Date = mw.ustring.sub(v.time,2,8)   -- date in YYYY-MM format
elseif v.precision == 9 then        -- year
Date = mw.ustring.sub(v.time,2,5)   -- date in YYYY format
end
if Date then -- translate
Date = ISOdate(Date, lang, '', 'dtstart', '100-999')
end
end
end
end
end
end  
if entity.claims.P571[1].qualifiers then                  -- non-trivial case: call heavy cavalery
local getDate = require("Module:Wikidata date")._date -- lazy loading: load only if needed
-- ====================================================
local result  = getDate(entity, 'P571', lang)        -- display the date in user's language
-- === add tag templates used for tracking          ===
Date = result.str
-- ====================================================
end
local frame = mw.getCurrentFrame()
end
-- add the template tag (all official infoboxes transclude {{Infobox template tag}} so files without that tag do not have an infobox
if icon and Date then
frame:expandTemplate{ title = 'Infobox template tag' }
Date = Date .. core.editAtSDC('P571', lang)
if args.date then
end
-- apply ISODate to function to date string to convert date in ISO format to translated date string
return Date
args.date = ISOdate._ISOdate(args.date, args.lang, '', 'dtstart', '100-999')    
end
end  
 
return Build_html(args) .. cats
-------------------------------------------------------------------------------
-- Dependencies: none
-------------------------------------------------------------------------------
function p._SDC_Source(entity, lang, icon)
-- get source from P7482 (source of file)
-- Code can handle {{Own}} template and URLs
local source, label
if entity and entity.claims and entity.claims.P7482 then
local statement = entity.claims.P7482[1]
-- get URL is source  is " file available on the internet (Q74228490) "
if statement.mainsnak.datavalue.value.id=='Q74228490' and statement.qualifiers and statement.qualifiers.P973 then
source = statement.qualifiers.P973[1].datavalue.value -- described at URL
if statement.qualifiers.P137 then -- "operator"
local id = statement.qualifiers.P137[1].datavalue.value.id
label = getBareLabel(id, lang)
source  = '[' .. source ..' ' .. label ..']'
end
end
-- add {{tl|own}} if source is "original creation by uploader (Q66458942)"
if statement.mainsnak.datavalue.value.id=='Q66458942' then
label = mw.message.new( 'Wm-license-own-work'):inLanguage(lang):plain()
source = mw.ustring.format('<span class="int-own-work" lang="%s">%s</span>',lang, label)
end
-- add {{tl|Own work by the original uploader}} if source is " Own work by the original uploader (Q87402110)"
if statement.mainsnak.datavalue.value.id=='Q87402110' then
label  = getBareLabel('Q87402110', lang)
source = mw.ustring.format('<span class="int-own-work" lang="%s">%s</span>',lang, label)
end
end
if icon and source then
source = source .. core.editAtSDC('P7482', lang)
end
return source
end
 
-------------------------------------------------------------------------------
-- Dependencies: Module:Core "getLabel" function
-------------------------------------------------------------------------------
function p._SDC_Author(entity, lang, icon)
-- get author from P170 (creator)
-- Code can handle usuall cases of "[[User:Example|Example]]" as well as users with Wikidata Item IDs
local author
if entity and entity.claims and entity.claims.P170 then
local creators = {}
for _,statement in ipairs(entity.claims.P170) do
if statement.mainsnak.snaktype == "value" then  -- Creator has item ID   
local val = statement.mainsnak.datavalue.value.id
table.insert(creators, core.getLabel(val, lang))
elseif statement.mainsnak.snaktype == "somevalue" then -- Creator defined by username
if statement.qualifiers then -- author name string (P2093)
    local qual = {}
local properties = {P2093='authorStr', P4174='username', P3831='role', P2699='url'}
for prop, field in pairs( properties ) do
if statement.qualifiers[prop] then
qual[field] = statement.qualifiers[prop][1].datavalue.value
end
end
local role = ''
if qual.role and entity.claims.P170[2] then -- add role only is multiple creators
role = '&nbsp;(' .. core.getLabel(qual.role.id, lang) .. ')'
end
if qual.username and qual.authorStr then        --   author name string (P2093) & Wikimedia username (P4174)
table.insert(creators, '[[User:'..qual.username..'|'..qual.authorStr..']]'..role)
elseif qual.username and not qual.authorStr then -- no author name string (P2093) & Wikimedia username (P4174)
table.insert(creators, '[[User:'..qual.username..'|'..qual.username..']]'..role)
elseif qual.url and qual.authorStr then         --    author name string (P2093) & URL (P2699)
table.insert(creators, '['..qual.url..' '..qual.authorStr..']'..role)
elseif qual.url and not qual.authorStr then      -- no author name string (P2093) & URL (P2699)
table.insert(creators, qual.url..role)
elseif  qual.authorStr then                      --    author name string (P2093)
table.insert(creators, qual.authorStr..role)
end
end
end
end -- end for
author = table.concat(creators, ', ')
end
if icon and author then
author = author .. core.editAtSDC('P170', lang)
end
return author
end
end


-- ===========================================================================
-------------------------------------------------------------------------------
-- === Version of the function to be called from template namespace
-- Dependencies: Module:Code "getLabel" function
-- ===========================================================================
-------------------------------------------------------------------------------
function p.information(frame)
function p._SDC_Location(entity, lang, icon)
-- switch to lowercase parameters to make them case independent
-- get location  P276 (location)
local args = {}
local location, prop
for name, value in pairs( frame:getParent().args ) do
if entity and entity.claims and entity.claims.P1071 then
if value ~= '' then -- nuke empty strings
local snak = entity.claims.P1071[1].mainsnak
local name1 = string.gsub( string.lower(name), ' ', '_')
if (snak.snaktype == "value") then  
args[name1] = value
location = core.getLabel(snak.datavalue.value.id, lang)
prop = 'P1071'
end
end
end
end
for name, value in pairs( frame.args ) do
if entity and entity.claims and entity.claims.P276 then
if value ~= '' then -- nuke empty strings
local snak = entity.claims.P276[1].mainsnak
local name1 = string.gsub( string.lower(name), ' ', '_')
if (snak.snaktype == "value") then  
args[name1] = value
location = core.getLabel(snak.datavalue.value.id, lang)
prop = 'P276'
end
end
end
end
if icon and location then
if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then  
location = location .. core.editAtSDC(prop, lang)
args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language
end
end
return location
-- call the inner "core" function
end
 
-- ===========================================================================
-- === Version of the functions to be called from template namespace
-- ===========================================================================
 
-------------------------------------------------------------------------------
-- information function creates a wikicode for {{Information}} template based on
-- passed arguments (through "frame") and data extracted from SDC. Allowed template
-- arguments are : 'description', 'date', 'permission', 'author', 'other_versions', 
-- 'source','other_fields', 'other_fields_1', 'demo' and 'lang'. All inputs do not
-- depend on capitalization and all "_" can be replaced with spaces.
-------------------------------------------------------------------------------
-- Dependencies: p._information
-------------------------------------------------------------------------------
function p.information(frame)
local args = core.getArgs(frame)
args.strict = true
return p._information(args)
return p._information(args)
end
-------------------------------------------------------------------------------
-- interface for templates to 5 functions for extracting description, source,
-- author, date and location information from SDC.
-- INPUTS (templaate parameters):
--  * "mid"  - pageID defining a file. Optional, defaulting to the current file.
--  * "lang"  - users language. Optional defaulting to the language of the user
--  * "icon"  - add "Edit this at Wikidata" icon? boolean ( 'true'/'false', 'yes'/'no', 1/0
-------------------------------------------------------------------------------
-- Dependencies: getEntity
-------------------------------------------------------------------------------
local function parseFrame(frame)
local args = core.getArgs(frame)
local entity = mw.wikibase.getEntity( args.mid )
local icon  = core.yesno(args.icon, true)
return {entity, args.lang, icon}
end
function p.SDC_Description(frame)
return p._SDC_Description(unpack(parseFrame(frame)))
end
function p.SDC_Source(frame)
return p._SDC_Source(unpack(parseFrame(frame)))
end
function p.SDC_Author(frame)
return p._SDC_Author(unpack(parseFrame(frame)))
end
function p.SDC_Date(frame)
return p._SDC_Date(unpack(parseFrame(frame)))
end
function p.SDC_Location(frame)
return p._SDC_Location(unpack(parseFrame(frame)))
end
end


return p
return p
-------------------------------------------------------------------------------
-- List of exported functions
-------------------------------------------------------------------------------
-- information
-- SDC_Description
-- SDC_Source
-- SDC_Author
-- SDC_Date
-- SDC_Location

Latest revision as of 00:09, 3 February 2023

Documentation for this module may be created at Module:Information/doc

--[[  
  __  __           _       _        ___        __                            _   _             
 |  \/  | ___   __| |_   _| | ___ _|_ _|_ __  / _| ___  _ __ _ __ ___   __ _| |_(_) ___  _ __  
 | |\/| |/ _ \ / _` | | | | |/ _ (_)| || '_ \| |_ / _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \ 
 | |  | | (_) | (_| | |_| | |  __/_ | || | | |  _| (_) | |  | | | | | | (_| | |_| | (_) | | | |
 |_|  |_|\___/ \__,_|\__,_|_|\___(_)___|_| |_|_|  \___/|_|  |_| |_| |_|\__,_|\__|_|\___/|_| |_|
                                                                                               
This module is intended to be the engine behind "Template:Information".

Please do not modify this code without applying the changes first at
"Module:Information/sandbox" and testing at "Module:Information/testcases".

Authors and maintainers:
* User:Jarekt - original version 
]]
-- =======================================
-- === Dependencies ======================
-- =======================================
require('Module:No globals') -- used for debugging purposes as it detects cases of unintended global variables
local ISOdate = require('Module:ISOdate')._ISOdate -- date localization
local core    = require('Module:Core')

-- ==================================================
-- === Internal functions ===========================
-- ==================================================

local function langWrapper(text, textLang) 
-- code equivalent to https://commons.wikimedia.org/wiki/Template:Description
	local language = mw.language.new( textLang )
	local dir      = language:getDir()  
	local LangName = language:ucfirst(mw.language.fetchLanguageName( textLang, textLang))
	local str = mw.ustring.format('<span class="language %s"><b>%s:</b></span>', textLang, LangName)
    return mw.ustring.format('<div class="description mw-content-%s" dir="%s" lang="%s">%s %s</div>', dir, dir, textLang, str, text)
end

-------------------------------------------------------------------------------
local function getBareLabel(id, userLang) 
-- code equivalent to require("Module:Wikidata label")._getLabel with Wikidata=- option
	local label, link
	-- build language fallback list
	local langList = mw.language.getFallbacksFor(userLang)
	table.insert(langList, 1, userLang)
	for _, lang in ipairs(langList) do  -- loop over language fallback list looking for label in the specific language
		label = mw.wikibase.getLabelByLang(id, lang)
		if label then break end                    -- label found and we are done
	end	
	return label or id
end

-------------------------------------------------------------------------------
local function message(name, lang)
	return mw.message.new( 'wm-license-information-'..name ):inLanguage(lang):plain()
end

-- ====================================================================
-- === This function is just responsible for producing HTML of the  ===
-- === template. At this stage all the fields are already filed     ===
-- ====================================================================
local function Build_html(args)
	local lang = args.lang -- user's language
	local dir  = mw.language.new( lang ):getDir()    -- get text direction
	local desTag = mw.ustring.format('<span class="summary fn" style="display:none">%s</span>', args.pagename)
	local prmTag = mw.ustring.format("<br /><small>([[%s|%s]])</small>", message('permission-reusing-link', lang), 
								 message('permission-reusing-text', lang))

	-- field specific preferences
	local params = {
		{field='description'    , id='fileinfotpl_desc', tag2=desTag, td='class="description"'},
		{field='other_fields_1'},
		{field='date'           , id='fileinfotpl_date', td=mw.ustring.format('lang="%s"', lang)},
		{field='source'         , id='fileinfotpl_src'}, 
		{field='author'         , id='fileinfotpl_aut'},
		{field='permission'     , id='fileinfotpl_perm', tag2=prmTag },
		{field='other_versions' , id='fileinfotpl_ver',  tag='other-versions'}, 
		{field='other_fields'},
	}
	local results = {}
	for _, param in ipairs(params) do
		local field, tag, cell1, cell2, id
		field = args[param.field]
		if param.id then -- skip "other fields" parameter
			if type(field) == 'string' then  -- add "id" to first <td> cell only if the field is present
				id = mw.ustring.format('id="%s" ', param.id)
			elseif type(field) == 'table' then
				-- the field was initially not present, it contains only our
				-- warning text; flatten it so that mw.ustring.format() gets a string
				field = field.missing
			end
			if field or (args.demo and param.tag) then  -- skip the row if still no field
				tag   = message(param.tag or param.field, lang) .. (param.tag2 or '')
				cell1 = mw.ustring.format('<td %sclass="fileinfo-paramfield" lang="%s">%s</td>\n', id or '', lang, tag)
				cell2 = mw.ustring.format('<td %s>\n%s</td>', param.td or '', field or '')
				field = mw.ustring.format('<tr style="vertical-align: top">\n%s%s\n</tr>\n\n', cell1, cell2)
			end
		end
		table.insert(results, field)
	end

	-- add table and outer layers
	local style = mw.ustring.format('class="fileinfotpl-type-information toccolours vevent '..
		'mw-content-%s" style="width: 100%%; direction: %s;" cellpadding="4"', dir, dir)
	results = mw.ustring.format('<table %s>\n\n%s\n</table>\n', style, table.concat(results))
	results = mw.ustring.format('<div class="hproduct commons-file-information-table">\n%s\n</div>', results)
	return results
end

-- ==================================================
-- === External functions ===========================
-- ==================================================
local p = {}

-- ===========================================================================
-- === Version of the function to be called from other LUA codes
-- ===========================================================================

-------------------------------------------------------------------------------
-- _information function creates a wikicode for {{Information}} template based on
-- passed arguments (through "args") and data extracted from SDC. Allowed fields of 
-- "args" are : 'description', 'date', 'permission', 'author', 'other_versions',  
-- 'source','other_fields', 'other_fields_1', 'demo' and 'lang'
-------------------------------------------------------------------------------
-- Dependencies: p._SDC_Description, p._SDC_Source, p._SDC_Author, p._SDC_Date, 
--    Build_html, Module:ISOdate (_date)
-------------------------------------------------------------------------------
function p._information(args)

	local cats = ''
	
	-- ============================================================================================
	-- === add [[Category:Pages using Information template with incorrect parameter]] if needed ===
	-- ============================================================================================
	local page = mw.title.getCurrentTitle()
	local lang = args.lang
	local namespace = page.namespace   -- get page namespace
	if namespace==6 or namespace==10 then
		local allowedFields = {'description', 'date', 'permission', 'author', 'other_versions',  
				'source','other_fields', 'other_fields_1', 'demo', 'lang', 'strict'}
		local set, badField = {}, {}
		for _, field in ipairs(allowedFields) do set[field] = true end
		for field, _ in pairs( args ) do 
			if not set[field] then
				table.insert(badField, field)
			end
		end
		if #badField>0 then
			cats = mw.ustring.format('\n;<span style="color:red">Error in [[Template:Information|{{Information}}'..
				' template]]: unknown parameter "%s".</span>',  table.concat(badField,'", "'))
			cats = cats .. '\n[[Category:Pages using Information template with incorrect parameter]]'
		end
	end
	if args.date then
		-- apply ISODate to function to date string to convert date in ISO format to translated date string
		args.date = ISOdate(args.date, lang, '', 'dtstart', '100-999')      
	end 
	args.pagename = page.text

	-- ====================================================
	-- === harvest structured data                      === 
	-- ====================================================
	local entity = mw.wikibase.getEntity()
	if namespace==6 and entity then -- file namespace
		-- call SDC functions only when needed
		local icon = true
		-- local field is missing -> get it from SDC
		args.description = args.description or p._SDC_Description(entity, lang, icon)  
		args.source      = args.source      or p._SDC_Source(entity, lang, icon)
		args.author      = args.author      or p._SDC_Author(entity, lang, icon) 
		args.date        = args.date        or p._SDC_Date(entity, lang, icon)
	end
	
	-- ====================================================
	-- === add tracking templates and categories        === 
	-- ====================================================
	-- add the template tag (all official infoboxes transclude {{Infobox template tag}} so files without that tag do not have an infobox
	mw.getCurrentFrame():expandTemplate{ title = 'Infobox template tag' } 

	-- files are required to have at least the 3 fields below
	if args.strict~=false then
		local reqFields = {description='Media lacking a description', author='Media lacking author information', source='Images without source'}
		for field, errCat in pairs(reqFields) do 
			if args[field] and mw.ustring.match(args[field],"^[%s%p]+$") then 
				args[field]=nil; 
			end -- ignore punctuation only fields
			if not args[field] then
				-- code equivalent to Template:Source missing, Template:Author missing, Template:Description missing
				local tag1 = 'class="boilerplate metadata" id="cleanup" style="text-align: center; background: #ffe; '..
					'margin: .75em 15%; padding: .5em; border: 1px solid #e3e3b0;'
				local tag2 = message(field..'-missing', lang)
				local tag3 = message(field..'-missing-request', lang)
				local dir  = mw.language.new( lang ):getDir()    -- get text direction
				args[field] = {missing =  mw.ustring.format('<div %s direction: %s;" lang="%s">%s\n%s\n</div>', tag1, dir, lang, tag2, tag3)}
				cats = cats .. '\n[[Category:'.. errCat ..']]'
			end
		end
	end
	if namespace~=6  then 
		cats = '' -- categories are added only to files
	end

	return Build_html(args) .. cats
end

-------------------------------------------------------------------------------
-- interface for other Lua codes to 5 functions for extracting description, source,
-- author, date and location information from SDC. 
-- INPUTS:
--  - "entity" - structure created by mw.wikibase.getEntity function
--  - "lang"  - users language
-------------------------------------------------------------------------------
-- Dependencies: langWrapper
-------------------------------------------------------------------------------
function p._SDC_Description(entity, lang, icon)
	-- create {{en|1=...}} template with SDC's caption
	local description, _
	if entity and entity.labels then -- get label in users language or one of that language fallback list
		local label = core.langSwitch(entity.labels, lang) 
		local labels, D = {}, {}
		if label then -- show either matching language
			labels[lang] = label
		else -- or if missing then show all
			labels = entity.labels
		end
		for _, label in pairs(labels) do -- add {{en|1=....}} like wrapper
			if icon and #D==0 then -- add editAtSDC icon to the first description
				label.value = label.value .. core.editAtSDC('ooui-php-4', lang)
			end
			table.insert(D, langWrapper(label.value, label.language, lang))
		end 
		description = table.concat(D, '\n') 
	end
	return description
end

-------------------------------------------------------------------------------
-- Dependencies: Module:Wikidata_date "_date" function, Module:ISOdate "_ISOdate" function
-------------------------------------------------------------------------------
function p._SDC_Date(entity, lang, icon)
	-- get creation date from  P571 (inception)
	-- Code can handle YYYY-MM-DD, YYYY-MM, and YYYY dates without any additional resources
	-- But can load [[Module:Wikidata date]] if needed
	local Date
	if entity and entity.claims and entity.claims.P571 then
		local snak = entity.claims.P571[1].mainsnak
		if (snak.snaktype == "value") then 
			local v = snak.datavalue.value
			if v and (v.calendarmodel=='http://www.wikidata.org/entity/Q1985727') and (mw.ustring.sub(v.time,1,1)=='+') then 
				if v.precision >= 11 then            -- day
					Date = mw.ustring.sub(v.time,2,11)   -- date in YYYY-MM-DD format
				elseif v.precision == 10 then        -- month
					Date = mw.ustring.sub(v.time,2,8)    -- date in YYYY-MM format
				elseif v.precision == 9 then         -- year
					Date = mw.ustring.sub(v.time,2,5)    -- date in YYYY format
				end
				if Date then -- translate
					Date = ISOdate(Date, lang, '', 'dtstart', '100-999')
				end
			end
		end
		if entity.claims.P571[1].qualifiers then                  -- non-trivial case: call heavy cavalery
			local getDate = require("Module:Wikidata date")._date -- lazy loading: load only if needed
			local result  = getDate(entity, 'P571', lang)         -- display the date in user's language
			Date = result.str
		end
	end
	if icon and Date then
		Date = Date .. core.editAtSDC('P571', lang)
	end
	return Date
end

-------------------------------------------------------------------------------
-- Dependencies: none
-------------------------------------------------------------------------------
function p._SDC_Source(entity, lang, icon)
	-- get source from P7482 (source of file)
	-- Code can handle {{Own}} template and URLs 
	local source, label
	if entity and entity.claims and entity.claims.P7482 then
		local statement = entity.claims.P7482[1]
		-- get URL is source  is " file available on the internet (Q74228490) " 
		if statement.mainsnak.datavalue.value.id=='Q74228490' and statement.qualifiers and statement.qualifiers.P973 then
			source = statement.qualifiers.P973[1].datavalue.value -- described at URL
			if statement.qualifiers.P137 then -- "operator"
				local id = statement.qualifiers.P137[1].datavalue.value.id
				label = getBareLabel(id, lang)
				source  = '[' .. source ..' ' .. label ..']'
			end
		end
		-- add {{tl|own}} if source is "original creation by uploader (Q66458942)" 
		if statement.mainsnak.datavalue.value.id=='Q66458942' then
			label = mw.message.new( 'Wm-license-own-work'):inLanguage(lang):plain()
			source = mw.ustring.format('<span class="int-own-work" lang="%s">%s</span>',lang, label)
		end
		-- add {{tl|Own work by the original uploader}} if source is " Own work by the original uploader (Q87402110)" 
		if statement.mainsnak.datavalue.value.id=='Q87402110' then
			label  = getBareLabel('Q87402110', lang)
			source = mw.ustring.format('<span class="int-own-work" lang="%s">%s</span>',lang, label)
		end
	end
	if icon and source then
		source = source .. core.editAtSDC('P7482', lang)
	end
	return source
end

-------------------------------------------------------------------------------
-- Dependencies: Module:Core "getLabel" function
-------------------------------------------------------------------------------
function p._SDC_Author(entity, lang, icon)
	-- get author from P170 (creator)
	-- Code can handle usuall cases of "[[User:Example|Example]]" as well as users with Wikidata Item IDs
	local author
	if entity and entity.claims and entity.claims.P170 then
		local creators = {}
		for _,statement in ipairs(entity.claims.P170) do
			if statement.mainsnak.snaktype == "value" then  -- Creator has item ID    
				local val = statement.mainsnak.datavalue.value.id
				table.insert(creators, core.getLabel(val, lang))
			elseif statement.mainsnak.snaktype == "somevalue" then -- Creator defined by username
				if statement.qualifiers then -- author name string (P2093) 
				    local qual = {}
					local properties = {P2093='authorStr', P4174='username', P3831='role', P2699='url'}
					for prop, field in pairs( properties ) do
						if statement.qualifiers[prop] then
							qual[field] = statement.qualifiers[prop][1].datavalue.value
						end
					end
					local role = ''
					if qual.role and entity.claims.P170[2] then -- add role only is multiple creators
						role = '&nbsp;(' .. core.getLabel(qual.role.id, lang) .. ')'
					end
					if qual.username and qual.authorStr then         --    author name string (P2093) & Wikimedia username (P4174) 
						table.insert(creators, '[[User:'..qual.username..'|'..qual.authorStr..']]'..role)
					elseif qual.username and not qual.authorStr then -- no author name string (P2093) & Wikimedia username (P4174) 
						table.insert(creators, '[[User:'..qual.username..'|'..qual.username..']]'..role)
					elseif qual.url and qual.authorStr then          --    author name string (P2093) & URL (P2699) 
						table.insert(creators, '['..qual.url..' '..qual.authorStr..']'..role)
					elseif qual.url and not qual.authorStr then      -- no author name string (P2093) & URL (P2699) 
						table.insert(creators, qual.url..role)
					elseif  qual.authorStr then                      --    author name string (P2093) 
						table.insert(creators, qual.authorStr..role)
					end
				end
			end
		end -- end for
		author = table.concat(creators, ', ')
	end
	if icon and author then
		author = author .. core.editAtSDC('P170', lang)
	end
	return author
end

-------------------------------------------------------------------------------
-- Dependencies: Module:Code "getLabel" function
-------------------------------------------------------------------------------
function p._SDC_Location(entity, lang, icon)
	-- get location  P276 (location)
	local location, prop
	if entity and entity.claims and entity.claims.P1071 then
		local snak = entity.claims.P1071[1].mainsnak
		if (snak.snaktype == "value") then 
			location = core.getLabel(snak.datavalue.value.id, lang)
			prop = 'P1071'
		end
	end
	if entity and entity.claims and entity.claims.P276 then
		local snak = entity.claims.P276[1].mainsnak
		if (snak.snaktype == "value") then 
			location = core.getLabel(snak.datavalue.value.id, lang)
			prop = 'P276'
		end
	end
	if icon and location then
		location = location .. core.editAtSDC(prop, lang)
	end
	return location
end

-- ===========================================================================
-- === Version of the functions to be called from template namespace
-- ===========================================================================

-------------------------------------------------------------------------------
-- information function creates a wikicode for {{Information}} template based on
-- passed arguments (through "frame") and data extracted from SDC. Allowed template
-- arguments are : 'description', 'date', 'permission', 'author', 'other_versions',  
-- 'source','other_fields', 'other_fields_1', 'demo' and 'lang'. All inputs do not 
-- depend on capitalization and all "_" can be replaced with spaces.
-------------------------------------------------------------------------------
-- Dependencies: p._information
-------------------------------------------------------------------------------
function p.information(frame)
	local args = core.getArgs(frame)
	args.strict = true
	return p._information(args)	
end

-------------------------------------------------------------------------------
-- interface for templates to 5 functions for extracting description, source,
-- author, date and location information from SDC. 
-- INPUTS (templaate parameters):
--  * "mid"   - pageID defining a file. Optional, defaulting to the current file.
--  * "lang"  - users language. Optional defaulting to the language of the user
--  * "icon"  - add "Edit this at Wikidata" icon? boolean ( 'true'/'false', 'yes'/'no', 1/0
-------------------------------------------------------------------------------
-- Dependencies: getEntity
-------------------------------------------------------------------------------
local function parseFrame(frame)
	local args = core.getArgs(frame)
	local entity = mw.wikibase.getEntity( args.mid )
	local icon   = core.yesno(args.icon, true)
	return {entity, args.lang, icon}
end

function p.SDC_Description(frame)
	return p._SDC_Description(unpack(parseFrame(frame)))
end

function p.SDC_Source(frame)
	return p._SDC_Source(unpack(parseFrame(frame)))
end

function p.SDC_Author(frame)
	return p._SDC_Author(unpack(parseFrame(frame)))
end

function p.SDC_Date(frame)
	return p._SDC_Date(unpack(parseFrame(frame)))
end

function p.SDC_Location(frame)
	return p._SDC_Location(unpack(parseFrame(frame)))
end

return p

-------------------------------------------------------------------------------
-- List of exported functions
-------------------------------------------------------------------------------
-- information
-- SDC_Description
-- SDC_Source
-- SDC_Author
-- SDC_Date
-- SDC_Location