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