[gen] Ref field: first cmplete version of Ref with link='popup'.
This commit is contained in:
parent
0bcd0055a3
commit
a45dfa8dd0
|
@ -168,6 +168,23 @@ class Ref(Field):
|
|||
navBaseCall, startNumber)"/>
|
||||
</form>''')
|
||||
|
||||
# Displays the button allowing to select from a popup objects to be linked
|
||||
# via the Ref field.
|
||||
pxLink = Px('''
|
||||
<a target="appyIFrame"
|
||||
var="tiedClassName=ztool.getPortalType(field.klass);
|
||||
className=ztool.getPortalType(obj.klass)"
|
||||
href=":'%s/query?className=%s&search=%s:%s:%s&popup=1' % \
|
||||
(ztool.absolute_url(), tiedClassName, obj.uid, field.name, \
|
||||
popupMode)">
|
||||
<input type="button" class="buttonSmall button"
|
||||
var="labelId= (popupMode=='repl') and 'search_button' or 'add_ref';
|
||||
icon= (popupMode=='repl') and 'search' or 'add';
|
||||
label=_(labelId)" value=":label"
|
||||
style=":'%s;%s' % (url(icon,bg=True), ztool.getButtonWidth(label))"
|
||||
onclick="openPopup('iframePopup')"/>
|
||||
</a>''')
|
||||
|
||||
# This PX displays, in a cell header from a ref table, icons for sorting the
|
||||
# ref field according to the field that corresponds to this column.
|
||||
pxSortIcons = Px('''
|
||||
|
@ -202,10 +219,13 @@ class Ref(Field):
|
|||
|
||||
# PX that displays referred objects as a list.
|
||||
pxViewList = Px('''
|
||||
<div if="not innerRef or mayAdd" style="margin-bottom: 4px">
|
||||
<div if="not innerRef or mayAdd or mayLink" style="margin-bottom: 4px">
|
||||
<span if="subLabel" class="discreet">:_(subLabel)</span>
|
||||
(<span class="discreet">:totalNumber</span>)
|
||||
<x>:field.pxAdd</x>
|
||||
<!-- This button opens a popup for linking additional objects -->
|
||||
<x if="mayLink and not inPickList"
|
||||
var2="popupMode='add'">:field.pxLink</x>
|
||||
<!-- The search button if field is queryable -->
|
||||
<input if="objects and field.queryable" type="button"
|
||||
class="buttonSmall button"
|
||||
|
@ -308,9 +328,9 @@ class Ref(Field):
|
|||
not field.isBack and zobj.mayEdit(field.writePermission);
|
||||
mayUnlink=False;
|
||||
mayAdd=False;
|
||||
navBaseCall='askRefField(%s,%s,%s,%s,**v**)' % \
|
||||
(q(ajaxHookId), q(zobj.absolute_url()), \
|
||||
q(field.name), q(innerRef));
|
||||
mayLink=False;
|
||||
navBaseCall='askRefField(%s,%s,%s,**v**)' % \
|
||||
(q(ajaxHookId), q(zobj.absolute_url()), q(innerRef));
|
||||
changeOrder=False;
|
||||
changeNumber=False;
|
||||
checkboxes=field.getAttribute(zobj, 'checkboxes') and \
|
||||
|
@ -404,11 +424,12 @@ class Ref(Field):
|
|||
mayEdit=not field.isBack and zobj.mayEdit(field.writePermission);
|
||||
mayUnlink=mayEdit and field.getAttribute(zobj, 'unlink');
|
||||
mayAdd=mayEdit and field.mayAdd(zobj, checkMayEdit=False);
|
||||
mayLink=mayEdit and field.mayAdd(zobj, mode='link', \
|
||||
checkMayEdit=False);
|
||||
addConfirmMsg=field.addConfirm and \
|
||||
_('%s_addConfirm' % field.labelId) or '';
|
||||
navBaseCall='askRefField(%s,%s,%s,%s,**v**)' % \
|
||||
(q(ajaxHookId), q(zobj.absolute_url()), \
|
||||
q(field.name), q(innerRef));
|
||||
navBaseCall='askRefField(%s,%s,%s,**v**)' % \
|
||||
(q(ajaxHookId), q(zobj.absolute_url()), q(innerRef));
|
||||
changeOrder=mayEdit and field.getAttribute(zobj, 'changeOrder');
|
||||
numbered=field.isNumbered(zobj);
|
||||
changeNumber=not inPickList and numbered and changeOrder and \
|
||||
|
@ -446,17 +467,7 @@ class Ref(Field):
|
|||
</select>
|
||||
<div if="not objects">-</div>
|
||||
<!-- The button for opening the popup -->
|
||||
<a target="appyIFrame"
|
||||
var="tiedClassName=ztool.getPortalType(field.klass);
|
||||
className=ztool.getPortalType(obj.klass)"
|
||||
href=":'%s/query?className=%s&search=%s:%s&popup=1' % \
|
||||
(ztool.absolute_url(), tiedClassName, obj.uid, field.name)">
|
||||
<input type="button" class="buttonSmall button"
|
||||
var="label=_('search_button')" value=":label"
|
||||
style=":'%s; %s' % (url('search', bg=True), \
|
||||
ztool.getButtonWidth(label))"
|
||||
onclick="openPopup('iframePopup')"/></a>
|
||||
</x>''')
|
||||
<x var="popupMode='repl'">:field.pxLink</x></x>''')
|
||||
|
||||
pxEdit = Px('''
|
||||
<x if="(field.link) and (field.link != 'list')">
|
||||
|
@ -1079,17 +1090,21 @@ class Ref(Field):
|
|||
# Link new objects
|
||||
if objects: self.linkObject(appyObj, objects)
|
||||
|
||||
def mayAdd(self, obj, checkMayEdit=True):
|
||||
'''May the user create a new referred object from p_obj via this Ref?
|
||||
If p_checkMayEdit is False, it means that the condition of being
|
||||
def mayAdd(self, obj, mode='create', checkMayEdit=True):
|
||||
'''May the user create (if p_mode == "create") or link
|
||||
(if mode == "link") (a) new referred object(s) from p_obj via this
|
||||
Ref? If p_checkMayEdit is False, it means that the condition of being
|
||||
allowed to edit this Ref field has already been checked somewhere
|
||||
else (it is always required, we just want to avoid checking it
|
||||
twice).'''
|
||||
# We can't (yet) do that on back references.
|
||||
if self.isBack: return gutils.No('is_back')
|
||||
# Check if this Ref is addable
|
||||
# Check if this Ref is addable/linkable.
|
||||
if mode == 'create':
|
||||
add = self.getAttribute(obj, 'add')
|
||||
if not add: return gutils.No('no_add')
|
||||
elif mode == 'link':
|
||||
if (self.link != 'popup') or not self.isMultiValued(): return
|
||||
# Have we reached the maximum number of referred elements?
|
||||
if self.multiplicity[1] != None:
|
||||
refCount = len(getattr(obj, self.name, ()))
|
||||
|
@ -1099,6 +1114,7 @@ class Ref(Field):
|
|||
if not obj.mayEdit(self.writePermission):
|
||||
return gutils.No('no_write_perm')
|
||||
# May the user create instances of the referred class?
|
||||
if mode == 'create':
|
||||
if not obj.getTool().userMayCreate(self.klass):
|
||||
return gutils.No('no_create_perm')
|
||||
return True
|
||||
|
@ -1294,6 +1310,14 @@ class Ref(Field):
|
|||
res.append(tool.getObject(uid))
|
||||
return res
|
||||
|
||||
def onSelectFromPopup(self, obj):
|
||||
'''This method is called on Ref fields with link="popup", when a user
|
||||
has selected objects from the popup, to be added to existing tied
|
||||
objects, from the view widget.'''
|
||||
obj = obj.appy()
|
||||
for tied in self.getPopupObjects(obj, obj.request, None):
|
||||
self.linkObject(obj, tied, noSecurity=False)
|
||||
|
||||
def onUiRequest(self, obj, rq):
|
||||
'''This method is called when an action tied to this Ref field is
|
||||
triggered from the user interface (link, unlink, link_many,
|
||||
|
|
|
@ -189,11 +189,23 @@ class UiSearch:
|
|||
self.translated = label and _(label) or ''
|
||||
self.translatedDescr = labelDescr and _(labelDescr) or ''
|
||||
|
||||
def setInitiator(self, initiator, field):
|
||||
def setInitiator(self, initiator, field, mode):
|
||||
'''If the search is defined in an attribute Ref.select, we receive here
|
||||
the p_initiator object and its Ref p_field.'''
|
||||
the p_initiator object, its Ref p_field and the p_mode, that can be:
|
||||
- "repl" if the objects selected in the popup will replace already
|
||||
tied objects;
|
||||
- "add" if those objects will be added to the already tied ones.
|
||||
.'''
|
||||
self.initiator = initiator
|
||||
self.initiatorField = field
|
||||
self.initiatorMode = mode
|
||||
# "initiatorHook" is the ID of the initiator field's XHTML tag.
|
||||
self.initiatorHook = '%s_%s' % (initiator.uid, field.name)
|
||||
|
||||
def getRootHookId(self):
|
||||
'''If an initiator field is there, return the initiator hook.
|
||||
Else, simply return the name of the search.'''
|
||||
return getattr(self, 'initiatorHook', self.name)
|
||||
|
||||
def showCheckboxes(self):
|
||||
'''If checkboxes are enabled for this search (and if an initiator field
|
||||
|
|
|
@ -736,7 +736,7 @@ class ToolMixin(BaseMixin):
|
|||
elif ':' in name:
|
||||
# The search is defined in a Ref field with link=popup. Get the
|
||||
# search, the initiator object and the Ref field.
|
||||
uid, ref = name.split(':')
|
||||
uid, ref, mode = name.split(':')
|
||||
initiator = self.getObject(uid, appy=True)
|
||||
initiatorField = initiator.getField(ref)
|
||||
res = getattr(initiator.klass, ref).select
|
||||
|
@ -756,7 +756,7 @@ class ToolMixin(BaseMixin):
|
|||
# Return a UiSearch if required.
|
||||
if ui:
|
||||
res = UiSearch(res, className, self)
|
||||
if initiator: res.setInitiator(initiator, initiatorField)
|
||||
if initiator: res.setInitiator(initiator, initiatorField, mode)
|
||||
return res
|
||||
|
||||
def advancedSearchEnabledFor(self, klass):
|
||||
|
|
|
@ -249,11 +249,13 @@ function askObjectHistory(hookId, objectUrl, maxPerPage, startNumber) {
|
|||
askAjaxChunk(hookId, 'GET', objectUrl, 'pxHistory', params);
|
||||
}
|
||||
|
||||
function askRefField(hookId, objectUrl, fieldName, innerRef, startNumber,
|
||||
action, actionParams){
|
||||
function askRefField(hookId, objectUrl, innerRef, startNumber, action,
|
||||
actionParams){
|
||||
var hookElems = hookId.split('_');
|
||||
var fieldName = hookElems[1];
|
||||
// Sends an Ajax request for getting the content of a reference field.
|
||||
var startKey = hookId + '_startNumber';
|
||||
var scope = hookId.split('_').pop();
|
||||
var scope = hookElems.pop();
|
||||
var params = {'innerRef': innerRef, 'scope': scope};
|
||||
params[startKey] = startNumber;
|
||||
if (action) params['action'] = action;
|
||||
|
@ -1028,7 +1030,7 @@ function onSelectDate(cal) {
|
|||
}
|
||||
}
|
||||
|
||||
function onSelectObjects(nodeId, objectUrl, sortKey, sortOrder,
|
||||
function onSelectObjects(nodeId, objectUrl, mode, sortKey, sortOrder,
|
||||
filterKey, filterValue){
|
||||
/* Objects have been selected in a popup, to be linked via a Ref with
|
||||
link='popup'. Get them. */
|
||||
|
@ -1042,12 +1044,21 @@ function onSelectObjects(nodeId, objectUrl, sortKey, sortOrder,
|
|||
}
|
||||
// Close the popup.
|
||||
closePopup('iframePopup');
|
||||
/* Refresh the Ref edit widget to include the linked objects. All those
|
||||
parameters are needed to replay the query in the popup. */
|
||||
askField(':'+nodeId, objectUrl, 'edit', null, null, null, null, null,
|
||||
{'selected': uids, 'semantics': semantics, 'sortKey': sortKey,
|
||||
/* When refreshing the Ref field we will need to pass all those parameters,
|
||||
for replaying the popup query. */
|
||||
var params = {'selected': uids, 'semantics': semantics, 'sortKey': sortKey,
|
||||
'sortOrder': sortOrder, 'filterKey': filterKey,
|
||||
'filterValue': filterValue});
|
||||
'filterValue': filterValue};
|
||||
if (mode == 'repl') {
|
||||
/* Link the selected objects (and unlink the potentially already linked
|
||||
ones) and refresh the Ref edit widget. */
|
||||
askField(':'+nodeId,objectUrl,'edit',null,null,null,null,null,params);
|
||||
}
|
||||
else {
|
||||
// Link the selected objects and refresh the Ref view widget.
|
||||
params['action'] = 'onSelectFromPopup';
|
||||
askField(':'+nodeId,objectUrl,'view',null,null,null,null,null,params);
|
||||
}
|
||||
}
|
||||
|
||||
function onSelectObject(tdId, nodeId, objectUrl) {
|
||||
|
|
|
@ -417,8 +417,9 @@ class ToolWrapper(AbstractWrapper):
|
|||
<input type="button" class="button"
|
||||
var="label=_('object_link_many')"
|
||||
value=":label"
|
||||
onclick=":'onSelectObjects(%s,%s,%s,%s,%s,%s)' % (q(rootHookId), \
|
||||
q(uiSearch.initiator.url),q(sortKey),q(sortOrder), \
|
||||
onclick=":'onSelectObjects(%s,%s,%s,%s,%s,%s,%s)' % \
|
||||
(q(rootHookId), q(uiSearch.initiator.url), \
|
||||
q(uiSearch.initiatorMode), q(sortKey), q(sortOrder), \
|
||||
q(filterKey), q(filterValue))"
|
||||
style=":'%s; %s' % (url('linkMany', bg=True), \
|
||||
ztool.getButtonWidth(label))"/>
|
||||
|
@ -450,8 +451,8 @@ class ToolWrapper(AbstractWrapper):
|
|||
_=ztool.translate;
|
||||
className=req['className'];
|
||||
searchName=req.get('search', '');
|
||||
rootHookId=rootHookId|searchName.replace(':', '_');
|
||||
uiSearch=uiSearch|ztool.getSearch(className,searchName,ui=True);
|
||||
rootHookId=uiSearch.getRootHookId();
|
||||
refInfo=ztool.getRefInfo();
|
||||
refObject=refInfo[0];
|
||||
refField=refInfo[1];
|
||||
|
@ -537,7 +538,7 @@ class ToolWrapper(AbstractWrapper):
|
|||
<div var="className=req['className'];
|
||||
searchName=req.get('search', '');
|
||||
uiSearch=ztool.getSearch(className, searchName, ui=True);
|
||||
rootHookId=searchName.replace(':', '_');
|
||||
rootHookId=uiSearch.getRootHookId();
|
||||
cssJs=None"
|
||||
id=":rootHookId">
|
||||
<script type="text/javascript">:uiSearch.search.getCbJsInit(rootHookId)
|
||||
|
|
Loading…
Reference in a new issue