appy.gen: added param 'maxChars' for any Type, allowing to limit the amount of data in user input fields. Wherever possible, it is implemented using HTML attribute 'maxlength'; on server-side, content that is bigger than specified by maxChars is truncated (ie, it is not possible to force a maxlength for html textareas); implemented a first protection against XSS attacks (Javasscript detection in user input).
This commit is contained in:
parent
9e7ddcc771
commit
bce384e2da
121
gen/__init__.py
121
gen/__init__.py
|
@ -360,7 +360,7 @@ class Type:
|
||||||
def __init__(self, validator, multiplicity, index, default, optional,
|
def __init__(self, validator, multiplicity, index, default, optional,
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission, specificWritePermission,
|
searchable, specificReadPermission, specificWritePermission,
|
||||||
width, height, colspan, master, masterValue, focus,
|
width, height, maxChars, colspan, master, masterValue, focus,
|
||||||
historized, sync, mapping):
|
historized, sync, mapping):
|
||||||
# The validator restricts which values may be defined. It can be an
|
# The validator restricts which values may be defined. It can be an
|
||||||
# interval (1,None), a list of string values ['choice1', 'choice2'],
|
# interval (1,None), a list of string values ['choice1', 'choice2'],
|
||||||
|
@ -425,6 +425,11 @@ class Type:
|
||||||
# Widget width and height
|
# Widget width and height
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
|
# While width and height refer to widget dimensions, maxChars hereafter
|
||||||
|
# represents the maximum number of chars that a given input field may
|
||||||
|
# accept (corresponds to HTML "maxlength" property). "None" means
|
||||||
|
# "unlimited".
|
||||||
|
self.maxChars = maxChars
|
||||||
# If the widget is in a group with multiple columns, the following
|
# If the widget is in a group with multiple columns, the following
|
||||||
# attribute specifies on how many columns to span the widget.
|
# attribute specifies on how many columns to span the widget.
|
||||||
self.colspan = colspan
|
self.colspan = colspan
|
||||||
|
@ -807,6 +812,16 @@ class Type:
|
||||||
type-specific validation. p_value is never empty.'''
|
type-specific validation. p_value is never empty.'''
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def securityCheck(self, obj, value):
|
||||||
|
'''This method performs some security checks on the p_value that
|
||||||
|
represents user input.'''
|
||||||
|
if not isinstance(value, basestring): return
|
||||||
|
# Search Javascript code in the value (prevent XSS attacks).
|
||||||
|
if '<script' in value:
|
||||||
|
obj.log('Detected Javascript in user input.', type='error')
|
||||||
|
raise 'Your behaviour is considered a security attack. System ' \
|
||||||
|
'administrator has been warned.'
|
||||||
|
|
||||||
def validate(self, obj, value):
|
def validate(self, obj, value):
|
||||||
'''This method checks that p_value, coming from the request (p_obj is
|
'''This method checks that p_value, coming from the request (p_obj is
|
||||||
being created or edited) and formatted through a call to
|
being created or edited) and formatted through a call to
|
||||||
|
@ -821,6 +836,8 @@ class Type:
|
||||||
return obj.translate('field_required')
|
return obj.translate('field_required')
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
# Perform security checks on p_value
|
||||||
|
self.securityCheck(obj, value)
|
||||||
# Triggers the sub-class-specific validation for this value
|
# Triggers the sub-class-specific validation for this value
|
||||||
message = self.validateValue(obj, value)
|
message = self.validateValue(obj, value)
|
||||||
if message: return message
|
if message: return message
|
||||||
|
@ -914,13 +931,13 @@ class Integer(Type):
|
||||||
page='main', group=None, layouts=None, move=0, indexed=False,
|
page='main', group=None, layouts=None, move=0, indexed=False,
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=6, height=None,
|
specificWritePermission=False, width=6, height=None,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
maxChars=13, colspan=1, master=None, masterValue=None,
|
||||||
historized=False, mapping=None):
|
focus=False, historized=False, mapping=None):
|
||||||
Type.__init__(self, validator, multiplicity, index, default, optional,
|
Type.__init__(self, validator, multiplicity, index, default, optional,
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, colspan, master,
|
specificWritePermission, width, height, maxChars, colspan,
|
||||||
masterValue, focus, historized, True, mapping)
|
master, masterValue, focus, historized, True, mapping)
|
||||||
self.pythonType = long
|
self.pythonType = long
|
||||||
|
|
||||||
def validateValue(self, obj, value):
|
def validateValue(self, obj, value):
|
||||||
|
@ -943,8 +960,8 @@ class Float(Type):
|
||||||
page='main', group=None, layouts=None, move=0, indexed=False,
|
page='main', group=None, layouts=None, move=0, indexed=False,
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=6, height=None,
|
specificWritePermission=False, width=6, height=None,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
maxChars=13, colspan=1, master=None, masterValue=None,
|
||||||
historized=False, mapping=None, precision=None,
|
focus=False, historized=False, mapping=None, precision=None,
|
||||||
sep=(',', '.')):
|
sep=(',', '.')):
|
||||||
# The precision is the number of decimal digits. This number is used
|
# The precision is the number of decimal digits. This number is used
|
||||||
# for rendering the float, but the internal float representation is not
|
# for rendering the float, but the internal float representation is not
|
||||||
|
@ -963,8 +980,8 @@ class Float(Type):
|
||||||
Type.__init__(self, validator, multiplicity, index, default, optional,
|
Type.__init__(self, validator, multiplicity, index, default, optional,
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
False, specificReadPermission, specificWritePermission,
|
False, specificReadPermission, specificWritePermission,
|
||||||
width, height, colspan, master, masterValue, focus,
|
width, height, maxChars, colspan, master, masterValue,
|
||||||
historized, True, mapping)
|
focus, historized, True, mapping)
|
||||||
self.pythonType = float
|
self.pythonType = float
|
||||||
|
|
||||||
def getFormattedValue(self, obj, value):
|
def getFormattedValue(self, obj, value):
|
||||||
|
@ -1112,8 +1129,8 @@ class String(Type):
|
||||||
show=True, page='main', group=None, layouts=None, move=0,
|
show=True, page='main', group=None, layouts=None, move=0,
|
||||||
indexed=False, searchable=False, specificReadPermission=False,
|
indexed=False, searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
historized=False, mapping=None, transform='none'):
|
focus=False, historized=False, mapping=None, transform='none'):
|
||||||
self.format = format
|
self.format = format
|
||||||
# The following field has a direct impact on the text entered by the
|
# The following field has a direct impact on the text entered by the
|
||||||
# user. It applies a transformation on it, exactly as does the CSS
|
# user. It applies a transformation on it, exactly as does the CSS
|
||||||
|
@ -1124,10 +1141,10 @@ class String(Type):
|
||||||
Type.__init__(self, validator, multiplicity, index, default, optional,
|
Type.__init__(self, validator, multiplicity, index, default, optional,
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, colspan, master,
|
specificWritePermission, width, height, maxChars, colspan,
|
||||||
masterValue, focus, historized, True, mapping)
|
master, masterValue, focus, historized, True, mapping)
|
||||||
self.isSelect = self.isSelection()
|
self.isSelect = self.isSelection()
|
||||||
# Default width and height vary according to String format
|
# Default width, height and maxChars vary according to String format
|
||||||
if width == None:
|
if width == None:
|
||||||
if format == String.TEXT: self.width = 60
|
if format == String.TEXT: self.width = 60
|
||||||
else: self.width = 30
|
else: self.width = 30
|
||||||
|
@ -1135,6 +1152,12 @@ class String(Type):
|
||||||
if format == String.TEXT: self.height = 5
|
if format == String.TEXT: self.height = 5
|
||||||
elif self.isSelect: self.height = 4
|
elif self.isSelect: self.height = 4
|
||||||
else: self.height = 1
|
else: self.height = 1
|
||||||
|
if maxChars == None:
|
||||||
|
if self.isSelect: pass
|
||||||
|
elif format == String.LINE: self.maxChars = 256
|
||||||
|
elif format == String.TEXT: self.maxChars = 9999
|
||||||
|
elif format == String.XHTML: self.maxChars = 9999
|
||||||
|
elif format == String.PASSWORD: self.maxChars = 20
|
||||||
self.filterable = self.indexed and (self.format == String.LINE) and \
|
self.filterable = self.indexed and (self.format == String.LINE) and \
|
||||||
not self.isSelect
|
not self.isSelect
|
||||||
|
|
||||||
|
@ -1330,6 +1353,10 @@ class String(Type):
|
||||||
def store(self, obj, value):
|
def store(self, obj, value):
|
||||||
if self.isMultiValued() and isinstance(value, basestring):
|
if self.isMultiValued() and isinstance(value, basestring):
|
||||||
value = [value]
|
value = [value]
|
||||||
|
# Truncate the result if longer than self.maxChars
|
||||||
|
if self.maxChars and isinstance(value, basestring) and \
|
||||||
|
(len(value) > self.maxChars):
|
||||||
|
value = value[:self.maxChars]
|
||||||
exec 'obj.%s = value' % self.name
|
exec 'obj.%s = value' % self.name
|
||||||
|
|
||||||
def getIndexType(self):
|
def getIndexType(self):
|
||||||
|
@ -1346,13 +1373,13 @@ class Boolean(Type):
|
||||||
page='main', group=None, layouts = None, move=0, indexed=False,
|
page='main', group=None, layouts = None, move=0, indexed=False,
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
historized=False, mapping=None):
|
focus=False, historized=False, mapping=None):
|
||||||
Type.__init__(self, validator, multiplicity, index, default, optional,
|
Type.__init__(self, validator, multiplicity, index, default, optional,
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, colspan, master,
|
specificWritePermission, width, height, None, colspan,
|
||||||
masterValue, focus, historized, True, mapping)
|
master, masterValue, focus, historized, True, mapping)
|
||||||
self.pythonType = bool
|
self.pythonType = bool
|
||||||
|
|
||||||
def getDefaultLayouts(self):
|
def getDefaultLayouts(self):
|
||||||
|
@ -1389,8 +1416,8 @@ class Date(Type):
|
||||||
show=True, page='main', group=None, layouts=None, move=0,
|
show=True, page='main', group=None, layouts=None, move=0,
|
||||||
indexed=False, searchable=False, specificReadPermission=False,
|
indexed=False, searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
historized=False, mapping=None):
|
focus=False, historized=False, mapping=None):
|
||||||
self.format = format
|
self.format = format
|
||||||
self.calendar = calendar
|
self.calendar = calendar
|
||||||
self.startYear = startYear
|
self.startYear = startYear
|
||||||
|
@ -1401,8 +1428,8 @@ class Date(Type):
|
||||||
Type.__init__(self, validator, multiplicity, index, default, optional,
|
Type.__init__(self, validator, multiplicity, index, default, optional,
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, colspan, master,
|
specificWritePermission, width, height, None, colspan,
|
||||||
masterValue, focus, historized, True, mapping)
|
master, masterValue, focus, historized, True, mapping)
|
||||||
|
|
||||||
def getCss(self, layoutType):
|
def getCss(self, layoutType):
|
||||||
if (layoutType == 'edit') and self.calendar:
|
if (layoutType == 'edit') and self.calendar:
|
||||||
|
@ -1462,13 +1489,13 @@ class File(Type):
|
||||||
page='main', group=None, layouts=None, move=0, indexed=False,
|
page='main', group=None, layouts=None, move=0, indexed=False,
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
historized=False, mapping=None, isImage=False):
|
focus=False, historized=False, mapping=None, isImage=False):
|
||||||
self.isImage = isImage
|
self.isImage = isImage
|
||||||
Type.__init__(self, validator, multiplicity, index, default, optional,
|
Type.__init__(self, validator, multiplicity, index, default, optional,
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
False, specificReadPermission, specificWritePermission,
|
False, specificReadPermission, specificWritePermission,
|
||||||
width, height, colspan, master, masterValue, focus,
|
width, height, None, colspan, master, masterValue, focus,
|
||||||
historized, True, mapping)
|
historized, True, mapping)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -1612,8 +1639,8 @@ class Ref(Type):
|
||||||
select=None, maxPerPage=30, move=0, indexed=False,
|
select=None, maxPerPage=30, move=0, indexed=False,
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=5,
|
specificWritePermission=False, width=None, height=5,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
historized=False, mapping=None, queryable=False,
|
focus=False, historized=False, mapping=None, queryable=False,
|
||||||
queryFields=None, queryNbCols=1):
|
queryFields=None, queryNbCols=1):
|
||||||
self.klass = klass
|
self.klass = klass
|
||||||
self.attribute = attribute
|
self.attribute = attribute
|
||||||
|
@ -1663,7 +1690,7 @@ class Ref(Type):
|
||||||
Type.__init__(self, validator, multiplicity, index, default, optional,
|
Type.__init__(self, validator, multiplicity, index, default, optional,
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
False, specificReadPermission, specificWritePermission,
|
False, specificReadPermission, specificWritePermission,
|
||||||
width, height, colspan, master, masterValue, focus,
|
width, height, None, colspan, master, masterValue, focus,
|
||||||
historized, sync, mapping)
|
historized, sync, mapping)
|
||||||
self.validable = self.link
|
self.validable = self.link
|
||||||
|
|
||||||
|
@ -1829,9 +1856,9 @@ class Computed(Type):
|
||||||
page='main', group=None, layouts=None, move=0, indexed=False,
|
page='main', group=None, layouts=None, move=0, indexed=False,
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, method=None, plainText=True, master=None,
|
maxChars=None, colspan=1, method=None, plainText=True,
|
||||||
masterValue=None, focus=False, historized=False, sync=True,
|
master=None, masterValue=None, focus=False, historized=False,
|
||||||
mapping=None, context={}):
|
sync=True, mapping=None, context={}):
|
||||||
# The Python method used for computing the field value
|
# The Python method used for computing the field value
|
||||||
self.method = method
|
self.method = method
|
||||||
# Does field computation produce plain text or XHTML?
|
# Does field computation produce plain text or XHTML?
|
||||||
|
@ -1847,8 +1874,8 @@ class Computed(Type):
|
||||||
Type.__init__(self, None, multiplicity, index, default, optional,
|
Type.__init__(self, None, multiplicity, index, default, optional,
|
||||||
False, show, page, group, layouts, move, indexed, False,
|
False, show, page, group, layouts, move, indexed, False,
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, colspan, master, masterValue, focus, historized,
|
height, None, colspan, master, masterValue, focus,
|
||||||
sync, mapping)
|
historized, sync, mapping)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
|
|
||||||
def callMacro(self, obj, macroPath):
|
def callMacro(self, obj, macroPath):
|
||||||
|
@ -1896,9 +1923,9 @@ class Action(Type):
|
||||||
page='main', group=None, layouts=None, move=0, indexed=False,
|
page='main', group=None, layouts=None, move=0, indexed=False,
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, action=None, result='computation', confirm=False,
|
maxChars=None, colspan=1, action=None, result='computation',
|
||||||
master=None, masterValue=None, focus=False, historized=False,
|
confirm=False, master=None, masterValue=None, focus=False,
|
||||||
mapping=None):
|
historized=False, mapping=None):
|
||||||
# Can be a single method or a list/tuple of methods
|
# Can be a single method or a list/tuple of methods
|
||||||
self.action = action
|
self.action = action
|
||||||
# For the 'result' param:
|
# For the 'result' param:
|
||||||
|
@ -1918,8 +1945,8 @@ class Action(Type):
|
||||||
Type.__init__(self, None, (0,1), index, default, optional,
|
Type.__init__(self, None, (0,1), index, default, optional,
|
||||||
False, show, page, group, layouts, move, indexed, False,
|
False, show, page, group, layouts, move, indexed, False,
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, colspan, master, masterValue, focus, historized,
|
height, None, colspan, master, masterValue, focus,
|
||||||
False, mapping)
|
historized, False, mapping)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
|
|
||||||
def getDefaultLayouts(self): return {'view': 'l-f', 'edit': 'lrv-f'}
|
def getDefaultLayouts(self): return {'view': 'l-f', 'edit': 'lrv-f'}
|
||||||
|
@ -1966,13 +1993,13 @@ class Info(Type):
|
||||||
page='main', group=None, layouts=None, move=0, indexed=False,
|
page='main', group=None, layouts=None, move=0, indexed=False,
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
historized=False, mapping=None):
|
focus=False, historized=False, mapping=None):
|
||||||
Type.__init__(self, None, (0,1), index, default, optional,
|
Type.__init__(self, None, (0,1), index, default, optional,
|
||||||
False, show, page, group, layouts, move, indexed, False,
|
False, show, page, group, layouts, move, indexed, False,
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, colspan, master, masterValue, focus, historized,
|
height, None, colspan, master, masterValue, focus,
|
||||||
False, mapping)
|
historized, False, mapping)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
|
|
||||||
class Pod(Type):
|
class Pod(Type):
|
||||||
|
@ -1987,9 +2014,9 @@ class Pod(Type):
|
||||||
page='main', group=None, layouts=None, move=0, indexed=False,
|
page='main', group=None, layouts=None, move=0, indexed=False,
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
historized=False, mapping=None, template=None, context=None,
|
focus=False, historized=False, mapping=None, template=None,
|
||||||
action=None, askAction=False, stylesMapping={},
|
context=None, action=None, askAction=False, stylesMapping={},
|
||||||
freezeFormat='pdf'):
|
freezeFormat='pdf'):
|
||||||
# The following param stores the path to a POD template
|
# The following param stores the path to a POD template
|
||||||
self.template = template
|
self.template = template
|
||||||
|
@ -2009,8 +2036,8 @@ class Pod(Type):
|
||||||
Type.__init__(self, None, (0,1), index, default, optional,
|
Type.__init__(self, None, (0,1), index, default, optional,
|
||||||
False, show, page, group, layouts, move, indexed,
|
False, show, page, group, layouts, move, indexed,
|
||||||
searchable, specificReadPermission,
|
searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, colspan, master,
|
specificWritePermission, width, height, None, colspan,
|
||||||
masterValue, focus, historized, False, mapping)
|
master, masterValue, focus, historized, False, mapping)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
|
|
||||||
def isFrozen(self, obj):
|
def isFrozen(self, obj):
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
<tal:comment replace="nothing">Edit macro for an Float.</tal:comment>
|
<tal:comment replace="nothing">Edit macro for an Float.</tal:comment>
|
||||||
<metal:edit define-macro="edit">
|
<metal:edit define-macro="edit">
|
||||||
<input tal:attributes="id name; name name; size widget/width;
|
<input tal:define="maxChars python: test(widget['maxChars'], widget['maxChars'], '')"
|
||||||
|
tal:attributes="id name; name name; size widget/width; maxlength maxChars;
|
||||||
value python: test(inRequest, requestValue, value)" type="text"/>
|
value python: test(inRequest, requestValue, value)" type="text"/>
|
||||||
</metal:edit>
|
</metal:edit>
|
||||||
|
|
||||||
|
@ -16,14 +17,15 @@
|
||||||
</metal:cell>
|
</metal:cell>
|
||||||
|
|
||||||
<tal:comment replace="nothing">Search macro for an Float.</tal:comment>
|
<tal:comment replace="nothing">Search macro for an Float.</tal:comment>
|
||||||
<metal:search define-macro="search">
|
<metal:search define-macro="search"
|
||||||
|
tal:define="maxChars python: test(widget['maxChars'], widget['maxChars'], '')">
|
||||||
<label tal:content="python: tool.translate(widget['labelId'])"></label><br>
|
<label tal:content="python: tool.translate(widget['labelId'])"></label><br>
|
||||||
<tal:from define="fromName python: '%s*float' % widgetName">
|
<tal:from define="fromName python: '%s*float' % widgetName">
|
||||||
<label tal:attributes="for fromName" tal:content="python: tool.translate('search_from')"></label>
|
<label tal:attributes="for fromName" tal:content="python: tool.translate('search_from')"></label>
|
||||||
<input type="text" tal:attributes="name fromName" size="4"/>
|
<input type="text" tal:attributes="name fromName; maxlength maxChars" size="4"/>
|
||||||
</tal:from>
|
</tal:from>
|
||||||
<tal:to define="toName python: '%s_to' % name">
|
<tal:to define="toName python: '%s_to' % name">
|
||||||
<label tal:attributes="for toName" tal:content="python: tool.translate('search_to')"></label>
|
<label tal:attributes="for toName" tal:content="python: tool.translate('search_to')"></label>
|
||||||
<input type="text" tal:attributes="name toName" size="4"/>
|
<input type="text" tal:attributes="name toName; maxlength maxChars" size="4"/>
|
||||||
</tal:to><br/>
|
</tal:to><br/>
|
||||||
</metal:search>
|
</metal:search>
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
<tal:comment replace="nothing">Edit macro for an Integer.</tal:comment>
|
<tal:comment replace="nothing">Edit macro for an Integer.</tal:comment>
|
||||||
<metal:edit define-macro="edit">
|
<metal:edit define-macro="edit">
|
||||||
<input tal:attributes="id name; name name; size widget/width;
|
<input tal:define="maxChars python: test(widget['maxChars'], widget['maxChars'], '')"
|
||||||
|
tal:attributes="id name; name name; size widget/width; maxlength maxChars;
|
||||||
value python: test(inRequest, requestValue, value)" type="text"/>
|
value python: test(inRequest, requestValue, value)" type="text"/>
|
||||||
</metal:edit>
|
</metal:edit>
|
||||||
|
|
||||||
|
@ -15,14 +16,15 @@
|
||||||
</metal:cell>
|
</metal:cell>
|
||||||
|
|
||||||
<tal:comment replace="nothing">Search macro for an Integer.</tal:comment>
|
<tal:comment replace="nothing">Search macro for an Integer.</tal:comment>
|
||||||
<metal:search define-macro="search">
|
<metal:search define-macro="search"
|
||||||
|
tal:define="maxChars python: test(widget['maxChars'], widget['maxChars'], '')">
|
||||||
<label tal:content="python: tool.translate(widget['labelId'])"></label><br>
|
<label tal:content="python: tool.translate(widget['labelId'])"></label><br>
|
||||||
<tal:from define="fromName python: '%s*int' % widgetName">
|
<tal:from define="fromName python: '%s*int' % widgetName">
|
||||||
<label tal:attributes="for fromName" tal:content="python: tool.translate('search_from')"></label>
|
<label tal:attributes="for fromName" tal:content="python: tool.translate('search_from')"></label>
|
||||||
<input type="text" tal:attributes="name fromName" size="4"/>
|
<input type="text" tal:attributes="name fromName; maxlength maxChars" size="4"/>
|
||||||
</tal:from>
|
</tal:from>
|
||||||
<tal:to define="toName python: '%s_to' % name">
|
<tal:to define="toName python: '%s_to' % name">
|
||||||
<label tal:attributes="for toName" tal:content="python: tool.translate('search_to')"></label>
|
<label tal:attributes="for toName" tal:content="python: tool.translate('search_to')"></label>
|
||||||
<input type="text" tal:attributes="name toName" size="4"/>
|
<input type="text" tal:attributes="name toName; maxlength maxChars" size="4"/>
|
||||||
</tal:to><br/>
|
</tal:to><br/>
|
||||||
</metal:search>
|
</metal:search>
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
tal:define="fmt widget/format;
|
tal:define="fmt widget/format;
|
||||||
isSelect widget/isSelect;
|
isSelect widget/isSelect;
|
||||||
isMaster widget/slaves;
|
isMaster widget/slaves;
|
||||||
isOneLine python: fmt in (0,3)">
|
isOneLine python: fmt in (0,3);
|
||||||
|
maxChars python: test(widget['maxChars'], widget['maxChars'], '')">
|
||||||
|
|
||||||
<tal:choice condition="isSelect">
|
<tal:choice condition="isSelect">
|
||||||
<select tal:define="possibleValues python:contextObj.getPossibleValues(name, withTranslations=True, withBlankValue=True)"
|
<select tal:define="possibleValues python:contextObj.getPossibleValues(name, withTranslations=True, withBlankValue=True)"
|
||||||
|
@ -41,7 +42,7 @@
|
||||||
</select>
|
</select>
|
||||||
</tal:choice>
|
</tal:choice>
|
||||||
<tal:line condition="python: isOneLine and not isSelect">
|
<tal:line condition="python: isOneLine and not isSelect">
|
||||||
<input tal:attributes="id name; name name; size widget/width;
|
<input tal:attributes="id name; name name; size widget/width; maxlength maxChars;
|
||||||
value python: test(inRequest, requestValue, value);
|
value python: test(inRequest, requestValue, value);
|
||||||
style python: 'text-transform:%s' % widget['transform'];
|
style python: 'text-transform:%s' % widget['transform'];
|
||||||
type python: (widget['format'] == 3) and 'password' or 'text'"/>
|
type python: (widget['format'] == 3) and 'password' or 'text'"/>
|
||||||
|
@ -53,8 +54,6 @@
|
||||||
style python: 'text-transform:%s' % widget['transform'];"
|
style python: 'text-transform:%s' % widget['transform'];"
|
||||||
tal:content="python: test(inRequest, requestValue, value)">
|
tal:content="python: test(inRequest, requestValue, value)">
|
||||||
</textarea>
|
</textarea>
|
||||||
<input type="hidden" value="text/plain" originalvalue="text/plain"
|
|
||||||
tal:attributes="name python: '%s_text_format' % name"/>
|
|
||||||
</tal:textarea>
|
</tal:textarea>
|
||||||
<tal:rich condition="python: fmt == 2">
|
<tal:rich condition="python: fmt == 2">
|
||||||
<tal:editor define="editor python: member.getProperty('wysiwyg_editor','').lower();
|
<tal:editor define="editor python: member.getProperty('wysiwyg_editor','').lower();
|
||||||
|
@ -84,7 +83,9 @@
|
||||||
<label tal:attributes="for widgetName" tal:content="python: tool.translate(widget['labelId'])"></label><br>
|
<label tal:attributes="for widgetName" tal:content="python: tool.translate(widget['labelId'])"></label><br>
|
||||||
<tal:comment replace="nothing">Show a simple search field for most String fields.</tal:comment>
|
<tal:comment replace="nothing">Show a simple search field for most String fields.</tal:comment>
|
||||||
<tal:simpleSearch condition="not: widget/isSelect">
|
<tal:simpleSearch condition="not: widget/isSelect">
|
||||||
<input type="text" tal:attributes="name python: '%s*string-%s' % (widgetName, widget['transform']);
|
<input type="text" tal:define="maxChars python: test(widget['maxChars'], widget['maxChars'], '')"
|
||||||
|
tal:attributes="name python: '%s*string-%s' % (widgetName, widget['transform']);
|
||||||
|
maxlength maxChars;
|
||||||
style python: 'text-transform:%s' % widget['transform']"/>
|
style python: 'text-transform:%s' % widget['transform']"/>
|
||||||
</tal:simpleSearch>
|
</tal:simpleSearch>
|
||||||
<tal:comment replace="nothing">Show a multi-selection box for fields whose
|
<tal:comment replace="nothing">Show a multi-selection box for fields whose
|
||||||
|
|
Loading…
Reference in a new issue