Compare commits

...

2 Commits

Author SHA1 Message Date
93e0b80128 live status and countdown timer 2018-09-30 15:20:42 -04:00
eb4ccddb37 adjust header and chatPane height 2018-09-30 01:30:50 -04:00
13 changed files with 127 additions and 30 deletions

View File

@ -14,14 +14,14 @@
</head>
<body>
<div id="globalWrapper">
<ul id="header" class="header" style="{% if request.session.get("hide_header") == True %}display:none;{% else %}display:initial;{% endif %}">
<li><a onclick="toggle_header();" href="javascript:void(0);"></a></li>
<li><a href="{{ url('homepage:index') }}">Home</a></li>
<div id="header" class="header" style="{% if request.session.get("hide_header") == True %}display:none;{% else %}display:flex;{% endif %}">
<span><a onclick="toggle_header();" href="javascript:void(0);"></a></span>
<span><a href="{{ url('homepage:index') }}">Home</a></span>
{% block header %}{% endblock %}
</ul>
<ul id="headerHidden" class="header" style="{% if request.session.get("hide_header") == True %}display:initial;{% else %}display:none;{% endif %}">
<li><a onclick="toggle_header();" href="javascript:void(0);"></a></li>
</ul>
</div>
<div id="headerHidden" class="header" style="{% if request.session.get("hide_header") == True %}display:initial;{% else %}display:none;{% endif %}">
<span><a onclick="toggle_header();" href="javascript:void(0);"></a></span>
</div>
<ul id="alerts">
{% for message in get_messages(request) %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>

View File

@ -42,3 +42,7 @@ class EditQuestForm(forms.Form):
Form for the /edit_quest page.
"""
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" %}
{% block title %}Edit {{ quest.title }}{% endblock %}
{% block head %}
<script>
window.onload = function() { document.getElementById('timezone').value = new Date().getTimezoneOffset(); };
</script>
{% endblock %}
{% block content %}
<center><h1>{{ quest.title }}</h1></center>
<form method="post" action="{{ url('quest:edit_quest', args=[quest_id]) }}">
@ -19,13 +24,15 @@
</tr>
<tr>
<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>
<td>Live In:</td>
<td>Placeholder</td>
<td>Live time:</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>
</table>
<input type="hidden" name="timezone" id="timezone">
<input type="submit">
</form>
{% endblock %}

View File

@ -7,7 +7,7 @@
{% endif %}
<script>
const quest_id = {{ quest.id }};
const page_num = {{ page_num }};
const page_num = '{{ page_num }}';
const SCRIPT_NAME = '{{ request.META["SCRIPT_NAME"] }}';
const anon_name = '{{ quest.anon_name }}';
</script>
@ -19,9 +19,9 @@
{% endblock %}
{% block header %}
{% if request.user == quest.owner %}
<li><a href="{{ url('quest:edit_quest', args=[quest_id]) }}">Edit Quest</a></li>
<span><a href="{{ url('quest:edit_quest', args=[quest_id, page_num]) }}">Edit Quest</a></span>
{% endif %}
<li>
<span>
<select onChange="window.location.href=this.value">
<optgroup label="Pages">
{% for page in pages %}
@ -36,8 +36,19 @@
</optgroup>
{% endif %}
</select>
</li>
<li id="toggleChat"><a onclick="toggle_chat()" href="javascript:void(0);">{% if request.session.get("hide_chat") == True %}←{% else %}→{% endif %}</a></li>
</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>
{% endblock %}
{% block content %}
<div id="questPane" style="width:{% if request.session.get("hide_chat") == True %}100%{% else %}70%{% endif %};">

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

View File

@ -8,6 +8,16 @@ h3 {
margin-bottom: 0.5em;
}
#live {
color: white;
background-color: red;
padding: 0.25em;
}
#toggleChat {
margin-left: auto;
}
#questPane {
float: left;
box-sizing: border-box;
@ -111,8 +121,8 @@ h3 {
}
#chatPane {
height: calc(100% - var(--header-height));
width: 30%;
height: calc(100vh - 2em);
right: 0;
position: fixed;
display: flex;

View File

@ -44,6 +44,7 @@ function load() {
socket.send('message', {message: text});
}
});
live_countdown();
}
/* Websocket receive */
@ -265,3 +266,16 @@ function toggle_chat() {
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'
urlpatterns = [
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>/<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.
"""
from datetime import timedelta, datetime, timezone
from django.contrib import messages
from django.http import HttpResponse
from django.shortcuts import render, redirect
@ -53,6 +55,21 @@ def edit_quest(request, quest_id, page_num=1):
form = EditQuestForm(request.POST)
if form.is_valid():
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()
return redirect('quest:quest',quest_id=quest.id, page_num=page_num)
else:

View File

@ -1,7 +1,3 @@
:root {
--header-height: 1.25em;
}
body {
margin: 0;
}
@ -18,13 +14,21 @@ body {
margin: 0;
padding: 0;
width: 100%;
height: var(--header-height);
height: 2em;
list-style-type: none;
background-color: #dddddd;
display: flex;
align-items: center;
}
.header li {
display: inline;
.header span {
padding-right: 0.25em;
padding-left: 0.25em;
}
.header span span {
padding-right: 0;
padding-left: 0;
}
.header a {

View File

@ -6,13 +6,13 @@ function toggle_cookie(cookie, state) {
xhr.send(cookie + '=' + state);
}
function toggle_header() {
if (document.getElementById('header').style.display == 'initial') {
if (document.getElementById('header').style.display == 'flex') {
document.getElementById('header').style.display = 'none';
document.getElementById('headerHidden').style.display = 'initial';
toggle_cookie('hide_header', 'on');
}
else {
document.getElementById('header').style.display = 'initial';
document.getElementById('header').style.display = 'flex';
document.getElementById('headerHidden').style.display = 'none';
toggle_cookie('hide_header', 'off');
}

3
todo
View File

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