Some macros and images were improved, enhanced search capabilities.

This commit is contained in:
Gaetan Delannay 2009-11-24 22:41:42 +01:00
parent 7435ff1601
commit 253e61612d
9 changed files with 65 additions and 29 deletions

View file

@ -12,7 +12,8 @@ import appy.gen
import appy.gen.descriptors
from appy.gen.po import PoMessage
from appy.gen import Date, String, State, Transition, Type, Search
from appy.gen.utils import GroupDescr, PageDescr, produceNiceMessage
from appy.gen.utils import GroupDescr, PageDescr, produceNiceMessage, \
sequenceTypes
TABS = 4 # Number of blanks in a Python indentation.
# ------------------------------------------------------------------------------
@ -100,6 +101,9 @@ class ArchetypeFieldDescriptor:
self.fieldType = 'LinesField'
self.widgetType = 'MultiSelectionWidget'
self.fieldParams['multiValued'] = True
if (type(self.appyType.validator) in sequenceTypes) and \
len(self.appyType.validator) <= 5:
self.widgetParams['format'] = 'checkbox'
else:
self.fieldType = 'StringField'
self.widgetType = 'SelectionWidget'

View file

@ -106,7 +106,8 @@ class ToolMixin(AbstractMixin):
_sortFields = {'title': 'sortable_title'}
def executeQuery(self, contentType, flavourNumber=1, searchName=None,
startNumber=0, search=None, remember=False):
startNumber=0, search=None, remember=False,
brainsOnly=False, maxResults=None):
'''Executes a query on a given p_contentType (or several, separated
with commas) in Plone's portal_catalog. Portal types are from the
flavour numbered p_flavourNumber. If p_searchName is specified, it
@ -115,7 +116,16 @@ class ToolMixin(AbstractMixin):
p_startNumber. If p_search is defined, it corresponds to a custom
Search instance (instead of a predefined named search like in
p_searchName). If both p_searchName and p_search are given, p_search
is ignored.'''
is ignored. This method returns a list of objects in the form of the
__dict__ attribute of an instance of SomeObjects (see in
appy.gen.utils). We return the __dict__ attribute instead of real
instance: that way, it can be used in ZPTs without security problems.
If p_brainsOnly is True, it returns a list of brains instead (can be
useful for some usages like knowing the number of objects without
needing to get information about them). If no p_maxResults is
specified, the method returns maximum
self.getNumberOfResultsPerPage(). p_maxResults is ignored if
p_brainsOnly is True.'''
# Is there one or several content types ?
if contentType.find(',') != -1:
# Several content types are specified
@ -125,7 +135,8 @@ class ToolMixin(AbstractMixin):
for pt in portalTypes]
else:
portalTypes = contentType
params = {'portal_type': portalTypes, 'batch': True}
params = {'portal_type': portalTypes}
if not brainsOnly: params['batch'] = True
# Manage additional criteria from a search when relevant
if searchName or search:
# In this case, contentType must contain a single content type.
@ -151,7 +162,9 @@ class ToolMixin(AbstractMixin):
if self._sortFields.has_key(sb): sb = self._sortFields[sb]
params['sort_on'] = sb
brains = self.portal_catalog.searchResults(**params)
res = SomeObjects(brains, self.getNumberOfResultsPerPage(), startNumber)
if brainsOnly: return brains
if not maxResults: maxResults = self.getNumberOfResultsPerPage()
res = SomeObjects(brains, maxResults, startNumber)
res.brainsToObjects()
# In some cases (p_remember=True), we need to keep some information
# about the query results in the current user's session, allowing him

View file

@ -54,9 +54,8 @@ class AbstractMixin:
pass
# Manage "add" permissions
obj._appy_managePermissions()
# Re/unindex object
if obj._appy_meta_type == 'tool': self.unindexObject()
else: obj.reindexObject()
# Reindex object
obj.reindexObject()
return obj
def delete(self):

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 232 B

BIN
gen/plone25/skin/delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

View file

@ -118,8 +118,8 @@
<metal:showDate define-macro="showDateField"
tal:define="v python: field.getAccessor(contextObj)()">
<span tal:condition="showLabel" tal:content="label" class="appyLabel"></span>
<span tal:content="python: v.strftime('%d/%m/') + str(v.year())"></span>
<span tal:condition="python: appyType['format'] == 0"
<span tal:condition="v" tal:content="python: v.strftime('%d/%m/') + str(v.year())"></span>
<span tal:condition="python: v and (appyType['format'] == 0)"
tal:content="python: v.strftime('%H:%M')"></span>
</metal:showDate>
@ -132,7 +132,7 @@
<span tal:condition="showLabel" tal:content="label" class="appyLabel"
tal:attributes="class python: 'appyLabel ' + contextObj.getCssClasses(appyType, asSlave=False);
id python: v"></span>
<tal:severalValues condition="severalValues">
<tal:severalValues condition="python: v and severalValues">
<ul class="appyList">
<tal:items repeat="sv v">
<tal:select condition="appyType/isSelect">
@ -146,7 +146,7 @@
</tal:items>
</ul>
</tal:severalValues>
<tal:singleValue condition="not: severalValues">
<tal:singleValue condition="python: v and not severalValues">
<tal:select condition="appyType/isSelect">
<span tal:replace="python: tool.translate('%s_%s_list_%s' % (contextObj.meta_type, field.getName(), v))"/>
</tal:select>
@ -617,7 +617,7 @@
tal:condition="python: searchName and descr">
<span class="discreet" tal:content="descr"></span><br/><br/>
</td>
<td align="right">
<td align="right" width="25%">
<tal:comment replace="nothing">Appy (top) navigation</tal:comment>
<metal:nav use-macro="here/skyn/macros/macros/appyNavigate"/>
</td>
@ -723,8 +723,9 @@
<tal:comment replace="nothing">Delete the element</tal:comment>
<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()"/>
title="Delete" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
tal:attributes="src string: $portal_url/skyn/delete.png;
onClick python:'javascript:onDeleteObject(\'%s\')' % obj.UID()"/>
</td>
</tr>
</table>

View file

@ -18,17 +18,6 @@
referenced object (edit, delete, etc).</tal:comment>
<table class="no-style-table" cellpadding="0" cellspacing="0">
<tr>
<tal:comment replace="nothing">Edit the element</tal:comment>
<td class="noPadding"><a tal:attributes="href python: obj.absolute_url() + '/skyn/edit'"
tal:condition="python: member.has_permission('Modify portal content', obj)">
<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">
<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)&gt;1) and member.has_permission('Modify portal content', obj)">
<tal:moveRef define="objectIndex python:contextObj.getAppyRefIndex(fieldName, obj);
@ -47,6 +36,18 @@
style="cursor:pointer"/>
</tal:moveRef>
</td>
<tal:comment replace="nothing">Edit the element</tal:comment>
<td class="noPadding"><a tal:attributes="href python: obj.absolute_url() + '/skyn/edit'"
tal:condition="python: member.has_permission('Modify portal content', obj)">
<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">
<img tal:condition="python: member.has_permission('Delete objects', obj)"
title="Delete" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
tal:attributes="src string: $portal_url/skyn/delete.png;
onClick python:'javascript:onDeleteObject(\'%s\')' % obj.UID()"/>
</td>
</tr>
</table>
</metal:objectActions>

View file

@ -97,6 +97,10 @@ class AbstractWrapper:
klass = property(get_klass)
def get_url(self): return self.o.absolute_url()+'/skyn/view'
url = property(get_url)
def get_history(self):
key = self.o.workflow_history.keys()[0]
return self.o.workflow_history[key]
history = property(get_history)
def link(self, fieldName, obj):
'''This method links p_obj to this one through reference field
@ -245,19 +249,33 @@ class AbstractWrapper:
replaced with normal chars.'''
return unicodedata.normalize('NFKD', s).encode("ascii","ignore")
def search(self, klass, sortBy='', **fields):
def search(self, klass, sortBy='', maxResults=None, **fields):
'''Searches objects of p_klass. p_sortBy must be the name of an indexed
field (declared with indexed=True); every param in p_fields must
take the name of an indexed field and take a possible value of this
field.'''
field. You can optionally specify a maximum number of results in
p_maxResults.'''
# Find the content type corresponding to p_klass
flavour = self.flavour
contentType = flavour.o.getPortalType(klass)
# Create the Search object
search = Search('customSearch', sortBy=sortBy, **fields)
res = self.tool.o.executeQuery(contentType,flavour.number,search=search)
res = self.tool.o.executeQuery(contentType,flavour.number,search=search,
maxResults=maxResults)
return [o.appy() for o in res['objects']]
def count(self, klass, **fields):
'''Identical to m_search above, but returns the number of objects that
match the search instead of returning the objects themselves. Use
this method instead of writing len(self.search(...)).'''
flavour = self.flavour
contentType = flavour.o.getPortalType(klass)
search = Search('customSearch', **fields)
res = self.tool.o.executeQuery(contentType,flavour.number,search=search,
brainsOnly=True)
if res: return res._len # It is a LazyMap instance
else: return 0
def reindex(self):
'''Asks a direct object reindexing. In most cases you don't have to
reindex objects "manually" with this method. When an object is