Some macros and images were improved, enhanced search capabilities.
This commit is contained in:
		
							parent
							
								
									7435ff1601
								
							
						
					
					
						commit
						253e61612d
					
				
					 9 changed files with 65 additions and 29 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gaetan Delannay
						Gaetan Delannay