From 3d5046e0c424da09ffacb9e3d41bc8dbb4ab876b Mon Sep 17 00:00:00 2001 From: Michael Hall Date: Sun, 25 Mar 2018 14:40:29 -0400 Subject: [PATCH] Improve Lookup field to be more intuitive and show initial value. Move css out of base.html and into new static get_together.css. Fixes #57 --- events/forms.py | 52 +++++++----------- events/models/locale.py | 12 +++- events/templates/forms/widgets/lookup.html | 6 +- get_together/static/css/get_together.css | 40 ++++++++++++++ get_together/static/img/search_icon.png | Bin 0 -> 783 bytes get_together/static/js/jquery-ui-lookup.js | 7 ++- get_together/templates/get_together/base.html | 38 +------------ get_together/views/__init__.py | 19 ++++++- 8 files changed, 101 insertions(+), 73 deletions(-) create mode 100644 get_together/static/css/get_together.css create mode 100644 get_together/static/img/search_icon.png diff --git a/events/forms.py b/events/forms.py index af7af1d..f46f8bf 100644 --- a/events/forms.py +++ b/events/forms.py @@ -4,29 +4,13 @@ from django.forms.widgets import TextInput, Media from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User +from .models.locale import Country, SPR, City from .models.profiles import Team, UserProfile from .models.events import Event, EventComment ,CommonEvent, Place, EventPhoto from datetime import time from time import strptime, strftime -class LookupMedia(Media): - def render(self): - return mark_safe('''''') - class Lookup(TextInput): input_type = 'text' template_name = 'forms/widgets/lookup.html' @@ -34,7 +18,7 @@ class Lookup(TextInput): checked_attribute = {'selected': True} option_inherits_attrs = False - def __init__(self, source='#', key="id", label="name", attrs=None): + def __init__(self, source, key="id", label='__str__', attrs=None): super().__init__(attrs) self.source = source self.key = key @@ -42,14 +26,18 @@ class Lookup(TextInput): def get_context(self, name, value, attrs): context = super().get_context(name, value, attrs) - context['widget']['source'] = self.source - context['widget']['key'] = self.key - context['widget']['label'] = self.label return context def format_value(self, value): if value is not None: - return mark_safe('' % (value, _('No change'))) + lookup_query = {self.key: value} + lookup_object = self.source.objects.get(**lookup_query) + lookup_field = getattr(lookup_object, self.label) + if callable(lookup_field): + lookup_value = lookup_field() + else: + lookup_value = lookup_field + return mark_safe('' % (value, lookup_value)) else: return mark_safe('') @@ -152,7 +140,7 @@ class TeamForm(forms.ModelForm): model = Team fields = ['name', 'description', 'category', 'city', 'web_url', 'tz'] widgets = { - 'city': Lookup(source='/api/cities/', label='name'), + 'city': Lookup(source=City), } raw_id_fields = ('city') def __init__(self, *args, **kwargs): @@ -164,7 +152,7 @@ class NewTeamForm(forms.ModelForm): model = Team fields = ['name', 'description', 'category', 'city', 'web_url', 'tz'] widgets = { - 'city': Lookup(source='/api/cities/', label='name'), + 'city': Lookup(source=City), } raw_id_fields = ('city') def __init__(self, *args, **kwargs): @@ -179,7 +167,7 @@ class TeamEventForm(forms.ModelForm): model = Event fields = ['name', 'start_time', 'end_time', 'summary', 'place', 'web_url', 'announce_url', 'tags'] widgets = { - 'place': Lookup(source='/api/places/', label='name'), + 'place': Lookup(source=Place), 'start_time': DateTimeWidget, 'end_time': DateTimeWidget } @@ -211,7 +199,7 @@ class NewPlaceForm(forms.ModelForm): model = Place fields = ['name', 'address', 'city', 'longitude', 'latitude', 'place_url', 'tz'] widgets = { - 'city': Lookup(source='/api/cities/', label='name'), + 'city': Lookup(source=City), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -244,11 +232,11 @@ class SendNotificationsForm(forms.ModelForm): } class SearchForm(forms.Form): - city = forms.IntegerField(required=False, widget=Lookup(source='/api/cities/', label='name')) + city = forms.IntegerField(required=False, widget=Lookup(source=City, label='name')) distance = forms.IntegerField(label=_("Distance(km)"), required=True) class Meta: widgets ={ - 'city': Lookup(source='/api/cities/', label='name'), + 'city': Lookup(source=City, label='name'), } class NewCommonEventForm(forms.ModelForm): @@ -272,10 +260,10 @@ class NewCommonEventForm(forms.ModelForm): 'tags', ] widgets ={ - 'country': Lookup(source='/api/countries/', label='name'), - 'spr': Lookup(source='/api/spr/', label='name'), - 'city': Lookup(source='/api/cities/', label='name'), - 'place': Lookup(source='/api/places/', label='name'), + 'country': Lookup(source=Country, label='name'), + 'spr': Lookup(source=SPR, label='name'), + 'city': Lookup(source=City, label='name'), + 'place': Lookup(source=Place, label='name'), 'start_time': DateTimeWidget, 'end_time': DateTimeWidget } diff --git a/events/models/locale.py b/events/models/locale.py index 561bd37..7e48fa0 100644 --- a/events/models/locale.py +++ b/events/models/locale.py @@ -44,12 +44,14 @@ class Country(models.Model): return 'no_country' class CountrySerializer(serializers.ModelSerializer): + display = serializers.CharField(source='__str__', read_only=True) class Meta: model = Country fields = ( 'id', 'name', - 'code' + 'code', + 'display', ) class SPR(models.Model): @@ -94,6 +96,13 @@ class City(models.Model): longitude = models.FloatField(help_text=_('Longitude in Degrees East'), null=True, blank=True) latitude = models.FloatField(help_text=_('Latitude in Degrees North'), null=True, blank=True) + @property + def short_name(self): + if self.spr.country.name == 'United States': + return u'%s, %s' % (self.name, self.spr.name) + else: + return u'%s, %s' % (self.name, self.spr.country.name) + def __str__(self): return u'%s, %s, %s' % (self.name, self.spr.name, self.spr.country.name) @@ -112,6 +121,7 @@ class CitySerializer(serializers.ModelSerializer): fields = ( 'id', 'name', + 'short_name', 'spr', 'tz', 'slug', diff --git a/events/templates/forms/widgets/lookup.html b/events/templates/forms/widgets/lookup.html index 35c8aea..2cdffa1 100644 --- a/events/templates/forms/widgets/lookup.html +++ b/events/templates/forms/widgets/lookup.html @@ -1,4 +1,6 @@ - + {{ widget.value }} + diff --git a/get_together/static/css/get_together.css b/get_together/static/css/get_together.css new file mode 100644 index 0000000..d834704 --- /dev/null +++ b/get_together/static/css/get_together.css @@ -0,0 +1,40 @@ +body { + padding-top: 5rem; +} +.footer { + padding-top: 1em; + padding-bottom: 1em; + border-top: #cfcfcf 1px solid; + background-color: #f5f5f5; + color: #aaaaaa; +} +.footer ul { + display: inline; + list-style-type: none; + margin-left: 0.5em; +} +.footer ul li { + display: inline; + margin-left: 0.5em; +} +.footer a { + text-decoration: none; + color: inherit; +} +.starter-template { + padding: 3rem 1.5rem; + text-align: center; +} +form { + display: inline; +} +.ui-selectmenu-menu .ui-menu { + height: 200px; +} +.gt_lookup .ui-selectmenu-icon.ui-icon { + background-position: 0px 0px; + background-image: url(/static/img/search_icon.png); + width: 16px; + height: 16px; +} + diff --git a/get_together/static/img/search_icon.png b/get_together/static/img/search_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..30d095f83b20cd1c2f4d77fdebb78e622ccf8814 GIT binary patch literal 783 zcmV+q1MvKbP)*8&Mnw@b6vHBXN+BwxJ;{^&iB9;#5dAC=NX-B&6EGrJR9w5C@B7bl0I< zi^WC6WDpT^ry*cNgII_Wg8>(bA$nkQ($;2(kxMV!d9O=Rlh(oS_2%iZHv+)g+8Wi~-tOml{?q#U`XgDE zp{gnj2E#*!VZIg$1?}+gFw)V{@wV|oBLFxY4&Tz!QY@3nz-qO^<#K(iR;!6xt!ATX z`sMEKuAx{gzS-E=I4cwiq0!ONE8+O~*gHKvO<0yC!C;VxqBto@k^ulpr4j`IGcz;9 z=kt+?i3tJ#xm@lFNF);P0)YVGIF5*-IN8{uAP7`0m%BGMHuk%(ua9hQZj$TkbhTRj zpePDF9uE{ndEW>O4Gj^O%T;1owq`b)5sSsNI-pXiKvh*-TwH|RZnuUT(%RaJrluwo zi^aM+Z8Dia(=-@{c_xY?eG^bFm!YaEnwy)^*g?=_GU4dx$l2D`rf+R+QU3!{sT8SH zD(LU;H`W22ot+t*%~spn+arsMi^Svc+y#JaHhT%p&dz?!X0sND!+}5`@Zvf^0l?1A zPHAdt%1Q{K>~_1taolNdZ|~#%{e2RNM9K#T2Nqq|p{goEp-^dHVBr2Gu)V#F?(S~H zCEX#yp7+5S8N>LQ(x(-EAFfuZdlhpyOi;LG;_>+Rxw*Lqx~^k*c=*??4zI4R0svN4Rz3@Ya7qX<`~j?+H_3@%uaE!$ N002ovPDHLkV1h^lX)^!- literal 0 HcmV?d00001 diff --git a/get_together/static/js/jquery-ui-lookup.js b/get_together/static/js/jquery-ui-lookup.js index 9725270..2501e73 100644 --- a/get_together/static/js/jquery-ui-lookup.js +++ b/get_together/static/js/jquery-ui-lookup.js @@ -22,7 +22,7 @@ _drawSearch: function() { var self = this; var selectField = this.element[0]; - this.searchField = $(''); + this.searchField = $(''); //this._addClass( this.searchField, "ui-selectmenu-menu", "ui-front" ); this.searchField.keyup(function() { self.options.search(this.value, function(searchText, results){ @@ -39,8 +39,11 @@ }); }); this.menuWrap.prepend(this.searchField); + }, + open: function(event) { + this._super() + this.searchField.focus() } - }); }(jQuery)); diff --git a/get_together/templates/get_together/base.html b/get_together/templates/get_together/base.html index c2af59f..656ce9b 100644 --- a/get_together/templates/get_together/base.html +++ b/get_together/templates/get_together/base.html @@ -28,43 +28,11 @@ + + {%block styles %}{% endblock %} - + diff --git a/get_together/views/__init__.py b/get_together/views/__init__.py index 1793320..dd6292c 100644 --- a/get_together/views/__init__.py +++ b/get_together/views/__init__.py @@ -43,6 +43,7 @@ def home(request, *args, **kwards): near_distance = int(request.GET.get("distance", DEFAULT_NEAR_DISTANCE)) context['distance'] = near_distance + city=None ll = None if "city" in request.GET and request.GET.get("city"): context['city_search'] = True @@ -56,6 +57,22 @@ def home(request, *args, **kwards): if g.latlng is not None and g.latlng[0] is not None and g.latlng[1] is not None: ll = g.latlng context['geoip_lookup'] = True + + try: + city_distance = 1 #km + while city is None and city_distance < 100: + minlat = ll[0]-(city_distance/KM_PER_DEGREE_LAT) + maxlat = ll[0]+(city_distance/KM_PER_DEGREE_LAT) + minlng = ll[1]-(city_distance/(KM_PER_DEGREE_LNG*math.cos(math.radians(ll[0])))) + maxlng = ll[1]+(city_distance/(KM_PER_DEGREE_LNG*math.cos(math.radians(ll[0])))) + nearby_cities = City.objects.filter(latitude__gte=minlat, latitude__lte=maxlat, longitude__gte=minlng, longitude__lte=maxlng) + if len(nearby_cities) == 0: + city_distance += 1 + else: + city = nearby_cities[0] + except: + pass # City lookup failed + except Exception as err: context['geoip_lookup'] = False print("Geocoder lookup failed for %s" % client_ip, err) @@ -84,7 +101,7 @@ def home(request, *args, **kwards): print("Error looking up nearby teams and events", err) traceback.print_exc() - search_form = SearchForm(initial={'distance': near_distance}) + search_form = SearchForm(initial={'city': city.id, 'distance': near_distance}) context['search_form'] = search_form return render(request, 'get_together/index.html', context)