K (Schützte „Modul:Foundationclass“: Automatic protection of selected project pages ([Bearbeiten=Nur Administratoren erlauben] (unbeschränkt) [Verschieben=Nur Administratoren erlauben] (unbeschränkt))) |
|||
(Eine dazwischenliegende Version von einem anderen Benutzer wird nicht angezeigt) | |||
Zeile 12: | Zeile 12: | ||
-- **************** declaration of static properties | -- **************** declaration of static properties | ||
− | |||
FoundationClass.static.globalConfig = mw.loadData( 'Module:Foundationclass/globalconfig' ) | FoundationClass.static.globalConfig = mw.loadData( 'Module:Foundationclass/globalconfig' ) | ||
FoundationClass.static.myCargoUtil = require('Module:CargoUtil') | FoundationClass.static.myCargoUtil = require('Module:CargoUtil') | ||
Zeile 437: | Zeile 436: | ||
:newline() | :newline() | ||
:wikitext(ClassDebug:printLog(debugLevel)) | :wikitext(ClassDebug:printLog(debugLevel)) | ||
+ | end | ||
+ | local getArgs = require('Module:Arguments').getArgs | ||
+ | local frame = mw.getCurrentFrame() | ||
+ | local args = getArgs(frame) | ||
+ | if args.dump == "true" then | ||
+ | return mw.text.nowiki( tostring(html) ) | ||
end | end | ||
return html | return html | ||
Zeile 458: | Zeile 463: | ||
:done() | :done() | ||
:newline() | :newline() | ||
+ | end | ||
+ | local getArgs = require('Module:Arguments').getArgs | ||
+ | local frame = mw.getCurrentFrame() | ||
+ | local args = getArgs(frame) | ||
+ | if args.dump == "true" then | ||
+ | return mw.text.nowiki( tostring(html) ) | ||
end | end | ||
return html | return html | ||
Zeile 640: | Zeile 651: | ||
local templateData = '' | local templateData = '' | ||
if #parameter > 0 then | if #parameter > 0 then | ||
− | local jsonData = '{\n\t"description": "' .. | + | local globalDescription = mw.ustring.gsub(mw.ustring.gsub(_CFG.global.description, '\t', ' '), '\n', ' ') |
+ | local jsonData = '{\n\t"description": "' .. globalDescription .. '",\n' .. | ||
'\t"params": {\n' | '\t"params": {\n' | ||
for _, param in pairs(parameter) do | for _, param in pairs(parameter) do | ||
− | paramdata = _CFG.parameter[param] | + | local paramdata = _CFG.parameter[param] |
jsonData = jsonData .. '\t\t"' .. param .. '": {\n' | jsonData = jsonData .. '\t\t"' .. param .. '": {\n' | ||
jsonData = jsonData .. '\t\t\t"type": "' .. mw.ustring.lower(paramdata.td_type) .. '",\n' | jsonData = jsonData .. '\t\t\t"type": "' .. mw.ustring.lower(paramdata.td_type) .. '",\n' | ||
Zeile 650: | Zeile 662: | ||
end | end | ||
if paramdata.description then | if paramdata.description then | ||
− | jsonData = jsonData .. '\t\t\t"description": "' .. mw.ustring.gsub(paramdata.description, '"', '\'\'') .. '",\n' | + | --jsonData = jsonData .. '\t\t\t"description": "' .. mw.ustring.gsub(paramdata.description, '"', '\'\'') .. '",\n' |
+ | --since 1.31 \n and \t are not allowed in json string, so replace them with a space | ||
+ | local paramDescription = mw.ustring.gsub(paramdata.description, '"', '\'\'') | ||
+ | paramDescription = mw.ustring.gsub(mw.ustring.gsub(paramDescription, '\t', ' '), '\n', ' ') | ||
+ | jsonData = jsonData .. '\t\t\t"description": "' .. paramDescription .. '",\n' | ||
end | end | ||
if paramdata.label then | if paramdata.label then | ||
Zeile 724: | Zeile 740: | ||
:newline() | :newline() | ||
:wikitext('<h2>Usage</h2>') | :wikitext('<h2>Usage</h2>') | ||
− | :wikitext(frame:expandTemplate{ title = 'Code', args = {' | + | :wikitext(frame:expandTemplate{ title = 'Code', args = {'html+handlebars', code} }) |
:newline() | :newline() | ||
:node(seeAlso) | :node(seeAlso) | ||
Zeile 1.119: | Zeile 1.135: | ||
elseif not FoundationClass.usesDataStore(self.class, 'smw') then | elseif not FoundationClass.usesDataStore(self.class, 'smw') then | ||
_debug(self, 2, ' Could not initialize by myself: Cargo query for \'' .. wherefield .. '=' .. wherefor .. '\' in table \'' .. _CFG.global.cargoTable .. '\' did not yield any result.') | _debug(self, 2, ' Could not initialize by myself: Cargo query for \'' .. wherefield .. '=' .. wherefor .. '\' in table \'' .. _CFG.global.cargoTable .. '\' did not yield any result.') | ||
+ | _debug(self, 3, ' Query was<pre>' .. FoundationClass.myTableTools.printTable(query) .. '</pre>') | ||
self:addError('Could not initialize by myself: Cargo query for \'' .. wherefield .. '=' .. wherefor .. '\' in table \'' .. _CFG.global.cargoTable .. '\' did not yield any result.') | self:addError('Could not initialize by myself: Cargo query for \'' .. wherefield .. '=' .. wherefor .. '\' in table \'' .. _CFG.global.cargoTable .. '\' did not yield any result.') | ||
end | end |
Aktuelle Version vom 6. April 2023, 19:19 Uhr
This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
This is a Template for Class Modules. It implements a class in Lua using Module:Middleclass and provides serveral static and public methods, commonly used in the typical form>page>store process.
Usage[Quelltext bearbeiten]
This is in a way an abstract class. It provides some static and public methods for resuse, and also maintains a store of private properties. If can be used to fast and easily create a typical class module that can handle:
- creating an appropriate form
- supplying your respective template with functionalities for
- object initialization via template parameters, arguments, and datastore (self initialization)
- general data assesment (basic plausibility tests)
- data storage (supported are cargo and semantic media wiki)
- error and warnings management
- output and rendering
- creating a template documentation
You can and should adjust the module in this methods:
- individual attribute adjustment for the semantic forms fields
- individual plausibility testing
- individual data initialization
- individual data store adjustments before stashing
You can access the objects core data store with getCoreData() and its uid with getUid().
How-To[Quelltext bearbeiten]
This is, what you have to do (see Useful templates for content of the corresponding pages):
- create your base module Module:Name
- create your class module Module:Name/class. For this, copy lua sample code below this list and apply the following changes:
- change all occurences of className into your class name
- change the highlighted lines and replace 'Name' with the Name of your module
- implement the abstract methods:
- myAgumentProcessing(coreData)
- myDataAdjustments(data)
- myPlausibilityTest(args)
- myStashAdjustments(stash)
- static:mySfDynamicFieldAttribute(fieldname, attribute, value)
- for the usual output generation, implement (shells given in sample code)
- addInfobox()
- addPageBody()
- create and fill your configuration Module:Name/config
- create your template Template:Name
- create your form Form:Name
- if applicable, create your category page Category:Name
- fill in documentation:
- of your base module (place one invoke below the first comment and before the includeonly)
- of your class module (new docu for your own public, static and private methods (which you can probably copy from other classes) and one invoke to show the inheritance. Sample code provided in Useful templates
- of your class module's configuration (just copy content)
- of your template (one invoke below the first comment and before the includeonly)
Useful templates[Quelltext bearbeiten]
base module:
|
---|
⧼classengine-template-module-page⧽
|
base module's documentation page:
|
---|
⧼classengine-template-module-documentation-page⧽ |
class module:
|
---|
⧼classengine-template-module-class-page⧽
|
class module's documentation page:
|
---|
⧼classengine-template-module-class-documentation-page⧽ |
class configuration (sample file):
|
---|
local superglobal = mw.loadData( 'Module:Foundationclass/globalconfig' )
local form = {
enable = true, -- Do you want to create a form for this class? Note: When you don't want to have a form _page_, but need this to be a part of another form (as a holds-template form), set this to true!
name = '', -- The name of the form, i.e. the form will be placed an page [[Form:Formname]]. If you don't need an actual form page, leave this empty (e.g. if this is a prot of another form as holds-template or such).
teaserText = '', -- This is the text displayed on the form:name page (before you see the actual form))
typeCreateLink = 'none', -- This field lets you choose, what kind of object create link is provided to the user on the form page: is there none, a formlink, or a forminput field? possible values are: 'none' (default), 'forminput', 'formlink'
createInfotext = '', -- This is the short text that appears right above the input field. Short being the important part. Please limit yourself to a short sentence.
createInputPlaceholder = '', -- Placeholder text that is shwon in the form create input field
createInputQueryString = '', -- You can use this option to pass information to the form; this information generally takes the form of ''templateName[fieldName]=value''. It should look like a typical URL query string; an example would be "query string=namespace=User&User[Is_employee]=yes".
createLinkPageName = '', -- With this, you can have the name of the page created by the form to be set automatically. You can use any of the parameters ''<template-name[field-name]>'' or ''<unique number>''. The latter takes options start=x, unique, random, and a number (length of id string, default 6).
-- IMPORTANT: If you want to use the one step process with a createLinkPageName, you have to add the output if your class's sfGenerateFormInfoTag() in comments to your form page!!!
-- this is a workaround for a semantic forms bug. see https://phabricator.wikimedia.org/T123230 for more information
createLinkQueryString = '', -- You can use this option to pass information to the form; this information generally takes the form of ''templateName[fieldName]=value''. It should look like a typical URL query string; an example would be "query string=namespace=User&User[Is_employee]=yes".
createLinkType = 'plain', -- This field lets you choose, what kind of form link is used to link to the form page: is it a plain link or a button (with parameter submission via get or post), possible values are nil, 'plain', 'button', 'post button'
labelCreate = '', -- label for create entity
labelEdit = '', -- label for edit entity
headerText = '', -- this is the text displayed above the form
notification = '', -- this notification will be displayed above your form
sectionList = {}, -- if you want to have hl2 sections of text after the datafields and before the freetext, name them here. Use strings for names of section headlines
allowsFreeText = false, -- will the form have a free text field?
freeTextPreload = nil, -- when this is set your free text will have a preload=<freeTextPreload> statement. of course only when allowsFreeText is set to true
buttons = {'save', 'preview', 'changes', 'cancel'}, -- which buttons should appera below the form
fieldSize = 80, -- what is the default size= for the form fields
textareaAttributes = { -- the defaults for your textarea fields
cols = 80,
rows = 4,
autogrow = true,
editor = 'wikieditor', -- other values would be false or 'none'...
},
fieldOrder = {
-- the order in which the form fields appear. NOTE: a parameter not in this list, will not appear in the form!!
-- YOU HAVE TO FILL THIS TABLE! Put in here all parameters, that are used in the form, even if you have your own sfGenerateForm() implemented using a different table.
-- Reason: This is also be used in plausibility tests
'',
},
}
local global = {
cargoTable = '', -- if you use dataStore cargo, name the table here. if you do not name a table, no persistant cargo data will be stored for that class
category = '', -- the mediawiki category, the entity is placed into
delimiter = ',', -- see to it, that the delimiter is not a character, that will be encoded by mw.text.encode. CargoUtil.store encodes the data for security reasons
description = '', -- a short description of the entity. will be displayed on the template documentation page for example
entityTitle = '', -- generic title for the entity
gardeningCategory = superglobal.gardeningCategory, -- the category, objects with erroneous/inplausible data will be put into
namespace = '', -- if you put this entity on a special namespace, name it here. NOTE: You have to be precise. This is case sensitive. But omit the colon.
smwIsSubobject = false, -- when using datastore smw: is this stored as subobject (and not as normal data)?
smwUseStorage = true, -- if you use dataStore smw, set this to true if you actually want persistant smw data to be stored for that class
}
local parameter = {
-- this is your list of parameters. you put all data here, that you would like to handle
-- * parameters of your form (and thus your template)
-- * when you fill td_type, your parameter will be shown on the template documentation page
-- * when you add the parameter name to form.fieldOrder, it will be added to the form and processed in plausibility tests
-- * add also data, that you only want to store (omit these from form.fieldOrder and leave the sf table, probably best, to leave td_type unset, too).
-- * hint: if you need a row in your table as information, add pseudo parameter w/o entry in fieldOrder, w/o sf table, w/o td_type, and w/o cargo/property entries
name = {
cardinality = 'single|list',
cargo_hidden = false, -- takes no value. If set, the field is not listed in either Special:ViewTable or Special:Drilldown, although it is still queriable.
cargo_size = nil, -- for fields of type "Text", sets the size of this field, i.e. the number of characters; default is 300
cargo_type = '',
description = '',
label = '',
property_name = '', -- please use underscores (_) instead of spaces
property_type = '', -- possible values are: Annotation URI, Boolean, Code, Date, Email, Number, Page (default), Quantity, Telephone Number, Temperature, Text, URL
severity = 'mandatory|suggested',
sf = {
-- note: this list is incomplete. see [[Module:SFfield/config]] for a complete list of supported attributes
-- note also: mandatory, list, property and values are derived form fields "above" this table
-- IMPORTANT: If you want this to be a regular form parameter, you have to add this table. even, if you leave it empty.
-- also: keep in mind that a parameter appears in the form only if you add its name to form.fieldOrder above
cargo_field = '',
cargo_table = '',
class = '',
default = '',
default_filename = '',
existing_values_only = true,
hidden = true,
image_preview = true,
input_type = '',
mapping_cargo_field = '',
mapping_cargo_table = '',
mapping_template = '',
max_values = 0,
maxlength = 0,
placeholder = '',
restricted = '', -- e.g.: restricted = superglobal.restrictionRole,
show_on_select = {}, -- takes either a string (in case of input type checkbox) or a table. table must be of format "selected value" : "field shown"
size = 0,
unique = true,
unique_for_category = true,
unique_for_namespace = true,
uploadable = true,
values_dependent_on = '',
values_from_category = '',
values_from_namespace = '',
},
td_default = '',
td_type = '',
values = {},
},
}
local template = {
name = 'nameOfYourTemplate', -- the name of your template. e.g.: your template can be found on the page [[Template:nameOfYourTemplate]]
templateDocumentationSeeAlso = {'List', 'of', 'similar', 'or', 'related', 'templates'} -- used in the see also-section of your template documentation
}
return {
form = form,
global = global,
parameter = parameter,
template = template,
}
|
configuration documentation page:
|
---|
⧼classengine-template-module-config-documentation-page⧽ |
template:
|
---|
⧼classengine-template-template-page⧽ |
template documentation page:
|
---|
⧼classengine-template-template-documentation-page⧽ |
form:
| ||
---|---|---|
⧼classengine-template-form-page⧽ |
category:
|
---|
⧼classengine-template-category-page⧽ |
gardening category:
|
---|
⧼classengine-template-gardeningcategory-page⧽ |
private, public, class or instance[Quelltext bearbeiten]
- | public | private |
---|---|---|
instance | function MyClass:publicMethod()
MyClass.publicProperty
|
local _privateMethod = function (self, var)
_private[self]._privateProperty
|
class | function MyClass.static:staticMethod()
MyClass.static.staticProperty
-- accessing
MyClass.staticProperty
-- being "outside":
MyClass:staticMethod()
-- being inside a static method
self:staticMethod()
-- being inside a public method
self.class:staticMethod()
|
local _privateMethod = function (self, var)
local _privateProperty
|
private[Quelltext bearbeiten]
property[Quelltext bearbeiten]
you can declare a property private in one of two ways:
- anywhere, preferably before your constructor, declare a
local var
to have a private propery, this is not recommended, but it allows you to declare a private property, that can be used by your static methods. thus being somewhat private static - for your instances, you can use the table _private[self] as a private store. it is available after your construrctor has been called (since this is an instance attribute)
method[Quelltext bearbeiten]
a private method is declared thus: local _privateMethod = function(self, var)
. If you want to use the method in an public/static/other private method before it is declared (aka: the calling method is on a lower line number than your private method's declaration), decare it ahead and define it later:
local _privateImportantMethod
..
privateImportantMethod = function(self, var)
private class and instance methods are basically the same.
public[Quelltext bearbeiten]
property[Quelltext bearbeiten]
can be dclared via class.property. DONT DO THIS. It is bad style!
method[Quelltext bearbeiten]
Declare them class:publicMethod(var). They are, after all, public
NOTE: public methods can be called by an instance, but also as static method:
function Class:public()
return 'public: ' .. tostring(self)
end
local me = Class:new()
me.public() -- returns "public: Instance of class Class"
Class:public() -- returns "public: class Class"
static[Quelltext bearbeiten]
property[Quelltext bearbeiten]
Declare a static property like this: class.static.myProperty = 'Hello World'
. This produces a public property, that can be accessed by the class, childclasses or instances via *.myProperty (replace * with class, object, childclass, ...)
method[Quelltext bearbeiten]
Much the same as static properties, but you should use the colon operator: function Class.static:staticMethod()
when definig the method. On accessig this method, you should use the dot-notation: function Class.staticMethod(self)
NOTE: Other than public methods, they can only be called by the class, but not by an instance:
function Class.static:static()
return 'static: ' .. tostring(self)
end
local me = Class:new()
me.static() -- returns "error: attempt to call method 'static' (a nil value)"
Class:static() -- returns "static: class Class"
Class.static(self) -- this is not called via colon (:) operator as to preserve the childClass's scope when inheriting from this class
Methods[Quelltext bearbeiten]
MediaWiki:Classengine-content-documentation-methods
private methods[Quelltext bearbeiten]
These private Methods can not be used by child classes!
_amIPlausible(self)[Quelltext bearbeiten]
Returs true or false, whether the object is plausible or not (i.e. has no errors or 1+)
- self
- object, me
- return
- boolean, whether the object is plausible or not
_debug(self, level, text)[Quelltext bearbeiten]
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
_plausibilityTest(self, args)[Quelltext bearbeiten]
Checks, if input provided via template is plausible enough, to represent the object (to be stored and displayed). Also fills the list of errors and does some argument preparation.
- self
- object, me
- args
- table, mandatory
- arguments passed to the template to be checked
- return
- boolean, whether the object is plausible or not
Properties[Quelltext bearbeiten]
static[Quelltext bearbeiten]
MediaWiki:Classengine-content-documentation-properties
private[Quelltext bearbeiten]
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.
- categories
- table, holds the objects categories
- coreData
- table, holds the objects data ofter initializing
- dbg
- object, my instance of Module:Debug/class for debugging purposes
- errors
- table, a list of errors that occurred
- fullpagename
- string, name of currentpage including namespace
- initialized
- boolean, is this object properly initialized
- loadedDataFromDataStore
- boolean, did this object get its data from the data store
- output
- object of type mw.html, holds all output to be rendered()
- pagename
- string, name of current page (or current page's super page) w/o namespace
- uid
- string, uinique identifier ('NIL' if unset)
- warnings
- table, a list of warnings that came up
Configuration Data[Quelltext bearbeiten]
This class holds gets its control data from the child class. Also, there is some global configuration data in Module:Foundationclass/globalconfig, that applies to all classes.
Dependencies[Quelltext bearbeiten]
If you want to use Module:Foundationclass, you also need the following items (and their doc pages!):
- Module:Middleclass
- Module:Foundationclass/config
- Module:Foundationclass/classDoc
- Module:Foundationclass/globalconfig
- Module:CargoUtil and Extension:Cargo if you want to use it as a data store
- Module:SmwUtil and Extension:Semantic MediaWiki if you want to use it as a data store
also
- Module:Arguments
- Module:Collapse
- Module:Debug/class
- Module:Error
- Module:Infobox
- Module:Lua banner
- Module:Message box
- Module:SFfield
- Module:SFfield
- Module:TableTools
- Module:Yesno
- {{code}}
- Extension:TemplateData
and of course Extension:Semantic Forms
Also, have a look at the extended functionality of the Class engine.
Interface messages[Quelltext bearbeiten]
To generate the Useful_templates, Foundationclass makes use of the following interface messages:
- MediaWiki:Classengine-content-documentation-methods
- MediaWiki:Classengine-content-documentation-properties
- MediaWiki:Classengine-template-module-page
- MediaWiki:Classengine-template-module-documentation-page
- MediaWiki:Classengine-template-module-class-page
- MediaWiki:Classengine-template-module-class-documentation-page
- MediaWiki:Classengine-template-module-config-documentation-page
- MediaWiki:Classengine-template-template-page
- MediaWiki:Classengine-template-template-documentation-page
- MediaWiki:Classengine-template-form-page
- MediaWiki:Classengine-template-category-page
- MediaWiki:Classengine-template-gardeningcategory-page
- MediaWiki:Classengine-template-property-page
Next in dev queue[Quelltext bearbeiten]
- have foundation class try to detect integer inputs (by td_type or cargo_type) and run a regexp in _plausibilityTest
- have foundationclass use mw message system for printouts instead of hardcoded text
- a template or page, that #autogenerates all categories, defined in Module:Foundationclass/globalconfig
local Class = require('Module:Middleclass').class
local FoundationClass = Class('FoundationClass')
local ClassDebug = require('Module:Debug/class')
local ClassSFfield = require('Module:SFfield/class')
-- ****************************************************************
-- * properties *
-- ****************************************************************
-- **************** initialization of table for private properties
local _private = setmetatable({}, {__mode = "k"}) -- weak table, storing all private attributes
-- **************** declaration of static properties
FoundationClass.static.globalConfig = mw.loadData( 'Module:Foundationclass/globalconfig' )
FoundationClass.static.myCargoUtil = require('Module:CargoUtil')
FoundationClass.static.mySmwUtil = require('Module:SmwUtil')
FoundationClass.static.myTableTools = require('Module:TableTools')
FoundationClass.static.myYesno = require('Module:Yesno')
-- these are later set by my child class:
local _debug -- function for debugging, declared later
-- ***************************************************************
-- * methods *
-- ***************************************************************
-- **************** declaration of static methods
function FoundationClass:initialize(user_uid, superHandler) -- constructor
local user_uid = user_uid or mw.title.getCurrentTitle().prefixedText
local shs = superHandler
local superHandler = (superHandler and type(superHandler) == 'table' and superHandler.addError and type(superHandler.addError) == 'function') and superHandler or nil
local _CFG = self.class.myConfiguration
local idString = user_uid and ('myUid_' ..user_uid) or ('NIL_' .. mw.title.getCurrentTitle().prefixedText)
-- initialize all private properties
_private[self] = {
categories = {},
coreData = {},
dbg = ClassDebug:new('class FoundationClass: ' .. idString),
errors = {},
initialized = false,
loadedDataFromDataStore = false,
loadedDataMyself = false,
output = mw.html.create(''),
superHandler = superHandler,
uid = user_uid,
warnings = {},
}
if _CFG.global.category and mw.title.getCurrentTitle().namespace ~= 10 then
self:addCategory(_CFG.global.category)
end
_debug(self, 1, 'Initializing object "' .. idString ..'", from ' .. tostring(self))
_debug(self, 1, ' my superhandler was ' .. tostring(shs))
_debug(self, 1, ' my superhandler is ' .. tostring(superHandler))
end
function FoundationClass.static:cargoGenerateTableStructure()
_debug(self, 1, 'entering FoundationClass.static:cargoGenerateTableStructure(), from ' .. tostring(self))
local _CFG = self.myConfiguration
-- warning: calling FoundationClass:cargoGenerateTableStructure() gives us no access to our configuration, use Class.cargoGenerateTableStructure(self) instead
local declaration = {}
-- first, add the uid field
declaration[FoundationClass.globalConfig.uidFieldName] = 'Text (hidden)'
for param, paramData in pairs(_CFG.parameter) do
if paramData.cargo_type and mw.ustring.len(paramData.cargo_type) > 0 then
if paramData.cardinality and paramData.cardinality == 'list' then
declaration[param] = 'List (' .. (_CFG.parameter[param].sf and _CFG.parameter[param].sf.delimiter or _CFG.global.delimiter) .. ') of ' .. paramData.cargo_type
else
declaration[param] = paramData.cargo_type
end
local additional_field_parameters = {}
if paramData.cargo_hidden then
table.insert(additional_field_parameters, 'hidden')
end
if paramData.cargo_size and (type(paramData.cargo_size) == 'number' or mw.ustring.match(paramData.cargo_size, '^[0-9]+$')) and
FoundationClass.myTableTools.inTable(FoundationClass.globalConfig.cargoTypesElegibleForSize, mw.ustring.lower(paramData.cargo_type)) then
table.insert(additional_field_parameters, 'size=' .. tostring(paramData.cargo_size))
end
if paramData.values and FoundationClass.myTableTools.size(paramData.values) > 0 and
FoundationClass.myTableTools.inTable(FoundationClass.globalConfig.cargoTypesElegibleForValue, mw.ustring.lower(paramData.cargo_type)) then
local av = 'allowed values='
for _, v in pairs(paramData.values) do
av = av .. v .. ','
end
table.insert(additional_field_parameters, mw.ustring.sub(av, 1, -2))
end
if #additional_field_parameters > 0 then
declaration[param] = declaration[param] .. ' (' .. table.concat(additional_field_parameters, ';') .. ')'
end
end
end
return declaration
end
function FoundationClass.static:categorize()
local thispage = mw.title.getCurrentTitle()
local _CFG = self.myConfiguration
local ret = ''
if self and _private[self] and _private[self].uid then
error('FoundationClass:categorize() must be called statically. Furthermore, it is not meant for categorizing class\'s objects but rather all pages belonging to the class\'s data pipeline (form, categories, modules, template, ...)')
elseif thispage.rootText == 'Classgenerator' or thispage.rootText == 'Foundationclass' then
ret = ret .. '[[Category:Class engine]]'
if FoundationClass.globalConfig.classCategory and mw.ustring.len(FoundationClass.globalConfig.classCategory) > 0 then
-- there has been a classCategory configured
if thispage.text == 'Foundationclass' or (thispage.subpageText and thispage.subpageText == 'class') then
-- add class category if on a class page or on foundationclass
ret = ret .. '[[Category:' .. FoundationClass.globalConfig.classCategory .. ']]'
end
if thispage.subpageText and (thispage.subpageText == 'config' or thispage.subpageText == 'globalconfig') then
-- add class category if on a config page
local basepage = mw.ustring.match(thispage.fullText, '^[^:]*:(.+)/config.*$')
local classpage
if basepage then
classpage = basepage .. '/class'
else
classpage = thispage.rootText .. '/config'
end
ret = ret .. '[[Category:' .. FoundationClass.globalConfig.classCategory .. '|' .. classpage .. ']]'
end
end
elseif thispage.namespace == 10 then
-- template namespace: add category if in correct namespace and there has been a templateCategory configured, also make sure, we are not part of classgenerator
if FoundationClass.globalConfig.templateCategory and mw.ustring.len(FoundationClass.globalConfig.templateCategory) > 0 then
ret = ret .. '[[Category:' .. FoundationClass.globalConfig.templateCategory .. ']]'
end
elseif thispage.namespace == 14 then
-- category namespace
if _CFG and _CFG.global and _CFG.global.gardeningCategory == thispage.text and FoundationClass.globalConfig.gardeningSuperCategory and mw.ustring.len(FoundationClass.globalConfig.gardeningSuperCategory) and thispage.text ~= FoundationClass.globalConfig.gardeningSuperCategory then
-- if class' gardening category and not the supergardening itself -> set gardening supercategory
ret = ret .. '[[Category:' .. FoundationClass.globalConfig.gardeningSuperCategory .. ']]'
elseif FoundationClass.globalConfig.projectSuperCategory and mw.ustring.len(FoundationClass.globalConfig.projectSuperCategory) > 0 then
-- not a gardening category and not called by a childclass. projectSuperCategory set
ret = ret .. '[[Category:' .. FoundationClass.globalConfig.projectSuperCategory .. ']]'
end
elseif thispage.namespace == mw.title.makeTitle('Form', 'NUL').namespace then
-- form namespace: add category if in correct namespace and there has been a formCategory configured, also make sure, we are not part of classgenerator
if FoundationClass.globalConfig.formCategory and #FoundationClass.globalConfig.formCategory > 0 then
ret = ret .. '[[Category:' .. FoundationClass.globalConfig.formCategory .. ']]'
end
elseif thispage.namespace == mw.title.makeTitle('Module', 'NUL').namespace then
-- module namespace: add category if in correct namespace and there has been a moduleCategory configured, also make sure, we are not part of classgenerator or foundationclass
if FoundationClass.globalConfig.moduleCategory and #FoundationClass.globalConfig.moduleCategory > 0 then
ret = ret .. '[[Category:' .. FoundationClass.globalConfig.moduleCategory .. ']]'
end
if thispage.subpageText and thispage.subpageText == 'class' and FoundationClass.globalConfig.classCategory and mw.ustring.len(FoundationClass.globalConfig.classCategory) > 0 then
-- add class category if on a class page and there has been a classCategory configured
ret = ret .. '[[Category:' .. FoundationClass.globalConfig.classCategory .. ']]'
end
if thispage.subpageText and thispage.subpageText == 'config' and FoundationClass.globalConfig.classCategory and mw.ustring.len(FoundationClass.globalConfig.classCategory) > 0 then
-- add class category if on a config page and there has been a classCategory configured
local basepage = mw.ustring.match(thispage.fullText, '^[^:]*:(.+)/config.*$')
local classpage
if basepage then
classpage = basepage .. '/class'
else
classpage = thispage.rootText .. '/config'
end
ret = ret .. '[[Category:' .. FoundationClass.globalConfig.classCategory .. '|' .. classpage .. ']]'
end
elseif thispage.namespace == mw.title.makeTitle('Property', 'NUL').namespace then
-- property namespace: add category if in correct namespace and there has been a propertyCategory configured
if FoundationClass.globalConfig.propertyCategory and #FoundationClass.globalConfig.propertyCategory > 0 then
ret = ret .. '[[Category:' .. FoundationClass.globalConfig.propertyCategory .. ']]'
end
end
return ret
end
function FoundationClass.static:categoryPage()
_debug(self, 1, 'entering FoundationClass.static:categoryPage(), from ' .. tostring(self))
local html = mw.html.create('')
if mw.title.getCurrentTitle().namespace == 14 then
local frame = mw.getCurrentFrame()
local _CFG = self.myConfiguration
local form
if _CFG.form.enable and _CFG.form.name and mw.ustring.len(_CFG.form.name) then
form = frame:callParserFunction('#default_form:' .. _CFG.form.name)
else
form = 'Seiten in dieser Kategorie haben kein Standardformular'
end
local mbox = require('Module:Message box').main('cmbox',
{
type = 'notice',
text = _CFG.global.description .. '\n* ' .. form .. '\n* ' ..
'Seiten in dieser Kategorie nutzen die Vorlage [[Template:' .. _CFG.template.name .. ']]'
})
html:wikitext(tostring(mbox))
:node(self:explainDataStore()) -- remember: self refers to a class, not an object and this method is static
else
error('FoundationClass:categoryPage() must be called from namespace category!', 2)
end
return html
end
function FoundationClass.static:explainDataStore()
_debug(self, 1, 'entering FoundationClass.static:explainDataStore(), from ' .. tostring(self))
local _CFG = self.myConfiguration
local collapse = require('Module:Collapse').main
local str = ''
if FoundationClass.usesDataStore(self, 'cargo') then
local declaration = self:cargoGenerateTableStructure() -- remember: self refers to a class, not an object and this method is static
-- add the default fields
for field, description in pairs(FoundationClass.globalConfig.cargoSpecialFields) do
declaration[field] = description
end
local fields = {}
for key, _ in pairs(declaration) do
table.insert(fields, key)
end
table.sort(fields)
local headline = 'Declaration for CARGO table "' .. (_CFG.global.cargoTable or 'NIL') .. '"'
local content = '<ul>'
for _, field in pairs(fields) do
local text = declaration[field]
if _CFG.parameter[field] and _CFG.parameter[field].description then
text = text .. ', <small>' .. _CFG.parameter[field].description .. '</small>'
elseif field == FoundationClass.globalConfig.uidFieldName then
text = text .. ', <small>Automatisch hinzugefügt! Wird verwendet, um individuelle Objekte innerhalb der Klasse zu identifizieren.</small>'
end
content = content .. '<li> ' .. field .. ': ' .. text .. '</li>'
end
content = content .. '</ul>\n[[Spezial:CargoTables/'.. (_CFG.global.cargoTable or 'Instance') .. '|View Data]]'
str = str .. collapse{header = headline, content = content, left = true} .. '\n'
end
if FoundationClass.usesDataStore(self, 'smw') then -- smw store
local property2param = FoundationClass.smwGetProperty2ParameterTranslationTable(self)
local properties = {}
local lang = mw.language.getContentLanguage()
for prop, field in pairs(property2param) do
if FoundationClass.globalConfig.ucfirst then
property = lang:ucfirst(prop)
else
property = prop
end
properties[property] = {
individual = true, -- essentially says: no special property
}
if _CFG.parameter[field] then
properties[property].description = _CFG.parameter[field].description
properties[property].type = (_CFG.parameter[field].property_type and _CFG.parameter[field].property_type or 'Page')
properties[property].values = (_CFG.parameter[field].values and #_CFG.parameter[field].values > 0) and ' (allowed values=' .. table.concat(_CFG.parameter[field].values, ', ') .. ')' or ''
elseif field == FoundationClass.globalConfig.smwClassProperty then
properties[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)'
properties[property].type = 'Text'
properties[property].values = ''
elseif field == FoundationClass.globalConfig.uidFieldName then
properties[property].description = 'Automatisch hinzugefügt! Wird verwendet, um individuelle Objekte innerhalb der Klasse zu identifizieren.'
properties[property].type = 'Text'
properties[property].values = ''
else
-- should never apply
properties[property].description = 'THIS should not have appeared. Please consult an admin'
properties[property].type = 'WARNING!'
properties[property].values = ' (see Module:Foundationclass, FoundationClass.static:explainDataStore() for more information)'
end
properties[property].text = ((_CFG.parameter[field] and _CFG.parameter[field].cardinality == 'list') and 'List of ' or '') .. properties[property].type .. properties[property].values ..
', <small>' .. properties[property].description .. '</small>'
end
if _CFG and _CFG.global and not _CFG.global.smwIsSubobject then
for key, value in pairs(FoundationClass.globalConfig.smwSpecialProperties) do
if FoundationClass.globalConfig.ucfirst then
property = lang:ucfirst(key)
else
property = key
end
properties[property] = { text = value, ucname }
end
end
local propertyList = {}
for key, _ in pairs(properties) do
table.insert(propertyList, key)
end
table.sort(propertyList)
local headline = 'Semantic properties used in this class:'
local content = '<ul>'
for _, property in pairs(propertyList) do
content = content .. '<li>[[Property:' .. property .. ']]: ' .. properties[property].text .. '</li>'
end
content = content .. '</ul>\n'
local attributes = {headers='plain', format='table', limit=0, searchlabel='Hier klicken für eine tabellarische Übersicht!'}
local fields = {}
for key, _ in pairs(properties) do
table.insert(fields, key)
end
table.sort(fields)
content = content .. FoundationClass.mySmwUtil.rawask({where='[[' .. FoundationClass.globalConfig.smwClassProperty .. '::' .. self.name .. ']]', fields = fields }, attributes) .. '\n'
str = str .. collapse{header = headline, content = content, left = true} .. '\n'
end
if #mw.text.trim(str) == 0 then
str = 'This template does not store any persistent data.'
end
str = '\n== Data Storage ==\n' .. str
return str
end
function FoundationClass.static:formRedlink(target, form, linktext, queryString)
_debug(self, 1, 'entering FoundationClass.static:formRedlink() to create a redlink to a form')
local target = target
local form = form
local linktext = linktext or target
local str
if target and form then
local frame = mw.getCurrentFrame()
args = { form = form }
if linktext then
args['link text'] = linktext
args['existing page link text'] = linktext
end
if queryString then
args['query string'] = queryString
end
str = frame:callParserFunction{ name='#formredlink:target=' .. target, args=args }
else
str = 'target or form missing on call to _formredlink()'
end
return str
end
function FoundationClass.static:gardeningCategoryPage()
_debug(self, 1, 'entering FoundationClass.static:gardeningCategoryPage(), from ' .. tostring(self))
local html = mw.html.create('')
if mw.title.getCurrentTitle().namespace == 14 then
local frame = mw.getCurrentFrame()
local _CFG = self.myConfiguration
local mbox = require('Module:Message box').main
html:wikitext(tostring(mbox('cmbox',
{
type = 'notice',
text = 'This category shows all elements of class ' .. self.name .. ' that have at least one error in their core data. This category must be empty at all times!'
})))
:newline()
:wikitext(tostring(mbox('cmbox',
{
type = 'content',
text = 'This category should be empty! Please tend to the articles contained herein!'
})))
-- add category if in namespace category and there has been a supercategory configured
if FoundationClass.globalConfig.gardeningCategory and #FoundationClass.globalConfig.gardeningCategory > 0 and FoundationClass.globalConfig.gardeningCategory ~= mw.title.getCurrentTitle().text then
html:wikitext('[[Category:' .. FoundationClass.globalConfig.gardeningCategory .. ']]')
end
else
error('FoundationClass:gardeningCategoryPage() must be called from namespace category!', 2)
end
return html
end
function FoundationClass.static:mwLink(target)
-- just a util method
if not target then
return ''
elseif type(target) == 'table' then
return '[[' .. mw.text.listToText(target, ']], [[', ']] und [[') .. ']]'
else
return '[[' .. target .. ']]'
end
end
function FoundationClass.static:sfGenerateForm()
_debug(self, 1, 'entering FoundationClass.static:sfGenerateForm(), from ' .. tostring(self))
local _CFG = self.myConfiguration
if not _CFG.form.enable then
return require('Module:Error').error{ message = 'Error: This class has no form page. Could not create link to form!', type = 'div' }
end
local tagStart = '{{{'
local tagEnd = '}}}'
-- 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())
:addClass('description-box')
:wikitext('<h2>' .. _CFG.global.entityTitle .. '</h2>')
:tag('p')
:wikitext(_CFG.form.headerText)
:done()
:newline()
:node(notification)
:done()
:tag('div')
:attr('id', 'wikiPreview')
:cssText('display: none; padding-bottom: 25px; margin-bottom: 25px; border-bottom: 1px solid #AAAAAA')
:done()
:newline()
-- deal with sections and free text
local sections = mw.html.create('')
local sectionlist = _CFG.form.sectionList and _CFG.form.sectionList or {}
for _, section in pairs(sectionlist) do
sections:wikitext('<h2>' .. section .. '</h2>')
:newline()
:wikitext(tagStart .. 'section|' .. section .. '|level=2|autogrow=true|cols=' .. _CFG.form.textareaAttributes.cols ..
'|rows=' .. math.max(8, 2*_CFG.form.textareaAttributes.rows) .. tagEnd)
:newline()
end
local freetext = mw.html.create('')
if _CFG.form.allowsFreeText then
freetext:wikitext(tagStart .. 'standard input|free text|autogrow=true|editor=wikieditor|cols=' .. math.min(200, 2*_CFG.form.textareaAttributes.cols) ..
'|rows=' .. math.min(48, 5*_CFG.form.textareaAttributes.rows) .. tagEnd)
:newline()
end
-- create the form buttons
local formbuttons = mw.html.create('div') -- we have to use a div here. this somehow helps the includes/SF_FormPrinter.php to correcly place the fieldset (blue box) around the form
if FoundationClass.myTableTools.inTable(_CFG.form.buttons, 'summary') then
formbuttons:tag('p')
:wikitext(tagStart .. 'standard input|summary' .. tagEnd)
:done()
:newline()
end
for _, button in pairs(_CFG.form.buttons) do
if button ~= 'summary' then
formbuttons:wikitext(tagStart .. 'standard input|' .. button .. tagEnd)
end
end
formbuttons:addClass('formbuttons')
:done()
-- assemble everything, so start the html object
local html = mw.html.create('div')
html:node(formheader)
:wikitext(tagStart .. 'for template|' .. _CFG.template.name .. '|label=' .. _CFG.global.entityTitle .. tagEnd)
:newline()
:node(self:sfGenerateFormTable())
:newline()
:wikitext("'''(*) Pflichtfeld'''<br>")
:newline()
:wikitext(tagStart .. 'end template' .. tagEnd)
:newline()
:node(sections)
:node(freetext)
:node(formbuttons)
local debugLevel = FoundationClass.globalConfig.debugLevel or self.myConfiguration.global.debugLevel
if debugLevel then
html:newline()
:newline()
:wikitext('<h2>Debug level is ' .. debugLevel .. '</h2>')
:newline()
:wikitext(ClassDebug:printLog(debugLevel))
end
local getArgs = require('Module:Arguments').getArgs
local frame = mw.getCurrentFrame()
local args = getArgs(frame)
if args.dump == "true" then
return mw.text.nowiki( tostring(html) )
end
return html
end
function FoundationClass.static:sfGenerateFormEntry()
_debug(self, 1, 'entering FoundationClass.static:sfGenerateFormEntry(), from ' .. tostring(self))
local _CFG = self.myConfiguration
local html = mw.html.create('')
local thispage = mw.title.getCurrentTitle()
html:wikitext('<h2>' .. _CFG.global.entityTitle .. '</h2>')
:newline()
:tag('p')
:wikitext(_CFG.form.teaserText)
:done()
:newline()
if _CFG.form.typeCreateLink and (mw.ustring.lower(_CFG.form.typeCreateLink) == 'forminput' or mw.ustring.lower(_CFG.form.typeCreateLink) == 'formlink') then
html:tag('p')
:wikitext(_CFG.form.createInfotext)
:wikitext(self:sfGenerateFormLink()) -- remember: self refers to a class, not an object and this method is static
:done()
:newline()
end
local getArgs = require('Module:Arguments').getArgs
local frame = mw.getCurrentFrame()
local args = getArgs(frame)
if args.dump == "true" then
return mw.text.nowiki( tostring(html) )
end
return html
end
function FoundationClass.static:sfGenerateFormInfoTag()
_debug(self, 1, 'entering FoundationClass.static:sfGenerateFormInfoTag(), from ' .. tostring(self))
local _CFG = self.myConfiguration
local frame = mw.getCurrentFrame()
if not _CFG.form.enable then
return require('Module:Error').error{ message = 'Error: This class has no form page. Could not create link to form!', type = 'div' }
end
local tagStart = '{{{'
local tagEnd = '}}}'
local queryString = ''
if (not _CFG.form.typeCreateLink or mw.ustring.lower(_CFG.form.typeCreateLink) ~= 'forminput') and _CFG.form.createLinkPageName and #_CFG.form.createLinkPageName > 0 then
local pageName = _CFG.form.createLinkPageName
if _CFG.global.namespace and mw.ustring.len(_CFG.global.namespace) > 0 and not mw.ustring.match(pageName, '^' .. _CFG.global.namespace .. ':.+$') then
pageName = _CFG.global.namespace .. ':' .. pageName
end
queryString = '|page name=' .. pageName
end
return tagStart .. 'info' .. queryString .. '|add title=' .. _CFG.form.labelCreate .. '|edit title=' .. _CFG.form.labelEdit .. tagEnd
end
function FoundationClass.static:sfGenerateFormLink()
_debug(self, 1, 'entering FoundationClass.static:sfGenerateFormInput(), from ' .. tostring(self))
local _CFG = self.myConfiguration
if not _CFG.form.enable or not _CFG.form.name or #_CFG.form.name == 0 then
return require('Module:Error').error{ message = 'Error: This class has no form page. Could not create link to form!', type = 'div' }
end
local frame = mw.getCurrentFrame()
local ret = ''
if _CFG.form.typeCreateLink and (_CFG.form.typeCreateLink == 'forminput' or _CFG.form.typeCreateLink == 'formlink') then
if _CFG.form.typeCreateLink == 'forminput' then
local args = { size = 40 }
if _CFG.form.createInputPlaceholder and mw.ustring.len(_CFG.form.createInputPlaceholder) > 0 then
args.placeholder = _CFG.form.createInputPlaceholder
end
if _CFG.form.InputQueryString and mw.ustring.len(_CFG.form.InputQueryString) > 0 then
args['query string'] = _CFG.form.InputQueryString
end
args['button text'] = _CFG.form.labelCreate
if _CFG.global.namespace and mw.ustring.len(_CFG.global.namespace) > 0 then
if args['query string'] then
args['query string'] = args['query string'] .. '&' .. 'namespace=' .. _CFG.global.namespace
else
args['query string'] = 'namespace=' .. _CFG.global.namespace
end
end
ret = frame:callParserFunction{name = '#forminput:form=' .. _CFG.form.name, args = args}
else
local args = {
tooltip = _CFG.form.createInfotext
}
if _CFG.form.createLinkQueryString and mw.ustring.len(_CFG.form.createLinkQueryString) > 0 then
args['query string'] = _CFG.form.createLinkQueryString
end
local linkType = _CFG.form.createLinkType
if linkType then
linkType = mw.ustring.lower(linkType)
if linkType ~= 'button' and linkType ~= 'post button' then
linkType = nil
end
end
args['link text'] = _CFG.form.labelCreate
args['link type'] = linkType
ret = frame:callParserFunction{name = '#formlink:form=' .. _CFG.form.name, args = args}
end
end
return ret
end
function FoundationClass.static:sfGenerateFormTable(fieldlist, tableid)
_debug(self, 1, 'entering FoundationClass.static:sfGenerateFormTable(fieldlist), from ' .. tostring(self))
local _CFG = self.myConfiguration
local fieldlist = fieldlist or _CFG.form.fieldOrder
-- set some form defaults
ClassSFfield:setDefaultSize(_CFG.form.fieldSize)
ClassSFfield:setDefaultTextAreaCols(_CFG.form.textareaAttributes.cols)
ClassSFfield:setDefaultTextAreaEditor(_CFG.form.textareaAttributes.editor)
ClassSFfield:setDefaultTextAreaRows(_CFG.form.textareaAttributes.rows)
-- now create the form table
local hidden = mw.html.create('')
local formtable = mw.html.create('table')
for _, fieldname in pairs(fieldlist) do
if _CFG.parameter[fieldname] and not self:mySfDynamicFieldAttribute(fieldname, 'disable', false) then
local field = self:sfInitField(fieldname)
if field then
if field:get('hidden') then
hidden:wikitext(field:render())
else
formtable:node(field:createTr(_CFG.parameter[fieldname].label, _CFG.parameter[fieldname].description))
end
elseif _CFG.parameter[fieldname].label and _CFG.parameter[fieldname].description and (not _CFG.parameter[fieldname].td_type or mw.ustring.len(_CFG.parameter[fieldname].td_type) == 0) then
mbox = require('Module:Message box').main('cmbox', { type = 'notice', text = "'''" .. _CFG.parameter[fieldname].label .. ":''' " .._CFG.parameter[fieldname].description})
formtable:tag('tr')
:attr('id', ClassSFfield:getShowOnSelectIdPrefix() .. mw.uri.encode(fieldname, 'WIKI'))
:tag('td')
:attr('colspan', 2)
:wikitext(tostring(mbox))
:done()
end
end
end
formtable:addClass(FoundationClass.globalConfig.formTableClass)
:css('width', 'auto')
if tableid then
formtable:attr('id', tableid)
end
formtable:done()
:node(hidden)
return formtable
end
function FoundationClass.static:sfInitField(fieldname)
_debug(self, 1, 'entering FoundationClass.static:sfInitField(fieldname) to initialize field ' .. fieldname or 'NOT SET' .. ', from ' .. tostring(self))
local _CFG = self.myConfiguration
local field
if _CFG.parameter[fieldname] and _CFG.parameter[fieldname].sf and not self:mySfDynamicFieldAttribute(fieldname, 'disable', false) then
field = ClassSFfield:new(fieldname)
if _CFG.parameter[fieldname].cardinality and _CFG.parameter[fieldname].cardinality == 'list' then
field:set('list', self:mySfDynamicFieldAttribute(fieldname, 'list', true))
local delimiter = _CFG.parameter[fieldname].sf and _CFG.parameter[fieldname].sf.delimiter or _CFG.global.delimiter
-- if we have a global or local delimiter set which is not the comma (','), provide it here automatically
if delimiter ~= ',' then
field:set('delimiter', self:mySfDynamicFieldAttribute(fieldname, 'delimiter', delimiter))
end
end
if _CFG.parameter[fieldname].severity and _CFG.parameter[fieldname].severity == 'mandatory' then
field:set('mandatory', self:mySfDynamicFieldAttribute(fieldname, 'mandatory', true))
end
if _CFG.parameter[fieldname].values then
field:set('values', self:mySfDynamicFieldAttribute(fieldname, 'values', _CFG.parameter[fieldname].values))
end
if _CFG.parameter[fieldname].sf then
for attr, val in pairs(_CFG.parameter[fieldname].sf) do
field:set(mw.ustring.gsub(attr, '_', ' '),
self:mySfDynamicFieldAttribute(fieldname, attr, val) -- remember: self refers to a class, not an object and this method is static
)
end
end
end
return field
end
function FoundationClass.static:smwGetProperty2ParameterTranslationTable()
_debug(self, 1, 'entering FoundationClass.static:smwGetProperty2ParameterTranslationTable(), from ' .. tostring(self))
if not FoundationClass.usesDataStore(self, 'smw') then
return nil
end
if not self.smwProperty2ParameterTranslationTable or FoundationClass.myTableTools.size(self.smwProperty2ParameterTranslationTable) == 0 then
local _CFG = self.myConfiguration
local translation = {}
translation[mw.ustring.gsub(FoundationClass.globalConfig.smwClassProperty, ' ', '_')] = mw.ustring.gsub(FoundationClass.globalConfig.smwClassProperty, ' ', '_')
translation[mw.ustring.gsub(FoundationClass.globalConfig.uidFieldName, ' ', '_')] = mw.ustring.gsub(FoundationClass.globalConfig.uidFieldName, ' ', '_')
for param, data in pairs(_CFG.parameter) do
if data.property_name and data.property_name:len() > 0 then
translation[mw.ustring.gsub(data.property_name, ' ', '_')] = param
end
end
self.smwProperty2ParameterTranslationTable = translation
end
return self.smwProperty2ParameterTranslationTable
end
function FoundationClass.static:templateDocumentation(arg)
_debug(self, 1, 'entering FoundationClass.static:templateDocumentation(), from ' .. tostring(self))
local _CFG = self.myConfiguration
local frame = mw.getCurrentFrame()
local arg = arg
local debugLevel = FoundationClass.globalConfig.debugLevel or self.myConfiguration.global.debugLevel
local thispage = mw.title.getCurrentTitle()
local luaBanner = require('Module:Lua banner')
-- first generate the template data for the "parameters"-section
local parameter = {}
for _, param in pairs(_CFG.form.fieldOrder) do
if _CFG.parameter[param] and _CFG.parameter[param].td_type then
table.insert(parameter, param)
end
end
local templateData = ''
if #parameter > 0 then
local globalDescription = mw.ustring.gsub(mw.ustring.gsub(_CFG.global.description, '\t', ' '), '\n', ' ')
local jsonData = '{\n\t"description": "' .. globalDescription .. '",\n' ..
'\t"params": {\n'
for _, param in pairs(parameter) do
local paramdata = _CFG.parameter[param]
jsonData = jsonData .. '\t\t"' .. param .. '": {\n'
jsonData = jsonData .. '\t\t\t"type": "' .. mw.ustring.lower(paramdata.td_type) .. '",\n'
if paramdata.td_default then
jsonData = jsonData .. '\t\t\t"default": "' .. paramdata.td_default .. '",\n'
end
if paramdata.description then
--jsonData = jsonData .. '\t\t\t"description": "' .. mw.ustring.gsub(paramdata.description, '"', '\'\'') .. '",\n'
--since 1.31 \n and \t are not allowed in json string, so replace them with a space
local paramDescription = mw.ustring.gsub(paramdata.description, '"', '\'\'')
paramDescription = mw.ustring.gsub(mw.ustring.gsub(paramDescription, '\t', ' '), '\n', ' ')
jsonData = jsonData .. '\t\t\t"description": "' .. paramDescription .. '",\n'
end
if paramdata.label then
jsonData = jsonData .. '\t\t\t"label": "' .. paramdata.label .. '",\n'
end
if paramdata.severity then
jsonData = jsonData .. '\t\t\t"suggested": ' .. ((paramdata.severity == 'suggested' or paramdata.severity == 'optional') and 'true,\n' or 'false,\n')
jsonData = jsonData .. '\t\t\t"required": ' .. ((paramdata.severity == 'mandatory' or paramdata.severity == 'required') and 'true,\n' or 'false,\n')
end
jsonData = mw.ustring.sub(jsonData, 1, -3) .. '\n\t\t},\n'
end
jsonData = mw.ustring.sub(jsonData, 1, -3) .. '\n\t}\n}'
if debugLevel then
templateData = '<pre>' .. jsonData .. '</pre>'
else
templateData = frame:extensionTag('templatedata', jsonData)
end
else
templateData = 'Dieses Template verfügt über keine nutzbaren (statischen) parameter.'
end
-- then assemble the code for the usage section
local code = '{{' .. thispage.rootText .. '\n'
for _, param in pairs(parameter) do
code = code .. '|' .. param .. '=\n'
end
code = code .. '}}\n'
-- the 'see also' links
local seeAlso = mw.html.create('')
local seeAlsoList = mw.html.create('')
if _CFG.template.templateDocumentationSeeAlso then
if type(_CFG.template.templateDocumentationSeeAlso) == 'table' then
for _, link in pairs(_CFG.template.templateDocumentationSeeAlso) do
if mw.ustring.find(link, ':', 1, true) then
link = mw.ustring.match(link, '^[^:]*:(.+)$')
end
seeAlsoList:tag('li')
:wikitext('{{[[:Template:' .. link .. '|' .. link .. ']]}}')
:done()
:newline()
end
else
local link = _CFG.global.templateDocumentationSeeAlso
if mw.ustring.find(link, ':', 1, true) then
link = mw.ustring.match(link, '^[^:]*:(.+)$')
end
seeAlsoList:tag('li')
:wikitext('{{[[:Template:' .. link .. '|' .. link .. ']]}}')
:done()
:newline()
end
seeAlso:wikitext('<h2>See also</h2>')
:newline()
:tag('ul')
:node(seeAlsoList)
:done()
:newline()
end
-- assemble
local html = mw.html.create('')
html:wikitext('<h2>Description</h2>')
:newline()
:wikitext(luaBanner._main({'Module:' .. thispage.rootText, 'Module:' .. thispage.rootText .. '/class',
'Module:' .. thispage.rootText .. '/config', 'Module:Foundationclass', 'Module:Middleclass'}))
:newline()
:wikitext(_CFG.global.description .. ((_CFG.global.category and mw.ustring.len(_CFG.global.category) > 0) and ('\n\n' .. mw.site.namespaces[14].name .. ': [[:Category:' .. _CFG.global.category .. ']]\n') or ''))
:newline()
:node(self:explainDataStore()) -- remember: self refers to a class, not an object and this method is static
:newline()
:newline()
:wikitext('<h2>Parameters</h2>')
:wikitext(templateData)
:newline()
:newline()
:wikitext('<h2>Usage</h2>')
:wikitext(frame:expandTemplate{ title = 'Code', args = {'html+handlebars', code} })
:newline()
:node(seeAlso)
:done()
if debugLevel then
html:newline()
:newline()
:wikitext('<h2>Debug level is ' .. debugLevel .. '</h2>')
:newline()
:wikitext(ClassDebug:printLog(debugLevel))
end
return html
end
function FoundationClass.static:usesDataStore(storeType)
_debug(self, 1, 'entering FoundationClass.static:usesDataStore(storeType) to do assertain, if store "' .. storeType .. '" is used, from ' .. tostring(self))
local _CFG = self.myConfiguration
return (FoundationClass.globalConfig.dataStore == 'both' or FoundationClass.globalConfig.dataStore == mw.ustring.lower(storeType)) and
(mw.ustring.lower(storeType) == 'smw' and _CFG.global.smwUseStorage) or (mw.ustring.lower(storeType) == 'cargo' and _CFG.global.cargoTable and #_CFG.global.cargoTable > 0)
end
function FoundationClass.static:staticMethod(var)
_debug(self, 1, 'entering FoundationClass.static:staticMethod() to do something, from ' .. tostring(self))
end
-- **************** declaration of private methods
local _amIPlausible = function (self)
return (#_private[self].errors == 0)
end
_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 _plausibilityTest = function (self, args)
_debug(self, 1, 'entering FoundationClass._plausibilityTest(self, args)')
local _CFG = self.class.myConfiguration
local args = args
-- first see, whether we are in the correct namespace (that is, if we are not initialzed from a datastore)
if not _private[self].superHandler and not _private[self].loadedDataFromDataStore and _CFG.global.namespace and #_CFG.global.namespace > 0 and (_CFG.global.namespace ~= mw.title.getCurrentTitle().nsText) then
self:addError("Diese Seite befindet sich in einem ungültigen Namesraum. Eingestellt ist ''" .. _CFG.global.namespace .. "'', festgestellt wurde: " .. ((mw.title.getCurrentTitle().nsText and #mw.title.getCurrentTitle().nsText > 0) and mw.title.getCurrentTitle().nsText or 'keiner'))
end
-- prepare for the "show on select"-complex
-- motivation:
-- when you have a selector with a show on select field, sf shows some fields dynamically. sf even lets you set these dynamically shown fields
-- to mandatory but checks for this only, if the field is shown.
-- problem: so with this in mind, it is possible, that we have a mandatory field in our configuration with no value, but still be pausible
-- since it only has to submit a value, if it is shown. but in the case it is shown, it has to submit a value
-- what we do: build a table fieldnameToCheck : { showSelectorFieldname : valuetoshow }
-- btw: this table fieldnameToCheck should only containe one element. if the programmer has the field "fieldnameToCheck" put in more than
-- one show on select, the resulting form is erratic.
local showOnSelectComplex = {}
for param, paramdata in pairs(_CFG.parameter) do
if not self.class.mySfDynamicFieldAttribute(self.class, param, 'disable', false) and paramdata.sf and paramdata.sf.show_on_select then
local sos = self.class.mySfDynamicFieldAttribute(self.class, param, 'show_on_select', paramdata.sf.show_on_select)
_debug(self, 3, ' got this in return: ' .. (type(sos) == 'string' and tostring(sos) or type(sos)))
if type(sos) ~= 'table' then
sos = tostring(sos)
if not showOnSelectComplex[sos] then
showOnSelectComplex[sos] = {}
end
-- this being a string makes sense only if input type is checkbox. we leave the responsibility to the programmer, though
showOnSelectComplex[sos][param] = FoundationClass.globalConfig.selectedCheckboxSubmitValue
else
-- assume type table
for selectedValue, showFields in pairs(sos) do
if type(showFields) ~= 'table' then
showFields = tostring(showFields)
if not showOnSelectComplex[showFields] then
showOnSelectComplex[showFields] = {}
end
showOnSelectComplex[showFields][param] = selectedValue
else
-- one last iteration
for _, showField in pairs(showFields) do
showFields = tostring(showFields)
if not showOnSelectComplex[showField] then
showOnSelectComplex[showField] = {}
end
showOnSelectComplex[showField][param] = selectedValue
end
end
end
end
end
end
_debug(self, 3, ' have this showOnSelectComplex: ' .. FoundationClass.myTableTools.printTable(showOnSelectComplex))
-- now do the plausibility test
for param, paramdata in pairs(_CFG.parameter) do
if not self.class.mySfDynamicFieldAttribute(self.class, param, 'disable', false) and paramdata.sf then
if not self.class.mySfDynamicFieldAttribute(self.class, param, 'hidden', false) then
-- it is not set to hidden, so evaluate
if args[param] and (type(args[param]) ~= 'string' or mw.ustring.len(args[param]) > 0) then
-- first, see if it's there
local value = args[param]
local values
if paramdata.values then
values = self.class.mySfDynamicFieldAttribute(self.class, param, 'values', paramdata.values)
end
if type(value) == 'string' and mw.ustring.match(value, '^[0-9]+$') then
-- because argument data coming form a parameter and not from database means a number is displayed as a string
-- problem: if we store an only numbers containing entry in values, this will fail, i.e. paramdate.values = {'0', '123'} can never work
value = tonumber(value)
end
if paramdata.cardinality == 'single' then
if values and not FoundationClass.myTableTools.inTable(values, value) and ((paramdata.sf.input_type ~= 'combobox' and paramdata.sf.input_type ~= 'tokens') or paramdata.sf.existing_values_only) then
-- 'values'-restriction given but value given not in values
-- only loophole being tokens or combobox and NOT existring_values_only
self:addError("Ungültiger Wert für parameter ''" .. param .. "'' festgestellt: " .. mw.text.encode(tostring(value)))
end
elseif values and ((paramdata.sf.input_type ~= 'combobox' and paramdata.sf.input_type ~= 'tokens') or paramdata.sf.existing_values_only) then
-- multivaluefield and 'values'-restriction given
-- only loophole being tokens or combobox and NOT existring_values_only
local vals = {}
if type(args[param]) == 'table' then
-- which can be, if we are initializing by data
vals = args[param]
else
for fragment in mw.text.gsplit(args[param], _CFG.parameter[param].sf and _CFG.parameter[param].sf.delimiter or _CFG.global.delimiter, true) do
if fragment and mw.ustring.len(mw.text.trim(fragment)) > 0 then
fragment = mw.text.trim(fragment)
if mw.ustring.match(fragment, '^[0-9]+$') then
fragment = tonumber(fragment)
end
table.insert(vals, fragment)
end
end
end
for _, v in pairs(vals) do
if not FoundationClass.myTableTools.inTable(values, v) then
self:addError("Ungültiger Wert für parameter ''" .. param .. "'' festgestellt: " .. mw.text.encode(v))
end
end
end
elseif FoundationClass.myTableTools.inTable(_CFG.form.fieldOrder, param) and paramdata.severity == 'mandatory' then
-- param not found but should be (since it is a form param) and it is also marked as mandatory and not set to hidden -->
-- before we assume error lets check for the one loophole: field could be part of a "show on select", thus being mandatory but not shown
local issueError = true
if showOnSelectComplex[param] then
-- yeah, the field is part of a "show on select". we only issue an error, if its selector indicates a show
issueError = false
for fieldname, showValue in pairs(showOnSelectComplex[param]) do
if tostring(args[fieldname]) == tostring(showValue) then
-- so it is shown and therefore should contain a value
issueError = true
end
end
end
if issueError then
self:addError("Pflichtfeld ''" .. param .. "'' fehlt!")
end
end
else
_debug(self, 1, ' field ' .. param .. ' is set to hidden. Not processing!')
end
else
_debug(self, 1, ' field ' .. param .. ' is disabled or no sf-table given. Not processing!')
end
end
return _amIPlausible(self)
end
local _privateMethod = function (self)
_debug(self, 1, 'entering FoundationClass._privateMethod() to do something')
end
-- **************** declaration of public methods
function FoundationClass:addCategory(category)
_debug(self, 1, 'entering FoundationClass:addCategory(category) with category ' .. (category and tostring(category) or 'EMPTY') .. ', from ' .. tostring(self))
local category = category
if category and mw.ustring.len(category) > 0 then
if _private[self].superHandler then
_debug(self, 3, ' found handler ' .. tostring(_private[self].superHandler) .. ', so we are probably not on the right page to lease a category. omitting categorizing into category "' .. category .. '"')
--_debug(self, 3, ' refering category to handler ' .. tostring(_private[self].superHandler))
--_private[self].superHandler:addCategory(category)
else
table.insert(_private[self].categories, category)
end
end
return true
end
function FoundationClass:addError(errortext)
_debug(self, 1, 'entering FoundationClass:addError(errortext), from ' .. tostring(self))
_debug(self, 3, ' with errortext ' .. tostring(errortext))
local errortext = errortext
if errortext and mw.ustring.len(errortext) > 0 then
if _private[self].superHandler then
_debug(self, 3, ' refering error to handler ' .. tostring(_private[self].superHandler))
errortext = (self:getUid() and (self:getUid() .. ': ') or '') .. errortext
_private[self].superHandler:addError(errortext)
end
-- have to store it myself, too. otherwise, I would always be plausible...
table.insert(_private[self].errors, errortext)
end
return true
end
function FoundationClass:addInfobox()
_debug(self, 1, 'entering FoundationClass:addInfobox(), from ' .. tostring(self))
return false
end
function FoundationClass:addOutput(content)
_debug(self, 1, 'entering FoundationClass:addOutput(), from ' .. tostring(self))
if type(content) == 'table' then
_private[self].output:node(content)
return true
elseif mw.ustring.len(tostring(content)) > 0 then
_private[self].output:wikitext(content)
return true
end
return false
end
function FoundationClass:addPageBody()
_debug(self, 1, 'entering FoundationClass:addPageBody(), from ' .. tostring(self))
_debug(self, 2, ' rendering errors and warnings and adding them to output')
local frame = mw.getCurrentFrame()
_private[self].output:node(self:renderErrors())
:node(self:renderWarnings())
if self:goodToGo() then
_private[self].output:wikitext('Please implement method <code>addPageBody()</code> to display page content!')
return true
end
return false
end
function FoundationClass:addError(errortext)
_debug(self, 1, 'entering FoundationClass:addError(errortext), from ' .. tostring(self))
_debug(self, 3, ' with errortext ' .. tostring(errortext))
local errortext = errortext
if errortext and mw.ustring.len(errortext) > 0 then
if _private[self].superHandler then
_debug(self, 3, ' refering error to handler ' .. tostring(_private[self].superHandler))
errortext = (self:getUid() and (self:getUid() .. ': ') or '') .. errortext
_private[self].superHandler:addError(errortext)
end
-- have to store it myself, too. otherwise, I would always be plausible...
table.insert(_private[self].errors, errortext)
end
return true
end
function FoundationClass:addWarning(warning)
_debug(self, 1, 'entering FoundationClass:addWarning(errortext), from ' .. tostring(self))
_debug(self, 3, ' with warning ' .. tostring(warning))
local warning = warning
if warning and mw.ustring.len(warning) > 0 then
if _private[self].superHandler then
_debug(self, 3, ' refering error to handler ' .. tostring(_private[self].superHandler))
warning = (self:getUid() and (self:getUid() .. ': ') or '') .. warning
_private[self].superHandler:addError(warning)
end
-- have to store it myself, too. otherwise, I would always be plausible...
table.insert(_private[self].warnings, warning)
end
return true
end
function FoundationClass:getCoreData()
_debug(self, 1, 'entering FoundationClass:getCoreData(), from ' .. tostring(self))
return _private[self].coreData
end
function FoundationClass:getUid()
_debug(self, 1, 'entering FoundationClass:getUid(), from ' .. tostring(self))
return _private[self].uid
end
function FoundationClass:goodToGo()
_debug(self, 1, 'entering FoundationClass:goodToGo(), from ' .. tostring(self))
return _amIPlausible(self) and _private[self].initialized
end
function FoundationClass:initFromArgs(args)
_debug(self, 1, 'entering FoundationClass:initFromArgs(args), from ' .. tostring(self))
local _CFG = self.class.myConfiguration
local args = args
if not args or type(args) ~= 'table' then
local getArgs = require('Module:Arguments').getArgs
local frame = mw.getCurrentFrame()
args = getArgs(frame)
end
if not _private[self].loadedDataMyself then
-- if we didn't load our data ourselves, assume that it comes from the store and assume, it's plausible
_plausibilityTest(self, args)
self:myPlausibilityTest(args)
end
if _amIPlausible(self) then
-- first set my uid
if not _private[self].coreData[FoundationClass.globalConfig.uidFieldName] then
_private[self].coreData[FoundationClass.globalConfig.uidFieldName] = self:getUid()
end
-- if I use smw as store, also set my class
if FoundationClass.usesDataStore(self.class, 'smw') and not _private[self].coreData[FoundationClass.globalConfig.smwClassProperty] then
_private[self].coreData[FoundationClass.globalConfig.smwClassProperty] = self.class.name
end
-- get the data from args into _private[self].coreData
for param, paramdata in pairs(_CFG.parameter) do
if paramdata.cardinality == 'single' then
_private[self].coreData[param] = args[param]
else
-- multivaluefield and given
if type(args[param]) == 'table' then
_private[self].coreData[param] = args[param]
else
local values
if args[param] then
values = {}
for fragment in mw.text.gsplit(args[param], _CFG.parameter[param].sf and _CFG.parameter[param].sf.delimiter or _CFG.global.delimiter, true) do
if fragment and mw.ustring.len(mw.text.trim(fragment)) > 0 then
table.insert(values, mw.text.trim(fragment))
end
end
end
_private[self].coreData[param] = values
end
end
end
-- here we do some individual argument processing
_debug(self, 3, ' calling self:myArgumentProcessing(_private[self].coreData)')
_private[self].coreData = self:myArgumentProcessing(_private[self].coreData)
_debug(self, 3, ' object initialized with data:<pre>' .. FoundationClass.myTableTools.printTable(_private[self].coreData) .. '</pre>')
--this can cause fatal error, if coreData contains to much data, for instance references to title-objects
_private[self].initialized = true
end
return _private[self].initialized
end
function FoundationClass:initFromData(data)
-- this takes data that comes from a data store and initializes itself with it
-- if we use data store smw, this makes a conversion from propery indexed data to parameter indexed data
-- if we use both data stores, data from cargo has precedence
_debug(self, 1, 'entering FoundationClass:initFromData() to do something, from ' .. tostring(self))
_debug(self, 3, ' got data:<pre>' .. FoundationClass.myTableTools.printTable(data) .. '</pre>')
local data = data
_private[self].loadedDataFromDataStore = true
if FoundationClass.usesDataStore(self.class, 'smw') then -- if we have store cargo, we take the dat as is.
-- transform the data array from { property_name : value } to { paramter : value }
local properties = FoundationClass.smwGetProperty2ParameterTranslationTable(self.class)
for property, param in pairs(properties) do
local property_ = property
local property = mw.ustring.gsub(property_, '_', ' ')
if data[property_] and not data[param] then
data[param] = data[property_]
data[property_] = nil
end
if data[property] and not data[param] then
data[param] = data[property]
data[property] = nil
end
end
end
data = self:myDataAdjustments(data)
if FoundationClass.myTableTools.size(data) > 0 then
return self:initFromArgs(data)
else
return false
end
end
function FoundationClass:initMyself(uid)
_debug(self, 1, 'entering FoundationClass:initMyself() to fetch my own data from datastore, from ' .. tostring(self))
local _CFG = self.class.myConfiguration
local uid = uid or self:getUid()
local myData = {}
if uid and FoundationClass.usesDataStore(self.class, 'cargo') then
_debug(self, 2, ' using datastore \'cargo\' with uid: ' .. uid)
-- build the query
local query = { tables = _CFG.global.cargoTable, fields = {}, where = ''}
local wherefield = FoundationClass.globalConfig.uidFieldName
local wherefor = '"' .. uid .. '"'
query.where = wherefield .. '=' .. wherefor
local declaration = FoundationClass.cargoGenerateTableStructure(self.class)
for field, _ in pairs(declaration) do
table.insert(query.fields, field)
end
local result = FoundationClass.myCargoUtil.query(query, {limit = 1})
if result and result[1] and type(result[1]) == 'table' and FoundationClass.myTableTools.size(result[1]) > 0 then
-- now we have data, call initFromData()
_debug(self, 2, ' Got data from cargo query, storing it')
myData = result[1]
elseif not FoundationClass.usesDataStore(self.class, 'smw') then
_debug(self, 2, ' Could not initialize by myself: Cargo query for \'' .. wherefield .. '=' .. wherefor .. '\' in table \'' .. _CFG.global.cargoTable .. '\' did not yield any result.')
_debug(self, 3, ' Query was<pre>' .. FoundationClass.myTableTools.printTable(query) .. '</pre>')
self:addError('Could not initialize by myself: Cargo query for \'' .. wherefield .. '=' .. wherefor .. '\' in table \'' .. _CFG.global.cargoTable .. '\' did not yield any result.')
end
end
if uid and FoundationClass.usesDataStore(self.class, 'smw') then
_debug(self, 2, ' using datastore \'smw\' with uid: ' .. uid)
-- build the query
local query = { select = {}, fields = {}, where = ''}
query.select[FoundationClass.globalConfig.smwClassProperty] = self.class.name
local wherefield = FoundationClass.globalConfig.uidFieldName
local wherefor = '"' .. uid .. '"'
query.select[wherefield] = wherefor
local properties = FoundationClass.smwGetProperty2ParameterTranslationTable(self.class)
for property, _ in pairs(properties) do
table.insert(query.fields, property)
end
local result = FoundationClass.mySmwUtil.query(query, {limit = 1})
if result and result[1] and type(result[1]) == 'table' and FoundationClass.myTableTools.size(result[1]) > 0 then
for property, smwdata in pairs(result[1]) do
if not myData[property] then
myData[property] = smwdata
end
end
end
end
if not FoundationClass.myTableTools.size(myData) then
if not uid then
_debug(self, 2, ' Could not initialize by myself: No valid uid was provided. Was type \'' .. type(uid) .. '.')
self:addError('Could not initialize by myself: No valid uid was provided. Was type \'' .. type(uid) .. '.')
elseif FoundationClass.usesDataStore(self.class, 'both') then
_debug(self, 2, ' Could not initialize by myself: Neither Cargo nor Smw provided any data. Was looking for \'' .. FoundationClass.globalConfig.uidFieldName .. ' with uid ' ..
uid .. ' in class ' .. self.class.name .. '.')
self:addError('Could not initialize by myself: Neither Cargo nor Smw provided any data. Was looking for \'' .. FoundationClass.globalConfig.uidFieldName .. ' with uid ' ..
uid .. ' in class ' .. self.class.name .. '.')
elseif FoundationClass.usesDataStore(self.class, 'cargo') then
_debug(self, 2, ' Could not initialize by myself: Cargo query for \'' .. FoundationClass.globalConfig.uidFieldName .. '=' .. uid .. '\' did not yield any result.')
self:addError('Could not initialize by myself: Cargo query for \'' .. FoundationClass.globalConfig.uidFieldName .. '=' .. uid .. '\' did not yield any result.')
else
_debug(self, 2, ' Could not initialize by myself: Smw query in class \'' .. self.class.name .. '\' for \'' .. FoundationClass.globalConfig.uidFieldName .. '=' .. uid .. '\' did not yield any result.')
self:addError('Could not initialize by myself: Smw query in class \'' .. self.class.name .. '\' for \'' .. FoundationClass.globalConfig.uidFieldName .. '=' .. uid .. '\' did not yield any result.')
end
else
-- now we have data, call initFromData()
_debug(self, 2, ' Got data from query, calling self:initFromData(myData)')
_private[self].loadedDataMyself = true
return self:initFromData(myData)
end
return false
end
function FoundationClass:render()
_debug(self, 1, 'entering FoundationClass:render(), from ' .. tostring(self))
self:addOutput(self:renderCategories())
local ret = tostring(_private[self].output)
local debugLevel = FoundationClass.globalConfig.debugLevel or self.class.myConfiguration.global.debugLevel
if debugLevel then
ret = ret .. '\n\n' .. '<h2>Debug level is ' .. debugLevel .. '</h2>\n' .. ClassDebug:printLog(debugLevel)
end
return ret
end
function FoundationClass:renderCategories()
_debug(self, 1, 'entering FoundationClass:renderCategories(), from ' .. tostring(self))
node = mw.html.create('')
if _private[self].categories and (#_private[self].categories > 0) and (self:getUid() == mw.title.getCurrentTitle().prefixedText) then
for _, category in pairs(_private[self].categories) do
node:wikitext('[[Category:' .. category .. ']]')
end
end
return node
end
function FoundationClass:renderErrors()
_debug(self, 1, 'entering FoundationClass:renderErrors(), from ' .. tostring(self))
local _CFG = self.class.myConfiguration
local error = require('Module:Error').error
node = mw.html.create('')
if #_private[self].errors > 0 then
if _CFG.global.gardeningCategory and mw.title.getCurrentTitle().namespace ~= 10 then
-- we have errors and we are currently not in template namespace. place article in gardening category
self:addCategory(_CFG.global.gardeningCategory)
end
node:wikitext('<h2 style="font-weight:bold;background-color:light-red;color:red">Fehler</h2>')
for _, str in pairs(_private[self].errors) do
node:wikitext(error{ message=str, tag='div'})
end
end
return node
end
function FoundationClass:renderWarnings()
_debug(self, 1, 'entering FoundationClass:renderWarnings(), from ' .. tostring(self))
node = mw.html.create('')
if #_private[self].warnings > 0 then
node:wikitext('<h2>Hinweise</h2>')
local lis = mw.html.create('')
for _, str in pairs(_private[self].warnings) do
lis:tag('li')
:wikitext(str)
:done()
end
node:tag('ul')
:node(lis)
end
return node
end
function FoundationClass:setSortkey(sortkey)
_debug(self, 1, 'entering FoundationClass:setSortkey(sortkey) with sortkey ' .. (sortkey and tostring(sortkey) or 'EMPTY') .. ', from ' .. tostring(self))
local sortkey = sortkey
if sortkey and mw.ustring.len(sortkey) > 0 then
if not _private[self].superHandler then
local frame = mw.getCurrentFrame()
frame:callParserFunction('DEFAULTSORT:' .. sortkey, 'noerror')
-- foobar. but viable workarount until new ipso is running
if mw.ext and mw.ext.displaytitle then
mw.ext.displaytitle.set(sortkey)
end
end
end
return true
end
function FoundationClass:setUid(uid)
_debug(self, 1, 'entering FoundationClass:setUid(uid), from ' .. tostring(self))
if uid and (type(uid) == 'table' or type(uid) == 'integer') then
_private[self].uid = uid
return true
end
return false
end
function FoundationClass:storeData()
_debug(self, 1, 'entering FoundationClass:storeData(), from ' .. tostring(self))
local _CFG = self.class.myConfiguration
local thisPage = mw.title.getCurrentTitle()
local ret = false
local lang = mw.language.getContentLanguage()
if FoundationClass.usesDataStore(self.class, 'cargo') and thisPage.namespace == 10 and lang:ucfirst(thisPage.text) == lang:ucfirst(_CFG.template.name) then
-- we must check for cargo data store first, because declaration must take place on namespace template where we have no data...
_debug(self, 2, ' proceeding (cargo data store detected, poceeding to declare)')
-- declaration of the cargo-table
local declaration = self.class.cargoGenerateTableStructure(self.class)
-- remember: self refers to an object not an class(!!!!) and this method is a static, so we have to call it directly and not with the colon operator
local ret = FoundationClass.myCargoUtil.declare(_CFG.global.cargoTable, declaration)
if mw.ustring.len(ret) > 0 then
self:addWarning(ret)
end
end
if _amIPlausible(self) and _private[self].initialized and not _private[self].loadedDataMyself then
_debug(self, 2, ' proceeding (plausible, initialized and got data from extern)')
if FoundationClass.usesDataStore(self.class, 'cargo') then
-- now store the cargo data
local stash = {}
local declaration = FoundationClass.cargoGenerateTableStructure(self.class)
for field, _ in pairs(declaration) do
if _private[self].coreData[field] then
if type(_private[self].coreData[field]) == 'table' then
stash[field] = table.concat(_private[self].coreData[field], (_CFG.parameter[field].sf and _CFG.parameter[field].sf.delimiter or _CFG.global.delimiter))
else
stash[field] = _private[self].coreData[field]
end
end
end
-- individual adjustments
stash = self:myStashAdjustments(stash, 'cargo')
-- we dont want myStashAdjustments add any fields that is not a cargo field (in case it accidently added a field, that was meant for smw)
if stash and type(stash) == 'table' then
for field, _ in pairs(stash) do
if not declaration[field] then
stash[field] = nil
end
end
end
if stash and FoundationClass.myTableTools.size(stash) > 0 then
local result = FoundationClass.myCargoUtil.store(_CFG.global.cargoTable, stash)
if mw.ustring.len(result) > 0 then
self:addWarning(result)
end
ret = true
else
ret = false
end
end -- of if FoundationClass.usesDataStore(self.class, 'cargo') then
if FoundationClass.usesDataStore(self.class, 'smw') then
-- now store smw properties
local stash = {}
local properties = FoundationClass.smwGetProperty2ParameterTranslationTable(self.class)
-- first get all parameter and their data in stash
for _, parameter in pairs(properties) do
if _private[self].coreData[parameter] then
stash[parameter] = _private[self].coreData[parameter]
end
end
-- individual adjustments, still with parameter as keys
stash = self:myStashAdjustments(stash, 'smw')
-- now convert the stash keys from parameter to property
-- that also takes care of any fields, that were accidently added for a cargo store but have no property assigned
if stash and FoundationClass.myTableTools.size(stash) > 0 then
local stash_new = {}
for property, parameter in pairs(properties) do
stash_new[property] = stash[parameter]
end
stash = stash_new
end
if stash and FoundationClass.myTableTools.size(stash) > 0 then
local result
if _CFG.global.smwIsSubobject then
result = FoundationClass.mySmwUtil.subobject(stash, self:getUid())
else
result = FoundationClass.mySmwUtil.set(stash)
end
if mw.ustring.len(result) > 0 then
self:addWarning(result)
end
ret = true
else
ret = false
end
end -- of if FoundationClass.usesDataStore(self.class, 'smw') then
end
return ret
end
function FoundationClass:method()
_debug(self, 1, 'entering FoundationClass:method() to do something, from ' .. tostring(self))
return true
end
-- these are special methods, so they are placed here. they are kind of abstract-ish in a way, that they thow a lua exception
-- if you don't have them implemented on your inherited class
function FoundationClass.static:mySfDynamicFieldAttribute(fieldname, attribute, value)
_debug(self, 1, 'ERROR: entering FoundationClass.static:mySfDynamicFieldAttribute(fieldname, attribute, value), from ' .. tostring(self))
error('You have to implement ' .. tostring(self.class) .. '.static:mySfDynamicFieldAttribute(fieldname, attribute, value). See Module:Foundationclass for documentation on this! (calling from ' .. tostring(self) .. ')', 1)
end
function FoundationClass:myArgumentProcessing(coreData)
_debug(self, 1, 'ERROR: entering FoundationClass:myArgumentProcessing(coreData), from ' .. tostring(self))
error('You have to implement ' .. tostring(self.class) .. ':myArgumentProcessing(coreData). See Module:Foundationclass for documentation on this! (calling from ' .. tostring(self) .. ')', 1)
end
function FoundationClass:myDataAdjustments(data)
_debug(self, 1, 'ERROR: entering FoundationClass:myDataAdjustments(data), from ' .. tostring(self))
error('You have to implement ' .. tostring(self.class) .. ':myDataAdjustments(coreData). See Module:Foundationclass for documentation on this! (calling from ' .. tostring(self) .. ')', 1)
end
function FoundationClass:myPlausibilityTest(args)
_debug(self, 1, 'ERROR: entering FoundationClass:myPlausibilityTest(args), from ' .. tostring(self))
error('You have to implement ' .. tostring(self.class) .. ':myPlausibilityTest(args). See Module:Foundationclass for documentation on this! (calling from ' .. tostring(self) .. ')', 1)
end
function FoundationClass:myStashAdjustments(stash)
_debug(self, 1, 'ERROR: entering FoundationClass:myStashAdjustments(stash), from ' .. tostring(self))
error('You have to implement ClassName:myStashAdjustments(stash). See Module:Foundationclass for documentation on this! (calling from ' .. tostring(self) .. ')', 1)
end
return FoundationClass