diff --git a/CHANGES.rst b/CHANGES.rst index b72fa6722..1190600c4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -13,6 +13,9 @@ There's a frood who really knows where his towel is. All Layout tab helper views use now ``collective.cover.CanEditLayout`` permission. The ``BaseGrid`` class is now located in the ``collective.cover.grids`` module. +- Remove dependency on ``portal_calendar`` tool for calendar tile. + [rodfersou, hvelarde] + - Remove dependency on plone.directives.form. [l34marr] diff --git a/src/collective/cover/profiles/default/metadata.xml b/src/collective/cover/profiles/default/metadata.xml index 82e7b6ccc..e445d598e 100644 --- a/src/collective/cover/profiles/default/metadata.xml +++ b/src/collective/cover/profiles/default/metadata.xml @@ -1,6 +1,6 @@ - 14 + 15 profile-collective.js.galleria:default profile-collective.js.jqueryui:default diff --git a/src/collective/cover/static/css/cover.css b/src/collective/cover/static/css/cover.css index b8e0727d5..3a38cdf64 100644 --- a/src/collective/cover/static/css/cover.css +++ b/src/collective/cover/static/css/cover.css @@ -249,30 +249,23 @@ table.invisible } /* Tile Calendar */ -.cover-calendar-tile .calendar-tile-header +.cover-calendar-tile .portletCalendar { - font-weight: bold; - line-height: normal; - - padding: .42em 1em; - - text-align: center; - - background: #ddd; + font-size: 1em; } -#content .cover-calendar-tile a.calendar-tile-prev, -#content .cover-calendar-tile a.calendar-tile-next +#content .cover-calendar-tile a.calendarPrevious, +#content .cover-calendar-tile a.calendarNext { margin: 0 -.5em; padding: 0 1em; border-bottom: none; } -.cover-calendar-tile a.calendar-tile-prev +.cover-calendar-tile a.calendarPrevious { float: left; } -.cover-calendar-tile a.calendar-tile-next +.cover-calendar-tile a.calendarNext { float: right; } diff --git a/src/collective/cover/static/js/main.js b/src/collective/cover/static/js/main.js index 417de82d0..32c53a3e2 100644 --- a/src/collective/cover/static/js/main.js +++ b/src/collective/cover/static/js/main.js @@ -1,14 +1,61 @@ $(function() { + // override jquery portlet event + // http://stackoverflow.com/a/14063574/2116850 + function refreshPortlet(hash, _options){ + var options = { + data: {}, + success: function(){}, + error: function(){}, + ajaxOptions: {}}; + $.extend(options, _options); + options.data.portlethash = hash; + ajaxOptions = options.ajaxOptions; + ajaxOptions.url = $('base').attr('href') + '/@@render-portlet'; + ajaxOptions.success = function(data){ + var container = $('[data-portlethash="' + hash + '"]'); + var portlet = $(data); + container.html(portlet); + options.success(data, portlet); + } + ajaxOptions.error = function(){ + options.error(); + } + ajaxOptions.data = options.data; + $.ajax(ajaxOptions); + } + $('body').undelegate('#calendar-next, #calendar-previous', 'click') + .delegate( + '.portletWrapper #calendar-next, ' + + '.portletWrapper #calendar-previous', + 'click', + function(e) { + e.preventDefault(); + var el = $(this); + var container = el.parents('.portletWrapper'); + refreshPortlet(container.data('portlethash'), { + data: { + month: el.data('month'), + year: el.data('year') + } + }); + return false; + }); + // override jquery portlet event + $('#content').on( 'click', - '.cover-calendar-tile a.calendar-tile-prev, ' + - '.cover-calendar-tile a.calendar-tile-next', + '.cover-calendar-tile .calendarPrevious, ' + + '.cover-calendar-tile .calendarNext', function(e) { e.preventDefault(); var $a = $(this); var $tile = $a.parents('.tile'); + var url = '@@updatetile' + if ($a.hasClass('kssCalendarChange')) { + url = $a.attr('href'); + } $.ajax({ - url: '@@updatetile', + url: url, data: { 'tile-id': $tile.attr('id'), 'month:int': $a.attr('data-month'), diff --git a/src/collective/cover/testing.py b/src/collective/cover/testing.py index 05d36af13..07d58c4eb 100644 --- a/src/collective/cover/testing.py +++ b/src/collective/cover/testing.py @@ -166,7 +166,6 @@ def setUpPloneSite(self, portal): set_image_field(portal['my-image1'], generate_jpeg(50, 50)) set_image_field(portal['my-image2'], generate_jpeg(50, 50)) set_image_field(portal['my-news-item'], generate_jpeg(50, 50)) - portal_workflow = portal.portal_workflow portal_workflow.setChainForPortalTypes( ['Collection'], ['simple_publication_workflow']) diff --git a/src/collective/cover/tests/test_calendar_tile.py b/src/collective/cover/tests/test_calendar_tile.py index 8e5c32af3..1c5874be3 100644 --- a/src/collective/cover/tests/test_calendar_tile.py +++ b/src/collective/cover/tests/test_calendar_tile.py @@ -14,7 +14,6 @@ def setUp(self): self.tile.__name__ = u'collective.cover.calendar' self.tile.id = u'test' - @unittest.expectedFailure # FIXME: raises BrokenImplementation def test_interface(self): self.interface = ICalendarTile self.klass = CalendarTile @@ -27,13 +26,3 @@ def test_default_configuration(self): def test_accepted_content_types(self): self.assertEqual(self.tile.accepted_ct(), []) - - -# load tests only in Plone < 5 -def test_suite(): - # FIXME: https://github.com/collective/collective.cover/issues/633 - from collective.cover.config import IS_PLONE_5 - if IS_PLONE_5: - return unittest.TestSuite() - - return unittest.defaultTestLoader.loadTestsFromName(__name__) diff --git a/src/collective/cover/tests/test_calendar_tile.robot b/src/collective/cover/tests/test_calendar_tile.robot index e9132b55c..0be8535d6 100644 --- a/src/collective/cover/tests/test_calendar_tile.robot +++ b/src/collective/cover/tests/test_calendar_tile.robot @@ -35,20 +35,44 @@ Test Calendar Tile # test next / prev buttons ${nextyear} = Execute Javascript ... return (function() { - ... var $next = jQuery('a.calendar-tile-next'); + ... var $next = jQuery('a.calendarNext'); + ... var str_klasses = $next.attr('class'); + ... if (str_klasses.indexOf('kssattr') >= 0) { + ... var klasses = str_klasses.split(' '); + ... var i, klass, len, year, year_check; + ... for (i = 0, len = klasses.length; i < len; i++) { + ... klass = klasses[i]; + ... year_check = 'kssattr-year-'; + ... if (klass.indexOf(year_check) === 0) { + ... return klass.slice(year_check.length); + ... } + ... } + ... } ... return $next.attr('data-year'); ... })(); ${nextmonth} = Execute Javascript ... return (function() { - ... var $next = jQuery('a.calendar-tile-next'); + ... var $next = jQuery('a.calendarNext'); + ... var str_klasses = $next.attr('class'); + ... if (str_klasses.indexOf('kssattr') >= 0) { + ... var klasses = str_klasses.split(' '); + ... var i, klass, len, month, month_check; + ... for (i = 0, len = klasses.length; i < len; i++) { + ... klass = klasses[i]; + ... month_check = 'kssattr-month-'; + ... if (klass.indexOf(month_check) === 0) { + ... return klass.slice(month_check.length); + ... } + ... } + ... } ... return $next.attr('data-month'); ... })(); - Wait Until Keyword Succeeds 5 sec 1 sec Click Link css=a.calendar-tile-next - Wait Until Keyword Succeeds 5 sec 1 sec Click Link css=a.calendar-tile-next - Page Should Contain Element xpath=.//a[@class='calendar-tile-prev'][@data-month='${nextmonth}'][@data-year='${nextyear}'] - Wait Until Keyword Succeeds 5 sec 1 sec Click Link css=a.calendar-tile-prev - Wait Until Keyword Succeeds 5 sec 1 sec Click Link css=a.calendar-tile-prev - Page Should Contain Element xpath=.//a[@class='calendar-tile-next'][@data-month='${nextmonth}'][@data-year='${nextyear}'] + Wait Until Keyword Succeeds 5 sec 1 sec Click Link css=a.calendarNext + Wait Until Keyword Succeeds 5 sec 1 sec Click Link css=a.calendarNext + Page Should Contain Element jquery=a.calendarPrevious[data-month=${nextmonth}][data-year=${nextyear}],a.calendarPrevious.kssattr-month-${nextmonth}.kssattr-year-${nextyear} + Wait Until Keyword Succeeds 5 sec 1 sec Click Link css=a.calendarPrevious + Wait Until Keyword Succeeds 5 sec 1 sec Click Link css=a.calendarPrevious + Page Should Contain Element jquery=a.calendarNext[data-month=${nextmonth}][data-year=${nextyear}],a.calendarNext.kssattr-month-${nextmonth}.kssattr-year-${nextyear} # delete the tile Open Layout Tab diff --git a/src/collective/cover/tests/test_upgrades.py b/src/collective/cover/tests/test_upgrades.py index 4f96c199a..35bdcf907 100644 --- a/src/collective/cover/tests/test_upgrades.py +++ b/src/collective/cover/tests/test_upgrades.py @@ -524,7 +524,6 @@ def test_registrations(self): self.assertGreaterEqual(int(version), int(self.to_version)) self.assertEqual(self._how_many_upgrades_to_do(), 4) - # FIXME: https://github.com/collective/collective.cover/issues/633 @unittest.skipIf(IS_PLONE_5, 'Upgrade step not supported under Plone 5') def test_register_calendar_tile(self): # address also an issue with Setup permission @@ -577,3 +576,14 @@ def test_register_calendar_script(self): self._do_upgrade_step(step) self.assertIn(script, js_tool.getResourceIds()) + + +class Upgrade14to15TestCase(UpgradeTestCaseBase): + + def setUp(self): + UpgradeTestCaseBase.setUp(self, u'14', u'15') + + def test_registrations(self): + version = self.setup.getLastVersionForProfile(self.profile_id)[0] + self.assertGreaterEqual(int(version), int(self.to_version)) + self.assertEqual(self._how_many_upgrades_to_do(), 2) diff --git a/src/collective/cover/tests/test_vocabularies.py b/src/collective/cover/tests/test_vocabularies.py index 75256ec19..894d796db 100644 --- a/src/collective/cover/tests/test_vocabularies.py +++ b/src/collective/cover/tests/test_vocabularies.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from collective.cover.config import IS_PLONE_5 from collective.cover.controlpanel import ICoverSettings from collective.cover.testing import INTEGRATION_TESTING from plone.registry.interfaces import IRegistry @@ -46,10 +45,6 @@ def test_available_tiles_vocabulary(self): 'collective.cover.richtext', ] - # FIXME: https://github.com/collective/collective.cover/issues/633 - if IS_PLONE_5: - expected.remove('collective.cover.calendar') - self.assertEqual(len(tiles), len(expected)) for i in expected: self.assertIn(i, tiles) @@ -73,10 +68,6 @@ def test_enabled_tiles_vocabulary(self): 'collective.cover.richtext', ] - # FIXME: https://github.com/collective/collective.cover/issues/633 - if IS_PLONE_5: - expected.remove('collective.cover.calendar') - self.assertEqual(len(tiles), len(expected)) for i in expected: self.assertIn(i, tiles) diff --git a/src/collective/cover/tiles/calendar.py b/src/collective/cover/tiles/calendar.py index e0eca847c..8ce9d6a74 100644 --- a/src/collective/cover/tiles/calendar.py +++ b/src/collective/cover/tiles/calendar.py @@ -1,187 +1,52 @@ # -*- coding: utf-8 -*- -from Acquisition import aq_inner from collective.cover import _ from collective.cover.tiles.base import IPersistentCoverTile from collective.cover.tiles.base import PersistentCoverTile -from DateTime import DateTime -from Products.CMFCore.utils import getToolByName -from Products.CMFPlone.utils import safe_unicode from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile -from time import localtime -from urllib import quote_plus -from zope.component import getMultiAdapter -from zope.i18nmessageid import MessageFactory from zope.interface import implementer - -PLMF = MessageFactory('plonelocales') +try: # plone.app.event + from plone.app.event.portlets.portlet_calendar import Assignment + from plone.app.event.portlets.portlet_calendar import Renderer + HAS_PLONE_APP_EVENT = True +except ImportError: # Plone 4.x + from plone.app.portlets.portlets.calendar import Assignment + from plone.app.portlets.portlets.calendar import Renderer + HAS_PLONE_APP_EVENT = False class ICalendarTile(IPersistentCoverTile): - pass + + """A tile that shows a calendar of published events.""" @implementer(ICalendarTile) class CalendarTile(PersistentCoverTile): - """Calendar Tile code is coppied from plone.app.portlet Portlet Calendar + + """A tile that shows a calendar of published events. + + The implementation is a wraper of the calendar portlet. """ index = ViewPageTemplateFile('templates/calendar.pt') - is_configurable = False is_editable = False is_droppable = False short_name = _(u'msg_short_name_calendar', default=u'Calendar') - def __init__(self, context, request): - super(CalendarTile, self).__init__(context, request) - self._setup() - - def _setup(self): - context = aq_inner(self.context) - self.calendar = getToolByName(context, 'portal_calendar') - self._ts = getToolByName(context, 'translation_service') - self.url_quote_plus = quote_plus - - self.now = localtime() - self.yearmonth = yearmonth = self.getYearAndMonthToDisplay() - self.year = year = yearmonth[0] - self.month = month = yearmonth[1] - - self.showPrevMonth = yearmonth > (self.now[0] - 1, self.now[1]) - self.showNextMonth = yearmonth < (self.now[0] + 1, self.now[1]) + def __call__(self, *args, **kwargs): + self.setup() + return super(CalendarTile, self).__call__(*args, **kwargs) - self.prevMonthYear, self.prevMonthMonth = self.getPreviousMonth(year, month) - self.nextMonthYear, self.nextMonthMonth = self.getNextMonth(year, month) + def setup(self): + helper = Renderer(self.context, self.request, None, None, Assignment()) + helper.update() - self.monthName = PLMF(self._ts.month_msgid(month), - default=self._ts.month_english(month)) + if HAS_PLONE_APP_EVENT: + self.helper_template = helper.render + else: + self.helper_template = helper._template def accepted_ct(self): """Return an empty list as no content types are accepted.""" return [] - - def getEventsForCalendar(self): - context = aq_inner(self.context) - year = self.year - month = self.month - portal_state = getMultiAdapter((self.context, self.request), name='plone_portal_state') - navigation_root_path = portal_state.navigation_root_path() - weeks = self.calendar.getEventsForCalendar(month, year, path=navigation_root_path) - for week in weeks: - for day in week: - daynumber = day['day'] - if daynumber == 0: - continue - day['is_today'] = self.isToday(daynumber) - if day['event']: - cur_date = DateTime(year, month, daynumber) - localized_date = [self._ts.ulocalized_time(cur_date, context=context, request=self.request)] - day['eventstring'] = '\n'.join(localized_date + [ - ' {0}'.format(self.getEventString(e)) for e in day['eventslist']]) - day['date_string'] = '{0}-{1}-{2}'.format(year, month, daynumber) - - return weeks - - def getEventString(self, event): - start = event['start'] and ':'.join(event['start'].split(':')[:2]) or '' - end = event['end'] and ':'.join(event['end'].split(':')[:2]) or '' - title = safe_unicode(event['title']) or u'event' - - if start and end: - eventstring = '{0}-{1} {2}'.format(start, end, title) - elif start: # can assume not event['end'] - eventstring = '{0} - {1}'.format(start, title) - elif event['end']: # can assume not event['start'] - eventstring = '{0} - {1}'.format(title, end) - else: # can assume not event['start'] and not event['end'] - eventstring = title - - return eventstring - - def getYearAndMonthToDisplay(self): - session = None - request = self.request - - # First priority goes to the data in the REQUEST - year = request.get('year', None) - month = request.get('month', None) - - # Next get the data from the SESSION - if self.calendar.getUseSession(): - session = request.get('SESSION', None) - if session: - if not year: - year = session.get('calendar_year', None) - if not month: - month = session.get('calendar_month', None) - - # Last resort to today - if not year: - year = self.now[0] - if not month: - month = self.now[1] - - # try to transform to number but fall back to current - # date if this is ambiguous - try: - year, month = int(year), int(month) - except (TypeError, ValueError): - year, month = self.now[:2] - - # Store the results in the session for next time - if session: - session.set('calendar_year', year) - session.set('calendar_month', month) - - # Finally return the results - return year, month - - def getPreviousMonth(self, year, month): - if month == 0 or month == 1: - month, year = 12, year - 1 - else: - month -= 1 - return (year, month) - - def getNextMonth(self, year, month): - if month == 12: - month, year = 1, year + 1 - else: - month += 1 - return (year, month) - - def getWeekdays(self): - """Returns a list of Messages for the weekday names.""" - weekdays = [] - # list of ordered weekdays as numbers - for day in self.calendar.getDayNumbers(): - weekdays.append(PLMF(self._ts.day_msgid(day, format='s'), - default=self._ts.weekday_english(day, format='a'))) - - return weekdays - - def isToday(self, day): - """Returns True if the given day and the current month and year equals - today, otherwise False. - """ - return ( - self.now[2] == day and self.now[1] == self.month and self.now[0] == self.year) - - def getReviewStateString(self): - states = self.calendar.getCalendarStates() - return ''.join(map(lambda x: 'review_state={0}&'.format(self.url_quote_plus(x)), states)) - - def getEventTypes(self): - types = self.calendar.getCalendarTypes() - return ''.join(map(lambda x: 'Type={0}&'.format(self.url_quote_plus(x)), types)) - - def getQueryString(self): - request = self.request - query_string = request.get('orig_query', - request.get('QUERY_STRING', None)) - if len(query_string) == 0: - query_string = '' - else: - query_string = '{0}&'.format(query_string) - return query_string diff --git a/src/collective/cover/tiles/templates/calendar.pt b/src/collective/cover/tiles/templates/calendar.pt index 498c13e89..07ff08837 100644 --- a/src/collective/cover/tiles/templates/calendar.pt +++ b/src/collective/cover/tiles/templates/calendar.pt @@ -1,96 +1,10 @@ + i18n:domain="collective.cover">
-
- « - - monthname - year - - » -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Month name
Su
- - 31 - - - 31 - 31
-
+ tal:content="structure view/helper_template">
diff --git a/src/collective/cover/tiles/tiles.zcml b/src/collective/cover/tiles/tiles.zcml index b3105e297..d3e3fa7e0 100644 --- a/src/collective/cover/tiles/tiles.zcml +++ b/src/collective/cover/tiles/tiles.zcml @@ -129,7 +129,7 @@ + diff --git a/src/collective/cover/upgrades/v15/__init__.py b/src/collective/cover/upgrades/v15/__init__.py new file mode 100644 index 000000000..40a96afc6 --- /dev/null +++ b/src/collective/cover/upgrades/v15/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/src/collective/cover/upgrades/v15/configure.zcml b/src/collective/cover/upgrades/v15/configure.zcml new file mode 100644 index 000000000..6e5f304c4 --- /dev/null +++ b/src/collective/cover/upgrades/v15/configure.zcml @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/src/collective/cover/vocabularies.py b/src/collective/cover/vocabularies.py index 69126afd9..cb2e43899 100644 --- a/src/collective/cover/vocabularies.py +++ b/src/collective/cover/vocabularies.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from collective.cover.config import IS_PLONE_5 from collective.cover.controlpanel import ICoverSettings from collective.cover.interfaces import IGridSystem from collective.cover.tiles.base import IPersistentCoverTile @@ -36,10 +35,6 @@ def __call__(self, context): settings = registry.forInterface(ICoverSettings) tiles = settings.available_tiles - # FIXME: https://github.com/collective/collective.cover/issues/633 - if IS_PLONE_5 and 'collective.cover.calendar' in tiles: - tiles.remove('collective.cover.calendar') - items = [SimpleTerm(value=i, title=i) for i in tiles] return SimpleVocabulary(items) @@ -59,10 +54,6 @@ class EnabledTilesVocabulary(object): """Return a list of tiles ready to work with collective.cover.""" def _enabled(self, name): - # FIXME: https://github.com/collective/collective.cover/issues/633 - if IS_PLONE_5 and name == 'collective.cover.calendar': - return False - tile_type = queryUtility(ITileType, name) if tile_type: return issubclass(tile_type.schema, IPersistentCoverTile)