Some macros and images were improved, enhanced search capabilities.
This commit is contained in:
parent
7435ff1601
commit
253e61612d
|
@ -12,7 +12,8 @@ import appy.gen
|
||||||
import appy.gen.descriptors
|
import appy.gen.descriptors
|
||||||
from appy.gen.po import PoMessage
|
from appy.gen.po import PoMessage
|
||||||
from appy.gen import Date, String, State, Transition, Type, Search
|
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.
|
TABS = 4 # Number of blanks in a Python indentation.
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -100,6 +101,9 @@ class ArchetypeFieldDescriptor:
|
||||||
self.fieldType = 'LinesField'
|
self.fieldType = 'LinesField'
|
||||||
self.widgetType = 'MultiSelectionWidget'
|
self.widgetType = 'MultiSelectionWidget'
|
||||||
self.fieldParams['multiValued'] = True
|
self.fieldParams['multiValued'] = True
|
||||||
|
if (type(self.appyType.validator) in sequenceTypes) and \
|
||||||
|
len(self.appyType.validator) <= 5:
|
||||||
|
self.widgetParams['format'] = 'checkbox'
|
||||||
else:
|
else:
|
||||||
self.fieldType = 'StringField'
|
self.fieldType = 'StringField'
|
||||||
self.widgetType = 'SelectionWidget'
|
self.widgetType = 'SelectionWidget'
|
||||||
|
|
|
@ -106,7 +106,8 @@ class ToolMixin(AbstractMixin):
|
||||||
|
|
||||||
_sortFields = {'title': 'sortable_title'}
|
_sortFields = {'title': 'sortable_title'}
|
||||||
def executeQuery(self, contentType, flavourNumber=1, searchName=None,
|
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
|
'''Executes a query on a given p_contentType (or several, separated
|
||||||
with commas) in Plone's portal_catalog. Portal types are from the
|
with commas) in Plone's portal_catalog. Portal types are from the
|
||||||
flavour numbered p_flavourNumber. If p_searchName is specified, it
|
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
|
p_startNumber. If p_search is defined, it corresponds to a custom
|
||||||
Search instance (instead of a predefined named search like in
|
Search instance (instead of a predefined named search like in
|
||||||
p_searchName). If both p_searchName and p_search are given, p_search
|
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 ?
|
# Is there one or several content types ?
|
||||||
if contentType.find(',') != -1:
|
if contentType.find(',') != -1:
|
||||||
# Several content types are specified
|
# Several content types are specified
|
||||||
|
@ -125,7 +135,8 @@ class ToolMixin(AbstractMixin):
|
||||||
for pt in portalTypes]
|
for pt in portalTypes]
|
||||||
else:
|
else:
|
||||||
portalTypes = contentType
|
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
|
# Manage additional criteria from a search when relevant
|
||||||
if searchName or search:
|
if searchName or search:
|
||||||
# In this case, contentType must contain a single content type.
|
# 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]
|
if self._sortFields.has_key(sb): sb = self._sortFields[sb]
|
||||||
params['sort_on'] = sb
|
params['sort_on'] = sb
|
||||||
brains = self.portal_catalog.searchResults(**params)
|
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()
|
res.brainsToObjects()
|
||||||
# In some cases (p_remember=True), we need to keep some information
|
# In some cases (p_remember=True), we need to keep some information
|
||||||
# about the query results in the current user's session, allowing him
|
# about the query results in the current user's session, allowing him
|
||||||
|
|
|
@ -54,9 +54,8 @@ class AbstractMixin:
|
||||||
pass
|
pass
|
||||||
# Manage "add" permissions
|
# Manage "add" permissions
|
||||||
obj._appy_managePermissions()
|
obj._appy_managePermissions()
|
||||||
# Re/unindex object
|
# Reindex object
|
||||||
if obj._appy_meta_type == 'tool': self.unindexObject()
|
obj.reindexObject()
|
||||||
else: obj.reindexObject()
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def delete(self):
|
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
BIN
gen/plone25/skin/delete.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 239 B |
|
@ -118,8 +118,8 @@
|
||||||
<metal:showDate define-macro="showDateField"
|
<metal:showDate define-macro="showDateField"
|
||||||
tal:define="v python: field.getAccessor(contextObj)()">
|
tal:define="v python: field.getAccessor(contextObj)()">
|
||||||
<span tal:condition="showLabel" tal:content="label" class="appyLabel"></span>
|
<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="v" tal:content="python: v.strftime('%d/%m/') + str(v.year())"></span>
|
||||||
<span tal:condition="python: appyType['format'] == 0"
|
<span tal:condition="python: v and (appyType['format'] == 0)"
|
||||||
tal:content="python: v.strftime('%H:%M')"></span>
|
tal:content="python: v.strftime('%H:%M')"></span>
|
||||||
</metal:showDate>
|
</metal:showDate>
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
<span tal:condition="showLabel" tal:content="label" class="appyLabel"
|
<span tal:condition="showLabel" tal:content="label" class="appyLabel"
|
||||||
tal:attributes="class python: 'appyLabel ' + contextObj.getCssClasses(appyType, asSlave=False);
|
tal:attributes="class python: 'appyLabel ' + contextObj.getCssClasses(appyType, asSlave=False);
|
||||||
id python: v"></span>
|
id python: v"></span>
|
||||||
<tal:severalValues condition="severalValues">
|
<tal:severalValues condition="python: v and severalValues">
|
||||||
<ul class="appyList">
|
<ul class="appyList">
|
||||||
<tal:items repeat="sv v">
|
<tal:items repeat="sv v">
|
||||||
<tal:select condition="appyType/isSelect">
|
<tal:select condition="appyType/isSelect">
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
</tal:items>
|
</tal:items>
|
||||||
</ul>
|
</ul>
|
||||||
</tal:severalValues>
|
</tal:severalValues>
|
||||||
<tal:singleValue condition="not: severalValues">
|
<tal:singleValue condition="python: v and not severalValues">
|
||||||
<tal:select condition="appyType/isSelect">
|
<tal:select condition="appyType/isSelect">
|
||||||
<span tal:replace="python: tool.translate('%s_%s_list_%s' % (contextObj.meta_type, field.getName(), v))"/>
|
<span tal:replace="python: tool.translate('%s_%s_list_%s' % (contextObj.meta_type, field.getName(), v))"/>
|
||||||
</tal:select>
|
</tal:select>
|
||||||
|
@ -617,7 +617,7 @@
|
||||||
tal:condition="python: searchName and descr">
|
tal:condition="python: searchName and descr">
|
||||||
<span class="discreet" tal:content="descr"></span><br/><br/>
|
<span class="discreet" tal:content="descr"></span><br/><br/>
|
||||||
</td>
|
</td>
|
||||||
<td align="right">
|
<td align="right" width="25%">
|
||||||
<tal:comment replace="nothing">Appy (top) navigation</tal:comment>
|
<tal:comment replace="nothing">Appy (top) navigation</tal:comment>
|
||||||
<metal:nav use-macro="here/skyn/macros/macros/appyNavigate"/>
|
<metal:nav use-macro="here/skyn/macros/macros/appyNavigate"/>
|
||||||
</td>
|
</td>
|
||||||
|
@ -723,8 +723,9 @@
|
||||||
<tal:comment replace="nothing">Delete the element</tal:comment>
|
<tal:comment replace="nothing">Delete the element</tal:comment>
|
||||||
<td class="noPadding">
|
<td class="noPadding">
|
||||||
<img tal:condition="python: member.has_permission('Delete objects', obj)"
|
<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"
|
title="Delete" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
|
||||||
tal:attributes="onClick python:'javascript:onDeleteObject(\'%s\')' % obj.UID()"/>
|
tal:attributes="src string: $portal_url/skyn/delete.png;
|
||||||
|
onClick python:'javascript:onDeleteObject(\'%s\')' % obj.UID()"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -18,17 +18,6 @@
|
||||||
referenced object (edit, delete, etc).</tal:comment>
|
referenced object (edit, delete, etc).</tal:comment>
|
||||||
<table class="no-style-table" cellpadding="0" cellspacing="0">
|
<table class="no-style-table" cellpadding="0" cellspacing="0">
|
||||||
<tr>
|
<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>
|
<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', obj)">
|
<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);
|
<tal:moveRef define="objectIndex python:contextObj.getAppyRefIndex(fieldName, obj);
|
||||||
|
@ -47,6 +36,18 @@
|
||||||
style="cursor:pointer"/>
|
style="cursor:pointer"/>
|
||||||
</tal:moveRef>
|
</tal:moveRef>
|
||||||
</td>
|
</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>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</metal:objectActions>
|
</metal:objectActions>
|
||||||
|
|
|
@ -97,6 +97,10 @@ class AbstractWrapper:
|
||||||
klass = property(get_klass)
|
klass = property(get_klass)
|
||||||
def get_url(self): return self.o.absolute_url()+'/skyn/view'
|
def get_url(self): return self.o.absolute_url()+'/skyn/view'
|
||||||
url = property(get_url)
|
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):
|
def link(self, fieldName, obj):
|
||||||
'''This method links p_obj to this one through reference field
|
'''This method links p_obj to this one through reference field
|
||||||
|
@ -245,19 +249,33 @@ class AbstractWrapper:
|
||||||
replaced with normal chars.'''
|
replaced with normal chars.'''
|
||||||
return unicodedata.normalize('NFKD', s).encode("ascii","ignore")
|
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
|
'''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
|
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
|
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
|
# Find the content type corresponding to p_klass
|
||||||
flavour = self.flavour
|
flavour = self.flavour
|
||||||
contentType = flavour.o.getPortalType(klass)
|
contentType = flavour.o.getPortalType(klass)
|
||||||
# Create the Search object
|
# Create the Search object
|
||||||
search = Search('customSearch', sortBy=sortBy, **fields)
|
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']]
|
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):
|
def reindex(self):
|
||||||
'''Asks a direct object reindexing. In most cases you don't have to
|
'''Asks a direct object reindexing. In most cases you don't have to
|
||||||
reindex objects "manually" with this method. When an object is
|
reindex objects "manually" with this method. When an object is
|
||||||
|
|
Loading…
Reference in a new issue