Commit 0a22f9a0 authored by njoyard's avatar njoyard

Merge branch 'autocomplete-all-the-things' into 'master'

Autocomplete all the things



See merge request !175
parents 2a3afb72 ec5ff1db
......@@ -11,7 +11,7 @@ setup(name='political-memory',
author_email='cortex@worlddomination.be',
url='http://github.com/political-memory/political_memory/',
install_requires=[
'django-autocomplete-light==3.1.6',
'django-autocomplete-light==3.2.0',
'django-autoslug>=1.9,<1.10',
'django-bootstrap3>=6,<7',
'django-coffeescript>=0.7,<0.8',
......
from memopol_settings.models import Setting
from representatives.models import Chamber, Group
from .forms import DossierSearchForm, RepresentativeSearchForm
def search_form_options(request):
d = {}
# Note: Those queries needs to be eval in the template so that we can cache
# it efficiently
from memopol_settings.models import Setting
d['chambers'] = Chamber.objects.all()
d['countries'] = Group.objects.filter(kind='country')
d['parties'] = Group.objects.filter(kind='group')
d['delegations'] = Group.objects.filter(kind='delegation')
d['committees'] = Group.objects.filter(kind='committee')
return d
def search_forms(request):
return {
'representative_search_form': RepresentativeSearchForm(request.GET),
'dossier_search_form': DossierSearchForm(request.GET)
}
def intro_text(request):
......
from django import forms
from dal import autocomplete, forward
from representatives.models import Chamber, Group
class RepresentativeSearchForm(forms.Form):
search = forms.CharField(
required=False,
label='Name',
widget=forms.TextInput(attrs={'placeholder': ''})
)
scoremin = forms.FloatField(
required=False,
label='Between',
widget=forms.NumberInput(attrs={'placeholder': 'Min. score'})
)
scoremax = forms.FloatField(
required=False,
label='and',
widget=forms.NumberInput(attrs={'placeholder': 'Max. score'})
)
chamber = forms.ModelChoiceField(
queryset=Chamber.objects.all(),
required=False,
widget=autocomplete.ModelSelect2(
url='chamber-autocomplete',
attrs={'data-html': 'true'}
)
)
country = forms.ModelChoiceField(
queryset=Group.objects.filter(kind='country'),
required=False,
widget=autocomplete.ModelSelect2(
url='group-autocomplete',
forward=(forward.Const('country', 'kind'),),
attrs={'data-html': 'true'}
)
)
party = forms.ModelChoiceField(
queryset=Group.objects.filter(kind='group'),
required=False,
widget=autocomplete.ModelSelect2(
url='group-autocomplete',
forward=(forward.Const('group', 'kind'),),
attrs={'data-html': 'true'}
)
)
committee = forms.ModelChoiceField(
queryset=Group.objects.filter(kind='committee'),
required=False,
widget=autocomplete.ModelSelect2(
url='group-autocomplete',
forward=(forward.Const('committee', 'kind'),),
attrs={'data-html': 'true'}
)
)
delegation = forms.ModelChoiceField(
queryset=Group.objects.filter(kind='delegation'),
required=False,
widget=autocomplete.ModelSelect2(
url='group-autocomplete',
forward=(forward.Const('delegation', 'kind'),),
attrs={'data-html': 'true'}
)
)
class DossierSearchForm(forms.Form):
search = forms.CharField(
required=False,
label='Name',
widget=forms.TextInput(attrs={'placeholder': ''})
)
chamber = forms.ModelChoiceField(
queryset=Chamber.objects.all(),
required=False,
widget=autocomplete.ModelSelect2(
url='chamber-autocomplete',
attrs={'data-html': 'true'}
)
)
......@@ -133,7 +133,7 @@ TEMPLATE_LOADERS = (
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'django.template.context_processors.request',
'memopol.context_processors.search_form_options',
'memopol.context_processors.search_forms',
'memopol.context_processors.intro_text'
)
......
......@@ -59,7 +59,7 @@ a.tag:hover {
}
body, .panel-title {
font-family: FiraSansRegulat, "Helvetica Neue",Helvetica,Arial,sans-serif;
font-family: FiraSansRegular, "Helvetica Neue",Helvetica,Arial,sans-serif;
}
h2, h3, h4, h5, h6 {
......@@ -99,7 +99,7 @@ label {
font-weight: 400;
}
.form-control, input, textarea {
.form-control, .control-label, input, textarea {
color: #212121 !important;
}
......@@ -129,7 +129,7 @@ label {
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);
}
textarea, textarea.form-control, input.form-control, input[type=text], input[type=password], input[type=email], input[type=number], [type=text].form-control, [type=password].form-control, [type=email].form-control, [type=tel].form-control, [contenteditable].form-control {
textarea, textarea.form-control, input.form-control, input[type=text], input[type=number], input[type=password], input[type=email], input[type=number], [type=text].form-control, [type=number].form-control, [type=password].form-control, [type=email].form-control, [type=tel].form-control, [contenteditable].form-control {
padding: 0;
border: none;
border-radius: 0;
......@@ -138,7 +138,7 @@ textarea, textarea.form-control, input.form-control, input[type=text], input[typ
box-shadow: inset 0 -1px 0 #ddd;
}
textarea:focus, textarea.form-control:focus, input.form-control:focus, input[type=text]:focus, input[type=password]:focus, input[type=email]:focus, input[type=number]:focus, [type=text].form-control:focus, [type=password].form-control:focus, [type=email].form-control:focus, [type=tel].form-control:focus, [contenteditable].form-control:focus {
textarea:focus, textarea.form-control:focus, input.form-control:focus, input[type=text]:focus, input[type=number]:focus, input[type=password]:focus, input[type=email]:focus, input[type=number]:focus, [type=text].form-control:focus, [type=number].form-control:focus, [type=password].form-control:focus, [type=email].form-control:focus, [type=tel].form-control:focus, [contenteditable].form-control:focus {
-webkit-box-shadow: inset 0 -2px 0 #487ED6;
box-shadow: inset 0 -2px 0 #487ED6;
}
......@@ -167,6 +167,49 @@ select:focus, select.form-control:focus {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAAJ1BMVEVmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmaP/QSjAAAADHRSTlMAAgMJC0uWpKa6wMxMdjkoAAAANUlEQVR4AeXJyQEAERAAsNl7Hf3X6xt0QL6JpZWq30pdvdadme+0PMdzvHm8YThHcT1H7K0BtOMDniZhWOgAAAAASUVORK5CYII=);
}
/***************************************************************
Select2
***************************************************************/
.select2-selection {
border: none !important;
border-radius: 0 !important;
box-shadow: rgb(221, 221, 221) 0px -1px 0px 0px inset !important;
}
.select2-container--focus .select2-selection {
box-shadow: rgb(72, 126, 214) 0px -2px 0px 0px inset !important;
}
.select2-selection__choice {
background-color: #487ED6 !important;
padding: .2em .6em .3em !important;
color: #fff !important;
vertical-align: baseline !important;
border-radius: .25em !important;
border-color: #487ED6 !important;
font-size: 80% !important;
font-weight: bold !important;
}
.select2-selection__choice__remove {
color: #fff !important;
}
.select2-icon-result {
display: flex;
flex-flow: row nowrap;
}
.select2-icon-result .group-icon {
flex-shrink: 0;
}
.select2-icon-result .select2-label {
flex-grow: 1;
}
/***************************************************************
Buttons
***************************************************************/
......@@ -485,6 +528,14 @@ iframe {
height: 1.75em;
}
.select2-icon-result .chamber-icon,
.select2-icon-result .group-icon,
.select2-icon-result .flag-icon {
width: 1.75em;
height: 1.75em;
margin-right: 0.5em;
}
.flag-icon:before {
content: initial;
}
......
{% load i18n memopol_tags %}
{% load fontawesome %}
{% load bootstrap3 %}
<form class="form-horizontal hidden-print" method="GET" action="{% url "representative-list" %}">
<div class="input-group">
......@@ -30,97 +31,20 @@
aria-expanded="{% if view == 'representative_list' and filter.data %}true{% else %}false{% endif %}" id="form-rep">
<form id="rep-search-form" class="form-horizontal" method="GET" action="{% url "representative-list" %}">
<div class="form-group">
<label class="col-sm-3" for="search-rep">{% trans "Name" %}</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="search" id="search-rep" value="{{ filter.data.search }}">
{% bootstrap_field representative_search_form.search layout='horizontal' %}
<div class="row">
<div class="col-md-7">
{% bootstrap_field representative_search_form.scoremin layout='horizontal' horizontal_label_class='col-md-5' horizontal_field_class='col-md-7' placeholder='prout' %}
</div>
</div>
<div class="form-group">
<label class="col-sm-3" for="score-min">{% trans "Score between" %}</label>
<div class="col-sm-4">
<input type="number" class="form-control" name="scoremin" id="score-min" value="{{ filter.data.scoremin }}">
</div>
<label class="col-sm-1" for="score-max">{% trans "and" %}</label>
<div class="col-sm-4">
<input type="number" class="form-control" name="scoremax" id="score-max" value="{{ filter.data.scoremax }}">
<div class="col-md-5">
{% bootstrap_field representative_search_form.scoremax layout='horizontal' horizontal_label_class='col-md-2' horizontal_field_class='col-md-10' %}
</div>
</div>
<div class="form-group">
<label class="col-sm-3" for="chamber-rep">{% trans "Chamber" %}</label>
<div class="col-sm-9">
<select class="form-control" id="chamber-rep" name="chamber">
<option value="">{% trans "All" %}</option>
{% for chamber in chambers %}
<option {% if filter.data.chamber = chamber.id|cast_str %}selected{% endif %} value="{{ chamber.id }}">
{{ chamber.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3" for="country">{% trans "Country" %}</label>
<div class="col-sm-9">
<select class="form-control" id="country" name="country">
<option value="">{% trans "All" %}</option>
{% for country in countries %}
<option {% if filter.data.country = country.id|cast_str %}selected{% endif %} value="{{ country.id }}">
{% if country.abbreviation %}{{ country.abbreviation }} &ndash;{% endif %}
{{ country.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3" for="party">{% trans "Party" %}</label>
<div class="col-sm-9">
<select class="form-control" id="party" name="party">
<option value="">{% trans "All" %}</option>
{% for party in parties %}
<option {% if filter.data.party = party.pk|cast_str %}selected{% endif %} value="{{ party.pk }}">
{% if party.abbreviation %}{{ party.abbreviation }} &ndash;{% endif %}
{{ party.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3" for="committee">{% trans "Committee" %}</label>
<div class="col-sm-9">
<select class="form-control" id="committee" name="committee">
<option value="">{% trans "All" %}</option>
{% for committee in committees %}
<option {% if filter.data.committee = committee.pk|cast_str %}selected{% endif %} value="{{ committee.pk }}" data-url="{% url "representative-list" %}?committee={{ committee.pk }}">
{% if committee.abbreviation %}{{ committee.abbreviation }} &ndash;{% endif %}
{{ committee.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3" for="delegation">{% trans "Delegation" %}</label>
<div class="col-sm-9">
<select class="form-control" id="delegation" name="delegation">
<option value="">{% trans "All" %}</option>
{% for delegation in delegations %}
<option {% if filter.data.delegation = delegation.pk|cast_str %}selected{% endif %} value="{{ delegation.pk }}" data-url="{% url "representative-list" %}?delegation={{ delegation.pk }}">
{{ delegation.name }}
</option>
{% endfor %}
</select>
</div>
</div>
{% bootstrap_field representative_search_form.chamber layout='horizontal' %}
{% bootstrap_field representative_search_form.country layout='horizontal' %}
{% bootstrap_field representative_search_form.party layout='horizontal' %}
{% bootstrap_field representative_search_form.committee layout='horizontal' %}
{% bootstrap_field representative_search_form.delegation layout='horizontal' %}
<button type="submit" class="btn btn-default">{% trans "Search" %}</button>
</form>
</div>
......@@ -133,29 +57,10 @@
<div class="collapse{% if view == 'dossier_list' and filter.data %} in{% endif %}"
aria-expanded="{% if view == 'dossier_list' and filter.data %}true{% else %}false{% endif %}" id="form-dossier">
<form id="dossier-search-form" class="form-horizontal" method="GET" action="{% url "dossier-list" %}">
<div class="form-group">
<label class="col-sm-3" for="search-dossier">{% trans "Name" %}</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="search" id="search-dossier" value="{{ filter.data.search }}">
</div>
</div>
<div class="form-group">
<label class="col-sm-3" for="chamber-dossier">{% trans "Chamber" %}</label>
<div class="col-sm-9">
<select class="form-control" name="chamber" id="chamber-dossier">
<option value="">{% trans "All" %}</option>
{% for chamber in chambers %}
<option {% if filter.data.chamber = chamber.id|cast_str %}selected{% endif %} value="{{ chamber.id }}">
{{ chamber.name }}
</option>
{% endfor %}
</select>
</div>
</div>
{% bootstrap_field dossier_search_form.search layout='horizontal' %}
{% bootstrap_field dossier_search_form.chamber layout='horizontal' %}
<button type="submit" class="btn btn-default">{% trans "Search" %}</button>
</form>
</div>
</div>
\ No newline at end of file
</div>
......@@ -9,16 +9,8 @@ class BaseTest(ResponseDiffTestMixin, test.TestCase):
"""
Common queries
- 1 for settings
- 5 for search forms
- 1 for chambers
- 1 for countries
- 1 for parties
- 1 for committees
- 1 for delegations
- 1 for the position form
- 1 for themes
"""
left_pane_queries = 7
left_pane_queries = 1
def setUp(self):
RepresentativeScore.refresh()
......@@ -72,8 +64,9 @@ class ThemeBaseTest(BaseTest):
"""
Common queries plus:
- 1 for the theme
- 1 for DAL to fetch its initial value in the position form
"""
queries = BaseTest.left_pane_queries + 1
queries = BaseTest.left_pane_queries + 2
@property
def url(self):
......
<option value="">All</option>
---
<option value="1">
European Parliament
</option>
---
<option value="2">
Assemblée nationale
</option>
---
<option value="3">
Sénat
</option>
\ No newline at end of file
<option value="">All</option>
---
<option value="1">
European Parliament
</option>
---
<option value="2">
Assemblée nationale
</option>
---
<option value="3">
Sénat
</option>
\ No newline at end of file
<option value="">All</option>
---
<option data-url="/representatives/?committee=345" value="345">
AnComImmu –
Commission chargée de l'application de l'article 26 de la constitution
</option>
---
<option data-url="/representatives/?committee=274" value="274">
AnComDef –
Commission de la défense nationale et des forces armées
</option>
---
<option data-url="/representatives/?committee=387" value="387">
Commission d'enquête relative aux moyens mis en œuvre par l'État pour lutter contre le terrorisme depuis le 7 janvier
</option>
---
<option data-url="/representatives/?committee=876" value="876">
Commission d'enquête sur les conditions d'abattage des animaux de boucherie dans les abattoirs français
</option>
---
<option data-url="/representatives/?committee=484" value="484">
Commission d'enquête sur les conditions d'octroi d'une autorisation d'émettre à la chaîne numéro 23 et de sa vente
</option>
---
<option data-url="/representatives/?committee=1297" value="1297">
Commission d'enquête visant à évaluer les conséquences sur l'investissement public et les services publics de proximité de la baisse des dotations de l'État aux communes et aux epci
</option>
---
<option data-url="/representatives/?committee=335" value="335">
AnComCult –
Commission des affaires culturelles et de l'éducation
</option>
---
<option data-url="/representatives/?committee=427" value="427">
AnComEco –
Commission des affaires économiques
</option>
---
<option data-url="/representatives/?committee=285" value="285">
AnComEtrg –
Commission des affaires étrangères
</option>
---
<option data-url="/representatives/?committee=364" value="364">
AnComEU –
Commission des affaires européennes
</option>
---
<option data-url="/representatives/?committee=365" value="365">
AnComSoc –
Commission des affaires sociales
</option>
---
<option data-url="/representatives/?committee=401" value="401">
AnComFin –
Commission des finances, de l'économie générale et du contrôle budgétaire
</option>
---
<option data-url="/representatives/?committee=530" value="530">
AnComLois –
Commission des lois constitutionnelles, de la législation et de l'administration générale de la république
</option>
---
<option data-url="/representatives/?committee=423" value="423">
AnComDevD –
Commission du développement durable et de l'aménagement du territoire
</option>
---
<option data-url="/representatives/?committee=346" value="346">
Commission spéciale chargée d'examiner le projet de loi Égalité et citoyenneté
</option>
---
<option data-url="/representatives/?committee=1622" value="1622">
Commission spéciale chargée d'examiner le projet de loi pour la croissance et l'activité
</option>
---
<option data-url="/representatives/?committee=286" value="286">
Commission spéciale pour l'examen de la proposition de loi renforçant la lutte contre le système prostitutionnel
</option>
---
<option data-url="/representatives/?committee=47" value="47">
AGRI –
Committee on Agriculture and Rural Development
</option>
---
<option data-url="/representatives/?committee=89" value="89">
CONT –
Committee on Budgetary Control
</option>
---
<option data-url="/representatives/?committee=34" value="34">
BUDG –
Committee on Budgets
</option>
---
<option data-url="/representatives/?committee=7" value="7">
LIBE –
Committee on Civil Liberties, Justice and Home Affairs
</option>
---
<option data-url="/representatives/?committee=37" value="37">
AFCO –
Committee on Constitutional Affairs
</option>
---
<option data-url="/representatives/?committee=20" value="20">
CULT –
Committee on Culture and Education
</option>
---
<option data-url="/representatives/?committee=8" value="8">
DEVE –
Committee on Development
</option>
---
<option data-url="/representatives/?committee=30" value="30">
ECON –
Committee on Economic and Monetary Affairs
</option>
---
<option data-url="/representatives/?committee=3" value="3">
EMPL –
Committee on Employment and Social Affairs
</option>
---
<option data-url="/representatives/?committee=55" value="55">
PECH –
Committee on Fisheries
</option>
---
<option data-url="/representatives/?committee=5" value="5">
AFET –
Committee on Foreign Affairs
</option>
---
<option data-url="/representatives/?committee=23" value="23">
ITRE –
Committee on Industry, Research and Energy
</option>
---
<option data-url="/representatives/?committee=49" value="49">
INTA –
Committee on International Trade
</option>
---
<option data-url="/representatives/?committee=9" value="9">
JURI –
Committee on Legal Affairs
</option>
---
<option data-url="/representatives/?committee=6" value="6">
PETI –
Committee on Petitions
</option>
---
<option data-url="/representatives/?committee=24" value="24">
REGI –
Committee on Regional Development
</option>
---
<option data-url="/representatives/?committee=48" value="48">
ENVI –
Committee on the Environment, Public Health and Food Safety
</option>
---
<option data-url="/representatives/?committee=58" value="58">
IMCO –
Committee on the Internal Market and Consumer Protection
</option>
---
<option data-url="/representatives/?committee=68" value="68">
TRAN –
Committee on Transport and Tourism
</option>
---
<option data-url="/representatives/?committee=77" value="77">
FEMM –
Committee on Women's Rights and Gender Equality
</option>
---
<option data-url="/representatives/?committee=61" value="61">
CRIS –
Special Committee on the Financial, Economic and Social Crisis
</option>
---
<option data-url="/representatives/?committee=50" value="50">
SURE –
Special committee on the policy challenges and budgetary resources for a sustainable European Union after 2013
</option>
---
<option data-url="/representatives/?committee=4" value="4">
DROI –
Subcommittee on Human Rights
</option>
\ No newline at end of file
<option value="">All</option>
---
<option value="98">
BE –
Belgium
</option>
---
<option value="88">
CZ –
Czech Republic
</option>
---
<option value="110">
FR –
France
</option>
---
<option value="22">
DE –
Germany
</option>
---
<option value="85">
HU –
Hungary
</option>
---
<option value="100">
IT –
Italy
</option>
---
<option value="93">
LV –
Latvia
</option>
---
<option value="57">
NL –
Netherlands
</option>
---
<option value="2">
PL –
Poland
</option>
---
<option value="19">
RO –
Romania
</option>
---
<option value="91">
ES –
Spain