[gen] Allow for ajax-based master-slave relationships within the search screen for Ref fields.
This commit is contained in:
parent
584e38abef
commit
6d6c842f12
16 changed files with 79 additions and 88 deletions
|
@ -51,15 +51,17 @@ class Field:
|
|||
pxRender = Px('''
|
||||
<x var="showChanges=showChanges|req.get('showChanges',False);
|
||||
layoutType=layoutType|req.get('layoutType');
|
||||
isSearch = layoutType == 'search';
|
||||
layout=field.layouts[layoutType];
|
||||
name=fieldName|field.name;
|
||||
widgetName = isSearch and ('w_%s' % name) or name;
|
||||
sync=field.sync[layoutType];
|
||||
outerValue=value|None;
|
||||
rawValue=zobj.getFieldValue(name, onlyIfSync=True, \
|
||||
layoutType=layoutType, \
|
||||
outerValue=outerValue);
|
||||
value=zobj.getFormattedFieldValue(name, rawValue, showChanges);
|
||||
requestValue=zobj.getRequestFieldValue(name);
|
||||
rawValue=not isSearch and zobj.getFieldValue(name, \
|
||||
onlyIfSync=True, layoutType=layoutType, outerValue=outerValue);
|
||||
value=not isSearch and \
|
||||
field.getFormattedValue(zobj, rawValue, showChanges);
|
||||
requestValue=not isSearch and zobj.getRequestFieldValue(name);
|
||||
inRequest=req.has_key(name);
|
||||
error=req.get('%s_error' % name);
|
||||
isMultiple=(field.multiplicity[1] == None) or \
|
||||
|
@ -68,6 +70,7 @@ class Field:
|
|||
slaveCss=field.getSlaveCss();
|
||||
tagCss=tagCss|'';
|
||||
tagCss=('%s %s' % (slaveCss, tagCss)).strip();
|
||||
zobj=zobj or ztool;
|
||||
tagId='%s_%s' % (zobj.UID(), name);
|
||||
tagName=field.master and 'slave' or '';
|
||||
layoutTarget=field">:tool.pxLayoutedObject</x>''')
|
||||
|
@ -345,8 +348,8 @@ class Field:
|
|||
'''Creates a dictionary indicating, for every layout type, if the field
|
||||
value must be retrieved synchronously or not.'''
|
||||
if isinstance(sync, bool):
|
||||
sync = {'edit': sync, 'view': sync, 'cell': sync}
|
||||
for layoutType in ('edit', 'view', 'cell'):
|
||||
sync = {'edit': sync, 'view': sync, 'cell': sync, 'search': sync}
|
||||
for layoutType in ('edit', 'view', 'search', 'cell'):
|
||||
if layoutType not in sync:
|
||||
sync[layoutType] = False
|
||||
return sync
|
||||
|
@ -405,9 +408,13 @@ class Field:
|
|||
for layoutType in layouts.iterkeys():
|
||||
if isinstance(layouts[layoutType], basestring):
|
||||
layouts[layoutType] = Table(layouts[layoutType])
|
||||
# Derive "view" and "cell" layouts from the "edit" layout when relevant
|
||||
# Derive "view", "search" and "cell" layouts from the "edit" layout
|
||||
# when relevant.
|
||||
if 'view' not in layouts:
|
||||
layouts['view'] = Table(other=layouts['edit'], derivedType='view')
|
||||
if 'search' not in layouts:
|
||||
layouts['search'] = Table(other=layouts['view'],
|
||||
derivedType='search')
|
||||
# Create the "cell" layout from the 'view' layout if not specified.
|
||||
if 'cell' not in layouts:
|
||||
layouts['cell'] = Table(other=layouts['view'], derivedType='cell')
|
||||
|
@ -587,14 +594,16 @@ class Field:
|
|||
res += '+'
|
||||
return res
|
||||
|
||||
def getOnChange(self, zobj, layoutType):
|
||||
def getOnChange(self, zobj, layoutType, className=None):
|
||||
'''When this field is a master, this method computes the call to the
|
||||
Javascript function that will be called when its value changes (in
|
||||
order to update slaves).'''
|
||||
if not self.slaves: return ''
|
||||
q = zobj.getTool().quote
|
||||
return 'updateSlaves(this,null,%s,%s)' % \
|
||||
(q(zobj.absolute_url()), q(layoutType))
|
||||
# When the field is on a search screen, we need p_className.
|
||||
cName = className and (',%s' % q(className)) or ''
|
||||
return 'updateSlaves(this,null,%s,%s,null,null%s)' % \
|
||||
(q(zobj.absolute_url()), q(layoutType), cName)
|
||||
|
||||
def isEmptyValue(self, value, obj=None):
|
||||
'''Returns True if the p_value must be considered as an empty value.'''
|
||||
|
|
|
@ -38,9 +38,7 @@ class Boolean(Field):
|
|||
value=":isChecked and 'True' or 'False'"/>
|
||||
</x>''')
|
||||
|
||||
pxSearch = Px('''
|
||||
<x var="typedWidget='%s*bool' % widgetName">
|
||||
<label lfor=":widgetName">:_(field.labelId)</label><br/>
|
||||
pxSearch = Px('''<x var="typedWidget='%s*bool' % widgetName">
|
||||
<x var="valueId='%s_yes' % name">
|
||||
<input type="radio" value="True" name=":typedWidget" id=":valueId"/>
|
||||
<label lfor=":valueId">:_('yes')</label>
|
||||
|
@ -53,8 +51,7 @@ class Boolean(Field):
|
|||
<input type="radio" value="" name=":typedWidget" id=":valueId"
|
||||
checked="checked"/>
|
||||
<label lfor=":valueId">:_('whatever')</label>
|
||||
</x><br/>
|
||||
</x>''')
|
||||
</x><br/></x>''')
|
||||
|
||||
def __init__(self, validator=None, multiplicity=(0,1), default=None,
|
||||
show=True, page='main', group=None, layouts = None, move=0,
|
||||
|
|
|
@ -38,11 +38,9 @@ class Computed(Field):
|
|||
</div>
|
||||
</x>''')
|
||||
|
||||
pxSearch = Px('''<x>
|
||||
<label lfor=":name">:field.labelId</label><br/>
|
||||
pxSearch = Px('''
|
||||
<input type="text" name=":'%s*string' % name" maxlength=":field.maxChars"
|
||||
size=":field.width" value=":field.sdefault"/>
|
||||
</x>''')
|
||||
size=":field.width" value=":field.sdefault"/>''')
|
||||
|
||||
def __init__(self, validator=None, multiplicity=(0,1), default=None,
|
||||
show=('view', 'result'), page='main', group=None,
|
||||
|
|
|
@ -81,10 +81,7 @@ class Date(Field):
|
|||
</x>
|
||||
</x>''')
|
||||
|
||||
pxSearch = Px('''
|
||||
<x var="years=range(field.startYear, field.endYear+1)">
|
||||
<label>:_(field.labelId)</label>
|
||||
<table>
|
||||
pxSearch = Px('''<table var="years=range(field.startYear, field.endYear+1)">
|
||||
<!-- From -->
|
||||
<tr var="fromName='%s_from' % name;
|
||||
dayFromName='%s_from_day' % name;
|
||||
|
@ -150,8 +147,7 @@ class Date(Field):
|
|||
</x>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</x>''')
|
||||
</table>''')
|
||||
|
||||
# Required CSS and Javascript files for this type.
|
||||
cssFiles = {'edit': ('jscalendar/calendar-blue.css',)}
|
||||
|
|
|
@ -35,8 +35,7 @@ class Float(Field):
|
|||
maxlength=":field.maxChars"
|
||||
value=":inRequest and requestValue or value" type="text"/>''')
|
||||
|
||||
pxSearch = Px('''<x>
|
||||
<label>:_(field.labelId)</label><br/>
|
||||
pxSearch = Px('''
|
||||
<!-- From -->
|
||||
<x var="fromName='%s*float' % widgetName">
|
||||
<label lfor=":fromName">:_('search_from')</label>
|
||||
|
@ -48,8 +47,7 @@ class Float(Field):
|
|||
<label lfor=":toName">:_('search_to')</label>
|
||||
<input type="text" name=":toName" maxlength=":field.maxChars"
|
||||
value=":field.sdefault[1]" size="field.swidth"/>
|
||||
</x><br/>
|
||||
</x>''')
|
||||
</x><br/>''')
|
||||
|
||||
def __init__(self, validator=None, multiplicity=(0,1), default=None,
|
||||
show=True, page='main', group=None, layouts=None, move=0,
|
||||
|
|
|
@ -32,8 +32,7 @@ class Integer(Field):
|
|||
maxlength=":field.maxChars"
|
||||
value=":inRequest and requestValue or value" type="text"/>''')
|
||||
|
||||
pxSearch = Px('''<x>
|
||||
<label>:_(field.labelId)</label><br/>
|
||||
pxSearch = Px('''
|
||||
<!-- From -->
|
||||
<x var="fromName='%s*int' % widgetName">
|
||||
<label lfor=":fromName">:_('search_from')</label>
|
||||
|
@ -45,8 +44,7 @@ class Integer(Field):
|
|||
<label lfor=":toName">:_('search_to')</label>
|
||||
<input type="text" name=":toName" maxlength=":field.maxChars"
|
||||
value=":field.sdefault[1]" size=":field.swidth"/>
|
||||
</x><br/>
|
||||
</x>''')
|
||||
</x><br/>''')
|
||||
|
||||
def __init__(self, validator=None, multiplicity=(0,1), default=None,
|
||||
show=True, page='main', group=None, layouts=None, move=0,
|
||||
|
|
|
@ -282,21 +282,20 @@ class Ref(Field):
|
|||
|
||||
pxEdit = Px('''
|
||||
<select if="field.link"
|
||||
var2="zobjects=field.getSelectableObjects(obj);
|
||||
var2="objects=field.getPossibleValues(obj);
|
||||
uids=[o.UID() for o in \
|
||||
field.getLinkedObjects(zobj).objects]"
|
||||
name=":name" id=":name" size=":isMultiple and field.height or ''"
|
||||
onchange=":field.getOnChange(zobj, layoutType)"
|
||||
multiple=":isMultiple">
|
||||
<option value="" if="not isMultiple">:_('choose_a_value')</option>
|
||||
<option for="ztied in zobjects" var2="uid=ztied.o.UID()"
|
||||
<option for="tied in objects" var2="uid=tied.uid"
|
||||
selected=":inRequest and (uid in requestValue) or \
|
||||
(uid in uids)"
|
||||
value=":uid">:field.getReferenceLabel(ztied)</option>
|
||||
value=":uid">:field.getReferenceLabel(tied)</option>
|
||||
</select>''')
|
||||
|
||||
pxSearch = Px('''<x>
|
||||
<label lfor=":widgetName">:_(field.labelId)</label><br/>
|
||||
pxSearch = Px('''
|
||||
<!-- The "and" / "or" radio buttons -->
|
||||
<x if="field.multiplicity[1] != 1"
|
||||
var2="operName='o_%s' % name;
|
||||
|
@ -309,12 +308,14 @@ class Ref(Field):
|
|||
<label lfor=":andName">:_('search_and')</label><br/>
|
||||
</x>
|
||||
<!-- The list of values -->
|
||||
<select name=":widgetName" size=":field.sheight" multiple="multiple">
|
||||
<option for="v in ztool.getSearchValues(name, className)"
|
||||
var2="uid=v[0]; title=field.getReferenceLabel(v[1])" value=":uid"
|
||||
title=":title">:ztool.truncateValue(title,field.swidth)</option>
|
||||
</select>
|
||||
</x>''')
|
||||
<select var="objects=field.getPossibleValues(tool);
|
||||
selectAll='masterValues' in req"
|
||||
name=":widgetName" size=":field.sheight" multiple="multiple"
|
||||
onchange=":field.getOnChange(ztool, 'search', className)">
|
||||
<option for="tied in objects" value=":tied.uid" selected=":selectAll"
|
||||
var2="title=field.getReferenceLabel(tied, unlimited=True)"
|
||||
title=":title">:ztool.truncateValue(title, field.swidth)</option>
|
||||
</select>''')
|
||||
|
||||
def __init__(self, klass=None, attribute=None, validator=None,
|
||||
multiplicity=(0,1), default=None, add=False, addConfirm=False,
|
||||
|
@ -740,11 +741,12 @@ class Ref(Field):
|
|||
newIndex = oldIndex + move
|
||||
uids.insert(newIndex, uid)
|
||||
|
||||
def getSelectableObjects(self, obj):
|
||||
'''This method returns the list of all objects that can be selected to
|
||||
be linked as references to p_obj via p_self. If master values are
|
||||
present in the request, we use field.masterValues method instead of
|
||||
self.select.'''
|
||||
def getPossibleValues(self, obj):
|
||||
'''This method returns the list of all objects that can be selected
|
||||
to be linked as references to p_obj via p_self. It is applicable only
|
||||
for ref fields with link=True. If master values are present in the
|
||||
request, we use field.masterValues method instead of self.select.
|
||||
'''
|
||||
req = obj.request
|
||||
if 'masterValues' in req:
|
||||
# Convert masterValue(s) from UID(s) to real object(s).
|
||||
|
@ -762,8 +764,8 @@ class Ref(Field):
|
|||
else:
|
||||
# If this field is a ajax-updatable slave, no need to compute
|
||||
# selectable objects: it will be overridden by method
|
||||
# self.masterValue by a subsequent ajax request (=the "if" statement
|
||||
# above).
|
||||
# self.masterValue by a subsequent ajax request (=the "if"
|
||||
# statement above).
|
||||
if self.masterValue and callable(self.masterValue): return []
|
||||
if not self.select:
|
||||
# No select method has been defined: we must retrieve all
|
||||
|
@ -774,7 +776,7 @@ class Ref(Field):
|
|||
return self.select(obj)
|
||||
|
||||
xhtmlToText = re.compile('<.*?>', re.S)
|
||||
def getReferenceLabel(self, refObject):
|
||||
def getReferenceLabel(self, refObject, unlimited=False):
|
||||
'''p_self must have link=True. I need to display, on an edit view, the
|
||||
p_refObject in the listbox that will allow the user to choose which
|
||||
object(s) to link through the Ref. The information to display may
|
||||
|
@ -793,6 +795,7 @@ class Ref(Field):
|
|||
if res:
|
||||
prefix = ' | '
|
||||
res += prefix + value
|
||||
if unlimited: return res
|
||||
maxWidth = self.width or 30
|
||||
if len(res) > maxWidth:
|
||||
res = res[:maxWidth-2] + '...'
|
||||
|
|
|
@ -144,8 +144,7 @@ class String(Field):
|
|||
<x if="not multipleValues">:field.pxView</x>
|
||||
</x>''')
|
||||
|
||||
pxSearch = Px('''<x>
|
||||
<label lfor="widgetName">:_(field.labelId)</label><br/>
|
||||
pxSearch = Px('''
|
||||
<!-- Show a simple search field for most String fields -->
|
||||
<input if="not field.isSelect" type="text" maxlength=":field.maxChars"
|
||||
size=":field.swidth" value=":field.sdefault"
|
||||
|
@ -173,8 +172,7 @@ class String(Field):
|
|||
selected=":v[0] in preSelected" value=":v[0]"
|
||||
title=":v[1]">:ztool.truncateValue(v[1], field.swidth)</option>
|
||||
</select>
|
||||
</x><br/>
|
||||
</x>''')
|
||||
</x><br/>''')
|
||||
|
||||
# Some predefined functions that may also be used as validators
|
||||
@staticmethod
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue