diff options
Diffstat (limited to 'static')
| -rw-r--r-- | static/fullnarp.js | 429 |
1 files changed, 209 insertions, 220 deletions
diff --git a/static/fullnarp.js b/static/fullnarp.js index 8b7d36d..3d60592 100644 --- a/static/fullnarp.js +++ b/static/fullnarp.js | |||
| @@ -1,4 +1,9 @@ | |||
| 1 | let ws; // WebSocket instance | 1 | let ws; // WebSocket instance |
| 2 | let allrooms = ['1','2','3'] | ||
| 3 | let allminutes = ['00','05','10','15','20','25','30','35','40','45','50','55'] | ||
| 4 | let allhours = ['10','11','12','13','14','15','16','17','18','19','20','21','22','23','00','01','02']; | ||
| 5 | let alldays = ['1','2','3','4']; | ||
| 6 | let raw_votes; | ||
| 2 | 7 | ||
| 3 | function toggle_grid(whichDay) { | 8 | function toggle_grid(whichDay) { |
| 4 | var vclasses= [['in-list'], ['in-calendar', 'onlyday1'], ['in-calendar', 'onlyday2'], ['in-calendar', 'onlyday3'], | 9 | var vclasses= [['in-list'], ['in-calendar', 'onlyday1'], ['in-calendar', 'onlyday2'], ['in-calendar', 'onlyday3'], |
| @@ -8,6 +13,128 @@ function toggle_grid(whichDay) { | |||
| 8 | document.body.classList.add(...vclasses[whichDay]); | 13 | document.body.classList.add(...vclasses[whichDay]); |
| 9 | } | 14 | } |
| 10 | 15 | ||
| 16 | function render_lectures(data) { | ||
| 17 | for (item of data) { | ||
| 18 | /* Take copy of hidden event template div and select them, if they're in | ||
| 19 | list of previous prereferences */ | ||
| 20 | var t = document.getElementById('template').cloneNode(true); | ||
| 21 | var event_id = item.event_id.toString(); | ||
| 22 | |||
| 23 | t.classList.add('event', 'duration_' + item.duration, 'lang_' + (item.language || 'en')); | ||
| 24 | t.setAttribute('event_id', event_id); | ||
| 25 | t.setAttribute('id', 'event_' + event_id); | ||
| 26 | t.setAttribute('fullnarp-duration', item.duration); | ||
| 27 | t.setAttribute('draggable', 'true'); | ||
| 28 | |||
| 29 | /* Sort textual info into event div */ | ||
| 30 | t.querySelector('.title').textContent = item.title; | ||
| 31 | t.querySelector('.speakers').textContent = item.speaker_names; | ||
| 32 | t.querySelector('.abstract').append(item.abstract); | ||
| 33 | |||
| 34 | /* Store speakers and their availabilities */ | ||
| 35 | window.event_speakers[event_id] = item.speakers; | ||
| 36 | for (speaker of item.speakers) { | ||
| 37 | var have_avails = false; | ||
| 38 | for (avail of speaker.availabilities) { | ||
| 39 | if (avail.id ) { | ||
| 40 | have_avails = true; | ||
| 41 | break; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | if (!have_avails) | ||
| 45 | t.classList.add('has_unavailable_speaker'); | ||
| 46 | } | ||
| 47 | |||
| 48 | /* Make the event drag&droppable */ | ||
| 49 | t.ondragstart = function( event, ui ) { | ||
| 50 | event.stopPropagation(); | ||
| 51 | |||
| 52 | event.dataTransfer.setData('text/plain', this.id ); | ||
| 53 | event.dataTransfer.dropEffect = 'move'; | ||
| 54 | event.dataTransfer.effectAllowed = 'move'; | ||
| 55 | event.target.classList.add('is-dragged'); | ||
| 56 | } | ||
| 57 | |||
| 58 | /* While dragging make source element small enough to allow | ||
| 59 | dropping below its original area */ | ||
| 60 | t.ondrag = function( event, ui ) { | ||
| 61 | event.stopPropagation(); | ||
| 62 | event.target.classList.add('is-dragged'); | ||
| 63 | |||
| 64 | /* When drag starts in list view, switch to calendar view */ | ||
| 65 | if( document.body.classList.contains('in-list') ) { | ||
| 66 | toggle_grid(5); | ||
| 67 | document.body.classList.add('was-list'); | ||
| 68 | } | ||
| 69 | if( document.body.classList.contains('in-drag') ) | ||
| 70 | return; | ||
| 71 | |||
| 72 | document.body.classList.add('in-drag'); | ||
| 73 | /* mark all possible drop points regarding to availability */ | ||
| 74 | for (hour of allhours) | ||
| 75 | for (minute of allminutes) | ||
| 76 | for (day of alldays) | ||
| 77 | document.querySelectorAll('.grid.day_'+day+'.time_'+hour+minute).forEach(elem => elem.classList.toggle('possible', check_avail(event.target, day, hour+minute))); | ||
| 78 | |||
| 79 | } | ||
| 80 | |||
| 81 | t.ondragend = function( event, ui ) { | ||
| 82 | event.stopPropagation(); | ||
| 83 | |||
| 84 | /* We removed in-list and the drop did not succeed. Go back to list view */ | ||
| 85 | if (document.body.classList.contains('was-list')) | ||
| 86 | toggle_grid(0); | ||
| 87 | |||
| 88 | document.querySelectorAll('.over').forEach(elem => elem.classList.remove('over')); | ||
| 89 | document.querySelectorAll('.is-dragged').forEach(elem => elem.classList.remove('id-dragged')); | ||
| 90 | document.querySelectorAll('.possible').forEach(elem => elem.classList.remove('possible')); | ||
| 91 | document.body.classList.remove('in-drag', 'was-list'); | ||
| 92 | } | ||
| 93 | |||
| 94 | /* start_time: 2014-12-29T21:15:00+01:00" */ | ||
| 95 | var start_time = new Date(item.start_time); | ||
| 96 | |||
| 97 | var day = start_time.getDate()-26; | ||
| 98 | var hour = start_time.getHours(); | ||
| 99 | var mins = start_time.getMinutes(); | ||
| 100 | |||
| 101 | /* After midnight: sort into yesterday */ | ||
| 102 | if( hour < 9 ) | ||
| 103 | day--; | ||
| 104 | |||
| 105 | /* Fix up room for 38c3 */ | ||
| 106 | room = (item.room_id || 'room_unknown').toString().replace('471','room1').replace('472','room2').replace('473','room3'); | ||
| 107 | |||
| 108 | /* Apply attributes to sort events into calendar */ | ||
| 109 | t.classList.add(room, 'day_' + day, 'time_' + (hour<10?'0':'') + hour + (mins<10?'0':'') + mins); | ||
| 110 | t.setAttribute('fullnarp-day', day); | ||
| 111 | t.setAttribute('fullnarp-time', (hour<10?'0':'') + hour + (mins<10?'0':'') + mins ); | ||
| 112 | t.setAttribute('fullnarp-room', room.replace('room','')); | ||
| 113 | |||
| 114 | mark_avail(t); | ||
| 115 | |||
| 116 | t.onclick = function(event) { | ||
| 117 | _this = this; | ||
| 118 | document.body.classList.remove('in-drag'); | ||
| 119 | if (document.body.classList.contains('correlate')) { | ||
| 120 | document.querySelectorAll('.selected').forEach(elem => elem.classList.remove('selected')); | ||
| 121 | document.querySelectorAll('.event').forEach(elem => mark_correlation(elem, _this)); | ||
| 122 | } | ||
| 123 | _this.classList.toggle('selected'); | ||
| 124 | document.querySelectorAll('.info').forEach(elem => elem.classList.add('hidden')); | ||
| 125 | event.stopPropagation(); | ||
| 126 | } | ||
| 127 | |||
| 128 | /* Put new event into DOM tree. Track defaults to 'Other' */ | ||
| 129 | var track = item.track_id.toString(); | ||
| 130 | t.classList.add('track_' + track ); | ||
| 131 | var d = document.getElementById(track); | ||
| 132 | if (!d) | ||
| 133 | d = document.getElementById('Other'); | ||
| 134 | d.append(t); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 11 | function distribute_votes() { | 138 | function distribute_votes() { |
| 12 | document.querySelectorAll('.event').forEach( function(element) { | 139 | document.querySelectorAll('.event').forEach( function(element) { |
| 13 | var eid = element.getAttribute('event_id'); | 140 | var eid = element.getAttribute('event_id'); |
| @@ -37,8 +164,8 @@ function distribute_votes() { | |||
| 37 | } | 164 | } |
| 38 | 165 | ||
| 39 | function corr_for_eventids(id1, id2) { | 166 | function corr_for_eventids(id1, id2) { |
| 40 | var d = 0, c = 0, cd = 0, l = window.raw_votes.length; | 167 | var d = 0, c = 0, cd = 0, l = raw_votes.length; |
| 41 | for (item of window.raw_votes) { | 168 | for (item of raw_votes) { |
| 42 | var x = 0; | 169 | var x = 0; |
| 43 | if( item.indexOf(id1) > -1 ) { ++d; x++;} | 170 | if( item.indexOf(id1) > -1 ) { ++d; x++;} |
| 44 | if( item.indexOf(id2) > -1 ) { ++c; cd+=x; } | 171 | if( item.indexOf(id2) > -1 ) { ++c; cd+=x; } |
| @@ -52,42 +179,42 @@ function corr_for_eventids(id1, id2) { | |||
| 52 | } | 179 | } |
| 53 | 180 | ||
| 54 | function show_all_correlates(el) { | 181 | function show_all_correlates(el) { |
| 55 | /* First identify the room to see what other rooms to consider | 182 | /* First identify the room to see what other rooms to consider |
| 56 | correlates always grow from the top slot to the right, | 183 | correlates always grow from the top slot to the right, |
| 57 | unless there's an overlapping event to the left that starts earlier | 184 | unless there's an overlapping event to the left that starts earlier |
| 58 | */ | 185 | */ |
| 59 | var event_room = el.getAttribute('fullnarp-room'); | 186 | var event_room = el.getAttribute('fullnarp-room'); |
| 60 | var event_day = el.getAttribute('fullnarp-day'); | 187 | var event_day = el.getAttribute('fullnarp-day'); |
| 61 | var event_time = el.getAttribute('fullnarp-time'); | 188 | var event_time = el.getAttribute('fullnarp-time'); |
| 62 | 189 | ||
| 63 | if (!event_time) return; | 190 | if (!event_time) return; |
| 64 | 191 | ||
| 65 | var event_start; | 192 | var event_start; |
| 66 | try { event_start = time_to_mins(event_time); } catch(e) { return; } | 193 | try { event_start = time_to_mins(event_time); } catch(e) { return; } |
| 67 | var event_duration = el.getAttribute('fullnarp-duration') / 60; | 194 | var event_duration = el.getAttribute('fullnarp-duration') / 60; |
| 68 | 195 | ||
| 69 | /* Only test events to the right, if they start at the exact same time */ | 196 | /* Only test events to the right, if they start at the exact same time */ |
| 70 | document.querySelectorAll('.event.day_'+event_day).forEach( function(check_el, index) { | 197 | document.querySelectorAll('.event.day_'+event_day).forEach( function(check_el, index) { |
| 71 | var check_room = check_el.getAttribute('fullnarp-room'); | 198 | var check_room = check_el.getAttribute('fullnarp-room'); |
| 72 | if (event_room == check_room) return; | 199 | if (event_room == check_room) return; |
| 73 | 200 | ||
| 74 | var check_time = check_el.getAttribute('fullnarp-time'); | 201 | var check_time = check_el.getAttribute('fullnarp-time'); |
| 75 | if (!check_time) return; | 202 | if (!check_time) return; |
| 76 | var check_start = time_to_mins(check_time); | 203 | var check_start = time_to_mins(check_time); |
| 77 | var check_duration = check_el.getAttribute('fullnarp-duration') / 60; | 204 | var check_duration = check_el.getAttribute('fullnarp-duration') / 60; |
| 78 | var dist = check_el.getAttribute('fullnarp-room') - event_room; | 205 | var dist = check_el.getAttribute('fullnarp-room') - event_room; |
| 79 | var overlap = check_start < event_start + event_duration && event_start < check_start + check_duration; | 206 | var overlap = check_start < event_start + event_duration && event_start < check_start + check_duration; |
| 80 | 207 | ||
| 81 | if (!overlap) return; | 208 | if (!overlap) return; |
| 82 | if (event_start == check_start && dist <= 0) return; | 209 | if (event_start == check_start && dist <= 0) return; |
| 83 | if (event_start < check_start) return; | 210 | if (event_start < check_start) return; |
| 84 | 211 | ||
| 85 | var corr = corr_for_eventids(el.getAttribute('event_id'), check_el.getAttribute('event_id')); | 212 | var corr = corr_for_eventids(el.getAttribute('event_id'), check_el.getAttribute('event_id')); |
| 86 | var dir = dist > 0 ? 'r' : 'l'; | 213 | var dir = dist > 0 ? 'r' : 'l'; |
| 87 | var div = document.createElement('div'); | 214 | var div = document.createElement('div'); |
| 88 | div.classList.add('corrweb', dir.repeat(Math.abs(dist)), 'day_' + event_day, 'room' + event_room, 'time_' + event_time, 'corr_d_' + corr); | 215 | div.classList.add('corrweb', dir.repeat(Math.abs(dist)), 'day_' + event_day, 'room' + event_room, 'time_' + event_time, 'corr_d_' + corr); |
| 89 | document.body.appendChild(div); | 216 | document.body.appendChild(div); |
| 90 | }) | 217 | }); |
| 91 | } | 218 | } |
| 92 | 219 | ||
| 93 | function display_correlation() { | 220 | function display_correlation() { |
| @@ -104,8 +231,8 @@ function display_correlation() { | |||
| 104 | function mark_correlation(dest, comp) { | 231 | function mark_correlation(dest, comp) { |
| 105 | var id1 = dest.getAttribute('event_id'); | 232 | var id1 = dest.getAttribute('event_id'); |
| 106 | var id2 = comp.getAttribute('event_id'); | 233 | var id2 = comp.getAttribute('event_id'); |
| 107 | var d = 0, c = 0, cd = 0, l = window.raw_votes.length; | 234 | var d = 0, c = 0, cd = 0, l =raw_votes.length; |
| 108 | for (vote of window.raw_votes) { | 235 | for (vote of raw_votes) { |
| 109 | var x = 0; | 236 | var x = 0; |
| 110 | if( vote.indexOf(id1) > -1 ) { ++d; x++;} | 237 | if( vote.indexOf(id1) > -1 ) { ++d; x++;} |
| 111 | if( vote.indexOf(id2) > -1 ) { ++c; cd+=x; } | 238 | if( vote.indexOf(id2) > -1 ) { ++c; cd+=x; } |
| @@ -208,8 +335,9 @@ function remove_event(event_id) { | |||
| 208 | el.classList.add('pending'); | 335 | el.classList.add('pending'); |
| 209 | if (ws && ws.readyState === WebSocket.OPEN) { | 336 | if (ws && ws.readyState === WebSocket.OPEN) { |
| 210 | var message = { | 337 | var message = { |
| 338 | action: "remove_event", | ||
| 211 | lastupdate: window.lastupdate, | 339 | lastupdate: window.lastupdate, |
| 212 | removeevent: event_id | 340 | event_id: event_id |
| 213 | } | 341 | } |
| 214 | ws.send(JSON.stringify(message)); | 342 | ws.send(JSON.stringify(message)); |
| 215 | console.log('Sent:', message); | 343 | console.log('Sent:', message); |
| @@ -233,8 +361,9 @@ function set_all_attributes(event_id, day, room, time, from_server) { | |||
| 233 | el.classList.add('pending'); | 361 | el.classList.add('pending'); |
| 234 | if (ws && ws.readyState === WebSocket.OPEN) { | 362 | if (ws && ws.readyState === WebSocket.OPEN) { |
| 235 | var message = { | 363 | var message = { |
| 364 | action: "set_event", | ||
| 236 | lastupdate: window.lastupdate, | 365 | lastupdate: window.lastupdate, |
| 237 | setevent: event_id, | 366 | event_id: event_id, |
| 238 | day: el.getAttribute('fullnarp-day'), | 367 | day: el.getAttribute('fullnarp-day'), |
| 239 | room: el.getAttribute('fullnarp-room'), | 368 | room: el.getAttribute('fullnarp-room'), |
| 240 | time: el.getAttribute('fullnarp-time') | 369 | time: el.getAttribute('fullnarp-time') |
| @@ -264,26 +393,51 @@ function signalFullnarpConnect(state) { | |||
| 264 | document.body.classList.add(state); | 393 | document.body.classList.add(state); |
| 265 | } | 394 | } |
| 266 | 395 | ||
| 267 | function getFullnarpData(lastupdate) { | 396 | function getFullnarpData() { |
| 268 | signalFullnarpConnect('fullnarp-connecting'); | 397 | signalFullnarpConnect('fullnarp-connecting'); |
| 269 | ws = new WebSocket('wss://erdgeist.org/38C3/halfnarp/fullnarp-ws'); | 398 | ws = new WebSocket('wss://content.events.ccc.de/fullnarp/ws/'); |
| 270 | 399 | ||
| 271 | ws.onopen = () => { | 400 | ws.onopen = () => { |
| 272 | console.log('Connected to WebSocket server'); | 401 | console.log('Connected to WebSocket server'); |
| 273 | //stateElement.textContent = 'Connected'; | 402 | var message = { |
| 403 | action: raw_votes ? "reconnect" : "bootstrap" | ||
| 404 | }; | ||
| 405 | ws.send(JSON.stringify(message)); | ||
| 406 | console.log('Sent:', message); | ||
| 274 | }; | 407 | }; |
| 275 | 408 | ||
| 276 | ws.onmessage = (event) => { | 409 | ws.onmessage = (event) => { |
| 277 | signalFullnarpConnect('fullnarp-connected'); | 410 | signalFullnarpConnect('fullnarp-connected'); |
| 278 | const data = JSON.parse(event.data); | 411 | const data = JSON.parse(event.data); |
| 279 | console.log('Received:', data); | 412 | console.log('Received:', data); |
| 280 | for (const [eventid, event_new] of Object.entries(data.data)) { | 413 | |
| 281 | if (document.getElementById(eventid)) | 414 | switch (data.property) { |
| 282 | set_all_attributes(eventid, 'day_'+event_new['day'], 'room'+event_new['room'], 'time_'+event_new['time'], true ) | 415 | |
| 416 | case 'pretalx': | ||
| 417 | render_lectures(data.data); | ||
| 418 | break; | ||
| 419 | |||
| 420 | case 'halfnarp': | ||
| 421 | for (eventidlist of data.data) | ||
| 422 | for (eventid of eventidlist) | ||
| 423 | window.votes[eventid] = 1 + (window.votes[eventid] || 0 ); | ||
| 424 | raw_votes = data.data; | ||
| 425 | distribute_votes(); | ||
| 426 | break; | ||
| 427 | |||
| 428 | case 'fullnarp': | ||
| 429 | for (const [eventid, event_new] of Object.entries(data.data)) { | ||
| 430 | if (document.getElementById(eventid)) | ||
| 431 | set_all_attributes(eventid, 'day_'+event_new['day'], 'room'+event_new['room'], 'time_'+event_new['time'], true ) | ||
| 432 | } | ||
| 433 | window.lastupdate = data.current_version; | ||
| 434 | current_version_string = ('00000'+data.current_version).slice(-5); | ||
| 435 | document.querySelector('.version').innerHTML = '<a href="https://content.events.ccc.de/fullnarp/versions/fullnarp_'+current_version_string+'.json">Version: '+data.current_version+'</a>'; | ||
| 436 | break; | ||
| 437 | |||
| 438 | default: | ||
| 439 | console.log(`Unknown property: ${data['property']}.`); | ||
| 283 | } | 440 | } |
| 284 | window.lastupdate = data.current_version; | ||
| 285 | current_version_string = ('00000'+data.current_version).slice(-5); | ||
| 286 | document.querySelector('.version').innerHTML = '<a href="https://erdgeist.org/38C3/halfnarp/versions/fullnarp_'+current_version_string+'.json">Version: '+data.current_version+'</a>'; | ||
| 287 | }; | 441 | }; |
| 288 | 442 | ||
| 289 | ws.onerror = (error) => { | 443 | ws.onerror = (error) => { |
| @@ -302,11 +456,6 @@ function getFullnarpData(lastupdate) { | |||
| 302 | function do_the_fullnarp() { | 456 | function do_the_fullnarp() { |
| 303 | var halfnarpAPI = 'talks_38C3.json'; | 457 | var halfnarpAPI = 'talks_38C3.json'; |
| 304 | var fullnarpAPI = 'votes_38c3.json'; | 458 | var fullnarpAPI = 'votes_38c3.json'; |
| 305 | var allrooms = ['1','2','3'] | ||
| 306 | var allminutes = ['00','05','10','15','20','25','30','35','40','45','50','55'] | ||
| 307 | var allhours = ['10','11','12','13','14','15','16','17','18','19','20','21','22','23','00','01','02']; | ||
| 308 | var alldays = ['1','2','3','4']; | ||
| 309 | var voted = 0; | ||
| 310 | window.event_speakers = {}; | 459 | window.event_speakers = {}; |
| 311 | window.votes = {}; | 460 | window.votes = {}; |
| 312 | 461 | ||
| @@ -383,8 +532,8 @@ function do_the_fullnarp() { | |||
| 383 | elem.classList.add('guide', 'time_' + hour + '00'); | 532 | elem.classList.add('guide', 'time_' + hour + '00'); |
| 384 | document.body.append(elem); | 533 | document.body.append(elem); |
| 385 | 534 | ||
| 386 | for (minute of allminutes) { | 535 | for (minute of allminutes) |
| 387 | for (room of allrooms) { | 536 | for (room of allrooms) |
| 388 | for (day of alldays) { | 537 | for (day of alldays) { |
| 389 | elem = document.createElement('div'); | 538 | elem = document.createElement('div'); |
| 390 | elem.classList.add('grid', 'time_' + hour + minute, 'day_' + day, 'room' + room ); | 539 | elem.classList.add('grid', 'time_' + hour + minute, 'day_' + day, 'room' + room ); |
| @@ -408,170 +557,10 @@ function do_the_fullnarp() { | |||
| 408 | return false; | 557 | return false; |
| 409 | } | 558 | } |
| 410 | } | 559 | } |
| 411 | } | ||
| 412 | } | ||
| 413 | } | 560 | } |
| 414 | 561 | ||
| 415 | /* Fetch list of votes to display */ | 562 | window.lastupdate = 0; |
| 416 | fetch(`${fullnarpAPI}?format=json`) | 563 | getFullnarpData(); |
| 417 | .then(response => { | ||
| 418 | if (!response.ok) { | ||
| 419 | throw new Error(`HTTP error when fetching fullnarp data! status: ${response.status}`); | ||
| 420 | } | ||
| 421 | return response.json(); | ||
| 422 | }).then(data => { | ||
| 423 | window.raw_votes = data; | ||
| 424 | for (eventidlist of data) | ||
| 425 | for (eventid of eventidlist) | ||
| 426 | window.votes[eventid] = 1 + (window.votes[eventid] || 0 ); | ||
| 427 | if( ++voted == 2 ) { | ||
| 428 | window.lastupdate = 0; | ||
| 429 | distribute_votes(); | ||
| 430 | getFullnarpData(0); | ||
| 431 | } | ||
| 432 | }).catch(error => { | ||
| 433 | console.error('Fetch error:', error); | ||
| 434 | }); | ||
| 435 | |||
| 436 | |||
| 437 | /* Fetch list of lectures to display */ | ||
| 438 | fetch(`${halfnarpAPI}?format=json`) | ||
| 439 | .then(response => { | ||
| 440 | if (!response.ok) { | ||
| 441 | throw new Error(`HTTP error when fetching halfnarp data! status: ${response.status}`); | ||
| 442 | } | ||
| 443 | return response.json(); | ||
| 444 | }).then(data => { | ||
| 445 | for (item of data) { | ||
| 446 | /* Take copy of hidden event template div and select them, if they're in | ||
| 447 | list of previous prereferences */ | ||
| 448 | var t = document.getElementById('template').cloneNode(true); | ||
| 449 | var event_id = item.event_id.toString(); | ||
| 450 | t.classList.add('event', 'duration_' + item.duration, 'lang_' + (item.language || 'en')); | ||
| 451 | t.setAttribute('event_id', event_id); | ||
| 452 | t.setAttribute('id', 'event_' + event_id) | ||
| 453 | t.setAttribute( 'fullnarp-duration', item.duration); | ||
| 454 | |||
| 455 | /* Sort textual info into event div */ | ||
| 456 | t.querySelector('.title').textContent = item.title; | ||
| 457 | t.querySelector('.speakers').textContent = item.speaker_names; | ||
| 458 | t.querySelector('.abstract').append(item.abstract); | ||
| 459 | |||
| 460 | /* Store speakers and their availabilities */ | ||
| 461 | window.event_speakers[event_id] = item.speakers; | ||
| 462 | for (speaker of item.speakers) { | ||
| 463 | var have_avails = false; | ||
| 464 | if (!speaker.availabilities) | ||
| 465 | console.log("Foo"); | ||
| 466 | for (avail of speaker.availabilities) { | ||
| 467 | if (avail.id ) { | ||
| 468 | have_avails = true; | ||
| 469 | break; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | if (!have_avails) | ||
| 473 | t.classList.add('has_unavailable_speaker'); | ||
| 474 | } | ||
| 475 | |||
| 476 | t.setAttribute('draggable', 'true'); | ||
| 477 | |||
| 478 | /* Make the event drag&droppable */ | ||
| 479 | t.ondragstart = function( event, ui ) { | ||
| 480 | event.stopPropagation(); | ||
| 481 | |||
| 482 | event.dataTransfer.setData('text/plain', this.id ); | ||
| 483 | event.dataTransfer.dropEffect = 'move'; | ||
| 484 | event.dataTransfer.effectAllowed = 'move'; | ||
| 485 | event.target.classList.add('is-dragged'); | ||
| 486 | } | ||
| 487 | |||
| 488 | /* While dragging make source element small enough to allow | ||
| 489 | dropping below its original area */ | ||
| 490 | t.ondrag = function( event, ui ) { | ||
| 491 | event.stopPropagation(); | ||
| 492 | event.target.classList.add('is-dragged'); | ||
| 493 | |||
| 494 | /* When drag starts in list view, switch to calendar view */ | ||
| 495 | if( document.body.classList.contains('in-list') ) { | ||
| 496 | toggle_grid(5); | ||
| 497 | document.body.classList.add('was-list'); | ||
| 498 | } | ||
| 499 | if( document.body.classList.contains('in-drag') ) | ||
| 500 | return; | ||
| 501 | |||
| 502 | document.body.classList.add('in-drag'); | ||
| 503 | /* mark all possible drop points regarding to availability */ | ||
| 504 | for (hour of allhours) | ||
| 505 | for (minute of allminutes) | ||
| 506 | for (day of alldays) | ||
| 507 | document.querySelectorAll('.grid.day_'+day+'.time_'+hour+minute).forEach(elem => elem.classList.toggle('possible', check_avail(event.target, day, hour+minute))); | ||
| 508 | |||
| 509 | } | ||
| 510 | |||
| 511 | t.ondragend = function( event, ui ) { | ||
| 512 | event.stopPropagation(); | ||
| 513 | |||
| 514 | /* We removed in-list and the drop did not succeed. Go back to list view */ | ||
| 515 | if (document.body.classList.contains('was-list')) | ||
| 516 | toggle_grid(0); | ||
| 517 | |||
| 518 | document.querySelectorAll('.over').forEach(elem => elem.classList.remove('over')); | ||
| 519 | document.querySelectorAll('.is-dragged').forEach(elem => elem.classList.remove('id-dragged')); | ||
| 520 | document.querySelectorAll('.possible').forEach(elem => elem.classList.remove('possible')); | ||
| 521 | document.body.classList.remove('in-drag', 'was-list'); | ||
| 522 | } | ||
| 523 | |||
| 524 | /* start_time: 2014-12-29T21:15:00+01:00" */ | ||
| 525 | var start_time = new Date(item.start_time); | ||
| 526 | |||
| 527 | var day = start_time.getDate()-26; | ||
| 528 | var hour = start_time.getHours(); | ||
| 529 | var mins = start_time.getMinutes(); | ||
| 530 | |||
| 531 | /* After midnight: sort into yesterday */ | ||
| 532 | if( hour < 9 ) | ||
| 533 | day--; | ||
| 534 | |||
| 535 | /* Fix up room for 38c3 */ | ||
| 536 | room = (item.room_id || 'room_unknown').toString().replace('471','room1').replace('472','room2').replace('473','room3'); | ||
| 537 | |||
| 538 | /* Apply attributes to sort events into calendar */ | ||
| 539 | t.classList.add(room, 'day_' + day, 'time_' + (hour<10?'0':'') + hour + (mins<10?'0':'') + mins); | ||
| 540 | t.setAttribute('fullnarp-day', day); | ||
| 541 | t.setAttribute('fullnarp-time', (hour<10?'0':'') + hour + (mins<10?'0':'') + mins ); | ||
| 542 | t.setAttribute('fullnarp-room', room.replace('room','')); | ||
| 543 | |||
| 544 | mark_avail(t); | ||
| 545 | |||
| 546 | t.onclick = function(event) { | ||
| 547 | _this = this; | ||
| 548 | document.body.classList.remove('in-drag'); | ||
| 549 | if (document.body.classList.contains('correlate')) { | ||
| 550 | document.querySelectorAll('.selected').forEach(elem => elem.classList.remove('selected')); | ||
| 551 | document.querySelectorAll('.event').forEach(elem => mark_correlation(elem, _this)); | ||
| 552 | } | ||
| 553 | _this.classList.toggle('selected'); | ||
| 554 | document.querySelectorAll('.info').forEach(elem => elem.classList.add('hidden')); | ||
| 555 | event.stopPropagation(); | ||
| 556 | } | ||
| 557 | |||
| 558 | /* Put new event into DOM tree. Track defaults to 'Other' */ | ||
| 559 | var track = item.track_id.toString(); | ||
| 560 | t.classList.add('track_' + track ); | ||
| 561 | var d = document.getElementById(track); | ||
| 562 | if (!d) | ||
| 563 | d = document.querySelector('#Other'); | ||
| 564 | d.append(t); | ||
| 565 | }; | ||
| 566 | |||
| 567 | if( ++voted == 2 ) { | ||
| 568 | window.lastupdate = 0; | ||
| 569 | distribute_votes(); | ||
| 570 | getFullnarpData(0); | ||
| 571 | } | ||
| 572 | }).catch(error => { | ||
| 573 | console.error('Fetch error:', error); | ||
| 574 | }); | ||
| 575 | 564 | ||
| 576 | document.onkeypress = function(e) { | 565 | document.onkeypress = function(e) { |
| 577 | document.body.classList.remove('in-drag'); | 566 | document.body.classList.remove('in-drag'); |
