Version vom 26. September 2018, 12:00 Uhr von Oetterer (Diskussion | Beiträge)
![]() | This module is rated as ready for general use. It has reached a mature form and is thought to be bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
![]() | This module depends on the following other modules: |
Usage[Quelltext bearbeiten]
{{#invoke:Article|main}}
local getArgs = require('Module:Arguments').getArgs
local _INFOBOX = require('Module:Infobox').infobox
local _CFG = mw.loadData('Modul:Article/config')
local _TT = require('Module:TableTools')
local _SMWUTIL = require('Module:SmwUtil')
local article = {}
local errors = {}
local os2osfamily = {}
function getPagesInCategory(category)
if category and #category > 0 then
local result = _SMWUTIL.ask({select = '[[Category:' .. category .. ']]', fields = {}}, { mainlabel = 'pageName' } )
local ret = {}
for _, v in pairs(result) do
if v.pageName and #v.pageName > 0 then
ret[v.pageName] = v.pageName
end
end
return ret
else
return nil
end
end
function getOs2osfamily()
if #os2osfamily == 0 then
local result = _SMWUTIL.ask({ select = '[[Category:Betriebssysteme]]', fields = 'is member of os family#-=family' }, { mainlabel = 'pageName' })
if not result or _TT.size(result) == 0 then
os2osfamily = _CFG.os2osfamily
else
for _, osdata in pairs(result) do
if osdata.pageName and osdata.family then
os2osfamily[mw.ustring.lower(osdata.pageName)] = mw.ustring.lower(osdata.family)
os2osfamily[osdata.pageName] = mw.ustring.lower(osdata.family)
end
end
end
end
return os2osfamily
end
function getArticleInfoboxType(uservalues_os)
if #os2osfamily == 0 then
if _CFG.control.useAutomatedOsFamilyDetection then
os2osfamily = getOs2osfamily()
else
os2osfamily = _CFG.os2osfamily
end
end
local families = {}
local ibType
for _, os in pairs(uservalues_os) do
if os2osfamily[mw.ustring.lower(os)] then
families[os2osfamily[mw.ustring.lower(os)]] = 1
ibType = os2osfamily[mw.ustring.lower(os)]
else
families[_CFG.control.fallbackIBType] = 1
ibType = _CFG.control.fallbackIBType
end
end
if _TT.size(families) ~= 1 then
return _CFG.control.fallbackIBType
else
return ibType
end
end
function getPortalListFor( services )
local validTechnicalServices = {}
for _, s in pairs( services ) do
if not _CFG.fallBack2default[s] then
table.insert( validTechnicalServices, s )
end
end
if #validTechnicalServices == 0 then
return {}
end
-- now build the query string and execute it
local query = {
select = '[[' .. table.concat( validTechnicalServices, ']] OR [[' ) .. ']]',
fields = { 'Shows on service landing page#-=portal' }
}
local result = _SMWUTIL.ask( query, { mainlabel = 'service' } )
-- build the lookup
local portalsLookup = {}
for _, row in pairs( result ) do
if type( row.portal ) ~= 'table' then
row.portal = { row.portal }
end
portalsLookup[row.service] = row.portal
portalsLookup[mw.ustring.lower(row.service)] = row.portal
end
-- why use this loop instead of processing the query result directly?
-- for the breadcrumb I want to prioritize services, so the parent
-- is derived from the first entered service.
-- Therefore I must base all my calculations on the original order
-- of services instead of the query order
local alreadyProcessed = {}
local portalList = {}
for _, service in pairs( services ) do
if portalsLookup[service] then
for _, v in pairs( portalsLookup[service] ) do
if not alreadyProcessed[v] then
table.insert( portalList, v )
alreadyProcessed[v] = true
end
end
elseif _CFG.fallBack2default[service]
and not alreadyProcessed[_CFG.control.displayDefaultAs]
then
table.insert( portalList, _CFG.control.displayDefaultAs )
alreadyProcessed[_CFG.control.displayDefaultAs] = true
end
end
return portalList
end
function printList( list, link, default )
if not list or _TT.size( list ) == 0 then
return default or ''
end
if not link then
return mw.text.listToText( list, ', ', ' und ' )
end
local linkedList = {}
local insertDefault = true
for _, v in pairs( list ) do
if not _CFG.fallBack2default[v] then
table.insert( linkedList, '[[' .. v .. ']]' )
elseif insertDefault then
table.insert( linkedList, _CFG.control.displayDefaultAs )
insertDefault = false
end
end
return mw.text.listToText( linkedList, ', ', ' und ' )
end
function split(str, sep)
if type(str) == 'table' then
return str
end
local r = {}
if not sep then
sep = ','
end
if str then
for v in mw.text.gsplit(str, sep, true) do
s = mw.text.trim(v)
if mw.ustring.len(s) > 0 then
table.insert(r, s)
end
end
end
if #r == 0 then
r = nil
end
return r
end
function article.processArgs(args)
--[[
This method takes the user provided arguments and
* checks all mandatory requirements
* converts all multivalue parameters to tables
* checks all provided valid entries
* sets default values for non mandatory and not provided parameters
* adds a preceeding 'Service:' to service if omitted
f
************** NOTE:
The following parameters will optionally be checked for validity:
* os
* service
see Modul:Article/config table control for more information
--]]
local uservalues = {}
for _, arg in pairs(_CFG.allParams) do
if _TT.inTable(_CFG.mandatory, arg) and (not args[arg] or #args[arg] == 0) then
table.insert(errors, "Pflichtfeld ''" .. arg .. "'' fehlt!")
elseif _TT.inTable(_CFG.multivalues, arg) then -- process multivalue parameters (can assume that mandatory fields are set)
if args[arg] and #args[arg] > 0 then -- multivalue parameter is set, so proceed
local valid = {}
local invalid = {}
if _CFG.validValues[arg] then
-- we only have valid values for type and targetgroup
for _, v in pairs(split(args[arg])) do -- for every entry, check if it is valid
if _TT.inTable(_CFG.validValues[arg], v) then
table.insert(valid, v)
else
table.insert(invalid, v)
end
end
else -- of if _CFG.validValues[arg] then
-- os and service can be validated later, if requested
valid = split(args[arg])
end -- of if _CFG.validValues[arg] then .. else
uservalues[arg] = valid
if #invalid > 0 then
table.insert(errors, "Parameter ''" .. arg .. "'' hat einen ungültigen Wert: " .. mw.text.listToText(invalid) .. "!")
end
else -- multivalue parameter is not set, take default (which can be nil)
uservalues[arg] = _TT.shallowClone(_CFG.defaultValues[arg])
end
else -- process singlevalue parameters (can assume that mandatory fields are set)
if not args[arg] or #args[arg] == 0 then -- if not set, take default (which can be nil)
uservalues[arg] = mw.clone(_CFG.defaultValues[arg])
elseif _CFG.validValues[arg] and not _TT.inTable(_CFG.validValues[arg], args[arg]) then
table.insert(errors, "Parameter ''" .. arg .. "'' hat einen ungültigen Wert: " .. args[arg] .. "!")
else
uservalues[arg] = args[arg]
end -- of if not args[arg] or #args[arg] == 0 then .. elseif .. else
end -- of if _TT.inTable(_CFG.mandatory, arg) and (not args[arg] or #args[arg] == 0) then .. elseif .. else
end -- of for _, arg in pairs(_CFG.allParams) do
-- special processing of service field. see to it, that all entries have a preceeding 'Service:'
for k, v in pairs(uservalues.service) do
-- the following is for backwards compatibilty when we migrated services from ns meta to ns service
if mw.ustring.find(v, 'Meta:', 1, true) then
-- this is due to legacy reasons. service entites were once stored in namespace meta
uservalues.service[k] = mw.ustring.gsub(v, 'Meta', 'Service', 1)
elseif not mw.ustring.find(v, 'Service:', 1, true) then
uservalues.service[k] = 'Service:' .. v
end
end
-- if requested, do some plausibility checks
if _CFG.control.validateParamOs then
-- valid_od is an associative list os -> osfamily. here, os is present as queried and in lowercase
local valid_os = getOs2osfamily()
local newvalues = {}
local fallingBack2default = nil
for _, os in pairs(uservalues.os) do
if not valid_os[mw.ustring.lower(os)] then
-- this could happen, if user manually added one of the fallback defaults
if _CFG.fallBack2default[os] then
if not fallingBack2default then
table.insert(newvalues, _CFG.defaultValues.os[1])
fallingBack2default = true
end
else
table.insert(errors, "Parameter ''os'' hat einen ungültigen Wert: '" .. os .. "'!")
end
else
table.insert(newvalues, os)
end -- of if not valid_os[os] then
end -- of for _, os in pairs(uservalues.os) do
uservalues.os = newvalues
end -- of if _CFG.control.validateParamOs then
if _CFG.control.validateParamService then
local valid_service = getPagesInCategory('Services')
local inactive_service = getPagesInCategory('Inactive services')
-- this is an associative list service -> service, whereas service is a pagename in ns service, e.g. Service:Mail
local all_services = valid_service
for k,v in pairs(inactive_service) do
all_services[k] = v
end
local newvalues = {}
local fallingBack2default = nil
for _, service in pairs(uservalues.service) do
if not all_services[service] then
if _CFG.fallBack2default[service] then
if not fallingBack2default then
table.insert(newvalues, _CFG.defaultValues.service[1])
fallingBack2default = true
end
else
table.insert(errors, "Parameter ''service'' hat einen ungültigen Wert: '" .. service .. "'!")
end
else
table.insert(newvalues, service)
end -- of if not valid_service[service] then
end -- of for _, service in pairs(uservalues.service) do
uservalues.service = newvalues
end -- end of if _CFG.control.validateParamService then
-- derive linked portal pages from technical services
uservalues._portal = getPortalListFor( uservalues.service )
return uservalues
end
function article.storeSementicData(uservalues)
local smwData = {}
for arg, prop in pairs(_CFG.arg2prop) do
smwData[prop] = uservalues[arg]
end
-- handling of special property "has sortkey"
if uservalues.disambiguation and #uservalues.disambiguation > 0 then
smwData['has sortkey'] = uservalues.disambiguation .. ' ' .. mw.title.getCurrentTitle().text
else
smwData['has sortkey'] = mw.title.getCurrentTitle().text
end
if uservalues.pagetype and #uservalues.pagetype > 0 then
smwData['is disambiguation page'] = 1
else
smwData['is disambiguation page'] = 0
end
_SMWUTIL.set(smwData)
-- debug:
--return '<pre>\nuservalues:\n' .. _TT.printTable(uservalues) .. '\n\nsmwData:' .. _TT.printTable(smwData) .. '</pre>'
end
function article.infobox(uservalues)
-- "calculate" type of infobox
local ib_type = getArticleInfoboxType(uservalues.os)
-- copy uservalues into local data tables
local os = mw.clone( uservalues.os )
local portal = mw.clone( uservalues._portal )
table.sort(os)
table.sort(portal)
local ib_args = {
bodyclass = '',
aboveclass = 'objtitle titletext',
title = uservalues.type,
above = _CFG.ibCoreData[ib_type].image .. ' ' .. _CFG.ibCoreData[ib_type].label,
headerclass = 'headertext',
labelstyle = 'width: 30%;',
datastyle = 'width: 70%;',
header1 = "Informationen",
label2 = 'Betriebssystem',
data2 = printList( os, true ),
label3 = 'Service',
data3 = printList( portal, true, 'keine' ),
label4 = 'Interessant für',
data4 = printList( uservalues.targetgroup ),
header6 = _CFG.ibCoreData[ib_type].portal
}
return _INFOBOX(ib_args)
end
function article.addBreadcrumbData( uservalues )
if not _CFG.control.idForParentField then
return ''
end
local findNonDefault = function( dataList )
if type( dataList ) ~= 'table' then
return false
end
for _, v in pairs( dataList ) do
if not _CFG.fallBack2default[v] then
return v
end
end
end
local portal = uservalues._portal
local parent = findNonDefault( portal )
if not parent then
parent = findNonDefault( uservalues.os )
end
if not parent and uservalues.disambiguation and #uservalues.disambiguation > 0 then
parent = uservalues.disambiguation
end
if not parent then
return ''
else
return '<span id="' .. _CFG.control.idForParentField .. '" style="display:none">' .. parent .. '</span>'
end
end
function article.addCategory(uservalues)
if mw.title.getCurrentTitle().namespace ~= 0 then
return ''
end
local cat = _CFG.type2category[uservalues.type] or _CFG.control.fallBackCategory
local category = '[[Category:' .. cat .. ']]'
return category
end
function article.addErrors()
local errorBoxes = mw.html.create('')
if #errors > 0 then
local messageBox = require('Module:Message box')
for _, errortext in pairs(errors) do
errorBoxes:wikitext(messageBox.main( 'ambox', {
type = 'delete',
text = errortext
-- More parameters...
})
)
end
if mw.title.getCurrentTitle().namespace == 0 then
errorBoxes:wikitext('[[Category:' .. _CFG.control.errorCategory .. ']]')
end
end
return errorBoxes
end
function article.addLinkToDisambiguation(uservalues)
local disambigLink = mw.html.create('')
if uservalues.disambiguation and #uservalues.disambiguation > 0 then
local hatnote = require('Module:Hatnote')._hatnote
disambigLink:wikitext(hatnote(_CFG.hatnote .. ' [[' .. uservalues.disambiguation .. ']]', {}))
end
return disambigLink
end
function article._main(args)
local uservalues = article.processArgs(args)
local output = mw.html.create('')
if #errors == 0 then
result = article.storeSementicData(uservalues)
if result then
-- only used in debug context
output:wikitext(result)
end
end
output:wikitext( article.addBreadcrumbData( uservalues ) )
:wikitext( article.infobox( uservalues ) )
:wikitext( article.addCategory( uservalues ) )
:node( article.addLinkToDisambiguation( uservalues ) )
:node( article.addErrors() )
-- when {{article}} is called by {{disambiguation}} you need to: {{#ifeq:{{#var:disambiguate_isdisambiguation|0}}|1||{{#set:Is disambiguation=0}}}}
-- --> maybe its enough, to not have it set at all... {{#set:Is disambiguation=1}} is done by {{disambiguate}}
return tostring(output)
end
function article.main(frame)
local args = getArgs(frame)
return article._main(args)
end
return article