[gen] New ajax system: more bugfixes.

This commit is contained in:
Gaetan Delannay 2015-02-05 14:05:29 +01:00
parent d23b9be5e5
commit 40e3612682
7 changed files with 48 additions and 35 deletions

View file

@ -176,7 +176,7 @@ class Ref(Field):
<a target="appyIFrame" <a target="appyIFrame"
var="tiedClassName=tiedClassName|ztool.getPortalType(field.klass); var="tiedClassName=tiedClassName|ztool.getPortalType(field.klass);
className=ztool.getPortalType(obj.klass)" className=ztool.getPortalType(obj.klass)"
href=":'%s/query?className=%s&amp;search=%s:%s:%s&amp;popup=1' % \ href=":'%s/query?className=%s&amp;search=%s*%s*%s&amp;popup=1' % \
(ztool.absolute_url(), tiedClassName, obj.uid, field.name, \ (ztool.absolute_url(), tiedClassName, obj.uid, field.name, \
popupMode)"> popupMode)">
<input type="button" <input type="button"
@ -287,13 +287,13 @@ class Ref(Field):
<!-- Loop on every (tied or selectable) object --> <!-- Loop on every (tied or selectable) object -->
<x for="tied in objects" <x for="tied in objects"
var2="@currentNumber=currentNumber + 1; var2="@currentNumber=currentNumber + 1;
rowCss=loop.tied.odd and 'even' or 'odd'">:obj.pxViewAsTied</x> rowCss=loop.tied.odd and 'even' or 'odd'">:tied.pxViewAsTied</x>
</table> </table>
<!-- Global actions --> <!-- Global actions -->
<x if="mayEdit and checkboxes">:field.pxGlobalActions</x> <x if="mayEdit and checkboxes">:field.pxGlobalActions</x>
<!-- (Bottom) navigation --> <!-- (Bottom) navigation -->
<x>:tool.pxNavigate</x> <x>:tool.pxNavigate</x>
<!-- Init checkboxes if present. --> <!-- Init checkboxes if present -->
<script if="checkboxes">:'initCbs(%s)' % q(ajaxHookId)</script> <script if="checkboxes">:'initCbs(%s)' % q(ajaxHookId)</script>
</div>''') </div>''')
@ -437,8 +437,8 @@ class Ref(Field):
collapse=field.getCollapseInfo(obj, False); collapse=field.getCollapseInfo(obj, False);
showSubTitles=req.get('showSubTitles', 'true') == 'true'"> showSubTitles=req.get('showSubTitles', 'true') == 'true'">
<!-- JS tables storing checkbox statuses if checkboxes are enabled --> <!-- JS tables storing checkbox statuses if checkboxes are enabled -->
<script if="checkboxesEnabled and renderAll and (render == 'list')" <script if="checkboxesEnabled and renderAll \
type="text/javascript">:field.getCbJsInit(zobj)</script> and (render == 'list')">:field.getCbJsInit(zobj)</script>
<x if="linkList and renderAll and mayEdit" <x if="linkList and renderAll and mayEdit"
var2="ajaxHookId='%s_%s_poss' % \ var2="ajaxHookId='%s_%s_poss' % \
(zobj.id, field.name)">:field.pxViewPickList</x> (zobj.id, field.name)">:field.pxViewPickList</x>
@ -1265,7 +1265,7 @@ class Ref(Field):
code = "\nnode['_appy_%%s_cbs']={};\nnode['_appy_%%s_sem']='%s';" % \ code = "\nnode['_appy_%%s_cbs']={};\nnode['_appy_%%s_sem']='%s';" % \
default default
poss = (self.link == 'list') and (code % ('poss', 'poss')) or '' poss = (self.link == 'list') and (code % ('poss', 'poss')) or ''
return "var node=document.getElementById('%s_%s');%s%s" % \ return "var node=findNode(this, '%s_%s');%s%s" % \
(obj.id, self.name, code % ('objs', 'objs'), poss) (obj.id, self.name, code % ('objs', 'objs'), poss)
def getAjaxData(self, hook, zobj, **params): def getAjaxData(self, hook, zobj, **params):

View file

@ -202,8 +202,8 @@ class UiSearch:
<td colspan=":len(columns)+1">:_('query_no_result')</td> <td colspan=":len(columns)+1">:_('query_no_result')</td>
</tr> </tr>
<x for="zobj in zobjects" <x for="zobj in zobjects"
var2="@currentNumber=currentNumber + 1; var2="rowCss=loop.zobj.odd and 'even' or 'odd';
rowCss=loop.zobj.odd and 'even' or 'odd'">:obj.pxViewAsResult</x> @currentNumber=currentNumber + 1">:zobj.appy().pxViewAsResult</x>
</table> </table>
<!-- The button for selecting objects and closing the popup --> <!-- The button for selecting objects and closing the popup -->
<div if="inPopup and cbShown" align=":dleft"> <div if="inPopup and cbShown" align=":dleft">
@ -241,7 +241,7 @@ class UiSearch:
<div var="ajaxHookId='queryResult'; <div var="ajaxHookId='queryResult';
className=req['className']; className=req['className'];
searchName=req.get('search', ''); searchName=req.get('search', '');
uiSearch=uiSearch|ztool.getSearch(className,searchName,ui=True); uiSearch=field|ztool.getSearch(className, searchName, ui=True);
rootHookId=uiSearch.getRootHookId(); rootHookId=uiSearch.getRootHookId();
refInfo=ztool.getRefInfo(); refInfo=ztool.getRefInfo();
refObject=refInfo[0]; refObject=refInfo[0];
@ -389,7 +389,7 @@ class UiSearch:
'''Returns the code that creates JS data structures for storing the '''Returns the code that creates JS data structures for storing the
status of checkboxes for every result of this search.''' status of checkboxes for every result of this search.'''
default = self.search.checkboxesDefault and 'unchecked' or 'checked' default = self.search.checkboxesDefault and 'unchecked' or 'checked'
return '''var node=document.getElementById('%s'); return '''var node=findNode(this, '%s');
node['_appy_objs_cbs'] = {}; node['_appy_objs_cbs'] = {};
node['_appy_objs_sem'] = '%s';''' % (hookId, default) node['_appy_objs_sem'] = '%s';''' % (hookId, default)

View file

@ -223,11 +223,11 @@ class ToolMixin(BaseMixin):
return res return res
def getRootClasses(self): def getRootClasses(self):
'''Returns the list of root classes for this application.''' '''Returns the list of root classes for this application'''
cfg = self.getProductConfig().appConfig cfg = self.getProductConfig().appConfig
rootClasses = cfg.rootClasses rootClasses = cfg.rootClasses
if not rootClasses: if not rootClasses:
# We consider every class as being a root class. # We consider every class as being a root class
rootClasses = self.getProductConfig().appClassNames rootClasses = self.getProductConfig().appClassNames
return [self.getAppyClass(k) for k in rootClasses] return [self.getAppyClass(k) for k in rootClasses]
@ -749,10 +749,10 @@ class ToolMixin(BaseMixin):
# It is a custom search whose parameters are in the session # It is a custom search whose parameters are in the session
fields = self.REQUEST.SESSION['searchCriteria'] fields = self.REQUEST.SESSION['searchCriteria']
res = Search('customSearch', **fields) res = Search('customSearch', **fields)
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, mode = 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

View file

@ -405,8 +405,8 @@ class BaseMixin:
pageInfo = phaseObj.getPageInfo(rq['page'], 'view') pageInfo = phaseObj.getPageInfo(rq['page'], 'view')
if not pageInfo: urlBack = tool.getHomePage() if not pageInfo: urlBack = tool.getHomePage()
else: urlBack = self.getUrl(page=pageInfo.page.name) else: urlBack = self.getUrl(page=pageInfo.page.name)
self.say(self.translate('object_canceled'))
self.removeLock(rq['page']) self.removeLock(rq['page'])
self.say(self.translate('object_canceled'))
if inPopup: return back if inPopup: return back
return self.goto(urlBack) return self.goto(urlBack)

View file

@ -403,7 +403,7 @@ function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
else hidden.value = 'False'; else hidden.value = 'False';
} }
// JS implementation of Python ''.rsplit. // JS implementation of Python ''.rsplit
function _rsplit(s, delimiter, limit) { function _rsplit(s, delimiter, limit) {
var elems = s.split(delimiter); var elems = s.split(delimiter);
var exc = elems.length - limit; var exc = elems.length - limit;
@ -419,11 +419,11 @@ function _rsplit(s, delimiter, limit) {
return res; return res;
} }
// (Un)checks a checkbox corresponding to a linked object. // (Un)checks a checkbox corresponding to a linked object
function toggleCb(checkbox) { function toggleCb(checkbox) {
var name = checkbox.getAttribute('name'); var name = checkbox.getAttribute('name');
var elems = _rsplit(name, '_', 3); 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.
var statuses = node['_appy_' + elems[2] + '_cbs']; var statuses = node['_appy_' + elems[2] + '_cbs'];
@ -440,17 +440,26 @@ function toggleCb(checkbox) {
} }
} }
// Initialise checkboxes of a Ref field or Search. function findNode(node, id) {
/* When coming back from the iframe popup, we are still in the context of the
iframe, which can cause problems for finding nodes. We have found that this
case can be detected by checking node.window. */
if (node.window) var container = node.window.document;
else var container = window.parent.document;
return container.getElementById(id);
}
// Initialise checkboxes of a Ref field or Search
function initCbs(id) { function initCbs(id) {
var elems = _rsplit(id, '_', 3); 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
var statuses = node['_appy_' + elems[2] + '_cbs']; var statuses = node['_appy_' + elems[2] + '_cbs'];
// Get the array semantics // Get the array semantics
var semantics = node['_appy_' + elems[2] + '_sem']; var semantics = node['_appy_' + elems[2] + '_sem'];
var value = (semantics == 'unchecked')? false: true; var value = (semantics == 'unchecked')? false: true;
// Update visible checkboxes. // Update visible checkboxes
var checkboxes = getElementsHavingName('input', id); var checkboxes = getElementsHavingName('input', id);
for (var i=0; i < checkboxes.length; i++) { for (var i=0; i < checkboxes.length; i++) {
if (checkboxes[i].value in statuses) checkboxes[i].checked = value; if (checkboxes[i].value in statuses) checkboxes[i].checked = value;
@ -458,15 +467,15 @@ function initCbs(id) {
} }
} }
// Toggle all checkboxes of a Ref field or Search. // Toggle all checkboxes of a Ref field or Search
function toggleAllCbs(id) { function toggleAllCbs(id) {
var elems = _rsplit(id, '_', 3); 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
var statuses = node['_appy_' + elems[2] + '_cbs']; var statuses = node['_appy_' + elems[2] + '_cbs'];
for (var key in statuses) delete statuses[key]; for (var key in statuses) delete statuses[key];
// Switch the array semantics. // Switch the array semantics
var semAttr = '_appy_' + elems[2] + '_sem'; var semAttr = '_appy_' + elems[2] + '_sem';
if (node[semAttr] == 'unchecked') node[semAttr] = 'checked'; if (node[semAttr] == 'unchecked') node[semAttr] = 'checked';
else node[semAttr] = 'unchecked'; else node[semAttr] = 'unchecked';
@ -892,7 +901,7 @@ function closePopup(popupId, clean) {
// Reinitialise the enclosing iframe // Reinitialise the enclosing iframe
var iframe = container.getElementById('appyIFrame'); var iframe = container.getElementById('appyIFrame');
iframe.style.width = null; iframe.style.width = null;
iframe.innerHTML = ''; while (iframe.firstChild) iframe.removeChild(iframe.firstChild);
// Leave the form silently if we are on an edit page // Leave the form silently if we are on an edit page
iframe.contentWindow.onbeforeunload = null; iframe.contentWindow.onbeforeunload = null;
} }
@ -907,10 +916,10 @@ function backFromPopup() {
function showAppyMessage(message) { function showAppyMessage(message) {
// Fill the message zone with the message to display // Fill the message zone with the message to display
var messageZone = document.getElementById('appyMessageContent'); var messageZone = getAjaxHook(':appyMessageContent');
messageZone.innerHTML = message; messageZone.innerHTML = message;
// Display the message zone // Display the message zone
var messageDiv = document.getElementById('appyMessage'); var messageDiv = getAjaxHook(':appyMessage');
messageDiv.style.display = 'block'; messageDiv.style.display = 'block';
} }
@ -1172,12 +1181,12 @@ function onSelectObjects(nodeId, objectUrl, mode, sortKey, sortOrder,
var node = document.getElementById(nodeId); var node = document.getElementById(nodeId);
var uids = stringFromDictKeys(node['_appy_objs_cbs']); var uids = stringFromDictKeys(node['_appy_objs_cbs']);
var semantics = node['_appy_objs_sem']; var semantics = node['_appy_objs_sem'];
// Show an error message if no element is selected. // Show an error message if no element is selected
if ((semantics == 'checked') && (!uids)) { if ((semantics == 'checked') && (!uids)) {
openPopup('alertPopup', no_elem_selected); openPopup('alertPopup', no_elem_selected);
return; return;
} }
// Close the popup. // Close the popup
closePopup('iframePopup'); closePopup('iframePopup');
/* When refreshing the Ref field we will need to pass all those parameters, /* When refreshing the Ref field we will need to pass all those parameters,
for replaying the popup query. */ for replaying the popup query. */
@ -1190,7 +1199,7 @@ function onSelectObjects(nodeId, objectUrl, mode, sortKey, sortOrder,
askField(':'+nodeId, objectUrl, 'edit', params, false); askField(':'+nodeId, objectUrl, 'edit', params, false);
} }
else { else {
// Link the selected objects and refresh the Ref view widget. // Link the selected objects and refresh the Ref view widget
params['action'] = 'onSelectFromPopup'; params['action'] = 'onSelectFromPopup';
askField(':'+nodeId, objectUrl, 'view', params, false); askField(':'+nodeId, objectUrl, 'view', params, false);
} }

View file

@ -279,7 +279,7 @@ class ToolWrapper(AbstractWrapper):
<!-- The message content --> <!-- The message content -->
<div id="appyMessageContent"></div> <div id="appyMessageContent"></div>
</div> </div>
<script type="text/javascript" var="messages=ztool.consumeMessages()" <script var="messages=ztool.consumeMessages()"
if="messages">::'showAppyMessage(%s)' % q(messages)</script>''') if="messages">::'showAppyMessage(%s)' % q(messages)</script>''')
# The page footer # The page footer

View file

@ -728,12 +728,16 @@ class AbstractWrapper(object):
x=resp.setHeader('Content-Language', lang); x=resp.setHeader('Content-Language', lang);
x=resp.setHeader('Cache-Control', 'no-cache')"> x=resp.setHeader('Cache-Control', 'no-cache')">
<!-- If an action is defined, execute it on p_zobj or on p_field. --> <!-- If an action is defined, execute it on p_zobj or on p_field -->
<x if="action" <x if="action"
var2="msg=ztool.executeAjaxAction(action, obj, field) or ''; var2="msg=ztool.executeAjaxAction(action, obj, field) or '';
x=resp.setHeader('Appy-Message', msg)"></x> x=resp.setHeader('Appy-Message', msg)"></x>
<!-- Then, call the PX on p_obj or on p_field. --> <!-- Consume and return any session message -->
<x var="msg=ztool.consumeMessages()" if="msg"
var2="x=resp.setHeader('Appy-Message', msg)"></x>
<!-- Then, call the PX on p_obj or on p_field -->
<x if="not field">:getattr(obj, px[0])</x> <x if="not field">:getattr(obj, px[0])</x>
<x if="field">:getattr(field, px[-1])</x> <x if="field">:getattr(field, px[-1])</x>
</x>''') </x>''')