Revamping filtering big time!
This commit is contained in:
parent
691c6533c3
commit
9071a9c524
|
@ -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'])
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
if(event_element != null) {
|
||||||
event_element.onclick = openModal
|
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);
|
||||||
|
});
|
||||||
|
|
|
@ -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">
|
||||||
<div class="form-group">
|
<li>All days</li>
|
||||||
<select id="day" name="day" class="form-control filter-control">
|
</a>
|
||||||
<option value="">All Days</option>
|
|
||||||
{% for day in camp.camp_days %}
|
{% for day in camp.camp_days %}
|
||||||
{% with month_padded=day.lower.date|date:"m" day_padded=day.lower.date|date:"d" %}
|
{% with month_padded=day.lower.date|date:"m" day_padded=day.lower.date|date:"d" %}
|
||||||
<option
|
<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 %}">
|
||||||
value="{{ day.lower.date|date:"Y-m-d" }}"
|
|
||||||
{% if urlyear and urlyear|add:"0" == day.lower.date.year and urlmonth == month_padded and urlday == day_padded %}
|
|
||||||
selected
|
|
||||||
{% endif %}>
|
|
||||||
{{ day.lower.date|date:"l" }}
|
{{ day.lower.date|date:"l" }}
|
||||||
</option>
|
</a>
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<select id="event_type" name="event_type" class="form-control filter-control">
|
<hr />
|
||||||
<option value="">All Types</option>
|
|
||||||
|
<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>
|
||||||
|
<h4>Type:</h4>
|
||||||
|
<ul>
|
||||||
{% for type in camp.event_types %}
|
{% for type in camp.event_types %}
|
||||||
<option value="{{ type.slug }}"{% if eventtype and eventtype == type %}selected{% endif %}>{{ type.name }}</option>
|
<li>
|
||||||
|
<input type="checkbox"
|
||||||
|
name="event_type"
|
||||||
|
value="{{ type.slug }}"
|
||||||
|
class="form-control event-type-checkbox"/> {{ type.name }}
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<select id="location" name="location" class="fa-select form-control filter-control">
|
<div>
|
||||||
<option value=""> All Locations</option>
|
<h4>Location:</h4>
|
||||||
{% for loc in camp.event_locations %}
|
<ul>
|
||||||
<option value="{{ loc.slug }}" {% if location and location == loc %}selected{% endif %}>&#x{{ loc.icon }}; {{ loc.name }}</option>
|
{% for location in camp.event_locations %}
|
||||||
|
<li>
|
||||||
|
<input type="checkbox"
|
||||||
|
name="locations"
|
||||||
|
value="{{ location.slug }}"
|
||||||
|
class="form-control location-checkbox"/> {{ location.name }}
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</ul>
|
||||||
|
</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 != '') {
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue