@@ -300,8 +298,7 @@ class Ref(Field):
# PX that displays the list of objects the user may select to insert into a
# ref field with link="list".
pxViewPickList = Px('''
-
@@ -240,8 +245,8 @@ class UiSearch:
# Render search results
pxResult = Px('''
:uiSearch.translatedDescr
-
:tool.pxNavigate
+
:tool.pxNavigate
@@ -397,13 +399,20 @@ class UiSearch:
def getAjaxData(self, hook, ztool, **params):
'''Initializes an AjaxData object on the DOM node corresponding to
p_hook = the whole search result.'''
- # Complete params with default parameters
+ # Complete params with default ones and optional filter/sort params. For
+ # performing a complete Ajax request, "className" and "searcName" are
+ # not needed because included in the PX name. But they are requested by
+ # sub-Ajax queries at the row level.
params['className'] = self.className
params['searchName'] = self.name
+ req = ztool.REQUEST
+ for param, default in UiSearch.sortFilterDefaults.iteritems():
+ params[param] = req.get(param, default)
+ # Convert params into a JS dict
params = sutils.getStringDict(params)
- return "getAjaxHook('%s',true)['ajax']=new AjaxData('%s', " \
- "'pxResult', %s, null, '%s')" % \
- (hook, hook, params, ztool.absolute_url())
+ px = '%s:%s:pxResult' % (self.className, self.name)
+ return "getAjaxHook('%s',true)['ajax']=new AjaxData('%s', '%s', %s, " \
+ "null, '%s')" % (hook, hook, px, params, ztool.absolute_url())
def getAjaxDataRow(self, zobj, parentHook, **params):
'''Initializes an AjaxData object on the DOM node corresponding to
diff --git a/gen/mixins/__init__.py b/gen/mixins/__init__.py
index 20fe2d9..7f73715 100644
--- a/gen/mixins/__init__.py
+++ b/gen/mixins/__init__.py
@@ -1247,7 +1247,15 @@ class BaseMixin:
def getHistoryCollapse(self):
'''Gets a Collapsible instance for showing a collapse or expanded
history in this object.'''
- return Collapsible('appyHistory', self.REQUEST)
+ return Collapsible('objectHistory', self.REQUEST)
+
+ def getHistoryAjaxData(self, hook, startNumber, batchSize):
+ '''Gets data allowing to ajax-ask paginated history data.'''
+ params = {'startNumber': startNumber, 'maxPerPage': batchSize}
+ # Convert params into a JS dict
+ params = sutils.getStringDict(params)
+ return "getAjaxHook('%s',true)['ajax']=new AjaxData('%s','pxHistory', "\
+ "%s, null, '%s')" % (hook, hook, params, self.absolute_url())
def mayNavigate(self):
'''May the currently logged user see the navigation panel linked to
diff --git a/gen/ui/appy.js b/gen/ui/appy.js
index c8fbf51..e4e1ea5 100644
--- a/gen/ui/appy.js
+++ b/gen/ui/appy.js
@@ -118,25 +118,6 @@ function injectChunk(elem, content, inner, searchTop){
return res;
}
-function clickOn(node) {
- // If node is a form, disable all form buttons
- if (node.tagName == 'FORM') {
- var i = node.elements.length -1;
- while (i >= 0) {
- if (node.elements[i].type == 'button') { clickOn(node.elements[i]); }
- i = i - 1;
- }
- return;
- }
- // Disable any click on p_node to be protected against double-click
- var cn = (node.className)? 'unclickable ' + node.className : 'unclickable';
- node.className = cn;
- /* For a button, show the preloader directly. For a link, show it only after
- a while, if the target page is still not there. */
- if (node.tagName != 'A') injectChunk(node, loadingButton);
- else setTimeout(function(){injectChunk(node, loadingLink)}, 700);
-}
-
function getAjaxHook(hookId, forceTop) {
/* Gets the XHTML element whose ID is p_hookId: it will be the placeholder
for the result of an ajax request. If p_hookId starts with ':', we search
@@ -309,61 +290,62 @@ function askAjax(hook, form, params) {
evalInnerScripts);
}
-/* The functions below wrap askAjaxChunk for getting specific content through
- an Ajax request. */
-function askQueryResult(hookId, objectUrl, className, searchName, popup,
- startNumber, sortKey, sortOrder, filterKey) {
- // Sends an Ajax request for getting the result of a query
- var params = {'className': className, 'search': searchName,
- 'startNumber': startNumber, 'popup': popup};
- if (sortKey) params['sortKey'] = sortKey;
- if (sortOrder) params['sortOrder'] = sortOrder;
- if (filterKey) {
- var filterWidget = document.getElementById(hookId + '_' + filterKey);
- if (filterWidget && filterWidget.value) {
- params['filterKey'] = filterKey;
- params['filterValue'] = encodeURIComponent(filterWidget.value);
+function askBunch(hookId, startNumber) {
+ askAjax(hookId, null, {'startNumber': startNumber})}
+
+function askBunchSorted(hookId, sortKey, sortOrder) {
+ var data = {'startNumber': '0', 'sortKey': sortKey, 'sortOrder': sortOrder};
+ askAjax(hookId, null, data);
+}
+
+function askBunchFiltered(hookId, filterKey) {
+ var data = {'startNumber': '0', 'filterKey': filterKey, 'filterValue': ''};
+ var node = document.getElementById(hookId + '_' + filterKey);
+ if (node.value) data['filterValue'] = encodeURIComponent(node.value);
+ askAjax(hookId, null, data);
+}
+
+function askBunchMove(hookId, startNumber, uid, move){
+ var moveTo = move;
+ if (typeof move == 'object'){
+ // Get the new index from an input field
+ var id = move.id;
+ id = id.substr(0, id.length-4);
+ var input = document.getElementById(id);
+ if (isNaN(input.value)) {
+ input.style.background = wrongTextInput;
+ return;
}
+ moveTo = 'index_' + input.value;
}
- var px = className + ':' + searchName + ':' + 'pxResult';
- askAjaxChunk(hookId, 'GET', objectUrl, px, params, null, evalInnerScripts);
+ var data = {'startNumber': startNumber, 'action': 'doChangeOrder',
+ 'refObjectUid': uid, 'move': moveTo};
+ askAjax(hookId, null, data);
}
-function askObjectHistory(hookId, objectUrl, maxPerPage, startNumber) {
- // Sends an Ajax request for getting the history of an object
- var params = {'maxPerPage': maxPerPage, 'startNumber': startNumber};
- askAjaxChunk(hookId, 'GET', objectUrl, 'pxHistory', params);
+function askBunchSortRef(hookId, startNumber, sortKey, reverse) {
+ var data = {'startNumber': startNumber, 'action': 'sort', 'sortKey': sortKey,
+ 'reverse': reverse};
+ askAjax(hookId, null, data);
}
-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 = hookElems.pop();
- var params = {'innerRef': innerRef, 'scope': scope};
- params[startKey] = startNumber;
- if (action) params['action'] = action;
- if (actionParams) {
- for (var key in actionParams) {
- if ((key == 'move') && (typeof actionParams[key] == 'object')) {
- // Get the new index from an input field
- var id = actionParams[key].id;
- id = id.substr(0, id.length-4);
- var input = document.getElementById(id);
- if (isNaN(input.value)) {
- input.style.background = wrongTextInput;
- return;
- }
- params[key] = 'index_' + input.value;
- }
- else params[key] = actionParams[key];
- };
+function clickOn(node) {
+ // If node is a form, disable all form buttons
+ if (node.tagName == 'FORM') {
+ var i = node.elements.length -1;
+ while (i >= 0) {
+ if (node.elements[i].type == 'button') { clickOn(node.elements[i]); }
+ i = i - 1;
+ }
+ return;
}
- var px = (scope == 'objs')? ':pxView': ':pxViewPickList';
- askAjaxChunk(hookId, 'GET', objectUrl, fieldName + px, params, null,
- evalInnerScripts);
+ // Disable any click on p_node to be protected against double-click
+ var cn = (node.className)? 'unclickable ' + node.className : 'unclickable';
+ node.className = cn;
+ /* For a button, show the preloader directly. For a link, show it only after
+ a while, if the target page is still not there. */
+ if (node.tagName != 'A') injectChunk(node, loadingButton);
+ else setTimeout(function(){injectChunk(node, loadingLink)}, 700);
}
function gotoTied(objectUrl, field, numberWidget, total) {
@@ -381,7 +363,7 @@ function gotoTied(objectUrl, field, numberWidget, total) {
function askField(hookId, objectUrl, layoutType, customParams, showChanges,
masterValues, requestValue, error, className){
- // Sends an Ajax request for getting the content of any field.
+ // Sends an Ajax request for getting the content of any field
var fieldName = hookId.split('_')[1];
var params = {'layoutType': layoutType, 'showChanges': showChanges};
if (customParams){for (var key in customParams) params[key]=customParams[key]}
@@ -833,10 +815,10 @@ function generatePod(node, uid, fieldName, template, podFormat, queryData,
f.checkedSem.value = '';
if (getChecked) {
// We must collect selected objects from a Ref field
- var node = document.getElementById(uid + '_' + getChecked);
- if (node && node.hasOwnProperty('_appy_objs_cbs')) {
- f.checkedUids.value = stringFromDictKeys(node['_appy_objs_cbs']);
- f.checkedSem.value = node['_appy_objs_sem'];
+ var cNode = document.getElementById(uid + '_' + getChecked);
+ if (cNode && cNode.hasOwnProperty('_appy_objs_cbs')) {
+ f.checkedUids.value = stringFromDictKeys(cNode['_appy_objs_cbs']);
+ f.checkedSem.value = cNode['_appy_objs_sem'];
}
}
// Submitting the form at the end blocks the animated gifs on FF
diff --git a/gen/wrappers/ToolWrapper.py b/gen/wrappers/ToolWrapper.py
index cb0b96b..e709378 100644
--- a/gen/wrappers/ToolWrapper.py
+++ b/gen/wrappers/ToolWrapper.py
@@ -24,44 +24,40 @@ class ToolWrapper(AbstractWrapper):
pxSortAndFilter = Px('''
-
+
+ onclick=":'askBunchFiltered(%s, %s)' % \
+ (q(ajaxHookId), q(field.name))"/>
''')
# Buttons for navigating among a list of objects (from a Ref field or a
# query): next,back,first,last...
pxNavigate = Px('''
-