[gen] Ref field has now global actions like 'unlink many', 'link many' and 'delete many'.

This commit is contained in:
Gaetan Delannay 2014-04-04 16:49:22 +02:00
parent e7c20f8d2b
commit 3621d0da92
12 changed files with 151 additions and 43 deletions

View file

@ -82,10 +82,10 @@ class Phase:
def addPageLinks(self, field, obj): def addPageLinks(self, field, obj):
'''If p_field is a navigable Ref, we must add, within self.pagesInfo, '''If p_field is a navigable Ref, we must add, within self.pagesInfo,
objects linked to p_obj through this ReF as links.''' objects linked to p_obj through this Ref as links.'''
if field.page.name in self.hiddenPages: return if field.page.name in self.hiddenPages: return
infos = [] infos = []
for ztied in field.getValue(obj, type='zobjects'): for ztied in field.getValue(obj, appy=False):
infos.append(Object(title=ztied.title, url=ztied.absolute_url())) infos.append(Object(title=ztied.title, url=ztied.absolute_url()))
self.pagesInfo[field.page.name].links = infos self.pagesInfo[field.page.name].links = infos

View file

@ -41,7 +41,7 @@ class Ref(Field):
<x var="includeShownInfo=includeShownInfo|False; <x var="includeShownInfo=includeShownInfo|False;
navInfo='ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \ navInfo='ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \
field.pageName, loop.tied.nb + 1 + startNumber, totalNumber); field.pageName, loop.tied.nb + 1 + startNumber, totalNumber);
navInfo=not field.isBack and navInfo or ''; navInfo=(not field.isBack and not inPickList) and navInfo or '';
cssClass=tied.o.getCssFor('title')"> cssClass=tied.o.getCssFor('title')">
<x>::tied.o.getSupTitle(navInfo)</x> <x>::tied.o.getSupTitle(navInfo)</x>
<a var="pageName=field.isBack and field.back.pageName or 'main'; <a var="pageName=field.isBack and field.back.pageName or 'main';
@ -56,16 +56,29 @@ class Ref(Field):
# objects (delete many, unlink many,...) # objects (delete many, unlink many,...)
pxGlobalActions = Px(''' pxGlobalActions = Px('''
<!-- Insert several objects (if in pick list) --> <!-- Insert several objects (if in pick list) -->
<input if="inPickList" type="button" class="button" <input if="inPickList" var2="action='link'" type="button" class="button"
value=":_('object_link_many')" value=":_('object_link_many')"
onClick=":'onLinkMany(%s)' % q(ajaxHookId)" onclick=":'onLinkMany(%s,%s)' % (q(action), q(ajaxHookId))"
style=":url('linkMany', bg=True)"/> style=":url('linkMany', bg=True)"/>
<!-- Unlink several objects -->
<input if="not isBack and field.unlink and canWrite and not inPickList"
var2="imgName=linkList and 'unlinkManyUp' or 'unlinkMany';
action='unlink'"
type="button" class="button" value=":_('object_unlink_many')"
onclick=":'onLinkMany(%s,%s)' % (q(action), q(ajaxHookId))"
style=":url(imgName, bg=True)"/>
<!-- Delete several objects -->
<input if="not isBack and field.delete and canWrite"
var2="action='delete'"
type="button" class="button" value=":_('object_delete_many')"
onclick=":'onLinkMany(%s,%s)' % (q(action), q(ajaxHookId))"
style=":url('deleteMany', bg=True)"/>
''') ''')
# This PX displays icons for triggering actions on a given referenced object # This PX displays icons for triggering actions on a given referenced object
# (edit, delete, etc). # (edit, delete, etc).
pxObjectActions = Px(''' pxObjectActions = Px('''
<table class="noStyle" var="isBack=field.isBack"> <table class="noStyle">
<tr> <tr>
<!-- Arrows for moving objects up or down --> <!-- Arrows for moving objects up or down -->
<td if="not isBack and (len(objects)&gt;1) and changeOrder and canWrite \ <td if="not isBack and (len(objects)&gt;1) and changeOrder and canWrite \
@ -247,6 +260,7 @@ class Ref(Field):
<x var="innerRef=False; <x var="innerRef=False;
ajaxHookId=ajaxHookId|'%s_%s_poss' % (zobj.id, field.name); ajaxHookId=ajaxHookId|'%s_%s_poss' % (zobj.id, field.name);
inPickList=True; inPickList=True;
isBack=field.isBack;
startNumber=field.getStartNumber('list', req, ajaxHookId); startNumber=field.getStartNumber('list', req, ajaxHookId);
info=field.getPossibleValues(zobj, startNumber=startNumber, \ info=field.getPossibleValues(zobj, startNumber=startNumber, \
someObjects=True, removeLinked=True); someObjects=True, removeLinked=True);
@ -263,7 +277,7 @@ class Ref(Field):
(q(ajaxHookId), q(zobj.absolute_url()), \ (q(ajaxHookId), q(zobj.absolute_url()), \
q(field.name), q(innerRef)); q(field.name), q(innerRef));
changeOrder=False; changeOrder=False;
checkboxes=checkboxes|field.checkboxesEnabled(zobj); checkboxes=field.checkboxesEnabled(zobj) and (totalNumber &gt; 1);
showSubTitles=showSubTitles|\ showSubTitles=showSubTitles|\
req.get('showSubTitles', 'true') == 'true'; req.get('showSubTitles', 'true') == 'true';
subLabel='selectable_objects'">:field.pxViewList</x>''') subLabel='selectable_objects'">:field.pxViewList</x>''')
@ -310,6 +324,7 @@ class Ref(Field):
linkList=field.link == 'list'; linkList=field.link == 'list';
renderAll=req.get('scope') != 'objs'; renderAll=req.get('scope') != 'objs';
inPickList=False; inPickList=False;
isBack=field.isBack;
startNumber=field.getStartNumber(render, req, ajaxHookId); startNumber=field.getStartNumber(render, req, ajaxHookId);
info=field.getValue(zobj,startNumber=startNumber,someObjects=True); info=field.getValue(zobj,startNumber=startNumber,someObjects=True);
objects=info.objects; objects=info.objects;
@ -327,16 +342,17 @@ class Ref(Field):
(q(ajaxHookId), q(zobj.absolute_url()), \ (q(ajaxHookId), q(zobj.absolute_url()), \
q(field.name), q(innerRef)); q(field.name), q(innerRef));
changeOrder=field.changeOrderEnabled(zobj); changeOrder=field.changeOrderEnabled(zobj);
checkboxes=field.checkboxesEnabled(zobj); checkboxesEnabled=field.checkboxesEnabled(zobj);
checkboxes=checkboxesEnabled and (totalNumber &gt; 1);
showSubTitles=req.get('showSubTitles', 'true') == 'true'"> showSubTitles=req.get('showSubTitles', 'true') == 'true'">
<!-- The definition of "atMostOneRef" above may sound strange: we <!-- The definition of "atMostOneRef" above may sound strange: we
shouldn't check the actual number of referenced objects. But for shouldn't check the actual number of referenced objects. But for
back references people often forget to specify multiplicities. So back references people often forget to specify multiplicities. So
concretely, multiplicities (0,None) are coded as (0,1). --> concretely, multiplicities (0,None) are coded as (0,1). -->
<!-- JS tables storing checkbox statuses if checkboxes are enabled --> <!-- JS tables storing checkbox statuses if checkboxes are enabled -->
<script if="checkboxes and renderAll" <script if="checkboxesEnabled and renderAll"
type="text/javascript">:field.getCbJsInit(zobj)</script> type="text/javascript">:field.getCbJsInit(zobj)</script>
<div if="linkList and renderAll" <div if="linkList and renderAll and canWrite"
var2="ajaxHookId='%s_%s_poss' % (zobj.id, field.name)" var2="ajaxHookId='%s_%s_poss' % (zobj.id, field.name)"
id=":ajaxHookId">:field.pxViewPickList</div> id=":ajaxHookId">:field.pxViewPickList</div>
<x if="render == 'list'" <x if="render == 'list'"
@ -759,7 +775,6 @@ class Ref(Field):
through this Ref field.''' through this Ref field.'''
# Security check # Security check
if not noSecurity: obj.allows(self.writePermission, raiseError=True) if not noSecurity: obj.allows(self.writePermission, raiseError=True)
# p_value can be a list of objects # p_value can be a list of objects
if type(value) in sutils.sequenceTypes: if type(value) in sutils.sequenceTypes:
for v in value: self.linkObject(obj, v, back=back) for v in value: self.linkObject(obj, v, back=back)
@ -964,30 +979,43 @@ class Ref(Field):
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,
unlink_many...).''' unlink_many, delete_many).'''
action = rq['linkAction'] action = rq['linkAction']
tool = obj.getTool() tool = obj.getTool()
if action == 'link': if not action.endswith('_many'):
# "link" or "unlink"
tied = tool.getObject(rq['targetUid']) tied = tool.getObject(rq['targetUid'])
self.linkObject(obj, tied, noSecurity=False) exec 'self.%sObject(obj, tied, noSecurity=False)' % action
elif action == 'unlink': else:
tied = tool.getObject(rq['targetUid']) # "link_many", "unlink_many", "delete_many"
self.unlinkObject(obj, tied, noSecurity=False)
elif action == 'link_many':
uids = rq['targetUid'].strip(',') or (); uids = rq['targetUid'].strip(',') or ();
if uids: uids = uids.split(',') if uids: uids = uids.split(',')
unchecked = rq['semantics'] == 'unchecked' unchecked = rq['semantics'] == 'unchecked'
# Browse possible values if action == 'link_many':
for tied in self.getPossibleValues(obj, removeLinked=True): # Get possible values (objects)
if unchecked: values = self.getPossibleValues(obj, removeLinked=True)
# Keep only tied objects not among uids. isObj = True
if tied.uid in uids: continue
else: else:
# Keep only tied objects being in uids. # Get current values (uids)
if tied.uid not in uids: continue values = list(getattr(obj.aq_base, self.name, ()))
self.linkObject(obj, tied.o, noSecurity=False) isObj = False
elif action == 'unlink_many': mustDelete = action == 'delete_many'
pass for value in values:
uid = not isObj and value or value.uid
if unchecked:
# Keep only objects not among uids.
if uid in uids: continue
else:
# Keep only objects being in uids.
if uid not in uids: continue
# (Un-)link or delete this object.
tied = not isObj and tool.getObject(value) or value.o
if mustDelete:
if tied.mayDelete(): tied.delete()
else:
# Link or unlink
exec 'self.%sObject(obj, tied, noSecurity=False)' % \
action.split('_')[0]
urlBack = obj.getUrl(rq['HTTP_REFERER']) urlBack = obj.getUrl(rq['HTTP_REFERER'])
obj.say(obj.translate('action_done')) obj.say(obj.translate('action_done'))
tool.goto(urlBack) tool.goto(urlBack)

View file

@ -191,15 +191,23 @@ msgstr ""
msgid "object_delete" msgid "object_delete"
msgstr "" msgstr ""
#. Default: "Delete selection"
msgid "object_delete_many"
msgstr ""
#. Default: "Remove" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
#. Default: "Remove selection"
msgid "object_unlink_many"
msgstr ""
#. Default: "Insert" #. Default: "Insert"
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements" #. Default: "Insert selection"
msgid "object_link_many" msgid "object_link_many"
msgstr "" msgstr ""

View file

@ -191,15 +191,23 @@ msgstr "تعديل"
msgid "object_delete" msgid "object_delete"
msgstr "" msgstr ""
#. Default: "Delete selection"
msgid "object_delete_many"
msgstr ""
#. Default: "Remove" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
#. Default: "Remove selection"
msgid "object_unlink_many"
msgstr ""
#. Default: "Insert" #. Default: "Insert"
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements" #. Default: "Insert selection"
msgid "object_link_many" msgid "object_link_many"
msgstr "" msgstr ""

View file

@ -191,15 +191,23 @@ msgstr "Bearbeiten"
msgid "object_delete" msgid "object_delete"
msgstr "Löschen" msgstr "Löschen"
#. Default: "Delete selection"
msgid "object_delete_many"
msgstr ""
#. Default: "Remove" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
#. Default: "Remove selection"
msgid "object_unlink_many"
msgstr ""
#. Default: "Insert" #. Default: "Insert"
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements" #. Default: "Insert selection"
msgid "object_link_many" msgid "object_link_many"
msgstr "" msgstr ""

View file

@ -192,17 +192,25 @@ msgstr "Edit"
msgid "object_delete" msgid "object_delete"
msgstr "Delete" msgstr "Delete"
#. Default: "Delete selection"
msgid "object_delete_many"
msgstr "Delete selection"
#. Default: "Remove" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "Unlink" msgstr "Unlink"
#. Default: "Remove selection"
msgid "object_unlink_many"
msgstr ""
#. Default: "Insert" #. Default: "Insert"
msgid "object_link" msgid "object_link"
msgstr "Insert" msgstr "Insert"
#. Default: "Insert selected elements" #. Default: "Insert selection"
msgid "object_link_many" msgid "object_link_many"
msgstr "Insert selected elements" msgstr "Insert selection"
#. Default: "(Un)check everything" #. Default: "(Un)check everything"
msgid "check_uncheck" msgid "check_uncheck"

View file

@ -191,15 +191,23 @@ msgstr "Editar"
msgid "object_delete" msgid "object_delete"
msgstr "Eliminar" msgstr "Eliminar"
#. Default: "Delete selection"
msgid "object_delete_many"
msgstr ""
#. Default: "Remove" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
#. Default: "Remove selection"
msgid "object_unlink_many"
msgstr ""
#. Default: "Insert" #. Default: "Insert"
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements" #. Default: "Insert selection"
msgid "object_link_many" msgid "object_link_many"
msgstr "" msgstr ""

View file

@ -192,15 +192,23 @@ msgstr "Modifier"
msgid "object_delete" msgid "object_delete"
msgstr "Supprimer" msgstr "Supprimer"
#. Default: "Delete selection"
msgid "object_delete_many"
msgstr "Supprimer la sélection"
#. Default: "Remove" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "Retirer" msgstr "Retirer"
#. Default: "Remove selection"
msgid "object_unlink_many"
msgstr "Retirer la sélection"
#. Default: "Insert" #. Default: "Insert"
msgid "object_link" msgid "object_link"
msgstr "Insérer" msgstr "Insérer"
#. Default: "Insert selected elements" #. Default: "Insert selection"
msgid "object_link_many" msgid "object_link_many"
msgstr "Insérer la sélection" msgstr "Insérer la sélection"

View file

@ -191,15 +191,23 @@ msgstr "Modifica"
msgid "object_delete" msgid "object_delete"
msgstr "Elimina" msgstr "Elimina"
#. Default: "Delete selection"
msgid "object_delete_many"
msgstr ""
#. Default: "Remove" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
#. Default: "Remove selection"
msgid "object_unlink_many"
msgstr ""
#. Default: "Insert" #. Default: "Insert"
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements" #. Default: "Insert selection"
msgid "object_link_many" msgid "object_link_many"
msgstr "" msgstr ""

View file

@ -191,15 +191,23 @@ msgstr "Bewerken"
msgid "object_delete" msgid "object_delete"
msgstr "Verwijderen" msgstr "Verwijderen"
#. Default: "Delete selection"
msgid "object_delete_many"
msgstr ""
#. Default: "Remove" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
#. Default: "Remove selection"
msgid "object_unlink_many"
msgstr ""
#. Default: "Insert" #. Default: "Insert"
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements" #. Default: "Insert selection"
msgid "object_link_many" msgid "object_link_many"
msgstr "" msgstr ""

View file

@ -262,10 +262,26 @@ function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
else hidden.value = 'False'; else hidden.value = 'False';
} }
// JS implementation of Python ''.rsplit.
function _rsplit(s, delimiter, limit) {
var elems = s.split(delimiter);
var exc = elems.length - limit;
if (exc <= 0) return elems;
// Merge back first elements to get p_limit elements.
var head = '';
var res = [];
for (var i=0; i < elems.length; i++) {
if (exc > 0) { head += elems[i] + delimiter; exc -= 1 }
else { if (exc == 0) { res.push(head + elems[i]); exc -= 1 }
else res.push(elems[i]) }
}
return res;
}
// (Un)checks a checkbox corresponding to a linked object. // (Un)checks a checkbox corresponding to a linked object.
function toggleRefCb(checkbox) { function toggleRefCb(checkbox) {
var name = checkbox.getAttribute('name'); var name = checkbox.getAttribute('name');
var elems = name.split('_'); var elems = _rsplit(name, '_', 3);
// Get the DOM node corresponding to the Ref field. // Get the DOM node corresponding to the Ref field.
var node = document.getElementById(elems[0] + '_' + elems[1]); var node = document.getElementById(elems[0] + '_' + elems[1]);
// Get the array that stores checkbox statuses. // Get the array that stores checkbox statuses.
@ -285,7 +301,7 @@ function toggleRefCb(checkbox) {
// Initialise checkboxes of a Ref field. // Initialise checkboxes of a Ref field.
function initRefCbs(id) { function initRefCbs(id) {
var elems = id.split('_'); var elems = _rsplit(id, '_', 3);
// Get the DOM node corresponding to the Ref field. // Get the DOM node corresponding to the Ref field.
var node = document.getElementById(elems[0] + '_' + elems[1]); var node = document.getElementById(elems[0] + '_' + elems[1]);
// Get the array that stores checkbox statuses. // Get the array that stores checkbox statuses.
@ -303,7 +319,7 @@ function initRefCbs(id) {
// Toggle all checkboxes of a Ref field. // Toggle all checkboxes of a Ref field.
function toggleAllRefCbs(id) { function toggleAllRefCbs(id) {
var elems = id.split('_'); var elems = _rsplit(id, '_', 3);
// Get the DOM node corresponding to the Ref field. // Get the DOM node corresponding to the Ref field.
var node = document.getElementById(elems[0] + '_' + elems[1]); var node = document.getElementById(elems[0] + '_' + elems[1]);
// Empty the array that stores checkbox statuses. // Empty the array that stores checkbox statuses.
@ -523,8 +539,8 @@ function onLink(action, sourceUid, fieldName, targetUid) {
f.submit(); f.submit();
} }
function onLinkMany(id) { function onLinkMany(action, id) {
var elems = id.split('_'); var elems = _rsplit(id, '_', 3);
// Get the DOM node corresponding to the Ref field. // Get the DOM node corresponding to the Ref field.
var node = document.getElementById(elems[0] + '_' + elems[1]); var node = document.getElementById(elems[0] + '_' + elems[1]);
// Get the uids of (un-)checked objects. // Get the uids of (un-)checked objects.
@ -535,7 +551,7 @@ function onLinkMany(id) {
var semantics = node['_appy_' + elems[2] + '_sem']; var semantics = node['_appy_' + elems[2] + '_sem'];
// Fill the form and ask for a confirmation // Fill the form and ask for a confirmation
f = document.getElementById('linkForm'); f = document.getElementById('linkForm');
f.linkAction.value = 'link_many'; f.linkAction.value = action + '_many';
f.sourceUid.value = elems[0]; f.sourceUid.value = elems[0];
f.fieldName.value = elems[1]; f.fieldName.value = elems[1];
f.targetUid.value = uids; f.targetUid.value = uids;

View file

@ -823,7 +823,7 @@ class XmlMarshaller:
v = field.getValue(instance) v = field.getValue(instance)
elif field.type == 'Ref': elif field.type == 'Ref':
fieldType = 'ref' fieldType = 'ref'
v = field.getValue(instance, type='zobjects') v = field.getValue(instance, appy=False)
else: else:
v = field.getValue(instance) v = field.getValue(instance)
self.dumpField(res, field.name, v, fieldType=fieldType) self.dumpField(res, field.name, v, fieldType=fieldType)