From 0130423826753526868ed94137866d9d3bd2c1d9 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Thu, 23 May 2019 18:03:44 +0200 Subject: [PATCH 01/10] finish PR (and some formatting) --- src/collective/collectionfilter/utils.py | 38 ++++++++++++++---------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/collective/collectionfilter/utils.py b/src/collective/collectionfilter/utils.py index 940d2b4e..06f8e956 100644 --- a/src/collective/collectionfilter/utils.py +++ b/src/collective/collectionfilter/utils.py @@ -1,34 +1,29 @@ # -*- coding: utf-8 -*- -from plone import api from plone.app.contenttypes.behaviors.collection import ISyndicatableCollection from Products.CMFCore.interfaces import IFolderish from Products.CMFPlone.utils import safe_unicode + import six def target_collection_base_path(context): for potential_context in context.aq_chain: - if ( - IFolderish.providedBy(potential_context) or - ISyndicatableCollection.providedBy(potential_context) - ): + if IFolderish.providedBy( + potential_context + ) or ISyndicatableCollection.providedBy(potential_context): context = potential_context break return '/'.join(context.getPhysicalPath()) -def target_collection_types(context): - return api.portal.get_registry_record( - 'collective.collectionfilter.target_collection_types', - default=['Collection', ]) - - def safe_decode(val): """Safely create unicode values. """ ret = val if isinstance(val, dict): - ret = dict([(safe_decode(k), safe_decode(v)) for k, v in val.items() if v]) # noqa + ret = dict( + [(safe_decode(k), safe_decode(v)) for k, v in val.items() if v] + ) elif isinstance(val, list): ret = [safe_decode(it) for it in val] elif isinstance(val, tuple): @@ -43,7 +38,9 @@ def safe_encode(val): """ ret = val if isinstance(val, dict): - ret = dict([(safe_encode(k), safe_encode(v)) for k, v in val.items() if v]) # noqa + ret = dict( + [(safe_encode(k), safe_encode(v)) for k, v in val.items() if v] + ) elif isinstance(val, list): ret = [safe_encode(it) for it in val] elif isinstance(val, tuple): @@ -58,13 +55,13 @@ def safe_iterable(value): return [] if isinstance(value, six.string_types): # do not expand a string to a list of chars - return [value, ] + return [value] else: try: return list(value) except TypeError: # int and other stuff - return [value, ] + return [value] # could not convert return [] @@ -92,3 +89,14 @@ def base_query(request_params={}, extra_ignores=[]): } urlquery.update({'collectionfilter': '1'}) # marker return urlquery + + +def get_top_request(request): + """Get highest request from a subrequest. + """ + + def _top_request(req): + parent_request = req.get('PARENT_REQUEST', None) + return _top_request(parent_request) if parent_request else req + + return _top_request(request) From cf72793d81e4ee22be0234328320b8bdeed8cbeb Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Thu, 23 May 2019 18:06:57 +0200 Subject: [PATCH 02/10] doc chnages --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 336fde2b..4eb3d723 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,7 @@ Changelog 3.2 (unreleased) ---------------- -- Nothing changed yet. +- Backport for @petschki: #42 Incorrect count on "all" when "Narrow down filter options" enabled and viewing a filtered result. [pigeonflight, jensens] 3.1 (2019-06-06) From 04f2575b47252e6f1fe616419d4cdefe613fdcbb Mon Sep 17 00:00:00 2001 From: Jon Pentland Date: Mon, 3 Dec 2018 23:09:40 +0000 Subject: [PATCH 03/10] Initial working POC of location filter portlet --- src/collective/collectionfilter/baseviews.py | 39 ++++++ .../collectionfilter/filteritems.py | 130 ++++++++++++++++++ src/collective/collectionfilter/interfaces.py | 25 ++++ .../collectionfilter/portlets/configure.zcml | 12 ++ .../portlets/locationfilter.pt | 38 +++++ .../portlets/locationfilter.py | 106 ++++++++++++++ .../portlets/profiles/default/portlets.xml | 5 + src/collective/collectionfilter/query.py | 7 + 8 files changed, 362 insertions(+) create mode 100644 src/collective/collectionfilter/portlets/locationfilter.pt create mode 100644 src/collective/collectionfilter/portlets/locationfilter.py diff --git a/src/collective/collectionfilter/baseviews.py b/src/collective/collectionfilter/baseviews.py index 1df1cc7c..15b01bd8 100644 --- a/src/collective/collectionfilter/baseviews.py +++ b/src/collective/collectionfilter/baseviews.py @@ -6,6 +6,7 @@ from Products.CMFPlone.utils import safe_unicode from collective.collectionfilter.filteritems import get_filter_items from collective.collectionfilter.query import make_query +from collective.collectionfilter.filteritems import get_location_filter_items from collective.collectionfilter.utils import base_query from collective.collectionfilter.utils import safe_decode from collective.collectionfilter.utils import safe_encode @@ -105,6 +106,44 @@ def results(self): return results +class BaseLocationView(BaseView): + + @property + def input_type(self): + if self.settings.input_type == 'links': + return 'link' + elif self.settings.filter_type == 'single': + if self.settings.input_type == 'checkboxes_radiobuttons': + return 'radio' + else: + return 'dropdown' + else: + return 'checkbox' + + def paths(self): + paths = [{'title':'Home', 'level': 0}] + params = self.top_request.form or {} + path = params.get('path', None) + if path is None: + return paths + level = 0 + for path in path.split('/'): + level += 1 + paths.append({'title': path, 'level': level}) + return paths + + def results(self): + results = get_location_filter_items( + target_collection=self.settings.target_collection, + filter_type=self.settings.filter_type, + narrow_down=self.settings.narrow_down, + view_name=self.settings.view_name, + cache_enabled=self.settings.cache_enabled, + request_params=self.top_request.form or {} + ) + return results + + class BaseSearchView(BaseView): @property diff --git a/src/collective/collectionfilter/filteritems.py b/src/collective/collectionfilter/filteritems.py index 621751f9..cb366903 100644 --- a/src/collective/collectionfilter/filteritems.py +++ b/src/collective/collectionfilter/filteritems.py @@ -235,3 +235,133 @@ def get_filter_items( ret += grouped_results return ret + + +# TODO: implement caching +def get_location_filter_items( + target_collection, + filter_type=DEFAULT_FILTER_TYPE, + narrow_down=False, + view_name='', + cache_enabled=True, + request_params=None +): + request_params = request_params or {} + custom_query = {} # Additional query to filter the collection + + collection = uuidToObject(target_collection) + if not collection: + return None + collection_url = collection.absolute_url() + collection_layout = collection.getLayout() + default_view = collection.restrictedTraverse(collection_layout) + + # Recursively transform all to unicode + request_params = safe_decode(request_params) + + # Support for the Event Listing view from plone.app.event + if isinstance(default_view, EventListing): + mode = request_params.get('mode', 'future') + date = request_params.get('date', None) + date = guess_date_from(date) if date else None + start, end = start_end_from_mode(mode, date, collection) + start, end = _prepare_range(collection, start, end) + custom_query.update(start_end_query(start, end)) + # TODO: expand events. better yet, let collection.results + # do that + + current_path_value = request_params.get('path') + urlquery = base_query(request_params) + + # Get all collection results with additional filter defined by urlquery + custom_query.update(urlquery) + custom_query = make_query(custom_query) + catalog_results = ICollection(collection).results( + batch=False, + brains=True, + custom_query=custom_query + ) + if not catalog_results: + return None + + filtered_path = '/'.join(list(plone.api.portal.get().getPhysicalPath()) + + (current_path_value and + current_path_value.split('/') or [])) + grouped_results = {} + for brain in catalog_results: + + # Get path, remove portal root from path, remove leading / + path = brain.getPath() + if path.startswith(filtered_path): + path = path[len(filtered_path)+1:] + + # If path is in the root, don't add anything to path + paths = path.split('/') + if len(paths) == 1: + continue + + first_path = paths[0] + if first_path in grouped_results: + # Add counter, if path is already present + grouped_results[first_path]['count'] += 1 + + # TODO: get title + title = first_path + + # Build filter url query + selected = first_path == current_path_value + _urlquery = urlquery.copy() + _urlquery['path'] = first_path + if selected is True and _urlquery.has_key('path'): + del _urlquery['path'] + + query_param = urlencode(safe_encode(_urlquery), doseq=True) + url = u'/'.join([it for it in [ + collection_url, + view_name, + '?' + query_param if query_param else None + ] if it]) + + + + css_class = 'filterItem {0}{1}'.format( + 'filter-' + idnormalizer.normalize(first_path), + ' selected' if selected else '' + ) + + grouped_results[first_path] = { + 'title': title, + 'url': url, + 'value': first_path, + 'css_class': css_class, + 'count': 1, + 'selected': selected + } + + # Entry to clear all filters + urlquery_all = { + k: v for k, v in urlquery.items() if k != 'path' + } + ret = [{ + 'title': translate( + _('location_reset', default=u'Reset'), context=getRequest() + ), + 'url': u'{0}/?{1}'.format( + collection_url, + urlencode(safe_encode(urlquery_all), doseq=True) + ), + 'value': 'all', + 'css_class': 'filterItem filter-all', + 'count': len(catalog_results), + 'selected': 'path' not in request_params + }] + + grouped_results = grouped_results.values() + + # TODO: sortable option + #if callable(sort_key_function): + # grouped_results = sorted(grouped_results, key=sort_key_function) + + ret += grouped_results + + return ret diff --git a/src/collective/collectionfilter/interfaces.py b/src/collective/collectionfilter/interfaces.py index df846338..183ae93d 100644 --- a/src/collective/collectionfilter/interfaces.py +++ b/src/collective/collectionfilter/interfaces.py @@ -157,6 +157,31 @@ class ICollectionSearchSchema(ICollectionFilterBaseSchema): """ +class ICollectionLocationFilterSchema(ICollectionFilterBaseSchema): + """Schema for the navigation filter. + """ + + show_count = schema.Bool( + title=_(u'label_show_count', default=u'Show count'), + description=_( + u'help_show_count', + default=u'Show the result count for each filter group.'), + default=False, + required=False + ) + + cache_enabled = schema.Bool( + title=_(u"label_cache_enabled", default=u"Enable Cache"), + description=_( + u'help_cache_enabled', + default=u"Enable caching of filter items. The cache is cleared as" + u" soon as the database has any changes." + ), + default=True, + required=False, + ) + + class IGroupByCriteria(Interface): """Interface for the GroupByCriteria utility. diff --git a/src/collective/collectionfilter/portlets/configure.zcml b/src/collective/collectionfilter/portlets/configure.zcml index 474075f5..fbc97a27 100644 --- a/src/collective/collectionfilter/portlets/configure.zcml +++ b/src/collective/collectionfilter/portlets/configure.zcml @@ -40,6 +40,18 @@ edit_permission="plone.app.portlets.ManagePortlets" /> + + + + + +
Title
+
+ + +
    + +
  • +
    +
+ + + +
+
+ diff --git a/src/collective/collectionfilter/portlets/locationfilter.py b/src/collective/collectionfilter/portlets/locationfilter.py new file mode 100644 index 00000000..861fe9b9 --- /dev/null +++ b/src/collective/collectionfilter/portlets/locationfilter.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +from .. import _ +from ..baseviews import BaseLocationView +from ..interfaces import ICollectionLocationFilterSchema +from plone.app.portlets.portlets import base +from plone.portlets.interfaces import IPortletDataProvider +from Products.CMFPlone.utils import get_top_request +from Products.CMFPlone.utils import getFSVersionTuple +from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile +from zope.component import queryUtility +from zope.interface import implementer + + +PLONE5 = getFSVersionTuple()[0] >= 5 + +if PLONE5: + base_AddForm = base.AddForm + base_EditForm = base.EditForm +else: + from plone.app.portlets.browser.z3cformhelper import AddForm as base_AddForm # noqa + from plone.app.portlets.browser.z3cformhelper import EditForm as base_EditForm # noqa + from z3c.form import field + + +class ICollectionLocationPortlet(ICollectionLocationFilterSchema, + IPortletDataProvider): + """Portlet interface based on ICollectionLocationFilterSchema + """ + + +@implementer(ICollectionLocationPortlet) +class Assignment(base.Assignment): + + header = u"" + target_collection = None + view_name = None + content_selector = '#content-core' + + def __init__( + self, + header=u"", + target_collection=None, + view_name=None, + content_selector='#content-core', + ): + self.header = header + self.target_collection = target_collection + self.view_name = view_name + self.content_selector = content_selector + + @property + def title(self): + if self.header: + return self.header + else: + return _(u'Collection Location Filter') + + +class Renderer(base.Renderer, BaseLocationView): + render = ViewPageTemplateFile('locationfilter.pt') + + @property + def filter_id(self): + request = get_top_request(self.request) + portlethash = request.form.get( + 'portlethash', + getattr(self, '__portlet_metadata__', {}).get('hash', '') + ) + return portlethash + + @property + def reload_url(self): + reload_url = '{0}/@@render-portlet?portlethash={1}'.format( + self.context.absolute_url(), + self.filter_id + ) + return reload_url + + +class AddForm(base_AddForm): + if PLONE5: + schema = ICollectionLocationFilterSchema + else: + fields = field.Fields(ICollectionLocationFilterSchema) + + label = _(u"Add Collection Location Filter Portlet") + description = _( + u"This portlet allows filtering of collection results based on their" + u"position in the site." + ) + + def create(self, data): + return Assignment(**data) + + +class EditForm(base_EditForm): + if PLONE5: + schema = ICollectionLocationFilterSchema + else: + fields = field.Fields(ICollectionLocationFilterSchema) + + label = _(u"Edit Collection Location Filter Portlet") + description = _( + u"This portlet allows filtering of collection results based on their" + u"position in the site." + ) diff --git a/src/collective/collectionfilter/portlets/profiles/default/portlets.xml b/src/collective/collectionfilter/portlets/profiles/default/portlets.xml index 8e85b16e..4df9fdfc 100644 --- a/src/collective/collectionfilter/portlets/profiles/default/portlets.xml +++ b/src/collective/collectionfilter/portlets/profiles/default/portlets.xml @@ -15,4 +15,9 @@ title="Collection Maps" description="This portlet allows map filtering in collection results." /> + diff --git a/src/collective/collectionfilter/query.py b/src/collective/collectionfilter/query.py index 07d68588..d7166aa4 100644 --- a/src/collective/collectionfilter/query.py +++ b/src/collective/collectionfilter/query.py @@ -6,6 +6,7 @@ from collective.collectionfilter.vocabularies import TEXT_IDX from logging import getLogger from zope.component import getUtility +import plone.api logger = getLogger('collective.collectionfilter') @@ -48,4 +49,10 @@ def make_query(params_dict): if TEXT_IDX in params_dict and params_dict.get(TEXT_IDX): query_dict[TEXT_IDX] = safe_decode(params_dict.get(TEXT_IDX)) + # Filter by path if passed in + if 'path' in params_dict: + additional_paths = params_dict['path'].split('/') + query_dict['path'] = {'query': '/'.join( + list(plone.api.portal.get().getPhysicalPath()) + additional_paths)} + return query_dict From edc5bbb8debbbe03d91557a1dc5ae380664ceffb Mon Sep 17 00:00:00 2001 From: Jon Pentland Date: Tue, 4 Dec 2018 15:32:05 +0000 Subject: [PATCH 04/10] Update styles. Add caching. Improve behaviour of portlet. --- src/collective/collectionfilter/baseviews.py | 27 +--- .../collectionfilter/filteritems.py | 122 ++++++++++++------ .../portlets/locationfilter.pt | 48 ++++--- .../resources/collectionfilter.less | 4 + 4 files changed, 113 insertions(+), 88 deletions(-) diff --git a/src/collective/collectionfilter/baseviews.py b/src/collective/collectionfilter/baseviews.py index 15b01bd8..cc62d99b 100644 --- a/src/collective/collectionfilter/baseviews.py +++ b/src/collective/collectionfilter/baseviews.py @@ -19,6 +19,7 @@ from six.moves.urllib.parse import urlencode from zope.component import queryUtility from zope.i18n import translate +import plone.api try: from collective.geolocationbehavior.interfaces import IGeoJSONProperties @@ -108,35 +109,9 @@ def results(self): class BaseLocationView(BaseView): - @property - def input_type(self): - if self.settings.input_type == 'links': - return 'link' - elif self.settings.filter_type == 'single': - if self.settings.input_type == 'checkboxes_radiobuttons': - return 'radio' - else: - return 'dropdown' - else: - return 'checkbox' - - def paths(self): - paths = [{'title':'Home', 'level': 0}] - params = self.top_request.form or {} - path = params.get('path', None) - if path is None: - return paths - level = 0 - for path in path.split('/'): - level += 1 - paths.append({'title': path, 'level': level}) - return paths - def results(self): results = get_location_filter_items( target_collection=self.settings.target_collection, - filter_type=self.settings.filter_type, - narrow_down=self.settings.narrow_down, view_name=self.settings.view_name, cache_enabled=self.settings.cache_enabled, request_params=self.top_request.form or {} diff --git a/src/collective/collectionfilter/filteritems.py b/src/collective/collectionfilter/filteritems.py index cb366903..cc2c988c 100644 --- a/src/collective/collectionfilter/filteritems.py +++ b/src/collective/collectionfilter/filteritems.py @@ -58,6 +58,25 @@ def _results_cachekey( return cachekey +def _location_results_cachekey( + method, + target_collection, + view_name, + cache_enabled, + request_params): + if not cache_enabled: + raise DontCache + cachekey = ( + target_collection, + view_name, + request_params, + ' '.join(plone.api.user.get_roles()), + plone.api.portal.get_current_language(), + str(plone.api.portal.get_tool('portal_catalog').getCounter()), + ) + return cachekey + + @ram.cache(_results_cachekey) def get_filter_items( target_collection, @@ -128,6 +147,8 @@ def get_filter_items( if not catalog_results: return None + #import pdb; pdb.set_trace() + # Attribute name for getting filter value from brain metadata_attr = groupby_criteria[group_by]['metadata'] # Optional modifier to set title from filter value @@ -237,11 +258,9 @@ def get_filter_items( return ret -# TODO: implement caching +@ram.cache(_location_results_cachekey) def get_location_filter_items( target_collection, - filter_type=DEFAULT_FILTER_TYPE, - narrow_down=False, view_name='', cache_enabled=True, request_params=None @@ -281,13 +300,34 @@ def get_location_filter_items( brains=True, custom_query=custom_query ) + + # Entry to clear all filters + urlquery_all = { + k: v for k, v in urlquery.items() if k != 'path' + } + ret = [{ + 'title': translate( + _('location_home', default=u'Home'), context=getRequest() + ), + 'url': u'{0}/?{1}'.format( + collection_url, + urlencode(safe_encode(urlquery_all), doseq=True) + ), + 'value': 'all', + 'css_class': 'navTreeItem filterItem filter-all selected', + 'count': len(catalog_results), + 'level': 0, + 'contenttype': 'folder' + }] + if not catalog_results: - return None + return ret - filtered_path = '/'.join(list(plone.api.portal.get().getPhysicalPath()) + - (current_path_value and - current_path_value.split('/') or [])) + portal = plone.api.portal.get() + qspaths = current_path_value and current_path_value.split('/') or [] + filtered_path = '/'.join(list(portal.getPhysicalPath()) + qspaths) grouped_results = {} + level = len(qspaths) + 1 for brain in catalog_results: # Get path, remove portal root from path, remove leading / @@ -304,17 +344,23 @@ def get_location_filter_items( if first_path in grouped_results: # Add counter, if path is already present grouped_results[first_path]['count'] += 1 + continue - # TODO: get title title = first_path + ctype = 'folder' + container = portal.portal_catalog.searchResults({'path': { + 'query': '/'.join(list(portal.getPhysicalPath()) + + qspaths + + [first_path]), + 'depth': 0, + }}) + if len(container) > 0: + title = container[0].Title + ctype = container[0].portal_type.lower() # Build filter url query - selected = first_path == current_path_value _urlquery = urlquery.copy() - _urlquery['path'] = first_path - if selected is True and _urlquery.has_key('path'): - del _urlquery['path'] - + _urlquery['path'] = '/'.join(qspaths + [first_path]) query_param = urlencode(safe_encode(_urlquery), doseq=True) url = u'/'.join([it for it in [ collection_url, @@ -322,11 +368,8 @@ def get_location_filter_items( '?' + query_param if query_param else None ] if it]) - - - css_class = 'filterItem {0}{1}'.format( - 'filter-' + idnormalizer.normalize(first_path), - ' selected' if selected else '' + css_class = 'navTreeItem filterItem {0}'.format( + 'filter-' + idnormalizer.normalize(first_path) ) grouped_results[first_path] = { @@ -335,30 +378,37 @@ def get_location_filter_items( 'value': first_path, 'css_class': css_class, 'count': 1, - 'selected': selected + 'level': level, + 'contenttype': ctype, } - # Entry to clear all filters - urlquery_all = { - k: v for k, v in urlquery.items() if k != 'path' - } - ret = [{ - 'title': translate( - _('location_reset', default=u'Reset'), context=getRequest() - ), - 'url': u'{0}/?{1}'.format( + # Add the selected paths + item = portal + level = 0 + for path in qspaths: + item = item.get(path, None) + if not item: + break + level += 1 + _urlquery = urlquery.copy() + _urlquery['path'] = '/'.join(qspaths[:qspaths.index(path) + 1]) + query_param = urlencode(safe_encode(_urlquery), doseq=True) + url = u'/'.join([it for it in [ collection_url, - urlencode(safe_encode(urlquery_all), doseq=True) - ), - 'value': 'all', - 'css_class': 'filterItem filter-all', - 'count': len(catalog_results), - 'selected': 'path' not in request_params - }] + view_name, + '?' + query_param if query_param else None + ] if it]) + ret.append({'title': item.Title(), + 'url': url, + 'value': path, + 'css_class': 'filter-%s selected' % idnormalizer.normalize(path), + 'count': len(catalog_results), + 'level': level, + 'contenttype': item.portal_type.lower()}) grouped_results = grouped_results.values() - # TODO: sortable option + # TODO: sortable option, probably should just sort by position in container #if callable(sort_key_function): # grouped_results = sorted(grouped_results, key=sort_key_function) diff --git a/src/collective/collectionfilter/portlets/locationfilter.pt b/src/collective/collectionfilter/portlets/locationfilter.pt index 7d8c99f6..c1cdff2f 100644 --- a/src/collective/collectionfilter/portlets/locationfilter.pt +++ b/src/collective/collectionfilter/portlets/locationfilter.pt @@ -1,5 +1,4 @@ - diff --git a/src/collective/collectionfilter/resources/collectionfilter.less b/src/collective/collectionfilter/resources/collectionfilter.less index b8233582..74a28d3d 100644 --- a/src/collective/collectionfilter/resources/collectionfilter.less +++ b/src/collective/collectionfilter/resources/collectionfilter.less @@ -113,3 +113,7 @@ padding: 0 0.5em; } } + +.locationFilter li.selected a > span{ + font-weight: bold; +} \ No newline at end of file From 0eac9022cf3539b1f520a239951fe476e5dd6b30 Mon Sep 17 00:00:00 2001 From: Jon Pentland Date: Tue, 4 Dec 2018 16:02:25 +0000 Subject: [PATCH 05/10] Remove debug trace --- src/collective/collectionfilter/filteritems.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/collective/collectionfilter/filteritems.py b/src/collective/collectionfilter/filteritems.py index cc2c988c..8022f94c 100644 --- a/src/collective/collectionfilter/filteritems.py +++ b/src/collective/collectionfilter/filteritems.py @@ -147,8 +147,6 @@ def get_filter_items( if not catalog_results: return None - #import pdb; pdb.set_trace() - # Attribute name for getting filter value from brain metadata_attr = groupby_criteria[group_by]['metadata'] # Optional modifier to set title from filter value From c598883d400d3695a0b030d0fa2636503a5e2ced Mon Sep 17 00:00:00 2001 From: Jon Pentland Date: Tue, 4 Dec 2018 16:03:19 +0000 Subject: [PATCH 06/10] Calculate results for each selected level --- .../collectionfilter/filteritems.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/collective/collectionfilter/filteritems.py b/src/collective/collectionfilter/filteritems.py index 8022f94c..f5f005bc 100644 --- a/src/collective/collectionfilter/filteritems.py +++ b/src/collective/collectionfilter/filteritems.py @@ -288,7 +288,7 @@ def get_location_filter_items( # do that current_path_value = request_params.get('path') - urlquery = base_query(request_params) + urlquery = base_query(request_params, ['path']) # Get all collection results with additional filter defined by urlquery custom_query.update(urlquery) @@ -322,8 +322,9 @@ def get_location_filter_items( return ret portal = plone.api.portal.get() + portal_path = portal.getPhysicalPath() qspaths = current_path_value and current_path_value.split('/') or [] - filtered_path = '/'.join(list(portal.getPhysicalPath()) + qspaths) + filtered_path = '/'.join(list(portal_path) + qspaths) grouped_results = {} level = len(qspaths) + 1 for brain in catalog_results: @@ -332,6 +333,8 @@ def get_location_filter_items( path = brain.getPath() if path.startswith(filtered_path): path = path[len(filtered_path)+1:] + else: + continue # If path is in the root, don't add anything to path paths = path.split('/') @@ -387,6 +390,18 @@ def get_location_filter_items( item = item.get(path, None) if not item: break + + # Get the results just in this subfolder + item_path = '/'.join(item.getPhysicalPath())[ + len('/'.join(portal_path))+1:] + custom_query = {'path': item_path} + custom_query.update(urlquery) + custom_query = make_query(custom_query) + catalog_results = ICollection(collection).results( + batch=False, + brains=True, + custom_query=custom_query + ) level += 1 _urlquery = urlquery.copy() _urlquery['path'] = '/'.join(qspaths[:qspaths.index(path) + 1]) From 9cac1f82cd55c026283ba469fdd8a70f025124d9 Mon Sep 17 00:00:00 2001 From: Jon Pentland Date: Tue, 4 Dec 2018 16:06:17 +0000 Subject: [PATCH 07/10] Update changes & readme --- CHANGES.rst | 3 +++ README.rst | 2 ++ 2 files changed, 5 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 4eb3d723..ee678078 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -133,6 +133,9 @@ New: - Make backwards compatible with Plone 5.0 [nngu6036, instification] +- Add Location Filter portlet. Allows to filter results based on location in site. + [instification] + Bug fixes: - When reloading the collection in JavaScript, use the content selector's parent as base to trigger events on. diff --git a/README.rst b/README.rst index e1d38f67..96fa2fd2 100644 --- a/README.rst +++ b/README.rst @@ -61,6 +61,8 @@ Simply do this somewhere in your buildout:: collective.collectionfilter[geolocation] ... +Besides the "Collection Filter" portlet/tile there is also a "Collection Search" portlet/tile for doing a fulltext search on the collection results and a "Location Filter" for filtering results based on their location in the site. + Overloading GroupByCriteria --------------------------- From dcf7d5c583b1b042d27d0e9ffbbf287c3273679f Mon Sep 17 00:00:00 2001 From: Jon Pentland Date: Wed, 5 Dec 2018 12:01:10 +0000 Subject: [PATCH 08/10] Bug fix - add show_count and cache_enabled option to portlet assignment --- src/collective/collectionfilter/portlets/locationfilter.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/collective/collectionfilter/portlets/locationfilter.py b/src/collective/collectionfilter/portlets/locationfilter.py index 861fe9b9..9b030dc6 100644 --- a/src/collective/collectionfilter/portlets/locationfilter.py +++ b/src/collective/collectionfilter/portlets/locationfilter.py @@ -42,11 +42,15 @@ def __init__( target_collection=None, view_name=None, content_selector='#content-core', + show_count=False, + cache_enabled=True ): self.header = header self.target_collection = target_collection self.view_name = view_name self.content_selector = content_selector + self.show_count = show_count + self.cache_enabled = cache_enabled @property def title(self): From c5100c90e1d126d9e75619f5ba187d7e25eed02e Mon Sep 17 00:00:00 2001 From: Jon Pentland Date: Fri, 28 Dec 2018 15:48:39 +0000 Subject: [PATCH 09/10] Make location filter 5.0.x compatible --- .../portlets/locationfilter.pt | 2 +- .../portlets/locationfilter.py | 35 +++++-------------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/collective/collectionfilter/portlets/locationfilter.pt b/src/collective/collectionfilter/portlets/locationfilter.pt index c1cdff2f..a6defa0c 100644 --- a/src/collective/collectionfilter/portlets/locationfilter.pt +++ b/src/collective/collectionfilter/portlets/locationfilter.pt @@ -1,4 +1,4 @@ -