Modul:SFfield/class

This is [[MediaWiki:Tagline]]. Set to <code>display:none</code> by chameleon skin.
< Modul:SFfield
Version vom 29. Februar 2016, 09:49 Uhr von imported>Oetterer (fixed an error with show on select for input_type checkbox)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu:Navigation, Suche
Documentation icon Module documentation[view] [edit] [history] [purge]

This is a Class Module. It implements a class in Lua using Module:Middleclass. This class provides methods for defining and creating Semantic Forms field-tags.

Usage

local classSFfield = require('Module:SFfield/class')
local field = classSFfield:new('name')
classSFfield:setDefaultSize(80)
field:set('input type', 'tokens')
field:set('list')
field:set('mandatory', true)
field:set('property', 'goes by name')
local output = field:render()


This class provides meththods for creating field tags to use in Semantic Forms. It is fast, easy to use and does some minor plausibility checks:

  • it only allows existing attributes to be set
  • it only allows existing "input type"s to be set

Concerniny "existing": The module knows all input types from Semantic Forms and Semantic Forms Inputs. All valid entries are defined in Configuration Data

Besides some debugging, the class does not print any error reports or development output. See Module:Debug/class for more information on how to access debug output.

There is are some static properties to default certain values when not set individually:

  • size for "tokens", "combobox", "text", ... fields
  • autogrow for "textarea" and "textarea with autocomplete"
  • cols for "textarea" and "textarea with autocomplete"
  • editor for "textarea" and "textarea with autocomplete"
  • rows for "textarea" and "textarea with autocomplete"

They are initialized in the class but can be overwritten by static methods.

Besides simple field-tags there is also a method with which you can have your tags enclosed in the typical tr-th-td structure to easily create a form table. You can also add a tooltip. If mandatory was set, it also prints a small asterix next to the label.

local node = field:createTr('Name', 'This field holds the full name, the person is known for.')


Constructor

new(fieldname)

Creates a new Object for class Name.

fieldname
string, mandatory
holds the name of the field; in SF-terms: this transforms to the parameter name of the referenced template
return
object, of class SFfield

Methods

Public methods

__tostring()

Returns a string representation of the field by calling render().

return
string, representation of itself

createTr(label, tooltip)

Uncloses the rendered field in a tr-th-td structure that can directly be used in an html formtable. When mandatory is set in the field, it adds an asterix after the label. A tooltip can also be provided.

label
string, mandatory
what var is for
tooltip
string, optional
explanatory text that helps the user fill this field
return
object of class mw.html, one table row (tr) containing an th with the labal (and tooltip) and a tr with the rendered field.

get(attribute)

Returns the value for the attribute.

attribute
string, mandatory
the name of the attribute, you wish to get
return
vaiable, the value for the attribute

render()

Renders the object and creates a semantic forms field already htmlentities-encoded (so it can be used directly in the form)

return
string, rendered and encoded field-tag

set(attribute, value)

Sets an attribute for the field. Checks attribute for validity before setting it. In case of attribute input type checks value for validity, too. When setting simple attributes like list or mandatory, omitting value is interpreted as adding the attribute. If you at anytime wish to remove such an attribute, you have to set value to false.

attribute
string, mandatory
the name of the attribute, you wish to set
value
(string

static methods

SFfield:getShowOnSelectIdPrefix()

Returns the static property used as prefix in the html-id attribute that serves as identifier for the show on select mechanism. When using the method createTr, you probably have no need for this.

return
string, prefix for the value of the id attribute

SFfield:setDefaultSize(val)

Sets the default size for text-like fields (tokens, combobox, text, ...). The default only applies, if this attribute is not set individually in a textarea field.

val
integer, mandatory
default size in characters for input fields
return
boolean, whether setting was successful or not

SFfield:setDefaultTextAreaAutogrow(val)

Sets the default autogrow-behaviour of textarea-type fields. The default only applies, if this attribute is not set individually in a textarea field.

val
boolean, mandatory
disables or enables default value for autogrow in textarea fields.
return
boolean, whether setting was successful or not

SFfield:setDefaultTextAreaCols(val)

Sets the default for number of columns for textarea-type fields. The default only applies, if this attribute is not set individually in a textarea field.

val
integer, mandatory
default for number of columns for the textarea fields.
return
boolean, whether setting was successful or not

SFfield:setDefaultTextAreaEditor(val)

Sets the default editor of textarea-type fields. The default only applies, if this attribute is not set individually in a textarea field.

val
string

SFfield:setDefaultTextAreaRows(val)

Sets the default for number of rows for textarea-type fields. The default only applies, if this attribute is not set individually in a textarea field.

val
integer, mandatory
default for number of rows for the textarea fields.
return
boolean, whether setting was successful or not

SFfield:setShowOnSelectIdPrefix(val)

Sets the default prefix for the html id-attribute used in the show on select complex.

val
string, mandatory
the static property will be set to this value
return
boolean, whether setting was successful or not

private methods

_processAttributes(self)

Converts the private property attributes (which holds all attributes for this field) from an array {attribute = value, ...} table to a sequence {'attriubte=value', ..} table. Also:

  • adds the attribute 'input type' if missing to a default, depending on setting of attribute 'list'
  • sets defaults (if applicable) for
    • size
    • autogrow
    • cols
    • editor
    • rows
  • does the 'show on select' table-conversion if necessary

self
object, me
var
type(string

Properties

static

_CFG
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!
  • global, table, global behaviour settings
  • validAttributes, table, a sequence of all valid attributes
  • validInputTypes, table, a sequence of all valid values for attribute "input type"
_TT
table, instance of Module:TableTools
_defaultListInputType
string, default value for attribute "input type" if unset. applies if "list" is set
_defaultSingleInputType
string, default value for attribute "input type" if unset. applies if "list" is not set
_defaultSize
integer, default size for most input types if not set
_defaultTextAreaAttributes
table, holds some default attribte values for textarea fields if unset
_mandatoryMarker
string, createTr uses this marker to depict mandatory fields
_showOnSelectIdPrefix
string, prefix string for html id-attributes for the show on select complex (e.g.: '")

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.

attributes
table, holds "my" attributes
dbg
object, my instance of Module:Debug/class for debugging purposes
name
string, name of this field

Configuration Data

This class holds it control data in Module:SFfield/config.

local class = require('Module:Middleclass').class
local classSFfield = class('SFfield')
local classDebug = require('Module:Debug/class')

-- ****************************************************************
-- *                          properties                          *
-- ****************************************************************
 
-- **************** initialization of table for private properties
local _private = setmetatable({}, {__mode = "k"})   -- weak table storing all private attributes
 
-- **************** declaration of private static properties
-- local _PROPERTY = require( 'Module:' )
local _CFG = mw.loadData( 'Module:SFfield/config' )
local _TT = require( 'Module:TableTools' )
local _defaultListInputType = 'tokens'
local _defaultSingleInputType = 'combobox'
local _defaultSize = 40
local _defaultTextAreaAttributes = {
	autogrow = true,
	cols = 80,
	editor = 'wikieditor',
	rows = 12
}
local _mandatoryMarker = '<sup>*</sup>'
local _showOnSelectIdPrefix = _CFG.global.showOnSelectIdPrefix

-- ***************************************************************
-- *                           methods                           *
-- ***************************************************************
 
-- **************** declaration of static methods
function classSFfield:initialize(fieldname)	-- constructor
	local fieldname = fieldname or 'no fieldname specified'
	local dbg = classDebug:new('SFfield_field_' .. fieldname)
	-- initialize all private properties
	_private[self] = {
		attributes = {},
		dbg = dbg,
		name = fieldname,
	}
	_private[self].dbg:log(11, 'Initializing field "' .. fieldname ..'"')
end	-- end of function classSFfield:initialize(fieldname)

function classSFfield.static:getShowOnSelectIdPrefix()
	return _showOnSelectIdPrefix
end

function classSFfield.static:setDefaultSize(val)
	if val and type(val) == 'number' then
		_defaultSize = val
		classDebug:log(13, ' classSFfield.static:setDefaultSize(): Setting _defaultSize to ' .. val, tostring(self) .. '.static')
		return true
	end
	return false
end

function classSFfield.static:setDefaultTextAreaAutogrow(val)
	if val and type(val) == 'boolean' then
		_defaultTextAreaAttributes.autogrow = val
		classDebug:log(13, 'classSFfield.static:setDefaultTextAreaAutogrow(): Setting _defaultTextAreaAttributes.autogrow to ' .. val,
			tostring(self) .. '.static')
		return true
	end
	return false
end

function classSFfield.static:setDefaultTextAreaCols(val)
	if val and type(val) == 'number' then
		_defaultTextAreaAttributes.cols = val
		classDebug:log(13, 'classSFfield.static:setDefaultTextAreaCols(): Setting _defaultTextAreaAttributes.cols to ' .. val,
			tostring(self) .. '.static')
		return true
	end
	return false
end

function classSFfield.static:setDefaultTextAreaEditor(val)
	if type(val) == 'boolean' then
		if val then
			_defaultTextAreaAttributes.editor = 'wikieditor'
			classDebug:log(13, 'classSFfield.static:setDefaultTextAreaEditor(): Setting _defaultTextAreaAttributes.editor to wikieditor',
				tostring(self) .. '.static')
		else
			_defaultTextAreaAttributes.editor = nil
			classDebug:log(13, 'classSFfield.static:setDefaultTextAreaEditor(): Setting _defaultTextAreaAttributes.editor to NIL',
				tostring(self) .. '.static')
		end
		return true
	elseif val and type(val) == 'string' then
		_defaultTextAreaAttributes.editor = val
		classDebug:log(13, 'classSFfield.static:setDefaultTextAreaEditor(): Setting _defaultTextAreaAttributes.editor to ' .. val,
			tostring(self) .. '.static')
		return true
	else
		classDebug:log(13, 'classSFfield.static:setDefaultTextAreaEditor(): doing nothing. parameter type is ' .. type(val),
			tostring(self) .. '.static')
	end
	return false
end

function classSFfield.static:setDefaultTextAreaRows(val)
	if val and type(val) == 'number' then
		_defaultTextAreaAttributes.rows = val
		classDebug:log(13, 'classSFfield.static:setDefaultTextAreaRows(): Setting _defaultTextAreaAttributes.rows to ' .. val, 
			tostring(self) .. '.static')
		return true
	end
	return false
end

function classSFfield.static:setShowOnSelectIdPrefix(val)
	if val and type(val) == 'string' then
		_showOnSelectIdPrefix = val
		classDebug:log(13, 'classSFfield.static:setShowOnSelectIdPrefix(): Setting _showOnSelectIdPrefix to ' .. val,
			tostring(self) .. '.static')
		return true
	end
	return false
end

-- **************** declaration of private methods
local _processAttributes = function (self)
	_private[self].dbg:log(11, 'entering _processAttributes() to process attributes and preparing them for printout')
	_private[self].dbg:log(13, ' _processAttributes(): attributes array so far looks like: <pre>' .. _TT.printTable(_private[self].attributes) .. '</pre>')
	local attributes = {}
	if not _private[self].attributes['input type'] and not (_private[self].attributes.hidden or _private[self].attributes['holds template']) then
		_private[self].dbg:log(13, ' _processAttributes(): no input type set. defaulting dependant on the setting of attribute "list"')
		if _private[self].attributes.list then
			_private[self].attributes['input type'] = _defaultListInputType
		else
			_private[self].attributes['input type'] = _defaultSingleInputType
		end
	end
	if _private[self].attributes['input type'] and (_private[self].attributes['input type'] == 'textarea' or _private[self].attributes['input type'] == 'textarea with autocomplete') then
		_private[self].dbg:log(13, ' _processAttributes(): textarea input type detected. setting defaults when unset')
		if _private[self].attributes.autogrow == nil then
			_private[self].attributes.autogrow = _defaultTextAreaAttributes.autogrow
		end
		if _private[self].attributes.cols == nil then
			_private[self].attributes.cols = _defaultTextAreaAttributes.cols
		end
		if _private[self].attributes.editor == nil and _defaultTextAreaAttributes.editor then
			_private[self].attributes.editor = _defaultTextAreaAttributes.editor
		end
		if _private[self].attributes.rows == nil then
			_private[self].attributes.rows = _defaultTextAreaAttributes.rows
		end
	elseif _private[self].attributes.size == nil and _private[self].attributes['input type']
			and not _TT.inTable({'radiobutton', 'hidden', 'checkbox', 'checkboxes'}, mw.ustring.lower(_private[self].attributes['input type'])) then
		_private[self].attributes.size = _defaultSize
	end
	
	for attr, val in pairs(_private[self].attributes) do
		if not _private[self].attributes['input type'] or _TT.inTable(_CFG.generalAttributes, mw.ustring.lower(attr)) or 
				_TT.inTable(_CFG.validAttributesPerType[_private[self].attributes['input type']], mw.ustring.lower(attr)) then
			local line
			if type(val) == 'boolean' then
				if val then
					line = attr
				end
			elseif type(val) == 'table' then
				_private[self].dbg:log(13, ' _processAttributes(): value of type "table" detected')
				if attr == 'show on select' then
					_private[self].dbg:log(13, ' _processAttributes(): belonging to attribute "show on select". processing table')
					line = attr .. '='
					for v, eid in pairs(val) do
						if type(eid) == 'table' then
							for _, eid_v in pairs(eid) do
								line = line .. v .. '=>' .. _showOnSelectIdPrefix .. eid_v .. ';'
							end
						else
							line = line .. v .. '=>' .. _showOnSelectIdPrefix .. eid .. ';'
						end
					end
				else
					_private[self].dbg:log(13, ' _processAttributes(): not belonging to attribute "show on select". processing table normally')
					local delimiter = _private[self].attributes.delimiter or _CFG.global.defaultDelimiter or ''
					-- unfortunately FoundationsClass tables get represented as arrays, albeit with integers ranging from 1 - n as keys. H2IK-Y! workaround:
					local tmpvals = {}
					for _, v in pairs(val) do
						table.insert(tmpvals, v)
					end
					line = attr .. '=' .. table.concat(tmpvals, delimiter) -- '1,2,3,' .. #val .. '-<pre>' .. require('Module:TableTools').printTable(val) .. '</pre>' ..table.maxn(val) --table.concat(val, '-')
				end
			else
				if attr == 'show on select' then
					line = attr .. '=' .. _showOnSelectIdPrefix .. val
				else
					line = attr .. '=' .. val
				end
			end
			if line then
				_private[self].dbg:log(13, ' _processAttributes(): adding "' .. line .. '" to table of attributes')
			end
			table.insert(attributes, line)
		else
			_private[self].dbg:log(13, ' _processAttributes(): ignoring attribute ' .. attr .. '; reason is: ' ..
				(_private[self].attributes['input type'] and 'not found in tables _CFG.generalAttributes and _CFG.validAttributesPerType["' .. _private[self].attributes['input type'] .. '"]' or 'no input type set')
			)
		end
	end
	return attributes
end


-- **************** declaration of public methods
function classSFfield:__tostring()
	_private[self].dbg:log(11, 'entering classSFfield:__tostring() to render field output')
	return self:render()
end

function classSFfield:createTr(label, tooltip)
	_private[self].dbg:log(11, 'entering classSFfield:createTr() to create a table row around self:render()')
	_private[self].dbg:log(12, ' classSFfield:createTr() has label "' .. (label and label or 'NOT PROVIDED') .. '"')
	_private[self].dbg:log(12, ' classSFfield:createTr() has tooltip "' .. (tooltip and tooltip or 'NONE') .. '"')
	local frame = mw.getCurrentFrame()
	tr = mw.html.create('tr')
	tr:attr( 'id', _showOnSelectIdPrefix .. mw.uri.encode(_private[self].name, 'WIKI') )
		:tag((_private[self].attributes.mandatory and 'th' or 'td'))
			:wikitext((label or 'LABEL_' .. fieldname) .. 
				(_private[self].attributes.mandatory and _mandatoryMarker or '') ..
				(tooltip and frame:callParserFunction(_CFG.global.tooltipParserFunction, tooltip) or ''))
			:done()
		:newline()
		:tag('td')
			:wikitext(self:render())
			:done()
		:newline()
		:done()
	return tr
end

function classSFfield:get(attribute)
	return _private[self].attributes[attribute]
end

function classSFfield:render()
	_private[self].dbg:log(11, 'entering classSFfield:render() to render field output')
	local str = '{{{field|' .. _private[self].name .. '|'
				.. table.concat(_processAttributes(self), '|') .. '}}}'
	_private[self].dbg:log(11, ' classSFfield:render() renders <code>' .. mw.text.nowiki(str) .. '</code>')
	return str
end

function classSFfield:set(attribute, value)
	local attribute = (attribute and mw.ustring.lower(attribute) or 'NOT PROVIDED!')
	_private[self].dbg:log(11, 'entering classSFfield:set() to set attribute: ' .. attribute)
	local value = value
	if value == nil then
		value = true
	end
	if _TT.inTable(_CFG.validAttributes, attribute) then
		-- we have a valid attribute. do some plausibility check
		if attribute == 'input type' then
			value = mw.ustring.lower(value)
			if not _TT.inTable(_CFG.validInputTypes, value) then
				_private[self].dbg:log(11, ' classSFfield:set() trying to set "intput type" to invalid value: ' .. value and mw.ustring.lower(value) or 'NIL')
				return false
			end
		end
		_private[self].attributes[attribute] = value
		if type(value) == 'number' or type(value) == 'string' then
			_private[self].dbg:log(12, ' classSFfield:set() setting attribute: "' .. attribute .. '" to value ' .. value)
		else
			_private[self].dbg:log(12, ' classSFfield:set() setting attribute: "' .. attribute .. '" to a value of type ' .. type(value))
		end
		return true
	else
		_private[self].dbg:log(11, ' classSFfield:set() called with invalid attribute: ' .. attribute)
		return false
	end
end

return classSFfield