From 98b62420a5d6ed1c8aa69af4b5391744ca4d30ff Mon Sep 17 00:00:00 2001 From: MaliRobot Date: Sat, 21 Sep 2019 22:18:57 +0200 Subject: [PATCH 01/11] import timetable script new version --- .../management/commands/load_timetable.py | 115 ++++++++++-------- 1 file changed, 62 insertions(+), 53 deletions(-) diff --git a/pyconbalkan/timetable/management/commands/load_timetable.py b/pyconbalkan/timetable/management/commands/load_timetable.py index 08edebf2..e61b453f 100644 --- a/pyconbalkan/timetable/management/commands/load_timetable.py +++ b/pyconbalkan/timetable/management/commands/load_timetable.py @@ -10,12 +10,21 @@ from pyconbalkan.speaker.models import Speaker from pyconbalkan.timetable.models import Presentation, Room, Slot +from django.core.exceptions import ObjectDoesNotExist + ALL_DATA_URL = "https://sessionize.com/api/v2/fwv5aino/view/All" class Command(BaseCommand): help = 'Closes the specified poll for voting' + # this should be synced with timetable model somehow, not hardcoded + PRESENTATION_TYPE = { + 'Talk': 10, + 'Workshop': 15, + 'Keynote': 5 + } + def add_arguments(self, parser): pass parser.add_argument('--year', nargs="?", type=int, default=timezone.now().year) @@ -24,75 +33,65 @@ def add_arguments(self, parser): def handle(self, *args, **options): conference = Conference.objects.get(year=options['year']) + _cant_find = [] data = requests.get(options['data_url']).json() questions = data['questions'] categories = data['categories'] rooms = data['rooms'] + sessions = data['sessions'] + speakers = data['speakers'] + + types = categories[0]['items'] + types = {x['id']:x['name'] for x in types} - # Sync rooms + Presentation.objects.filter(conference=conference).delete() Room.objects.filter(conference=conference).delete() Slot.objects.filter(conference=conference).delete() - all_presentations_this_year = list(Presentation.objects.filter(conference=conference).values_list("id", "title")) for room in rooms: - Room.objects.create( - pk=room['id'], - conference=conference, - name=room['name'], - sort_order=room['sort'] - ) - - - # Make speaker dict - speakers = {} - for _ in data['speakers']: - first_name = _.pop('firstName') - last_name = _.pop('lastName') - speakers[f"{first_name} {last_name}"] = _ - - for speaker in speakers.values(): - for i, session in enumerate(speaker['sessions']): - speaker['sessions'][i] = list(filter(lambda _: int(_['id']) == session, data['sessions']))[0] - - # Attach Speaker obj from DB - speakers_qs = Speaker.objects.all().prefetch_related( - Prefetch( - "presentations", - queryset=Presentation.objects.filter(active=True, conference=conference).order_by("type") - ) - ) - - _cant_find = [] - for speaker in speakers_qs: - if not any(speaker.presentations.all()): - continue + if not Room.objects.filter(pk=room['id']).exists(): + Room.objects.create( + pk=room['id'], + conference=conference, + name=room['name'], + sort_order=room['sort'] + ) - r = list(fuzzyfinder(speaker.full_name, speakers.keys())) - if not any(r): - _cant_find.append(speaker) - continue - speakers[r[0]]["model_speaker"] = speaker - speaker = speakers[r[0]] - for _ in speaker['sessions']: - r = list(fuzzyfinder(_['title'], list(zip(*all_presentations_this_year))[1])) - if not any(r): - _cant_find.append(_) + for session in sessions: + speaker_id = session['speakers'][0] + speaker = self.get_speaker(speaker_id, speakers) + if speaker == None: + print(speaker_id, 'Not found') + else: + speaker = speaker.id + + if not Presentation.objects.filter(pk=session['id']).exists(): + presentation = Presentation.objects.create( + pk=session['id'], + active=False, + title=session['title'], + description=session['description'], + type=self.PRESENTATION_TYPE[types[session['categoryItems'][0]]], + speaker_id=speaker, + conference_id=conference.id, + ) + else: + presentation = Presentation.objects.filter(pk=session['id']) - try: - presentation = Presentation.objects.get(title__icontains=_['title']) - except Presentation.DoesNotExist: - _cant_find.append(_) - # TODO NEXT YEAR MAYBE, GET TZ FROM CONFERENCE OBJECT ?! + start = timezone.make_aware(datetime.strptime(session['startsAt'], "%Y-%m-%dT%H:%M:%S")) + end = timezone.make_aware(datetime.strptime(session['endsAt'], "%Y-%m-%dT%H:%M:%S")) + if not Slot.objects.filter(from_date=start,to_date=end,room_id=session['roomId']): Slot.objects.create( - from_date=timezone.make_aware(datetime.strptime(_['startsAt'], "%Y-%m-%dT%H:%M:%S")), - to_date=timezone.make_aware(datetime.strptime(_['endsAt'], "%Y-%m-%dT%H:%M:%S")), - talk=presentation, - room=Room.objects.get(pk=_['roomId']), - conference=conference + active=False, + from_date=start, + to_date=end, + room_id=session['roomId'], + talk_id=presentation.id, + conference_id=conference.id, ) if any(_cant_find): @@ -100,3 +99,13 @@ def handle(self, *args, **options): print(_cant_find) else: raise Exception("Had problems with the following", _cant_find) + + def get_speaker(self, speaker_id, speakers): + for speaker in speakers: + if speaker['id'] == speaker_id: + full_name = " ".join(speaker['fullName'].split()) + try: + return Speaker.objects.get(full_name=full_name) + except ObjectDoesNotExist: + return None + return None \ No newline at end of file From ee47522b87e9238979d3c1f90d5c83a472d796e3 Mon Sep 17 00:00:00 2001 From: MaliRobot Date: Sat, 21 Sep 2019 22:32:01 +0200 Subject: [PATCH 02/11] use get or create --- .../management/commands/load_timetable.py | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/pyconbalkan/timetable/management/commands/load_timetable.py b/pyconbalkan/timetable/management/commands/load_timetable.py index e61b453f..59b72b83 100644 --- a/pyconbalkan/timetable/management/commands/load_timetable.py +++ b/pyconbalkan/timetable/management/commands/load_timetable.py @@ -51,13 +51,12 @@ def handle(self, *args, **options): Slot.objects.filter(conference=conference).delete() for room in rooms: - if not Room.objects.filter(pk=room['id']).exists(): - Room.objects.create( - pk=room['id'], - conference=conference, - name=room['name'], - sort_order=room['sort'] - ) + Room.objects.get_or_create( + pk=room['id'], + conference=conference, + name=room['name'], + sort_order=room['sort'] + ) for session in sessions: @@ -69,30 +68,26 @@ def handle(self, *args, **options): else: speaker = speaker.id - if not Presentation.objects.filter(pk=session['id']).exists(): - presentation = Presentation.objects.create( - pk=session['id'], - active=False, - title=session['title'], - description=session['description'], - type=self.PRESENTATION_TYPE[types[session['categoryItems'][0]]], - speaker_id=speaker, - conference_id=conference.id, - ) - else: - presentation = Presentation.objects.filter(pk=session['id']) + presentation, created = Presentation.objects.get_or_create( + pk=session['id'], + active=False, + title=session['title'], + description=session['description'], + type=self.PRESENTATION_TYPE[types[session['categoryItems'][0]]], + speaker_id=speaker, + conference_id=conference.id, + ) start = timezone.make_aware(datetime.strptime(session['startsAt'], "%Y-%m-%dT%H:%M:%S")) end = timezone.make_aware(datetime.strptime(session['endsAt'], "%Y-%m-%dT%H:%M:%S")) - if not Slot.objects.filter(from_date=start,to_date=end,room_id=session['roomId']): - Slot.objects.create( - active=False, - from_date=start, - to_date=end, - room_id=session['roomId'], - talk_id=presentation.id, - conference_id=conference.id, - ) + Slot.objects.get_or_create( + active=False, + from_date=start, + to_date=end, + room_id=session['roomId'], + talk_id=presentation.id, + conference_id=conference.id, + ) if any(_cant_find): if options['force']: From 3f4cc7a582ef7a2503bd06c148af189b6e651c61 Mon Sep 17 00:00:00 2001 From: MaliRobot Date: Mon, 23 Sep 2019 00:27:24 +0200 Subject: [PATCH 03/11] timetable js --- pyconbalkan/core/static/css/timetablejs.css | 1 + pyconbalkan/core/static/js/timetable.js | 8 +- .../timetable/templates/timetable.html | 103 ++++++------------ pyconbalkan/timetable/views.py | 24 ++-- 4 files changed, 46 insertions(+), 90 deletions(-) create mode 100644 pyconbalkan/core/static/css/timetablejs.css diff --git a/pyconbalkan/core/static/css/timetablejs.css b/pyconbalkan/core/static/css/timetablejs.css new file mode 100644 index 00000000..537460f4 --- /dev/null +++ b/pyconbalkan/core/static/css/timetablejs.css @@ -0,0 +1 @@ +.timetable{display:flex;align-items:stretch;width:100%;max-width:100%;box-sizing:border-box}.timetable *{box-sizing:inherit}.timetable li,.timetable ul{list-style-type:none;margin:0}.timetable li,.timetable ul{padding:0}.timetable>aside{flex:none;max-width:30%;padding:0!important;margin-top:46px;border-right:5px solid transparent;position:relative}.timetable>aside li{padding:0 15px;background-color:#efefef;line-height:46px}.timetable>aside li:not(:last-of-type){border-bottom:1px solid #fff}.timetable>aside .row-heading{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;word-wrap:normal}.timetable>aside:before{content:"";display:block;background-color:#fff;height:46px;position:relative;margin-top:-46px;top:0}.timetable aside li,.timetable time li{height:46px}.timetable>section{flex:3 0 auto;width:0;padding:0!important}.timetable>section time{display:block;width:100%;overflow-x:scroll;-webkit-overflow-scrolling:touch}.timetable>section>header{position:relative;top:0;z-index:3;width:100%;overflow:hidden;background-color:#fff;transform-style:preserve-3d}.timetable>section>header ul{display:flex;height:46px;align-items:center}.timetable>section>header li{flex:none;display:block;position:relative;width:96px}.timetable>section>header li .time-label{display:block;position:absolute;left:0}.timetable>section>header li:not(:first-of-type) .time-label{transform:translateX(-50%)}.timetable>section>header li:last-of-type{width:0}.timetable>section>header li:last-of-type .time-label{transform:translateX(-100%)}.timetable ul.room-timeline{border-left:none;display:flex;flex-direction:column;align-items:stretch}.timetable ul.room-timeline li{position:relative;background-color:#f4f4f4;height:46px}.timetable ul.room-timeline li:nth-of-type(odd){background-color:#fdfdfd}.timetable ul.room-timeline li:first-of-type{border-top:1px solid #e5e5e5}.timetable ul.room-timeline li:last-of-type{border-bottom:1px solid #e5e5e5}.timetable ul.room-timeline li:not(:last-of-type){border-bottom:none}.timetable ul.room-timeline li:first-child .time-entry{height:44px}.timetable ul.room-timeline li:after,.timetable ul.room-timeline li:before{content:"";position:absolute;z-index:1;left:0;top:0;right:0;bottom:0}.timetable ul.room-timeline li:before{background-image:linear-gradient(90deg,#e5e5e5 1px,transparent 0);background-size:24px auto}.timetable ul.room-timeline li:after{background-image:linear-gradient(90deg,#e5e5e5,#e5e5e5 1px,#f4f4f4 0,#f4f4f4 2px,#e5e5e5 0,#e5e5e5 3px,transparent 0,transparent);background-size:96px auto;background-position:-2px 0}.timetable .time-entry{background-color:#ec6a5e;transition:background-color .2s;height:45px;display:block;position:absolute;z-index:2;padding:0 10px;white-space:normal;overflow:hidden;color:#fff;border:1px solid #e32c1b;transform-style:preserve-3d}.timetable .time-entry small{position:relative;top:50%;transform:translateY(-50%);display:block}.timetable .time-entry:hover{background-color:#e74030} \ No newline at end of file diff --git a/pyconbalkan/core/static/js/timetable.js b/pyconbalkan/core/static/js/timetable.js index 26645467..4e45c775 100644 --- a/pyconbalkan/core/static/js/timetable.js +++ b/pyconbalkan/core/static/js/timetable.js @@ -1,7 +1 @@ -$(".btn-room").click(function() { - let roomNumber = this.innerHTML; - $(".btn-room").removeClass('button--yellow'); - $(".presentations").addClass('hidden'); - $("." + roomNumber).removeClass('hidden'); - $(".btn-" + roomNumber).addClass('button--yellow'); -}); \ No newline at end of file +!function(e,t){"function"==typeof define&&define.amd?define(["exports"],t):t("undefined"!=typeof exports?exports:e.syncscroll={})}(this,function(e){var t="Width",n="Height",o="Top",r="Left",i="scroll",a="client",s=[],c=function(){var e,c,l,u,d,f=document.getElementsByClassName("syncscroll");for(d in s)if(s.hasOwnProperty(d))for(e=0;e=0&&e<24}function r(e,t){return t.indexOf(e)!==-1}function i(e,t){var n=e instanceof Date&&t instanceof Date,o=e=e?t-e:24+t-e}function s(e){for(;e.firstChild;)e.removeChild(e.firstChild)}function c(e,t){var n;if(t){var o=e>=12?"PM":"AM";n=(e+11)%12+1+":00"+o}else{var r=e<10?"0":"";n=r+e+":00"}return n}Timetable.prototype={setScope:function(t,n){if(!e(t,n))throw new RangeError("Timetable scope should consist of (start, end) in whole hours from 0 to 23");return this.scope.hourStart=t,this.scope.hourEnd=n,this},useTwelveHour:function(){this.usingTwelveHour=!0},addLocations:function(e){function t(){return e instanceof Array}var n=this.locations;if(!t())throw new Error("Tried to add locations in wrong format");return e.forEach(function(e){if(r(e,n))throw new Error("Location already exists");n.push(e)}),this},addEvent:function(e,t,n,o,a){if(!r(t,this.locations))throw new Error("Unknown location");if(!i(n,o))throw new Error("Invalid time range: "+JSON.stringify([n,o]));var s="[object Object]"===Object.prototype.toString.call(a);return this.events.push({name:e,location:t,startDate:n,endDate:o,options:s?a:void 0}),this}},Timetable.Renderer.prototype={draw:function(e){function t(e){if(null===e)throw new Error("Timetable container not found")}function n(e){var t=e.appendChild(document.createElement("aside")),n=t.appendChild(document.createElement("ul"));o(n)}function o(e){for(var t=0;tTimetable -
- {% if rooms %} -
    - {% for room in rooms %} -
  • {{ room.name }}
  • + + + +
    + + {% for date, slots in slots_by_date.items %} + {% endfor %} - {% endif %} + {% endblock main_content %} + {% block scripts %} - {% endblock %} \ No newline at end of file diff --git a/pyconbalkan/timetable/views.py b/pyconbalkan/timetable/views.py index 246b77d0..cb8ce2bd 100644 --- a/pyconbalkan/timetable/views.py +++ b/pyconbalkan/timetable/views.py @@ -2,25 +2,21 @@ from django.shortcuts import render from pyconbalkan.timetable.models import Room, Slot +from django.db.models.functions import TruncDate def timetable_view(request): - slots_by_rooms = {} rooms = Room.objects.all() slots = Slot.objects.all() - slots_order_by_date = slots.order_by('from_date') - for room in rooms: - slots_by_rooms[room.name] = slots_order_by_date.filter(room=room) - days_count = 0 - DAYS = {} - for slot in slots: - if slot.from_date.date() not in DAYS: - DAYS[slot.from_date.date()] = 'Day {}'.format(days_count + 1) - days_count += 1 + dates = slots.annotate(date=TruncDate('from_date')).values('date').distinct() + slots_by_date = {} + + for i, date in enumerate(dates): + slots_by_date[i] = Slot.objects.filter(from_date__date=date['date']) + context = { - 'slots': slots_order_by_date, - 'slots_by_rooms': slots_by_rooms, + 'slots_by_date': slots_by_date, 'rooms': rooms, - 'DAYS': DAYS + 'dates': dates } - return render(request, 'timetable_sessionize.html', context) + return render(request, 'timetable.html', context) From df5a8e6cfbe0795b029c84b6ccd23b8d7c9ab5ff Mon Sep 17 00:00:00 2001 From: MaliRobot Date: Mon, 23 Sep 2019 22:39:54 +0200 Subject: [PATCH 04/11] date selector --- .../timetable/templates/timetable.html | 46 ++++++++++++++----- pyconbalkan/timetable/views.py | 8 ++-- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/pyconbalkan/timetable/templates/timetable.html b/pyconbalkan/timetable/templates/timetable.html index 67ff21a5..8162eb9d 100644 --- a/pyconbalkan/timetable/templates/timetable.html +++ b/pyconbalkan/timetable/templates/timetable.html @@ -5,20 +5,26 @@ -
    - {% for date, slots in slots_by_date.items %} - + {% endfor %} + {% endblock main_content %} {% block scripts %} + {% endblock %} \ No newline at end of file diff --git a/pyconbalkan/timetable/views.py b/pyconbalkan/timetable/views.py index cb8ce2bd..0bffb96e 100644 --- a/pyconbalkan/timetable/views.py +++ b/pyconbalkan/timetable/views.py @@ -8,15 +8,17 @@ def timetable_view(request): rooms = Room.objects.all() slots = Slot.objects.all() - dates = slots.annotate(date=TruncDate('from_date')).values('date').distinct() + unique_dates = slots.annotate(date=TruncDate('from_date')).values('date').distinct() slots_by_date = {} + dates = [] - for i, date in enumerate(dates): + for i, date in enumerate(unique_dates): slots_by_date[i] = Slot.objects.filter(from_date__date=date['date']) + dates.append(date['date']) context = { 'slots_by_date': slots_by_date, 'rooms': rooms, - 'dates': dates + 'dates': sorted(dates) } return render(request, 'timetable.html', context) From c29710bdf75fcc8343cd60a73ebe160d6fe4fbc3 Mon Sep 17 00:00:00 2001 From: MaliRobot Date: Tue, 24 Sep 2019 19:40:22 +0200 Subject: [PATCH 05/11] table minor css changes --- pyconbalkan/core/static/css/timetablejs.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyconbalkan/core/static/css/timetablejs.css b/pyconbalkan/core/static/css/timetablejs.css index 537460f4..d76f3617 100644 --- a/pyconbalkan/core/static/css/timetablejs.css +++ b/pyconbalkan/core/static/css/timetablejs.css @@ -1 +1 @@ -.timetable{display:flex;align-items:stretch;width:100%;max-width:100%;box-sizing:border-box}.timetable *{box-sizing:inherit}.timetable li,.timetable ul{list-style-type:none;margin:0}.timetable li,.timetable ul{padding:0}.timetable>aside{flex:none;max-width:30%;padding:0!important;margin-top:46px;border-right:5px solid transparent;position:relative}.timetable>aside li{padding:0 15px;background-color:#efefef;line-height:46px}.timetable>aside li:not(:last-of-type){border-bottom:1px solid #fff}.timetable>aside .row-heading{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;word-wrap:normal}.timetable>aside:before{content:"";display:block;background-color:#fff;height:46px;position:relative;margin-top:-46px;top:0}.timetable aside li,.timetable time li{height:46px}.timetable>section{flex:3 0 auto;width:0;padding:0!important}.timetable>section time{display:block;width:100%;overflow-x:scroll;-webkit-overflow-scrolling:touch}.timetable>section>header{position:relative;top:0;z-index:3;width:100%;overflow:hidden;background-color:#fff;transform-style:preserve-3d}.timetable>section>header ul{display:flex;height:46px;align-items:center}.timetable>section>header li{flex:none;display:block;position:relative;width:96px}.timetable>section>header li .time-label{display:block;position:absolute;left:0}.timetable>section>header li:not(:first-of-type) .time-label{transform:translateX(-50%)}.timetable>section>header li:last-of-type{width:0}.timetable>section>header li:last-of-type .time-label{transform:translateX(-100%)}.timetable ul.room-timeline{border-left:none;display:flex;flex-direction:column;align-items:stretch}.timetable ul.room-timeline li{position:relative;background-color:#f4f4f4;height:46px}.timetable ul.room-timeline li:nth-of-type(odd){background-color:#fdfdfd}.timetable ul.room-timeline li:first-of-type{border-top:1px solid #e5e5e5}.timetable ul.room-timeline li:last-of-type{border-bottom:1px solid #e5e5e5}.timetable ul.room-timeline li:not(:last-of-type){border-bottom:none}.timetable ul.room-timeline li:first-child .time-entry{height:44px}.timetable ul.room-timeline li:after,.timetable ul.room-timeline li:before{content:"";position:absolute;z-index:1;left:0;top:0;right:0;bottom:0}.timetable ul.room-timeline li:before{background-image:linear-gradient(90deg,#e5e5e5 1px,transparent 0);background-size:24px auto}.timetable ul.room-timeline li:after{background-image:linear-gradient(90deg,#e5e5e5,#e5e5e5 1px,#f4f4f4 0,#f4f4f4 2px,#e5e5e5 0,#e5e5e5 3px,transparent 0,transparent);background-size:96px auto;background-position:-2px 0}.timetable .time-entry{background-color:#ec6a5e;transition:background-color .2s;height:45px;display:block;position:absolute;z-index:2;padding:0 10px;white-space:normal;overflow:hidden;color:#fff;border:1px solid #e32c1b;transform-style:preserve-3d}.timetable .time-entry small{position:relative;top:50%;transform:translateY(-50%);display:block}.timetable .time-entry:hover{background-color:#e74030} \ No newline at end of file +.timetable{display:flex;align-items:stretch;width:100%;max-width:100%;box-sizing:border-box}.timetable *{box-sizing:inherit}.timetable li,.timetable ul{list-style-type:none;margin:0}.timetable li,.timetable ul{padding:0}.timetable>aside{flex:none;max-width:30%;padding:0!important;margin-top:46px;border-right:5px solid transparent;position:relative}.timetable>aside li{padding:0 15px;background-color:#efefef;line-height:46px}.timetable>aside li:not(:last-of-type){border-bottom:1px solid #fff}.timetable>aside .row-heading{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;word-wrap:normal}.timetable>aside:before{content:"";display:block;background-color:#fff;height:46px;position:relative;margin-top:-46px;top:0}.timetable aside li,.timetable time li{height:140px}.timetable>section{flex:3 0 auto;width:0;padding:0!important}.timetable>section time{display:block;width:100%;overflow-x:scroll;-webkit-overflow-scrolling:touch}.timetable>section>header{position:relative;top:0;z-index:3;width:100%;overflow:hidden;background-color:#fff;transform-style:preserve-3d}.timetable>section>header ul{display:flex;height:46px;align-items:center}.timetable>section>header li{flex:none;display:block;position:relative;width:96px}.timetable>section>header li .time-label{display:block;position:absolute;left:0}.timetable>section>header li:not(:first-of-type) .time-label{transform:translateX(-50%)}.timetable>section>header li:last-of-type{width:0}.timetable>section>header li:last-of-type .time-label{transform:translateX(-100%)}.timetable ul.room-timeline{border-left:none;display:flex;flex-direction:column;align-items:stretch}.timetable ul.room-timeline li{position:relative;background-color:#f4f4f4;height:140px}.timetable ul.room-timeline li:nth-of-type(odd){background-color:#fdfdfd}.timetable ul.room-timeline li:first-of-type{border-top:1px solid #e5e5e5}.timetable ul.room-timeline li:last-of-type{border-bottom:1px solid #e5e5e5}.timetable ul.room-timeline li:not(:last-of-type){border-bottom:none}.timetable ul.room-timeline li:first-child .time-entry{height:140px}.timetable ul.room-timeline li:after,.timetable ul.room-timeline li:before{content:"";position:absolute;z-index:1;left:0;top:0;right:0;bottom:0}.timetable ul.room-timeline li:before{background-image:linear-gradient(90deg,#e5e5e5 1px,transparent 0);background-size:24px auto}.timetable ul.room-timeline li:after{background-image:linear-gradient(90deg,#e5e5e5,#e5e5e5 1px,#f4f4f4 0,#f4f4f4 2px,#e5e5e5 0,#e5e5e5 3px,transparent 0,transparent);background-size:96px auto;background-position:-2px 0}.timetable .time-entry{background-color:#ec6a5e;transition:background-color .2s;height:45px;display:block;position:absolute;z-index:2;padding:0 10px;white-space:normal;overflow:hidden;color:#fff;border:1px solid #e32c1b;transform-style:preserve-3d}.timetable .time-entry small{position:relative;top:50%;transform:translateY(-50%);display:block}.timetable .time-entry:hover{background-color:#e74030} \ No newline at end of file From e51b634382d660d7be3b8e0bcd080d083834cbd1 Mon Sep 17 00:00:00 2001 From: MaliRobot Date: Tue, 24 Sep 2019 20:35:10 +0200 Subject: [PATCH 06/11] session type with title in speaker page --- .../core/static/css/components/person.css | 19 +++++++++++++++++++ pyconbalkan/speaker/templates/speaker.html | 16 +++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/pyconbalkan/core/static/css/components/person.css b/pyconbalkan/core/static/css/components/person.css index a99ad207..24606e32 100644 --- a/pyconbalkan/core/static/css/components/person.css +++ b/pyconbalkan/core/static/css/components/person.css @@ -32,12 +32,31 @@ .presentation__talk { color: #343C3E; + } .presentation__workshop { color: #666; } +.presentation__keynote, +.presentation__talk, +.presentation__workshop { + padding-left: 1em; +} + +.cat-session { + border: 1px solid; + border-radius: 2px; + width: 3em; + text-align: center; + color: #3aaee2; + font-size: 14px; + font-weight: 700; + float:left; + margin-top: 1.3em; +} + .speaker, .organizer, .sponsor { diff --git a/pyconbalkan/speaker/templates/speaker.html b/pyconbalkan/speaker/templates/speaker.html index 26ccbb8c..77c831f8 100644 --- a/pyconbalkan/speaker/templates/speaker.html +++ b/pyconbalkan/speaker/templates/speaker.html @@ -31,17 +31,27 @@

    PyCon Balkan {{ conference }} Talks

    {% for presentation in presentations %} {% if presentation.type == 5 %} {# Keynote talk #}
    -

    {{ presentation.title }}

    +
    +
    KEY
    +

    {{ presentation.title }}

    +

    {{ presentation.description|markdownify }}

    {% elif presentation.type == 10 %} {# Normal talk #}
    -

    {{ presentation.title }}

    +
    +

    TLK

    +

    {{ presentation.title }}

    +

    {{ presentation.description|markdownify }}

    +
    {% elif presentation.type == 15 %} {# Workshop #}
    -

    {{ presentation.title }}

    +
    +

    WRK

    +

    {{ presentation.title }}

    +

    {{ presentation.description|markdownify }}

    {% endif %} From 815f30d8cb3dc31104638a67664ebba76956e8ee Mon Sep 17 00:00:00 2001 From: MaliRobot Date: Tue, 24 Sep 2019 23:58:14 +0200 Subject: [PATCH 07/11] styling the table --- .../core/static/css/components/timetable.css | 52 +++++++++++++++++++ .../timetable/templates/timetable.html | 11 ++-- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/pyconbalkan/core/static/css/components/timetable.css b/pyconbalkan/core/static/css/components/timetable.css index 6cba71ca..aa0fa55d 100644 --- a/pyconbalkan/core/static/css/components/timetable.css +++ b/pyconbalkan/core/static/css/components/timetable.css @@ -1,3 +1,55 @@ +#dates-wrapper { + text-align: center; +} + +.day-select { + border: 1px solid #343C3E; + border-radius: 6px; + background: white; + font-size: 16px; + padding: 6px; + text-decoration: none; + margin: 1em; +} + +.day-select:focus {outline:0;} + +.day-select:active, +.day-select:hover, +.selected-day { + background: #27aae1; + color: white; + border: 1px solid transparent; +} + +.room-timeline { + width: 1800px !important; + overflow: hidden !important; +} + +.timetable .time-entry { + background-color: #27aae1 !important; + border: 1px solid #efefef !important; + text-decoration: none; + font-size: 14px; +} + +.timetable .time-entry:hover { + background-color: #343c3e !important; +} + +.timetable>section>header li { + width: 218px !important; +} + +.timetable ul.room-timeline li:before { + background-image: unset !important; +} + +.timetable ul.room-timeline li:after { + background-size: 107px auto !important; +} + .presentation { display: flex; margin: 15px 0; diff --git a/pyconbalkan/timetable/templates/timetable.html b/pyconbalkan/timetable/templates/timetable.html index a4be011d..475fa23d 100644 --- a/pyconbalkan/timetable/templates/timetable.html +++ b/pyconbalkan/timetable/templates/timetable.html @@ -6,9 +6,9 @@ -
    +
    {% for date in dates %} - + {% endfor %}
    @@ -31,7 +31,7 @@ new Date({{ slot.from_date|date:"Y,n-1,j,H,i"}}), new Date({{ slot.to_date|date:"Y,n-1,j,H,i"}}), { - url: '/speaker/{{ slot.talk.slugify_speaker }}/#{{ slot.talk.slugify }}', // makes the event clickable + url: {% if slot.talk.speaker %}'/speaker/{{ slot.talk.slugify_speaker }}/#{{ slot.talk.slugify }}'{% else %}'#'{% endif %}, // makes the event clickable class: 'day-{{ slot.from_date|date:"j" }}', // additional css class data: { // each property will be added to the data-* attributes of the DOM node for this event day: '{{ slot.from_date|date:"Y,n-1,j" }}', @@ -56,12 +56,13 @@ $(window).ready(function() { $(".time-entry").hide(); $(".day-3").show(); + $(".day-select:first").addClass('selected-day'); $("button").click(function(e){ - console.log(timetable); $(".time-entry").hide(); + $(".day-select").removeClass('selected-day'); var cl = $(this).data('day'); - console.log(cl); $('.'+cl).show(); + $(this).addClass('selected-day'); }); }); From 4904899bc00605f61b6061117693bf4bbe95e8cb Mon Sep 17 00:00:00 2001 From: MaliRobot Date: Wed, 25 Sep 2019 21:42:45 +0200 Subject: [PATCH 08/11] mr fixes --- .../core/static/css/components/timetable.css | 16 ++++++++-------- pyconbalkan/speaker/templates/speaker.html | 17 +++-------------- .../management/commands/load_timetable.py | 11 ++--------- pyconbalkan/timetable/models.py | 6 ++++++ pyconbalkan/timetable/templates/timetable.html | 13 ++++++++----- 5 files changed, 27 insertions(+), 36 deletions(-) diff --git a/pyconbalkan/core/static/css/components/timetable.css b/pyconbalkan/core/static/css/components/timetable.css index aa0fa55d..b7b02464 100644 --- a/pyconbalkan/core/static/css/components/timetable.css +++ b/pyconbalkan/core/static/css/components/timetable.css @@ -22,10 +22,10 @@ border: 1px solid transparent; } -.room-timeline { - width: 1800px !important; - overflow: hidden !important; -} +/*.room-timeline {*/ +/* width: 1800px !important;*/ +/* overflow: hidden !important;*/ +/*}*/ .timetable .time-entry { background-color: #27aae1 !important; @@ -38,16 +38,16 @@ background-color: #343c3e !important; } -.timetable>section>header li { - width: 218px !important; -} +/*.timetable>section>header li {*/ +/* width: 233px !important;*/ +/*}*/ .timetable ul.room-timeline li:before { background-image: unset !important; } .timetable ul.room-timeline li:after { - background-size: 107px auto !important; + background-size: 112px auto !important } .presentation { diff --git a/pyconbalkan/speaker/templates/speaker.html b/pyconbalkan/speaker/templates/speaker.html index 13dbd6f6..26ccbb8c 100644 --- a/pyconbalkan/speaker/templates/speaker.html +++ b/pyconbalkan/speaker/templates/speaker.html @@ -31,31 +31,20 @@

    PyCon Balkan {{ conference }} Talks

    {% for presentation in presentations %} {% if presentation.type == 5 %} {# Keynote talk #}
    -
    -
    KEY
    -

    {{ presentation.title }}

    -
    +

    {{ presentation.title }}

    {{ presentation.description|markdownify }}

    {% elif presentation.type == 10 %} {# Normal talk #}
    -
    -

    TLK

    -

    {{ presentation.title }}

    -
    +

    {{ presentation.title }}

    {{ presentation.description|markdownify }}

    -
    {% elif presentation.type == 15 %} {# Workshop #}
    -
    -

    WRK

    -

    {{ presentation.title }}

    -
    +

    {{ presentation.title }}

    {{ presentation.description|markdownify }}

    {% endif %} -
    {% for tag in presentation.tags.all %}
    {{ tag }}
    diff --git a/pyconbalkan/timetable/management/commands/load_timetable.py b/pyconbalkan/timetable/management/commands/load_timetable.py index 59b72b83..35a79d0d 100644 --- a/pyconbalkan/timetable/management/commands/load_timetable.py +++ b/pyconbalkan/timetable/management/commands/load_timetable.py @@ -16,14 +16,7 @@ class Command(BaseCommand): - help = 'Closes the specified poll for voting' - - # this should be synced with timetable model somehow, not hardcoded - PRESENTATION_TYPE = { - 'Talk': 10, - 'Workshop': 15, - 'Keynote': 5 - } + help = 'Import data from sessionize' def add_arguments(self, parser): pass @@ -73,7 +66,7 @@ def handle(self, *args, **options): active=False, title=session['title'], description=session['description'], - type=self.PRESENTATION_TYPE[types[session['categoryItems'][0]]], + type=Presentation.PRESENTATION_TYPE_REVERSE[types[session['categoryItems'][0]]], speaker_id=speaker, conference_id=conference.id, ) diff --git a/pyconbalkan/timetable/models.py b/pyconbalkan/timetable/models.py index 0a7d8d73..1feb3a06 100644 --- a/pyconbalkan/timetable/models.py +++ b/pyconbalkan/timetable/models.py @@ -19,6 +19,12 @@ class Presentation(AbstractConference, ActiveModel): (KEYNOTE, 'Keynote'), ) + PRESENTATION_TYPE_REVERSE = { + 'Talk': TALK, + 'Workshop': WORKSHOP, + 'Keynote': KEYNOTE + } + title = models.CharField(null=True, blank=True, max_length=100) description = MarkdownxField(null=True, blank=True) type = models.IntegerField(choices=PRESENTATION_TYPE, default=TALK) diff --git a/pyconbalkan/timetable/templates/timetable.html b/pyconbalkan/timetable/templates/timetable.html index 475fa23d..38ed39da 100644 --- a/pyconbalkan/timetable/templates/timetable.html +++ b/pyconbalkan/timetable/templates/timetable.html @@ -8,7 +8,9 @@
    {% for date in dates %} - + {% with i=forloop.counter %} + + {% endwith %} {% endfor %}
    @@ -23,6 +25,7 @@ timetable.addLocations(rooms); {% for date, slots in slots_by_date.items %} + {% with i=forloop.counter %} {% for slot in slots %} timetable.addEvent( @@ -32,9 +35,9 @@ new Date({{ slot.to_date|date:"Y,n-1,j,H,i"}}), { url: {% if slot.talk.speaker %}'/speaker/{{ slot.talk.slugify_speaker }}/#{{ slot.talk.slugify }}'{% else %}'#'{% endif %}, // makes the event clickable - class: 'day-{{ slot.from_date|date:"j" }}', // additional css class + class: 'day-{{ i }}', // additional css class data: { // each property will be added to the data-* attributes of the DOM node for this event - day: '{{ slot.from_date|date:"Y,n-1,j" }}', + day: '{{ slot.from_date|date:"Y-n-j" }}', description: '{{ slot.talk.description | linebreaksbr }}', }, onClick: function(event, timetable, clickEvent) {}, @@ -42,7 +45,7 @@ ); {% endfor %} - + {% endwith %} var renderer = new Timetable.Renderer(timetable); renderer.draw('.timetable'); @@ -55,7 +58,7 @@