Added an AJAX framework within appy.gen, and its first use: a pagination mechanism for producing paginated references in the reference widget.
This commit is contained in:
parent
4c4b2d0f87
commit
605c42d94e
20 changed files with 546 additions and 187 deletions
25
gen/plone25/skin/ajax.pt
Normal file
25
gen/plone25/skin/ajax.pt
Normal file
|
@ -0,0 +1,25 @@
|
|||
<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();
|
||||
action request/action|nothing;
|
||||
response request/RESPONSE;
|
||||
member context/portal_membership/getAuthenticatedMember;
|
||||
portal context/portal_url/getPortalObject;
|
||||
portal_url context/portal_url/getPortalPath;
|
||||
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:executeAction condition="action">
|
||||
<tal:do define="dummy python: contextObj.getAppyAttribute('on'+action)()" omit-tag=""/>
|
||||
</tal:executeAction>
|
||||
<metal:callMacro use-macro="python: context.get(page).macros.get(macro)"/>
|
||||
</tal:ajax>
|
BIN
gen/plone25/skin/arrowLeftDouble.png
Normal file
BIN
gen/plone25/skin/arrowLeftDouble.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 212 B |
BIN
gen/plone25/skin/arrowLeftSimple.png
Normal file
BIN
gen/plone25/skin/arrowLeftSimple.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 218 B |
BIN
gen/plone25/skin/arrowRightDouble.png
Normal file
BIN
gen/plone25/skin/arrowRightDouble.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 212 B |
BIN
gen/plone25/skin/arrowRightSimple.png
Normal file
BIN
gen/plone25/skin/arrowRightSimple.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 216 B |
|
@ -74,7 +74,7 @@
|
|||
<form name="edit_form" method="post" enctype="multipart/form-data"
|
||||
class="enableUnloadProtection atBaseEditForm"
|
||||
tal:attributes="action python: contextObj.absolute_url()+'/skyn/do'">
|
||||
<div metal:use-macro="here/skyn/macros/macros/listFields" />
|
||||
<div metal:use-macro="here/skyn/macros/macros/listFields" /><br/>
|
||||
<input type="hidden" name="action" value="Update"/>
|
||||
<input type="hidden" name="fieldset" tal:attributes="value fieldset"/>
|
||||
<input type="hidden" name="pageName" tal:attributes="value pageName"/>
|
||||
|
|
|
@ -107,7 +107,10 @@
|
|||
<input type="hidden" name="action" value="ExecuteAppyAction"/>
|
||||
<input type="hidden" name="objectUid" tal:attributes="value contextObj/UID"/>
|
||||
<input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
|
||||
<input type="submit" name="do" tal:attributes="value label"/>
|
||||
<input type="submit" name="do" tal:attributes="value label" onClick="javascript:;"/>
|
||||
<tal:comment replace="nothing">The previous onClick is simply used to prevent Plone
|
||||
from adding a CSS class that displays a popup when the user triggers the form multiple
|
||||
times.</tal:comment>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
@ -115,7 +118,8 @@
|
|||
tal:define="field fieldDescr/atField|widgetDescr/atField;
|
||||
appyType fieldDescr/appyType|widgetDescr/appyType;
|
||||
showLabel showLabel|python:True;
|
||||
label python: tool.translate(field.widget.label_msgid);
|
||||
labelId field/widget/label_msgid;
|
||||
label python: tool.translate(labelId);
|
||||
descrId field/widget/description_msgid|python:'';
|
||||
description python: tool.translate(descrId)"
|
||||
tal:attributes="class python: contextObj.getCssClasses(appyType, asSlave=True)">
|
||||
|
@ -157,8 +161,7 @@
|
|||
<tal:comment replace="nothing">For other fields like Refs we use specific view/edit macros.</tal:comment>
|
||||
<tal:viewRef condition="python: (not isEdit) and (appyType['type'] == 'Ref')">
|
||||
<tal:ref define="isBack python:False;
|
||||
fieldRel python:field.relationship;
|
||||
objs python:contextObj.getAppyRefs(field.getName());
|
||||
fieldName field/getName;
|
||||
innerRef innerRef|python:False">
|
||||
<metal:viewRef use-macro="here/skyn/ref/macros/showReference" />
|
||||
</tal:ref>
|
||||
|
@ -186,10 +189,9 @@
|
|||
<div metal:define-macro="showBackwardField"
|
||||
tal:define="isBack python:True;
|
||||
appyType widgetDescr/appyType;
|
||||
fieldRel widgetDescr/fieldRel;
|
||||
objs python:contextObj.getBRefs(fieldRel);
|
||||
label python:contextObj.translate('%s_%s_back' % (contextObj.meta_type, appyType['backd']['attribute']));
|
||||
description python:'';
|
||||
fieldName widgetDescr/fieldRel;
|
||||
labelId python: '%s_%s_back' % (contextObj.meta_type, appyType['backd']['attribute']);
|
||||
descrId python: '';
|
||||
innerRef innerRef|python:False">
|
||||
<div metal:use-macro="here/skyn/ref/macros/showReference" />
|
||||
</div>
|
||||
|
@ -309,6 +311,63 @@
|
|||
<tal:comment replace="nothing">"Static" javascripts</tal:comment>
|
||||
<script language="javascript">
|
||||
<!--
|
||||
// AJAX machinery
|
||||
var xhrObjects = new Array(); // An array of XMLHttpRequest objects
|
||||
function XhrObject() { // Wraps a XmlHttpRequest object
|
||||
this.freed = 1; // Is this xhr object already dealing with a request or not?
|
||||
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.
|
||||
}
|
||||
|
||||
function getAjaxChunk(pos) {
|
||||
// This function is the callback called by the AJAX machinery (see function
|
||||
// askAjaxChunk below) when an Ajax response is available.
|
||||
// First, find back the correct XMLHttpRequest object
|
||||
if ( (typeof(xhrObjects[pos]) != 'undefined') &&
|
||||
(xhrObjects[pos].freed == 0)) {
|
||||
var hook = xhrObjects[pos].hook;
|
||||
if (xhrObjects[pos].xhr.readyState == 1) {
|
||||
// The request has been initialized: display the waiting radar
|
||||
var hookElem = document.getElementById(hook);
|
||||
if (hookElem) hookElem.innerHTML = "<div align=\"center\"><img src=\"skyn/waiting.gif\"/><\/div>";
|
||||
}
|
||||
if (xhrObjects[pos].xhr.readyState == 4) {
|
||||
// We have received the HTML chunk
|
||||
var hookElem = document.getElementById(hook);
|
||||
if (hookElem && (xhrObjects[pos].xhr.status == 200)) {
|
||||
hookElem.innerHTML = xhrObjects[pos].xhr.responseText;
|
||||
}
|
||||
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.
|
||||
// First, get a non-busy XMLHttpRequest object.
|
||||
var pos = -1;
|
||||
for (var i=0; i < xhrObjects.length; i++) {
|
||||
if (xhrObjects[i].freed == 1) { pos = i; break; }
|
||||
}
|
||||
if (pos == -1) {
|
||||
pos = xhrObjects.length;
|
||||
xhrObjects[pos] = new XhrObject();
|
||||
}
|
||||
xhrObjects[pos].hook = hook;
|
||||
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(); }
|
||||
}
|
||||
}
|
||||
|
||||
// Function used by checkbox widgets for having radio-button-like behaviour
|
||||
function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
|
||||
vis = document.getElementById(visibleCheckbox);
|
||||
|
@ -805,3 +864,47 @@
|
|||
<metal:phases use-macro="here/skyn/macros/macros/phases"/>
|
||||
</dt>
|
||||
</metal:portletContent>
|
||||
|
||||
<tal:comment replace="nothing">
|
||||
Buttons for navigating among a list of elements (next, back, first, last, etc).
|
||||
</tal:comment>
|
||||
<metal:appyNavigate define-macro="appyNavigate" tal:condition="python: totalNumber > batchSize">
|
||||
<table cellpadding="0" cellspacing="0" align="right" class="appyNav"
|
||||
tal:define="baseUrl python: contextObj.getUrl('showRef', **{'fieldName': fieldName, 'isBack': isBack, 'innerRef': innerRef, 'labelId': labelId, 'descrId': descrId}) + '&%s_startNumber=' % ajaxHookId">
|
||||
<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+'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+str(sNumber))"/></td>
|
||||
<tal:comment replace="nothing">Explain which elements are currently shown</tal:comment>
|
||||
<td class="discreet">
|
||||
<span tal:replace="python: startNumber+1"/>
|
||||
<img tal:attributes="src string: $portal_url/skyn/to.png"/>
|
||||
<span tal:replace="python: startNumber+len(objs)"/>
|
||||
</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+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+str(sNumber))"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</metal:appyNavigate>
|
||||
|
|
|
@ -21,31 +21,28 @@
|
|||
<img src="edit.gif" title="label_edit" i18n:domain="plone" i18n:attributes="title" />
|
||||
</a></td>
|
||||
<tal:comment replace="nothing">Delete the element</tal:comment>
|
||||
<td class="noPadding"><a tal:attributes="href python: obj.absolute_url() + '/delete_confirmation'"
|
||||
tal:condition="python: member.has_permission('Delete objects', obj)">
|
||||
<img src="delete_icon.gif" title="label_remove" i18n:domain="plone" i18n:attributes="title" />
|
||||
</a></td>
|
||||
<td class="noPadding">
|
||||
<img tal:condition="python: member.has_permission('Delete objects', obj)"
|
||||
src="delete_icon.gif" title="Delete" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
|
||||
tal:attributes="onClick python:'javascript:onDeleteObject(\'%s\')' % obj.UID()"/>
|
||||
</td>
|
||||
<tal:comment replace="nothing">Arrows for moving objects up or down</tal:comment>
|
||||
<td class="noPadding" tal:condition="python: len(objs)>1">
|
||||
<form tal:condition="python: member.has_permission('Modify portal content', obj)"
|
||||
tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'"
|
||||
tal:define="objectIndex python:contextObj.getAppyRefIndex(field.getName(), obj)">
|
||||
<input type="hidden" name="action" value="ChangeRefOrder"/>
|
||||
<input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
|
||||
<input type="hidden" name="refObjectUid" tal:attributes="value obj/UID"/>
|
||||
<tal:comment replace="nothing">Arrow up</tal:comment>
|
||||
<span tal:condition="python: objectIndex > 0">
|
||||
<input type="image" name="moveUp" class="imageInput"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowUp.png;
|
||||
title python: tool.translate('move_up')"/>
|
||||
</span>
|
||||
<tal:comment replace="nothing">Arrow down</tal:comment>
|
||||
<span tal:condition="python: objectIndex < (len(objs)-1)">
|
||||
<input type="image" name="moveDown" class="imageInput"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowDown.png;
|
||||
title python: tool.translate('move_down')"/>
|
||||
</span>
|
||||
</form>
|
||||
<td class="noPadding" tal:condition="python: (len(objs)>1) and member.has_permission('Modify portal content', obj)">
|
||||
<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:comment replace="nothing">Move up</tal:comment>
|
||||
<img tal:define="ajaxUrl python: baseUrl + '&move=up'" 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)"
|
||||
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)"
|
||||
tal:attributes="src string: $portal_url/skyn/arrowDown.png;
|
||||
title python: tool.translate('move_down');
|
||||
onClick python: 'askAjaxChunk(\'%s\', \'%s\')' % (ajaxHookId, ajaxUrl)"
|
||||
style="cursor:pointer"/>
|
||||
</tal:moveRef>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -58,18 +55,59 @@
|
|||
<img style="cursor:pointer" tal:condition="showPlusIcon"
|
||||
tal:attributes="src string:$portal_url/skyn/plus.png;
|
||||
title python: tool.translate('add_ref');
|
||||
onClick python: 'href: window.location=\'%s/skyn/do?action=Create&initiator=%s&field=%s&type_name=%s\'' % (folder.absolute_url(), contextObj.UID(), field.getName(), linkedPortalType)"/>
|
||||
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 shows a reference field. More precisely, it shows nothing, but calls
|
||||
a Javascript function that will asynchonously call (via a XmlHttpRequest object) the
|
||||
macro 'showReferenceContent' defined below, that will really show content.
|
||||
It requires:
|
||||
- isBack (bool) Is the reference a backward or forward reference?
|
||||
- fieldName (string) The name of the reference field (if it is a forward reference)
|
||||
or the name of the Archetypes relationship (if it is a backward reference)
|
||||
- innerRef (bool) Are we rendering a reference within a reference or not?
|
||||
- contextObj (object) the object from which the reference starts
|
||||
- labelId (string) the i18n id of the reference field label
|
||||
- descrId (string) the i18n id of the reference field description
|
||||
</tal:comment>
|
||||
<div metal:define-macro="showReference"
|
||||
tal:define="folder python: test(contextObj.isPrincipiaFolderish, contextObj, contextObj.getParentNode());
|
||||
tal:define="ajaxHookId python: contextObj.UID()+fieldName;
|
||||
ajaxUrl python: contextObj.getUrl('showRef', **{'fieldName': fieldName, 'isBack': isBack, 'innerRef': innerRef, 'labelId': labelId, 'descrId': descrId})"
|
||||
tal:attributes="id ajaxHookId">
|
||||
<script language="javascript"
|
||||
tal:content="python: 'askAjaxChunk(\'%s\',\'%s\')' % (ajaxHookId, ajaxUrl)">
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<tal:comment replace="nothing">
|
||||
This macro is called by a XmlHttpRequest for displaying the paginated referred objects
|
||||
of a reference field.
|
||||
</tal:comment>
|
||||
<div metal:define-macro="showReferenceContent"
|
||||
tal:define="fieldName request/fieldName;
|
||||
isBack python: test(request['isBack']=='True', True, False);
|
||||
innerRef python: test(request['innerRef']=='True', True, False);
|
||||
labelId request/labelId;
|
||||
descrId request/descrId;
|
||||
ajaxHookId python: contextObj.UID()+fieldName;
|
||||
startNumber python: int(request.get('%s_startNumber' % ajaxHookId, 0));
|
||||
appyType python: contextObj.getAppyType(fieldName, not isBack);
|
||||
tool contextObj/getTool;
|
||||
refObjects python:contextObj.getAppyRefs(fieldName, not isBack, startNumber);
|
||||
objs refObjects/objects;
|
||||
totalNumber refObjects/totalNumber;
|
||||
batchSize refObjects/batchSize;
|
||||
folder python: test(contextObj.isPrincipiaFolderish, contextObj, contextObj.getParentNode());
|
||||
flavour python:tool.getFlavour(contextObj);
|
||||
linkedPortalType python:flavour.getPortalType(appyType['klass']);
|
||||
addPermission python: '%s: Add %s' % (appName, linkedPortalType);
|
||||
addPermission python: '%s: Add %s' % (tool.getAppName(), linkedPortalType);
|
||||
multiplicity python:test(isBack, appyType['backd']['multiplicity'], appyType['multiplicity']);
|
||||
maxReached python:(multiplicity[1] != None) and (len(objs) >= multiplicity[1]);
|
||||
showPlusIcon python:not isBack and appyType['add'] and not maxReached and member.has_permission(addPermission, folder);
|
||||
atMostOneRef python: (multiplicity[1] == 1) and (len(objs)<=1)">
|
||||
atMostOneRef python: (multiplicity[1] == 1) and (len(objs)<=1);
|
||||
label python: tool.translate(labelId);
|
||||
description python: tool.translate(descrId)">
|
||||
|
||||
<tal:comment replace="nothing">This macro displays the Reference widget on a "consult" page.
|
||||
|
||||
|
@ -106,6 +144,7 @@
|
|||
<fieldset tal:attributes="class python:test(innerRef, 'innerAppyFieldset', '')">
|
||||
<legend tal:condition="python: not innerRef or showPlusIcon">
|
||||
<span tal:condition="not: innerRef" tal:content="label"/>
|
||||
<tal:numberOfRefs>(<span tal:replace="totalNumber"/>)</tal:numberOfRefs>
|
||||
<metal:plusIcon use-macro="here/skyn/ref/macros/plusIcon"/>
|
||||
</legend>
|
||||
|
||||
|
@ -113,6 +152,9 @@
|
|||
<p tal:condition="python: not innerRef and description"
|
||||
tal:content="description" class="discreet" ></p>
|
||||
|
||||
<tal:comment replace="nothing">Appy (top) navigation</tal:comment>
|
||||
<metal:nav use-macro="here/skyn/macros/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>
|
||||
|
||||
|
@ -167,9 +209,8 @@
|
|||
</tal:showNormalField>
|
||||
<tal:showRef condition="python: appyType['type'] == 'Ref'">
|
||||
<tal:ref tal:define="isBack python:appyType['isBack'];
|
||||
fieldRel python:field.relationship;
|
||||
objs python:contextObj.getAppyRefs(field.getName());
|
||||
innerRef python:True">
|
||||
fieldName python: test(isBack, field.relationship, field.getName());
|
||||
innerRef python:True">
|
||||
<metal:showField use-macro="here/skyn/ref/macros/showReference" />
|
||||
</tal:ref>
|
||||
</tal:showRef>
|
||||
|
@ -190,6 +231,10 @@
|
|||
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<tal:comment replace="nothing">Appy (bottom) navigation</tal:comment>
|
||||
<metal:nav use-macro="here/skyn/macros/macros/appyNavigate"/>
|
||||
|
||||
</fieldset>
|
||||
<tal:comment replace="nothing">A carriage return needed in some cases.</tal:comment>
|
||||
<br tal:define="widgetDescr widgetDescr|nothing"
|
||||
|
@ -202,7 +247,7 @@
|
|||
appyType python:here.getAppyType(field.getName());
|
||||
allBrains python:here.uid_catalog(portal_type=refPortalType);
|
||||
brains python:here.callAppySelect(appyType['select'], allBrains);
|
||||
refUids python: [o.UID() for o in here.getAppyRefs(field.getName())];
|
||||
refUids python: [o.UID() for o in here.getAppyRefs(field.getName())['objects']];
|
||||
isMultiple python:test(appyType['multiplicity'][1]!=1, 'multiple', '');
|
||||
appyFieldName python: 'appy_ref_%s' % field.getName();
|
||||
inError python:test(errors.has_key(field.getName()), True, False);
|
||||
|
|
BIN
gen/plone25/skin/to.png
Normal file
BIN
gen/plone25/skin/to.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 214 B |
BIN
gen/plone25/skin/waiting.gif
Executable file
BIN
gen/plone25/skin/waiting.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
Loading…
Add table
Add a link
Reference in a new issue