appy.gen: bugfixes in the List field.
This commit is contained in:
parent
6d0549e6ce
commit
7d605d1fbb
|
@ -583,7 +583,6 @@ class Type:
|
||||||
else:
|
else:
|
||||||
master, masterValue = masterData
|
master, masterValue = masterData
|
||||||
reqValue = master.getRequestValue(obj.REQUEST)
|
reqValue = master.getRequestValue(obj.REQUEST)
|
||||||
reqValue = master.getStorableValue(reqValue)
|
|
||||||
# reqValue can be a list or not
|
# reqValue can be a list or not
|
||||||
if type(reqValue) not in sequenceTypes:
|
if type(reqValue) not in sequenceTypes:
|
||||||
return reqValue in masterValue
|
return reqValue in masterValue
|
||||||
|
@ -783,10 +782,21 @@ class Type:
|
||||||
return res
|
return res
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def getRequestValue(self, request):
|
def getRequestValue(self, request, requestName=None):
|
||||||
'''Gets the string (or list of strings if multi-valued)
|
'''Gets a value for this field as carried in the request object. In the
|
||||||
representation of this field as found in the p_request.'''
|
simplest cases, the request value is a single value whose name in the
|
||||||
return request.get(self.name, None)
|
request is the name of the field.
|
||||||
|
|
||||||
|
Sometimes (ie: a Date: see the overriden method in the Date class),
|
||||||
|
several request values must be combined.
|
||||||
|
|
||||||
|
Sometimes (ie, a field which is a sub-field in a List), the name of
|
||||||
|
the request value(s) representing the field value do not correspond
|
||||||
|
to the field name (ie: the request name includes information about
|
||||||
|
the container field). In this case, p_requestName must be used for
|
||||||
|
searching into the request, instead of the field name (self.name).'''
|
||||||
|
name = requestName or self.name
|
||||||
|
return request.get(name, None)
|
||||||
|
|
||||||
def getStorableValue(self, value):
|
def getStorableValue(self, value):
|
||||||
'''p_value is a valid value initially computed through calling
|
'''p_value is a valid value initially computed through calling
|
||||||
|
@ -1474,11 +1484,12 @@ class Date(Type):
|
||||||
res += ' %s' % value.strftime('%H:%M')
|
res += ' %s' % value.strftime('%H:%M')
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getRequestValue(self, request):
|
def getRequestValue(self, request, requestName=None):
|
||||||
|
name = requestName or self.name
|
||||||
# Manage the "date" part
|
# Manage the "date" part
|
||||||
value = ''
|
value = ''
|
||||||
for part in self.dateParts:
|
for part in self.dateParts:
|
||||||
valuePart = request.get('%s_%s' % (self.name, part), None)
|
valuePart = request.get('%s_%s' % (name, part), None)
|
||||||
if not valuePart: return None
|
if not valuePart: return None
|
||||||
value += valuePart + '/'
|
value += valuePart + '/'
|
||||||
value = value[:-1]
|
value = value[:-1]
|
||||||
|
@ -1486,7 +1497,7 @@ class Date(Type):
|
||||||
if self.format == self.WITH_HOUR:
|
if self.format == self.WITH_HOUR:
|
||||||
value += ' '
|
value += ' '
|
||||||
for part in self.hourParts:
|
for part in self.hourParts:
|
||||||
valuePart = request.get('%s_%s' % (self.name, part), None)
|
valuePart = request.get('%s_%s' % (name, part), None)
|
||||||
if not valuePart: return None
|
if not valuePart: return None
|
||||||
value += valuePart + ':'
|
value += valuePart + ':'
|
||||||
value = value[:-1]
|
value = value[:-1]
|
||||||
|
@ -1544,8 +1555,9 @@ class File(Type):
|
||||||
if not value: return value
|
if not value: return value
|
||||||
return value._zopeFile
|
return value._zopeFile
|
||||||
|
|
||||||
def getRequestValue(self, request):
|
def getRequestValue(self, request, requestName=None):
|
||||||
return request.get('%s_file' % self.name)
|
name = requestName or self.name
|
||||||
|
return request.get('%s_file' % name)
|
||||||
|
|
||||||
def getDefaultLayouts(self): return {'view':'l-f','edit':'lrv-f'}
|
def getDefaultLayouts(self): return {'view':'l-f','edit':'lrv-f'}
|
||||||
|
|
||||||
|
@ -2251,25 +2263,22 @@ class List(Type):
|
||||||
for n, field in self.fields:
|
for n, field in self.fields:
|
||||||
if n == name: return field
|
if n == name: return field
|
||||||
|
|
||||||
def getRequestValue(self, request):
|
def getRequestValue(self, request, requestName=None):
|
||||||
'''Concatenates the list from distinct form elements in the request.'''
|
'''Concatenates the list from distinct form elements in the request.'''
|
||||||
prefix = self.name + '*' + self.fields[0][0] + '*'
|
name = requestName or self.name # A List may be into another List (?)
|
||||||
|
prefix = name + '*' + self.fields[0][0] + '*'
|
||||||
res = {}
|
res = {}
|
||||||
for key in request.keys():
|
for key in request.keys():
|
||||||
if not key.startswith(prefix): continue
|
if not key.startswith(prefix): continue
|
||||||
# I have found a row. Gets its index
|
# I have found a row. Gets its index
|
||||||
row = Object()
|
row = Object()
|
||||||
|
if '_' in key: key = key[:key.index('_')]
|
||||||
rowIndex = int(key.split('*')[-1])
|
rowIndex = int(key.split('*')[-1])
|
||||||
if rowIndex == -1: continue # Ignore the template row.
|
if rowIndex == -1: continue # Ignore the template row.
|
||||||
for name, field in self.fields:
|
for subName, subField in self.fields:
|
||||||
keyName = '%s*%s*%s' % (self.name, name, rowIndex)
|
keyName = '%s*%s*%s' % (name, subName, rowIndex)
|
||||||
if request.has_key(keyName):
|
v = subField.getRequestValue(request, requestName=keyName)
|
||||||
# Simulate the request as if it was for a single value
|
setattr(row, subName, v)
|
||||||
request.set(field.name, request[keyName])
|
|
||||||
v = field.getRequestValue(request)
|
|
||||||
else:
|
|
||||||
v = None
|
|
||||||
setattr(row, name, v)
|
|
||||||
res[rowIndex] = row
|
res[rowIndex] = row
|
||||||
# Produce a sorted list.
|
# Produce a sorted list.
|
||||||
keys = res.keys()
|
keys = res.keys()
|
||||||
|
@ -2280,7 +2289,7 @@ class List(Type):
|
||||||
# instead of taking it from the specific request key. Indeed, specific
|
# instead of taking it from the specific request key. Indeed, specific
|
||||||
# request keys contain row indexes that may be wrong after row deletions
|
# request keys contain row indexes that may be wrong after row deletions
|
||||||
# by the user.
|
# by the user.
|
||||||
request.set(self.name, res)
|
request.set(name, res)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getStorableValue(self, value):
|
def getStorableValue(self, value):
|
||||||
|
@ -2301,6 +2310,22 @@ class List(Type):
|
||||||
if i >= len(outerValue): return ''
|
if i >= len(outerValue): return ''
|
||||||
return getattr(outerValue[i], name, '')
|
return getattr(outerValue[i], name, '')
|
||||||
|
|
||||||
|
def getCss(self, layoutType):
|
||||||
|
'''Gets the CSS required by sub-fields if any.'''
|
||||||
|
res = ()
|
||||||
|
for name, field in self.fields:
|
||||||
|
css = field.getCss(layoutType)
|
||||||
|
if css: res += css
|
||||||
|
return res
|
||||||
|
|
||||||
|
def getJs(self, layoutType):
|
||||||
|
'''Gets the JS required by sub-fields if any.'''
|
||||||
|
res = ()
|
||||||
|
for name, field in self.fields:
|
||||||
|
js = field.getJs(layoutType)
|
||||||
|
if js: res += js
|
||||||
|
return res
|
||||||
|
|
||||||
# Workflow-specific types and default workflows --------------------------------
|
# Workflow-specific types and default workflows --------------------------------
|
||||||
appyToZopePermissions = {
|
appyToZopePermissions = {
|
||||||
'read': ('View', 'Access contents information'),
|
'read': ('View', 'Access contents information'),
|
||||||
|
|
|
@ -121,7 +121,7 @@ class ToolMixin(BaseMixin):
|
||||||
p_code.'''
|
p_code.'''
|
||||||
return languages.get(code)[2]
|
return languages.get(code)[2]
|
||||||
|
|
||||||
def getCssJs(self):
|
def getGlobalCssJs(self):
|
||||||
'''Returns the list of CSS and JS files to include in the main template.
|
'''Returns the list of CSS and JS files to include in the main template.
|
||||||
The method ensures that appy.css and appy.js come first.'''
|
The method ensures that appy.css and appy.js come first.'''
|
||||||
names = self.getPhysicalRoot().ui.objectIds('File')
|
names = self.getPhysicalRoot().ui.objectIds('File')
|
||||||
|
|
|
@ -562,7 +562,10 @@ class BaseMixin:
|
||||||
field is supposed to belong to self's class.'''
|
field is supposed to belong to self's class.'''
|
||||||
isInnerType = '*' in name # An inner type lies within a List type.
|
isInnerType = '*' in name # An inner type lies within a List type.
|
||||||
subName = None
|
subName = None
|
||||||
if isInnerType: name, subName, i = name.split('*')
|
if isInnerType:
|
||||||
|
elems = name.split('*')
|
||||||
|
if len(elems) == 2: name, subName = elems
|
||||||
|
else: name, subName, i = elems
|
||||||
if not className:
|
if not className:
|
||||||
klass = self.__class__.wrapperClass
|
klass = self.__class__.wrapperClass
|
||||||
else:
|
else:
|
||||||
|
@ -614,10 +617,10 @@ class BaseMixin:
|
||||||
res.append(appyType)
|
res.append(appyType)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getCssAndJs(self, fields, layoutType):
|
def getCssJs(self, fields, layoutType):
|
||||||
'''Gets the list of Javascript and CSS files required by Appy types
|
'''Gets the list of Javascript and CSS files required by Appy types
|
||||||
p_fields when shown on p_layoutType.'''
|
p_fields when shown on p_layoutType.'''
|
||||||
# lists css and js below are not sets, because order of Javascript
|
# Lists css and js below are not sets, because order of Javascript
|
||||||
# inclusion can be important, and this could be losed by using sets.
|
# inclusion can be important, and this could be losed by using sets.
|
||||||
css = []
|
css = []
|
||||||
js = []
|
js = []
|
||||||
|
|
|
@ -12,18 +12,18 @@ acronym {cursor: help;}
|
||||||
input[type=image] { border: 0; background: none; }
|
input[type=image] { border: 0; background: none; }
|
||||||
input[type=checkbox] { border: 0; background: none; cursor: pointer;}
|
input[type=checkbox] { border: 0; background: none; cursor: pointer;}
|
||||||
input[type=radio] { border: 0; background: none; cursor: pointer;}
|
input[type=radio] { border: 0; background: none; cursor: pointer;}
|
||||||
input[type=file] { border: 0px solid #cccccc;
|
input[type=file] { border: 0px solid #D7DEE4;
|
||||||
background-color: #f8f8f8; cursor: pointer;}
|
background-color: #f8f8f8; cursor: pointer;}
|
||||||
input[type=button] { border: 1px solid #cccccc;
|
input[type=button] { border: 1px solid #D7DEE4;
|
||||||
background-color: #f8f8f8; cursor: pointer;}
|
background-color: #f8f8f8; cursor: pointer;}
|
||||||
input[type=submit] { border: 1px solid #cccccc; background-color: #f8f8f8;
|
input[type=submit] { border: 1px solid #D7DEE4; background-color: #f8f8f8;
|
||||||
cursor: pointer; }
|
cursor: pointer; }
|
||||||
input[type=password] { border: 1px solid #cccccc; background-color: #f8f8f8;
|
input[type=password] { border: 1px solid #D7DEE4; background-color: #f8f8f8;
|
||||||
font-family: Helvetica,Arial,sans-serif;}
|
font-family: Helvetica,Arial,sans-serif;}
|
||||||
input[type=text] { border: 1px solid #cccccc; background-color: #f8f8f8;
|
input[type=text] { border: 1px solid #D7DEE4; background-color: #f8f8f8;
|
||||||
font-family: Helvetica,Arial,sans-serif;
|
font-family: Helvetica,Arial,sans-serif;
|
||||||
margin-bottom: 1px}
|
margin-bottom: 1px}
|
||||||
select { border: 1px solid #cccccc; background-color: #f8f8f8;}
|
select { border: 1px solid #D7DEE4; background-color: #f8f8f8;}
|
||||||
|
|
||||||
textarea { width: 99%; font: 100% Helvetica,Arial,sans-serif;
|
textarea { width: 99%; font: 100% Helvetica,Arial,sans-serif;
|
||||||
border: 1px solid #a79e9e; background-color: #f8f8f8;}
|
border: 1px solid #a79e9e; background-color: #f8f8f8;}
|
||||||
|
@ -82,7 +82,7 @@ img {border: 0}
|
||||||
.section2 { font-size: 110%; font-style: italic; margin: 0.45em 0em 0.2em 0;
|
.section2 { font-size: 110%; font-style: italic; margin: 0.45em 0em 0.2em 0;
|
||||||
border-bottom: 2px solid grey; }
|
border-bottom: 2px solid grey; }
|
||||||
.section3 { font-size: 100%; font-style: italic; margin: 0.45em 0em 0.1em 0;
|
.section3 { font-size: 100%; font-style: italic; margin: 0.45em 0em 0.1em 0;
|
||||||
background-color: #efeae8; text-align: center; color: grey; }
|
background-color: #F4F5F6; text-align: center; color: grey; }
|
||||||
.odd { background-color: white; }
|
.odd { background-color: white; }
|
||||||
.even { background-color: #F4F5F6; }
|
.even { background-color: #F4F5F6; }
|
||||||
.summary {margin-bottom: 5px;}
|
.summary {margin-bottom: 5px;}
|
||||||
|
|
|
@ -502,26 +502,58 @@ function updateRowNumber(row, rowIndex, action) {
|
||||||
with new p_rowIndex. If p_action is 'set', p_rowIndex becomes the new
|
with new p_rowIndex. If p_action is 'set', p_rowIndex becomes the new
|
||||||
index. If p_action is 'add', new index becomes:
|
index. If p_action is 'add', new index becomes:
|
||||||
existing index + p_rowIndex. */
|
existing index + p_rowIndex. */
|
||||||
tagTypes = ['input', 'select'];
|
var tagTypes = ['input', 'select', 'img'];
|
||||||
currentIndex = -1;
|
var currentIndex = -1;
|
||||||
for (var i=0; i < tagTypes.length; i++) {
|
for (var i=0; i < tagTypes.length; i++) {
|
||||||
widgets = row.getElementsByTagName(tagTypes[i]);
|
var widgets = row.getElementsByTagName(tagTypes[i]);
|
||||||
for (var j=0; j < widgets.length; j++) {
|
for (var j=0; j < widgets.length; j++) {
|
||||||
id = widgets[j].id;
|
var id = widgets[j].id;
|
||||||
name = widgets[j].name;
|
if (!id) continue;
|
||||||
|
var name = widgets[j].name;
|
||||||
|
// Extract the suffix if there is one (ie, if the field is a Date part:
|
||||||
|
// _img, _day,...).
|
||||||
|
var iSuffix = id.lastIndexOf('_');
|
||||||
|
var idSuffix = '';
|
||||||
|
if (iSuffix != -1) {
|
||||||
|
idSuffix = id.substring(iSuffix);
|
||||||
|
id = id.substring(0, iSuffix);
|
||||||
|
}
|
||||||
|
var nSuffix = name.lastIndexOf('_');
|
||||||
|
var nameSuffix = '';
|
||||||
|
if (nSuffix != -1) {
|
||||||
|
nameSuffix = id.substring(nSuffix);
|
||||||
|
name = name.substring(0, nSuffix);
|
||||||
|
}
|
||||||
|
// Compute the current row index if not already done.
|
||||||
idNbIndex = id.lastIndexOf('*') + 1;
|
idNbIndex = id.lastIndexOf('*') + 1;
|
||||||
nameNbIndex = name.lastIndexOf('*') + 1;
|
nameNbIndex = name.lastIndexOf('*') + 1;
|
||||||
// Compute the current row index if not already done.
|
|
||||||
if (currentIndex == -1) {
|
if (currentIndex == -1) {
|
||||||
currentIndex = parseInt(id.substring(idNbIndex));
|
currentIndex = parseInt(id.substring(idNbIndex));
|
||||||
}
|
}
|
||||||
// Compute the new values for attributes "id" and "name".
|
// Compute the new values for attributes "id" and "name".
|
||||||
newId = id.substring(0, idNbIndex);
|
newId = id.substring(0, idNbIndex);
|
||||||
newName = id.substring(0, nameNbIndex);
|
newName = name.substring(0, nameNbIndex);
|
||||||
newIndex = rowIndex;
|
newIndex = rowIndex;
|
||||||
if (action == 'add') newIndex = newIndex + currentIndex;
|
if (action == 'add') newIndex = newIndex + currentIndex;
|
||||||
widgets[j].id = newId + String(newIndex);
|
var oldId = widgets[j].id;
|
||||||
widgets[j].name = newName + String(newIndex);
|
widgets[j].id = newId + String(newIndex) + idSuffix;
|
||||||
|
if (name) widgets[j].name = newName + String(newIndex) + nameSuffix;
|
||||||
|
/* In the case of an img that must show a calendar, update the script that
|
||||||
|
is triggered when clicking on it. */
|
||||||
|
if ((tagTypes[i] == 'img') && (idSuffix == '_img')) {
|
||||||
|
var scripts = row.getElementsByTagName('script');
|
||||||
|
for (var k=0; k < scripts.length; k++) {
|
||||||
|
var text = scripts[k].text;
|
||||||
|
if (text.indexOf(oldId) != -1) {
|
||||||
|
var oldIdField = oldId.substring(0, oldId.length-4);
|
||||||
|
var newIdField = widgets[j].id.substring(0, widgets[j].id.length-4);
|
||||||
|
text = text.replace(oldIdField, newIdField);
|
||||||
|
scripts[k].text = text.replace(oldId, widgets[j].id);
|
||||||
|
eval(scripts[k].text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -530,9 +562,9 @@ function insertRow(tableId) {
|
||||||
table = document.getElementById(tableId);
|
table = document.getElementById(tableId);
|
||||||
newRow = table.rows[1].cloneNode(true);
|
newRow = table.rows[1].cloneNode(true);
|
||||||
newRow.style.display = 'table-row';
|
newRow.style.display = 'table-row';
|
||||||
// Within newRow, I must include in field names and ids the row number
|
// Within newRow, incorporate the row number within field names and ids.
|
||||||
updateRowNumber(newRow, table.rows.length-3, 'set');
|
|
||||||
table.tBodies[0].appendChild(newRow);
|
table.tBodies[0].appendChild(newRow);
|
||||||
|
updateRowNumber(newRow, table.rows.length-4, 'set');
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteRow(tableId, deleteImg) {
|
function deleteRow(tableId, deleteImg) {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
phaseInfo python: contextObj.getAppyPhases(currentOnly=True, layoutType=layoutType);
|
phaseInfo python: contextObj.getAppyPhases(currentOnly=True, layoutType=layoutType);
|
||||||
phase phaseInfo/name;
|
phase phaseInfo/name;
|
||||||
page request/page|python:'main';
|
page request/page|python:'main';
|
||||||
cssJs python: contextObj.getCssAndJs(contextObj.getAppyTypes(layoutType, page), layoutType);
|
cssJs python: contextObj.getCssJs(contextObj.getAppyTypes(layoutType, page), layoutType);
|
||||||
confirmMsg request/confirmMsg | nothing;"
|
confirmMsg request/confirmMsg | nothing;"
|
||||||
tal:on-error="structure python: tool.manageError(error)">
|
tal:on-error="structure python: tool.manageError(error)">
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
tal:define="className request/className;
|
tal:define="className request/className;
|
||||||
refInfo request/ref|nothing;
|
refInfo request/ref|nothing;
|
||||||
searchInfo python: tool.getSearchInfo(className, refInfo);
|
searchInfo python: tool.getSearchInfo(className, refInfo);
|
||||||
cssJs python: tool.getCssAndJs(searchInfo['fields'], 'edit')">
|
cssJs python: tool.getCssJs(searchInfo['fields'], 'edit')">
|
||||||
|
|
||||||
<tal:comment replace="nothing">Include type-specific CSS and JS.</tal:comment>
|
<tal:comment replace="nothing">Include type-specific CSS and JS.</tal:comment>
|
||||||
<link tal:repeat="cssFile cssJs/css" rel="stylesheet" type="text/css"
|
<link tal:repeat="cssFile cssJs/css" rel="stylesheet" type="text/css"
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title tal:content="tool/getAppName"></title>
|
<title tal:content="tool/getAppName"></title>
|
||||||
<tal:link repeat="name tool/getCssJs">
|
<tal:link repeat="name tool/getGlobalCssJs">
|
||||||
<link tal:condition="python: name.endswith('.css')"
|
<link tal:condition="python: name.endswith('.css')"
|
||||||
rel="stylesheet" type="text/css" tal:attributes="href string:$appUrl/ui/$name"/>
|
rel="stylesheet" type="text/css" tal:attributes="href string:$appUrl/ui/$name"/>
|
||||||
<script tal:condition="python: name.endswith('.js')"
|
<script tal:condition="python: name.endswith('.js')"
|
||||||
|
|
Loading…
Reference in a new issue