Provide a custom Plomino field type as a plugin
You implement your own Plomino field types into a Python package and provide them to Plomino as Zope3 utility components.
Plomino provides a set of field types (text, number, richtext, datagrid, etc.).
But a custom Plomino field type can be declared to Plomino from a custom package in order to extend the Plomino behavior.
Example:
from zope.formlib import form
from zope.interface import implements
from zope import component
from zope.pagetemplate.pagetemplatefile import PageTemplateFile
from zope.schema import getFields
from zope.schema import Text, TextLine
from Products.Five.formlib.formbase import EditForm
from Products.CMFPlomino.interfaces import IPlominoField
from Products.CMFPlomino.fields.dictionaryproperty import DictionaryProperty
from Products.CMFPlomino.fields.base import IBaseField, BaseField
A Zope schema defines the field setting parameters.
class IRomanNumberField(IBaseField):
"""
Roman number field schema
"""
color = TextLine(title=u'Color',
description=u'Font color to apply to roman number display.',
required=False)
A class derivated from BaseField will implement this interface.
It must mandatorily contain:
- plomino_field_parameters: it declares the field main parameters,
- read_template: the PageTemplate in charge of rendering the field in read mode,
- edit_template: the PageTemplate in charge of rendering the field in edit mode.
It can also overwrite the different methods of BaseField, like processInput (in charge of converting the submitted value into the actual item value, or validate (in charge of validating the submitted value before saving).
class RomanNumberField(BaseField):
""" This field stores integers as roman numerals
"""
implements(IRomanNumberField)
plomino_field_parameters = {'interface': IRomanNumberField,
'label': "RomanNumber",
'index_type': "FieldIndex"}
read_template = PageTemplateFile('roman_read.pt')
edit_template = PageTemplateFile('roman_edit.pt')
def validate(self, strValue):
"""
"""
errors=[]
fieldname = self.context.id
try:
v = int(submittedValue)
except:
errors.append(fieldname + " must be an integer.")
return errors
def processInput(self, strValue):
""" convert int to roman (example based on vegaseat code snippet)
"""
number = int(strValue)
numerals = { 1 : "I", 4 : "IV", 5 : "V", 9 : "IX", 10 : "X",
40 : "XL", 50 : "L", 90 : "XC", 100 : "C", 400 : "CD",
500 : "D", 900 : "CM", 1000 : "M" }
result = ""
for value, numeral in sorted(numerals.items(), reverse=True):
while number >= value:
result += numeral
number -= value
return result
The plugin field must be provided as an utility so Plomino can find it (the utility name must be in upper case):
component.provideUtility(RomanNumberField, IPlominoField, 'ROMANNUMBER')
And the SettingForm must built based on the field's schema: (no customization needed here)
for f in getFields(IRomanNumberField).values():
setattr(RomanNumberField, f.getName(),
DictionaryProperty(f, 'parameters'))
class SettingForm(EditForm):
"""
"""
form_fields = form.Fields(IRomanNumberField)
Then in configure.zcml, declare the field as adapter for PlominoField: (assuming that previous code is in romannumber.py)
<adapter
for="Products.CMFPlomino.interfaces.IPlominoField"
provides=".romannumber.IRomanNumberField"
factory=".romannumber.RomanNumberField" />
and declare the settings form as a browser page (its name must be xxx+'settings' where xxx is the utility name in lowercase)
<browser:page
name="romannumbersettings"
for="Products.CMFPlomino.interfaces.IPlominoField"
class=".romannumber.SettingForm"
permission="plomino.DESIGN_PERMISSION" />
The 2 page templates can be based on the following examples:
roman_read.pt:
<tal:block tal:define="v options/fieldvalue"
tal:content="python:str(v)">XXII</tal:block>
roman_edit.pt:
<span>
<input type="text"
tal:attributes="name options/fieldname;
value options/fieldvalue" />
</span>

