Modul:Classgenerator/class: Unterschied zwischen den Versionen

CamNet - das Wiki
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
 
Zeile 66: Zeile 66:
local val = value
local val = value
if fieldname == 'template_name' and attribute == 'default' then
if fieldname == 'template_name' and attribute == 'default' then
val = mw.ustring.lower(pagename)
val = mw.ustring.lower(pagename):gsub("^%l", string.upper)
end
end
if fieldname == 'global_entityTitle' and attribute == 'default' then
if fieldname == 'global_entityTitle' and attribute == 'default' then
Zeile 143: Zeile 143:
local html = mw.html.create('div')
local html = mw.html.create('div')
html:node(formheader)
html:node(formheader)
:wikitext('__NOTOC__')
:newline()
:wikitext('<h1>GLOBAL-Section</h1>')
:wikitext('<h1>GLOBAL-Section</h1>')
:newline()
:newline()
Zeile 295: Zeile 297:
datastyle = 'width: 70%;',
datastyle = 'width: 70%;',
title = coreData.className,
title = coreData.className,
subheader = 'Class',
above = 'Class',
label1 = 'Title',
label1 = 'Title',
data1 = coreData.global_entityTitle and coreData.global_entityTitle or '',
data1 = coreData.global_entityTitle and coreData.global_entityTitle or '',
Zeile 325: Zeile 327:
data22 = coreData.page.gardeningCategory and '[[:' .. coreData.page.gardeningCategory.name .. ']]' or '',
data22 = coreData.page.gardeningCategory and '[[:' .. coreData.page.gardeningCategory.name .. ']]' or '',
}
}
local i = 31
if _private[self].identity and #_private[self].identity > 0 then
ib_args.header30 = 'Identity'
for _, param in ipairs(_private[self].identity) do
ib_args['label' .. i] = param.param
ib_args['data' .. i] = param.label
i = i + 1
end
i = i + 5
end
if usesSmw and coreData.properties.order and #coreData.properties.order > 0 then
if usesSmw and coreData.properties.order and #coreData.properties.order > 0 then
ib_args.header30 = 'Properties'
ib_args['header' .. (i-1)] = 'Properties'
local i = 31
for _, property in pairs(coreData.properties.order) do
for _, property in pairs(coreData.properties.order) do
ib_args['label' .. i] = coreData.properties.data[property].type
ib_args['label' .. i] = coreData.properties.data[property].type
Zeile 385: Zeile 397:
else
else
done = false
done = false
step1 = imgNo .. ' You have to create your module pages. This, you have to do <b>manually</b>. Go to [[#Page contents|section Page contents]], copy the module content and edit the corresponding module, ' ..
local step1insert
if _CFG.template.enableModuleCreation then
step1insert = 'This can be easily done by the click of a button [[#Page_autocreation|below]]. However, if you are a control freak, do this'
else
step1insert = 'This, you have to do'
end
step1 = imgNo .. ' You have to create your module pages, first. ' .. step1insert ..
' <b>manually</b>. Go to [[#Page contents|section Page contents]], copy the module content and edit the corresponding module, ' ..
'pasting all the copied content. Save and close. You have to do this for the following module(s): <ul> ' ..
'pasting all the copied content. Save and close. You have to do this for the following module(s): <ul> ' ..
(not coreData.page.base.exists and '<li>[[#Page contents|' .. coreData.page.base.name .. ']]</li>' or '') ..
(not coreData.page.base.exists and '<li>[[#Page contents|' .. coreData.page.base.name .. ']]</li>' or '') ..
Zeile 466: Zeile 485:
imgNo .. ' You are not finished yet, please tend to your tasks.'
imgNo .. ' You are not finished yet, please tend to your tasks.'
local manual = mw.html.create('')
local manual = mw.html.create('')
manual:wikitext('<h2>Your 2do checklist</h2>')
if not done then
:tag('ol')
manual:wikitext('<h2>Your 2do checklist</h2>')
:cssText('margin: 0.3em 0 0 1.6em; padding: 0')
:tag('ol')
:tag('li')
:cssText('margin: 0.3em 0 0 1.6em; padding: 0')
:wikitext(step1)
:tag('li')
:wikitext(step1)
:done()
:tag('li')
:wikitext(step2)
:done()
:tag('li')
:wikitext(step3)
:done()
:tag('li')
:wikitext(step4)
:done()
:done()
:done()
:newline()
end
-- here, add the identity
local identity = mw.html.create('')
if thisConfig then
identity:wikitext('<h2>Class identity</h2>')
local trs = mw.html.create('')
for _, paramData in ipairs( _private[self].identity ) do
local param = paramData.param
trs:tag('tr')
:tag('td')
:wikitext('<strong>' .. param .. '</strong>')
:newline()
:done()
:tag('td')
:wikitext(thisConfig.parameter[param].label)
:newline()
:done()
:tag('td')
:wikitext(thisConfig.parameter[param].severity)
:css('text-align', 'center')
:css('color', (thisConfig.parameter[param].severity == 'mandatory' and 'red' or 'inherit'))
:newline()
:done()
:tag('td')
:wikitext(thisConfig.parameter[param].cardinality)
:css('text-align', 'center')
:newline()
:done()
:tag('td')
:wikitext(thisConfig.parameter[param].description)
:newline()
:done()
:newline()
:done()
end
identity:tag('table')
:addClass('wikitable')
:addClass('sortable')
:newline()
:tag('tr')
:tag('th')
:wikitext('Parameter')
:newline()
:done()
:tag('th')
:wikitext('Label')
:newline()
:done()
:done()
:tag('li')
:tag('th')
:wikitext(step2)
:wikitext('Severity')
:newline()
:done()
:done()
:tag('li')
:tag('th')
:wikitext(step3)
:wikitext('Cardinality')
:newline()
:done()
:done()
:tag('li')
:tag('th')
:wikitext(step4)
:wikitext('Description')
:newline()
:done()
:done()
:done()
:done()
:node(trs)
:allDone()
end
-- get the data store details, if all the modules exist and we have a datastore configured
-- get the data store details, if all the modules exist and we have a datastore configured
local datastore = mw.html.create('')
local datastore = mw.html.create('')
Zeile 540: Zeile 627:
-- in missing we store, if a page in a given namespace is missing. Namespaces are stored by their ids (numbers)
-- in missing we store, if a page in a given namespace is missing. Namespaces are stored by their ids (numbers)
for _, pid in pairs(coreData.page.order) do
for _, pid in pairs(coreData.page.order) do
-- due to extension autocreatepage messing up module pages, in namepace module we only autocreate doc pages
-- once, extension autocreatepage messed up module pages.
-- if module creation is still disabled, we only autocreate doc pages namepace module
if not coreData.page[pid].exists and not Classgenerator.myTableTools.inTable(missing, coreData.page[pid].namespace) and  
if not coreData.page[pid].exists and not Classgenerator.myTableTools.inTable(missing, coreData.page[pid].namespace) and  
(coreData.page[pid].namespace ~= 828 or coreData.page[pid].isDocPage) then
(coreData.page[pid].namespace ~= 828 or coreData.page[pid].isDocPage or _CFG.template.enableModuleCreation) then
table.insert(missing, coreData.page[pid].namespace)
table.insert(missing, coreData.page[pid].namespace)
end
end
Zeile 557: Zeile 645:
if coreData.autocreate[ns] and coreData.autocreate[ns] > os.time() - _CFG.template.autoCreationTimeDiff then
if coreData.autocreate[ns] and coreData.autocreate[ns] > os.time() - _CFG.template.autoCreationTimeDiff then
-- ************************************* actual autocreation is done here
-- ************************************* actual autocreation is done here
-- we iterate over all namespaces for which pages are missing (var missing) and spring into action, if we have a numeric value supplied for that namespace coreData.autocreate[ns] that is recent enough
-- We iterate over all namespaces for which pages are missing (var missing) and spring into action,
-- now we have a namespace, we want to create pages for (var nsid) (all that is done in the recent 4 lines). what we do in the following lines:
-- if we have a numeric value supplied for that namespace coreData.autocreate[ns] that is recent enough.
-- we iterate over all pages in coreData.page.order and spring into action, if the interation instance (pid) is in the namespace (nsid), the page is non exist and is not a module
-- Now we have a namespace, we want to create pages for (var nsid) (all that is done in the recent lines).
-- in that action body, we create the page with the precalcualted content
-- what we do in the following lines:
-- also: for convenience, we create some global project (meta)categories, if related to the current page (project-form-category if nsid for forms, etc.) and configured in Foundationclass/globalconfig. here is an overview
-- We iterate over all pages in coreData.page.order and spring into action, if the iteration instance (pid)
-- is in the namespace (nsid), the page is non exist and is not a module or module creation is enabled
-- in that action body, we create the page with the pre-calculated content
-- Also: for convenience, we create some global project (meta)categories, if related to the current page
-- (project-form-category if nsid for forms, etc.) and configured in Foundationclass/globalconfig. here is an overview
-- Classgenerator.globalConfig.formCategory : MediaWiki:Classengine-content-project-form-category
-- Classgenerator.globalConfig.formCategory : MediaWiki:Classengine-content-project-form-category
-- Classgenerator.globalConfig.gardeningSuperCategory : MediaWiki:Classengine-content-project-gardening-supercategory
-- Classgenerator.globalConfig.gardeningSuperCategory : MediaWiki:Classengine-content-project-gardening-supercategory
Zeile 570: Zeile 662:
for _, pid in pairs(coreData.page.order) do
for _, pid in pairs(coreData.page.order) do
_debug(self, 3, ' testing page "' .. coreData.page[pid].name .. '": namespace id is ' .. coreData.page[pid].namespace ..
_debug(self, 3, ' testing page "' .. coreData.page[pid].name .. '": namespace id is ' .. coreData.page[pid].namespace ..
', and page does ' ..(not coreData.page[pid].exists and 'not ' or '') .. 'exist')
', and page does ' .. (not coreData.page[pid].exists and 'not ' or '') .. 'exist')
if coreData.page[pid].namespace == nsid and not coreData.page[pid].exists and (nsid ~= 828 or coreData.page[pid].isDocPage) then
if coreData.page[pid].namespace == nsid and not coreData.page[pid].exists and
if pid == 'gardeningCategory' and Classgenerator.globalConfig.gardeningSuperCategory and #Classgenerator.globalConfig.gardeningSuperCategory > 0 then
(nsid ~= 828 or coreData.page[pid].isDocPage or _CFG.template.enableModuleCreation) then
if pid == 'gardeningCategory' and Classgenerator.globalConfig.gardeningSuperCategory
and #Classgenerator.globalConfig.gardeningSuperCategory > 0 then
-- we just iterated over the gardening category page (so this class has one) but we did not create it, yet)
-- we just iterated over the gardening category page (so this class has one) but we did not create it, yet)
-- blindly try to create the gardening supercategory first, in case the class's gardening category is the gardening supercategory, we dont want the class specific content
-- blindly, try to create the gardening supercategory first, in case the class's gardening category is the
-- gardening supercategory, we dont want the class specific content
local content = '{{MediaWiki:Classengine-content-project-gardening-supercategory}}'
local content = '{{MediaWiki:Classengine-content-project-gardening-supercategory}}'
_debug(self, 3, ' trying to autocreate garderning supercategory page "' .. Classgenerator.globalConfig.gardeningSuperCategory .. '" with # of content being ' .. #content)
_debug(self, 3, ' trying to autocreate garderning supercategory page "' .. Classgenerator.globalConfig.gardeningSuperCategory .. '" with # of content being ' .. #content)
Zeile 597: Zeile 692:
end
end
elseif nsid == 828 and Classgenerator.globalConfig.moduleCategory and #Classgenerator.globalConfig.moduleCategory > 0 then
elseif nsid == 828 and Classgenerator.globalConfig.moduleCategory and #Classgenerator.globalConfig.moduleCategory > 0 then
-- we just iterated a module doc page (so this class has one) and created it (yay). Now blindly create the moduleCategory as well...
-- we just iterated over a module (doc) page (so this class has one) and created it (yay). Now blindly create the moduleCategory as well...
local content = '{{MediaWiki:Classengine-content-project-module-category}}'
local content = '{{MediaWiki:Classengine-content-project-module-category}}'
_debug(self, 3, ' trying to autocreate module category page "' .. Classgenerator.globalConfig.moduleCategory .. '" with # of content being ' .. #content)
_debug(self, 3, ' trying to autocreate module category page "' .. Classgenerator.globalConfig.moduleCategory .. '" with # of content being ' .. #content)
Zeile 645: Zeile 740:
end
end
-- create the tr for the ns
-- create the tr for the ns
local module_text = _CFG.template.enableModuleCreation and 'module pages and docs' or 'only module docs'
actable:tag('tr')
actable:tag('tr')
:tag('th')
:tag('th')
:css('text-align', 'left')
:css('text-align', 'left')
:css('width', widthTh)
:css('width', widthTh)
:wikitext('Create ' .. ((nsid == 828 and 'module docs' or (ns == 'property' and 'properties' or (ns .. (ns == 'template' and 's' or '')))) .. ':'))
:wikitext('Create ' .. ((nsid == 828 and module_text or (ns == 'property' and 'properties' or (ns .. (ns == 'template' and 's' or '')))) .. ':'))
-- note: nsid == mw.title.new('NUL', 'Property').namespace is necessary since canonicalname for property namespace does not translate uniquely over different languages :(
-- note: nsid == mw.title.new('NUL', 'Property').namespace is necessary since canonicalname for property namespace does not translate uniquely over different languages :(
:done()
:done()
Zeile 666: Zeile 762:
:done()
:done()
:newline()
:newline()
end
end
if Classgenerator.myTableTools.size(missing) > 0 then
if Classgenerator.myTableTools.size(missing) > 0 then
-- show the all button
-- show the "all"-button
local querystring = ''
local querystring = ''
for _, nsid in pairs(missing) do
for _, nsid in pairs(missing) do
local ns = mw.ustring.lower(_namespaceName(self, nsid))
local ns = mw.ustring.lower(_namespaceName(self, nsid))
querystring = querystring .. 'Classgenerator[global_autocreate_' .. ns .. ']=' .. os.time() .. '&'
querystring = 'Classgenerator[global_autocreate_' .. ns .. ']=' .. os.time() .. '&'
end
end
querystring = mw.ustring.sub(querystring, 1, -2)
querystring = mw.ustring.sub(querystring, 1, -2)
Zeile 692: Zeile 787:
:done()
:done()
:newline()
:newline()
pageAutoCreation:wikitext('<b>Note:</b> Creation of module pages is impossible due to an incompatibility issue.')
pageAutoCreation:wikitext('Use the following buttons ao create the corresponding pages automatically:')
:newline()
:newline()
:node(actable)
:node(actable)
Zeile 779: Zeile 874:
:node(smwPropertyHint)
:node(smwPropertyHint)
:node(manual)
:node(manual)
:node(identity)
:newline()
:newline()
:node(datastore)
:node(datastore)
Zeile 834: Zeile 930:
coreData.form_createInfotext = coreData.form_createInfotext .. ' '
coreData.form_createInfotext = coreData.form_createInfotext .. ' '
end
end
coreData.template_name = coreData.template_name:gsub("^%l", string.upper)
local parameter_parameter
local parameter_parameter
local fieldOrder
local fieldOrder
Zeile 1.047: Zeile 1.144:
propertyData = {}
propertyData = {}
propertyOrder = {}
propertyOrder = {}
for prop, parameter in pairs(matrix) do
for prop, parameterList in pairs(matrix) do
if FoundationClass.globalConfig.ucfirst then
for _, parameter in pairs(parameterList) do
property = lang:ucfirst(prop)
if FoundationClass.globalConfig.ucfirst then
else
property = lang:ucfirst(prop)
property = prop
else
end
property = prop
table.insert(propertyOrder, property)
end
local obj = mw.title.new(property, 'Property')
table.insert(propertyOrder, property)
propertyData[property] = {  
local obj = mw.title.new(property, 'Property')
editlink = obj:fullUrl{action='edit'},
propertyData[property] = {  
exists = obj.exists,
editlink = obj:fullUrl{action='edit'},
parameter = parameter,
exists = obj.exists,
}
parameter = parameter,
if thisConfig.parameter[parameter] then
}
propertyData[property].description = thisConfig.parameter[parameter].description
if thisConfig.parameter[parameter] then
propertyData[property].type = thisConfig.parameter[parameter].property_type
propertyData[property].description = thisConfig.parameter[parameter].description
propertyData[property].values = thisConfig.parameter[parameter].values
propertyData[property].type = thisConfig.parameter[parameter].property_type
elseif parameter == FoundationClass.globalConfig.smwClassProperty then
propertyData[property].values = thisConfig.parameter[parameter].values
propertyData[property].description = 'Automatisch hinzugefügt! Wird verwendet, um Mitglieder dieser Klasse zu finden (funktioniert auch, ohne dass eine Kategorie definiert wird und auch fur subobjects)'
elseif parameter == FoundationClass.globalConfig.smwClassProperty then
propertyData[property].type = 'Text'
propertyData[property].description = 'Automatisch hinzugefügt! Wird verwendet, um Mitglieder dieser Klasse zu finden (funktioniert auch, ohne dass eine Kategorie definiert wird und auch fur subobjects)'
elseif parameter == FoundationClass.globalConfig.uidFieldName then
propertyData[property].type = 'Text'
propertyData[property].description = 'Automatisch hinzugefügt! Wird verwendet, um individuelle Objekte innerhalb der Klasse zu identifizieren.'
elseif parameter == FoundationClass.globalConfig.uidFieldName then
propertyData[property].type = 'Text'
propertyData[property].description = 'Automatisch hinzugefügt! Wird verwendet, um individuelle Objekte innerhalb der Klasse zu identifizieren.'
end
propertyData[property].type = 'Text'
local values = ''
end
if propertyData[property].values then
local values = ''
values = values .. 'The allowed values are:'
if propertyData[property].values then
for _, value in pairs(propertyData[property].values) do
values = values .. 'The allowed values are:'
values = values .. '\n* [[Allows value::' .. value .. ']]'
for _, value in pairs(propertyData[property].values) do
values = values .. '\n* [[Allows value::' .. value .. ']]'
end
else
values = 'No restriction given'
end
end
else
propertyData[property].content = mw.message.new('classengine-template-property-page'):rawParams(propertyData[property].description, propertyData[property].type, values, _private[self].pagename, propertyCategory):plain()
values = 'No restriction given'
end
end
--propertyData[property].content = mw.message.new('classengine-template-property-page'):rawParams(propertyData[property].description, propertyData[property].type, values, _private[self].pagename, propertyCategory):plain()
propertyData[property].content = 'description: ' .. (propertyData[property].description or 'missing')
.. '\ntype:' ..  (propertyData[property].type or 'missing')
.. '\nvalues: ' .. values
.. '\npagename: ' .. (_private[self].pagename or 'missing')
.. '\nCategory: ' .. propertyCategory
.. '\nmatrix: ' .. Classgenerator.myTableTools.printTable(matrix)
end
end
table.sort(propertyOrder)
table.sort(propertyOrder)
end
end
coreData.properties = { data = propertyData, order = propertyOrder }
coreData.properties = { data = propertyData, order = propertyOrder }
-- calculate identity
if thisConfig then
local ib_identity = {}
local parameterList = {}
for param, _ in pairs(thisConfig.parameter) do
table.insert(parameterList, param)
end
function findKey( t, v )
for k, vv in ipairs(t) do
if vv == v then
return k
end
end
end
for _, param in ipairs( fieldOrder ) do -- lets test fieldOrder, if not, use parameterList
table.insert(
ib_identity,
{
param = param,
label = thisConfig.parameter[param].label
}
)
table.remove(parameterList, findKey(parameterList, param))
end
if #parameterList > 0 then
table.sort(parameterList)
for _, param in ipairs(parameterList) do
table.insert(
ib_identity,
{
param = param,
label = thisConfig.parameter[param].label
}
)
end
end
_private[self].identity = ib_identity
end
return coreData -- this is your new coreData.
return coreData -- this is your new coreData.
end
end

Aktuelle Version vom 2. Juli 2024, 15:57 Uhr

Documentation icon Module documentation

This is a Class Module. It implements a class in Lua using Module:Middleclass and the template class Module:Foundationclass. This class provides methods for PURPOSE.

Usage

local name = args[1] or args.name or mw.title.getCurrentTitle().rootText
local Class = require('Module:Name/class')
local me = Class:new(name)
me:initDataFromArgs(args)
me:storeData()
me:addInfobox()
me:addPageBody()
return me:render()

Methods

Constructor

new(uid)

Creates a new Object for the class.

uid
variable, optional
used to identify the object
return
object, of the class

public methods

addInfobox()

If no errors and data is present, adds an infobox to the object's output.

return
boolean, whether adding was successful or not

addPageBody()

Adds a page body (all content besides the infobox) to the object's output: Errors and Warnings, sample configuration, statistics, ... Of course, only if there is data.

return
boolean, whether adding was successful or not

myArgumentProcessing(coreData)

Performs the individual argument processing in initDataFromArgs(args) right before inititializing it.

coreData
table, mandatory
the core data of the object. the one to process individually before initialization
return
table, the new core data array to be used

myPlausibilityTest(args)

Performs the individual plausibility tests in initDataFromArgs(args) before entering the initialization part. NOTE: The return value will be ignored. If this finds errors, it must add them to the list of errors via addError(errortext).

args
table, mandatory
arguments passed to the template to be checked
return
boolean, whether the object is plausible or not.

myStashAdjustments(self, stash)

Performs the adjusts the stash in storeData() right before storing it.

stash
table, mandatory
the array of data to be saved (in the form fieldname: value)
return
boolean, the new stash

static methods

ClassClassgenerator:mySfDynamicFieldAttribute(fieldname, attribute, value)

For some semantic form fields there are attribute values, that are not static, thus can not be provided at forehand in the configuration file. This method does the trick to adapt them at runtime shortly before the field is rendered. Essentially: the method checks, if it has a special rule for the pair fieldname:attribute and if so, calculates the new value. if not, the old value is returned.

fieldname
string, mandatory
the form field's name, needed to match current paring to an existing special treatment rule
attribute
string, mandatory
the form field's attribute, needed to match current paring to an existing special treatment rule
value
variable, mandatory
the value, that is already provided in the configuration file. this will be adapted by the method, if there is a special rule for the pair fieldname:attribute.
return
string, the value to be used forthwith (which can be the old one or a freshly calculated)

private methods

_debug(self, level, text)

Adds output to the internal debug log.

self
object, me
level
int; mandatory
debug level for the message
text
string; mandatory
debug message text
return
void

_namespaceName (self, namespaceId)

Takes the id of a namespace and converts it to the human readable name. Normally returns mw.site.namespaces[id].canonicalName...

self
object, me
namespaceId
int; mandatory
for which namespace id the name should be returned
return
string, name of namespace

_processAttribute(self, attr, indent, name)

Takes an attribute and builds from that (and self:getCoreData()) one entry in the class's config file.

self
object, me
attr
string; mandatory
for which attribute should the entry be build
indent
string; mandatory
indentation of line
name
string; optional
normally the parameter name will be constructed out of attr. if you have special needs as a name, you can supply them via this parameter. name takes precedence, if provided.
return
string, the entry that can directly be added to the config file/string

Properties

static

See also Static Properties

ClassName.myConfiguration
this is your configuration. It is devided in several section, each a
table, holds configuration data found in Module:Name/config
WARNING: This is a read only table and besides functions pairs() and ipairs() nothing else will work on it, especially not the functions of the table library!
    • form, table, holds data used to create the form. here are some of them:
      • formButtons, table, which buttons should be printed at the bottom
      • fieldOrder, table, in which order the form fields should appear (note: only fields listed here will be added to the form)
    • global, table, holds some global configuration data
    • parameter, table, holds all data about all parameter used in the module (be they form only, data store only or normal). The table has the form paramname = { table of paramdata }. The tables for the parameter have data as follows:
      • cardinality, string, mandatory, one of singe or list
      • cargo_type, string, optional, if the parameter is to be stored in cargo, add the field type here (one of Page, Text, Integer, Float, Date, Datetime, Boolean (which should be provided as 1 or 0), Coordinates, Wikitext, File, String, URL, or Email)
      • description, string, mandatory, a description of this parameter
      • label, string, mandatory, the label used in the form and the template documentation
      • severity, string, optional, if provided one of mandatory, suggested
      • sf, table, optional, used to add more attributes to the semantic forms field. ref Module:SFfield/config for all possible attributes. Note that the table is of type attribute_name : value. Value can be of type string, integer, boolean, and (in case of 'show on select') a table. Please note, that the attribute name cannot contain a " " (space). Use the underscore instead.
      • td_default, string, optional, if you want a default value to be indicated in the template data section on the documentation page, add it here
      • td_type, string, optional, if the parameter should be present in the template documentation page, fill this field. all possible values are listed here
      • values, table, optional, if you want the possible values to be restricted to a specific set, fill this table
    • template, table, holds some data used only in the template
className.publicStaticProperty
type, explanation
_privateStaticProperty
type, explanation

private

Note: all private properties are stored in table _private[self]. _private is a static array that is indexed by self, so the table _private[self] holds all properties for instance self.

dbg
object, my instance of Module:Debug/class for debugging purposes. only present afer first call of _debug(self, level, text)

Configuration Data

This class holds its control data in Module:Classgenerator/config.

Inheritance

Methods

Note: You still reference those either by self:publicMethod() or Classgenerator:staticMethod() and Classgenerator.staticProperty respectively!

Constructor

new(uid, superhandler)

Creates a new Object for the class.

uid
variable, suggested
used to identify the object. defaults to mw.title.getCurrentTitle().prefixedText
superhandler
object of childclass of Foundationclass, optional
supply the superhandler, if you instanciate an object within another object. the instanciated object will pass errors and warnings to the superhandler and forgo adding an object category
return
object, of the class

Abstract Methods

myArgumentProcessing(coreData)

Performs the individual argument processing in initFromArgs(args) right before inititializing it.

coreData
table, mandatory
the core data of the object. the one to process individually before initialization
return
table, the new core data array to be used

myDataAdjustments(data)

Performs a transformation form data (coming from the datastore) into data used for argument processing. This is called by initFromData(data) (for smw: after property to parameter conversion) and is directly passed to initFromArgs(args) and subsequently plausibility test.

data
table, mandatory
a data table coming directly from the data store
return
table, the new data table suiteable for argument processing

myPlausibilityTest(args)

Performs the individual plausibility tests in initFromArgs(args) before entering the initialization part. NOTE: The return value will be ignored. If this finds errors, it must add them to the list of errors via addError(errortext).

args
table, mandatory
arguments passed to the template to be checked
return
boolean, whether the object is plausible or not.

myStashAdjustments(stash, storeType)

Can adjusts the stash in storeData() right before storing it.

stash
table, mandatory
the array of data to be saved (in the form fieldname: value)
storeType
string, mandatory
type of storage method used with the current call (either 'cargo' or 'swm'). In case you use both stores and your stash adjustment differs with each of this methods
return
table, the new stash

FoundationClass:mySfDynamicFieldAttribute(fieldname, attribute, value)

For some semantic form fields there are attribute values, that are not static, thus can not be provided at forehand in the configuration file. This method does the trick to adapt them at runtime shortly before the field is rendered. Essentially: the method checks, if it has a special rule for the pair fieldname:attribute and if so, calculates the new value. if not, the old value is returned. Note, that you can completely disable a form field with this when you return false on attribute "disable".

fieldname
string, mandatory
the form field's name, needed to match current paring to an existing special treatment rule
attribute
string, mandatory
the form field's attribute, needed to match current paring to an existing special treatment rule
value
variable, mandatory
the value, that is already provided in the configuration file. this will be adapted by the method, if there is a special rule for the pair fieldname:attribute.
return
string, the value to be used forthwith (which can be the old one or a freshly calculated)

Public methods

addCategory(category)

Prepares to add the page to category category. Note: until you actually call render() or renderCategories(), this will not be implemented

category
string, mandatory
the name of the category, to add the page to
return
boolean, true

addError(errortext)

adds errortext as new error to the list of errors, rendered at a later time.

errortext
string, mandatory
text added to list of errors
return
boolean, whether adding was successful or not

addInfobox()

If no errors and data is present, adds an infobox to the object's output. NOTE: This is a shell method and should be overwritten!

return
boolean, whether adding was successful or not

addOutput(content)

Adds something to the page's output. Something can be of type string, int, or table (that needs to have __tostring() implemented)

content
string, int, or table; mandatory
content element that is added to page's output
return
boolean, whether adding was successful or not

addPageBody()

Adds a page body (all content besides the infobox) to the object's output: Errors and Warnings, sample configuration, statistics, ... Of course, only if there is data. NOTE: This is a shell method and should be overwritten!

return
boolean, whether adding was successful or not

addWarning(warning)

adds warning as new warning to the list of warnings, to be rendered at a later time (with renderWarnings()).

warning
string, mandatory
text added to list of warnings
return
boolean, whether adding was successful or not

getCoreData()

Returns the table of coreData

return
table, the value for _private[self].coreData, emtpy if not initialized

getUid()

Returns the object's uid, nil if not set

return
variable, the value for _private[self].uid

goodToGo()

Is this a proper object (with data and no errors)

return
boolean, whether we are proper initialized

initFromArgs(args)

Initializes the object with a data table, containing arguments (template parameter). Does plausibility tests and mangling of input and either fills list of errors or adds input to the object's data. {{{1}}}

initFromData(data)

Initializes the object with a data table, coming from the datastore. Depending on datastore, that means that the table keys might be different than when using arguments form the template. Does plausibility tests and mangling of input and either fills list of errors or adds input to the object's data. {{{1}}}

initMyself(uid)

Initializes the object with data from the data store. The method queries for the object's uid in the container defined by Foundationclass.globalConfig.uidFieldName (can be set to an infividual name in Module:Foundationclass/globalconfig) in either the class's table (in case of datastore cargo) or for objects that have Foundationclass.globalConfig.smwClassProperty set to class.name (in case of datastore smw). The uid was either passed to the method (priority) or submitted to the constructor. Does NOT do plausibility tests and mangling of input but assumes the data comes directly from the data store and thus can be trusted (i.e. passes _plausibilityTest())

uid
string, optional
the data, the object can use to identify itself. This field can be omitted, in which case the uid that was submitted to the constructor will be used.
return
boolean, whether initialization was successful or not

render()

Renders the object's output

return
string, the textual representation of the object (which can vary, depending on what add*-methods you called before)

renderCategories()

Renders the object's categories (if any), thus adding them to the output stream and in turn sorting the page in it, if and only if render() is called on the object's page (when self:getUid == Classgenerator/class).

return
object of type mw.html, the wikitext necessary to add the page to the categories

renderErrors()

Renders the object's errors (if any)

return
object of type mw.html, the representation of the list of errors

renderWarnings()

Renders the object's warnings (if any)

return
object of type mw.html, the representation of the list of warnings

setSortkey(sortkey)

Sets a default sortkey for this page using the magic word DEFAULTSORT. Only applies, if no superhandler is given.

sortkey
string, mandatory
new sortkey for this page
return
void

setUid(value)

Sets my uid to the given value. normally this should be set by constructor

value
string/integer, mandatory
new valued for my uid
return
boolean, true/false

storeData()

If this was initialized with outside data and there are no errors, stores the arguments in an appropriate data store (smw or cargo). In case of cargo, also calls the necessary #cargo_declare parser function if in the template namespace.

return
boolean, whether store was successful or not

Static methods

FoundationClass:categorize()

Placed on one to class's pages (usually not on the class object pages), this calculates the necessary (meta-) category, to put the page in, using pagetitle, subpagetitle, namespace, and so on. Your project's categories (defined in Module:Foundationclass/globalconfig) are used.

return
string, to be put on page, so that it will be categorized

FoundationClass:categoryPage()

Procudes the output for our corresponding category page. Including the message box and the display of the data structure.

return
object of type mw.html, the representation of the category page's content

FoundationClass:cargoGenerateTableStructure()

Produces a cargo table declaration array (fieldname => declaration of field) that can be used in method storeData() for cargo_declare.

return
table, data structure for cargo table

FoundationClass:explainDataStore()

Produces a textual explanation of the used datastructure (table definition for cargo or property list and types for smw) that can be printed on various dodumentation pages

return
string, a textual explanation

FoundationClass:formRedlink(target, form, linktext, queryString)

Takes a pagename (target) and a formname (form) and then generates a link to that page if the page exists. Otherwise it links to the form to create the page. Linktext is target per default, if you do not provide linktext

target
string, mandatory
the pagename (including namespace) to link to
form
string, mandatory
the name of the form (w/o the form namespace!!) to fallback to, if page does not exist
linktext
string, optional
text you want to display instead of target
queryString
string, optional
the query string provided to the form, e.g. 'Template[page]=' .. mw.title.getCurrentTitle().prefixedText
return
string, the requested link

FoundationClass:gardeningCategoryPage()

Procudes the output for the class' gardening category page (if any). Includung the message boxes.

return
object of type mw.html, the representation of the gardening category page's content

FoundationClass:mwLink(object)

Takes object and links it (adding square brackets). If object is a table, it iterates over it with lua's mw.text.listToText()

object
mixed
object to return as linked string(s)
return
string, with all elements of object mw-linked

FoundationClass:placeInNamespace(pagename, namespace)

Makes sure, that (string) pagename resides in (string) namespace. Returns the pagename w/ new namespace and w/o any namespace

pagename
string
name of page to be prepended with new namespace
namespace
string
new namespace for page
return
string, full page name in new namespace
string, base page name without any namespace

FoundationClass:sfGenerateForm()

Generates all output necessary for a form, that can be used to create or maintain an object of this class. Note: this output is to be put inside the <includeonly>-tag on the Form page.

return
object of class mw.html, the representation of the form

FoundationClass:sfGenerateFormEntry()

Generates the "teaser" text shown on the form page when accessing it to create a form (before you type in the name in the input field)

return
object of class mw.html, the representation of the form teaser

FoundationClass:sfGenerateFormInfoTag()

Generates a form's info-tag, together with create and edit title and - if applicable - the query string (in case we have createLinkType formlink).

return
string, a semantic form info tag

FoundationClass:sfGenerateFormLink(params)

Generates a form input field or a form link that links to the class's form (essentially calls the parser function #forminput or #formlink respectively).

params
table, data to pass to the form link/input generator. supported fields are: label and query string
return
string, the input field, that lints to the form

FoundationClass:sfGenerateFormTable(fieldlist)

Generates a table that can be used in a form inside the {{{for template}}} tag. The table contains all fields, that are named in the table parameter fieldlist (which defaults to _CFG.form.fieldOrder) and that are present in _CFG.parameter.. All fields with attribute hidden are placed after the closing /table-tag

fieldlist
table, optional
contains a list of fieldnames, to be processed and added to the return node.
return
object of class mw.html, the representation of the formtable

FoundationClass:sfInitField(fieldname)

Creates a field object of Class SFfield and initializes it per myConfiguration.parameters[fieldname] if entry is present

fieldname
string, mandatory
contains the name of the field to initialize
return
object of Class SFfield, the initialized field object. nil if fieldname is not present in parameter-array

FoundationClass:smwGetProperty2ParameterTranslationTable()

Returns a translation table property-name => parametername, if data store smw is used.

return
table, for every property used in the class the corresponding parameter name

FoundationClass:templateDocumentation()

Generates almost all the output, necessary to have a good documentation page for the corresponding template. Only missing the {{documentation subpage}} call at the top and the includeonly part at the bottom.

return
object of class mw.html, the representation of the template documentation

FoundationClass:usesDataStore(store)

Returs true, if class uses store as datastore. Available stores are 'cargo' and 'smw'

store
string, mandatory
store type to check against
return
bool, whether store store is used as data store

Static Properties

FoundationClass.globalConfig
table, holds some global configuration (data, that applies to all classes the same way). See Module:Foundationclass/globalconfig for details.
FoundationClass.myCargoUtil
table, instance of Module:CargoUtil
FoundationClass.mySwmUtil
table, instance of Module:SmwUtil
FoundationClass.myTableTools
table, instance of Module:TableTools
FoundationClass.myYesno
table, instance of Module:Yesno

Dependecies

Apart from the obvious (being all pages in Category:Class engine), we also need:

Nice to have:

Please check also Foundationclass's dependencies.

Interface messages

To generate your project's meta categories, Classgenerator makes use of the following interface messages:

You may edit them freely for your convenience to suit your needs.

local FoundationClass = require('Module:Foundationclass')
local ClassDebug = require('Module:Debug/class')

-- ****************************************************************
-- *                         inheritance                          *
-- ****************************************************************
local Classgenerator = FoundationClass:subclass('Classgenerator')
-- setting class's configuration data
Classgenerator.static.myConfiguration = mw.loadData('Module:Classgenerator/config')
--   being in a static method, use self.myConfiguration
--   being in a private method, that knows self or in a public method, use self.class.myConfiguration

-- ****************************************************************
-- *                          properties                          *
-- ****************************************************************

-- **************** initialization of table for private properties
local _private = setmetatable({}, {__mode = 'k'})   -- weak table storing all private attributes

-- **************** declaration of public static properties
-- Classgenerator.static.myPropertyModule = require('Module:extern')
-- Classgenerator.static.staticProperty = 'value'

-- remember the static classes provided by Foundationclass:
-- Classgenerator.globalConfig
-- Classgenerator.myCargoUtil
-- Classgenerator.myTableTools

-- **************** declaration of (global) private properties
-- for properties you should rather use constructor and _private[self]. this only, if you need a private class property
-- you should, however predeclare private methods here
local _debug	-- private method declared later
local _privateMethodAhead	-- declaration ahead, so this private method can be used in the constructor and in other private methods

-- ***************************************************************
-- *                           methods                           *
-- ***************************************************************
 
-- **************** declaration of static methods
function Classgenerator:initialize(uid)
	local _CFG = self.class.myConfiguration
	FoundationClass.initialize(self, uid)
	local page = mw.title.getCurrentTitle().text
	if uid and mw.ustring.match(uid, '^' .. _CFG.global.namespace .. ':.+$') then
		page = mw.ustring.match(uid, '^' .. _CFG.global.namespace .. ':(.+)$')
	end
	_private[self] = {
		dbg = ClassDebug:new(tostring(self.class) .. ': id ' .. uid),
		pagename = page
	}
	_debug(self, 1, ' Classgenerator: done initializing object &quot;' .. uid ..'&quot;, from ' .. tostring(self))
end

-- use use self.myConfiguration to access your configuration in a static method
function Classgenerator.static:aStaticMethod(var)
	_debug(self, 1, 'entering Classgenerator.static:aStaticMethod() to do something, from ' .. tostring(self))
end

function Classgenerator.static:mySfDynamicFieldAttribute(fieldname, attribute, value)
	_debug(self, 1, 'entering Classgenerator.static:mySfDynamicFieldAttribute(fieldname, attribute, value), from ' .. tostring(self))
	_debug(self, 2, ' with parameters &quot;' .. fieldname .. '&quot;, &quot;' .. attribute .. '&quot; and a ' .. type(value) .. ' value')
	-- function that can process any attribute/value pair just before rendering the semantic forms field
	-- usually done, to generate a dynamic 'default' value
	-- keep in mind: you can completely disable a form field, if you return true on attribute "disable". note however, that this causes the field to not show at all, no data will be transported/saved
	local pagename = mw.title.getCurrentTitle().text
	local val = value
	if fieldname == 'template_name' and attribute == 'default' then
		val = mw.ustring.lower(pagename):gsub("^%l", string.upper)
	end
	if fieldname == 'global_entityTitle' and attribute == 'default' then
		val = mw.ustring.gsub(pagename, '[ /]', '')
	end
	if fieldname == 'global_cargoTable' and attribute == 'default' then
		val = mw.ustring.gsub(pagename, '[ /]', '')
	end
	if Classgenerator.globalConfig.dataStore ~= 'cargo' and Classgenerator.globalConfig.dataStore ~= 'both' then
		if fieldname == 'global_cargoTable' and attribute == 'disable' then
			val = true
		end
		if fieldname == 'global_cargoUidFieldname' and attribute == 'disable' then
			val = true
		end
	end
	if Classgenerator.globalConfig.dataStore ~= 'smw' and Classgenerator.globalConfig.dataStore ~= 'both' then
		if fieldname == 'global_smwIsSubobject' and attribute == 'disable' then
			val = true
		end
		if fieldname == 'global_smwUseStorage' and attribute == 'disable' then
			val = true
		end
		if fieldname == 'global_autocreate_property' and attribute == 'disable' then
			val = true
		end
	end
	return val	-- this value will be used as new value for field's attribute
end

function Classgenerator.static:sfGenerateForm()
	_debug(self, 1, 'entering Classgenerator.static:sfGenerateForm(), from ' .. tostring(self))
	local _CFG = self.myConfiguration
	local ClassgeneratorParameter  = require('Module:Classgenerator/parameter/class')
	local ClassSFfield = require('Module:SFfield/class')
	local tagStart = '{{{'
	local tagEnd = '}}}'
	local frame = mw.getCurrentFrame()
	-- create the form header
	local notification = mw.html.create('')
	if _CFG.form.notification and mw.ustring.len(_CFG.form.notification) > 0 then
		local mbox = require('Module:Message box')
		notification:wikitext(mbox.main('ombox', { text = _CFG.form.notification }))
			:newline()
	end
	local formheader = mw.html.create('')
	formheader:wikitext(self:sfGenerateFormInfoTag())
		:wikitext('<h2>' .. _CFG.global.entityTitle .. '</h2>')
		:tag('p')
			:wikitext(_CFG.form.headerText)
			:done()
			:newline()
		:node(notification)
		:tag('div')
			:attr('id', 'wikiPreview')
			:cssText('display: none; padding-bottom: 25px; margin-bottom: 25px; border-bottom: 1px solid #AAAAAA;')
			:done()
			:newline()
	-- create the form buttons
	local formbuttons = mw.html.create('div')
	for _, button in pairs(_CFG.form.buttons) do
		formbuttons:wikitext(tagStart .. 'standard input|' .. button .. tagEnd)
	end
	formbuttons:addClass('formbuttons')
		:done()
	-- calculate the fieldlists:
	local fieldlists = {}
	for _, field in pairs(_CFG.form.fieldOrder) do
		local tab = mw.ustring.match(field, '^([a-z]+)_.+')
		if not fieldlists[tab] then
			fieldlists[tab] = {}
		end
		table.insert(fieldlists[tab], field)
	end
	-- assemble everything, so start the html object
	local html = mw.html.create('div')
	html:node(formheader)
		:wikitext('__NOTOC__')
		:newline()
		:wikitext('<h1>GLOBAL-Section</h1>')
		:newline()
		:tag('div')
			:wikitext('This section deals with all the class\'s global data, i.e. all data you need for your "template" part as wenn as for your form, ... ')
			:done()
			:newline()
		:wikitext(tagStart .. 'for template|' .. _CFG.template.name .. '|label=' .. _CFG.global.entityTitle .. tagEnd)
		:newline()
		:node(self:sfGenerateFormTable(fieldlists.global))
		:newline()
		:wikitext('<h1>FORM-Section</h1>')
		:newline()
		:tag('div')
			:wikitext('This section deals with all the data, you need to create and operate a form for this class. If you don\'t want a form, disable this section. ' ..
					'If you need a form (e.g. as part of another form), but no form page, enable this section but leave the field for form page name emtpy.')
			:done()
			:newline()
		:node(self:sfGenerateFormTable(fieldlists.form))
		:newline()
		:wikitext('<h1>TEMPLATE-Section</h1>')
		:newline()
		:tag('div')
			:wikitext('This section deals with all the data, you need to create and operate a template for this class. If you need tempalte specific parameters ' ..
				'(meaning parameteres that you only need to operate the "action"-part), put them into this section\'s custom field')
			:done()
			:newline()
		:node(self:sfGenerateFormTable(fieldlists.template))
		:newline()
		:wikitext('<h1>PARAMETERS-Section</h1>')
		:newline()
		:tag('div')
			:wikitext('This section deals with all your parameters. You need an entry for every form input field, every template parameter, every data field you want to store, and even every notification line.')
			:tag('ul')
				:tag('li')
					:wikitext("To produce a normal parameter, add an entry, choose storage type, set '''Regular form parameter''' to yes, choose a form input type, and a template doc type.")
					:done()
					:newline()
				:tag('li')
					:wikitext("If you want a data field to be stored in your data storage but not defined in the form, choose a data storage type and set '''Regular form parameter''' to no. ")
					:done()
					:newline()
				:tag('li')
					:wikitext("If you want a mutiple template to be parsed to a parameter, create a normal parameter (as described above) and choose '''Regular form parameter''' to  be ''Holds template''.")
					:done()
					:newline()
				:tag('li')
					:wikitext("A parameter with a form input that is not stored is created like a regular parameter but without setting any data storage type.")
					:done()
					:newline()
				:tag('li')
					:wikitext("Finally, you can create a message line. This is useful, if you want to convey any information to the user, that is to important for a description-tooltip. " ..
						"What you need to do is disable everything ('''Template doc parameter type ''', data storage) and set '''Regular form parameter''' to ''Information''. " ..
						"You probalby want to add the parameter to one or more ''show on select'' entries, too.")
					:done()
					:newline()
				:done()
				:newline()
			:done()
			:newline()
		:node(self:sfInitField('parameter_parameter'):render())
		:newline()
		:wikitext(frame:extensionTag('headertabs'))
		:newline()
		:wikitext("'''(*) Pflichtfeld'''")
		:newline()
		:wikitext(tagStart .. 'end template' .. tagEnd)
		:newline()
		:wikitext(ClassgeneratorParameter:sfGenerateForm())
		:newline()
		:node(formbuttons)
	local debugLevel = FoundationClass.globalConfig.debugLevel or self.myConfiguration.global.debugLevel
	if debugLevel then
		html:newline()
			:newline()
			:wikitext(ClassDebug:printLog(debugLevel))
	end
	return html
end

-- **************** declaration of private methods
-- use self.class.myConfiguration to access your configuration in a public or a private method that is called by a public method
_debug = function (self, level, text)
	if _private[self] and _private[self].dbg then
		local debugLevel = FoundationClass.globalConfig.debugLevel or self.class.myConfiguration.global.debugLevel
		if debugLevel and level <= debugLevel then
			_private[self].dbg:log(level, text)
		end
	else
		local debugLevel = FoundationClass.globalConfig.debugLevel or self.myConfiguration.global.debugLevel
		if debugLevel and level <= debugLevel then
			ClassDebug:log(level, text, tostring(self) .. '.static')
		end
	end
end

local _namespaceName = function (self, namespaceId)
	_debug(self, 1, 'entering private _namespaceName() to translate namespace namespaceId ' .. namespaceId .. ' into a universal name, from ' .. tostring(self))
	local ret, nulProperty = pcall(mw.title.new, 'NUL', 'Property')
	if ret and (namespaceId == nulProperty.namespace) then
		return 'property'	-- if you change this, check on other places, this is checked against and change that, too
	else
		return mw.site.namespaces[namespaceId].canonicalName
	end
end

local _processAttribute = function (self, attr, indent, name)
	_debug(self, 1, 'entering private _processAttribute() to print a line for attribute ' .. attr .. ', from ' .. tostring(self))
	local coreData = self:getCoreData()
	local attr = attr
	local val = coreData[attr]
	if type(val) == 'boolean' then
		val = val and 'true' or 'false'
	end
	local ret = ''
	local fieldname = mw.ustring.match(attr, '^[^_]+_(.+)$')
	ret = indent .. (name and name or fieldname) .. ' = '
	if not val then
		ret = ret .. 'nil'
	elseif type(val) == 'table' then
		ret = ret .. Classgenerator.myTableTools.printTable(val, 'inline')
	elseif val == 'true' or val == 'false' or mw.ustring.match(val, '^[0-9]+$') or (attr == 'global_gardeningCategory' and val == 'superglobal.gardeningSuperCategory') then
		ret = ret .. val
	else
		ret = ret .. "'" .. mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(val, "\\'", "'"), "'", "\\'"), '\n', '\\n\' ..\n' .. indent .. '\t\'') .. "'"	-- the gsub catches multiline input from textareas
	end
	ret = ret .. ','
	if self.class.myConfiguration.template.addCommentsToConfig then
		ret = ret .. '\t-- ' .. self.class.myConfiguration.parameter[attr].description
	end
	ret = ret .. '\n'
	return ret
end

local _privateMethod = function (self)
	_debug(self, 1, 'entering private _privateMethod() to do something, from ' .. tostring(self))
end

-- **************** declaration of public methods
-- use self.class.myConfiguration to access your configuration in a public method
function Classgenerator:addInfobox()
	_debug(self, 1, 'entering Classgenerator:addInfobox(), from ' .. tostring(self))
	if self:goodToGo() then
		local _CFG = self.class.myConfiguration
		local coreData = self:getCoreData()
		local usesSmw = FoundationClass.globalConfig.dataStore and (FoundationClass.globalConfig.dataStore == 'both' or FoundationClass.globalConfig.dataStore == 'smw') and FoundationClass.myYesno(coreData.global_smwUseStorage)
		local ib_args = {
			bodyclass = 'infobox_name',
			aboveclass = 'objtitle titletext',
			headerclass = 'headertext',
			labelstyle = 'width: 30%;',
			datastyle = 'width: 70%;',
			title = coreData.className,
			above = 'Class',
			label1 = 'Title',
			data1 = coreData.global_entityTitle and coreData.global_entityTitle or '',
			label2 = _CFG.parameter.global_edit_timestamp.label,
			data2 = coreData.last_edited,
			label3 = 'Store available',
			data3 = (FoundationClass.globalConfig.dataStore and mw.ustring.len(FoundationClass.globalConfig.dataStore) > 0) and FoundationClass.globalConfig.dataStore or '',
			label5 = 'Cargo table',
			data5 = (FoundationClass.globalConfig.dataStore and (FoundationClass.globalConfig.dataStore == 'both' or FoundationClass.globalConfig.dataStore == 'cargo')) and coreData.global_cargoTable or '',
			label6 = 'Smw class',
			data6 = usesSmw and _private[self].pagename or '',
			label7 = 'Namespace',
			data7 = coreData.global_namespace and coreData.global_namespace or 'MAIN',
			data9 = coreData.global_description,
			header10 = 'Pages',
			label12 = 'Module',
			data12 = _private[self].pagename and '[[Module:' .. _private[self].pagename .. ']]' or '',
			label13 = 'Class',
			data13 = _private[self].pagename and '[[Module:' .. _private[self].pagename .. '/class]]' or '',
			label14 = 'Config',
			data14 = _private[self].pagename and '[[Module:' .. _private[self].pagename .. '/config]]' or '',
			label17 = 'Template',
			data17 = coreData.template_name and '[[Template:' .. coreData.template_name .. ']]' or '',
			label19 = 'Form',
			data19 = coreData.page.form and '[[:' .. coreData.page.form.name .. ']]' or '',
			label21 = 'Category',
			data21 = coreData.page.category and '[[:' .. coreData.page.category.name .. ']]' or '',
			label22 = 'Gardening',
			data22 = coreData.page.gardeningCategory and '[[:' .. coreData.page.gardeningCategory.name .. ']]' or '',
		}
		local i = 31
		if _private[self].identity and #_private[self].identity > 0 then
			ib_args.header30 = 'Identity'
			for _, param in ipairs(_private[self].identity) do
				ib_args['label' .. i] = param.param
				ib_args['data' .. i] = param.label
				i = i + 1
			end
			i = i + 5	
		end
		
		if usesSmw and coreData.properties.order and #coreData.properties.order > 0 then
			ib_args['header' .. (i-1)] = 'Properties'
			for _, property in pairs(coreData.properties.order) do
				ib_args['label' .. i] = coreData.properties.data[property].type
				ib_args['data' .. i] = '[[Property:' .. property .. '|' .. property .. ']]'
				i = i + 1
			end
		end
		self:addOutput(require('Module:Infobox').infobox(ib_args))
		return true
	end
	return false
end

function Classgenerator:addPageBody()
	_debug(self, 1, 'entering Classgenerator:addPageBody(), from ' .. tostring(self))
	_debug(self, 2, ' rendering errors and warnings and adding them to output')
	self:addOutput(self:renderErrors())
	self:addOutput(self:renderWarnings())
	if self:goodToGo() then
		local frame = mw.getCurrentFrame()
		local lang = mw.language.new('en-gb')
		local _CFG = self.class.myConfiguration
		local coreData = self:getCoreData()
		local imageExtension = require( 'Module:Util' ).globalFileExtension()
		-- start
		local widthTh = '300px'
		local widthTd = '200px'
		-- build the page status table
		-- first the two status table cells "green" and "red"
		local imgYes = '[[File:Yes check' .. imageExtension .. '|13px|alt=Yes|link=]]'
		local imgNo = '[[File:X mark' .. imageExtension .. '|13px|alt=No|link=]]'
		local tdYa = mw.html.create('td')
		tdYa:cssText('background: #90ff90; color:black; vertical-align: middle; text-align: center; width:' .. widthTd)
			:addClass('table-yes')
			:wikitext(imgYes)
		local tdNa = mw.html.create('td')
		tdNa:cssText('background: #FF9090; color:black; vertical-align: middle; text-align: center; width:' .. widthTd)
			:addClass('table-no')
			:wikitext(imgNo)
		local classExists = coreData.page.class.exists and coreData.page.config.exists
		local modulesExist = coreData.page.base.exists and classExists
		local thisClass
		local thisConfig
		if classExists then
			thisClass = require(coreData.page.class.name)
			thisConfig = require(coreData.page.config.name)
		end
		local thisUsesCargo = (FoundationClass.globalConfig.dataStore == 'both' or FoundationClass.globalConfig.dataStore == 'cargo') and coreData.global_cargoTable and #coreData.global_cargoTable > 0
		local thisUsesSmw = (FoundationClass.globalConfig.dataStore == 'both' or FoundationClass.globalConfig.dataStore == 'smw') and FoundationClass.myYesno(coreData.global_smwUseStorage)
		-- write the 2do checklist
		local done = true
		local step1
		local step2
		local step3
		if modulesExist then
			step1 = imgYes .. ' You created all your modules'
		else
			done = false
			local step1insert
			if _CFG.template.enableModuleCreation then
				step1insert = 'This can be easily done by the click of a button [[#Page_autocreation|below]]. However, if you are a control freak, do this'
			else
				step1insert = 'This, you have to do'
			end
			step1 = imgNo .. ' You have to create your module pages, first. ' .. step1insert ..
				' <b>manually</b>. Go to [[#Page contents|section Page contents]], copy the module content and edit the corresponding module, ' ..
				'pasting all the copied content. Save and close. You have to do this for the following module(s): <ul> ' ..
				(not coreData.page.base.exists and '<li>[[#Page contents|' .. coreData.page.base.name .. ']]</li>' or '') ..
				(not coreData.page.class.exists and '<li>[[#Page contents|' .. coreData.page.class.name .. ']]</li>' or '') ..
				(not coreData.page.config.exists and '<li>[[#Page contents|' .. coreData.page.config.name .. ']]</li>' or '') .. '</ul>'
		end
		if coreData.page.baseDoc.exists and coreData.page.classDoc.exists and coreData.page.configDoc.exists and coreData.page.template.exists and coreData.page.templateDoc.exists and
				(not coreData.page.form or coreData.page.form.exists) and (not coreData.page.category or coreData.page.category.exists) and (not coreData.page.gardeningCategory or coreData.page.gardeningCategory.exists) then
			step2 = imgYes .. ' You created all auxilliary pages'
		else
			done = false
			step2 = imgNo .. ' You have to create auxilliary pages. This, you can do <b>automatically</b>. Go to [[#Page autocreation|section Page autocreation]], hit the corresponding "Create"-button or ' ..
				'create all pages at once. Please do this for the following page(s): <ul> ' ..
				(not (coreData.page.baseDoc.exists or coreData.page.classDoc.exists or coreData.page.configDoc.exists) and '<li>Module documentation pages</li>' or '') ..
				(not (coreData.page.template.exists or coreData.page.templateDoc.exists) and '<li>Template and/or template documentation page</li>' or '') ..
				((coreData.page.form and not coreData.page.form.exists) and '<li>Form page</li>' or '') ..
				(((coreData.page.category and not coreData.page.category.exists) or (coreData.page.gardeningCategory and not coreData.page.gardeningCategory.exists)) and '<li>Category page(s)</li>' or '') .. '</ul>'
		end
		local storeCargoInstruction
		local allPropertiesThere = true
		local cargoTableCreateLink = false
		if thisUsesCargo then
			-- we actually use cargo. check, if cargo table is there or throws an error? if all right, then yes, else instruction above
			if modulesExist and coreData.page.template.exists then
				cargoTableCreateLink = true
				attr = { limit = 1, default = '' }
				attr['more results text'] = ''
				local tableEntryId = mw.text.trim(mw.text.unstrip(FoundationClass.myCargoUtil.rawquery({tables = coreData.global_cargoTable, fields = {'_ID'}}, attr)))
				if mw.ustring.match(mw.text.trim(tableEntryId), '^[0-9]*$') then
					storeCargoInstruction = imgYes .. ' Your cargo table does exist! (Note: When you change your cargo table\'s declaration, you need to [[#Page autocreation|rebuild it]], though)'
				else
					done = false
					storeCargoInstruction = imgNo .. ' Please [[#Page autocreation|create your cargo table]]!'
				end
			else
				done = false
				storeCargoInstruction = imgNo .. ' To be able to create your cargo table, you have to create the following page(s): <ul>' ..
					(not coreData.page.base.exists and '<li>' .. coreData.page.base.name .. '</li>' or '') ..
					(not coreData.page.class.exists and '<li>' .. coreData.page.class.name .. '</li>' or '') ..
					(not coreData.page.config.exists and '<li>' .. coreData.page.config.name .. '</li>' or '') ..
					(not coreData.page.template.exists and '<li>' .. coreData.page.template.name .. '</li>' or '') .. '</ul>'
			end
		end
		if thisUsesSmw then
			-- we actually use smw. check, if all properties are present? if all right, then yes, else instruction above
			if coreData.properties and coreData.properties.data and FoundationClass.myTableTools.size(coreData.properties.data) > 0 then
				for property, propertyData in pairs(coreData.properties.data) do
					allPropertiesThere = allPropertiesThere and propertyData.exists
				end
				if allPropertiesThere then
					storeSwmInstruction = imgYes .. ' All your property pages are present and accounted for!'
				else
					done = false
					storeSwmInstruction = imgNo .. ' Please <b>[[#Page autocreation|autocreate]]</b> your properties! The following are missing: <ul>'
					for _, property in pairs(coreData.properties.order) do
						local pdata = coreData.properties.data[property]
						if not pdata or not pdata.exists then
							storeSwmInstruction = storeSwmInstruction .. '<li>[[Property:' .. property .. ']]</li>'
						end
					end
					storeSwmInstruction = storeSwmInstruction .. '</ul>'
				end
			else
				done = false
				storeSwmInstruction = imgNo .. ' To be able to create your smw properties, you have to create the following page(s): <ul>' ..
					(not coreData.page.class.exists and '<li>' .. coreData.page.class.name .. '</li>' or '') ..
					(not coreData.page.config.exists and '<li>' .. coreData.page.config.name .. '</li>' or '') .. '</ul>'
			end
		end
		if storeCargoInstruction or storeSwmInstruction then
			if storeCargoInstruction and storeSwmInstruction then
				step3 = 'Your class used cargo AND smw store. You have to create both data stores: <ul><li>' .. storeCargoInstruction .. '</li><li>' .. storeSwmInstruction .. '</li></ul>'
			else
				step3 = storeCargoInstruction or storeSwmInstruction
			end
		else
			step3 = imgYes .. ' This class does not use a data store. Nothing to be done here!'
		end
		local step4 = done and imgYes .. ' You are done. Remember, when you want to change parameters in your config, edit this page and write your [' .. coreData.page.config.editlink .. ' config file] new' or 
			imgNo .. ' You are not finished yet, please tend to your tasks.'
		local manual = mw.html.create('')
		if not done then
			manual:wikitext('<h2>Your 2do checklist</h2>')
				:tag('ol')
					:cssText('margin: 0.3em 0 0 1.6em; padding: 0')
					:tag('li')
						:wikitext(step1)
						:done()
					:tag('li')
						:wikitext(step2)
						:done()
					:tag('li')
						:wikitext(step3)
						:done()
					:tag('li')
						:wikitext(step4)
						:done()
					:done()
				:done()
				:newline()
		end
		-- here, add the identity
		local identity = mw.html.create('')
		if thisConfig then
			identity:wikitext('<h2>Class identity</h2>')
			local trs = mw.html.create('')
			for _, paramData in ipairs( _private[self].identity ) do
				local param = paramData.param
				trs:tag('tr')
					:tag('td')
						:wikitext('<strong>' .. param .. '</strong>')
						:newline()
						:done()
					:tag('td')
						:wikitext(thisConfig.parameter[param].label)
						:newline()
						:done()
					:tag('td')
						:wikitext(thisConfig.parameter[param].severity)
						:css('text-align', 'center')
						:css('color', (thisConfig.parameter[param].severity == 'mandatory' and 'red' or 'inherit'))
						:newline()
						:done()
					:tag('td')
						:wikitext(thisConfig.parameter[param].cardinality)
						:css('text-align', 'center')
						:newline()
						:done()
					:tag('td')
						:wikitext(thisConfig.parameter[param].description)
						:newline()
						:done()
				:newline()
				:done()
			end
			identity:tag('table')
				:addClass('wikitable')
				:addClass('sortable')
				:newline()
				:tag('tr')
					:tag('th')
						:wikitext('Parameter')
						:newline()
					:done()
					:tag('th')
						:wikitext('Label')
						:newline()
					:done()
					:tag('th')
						:wikitext('Severity')
						:newline()
					:done()
					:tag('th')
						:wikitext('Cardinality')
						:newline()
					:done()
					:tag('th')
						:wikitext('Description')
						:newline()
					:done()
				:done()
				:node(trs)
			:allDone()
		end
		
		-- get the data store details, if all the modules exist and we have a datastore configured
		local datastore = mw.html.create('')
		if thisClass then
			datastore:node(thisClass:explainDataStore())
				:newline()
		end
		-- build the status table
		local statusTrs = mw.html.create('')
		for _, pid in pairs(coreData.page.order) do
			statusTrs:tag('tr')
				:tag('th')
					:css('text-align', 'left')
					:css('width', widthTh)
					:wikitext(coreData.page[pid].name)
					:done()
					:newline()
				:node(coreData.page[pid].exists and tdYa or tdNa)
				:newline()
				:done()
				:newline()
		end
		if thisUsesSmw and coreData.properties and coreData.properties.data and FoundationClass.myTableTools.size(coreData.properties.data) > 0 then
			statusTrs:tag('tr')
				:tag('th')
					:css('text-align', 'center')
					:css('width', widthTh)
					:attr('colspan', 2)
					:wikitext('Property pages for your smw store')
					:done()
					:newline()
			for _, property in pairs(coreData.properties.order) do
				statusTrs:tag('tr')
					:tag('th')
						:css('text-align', 'left')
						:css('width', widthTh)
						:wikitext('Property:' .. property)
						:done()
						:newline()
					:node(coreData.properties.data[property].exists and tdYa or tdNa)
					:newline()
					:done()
					:newline()
			end
		end
		local statusTable = mw.html.create('table')
		statusTable:node(statusTrs)
		-- page autocreation
		local extAutoCreatePage = pcall(frame.callParserFunction, frame, {name = '#createpageifnotex:Module:Classgenerator', args = {'NUL'}})
		local autoCreation = _CFG.template.createPages and extAutoCreatePage
		local pageAutoCreation = mw.html.create('')
		pageAutoCreation:wikitext('<h2>Page autocreation</h2>')
			:newline()
		if autoCreation then
			-- depending on parameters and existence of pages do the autocreate or print the button
			-- first see, which pagecomplexes (modules(docs), templates, form, category) are missing
			local missing = {}
			-- in missing we store, if a page in a given namespace is missing. Namespaces are stored by their ids (numbers)
			for _, pid in pairs(coreData.page.order) do
				-- once, extension autocreatepage messed up module pages.
				-- if module creation is still disabled, we only autocreate doc pages namepace module
				if not coreData.page[pid].exists and not Classgenerator.myTableTools.inTable(missing, coreData.page[pid].namespace) and 
						(coreData.page[pid].namespace ~= 828 or coreData.page[pid].isDocPage or _CFG.template.enableModuleCreation) then
					table.insert(missing, coreData.page[pid].namespace)
				end
			end
			if thisUsesSmw and not allPropertiesThere then
				table.insert(missing, mw.title.new('NUL', 'Property').namespace)
			end
			-- now generate the printout or call the parser function depending on global_autocreate_* status
			-- remember the switches 'global_autocreate_module', 'global_autocreate_template', 'global_autocreate_form', 'global_autocreate_category', and 'global_autocreate_property'
			local actable = mw.html.create('table')
			for _, nsid  in pairs(missing) do
				local ns = mw.ustring.lower(_namespaceName(self, nsid))
				local information = ''
				if coreData.autocreate[ns] and coreData.autocreate[ns] > os.time() - _CFG.template.autoCreationTimeDiff then
					-- ************************************* actual autocreation is done here
					-- We iterate over all namespaces for which pages are missing (var missing) and spring into action,
					-- if we have a numeric value supplied for that namespace coreData.autocreate[ns] that is recent enough.
					-- Now we have a namespace, we want to create pages for (var nsid) (all that is done in the recent lines).
					-- what we do in the following lines:
					-- We iterate over all pages in coreData.page.order and spring into action, if the iteration instance (pid)
					-- is in the namespace (nsid), the page is non exist and is not a module or module creation is enabled
					-- in that action body, we create the page with the pre-calculated content
					-- Also: for convenience, we create some global project (meta)categories, if related to the current page
					-- (project-form-category if nsid for forms, etc.) and configured in Foundationclass/globalconfig. here is an overview
					--	Classgenerator.globalConfig.formCategory			: MediaWiki:Classengine-content-project-form-category
					--	Classgenerator.globalConfig.gardeningSuperCategory	: MediaWiki:Classengine-content-project-gardening-supercategory
					--	Classgenerator.globalConfig.moduleCategory			: MediaWiki:Classengine-content-project-module-category
					--	Classgenerator.globalConfig.projectSuperCategory	: MediaWiki:Classengine-content-project-supercategory
					--	Classgenerator.globalConfig.propertyCategory		: MediaWiki:Classengine-content-project-property-category
					--	Classgenerator.globalConfig.templateCategory		: MediaWiki:Classengine-content-project-templates
					for _, pid in pairs(coreData.page.order) do
						_debug(self, 3, ' testing page "' .. coreData.page[pid].name .. '": namespace id is ' .. coreData.page[pid].namespace ..
							', and page does ' .. (not coreData.page[pid].exists and 'not ' or '') .. 'exist')
						if coreData.page[pid].namespace == nsid and not coreData.page[pid].exists and
							(nsid ~= 828 or coreData.page[pid].isDocPage or _CFG.template.enableModuleCreation) then
							if pid == 'gardeningCategory' and Classgenerator.globalConfig.gardeningSuperCategory
								and #Classgenerator.globalConfig.gardeningSuperCategory > 0 then
								-- we just iterated over the gardening category page (so this class has one) but we did not create it, yet)
								-- blindly, try to create the gardening supercategory first, in case the class's gardening category is the
								-- gardening supercategory, we dont want the class specific content
								local content = '{{MediaWiki:Classengine-content-project-gardening-supercategory}}'
								_debug(self, 3, ' trying to autocreate garderning supercategory page "' .. Classgenerator.globalConfig.gardeningSuperCategory .. '" with # of content being ' .. #content)
								local ret = frame:callParserFunction{ name = '#createpageifnotex:Category:' .. Classgenerator.globalConfig.gardeningSuperCategory, args = { content } }
								if #ret > 0 then
									information = information .. '<br>' .. ret .. '\n'
								end
							end
							-- here we actually create the missing page. THIS IS CORE FEATURE :)
							_debug(self, 3, ' trying to autocreate page "' .. coreData.page[pid].name .. '" with # of content being ' .. #coreData.page[pid].content)
							local ret = frame:callParserFunction{ name = '#createpageifnotex:' .. coreData.page[pid].name, args = { frame:preprocess(coreData.page[pid].content) } }
							if #ret > 0 then
								information = information .. '<br>' .. ret .. '\n'
							end
							if pid == 'form' and Classgenerator.globalConfig.formCategory and #Classgenerator.globalConfig.formCategory > 0 then
								-- we just iterated over the form page (so this class has one) and created it (yay). Now blindly create the formCategory as well...
								local content = '{{MediaWiki:Classengine-content-project-form-category}}'
								_debug(self, 3, ' trying to autocreate form category page "' .. Classgenerator.globalConfig.formCategory .. '" with # of content being ' .. #content)
								local ret = frame:callParserFunction{ name = '#createpageifnotex:Category:' .. Classgenerator.globalConfig.formCategory, args = { content } }
								if #ret > 0 then
									information = information .. '<br>' .. ret .. '\n'
								end
							elseif nsid == 828 and Classgenerator.globalConfig.moduleCategory and #Classgenerator.globalConfig.moduleCategory > 0 then
								-- we just iterated over a module (doc) page (so this class has one) and created it (yay). Now blindly create the moduleCategory as well...
								local content = '{{MediaWiki:Classengine-content-project-module-category}}'
								_debug(self, 3, ' trying to autocreate module category page "' .. Classgenerator.globalConfig.moduleCategory .. '" with # of content being ' .. #content)
								local ret = frame:callParserFunction{ name = '#createpageifnotex:Category:' .. Classgenerator.globalConfig.moduleCategory, args = { content } }
								if #ret > 0 then
									information = information .. '<br>' .. ret .. '\n'
								end
							elseif pid == 'category' and Classgenerator.globalConfig.projectSuperCategory and #Classgenerator.globalConfig.projectSuperCategory > 0 then
								-- we just iterated over the category page (so this class has one) and created it (yay). Now blindly create the supercategory as well...
								local content = '{{MediaWiki:Classengine-content-project-supercategory}}'
								_debug(self, 3, ' trying to autocreate super category page "' .. Classgenerator.globalConfig.projectSuperCategory .. '" with # of content being ' .. #content)
								local ret = frame:callParserFunction{ name = '#createpageifnotex:Category:' .. Classgenerator.globalConfig.projectSuperCategory, args = { content } }
								if #ret > 0 then
									information = information .. '<br>' .. ret .. '\n'
								end
							elseif nsid == 10 and Classgenerator.globalConfig.templateCategory and #Classgenerator.globalConfig.templateCategory > 0 then
								-- we just iterated over a page in template namespace (so this class has one) and created it (yay). Now blindly create the templateCategory as well...
								local content = '{{MediaWiki:Classengine-content-project-template-category}}'
								_debug(self, 3, ' trying to autocreate template category page "' .. Classgenerator.globalConfig.templateCategory .. '" with # of content being ' .. #content)
								local ret = frame:callParserFunction{ name = '#createpageifnotex:Category:' .. Classgenerator.globalConfig.templateCategory, args = { content } }
								if #ret > 0 then
									information = information .. '<br>' .. ret .. '\n'
								end
							end
						end
					end
					if thisUsesSmw and (nsid == mw.title.new('NUL', 'Property').namespace) and coreData.properties.data then
						-- add here autocreation of properties
						for property, pdata in pairs(coreData.properties.data) do
							if not pdata.exists then
								local content = pdata.content
								_debug(self, 3, ' trying to autocreate property page "' .. property .. '" with # of content being ' .. #content)
								local ret = frame:callParserFunction{ name = '#createpageifnotex:Property:' .. property, args = { frame:preprocess(pdata.content) } }
								if #ret > 0 then
									information = information .. '<br>' .. ret .. '\n'
								end
							end
						end
						-- we just iterated over all missing property pages (so this class has some) and created them (yay). Now blindly create the propertyCategory as well...
						local content = '{{MediaWiki:Classengine-content-project-property-category}}'
						_debug(self, 3, ' trying to autocreate property category page "' .. Classgenerator.globalConfig.propertyCategory .. '" with # of content being ' .. #content)
						local ret = frame:callParserFunction{ name = '#createpageifnotex:Category:' .. Classgenerator.globalConfig.propertyCategory, args = { content } }
						if #ret > 0 then
							information = information .. '<br>' .. ret .. '\n'
						end
					end
				end
				-- create the tr for the ns
				local module_text = _CFG.template.enableModuleCreation and 'module pages and docs' or 'only module docs'
				actable:tag('tr')
					:tag('th')
						:css('text-align', 'left')
						:css('width', widthTh)
						:wikitext('Create ' .. ((nsid == 828 and module_text or (ns == 'property' and 'properties' or (ns .. (ns == 'template' and 's' or '')))) .. ':'))
							-- note: nsid == mw.title.new('NUL', 'Property').namespace is necessary since canonicalname for property namespace does not translate uniquely over different languages :(
						:done()
						:newline()
					:tag('td')
						:cssText('color:black; vertical-align: middle; text-align: center; width:' .. widthTd)
						:css('background', (coreData.autocreate[ns] and coreData.autocreate[ns] > os.time() - _CFG.template.autoCreationTimeDiff) and '#90ff90' or '#FF9090' )
						:wikitext(frame:callParserFunction{name = '#autoedit', args={form='Classgenerator', target=self:getUid(),
							'link text=' .. (coreData.autocreate[ns] and 'Requested on ' .. os.date('%d.%m.%Y %X', coreData.autocreate[ns]) or 'Create automatically!')  .. 
								(#information > 0 and ('Call returned ' .. information) or ''),
							'reload', summary="Requesting the autocreation of " .. coreData.className .. ' for pages of type ' .. ns,
							'query string=Classgenerator[global_autocreate_' .. ns .. ']=' .. os.time()}
							})
						:done()
						:newline()
					:done()
					:newline()
			end
			if Classgenerator.myTableTools.size(missing) > 0 then
				-- show the "all"-button
				local querystring = ''
				for _, nsid in pairs(missing) do
					local ns = mw.ustring.lower(_namespaceName(self, nsid))
					querystring = 'Classgenerator[global_autocreate_' .. ns .. ']=' .. os.time() .. '&'
				end
				querystring = mw.ustring.sub(querystring, 1, -2)
				actable:tag('tr')
					:tag('th')
						:css('text-align', 'left')
						:css('width', widthTh)
						:wikitext('Create all pages:')
						:done()
						:newline()
					:tag('td')
						:cssText('background: #FF9090; color:black; vertical-align: middle; text-align: center; width:' .. widthTd)
						:wikitext(frame:callParserFunction{name = '#autoedit', args={form='Classgenerator', target=self:getUid(),
							'link text=Create automatically!', 'reload', summary="Requesting the autocreation of all missing pages", 'query string=' .. querystring }
							})
						:done()
						:newline()
					:done()
					:newline()
				pageAutoCreation:wikitext('Use the following buttons ao create the corresponding pages automatically:')
					:newline()
					:node(actable)
					:newline()
			else
				pageAutoCreation:wikitext('All pages present!')
					:newline()
					:tag('p')
						:wikitext('<small><b>Note:</b> Creation of module pages is impossible due to an incompatibility issue.</small>')
						:newline()
						:done()
					:newline()
			end
		else
			pageAutoCreation:wikitext('Page autocreation is only possible if activated in your [[Module:Classgenerator/config]]-file (see template-section) and '
					.. 'Extension AutoCreatePage being installed.')
				:newline()
		end
		if cargoTableCreateLink then
			pageAutoCreation:wikitext('<b>Cargo data store:</b>To (re-)create your cargo table, follow <span class="plainlinks">[' .. coreData.page.template.recreatedata .. ' this link]</span> and then press ok!')
				:newline()
		end
		
		-- build the content collapses
		local collapse = require('Module:Collapse').main
		local bg_sets = { exist = {'#cfc', '#9c9'}, nonexist = {'#fcc', '#c99'} }
		local bg = 1
		local pageContent = mw.html.create('')
		for _, pid in pairs(coreData.page.order) do
			local content
			local bgs = coreData.page[pid].exists and bg_sets.exist or bg_sets.nonexist
			if coreData.page[pid].namespace == 828 and not coreData.page[pid].isDocPage then
				content = frame:expandTemplate{ title = 'Code', args = {lang = 'lua', code = coreData.page[pid].content, line = '1'}}
			else
				content = '<pre style="white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; white-space:pre-wrap; word-wrap:break-word;">' .. 
					mw.text.nowiki(frame:preprocess(coreData.page[pid].content)) .. '</pre>'
			end
			pageContent:wikitext(collapse({ header = 'Contents of <b>[[:' .. coreData.page[pid].name .. ']]</b> ' ..
							'<span class="plainlinks" style="font-size:75%;">&#91;[' .. coreData.page[pid].editlink ..
							' EDIT]&#93;</span>',
						content = content, left = true, bg = bgs[bg]
					}))
				:newline()
			bg = (bg == 2 and 1 or 2)
		end
		if thisUsesSmw and coreData.properties.order then
			-- add here the collpases of the properties
			pageContent:tag('p')
				:wikitext('<h3>All property pages</h3>')
				:done()
			for _, property in pairs(coreData.properties.order) do
				local bgs = coreData.properties.data[property].exists and bg_sets.exist or bg_sets.nonexist
				local content = '<pre style="white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; white-space:pre-wrap; word-wrap:break-word;">' .. 
					mw.text.nowiki(frame:preprocess(coreData.properties.data[property].content)) .. '</pre>'
				pageContent:wikitext(collapse({ header = 'Contents of <b>[[:Property:' .. property .. ']]</b> ' ..
								'<span class="plainlinks" style="font-size:75%;">&#91;[' .. coreData.properties.data[property].editlink ..
								' EDIT]&#93;</span>',
							content = content, left = true, bg = bgs[bg]
						}))
					:newline()
				bg = (bg == 2 and 1 or 2)
			end
		end
		local updateWarning = mw.html.create('')
		if coreData.now_timestamp - coreData.edit_timestamp < 2*60*60 then
			local mbox = require('Module:Message box')
			updateWarning:wikitext(mbox.main('ombox', { type='content', text = 'Note: You updated the class ' .. coreData.edit_time_before .. ' ago. Did you write your [[#Page contents|config file]] new? ' ..
						'Changes won\'t take effect unless you do!' .. ((thisUsesCargo and cargoTableCreateLink) and '<p><span class="plainlinks">Also: If you changed your cargo table\'s declaration, [' .. 
						coreData.page.template.editlink .. ' edit your template] and [[#Page autocreation|rebuild your cargo table]]!</span>' or '')}))
				:newline()
		end
		local smwPropertyHint = mw.html.create('')
		if (FoundationClass.globalConfig.dataStore == 'both' or FoundationClass.globalConfig.dataStore == 'smw')
				and FoundationClass.myYesno(coreData.global_smwUseStorage)
				and not coreData.properties.order then
			local mbox = require('Module:Message box')
			smwPropertyHint:wikitext(mbox.main('ombox', { type='notice', text = 'Hint: If you use properties in your class, they will not display in <i>Page contents</i>, nor be listed in <i>Page status</i> or '
					.. 'autocreated in <i>Page autocreation</i> unless you have your class and config page created!'}))
				:newline()
		end
		-- assemble everything
		local html = mw.html.create('')
		html:wikitext(coreData.global_description)
			:newline()
			:node(updateWarning)
			:node(smwPropertyHint)
			:node(manual)
			:node(identity)
			:newline()
			:node(datastore)
			:wikitext('<h2>Page status</h2>')
			:newline()
			:wikitext(autoCreation and 'This status may be inaccurate, if you just created pages. In that case, run jobs and clear cache of this page.' or '')
			:node(statusTable)
			:newline()
			:node(pageAutoCreation)
			:wikitext('<h2>Page contents</h2>')
			:newline()
			:node(pageContent)
			:newline()
			:done()
		local debugLevel = FoundationClass.globalConfig.debugLevel or _CFG.global.debugLevel
		if debugLevel then
			html:tag('pre')
--				:wikitext(FoundationClass.myTableTools.printTable(coreData))
--				:wikitext(FoundationClass.myTableTools.printTable(thisClass:smwProperty2ParameterTranslationTable()))
				:wikitext(ClassDebug:printLog(debugLevel))
				:done()
		end
		self:addOutput(html)

		return true
	end
	return false
end

function Classgenerator:myArgumentProcessing(coreData)
	_debug(self, 1, 'entering Classgenerator:myArgumentProcessing(args) to process coreData, from ' .. tostring(self))
	-- function that performs some individual transformation args --&amp;gt; coreData
	local _CFG = self.class.myConfiguration
	local coreData = coreData
	local lang = mw.language.new('en')
	coreData.className = lang:ucfirst(mw.text.trim(mw.ustring.gsub(self:getUid(), ':', '')))
	coreData.edit_timestamp = lang:formatDate('U', coreData.global_edit_timestamp)
	coreData.now_timestamp = lang:formatDate('U') + 60*60
	coreData.edit_time_before = lang:formatDuration(coreData.now_timestamp-coreData.edit_timestamp)
	coreData.last_edited = lang:formatDate('d.m.Y H:i:s', coreData.global_edit_timestamp)
	if coreData.global_gardeningCategory_chooser and mw.ustring.lower(coreData.global_gardeningCategory_chooser) == 'global' then
		coreData.global_gardeningCategory = 'superglobal.gardeningSuperCategory'
	end
	if mw.ustring.find(coreData.className, '[ /]', 1) then
		local tmp = ''
		for fragment in mw.text.gsplit(coreData.className, '[ /]') do
			tmp = tmp .. lang:ucfirst(fragment)
		end
		coreData.className = tmp
	end
	if coreData.global_cargoTable then
		coreData.global_cargoTable = mw.ustring.gsub(mw.ustring.lower(coreData.global_cargoTable), ' ', '_')
	end
	if coreData.form_createInfotext and #coreData.form_createInfotext > 0 and mw.ustring.sub(coreData.form_createInfotext, -1) ~= ' ' then
		coreData.form_createInfotext = coreData.form_createInfotext .. ' '
	end
	coreData.template_name = coreData.template_name:gsub("^%l", string.upper)
	local parameter_parameter
	local fieldOrder
	if coreData.parameter_parameter then
		parameters = ''
		fieldOrder = {}
		local classGenParamConfig = mw.loadData('Module:Classgenerator/parameter/config')
		for result in mw.text.gsplit(coreData.parameter_parameter, classGenParamConfig.template.delimiterResult, true) do
			local fieldname, parameter = mw.ustring.match(result, '^([^#]*)' .. classGenParamConfig.template.delimiterFormFieldName .. '(.+)$')
			if fieldname and mw.ustring.len(mw.text.trim(fieldname)) > 0 then
				table.insert(fieldOrder, mw.text.trim(fieldname))
			end
			if parameter and mw.ustring.len(parameter) > 0 then
				parameters = parameters .. parameter
			end
		end
	end
	coreData.parameter_parameter = parameters
	coreData.form_enable = FoundationClass.myYesno(coreData.form_enable)
	if coreData.form_enable then
		coreData.form_fieldOrder = fieldOrder
		form_buttons = { 'save' }
		if coreData.form_buttons and #coreData.form_buttons > 0 then
			for _, button in pairs(coreData.form_buttons) do
				table.insert(form_buttons, button)
			end
		end
		table.insert(form_buttons, 'cancel')
	end
	coreData.form_buttons = form_buttons
	-- here build the class config
	local contentClassConfig = mw.ustring.gsub(_CFG.template.configIntro, _CFG.template.placeHolderClassName, coreData.className) ..
		'local global = {\n' ..
		'\tdebugLevel = false,'
	if self.class.myConfiguration.template.addCommentsToConfig then
		contentClassConfig = contentClassConfig .. '\t-- set this to the level you wish to display at render. false if disabled. this is a class based setting. ' ..
			'you can set this globally at Foundationclass/globalconfig, causing all child classes to debug.'
	end
	contentClassConfig = contentClassConfig .. '\n'
	-- calculate the fieldlists:
	local fieldlists = {}
	for _, field in pairs(_CFG.form.fieldOrder) do
		local tab = mw.ustring.match(field, '^([a-z]+)_.+')
		if not fieldlists[tab] then
			fieldlists[tab] = {}
		end
		table.insert(fieldlists[tab], field)
	end
	local omissionList = {'global_autocreate_module', 'global_autocreate_template', 'global_autocreate_form', 'global_autocreate_category', 'global_autocreate_property', 'global_edit_timestamp', 'global_gardeningCategory_chooser',
		'form_textareaAttributes_cols', 'form_textareaAttributes_rows', 'form_textareaAttributes_autogrow', 'form_textareaAttributes_editor', 'form_createLinkInfo', 
		'global_customization', 'form_customization', 'template_customization' }
	for _, attr in pairs(fieldlists.global) do
		if not Classgenerator.myTableTools.inTable(omissionList, attr) and self.class.myConfiguration.parameter[attr] then
			contentClassConfig = contentClassConfig .. _processAttribute(self, attr, '\t')
		end
	end
	if coreData.global_customization then
		for line in mw.text.gsplit(coreData.global_customization, '\n', true) do
			contentClassConfig = contentClassConfig .. '\t' .. line .. '\n'
		end
	end
	contentClassConfig = contentClassConfig .. '}\n\nlocal form = {\n'
	for _, attr in pairs(fieldlists.form) do
		if not Classgenerator.myTableTools.inTable(omissionList, attr) and self.class.myConfiguration.parameter[attr] then
			contentClassConfig = contentClassConfig .. _processAttribute(self, attr, '\t')
		end
	end
	contentClassConfig = contentClassConfig .. '\ttextareaAttributes = {	-- the defaults for your textarea fields\n'
	for _, attr in pairs({'form_textareaAttributes_cols', 'form_textareaAttributes_rows', 'form_textareaAttributes_autogrow', 'form_textareaAttributes_editor'}) do
		local name = mw.ustring.match(attr, '^form_textareaAttributes_(.+)$')
		contentClassConfig = contentClassConfig .. _processAttribute(self, attr, '\t\t', name)
	end
	contentClassConfig = contentClassConfig .. '\t},\n'
	contentClassConfig = contentClassConfig .. _processAttribute(self, 'form_fieldOrder', '\t')
	if coreData.form_customization then
		for line in mw.text.gsplit(coreData.form_customization, '\n', true) do
			contentClassConfig = contentClassConfig .. '\t' .. line .. '\n'
		end
	end
	contentClassConfig = contentClassConfig .. '}\n\nlocal template = {\n'
	for _, attr in pairs(fieldlists.template) do
		if not Classgenerator.myTableTools.inTable(omissionList, attr) and self.class.myConfiguration.parameter[attr] then
			contentClassConfig = contentClassConfig .. _processAttribute(self, attr, '\t')
		end
	end
	if coreData.template_customization then
		for line in mw.text.gsplit(coreData.template_customization, '\n', true) do
			contentClassConfig = contentClassConfig .. '\t' .. mw.text.trim(line) .. '\n'
		end
	end
	contentClassConfig = contentClassConfig .. '}\n\nlocal parameter = {\n' .. coreData.parameter_parameter .. '}\n\n' ..
		'return {\n' ..
		'\tform = form,\n' ..
		'\tglobal = global,\n' ..
		'\tparameter = parameter,\n' ..
		'\ttemplate = template,\n}\n'
	local classCategory = Classgenerator.globalConfig.classCategory or 'none'
	local formCategory = Classgenerator.globalConfig.formCategory or 'none'
	local gardeningCategory = Classgenerator.globalConfig.gardeningSuperCategory or 'none'
	local moduleCategory = Classgenerator.globalConfig.moduleCategory or 'none'
	local propertyCategory = Classgenerator.globalConfig.propertyCategory or 'none'
	local superCategory = Classgenerator.globalConfig.projectSuperCategory or 'none'
	local templateCategory = Classgenerator.globalConfig.templateCategory or 'none'
	local page = {}
	page.order = {'base', 'baseDoc', 'class', 'classDoc', 'config', 'configDoc', 'template', 'templateDoc'}
	page.base = {
		name = 'Module:' .. _private[self].pagename,
		content = mw.message.new('classengine-template-module-page'):rawParams(_private[self].pagename):plain()
	}
	page.baseDoc = {
		name = 'Module:' .. _private[self].pagename .. '/doc',
		content = mw.message.new('classengine-template-module-documentation-page'):rawParams(_private[self].pagename, moduleCategory):plain()
	}
	page.class = {
		name = 'Module:' .. _private[self].pagename .. '/class',
		content = mw.message.new('classengine-template-module-class-page'):rawParams(_private[self].pagename, coreData.className):plain()
	}
	page.classDoc = {
		name = 'Module:' .. _private[self].pagename .. '/class/doc',
		content = mw.message.new('classengine-template-module-class-documentation-page'):rawParams(_private[self].pagename, coreData.className, moduleCategory, classCategory):plain()
	}
	page.config = {
		name = 'Module:' .. _private[self].pagename .. '/config',
		content = contentClassConfig,
	}
	page.configDoc = {
		name = 'Module:' .. _private[self].pagename .. '/config/doc',
		content = mw.message.new('classengine-template-module-config-documentation-page'):rawParams(_private[self].pagename, moduleCategory, classCategory):plain()
	}
	page.template = {
		name = 'Template:' .. coreData.template_name,
		content = mw.message.new('classengine-template-template-page'):rawParams(_private[self].pagename):plain()
	}
	page.templateDoc = {
		name = 'Template:' .. coreData.template_name .. '/doc',
		content = mw.message.new('classengine-template-template-documentation-page'):rawParams(_private[self].pagename, templateCategory):plain()
	}
	if coreData.form_name and #coreData.form_name > 0 then
		table.insert(page.order, 'form')
		page.form = {
			name = 'Form:' .. coreData.form_name,
			content = mw.message.new('classengine-template-form-page'):rawParams(_private[self].pagename, formCategory):plain()
		}
	end
	if coreData.global_category and #coreData.global_category> 0 then
		table.insert(page.order, 'category')
		page.category = {
			name = 'Category:' .. coreData.global_category,
			content = mw.message.new('classengine-template-category-page'):rawParams(_private[self].pagename, superCategory):plain()
		}
	end
	if coreData.global_gardeningCategory and #coreData.global_gardeningCategory > 0 then
		table.insert(page.order, 'gardeningCategory')
		local pagename = coreData.global_gardeningCategory
		if pagename == 'superglobal.gardeningSuperCategory' then
			pagename = FoundationClass.globalConfig.gardeningSuperCategory
		end
		page.gardeningCategory = {
			name = 'Category:' .. pagename,
			content = mw.message.new('classengine-template-gardeningcategory-page'):rawParams(_private[self].pagename, gardeningCategory):plain()
		}
	end
	for _, pid in pairs(page.order) do
		local obj = mw.title.new(page[pid].name)
		page[pid].exists = obj.exists
		page[pid].namespace = obj.namespace
		page[pid].editlink = obj:fullUrl{action='edit'}
		if pid == 'template' then
			page[pid].recreatedata = obj:fullUrl{action='recreatedata'}
		end
		page[pid].isDocPage = (mw.ustring.sub(page[pid].name, -4) == '/doc')
		if page[pid].isDocPage then
			page[pid].content = page[pid].content .. '<h2>Maintenanace notes</h2>\n' ..
				'This page was created by [[Module:Classgenerator]] and belongs to [[' .. self:getUid() .. ']].\n'
			if pid == 'configDoc' then
				page[pid].content = page[pid].content .. '\n{{((}}ombox| type=content | text = It is strongly advised, to not edit this page but to use [' ..
				'https://{{((}}SERVERNAME{{))}}{{((}}SCRIPTPATH{{))}}/Special:FormEdit/Classgenerator/' .. mw.uri.encode(self:getUid(), "PATH") .. ' ' .. 
					'the Classgenerator form] instead! After that, use your new configuration to replace the contents of this page.{{))}}'
			end
		end
	end
	local thisClass
	local thisConfig
	if page.class.exists and page.config.exists then
		thisClass = require(page.class.name)
		thisConfig = require(page.config.name)
	end
	if page.form and (not coreData.form_typeCreateLink or coreData.form_typeCreateLink ~= 'forminput') and coreData.form_createLinkPageName and mw.ustring.len(coreData.form_createLinkPageName) > 0 then
		local pageName = coreData.form_createLinkPageName
		if coreData.global_namespace and mw.ustring.len(coreData.global_namespace) > 0 and not mw.ustring.match(pageName, '^' .. coreData.global_namespace .. ':.+$') then
			pageName = coreData.global_namespace .. ':' .. pageName
		end
		local infostr = '{{((}}{info|page name=' .. pageName .. '|add title=' .. (coreData.form_labelCreate or 'create entity') .. '|edit title=' .. (coreData.form_labelEdit or 'edit entity') .. '}{{))}}'
		page.form.content = page.form.content .. '<!{{#invoke:String|rep|-|2}} this is a workaround, needed because of a SF bug: ' .. infostr ..
			'. see https://phabricator.wikimedia.org/T123230 for more information {{#invoke:String|rep|-|2}}>'
	end
	coreData.page = page
	local autocreate = {}
	autocreate.module = FoundationClass.myYesno(coreData.global_autocreate_module, tonumber(coreData.global_autocreate_module))
	autocreate.template = FoundationClass.myYesno(coreData.global_autocreate_template, tonumber(coreData.global_autocreate_template))
	autocreate.form = coreData.form_name and FoundationClass.myYesno(coreData.global_autocreate_form, tonumber(coreData.global_autocreate_form))
	autocreate.category = (coreData.global_category or coreData.global_gardeningCategory) and FoundationClass.myYesno(coreData.global_autocreate_category, tonumber(coreData.global_autocreate_category))
	if (FoundationClass.globalConfig.dataStore == 'both' or FoundationClass.globalConfig.dataStore == 'smw') and FoundationClass.myYesno(coreData.global_smwUseStorage) then
		local propertyNSName = _namespaceName(self, mw.title.new('NUL', 'Property').namespace)
		autocreate[propertyNSName] = FoundationClass.myYesno(coreData['global_autocreate_' .. propertyNSName], tonumber(coreData['global_autocreate_' .. propertyNSName]))
	end
	coreData.autocreate = autocreate
	local propertyData
	local propertyOrder
	if (FoundationClass.globalConfig.dataStore == 'both' or FoundationClass.globalConfig.dataStore == 'smw') and FoundationClass.myYesno(coreData.global_smwUseStorage) and thisClass and thisConfig and thisConfig.global.smwUseStorage then
		-- we use smw and class and config are created and accessible. we can get property information and prepare data
		local matrix = thisClass:smwGetProperty2ParameterTranslationTable()
		propertyData = {}
		propertyOrder = {}
		for prop, parameterList in pairs(matrix) do
			for _, parameter in pairs(parameterList) do
				if FoundationClass.globalConfig.ucfirst then
					property = lang:ucfirst(prop)
				else
					property = prop
				end
				table.insert(propertyOrder, property)
				local obj = mw.title.new(property, 'Property')
				propertyData[property] = { 
					editlink = obj:fullUrl{action='edit'},
					exists = obj.exists,
					parameter = parameter,
				}
				if thisConfig.parameter[parameter] then
					propertyData[property].description = thisConfig.parameter[parameter].description
					propertyData[property].type = thisConfig.parameter[parameter].property_type
					propertyData[property].values = thisConfig.parameter[parameter].values
				elseif parameter == FoundationClass.globalConfig.smwClassProperty then
					propertyData[property].description = 'Automatisch hinzugefügt! Wird verwendet, um Mitglieder dieser Klasse zu finden (funktioniert auch, ohne dass eine Kategorie definiert wird und auch fur subobjects)'
					propertyData[property].type = 'Text'
				elseif parameter == FoundationClass.globalConfig.uidFieldName then
					propertyData[property].description = 'Automatisch hinzugefügt! Wird verwendet, um individuelle Objekte innerhalb der Klasse zu identifizieren.'
					propertyData[property].type = 'Text'
				end
				local values = ''
				if propertyData[property].values then
					values = values .. 'The allowed values are:'
					for _, value in pairs(propertyData[property].values) do
						values = values .. '\n* [[Allows value::' .. value .. ']]'
					end
				else
					values = 'No restriction given'
				end
				propertyData[property].content = mw.message.new('classengine-template-property-page'):rawParams(propertyData[property].description, propertyData[property].type, values, _private[self].pagename, propertyCategory):plain()
			end
		end
		table.sort(propertyOrder)
	end
	coreData.properties = { data = propertyData, order = propertyOrder }
	-- calculate identity
	if thisConfig then
		local ib_identity = {}
		local parameterList = {}
		for param, _ in pairs(thisConfig.parameter) do
			table.insert(parameterList, param)
		end
		function findKey( t, v )
			for k, vv in ipairs(t) do
				if vv == v then
					return k
				end
			end
		end
		for _, param in ipairs( fieldOrder ) do	-- lets test fieldOrder, if not, use parameterList
			table.insert(
				ib_identity,
				{
					param = param,
					label = thisConfig.parameter[param].label
				}
			)
			table.remove(parameterList, findKey(parameterList, param))
		end
		if #parameterList > 0 then
			table.sort(parameterList)
			for _, param in ipairs(parameterList) do
				table.insert(
					ib_identity,
					{
						param = param,
						label = thisConfig.parameter[param].label
					}
				)
			end
		end
		_private[self].identity = ib_identity
	end
	return coreData	-- this is your new coreData.
end

function Classgenerator:myPlausibilityTest(args)
	_debug(self, 1, 'entering Classgenerator:myPlausibilityTest(args) to test arguments, from ' .. tostring(self))
	-- function that performs the individual plausibility tests
	-- note: before you access a field args.fieldname you should check for existance
	-- self:addError(text)
	return false	-- return value will be ignored. but if you add any error, the object's initialization will fail with the error
end

function Classgenerator:myStashAdjustments(stash)
	_debug(self, 1, 'entering Classgenerator:myStashAdjustments(stash) to do some minor adjustments on data before storing, from ' .. tostring(self))
	-- function that alters the stash before storing the data
	local stash = stash
	return stash	-- this is your new stash. this will be stored. it has format (fieldname: value)
end

function Classgenerator:method()
	_debug(self, 1, 'entering Classgenerator:method() to do something, from ' .. tostring(self))
	return true
end

return Classgenerator