Index: /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/browser/resources/batch.js
===================================================================
--- /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/browser/resources/batch.js	(revision 2754)
+++ /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/browser/resources/batch.js	(revision 2755)
@@ -18,7 +18,5 @@
 
     var bind_prev_handler = function(link, index){
-      if (index == 0) {
-        jq(link).hide();
-      }
+      if (index == 0) jq(link).hide();
       jq(link).unbind();
       jq(link).click(function(e) {
@@ -33,7 +31,5 @@
     };
     var bind_next_handler = function(link, index){
-      if (index == nav_links.size()-1) {
-        jq(link).hide();
-      }
+      if (index == nav_links.size()-1) jq(link).hide();
       jq(link).unbind();
       jq(link).click(function(e) {
Index: /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/collection.pt
===================================================================
--- /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/collection.pt	(revision 2754)
+++ /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/collection.pt	(revision 2755)
@@ -3,5 +3,5 @@
     tal:define="collection_url view/collection_url;
                 styling view/data/styling"
-    tal:attributes="class string:${attrs/class} ${styling}">
+    tal:attributes="class python: styling and '%s %s'% (attrs['class'], styling) or attrs['class']">
 
     <dt class="portletHeader">
Index: /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/tests/base.py
===================================================================
--- /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/tests/base.py	(revision 2755)
+++ /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/tests/base.py	(revision 2755)
@@ -0,0 +1,42 @@
+from Products.Five import zcml
+from Products.Five import fiveconfigure
+
+from Testing import ZopeTestCase as ztc
+
+from Products.PloneTestCase import PloneTestCase as ptc
+from Products.PloneTestCase.layer import onsetup
+
+@onsetup
+def setup_product():
+    """Set up additional products and ZCML required to test this product.
+
+    The @onsetup decorator causes the execution of this body to be deferred
+    until the setup of the Plone site testing layer.
+    """
+
+    # Load the ZCML configuration for this package and its dependencies
+
+    fiveconfigure.debug_mode = True
+    import quintagroup.portlet.collection
+    zcml.load_config('configure.zcml', quintagroup.portlet.collection)
+    fiveconfigure.debug_mode = False
+
+    # We need to tell the testing framework that these products
+    # should be available. This can't happen until after we have loaded
+    # the ZCML.
+
+    ztc.installPackage('quintagroup.portlet.collection')
+
+# The order here is important: We first call the deferred function and then
+# let PloneTestCase install it during Plone site setup
+
+setup_product()
+ptc.setupPloneSite(products=['quintagroup.portlet.collection'])
+
+class TestCase(ptc.PloneTestCase):
+    """Base class used for test cases
+    """
+
+class FunctionalTestCase(ptc.FunctionalTestCase):
+    """Test case class used for functional (doc-)tests
+    """
Index: /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/tests/test_portlet.py
===================================================================
--- /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/tests/test_portlet.py	(revision 2755)
+++ /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/tests/test_portlet.py	(revision 2755)
@@ -0,0 +1,246 @@
+from zope.component import getUtility, getMultiAdapter
+
+from plone.portlets.interfaces import IPortletType
+from plone.portlets.interfaces import IPortletManager
+from plone.portlets.interfaces import IPortletAssignment
+from plone.portlets.interfaces import IPortletDataProvider
+from plone.portlets.interfaces import IPortletRenderer
+
+from plone.app.portlets.storage import PortletAssignmentMapping
+
+from quintagroup.portlet.collection import collection
+
+from quintagroup.portlet.collection.tests.base import TestCase
+
+
+from Products.CMFCore.utils import getToolByName
+
+class TestQPortletCollection(TestCase):
+    def afterSetUp(self):
+        self.setRoles(('Manager',))
+
+    def testPortletTypeRegistered(self):
+        portlet = getUtility(IPortletType, name='quintagroup.portlet.collection.Collection')
+        self.assertEquals(portlet.addview, 'quintagroup.portlet.collection.Collection')
+
+    def testInterfaces(self):
+        portlet = collection.Assignment(header=u"title")
+        self.failUnless(IPortletAssignment.providedBy(portlet))
+        self.failUnless(IPortletDataProvider.providedBy(portlet.data))
+
+    def testInvokeAddview(self):
+        portlet = getUtility(IPortletType, name='quintagroup.portlet.collection.Collection')
+        mapping = self.portal.restrictedTraverse('++contextportlets++plone.leftcolumn')
+        for m in mapping.keys():
+            del mapping[m]
+        addview = mapping.restrictedTraverse('+/' + portlet.addview)
+
+        addview.createAndAdd(data={'header' : u"test title"})
+
+        self.assertEquals(len(mapping), 1)
+        self.failUnless(isinstance(mapping.values()[0], collection.Assignment))
+
+    def testInvokeEditView(self):
+        mapping = PortletAssignmentMapping()
+        request = self.folder.REQUEST
+
+        mapping['foo'] = collection.Assignment(header=u"title")
+        editview = getMultiAdapter((mapping['foo'], request), name='edit')
+        self.failUnless(isinstance(editview, collection.EditForm))
+
+    def testRenderer(self):
+        context = self.folder
+        request = self.folder.REQUEST
+        view = self.folder.restrictedTraverse('@@plone')
+        manager = getUtility(IPortletManager, name='plone.rightcolumn', context=self.portal)
+        assignment = collection.Assignment(header=u"title")
+
+        renderer = getMultiAdapter((context, request, view, manager, assignment), IPortletRenderer)
+        self.failUnless(isinstance(renderer, collection.Renderer))
+
+class TestQPortletCollectionRenderer(TestCase):
+
+    def afterSetUp(self):
+        self.setRoles(('Manager',))
+        self.pages = self._createType(self.folder, 'Topic', 'pages')
+        crit = self.folder.pages.addCriterion('portal_type', 'ATSimpleStringCriterion')
+        crit.setValue('Document')
+
+    def renderer(self, context=None, request=None, view=None, manager=None, assignment=None):
+        context = context or self.folder
+        request = request or self.folder.REQUEST
+        view = view or self.folder.restrictedTraverse('@@plone')
+        manager = manager or getUtility(IPortletManager, name='plone.rightcolumn', context=self.portal)
+        assignment = assignment or collection.Assignment(header=u"title")
+
+        return getMultiAdapter((context, request, view, manager, assignment), IPortletRenderer)
+
+    def _createType(self, context, portal_type, id, **kwargs):
+        """Helper method to create a new type
+        """
+        ttool = getToolByName(context, 'portal_types')
+        cat = self.portal.portal_catalog
+
+        fti = ttool.getTypeInfo(portal_type)
+        fti.constructInstance(context, id, **kwargs)
+        obj = getattr(context.aq_inner.aq_explicit, id)
+        cat.indexObject(obj)
+        return obj
+
+    def test_render(self):
+        r = self.renderer(context=self.portal, assignment=collection.Assignment(header=u"title"))
+        r = r.__of__(self.folder)
+        r.update()
+        output = r.render()
+
+        # this test failed due to changed behavior. We'll not output anything if the portlet does not point to a collection
+
+        #self.failUnless('title' in output)
+        #self.failUnless('<b>text</b>' in output)
+
+
+    def test_collection_path_unicode(self):
+        """
+        Cover problem in #9184
+        """
+        r = self.renderer(context=self.portal,
+                          assignment=collection.Assignment(header=u"title",
+                                                           target_collection=u"/events"))
+        r  = r.__of__(self.folder)
+        self.assertEqual(r.collection().id, 'events')
+
+    def test_portletStyle(self):
+        renderer = self.renderer(context=self.portal,
+                                 assignment=collection.Assignment(header=u"title",
+                                                                  styling="TestClass"))
+        renderer = renderer.__of__(self.folder)
+        renderer.update()
+
+        self.failUnless('TestClass' in renderer.render())
+
+    def test_attributes(self):
+        page = self._createType(self.folder, 'Document', 'page')
+        page.update(title="Test Page", description="Test description")
+        renderer = self.renderer(context=self.portal,
+                                 assignment=collection.Assignment(header=u"title",
+                                                                  item_attributes=[u'Title'],
+                                                                  target_collection='/Members/test_user_1_/pages'))
+        renderer = renderer.__of__(self.folder)
+        renderer.update()
+        self.failUnless('Test Page' in renderer.render())
+        self.failUnless('Test description' not in renderer.render())
+
+class TestQPortletCollectionQuery(TestCase):
+
+    def afterSetUp(self):
+        self.setRoles(('Manager',))
+        #make a collection
+        self.collection = self._createType(self.folder, 'Topic', 'collection')
+
+    def _createType(self, context, portal_type, id, **kwargs):
+        """Helper method to create a new type
+        """
+        ttool = getToolByName(context, 'portal_types')
+        cat = self.portal.portal_catalog
+
+        fti = ttool.getTypeInfo(portal_type)
+        fti.constructInstance(context, id, **kwargs)
+        obj = getattr(context.aq_inner.aq_explicit, id)
+        cat.indexObject(obj)
+        return obj
+
+
+    def renderer(self, context=None, request=None, view=None, manager=None, assignment=None):
+        context = context or self.folder
+        request = request or self.folder.REQUEST
+        view = view or self.folder.restrictedTraverse('@@plone')
+        manager = manager or getUtility(IPortletManager, name='plone.leftcolumn', context=self.portal)
+        assignment = assignment
+        return getMultiAdapter((context, request, view, manager, assignment), IPortletRenderer)
+
+    def testSimpleQuery(self):
+        # set up our collection to search for Folders
+        crit = self.folder.collection.addCriterion('portal_type', 'ATSimpleStringCriterion')
+        crit.setValue('Folder')
+
+        # add a few folders
+        for i in range(6):
+            self.folder.invokeFactory('Folder', 'folder_%s'%i)
+            getattr(self.folder, 'folder_%s'%i).reindexObject()
+
+        # the folders are returned by the topic
+        collection_num_items = len(self.folder.collection.queryCatalog())
+        # We better have some folders
+        self.failUnless(collection_num_items >= 6)
+
+        mapping = PortletAssignmentMapping()
+        request = self.folder.REQUEST
+        mapping['foo'] = collection.Assignment(header=u"title", target_collection='/Members/test_user_1_/collection')
+        collectionrenderer = self.renderer(context=None, request=None, view=None, manager=None, assignment=mapping['foo'])
+
+        # we want the portlet to return us the same results as the collection
+        self.assertEquals(collection_num_items, len(collectionrenderer.results()))
+
+    def testRandomQuery(self):
+        # we're being perhaps a bit too clever in random mode with the internals of the
+        # LazyMap returned by the collection query, so let's try a bunch of scenarios
+        # to make sure they work
+
+        # set up our portlet renderer
+        mapping = PortletAssignmentMapping()
+        request = self.folder.REQUEST
+        mapping['foo'] = collection.Assignment(header=u"title",
+                                               random=True,
+                                               target_collection='/Members/test_user_1_/collection')
+        collectionrenderer = self.renderer(context=None, request=None, view=None, manager=None, assignment=mapping['foo'])
+
+        # add some folders
+        for i in range(6):
+            self.folder.invokeFactory('Folder', 'folder_%s'%i)
+            getattr(self.folder, 'folder_%s'%i).reindexObject()
+
+        # collection with no criteria -- should return empty list, without error
+        self.assertEqual(len(collectionrenderer.results()), 0)
+
+        # let's make sure the results aren't being memoized
+        old_func = self.folder.collection.queryCatalog
+        global collection_was_called
+        collection_was_called = False
+        def mark_collection_called(**kw):
+            global collection_was_called
+            collection_was_called = True
+        self.folder.collection.queryCatalog = mark_collection_called
+        collectionrenderer.results()
+        self.folder.collection.queryCatalog = old_func
+        self.failUnless(collection_was_called)
+
+        # collection with simple criterion -- should return 1 (random) folder
+        crit = self.folder.collection.addCriterion('portal_type', 'ATSimpleStringCriterion')
+        crit.setValue('Folder')
+        self.assertEqual(len(collectionrenderer.results()), 1)
+
+        # collection with multiple criteria -- should behave similarly
+        crit = self.folder.collection.addCriterion('Creator', 'ATSimpleStringCriterion')
+        crit.setValue('test_user_1_')
+        collectionrenderer.results()
+
+        # collection with sorting -- should behave similarly (sort is ignored internally)
+        self.folder.collection.setSortCriterion('modified', False)
+        self.assertEqual(len(collectionrenderer.results()), 1)
+
+        # same criteria, now with limit set to 2 -- should return 2 (random) folders
+        collectionrenderer.data.limit = 2
+        self.assertEqual(len(collectionrenderer.results()), 2)
+
+        # make sure there's no error if the limit is greater than the # of results found
+        collectionrenderer.data.limit = 10
+        self.failUnless(len(collectionrenderer.results()) >= 6)
+
+
+def test_suite():
+    from unittest import TestSuite, makeSuite
+    suite = TestSuite()
+    suite.addTest(makeSuite(TestQPortletCollection))
+    suite.addTest(makeSuite(TestQPortletCollectionRenderer))
+    suite.addTest(makeSuite(TestQPortletCollectionQuery))
+    return suite
Index: /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/vocabularies.py
===================================================================
--- /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/vocabularies.py	(revision 2754)
+++ /quintagroup.portlet.collection/trunk/quintagroup/portlet/collection/vocabularies.py	(revision 2755)
@@ -21,5 +21,5 @@
     implements(IVocabularyFactory)
 
-    
+
     def __call__(self, context):
         styles = getStylesVocabulary(context)
@@ -34,7 +34,4 @@
                 value = value.decode(charset)
             items.append(SimpleTerm(value, value, _(title)))
-        return SimpleVocabulary(items)
-
-        items = [SimpleTerm(value, value, title) for value, title in PORTLET_CSS_STYLES]
         return SimpleVocabulary(items)
 
