Reworked AJAX framework with a lot of new sorting and filtering possibilities.
This commit is contained in:
parent
46cda3f755
commit
fd775e17a2
11 changed files with 851 additions and 890 deletions
|
@ -1,15 +1,12 @@
|
|||
<tal:comment replace="nothing">
|
||||
This page is called by a XmlHttpRequest object. It requires parameters "page" and "macro":
|
||||
they are used to call the macro that will render the HTML chunk to be returned to the browser.
|
||||
It also requires parameters "objectUid", which is the UID of the related object. The object will
|
||||
be available to the macro as "contextObj".
|
||||
It can also have a parameter "action", that refers to a method that will be triggered on
|
||||
contextObj before returning the result of the macro to the browser.
|
||||
</tal:comment>
|
||||
<tal:ajax define="page request/page;
|
||||
macro request/macro;
|
||||
macroPath python: 'here/%s/macros/%s' % (page, macro);
|
||||
contextObj python: context.uid_catalog(UID=request['objectUid'])[0].getObject();
|
||||
contextObj context/getParentNode;
|
||||
action request/action|nothing;
|
||||
response request/RESPONSE;
|
||||
member context/portal_membership/getAuthenticatedMember;
|
||||
|
@ -18,8 +15,11 @@
|
|||
dummy python:response.setHeader('Content-Type','text/html;;charset=utf-8');
|
||||
dummy2 python:response.setHeader('Expires', 'Mon, 11 Dec 1975 12:05:05 GMT');
|
||||
dummy3 python:response.setHeader('CacheControl', 'no-cache')">
|
||||
<tal:comment replace="nothing">Keys "Expires" and "CacheControl" are used for preventing IE to cache
|
||||
this page. Indeed, this page is retrieved through an asynchronous XMLHttpRequest by the browser, and
|
||||
IE caches this by default.</tal:comment>
|
||||
<tal:executeAction condition="action">
|
||||
<tal:do define="dummy python: contextObj.getAppyValue('on'+action)()" omit-tag=""/>
|
||||
</tal:executeAction>
|
||||
<metal:callMacro use-macro="python: context.get(page).macros.get(macro)"/>
|
||||
<metal:callMacro use-macro="python: portal.skyn.get(page).macros.get(macro)"/>
|
||||
</tal:ajax>
|
||||
|
|
|
@ -295,12 +295,12 @@
|
|||
batchSize historyInfo/batchSize;
|
||||
totalNumber historyInfo/totalNumber;
|
||||
ajaxHookId python:'appyHistory';
|
||||
baseUrl python: contextObj.getUrl('showHistory', startNumber='**v**');
|
||||
navBaseCall python: 'askObjectHistory(\'%s\',\'%s\',**v**)' % (ajaxHookId, contextObj.absolute_url());
|
||||
tool contextObj/getTool">
|
||||
|
||||
<tal:comment replace="nothing">Table containing the history</tal:comment>
|
||||
<tal:history condition="objs">
|
||||
<metal:nav use-macro="here/skyn/macros/macros/appyNavigate"/>
|
||||
<metal:nav use-macro="here/skyn/navigate/macros/appyNavigate"/>
|
||||
<table width="100%" class="listing nosort">
|
||||
<tr i18n:domain="plone">
|
||||
<th i18n:translate="listingheader_action"/>
|
||||
|
@ -370,8 +370,11 @@
|
|||
this.xhr = false;
|
||||
if (window.XMLHttpRequest) this.xhr = new XMLHttpRequest();
|
||||
else this.xhr = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
this.hook = ''; // The ID of the HTML element in the page that will be
|
||||
// replaced by result of executing the Ajax request.
|
||||
this.hook = ''; /* The ID of the HTML element in the page that will be
|
||||
replaced by result of executing the Ajax request. */
|
||||
this.onGet = ''; /* The name of a Javascript function to call once we
|
||||
receive the result. */
|
||||
this.info = {}; /* An associative array for putting anything else. */
|
||||
}
|
||||
|
||||
function getAjaxChunk(pos) {
|
||||
|
@ -391,15 +394,35 @@
|
|||
var hookElem = document.getElementById(hook);
|
||||
if (hookElem && (xhrObjects[pos].xhr.status == 200)) {
|
||||
hookElem.innerHTML = xhrObjects[pos].xhr.responseText;
|
||||
// Call a custom Javascript function if required
|
||||
if (xhrObjects[pos].onGet) {
|
||||
xhrObjects[pos].onGet(xhrObjects[pos], hookElem);
|
||||
}
|
||||
}
|
||||
xhrObjects[pos].freed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function askAjaxChunk(hook, url) {
|
||||
// This function will ask to get a chunk of HTML on the server by
|
||||
// triggering a XMLHttpRequest.
|
||||
function askAjaxChunk(hook,mode,url,page,macro,params,beforeSend,onGet) {
|
||||
/* This function will ask to get a chunk of HTML on the server through a
|
||||
XMLHttpRequest. p_mode can be 'GET' or 'POST'. p_url is the URL of a
|
||||
given server object. On this URL we will call the page "ajax.pt" that
|
||||
will call a specific p_macro in a given p_page with some additional
|
||||
p_params (must be an associative array) if required.
|
||||
|
||||
p_hook is the ID of the HTML element that will be filled with the HTML
|
||||
result from the server.
|
||||
|
||||
p_beforeSend is a Javascript function to call before sending the request.
|
||||
This function will get 2 args: the XMLHttpRequest object and the
|
||||
p_params. This method can return, in a string, additional parameters to
|
||||
send, ie: "¶m1=blabla¶m2=blabla".
|
||||
|
||||
p_onGet is a Javascript function to call when we will receive the answer.
|
||||
This function will get 2 args, too: the XMLHttpRequest object and the
|
||||
HTML node element into which the result has been inserted.
|
||||
*/
|
||||
// First, get a non-busy XMLHttpRequest object.
|
||||
var pos = -1;
|
||||
for (var i=0; i < xhrObjects.length; i++) {
|
||||
|
@ -410,16 +433,86 @@
|
|||
xhrObjects[pos] = new XhrObject();
|
||||
}
|
||||
xhrObjects[pos].hook = hook;
|
||||
xhrObjects[pos].onGet = onGet;
|
||||
if (xhrObjects[pos].xhr) {
|
||||
xhrObjects[pos].freed = 0;
|
||||
// Perform the asynchronous HTTP GET
|
||||
xhrObjects[pos].xhr.open('GET', url, true);
|
||||
xhrObjects[pos].xhr.onreadystatechange = function() { getAjaxChunk(pos); }
|
||||
if (window.XMLHttpRequest) { xhrObjects[pos].xhr.send(null); }
|
||||
else if (window.ActiveXObject) { xhrObjects[pos].xhr.send(); }
|
||||
var rq = xhrObjects[pos];
|
||||
rq.freed = 0;
|
||||
// Construct parameters
|
||||
var paramsFull = 'page=' + page + '¯o=' + macro;
|
||||
if (params) {
|
||||
for (var paramName in params)
|
||||
paramsFull = paramsFull + '&' + paramName + '=' + params[paramName];
|
||||
}
|
||||
// Call beforeSend if required
|
||||
if (beforeSend) {
|
||||
var res = beforeSend(rq, params);
|
||||
if (res) paramsFull = paramsFull + res;
|
||||
}
|
||||
// Construct the URL to call
|
||||
var urlFull = url + '/skyn/ajax';
|
||||
if (mode == 'GET') {
|
||||
urlFull = urlFull + '?' + paramsFull;
|
||||
}
|
||||
// Perform the asynchronous HTTP GET or POST
|
||||
rq.xhr.open(mode, urlFull, true);
|
||||
if (mode == 'POST') {
|
||||
// Set the correct HTTP headers
|
||||
rq.xhr.setRequestHeader(
|
||||
"Content-Type", "application/x-www-form-urlencoded");
|
||||
rq.xhr.setRequestHeader("Content-length", paramsFull.length);
|
||||
rq.xhr.setRequestHeader("Connection", "close");
|
||||
rq.xhr.onreadystatechange = function(){ getAjaxChunk(pos); }
|
||||
rq.xhr.send(paramsFull);
|
||||
}
|
||||
else if (mode == 'GET') {
|
||||
rq.xhr.onreadystatechange = function() { getAjaxChunk(pos); }
|
||||
if (window.XMLHttpRequest) { rq.xhr.send(null); }
|
||||
else if (window.ActiveXObject) { rq.xhr.send(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The functions below wrap askAjaxChunk for getting specific content through
|
||||
an Ajax request. */
|
||||
function askQueryResult(hookId, objectUrl, contentType, flavourNumber,
|
||||
searchName, startNumber, sortKey, sortOrder, filterKey) {
|
||||
// Sends an Ajax request for getting the result of a query.
|
||||
var params = {'type_name': contentType, 'flavourNumber': flavourNumber,
|
||||
'search': searchName, 'startNumber': startNumber};
|
||||
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'] = filterWidget.value;
|
||||
}
|
||||
}
|
||||
askAjaxChunk(hookId,'GET',objectUrl,'macros','queryResult',params);
|
||||
}
|
||||
|
||||
function askObjectHistory(hookId, objectUrl, startNumber) {
|
||||
// Sends an Ajax request for getting the history of an object
|
||||
var params = {'startNumber': startNumber};
|
||||
askAjaxChunk(hookId, 'GET', objectUrl, 'macros', 'history', params);
|
||||
}
|
||||
|
||||
function askRefField(hookId, objectUrl, fieldName, isBack, innerRef, labelId,
|
||||
descrId, startNumber, action, actionParams){
|
||||
// Sends an Ajax request for getting the content of a reference field.
|
||||
var startKey = hookId + '_startNumber';
|
||||
var params = {'fieldName': fieldName, 'isBack': isBack,
|
||||
'innerRef': innerRef, 'labelId': labelId,
|
||||
'descrId': descrId };
|
||||
params[startKey] = startNumber;
|
||||
if (action) params['action'] = action;
|
||||
if (actionParams) {
|
||||
for (key in actionParams) { params[key] = actionParams[key]; };
|
||||
}
|
||||
askAjaxChunk(hookId, 'GET', objectUrl, 'ref', 'showReferenceContent',
|
||||
params);
|
||||
}
|
||||
|
||||
// Function used by checkbox widgets for having radio-button-like behaviour
|
||||
function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
|
||||
vis = document.getElementById(visibleCheckbox);
|
||||
|
@ -633,10 +726,9 @@
|
|||
<td colspan="2">
|
||||
<span id="appyHistory"
|
||||
tal:attributes="style python:test(historyExpanded, 'display:block', 'display:none')">
|
||||
<div tal:define="ajaxHookId python: contextObj.UID() + '_history';
|
||||
ajaxUrl python: contextObj.getUrl('showHistory')"
|
||||
<div tal:define="ajaxHookId python: contextObj.UID() + '_history';"
|
||||
tal:attributes="id ajaxHookId">
|
||||
<script language="javascript" tal:content="python: 'askAjaxChunk(\'%s\',\'%s\')' % (ajaxHookId, ajaxUrl)">
|
||||
<script language="javascript" tal:content="python: 'askObjectHistory(\'%s\',\'%s\',0)' % (ajaxHookId, contextObj.absolute_url())">
|
||||
</script>
|
||||
</div>
|
||||
</span>
|
||||
|
@ -655,7 +747,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<metal:nav use-macro="here/skyn/macros/macros/objectNavigate"/>
|
||||
<metal:nav use-macro="here/skyn/navigate/macros/objectNavigate"/>
|
||||
|
||||
<tal:comment replace="nothing">Tabs</tal:comment>
|
||||
<ul class="contentViews appyTabs" tal:condition="python: len(appyPages)>1">
|
||||
|
@ -726,12 +818,16 @@
|
|||
searchLabel python: test(searchName=='_advanced', 'search_results', '%s_search_%s' % (contentType, searchName));
|
||||
searchDescr python: '%s_descr' % searchLabel;
|
||||
severalTypes python: contentType and (contentType.find(',') != -1);
|
||||
queryResult python: tool.executeQuery(contentType, flavourNumber, searchName, startNumber, remember=True);
|
||||
sortKey request/sortKey| python:'';
|
||||
sortOrder request/sortOrder| python:'asc';
|
||||
filterKey request/filterKey| python:'';
|
||||
filterValue request/filterValue | python:'';
|
||||
queryResult python: tool.executeQuery(contentType, flavourNumber, searchName, startNumber, remember=True, sortBy=sortKey, sortOrder=sortOrder, filterKey=filterKey, filterValue=filterValue);
|
||||
objs queryResult/objects;
|
||||
totalNumber queryResult/totalNumber;
|
||||
batchSize queryResult/batchSize;
|
||||
ajaxHookId python:'queryResult';
|
||||
baseUrl python: tool.getQueryUrl(contentType, flavourNumber, searchName, startNumber='**v**');
|
||||
navBaseCall python: 'askQueryResult(\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',**v**)' % (ajaxHookId, tool.absolute_url(), contentType, flavourNumber, searchName);
|
||||
newSearchUrl python: '%s/skyn/search?type_name=%s&flavourNumber=%d' % (tool.getAppFolder().absolute_url(), contentType, flavourNumber);">
|
||||
|
||||
<tal:result condition="objs">
|
||||
|
@ -753,7 +849,7 @@
|
|||
</td>
|
||||
<td align="right" width="25%">
|
||||
<tal:comment replace="nothing">Appy (top) navigation</tal:comment>
|
||||
<metal:nav use-macro="here/skyn/macros/macros/appyNavigate"/>
|
||||
<metal:nav use-macro="here/skyn/navigate/macros/appyNavigate"/>
|
||||
</td>
|
||||
</tr></table>
|
||||
|
||||
|
@ -763,26 +859,20 @@
|
|||
excepted for workflow state (which is not a field): in this case it is simply the
|
||||
string "workflowState".</tal:comment>
|
||||
|
||||
<tal:comment replace="nothing">Headers, with (disabled) filters and sort arrows</tal:comment>
|
||||
<tal:comment replace="nothing">Headers, with filters and sort arrows</tal:comment>
|
||||
<tr>
|
||||
<tal:comment replace="nothing">Mandatory column "Title"/"Name"</tal:comment>
|
||||
<th><!--img tal:attributes= "src string: $portal_url/arrowDown.gif;
|
||||
onClick python:'javascript:onSort(\'title\')';"
|
||||
id="arrow_title" style="cursor:pointer"/-->
|
||||
|
||||
<th tal:define="fieldName python:'title'; sortable python:True; filterable python:True">
|
||||
<span tal:content="python: tool.translate('ref_name')"/>
|
||||
<!--input id="filter_title" type="text" size="5" onkeyup="javascript:onTextEntered('title')"/-->
|
||||
<tal:comment replace="nothing">Input fields like this have been commented out because they will
|
||||
be replaced by Ajax server- searches that will be more relevant (the current Javascript search
|
||||
is limited to the batch, which has little interest).</tal:comment>
|
||||
<metal:sortAndFilter use-macro="here/skyn/navigate/macros/sortAndFilter"/>
|
||||
</th>
|
||||
|
||||
<tal:comment replace="nothing">Columns corresponding to other fields</tal:comment>
|
||||
<tal:columnHeader repeat="fieldDescr fieldDescrs">
|
||||
<th tal:define="fieldName fieldDescr/atField/getName|string:workflow_state">
|
||||
<!--img tal:attributes= "src string: $portal_url/arrowDown.gif;
|
||||
onClick python:'javascript:onSort(\'%s\')' % fieldName;
|
||||
id python: 'arrow_%s' % fieldName"
|
||||
style="cursor:pointer"/-->
|
||||
<th tal:define="fieldName fieldDescr/atField/getName|string:workflow_state;
|
||||
sortable fieldDescr/sortable|nothing;
|
||||
filterable fieldDescr/filterable|nothing;">
|
||||
<tal:comment replace="nothing">Display header for a "standard" field</tal:comment>
|
||||
<tal:standardField condition="python: fieldName != 'workflow_state'">
|
||||
<span tal:replace="python: tool.translate(fieldDescr['atField'].widget.label_msgid)"/>
|
||||
|
@ -791,20 +881,13 @@
|
|||
<tal:workflowState condition="python: fieldName == 'workflow_state'">
|
||||
<span tal:replace="python: tool.translate('workflow_state')"/>
|
||||
</tal:workflowState>
|
||||
<!--input type="text" size="5"
|
||||
tal:attributes="id python: 'filter_%s' % fieldName;
|
||||
onkeyup python:'javascript:onTextEntered(\'%s\')' % fieldName"/-->
|
||||
<metal:sortAndFilter use-macro="here/skyn/navigate/macros/sortAndFilter"/>
|
||||
</th>
|
||||
</tal:columnHeader>
|
||||
|
||||
<tal:comment replace="nothing">Column "Object type", shown if instances of several types are shown</tal:comment>
|
||||
<th tal:condition="severalTypes"><!--img
|
||||
tal:attributes= "src string: $portal_url/arrowDown.gif;
|
||||
onClick python:'javascript:onSort(\'root_type\')';"
|
||||
id = "arrow_root_type" style="cursor:pointer"/-->
|
||||
<th tal:condition="severalTypes">
|
||||
<span tal:replace="python: tool.translate('root_type')"/>
|
||||
<!--input type="text" size="5" id="filter_root_type"
|
||||
tal:attributes="onkeyup python:'javascript:onTextEntered(\'root_type\')'"/-->
|
||||
</th>
|
||||
|
||||
<tal:comment replace="nothing">Column "Actions"</tal:comment>
|
||||
|
@ -872,7 +955,7 @@
|
|||
</table>
|
||||
|
||||
<tal:comment replace="nothing">Appy (bottom) navigation</tal:comment>
|
||||
<metal:nav use-macro="here/skyn/macros/macros/appyNavigate"/>
|
||||
<metal:nav use-macro="here/skyn/navigate/macros/appyNavigate"/>
|
||||
</fieldset>
|
||||
</tal:result>
|
||||
|
||||
|
@ -952,91 +1035,3 @@
|
|||
</table>
|
||||
</form>
|
||||
</metal:transitions>
|
||||
|
||||
<div metal:define-macro="appyNavigate" tal:condition="python: totalNumber > batchSize" align="right">
|
||||
<tal:comment replace="nothing">
|
||||
Buttons for navigating among a list of elements (next, back, first, last, etc).
|
||||
</tal:comment>
|
||||
<table cellpadding="0" cellspacing="0" class="appyNav">
|
||||
<tr>
|
||||
<tal:comment replace="nothing">Go to the first page</tal:comment>
|
||||
<td><img style="cursor:pointer" tal:condition="python: (startNumber != 0) and (startNumber != batchSize)"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowLeftDouble.png;
|
||||
title python: tool.translate('goto_first');
|
||||
onClick python: 'askAjaxChunk(\'%s\', \'%s\')' % (ajaxHookId, baseUrl.replace('**v**', '0'))"/></td>
|
||||
<tal:comment replace="nothing">Go to the previous page</tal:comment>
|
||||
<td><img style="cursor:pointer" tal:condition="python: startNumber != 0"
|
||||
tal:define="sNumber python: startNumber - batchSize"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowLeftSimple.png;
|
||||
title python: tool.translate('goto_previous');
|
||||
onClick python: 'askAjaxChunk(\'%s\', \'%s\')' % (ajaxHookId, baseUrl.replace('**v**', str(sNumber)))"/></td>
|
||||
<tal:comment replace="nothing">Explain which elements are currently shown</tal:comment>
|
||||
<td class="discreet" valign="middle">
|
||||
<span tal:replace="python: startNumber+1"/>
|
||||
<img tal:attributes="src string: $portal_url/skyn/to.png"/>
|
||||
<span tal:replace="python: startNumber+len(objs)"/> <b>//</b>
|
||||
<span tal:replace="python: totalNumber"/>
|
||||
</td>
|
||||
<tal:comment replace="nothing">Go to the next page</tal:comment>
|
||||
<td><img style="cursor:pointer" tal:condition="python: sNumber < totalNumber"
|
||||
tal:define="sNumber python: startNumber + batchSize"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowRightSimple.png;
|
||||
title python: tool.translate('goto_next');
|
||||
onClick python: 'askAjaxChunk(\'%s\', \'%s\')' % (ajaxHookId, baseUrl.replace('**v**', str(sNumber)))"/></td>
|
||||
<tal:comment replace="nothing">Go to the last page</tal:comment>
|
||||
<td><img style="cursor:pointer" tal:condition="python: (startNumber != sNumber) and (startNumber != sNumber-batchSize)"
|
||||
tal:define="lastPageIsIncomplete python: totalNumber % batchSize;
|
||||
nbOfCompletePages python: totalNumber/batchSize;
|
||||
nbOfCountedPages python: test(lastPageIsIncomplete, nbOfCompletePages, nbOfCompletePages-1);
|
||||
sNumber python: (nbOfCountedPages*batchSize)"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowRightDouble.png;
|
||||
title python: tool.translate('goto_last');
|
||||
onClick python: 'askAjaxChunk(\'%s\', \'%s\')' % (ajaxHookId, baseUrl.replace('**v**', str(sNumber)))"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div metal:define-macro="objectNavigate" tal:condition="request/nav|nothing" align="right">
|
||||
<tal:comment replace="nothing">
|
||||
Buttons for going to next/previous elements if this one is among bunch of referenced or searched objects.
|
||||
currentNumber starts with 1.
|
||||
</tal:comment>
|
||||
<table cellpadding="0" cellspacing="0"
|
||||
tal:define="navInfo tool/getNavigationInfo;
|
||||
currentNumber navInfo/currentNumber;
|
||||
totalNumber navInfo/totalNumber;
|
||||
firstUrl navInfo/firstUrl;
|
||||
previousUrl navInfo/previousUrl;
|
||||
nextUrl navInfo/nextUrl;
|
||||
lastUrl navInfo/lastUrl;
|
||||
sourceUrl navInfo/sourceUrl;
|
||||
backText navInfo/backText">
|
||||
<tr>
|
||||
<tal:comment replace="nothing">Go to the source URL (search or referred object)</tal:comment>
|
||||
<td><a tal:condition="sourceUrl" tal:attributes="href sourceUrl"><img style="cursor:pointer"
|
||||
tal:attributes="src string: $portal_url/skyn/gotoSource.png;
|
||||
title python: backText + ' : ' + tool.translate('goto_source')"/></a></td>
|
||||
<tal:comment replace="nothing">Go to the first page</tal:comment>
|
||||
<td><a tal:condition="firstUrl" tal:attributes="href firstUrl"><img style="cursor:pointer"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowLeftDouble.png;
|
||||
title python: tool.translate('goto_first')"/></a></td>
|
||||
<tal:comment replace="nothing">Go to the previous page</tal:comment>
|
||||
<td><a tal:condition="previousUrl" tal:attributes="href previousUrl"><img style="cursor:pointer"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowLeftSimple.png;
|
||||
title python: tool.translate('goto_previous')"/></a></td>
|
||||
<tal:comment replace="nothing">Explain which element is currently shown</tal:comment>
|
||||
<td class="discreet" valign="middle">
|
||||
<span tal:replace="python: currentNumber"/> <b>//</b>
|
||||
<span tal:replace="python: totalNumber"/>
|
||||
</td>
|
||||
<tal:comment replace="nothing">Go to the next page</tal:comment>
|
||||
<td><a tal:condition="python: nextUrl" tal:attributes="href nextUrl"><img style="cursor:pointer"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowRightSimple.png;
|
||||
title python: tool.translate('goto_next')"/></a></td>
|
||||
<tal:comment replace="nothing">Go to the last page</tal:comment>
|
||||
<td><a tal:condition="lastUrl" tal:attributes="href lastUrl"><img style="cursor:pointer"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowRightDouble.png;
|
||||
title python: tool.translate('goto_last')"/></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -21,132 +21,12 @@
|
|||
searchName python:context.REQUEST.get('search', '')">
|
||||
|
||||
<div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
|
||||
<script language="javascript">
|
||||
<!--
|
||||
function getSortValue(row, fieldName) {
|
||||
// Find, from p_fieldName, the cell that is used for sorting.
|
||||
var cellId = "field_" + fieldName;
|
||||
var cells = row.cells;
|
||||
for (var i=0; i < cells.length; i++) {
|
||||
if (cells[i].id == cellId) {
|
||||
// Ok we have the cell on which we must sort.
|
||||
// Now get the cell content.
|
||||
// If the cell contains links, content is the 1st link content
|
||||
var innerLinks = cells[i].getElementsByTagName("a");
|
||||
if (innerLinks.length > 0) {
|
||||
return innerLinks[0].innerHTML;
|
||||
} else {
|
||||
return cells[i].innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sortRows(fieldName, ascending) {
|
||||
var queryRows = cssQuery('#query_row');
|
||||
// Create a wrapper for sorting
|
||||
var RowWrapper = function(row, fieldName) {
|
||||
this.value = getSortValue(row, fieldName);
|
||||
this.cloned_node = row.cloneNode(true);
|
||||
this.toString = function() {
|
||||
if (this.value.toString) {
|
||||
return this.value.toString();
|
||||
} else {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Wrap nodes
|
||||
var items = new Array();
|
||||
for (var i=0; i<queryRows.length; i++) {
|
||||
items.push(new RowWrapper(queryRows[i], fieldName));
|
||||
}
|
||||
// Sort nodes
|
||||
items.sort();
|
||||
if (!ascending) {
|
||||
items.reverse();
|
||||
}
|
||||
// Reorder nodes
|
||||
for (var i=0; i<items.length; i++) {
|
||||
var dest = queryRows[i];
|
||||
dest.parentNode.replaceChild(items[i].cloned_node, dest);
|
||||
}
|
||||
};
|
||||
|
||||
function onSort(fieldName){
|
||||
// First, switch the sort arrow (up->down or down->up)
|
||||
var arrow = document.getElementById("arrow_" + fieldName);
|
||||
var sortAscending = (arrow.src.indexOf('arrowDown.gif') != -1);
|
||||
if (sortAscending){
|
||||
// Display "up" image
|
||||
arrow.src = arrow.src.replace('arrowDown.gif', 'arrowUp.gif')
|
||||
}
|
||||
else { // Display "down" image
|
||||
arrow.src = arrow.src.replace('arrowUp.gif', 'arrowDown.gif')
|
||||
}
|
||||
// Then, sort the rows on column "fieldName".
|
||||
sortRows(fieldName, sortAscending);
|
||||
}
|
||||
|
||||
function cellMatches(cell, searchValue) {
|
||||
// This function returns true if the HTML p_cell contains p_searchValue
|
||||
var innerLinks = cell.getElementsByTagName("a");
|
||||
// If the cell contains links, we search within the link contents
|
||||
for (var i=0; i < innerLinks.length; i++){
|
||||
var linkContent = innerLinks[i].innerHTML.toLowerCase();
|
||||
if (linkContent.indexOf(searchValue) != -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// If we are here, we still have no match. Let's search directly within
|
||||
// the cell.
|
||||
var cellContent = cell.innerHTML.toLowerCase();
|
||||
if (cellContent.indexOf(searchValue) != -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function onTextEntered(fieldName) {
|
||||
// Is called whenever text is entered into field named p_fieldName.
|
||||
var cellId = "field_" + fieldName
|
||||
var field = document.getElementById("filter_" + fieldName);
|
||||
var fieldValue = field.value.toLowerCase();
|
||||
if (fieldValue.length >= 3) {
|
||||
// Browse all rows and check if it should be visible or not.
|
||||
var queryRows = cssQuery('#query_row');
|
||||
for (var i=0; i < queryRows.length; i++) {
|
||||
// Find the value of the cell.
|
||||
var queryCells = queryRows[i].cells;
|
||||
for (var j=0; j < queryCells.length; j++) {
|
||||
if (queryCells[j].id == cellId) {
|
||||
if (cellMatches(queryCells[j], fieldValue)) {
|
||||
queryRows[i].style.display = "";
|
||||
}
|
||||
else {
|
||||
queryRows[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Show all rows
|
||||
var queryRows = cssQuery('#query_row');
|
||||
for (var i=0; i < queryRows.length; i++) {
|
||||
queryRows[i].style.display = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
-->
|
||||
</script>
|
||||
|
||||
<tal:comment replace="nothing">Query result</tal:comment>
|
||||
<div id="queryResult"></div>
|
||||
|
||||
<script language="javascript"
|
||||
tal:define="ajaxUrl python: tool.getQueryUrl(contentType, flavourNumber, searchName)"
|
||||
tal:content="python: 'askAjaxChunk(\'queryResult\',\'%s\')' % ajaxUrl">
|
||||
tal:content="python: 'askQueryResult(\'queryResult\', \'%s\',\'%s\',\'%s\',\'%s\',0)' % (tool.absolute_url(), contentType, flavourNumber, searchName)">
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -20,19 +20,19 @@
|
|||
<tr>
|
||||
<tal:comment replace="nothing">Arrows for moving objects up or down</tal:comment>
|
||||
<td class="noPadding" tal:condition="python: (len(objs)>1) and member.has_permission('Modify portal content', contextObj)">
|
||||
<tal:moveRef define="objectIndex python:contextObj.getAppyRefIndex(fieldName, obj);
|
||||
baseUrl python: contextObj.getUrl('showRef', **{'fieldName': fieldName, 'isBack': isBack, 'innerRef': innerRef, 'labelId': labelId, 'descrId': descrId, '%s_startNumber' % ajaxHookId: startNumber, 'action':'ChangeRefOrder', 'refObjectUid': obj.UID()})">
|
||||
<tal:moveRef define="objectIndex python: contextObj.getAppyRefIndex(fieldName, obj);
|
||||
ajaxBaseCall python: navBaseCall.replace('**v**', '\'%s\',\'ChangeRefOrder\', {\'refObjectUid\':\'%s\', \'move\':\'**v**\'}' % (startNumber, obj.UID()))">
|
||||
<tal:comment replace="nothing">Move up</tal:comment>
|
||||
<img tal:define="ajaxUrl python: baseUrl + '&move=up'" tal:condition="python: objectIndex > 0"
|
||||
<img tal:condition="python: objectIndex > 0"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowUp.png;
|
||||
title python: tool.translate('move_up');
|
||||
onClick python: 'askAjaxChunk(\'%s\', \'%s\')' % (ajaxHookId, ajaxUrl)"
|
||||
onClick python: ajaxBaseCall.replace('**v**', 'up')"
|
||||
style="cursor:pointer"/>
|
||||
<tal:comment replace="nothing">Move down</tal:comment>
|
||||
<img tal:define="ajaxUrl python: baseUrl + '&move=down'" tal:condition="python: objectIndex < (totalNumber-1)"
|
||||
<img tal:condition="python: objectIndex < (totalNumber-1)"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowDown.png;
|
||||
title python: tool.translate('move_down');
|
||||
onClick python: 'askAjaxChunk(\'%s\', \'%s\')' % (ajaxHookId, ajaxUrl)"
|
||||
onClick python: ajaxBaseCall.replace('**v**', 'down')"
|
||||
style="cursor:pointer"/>
|
||||
</tal:moveRef>
|
||||
</td>
|
||||
|
@ -63,6 +63,22 @@
|
|||
onClick python: 'href: window.location=\'%s/skyn/do?action=Create&initiator=%s&field=%s&type_name=%s\'' % (folder.absolute_url(), contextObj.UID(), fieldName, linkedPortalType)"/>
|
||||
</metal:plusIcon>
|
||||
|
||||
<tal:comment replace="nothing">
|
||||
This macro displays, in a cell header from a ref table, icons for sorting the
|
||||
ref field according to the field that corresponds to this column.
|
||||
</tal:comment>
|
||||
<metal:sortIcons define-macro="sortIcons"
|
||||
tal:define="ajaxBaseCall python: navBaseCall.replace('**v**', '\'%s\',\'SortReference\', {\'sortKey\':\'%s\', \'reverse\':\'**v**\'}' % (startNumber, shownField))">
|
||||
<img style="cursor:pointer"
|
||||
tal:attributes="src string:$portal_url/skyn/sortAsc.png;
|
||||
title python: tool.translate('sort_asc');
|
||||
onClick python: ajaxBaseCall.replace('**v**', 'False')"/>
|
||||
<img style="cursor:pointer"
|
||||
tal:attributes="src string:$portal_url/skyn/sortDesc.png;
|
||||
title python: tool.translate('sort_desc');
|
||||
onClick python: ajaxBaseCall.replace('**v**', 'True')"/>
|
||||
</metal:sortIcons>
|
||||
|
||||
<tal:comment replace="nothing">
|
||||
This macro shows a reference field. More precisely, it shows nothing, but calls
|
||||
a Javascript function that will asynchonously call (via a XmlHttpRequest object) the
|
||||
|
@ -77,11 +93,10 @@
|
|||
- descrId (string) the i18n id of the reference field description
|
||||
</tal:comment>
|
||||
<div metal:define-macro="showReference"
|
||||
tal:define="ajaxHookId python: contextObj.UID() + fieldName;
|
||||
ajaxUrl python: contextObj.getUrl('showRef', **{'fieldName': fieldName, 'isBack': isBack, 'innerRef': innerRef, 'labelId': labelId, 'descrId': descrId})"
|
||||
tal:define="ajaxHookId python: contextObj.UID() + fieldName"
|
||||
tal:attributes="id ajaxHookId">
|
||||
<script language="javascript"
|
||||
tal:content="python: 'askAjaxChunk(\'%s\',\'%s\')' % (ajaxHookId, ajaxUrl)">
|
||||
tal:content="python: 'askRefField(\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',0)' % (ajaxHookId, contextObj.absolute_url(), fieldName, isBack, innerRef, labelId, descrId)">
|
||||
</script>
|
||||
</div>
|
||||
|
||||
|
@ -113,7 +128,7 @@
|
|||
atMostOneRef python: (multiplicity[1] == 1) and (len(objs)<=1);
|
||||
label python: tool.translate(labelId);
|
||||
description python: tool.translate(descrId);
|
||||
baseUrl python: contextObj.getUrl('showRef', **{'fieldName': fieldName, 'isBack': isBack, 'innerRef': innerRef, 'labelId': labelId, 'descrId': descrId, '%s_startNumber' % ajaxHookId: '**v**'})">
|
||||
navBaseCall python: 'askRefField(\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',**v**)' % (ajaxHookId, contextObj.absolute_url(), fieldName, isBack, innerRef, labelId, descrId)">
|
||||
|
||||
<tal:comment replace="nothing">This macro displays the Reference widget on a "consult" page.
|
||||
|
||||
|
@ -159,7 +174,7 @@
|
|||
tal:content="description" class="discreet" ></p>
|
||||
|
||||
<tal:comment replace="nothing">Appy (top) navigation</tal:comment>
|
||||
<metal:nav use-macro="here/skyn/macros/macros/appyNavigate"/>
|
||||
<metal:nav use-macro="here/skyn/navigate/macros/appyNavigate"/>
|
||||
|
||||
<tal:comment replace="nothing">No object is present</tal:comment>
|
||||
<p tal:condition="not:objs" tal:content="python: tool.translate('no_ref')"></p>
|
||||
|
@ -183,14 +198,21 @@
|
|||
align="right" tal:condition="python: not isBack and objs" cellpadding="0" cellspacing="0">
|
||||
<tr tal:condition="appyType/showHeaders">
|
||||
<th tal:condition="python: 'title' not in appyType['shownInfo']"
|
||||
tal:content="python: tool.translate('ref_name')"></th>
|
||||
tal:define="shownField python:'title'">
|
||||
<span tal:content="python: tool.translate('ref_name')"></span>
|
||||
<metal:sortIcons use-macro="here/skyn/ref/macros/sortIcons" />
|
||||
</th>
|
||||
<th tal:repeat="shownField appyType/shownInfo">
|
||||
<tal:showHeader condition="python: objs[0].getField(shownField)">
|
||||
<tal:titleHeader condition="python: shownField == 'title'"
|
||||
content="python: tool.translate('ref_name')"/>
|
||||
<tal:titleHeader condition="python: shownField == 'title'">
|
||||
<span tal:content="python: tool.translate('ref_name')"></span>
|
||||
<metal:sortIcons use-macro="here/skyn/ref/macros/sortIcons" />
|
||||
</tal:titleHeader>
|
||||
<tal:otherHeader condition="python: shownField != 'title'"
|
||||
define="labelId python: objs[0].getField(shownField).widget.label_msgid"
|
||||
content="python: tool.translate(labelId)"/>
|
||||
define="labelId python: objs[0].getField(shownField).widget.label_msgid">
|
||||
<span tal:content="python: tool.translate(labelId)"></span>
|
||||
<metal:sortIcons use-macro="here/skyn/ref/macros/sortIcons" />
|
||||
</tal:otherHeader>
|
||||
</tal:showHeader>
|
||||
</th>
|
||||
<th tal:content="python: tool.translate('ref_actions')"></th>
|
||||
|
@ -242,7 +264,7 @@
|
|||
</table>
|
||||
|
||||
<tal:comment replace="nothing">Appy (bottom) navigation</tal:comment>
|
||||
<metal:nav use-macro="here/skyn/macros/macros/appyNavigate"/>
|
||||
<metal:nav use-macro="here/skyn/navigate/macros/appyNavigate"/>
|
||||
|
||||
</fieldset>
|
||||
<tal:comment replace="nothing">A carriage return needed in some cases.</tal:comment>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue