Revamping filtering big time!

This commit is contained in:
Víðir Valberg Guðmundsson 2017-04-21 01:34:22 +02:00
parent 691c6533c3
commit 9071a9c524
6 changed files with 210 additions and 53 deletions

View File

@ -1,5 +1,6 @@
from channels.generic.websockets import JsonWebsocketConsumer from channels.generic.websockets import JsonWebsocketConsumer
from camps.models import Camp
from .models import EventInstance, Favorite from .models import EventInstance, Favorite
@ -10,7 +11,17 @@ class ScheduleConsumer(JsonWebsocketConsumer):
return ['schedule_users'] return ['schedule_users']
def connect(self, message, **kwargs): def connect(self, message, **kwargs):
self.send({"accept": True}) camp_slug = message.http_session['campslug']
camp = Camp.objects.get(slug=camp_slug)
days = list(map(lambda x: {'repr': x.lower.strftime('%A %Y-%m-%d'), 'iso': x.lower.strftime('%Y-%m-%d')}, camp.get_days('camp')))
event_instances_query_set = EventInstance.objects.filter(event__camp=camp)
event_instances = list(map(lambda x: x.to_json(), event_instances_query_set))
self.send({
"accept": True,
"event_instances": event_instances,
"days": days,
"action": "init"
})
def raw_receive(self, message, **kwargs): def raw_receive(self, message, **kwargs):
content = self.decode_json(message['text']) content = self.decode_json(message['text'])

View File

@ -460,13 +460,18 @@ class EventInstance(CampRelatedModel):
'event_slug': self.event.slug, 'event_slug': self.event.slug,
'abstract': abstract, 'abstract': abstract,
'from': self.when.lower.isoformat(), 'from': self.when.lower.isoformat(),
'to': self.when.lower.isoformat(), 'to': self.when.upper.isoformat(),
'url': str(self.event.get_absolute_url()), 'url': str(self.event.get_absolute_url()),
'id': self.id, 'id': self.id,
'speakers': [ 'speakers': [
{ 'name': speaker.name { 'name': speaker.name
, 'url': str(speaker.get_absolute_url()) , 'url': str(speaker.get_absolute_url())
} for speaker in self.event.speakers.all()] } for speaker in self.event.speakers.all()
],
'bg-color': self.event.event_type.color,
'fg-color': '#fff' if self.event.event_type.light_text else '#000',
'event_type': self.event.event_type.slug,
'location': self.location.slug,
} }
if user and user.is_authenticated: if user and user.is_authenticated:

View File

@ -1,5 +1,6 @@
const webSocketBridge = new channels.WebSocketBridge(); const webSocketBridge = new channels.WebSocketBridge();
var modals = {}; var modals = {};
var EVENT_INSTANCES, DAYS;
function toggleFavoriteButton(button) { function toggleFavoriteButton(button) {
if(button.getAttribute('data-state') == 'true') { if(button.getAttribute('data-state') == 'true') {
@ -27,9 +28,8 @@ function toggleFavoriteButton(button) {
} }
webSocketBridge.connect('/schedule/'); webSocketBridge.connect('/schedule/');
webSocketBridge.socket.addEventListener('open', function() { //webSocketBridge.socket.addEventListener('open', function() {
webSocketBridge.send({action: 'init', camp_slug: '{{ camp.slug }}'}); //});
});
webSocketBridge.listen(function(payload, stream) { webSocketBridge.listen(function(payload, stream) {
if(payload['action'] == 'event_instance') { if(payload['action'] == 'event_instance') {
event_instance_id = payload['event_instance']['id']; event_instance_id = payload['event_instance']['id'];
@ -60,8 +60,95 @@ webSocketBridge.listen(function(payload, stream) {
speakers_div.appendChild(speaker_li); speakers_div.appendChild(speaker_li);
} }
} }
if(payload['action'] == 'init') {
EVENT_INSTANCES = payload['event_instances'];
console.log(EVENT_INSTANCES);
DAYS = payload['days'];
render_schedule([], []);
}
}); });
function render_schedule(types, locations) {
var event_instances = get_instances(types, locations);
var schedule_container = document.getElementById('schedule-container');
schedule_container.innerHTML = "";
var cloned_days = DAYS.slice(0);
var rendered_days = cloned_days.map(function(day) {
day_event_instances = event_instances.slice(0).filter(
function(event_instance) {
var event_day = event_instance['from'].slice(0, 10);
return event_day == day['iso'];
}
);
return render_day(day, day_event_instances);
});
for(day_id in rendered_days) {
schedule_container.appendChild(rendered_days[day_id]['label']);
schedule_container.appendChild(rendered_days[day_id]['element']);
}
}
function render_day(day, event_instances) {
var element = document.createElement('div');
element.classList.add('schedule-day-row');
var day_label = document.createElement('h4');
day_label.innerHTML = day['repr'];
element.appendChild(day_label);
for(event_instance_id in event_instances) {
var event_instance = event_instances[event_instance_id];
var rendered_event_instance = render_event_instance(event_instance);
element.appendChild(rendered_event_instance);
}
return {"label": day_label, "element": element};
}
function render_event_instance(event_instance) {
var element = document.createElement('a');
element.setAttribute(
'style',
'background-color: ' + event_instance['bg-color'] +
'; color: ' + event_instance['fg-color']);
element.classList.add('event');
element.dataset.eventInstanceId = event_instance['id'];
time_element = document.createElement('small');
time_element.innerHTML = event_instance.from.slice(11, 16) + " - " + event_instance.to.slice(11, 16);
title_element = document.createElement('p');
title_element.innerHTML = event_instance['title'];
element.appendChild(time_element);
element.appendChild(title_element);
element.onclick = openModal
return element
}
function get_instances(types, locations) {
var event_instances = EVENT_INSTANCES.slice(0);
if(locations.length != 0) {
event_instances = event_instances.filter(
function(event_instance) {
return locations.includes(event_instance['location']);
}
);
}
if(types.length != 0) {
event_instances = event_instances.filter(
function(event_instance) {
console.log(event_instance['event_type']);
console.log(types);
console.log(event_instance['event_type'] in types);
return types.includes(event_instance['event_type']);
}
);
}
return event_instances
}
function openModal(e) { function openModal(e) {
e.preventDefault(); e.preventDefault();
@ -71,7 +158,7 @@ function openModal(e) {
target = e.target.parentElement target = e.target.parentElement
} }
event_instance_id = target.dataset['eventinstanceId']; event_instance_id = target.dataset.eventInstanceId;
modal = modals[event_instance_id]; modal = modals[event_instance_id];
@ -88,12 +175,27 @@ function openModal(e) {
webSocketBridge.send({action: 'get_event_instance', event_instance_id: event_instance_id}) webSocketBridge.send({action: 'get_event_instance', event_instance_id: event_instance_id})
} }
function init_modals(event_class_name) { function init_modals(event_class_name) {
var event_elements = document.getElementsByClassName(event_class_name); var event_elements = document.getElementsByClassName(event_class_name);
for (var event_id in event_elements) { for (var event_id in event_elements) {
event_element = event_elements.item(event_id); event_element = event_elements.item(event_id);
event_element.onclick = openModal if(event_element != null) {
event_element.onclick = openModal
}
} }
} }
var filter = document.getElementById('filter')
filter.addEventListener('change', function(e) {
var type_input = Array.prototype.slice.call(document.querySelectorAll('.event-type-checkbox:checked'));
var types = type_input.map(function(box) {
return box.value
})
var location_input = Array.prototype.slice.call(document.querySelectorAll('.location-checkbox:checked'));
var event_locations = location_input.map(function(box) {
return box.value
})
render_schedule(types, event_locations);
});

View File

@ -4,37 +4,53 @@
{% block program_content %} {% block program_content %}
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="schedule-days btn-group">
<form method="get" id="filter" class="form-inline"> <a href="{% url 'schedule_index' camp_slug=camp.slug %}" class="btn btn-default">
<li>All days</li>
</a>
{% for day in camp.camp_days %}
{% with month_padded=day.lower.date|date:"m" day_padded=day.lower.date|date:"d" %}
<a href="{% url 'schedule_day' camp_slug=camp.slug year=day.lower.date.year month=day.lower.date|date:'m' day=day.lower.date|date:'d' %}" class="btn btn-{% if urlyear and urlyear|add:"0" == day.lower.date.year and urlmonth == month_padded and urlday == day_padded %}primary{% else %}default{% endif %}">
{{ day.lower.date|date:"l" }}
</a>
{% endwith %}
{% endfor %}
</div>
</div>
<hr />
<div class="row">
<div class="col-sm-3 col-sm-push-9 schedule-filter">
<form id="filter" class="form-inline">
<div class="form-group"> <div class="form-group">
<select id="day" name="day" class="form-control filter-control"> <div>
<option value="">All Days</option> <h4>Type:</h4>
{% for day in camp.camp_days %} <ul>
{% with month_padded=day.lower.date|date:"m" day_padded=day.lower.date|date:"d" %} {% for type in camp.event_types %}
<option <li>
value="{{ day.lower.date|date:"Y-m-d" }}" <input type="checkbox"
{% if urlyear and urlyear|add:"0" == day.lower.date.year and urlmonth == month_padded and urlday == day_padded %} name="event_type"
selected value="{{ type.slug }}"
{% endif %}> class="form-control event-type-checkbox"/> {{ type.name }}
{{ day.lower.date|date:"l" }} </li>
</option> {% endfor %}
{% endwith %} </ul>
{% endfor %} </div>
</select>
<select id="event_type" name="event_type" class="form-control filter-control"> <div>
<option value="">All Types</option> <h4>Location:</h4>
{% for type in camp.event_types %} <ul>
<option value="{{ type.slug }}"{% if eventtype and eventtype == type %}selected{% endif %}>{{ type.name }}</option> {% for location in camp.event_locations %}
{% endfor %} <li>
</select> <input type="checkbox"
name="locations"
<select id="location" name="location" class="fa-select form-control filter-control"> value="{{ location.slug }}"
<option value="">&#xf0ac; All Locations</option> class="form-control location-checkbox"/> {{ location.name }}
{% for loc in camp.event_locations %} </li>
<option value="{{ loc.slug }}" {% if location and location == loc %}selected{% endif %}>&#x{{ loc.icon }}; {{ loc.name }}</option> {% endfor %}
{% endfor %} </ul>
</select> </div>
<a href="{% url 'ics_view' camp_slug=camp.slug %}{{ get_string }}" class="btn btn-default form-control filter-control"> <a href="{% url 'ics_view' camp_slug=camp.slug %}{{ get_string }}" class="btn btn-default form-control filter-control">
<i class="fa fa-calendar"></i> ICS <i class="fa fa-calendar"></i> ICS
@ -42,26 +58,23 @@
</div> </div>
</form> </form>
</div> </div>
<div class="col-sm-9 col-sm-pull-3">
{% block schedule_content %}
{% endblock schedule_content %}
</div>
</div> </div>
<hr /> <hr />
{% block schedule_content %}
{% endblock schedule_content %}
{% url 'schedule_index' camp_slug=camp.slug as baseurl %} {% url 'schedule_index' camp_slug=camp.slug as baseurl %}
<script> <script>
$('.filter-control').on('change', function() { $('.filter-control').on('change', function() {
var day = $('#day').val();
var type = $('#event_type').val(); var type = $('#event_type').val();
var loc = $('#location').val(); var loc = $('#location').val();
var url = "{{baseurl}}"; var url = "{{baseurl}}";
if(day) {
url = url + day + '/';
}
if(type != '' || loc != '') { if(type != '' || loc != '') {
url = url + '?'; url = url + '?';
if(type != '') { if(type != '') {

View File

@ -4,6 +4,10 @@
{% load staticfiles %} {% load staticfiles %}
{% block schedule_content %} {% block schedule_content %}
<div id="schedule-container"></div>
{% comment %}
{% if eventinstances %} {% if eventinstances %}
{% for day in camp.camp_days %} {% for day in camp.camp_days %}
{{ day.lower.date|date:"D d/m" }} <br /> {{ day.lower.date|date:"D d/m" }} <br />
@ -29,13 +33,10 @@
{% else %} {% else %}
<h2>No scheduled events for {{ camp.title }} yet!</h2> <h2>No scheduled events for {{ camp.title }} yet!</h2>
{% endif %} {% endif %}
{% endcomment %}
{% include "event_modal.html" %} {% include "event_modal.html" %}
<script src="{% static "channels/js/websocketbridge.js" %}"></script> <script src="{% static "channels/js/websocketbridge.js" %}"></script>
<script src="{% static "js/event_instance_websocket.js" %}"></script> <script src="{% static "js/event_instance_websocket.js" %}"></script>
<script>
init_modals('event');
</script>
{% endblock schedule_content %} {% endblock schedule_content %}

View File

@ -89,10 +89,6 @@ a, a:active, a:focus {
/* btn-group */ /* btn-group */
.btn-group .btn {
border-right: 0;
}
.btn-group .btn:last-of-type { .btn-group .btn:last-of-type {
border-right: 1px solid #ccc; border-right: 1px solid #ccc;
} }
@ -161,6 +157,7 @@ footer {
min-height: 100px; min-height: 100px;
flex-grow: 1; flex-grow: 1;
border: 1px solid black; border: 1px solid black;
cursor: pointer;
} }
.event-td { .event-td {
@ -207,3 +204,31 @@ footer {
padding: 5px !important; padding: 5px !important;
border: 0 !important; border: 0 !important;
} }
.schedule-filter ul {
list-style: none;
padding: 0;
}
@media (min-width: 520px) {
.schedule-filter {
border-left: 1px solid #eee;
}
}
.schedule-days {
list-style: none;
padding: 0;
display: flex;
}
.schedule-days a {
display: inline;
flex-grow: 1;
}
.schedule-day-row {
display: flex;
flex-wrap: wrap;
}