diff --git a/src/program/consumers.py b/src/program/consumers.py index 0501ea9f..c1994354 100644 --- a/src/program/consumers.py +++ b/src/program/consumers.py @@ -1,5 +1,6 @@ from channels.generic.websockets import JsonWebsocketConsumer +from camps.models import Camp from .models import EventInstance, Favorite @@ -10,7 +11,17 @@ class ScheduleConsumer(JsonWebsocketConsumer): return ['schedule_users'] 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): content = self.decode_json(message['text']) diff --git a/src/program/models.py b/src/program/models.py index 33f98139..063b0c6f 100644 --- a/src/program/models.py +++ b/src/program/models.py @@ -460,13 +460,18 @@ class EventInstance(CampRelatedModel): 'event_slug': self.event.slug, 'abstract': abstract, 'from': self.when.lower.isoformat(), - 'to': self.when.lower.isoformat(), + 'to': self.when.upper.isoformat(), 'url': str(self.event.get_absolute_url()), 'id': self.id, 'speakers': [ { 'name': speaker.name , '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: diff --git a/src/program/static/js/event_instance_websocket.js b/src/program/static/js/event_instance_websocket.js index 27af8fe9..62cda220 100644 --- a/src/program/static/js/event_instance_websocket.js +++ b/src/program/static/js/event_instance_websocket.js @@ -1,5 +1,6 @@ const webSocketBridge = new channels.WebSocketBridge(); var modals = {}; +var EVENT_INSTANCES, DAYS; function toggleFavoriteButton(button) { if(button.getAttribute('data-state') == 'true') { @@ -27,9 +28,8 @@ function toggleFavoriteButton(button) { } webSocketBridge.connect('/schedule/'); -webSocketBridge.socket.addEventListener('open', function() { - webSocketBridge.send({action: 'init', camp_slug: '{{ camp.slug }}'}); -}); +//webSocketBridge.socket.addEventListener('open', function() { +//}); webSocketBridge.listen(function(payload, stream) { if(payload['action'] == 'event_instance') { event_instance_id = payload['event_instance']['id']; @@ -60,8 +60,95 @@ webSocketBridge.listen(function(payload, stream) { 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) { e.preventDefault(); @@ -71,7 +158,7 @@ function openModal(e) { target = e.target.parentElement } - event_instance_id = target.dataset['eventinstanceId']; + event_instance_id = target.dataset.eventInstanceId; modal = modals[event_instance_id]; @@ -88,12 +175,27 @@ function openModal(e) { webSocketBridge.send({action: 'get_event_instance', event_instance_id: event_instance_id}) } - function init_modals(event_class_name) { var event_elements = document.getElementsByClassName(event_class_name); for (var event_id in event_elements) { 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); +}); diff --git a/src/program/templates/schedule_base.html b/src/program/templates/schedule_base.html index 8ae93c20..9d16c8fc 100644 --- a/src/program/templates/schedule_base.html +++ b/src/program/templates/schedule_base.html @@ -4,37 +4,53 @@ {% block program_content %}
-
-
+
+ +
  • All days
  • +
    + {% for day in camp.camp_days %} + {% with month_padded=day.lower.date|date:"m" day_padded=day.lower.date|date:"d" %} + + {{ day.lower.date|date:"l" }} + + {% endwith %} + {% endfor %} +
    +
    + +
    + +
    +
    +
    - +
    +

    Type:

    +
      + {% for type in camp.event_types %} +
    • + {{ type.name }} +
    • + {% endfor %} +
    +
    - - - +
    +

    Location:

    +
      + {% for location in camp.event_locations %} +
    • + {{ location.name }} +
    • + {% endfor %} +
    +
    ICS @@ -42,26 +58,23 @@
    +
    + {% block schedule_content %} + {% endblock schedule_content %} +

    -{% block schedule_content %} -{% endblock schedule_content %} {% url 'schedule_index' camp_slug=camp.slug as baseurl %} - - {% endblock schedule_content %} diff --git a/src/static_src/css/bornhack.css b/src/static_src/css/bornhack.css index 696c74db..adafdf42 100644 --- a/src/static_src/css/bornhack.css +++ b/src/static_src/css/bornhack.css @@ -89,10 +89,6 @@ a, a:active, a:focus { /* btn-group */ -.btn-group .btn { - border-right: 0; -} - .btn-group .btn:last-of-type { border-right: 1px solid #ccc; } @@ -161,6 +157,7 @@ footer { min-height: 100px; flex-grow: 1; border: 1px solid black; + cursor: pointer; } .event-td { @@ -207,3 +204,31 @@ footer { padding: 5px !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; +}