appy.gen: bugfixes in the List field.

This commit is contained in:
Gaetan Delannay 2012-03-01 17:35:23 +01:00
parent 6d0549e6ce
commit 7d605d1fbb
8 changed files with 107 additions and 47 deletions

View file

@ -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'),

View file

@ -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')

View 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 = []

View file

@ -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;}

View file

@ -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) {

View file

@ -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)">

View file

@ -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"

View file

@ -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')"