live status and countdown timer

This commit is contained in:
iou1name 2018-09-30 15:20:42 -04:00
parent eb4ccddb37
commit 93e0b80128
11 changed files with 103 additions and 8 deletions

View File

@ -42,3 +42,7 @@ class EditQuestForm(forms.Form):
Form for the /edit_quest page. Form for the /edit_quest page.
""" """
anon_name = forms.CharField(max_length=20) anon_name = forms.CharField(max_length=20)
live = forms.BooleanField(required=False)
live_date = forms.DateField(required=False)
live_time = forms.TimeField(required=False)
timezone = forms.IntegerField()

View File

@ -1,5 +1,10 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block title %}Edit {{ quest.title }}{% endblock %} {% block title %}Edit {{ quest.title }}{% endblock %}
{% block head %}
<script>
window.onload = function() { document.getElementById('timezone').value = new Date().getTimezoneOffset(); };
</script>
{% endblock %}
{% block content %} {% block content %}
<center><h1>{{ quest.title }}</h1></center> <center><h1>{{ quest.title }}</h1></center>
<form method="post" action="{{ url('quest:edit_quest', args=[quest_id]) }}"> <form method="post" action="{{ url('quest:edit_quest', args=[quest_id]) }}">
@ -19,13 +24,15 @@
</tr> </tr>
<tr> <tr>
<td>Live:</td> <td>Live:</td>
<td><input type="checkbox" name="live" value="off"></td> <td><input type="checkbox" name="live"{% if quest.live %} checked{% endif %}></td>
</tr> </tr>
<tr> <tr>
<td>Live In:</td> <td>Live time:</td>
<td>Placeholder</td> <td><input type="date" name="live_date" id="live_date" value="{{ localtime(quest.live_time).strftime('%Y-%m-%d') }}"></td>
<td><input type="time" name="live_time" id="live_time" step="60" value="{{ localtime(quest.live_time).strftime('%H:%M:%S') }}"></td>
</tr> </tr>
</table> </table>
<input type="hidden" name="timezone" id="timezone">
<input type="submit"> <input type="submit">
</form> </form>
{% endblock %} {% endblock %}

View File

@ -37,6 +37,17 @@
{% endif %} {% endif %}
</select> </select>
</span> </span>
{% if quest.live %}
<span id="live">
LIVE
</span>
{% else %}
{% if quest.live_time %}
<span id="liveIn">
Live in: <span id="liveCountdown"></span> (<span id="liveTime">{{ localtime(quest.live_time).strftime('%Y-%m-%d %H:%M') }}</span>)
</span>
{% endif %}
{% endif %}
<span id="toggleChat"><a onclick="toggle_chat()" href="javascript:void(0);">{% if request.session.get("hide_chat") == True %}←{% else %}→{% endif %}</a></span> <span id="toggleChat"><a onclick="toggle_chat()" href="javascript:void(0);">{% if request.session.get("hide_chat") == True %}←{% else %}→{% endif %}</a></span>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View File

@ -0,0 +1,29 @@
# Generated by Django 2.1.1 on 2018-09-28 11:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('quest', '0002_auto_20180925_0936'),
]
operations = [
migrations.AddField(
model_name='quest',
name='live',
field=models.BooleanField(default=False),
preserve_default=False,
),
migrations.AddField(
model_name='quest',
name='live_time',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AlterField(
model_name='page',
name='appendix',
field=models.BooleanField(),
),
]

View File

@ -15,6 +15,8 @@ class Quest(models.Model):
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
on_delete=models.CASCADE) on_delete=models.CASCADE)
anon_name = models.CharField(max_length=20, default="Anonymous") anon_name = models.CharField(max_length=20, default="Anonymous")
live = models.BooleanField()
live_time = models.DateTimeField(blank=True, null=True)
class Message(models.Model): class Message(models.Model):
@ -38,7 +40,7 @@ class Page(models.Model):
quest = models.ForeignKey(Quest, on_delete=models.CASCADE) quest = models.ForeignKey(Quest, on_delete=models.CASCADE)
page_num = models.CharField(max_length=4) page_num = models.CharField(max_length=4)
title = models.CharField(max_length=200) title = models.CharField(max_length=200)
appendix = models.BooleanField(default=False) appendix = models.BooleanField()
def __str__(self): def __str__(self):
return self.title return self.title

View File

@ -8,6 +8,12 @@ h3 {
margin-bottom: 0.5em; margin-bottom: 0.5em;
} }
#live {
color: white;
background-color: red;
padding: 0.25em;
}
#toggleChat { #toggleChat {
margin-left: auto; margin-left: auto;
} }

View File

@ -44,6 +44,7 @@ function load() {
socket.send('message', {message: text}); socket.send('message', {message: text});
} }
}); });
live_countdown();
} }
/* Websocket receive */ /* Websocket receive */
@ -265,3 +266,16 @@ function toggle_chat() {
toggle_cookie('hide_chat', 'off'); toggle_cookie('hide_chat', 'off');
} }
} }
function live_countdown() {
if (!document.getElementById('liveTime')) { return; }
setInterval(function() {
let delta = new Date(document.getElementById('liveTime').innerText) - new Date();
let days = parseInt(delta / (24*60*60*1000));
let hours = parseInt((delta % (24*60*60*1000)) / (60*60*1000));
let minutes = parseInt((delta % (60*60*1000)) / (60*1000));
let seconds = parseInt((delta % (60*1000)) / (1000));
let str = ((days) ? padToTwo(days) + ':' : '') + ((hours) ? padToTwo(hours) + ':' : '') + ((minutes) ? padToTwo(minutes) + ':' : '') + padToTwo(seconds);
document.getElementById('liveCountdown').innerText = str;
}, 1000);
}

View File

@ -9,8 +9,8 @@ from . import views
app_name = 'quest' app_name = 'quest'
urlpatterns = [ urlpatterns = [
path('', views.index, name='index'), path('', views.index, name='index'),
path('<int:quest_id>', views.quest, name='quest'),
path('<int:quest_id>/<page_num>', views.quest, name='quest'),
path('<int:quest_id>/edit_quest', views.edit_quest, name='edit_quest'), path('<int:quest_id>/edit_quest', views.edit_quest, name='edit_quest'),
path('<int:quest_id>/<page_num>/edit_quest', views.edit_quest, name='edit_quest'), path('<int:quest_id>/<page_num>/edit_quest', views.edit_quest, name='edit_quest'),
path('<int:quest_id>', views.quest, name='quest'),
path('<int:quest_id>/<page_num>', views.quest, name='quest'),
] ]

View File

@ -2,6 +2,8 @@
""" """
Quest and quest accessory views. Quest and quest accessory views.
""" """
from datetime import timedelta, datetime, timezone
from django.contrib import messages from django.contrib import messages
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
@ -53,6 +55,21 @@ def edit_quest(request, quest_id, page_num=1):
form = EditQuestForm(request.POST) form = EditQuestForm(request.POST)
if form.is_valid(): if form.is_valid():
quest.anon_name = form.cleaned_data['anon_name'] quest.anon_name = form.cleaned_data['anon_name']
quest.live = form.cleaned_data['live']
live_date = form.cleaned_data['live_date']
live_time = form.cleaned_data['live_time']
if live_date and live_time:
live_datetime = datetime.combine(
live_date,
live_time,
timezone.utc
)
tz_delta = timedelta(minutes=form.cleaned_data['timezone'])
live_datetime = live_datetime + tz_delta
quest.live_time = live_datetime
else:
quest.live_time = None
quest.save() quest.save()
return redirect('quest:quest',quest_id=quest.id, page_num=page_num) return redirect('quest:quest',quest_id=quest.id, page_num=page_num)
else: else:

View File

@ -23,6 +23,12 @@ body {
.header span { .header span {
padding-right: 0.25em; padding-right: 0.25em;
padding-left: 0.25em;
}
.header span span {
padding-right: 0;
padding-left: 0;
} }
.header a { .header a {

3
todo
View File

@ -1,5 +1,4 @@
New Features: New Features:
Live indicator/countdown
Notifications Notifications
Banner images Banner images
Search page Search page
@ -10,13 +9,13 @@ Account managament/logout
Display profile link in header bar Display profile link in header bar
Tagging system Tagging system
Quote backlinks Quote backlinks
Quest homepage
Improvements: Improvements:
More options for text posts (lists and so on) More options for text posts (lists and so on)
More rigorous input checking in events.py More rigorous input checking in events.py
New post displays chat message New post displays chat message
Poll vote highlights entire option Poll vote highlights entire option
Poll vote doesn't disappear checkbox
Total voters per poll Total voters per poll
Chat archives Chat archives
Only last 100 (50?) chat messages are loaded on page load Only last 100 (50?) chat messages are loaded on page load