FANDOM


--[[  
 
This module is intended to be the engine behind "Template:Creator".
 
Please do not modify this code without applying the changes first at "Module:Creator/sandbox" and testing 
at "Module:Creator/testcases".
 
Authors and maintainers:
* User:Jarekt - original version 
 
 
Handling of the fields
 ==============================================================================
 |field name        | property  | pull | push | missing  | mismatch | redundant 
 ==============================================================================
 |Name              | label     | 1    |  0   |          |          |
 |Alternative names |           |      |  0   |          |          |
 |Sortkey           | P734,P735 | 1    |  0   |          |          | 1
 |Birthdate         | P569      | 1*   |  1   |  1       | 1*       | 1*
 |Deathdate         | P570      | 1*   |  1   |  1       | 1*       | 1*
 |Birthloc          | P19       | 1    |  1*  |  1       | 1        | 1
 |Deathloc          | P20       | 1    |  1*  |  1       | 1        | 1
 |Workperiod        |P2031,P2032| 1    |      |          |          |
 |Workloc           | P937      | 1*   |  1*  |  1       | 1        | 1
 |Image             | P18       | 1    |  1   |  1       | 1        | 1
 |Homecat           | P373      | 1    |  1   |  1       | 1        | 1
 |Nationality       | P27       | 1*   |      |  1       | 1        | 1
 |Gender            | P21       | 1    |  1   |  1       | 1        | 1
 |Occupation        | P106      | 1*   |      |          |          |
 |Linkback          | P1472     | 1    |  1   |  1       | 1        | 1
 |Wikisource        | sitelinks | 1    |  0   |          |          | 1
 |Wikiquote         | sitelinks | 1    |  0   |          |          | 1
 ===============================================================================
 
 pull - can we pull data from wikidata ? 
   - 2  - wikidata then commons
   - 1  - commons then wikidata
   - 1* - commons then wikidata but still needs work
   -    - not implemented yet
   - 0  - will not implement
 push      - upload to wikidata through quick statements?
 missing   - detect if missing on Wikidata
 mismatch  - detect mismatch between wikidata and commons
 redundant - detect if redundant identical values on wikidata and commons
]]
local Wikidata1 = require("Module:Wikidata")
local Wikidata2 = require("Module:Wikidata label")    -- used for creation of name based on wikidata
local Wikidata3 = require("Module:Wikidata date")     -- used for procesing of date properties
local AC        = require("Module:Authority control") -- used for formating of AC row
local Name      = require("Module:Name")    -- used for adding "options" fields to "name"
local City      = require("Module:City")    -- used to add wikidata bases links to names of places
local ISOdate   = require("Module:ISOdate") -- used for internationalization of dates
local q2iso     = require("Module:Creator/conf")
 
-- ==================================================
-- === Internal functions ===========================
-- ==================================================
 
local function empty2nil(str)
	if str=='' then
		return nil
	else 
		return str;
	end
end
 
local function timestamp(dateStr)
	local tStamp = nil
	if string.match(dateStr,"^%d%d%d%d$") then               -- if YYYY  format 
		tStamp = '+' .. dateStr .. '-00-00T00:00:00Z/9'
	elseif string.match(dateStr,"^%d%d%d%d%-%d%d$") then      -- if YYYY-MM format 
		tStamp = '+' .. dateStr .. '-00T00:00:00Z/10'
	elseif string.match(dateStr,"^%d%d%d%d%-%d%d%-%d%d$") then  -- if YYYY-MM-DD format 
		tStamp = '+' .. dateStr .. 'T00:00:00Z/11'
	end
	return tStamp
end
 
-- ====================================================================
-- This function is responsible for producing HTML of a single row of the template
-- At this stage all the fields are already filed. There is either one or two fields
-- INPUTS:
-- * param1 and param2 - structures for 2 fields containing fields:
--    - tag      - I18n tag used for localization of the field name. Usually name of page in MediaWiki namespace which was imported from translatewiki.org. 
--                 Alternative is to pass already translated field name.
--    - field    - field content
--    - id       - ID tag added to HTML's <td> cell. if IDs of 2 fields ar the same than we ignore the second one
--    - wrapper  - some fields need a <span class=...> wrapper around the field content 
-- ====================================================================
local function Build_html_row(param1, param2, args)
	local tag, cell1, cell2, cell3
	local field1 = args[param1.field]
	local field2 = args[param2.field]
	if field1=='' then field1=nul; end
	if field2=='' then field2=nul; end
	if not (field1 or field2 or args.demo) then 
		return ''
	end
	if field2 then tag = param2.tag	else tag = param1.tag	end -- use different tag based on presence of field2
	if string.sub(tag,1,10) == 'wm-license' then
		tag = mw.message.new( tag ):inLanguage(args.lang):plain() -- label message in args.lang language
	end
	cell1 = string.format('<td style="%s">%s</td>\n', args.style2, tag)
	if param1.id==param2.id then -- 2 cell row
		cell2 = string.format('<td colspan="2" style="%s" id="%s">'.. param1.wrapper ..'</td>', args.style1, param1.id, field1 or '')
		cell3 = ''
	else                         -- 3 cell row
		cell2 = string.format('<td style="min-width:100px; %s" id="%s">\n%s</td>', args.style1, param1.id, field1 or '')
		cell3 = string.format('<td style="min-width:100px; %s" id="%s">\n%s</td>', args.style1, param2.id, field2 or '')
	end
	return string.format('<tr valign="top">\n%s%s%s</tr>\n', cell1, cell2, cell3)
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 results, line, style, field
	args.style1 = 'border:1px solid #aaa;'
	args.style2 = 'background-color:#e0e0ee; font-weight:bold; ' .. args.style1
	args.style3 = 'min-width:130px; ' .. args.style1
 
	-- Top line with Creator name, lifespan and link icons -
	field = string.format('<span class="fn" id="creator"><bdi>%s\n</bdi></span>&nbsp;%s', args.name or 'missing name', args.lifespan or '') 
	field = string.format('%s&nbsp;[[File:Blue pencil.svg|15px|%s|link=%s]]', field, args.linkback_tag, args.linkback or '') 
	if args.wikidata then -- Wikidata Link
		field = string.format('%s&nbsp;[[File:Wikidata-logo.svg|20px|wikidata:%s|link=wikidata:%s]]', field, args.wikidata, args.wikidata) 
	end
	if args.wikisource then --Wikisource link
		field = string.format('%s&nbsp;[[File:Wikisource-logo.svg|15px|%s|link=%s]]', field, args.wikisource, args.wikisource) 
	end
	if args.wikiquote then --Wikiquote link
		field = string.format('%s&nbsp;[[File:Wikiquote-logo.svg|15px|%s|link=%s]]', field, args.wikiquote, args.wikiquote) 
	end
	if args.QS then -- quick_statement link to upload missing info to wikidata
		field = string.format('%s&nbsp;%s', field, args.QS) 
	end
	line = string.format('<th colspan="4" style="%s">%s</th>', args.style2, field) 
	results = string.format('<tr valign="top">\n%s\n</tr>\n', line)
 
	-- Stub 
	if args.type and string.lower(args.type) == 'stub' then
		if not args.stub_label then 
			args.stub_label = string.format('This template is a [[w:Wikipedia:Stub|stub]]. Click [[%s|here]] to expand it.', args.linkback)
		end
		line = string.format('<th colspan="4" style="%s font-weight:bold;">%s\n</th>', args.style2, args.stub_label) 
		results = string.format('%s<tr valign="top">\n%s\n</tr>\n', results, line)
	end
 
	-- Image on the Left
	if not args.image and args.demo then
		args.image = 'Silver - replace this image male.svg'
	end
	if args.image then --Wikiquote link
		if not args.imgwidth then 
			args.imgwidth = '120'
		end
		field = string.format('[[File:%s|%sx360px|alt=%s|class=photo]]', args.image, args.imgwidth, args.name or '') 
		line = string.format('<td rowspan="9" style="width:%spx" id="fileinfotpl_creator_image"><span class="wpImageAnnotatorControl wpImageAnnotatorOff">%s</span></td>', args.imgwidth, field) 
		results = string.format('%s<tr valign="top">\n%s\n</tr>\n', results, line)	
	end
 
	-- add other fields
	local param = {
		{tag='wm-license-creator-alternative-names'          , field='alternative_names', id='fileinfotpl_creator_alt-name_value'   , wrapper='<span class="nickname">\n%s</span>' },
		{tag='wm-license-creator-description'                , field='description'      , id='fileinfotpl_creator_desc_value'       , wrapper='%s' },
		{tag='wm-license-creator-date-of-birth'              , field='birthdate'        , id='fileinfotpl_creator_birthdate_value'  , wrapper='%s' },
		{tag='wm-license-creator-date-of-birth-and-death'    , field='deathdate'        , id='fileinfotpl_creator_deathdate_value'  , wrapper='%s' },
		{tag='wm-license-creator-location-of-birth'          , field='birthloc'         , id='fileinfotpl_creator_birthloc_value'   , wrapper='%s' },
		{tag='wm-license-creator-location-of-birth-and-death', field='deathloc'         , id='fileinfotpl_creator_deathloc_value'   , wrapper='%s' },
		{tag='wm-license-creator-work-period'                , field='workperiod'       , id='fileinfotpl_creator_work-period_value', wrapper='%s' },
		{tag='wm-license-creator-work-location'              , field='workloc'          , id='fileinfotpl_creator_work-location'    , wrapper='<span class="locality">\n%s</span>' },
		{tag=args.authority_tag                              , field='authority'        , id='fileinfotpl_creator_authority_value'  , wrapper='%s' },
		{tag='wm-license-artwork-references'                 , field='references'       , id='fileinfotpl_creator_references'       , wrapper='<span>\n%s</span>'}
	}
	results = results .. Build_html_row(param[ 1], param[ 1], args)
	results = results .. Build_html_row(param[ 2], param[ 2], args)
	results = results .. Build_html_row(param[ 3], param[ 4], args)
	results = results .. Build_html_row(param[ 5], param[ 6], args)
	results = results .. Build_html_row(param[ 7], param[ 7], args)
	results = results .. Build_html_row(param[ 8], param[ 8], args)
	results = results .. Build_html_row(param[ 9], param[ 9], args)
	results = results .. Build_html_row(param[10], param[10], args)
 
	-- build table
	local dir, text_align
	local collapsed = ''
	if mw.language.new( args.lang ):isRTL() then
		dir = 'rtl'
		text_align = 'right'
	else
		dir = 'ltr'
		text_align = 'left'
	end 
	if args.namespace == 6 then
		collapsed = 'collapsed'
	end
	local style = string.format('class="toccolours collapsible %s" cellpadding="2" cellspacing="0" style="direction:%s; text-align:%s; border-collapse:collapse; background:#f0f0ff; border:1px solid #aaa;" lang="%s"',
		collapsed, dir, text_align, args.lang)
	results = string.format('<table %s>\n%s\n</table>\n', style, results)
	results = string.format('<div class="vcard">\n%s\n</div>\n', results)
 
	-- add references and documentation which are only visible in creator namespace
	if args.namespace==100 then
		local doc = mw.getCurrentFrame():expandTemplate{ title ='documentation', args = { 'Template:Creator/documentation' } }
		results = results .. doc -- add documentation to pages in creator namespace
	end
	return results
end
 
-- ===========================================================================
-- === This function is just responsible for adding maintenance categories ===
-- === which are not related to wikidata                                   ===
-- === INPUTS:                                                             ===
-- ===  * args  - merged data from the inputs and Wikidata                 ===
-- ===========================================================================
local function add_maintenance_categories(args)
	local cats = '' -- categories 
 
	-- ====================================================
	-- === automatic tagging of pages in all namespaces === 
	-- ====================================================
	if args.type=='' or args.type=='person' then
	    -- add an empty template which can be used as a tag in CatScan
		local dod  = args.deathyear or args.deathdate -- date of death
		local dob  = args.birthyear or args.birthdate -- date of birth
		local d    = os.date('!*t')
		local year = tonumber(d.year)                 -- current year
		local pma  = nil                              -- years since death
		if dod then
			dod = tonumber(ISOdate._ISOyear(dod))
			if dod then
				pma = year-dod
			end
		end
		if dob and not pma then
			dob = tonumber(ISOdate._ISOyear(dob))
			if dob then
				pma = year-dob-100 -- Assumes max 100 lifespan
			end
		end
 
		local tag = nil
		if pma and pma>100 then 
			mw.getCurrentFrame():expandTemplate{ title ='Works of authors who died more than 100 years ago' }
		elseif pma and pma>70 then 
			mw.getCurrentFrame():expandTemplate{ title ='Works of authors who died more than 70 years ago' }
		elseif (dod or dob or 0)>year-65 then 
			mw.getCurrentFrame():expandTemplate{ title ='Works of authors who died less than 65 years ago' }
		end
	end 
 
	-- ============================================================
	-- === automatic categorization of pages in File: namespace === 
	-- ============================================================
	if args.namespace==6 then
		if not args.image then
			mw.getCurrentFrame():expandTemplate{ title = 'Creator template no image' } -- add the template tag
		end
		return cats
	end
 
	-- ===============================================================
	-- === automatic categorization of pages in Creator: namespace === 
	-- === all pages                                               ===
	-- ===============================================================
	if args.namespace~=100 then
		return cats
	end
 
	-- add [[Category:Creator templates]] category
	cats = cats .. string.format('\n[[Category:Creator templates|%s]]',args.sortkey or ' ')
 
	-- check for key information
	if not args.linkback or not args.name or not args.sortkey then
		cats = cats .. '\n[[Category:Creator templates without key information]]'
	end
 
	-- add homecat category
	if args.homecat then
		cats = cats .. string.format('\n[[Category:%s]]',args.homecat)
	end
 
	-- add type category
	if args.type then
		local lut = { 
			['commons user'] = '\n[[Category:User creator templates]]',
			['corporation']  = '\n[[Category:Corporate creator templates]]',
			['group']        = '\n[[Category:Group creator templates]]',
			['stub']         = '\n[[Category:Creator template stubs]]'
		}
		cats = cats ..  (lut[args.type] or '')
		if args.type=='commons user' then
			return cats
		end
	elseif args.image and not args.gender then
		cats = cats .. '\n[[Category:Creator templates with image but no gender]]'
	end
 
	-- ===============================================================
	-- === automatic categorization of pages in Creator: namespace === 
	-- === all pages except: 'commons user'  and 'stub' type       ===
	-- ===============================================================
 
	-- check for image
	if not args.image then
		cats = cats .. '\n[[Category:Creator templates without images]]'
	end
	-- check for wikidata q-code
	if not args.wikidata then
		cats = cats .. '\n[[Category:Creator templates without Wikidata link]]'
	end
	-- check for homecat
	if not args.homecat then
		cats = cats .. '\n[[Category:Creator templates without home category]]'
	else
		local hc = mw.title.new('Category:'..args.homecat)
		if not hc.exists then
			cats = cats .. '\n[[Category:Creator templates with non-existing home categories]]'
		end 
		hc = mw.title.new('Creator:'..args.homecat)
		if hc:localUrl() ~= mw.title.getCurrentTitle():localUrl() then
			cats = cats .. '\n[[Category:Creator templates with non-matching home categories]]'
		end
	end
 
	return cats
end
 
-- ===========================================================================
-- === This function is responsible for adding maintenance categories      ===
-- === to pages in category namespace                                      ===
-- === INPUTS:                                                             ===
-- ===  * args - original inputs from the creator template page            ===
-- ===========================================================================
local function add_categories_to_category_namespace(args)
	local cats
	if args.namespace~=14 or args.homecat and mw.title.new('Category:' .. args.homecat):localUrl() ~= mw.title.getCurrentTitle():localUrl() then
		return '' -- if not a home category than exit
	end
 
	cats = string.format('\n[[Category:Creator template home categories|%s]]',args.sortkey or ' ')
	-- check for wikidata q-code
	if not args.wikidata then
		cats = cats .. '\n[[Category:Creator template home categories without Wikidata link]]'
	end
 
	if args.option == 'autocategorize' then
		cats = string.format('%s\n[[Category:People by name|%s]]', cats, args.sortkey or ' ')
		if args.deathyear then
				cats = string.format('%s\n[[Category:%i deaths|%s]]', cats, args.deathyear, args.sortkey or ' ')
		end
		if args.birthyear then
				cats = string.format('%s\n[[Category:%i births|%s]]', cats, args.birthyear, args.sortkey or ' ')
		end
	end
 
	return cats
end
 
-- ===========================================================================
-- === This function is responsible for adding maintenance categories      ===
-- === to pages in creator namespace which are related to wikidata         ===
-- === INPUTS:                                                             ===
-- ===  * args - original inputs from the creator template page            ===
-- ===  * data - data pulled from Wikidata                                 ===
-- ===========================================================================
local function add_categories_to_creator_namespace(args, data)
	local cats = ''     -- categories 
	local qsTable = {}  -- table to store QuickStatements 
	local today = '+' .. os.date('!%F') .. 'T00:00:00Z/11'
	-- two forms of QuickStatements command with and without quotes
	local qsCommand = {'%s \t %s \t %s \t S143 \t Q24731821 \t S813 \t ' .. today, '%s \t %s \t "%s" \t S143 \t Q24731821 \t S813 \t ' .. today}
 
	-- compare Linkback to the actual page name. Many "Linkbacks" are created with 
	-- Module:Creator which produces &#38; and &#39;  instead of "&" and "'"
	if args.linkback then
		local linkback = args.linkback
		linkback = mw.ustring.gsub(linkback, '&#39;', "'")
		linkback = mw.ustring.gsub(linkback, '&#38;', "&")
		if linkback ~= ('Creator:' .. args.pagename) then
			cats = cats .. '\n[[Category:Creator templates with mismatching linkback]]'
		end
	end
 
	--  if no q-code but we have authority field -> create new item
	if not args.wikidata and args.create then
		args.wikidata = 'LAST' 
		table.insert( qsTable, 'CREATE' )
		table.insert( qsTable, 'LAST \t P31 \t Q5 \t S143 \t Q24731821' )  -- instance of human
		table.insert( qsTable, 'LAST \t Len \t "'.. args.pagename .. '"' ) -- english label
		local property = {'P18', 'P19', 'P20', 'P21', 'P27', 'P31', 'P373', 'P569', 'P570', 'P734', 'P735', 'P937', 'P1412', 'P1472'}
		for _,P in ipairs( property ) do
			data[P] = nil
		end
	end
 
	-- add [[Category:Creator templates with unknown parameter]] category
	local fields = {name=1, alternative_names=2, sortkey=2, birthdate=1, deathdate=1, birthloc=1, deathloc=1, workperiod=2, workloc=2, 
	        image=1, homecat=1, nationality=2, gender=1, occupation=2, description=1, authority=1, type=2, wikisource=1, wikiquote=1,
					namespace=0, linkback=2, wikidata=2, lang=0, pagename=0, reference=0, references=0, lifespan=0, birthyear=0, deathyear=0 }
	for field, value in pairs( args ) do 
		if not fields[field] then
			cats = string.format('%s\n[[Category:Creator templates with unknown parameter|%s]]', cats, field)
		end
	end
 
	-- skip the rest if no q-code
	if not args.wikidata then
		return cats, ''
	end
 
	-- add [[Category:Creator templates with Wikidata link: local ... parameter]] category
	for field, num in pairs( fields ) do
		if args[field] and num==1 then
			cats = string.format('%s\n[[Category:Creator templates with Wikidata link: local %s]]', cats, field)
		end
	end
 
	-- ==================================================
	-- === individual property preparation  === 
	-- ==================================================
 
	-- look up q-codes of locations
	local LookupTable = mw.loadData("Module:City/data")
	fields = {'birthloc', 'deathloc', 'workloc'}
	for _,field in ipairs( fields ) do 
		if args[field] then
			field1 = field .. '_'
			if string.match(args[field],"^Q%d+$") then
				args[field1] = args[field] -- already a q-code
			else
				args[field1] = LookupTable[mw.ustring.lower(args[field])]
			end
		end
	end
 
	if args.gender  then
		local GenderLut = { m='Q6581097', male='Q6581097', f='Q6581072', female='Q6581072'}
		args.gender_ = GenderLut[mw.ustring.lower(args.gender)] -- look up q-code for each gender
	end
 
	if args.birthdate and (string.match(args.birthdate,"^%d%d%d%d$") or string.match(args.birthdate,"^%d%d%d%d%-%d%d$") or string.match(args.birthdate,"^%d%d%d%d%-%d%d%-%d%d$")) then -- if YYYY or YYYY-MM-DD format 
		args.birthdate_ = args.birthdate
	end
	if args.deathdate and (string.match(args.deathdate,"^%d%d%d%d$") or string.match(args.deathdate,"^%d%d%d%d%-%d%d$") or string.match(args.deathdate,"^%d%d%d%d%-%d%d%-%d%d$")) then -- if YYYY or YYYY-MM-DD format 
		args.deathdate_ = args.deathdate
	end
	if args.nationality and #args.nationality==2 then -- at this point handle only simple 2 character case
		args.nationality_ = string.upper(args.nationality)
	end
	if args.image then 
		args.image_ = mw.uri.decode( args.image, "WIKI" )
	end
 
	-- =============================
	-- === batch categorization  ===
	-- =============================
 
	-- Fields:
	-- * field1 - name of original args field. Will be used to test the presence of 
	--            the field and the name will be used to create  maintenance category
	-- * field2 - name of modified args field. The value will be compared to wikidata property
	-- * property - matching wikidata property
	-- * form - some QuickStatements require field in "" and some do not, Nul means no QS 
	local conf = {
		{field1='image',       field2='image_',       property='P18',   form=2},
		{field1='gender',      field2='gender_',      property='P21',   form=1},
		{field1='linkback',    field2='pagename',     property='P1472', form=2, notRedundant=1},
		{field1='birthloc',    field2='birthloc_',    property='P19',   form=1},
		{field1='deathloc',    field2='deathloc_',    property='P20',   form=1},
		{field1='workloc',     field2='workloc_',     property='P937',  form=1},
		{field1='homecat',     field2='homecat',      property='P373',  form=2},
		{field1='nationality', field2='nationality_', property='P27',   form=nul},
		{field1='birthdate',   field2='birthdate_',   property='P569',  form=nul},
		{field1='deathdate',   field2='deathdate_',   property='P570',  form=nul},
	}
 
	for _,params in ipairs( conf ) do
		local field = args[params.field2]
		local prop  = data[params.property]
		if field and prop and field~=prop then 
			cats = string.format('%s\n[[Category:Creator templates with Wikidata link: mismatching %s]]', cats, params.field1)
		elseif field and prop and field==prop and not params.notRedundant then 
			cats = string.format('%s\n[[Category:Creator templates with Wikidata link: redundant %s]]', cats, params.field1)
		elseif field and not prop and params.form then
			cats = string.format('%s\n[[Category:Creator templates with Wikidata link: item missing %s]]', cats, params.field1)
			table.insert( qsTable, string.format(qsCommand[params.form], args.wikidata, params.property, field) )
		elseif args[params.field1] and not prop then -- missing on Wikidata but no code to transfer it yet
			cats = string.format('%s\n[[Category:Creator templates with Wikidata link: item missing %s]]', cats, params.field1)
		end
	end
 
	-- custom "redundant" rules
	if (data.wikisource and args.wikisource) then
		cats = cats .. '\n[[Category:Creator templates with Wikidata link: redundant wikisource]]'
	end
	if (data.wikiquote and args.wikiquote) then
		cats = cats .. '\n[[Category:Creator templates with Wikidata link: redundant wikiquote]]'
	end
	if (data.P734 and args.sortkey) then
		cats = cats .. '\n[[Category:Creator templates with Wikidata link: redundant sortkey]]'
	end
	if (data.P106 and args.occupation and data.P106==string.lower(args.occupation)) then
		cats = cats .. '\n[[Category:Creator templates with Wikidata link: redundant occupation]]'
	end	
	if args.birthdate and #args.birthdate==4 and data.P569 and #data.P569>4 and string.sub(data.P569,1,4)==args.birthdate then -- if YYYY or YYYY-MM-DD format 
		cats = string.gsub(cats, 'mismatching birthdate' , 'redundant birthdate' )
	end
	if args.deathdate and #args.deathdate==4 and data.P570 and #data.P570>4 and string.sub(data.P570,1,4)==args.deathdate then -- if YYYY or YYYY-MM-DD format 
		cats = string.gsub(cats, 'mismatching deathdate' , 'redundant deathdate' )
	end
	if args.birthloc and data.P19 and args.birthloc~=data.P20 then 
		local label = mw.wikibase.getEntity(data.P19):getLabel('en')
		if label==args.birthloc then
			cats = string.gsub(cats, '\n[[Category:Creator templates with Wikidata link: mismatching birthloc]]' , '' )
			cats = cats .. '\n[[Category:Creator templates with Wikidata link: redundant birthloc]]'
		end
	end	
	if args.deathloc and data.P20 and args.deathloc~=data.P20 then 
		local label = mw.wikibase.getEntity(data.P20):getLabel('en')
		if label==args.deathloc then
			cats = string.gsub(cats, '\n[[Category:Creator templates with Wikidata link: mismatching deathloc]]' , '' )
			cats = cats .. '\n[[Category:Creator templates with Wikidata link: redundant deathloc]]'
		end
	end
 
	-- QS for birthdate
	if args.birthdate and (not data.P569 or (#args.birthdate>4 and data.P569 and #data.P569==4 and string.sub(args.birthdate,1,4)==data.P569)) then
		field = timestamp(args.birthdate)
		if field then
			table.insert( qsTable, string.format(qsCommand[1], args.wikidata, 'P569', field) )
		end
	end
 
	-- QS for deathdate
	if args.deathdate and (not data.P570 or (#args.deathdate>4 and data.P570 and #data.P570==4 and string.sub(args.deathdate,1,4)==data.P570)) then
		field = timestamp(args.deathdate)
		if field then
			table.insert( qsTable, string.format(qsCommand[1], args.wikidata, 'P570', field) )
		end
	end
 
	if args.wikidata == 'LAST' then
		args.wikidata = nil -- no longer needed
		data          = nil;
	end
 
	-- convert QS table to a string
	local QS   = ''     -- quick_statements final string
	if #qsTable>0 then
		local qsHeader  = 'https://tools.wmflabs.org/quickstatements/#v1='
		local qsWrapper = '&nbsp;[[File:Commons_to_Wikidata_QuickStatements.svg|15px|link=%s]]'
		QS = string.format(qsWrapper, qsHeader .. table.concat( qsTable, '%0A'))
		QS = mw.ustring.gsub(QS, ' \t ', "%%09")
		QS = mw.ustring.gsub(QS, '"'   , "%%22")
		QS = mw.ustring.gsub(QS, ' '   , "%%20")
		cats = cats .. '\n[[Category:Creator templates with Wikidata link: quick statements]]'
	end
	return cats, QS
end
 
-- ==================================================
-- === External functions ===========================
-- ==================================================
local p = {}
 
-- ===========================================================================
-- === Version of the function to be called from other LUA codes
-- ===========================================================================
function p._creator(args)
	local str
	local cats = '' -- categories 
	local QS = ''   -- quick_statements 
	local entity = nil
	if mw.wikibase and args.wikidata then
	  --mw.log("'" .. args.wikidata .. "'")
		entity = mw.wikibase.getEntity(args.wikidata)
		if not entity then
			 cats = '[[Category:Creator templates with bad Wikidata link|invalid]]' 
		end
	end
 
	-- ===========================================================================
	-- === Step 1: harverst wikidata properties matching creator template fields
	-- ===========================================================================
	local data = {} -- structure similar to "args" but filled with wikidata data
	if entity then
		-- harvest string and Q-code properties
		local property = {'P18', 'P19', 'P20', 'P21', 'P27', 'P31', 'P373', 'P734', 'P735', 'P937', 'P1412', 'P1472'}
		for _,P in ipairs( property ) do
			if entity.claims and entity.claims[P] then -- if we have wikidata item and item has the property
				-- capture all Wikidata values for the identifier
				for _, statement in pairs( entity:getBestStatements( P )) do
					if (statement.mainsnak.snaktype == "value") then -- or if statement.mainsnak.datavalue then 
						local v = statement.mainsnak.datavalue.value
						if v['numeric-id'] then
							v = 'Q' .. tostring( v['numeric-id'] )
						end
						data[P] = v
					end
				end
			end
		end
		-- harvest time properties
		local property = {'P569', 'P570', 'P2031', 'P2032', 'P1636'}
		for _,prop in ipairs( property ) do
			data[prop], data[prop .. 'Year'] = Wikidata3._date(entity, prop, args.lang)
		end
 
		data.name  = Wikidata2._getLabel(entity, args.lang, "wikipedia") -- create name based on wikidata label
 
		-- process P27/nationality and P106/Occupation
		local N = Wikidata1.formatStatements({item=entity, property='p27',link='-',conjtype ='/',displayformat='raw'})
		N = mw.text.split(N or '', '/')
		N[1] = q2iso[N[1] or ''] -- look up 2 letter codes
		N[2] = q2iso[N[2] or ''] -- look up 2 letter codes
		if N[1] and N[2] then
			data.P27 = N[1] .. "/" .. N[2]
		else
			data.P27 = N[1] or N[2]
		end
		data.P106 = Wikidata1.formatStatements({item=entity, property='p106',link='-',conjtype ='/', lang='en'})
 
		-- prepare fallback list of languages
		local langList = mw.language.getFallbacksFor(args.lang)
		table.insert(langList, 1, args.lang)	
		if data.P1412 then -- language spoken (only first one considered)
			-- lookup "Wikimedia language code" and add it to the list
			table.insert(langList, Wikidata1.formatStatements({item=data.P1412, property='p424',link='-'})) 
		end
 
		-- get wikisource link
		for i, language in ipairs(langList) do 
			sitelink = entity:getSitelink(language .. 'wikisource')
			if sitelink then 
				data.wikisource = string.format('s:%s:%s', language, sitelink)
				break 
			end
		end		
		-- get wikiquote link
		for i, language in ipairs(langList) do 
			sitelink = entity:getSitelink(language .. 'wikiquote')
			if sitelink then 
				data.wikiquote = string.format('q:%s:%s', language, sitelink)
				break 
			end
		end
	end -- if entity then
 
	-- If creator namespace and "person" template than add maintenance categories
	args.QS = nil;
	if args.namespace==100 and (args.type=='' or args.type=='person') then
		str, args.QS = add_categories_to_creator_namespace(args, data)
		cats = cats .. str
	end
 
	-- ===========================================================================
	-- === Step 2: one by one merge wikidata and creator data
	-- ===========================================================================
	-- process "name" field
	 if data.name and not (args.name and mw.ustring.match( data.name, '%|Q%d+%]%]')) then
		args.name = data.name -- use wikidata name if we have q-code and wikidata has label
	 end
	if args.option and args.option~='autocategorize' then -- modify name based on "option" parameter
		local base_name = args.name
		-- call [[module:Name]] with the task
		args.name = Name._name(args.option, args.name, args.lang)
		if args.name  == "name not supported" then 
			args.name = base_name
			cats = cats .. '\n[[Category:Bad use of creator template - option]]'
		end
	end
 
	-- process "linkback" field
	args.linkback_tag  = mw.message.new( 'wm-license-creator-linkback' ):inLanguage(args.lang):plain()
	if not args.linkback and data.P1472 then
		args.linkback = 'Creator:' .. data.P1472 -- look up linkback on wikidata
	end
 
	-- process "wikisource" and "wikiquote" fields
	args.wikisource = data.wikisource or args.wikisource
	args.wikiquote  = data.wikiquote  or args.wikiquote
 
	-- compare commons and wikidata results
	if args.namespace==100 then
		if data.P19 then 
			data.P19 = Wikidata2._getLabel(data.P19, args.lang, "wikipedia")
		end
		if data.P20 then 
			data.P20 = Wikidata2._getLabel(data.P20, args.lang, "wikipedia")
		end
		if data.P569 then 
			data.P569 = ISOdate._ISOdate(data.P569, args.lang)
		end
		if data.P570 then 
			data.P570 = ISOdate._ISOdate(data.P570, args.lang)
		end
		args.birthdate = ISOdate._ISOdate(args.birthdate or args.birthyear, args.lang)
		args.deathdate = ISOdate._ISOdate(args.deathdate or args.deathyear, args.lang)
		local conf = { birthloc='P19', deathloc='P20', birthdate='P569', deathdate='P570' }
		for field,prop in pairs( conf ) do
			if (args[field] and data[prop] and args[field]~=data[prop] ) then
				args[field] = string.format('<span style=\"color:darkgreen\">%s</span> / <span style=\"color:blue\">%s</span>', args[field], data[prop])
			elseif (args[field] and data[prop] and args[field]==data[prop] ) then
				args[field] = string.format('<span style=\"color:darkmagenta\">%s</span>', args[field])
			end
		end
	end
 
	-- process places fields
	args.birthloc = args.birthloc or data.P19
	args.deathloc = args.deathloc or data.P20
	args.workloc  = args.workloc  or data.P937
	if (args.birthloc==args.deathloc) then
		args.birthloc = City._city(args.birthloc, args.lang)
		args.deathloc = args.birthloc 
		args.birthloc = args.birthloc 
	else
		args.birthloc = City._city(args.birthloc, args.lang) 
		args.deathloc = City._city(args.deathloc, args.lang)
	end
	if args.workloc and not string.find(args.workloc, ' ') then
		args.workloc = City._city(args.workloc, args.lang) 
	end
 
	-- process date fields
	args.birthdate = args.birthdate or data.P569
	args.deathdate = args.deathdate or data.P570
	if not args.birthyear and args.birthdate then
		args.birthyear = empty2nil(ISOdate._ISOyear(args.birthdate)) or tostring(data.P569Year or '')
	end
	if not args.deathyear and args.deathdate then
		args.deathyear = empty2nil(ISOdate._ISOyear(args.deathdate)) or tostring(data.P570Year or '')
	end
	args.birthdate = ISOdate._ISOdate(args.birthdate or args.birthyear, args.lang)
	args.deathdate = ISOdate._ISOdate(args.deathdate or args.deathyear, args.lang)
	if (not args.birthdate or args.birthdate =='') and data.P1636 then
		args.birthdate = mw.getCurrentFrame():expandTemplate{ title='Lifetime date', args={'baptism', data.P1636, lang=args.lang} }
		args.birthyear = data.P1636Year
	end
	if args.birthdate =='' then args.birthdate =nil; end
	if args.deathdate =='' then args.deathdate =nil; end
	if args.birthyear =='' then args.birthyear =nil; end
	if args.deathyear =='' then args.deathyear =nil; end
 
	-- workperiod
	if not args.workperiod and data.P2031 and data.P2032 then 
		args.workperiod = data.P2031 .. '&ndash;' .. data.P2032
	end
 
	-- lifespan displayed after name
	if not args.lifespan then
		if args.birthyear or args.deathyear then -- create from birth/death dates
			args.lifespan = string.format('(%s-%s)', args.birthyear or ' ', args.deathyear or ' ') 
			if #args.lifespan<=5 then args.lifespan = ''; end -- no dates are given
		elseif data.P2031 and data.P2032 then -- create from work period
			args.lifespan = string.format('([[d:Q36424|fl.]] %s-%s)', data.P2031, data.P2032)  
		end
	end
	if args.lifespan then
		args.lifespan = string.gsub(args.lifespan, '-', '&ndash;')
	end
 
	-- process "Authority Control" field
	args.authority_tag = AC.getAuthorityControlTag(args.lang)
	if not args.authority and args.wikidata then
		local AC_cats
		args.authority, AC_cats = AC._authorityControl(entity, {Wikidata = args.wikidata}, args.lang, 5) 
		if not (args.namespace == 2 or args.namespace == 6 or args.namespace == 828 or math.fmod(args.namespace,2)==1) then
			cats = cats .. AC_cats -- lets not add authorityControl categories to user pages, files, modules or talk pages and concentrate on templates and categories instead
		end
	end
 
	-- process "gender" field
	args.gender = args.gender  or data.P21 or 'm'
	if args.gender=='Q6581097' or args.gender=='Q2449503' then
		args.gender = 'male'
	end
	if args.gender=='Q6581072' or args.gender=='Q1052281' then
		args.gender = 'female'
	end
 
	-- process "nationality" and "occupation" fields
	args.nationality = args.nationality or data.P27
	args.occupation  = args.occupation  or data.P106
	args.Occupation  = mw.text.split(args.occupation or '', '/')
 
	-- process "description" field
	if args.nationality and args.Occupation[1] then
		local Args = {args.gender, args.nationality, args.Occupation[1], args.Occupation[2] or '', args.Occupation[3] or '', args.Occupation[4] or '', lang=args.lang}
		str = mw.getCurrentFrame():expandTemplate{ title='NationAndOccupation', args=Args }
		if args.description and str and #str>0 then
			args.description =  str .. '<br/>' .. args.description
		else
			args.description =  str .. (args.description or '')
		end
	end
 
	-- process "sortkey" field
	if not args.sortkey then
		local lastname, firstname
		if data.P734 then
			lastname = data.P734
		else
			name_part = mw.text.split(args.pagename, ' ')
			lastname  = name_part[#name_part]
		end
		if data.P735 then
			firstname = data.P735
		else
			firstname = args.pagename
		end
		args.sortkey =  lastname .. ', ' .. firstname 
	end
	args.sortkey  = mw.ustring.toNFC(args.sortkey)
 
	-- others
	args.image    = args.image   or data.P18
	args.homecat  = args.homecat or data.P373
	if args.namespace~=100 then 
		args.references = nil
	end
 
	-- ===========================================================================
	-- === Step 3: create maintenance categories and render html of the table
	-- ===========================================================================
	if args.namespace==14 and (args.type=='' or args.type=='person') then
		str = add_categories_to_category_namespace(args)
		cats = cats .. str
	end
	cats = cats .. add_maintenance_categories( args)
	local results = Build_html(args)
	return results, cats
end
 
-- ===========================================================================
-- === Version of the function to be called from template namespace
-- ===========================================================================
function p.creator(frame)
	-- switch to lowercase parameters to make them case independent
	local args = {}
	for name, value in pairs( frame:getParent().args ) do 
		if value ~= '' then -- nuke empty strings
			local name1 = string.gsub( string.lower(name), ' ', '_')
			args[name1] = value
		end
	end
	for name, value in pairs( frame.args ) do 
		if value ~= '' then -- nuke empty strings
			local name1 = string.gsub( string.lower(name), ' ', '_')
			args[name1] = value
		end
	end
 
	if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then 
		args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language
	end
	args.namespace  = mw.title.getCurrentTitle().namespace  -- get page namespace
	args.pagename   = mw.title.getCurrentTitle().text       -- ger {{PAGENAME}}
	args.references = args.references or args.reference     -- two alternative names for references
	args.type       = string.lower(args.type or '')         -- if 'type' field is not specified than set to ""
 
	-- call the inner "core" function
	local results, cats = p._creator(args)	
	return results..cats
end
 
return p

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.