Skip to content

Commit

Permalink
Merge pull request #23 from collective/issue_15
Browse files Browse the repository at this point in the history
implement selection of location in portlet
  • Loading branch information
hvelarde committed Nov 1, 2013
2 parents 207245d + bff2f06 commit 7f99ef5
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 29 deletions.
2 changes: 1 addition & 1 deletion CHANGES.rst
Expand Up @@ -6,7 +6,7 @@ There's a frood who really knows where his towel is.
1.0a4 (unreleased)
^^^^^^^^^^^^^^^^^^

- Nothing changed yet.
- Configurable weather portlet (header and location). [marcosfromero]


1.0a3 (2013-10-29)
Expand Down
4 changes: 2 additions & 2 deletions src/collective/weather/browser/css/style.css
Expand Up @@ -33,7 +33,7 @@ dl.actionMenu a#current-city{
right: 0;
}

#top-weather-viewlet #current-weather {
#top-weather-viewlet .current-weather {
float: right;
padding-right: 0.5em;
}
Expand All @@ -59,4 +59,4 @@ dl.actionMenu a.city-not-selected {
.portletWeather dd {
text-align: right;
padding: 1em 0;
}
}
2 changes: 1 addition & 1 deletion src/collective/weather/browser/js/weather.js
Expand Up @@ -15,7 +15,7 @@ function showCityWeather(cityId){
async : true,
data: data,
success: function(results){
$("div#current-weather").parent().html(results);
$("#top-weather-viewlet .current-weather").parent().html(results);
createCookie("collective.weather.current_city", cityId, 30);
}
});
Expand Down
Expand Up @@ -9,7 +9,7 @@
tal:attributes="data-city-id city_id">
<span tal:content="city_name">Córdoba, Argentina</span>
</a>
<div id="current-weather">
<div class="current-weather">
<div tal:condition="view/weather_info">
<tal:block tal:define="current_weather python:view.weather_info['weather']">
<img class="weather-icon"
Expand Down
7 changes: 7 additions & 0 deletions src/collective/weather/configure.zcml
Expand Up @@ -58,4 +58,11 @@
layer="collective.weather.interfaces.IWeatherLayer"
/>

<!-- Vocabularies -->
<utility
provides="zope.schema.interfaces.IVocabularyFactory"
component=".vocabularies.LocationsVocabulary"
name="collective.weather.Locations"
/>

</configure>
1 change: 1 addition & 0 deletions src/collective/weather/portlets/configure.zcml
Expand Up @@ -12,6 +12,7 @@
edit_permission="cmf.ManagePortal"
renderer=".weather.Renderer"
addview=".weather.AddForm"
editview=".weather.EditForm"
/>

</configure>
34 changes: 31 additions & 3 deletions src/collective/weather/portlets/weather.pt
@@ -1,11 +1,39 @@
<dl class="portlet portletWeather"
i18n:domain="collective.weather"
tal:define="portal context/@@plone_portal_state/portal">
tal:define="portal context/@@plone_portal_state/portal;
current_city view/current_city|nothing"
tal:condition="current_city">

<dt class="portletHeader">
<span i18n:translate="">Weather</span>
<span tal:content="view/data/header">Weather</span>
</dt>

<dd tal:content="structure portal/current-weather" />
<dd i18n:domain="collective.weather"
tal:condition="current_city">

<span tal:define="city_name current_city/name|nothing"
tal:content="city_name">Cordoba, Argentina
</span>
<div class="current-weather"
tal:define="weather_info view/weather_info|nothing">
<div tal:condition="weather_info">
<tal:block tal:define="current_weather python:weather_info['weather']">
<img class="weather-icon"
tal:attributes="src python:current_weather['icon'];
title python:current_weather['conditions'];
alt python:current_weather['conditions']"
i18n:attributes="alt; title" />
<span class="weather-temp" tal:content="python:current_weather['temp']" />
</tal:block>
</div>

<div tal:condition="not:weather_info">
<img class="weather-icon" title="No weather information" alt="No weather information"
tal:attributes="src string:++resource++collective.weather.icons/NA.png"
i18n:attributes="alt; title" />
</div>
</div>

</dd>

</dl>
80 changes: 63 additions & 17 deletions src/collective/weather/portlets/weather.py
Expand Up @@ -3,46 +3,92 @@
from collective.weather import _
from collective.weather.interfaces import IWeatherUtility
from plone.app.portlets.portlets import base
from plone.app.portlets.browser.formhelper import NullAddForm
from plone.portlets.interfaces import IPortletDataProvider
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from zope import schema
from zope.component import getUtility
from zope.formlib import form
from zope.interface import implements
from zope.schema.interfaces import IVocabularyFactory


class IWeatherPortlet(IPortletDataProvider):
"""A weather portlet.
"""
'''A weather portlet.
'''

header = schema.TextLine(
title=_(u'Portlet header'),
description=_(u'Title of the rendered portlet.'),
required=True,
)

location = schema.Choice(
title=_(u'Location'),
description=_(u'Choose one of the preconfigured locations.'),
required=True,
vocabulary='collective.weather.Locations',
)


class Assignment(base.Assignment):
"""Portlet assignment.
"""
'''Portlet assignment.
'''

implements(IWeatherPortlet)

header = u''
location = u''

def __init__(self, header=u'', location=u''):
self.header = header
self.location = location

@property
def title(self):
"""This property is used to give the title of the portlet in the
"manage portlets" screen.
"""
return _(u'Weather portlet')
'''This property is used to give the title of the portlet in the
'manage portlets' screen.
'''
return self.header


class Renderer(base.Renderer):
"""Portlet renderer.
"""
'''Portlet renderer.
'''

render = ViewPageTemplateFile('weather.pt')

def update(self):
weather_utility = getUtility(IWeatherUtility)
self.weather_info = weather_utility.get_weather_info()
factory = getUtility(
IVocabularyFactory, name='collective.weather.Locations')
vocab = factory(self.context)
self.current_city = None
if self.data.location in vocab:
location = vocab.by_value[self.data.location]
self.current_city = {'id': location.value, 'name': location.title}

self.weather_info = None
if not self.current_city is None:
weather_utility.update_weather_info(self.current_city['id'])
self.weather_info = weather_utility.get_weather_info(self.current_city)


class AddForm(base.AddForm):
'''Portlet add form.
'''

form_fields = form.Fields(IWeatherPortlet)

label = _(u'Add Weather Portlet')

def create(self, data):
return Assignment(**data)


class EditForm(base.EditForm):
'''Portlet edit form.
'''

class AddForm(NullAddForm):
"""Portlet add form.
"""
form_fields = form.Fields(IWeatherPortlet)

def create(self):
return Assignment()
label = _(u'Edit Weather Portlet')
25 changes: 25 additions & 0 deletions src/collective/weather/tests/test_vocabularies.py
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-

from collective.weather.testing import INTEGRATION_TESTING
from zope.component import queryUtility
from zope.schema.interfaces import IVocabularyFactory

import unittest2 as unittest


class VocabulariesTestCase(unittest.TestCase):

layer = INTEGRATION_TESTING

def setUp(self):
self.portal = self.layer['portal']

def test_locations_vocabulary(self):
name = 'collective.weather.Locations'
util = queryUtility(IVocabularyFactory, name)
self.assertIsNotNone(util)
locations = util(self.portal)
# as defined in the test fixture
self.assertEqual(len(locations), 2)
self.assertIn('Cordoba', locations)
self.assertIn(u'Los Angeles', locations)
6 changes: 2 additions & 4 deletions src/collective/weather/tests/test_weather_portlet.py
Expand Up @@ -46,7 +46,6 @@ def test_interfaces(self):
self.assertTrue(IPortletAssignment.providedBy(portlet))
self.assertTrue(IPortletDataProvider.providedBy(portlet.data))

@unittest.skip('Portlet has no add view... yet')
def test_invoke_add_view(self):
portlet = getUtility(IPortletType, name=self.name)
mapping = self.portal.restrictedTraverse('++contextportlets++plone.leftcolumn')
Expand All @@ -55,12 +54,11 @@ def test_invoke_add_view(self):
del mapping[m]

addview = mapping.restrictedTraverse('+/' + portlet.addview)
addview.createAndAdd(data={})
addview.createAndAdd(data={'header': u'Weather', 'location': u'Cordoba'})

self.assertEqual(len(mapping), 1)
self.assertTrue(isinstance(mapping.values()[0], weather.Assignment))

@unittest.skip('Portlet has no edit view... yet')
def test_invoke_edit_view(self):
mapping = PortletAssignmentMapping()

Expand Down Expand Up @@ -101,7 +99,7 @@ def renderer(self, context=None, request=None, view=None, manager=None, assignme
(context, request, view, manager, assignment), IPortletRenderer)

def test_render(self):
assignment = weather.Assignment()
assignment = weather.Assignment(header=u'Weather', location=u'Cordoba')

r = self.renderer(assignment=assignment)
r = r.__of__(self.portal)
Expand Down
19 changes: 19 additions & 0 deletions src/collective/weather/vocabularies.py
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-

from collective.weather.interfaces import IWeatherUtility
from zope.component import getUtility
from zope.schema.vocabulary import SimpleVocabulary


def LocationsVocabulary(context):
"""Creates a vocabulary to expose configured locations.
"""

weather_utility = getUtility(IWeatherUtility)
locations = weather_utility.get_cities_list()
items = []
for l in locations:
items.append(
SimpleVocabulary.createTerm(l['id'], l['location_id'], l['name']))

return SimpleVocabulary(items)

0 comments on commit 7f99ef5

Please sign in to comment.