add option-based filtering (overridable via request params
This commit is contained in:
		
							parent
							
								
									1e46a7dc67
								
							
						
					
					
						commit
						757a1cd60c
					
				
					 5 changed files with 51 additions and 9 deletions
				
			
		|  | @ -132,6 +132,7 @@ class BaseView(GenericView, I18NView): | ||||||
|     actions = {} |     actions = {} | ||||||
|     portlet_actions = [] |     portlet_actions = [] | ||||||
|     parts = () |     parts = () | ||||||
|  |     filter_input = () | ||||||
|     icon = None |     icon = None | ||||||
|     modeName = 'view' |     modeName = 'view' | ||||||
|     isToplevel = False |     isToplevel = False | ||||||
|  | @ -563,16 +564,22 @@ class BaseView(GenericView, I18NView): | ||||||
|             return DummyOptions() |             return DummyOptions() | ||||||
|         return component.queryAdapter(self.adapted, IOptions) or DummyOptions() |         return component.queryAdapter(self.adapted, IOptions) or DummyOptions() | ||||||
| 
 | 
 | ||||||
|     @Lazy |  | ||||||
|     def globalOptions(self): |  | ||||||
|         return IOptions(self.loopsRoot) |  | ||||||
| 
 |  | ||||||
|     @Lazy |     @Lazy | ||||||
|     def typeOptions(self): |     def typeOptions(self): | ||||||
|         if self.typeProvider is None: |         if self.typeProvider is None: | ||||||
|             return DummyOptions() |             return DummyOptions() | ||||||
|         return IOptions(adapted(self.typeProvider)) |         return IOptions(adapted(self.typeProvider)) | ||||||
| 
 | 
 | ||||||
|  |     @Lazy | ||||||
|  |     def globalOptions(self): | ||||||
|  |         return IOptions(self.loopsRoot) | ||||||
|  | 
 | ||||||
|  |     def getOptions(self, key): | ||||||
|  |         for opt in (self.options, self.typeOptions, self.globalOptions): | ||||||
|  |             value = opt[key] | ||||||
|  |             if not isinstance(value, DummyOptions): | ||||||
|  |                 return value | ||||||
|  | 
 | ||||||
|     def getPredicateOptions(self, relation): |     def getPredicateOptions(self, relation): | ||||||
|         return IOptions(adapted(relation.predicate), None) or DummyOptions() |         return IOptions(adapted(relation.predicate), None) or DummyOptions() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -361,7 +361,8 @@ class ConceptView(BaseView): | ||||||
|                 options = IOptions(adapted(r.predicate), None) |                 options = IOptions(adapted(r.predicate), None) | ||||||
|                 if options is not None and options('hide_children'): |                 if options is not None and options('hide_children'): | ||||||
|                     continue |                     continue | ||||||
|                 if not fv.check(r.context): |                 filterOptions = self.getOptions('filter') | ||||||
|  |                 if not fv.check(r.context, filterOptions): | ||||||
|                     continue |                     continue | ||||||
|             yield r |             yield r | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,15 +1,16 @@ | ||||||
| <html i18n:domain="loops"> | <html i18n:domain="loops"> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| <metal:data define-macro="conceptinfo"> | <metal:data define-macro="layout"> | ||||||
|   <tal:part repeat="part item/parts"> |   <tal:part repeat="part item/getParts"> | ||||||
|     <metal:part use-macro="part/renderer" /> |     <metal:part use-macro="part/macro" /> | ||||||
|   </tal:part> |   </tal:part> | ||||||
| </metal:data> | </metal:data> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| <metal:data define-macro="conceptdata"> | <metal:data define-macro="conceptdata"> | ||||||
|   <div tal:attributes="class string:content-$level;"> |   <div tal:attributes="class string:content-$level;"> | ||||||
|  |       <metal:block use-macro="view/concept_macros/filter_input" /> | ||||||
|       <metal:block use-macro="view/concept_macros/concepttitle" /> |       <metal:block use-macro="view/concept_macros/concepttitle" /> | ||||||
|       <metal:slot define-slot="fields"> |       <metal:slot define-slot="fields"> | ||||||
|         <metal:block use-macro="view/concept_macros/conceptfields" /> |         <metal:block use-macro="view/concept_macros/conceptfields" /> | ||||||
|  | @ -29,6 +30,18 @@ | ||||||
| </metal:data> | </metal:data> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | <metal:selection define-macro="filter_input"> | ||||||
|  |   <div tal:define="criteria item/filter" | ||||||
|  |        tal:condition="criteria"> | ||||||
|  |     <form method="get" name="filter" id="form-filter"> | ||||||
|  |       <span tal:repeat="crit criteria"> | ||||||
|  |         <metal:input use-macro="crit/macro" /> | ||||||
|  |       </span> | ||||||
|  |     </form> | ||||||
|  |   </div> | ||||||
|  | </metal:selection> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| <metal:title define-macro="concepttitle"> | <metal:title define-macro="concepttitle"> | ||||||
|   <metal:title define-macro="concepttitle_only"> |   <metal:title define-macro="concepttitle_only"> | ||||||
|     <tal:actions condition="view/showObjectActions"> |     <tal:actions condition="view/showObjectActions"> | ||||||
|  |  | ||||||
|  | @ -27,6 +27,7 @@ from zope.app.pagetemplate import ViewPageTemplateFile | ||||||
| from zope.cachedescriptors.property import Lazy | from zope.cachedescriptors.property import Lazy | ||||||
| 
 | 
 | ||||||
| from cybertools.browser.configurator import ViewConfigurator, MacroViewProperty | from cybertools.browser.configurator import ViewConfigurator, MacroViewProperty | ||||||
|  | from cybertools.stateful.interfaces import IStateful | ||||||
| from loops.browser.node import NodeView | from loops.browser.node import NodeView | ||||||
| from loops.concept import Concept | from loops.concept import Concept | ||||||
| from loops.organize.party import getPersonForUser | from loops.organize.party import getPersonForUser | ||||||
|  | @ -107,7 +108,17 @@ class FilterView(NodeView): | ||||||
|             result.setdefault(obj.getType(), set([])).add(obj) |             result.setdefault(obj.getType(), set([])).add(obj) | ||||||
|         return result |         return result | ||||||
| 
 | 
 | ||||||
|     def check(self, obj): |     def check(self, obj, options=None): | ||||||
|  |         if options: | ||||||
|  |             for std in options.states.keys(): | ||||||
|  |                 stf = component.getAdapter(obj, IStateful, name=std) | ||||||
|  |                 formStates = self.request.form.get('states.' + std) | ||||||
|  |                 if formStates: | ||||||
|  |                     if stf.state not in formStates.split(','): | ||||||
|  |                         return False | ||||||
|  |                 else: | ||||||
|  |                     if stf.state not in getattr(options.states, std): | ||||||
|  |                         return False | ||||||
|         fs = self.filterStructure |         fs = self.filterStructure | ||||||
|         if not fs: |         if not fs: | ||||||
|             return True |             return True | ||||||
|  |  | ||||||
|  | @ -1,3 +1,10 @@ | ||||||
|  | <html i18n:domain="loops"> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | <metal:input define-macro="filter_allstates"> | ||||||
|  |   <input type="checkbox" name="filter.allstates" value="yes" | ||||||
|  |          tal:attributes="checked crit/checked" /> | ||||||
|  | </metal:input> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| <metal:query define-macro="query"> | <metal:query define-macro="query"> | ||||||
|  | @ -55,3 +62,6 @@ | ||||||
|     </form> |     </form> | ||||||
|   </div> |   </div> | ||||||
| </metal:query> | </metal:query> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | </html> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue