[gen] Allow for ajax-based master-slave relationships within the search screen for Ref fields.

This commit is contained in:
Gaetan Delannay 2014-03-05 13:25:36 +01:00
parent 584e38abef
commit 6d6c842f12
16 changed files with 79 additions and 88 deletions

View file

@ -51,15 +51,17 @@ class Field:
pxRender = Px(''' pxRender = Px('''
<x var="showChanges=showChanges|req.get('showChanges',False); <x var="showChanges=showChanges|req.get('showChanges',False);
layoutType=layoutType|req.get('layoutType'); layoutType=layoutType|req.get('layoutType');
isSearch = layoutType == 'search';
layout=field.layouts[layoutType]; layout=field.layouts[layoutType];
name=fieldName|field.name; name=fieldName|field.name;
widgetName = isSearch and ('w_%s' % name) or name;
sync=field.sync[layoutType]; sync=field.sync[layoutType];
outerValue=value|None; outerValue=value|None;
rawValue=zobj.getFieldValue(name, onlyIfSync=True, \ rawValue=not isSearch and zobj.getFieldValue(name, \
layoutType=layoutType, \ onlyIfSync=True, layoutType=layoutType, outerValue=outerValue);
outerValue=outerValue); value=not isSearch and \
value=zobj.getFormattedFieldValue(name, rawValue, showChanges); field.getFormattedValue(zobj, rawValue, showChanges);
requestValue=zobj.getRequestFieldValue(name); requestValue=not isSearch and zobj.getRequestFieldValue(name);
inRequest=req.has_key(name); inRequest=req.has_key(name);
error=req.get('%s_error' % name); error=req.get('%s_error' % name);
isMultiple=(field.multiplicity[1] == None) or \ isMultiple=(field.multiplicity[1] == None) or \
@ -68,6 +70,7 @@ class Field:
slaveCss=field.getSlaveCss(); slaveCss=field.getSlaveCss();
tagCss=tagCss|''; tagCss=tagCss|'';
tagCss=('%s %s' % (slaveCss, tagCss)).strip(); tagCss=('%s %s' % (slaveCss, tagCss)).strip();
zobj=zobj or ztool;
tagId='%s_%s' % (zobj.UID(), name); tagId='%s_%s' % (zobj.UID(), name);
tagName=field.master and 'slave' or ''; tagName=field.master and 'slave' or '';
layoutTarget=field">:tool.pxLayoutedObject</x>''') layoutTarget=field">:tool.pxLayoutedObject</x>''')
@ -345,8 +348,8 @@ class Field:
'''Creates a dictionary indicating, for every layout type, if the field '''Creates a dictionary indicating, for every layout type, if the field
value must be retrieved synchronously or not.''' value must be retrieved synchronously or not.'''
if isinstance(sync, bool): if isinstance(sync, bool):
sync = {'edit': sync, 'view': sync, 'cell': sync} sync = {'edit': sync, 'view': sync, 'cell': sync, 'search': sync}
for layoutType in ('edit', 'view', 'cell'): for layoutType in ('edit', 'view', 'search', 'cell'):
if layoutType not in sync: if layoutType not in sync:
sync[layoutType] = False sync[layoutType] = False
return sync return sync
@ -405,9 +408,13 @@ class Field:
for layoutType in layouts.iterkeys(): for layoutType in layouts.iterkeys():
if isinstance(layouts[layoutType], basestring): if isinstance(layouts[layoutType], basestring):
layouts[layoutType] = Table(layouts[layoutType]) 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: if 'view' not in layouts:
layouts['view'] = Table(other=layouts['edit'], derivedType='view') 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. # Create the "cell" layout from the 'view' layout if not specified.
if 'cell' not in layouts: if 'cell' not in layouts:
layouts['cell'] = Table(other=layouts['view'], derivedType='cell') layouts['cell'] = Table(other=layouts['view'], derivedType='cell')
@ -587,14 +594,16 @@ class Field:
res += '+' res += '+'
return 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 '''When this field is a master, this method computes the call to the
Javascript function that will be called when its value changes (in Javascript function that will be called when its value changes (in
order to update slaves).''' order to update slaves).'''
if not self.slaves: return '' if not self.slaves: return ''
q = zobj.getTool().quote q = zobj.getTool().quote
return 'updateSlaves(this,null,%s,%s)' % \ # When the field is on a search screen, we need p_className.
(q(zobj.absolute_url()), q(layoutType)) 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): def isEmptyValue(self, value, obj=None):
'''Returns True if the p_value must be considered as an empty value.''' '''Returns True if the p_value must be considered as an empty value.'''

View file

@ -38,9 +38,7 @@ class Boolean(Field):
value=":isChecked and 'True' or 'False'"/> value=":isChecked and 'True' or 'False'"/>
</x>''') </x>''')
pxSearch = Px(''' pxSearch = Px('''<x var="typedWidget='%s*bool' % widgetName">
<x var="typedWidget='%s*bool' % widgetName">
<label lfor=":widgetName">:_(field.labelId)</label><br/>&nbsp;&nbsp;
<x var="valueId='%s_yes' % name"> <x var="valueId='%s_yes' % name">
<input type="radio" value="True" name=":typedWidget" id=":valueId"/> <input type="radio" value="True" name=":typedWidget" id=":valueId"/>
<label lfor=":valueId">:_('yes')</label> <label lfor=":valueId">:_('yes')</label>
@ -53,8 +51,7 @@ class Boolean(Field):
<input type="radio" value="" name=":typedWidget" id=":valueId" <input type="radio" value="" name=":typedWidget" id=":valueId"
checked="checked"/> checked="checked"/>
<label lfor=":valueId">:_('whatever')</label> <label lfor=":valueId">:_('whatever')</label>
</x><br/> </x><br/></x>''')
</x>''')
def __init__(self, validator=None, multiplicity=(0,1), default=None, def __init__(self, validator=None, multiplicity=(0,1), default=None,
show=True, page='main', group=None, layouts = None, move=0, show=True, page='main', group=None, layouts = None, move=0,

View file

@ -38,11 +38,9 @@ class Computed(Field):
</div> </div>
</x>''') </x>''')
pxSearch = Px('''<x> pxSearch = Px('''
<label lfor=":name">:field.labelId</label><br/>&nbsp;&nbsp;
<input type="text" name=":'%s*string' % name" maxlength=":field.maxChars" <input type="text" name=":'%s*string' % name" maxlength=":field.maxChars"
size=":field.width" value=":field.sdefault"/> size=":field.width" value=":field.sdefault"/>''')
</x>''')
def __init__(self, validator=None, multiplicity=(0,1), default=None, def __init__(self, validator=None, multiplicity=(0,1), default=None,
show=('view', 'result'), page='main', group=None, show=('view', 'result'), page='main', group=None,

View file

@ -81,10 +81,7 @@ class Date(Field):
</x> </x>
</x>''') </x>''')
pxSearch = Px(''' pxSearch = Px('''<table var="years=range(field.startYear, field.endYear+1)">
<x var="years=range(field.startYear, field.endYear+1)">
<label>:_(field.labelId)</label>
<table>
<!-- From --> <!-- From -->
<tr var="fromName='%s_from' % name; <tr var="fromName='%s_from' % name;
dayFromName='%s_from_day' % name; dayFromName='%s_from_day' % name;
@ -150,8 +147,7 @@ class Date(Field):
</x> </x>
</td> </td>
</tr> </tr>
</table> </table>''')
</x>''')
# Required CSS and Javascript files for this type. # Required CSS and Javascript files for this type.
cssFiles = {'edit': ('jscalendar/calendar-blue.css',)} cssFiles = {'edit': ('jscalendar/calendar-blue.css',)}

View file

@ -35,8 +35,7 @@ class Float(Field):
maxlength=":field.maxChars" maxlength=":field.maxChars"
value=":inRequest and requestValue or value" type="text"/>''') value=":inRequest and requestValue or value" type="text"/>''')
pxSearch = Px('''<x> pxSearch = Px('''
<label>:_(field.labelId)</label><br/>&nbsp;&nbsp;
<!-- From --> <!-- From -->
<x var="fromName='%s*float' % widgetName"> <x var="fromName='%s*float' % widgetName">
<label lfor=":fromName">:_('search_from')</label> <label lfor=":fromName">:_('search_from')</label>
@ -48,8 +47,7 @@ class Float(Field):
<label lfor=":toName">:_('search_to')</label> <label lfor=":toName">:_('search_to')</label>
<input type="text" name=":toName" maxlength=":field.maxChars" <input type="text" name=":toName" maxlength=":field.maxChars"
value=":field.sdefault[1]" size="field.swidth"/> value=":field.sdefault[1]" size="field.swidth"/>
</x><br/> </x><br/>''')
</x>''')
def __init__(self, validator=None, multiplicity=(0,1), default=None, def __init__(self, validator=None, multiplicity=(0,1), default=None,
show=True, page='main', group=None, layouts=None, move=0, show=True, page='main', group=None, layouts=None, move=0,

View file

@ -32,8 +32,7 @@ class Integer(Field):
maxlength=":field.maxChars" maxlength=":field.maxChars"
value=":inRequest and requestValue or value" type="text"/>''') value=":inRequest and requestValue or value" type="text"/>''')
pxSearch = Px('''<x> pxSearch = Px('''
<label>:_(field.labelId)</label><br/>&nbsp;&nbsp;
<!-- From --> <!-- From -->
<x var="fromName='%s*int' % widgetName"> <x var="fromName='%s*int' % widgetName">
<label lfor=":fromName">:_('search_from')</label> <label lfor=":fromName">:_('search_from')</label>
@ -45,8 +44,7 @@ class Integer(Field):
<label lfor=":toName">:_('search_to')</label> <label lfor=":toName">:_('search_to')</label>
<input type="text" name=":toName" maxlength=":field.maxChars" <input type="text" name=":toName" maxlength=":field.maxChars"
value=":field.sdefault[1]" size=":field.swidth"/> value=":field.sdefault[1]" size=":field.swidth"/>
</x><br/> </x><br/>''')
</x>''')
def __init__(self, validator=None, multiplicity=(0,1), default=None, def __init__(self, validator=None, multiplicity=(0,1), default=None,
show=True, page='main', group=None, layouts=None, move=0, show=True, page='main', group=None, layouts=None, move=0,

View file

@ -282,21 +282,20 @@ class Ref(Field):
pxEdit = Px(''' pxEdit = Px('''
<select if="field.link" <select if="field.link"
var2="zobjects=field.getSelectableObjects(obj); var2="objects=field.getPossibleValues(obj);
uids=[o.UID() for o in \ uids=[o.UID() for o in \
field.getLinkedObjects(zobj).objects]" field.getLinkedObjects(zobj).objects]"
name=":name" id=":name" size=":isMultiple and field.height or ''" name=":name" id=":name" size=":isMultiple and field.height or ''"
onchange=":field.getOnChange(zobj, layoutType)" onchange=":field.getOnChange(zobj, layoutType)"
multiple=":isMultiple"> multiple=":isMultiple">
<option value="" if="not isMultiple">:_('choose_a_value')</option> <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 \ selected=":inRequest and (uid in requestValue) or \
(uid in uids)" (uid in uids)"
value=":uid">:field.getReferenceLabel(ztied)</option> value=":uid">:field.getReferenceLabel(tied)</option>
</select>''') </select>''')
pxSearch = Px('''<x> pxSearch = Px('''
<label lfor=":widgetName">:_(field.labelId)</label><br/>&nbsp;&nbsp;
<!-- The "and" / "or" radio buttons --> <!-- The "and" / "or" radio buttons -->
<x if="field.multiplicity[1] != 1" <x if="field.multiplicity[1] != 1"
var2="operName='o_%s' % name; var2="operName='o_%s' % name;
@ -309,12 +308,14 @@ class Ref(Field):
<label lfor=":andName">:_('search_and')</label><br/> <label lfor=":andName">:_('search_and')</label><br/>
</x> </x>
<!-- The list of values --> <!-- The list of values -->
<select name=":widgetName" size=":field.sheight" multiple="multiple"> <select var="objects=field.getPossibleValues(tool);
<option for="v in ztool.getSearchValues(name, className)" selectAll='masterValues' in req"
var2="uid=v[0]; title=field.getReferenceLabel(v[1])" value=":uid" name=":widgetName" size=":field.sheight" multiple="multiple"
title=":title">:ztool.truncateValue(title,field.swidth)</option> onchange=":field.getOnChange(ztool, 'search', className)">
</select> <option for="tied in objects" value=":tied.uid" selected=":selectAll"
</x>''') 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, def __init__(self, klass=None, attribute=None, validator=None,
multiplicity=(0,1), default=None, add=False, addConfirm=False, multiplicity=(0,1), default=None, add=False, addConfirm=False,
@ -740,11 +741,12 @@ class Ref(Field):
newIndex = oldIndex + move newIndex = oldIndex + move
uids.insert(newIndex, uid) uids.insert(newIndex, uid)
def getSelectableObjects(self, obj): def getPossibleValues(self, obj):
'''This method returns the list of all objects that can be selected to '''This method returns the list of all objects that can be selected
be linked as references to p_obj via p_self. If master values are to be linked as references to p_obj via p_self. It is applicable only
present in the request, we use field.masterValues method instead of for ref fields with link=True. If master values are present in the
self.select.''' request, we use field.masterValues method instead of self.select.
'''
req = obj.request req = obj.request
if 'masterValues' in req: if 'masterValues' in req:
# Convert masterValue(s) from UID(s) to real object(s). # Convert masterValue(s) from UID(s) to real object(s).
@ -762,8 +764,8 @@ class Ref(Field):
else: else:
# If this field is a ajax-updatable slave, no need to compute # If this field is a ajax-updatable slave, no need to compute
# selectable objects: it will be overridden by method # selectable objects: it will be overridden by method
# self.masterValue by a subsequent ajax request (=the "if" statement # self.masterValue by a subsequent ajax request (=the "if"
# above). # statement above).
if self.masterValue and callable(self.masterValue): return [] if self.masterValue and callable(self.masterValue): return []
if not self.select: if not self.select:
# No select method has been defined: we must retrieve all # No select method has been defined: we must retrieve all
@ -774,7 +776,7 @@ class Ref(Field):
return self.select(obj) return self.select(obj)
xhtmlToText = re.compile('<.*?>', re.S) 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_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 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 object(s) to link through the Ref. The information to display may
@ -793,6 +795,7 @@ class Ref(Field):
if res: if res:
prefix = ' | ' prefix = ' | '
res += prefix + value res += prefix + value
if unlimited: return res
maxWidth = self.width or 30 maxWidth = self.width or 30
if len(res) > maxWidth: if len(res) > maxWidth:
res = res[:maxWidth-2] + '...' res = res[:maxWidth-2] + '...'

View file

@ -144,8 +144,7 @@ class String(Field):
<x if="not multipleValues">:field.pxView</x> <x if="not multipleValues">:field.pxView</x>
</x>''') </x>''')
pxSearch = Px('''<x> pxSearch = Px('''
<label lfor="widgetName">:_(field.labelId)</label><br/>&nbsp;&nbsp;
<!-- Show a simple search field for most String fields --> <!-- Show a simple search field for most String fields -->
<input if="not field.isSelect" type="text" maxlength=":field.maxChars" <input if="not field.isSelect" type="text" maxlength=":field.maxChars"
size=":field.swidth" value=":field.sdefault" size=":field.swidth" value=":field.sdefault"
@ -173,8 +172,7 @@ class String(Field):
selected=":v[0] in preSelected" value=":v[0]" selected=":v[0] in preSelected" value=":v[0]"
title=":v[1]">:ztool.truncateValue(v[1], field.swidth)</option> title=":v[1]">:ztool.truncateValue(v[1], field.swidth)</option>
</select> </select>
</x><br/> </x><br/>''')
</x>''')
# Some predefined functions that may also be used as validators # Some predefined functions that may also be used as validators
@staticmethod @staticmethod

View file

@ -7,6 +7,7 @@
# "edit" represents a given page for a given Appy class, in edit mode. # "edit" represents a given page for a given Appy class, in edit mode.
# "cell" represents a cell in a table, like when we need to render a field # "cell" represents a cell in a table, like when we need to render a field
# value in a query result or in a reference table. # value in a query result or in a reference table.
# "search" represents an advanced search screen.
# Layout elements for a class or page ------------------------------------------ # Layout elements for a class or page ------------------------------------------
# s - The page summary, containing summarized information about the page or # s - The page summary, containing summarized information about the page or
@ -113,7 +114,7 @@ class Table:
'''Represents a table where to dispose graphical elements.''' '''Represents a table where to dispose graphical elements.'''
simpleParams = ('style', 'css_class', 'cellpadding', 'cellspacing', 'width', simpleParams = ('style', 'css_class', 'cellpadding', 'cellspacing', 'width',
'align') 'align')
derivedRepls = {'view': 'hrvd', 'cell': 'ldc'} derivedRepls = {'view': 'hrvd', 'search': '', 'cell': 'ldc'}
def __init__(self, layoutString=None, style=None, css_class='', def __init__(self, layoutString=None, style=None, css_class='',
cellpadding=0, cellspacing=0, width='100%', align='left', cellpadding=0, cellspacing=0, width='100%', align='left',
other=None, derivedType=None): other=None, derivedType=None):

View file

@ -648,6 +648,8 @@ class ToolMixin(BaseMixin):
for attrName in rq.form.keys(): for attrName in rq.form.keys():
if attrName.startswith('w_') and \ if attrName.startswith('w_') and \
not self._searchValueIsEmpty(attrName): not self._searchValueIsEmpty(attrName):
field = self.getAppyType(attrName[2:], rq.form['className'])
if not field.persist: continue
# We have a(n interval of) value(s) that is not empty for a # We have a(n interval of) value(s) that is not empty for a
# given field. # given field.
attrValue = rq.form[attrName] attrValue = rq.form[attrName]
@ -1384,18 +1386,6 @@ class ToolMixin(BaseMixin):
res = self.goto(siteUrl, self.translate('wrong_password_reinit')) res = self.goto(siteUrl, self.translate('wrong_password_reinit'))
return res return res
def getSearchValues(self, name, className):
'''Gets the possible values for selecting a value for searching field
p_name belonging to class p_className.'''
klass = self.getAppyClass(className, wrapper=True)
method = getattr(klass, name).searchSelect
tool = self.appy()
if method.__class__.__name__ == 'function':
objects = method(tool)
else:
objects = method.__get__(tool)(tool)
return [(o.uid, o) for o in objects]
def getGoogleAnalyticsCode(self): def getGoogleAnalyticsCode(self):
'''If the config defined a Google Analytics ID, this method returns the '''If the config defined a Google Analytics ID, this method returns the
Javascript code to be included in every page, allowing Google Javascript code to be included in every page, allowing Google

View file

@ -690,6 +690,7 @@ class BaseMixin:
'''Returns the database value of field named p_name for p_self. '''Returns the database value of field named p_name for p_self.
If p_onlyIfSync is True, it returns the value only if appyType can be If p_onlyIfSync is True, it returns the value only if appyType can be
retrieved in synchronous mode.''' retrieved in synchronous mode.'''
if layoutType == 'search': return # No object in search screens.
field = self.getAppyType(name) field = self.getAppyType(name)
if not onlyIfSync or (onlyIfSync and field.sync[layoutType]): if not onlyIfSync or (onlyIfSync and field.sync[layoutType]):
# We must really get the field value. # We must really get the field value.
@ -699,11 +700,6 @@ class BaseMixin:
listType = self.getAppyType(listName) listType = self.getAppyType(listName)
return listType.getInnerValue(self, outerValue, name, int(i)) return listType.getInnerValue(self, outerValue, name, int(i))
def getFormattedFieldValue(self, name, value, showChanges=False):
'''Gets a nice, string representation of p_value which is a value from
field named p_name.'''
return self.getAppyType(name).getFormattedValue(self,value,showChanges)
def getRequestFieldValue(self, name): def getRequestFieldValue(self, name):
'''Gets the value of field p_name as may be present in the request.''' '''Gets the value of field p_name as may be present in the request.'''
# Return the request value for standard fields. # Return the request value for standard fields.

View file

@ -10,7 +10,8 @@ from appy.gen.wrappers.TranslationWrapper import TranslationWrapper as WT
from appy.gen.wrappers.PageWrapper import PageWrapper as WPage from appy.gen.wrappers.PageWrapper import PageWrapper as WPage
from Globals import InitializeClass from Globals import InitializeClass
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
tfw = {"edit":"f","cell":"f","view":"f"} # Layout for Translation fields # Layouts for Translation fields
tfw = {"edit":"f","cell":"f","view":"f","search":"f"}
<!imports!> <!imports!>
<!User!> <!User!>

View file

@ -93,6 +93,7 @@ input.button { border-width: 0 !important; color: #666666; height: 23px;
margin: 0.1em 0 0.3em ; border-bottom: 1px dashed grey } margin: 0.1em 0 0.3em ; border-bottom: 1px dashed grey }
.portletSearch { font-size: 90%; font-style: italic } .portletSearch { font-size: 90%; font-style: italic }
.inputSearch { height: 15px; width: 132px; margin: 3px 3px 2px 3px !important } .inputSearch { height: 15px; width: 132px; margin: 3px 3px 2px 3px !important }
td.search { padding-top: 8px }
.content { padding: 14px 14px 9px 15px; background-color: #f1f1f1 } .content { padding: 14px 14px 9px 15px; background-color: #f1f1f1 }
.grey { display: none; position: absolute; left: 0px; top: 0px; z-index:2; .grey { display: none; position: absolute; left: 0px; top: 0px; z-index:2;
background:grey; opacity:0.5; -moz-opacity:0.5; -khtml-opacity:0.5; background:grey; opacity:0.5; -moz-opacity:0.5; -khtml-opacity:0.5;

View file

@ -244,15 +244,16 @@ function askComputedField(hookId, objectUrl, fieldName) {
} }
function askField(hookId, objectUrl, layoutType, showChanges, masterValues, function askField(hookId, objectUrl, layoutType, showChanges, masterValues,
requestValue, error){ requestValue, error, className){
// Sends an Ajax request for getting the content of any field. // Sends an Ajax request for getting the content of any field.
var fieldName = hookId.split('_')[1]; var fieldName = hookId.split('_')[1];
var params = {'layoutType': layoutType, 'showChanges': showChanges}; var params = {'layoutType': layoutType, 'showChanges': showChanges};
if (masterValues) params['masterValues'] = masterValues.join('*'); if (masterValues) params['masterValues'] = masterValues.join('*');
if (requestValue) params[fieldName] = requestValue; if (requestValue) params[fieldName] = requestValue;
if (error) params[fieldName + '_error'] = error; if (error) params[fieldName + '_error'] = error;
askAjaxChunk(hookId, 'GET', objectUrl, fieldName+':pxRender', params, null, var px = fieldName + ':pxRender';
evalInnerScripts); if (className) px = className + ':' + px;
askAjaxChunk(hookId, 'GET', objectUrl, px, params, null, evalInnerScripts);
} }
// Function used by checkbox widgets for having radio-button-like behaviour // Function used by checkbox widgets for having radio-button-like behaviour
@ -354,6 +355,8 @@ function getSlaves(master) {
allSlaves = getElementsHavingName('table', 'slave'); allSlaves = getElementsHavingName('table', 'slave');
res = []; res = [];
masterName = master.attributes['name'].value; masterName = master.attributes['name'].value;
// Remove leading 'w_' if the master is in a search screen.
if (masterName.indexOf('w_') == 0) masterName = masterName.slice(2);
if (master.type == 'checkbox') { if (master.type == 'checkbox') {
masterName = masterName.substr(0, masterName.length-8); masterName = masterName.substr(0, masterName.length-8);
} }
@ -370,7 +373,8 @@ function getSlaves(master) {
return res; return res;
} }
function updateSlaves(master,slave,objectUrl,layoutType,requestValues,errors){ function updateSlaves(master, slave, objectUrl, layoutType, requestValues,
errors, className){
/* Given the value(s) in a master field, we must update slave's visibility or /* Given the value(s) in a master field, we must update slave's visibility or
value(s). If p_slave is given, it updates only this slave. Else, it updates value(s). If p_slave is given, it updates only this slave. Else, it updates
all slaves of p_master. */ all slaves of p_master. */
@ -401,7 +405,8 @@ function updateSlaves(master,slave,objectUrl,layoutType,requestValues,errors){
var err = null; var err = null;
if (errors && (slaveName in errors)) if (errors && (slaveName in errors))
err = errors[slaveName]; err = errors[slaveName];
askField(slaveId,objectUrl,layoutType,false,masterValues,reqValue,err); askField(slaveId, objectUrl, layoutType, false, masterValues, reqValue,
err, className);
} }
} }
} }

View file

@ -495,6 +495,7 @@ class ToolWrapper(AbstractWrapper):
refInfo=req.get('ref', None); refInfo=req.get('ref', None);
searchInfo=ztool.getSearchInfo(className, refInfo); searchInfo=ztool.getSearchInfo(className, refInfo);
cssJs={}; cssJs={};
layoutType='search';
x=ztool.getCssJs(searchInfo.fields, 'edit', cssJs)"> x=ztool.getCssJs(searchInfo.fields, 'edit', cssJs)">
<!-- Include type-specific CSS and JS. --> <!-- Include type-specific CSS and JS. -->
@ -506,7 +507,6 @@ class ToolWrapper(AbstractWrapper):
<!-- Search title --> <!-- Search title -->
<h1><x>:_('%s_plural'%className)</x> &ndash; <h1><x>:_('%s_plural'%className)</x> &ndash;
<x>:_('search_title')</x></h1> <x>:_('search_title')</x></h1>
<br/>
<!-- Form for searching objects of request/className. --> <!-- Form for searching objects of request/className. -->
<form name="search" action=":ztool.absolute_url()+'/do'" method="post"> <form name="search" action=":ztool.absolute_url()+'/do'" method="post">
<input type="hidden" name="action" value="SearchObjects"/> <input type="hidden" name="action" value="SearchObjects"/>
@ -516,13 +516,11 @@ class ToolWrapper(AbstractWrapper):
<table width="100%"> <table width="100%">
<tr for="searchRow in ztool.getGroupedSearchFields(searchInfo)" <tr for="searchRow in ztool.getGroupedSearchFields(searchInfo)"
valign="top"> valign="top">
<td for="field in searchRow" <td for="field in searchRow" class="search"
var2="scolspan=field and field.scolspan or 1" var2="scolspan=field and field.scolspan or 1"
colspan=":scolspan" colspan=":scolspan"
width=":'%d%%' % ((100/searchInfo.nbOfColumns)*scolspan)"> width=":'%d%%' % ((100/searchInfo.nbOfColumns)*scolspan)">
<x if="field" <x if="field">:field.pxRender</x>
var2="name=field.name;
widgetName='w_%s' % name">:field.pxSearch</x>
<br class="discreet"/> <br class="discreet"/>
</td> </td>
</tr> </tr>

View file

@ -575,7 +575,9 @@ class AbstractWrapper(object):
lang=ztool.getUserLanguage(); q=ztool.quote; lang=ztool.getUserLanguage(); q=ztool.quote;
action=req.get('action', None); action=req.get('action', None);
px=req['px'].split(':'); px=req['px'].split(':');
field=(len(px) == 2) and zobj.getAppyType(px[0]) or None; className=(len(px) == 3) and px[0] or None;
field=className and zobj.getAppyType(px[1], className) or None;
field=(len(px) == 2) and zobj.getAppyType(px[0]) or field;
dir=ztool.getLanguageDirection(lang); dir=ztool.getLanguageDirection(lang);
dleft=(dir == 'ltr') and 'left' or 'right'; dleft=(dir == 'ltr') and 'left' or 'right';
dright=(dir == 'ltr') and 'right' or 'left'; dright=(dir == 'ltr') and 'right' or 'left';
@ -590,7 +592,7 @@ class AbstractWrapper(object):
<!-- Then, call the PX on p_obj or on p_field. --> <!-- Then, call the PX on p_obj or on p_field. -->
<x if="not field">:getattr(obj, px[0])</x> <x if="not field">:getattr(obj, px[0])</x>
<x if="field">:getattr(field, px[1])</x> <x if="field">:getattr(field, px[-1])</x>
</x>''') </x>''')
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------