Модуль:Artwork/core

    Матеріал з Релігія в огні

    Документацію для цього модуля можна створити у Модуль:Artwork/core/документація

    --[[  
      __  __           _       _           _         _                      _        __                 
     |  \/  | ___   __| |_   _| | ___ _   / \   _ __| |___      _____  _ __| | __   / /__ ___  _ __ ___ 
     | |\/| |/ _ \ / _` | | | | |/ _ (_) / _ \ | '__| __\ \ /\ / / _ \| '__| |/ /  / / __/ _ \| '__/ _ \
     | |  | | (_) | (_| | |_| | |  __/_ / ___ \| |  | |_ \ V  V / (_) | |  |   <  / / (_| (_) | | |  __/
     |_|  |_|\___/ \__,_|\__,_|_|\___(_)_/   \_\_|   \__| \_/\_/ \___/|_|  |_|\_\/_/ \___\___/|_|  \___|
                                                                                                                                                                                   
    This submodule is intended for converting inputs into html.
    
    Please do not modify this code without applying the changes first at 
    "Module:Artwork/sandbox" and testing at "Template:
    /testcases".
    
    Authors and maintainers:
    * User:Jarekt - original version 
    ]]
    require('strict') -- used for debugging purposes as it detects cases of unintended global variables
    local getLabel = require("Module:Wikidata label")._getLabel            -- used for creation of name based on Wikidata
    local core     = require("Module:Core")
    local labels   = require("Module:I18n/artwork")                        -- internationalization of labels
    local bit32    = require("bit32")
    local TagQS    = require('Module:TagQS')
    local City     = require("Module:City")                                -- used to add Wikidata based links to names of places
    local ISOdate  = require('Module:ISOdate')                             -- used for simple date formating
    local p = {}
    
    -- Lazy loading function: load them only if they are needed
    local function ObjectLocation_label()
    	return mw.loadData('Module:i18n/coordinates').ObjectLocation
    end
    
    local function Creator(args)
    	return require("Module:Creator")._creator(args)
    end
    
    local function Institution(args)
    	return require("Module:Institution")._institution(args)
    end
    
    -- ==================================================
    -- === Internal functions ===========================
    -- ==================================================
    
    -------------------------------------------------------------------------------
    local function isodate2timestamp(dateStr)
    -- convert isodate to timestamp used by quick statements
    	local tStamp = nil
    	if string.match(dateStr,"^[0-1]%d%d%d$") then               -- if YYYY  format 
    		tStamp = '+' .. dateStr .. '-00-00T00:00:00Z/9'
    	elseif string.match(dateStr,"^[0-1]%d%d%d%-[0-1]%d$") then      -- if YYYY-MM format 
    		tStamp = '+' .. dateStr .. '-00T00:00:00Z/10'
    	elseif string.match(dateStr,"^[0-1]%d%d%d%-[0-1]%d%-[0-3]%d$") then  -- if YYYY-MM-DD format 
    		tStamp = '+' .. dateStr .. 'T00:00:00Z/11'
    	end
    	return tStamp
    end
    
    -------------------------------------------------------------------------------
    local function if_else(Boolean, TrueStatement, FalseStatement)
    	if Boolean then
    		return TrueStatement
    	else
    		return FalseStatement
    	end
    end
    
    -------------------------------------------------------------------------------
    local function empty2nil(str)
    	if str=='' then
    		return nil
    	else 
    		return str
    	end
    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 are 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(param, args)
    	local LUT = {artwork=0, photograph=1, book=2}
        local demo = args.demo and bit32.extract( param.demo or 0, LUT[args.infobox])==1
    	local field = args[param.field]
    	if field=='' then field=nil; end
    	if not (field or demo) then 
    		return nil
    	end
    	if not param.id then -- "other fields" parameter
    		return field
    	end
    	local tag = param.tag or 'bad'
    	if string.sub(tag,1,10) == 'wm-license' then
    		tag = mw.message.new( tag ):inLanguage(args.lang):plain() -- label message in args.lang language
    	elseif string.match(tag, "^[QP]%d+$") then
    		tag = getLabel(tag, args.lang, "-", "ucfirst")
    	elseif labels[tag] then
    		tag = core.langSwitch(labels[tag], args.lang)
    	end
    	local cell1 = string.format('<td id="%s" class="fileinfo-paramfield" lang="%s">%s</td>\n', param.id, args.lang, tag)
    	local cell2 = string.format('<td>\n'.. param.wrapper ..'</td>', field or '')
    	return string.format('<tr valign="top">\n%s%s\n</tr>\n\n', cell1, cell2)
    end
    
    
    -- ====================================================================
    -- === This function is just responsible for producing HTML of the  ===
    -- === template. At this stage all the fields are already filled    ===
    -- ====================================================================
    function p.build_html(args)
    	-- get text direction
    	local dir = if_else(mw.language.new( args.lang ):isRTL(),'rtl','ltr')
    	
    	-- original_description row has a different look than other rows
    	if args.original_description and (args.original_description_info or args.biased) then
    		local tag1, tag2 = "", ""
    		if args.original_description_info then
    			tag1 = string.format('<div style="background:#dde; font-size:86%%; direction:%s;">%s</div>', dir, args.original_description_info)
    		end
    		if args.biased then
    			tag2 = core.langSwitch(labels.inaccurate_description, args.lang)
    			tag2 = string.format('<div style="padding:0.5ex; margin:0 0 0.5ex 0; border: 1px solid red;">%s: %s</div>', tag2, args.biased)
    		end
    		args.original_description = tag1 .. tag2 .. args.original_description
    	end
    	
    	-- files with no source will be flagged
    	if (not args.source) and (not args.source_) and (args.strict==true) and (args.namespace==6) then
    		args.nosource = mw.getCurrentFrame():expandTemplate{ title = 'Source missing' }
    	end
    	if args.demo or args.coordinates then
    		labels.ObjectLocation = ObjectLocation_label()
    	end
    	
    	local nCol = 2
    	if not args.image and args.demo then
    		args.image = args.demo_image
    	end
    	if args.image  then
    		nCol = 3
    	end
    	
    	-- Top line 
    	local top, results = {}, {}
    	if args.name then
    		table.insert(top, string.format('<span class="fn" id="artwork"><bdi>%s\n</bdi></span>', args.name ) )
    	end
    	if args.linkback then -- Wikidata Link
    		table.insert(top, string.format('[[File:Blue pencil.svg|15px|%s|link=%s]]', args.linkback, args.linkback) )
    	end	
    	if args.wikidata then -- Wikidata Link
    		table.insert(top, string.format('[[File:Wikidata-logo.svg|20px|wikidata:%s|link=wikidata:%s]]', args.wikidata, args.wikidata) )
    		table.insert(top, string.format('[[File:Wikidata-Reasonator_small_logo.svg|5px|reasonator:%s|link=https://reasonator.toolforge.org/test/?q=%s]]', args.wikidata, args.wikidata) )
    	end
    	if args.wikisource then --Wikisource link
    		table.insert(top, string.format('[[File:Wikisource-logo.svg|15px|%s|link=%s]]', args.wikisource, args.wikisource) )
    	end
    	if args.wikiquote then --Wikiquote link
    		table.insert(top, string.format('[[File:Wikiquote-logo.svg|15px|%s|link=%s]]', args.wikiquote, args.wikiquote) )
    	end
    	if #top>0 and args.QS then -- quick_statement link to upload missing info to Wikidata (add if the row is not empty)
    		table.insert(top, string.format('%s', args.QS) )
    	end
    	if #top>0 then
    		local line = string.format('<th colspan="%i" style="background-color:#ccf; font-weight:bold; border:1px solid #aaa" text-align="left">%s</th>', nCol, table.concat(top, '&nbsp;')) 
    		table.insert(results, string.format('<tr valign="top">\n%s\n</tr>\n', line))
    	end
    	
    	-- Permissions tag
    	local tag1 = mw.message.new( "wm-license-information-permission" ):inLanguage(args.lang):plain()
    	local tag2 = mw.message.new( "wm-license-information-permission-reusing-link" ):inLanguage(args.lang):plain()
    	local tag3 = mw.message.new( "wm-license-information-permission-reusing-text" ):inLanguage(args.lang):plain()
    	local permission_tag = string.format("%s<br /><small>([[%s|%s]])</small>", tag1, tag2, tag3)
    	
    	-- define constants for readability
    	-- demo=art+photo+book will show that row in demo mode in {{artwork}, {{Photograph}} and {{Book}} templates
    	local none, art, photo, book  = 0, 1, 2, 4
    	
    	-- add other fields 'author_of_foreword', 'author_of_afterword'
    	local param = {
    		-- field name                   machine readable tag                         field name i18n approach                     show in demo mode?   field value wrapper
    		{field='artist'               , id='fileinfotpl_aut'                       , tag='wm-license-artwork-artist',             demo=art,            wrapper='<div class="fn value">\n%s</div>'},
    		{field='author'               , id='fileinfotpl_aut'                       , tag='wm-license-information-author',         demo=          book, wrapper='<div class="fn value">\n%s</div>'},
    		{field='editor'               , id='fileinfotpl_book_editor'               , tag='wm-license-book-editor',                demo=          book, wrapper='<div class="fn value">\n%s</div>'},
    		{field='translator'           , id='fileinfotpl_book_translator'           , tag='wm-license-book-translator',            demo=          book, wrapper='<div class="fn value">\n%s</div>'},
    		{field='illustrator'          , id='fileinfotpl_book_illustrator'          , tag='wm-license-book-illustrator',           demo=          book, wrapper='<div class="fn value">\n%s</div>'},
    		{field='author_of_foreword'   , id='fileinfotpl_aut'                       , tag='P2679',                                 demo=          book, wrapper='<div class="fn value">\n%s</div>'},
    		{field='author_of_afterword'  , id='fileinfotpl_aut'                       , tag='P2680',                                 demo=          book, wrapper='<div class="fn value">\n%s</div>'},
    		{field='architect'            , id='fileinfotpl_aut'                       , tag='Q42973',                                demo=none,           wrapper='<div class="fn value">\n%s</div>'},
    		{field='designer'             , id='fileinfotpl_aut'                       , tag='Q5322166',                              demo=none,           wrapper='<div class="fn value">\n%s</div>'},
    		{field='photographer'         , id='fileinfotpl_aut'                       , tag='Q33231',                                demo=    photo,      wrapper='<div class="fn value">\n%s</div>'},
    		{field='other_fields_1'},
    		-- title & desctiption block
    		{field='title'                , id='fileinfotpl_art_title'                 , tag='wm-license-artwork-title',              demo=art+photo+book, wrapper='<div class="fn">\n%s</div>'},
    		{field='subtitle'             , id='fileinfotpl_book_subtitle'             , tag='wm-license-book-subtitle',              demo=          book, wrapper='%s'},
    		{field='part_of'              , id='fileinfotpl_art_part_of'               , tag='P361',                                  demo=art+photo+book, wrapper='%s'},
    		{field='series_title'         , id='fileinfotpl_book_series-title'         , tag='wm-license-book-series-title',          demo=          book, wrapper='%s'},
    		{field='volume'               , id='fileinfotpl_book_volume'               , tag='wm-license-book-volume',                demo=          book, wrapper='%s'},
    		{field='edition'              , id='fileinfotpl_edition'                   , tag='wm-license-book-edition',               demo=          book, wrapper='%s'},
    		{field='publisher'            , id='fileinfotpl_book_publisher'            , tag='wm-license-book-publisher',             demo=          book, wrapper='<div class="fn value">\n%s</div>'},
    		{field='printer'              , id='fileinfotpl_book_printer'              , tag='wm-license-book-printer',               demo=          book, wrapper='<div class="fn value">\n%s</div>'},
    		{field='object_type'          , id='fileinfotpl_art_object_type'           , tag='object_type',                           demo=art,            wrapper='%s'},
    		{field='genre'                , id='fileinfotpl_art_genre'                 , tag='Q483394',                               demo=          book, wrapper='%s'},
    		{field='original_description' , id='fileinfotpl_desc'                      , tag='original_description',                  demo=    photo,      wrapper='<div class="description">\n%s</div>'},
    		{field='description'          , id='fileinfotpl_desc'                      , tag='wm-license-information-description',    demo=art+photo+book, wrapper='<div class="description">\n%s</div>'},
    		{field='pageoverview'         , id='fileinfotpl_book-page-overview'        , tag='wm-license-book-page-overview',         demo=none,           wrapper='%s'},
    		{field='depicted_people'      , id='fileinfotpl_art_depicted_people'       , tag='depicted_people',                       demo=art+photo,      wrapper='%s'},
    		{field='depicted_place'       , id='fileinfotpl_art_depicted_place'        , tag='depicted_place',                        demo=art+photo,      wrapper='%s'},
    		{field='depicted_part'        , id='fileinfotpl_art_depicted_part'         , tag='P5961',                                 demo=art+photo+book, wrapper='%s'},
    		{field='language'             , id='fileinfotpl_book_language'             , tag='wm-license-book-language',              demo=          book, wrapper='%s'},
    		{field='other_fields_2'},
    		-- date, object outside description, history, etc.
    		{field='date'                 , id='fileinfotpl_date'                      , tag='wm-license-information-date',           demo=art+photo,      wrapper='%s'},
    		{field='publication_date'     , id='fileinfotpl_publication_date'          , tag='P577',                                  demo=          book, wrapper='%s'},
    		{field='medium'               , id='fileinfotpl_art_medium'                , tag='wm-license-artwork-medium',             demo=art+photo,      wrapper='%s'},
    		{field='dimensions'           , id='fileinfotpl_art_dimensions'            , tag='wm-license-artwork-dimensions',         demo=art+photo,      wrapper='%s'},
    		{field='institution'          , id='fileinfotpl_art_gallery'               , tag='Q2668072',                              demo=art+photo,      wrapper='%s'},
    		{field='department'           , id='fileinfotpl_art_location'              , tag='wm-license-artwork-current-location',   demo=art+photo     , wrapper='<div class="locality">\n%s</div>'},
    		{field='id'                   , id='fileinfotpl_art_id'                    , tag='wm-license-artwork-id',                 demo=art+photo,      wrapper='<div class="identifier">\n%s</div>'},
    		{field='coordinates'          , id='fileinfo-paramfield'                   , tag='ObjectLocation',                        demo=art+photo,      wrapper='%s'}, 
    		{field='place_of_publication' , id='fileinfotpl_book_place-of-publication' , tag='wm-license-book-place-of-publication',  demo=          book, wrapper='%s'},
    		{field='place_of_creation'    , id='fileinfotpl_art_creation_place'        , tag='place_of_creation',                     demo=art,            wrapper='%s'},
    		{field='place_of_discovery'   , id='fileinfotpl_art_discovery_place'       , tag='place_of_discovery',                    demo=art,            wrapper='%s'},
    		{field='object_history'       , id='fileinfotpl_art_object_history'        , tag='wm-license-artwork-object-history',     demo=art,            wrapper='%s'},
    		{field='exhibition_history'   , id='fileinfotpl_art_exhibition_history'    , tag='exhibition_history',                    demo=art+photo,      wrapper='%s'},
    		{field='credit_line'          , id='fileinfotpl_art_credit_line'           , tag='wm-license-artwork-credit-line',        demo=art,            wrapper='%s'},
    		{field='inscriptions'         , id='fileinfotpl_art_inscriptions'          , tag='wm-license-artwork-inscriptions',       demo=art,            wrapper='%s'},
    		{field='notes'                , id='fileinfotpl_art_notes'                 , tag='wm-license-artwork-notes',              demo=art+photo,      wrapper='%s'},
    		{field='other_fields_3'},
    		-- references, and sources
    		{field='references'           , id='fileinfotpl_art_references'            , tag='wm-license-artwork-references',         demo=art+photo+book, wrapper='%s'},
    		{field='authority'            , id='fileinfotpl_art_authority'             , tag='Q36524',                                demo=none,           wrapper='%s'},
    		{field='source'               , id='fileinfotpl_src'                       , tag='wm-license-artwork-source',             demo=art,            wrapper='%s'}, -- source/photographer
    		{field='source_'              , id='fileinfotpl_src'                       , tag='wm-license-information-source',         demo=    photo+book, wrapper='%s'}, -- source
    		{field='nosource'             , id='fileinfotpl_nosrc'                     , tag='wm-license-information-source',         demo=none,           wrapper='%s'},
    		{field='permission'           , id='fileinfotpl_perm'                      , tag=permission_tag,                          demo=art+photo+book, wrapper='%s'},
    		{field='other_versions'       , id='fileinfotpl_ver'                       , tag='wm-license-information-other-versions', demo=art+photo+book, wrapper='%s'}, 
    		{field='other_fields'},
    		{field='camera_coord'},
    	}
    	for i=1,#param do
    		table.insert(results, Build_html_row(param[i], args))
    	end
    	
    	-- add material on the right: image, wikisource icon, etc.
    	if args.image then 
    		if args.image_page and args.image  then -- page parameter for DjVu and PDF files
    			args.image = string.format('%s|page=%i', args.image, args.image_page)
    		end
    		if args.infobox=='book' then -- page parameter for DjVu and PDF files
    			tag1 = mw.message.new( 'wm-license-book-start-this-book' ):inLanguage(args.lang):plain()
    			tag2 = string.format('|thumb|[[:File:%s|%s]]', args.image, tag1)
    		else
    			tag2 = ''
    		end
    		local field = string.format('[[File:%s|250x250px|alt=%s|class=photo%s]]', args.image, args.name or '', tag2) 
    		local nRow = #results -- number of rows below 
    		local line = string.format('<td rowspan="%i" style="width:200px; text-align: right;" id="fileinfotpl_creator_image"><div class="wpImageAnnotatorControl wpImageAnnotatorOff">%s</div></td></tr>\n\n', nRow, field) 
    		results[2] = mw.ustring.gsub(results[2], "</tr>%s*$", line); -- attach image section to the right side of the table, by attaching to row #2
    	end
    	
    	-- add table and outer layers
    	local style = string.format('class="fileinfotpl-type-artwork toccolours vevent mw-content-%s" dir="%s" style="width: 100%%" cellpadding="4"', dir, dir)
    	results = string.format('<table %s>\n%s\n</table>\n', style, table.concat(results)) -- combine "results", an array of strings into a single string
    	results = string.format('<div class="hproduct commons-file-information-table">\n%s\n</div>\n', results)
    	return results
    end
    
    -- ===========================================================================
    -- === Read input "frame", normalize input parameters (lower case, etc.)   ===
    -- === and resolve potential aliases                                       ===
    -- === INPUTS:                                                             ===
    -- ===  * frame - contains input parameters passed from the template       ===
    -- === OUTPUTS:                                                            ===
    -- ===  * args - cleaned up inputs                                         ===
    -- ===========================================================================
    function p.read_input_parameters(frame)
    	-- switch to lowercase parameters to make them case independent
    	local args = core.getArgs(frame)
    	
    	-- resolve aliases
    	args.permission        = args.permission       or args.license
    	args.medium            = args.medium           or args.technique
    	args.date              = args.date             or args.year
    	args.department        = args.department       or args.location
    	args.id                = args.accession_number or args.id
    	args.object_type       = args.object_type      or args.type
    	args.dimensions        = args.dimensions       or args.size
    	args.object_history    = args.object_history   or args.history
    	args.coordinates       = args.coordinates      or args.object_location
    	args.institution       = args.institution or args.gallery or args.museum
    	args.place_of_creation = args.place_of_creation or args.place_of_origin or args.country
    	args.original_description = args.original_description or args.original_caption
    	
    	-- remove unneeded parameters
    	args.technique, args.year, args.size,   args.gallery           = nil, nil, nil, nil
    	args.location,  args.type, args.museum, args.accession_number  = nil, nil, nil, nil
    	args.place_of_origin, args.country, args.history, args.license = nil, nil, nil, nil
    	args.object_location, args.original_caption = nil, nil
    	
    	-- ensure the right format
    	args.wikidata_cat = core.yesno(args.wikidata_cat, true)
    	args.strict       = core.yesno(args.strict, true)
    	args.noimage      = core.yesno(args.noimage, false)
    	args.no_qs        = core.yesno(args.no_qs, false)
    	args.no_sdc       = core.yesno(args.no_sdc, false)
    	args.image_page   = tonumber(args.image_page)
    	if args.language and #args.language==2 then 
    		args.language = frame:callParserFunction( "#language", { args.language, args.lang } ) -- get  language of the written work
    	end
    	
    	return args
    end
    
    -- ===========================================================================
    function p.verify_input_parameters(args)
    	local cats = '' -- categories 
    	
    	-- add [[Category:Creator templates with unknown parameter]] category, if some parameter not on the following list is used
    	local fields = { 'title', 'object_type', 'description', 'date', 'medium', 'permission', 
    		'artist', 'author', 'architect', 'designer', 'illustrator', 'publisher', 'editor', 'translator', 'printer', 'photographer', 
    		'dimensions',  'institution', 'department',  'references', 'object_history', 'genre',
    		'exhibition_history', 'credit_line', 'other_versions', 'source', 'strict', 'inscriptions', 'notes', 'linkback', 'camera_coord',
    		'other_fields', 'other_fields_1', 'other_fields_2', 'other_fields_3',  'demo', 'id', 'wikidata', 'year', 'homecat', 'authority',
    		'place_of_creation', 'place_of_discovery', 'source_', 'wikidata_cat', 'namespace', 'lang', 'image', 'noimage', 
    		'depicted_people', 'depicted_place', 'original_description_info', 'original_description', 'biased', 'photo_date', 'infobox',
    		'place_of_publication', 'publication_date', 'language', 'subtitle', 'series_title', 'volume', 'edition', 'edition_of', 
    		'pageoverview', 'wikisource', 'wikiquote', 'demo_image', 'image_page', 'depicted_part', 'mimeType', 'num_pages', 
    		'author_of_foreword', 'author_of_afterword', 'infobox', 'no_qs', 'no_sdc', 'part_of'
    	}
    	local set = {}
    	for _, field in ipairs(fields) do set[field] = true end
    	for field, _ in pairs( args ) do 
    		if not set[field] then
    			local LUT = {artwork='Artwork', photograph='Photograph', book='Book'}
    			local infobox = LUT[args.infobox]
    			cats = cats .. '[[Category:Pages using ' .. infobox .. ' template with incorrect parameter]]'
    			cats = cats .. string.format('\n;<span style="color:red">Error in [[Template:%s|{{%s}} template]]: unknown parameter "%s".</span>', infobox, infobox, field)
    		end
    	end 
    	return cats
    end
    
    -- ===========================================================================
    function p.clean_input_parameters(args)
    	local lang = args.lang  -- user's language
    	
    	-- === Step 1: clean up of template arguments "args"
    	local page = mw.title.getCurrentTitle()
    	args.namespace   = page.namespace   -- get page namespace
    	args.url         = page:canonicalUrl()
    	args.pagename    = page.text
    	if args.namespace==6 then -- file namespace
    		args.mimeType  = page.file.mimeType
    		args.num_pages = 1
    		if page.file.pages then
    			args.num_pages = #page.file.pages -- in case of DjVu or PDF files count pages
    		end
    	end
    	if args.date then 
    		args.year = empty2nil(ISOdate._ISOyear(args.date)) -- get year
    	end
    	
    	-- for places run them through {{City}} template
    	local fields = { 'depicted_people', 'depicted_place', 'place_of_discovery', 'part_of'	}
    	for _, field in ipairs( fields ) do 
    		if args[field] and not string.find(args[field], ' ') then
    			args[field] = City._city(args[field], lang) -- single word depicted_people will get a link
    		end	
    	end
    		
    	-- for dates run them through {{ISOdate}} template and add invisible QS tag if possible
    	local fields = { 'date', 'publication_date'}
    	for _, field in ipairs( fields ) do 
    		if args[field] then 
    			local val  = isodate2timestamp(args[field])        -- if date is in YYYY, YYYY-MM or YYYY-MM-DD formats than it will be saved
    			args[field] = ISOdate._ISOdate(args[field], lang) -- apply ISODate to function to date string to convert date in ISO format to translated date string 
    			if val then                                         -- if date is in ISO format than add an invisible tag which will be used to potentially add this date to QS used to move it to Wikidata
    				args[field] = args[field] .. TagQS.createTag('date', nil, val)
    			end		
    		end
    	end
    	
    	-- collapse local {{Creator}} and {{Institution}} templates and extract item ID from them 
    	local fields = {author='creator', artist='creator', photographer='creator', architect='creator', printer='creator', 
    		designer='creator', editor='creator', translator='creator', illustrator='creator', institution='institution'}
    	for field, keyword in pairs( fields ) do 
    		if args[field] then 
    			if string.match(args[field], "^Q%d+$") and keyword=='creator' then -- this is wikidata item
    				args[field..'_id'] = args[field]
    				if keyword=='creator' then
    					args[field] = Creator({wikidata=args[field], lang=lang, collapse=1})-- create creator based on item id 
    				elseif keyword=='institution' then
    					args[field] = Institution({wikidata=args[field], lang=lang, collapse=1})-- create institution based on item id 
    				end
    			else
    				-- collapse local {{Creator}} and {{Institution}} templates
    				args[field] = mw.ustring.gsub (args[field], 'table class="toccolours collapsible%s*"', 'table class="toccolours collapsible collapsed"')
    				-- extract item ID: retrieve the tag and grab the second component
    				local v = mw.text.split(  TagQS.readTag(args[field], keyword) or '', '|', true )
    				if v and #v>=2 then 
    					args[field..'_id'] = v[2]
    				end
    			end
    		end
    	end
    	
    	-- in case of invisible QS tags add correct property based on which field and infobox it come from 
    	local repList = { {'author', 'book',   'creator', 'P170', 'P50' }, 
    		{'artist',           'artwork',    'creator', 'P170', 'P170' },
    		{'illustrator',      'book',       'creator', 'P170', 'P110'}, 
    		{'editor',           'book',       'creator', 'P170', 'P98' }, 
    		{'translator',       'book',       'creator', 'P170', 'P655'}, 
    		{'printer',          'book',       'creator', 'P170', 'P872'}, 
    		{'publication_date', 'book',       'date',     nil,   'P577'}, 
    		{'date',             'photograph', 'date',     nil,   'P571'}, 
    		{'date',             'artwork',    'date',     nil,   'P571'}}   
    	for _, repItem in ipairs( repList ) do
    		local field, infobox, tag, oldP, newP = unpack(repItem)
    		if args[field] and args.infobox==infobox then 	
    			args[field] = TagQS.changeProperty(args[field], tag, oldP, newP) 
    			args[field] = TagQS.changeField(args[field], tag, field) 
    		end
    	end
    	if args.source and mw.ustring.find( args.source, 'www%.wga%.hu' ) then
    		-- code to help copy links to www.wga.hu to Wikidata
    		args.reference_wga = string.gsub(args.source, 'http://www%.wga%.hu', 'https://www.wga.hu')
    	end
    	return args
    end
    
    -- ===========================================================================
    function p.test(frame)
    	local args  = p.read_input_parameters(frame)
    	args.infobox = 'artwork'
    	local cats0 = p.verify_input_parameters(args)
    	args  = p.clean_input_parameters(args)
    	return p.build_html(args)
    end
    
    return p