[gen] Ref field: allow to insert many selected items at once (Ref fields with link='list').

This commit is contained in:
Gaetan Delannay 2014-04-03 17:32:57 +02:00
parent 084f1f9a23
commit e7c20f8d2b
16 changed files with 353 additions and 123 deletions

View file

@ -52,6 +52,16 @@ class Ref(Field):
'display:none'">::tied.o.getSubTitle()</span> 'display:none'">::tied.o.getSubTitle()</span>
</x>''') </x>''')
# This PX displays buttons for triggering global actions on several linked
# objects (delete many, unlink many,...)
pxGlobalActions = Px('''
<!-- Insert several objects (if in pick list) -->
<input if="inPickList" type="button" class="button"
value=":_('object_link_many')"
onClick=":'onLinkMany(%s)' % q(ajaxHookId)"
style=":url('linkMany', 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('''
@ -88,14 +98,17 @@ class Ref(Field):
</td> </td>
<!-- Unlink --> <!-- Unlink -->
<td if="not isBack and field.unlink and canWrite and not inPickList"> <td if="not isBack and field.unlink and canWrite and not inPickList">
<img class="clickable" title=":_('object_unlink')" src=":url('unlink')" <img var="imgName=linkList and 'unlinkUp' or 'unlink';
onclick=":'onUnlinkObject(%s,%s,%s)' % (q(zobj.id), \ action='unlink'"
class="clickable" title=":_('object_unlink')" src=":url(imgName)"
onclick=":'onLink(%s,%s,%s,%s)' % (q(action), q(zobj.id), \
q(field.name), q(tied.o.id))"/> q(field.name), q(tied.o.id))"/>
</td> </td>
<!-- Insert (if in pick list) --> <!-- Insert (if in pick list) -->
<td if="inPickList"> <td if="inPickList">
<img class="clickable" title=":_('object_link')" src=":url('link')" <img var="action='link'" class="clickable" title=":_('object_link')"
onclick=":'onLinkObject(%s,%s,%s)' % (q(zobj.id), \ src=":url(action)"
onclick=":'onLink(%s,%s,%s,%s)' % (q(action), q(zobj.id), \
q(field.name), q(tied.o.id))"/> q(field.name), q(tied.o.id))"/>
</td> </td>
</tr> </tr>
@ -137,7 +150,6 @@ class Ref(Field):
# PX that displays referred objects as a list. # PX that displays referred objects as a list.
pxViewList = Px(''' pxViewList = Px('''
<div id=":ajaxHookId">
<!-- Display a simplified widget if at most 1 referenced object. --> <!-- Display a simplified widget if at most 1 referenced object. -->
<table if="atMostOneRef"> <table if="atMostOneRef">
<tr valign="top"> <tr valign="top">
@ -174,67 +186,86 @@ class Ref(Field):
<!-- No object is present --> <!-- No object is present -->
<p class="discreet" if="not objects">:_('no_ref')</p> <p class="discreet" if="not objects">:_('no_ref')</p>
<table if="objects" class=":innerRef and 'innerAppyTable' or ''" <!-- Show forward or backward reference(s) -->
width="100%"> <table if="objects" class=":not innerRef and 'list' or ''"
<tr valign="bottom"> width=":innerRef and '100%' or field.layouts['view'].width"
<td> var2="columns=ztool.getColumnsSpecifiers(tiedClassName, \
<!-- Show forward or backward reference(s) --> field.shownInfo, dir)">
<table class=":not innerRef and 'list' or ''" <tr if="field.showHeaders">
width=":innerRef and '100%' or field.layouts['view'].width" <th for="column in columns" width=":column.width"
var="columns=ztool.getColumnsSpecifiers(tiedClassName, \ align="column.align" var2="refField=column.field">
field.shownInfo, dir)"> <span>:_(refField.labelId)</span>
<tr if="field.showHeaders"> <x>:field.pxSortIcons</x>
<th for="column in columns" width=":column.width" <x var="className=tiedClassName;
align="column.align" var2="refField=column.field"> field=refField">:tool.pxShowDetails</x>
<span>:_(refField.labelId)</span> </th>
<x>:field.pxSortIcons</x> <th if="checkboxes" class="cbCell">
<x var="className=tiedClassName; <img src=":url('checkall')" class="clickable"
field=refField">:tool.pxShowDetails</x> title=":_('check_uncheck')"
</th> onclick=":'toggleAllRefCbs(%s)' % q(ajaxHookId)"/>
</tr> </th>
<tr for="tied in objects" valign="top" </tr>
class=":loop.tied.odd and 'even' or 'odd'"> <tr for="tied in objects" valign="top"
<td for="column in columns" class=":loop.tied.odd and 'even' or 'odd'">
width=":column.width" align=":column.align" <td for="column in columns" width=":column.width" align=":column.align"
var2="refField=column.field"> var2="refField=column.field">
<!-- The "title" field --> <!-- The "title" field -->
<x if="refField.name == 'title'"> <x if="refField.name == 'title'">
<x>:field.pxObjectTitle</x> <x>:field.pxObjectTitle</x>
<div if="tied.o.mayAct()">:field.pxObjectActions</div> <div if="tied.o.mayAct()">:field.pxObjectActions</div>
</x> </x>
<!-- Any other field --> <!-- Any other field -->
<x if="refField.name != 'title'"> <x if="refField.name != 'title'">
<x var="zobj=tied.o; obj=tied; layoutType='cell'; <x var="zobj=tied.o; obj=tied; layoutType='cell';
innerRef=True; field=refField" innerRef=True; field=refField"
if="zobj.showField(field.name, \ if="zobj.showField(field.name, \
layoutType='result')">:field.pxRender</x> layoutType='result')">:field.pxRender</x>
</x> </x>
</td> </td>
</tr> <td if="checkboxes" class="cbCell">
</table> <input var="tiedUid=tied.uid" type="checkbox" name=":ajaxHookId"
checked="checked" value=":tiedUid" onclick="toggleRefCb(this)"/>
</td> </td>
</tr> </tr>
</table> </table>
<!-- Global actions -->
<div if="canWrite and (totalNumber &gt; 1)"
align=":dright">:field.pxGlobalActions</div>
<!-- (Bottom) navigation --> <!-- (Bottom) navigation -->
<x>:tool.pxNavigate</x> <x>:tool.pxNavigate</x>
</x></div>''')
<!-- Init checkboxes if present. -->
<script if="checkboxes"
type="text/javascript">:'initRefCbs(%s)' % q(ajaxHookId)</script>
</x>''')
# PX that displays the list of objects the user may select to insert into a # PX that displays the list of objects the user may select to insert into a
# ref field with link="list". # ref field with link="list".
pxViewPickList = Px(''' pxViewPickList = Px('''
<x var="ajaxHookId='%s_%s_poss' % (zobj.id, field.name); <x var="innerRef=False;
ajaxHookId=ajaxHookId|'%s_%s_poss' % (zobj.id, field.name);
inPickList=True; inPickList=True;
startNumber=field.getStartNumber(render, 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);
objects=info.objects; objects=info.objects;
totalNumber=info.totalNumber; totalNumber=info.totalNumber;
batchSize=info.batchSize; batchSize=info.batchSize;
batchNumber=len(objects); batchNumber=len(objects);
tiedClassName=tiedClassName|ztool.getPortalType(field.klass);
canWrite=canWrite|\
not field.isBack and zobj.allows(field.writePermission);
showPlusIcon=False;
atMostOneRef=False;
navBaseCall='askRefField(%s,%s,%s,%s,**v**)' % \ navBaseCall='askRefField(%s,%s,%s,%s,**v**)' % \
(q(ajaxHookId), q(zobj.absolute_url()), \ (q(ajaxHookId), q(zobj.absolute_url()), \
q(field.name), q(innerRef)); q(field.name), q(innerRef));
changeOrder=False;
checkboxes=checkboxes|field.checkboxesEnabled(zobj);
showSubTitles=showSubTitles|\
req.get('showSubTitles', 'true') == 'true';
subLabel='selectable_objects'">:field.pxViewList</x>''') subLabel='selectable_objects'">:field.pxViewList</x>''')
# PX that displays referred objects as menus. # PX that displays referred objects as menus.
@ -269,12 +300,15 @@ class Ref(Field):
</td> </td>
</tr></table>''') </tr></table>''')
# PX that displays referred objects through this field. # PX that displays referred objects through this field. In mode link="list",
# if, in the request, key "scope" is present and holds value "objs", the
# pick list (containing possible values) will not be rendered.
pxView = Px(''' pxView = Px('''
<x var="innerRef=req.get('innerRef', False) == 'True'; <x var="innerRef=req.get('innerRef', False) == 'True';
ajaxHookId='%s_%s_objs' % (zobj.id, field.name); ajaxHookId='%s_%s_objs' % (zobj.id, field.name);
render=render|'list'; render=render|'list';
linkList=field.link == 'list'; linkList=field.link == 'list';
renderAll=req.get('scope') != 'objs';
inPickList=False; inPickList=False;
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);
@ -293,15 +327,23 @@ 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);
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). -->
<x if="linkList">:field.pxViewPickList</x> <!-- JS tables storing checkbox statuses if checkboxes are enabled -->
<script if="checkboxes and renderAll"
type="text/javascript">:field.getCbJsInit(zobj)</script>
<div if="linkList and renderAll"
var2="ajaxHookId='%s_%s_poss' % (zobj.id, field.name)"
id=":ajaxHookId">:field.pxViewPickList</div>
<x if="render == 'list'" <x if="render == 'list'"
var2="subLabel=linkList and 'selected_objects' or \ var2="subLabel=linkList and 'selected_objects' or None">
None">:field.pxViewList</x> <div if="renderAll" id=":ajaxHookId">:field.pxViewList</div>
<x if="not renderAll">:field.pxViewList</x>
</x>
<x if="render == 'menus'">:field.pxViewMenus</x> <x if="render == 'menus'">:field.pxViewMenus</x>
</x>''') </x>''')
@ -356,10 +398,10 @@ class Ref(Field):
width=None, height=5, maxChars=None, colspan=1, master=None, width=None, height=5, maxChars=None, colspan=1, master=None,
masterValue=None, focus=False, historized=False, mapping=None, masterValue=None, focus=False, historized=False, mapping=None,
label=None, queryable=False, queryFields=None, queryNbCols=1, label=None, queryable=False, queryFields=None, queryNbCols=1,
navigable=False, changeOrder=True, sdefault='', scolspan=1, navigable=False, changeOrder=True, checkboxes=True,
swidth=None, sheight=None, sselect=None, persist=True, sdefault='', scolspan=1, swidth=None, sheight=None,
render='list', menuIdMethod=None, menuInfoMethod=None, sselect=None, persist=True, render='list', menuIdMethod=None,
menuUrlMethod=None): menuInfoMethod=None, menuUrlMethod=None):
self.klass = klass self.klass = klass
self.attribute = attribute self.attribute = attribute
# May the user add new objects through this ref ? # May the user add new objects through this ref ?
@ -444,9 +486,13 @@ class Ref(Field):
self.queryNbCols = queryNbCols self.queryNbCols = queryNbCols
# Within the portlet, will referred elements appear ? # Within the portlet, will referred elements appear ?
self.navigable = navigable self.navigable = navigable
# If changeOrder is False, it even if the user has the right to modify # If "changeOrder" is False, it even if the user has the right to modify
# the field, it will not be possible to move objects or sort them. # the field, it will not be possible to move objects or sort them.
self.changeOrder = changeOrder self.changeOrder = changeOrder
# If "checkboxes" is True, every linked object will be "selectable" vi
# a checkbox: global actions will be possible, that will act on the
# subset of selected objects: delete, unlink, etc.
self.checkboxes = checkboxes
# There are different ways to render a bunch of linked objects: # There are different ways to render a bunch of linked objects:
# - "list" (the default) renders them as a list (=a XHTML table); # - "list" (the default) renders them as a list (=a XHTML table);
# - "menus" renders them as a series of popup menus, grouped by type. # - "menus" renders them as a series of popup menus, grouped by type.
@ -708,9 +754,12 @@ class Ref(Field):
elif nbOfRefs > maxRef: elif nbOfRefs > maxRef:
return obj.translate('max_ref_violated') return obj.translate('max_ref_violated')
def linkObject(self, obj, value, back=False): def linkObject(self, obj, value, back=False, noSecurity=True):
'''This method links p_value (which can be a list of objects) to p_obj '''This method links p_value (which can be a list of objects) to p_obj
through this Ref field.''' through this Ref field.'''
# Security check
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)
@ -736,9 +785,11 @@ class Ref(Field):
# Update the back reference # Update the back reference
if not back: self.back.linkObject(value, obj, back=True) if not back: self.back.linkObject(value, obj, back=True)
def unlinkObject(self, obj, value, back=False): def unlinkObject(self, obj, value, back=False, noSecurity=True):
'''This method unlinks p_value (which can be a list of objects) from '''This method unlinks p_value (which can be a list of objects) from
p_obj through this Ref field.''' p_obj through this Ref field.'''
# Security check
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.unlinkObject(obj, v, back=back) for v in value: self.unlinkObject(obj, v, back=back)
@ -827,6 +878,39 @@ class Ref(Field):
else: else:
return self.callMethod(obj, self.changeOrder) return self.callMethod(obj, self.changeOrder)
def checkboxesEnabled(self, obj):
'''Are checkboxes enabled?'''
if isinstance(self.checkboxes, bool):
return self.checkboxes
else:
return self.callMethod(obj, self.checkboxes)
def getCbJsInit(self, obj):
'''When checkboxes are enabled, this method defines a JS associative
array (named "_appy_objs_cbs") that will store checkboxes' statuses.
This array is needed because all linked objects are not visible at
the same time (pagination).
Moreover, if self.link is "list", an additional array (named
"_appy_poss_cbs") is defined for possible values.
Initial semantics of this (those) array(s) is as follows: if a key
is present in it for a given linked object, it means that the
checkbox is unchecked. All linked objects are thus selected by
default. This semantics may be inverted: presence of a key may mean
that the checkbox is checked. The current array semantics is stored
in a variable named "_appy_objs_sem" (or "_appy_poss_sem") and may
hold "unchecked" (initial semantics) or "checked" (inversed
semantics). Inversing semantic allows to keep the array small even
when checking/unchecking all checkboxes.
The mentioned JS arrays and variables are stored as attributes of the
DOM node representing this field.'''
code = "\nnode['_appy_%s_cbs']={};\nnode['_appy_%s_sem']='unchecked';"
poss = (self.link == 'list') and (code % ('poss', 'poss')) or ''
return "var node=document.getElementById('%s_%s');%s%s" % \
(obj.id, self.name, code % ('objs', 'objs'), poss)
def doChangeOrder(self, obj): def doChangeOrder(self, obj):
'''Moves a referred object up or down.''' '''Moves a referred object up or down.'''
rq = obj.REQUEST rq = obj.REQUEST
@ -877,6 +961,37 @@ class Ref(Field):
reverse = rq.get('reverse') == 'True' reverse = rq.get('reverse') == 'True'
obj.appy().sort(self.name, sortKey=sortKey, reverse=reverse) obj.appy().sort(self.name, sortKey=sortKey, reverse=reverse)
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,
unlink_many...).'''
action = rq['linkAction']
tool = obj.getTool()
if action == 'link':
tied = tool.getObject(rq['targetUid'])
self.linkObject(obj, tied, noSecurity=False)
elif action == 'unlink':
tied = tool.getObject(rq['targetUid'])
self.unlinkObject(obj, tied, noSecurity=False)
elif action == 'link_many':
uids = rq['targetUid'].strip(',') or ();
if uids: uids = uids.split(',')
unchecked = rq['semantics'] == 'unchecked'
# Browse possible values
for tied in self.getPossibleValues(obj, removeLinked=True):
if unchecked:
# Keep only tied objects not among uids.
if tied.uid in uids: continue
else:
# Keep only tied objects being in uids.
if tied.uid not in uids: continue
self.linkObject(obj, tied.o, noSecurity=False)
elif action == 'unlink_many':
pass
urlBack = obj.getUrl(rq['HTTP_REFERER'])
obj.say(obj.translate('action_done'))
tool.goto(urlBack)
def autoref(klass, field): def autoref(klass, field):
'''klass.field is a Ref to p_klass. This kind of auto-reference can't be '''klass.field is a Ref to p_klass. This kind of auto-reference can't be
declared in the "normal" way, like this: declared in the "normal" way, like this:

View file

@ -179,29 +179,13 @@ class BaseMixin:
(appy.user.login, appy.klass.__name__, appy.uid)) (appy.user.login, appy.klass.__name__, appy.uid))
self.goto(self.getUrl(rq['HTTP_REFERER'])) self.goto(self.getUrl(rq['HTTP_REFERER']))
def onUnlink(self):
'''Called when an object unlinking is triggered from the ui.'''
rq = self.REQUEST
tool = self.getTool()
sourceObject = tool.getObject(rq['sourceUid'])
targetObject = tool.getObject(rq['targetUid'])
field = sourceObject.getAppyType(rq['fieldName'])
field.unlinkObject(sourceObject, targetObject)
urlBack = self.getUrl(rq['HTTP_REFERER'])
self.say(self.translate('action_done'))
self.goto(urlBack)
def onLink(self): def onLink(self):
'''Called when an object linking is triggered from the ui.''' '''Called when object (un)linking is triggered from the ui.'''
rq = self.REQUEST rq = self.REQUEST
tool = self.getTool() tool = self.getTool()
sourceObject = tool.getObject(rq['sourceUid']) sourceObject = tool.getObject(rq['sourceUid'])
targetObject = tool.getObject(rq['targetUid'])
field = sourceObject.getAppyType(rq['fieldName']) field = sourceObject.getAppyType(rq['fieldName'])
field.linkObject(sourceObject, targetObject) return field.onUiRequest(sourceObject, rq)
urlBack = self.getUrl(rq['HTTP_REFERER'])
self.say(self.translate('action_done'))
self.goto(urlBack)
def onCreate(self): def onCreate(self):
'''This method is called when a user wants to create a root object in '''This method is called when a user wants to create a root object in

View file

@ -83,11 +83,11 @@ msgstr ""
msgid "add_ref" msgid "add_ref"
msgstr "" msgstr ""
#. Default: "Selectable elements" #. Default: "Available elements"
msgid "selectable_objects" msgid "selectable_objects"
msgstr "" msgstr ""
#. Default: "Selected elements" #. Default: "Inserted elements"
msgid "selected_objects" msgid "selected_objects"
msgstr "" msgstr ""
@ -191,7 +191,7 @@ msgstr ""
msgid "object_delete" msgid "object_delete"
msgstr "" msgstr ""
#. Default: "Unlink" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
@ -199,6 +199,14 @@ msgstr ""
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements"
msgid "object_link_many"
msgstr ""
#. Default: "(Un)check everything"
msgid "check_uncheck"
msgstr ""
#. Default: "Unlock" #. Default: "Unlock"
msgid "page_unlock" msgid "page_unlock"
msgstr "" msgstr ""

View file

@ -83,11 +83,11 @@ msgstr ""
msgid "add_ref" msgid "add_ref"
msgstr "" msgstr ""
#. Default: "Selectable elements" #. Default: "Available elements"
msgid "selectable_objects" msgid "selectable_objects"
msgstr "" msgstr ""
#. Default: "Selected elements" #. Default: "Inserted elements"
msgid "selected_objects" msgid "selected_objects"
msgstr "" msgstr ""
@ -191,7 +191,7 @@ msgstr "تعديل"
msgid "object_delete" msgid "object_delete"
msgstr "" msgstr ""
#. Default: "Unlink" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
@ -199,6 +199,14 @@ msgstr ""
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements"
msgid "object_link_many"
msgstr ""
#. Default: "(Un)check everything"
msgid "check_uncheck"
msgstr ""
#. Default: "Unlock" #. Default: "Unlock"
msgid "page_unlock" msgid "page_unlock"
msgstr "" msgstr ""

View file

@ -83,11 +83,11 @@ msgstr "Kein Element"
msgid "add_ref" msgid "add_ref"
msgstr "Hinzufügen" msgstr "Hinzufügen"
#. Default: "Selectable elements" #. Default: "Available elements"
msgid "selectable_objects" msgid "selectable_objects"
msgstr "" msgstr ""
#. Default: "Selected elements" #. Default: "Inserted elements"
msgid "selected_objects" msgid "selected_objects"
msgstr "" msgstr ""
@ -191,7 +191,7 @@ msgstr "Bearbeiten"
msgid "object_delete" msgid "object_delete"
msgstr "Löschen" msgstr "Löschen"
#. Default: "Unlink" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
@ -199,6 +199,14 @@ msgstr ""
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements"
msgid "object_link_many"
msgstr ""
#. Default: "(Un)check everything"
msgid "check_uncheck"
msgstr ""
#. Default: "Unlock" #. Default: "Unlock"
msgid "page_unlock" msgid "page_unlock"
msgstr "" msgstr ""

View file

@ -84,13 +84,13 @@ msgstr "No object."
msgid "add_ref" msgid "add_ref"
msgstr "Add a new one" msgstr "Add a new one"
#. Default: "Selectable elements" #. Default: "Available elements"
msgid "selectable_objects" msgid "selectable_objects"
msgstr "Selectable elements" msgstr "Selectable elements"
#. Default: "Selected elements" #. Default: "Inserted elements"
msgid "selected_objects" msgid "selected_objects"
msgstr "Selected elements" msgstr "Inserted elements"
#. Default: "The action has been successfully executed." #. Default: "The action has been successfully executed."
msgid "action_ok" msgid "action_ok"
@ -192,7 +192,7 @@ msgstr "Edit"
msgid "object_delete" msgid "object_delete"
msgstr "Delete" msgstr "Delete"
#. Default: "Unlink" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "Unlink" msgstr "Unlink"
@ -200,6 +200,14 @@ msgstr "Unlink"
msgid "object_link" msgid "object_link"
msgstr "Insert" msgstr "Insert"
#. Default: "Insert selected elements"
msgid "object_link_many"
msgstr "Insert selected elements"
#. Default: "(Un)check everything"
msgid "check_uncheck"
msgstr "(Un)check everything"
#. Default: "Unlock" #. Default: "Unlock"
msgid "page_unlock" msgid "page_unlock"
msgstr "Unlock" msgstr "Unlock"

View file

@ -83,11 +83,11 @@ msgstr "Ningún elemento."
msgid "add_ref" msgid "add_ref"
msgstr "Añadir" msgstr "Añadir"
#. Default: "Selectable elements" #. Default: "Available elements"
msgid "selectable_objects" msgid "selectable_objects"
msgstr "" msgstr ""
#. Default: "Selected elements" #. Default: "Inserted elements"
msgid "selected_objects" msgid "selected_objects"
msgstr "" msgstr ""
@ -191,7 +191,7 @@ msgstr "Editar"
msgid "object_delete" msgid "object_delete"
msgstr "Eliminar" msgstr "Eliminar"
#. Default: "Unlink" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
@ -199,6 +199,14 @@ msgstr ""
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements"
msgid "object_link_many"
msgstr ""
#. Default: "(Un)check everything"
msgid "check_uncheck"
msgstr ""
#. Default: "Unlock" #. Default: "Unlock"
msgid "page_unlock" msgid "page_unlock"
msgstr "" msgstr ""

View file

@ -84,13 +84,13 @@ msgstr "Aucun élément."
msgid "add_ref" msgid "add_ref"
msgstr "Ajouter" msgstr "Ajouter"
#. Default: "Selectable elements" #. Default: "Available elements"
msgid "selectable_objects" msgid "selectable_objects"
msgstr "Éléments sélectionnables" msgstr "Éléments sélectionnables"
#. Default: "Selected elements" #. Default: "Inserted elements"
msgid "selected_objects" msgid "selected_objects"
msgstr "Éléments sélectionnés" msgstr "Éléments insérés"
#. Default: "The action has been successfully executed." #. Default: "The action has been successfully executed."
msgid "action_ok" msgid "action_ok"
@ -192,14 +192,22 @@ msgstr "Modifier"
msgid "object_delete" msgid "object_delete"
msgstr "Supprimer" msgstr "Supprimer"
#. Default: "Unlink" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "Dissocier" msgstr "Retirer"
#. Default: "Insert" #. Default: "Insert"
msgid "object_link" msgid "object_link"
msgstr "Insérer" msgstr "Insérer"
#. Default: "Insert selected elements"
msgid "object_link_many"
msgstr "Insérer la sélection"
#. Default: "(Un)check everything"
msgid "check_uncheck"
msgstr "Tout (dé)sélectionner"
#. Default: "Unlock" #. Default: "Unlock"
msgid "page_unlock" msgid "page_unlock"
msgstr "Déverrouiller" msgstr "Déverrouiller"

View file

@ -83,11 +83,11 @@ msgstr "Nessun elemento"
msgid "add_ref" msgid "add_ref"
msgstr "Aggiungi un nuovo" msgstr "Aggiungi un nuovo"
#. Default: "Selectable elements" #. Default: "Available elements"
msgid "selectable_objects" msgid "selectable_objects"
msgstr "" msgstr ""
#. Default: "Selected elements" #. Default: "Inserted elements"
msgid "selected_objects" msgid "selected_objects"
msgstr "" msgstr ""
@ -191,7 +191,7 @@ msgstr "Modifica"
msgid "object_delete" msgid "object_delete"
msgstr "Elimina" msgstr "Elimina"
#. Default: "Unlink" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
@ -199,6 +199,14 @@ msgstr ""
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements"
msgid "object_link_many"
msgstr ""
#. Default: "(Un)check everything"
msgid "check_uncheck"
msgstr ""
#. Default: "Unlock" #. Default: "Unlock"
msgid "page_unlock" msgid "page_unlock"
msgstr "" msgstr ""

View file

@ -83,11 +83,11 @@ msgstr "Geen element."
msgid "add_ref" msgid "add_ref"
msgstr "Toevoegen" msgstr "Toevoegen"
#. Default: "Selectable elements" #. Default: "Available elements"
msgid "selectable_objects" msgid "selectable_objects"
msgstr "" msgstr ""
#. Default: "Selected elements" #. Default: "Inserted elements"
msgid "selected_objects" msgid "selected_objects"
msgstr "" msgstr ""
@ -191,7 +191,7 @@ msgstr "Bewerken"
msgid "object_delete" msgid "object_delete"
msgstr "Verwijderen" msgstr "Verwijderen"
#. Default: "Unlink" #. Default: "Remove"
msgid "object_unlink" msgid "object_unlink"
msgstr "" msgstr ""
@ -199,6 +199,14 @@ msgstr ""
msgid "object_link" msgid "object_link"
msgstr "" msgstr ""
#. Default: "Insert selected elements"
msgid "object_link_many"
msgstr ""
#. Default: "(Un)check everything"
msgid "check_uncheck"
msgstr ""
#. Default: "Unlock" #. Default: "Unlock"
msgid "page_unlock" msgid "page_unlock"
msgstr "" msgstr ""

View file

@ -66,7 +66,7 @@ img { border: 0; vertical-align: middle }
background-color: #dbdde1; font-weight: bold } background-color: #dbdde1; font-weight: bold }
.navigate td { padding: 4px 9px } .navigate td { padding: 4px 9px }
.login { margin: 3px; color: black } .login { margin: 3px; color: black }
input.button { border-width: 0 !important; color: #666666; height: 23px; input.button { border-width: 0 !important; color: #666666; height: 24px;
width: 150px; cursor:pointer; font-size: 90%; padding: 1px 0 0 10px; width: 150px; cursor:pointer; font-size: 90%; padding: 1px 0 0 10px;
background-color: transparent !important } background-color: transparent !important }
.buttons { margin-left: 4px } .buttons { margin-left: 4px }
@ -157,3 +157,4 @@ td.search { padding-top: 8px }
.error { margin: 5px } .error { margin: 5px }
.podName { font-size: 90% } .podName { font-size: 90% }
.podTable { margin-left: 15px } .podTable { margin-left: 15px }
.cbCell { width: 10px; text-align: center}

View file

@ -229,13 +229,16 @@ function askRefField(hookId, objectUrl, fieldName, innerRef, startNumber,
action, actionParams){ action, actionParams){
// 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 params = {'innerRef': innerRef }; var scope = hookId.split('_').pop();
var params = {'innerRef': innerRef, 'scope': scope};
params[startKey] = startNumber; params[startKey] = startNumber;
if (action) params['action'] = action; if (action) params['action'] = action;
if (actionParams) { if (actionParams) {
for (key in actionParams) { params[key] = actionParams[key]; }; for (key in actionParams) { params[key] = actionParams[key]; };
} }
askAjaxChunk(hookId, 'GET', objectUrl, fieldName+':pxView', params); var px = (scope == 'objs')? ':pxView': ':pxViewPickList';
askAjaxChunk(hookId, 'GET', objectUrl, fieldName + px, params, null,
evalInnerScripts);
} }
function askField(hookId, objectUrl, layoutType, showChanges, masterValues, function askField(hookId, objectUrl, layoutType, showChanges, masterValues,
@ -251,7 +254,7 @@ function askField(hookId, objectUrl, layoutType, showChanges, masterValues,
askAjaxChunk(hookId, 'GET', objectUrl, px, params, null, evalInnerScripts); askAjaxChunk(hookId, 'GET', objectUrl, px, params, null, evalInnerScripts);
} }
// Function used by checkbox widgets for having radio-button-like behaviour // Used by checkbox widgets for having radio-button-like behaviour.
function toggleCheckbox(visibleCheckbox, hiddenBoolean) { function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
vis = document.getElementById(visibleCheckbox); vis = document.getElementById(visibleCheckbox);
hidden = document.getElementById(hiddenBoolean); hidden = document.getElementById(hiddenBoolean);
@ -259,6 +262,61 @@ function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
else hidden.value = 'False'; else hidden.value = 'False';
} }
// (Un)checks a checkbox corresponding to a linked object.
function toggleRefCb(checkbox) {
var name = checkbox.getAttribute('name');
var elems = name.split('_');
// Get the DOM node corresponding to the Ref field.
var node = document.getElementById(elems[0] + '_' + elems[1]);
// Get the array that stores checkbox statuses.
var statuses = node['_appy_' + elems[2] + '_cbs'];
// Get the array semantics
var semantics = node['_appy_' + elems[2] + '_sem'];
var uid = checkbox.value;
if (semantics == 'unchecked') {
if (!checkbox.checked) statuses[uid] = null;
else {if (uid in statuses) delete statuses[uid]};
}
else { // semantics is 'checked'
if (checkbox.checked) statuses[uid] = null;
else {if (uid in statuses) delete statuses[uid]};
}
}
// Initialise checkboxes of a Ref field.
function initRefCbs(id) {
var elems = id.split('_');
// Get the DOM node corresponding to the Ref field.
var node = document.getElementById(elems[0] + '_' + elems[1]);
// Get the array that stores checkbox statuses.
var statuses = node['_appy_' + elems[2] + '_cbs'];
// Get the array semantics
var semantics = node['_appy_' + elems[2] + '_sem'];
var value = (semantics == 'unchecked')? false: true;
// Update visible checkboxes.
var checkboxes = getElementsHavingName('input', id);
for (var i=0; i < checkboxes.length; i++) {
if (checkboxes[i].value in statuses) checkboxes[i].checked = value;
else checkboxes[i].checked = !value;
}
}
// Toggle all checkboxes of a Ref field.
function toggleAllRefCbs(id) {
var elems = id.split('_');
// Get the DOM node corresponding to the Ref field.
var node = document.getElementById(elems[0] + '_' + elems[1]);
// Empty the array that stores checkbox statuses.
var statuses = node['_appy_' + elems[2] + '_cbs'];
for (var key in statuses) delete statuses[key];
// Switch the array semantics.
var semAttr = '_appy_' + elems[2] + '_sem';
if (node[semAttr] == 'unchecked') node[semAttr] = 'checked';
else node[semAttr] = 'unchecked';
// Update the visible checkboxes
initRefCbs(id);
}
// Shows/hides a dropdown menu // Shows/hides a dropdown menu
function toggleDropdown(dropdownId, forcedValue){ function toggleDropdown(dropdownId, forcedValue){
var dropdown = document.getElementById(dropdownId); var dropdown = document.getElementById(dropdownId);
@ -456,22 +514,35 @@ function onDeleteEvent(objectUid, eventTime) {
askConfirm('form', 'deleteEventForm', action_confirm); askConfirm('form', 'deleteEventForm', action_confirm);
} }
function onUnlinkObject(sourceUid, fieldName, targetUid) { function onLink(action, sourceUid, fieldName, targetUid) {
f = document.getElementById('unlinkForm');
f.sourceUid.value = sourceUid;
f.fieldName.value = fieldName;
f.targetUid.value = targetUid;
askConfirm('form', 'unlinkForm', action_confirm);
}
function onLinkObject(sourceUid, fieldName, targetUid) {
f = document.getElementById('linkForm'); f = document.getElementById('linkForm');
f.linkAction.value = action;
f.sourceUid.value = sourceUid; f.sourceUid.value = sourceUid;
f.fieldName.value = fieldName; f.fieldName.value = fieldName;
f.targetUid.value = targetUid; f.targetUid.value = targetUid;
f.submit(); f.submit();
} }
function onLinkMany(id) {
var elems = id.split('_');
// Get the DOM node corresponding to the Ref field.
var node = document.getElementById(elems[0] + '_' + elems[1]);
// Get the uids of (un-)checked objects.
var statuses = node['_appy_' + elems[2] + '_cbs'];
var uids = '';
for (var uid in statuses) uids += uid + ',';
// Get the array semantics
var semantics = node['_appy_' + elems[2] + '_sem'];
// Fill the form and ask for a confirmation
f = document.getElementById('linkForm');
f.linkAction.value = 'link_many';
f.sourceUid.value = elems[0];
f.fieldName.value = elems[1];
f.targetUid.value = uids;
f.semantics.value = semantics;
askConfirm('form', 'linkForm', action_confirm);
}
function onUnlockPage(objectUid, pageName) { function onUnlockPage(objectUid, pageName) {
f = document.getElementById('unlockForm'); f = document.getElementById('unlockForm');
f.objectUid.value = objectUid; f.objectUid.value = objectUid;

BIN
gen/ui/checkall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

BIN
gen/ui/linkMany.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

BIN
gen/ui/unlinkUp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

View file

@ -115,19 +115,14 @@ class ToolWrapper(AbstractWrapper):
<input type="hidden" name="objectUid"/> <input type="hidden" name="objectUid"/>
<input type="hidden" name="eventTime"/> <input type="hidden" name="eventTime"/>
</form> </form>
<!-- Global form for unlinking an object --> <!-- Global form for (un)linking (an) object(s) -->
<form id="unlinkForm" method="post" action="do">
<input type="hidden" name="action" value="Unlink"/>
<input type="hidden" name="sourceUid"/>
<input type="hidden" name="fieldName"/>
<input type="hidden" name="targetUid"/>
</form>
<!-- Global form for linking an object -->
<form id="linkForm" method="post" action="do"> <form id="linkForm" method="post" action="do">
<input type="hidden" name="action" value="Link"/> <input type="hidden" name="action" value="Link"/>
<input type="hidden" name="linkAction"/>
<input type="hidden" name="sourceUid"/> <input type="hidden" name="sourceUid"/>
<input type="hidden" name="fieldName"/> <input type="hidden" name="fieldName"/>
<input type="hidden" name="targetUid"/> <input type="hidden" name="targetUid"/>
<input type="hidden" name="semantics"/>
</form> </form>
<!-- Global form for unlocking a page --> <!-- Global form for unlocking a page -->
<form id="unlockForm" method="post" action="do"> <form id="unlockForm" method="post" action="do">