[gen] Added field appyclass.breadcrumb, allowing to show/hide the breadcrumb when displaying instances of this class; added field appyclass.resultMode, allowing to choose between 'list' or 'grid' mode (previously, only list mode was enabled) when showing instances of this class as a result of some query.

This commit is contained in:
Gaetan Delannay 2013-03-09 16:06:12 +01:00
parent 46f5b8e464
commit c5ec54f0e5
4 changed files with 182 additions and 129 deletions

View file

@ -9,7 +9,8 @@ from appy.gen.wrappers import AbstractWrapper
from appy.gen.descriptors import ClassDescriptor from appy.gen.descriptors import ClassDescriptor
from appy.gen.mail import sendMail from appy.gen.mail import sendMail
from appy.shared import mimeTypes from appy.shared import mimeTypes
from appy.shared.utils import getOsTempFolder, sequenceTypes, normalizeString from appy.shared.utils import getOsTempFolder, sequenceTypes, normalizeString, \
splitList
from appy.shared.data import languages from appy.shared.data import languages
try: try:
from AccessControl.ZopeSecurityPolicy import _noroles from AccessControl.ZopeSecurityPolicy import _noroles
@ -224,6 +225,13 @@ class ToolMixin(BaseMixin):
for key in self.queryParamNames]) for key in self.queryParamNames])
return res return res
def getResultMode(self, className):
'''Must we show, on result.pt, instances of p_className as a list or
as a grid?'''
klass = self.getAppyClass(className)
if hasattr(klass, 'resultMode'): return klass.resultMode
return 'list' # The default mode
def getImportElements(self, contentType): def getImportElements(self, contentType):
'''Returns the list of elements that can be imported from p_path for '''Returns the list of elements that can be imported from p_path for
p_contentType.''' p_contentType.'''
@ -416,6 +424,11 @@ class ToolMixin(BaseMixin):
return '<acronym title="%s">%s</acronym>' % \ return '<acronym title="%s">%s</acronym>' % \
(text, uText[:width].encode('utf-8') + '...') (text, uText[:width].encode('utf-8') + '...')
def splitList(self, l, sub):
'''Returns a list made of the same elements as p_l, but grouped into
sub-lists of p_sub elements.'''
return splitList(l, sub)
def getLayoutType(self): def getLayoutType(self):
'''Guess the current layout type, according to actual URL.''' '''Guess the current layout type, according to actual URL.'''
actualUrl = self.REQUEST['ACTUAL_URL'] actualUrl = self.REQUEST['ACTUAL_URL']

View file

@ -1606,7 +1606,12 @@ class BaseMixin:
if parent.meta_type not in ('Folder', 'Temporary Folder'): return parent if parent.meta_type not in ('Folder', 'Temporary Folder'): return parent
def getBreadCrumb(self): def getBreadCrumb(self):
'''Gets breadcrumb info about this object and its parents.''' '''Gets breadcrumb info about this object and its parents (if it must
be shown).'''
# Return an empty breadcrumb if it must not be shown.
klass = self.getClass()
if hasattr(klass, 'breadcrumb') and not klass.breadcrumb: return ()
# Compute the breadcrumb
res = [{'url': self.absolute_url(), res = [{'url': self.absolute_url(),
'title': self.getFieldValue('title', layoutType='view')}] 'title': self.getFieldValue('title', layoutType='view')}]
parent = self.getParent() parent = self.getParent()
@ -1746,7 +1751,8 @@ class BaseMixin:
appyType = self.getAppyType(name) appyType = self.getAppyType(name)
else: else:
appyType = self.getAppyType(name.split('_img_')[0]) appyType = self.getAppyType(name.split('_img_')[0])
if not appyType.isShowable(self, 'view'): if (not appyType.isShowable(self, 'view')) and \
(not appyType.isShowable(self, 'result')):
from zExceptions import NotFound from zExceptions import NotFound
raise NotFound() raise NotFound()
theFile = getattr(self.aq_base, name, None) theFile = getattr(self.aq_base, name, None)

View file

@ -4,42 +4,42 @@ pre { font: 100% Helvetica,Arial,sans-serif; margin: 0}
h1 { font-size: 14pt; margin:6px 0 6px 0 } h1 { font-size: 14pt; margin:6px 0 6px 0 }
h2 { font-size: 13pt; margin:6px 0 6px 0; font-style: italic; h2 { font-size: 13pt; margin:6px 0 6px 0; font-style: italic;
font-weight: normal } font-weight: normal }
h3 { font-size: 12pt; margin:4px 0 4px 0; font-weight: bold;} h3 { font-size: 12pt; margin:4px 0 4px 0; font-weight: bold }
h4 { font-size: 11pt; margin:4px 0 4px 0 } h4 { font-size: 11pt; margin:4px 0 4px 0 }
h5 { font-size: 10pt; margin:0; font-style: italic; font-weight: normal; h5 { font-size: 10pt; margin:0; font-style: italic; font-weight: normal;
background-color: #d7dee4 } background-color: #d7dee4 }
h6 { font-size: 9pt; margin:0; font-weight: bold;} h6 { font-size: 9pt; margin:0; font-weight: bold }
a { text-decoration: none; color: #436976;} a { text-decoration: none; color: #436976 }
a:visited { color: #436976;} a:visited { color: #436976 }
table { font-size: 100%; border-spacing: 0px; border-collapse:collapse;} table { font-size: 100%; border-spacing: 0px; border-collapse:collapse;}
form { margin: 0; padding: 0;} form { margin: 0; padding: 0 }
p { margin: 0;} p { margin: 0 }
acronym {cursor: help;} acronym { cursor: help }
input { font: 92% Helvetica,Arial,sans-serif } input { font: 92% Helvetica,Arial,sans-serif }
input[type=image] { border: 0; background: none; cursor: pointer; } input[type=image] { border: 0; background: none; cursor: pointer }
input[type=checkbox] { border: 0; background: none; cursor: pointer;} input[type=checkbox] { border: 0; background: none; cursor: pointer }
input[type=radio] { border: 0; background: none; cursor: pointer;} input[type=radio] { border: 0; background: none; cursor: pointer }
input[type=file] { border: 0px solid #d0d0d0; input[type=file] { border: 0px solid #d0d0d0;
background-color: #f8f8f8; cursor: pointer;} background-color: #f8f8f8; cursor: pointer }
input[type=button] { border: 1px solid #d0d0d0; input[type=button] { border: 1px solid #d0d0d0;
background-color: #f8f8f8; cursor: pointer;} background-color: #f8f8f8; cursor: pointer }
input[type=submit] { border: 1px solid #d0d0d0; background-color: #f8f8f8; input[type=submit] { border: 1px solid #d0d0d0; background-color: #f8f8f8;
cursor: pointer; } cursor: pointer }
input[type=password] { border: 1px solid #d0d0d0; background-color: #f8f8f8; input[type=password] { border: 1px solid #d0d0d0; background-color: #f8f8f8;
font-family: Helvetica,Arial,sans-serif;} font-family: Helvetica,Arial,sans-serif }
input[type=text] { border: 1px solid #d0d0d0; background-color: #f8f8f8; input[type=text] { border: 1px solid #d0d0d0; background-color: #f8f8f8;
font-family: Helvetica,Arial,sans-serif; font-family: Helvetica,Arial,sans-serif;
margin-bottom: 1px } margin-bottom: 1px }
select { border: 1px solid #d0d0d0; background-color: #f8f8f8;} select { border: 1px solid #d0d0d0; background-color: #f8f8f8 }
textarea { width: 99%; font: 100% Helvetica,Arial,sans-serif; textarea { width: 99%; font: 100% Helvetica,Arial,sans-serif;
border: 1px solid #d0d0d0; background-color: #f8f8f8;} border: 1px solid #d0d0d0; background-color: #f8f8f8 }
label { font-weight: 600; font-style: italic; line-height: 1.4em;} label { font-weight: 600; font-style: italic; line-height: 1.4em }
legend { padding-bottom: 2px; padding-right: 3px; color: black;} legend { padding-bottom: 2px; padding-right: 3px; color: black }
ul { line-height: 1.2em; margin: 0 0 0.2em 0.6em; padding: 0; ul { line-height: 1.2em; margin: 0 0 0.2em 0.6em; padding: 0;
list-style: none outside none;} list-style: none outside none }
ul li { margin: 0; background-image: url("ui/li.gif"); padding-left: 10px; ul li { margin: 0; background-image: url("ui/li.gif"); padding-left: 10px;
background-repeat: no-repeat; background-position: 0 4px;} background-repeat: no-repeat; background-position: 0 4px }
img { border: 0; vertical-align: middle } img { border: 0; vertical-align: middle }
/* Styles that apply when viewing content of XHTML fields, that mimic styles /* Styles that apply when viewing content of XHTML fields, that mimic styles
@ -51,36 +51,36 @@ img { border: 0; vertical-align: middle}
.main { width: 900px; background-color: white; box-shadow: 3px 3px 3px #A9A9A9; .main { width: 900px; background-color: white; box-shadow: 3px 3px 3px #A9A9A9;
border-style: solid; border-width: 1px; border-color: grey } border-style: solid; border-width: 1px; border-color: grey }
.top { height: 89px; margin-left: 3em; vertical-align: top;} .top { height: 89px; margin-left: 3em; vertical-align: top }
.lang { margin-right: 6px; } .lang { margin-right: 6px }
.userStrip { background-color: #6282B3; height: 35px; .userStrip { background-color: #6282B3; height: 35px;
border-top: 3px solid #034984; border-bottom: 2px solid #034984; } border-top: 3px solid #034984; border-bottom: 2px solid #034984 }
.userStripText { padding: 0 0.3em 0 0.3em; color: white } .userStripText { padding: 0 0.3em 0 0.3em; color: white }
.userStrip a { color: #e7e7e7 } .userStrip a { color: #e7e7e7 }
.userStrip a:visited { color: #e7e7e7 } .userStrip a:visited { color: #e7e7e7 }
.navigate { border-bottom: 1px solid #5F7983; .navigate { border-bottom: 1px solid #5F7983;
background-color: #dbdde1; font-weight: bold } background-color: #dbdde1; font-weight: bold }
.navigate td { padding: 4px 9px } .navigate td { padding: 4px 9px }
.login { margin-top: 2px; margin-bottom: 2px; color: black;} .login { margin-top: 2px; margin-bottom: 2px; color: black }
.buttons { margin-left: 4px;} .buttons { margin-left: 4px }
.fakeButton { border: 1px solid #D7DEE4; background-color: #fde8e0; .fakeButton { border: 1px solid #D7DEE4; background-color: #fde8e0;
padding: 0px 8px 2px; font: italic 92% Helvetica,Arial,sans-serif} padding: 0px 8px 2px; font: italic 92% Helvetica,Arial,sans-serif}
.message { position: absolute; top: -40px; left: 150px; font-size: 90%; .message { position: absolute; top: -40px; left: 150px; font-size: 90%;
width: 600px; border: 1px #F0C36D solid; padding: 6px; width: 600px; border: 1px #F0C36D solid; padding: 6px;
background-color: #F9EDBE; text-align: center; background-color: #F9EDBE; text-align: center;
border-radius: 2px 2px 2px 2px; box-shadow: 0 2px 4px #A9A9A9;} border-radius: 2px 2px 2px 2px; box-shadow: 0 2px 4px #A9A9A9 }
.focus { font-size: 90%; margin: 7px 0 7px 0; padding: 7px; .focus { font-size: 90%; margin: 7px 0 7px 0; padding: 7px;
background-color: #d7dee4; border-radius: 2px 2px 2px 2px; background-color: #d7dee4; border-radius: 2px 2px 2px 2px;
box-shadow: 0 2px 4px #A9A9A9 } box-shadow: 0 2px 4px #A9A9A9 }
.focus td { padding: 4px 0px 4px 4px } .focus td { padding: 4px 0px 4px 4px }
.discreet { font-size: 90%; color: grey } .discreet { font-size: 90%; color: grey }
.lostPassword a { font-size: 90%; color: white; padding-left: 1em;} .lostPassword a { font-size: 90%; color: white; padding-left: 1em }
.portlet { width: 150px; border-right: 1px solid #5F7983; .portlet { width: 150px; border-right: 1px solid #5F7983;
background-color: #ededed } background-color: #ededed }
.portletContent { margin: 4px 9px } .portletContent { margin: 4px 9px }
.portletTitle { font-weight: bold; font-size: 110%; margin-bottom: 4px;} .portletTitle { font-weight: bold; font-size: 110%; margin-bottom: 4px }
.portletCurrent { font-weight: bold; } .portletCurrent { font-weight: bold }
.portletSep { border-top: 1px solid #5F7983; margin-top: 2px;} .portletSep { border-top: 1px solid #5F7983; margin-top: 2px }
.portletPage { font-style: italic } .portletPage { font-style: italic }
.portletGroup { font-variant: small-caps; font-weight: bold; font-size: 105%; .portletGroup { font-variant: small-caps; font-weight: bold; font-size: 105%;
margin: 0.1em 0 0.3em ; border-bottom: 1px dashed grey } margin: 0.1em 0 0.3em ; border-bottom: 1px dashed grey }
@ -88,50 +88,50 @@ img { border: 0; vertical-align: middle}
.content { padding: 14px 14px 9px 15px; background-color: #f1f1f1 } .content { padding: 14px 14px 9px 15px; background-color: #f1f1f1 }
.grey { display: none; position: absolute; left: 0px; top: 0px; .grey { display: none; position: absolute; left: 0px; top: 0px;
background:grey; opacity:0.5; -moz-opacity:0.5; -khtml-opacity:0.5; background:grey; opacity:0.5; -moz-opacity:0.5; -khtml-opacity:0.5;
filter:alpha(Opacity=50);} filter:alpha(Opacity=50) }
.popup { display: none; position: absolute; top: 30%; left: 35%; .popup { display: none; position: absolute; top: 30%; left: 35%;
width: 350px; z-index : 100; background: white; padding: 8px; width: 350px; z-index : 100; background: white; padding: 8px;
border: 1px solid grey; } border: 1px solid grey }
.list { border: 1px solid grey; margin-bottom: 3px;} .list { border: 1px solid grey; margin-bottom: 3px }
.list td, .list th { border: 1px solid grey; .list td, .list th { border: 1px solid grey;
padding-left: 5px; padding-right: 5px; padding-top: 3px;} padding-left: 5px; padding-right: 5px; padding-top: 3px }
.list th { background-color: #d7dee4; font-style: italic; font-weight: normal } .list th { background-color: #d7dee4; font-style: italic; font-weight: normal }
.grid th { font-style: italic; font-weight: normal; .grid th { font-style: italic; font-weight: normal;
border-bottom: 2px solid grey; padding: 2px 2px } border-bottom: 2px solid grey; padding: 2px 2px }
.grid td { padding-right: 5px } .grid td { padding-right: 5px }
.cellGap { padding-right: 0.4em } .cellGap { padding-right: 0.4em }
.cellDashed { border: 1px dashed grey !important } .cellDashed { border: 1px dashed grey !important }
.noStyle { border: 0 !important; padding: 0 !important; margin: 0 !important; } .noStyle { border: 0 !important; padding: 0 !important; margin: 0 !important }
.noStyle td { border:0 !important; padding:0 !important; margin:0 !important; } .noStyle td { border:0 !important; padding:0 !important; margin:0 !important }
.translationLabel { background-color: #EAEAEA; border-bottom: 1px dashed grey; .translationLabel { background-color: #EAEAEA; border-bottom: 1px dashed grey;
margin-top: 0.5em; margin-bottom: 0.5em; } margin-top: 0.5em; margin-bottom: 0.5em }
.section1 { font-size: 120%; margin: 0.45em 0em 0.1em 0; .section1 { font-size: 120%; margin: 0.45em 0em 0.1em 0;
padding: 0.3em 0em 0.2em 0.1em; background-color: #eef3f5; padding: 0.3em 0em 0.2em 0.1em; background-color: #eef3f5;
border-top: 1px solid #8CACBB;border-bottom: 1px solid #8CACBB; } border-top: 1px solid #8CACBB;border-bottom: 1px solid #8CACBB }
.section2 { font-size: 110%; font-style: italic; margin: 0.45em 0em 0.2em 0; .section2 { font-size: 110%; font-style: italic; margin: 0.45em 0em 0.2em 0;
border-bottom: 2px solid grey; } border-bottom: 2px solid grey }
.section3 { font-size: 100%; font-style: italic; font-weight: bold; .section3 { font-size: 100%; font-style: italic; font-weight: bold;
margin: 0.45em 0em 0.1em 0; background-color: #95a1b3; margin: 0.45em 0em 0.1em 0; background-color: #95a1b3;
text-align: center; color: white; } text-align: center; color: white }
.odd { background-color: #f9f9f9; } .odd { background-color: #f9f9f9 }
.even { background-color: #f4f4f4; } .even { background-color: #f4f4f4 }
.summary { margin-bottom: 5px; background-color: #e9e9e9; .summary { margin-bottom: 5px; background-color: #e9e9e9;
border: 1px dashed grey } border: 1px dashed grey }
.objectTitle { font-size: 11pt; border-bottom: 3px solid grey; .objectTitle { font-size: 11pt; border-bottom: 3px solid grey;
font-weight: bold;} font-weight: bold }
.by { padding: 5px; color: grey; font-size: 97% } .by { padding: 5px; color: grey; font-size: 97% }
.underline { border-bottom: 1px dotted grey;} .underline { border-bottom: 1px dotted grey }
.state { font-weight: bold; border-bottom: 1px dashed grey;} .state { font-weight: bold; border-bottom: 1px dashed grey }
.historyLabel { font-variant: small-caps; font-weight: bold;} .historyLabel { font-variant: small-caps; font-weight: bold }
.history td { border-top: 1px solid grey; padding: 0 5px 0 5px } .history td { border-top: 1px solid grey; padding: 0 5px 0 5px }
.history th { font-style: italic; text-align: left; padding: 0 5px 0 5px } .history th { font-style: italic; text-align: left; padding: 0 5px 0 5px }
.topSpace { margin-top: 15px;} .topSpace { margin-top: 15px }
.bottomSpace { margin-bottom: 15px;} .bottomSpace { margin-bottom: 15px }
.pageLink { padding-left: 8px } .pageLink { padding-left: 8px }
.footer { font-size: 95% } .footer { font-size: 95% }
.footer td { background-color: #CBCBC9; border-top: 1px solid grey; .footer td { background-color: #CBCBC9; border-top: 1px solid grey;
padding: 0.4em 1em 0.5em } padding: 0.4em 1em 0.5em }
.code { font-family: "Lucida Console","Courier New";} .code { font-family: "Lucida Console","Courier New" }
.codePara { background-color: #EEFFCC; border-color: grey; .codePara { background-color: #EEFFCC; border-color: grey;
border-style: solid none; border-width: 1px medium; border-style: solid none; border-width: 1px medium;
color: #333333; line-height: 120%; color: #333333; line-height: 120%;

View file

@ -1,3 +1,87 @@
<tal:comment replace="nothing">Show field content of a given object.</tal:comment>
<metal:field define-macro="field">
<tal:comment replace="nothing">Title</tal:comment>
<tal:title condition="python: widget['name'] == 'title'">
<tal:icons replace="structure obj/getIcons"/>
<a tal:define="navInfo python:'search.%s.%s.%d.%d' % (className, searchName, repeat['obj'].number()+startNumber, totalNumber);"
tal:content="obj/Title" tal:attributes="href python: obj.getUrl(nav=navInfo, page=obj.getDefaultViewPage())"></a>
<div name="subTitle" tal:content="structure obj/getSubTitle"
tal:attributes="style python: showSubTitles and 'display:block' or 'display:none'"></div>
<tal:comment replace="nothing">Actions: edit, delete</tal:comment>
<div tal:attributes="align dright" tal:condition="obj/mayAct">
<a tal:define="navInfo python:'search.%s.%s.%d.%d' % (className, searchName, repeat['obj'].number()+startNumber, totalNumber);"
tal:attributes="href python: obj.getUrl(mode='edit', page=obj.getDefaultEditPage(), nav=navInfo)"
tal:condition="obj/mayEdit">
<img tal:attributes="src string: $appUrl/ui/edit.png;
title python: _('object_edit')"/></a><img
tal:condition="obj/mayDelete" style="cursor:pointer"
tal:attributes="src string: $appUrl/ui/delete.png;
title python: _('object_delete');
onClick python:'onDeleteObject(\'%s\')' % obj.UID()"/>
</div>
</tal:title>
<tal:comment replace="nothing">Any other field</tal:comment>
<tal:other condition="python: widget['name'] != 'title'">
<tal:field define="contextObj python:obj;
layoutType python:'cell';
innerRef python:True"
condition="python: contextObj.showField(widget['name'], 'result')">
<metal:f use-macro="context/ui/widgets/show/macros/field"/>
</tal:field>
</tal:other>
</metal:field>
<tal:comment replace="nothing">Show query results as a list.</tal:comment>
<table metal:define-macro="list" class="list" width="100%">
<tal:comment replace="nothing">Headers, with filters and sort arrows</tal:comment>
<tr>
<tal:header repeat="column columns">
<th tal:define="widget column/field;
sortable python: tool.isSortable(widget['name'], className, 'search');
filterable widget/filterable|nothing"
tal:attributes="width column/width; align column/align">
<span tal:replace="structure python: tool.truncateText(_(widget['labelId']))"/>
<metal:icons use-macro="context/ui/navigate/macros/sortAndFilter"/>
<metal:details use-macro="context/ui/navigate/macros/showDetails"/>
</th>
</tal:header>
</tr>
<tal:comment replace="nothing">Results</tal:comment>
<tal:row repeat="obj objs">
<tr id="query_row" valign="top" tal:define="odd repeat/obj/odd"
tal:attributes="class python:test(odd, 'even', 'odd')">
<tal:fields repeat="column columns">
<td tal:define="widget column/field"
tal:attributes="id python:'field_%s' % widget['name'];
width column/width; align column/align">
<metal:f use-macro="context/ui/result/macros/field"/>
</td>
</tal:fields>
</tr>
</tal:row>
</table>
<tal:comment replace="nothing">Show query results as a grid.</tal:comment>
<table metal:define-macro="grid" width="100%"
tal:define="modeElems python: resultMode.split('_');
cols python: (len(modeElems)==2) and int(modeElems[1]) or 4;
rows python: tool.splitList(objs, cols)">
<tr tal:repeat="row rows" valign="middle">
<td tal:repeat="obj row" tal:attributes="width python: '%d%%'%(100/cols)"
align="center" style="padding-top: 8px">
<tal:col repeat="column columns">
<tal:field define="widget column/field">
<metal:f use-macro="context/ui/result/macros/field"/>
</tal:field>
</tal:col>
</td>
</tr>
</table>
<tal:comment replace="nothing">Show paginated query results as a list or grid.</tal:comment>
<div id="queryResult" metal:define-macro="queryResult" <div id="queryResult" metal:define-macro="queryResult"
tal:define="_ python: tool.translate; tal:define="_ python: tool.translate;
className request/className; className request/className;
@ -20,7 +104,8 @@
ajaxHookId python:'queryResult'; ajaxHookId python:'queryResult';
navBaseCall python: 'askQueryResult(\'%s\',\'%s\',\'%s\',\'%s\',**v**)' % (ajaxHookId, tool.absolute_url(), className, searchName); navBaseCall python: 'askQueryResult(\'%s\',\'%s\',\'%s\',\'%s\',**v**)' % (ajaxHookId, tool.absolute_url(), className, searchName);
newSearchUrl python: '%s/ui/search?className=%s%s' % (tool.absolute_url(), className, refUrlPart); newSearchUrl python: '%s/ui/search?className=%s%s' % (tool.absolute_url(), className, refUrlPart);
showSubTitles python: request.get('showSubTitles', 'true') == 'true'"> showSubTitles python: request.get('showSubTitles', 'true') == 'true';
resultMode python: tool.getResultMode(className)">
<tal:result condition="objs"> <tal:result condition="objs">
<tal:comment replace="nothing">Display here POD templates if required.</tal:comment> <tal:comment replace="nothing">Display here POD templates if required.</tal:comment>
@ -56,68 +141,17 @@
</td> </td>
</tr> </tr>
</table> </table>
<table tal:define="columnLayouts python: tool.getResultColumnsLayouts(className, refInfo);
columns python: objs[0].getColumnsSpecifiers(columnLayouts, dir)"
class="list" width="100%">
<tal:comment replace="nothing">Headers, with filters and sort arrows</tal:comment>
<tr>
<tal:header repeat="column columns">
<th tal:define="widget column/field;
sortable python: tool.isSortable(widget['name'], className, 'search');
filterable widget/filterable|nothing"
tal:attributes="width column/width; align column/align">
<span tal:replace="structure python: tool.truncateText(_(widget['labelId']))"/>
<metal:icons use-macro="context/ui/navigate/macros/sortAndFilter"/>
<metal:details use-macro="context/ui/navigate/macros/showDetails"/>
</th>
</tal:header>
</tr>
<tal:comment replace="nothing">Results</tal:comment> <tal:comment replace="nothing">Results, as a list or grid</tal:comment>
<tal:row repeat="obj objs"> <tal:res define="columnLayouts python: tool.getResultColumnsLayouts(className, refInfo);
<tr id="query_row" valign="top" tal:define="odd repeat/obj/odd" columns python: objs[0].getColumnsSpecifiers(columnLayouts, dir)">
tal:attributes="class python:test(odd, 'even', 'odd')"> <tal:asList condition="python: resultMode == 'list'">
<metal:list use-macro="context/ui/result/macros/list"/>
<tal:fields repeat="column columns"> </tal:asList>
<td tal:define="widget column/field" <tal:asGrid condition="python: resultMode != 'list'">
tal:attributes="id python:'field_%s' % widget['name']; <metal:grid use-macro="context/ui/result/macros/grid"/>
width column/width; align column/align"> </tal:asGrid>
<tal:comment replace="nothing">Title</tal:comment> </tal:res>
<tal:title condition="python: widget['name'] == 'title'">
<tal:icons replace="structure obj/getIcons"/>
<a tal:define="navInfo python:'search.%s.%s.%d.%d' % (className, searchName, repeat['obj'].number()+startNumber, totalNumber);"
tal:content="obj/Title" tal:attributes="href python: obj.getUrl(nav=navInfo, page=obj.getDefaultViewPage())"></a>
<div name="subTitle" tal:content="structure obj/getSubTitle"
tal:attributes="style python: showSubTitles and 'display:block' or 'display:none'"></div>
<tal:comment replace="nothing">Actions: edit, delete</tal:comment>
<div tal:attributes="align dright" tal:condition="obj/mayAct">
<a tal:define="navInfo python:'search.%s.%s.%d.%d' % (className, searchName, repeat['obj'].number()+startNumber, totalNumber);"
tal:attributes="href python: obj.getUrl(mode='edit', page=obj.getDefaultEditPage(), nav=navInfo)"
tal:condition="obj/mayEdit">
<img tal:attributes="src string: $appUrl/ui/edit.png;
title python: _('object_edit')"/></a><img
tal:condition="obj/mayDelete" style="cursor:pointer"
tal:attributes="src string: $appUrl/ui/delete.png;
title python: _('object_delete');
onClick python:'onDeleteObject(\'%s\')' % obj.UID()"/>
</div>
</tal:title>
<tal:comment replace="nothing">Any other field</tal:comment>
<tal:other condition="python: widget['name'] != 'title'">
<tal:field define="contextObj python:obj;
layoutType python:'cell';
innerRef python:True"
condition="python: contextObj.showField(widget['name'], 'result')">
<metal:field use-macro="context/ui/widgets/show/macros/field"/>
</tal:field>
</tal:other>
</td>
</tal:fields>
</tr>
</tal:row>
</table>
<tal:comment replace="nothing">Appy (bottom) navigation</tal:comment> <tal:comment replace="nothing">Appy (bottom) navigation</tal:comment>
<metal:nav use-macro="here/ui/navigate/macros/appyNavigate"/> <metal:nav use-macro="here/ui/navigate/macros/appyNavigate"/>