appy.gen: bugfix while using Zope behind Apache and using the VHM; Ref.view macro is not called via Ajax anymore for single-valued Refs (when displaying lists containing single-valued Ref fields, it produces too many ajax requests, leading to ConflictErrors in the ZODB).
This commit is contained in:
parent
5928996730
commit
40e8a5f258
|
@ -1926,6 +1926,30 @@ class Ref(Type):
|
||||||
res.select = None # Not callable from tool.
|
res.select = None # Not callable from tool.
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def mayAdd(self, obj, folder):
|
||||||
|
'''May the user create a new referred object to p_obj via this Ref,
|
||||||
|
in p_folder?'''
|
||||||
|
# We can't (yet) do that on back references.
|
||||||
|
if self.isBack: return
|
||||||
|
# Check if this Ref is addable
|
||||||
|
if callable(self.add):
|
||||||
|
add = self.callMethod(obj, self.add)
|
||||||
|
else:
|
||||||
|
add = self.add
|
||||||
|
if not add: return
|
||||||
|
# Have we reached the maximum number of referred elements?
|
||||||
|
if self.multiplicity[1] != None:
|
||||||
|
refCount = len(getattr(obj, self.name, ()))
|
||||||
|
if refCount >= self.multiplicity[1]: return
|
||||||
|
# May the user edit this Ref field?
|
||||||
|
if not obj.allows(self.writePermission): return
|
||||||
|
# Have the user the correct add permission on p_folder?
|
||||||
|
tool = obj.getTool()
|
||||||
|
addPermission = '%s: Add %s' % (tool.getAppName(),
|
||||||
|
tool.getPortalType(self.klass))
|
||||||
|
if not obj.getUser().has_permission(addPermission, folder): return
|
||||||
|
return True
|
||||||
|
|
||||||
class Computed(Type):
|
class Computed(Type):
|
||||||
def __init__(self, validator=None, multiplicity=(0,1), index=None,
|
def __init__(self, validator=None, multiplicity=(0,1), index=None,
|
||||||
default=None, optional=False, editDefault=False, show='view',
|
default=None, optional=False, editDefault=False, show='view',
|
||||||
|
|
|
@ -302,15 +302,15 @@ class BaseMixin:
|
||||||
'''Reindexes this object the catalog. If names of indexes are specified
|
'''Reindexes this object the catalog. If names of indexes are specified
|
||||||
in p_indexes, recataloging is limited to those indexes. If p_unindex
|
in p_indexes, recataloging is limited to those indexes. If p_unindex
|
||||||
is True, instead of cataloguing the object, it uncatalogs it.'''
|
is True, instead of cataloguing the object, it uncatalogs it.'''
|
||||||
url = self.absolute_url_path()
|
path = '/'.join(self.getPhysicalPath())
|
||||||
catalog = self.getPhysicalRoot().catalog
|
catalog = self.getPhysicalRoot().catalog
|
||||||
if unindex:
|
if unindex:
|
||||||
catalog.uncatalog_object(url)
|
catalog.uncatalog_object(path)
|
||||||
else:
|
else:
|
||||||
if indexes:
|
if indexes:
|
||||||
catalog.catalog_object(self, url, idxs=indexes)
|
catalog.catalog_object(self, path, idxs=indexes)
|
||||||
else:
|
else:
|
||||||
catalog.catalog_object(self, url)
|
catalog.catalog_object(self, path)
|
||||||
|
|
||||||
def say(self, msg, type='info'):
|
def say(self, msg, type='info'):
|
||||||
'''Prints a p_msg in the user interface. p_logLevel may be "info",
|
'''Prints a p_msg in the user interface. p_logLevel may be "info",
|
||||||
|
@ -533,6 +533,11 @@ class BaseMixin:
|
||||||
if not refs: raise IndexError()
|
if not refs: raise IndexError()
|
||||||
return refs.index(obj.UID())
|
return refs.index(obj.UID())
|
||||||
|
|
||||||
|
def mayAddReference(self, name, folder):
|
||||||
|
'''May the user add references via Ref field named p_name in
|
||||||
|
p_folder?'''
|
||||||
|
return self.getAppyType(name).mayAdd(self, folder)
|
||||||
|
|
||||||
def isDebug(self):
|
def isDebug(self):
|
||||||
'''Are we in debug mode ?'''
|
'''Are we in debug mode ?'''
|
||||||
for arg in sys.argv:
|
for arg in sys.argv:
|
||||||
|
|
|
@ -59,8 +59,8 @@ img {border: 0}
|
||||||
.portletSep { border-top: 1px solid #5F7983; margin-top: 2px;}
|
.portletSep { border-top: 1px solid #5F7983; margin-top: 2px;}
|
||||||
.portletPage { font-style: italic; }
|
.portletPage { font-style: italic; }
|
||||||
.portletGroup { font-variant: small-caps; font-weight: bold; font-style: normal;
|
.portletGroup { font-variant: small-caps; font-weight: bold; font-style: normal;
|
||||||
margin: 0.4em 0 0.2em 0; }
|
margin: 0 0 0.2em 0; }
|
||||||
.phase { border-style: dashed; border-width: thin; padding: 0 0.6em 5px 1em;}
|
.phase { border-style: dashed; border-width: thin; padding: 4px 0.6em 5px 1em;}
|
||||||
.phaseSelected { background-color: #F4F5F6; }
|
.phaseSelected { background-color: #F4F5F6; }
|
||||||
.content { padding: 14px 14px 9px 15px;}
|
.content { padding: 14px 14px 9px 15px;}
|
||||||
.grey { display: none; position: absolute; left: 0px; top: 0px;
|
.grey { display: none; position: absolute; left: 0px; top: 0px;
|
||||||
|
|
|
@ -106,21 +106,20 @@
|
||||||
tal:condition="python: phases" width="100%">
|
tal:condition="python: phases" width="100%">
|
||||||
<tal:phase repeat="phase phases">
|
<tal:phase repeat="phase phases">
|
||||||
<tal:comment replace="nothing">The box containing phase-related information</tal:comment>
|
<tal:comment replace="nothing">The box containing phase-related information</tal:comment>
|
||||||
<tr>
|
<tr tal:define="singlePage python: len(phase['pages']) == 1">
|
||||||
<td tal:define="label python:'%s_phase_%s' % (contextObj.meta_type, phase['name']);
|
<td tal:define="label python:'%s_phase_%s' % (contextObj.meta_type, phase['name']);
|
||||||
status phase/phaseStatus;
|
status phase/phaseStatus;
|
||||||
phaseCss python: (status == 'Current') and ' phaseSelected' or '';"
|
phaseCss python: (status == 'Current') and ' phaseSelected' or '';"
|
||||||
tal:attributes="class python: not singlePhase and 'phase%s' % phaseCss or ''">
|
tal:attributes="class python: not singlePhase and 'phase%s' % phaseCss or ''">
|
||||||
<tal:comment replace="nothing">The title of the phase</tal:comment>
|
<tal:comment replace="nothing">The title of the phase</tal:comment>
|
||||||
<div class="portletGroup" tal:condition="not: singlePhase"
|
<div class="portletGroup" tal:condition="python: not singlePhase and not singlePage"
|
||||||
tal:content="structure python: _(label)">
|
tal:content="structure python: _(label)">
|
||||||
</div>
|
</div>
|
||||||
<tal:comment replace="nothing">The page(s) within the phase</tal:comment>
|
<tal:comment replace="nothing">The page(s) within the phase</tal:comment>
|
||||||
<table width="100%" cellpadding="0"
|
<table width="100%" cellpadding="0">
|
||||||
tal:define="singlePage python: len(phase['pages']) == 1">
|
|
||||||
<tal:page repeat="aPage phase/pages">
|
<tal:page repeat="aPage phase/pages">
|
||||||
<tal:comment replace="nothing">1st line: page name and icons</tal:comment>
|
<tal:comment replace="nothing">1st line: page name and icons</tal:comment>
|
||||||
<tr valign="top" tal:condition="not: singlePage">
|
<tr valign="top" tal:condition="python: not (singlePhase and singlePage)">
|
||||||
<td tal:attributes="class python: test(aPage == page, 'portletCurrent portletPage', 'portletPage')">
|
<td tal:attributes="class python: test(aPage == page, 'portletCurrent portletPage', 'portletPage')">
|
||||||
<a tal:attributes="href python: contextObj.getUrl(page=aPage)"
|
<a tal:attributes="href python: contextObj.getUrl(page=aPage)"
|
||||||
tal:content="structure python: _('%s_page_%s' % (contextObj.meta_type, aPage))">
|
tal:content="structure python: _('%s_page_%s' % (contextObj.meta_type, aPage))">
|
||||||
|
|
|
@ -88,22 +88,34 @@
|
||||||
</metal:sortIcons>
|
</metal:sortIcons>
|
||||||
|
|
||||||
<tal:comment replace="nothing">View macro for a Ref.</tal:comment>
|
<tal:comment replace="nothing">View macro for a Ref.</tal:comment>
|
||||||
<div metal:define-macro="view"
|
<metal:view metal:define-macro="view"
|
||||||
tal:define= "innerRef innerRef|python:False;
|
tal:define="singleRef python: widget['multiplicity'][1] == 1">
|
||||||
|
<tal:comment replace="nothing">
|
||||||
|
For performance reasons, multivalued references are called via Ajax, while single-valued aren't.
|
||||||
|
</tal:comment>
|
||||||
|
<tal:ajax condition="not: singleRef">
|
||||||
|
<div tal:define= "innerRef innerRef|python:False;
|
||||||
ajaxHookId python: contextObj.UID() + name"
|
ajaxHookId python: contextObj.UID() + name"
|
||||||
tal:attributes = "id ajaxHookId">
|
tal:attributes = "id ajaxHookId">
|
||||||
<script name="appyHook" tal:content="python: 'askRefField(\'%s\',\'%s\',\'%s\',\'%s\',0)' % (ajaxHookId, contextObj.absolute_url(), name, innerRef)">
|
<script name="appyHook" tal:content="python: 'askRefField(\'%s\',\'%s\',\'%s\',\'%s\',0)' % (ajaxHookId, contextObj.absolute_url(), name, innerRef)">
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
|
</tal:ajax>
|
||||||
|
<div tal:condition="singleRef">
|
||||||
|
<tal:request define="dummy python: request.set('fieldName', widget['name'])">
|
||||||
|
<metal:ref use-macro="app/ui/widgets/ref/macros/viewContent"/>
|
||||||
|
</tal:request>
|
||||||
|
</div>
|
||||||
|
</metal:view>
|
||||||
|
|
||||||
<tal:comment replace="nothing">
|
<tal:comment replace="nothing">
|
||||||
This macro is called by a XmlHttpRequest for displaying the paginated
|
This macro is called by a XmlHttpRequest (or directly by the macro above)
|
||||||
referred objects of a reference field.
|
for displaying the referred objects of a reference field.
|
||||||
</tal:comment>
|
</tal:comment>
|
||||||
<div metal:define-macro="viewContent"
|
<div metal:define-macro="viewContent"
|
||||||
tal:define="fieldName request/fieldName;
|
tal:define="fieldName request/fieldName;
|
||||||
appyType python: contextObj.getAppyType(fieldName, asDict=True);
|
appyType python: contextObj.getAppyType(fieldName, asDict=True);
|
||||||
innerRef python: test(request['innerRef']=='True', True, False);
|
innerRef python: test(request.get('innerRef', False)=='True', True, False);
|
||||||
ajaxHookId python: contextObj.UID()+fieldName;
|
ajaxHookId python: contextObj.UID()+fieldName;
|
||||||
startNumber python: int(request.get('%s_startNumber' % ajaxHookId, 0));
|
startNumber python: int(request.get('%s_startNumber' % ajaxHookId, 0));
|
||||||
tool contextObj/getTool;
|
tool contextObj/getTool;
|
||||||
|
@ -114,12 +126,9 @@
|
||||||
batchSize refObjects/batchSize;
|
batchSize refObjects/batchSize;
|
||||||
folder python: contextObj.isPrincipiaFolderish and contextObj or contextObj.getParentNode();
|
folder python: contextObj.isPrincipiaFolderish and contextObj or contextObj.getParentNode();
|
||||||
linkedPortalType python: tool.getPortalType(appyType['klass']);
|
linkedPortalType python: tool.getPortalType(appyType['klass']);
|
||||||
addPermission python: '%s: Add %s' % (tool.getAppName(), linkedPortalType);
|
|
||||||
canWrite python: not appyType['isBack'] and contextObj.allows(appyType['writePermission']);
|
canWrite python: not appyType['isBack'] and contextObj.allows(appyType['writePermission']);
|
||||||
multiplicity appyType/multiplicity;
|
showPlusIcon python: contextObj.mayAddReference(fieldName, folder);
|
||||||
maxReached python:(multiplicity[1] != None) and (len(objs) >= multiplicity[1]);
|
atMostOneRef python: (appyType['multiplicity'][1] == 1) and (len(objs)<=1);
|
||||||
showPlusIcon python:not appyType['isBack'] and appyType['add'] and not maxReached and user.has_permission(addPermission, folder) and canWrite;
|
|
||||||
atMostOneRef python: (multiplicity[1] == 1) and (len(objs)<=1);
|
|
||||||
label python: contextObj.translate('label', field=appyType);
|
label python: contextObj.translate('label', field=appyType);
|
||||||
addConfirmMsg python: appyType['addConfirm'] and _('%s_addConfirm' % appyType['labelId']) or '';
|
addConfirmMsg python: appyType['addConfirm'] and _('%s_addConfirm' % appyType['labelId']) or '';
|
||||||
navBaseCall python: 'askRefField(\'%s\',\'%s\',\'%s\',\'%s\',**v**)' % (ajaxHookId, contextObj.absolute_url(), fieldName, innerRef)">
|
navBaseCall python: 'askRefField(\'%s\',\'%s\',\'%s\',\'%s\',**v**)' % (ajaxHookId, contextObj.absolute_url(), fieldName, innerRef)">
|
||||||
|
@ -163,10 +172,6 @@
|
||||||
<img src="search.gif" tal:attributes="title python: _('search_objects')"/></a>
|
<img src="search.gif" tal:attributes="title python: _('search_objects')"/></a>
|
||||||
</legend>
|
</legend>
|
||||||
|
|
||||||
<tal:comment replace="nothing">Object description</tal:comment>
|
|
||||||
<p class="discreet" tal:condition="python: not innerRef and appyType['hasDescr']"
|
|
||||||
tal:content="python: contextObj.translate('descr', field=appyType)"></p>
|
|
||||||
|
|
||||||
<tal:comment replace="nothing">Appy (top) navigation</tal:comment>
|
<tal:comment replace="nothing">Appy (top) navigation</tal:comment>
|
||||||
<metal:nav use-macro="here/ui/navigate/macros/appyNavigate"/>
|
<metal:nav use-macro="here/ui/navigate/macros/appyNavigate"/>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue