diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index f5af7cd1..b3037bab 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -3,7 +3,6 @@ name: CI
on:
push:
branches-ignore:
- - "master"
- "releases/**"
jobs:
@@ -12,18 +11,52 @@ jobs:
strategy:
fail-fast: false
matrix:
- plone-version:
+ plone-version:
- '5.0'
- '5.1'
- '5.2'
- python-version: ['2.7']
- include:
- - plone-version: 5.2
+ python-version: ['2.7', '3.6', '3.7', '3.8']
+ layer:
+ - Portlet_AjaxDisabled
+ - Portlet_AjaxEnabled
+ - Tile
+ - unit
+ coverage: ['no_coverage', 'coverage']
+ exclude:
+ - plone-version: 5.0
+ layer: Tile # standardtiles 2.3.2 does support using the request to query. embed might still be possible
+ - plone-version: 5.0
+ layer: Portlet_AjaxEnabled # passes but meaningless as it skips all the tests
+ # Only 5.2+ runs on py3
+ - plone-version: 5.0
python-version: 3.6
- - plone-version: 5.2
+ - plone-version: 5.0
python-version: 3.7
- - plone-version: 5.2
+ - plone-version: 5.0
python-version: 3.8
+ - plone-version: 5.1
+ python-version: 3.6
+ - plone-version: 5.1
+ python-version: 3.7
+ - plone-version: 5.1
+ python-version: 3.8
+ # Save some time by not running all the robot tests
+ - python-version: 3.6
+ layer: Portlet_AjaxDisabled
+ - python-version: 3.7
+ layer: Portlet_AjaxDisabled
+ - python-version: 3.6
+ layer: Tile
+ - python-version: 3.7
+ layer: Tile
+ # save some time only running coverage on the 5.2 tests
+ - plone-version: 5.0
+ coverage: coverage
+ - plone-version: 5.1
+ coverage: coverage
+ - plone-version: 5.2
+ coverage: no_coverage
+
steps:
- uses: actions/checkout@v2
- name: Set up Python
@@ -35,13 +68,13 @@ jobs:
sudo apt-get update -y
# sudo apt-get install -y build-essentials
sudo apt-get install -y libxml2-dev libxslt-dev python-dev
- # sudo apt-get install py-pip
+ # sudo apt-get install py-pip
pip install \
virtualenv wheel
- uses: nanasess/setup-chromedriver@master
# with:
# # Optional: do not specify to match Chrome's version
- # chromedriver-version: '77.0.3865.40'
+ # chromedriver-version: '77.0.3865.40'
- name: Cache multiple paths
uses: actions/cache@v2
with:
@@ -49,10 +82,11 @@ jobs:
~/buildout-cache
~/extends
~/.cache/pip
- # key: ${{ runner.os }}-buildout-${{ hashFiles('**/*.cfg') }}-${{ matrix.plone-version }}-${{ matrix.python-version }}
- key: ${{ runner.os }}-buildout-${{ matrix.plone-version }}-${{ matrix.python-version }}
+ key: ${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.plone-version }}-${{ hashFiles('**/*.cfg') }}
restore-keys: |
- ${{ runner.os }}-buildout-
+ ${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.plone-version }}-
+ ${{ runner.os }}-${{ matrix.python-version }}-
+ ${{ runner.os }}-
- name: setup buildout cache
run: |
mkdir -p ~/buildout-cache/{eggs,downloads}
@@ -69,44 +103,67 @@ jobs:
bin/buildout -t 10 -Nc test-${{ matrix.plone-version }}.x.cfg
bin/pip install zest.pocompile
bin/pocompile src
- - name: test
+ - name: test robot
+ if: ${{ matrix.coverage != 'coverage' && matrix.layer != 'unit' }}
run: |
export DISPLAY=:99.0
chromedriver --url-base=/wd/hub &
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional
sleep 3
- bin/test --all
+ bin/test --all --layer ${{ matrix.layer }} --list-tests
+ bin/test --all --layer ${{ matrix.layer }}
+ - name: test unit
+ if: ${{ matrix.coverage != 'coverage' && matrix.layer == 'unit' }}
+ run: |
+ bin/test --unit --list-tests
+ bin/test --unit
+ - name: createcoverage
+ if: ${{ matrix.coverage == 'coverage' && matrix.layer != 'unit' }}
+ run: |
+ export DISPLAY=:99.0
+ chromedriver --url-base=/wd/hub &
+ sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional
+ sleep 3
+ bin/test --all --layer ${{ matrix.layer }} --list-tests
+ bin/createcoverage -t '--all --layer ${{ matrix.layer }}'
+ bin/coverage json -i
+ - name: createcoverage
+ if: ${{ matrix.coverage == 'coverage' && matrix.layer == 'unit' }}
+ run: |
+ bin/test --unit --list-tests
+ bin/createcoverage -t '--unit'
+ bin/coverage json -i
+ - name: Coveralls
+ if: ${{ matrix.coverage == 'coverage' }}
+ uses: AndreMiras/coveralls-python-action@develop
+ with:
+ parallel: true
+ flag-name: ${{ matrix.plone-version }}-${{ matrix.python-version }}-${{ matrix.layer }}
- name: code-analysis
- run: echo "${{ matrix.plone-version }}" | grep 5.1 || bin/code-analysis
+ if: always()
+ run: echo "${{ matrix.plone-version }}" | grep 5.1 || bin/code-analysis
+ - name: black
+ if: ${{ matrix.python-version == '3.8' }}
+ # black dropped Python2.7 support in 22.1.0 (it's first stable release)
+ run: |
+ pip install black==21.12b0
+ black --check src
- name: Artifact Robot Test Report
if: failure()
uses: actions/upload-artifact@v1
with:
- name: test_results
+ name: test_results-${{ matrix.python-version }}-${{ matrix.plone-version }}-${{ matrix.layer }}
path: ./parts/test
- uses: actions/setup-python@v2
if: failure()
with:
- python-version: 2.7
+ python-version: 2.7
- name: Robottest report
+ continue-on-error: true
if: failure()
run: |
pip2.7 install popt || pip2.7 install --user popt
grep --include=output.xml -Rl FAIL parts/test | xargs --no-run-if-empty -n 1 popt
- - name: createcoverage
- run: |
- export DISPLAY=:99.0
- chromedriver --url-base=/wd/hub &
- sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional
- sleep 3
- bin/createcoverage -t '--all'
- # bin/createcoverage
- bin/coverage json -i
- - name: Coveralls
- uses: AndreMiras/coveralls-python-action@develop
- with:
- parallel: true
- flag-name: ${{ matrix.plone-version }}-${{ matrix.python-version }}
coveralls_finish:
needs: build
diff --git a/CHANGES.rst b/CHANGES.rst
index 89cdcb47..01ef4c6d 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,7 +1,31 @@
Changelog
=========
-3.6 (unreleased)
+4.0 (unreleased)
+
+Breaking Change:
+
+- Add idx parameter to display_modifier call, so that we can use the index name to resolve the correct translated taxonomy titles in collective.taxonomy. This means that the display_modifier method in the groupby_modifier adapters needs to expect this parameter too!
+ [MrTango]
+
+Bug Fixes:
+
+- Fix edge cases where "All" wasn't translated.
+ [agitator]
+
+- Ensure a `GroupByCriteria`'s `sort_key_function` function `lower()` call gets a string.
+ [jensens]
+
+- Fixed searches for only non-alphanumeric characters causing an exception to be displayed.
+ [JeffersonBledsoe]
+
+Other:
+
+- Code-Style Black and Isort
+ [jensens]
+
+
+3.5.1 (2021-05-26)
----------------
- Updated de and ch-de translations
@@ -11,7 +35,7 @@ Changelog
3.5 (2021-05-26)
----------------
-- Use collection from context as default. `target_collection` is now used to select an alternative collection as result source.
+- Use collection from context as default. `target_collection` is now used to select an alternative collection as result source.
This allows to copy and paste preconfigured collections for reuse without reconfiguring each filter element.
[agitator]
diff --git a/README.rst b/README.rst
index 5241be7e..ca2210c5 100644
--- a/README.rst
+++ b/README.rst
@@ -13,11 +13,11 @@ collective.collectionfilter
:target: https://github.com/collective/collective.collectionfilter/actions
-Faceted navigation filter for collection results.
+Faceted navigation filter for collection or contentlisting tiles.
-This Plone 5 addon allows you to filter collections results for additional catalog metadata.
+This Plone 5 addon allows you to filter listing results for fields which are indexed in the catalog
+(Plones internal search tool).
For example, you can add a subject filter, but also a filter for authors or portal types.
-This can also be used to build tag clouds.
The filter types can be extended (see: ``collective.collectionfilter.vocabularies``).
@@ -35,27 +35,42 @@ There are three portlets/tiles available for filtering:
a list of indexes where the user can sort the filtered result listing
-Filter Results with portlets
+Filter Results of Collections
----------------------------
-Add as many of the filter portlets above to any context you want (most likely the source collection)
-and assign a collection with results to it.
+Add as many filter/search portlets directly to a collection.
-When you select values from the filter the results are loaded asynchronously inside the container
-with the selector defined in the field ``Content Selector``. Make sure the selector exists on the
-source collection template and on the target page which shows the filtered results.
+When you select values from the filter the results are loaded asynchronously onto the page (no page refresh).
+Unless you turn off ajax loading in the registery or are using Plone 5.0. If you are using special theme or view template
+you can customize ``Content Selector`` and/or ```View Template``` to ensure ajax loading works correctly.
+Make sure the selector exists on the source collection template and on the target page which shows the filtered results.
+
+It is also possible to use filter portlets that aren't directly on a collection by specifying a target collection.
+To use ajax loading you will need to ensure your content selector is visible on the page. If not using ajax loading selecting a filter
+option will redirect you to the collection.
Mosaic Integration
------------------
+Use the package extra to install the required dependencies::
+
+ [buildout]
+ ...
+ eggs +=
+ collective.collectionfilter[mosaic]
+ ...
+
The three tiles can be added within the Mosaic editor multiple times. Just select them in the ``Insert`` menu
and assign a collection to it. To show the results of the collection simply add a
-``Existing Content`` tile which links to the same collection your filter tiles are assigned with.
+``Content Listing`` tile.
+
+It's possible to use multiple content listings and multiple filters on the same page by specifying additional unique classes in
+the listing tiles settings and then adding these classes to the ``Content Selector`` setting of the filter tile.
+
+If you want to use filter tiles with a collection then add a content listing tile with the setting to use the query from the context.
+It is also possible to use the ``Embed content`` tile if there is a unique selector on your collection view.
-TODO: right now the collection needs a default_view template, which wraps the result list with a unique selector
-inside the ``#content-core`` container. so the collectionfilter can load the filtered result correctly from
-the collection into the container inside the existing content tile.
Geolocation filter support
@@ -129,12 +144,12 @@ Write an adapter::
@implementer(IGroupByModifier)
@adapter(IGroupByCriteria)
def groupby_modifier(groupby):
- groupby._groupby['Subject']['display_modifier'] = lambda x: x.upper()
+ groupby._groupby['Subject']['display_modifier'] = lambda x, idx: x.upper()
groupby._groupby['Subject']['sort_key_function'] = subjectsort
groupby._groupby['my_new_index'] = {
'index': 'my_new_index',
'metadata': 'my_new_index_metadata_colum',
- 'display_modifier': lambda it: u'this is awesome: {0}'.format(it)
+ 'display_modifier': lambda it, idx: u'this is awesome: {0}'.format(it)
}
Register the adapter::
diff --git a/base.cfg b/base.cfg
index e6c6ba0f..89d11bfb 100644
--- a/base.cfg
+++ b/base.cfg
@@ -1,14 +1,21 @@
[buildout]
-extensions = mr.developer
+# extensions = mr.developer
versions = versions
+[code-analysis]
+directory = ${buildout:directory}/src/collective/collectionfilter
+flake8-ignore = E501,E241,W503
+
[versions]
collective.collectionfilter =
collective.geolocationbehavior = >=1.6.0
plone.formwidget.geolocation = >=2.2.0
plone.patternslib = >=1.1.0
+plone.app.standardtiles = >= 2.4.0
+plone.batching = >=1.1.7
# plone.app.standardtiles = 2.3.1 # fix https://github.com/plone/plone.app.standardtiles/issues/111
+pycodestyle =
# Robot Testing (see buildout.coredev[5.2]/versions.cfg)
plone.app.robotframework = 1.5.4
@@ -22,5 +29,25 @@ robotframework-selenium2screenshots = 0.8.1
robotsuite = 2.2.1
selenium = 3.141.0
-[code-analysis]
-directory= ${buildout:directory}/src/collective/collectionfilter
+[versions:python27]
+# to get codeanalysis working
+build = 0.1
+coverage = 5.5
+
+# Required by:
+# build==0.1.0
+packaging = 20.8
+contextlib2 = 0.6.0.post1
+
+# Required by:
+# build==0.1.0
+typing = 3.7.4.3
+
+
+flake8 = 3.9.2
+configparser = <5.0.0
+
+flake8-pep3101 = 0.6
+flake8-commas = 0.1.6
+flake8-isort = 1.3
+flake8-deprecated = 1.0
diff --git a/buildout.cfg b/buildout.cfg
index 1a65a6da..a7fcd56b 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -63,3 +63,7 @@ eggs =
scripts =
plone-compile-resources
# zopepy
+
+
+[instance]
+eggs+= plone.staticresources
\ No newline at end of file
diff --git a/setup.py b/setup.py
index aa9dff61..0bf3687c 100644
--- a/setup.py
+++ b/setup.py
@@ -52,6 +52,10 @@ def read(*rnames):
"plone.app.contenttypes",
],
extras_require={
+ "mosaic": [
+ "plone.app.mosaic >= 2.2.3",
+ "plone.app.standardtiles >= 2.4.0",
+ ],
"geolocation": [
# support for latitude/longitude catalog index
"collective.geolocationbehavior >= 1.6.0",
diff --git a/src/collective/collectionfilter/baseviews.py b/src/collective/collectionfilter/baseviews.py
index dc0ad5c6..ad59990f 100644
--- a/src/collective/collectionfilter/baseviews.py
+++ b/src/collective/collectionfilter/baseviews.py
@@ -2,6 +2,7 @@
from Acquisition import aq_inner
from collective.collectionfilter import PLONE_VERSION
from collective.collectionfilter.filteritems import get_filter_items
+from collective.collectionfilter.filteritems import ICollectionish
from collective.collectionfilter.interfaces import IGroupByCriteria
from collective.collectionfilter.query import make_query
from collective.collectionfilter.utils import base_query
@@ -11,7 +12,6 @@
from collective.collectionfilter.vocabularies import TEXT_IDX
from plone import api
from plone.api.portal import get_registry_record as getrec
-from plone.app.contenttypes.behaviors.collection import ICollection
from plone.app.uuid.utils import uuidToCatalogBrain
from plone.app.uuid.utils import uuidToObject
from plone.i18n.normalizer.interfaces import IIDNormalizer
@@ -19,7 +19,7 @@
from plone.uuid.interfaces import IUUID
from Products.CMFPlone.utils import get_top_request
from Products.CMFPlone.utils import safe_unicode
-from six.moves.urllib.parse import urlencode
+from six.moves.urllib.parse import urlencode, parse_qsl
from zope.component import getUtility
from zope.component import queryUtility
from zope.i18n import translate
@@ -98,10 +98,24 @@ def pat_options(self):
"collectionUUID": self.collection_uuid,
"reloadURL": self.reload_url,
"ajaxLoad": self.ajax_load,
- "contentSelector": self.settings.content_selector,
+ "contentSelector": self.content_selector,
}
)
+ @property
+ def content_selector(self):
+ if self.settings.content_selector:
+ return self.settings.content_selector
+
+ collectionish = (
+ ICollectionish(self.collection.getObject()) if self.collection else None
+ )
+ selector = collectionish.content_selector
+ if collectionish is None or not selector:
+ return u"#content-core"
+ else:
+ return selector
+
@property
def ajax_load(self):
if PLONE_VERSION < "5.1":
@@ -142,6 +156,46 @@ def results(self):
view_name=self.settings.view_name,
cache_enabled=self.settings.cache_enabled,
request_params=self.top_request.form or {},
+ content_selector=self.settings.content_selector,
+ default_filtering_behaviour=self.settings.default_filtering_behaviour,
+ )
+
+ if (
+ self.request.response.headers.get("x-tile-url")
+ and self.request.get("PARENT_REQUEST") is None
+ ):
+ # We are in the edit mosaic page so we don't want to redirect
+ return results
+
+ # In the case of tiles we are in a subrequest (ie tile). We need to really redirect
+ req = self.request.get("PARENT_REQUEST", self.request)
+
+ # In order to handle filters with no "All" option we need redirect urls that
+ # haven't been processed yet picking default options for those filters
+ if getattr(req, "collectionfilter", None) or not results:
+ # assume we already fixed the params
+ return results
+
+ existing_query_string = req["QUERY_STRING"]
+ # Using `parse_qsl` then converting to a list as `parse_qs` ends up producing lists for the values
+ query_object = dict(parse_qsl(existing_query_string))
+
+ if self.settings.group_by not in query_object:
+ if self.settings.default_filtering_behaviour == "Select first":
+ query_object[self.settings.group_by] = results[0]["value"]
+ query_object["collectionfilter"] = 1
+
+ # if req['HTTP_COOKIE']:
+ # # when saving a tile the redirect hides teh status message.
+ # # The statusmessage is in HTTP_COOKIES but removed from req.cookies
+ # c = Cookie.Cookie()
+ # c.load(req['HTTP_COOKIE'])
+ # if "statusmessages" in c:
+ # # TODO: set using proper interface
+ # req.response.setCookie("statusmessages", c['statusmessages'].value)
+
+ req.response.redirect(
+ "%s?%s" % (req["ACTUAL_URL"], urlencode(safe_encode(query_object)))
)
return results
@@ -217,7 +271,11 @@ def ajax_url(self):
class BaseSortOnView(BaseView):
def results(self):
- collection = self.collection.getObject()
+ collection = ICollectionish(self.collection.getObject()).selectContent(
+ self.settings.content_selector
+ )
+ if collection is None:
+ return
curr_val = self.top_request.get("sort_on", collection.sort_on)
curr_order = self.top_request.get(
"sort_order", "descending" if collection.sort_reversed else "ascending"
@@ -298,8 +356,10 @@ def locations(self):
# defined by urlquery
custom_query = base_query(request_params)
custom_query = make_query(custom_query)
- return ICollection(collection).results(
- batch=False, brains=True, custom_query=custom_query
+ return (
+ ICollectionish(collection)
+ .selectContent(self.settings.content_selector)
+ .results(custom_query, request_params)
)
@property
diff --git a/src/collective/collectionfilter/configure.zcml b/src/collective/collectionfilter/configure.zcml
index 027c37ff..1871ad93 100644
--- a/src/collective/collectionfilter/configure.zcml
+++ b/src/collective/collectionfilter/configure.zcml
@@ -48,6 +48,10 @@
name="collective.collectionfilter.SortOnIndexes"
/>
+
+
Title
-
+
-
-
+
-
+
diff --git a/src/collective/collectionfilter/portlets/collectionfilter.py b/src/collective/collectionfilter/portlets/collectionfilter.py
index 9301d4d9..e4073e7e 100644
--- a/src/collective/collectionfilter/portlets/collectionfilter.py
+++ b/src/collective/collectionfilter/portlets/collectionfilter.py
@@ -28,6 +28,7 @@ class Assignment(base.Assignment):
view_name = None
content_selector = "#content-core"
hide_if_empty = False
+ default_filtering_behaviour = "Show all"
# list_scaling = None
def __init__(
@@ -43,6 +44,7 @@ def __init__(
view_name=None,
content_selector="#content-core",
hide_if_empty=False,
+ default_filtering_behaviour=True,
# list_scaling=None
):
self.header = header
@@ -56,6 +58,7 @@ def __init__(
self.view_name = view_name
self.content_selector = content_selector
self.hide_if_empty = hide_if_empty
+ self.default_filtering_behaviour = default_filtering_behaviour
# self.list_scaling = list_scaling
@property
diff --git a/src/collective/collectionfilter/portlets/profiles/uninstall/portlets.xml b/src/collective/collectionfilter/portlets/profiles/uninstall/portlets.xml
index b52499c8..eeae7405 100644
--- a/src/collective/collectionfilter/portlets/profiles/uninstall/portlets.xml
+++ b/src/collective/collectionfilter/portlets/profiles/uninstall/portlets.xml
@@ -9,11 +9,11 @@
addview="collective.collectionfilter.portlets.CollectionSearch"
/>
diff --git a/src/collective/collectionfilter/query.py b/src/collective/collectionfilter/query.py
index e6fc4a43..375185d3 100644
--- a/src/collective/collectionfilter/query.py
+++ b/src/collective/collectionfilter/query.py
@@ -10,6 +10,8 @@
from Products.CMFPlone.browser.search import quote_chars
from zope.component import getUtility
+from Products.CMFPlone.UnicodeSplitter.config import rxGlob_U
+
try:
from Products.CMFPlone.browser.search import quote
@@ -28,6 +30,8 @@ def quote(term):
def sanitise_search_query(query):
+ if not rxGlob_U.findall(query):
+ return u""
for char in ENCODED_BAD_CHARS:
query = query.replace(char, " ")
clean_query = [quote(token) for token in query.split()]
diff --git a/src/collective/collectionfilter/testing.py b/src/collective/collectionfilter/testing.py
index 253d8f6b..dc041935 100644
--- a/src/collective/collectionfilter/testing.py
+++ b/src/collective/collectionfilter/testing.py
@@ -13,6 +13,7 @@
from Products.PluginIndexes.BooleanIndex.BooleanIndex import BooleanIndex
import json
+import os
try:
@@ -89,7 +90,9 @@ def setUpPloneSite(self, portal):
"Document",
id="testdoc",
title=u"Test Document and Document đ",
- text=RichTextValue(u"Ein heiĂes Test Dokument"),
+ text=RichTextValue(
+ u"Ein heiĂes Test Dokument", "text/plain", "text/html"
+ ),
subject=[u"Sßper", u"Dokumänt"],
exclude_from_nav=False,
)
@@ -97,7 +100,9 @@ def setUpPloneSite(self, portal):
"Document",
id="testdoc2",
title=u"Page đ",
- text=RichTextValue(u"Ein heiBes Test Dokument"),
+ text=RichTextValue(
+ u"Ein heiBes Test Dokument", "text/plain", "text/html"
+ ),
subject=[u"Dokumänt"],
exclude_from_nav=True,
)
@@ -137,7 +142,7 @@ def setUpPloneSite(self, portal):
REMOTE_LIBRARY_BUNDLE_FIXTURE,
z2.ZSERVER_FIXTURE,
),
- name="CollectiveCollectionFilterLayer:AcceptanceTesting_AjaxEnabled",
+ name="CollectiveCollectionFilterLayer:AcceptanceTestingPortlet_AjaxEnabled",
)
@@ -154,5 +159,26 @@ def setUpPloneSite(self, portal):
REMOTE_LIBRARY_BUNDLE_FIXTURE,
z2.ZSERVER_FIXTURE,
),
- name="CollectiveCollectionFilterLayer:AcceptanceTesting_AjaxDisabled",
+ name="CollectiveCollectionFilterLayer:AcceptanceTestingPortlet_AjaxDisabled",
+)
+
+
+class CollectiveCollectionFilterTilesLayer(CollectiveCollectionFilterLayer):
+ def setUpPloneSite(self, portal):
+ os.environ["ROBOT_USE_TILES"] = "True"
+ super(CollectiveCollectionFilterTilesLayer, self).setUpPloneSite(portal)
+
+ def tearDownPloneSite(self, portal):
+ super(CollectiveCollectionFilterTilesLayer, self).tearDownPloneSite(portal)
+ del os.environ["ROBOT_USE_TILES"]
+
+
+TILES_FIXTURE = CollectiveCollectionFilterTilesLayer()
+COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_TILES = FunctionalTesting(
+ bases=(
+ TILES_FIXTURE,
+ REMOTE_LIBRARY_BUNDLE_FIXTURE,
+ z2.ZSERVER_FIXTURE,
+ ),
+ name="CollectiveCollectionFilterLayer:AcceptanceTesting_Tiles",
)
diff --git a/src/collective/collectionfilter/tests/profiles/testing/types/Collection.xml b/src/collective/collectionfilter/tests/profiles/testing/types/Collection.xml
new file mode 100644
index 00000000..e0e40df1
--- /dev/null
+++ b/src/collective/collectionfilter/tests/profiles/testing/types/Collection.xml
@@ -0,0 +1,20 @@
+
+
diff --git a/src/collective/collectionfilter/tests/robot/keywords.robot b/src/collective/collectionfilter/tests/robot/keywords.robot
index da70acc7..181678d8 100644
--- a/src/collective/collectionfilter/tests/robot/keywords.robot
+++ b/src/collective/collectionfilter/tests/robot/keywords.robot
@@ -4,16 +4,26 @@
Resource plone/app/robotframework/selenium.robot
Resource plone/app/robotframework/keywords.robot
Resource Selenium2Screenshots/keywords.robot
+Library OperatingSystem
+
*** Variables ***
${BROWSER} chrome
-
*** Keywords *****************************************************************
+Default Setup
+# Not passed in as variable by robotsuite as variables collected before layer setup
+ ${USE_TILES}= Get Environment Variable ROBOT_USE_TILES default=${False}
+ ${USE_TILES}= Set Test Variable ${USE_TILES}
+ open test browser
+ #Set Window Size ${1400} ${8000}
+
Default Teardown
Run Keyword If Test Failed Capture Page Screenshot
+ Run Keyword If Test Failed Log Source
+# Run Keyword If Test Failed Log Variables
Close all browsers
# --- Given ------------------------------------------------------------------
@@ -50,11 +60,69 @@ View Test Collection
Log in as site owner
Go to ${PLONE_URL}/testcollection
+Run Keyword by label
+ [Arguments] ${label} ${keyword} @{args}
+ # Possible to get 2 mosaic overlays with the same labels on page at once
+ ${xpath}= set variable //*[ @id=//label[.//*[normalize-space(text())='${label}'] or normalize-space(text()) ='${label}']/@for and not(ancestor::div[contains(@class, 'mosaic-overlay')])]
+ Wait until page contains element xpath=${xpath}
+ run keyword ${keyword} xpath=${xpath} @{args}
Click Input "${label}"
Wait until page contains element xpath=//input[@id=//label[.//*[normalize-space(text())='${label}'] or normalize-space(text()) ='${label}']/@for]
Click Element xpath=//input[@id=//label[.//*[normalize-space(text())='${label}'] or normalize-space(text()) ='${label}']/@for]
+Select InAndOut
+ [Arguments] ${label} @{values}
+ Wait until page contains element xpath=//label[.//*[normalize-space(text())='${label}'] or normalize-space(text()) ='${label}']
+ ${id}= Get Element Attribute xpath=//label[.//*[normalize-space(text())='${label}'] or normalize-space(text()) ='${label}'] for
+ FOR ${value} IN @{values}
+ Select from List by value css=select#${id}-from ${value}
+ Click element css=#${id} button[name='from2toButton']
+ END
+
+
+Select single select2
+ [Arguments] ${locator} ${value}
+ ${select2}= get webelement ${locator}
+ execute javascript $(arguments[0]).select2("open") ARGUMENTS ${select2}
+ wait until element is visible css=.select2-result-label
+ Click Element xpath=//div[contains(@class,'select2-result-label') and text() = '${value}']
+
+ #Click link link=Select criteria
+ #pause
+ #select from list by label xpath=(//div[@class='querystring-criteria-index'])[5]//select Type
+ #Click Element xpath=(//div[@class='querystring-criteria-index'])[5]//*[@class='select2-arrow']//a
+ # $($x("(//div[@class='querystring-criteria-index'])[5]/div")).select2("val", "portal_type").trigger("change")
+
+
+Select multi select2
+ [Arguments] ${locator} @{values}
+ # select2-choices select2-search-field select2-input
+ #select from list by label xpath=(//select[@class='querystring-criteria-value-MultipleSelectionWidget'])[1] Event
+ #select from list by label xpath=(//select[@class='querystring-criteria-value-MultipleSelectionWidget'])[1] Page
+ ${select2}= get webelement ${locator}
+ execute javascript $(arguments[0]).select2("val",arguments[1]) ARGUMENTS ${select2} ${values}
+ FOR ${value} IN @{values}
+ # Hack to only find those in the tile popup up not the mosaic popup
+ #\ wait until element is visible //*[contains(@class,'plone-modal ')]//li[@class='select2-search-choice']//*[contains(text(), '${value}')]
+ Wait until keyword succeeds 5s 1s call method ${select2} find_elements by=xpath value=.//li[@class='select2-search-choice']//*[contains(text(), '${value}')]
+ END
+
+ # Click Element xpath=(//div[@class='querystring-criteria-value'])[3]//input
+ # wait until element is visible css=.select2-result-label
+ # Click Element xpath=//div[contains(@class,'select2-result-label') and text() = 'Event']
+ # Click Element xpath=(//div[@class='querystring-criteria-value'])[3]//input
+ # wait until element is visible css=.select2-result-label
+ # Click Element xpath=//div[contains(@class,'select2-result-label') and text() = 'Page']
+
+select multi select2 with label
+ [Arguments] ${label} @{values}
+ # select2 don't have proper labels because the @for doesn't match an id of anything
+ ${xpath}= set variable //label[normalize-space(text()) ='${label}']/following-sibling::div[contains(@class,'select2-container')]
+ Wait until page contains element xpath=${xpath}
+ run keyword select multi select2 xpath=${xpath} @{values}
+
+
Click Button with text
[Arguments] ${text} ${pos}=1
Wait until page contains element xpath=(//*[@type="submit" and (normalize-space(@value)='${text}' or normalize-space(text())='${text}')])[${pos}]
@@ -79,6 +147,19 @@ Select related filter collection
Wait until page contains element partial link=Test Collection
Click element partial link=Test Collection
+_Click dropdown option "${option}"
+ ${value} = Get Substring ${option} 9 # 9 characters in `dropdown_`
+ Click element css=option[value="${value}"]
+
+Set Options
+ [Arguments] @{options}
+ FOR ${option} IN @{options}
+ Run Keyword If 'dropdown_' in '${option}' _Click dropdown option "${option}"
+ ... ELSE Click Input "${option}"
+ END
+
+# ---- CF stuff
+
Add search portlet
Wait until page contains element css=select.add-portlet
Select From List by label css=select.add-portlet Collection Search
@@ -90,7 +171,7 @@ Add search portlet
Wait until page contains element xpath=//div[@class='portletAssignments']//a[text()='Searchable Text']
Add filter portlet
- [Arguments] ${group_criteria} ${filter_type} ${input_type}
+ [Arguments] ${group_criteria} ${filter_type} ${input_type} @{options}
Wait until page contains element css=select.add-portlet
Select From List by label css=select.add-portlet Collection Filter
@@ -98,13 +179,25 @@ Add filter portlet
Input text css=input#form-widgets-header ${group_criteria}
#Select related filter collection
- Select from List by value css=select#form-widgets-group_by ${group_criteria}
- Click Input "Show count"
- Select from List by value css=select#form-widgets-filter_type ${filter_type}
- Select from List by value css=select#form-widgets-input_type ${input_type}
+ Set Filter Options ${group_criteria} ${filter_type} ${input_type} @{options}
+ # Select from List by value css=select#form-widgets-group_by ${group_criteria}
+ # Click Input "Show count"
+ # Select from List by value css=select#form-widgets-filter_type ${filter_type}
+ # Select from List by value css=select#form-widgets-input_type ${input_type}
Click element css=.plone-modal-footer input#form-buttons-add
Wait until page contains element xpath=//div[contains(@class, 'portletAssignments')]//a[text()='${group_criteria}']
+
+Set Filter Options
+ [Arguments] ${group_by} ${filter_type} ${input_type} @{options}
+
+ Run Keyword by label Group by Select from List by value ${group_by}
+ Run Keyword by label Filter Type Select from List by value ${filter_type}
+ Run Keyword by label Input Type Select from List by value ${input_type}
+ Set Options @{options}
+ Click Input "Show count"
+
+
Add sorting portlet
[Arguments] ${sort_on} ${input_type}
@@ -113,37 +206,81 @@ Add sorting portlet
Wait until element is visible css=input#form-widgets-header
Input text css=input#form-widgets-header Sort on
- Select from List by value css=select#form-widgets-sort_on-from ${sort_on}
- Click element css=#form-widgets-sort_on button[name='from2toButton']
- Select from List by value css=select#form-widgets-input_type ${input_type}
+
+ Set Sorting Options ${sort_on} ${input_type}
+
Click element css=.plone-modal-footer input#form-buttons-add
Wait until page contains element xpath=//div[contains(@class, 'portletAssignments')]//a[text()='Sort on']
+Set sorting Options
+ [Arguments] ${sort_on} ${input_type}
+ #Run keyword by label Enabled sort indexes select multi select2 ${sort_on}
+ select multi select2 with label Enabled sort indexes ${sort_on}
+ Run Keyword by label Input Type Select from List by value ${input_type}
+
+
+Add Info portlet
+ [Arguments] ${header} @{templates} ${hide_when}=${None}
+
+ Wait until page contains element css=select.add-portlet
+ Select From List by label css=select.add-portlet Collection Filter Search Info
+ Wait until element is visible css=input#form-widgets-header
+
+ Input text css=input#form-widgets-header ${header}
+ Set Info Settings form-widgets @{templates} hide_when=${hide_when}
+ Click element css=.plone-modal-footer input#form-buttons-add
+ Wait until page contains element xpath=//div[contains(@class, 'portletAssignments')]//a[text()='${header}']
+
+
+
Should be ${X} filter options
- Wait until keyword succeeds 5s 1s Page Should Contain Element xpath=//div[contains(@class, 'filterContent')]//*[contains(@class, 'filterItem')] limit=${X}
+ Wait until keyword succeeds 2s 1s Page Should Contain Element xpath=//div[contains(@class, 'filterContent')]//*[contains(@class, 'filterItem')] limit=${X}
+
+Should be filter options
+ [Arguments] @{values}
+ Wait until keyword succeeds 2s 1s List Labels Should Equal xpath=//div[contains(@class, 'filterContent')]//select @{values}
+
+Should be filter checkboxes
+ [Arguments] @{values}
+ Wait until keyword succeeds 2s 1s Labels Should Equal xpath=//div[contains(@class, 'filterContent')]//span[@class='filterLabel'] @{values}
+
+List Labels Should Equal
+ [Arguments] ${selector} @{expect}
+ @{options}= get list items ${selector}
+ Should Be Equal ${expect} ${options}
+
+Labels Should Equal
+ [Arguments] ${selector} @{expect}
+ @{locators}= Get Webelements ${selector}
+ ${result}= Create List
+ FOR ${locator} IN @{locators}
+ ${name}= Get Text ${locator}
+ Append To List ${result} ${name}
+ END
+ Should Be Equal ${expect} ${result}
Should be ${X} collection results
- Wait until element is visible css=#content-core
- Wait until keyword succeeds 5s 1s Page Should Contain Element xpath=//article[@class='entry'] limit=${X}
+ # Wait until element is visible css=#content-core
+ # below should work for both collections and contentlisting tiles
+ Wait until keyword succeeds 5s 1s Page Should Contain Element xpath=//span[@class='summary'] limit=${X}
Should be ${X} pages
${X}= evaluate ${X} + 1 # need we have next or previous
Wait until keyword succeeds 5s 1s Page Should Contain Element xpath=//nav[@class='pagination']//a limit=${X}
-Set Batch Size
- [Arguments] ${batch_size}
+Should be Info with text: ${text}
+ wait until element contains css=.filterInfoContent ${text}
- Go to ${PLONE_URL}/testcollection/edit
- Input text css=input#form-widgets-ICollection-item_count ${batch_size}
- Click element css=input#form-buttons-save
- Go to ${PLONE_URL}/testcollection
+# TODO: there is a bug where the aside.collectionInfo is still visible on screen.
+Should be no Info
+ wait until element is not visible css=.filterInfoContent
-Set portlet "${title}" "${checkbox}"
- Click Link ${title}
- Click Input "${checkbox}"
- Click element css=.plone-modal-footer input#form-buttons-apply
- Wait until page does not contain element css=.plone-modal-dialog
+# Set portlet "${title}" "${checkbox}"
+# Click Link ${title}
+# Click Input "${checkbox}"
+# Click element css=.plone-modal-footer input#form-buttons-apply
+# Wait until page does not contain element css=.plone-modal-dialog
Click Page "${page}"
Click element xpath=//nav[@class='pagination']//a[${page}]
@@ -153,8 +290,39 @@ Ajax has completed
# --- Setup -------------------------------------------------------------------
I've got a site with a collection
+ [arguments] ${batch}=20
Log in as site owner
- Go to ${PLONE_URL}/testcollection
+ run keyword if ${USE_TILES} run keyword Enable mosaic layout for page ${PLONE_URL}/testdoc batch=${batch}
+ run keyword unless ${USE_TILES} Go to ${PLONE_URL}/testcollection
+ run keyword unless ${USE_TILES} Set Batch Size ${batch}
+
+I've got a site without a listing
+ I've got a site with a collection 0
+
+My collection has a collection search
+ run keyword if ${USE_TILES} My collection has a collection search tile
+ run keyword unless ${USE_TILES} My collection has a collection search portlet
+
+My collection has a collection filter
+ [Arguments] ${group_by}=Subject ${op}=or ${style}=checkboxes_dropdowns @{options}
+ run keyword if ${USE_TILES} My collection has a collection filter tile ${group_by} ${op} ${style} @{options}
+ run keyword unless ${USE_TILES} My collection has a collection filter portlet ${group_by} ${op} ${style} @{options}
+
+My collection has a collection sorting
+ [Arguments] ${sort_on}=sortable_title
+ run keyword if ${USE_TILES} My collection has a collection sorting tile ${sort_on}
+ run keyword unless ${USE_TILES} My collection has a collection sorting portlet ${sort_on}
+
+My collection has a collection info
+ [Arguments] ${header}="Current Filter" @{templates} ${hide_when}=${None}
+ run keyword if ${USE_TILES} My collection has a collection info tile ${header} @{templates} hide_when=${hide_when}
+ run keyword unless ${USE_TILES} My collection has a collection info portlet ${header} @{templates} hide_when=${hide_when}
+
+I'm viewing the collection
+ run keyword if ${USE_TILES} Go to ${PLONE_URL}/testdoc
+ run keyword unless ${USE_TILES} Go to ${PLONE_URL}/testcollection
+ # Should be 3 collection results
+
My collection has a collection search portlet
Go to ${PLONE_URL}/testcollection
@@ -162,11 +330,11 @@ My collection has a collection search portlet
Add search portlet
My collection has a collection filter portlet
- [Arguments] ${group_by}=Subject ${op}=or ${style}=checkboxes_dropdowns
+ [Arguments] ${group_by}=Subject ${op}=or ${style}=checkboxes_dropdowns @{options}
Go to ${PLONE_URL}/testcollection
Manage portlets
- Add filter portlet ${group_by} ${op} ${style}
+ Add filter portlet ${group_by} ${op} ${style} @{options}
My collection has a collection sorting portlet
[Arguments] ${sort_on}=sortable_title
@@ -175,11 +343,38 @@ My collection has a collection sorting portlet
Manage portlets
Add sorting portlet ${sort_on} links
-I'm viewing the collection
+My collection has a collection info portlet
+ [Arguments] ${header}="Current Filter" @{templates} ${hide_when}=${None}
+
Go to ${PLONE_URL}/testcollection
- Should be 3 collection results
+ Manage portlets
+ Add info portlet ${header} @{templates} hide_when=${hide_when}
+
+Open collection settings
+
+movable removable mosaic-tile
+Set Batch Size
+ [Arguments] ${batch_size}
+
+ run keyword unless ${USE_TILES} Go to ${PLONE_URL}/testcollection/edit
+ run keyword if ${USE_TILES} Edit Listing Tile
+ Run keyword by label Item count Input Text ${batch_size}
+ Click Button Save
+ run keyword if ${USE_TILES} Click Button Save
+ # Go to ${PLONE_URL}/testcollection
+
+Edit Listing Tile
+ Go to ${PLONE_URL}/testdoc/edit
+ #Wait until page contains element css=.mosaic-btn-delete
+ #Wait until page contains element css=#mosaic-panel
+ Wait Until Element Is Visible css=.mosaic-toolbar
+ #Unselect Frame
+ #mouse over css=.mosaic-plone.app.standardtiles.contentlisting-tile
+ click element css=.contentlisting-tile
+ Edit Current Tile
+
# --- Core Functionality ------------------------------------------------------
I search for "${search}" with ajax
Wait until element is not visible css=.collectionSearch button[type='submit'] timeout=5 sec
@@ -203,6 +398,13 @@ I should have a portlet titled "${filter_title}" with ${number_of_results} filte
Page Should Contain Element xpath=//${portlet_title_xpath}
Wait until keyword succeeds 5s 1s Page Should Contain Element xpath=//${portlet_title_xpath}/parent::*[contains(@class, 'collectionFilter')]//${filter_item_xpath} limit=${number_of_results}
+I should have a filter with ${number_of_results} options
+ Wait until keyword succeeds 5s 1s Page Should Contain Element xpath=//aside[contains(@class,'collectionFilter') and count(.//div[contains(@class, 'filterContent')]//li[contains(@class, 'filterItem')])=${number_of_results} ] limit=1
+
+I should see ${number} filter options on the page
+ Page should contain element xpath=//aside[contains(@class,'collectionFilter') ]//div[contains(@class, 'filterContent')]//li[contains(@class, 'filterItem')] limit=${number}
+
+
I should not have a portlet titled "${filter_title}"
${portlet_title_xpath} Convert to string header[@class='portletHeader' and descendant-or-self::*[contains(text(), '${filter_title}')]]
@@ -210,32 +412,81 @@ I should not have a portlet titled "${filter_title}"
I should not see any results
- Sleep 1 sec
- Element should be visible xpath=//*[@id="content-core"]/*[text()="No results were found."]
+ Wait until keyword succeeds 5s 1s Element should be visible xpath=//*[@id="content-core"]/*[text()="No results were found."]
+
+I should have a portlet titled "${filter_title}" with text ${text}
+ ${portlet_title_xpath} Convert to string header[@class='portletHeader' and contains(text(), '${filter_title}')]
+ ${filter_item_xpath} Convert to string div[contains(@class, 'portletContent')]
+
+ Page Should Contain Element xpath=//${portlet_title_xpath}
+ Wait Until Element Contains xpath=//${portlet_title_xpath}/parent::*[contains(@class, 'collectionFilterInfo')]//${filter_item_xpath} ${text}
I sort by "${sort_on}"
- Wait until element is visible css=.collectionSortOn
+ Wait until element is visible xpath=//span[contains(normalize-space(text()), '${sort_on}')]
+ ${glyph}= Get Element Attribute xpath=//span[contains(normalize-space(text()), '${sort_on}')]//span class
+ Click Link link=${sort on}
+ Wait until element is not visible xpath=//span[contains(normalize-space(text()), '${sort_on}')]//span[@class='${glyph}']
+
+Results Are Sorted
+ ${xpath}= Set Variable //span[@class='summary']
+ ${count}= Get Element Count xpath=${xpath}
+ ${names}= Create List
+ FOR ${i} IN RANGE 1 ${count} + 1
+ ${name}= Get Text xpath=(${xpath})[${i}]
+ Append To List ${names} ${name}
+ END
+
+ ${sorted}= copy list ${names} False
+ sort list ${sorted}
+ log many ${sorted} ${names}
+ run keyword if $sorted!=$names Fail Results are not sorted ${sorted}!=${names}
- Click Element css=.collectionSortOn .sortItem .${sort_on}
- Wait until keyword succeeds 5s 1s Page Should Contain Element css=.collectionSortOn .sortItem.selected .${sort_on} span.glyphicon-sort-by-attributes
+# --- Tiles -------------------------------------------------------------------
- Click Element css=.collectionSortOn .sortItem .${sort_on}
- Wait until keyword succeeds 5s 1s Page Should Contain Element css=.collectionSortOn .sortItem.selected .${sort_on} span.glyphicon-sort-by-attributes-alt
-should be no errors
+My collection has a collection filter tile
+ [Arguments] ${group_by}=Subject ${op}=or ${style}=checkboxes_dropdowns @{options}
+
+ Go to ${PLONE_URL}/testdoc/edit
+ Add filter tile ${group_by} ${op} ${style} @{options}
+ Save mosaic page
+
+My collection has a collection search tile
+
+ Go to ${PLONE_URL}/testdoc/edit
+ Add search tile
+ Save mosaic page
+
+My collection has a collection info tile
+ [Arguments] ${header} @{templates} ${hide_when}=${None}
+
+ Go to ${PLONE_URL}/testdoc/edit
+ Add info tile @{templates} hide_when=${hide_when}
+ Save mosaic page
+
+My collection has a collection sorting tile
+ [Arguments] ${sort_on}
+ Go to ${PLONE_URL}/testdoc/edit
+ Insert Tile "Collection Result Listing Sort"
+ Set Sorting Options ${sort_on} links
+ # Run Keyword by label Content Selector Input Text .contentlisting-tile
+ Click element css=.pattern-modal-buttons #buttons-save
+ Drag tile
+# Click button Edit
+ Save mosaic page
-# --- Tiles -------------------------------------------------------------------
Enable mosaic layout for page
- [Arguments] ${page}
+ [Arguments] ${page}=${PLONE_URL}/testdoc ${batch}=20
+ go to ${page}
# Setup Mosaic display and open editor
Click element link=Display
Wait Until Element Is visible css=#plone-contentmenu-display-layout_view
Click element link=Mosaic layout
Go to ${page}/edit
- # Create default layout
+ # Create default layout if its a Page
Wait Until Element Is Visible css=.mosaic-select-layout
Wait until Page contains element xpath=//a[@data-value='default/basic.html']
Click element xpath=//a[@data-value='default/basic.html']
@@ -246,60 +497,131 @@ Enable mosaic layout for page
Wait Until Element Is visible css=.mosaic-button-customizelayout
Click element css=.mosaic-button-customizelayout
+ # Add a embed content tile pointing to the collection
+ #Add existing content tile /testdoc
+ run keyword if ${batch} > 0 Add contentlisting tile ${batch}
+
Save mosaic page
+Edit mosaic page
+ [Arguments] ${page}=${PLONE_URL}/testdoc
+ Go to ${page}/edit
+ Wait Until Element Is Visible css=.mosaic-toolbar
+
Save mosaic page
Wait Until Element Is Visible css=.mosaic-button-save timeout=5 sec
Click button css=.mosaic-button-save
- Wait until page contains Changes saved timeout=10 sec
+ # HACK: Due to bug. If you save it once it works? https://github.com/plone/plone.app.mosaic/issues/421
+ # You get a "do you want to leave site" popup
+ run keyword and ignore error alert should not be present timeout=1 sec
+ # Wait until page contains Changes saved timeout=2 sec
+
+
+# Save mosaic page
+# Wait Until Element Is Visible css=.mosaic-button-save timeout=5 sec
+# Click button css=.mosaic-button-save
+# Wait until page contains Changes saved timeout=2 sec
+
Add filter tile
- [Arguments] ${collection_name} ${filter_type} ${input_type}
+ [Arguments] ${group_by} ${filter_type} ${input_type} @{options}
- # Insert content filter
- Wait Until Element Is Visible css=.mosaic-toolbar
- Click element css=.select2-container.mosaic-menu-insert a
- Wait until element is visible xpath=//li[contains(@class, "select2-result-selectable") and div/text() = "Collection Filter"]
- Click element xpath=//li[contains(@class, "select2-result-selectable") and div/text() = "Collection Filter"]
+ Insert Tile "Collection Filter"
+ Drag tile
+ Edit Current Tile
+# Wait until element is visible xpath=//div[@class='plone-modal-dialog' and .//*[contains(text(), 'Collection')]]
+ #run keyword if $collection_name set relateditem formfield-collective-collectionfilter-tiles-filter-target_collection ${collection_name}
+
+ Set Filter Options ${group_by} ${filter_type} ${input_type} @{options}
+ # Run Keyword by label Content Selector Input Text .contentlisting-tile
- # Complete filter form
- Wait until element is visible xpath=//div[@class='plone-modal-dialog' and .//*[contains(text(), 'Collection')]]
- Click element xpath=//div[@id='formfield-collective-collectionfilter-tiles-filter-target_collection']//ul[@class='select2-choices']
- Wait until element is visible xpath=//div[@id='select2-drop']//a[.//text() = '/${collection_name}']
- Click element xpath=//div[@id='select2-drop']//a[.//text() = '/${collection_name}']
- Select from List by value css=select#collective-collectionfilter-tiles-filter-group_by ${filter_type}
- Select from List by value css=select#collective-collectionfilter-tiles-filter-input_type ${input_type}
Click element css=.pattern-modal-buttons #buttons-save
- Drag tile
Add search tile
- [Arguments] ${collection_name}
+ [Arguments] ${collection_name}=${None}
- # Insert collection search
- Wait Until Element Is Visible css=.mosaic-toolbar
- Click element css=.select2-container.mosaic-menu-insert a
- Wait until element is visible xpath=//li[contains(@class, "select2-result-selectable") and div/text() = "Collection Search"]
- Click element xpath=//li[contains(@class, "select2-result-selectable") and div/text() = "Collection Search"]
+ Insert tile "Collection Search"
+ Drag tile
+ Edit Current Tile
+ run keyword if $collection_name set relateditem formfield-collective-collectionfilter-tiles-search-target_collection ${collection_name}
+ # Run Keyword by label Content Selector Input Text .contentlisting-tile
+ Click element css=.pattern-modal-buttons #buttons-save
+
+
+Add info tile
+ [Arguments] @{templates} ${hide_when}=${None} ${collection_name}=${None}
+ Insert tile "Collection Filter Info"
+ run keyword if $collection_name set relateditem formfield-collective-collectionfilter-tiles-info-target_collection ${collection_name}
# Complete filter form
- Wait until element is visible xpath=//div[@class='plone-modal-dialog' and .//*[contains(text(), 'Collection')]]
- Wait until element is visible css=#collective-collectionfilter-tiles-search-header
- Click element xpath=//div[@id='formfield-collective-collectionfilter-tiles-search-target_collection']//ul[@class='select2-choices']
- Wait until element is visible xpath=//div[@id='select2-drop']//a[.//text() = '/${collection_name}']
- Click element xpath=//div[@id='select2-drop']//a[.//text() = '/${collection_name}']
+ Set Info Settings collective-collectionfilter-tiles-info @{templates} hide_when=${hide_when}
+ # Run Keyword by label Content Selector Input Text .contentlisting-tile
+
Click element css=.pattern-modal-buttons #buttons-save
+ Drag tile
+
+Set Info Settings
+ [Arguments] ${prefix} @{templates} ${hide_when}
+
+ select multi select2 with label Template Type @{templates}
+ Run keyword if $hide_when is not ${None} Run Keyword select multi select2 with label Hide when ${hide_when}
+
+
+
+Add existing content tile
+ [Arguments] ${collection_name}=${None}
+ Insert tile "Existing Content"
+ run keyword if $collection_name set relateditem formfield-plone-app-standardtiles-existingcontent-content_uid ${collection_name}
+ Click element css=.pattern-modal-buttons #buttons-save
+
+ Drag tile
+
+Add contentlisting tile
+ [Arguments] ${batch}=20
+ Insert tile "Content listing"
Drag tile
+ Edit Current Tile
+ # TODO: test using this method
+ # Run Keyword by label Use query parameters from content click element
+
+ # Since we aren't using the collection we need to recreate the same settings clickin on select2
+ wait until element is visible link=Select criteria
+ select single select2 xpath=(//div[@id='formfield-plone-app-standardtiles-contentlisting-query']//div[@class='querystring-criteria-index'])[2]/div Type
+ select multi select2 xpath=(//div[@id='formfield-plone-app-standardtiles-contentlisting-query']//div[@class='querystring-criteria-value'])[2]/div Event Document
+ # TODO: no item count in plone 5.0
+ Run Keyword by label Item count Input Text ${batch}
+
+ Click element css=.pattern-modal-buttons #buttons-save
+
+Edit Current Tile
+ Click Button css=.mosaic-selected-tile .mosaic-btn-settings
+
Drag tile
Wait until page contains element css=.mosaic-helper-tile-new
Wait until element is visible css=.mosaic-helper-tile-new
Update element style css=.mosaic-IDublinCore-description-tile .mosaic-divider-bottom display block
- Mouse over css=.mosaic-IDublinCore-description-tile .mosaic-divider-bottom
+ Mouse over xpath=(//*[contains(@class,'movable')])[last()-1]
Click element css=.mosaic-selected-divider
+ #Click element xpath=(//*[contains(@class,'movable')])[last()-1]
Filter by
[Arguments] ${filter}
Wait until element is visible css=.filterContent
Select from List by value xpath=//div[@class = 'filterContent']//select ${filter}
+
+# TODO: doesn't work yet
+Set relateditem
+ [Arguments] ${id} ${path}
+ Wait until element is visible xpath=//div[@id='${id}']
+ Click element xpath=//div[@id='${id}']//ul[@class='select2-choices']
+ Wait until element is visible xpath=//div[@id='select2-drop']//a[.//text() = '${path}']
+ Click element xpath=//div[@id='select2-drop']//a[.//text() = '${path}']
+
+Insert Tile "${name}"
+ Wait Until Element Is Visible css=.mosaic-toolbar
+ Click element css=.select2-container.mosaic-menu-insert a
+ Wait until element is visible xpath=//li[contains(@class, "select2-result-selectable") and div/text() = "${name}"]
+ Click element xpath=//li[contains(@class, "select2-result-selectable") and div/text() = "${name}"]
diff --git a/src/collective/collectionfilter/tests/robot/test_filterportlets.robot b/src/collective/collectionfilter/tests/robot/test_filterportlets.robot
index dd610eb2..9c0e18be 100644
--- a/src/collective/collectionfilter/tests/robot/test_filterportlets.robot
+++ b/src/collective/collectionfilter/tests/robot/test_filterportlets.robot
@@ -5,7 +5,7 @@ Resource keywords.robot
# Library Remote ${PLONE_URL}/RobotRemote
-Test Setup View Test Collection
+Test Setup Default Setup
Test Teardown Default Teardown
@@ -13,99 +13,127 @@ Test Teardown Default Teardown
*** Test Cases ***************************************************************
-Scenario: Add filter portlets to collection
-
- Manage portlets
- Add search portlet
- Add filter portlet Subject or checkboxes_dropdowns
- Add sorting portlet sortable_title links
- Go to ${PLONE_URL}/testcollection
- Should be 3 collection results
-
- Click Input "Dokumänt (2)"
- Should be 2 collection results
-
- Click Input "All (3)"
- Should be 3 collection results
+Scenario: Add filter to collection
+ Given I've got a site with a collection
+ and my collection has a collection filter Subject or checkboxes_dropdowns
+ When I'm viewing the collection
+ then Should be 3 collection results
+ and Should be filter checkboxes All (3) Dokumänt (2) Evänt (1) Sßper (2)
+ When Click Input "Dokumänt (2)"
+ then Should be 2 collection results
+ and Should be filter checkboxes All (3) Dokumänt (2) Evänt (1) Sßper (2)
+ When Click Input "All (3)"
+ then Should be 3 collection results
+ and Should be filter checkboxes All (3) Dokumänt (2) Evänt (1) Sßper (2)
Scenario: Test Batching
- Manage portlets
- Add filter portlet Subject or checkboxes_dropdowns
- Go to ${PLONE_URL}/testcollection
- Should be 3 collection results
-
- Set Batch Size 1
-
- Should be 1 collection results
-
- Click Input "SĂźper (2)"
- Should be 1 collection results
- Should be 1 pages
-
- Click Page "1"
- Should be 1 collection results
- Should be 1 pages
+ Given I've got a site with a collection batch=1
+ and my collection has a collection filter Subject or checkboxes_dropdowns
+ and I'm viewing the collection
+ then Should be 1 collection results
+ when Click Input "SĂźper (2)"
+ then Should be 1 collection results
+ and Should be 1 pages
+ when Click Page "1"
+ then Should be 1 collection results
+ then Should be 1 pages
${loc}= get location
should contain ${loc} collectionfilter=1
Scenario: Hide when no options
- Manage portlets
- Add filter portlet author_name or checkboxes_dropdowns
- Go to ${PLONE_URL}/testcollection
+ Given I've got a site with a collection
+ and my collection has a collection filter author_name or checkboxes_dropdowns Hide if empty
+ When I'm viewing the collection
+ then Should be 3 collection results
+ then Should be 0 filter options
- Should be 3 collection results
- Should be 1 filter options
+Scenario: Disable all filter option
- Manage portlets
- Set portlet "author_name" "Hide if empty"
- Go to ${PLONE_URL}/testcollection
- # No idea why intermittently we get 1 filter option below instead of 0
- log source
- Should be 0 filter options
- Should be 3 collection results
+ Given I've got a site with a collection
+ and my collection has a collection filter Subject or checkboxes_dropdowns dropdown_Select first # The 'Enable all filter option' argument here is toggling it off, so it is disabled
+ When I'm viewing the collection
+ Then Should be 2 collection results
+ and Should be filter checkboxes Dokumänt (2) Evänt (1) Sßper (2)
Scenario: show hidden filter if just narrowed down
- Given Manage portlets
- and Add filter portlet Type single checkboxes_dropdowns
- and Set portlet "Type" "Narrow down filter options"
- and Go to ${PLONE_URL}/testcollection
- and Should be 3 filter options
-
+ Given I've got a site with a collection
+ and my collection has a collection filter portal_type single checkboxes_dropdowns Narrow down filter options
+ When I'm viewing the collection
+ and Should be filter options All (3) Event (1) Page (2)
and Select Filter Option "Event (1)"
- and Should be 2 filter options
-
- When Manage portlets
- and Set portlet "Type" "Hide if empty"
- and Go to ${PLONE_URL}/testcollection
- and Should be 3 filter options
+ Then Should be filter options All (3) Event (1)
+Scenario: don't hide hidden filter if just narrowed down
+ Given I've got a site with a collection
+ and my collection has a collection filter portal_type single checkboxes_dropdowns Narrow down filter options Hide if empty
+ When I'm viewing the collection
+ and Should be filter options All (3) Event (1) Page (2)
# But if we filter it down it shouldn't disappear as then we have no way to click "All" to get back
and Select Filter Option "Event (1)"
- Log source
- Then Should be 2 filter options
+ Then Should be filter options All (3) Event (1)
Scenario: Displaying multiple collection filters on a single page
Given I've got a site with a collection
- and my collection has a collection filter portlet
- and my collection has a collection filter portlet group_by=Type
- When I'm viewing the collection
- Then I should have a portlet titled "Subject" with 4 filter options
- and I should have a portlet titled "Type" with 3 filter options
+ and my collection has a collection filter
+ and my collection has a collection filter group_by=portal_type
+ When I'm viewing the collection
+ Then I should have a filter with 4 options
+ and I should have a filter with 3 options
+ and I should see 7 filter options on the page
+ and Should be filter checkboxes All (3) Dokumänt (2) Evänt (1) Sßper (2) All (3) Event (1) Page (2)
-Scenario: Combine search and OR filter
+Scenario: Combine search and AND filter
Given I've got a site with a collection
- and my collection has a collection search portlet
- and my collection has a collection filter portlet Subject and checkboxes_dropdowns
+ and my collection has a collection search
+ and my collection has a collection filter Subject and checkboxes_dropdowns
When I'm viewing the collection
- and Click Input "SĂźper (2)"
+ and Should be filter checkboxes All (3) Dokumänt (2) Evänt (1) Sßper (2)
+ Then Click Input "SĂźper (2)"
and Should be 2 collection results
- and Click Input "Evänt (1)"
+ and Should be filter checkboxes All (3) Dokumänt (2) Evänt (1) Sßper (2)
+ Then Click Input "Evänt (1)"
and Should be 1 collection results
- and I search for "Event"
+ and Should be filter checkboxes All (3) Dokumänt (2) Evänt (1) Sßper (2)
+ Then I search for "Event"
and Should be 1 collection results
+ and Should be filter checkboxes All (1) Evänt (1) Sßper (1)
+
+
+Scenario: Search filter
+ Given I've got a site with a collection
+ and my collection has a collection search
+ and my collection has a collection filter
+ and I'm viewing the collection
+ When I search for "Document"
+ Then should be 1 collection results
+ and Should be filter checkboxes All (1) Dokumänt (1) Sßper (1)
+
+ When I search for "& - * $"
+ # Checking for no error rather than results as Plone 5.2 will display no
+ # results for a 'bad' query, while Plone 5.1/ 5.0 will display all of the results
+ Then page should not contain error
+
+ # Searching for query keywords (https://github.com/collective/collective.collectionfilter/issues/85)
+ When I search for "and Document"
+ Then should be 1 collection results
+ and Should be filter checkboxes All (1) Dokumänt (1) Sßper (1)
+ When I search for "or Document"
+ Then should be 0 collection results
+ and I should see 0 filter options on the page
+ When I search for "not Document"
+ Then should be 0 collection results
+ and I should see 0 filter options on the page
+
+ # the following doesn't work ... I think no 'keyup' event is fired
+ # Given I'm viewing the collection
+ # When I search for ${EMPTY} and click search
+ # Then should be 2 collection results
+ # and should be 4 filter options
+
+
diff --git a/src/collective/collectionfilter/tests/robot/test_filterportlets_ajaxdisabled.robot b/src/collective/collectionfilter/tests/robot/test_filterportlets_ajaxdisabled.robot
deleted file mode 100644
index 6773a0a5..00000000
--- a/src/collective/collectionfilter/tests/robot/test_filterportlets_ajaxdisabled.robot
+++ /dev/null
@@ -1,40 +0,0 @@
-
-*** Settings *****************************************************************
-
-Resource keywords.robot
-
-# Library Remote ${PLONE_URL}/RobotRemote
-
-Test Setup Open test browser
-Test Teardown Default Teardown
-
-
-*** Test Cases ***************************************************************
-
-Scenario: Searching through a portlet with ajax disabled
- Given I've got a site with a collection
- and my collection has a collection search portlet
- and my collection has a collection filter portlet
- and I'm viewing the collection
- When I search for "Document" and click search
- Then should be 1 collection results
- and should be 3 filter options
-
- # Searching for query keywords (https://github.com/collective/collective.collectionfilter/issues/85)
- When I search for "and Document" and click search
- Then should be 1 collection results
- and I should have a portlet titled "Subject" with 3 filter options
- When I search for "or Document" and click search
- Then I should not see any results
- and I should have a portlet titled "Subject" with 0 filter options
- When I search for "not Document" and click search
- Then I should not see any results
- and I should have a portlet titled "Subject" with 0 filter options
-
- # the following doesn't work ... I think no 'keyup' event is fired
- # Given I'm viewing the collection
- # When I search for ${EMPTY} and click search
- # Then should be 2 collection results
- # and should be 4 filter options
-
-
diff --git a/src/collective/collectionfilter/tests/robot/test_filterportlets_ajaxenabled.robot b/src/collective/collectionfilter/tests/robot/test_filterportlets_ajaxenabled.robot
deleted file mode 100644
index ee718ce8..00000000
--- a/src/collective/collectionfilter/tests/robot/test_filterportlets_ajaxenabled.robot
+++ /dev/null
@@ -1,38 +0,0 @@
-
-*** Settings *****************************************************************
-
-Resource keywords.robot
-
-# Library Remote ${PLONE_URL}/RobotRemote
-
-Test Setup Open test browser
-Test Teardown Default Teardown
-
-
-*** Test Cases ***************************************************************
-
-Scenario: Searching through a portlet with ajax enabled
- Given I've got a site with a collection
- and my collection has a collection search portlet
- and my collection has a collection filter portlet
- and I'm viewing the collection
- When I search for "Document" with ajax
- Then should be 1 collection results
- and should be 3 filter options
-
- # Searching for query keywords (https://github.com/collective/collective.collectionfilter/issues/85)
- When I search for "and Document" with ajax
- Then should be 1 collection results
- and I should have a portlet titled "Subject" with 3 filter options
- When I search for "or Document" with ajax
- Then I should not see any results
- and I should have a portlet titled "Subject" with 0 filter options
- When I search for "not Document" with ajax
- Then I should not see any results
- and I should have a portlet titled "Subject" with 0 filter options
-
- # the following doesn't work ... I think no 'keyup' event is fired
- # Given I'm viewing the collection
- # When I search for ${EMPTY} with ajax
- # Then should be 2 collection results
- # and should be 4 filter options
diff --git a/src/collective/collectionfilter/tests/robot/test_filtertiles_ajaxdisabled.robot b/src/collective/collectionfilter/tests/robot/test_filtertiles_ajaxdisabled.robot
deleted file mode 100644
index 8ea2b8ff..00000000
--- a/src/collective/collectionfilter/tests/robot/test_filtertiles_ajaxdisabled.robot
+++ /dev/null
@@ -1,47 +0,0 @@
-
-*** Settings *****************************************************************
-
-Resource keywords.robot
-
-# Library Remote ${PLONE_URL}/RobotRemote
-
-Test Setup Open test browser
-Test Teardown Default Teardown
-
-*** Variables ***
-
-${COLLECTION_NAME} testcollection
-${TEST_PAGE} ${PLONE_URL}/testdoc
-
-
-*** Test Cases ***************************************************************
-
-# Scenario: Add filter tiles to page for collection
-
-# Log in as site owner
-# Go to ${TEST_PAGE}
-
-# # Setup full mosaic display and open editor
-# Enable mosaic layout for page ${TEST_PAGE}
-
-# # Add tiles to page
-# Go to ${TEST_PAGE}/edit
-# Add filter tile ${COLLECTION_NAME} Subject checkboxes_dropdowns
-# Add search tile ${COLLECTION_NAME}
-# Save mosaic page
-# Go to ${TEST_PAGE}
-
-# # Check collection filter filters collections
-# # Broken when running with AJAX enabled
-# Go to ${TEST_PAGE}
-# Filter by Dokumänt
-# Should be 2 collection results
-
-# # Check collection search filters collections
-# Given go to ${TEST_PAGE}
-# When I search for Document and click search
-# Then should be 1 collection results
-
-# Given Go to ${TEST_PAGE}
-# When I search for ${EMPTY} and click search
-# Then should be 3 collection results
diff --git a/src/collective/collectionfilter/tests/robot/test_sortingportlets.robot b/src/collective/collectionfilter/tests/robot/test_sortingportlets.robot
index cc433a16..b7bd2c74 100644
--- a/src/collective/collectionfilter/tests/robot/test_sortingportlets.robot
+++ b/src/collective/collectionfilter/tests/robot/test_sortingportlets.robot
@@ -5,7 +5,7 @@ Resource keywords.robot
# Library Remote ${PLONE_URL}/RobotRemote
-Test Setup Open test browser
+Test Setup Default Setup
Test Teardown Default Teardown
@@ -13,21 +13,22 @@ Test Teardown Default Teardown
Scenario: Sorting with result sorting portlet
Given I've got a site with a collection
- and my collection has a collection sorting portlet
+ and my collection has a collection sorting
and I'm viewing the collection
-
- I sort by "sortable_title"
- and I should not have a portlet titled "Error"
+ and I sort by "Sortable Title"
+ and Page should not contain Error
+ and Results are Sorted
Scenario: Combine sort and OR filter
Given I've got a site with a collection
- and my collection has a collection sorting portlet
- and my collection has a collection filter portlet Subject and checkboxes_dropdowns
+ and my collection has a collection sorting
+ and my collection has a collection filter Subject and checkboxes_dropdowns
When I'm viewing the collection
and Click Input "SĂźper (2)"
and Should be 2 collection results
and Click Input "Evänt (1)"
and Should be 1 collection results
- Then I sort by "sortable_title"
+ Then I sort by "Sortable Title"
+ and Page should not contain Error
and Should be 1 collection results
- and I should not have a portlet titled "Error"
+ and Results are Sorted
diff --git a/src/collective/collectionfilter/tests/robot/test_tilesonly.robot b/src/collective/collectionfilter/tests/robot/test_tilesonly.robot
new file mode 100644
index 00000000..c4430a79
--- /dev/null
+++ b/src/collective/collectionfilter/tests/robot/test_tilesonly.robot
@@ -0,0 +1,30 @@
+
+*** Settings *****************************************************************
+
+Resource keywords.robot
+
+# Library Remote ${PLONE_URL}/RobotRemote
+
+Test Setup Default Setup
+Test Teardown Default Teardown
+
+
+
+
+*** Test Cases ***************************************************************
+
+Scenario: Add filter before content listing
+ Given I've got a site without a listing
+ When my collection has a collection filter
+ then Page should contain need to add a Content Listing
+ When my collection has a collection search
+ then Page should contain need to add a Content Listing
+ When my collection has a collection sorting
+ then Page should contain need to add a Content Listing
+ When edit mosaic page
+ and save mosaic page
+ then Page should contain need to add a Content Listing
+ When edit mosaic page
+ and Add contentlisting tile
+ and save mosaic page
+ then Page should not contain need to add a Content Listing
diff --git a/src/collective/collectionfilter/tests/test_filteritems.py b/src/collective/collectionfilter/tests/test_filteritems.py
index a4efa8e0..3dde914b 100644
--- a/src/collective/collectionfilter/tests/test_filteritems.py
+++ b/src/collective/collectionfilter/tests/test_filteritems.py
@@ -207,8 +207,8 @@ def test_and_filter_type(self):
self.assertEqual(len(result), 4)
self.assertEqual(get_data_by_val(result, "all")["count"], 3)
- # TODO: I'm not sure these counts are correct. It should represent how many results you will get if you click so should be smaller than this
- # but I guess you need to turn on narrow down for that?
+ # TODO: I'm not sure these counts are correct. It should represent how many results you will get if you click
+ # so should be smaller than this but I guess you need to turn on narrow down for that?
self.assertEqual(get_data_by_val(result, u"SĂźper")["count"], 2)
self.assertEqual(get_data_by_val(result, u"Evänt")["count"], 1)
self.assertEqual(get_data_by_val(result, u"Dokumänt")["count"], 2)
diff --git a/src/collective/collectionfilter/tests/test_robot.py b/src/collective/collectionfilter/tests/test_robot.py
index 5fcc0700..92c1bd4a 100644
--- a/src/collective/collectionfilter/tests/test_robot.py
+++ b/src/collective/collectionfilter/tests/test_robot.py
@@ -5,6 +5,9 @@
from collective.collectionfilter.testing import (
COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_ENABLED,
)
+from collective.collectionfilter.testing import (
+ COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_TILES,
+)
from plone import api
from plone.app.testing import ROBOT_TEST_LEVEL
from plone.testing import layered
@@ -23,28 +26,56 @@ def test_suite():
for doc in os.listdir(robot_dir)
if doc.endswith(".robot") and doc.startswith("test_")
]
- l1 = ROBOT_TEST_LEVEL
- l2 = ROBOT_TEST_LEVEL + 1
for robot_test in robot_tests:
if api.env.plone_version() < "5.1" and "ajaxenabled" in robot_test:
continue
- elif api.env.plone_version() < "5.1":
- test_layer = (
- (l1, COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_DISABLED),
- )
elif "ajaxenabled" in robot_test:
test_layer = (
- (l1, COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_ENABLED),
+ (
+ ROBOT_TEST_LEVEL,
+ COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_ENABLED,
+ ),
)
elif "ajaxdisabled" in robot_test:
test_layer = (
- (l1, COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_DISABLED),
+ (
+ ROBOT_TEST_LEVEL,
+ COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_DISABLED,
+ ),
+ )
+ elif "_tiles" in robot_test:
+ test_layer = (
+ (
+ ROBOT_TEST_LEVEL,
+ COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_TILES,
+ ),
+ )
+ elif api.env.plone_version() < "5.1":
+ test_layer = (
+ (
+ ROBOT_TEST_LEVEL,
+ COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_TILES,
+ ),
+ (
+ ROBOT_TEST_LEVEL,
+ COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_DISABLED,
+ ),
)
else:
# We will run generic tests with and without ajax to test everything
test_layer = (
- (l2, COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_DISABLED),
- (l1, COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_ENABLED),
+ (
+ ROBOT_TEST_LEVEL,
+ COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_TILES,
+ ),
+ (
+ ROBOT_TEST_LEVEL,
+ COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_DISABLED,
+ ),
+ (
+ ROBOT_TEST_LEVEL,
+ COLLECTIVE_COLLECTIONFILTER_ACCEPTANCE_TESTING_AJAX_ENABLED,
+ ),
)
for level, layer in test_layer:
robottestsuite = robotsuite.RobotTestSuite(robot_test)
diff --git a/src/collective/collectionfilter/tiles/__init__.py b/src/collective/collectionfilter/tiles/__init__.py
index 50478f63..e6e42637 100644
--- a/src/collective/collectionfilter/tiles/__init__.py
+++ b/src/collective/collectionfilter/tiles/__init__.py
@@ -1,6 +1,18 @@
# -*- coding: utf-8 -*-
+from collective.collectionfilter import _
+from collective.collectionfilter.filteritems import CollectionishCollection
+from collective.collectionfilter.interfaces import ICollectionish
from plone import api
+from plone.app.blocks.layoutbehavior import ILayoutAware
+from plone.app.blocks.layoutbehavior import ILayoutBehaviorAdaptable
+from plone.app.contenttypes.behaviors.collection import ICollection
from plone.tiles.tile import PersistentTile
+from zope.component import adapter
+from zope.component import getMultiAdapter
+from zope.component import queryAdapter
+from zope.interface import implementer
+
+import re
class DictDataWrapper(object):
@@ -17,7 +29,7 @@ def __getattr__(self, name):
class BaseFilterTile(PersistentTile):
def available(self):
# do not render when page is ajax loaded
- return "ajax_load" not in self.top_request
+ return "ajax_load" not in self.top_request and self.is_available
@property
def edit_url(self):
@@ -36,3 +48,150 @@ def filter_id(self):
@property
def reload_url(self):
return self.url
+
+
+def findall_tiles(context, spec):
+ request = context.REQUEST
+ la = ILayoutAware(context)
+ layout = (
+ la.customContentLayout
+ if la.customContentLayout is not None
+ else la.contentLayout
+ if la.contentLayout is not None
+ else la.content
+ )
+ if layout is None:
+ return []
+ urls = re.findall(r"(@@[\w\.]+/\w+)", layout)
+ urls = [url for url in urls if url.startswith("@@{}".format(spec))]
+ # TODO: maybe better to get tile data? using ITileDataManager(id)?
+ our_tile = request.response.headers.get("x-tile-url")
+ tiles = [context.unrestrictedTraverse(str(url)) for url in urls]
+ # mosaic get confused if we are doing this while creating a filter tile
+ if request.response.headers.get("x-tile-url"):
+ if our_tile:
+ request.response.headers["x-tile-url"] = our_tile
+ else:
+ del request.response.headers["x-tile-url"]
+ return tiles
+
+
+@implementer(ICollectionish)
+@adapter(ILayoutBehaviorAdaptable)
+class CollectionishLayout(CollectionishCollection):
+ """Provide interface for either objects with contentlisting tiles or collections or both"""
+
+ tile = None
+ collection = None
+
+ def __init__(self, context):
+ """Adapt either collections or contentlisting tile. The name is sorted content selector"""
+ self.context = context
+
+ self.selectContent("") # get first tile
+
+ if self.tile is None:
+ # Could still be a ILayoutAware collection
+ try:
+ self.collection = ICollection(self.context)
+ except TypeError:
+ self.collection = None
+ else:
+ self.collection = self.tile # to get properties
+
+ def selectContent(self, selector=None):
+ """Pick tile that selector will match, otherwise pick first one.
+ Return None if no listing tile or collection is suitable, else return this adapter.
+ """
+
+ if selector is None:
+ selector = ""
+ self.tile = None
+ tiles = findall_tiles(self.context, "plone.app.standardtiles.contentlisting")
+ for tile in tiles:
+ tile.update()
+ tile_classes = tile.tile_class.split() + [""]
+ # First tile that matches all the selector classes
+ if all([_class in tile_classes for _class in selector.split(".")]):
+ self.tile = tile
+ break
+ if tiles and self.tile is None:
+ # TODO: what if the class is inside a special template? Just pick first?
+ # none of the selectors worked. Just pick any and hope it works?
+ self.tile = tile
+ if self.tile is not None or self.collection is not None:
+ return self
+ else:
+ return None
+
+ @property
+ def sort_reversed(self):
+ if self.tile is not None:
+ return self.sort_order == "reverse"
+ else:
+ return self.collection.sort_reversed
+
+ @property
+ def content_selector(self):
+ """will return None if no tile or colleciton found"""
+ if self.collection is None:
+ return None
+ elif self.tile is None:
+ return super(CollectionishLayout, self).content_selector
+ classes = ["contentlisting-tile"]
+ if self.tile.tile_class:
+ classes += self.tile.tile_class.split()
+ return "." + ".".join(classes)
+
+ def results(self, custom_query, request_params):
+ """Search results"""
+ if self.tile is None:
+ return super(CollectionishLayout, self).results(
+ custom_query, request_params
+ )
+
+ builder = getMultiAdapter(
+ (self.context, self.context.REQUEST), name="querybuilderresults"
+ )
+
+ # Include query parameters from request if not set to ignore
+ contentFilter = {}
+ if not getattr(self.tile, "ignore_request_params", False):
+ contentFilter = dict(self.context.REQUEST.get("contentFilter", {}))
+
+ # TODO: handle events extra params
+
+ return builder(
+ query=self.query,
+ sort_on=self.sort_on or "getObjPositionInParent",
+ sort_order=self.sort_order,
+ limit=self.limit,
+ batch=False,
+ brains=True,
+ custom_query=custom_query if custom_query is not None else contentFilter,
+ )
+
+
+def validateFilterTileModify(tile, event):
+ # TODO: is ok in the acquisiton path?
+ target = tile.collection
+ if target is not None:
+ target = queryAdapter(target.getObject(), ICollectionish)
+ if target is None or target.content_selector is None:
+ api.portal.show_message(
+ _(
+ u"You will need to add a Content Listing tile or target a collection to make Filters work"
+ ),
+ request=tile.context.REQUEST,
+ type=u"warning",
+ )
+ return False
+ return True
+
+
+def validateFilterMosaicModify(context, event):
+ # search the layout for any filters and then see if they have a matching listing
+ tiles = findall_tiles(context, "collective.collectionfilter.tiles.")
+ for tile in tiles:
+ if not validateFilterTileModify(tile, event):
+ break
diff --git a/src/collective/collectionfilter/tiles/configure.zcml b/src/collective/collectionfilter/tiles/configure.zcml
index bcf4775f..062c1b43 100644
--- a/src/collective/collectionfilter/tiles/configure.zcml
+++ b/src/collective/collectionfilter/tiles/configure.zcml
@@ -8,6 +8,25 @@
+
+
+
+
+
+
+
+
=3.7
# Needed for mosaic. Might also try to pin an earlier version of mosaic if this doesn't work
plone.app.mosaic = 2.1.1
plone.app.blocks = 4.1.1
plone.app.drafts = 1.1.2
-plone.app.standardtiles = 2.3.0
-plone.app.tiles = 3.0.3
+plone.app.standardtiles = < 2.4.0
+plone.app.tiles = 3.1.2
plone.tiles = 2.0.0
plone.jsonserializer = 0.9.6
diff --git a/test-5.1.x.cfg b/test-5.1.x.cfg
index 643dc8ee..197a209d 100644
--- a/test-5.1.x.cfg
+++ b/test-5.1.x.cfg
@@ -3,7 +3,6 @@ extends =
https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-5.1.x.cfg
https://raw.githubusercontent.com/collective/buildout.plonetest/master/qa.cfg
base.cfg
- versions-2.7.cfg
parts +=
test
@@ -14,14 +13,11 @@ package-name = collective.collectionfilter
package-extras = [test]
test-eggs =
-[code-analysis]
-flake8-ignore = E501,E241
-
[versions]
setuptools =
zc.buildout =
configparser = 3.8.1
-coverage = >=3.7
+
plone.formwidget.geolocation = < 2.2.2 # Introduced a dep on CMFPlone 5.2
diff --git a/test-5.2.x.cfg b/test-5.2.x.cfg
index 6f082c72..dd888675 100644
--- a/test-5.2.x.cfg
+++ b/test-5.2.x.cfg
@@ -2,6 +2,7 @@
extends =
https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-5.2.x.cfg
https://raw.githubusercontent.com/collective/buildout.plonetest/master/qa.cfg
+ https://raw.githubusercontent.com/plone/plone.app.mosaic/master/versions.cfg
base.cfg
parts +=
@@ -14,10 +15,8 @@ package-extras = [test]
test-eggs =
[code-analysis]
-flake8-ignore = E501,E241
+extensions +=
+ flake8-black
-[versions]
-#setuptools =
-#zc.buildout =
+[versions:python3]
coverage = >=3.7
-
diff --git a/versions-2.7.cfg b/versions-2.7.cfg
deleted file mode 100644
index e8c1217a..00000000
--- a/versions-2.7.cfg
+++ /dev/null
@@ -1,29 +0,0 @@
-[versions]
-# to get codeanalysis working
-build = 0.1
-
-# Required by:
-# build==0.1.0
-# pep517==0.9.1
-importlib-metadata = 3.3.0
-
-# Required by:
-# build==0.1.0
-packaging = 20.8
-
-# Required by:
-# build==0.1.0
-typing = 3.7.4.3
-
-# Required by:
-# pep517==0.9.1
-zipp = 3.4.0
-
-pycodestyle = 2.0.0
-flake8 = 2.6.2
-configparser = <5.0.0
-
-flake8-pep3101 = 0.6
-flake8-commas = 0.1.6
-flake8-isort = 1.3
-flake8-deprecated = 1.0
\ No newline at end of file