Compare commits
6 Commits
617f0b7a6d
...
3e015e75d9
Author | SHA1 | Date | |
---|---|---|---|
3e015e75d9 | |||
5485bf8aa9 | |||
1c1ed68d7b | |||
3d0f1beadf | |||
3f073a9d03 | |||
78820ac797 |
|
@ -40,7 +40,7 @@ class QuestConsumer(WebsocketConsumer):
|
||||||
return
|
return
|
||||||
self.events[event](self, data.get('data'))
|
self.events[event](self, data.get('data'))
|
||||||
|
|
||||||
def send(self, event, data):
|
def send(self, event, data={}):
|
||||||
"""
|
"""
|
||||||
Overridden method. If a dictionary is provided, it is converted
|
Overridden method. If a dictionary is provided, it is converted
|
||||||
to JSON before sending it.
|
to JSON before sending it.
|
||||||
|
|
156
quest/events.py
156
quest/events.py
|
@ -6,10 +6,13 @@ QuestConsumer object in consumers.py.
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
import types
|
import types
|
||||||
|
import random
|
||||||
|
|
||||||
import bleach
|
import bleach
|
||||||
|
from django.utils.timezone import localtime
|
||||||
|
|
||||||
from quest.models import Message, Quest
|
from quest.models import Message, Quest, Post, DiceCall
|
||||||
|
from quest.forms import DiceCallForm
|
||||||
|
|
||||||
def message(socket, data):
|
def message(socket, data):
|
||||||
"""
|
"""
|
||||||
|
@ -19,12 +22,14 @@ def message(socket, data):
|
||||||
message = data.get('message')
|
message = data.get('message')
|
||||||
quest_id = data.get('quest_id')
|
quest_id = data.get('quest_id')
|
||||||
|
|
||||||
|
# cleaning
|
||||||
message = message.strip()
|
message = message.strip()
|
||||||
if not message:
|
if not message:
|
||||||
return
|
return
|
||||||
tags = ["b", "code", "i", "s"]
|
tags = ["b", "code", "i", "s"]
|
||||||
message = bleach.clean(message, tags=tags)
|
message = bleach.clean(message, tags=tags)
|
||||||
|
|
||||||
|
# greentext
|
||||||
lines = []
|
lines = []
|
||||||
for line in message.splitlines():
|
for line in message.splitlines():
|
||||||
if line.startswith(">") and not line.startswith(">>"):
|
if line.startswith(">") and not line.startswith(">>"):
|
||||||
|
@ -32,6 +37,7 @@ def message(socket, data):
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
message = "<br>".join(lines)
|
message = "<br>".join(lines)
|
||||||
|
|
||||||
|
# quote links
|
||||||
quotes = re.findall(r">>\d+", message)
|
quotes = re.findall(r">>\d+", message)
|
||||||
for quote in quotes:
|
for quote in quotes:
|
||||||
msg_id = quote.replace(">>", "")
|
msg_id = quote.replace(">>", "")
|
||||||
|
@ -41,6 +47,32 @@ def message(socket, data):
|
||||||
msg += 'onmouseout="clearPreview()">' + quote + '</a>'
|
msg += 'onmouseout="clearPreview()">' + quote + '</a>'
|
||||||
message = message.replace(quote, msg)
|
message = message.replace(quote, msg)
|
||||||
|
|
||||||
|
# handle image
|
||||||
|
|
||||||
|
# dice rolling
|
||||||
|
if any(map(message.startswith, ["/dice", "/roll"])):
|
||||||
|
reg = re.search(r"(\d+)d(\d+)([+-]\d+)?", data["message"])
|
||||||
|
if not reg:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
groups = [0 if d is None else int(d) for d in reg.groups()]
|
||||||
|
dice_num, dice_sides, dice_mod = groups
|
||||||
|
assert 0 < dice_num < 100
|
||||||
|
assert 0 < dice_sides < 100
|
||||||
|
assert -1000 < dice_mod < 1000
|
||||||
|
except (ValueError, AssertionError):
|
||||||
|
return
|
||||||
|
dice = [random.randint(1, dice_sides) for _ in range(dice_num)]
|
||||||
|
total = sum(dice) + dice_mod
|
||||||
|
roll_msg = f"Rolled {', '.join(map(str, dice))}"
|
||||||
|
if dice_mod:
|
||||||
|
if dice_mod > 0:
|
||||||
|
roll_msg += " + " + str(dice_mod)
|
||||||
|
else:
|
||||||
|
roll_msg += " - " + str(dice_mod)[1:]
|
||||||
|
roll_msg += " = " + str(total)
|
||||||
|
message += '<hr class="msgSrvHr" /><b>' + roll_msg + "</b>"
|
||||||
|
|
||||||
user = socket.scope['user']
|
user = socket.scope['user']
|
||||||
|
|
||||||
m = Message(
|
m = Message(
|
||||||
|
@ -58,6 +90,128 @@ def message(socket, data):
|
||||||
socket.send('message', data)
|
socket.send('message', data)
|
||||||
|
|
||||||
|
|
||||||
|
def text_post(socket, data):
|
||||||
|
"""
|
||||||
|
Called when the QM creates a new text post.
|
||||||
|
"""
|
||||||
|
# TODO: security
|
||||||
|
quest_id = data.get('quest_id')
|
||||||
|
post_text = data.get('text')
|
||||||
|
page_num = data.get('page_num')
|
||||||
|
|
||||||
|
# cleaning
|
||||||
|
post_text = bleach.clean(post_text.strip())
|
||||||
|
post_text = text.replace("\n", "<br>")
|
||||||
|
|
||||||
|
# handle image
|
||||||
|
|
||||||
|
p = Post(
|
||||||
|
quest=Quest.objects.get(id=quest_id),
|
||||||
|
page_num=page_num,
|
||||||
|
post_type='text',
|
||||||
|
post_text=post_text)
|
||||||
|
p.save()
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
data['post_text'] = post_text
|
||||||
|
data['post_type'] = 'text'
|
||||||
|
data['date'] = localtime(p.timestamp).strftime('%Y-%m-%d %H:%M')
|
||||||
|
data['post_id'] = p.id
|
||||||
|
socket.send('new_post', data)
|
||||||
|
|
||||||
|
|
||||||
|
def dice_post(socket, data):
|
||||||
|
"""
|
||||||
|
Called when the QM makes a new dice post.
|
||||||
|
"""
|
||||||
|
quest_id = data.get('quest_id')
|
||||||
|
page_num = data.get('page_num')
|
||||||
|
form = DiceCallForm(data)
|
||||||
|
if not form.is_valid():
|
||||||
|
return # error message?
|
||||||
|
form = form.cleaned_data
|
||||||
|
|
||||||
|
dice_roll = str(form['diceNum']) + "d"
|
||||||
|
dice_roll += str(form['diceSides'])
|
||||||
|
if form['diceMod']:
|
||||||
|
if form['diceMod'] > 0:
|
||||||
|
dice_roll += "+"
|
||||||
|
dice_roll += str(form['diceMod'])
|
||||||
|
|
||||||
|
post_text = "Roll " + dice_roll
|
||||||
|
if form['diceChal']:
|
||||||
|
post_text += " vs DC" + str(form['diceChal'])
|
||||||
|
|
||||||
|
p = Post(
|
||||||
|
quest=Quest.objects.get(id=quest_id),
|
||||||
|
page_num=page_num,
|
||||||
|
post_type='dice',
|
||||||
|
post_text=post_text
|
||||||
|
)
|
||||||
|
p.save()
|
||||||
|
d = DiceCall(
|
||||||
|
post=p,
|
||||||
|
dice_roll=dice_roll,
|
||||||
|
strict=form['diceStrict'],
|
||||||
|
dice_challenge=form['diceChal'],
|
||||||
|
rolls_taken=form['diceRollsTaken'],
|
||||||
|
open=True,
|
||||||
|
)
|
||||||
|
d.save()
|
||||||
|
|
||||||
|
socket.send('close_all_posts')
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
data['post_text'] = post_text
|
||||||
|
data['post_type'] = 'dice'
|
||||||
|
data['date'] = localtime(p.timestamp).strftime('%Y-%m-%d %H:%M')
|
||||||
|
data['post_id'] = p.id
|
||||||
|
socket.send('new_post', data)
|
||||||
|
|
||||||
|
|
||||||
|
def close_post(socket, data):
|
||||||
|
"""
|
||||||
|
Called when the QM closes an open post.
|
||||||
|
"""
|
||||||
|
post_id = data.get('post_id')
|
||||||
|
p = Post.objects.get(id=post_id)
|
||||||
|
if data.get('post_type') == 'dice':
|
||||||
|
p.dicecall.open = False
|
||||||
|
p.dicecall.save()
|
||||||
|
elif data.get('post_type') == 'poll':
|
||||||
|
p.poll.open = False
|
||||||
|
p.poll.save()
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
data['post_id'] = post_id
|
||||||
|
socket.send('close_post', data)
|
||||||
|
|
||||||
|
|
||||||
|
def open_post(socket, data):
|
||||||
|
"""
|
||||||
|
Called when the QM opens a closed post.
|
||||||
|
"""
|
||||||
|
# TODO: only posts on last page can be opened
|
||||||
|
post_id = data.get('post_id')
|
||||||
|
p = Post.objects.get(id=post_id)
|
||||||
|
if data.get('post_type') == 'dice':
|
||||||
|
posts = Post.objects.filter(post_type='dice', dicecall__open=True)
|
||||||
|
for post in posts:
|
||||||
|
post.dicecall.open = False
|
||||||
|
post.dicecall.save()
|
||||||
|
socket.send('close_all_posts', {'post_type': 'dice'})
|
||||||
|
|
||||||
|
p.dicecall.open = True
|
||||||
|
p.dicecall.save()
|
||||||
|
elif data.get('post_type') == 'poll':
|
||||||
|
p.poll.open = True
|
||||||
|
p.poll.save()
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
data['post_id'] = post_id
|
||||||
|
socket.send('open_post', data)
|
||||||
|
|
||||||
|
|
||||||
events = {}
|
events = {}
|
||||||
for obj in dir():
|
for obj in dir():
|
||||||
if type(locals()[obj]) == types.FunctionType:
|
if type(locals()[obj]) == types.FunctionType:
|
||||||
|
|
19
quest/forms.py
Normal file
19
quest/forms.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Form(s) for the quest page.
|
||||||
|
"""
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
class DiceCallForm(forms.Form):
|
||||||
|
"""
|
||||||
|
The form for the QM making dice calls.
|
||||||
|
"""
|
||||||
|
diceNum = forms.IntegerField(min_value=1, max_value=99)
|
||||||
|
diceSides = forms.IntegerField(min_value=1, max_value=99)
|
||||||
|
diceMod = forms.IntegerField(
|
||||||
|
min_value=-999, max_value=999, required=False)
|
||||||
|
diceChal = forms.IntegerField(
|
||||||
|
min_value=1, max_value=999, required=False)
|
||||||
|
diceRollsTaken = forms.IntegerField(
|
||||||
|
min_value=1, max_value=99, required=False)
|
||||||
|
diceStrict = forms.BooleanField(required=False)
|
|
@ -9,7 +9,7 @@
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript" src="{{ static('quest.js') }}"></script>
|
<script type="text/javascript" src="{{ static('quest.js') }}"></script>
|
||||||
{% if request.user == quest.owner %}
|
{% if request.user == quest.owner %}
|
||||||
{#<script type="text/javascript" src="{{ static('questQM.js') }}"></script>#}
|
<script type="text/javascript" src="{{ static('questQM.js') }}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script>window.onload = load;</script>
|
<script>window.onload = load;</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -34,9 +34,9 @@
|
||||||
{% if post.post_type == "text" %}
|
{% if post.post_type == "text" %}
|
||||||
<div class="questPost textPost">
|
<div class="questPost textPost">
|
||||||
{% elif post.post_type == "dice" %}
|
{% elif post.post_type == "dice" %}
|
||||||
<div class="questPost dicePost{% if post == posts|last %} activePost{% endif %}">
|
<div class="questPost dicePost{% if post.dicecall.open %} activePost{% endif %}">
|
||||||
{% elif post.post_type == "poll" %}
|
{% elif post.post_type == "poll" %}
|
||||||
<div class="questPost pollPost{% if post == posts|last %} activePost{% endif %}">
|
<div class="questPost pollPost{% if post.poll.open %} activePost{% endif %}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="questPostMeta">
|
<div class="questPostMeta">
|
||||||
{{ localtime(post.timestamp).strftime('%Y-%m-%d %H:%M') }}
|
{{ localtime(post.timestamp).strftime('%Y-%m-%d %H:%M') }}
|
||||||
|
@ -44,9 +44,12 @@
|
||||||
{% if post.post_type == "text" %}
|
{% if post.post_type == "text" %}
|
||||||
<br /><a href="javascript:void(0);" id="editPost-{{ post.id }}" onclick="edit_post({{ post.id }})">Edit</a>
|
<br /><a href="javascript:void(0);" id="editPost-{{ post.id }}" onclick="edit_post({{ post.id }})">Edit</a>
|
||||||
<a href="javascript:void(0);" id="savePost-{{ post.id }}" onclick="save_post('{{ post.id }}')" style="display:none;">Save</a>
|
<a href="javascript:void(0);" id="savePost-{{ post.id }}" onclick="save_post('{{ post.id }}')" style="display:none;">Save</a>
|
||||||
{% elif post.post_type in ("dice", "poll") and post == posts|last %}
|
{% elif post.post_type == "dice" %}
|
||||||
<br /><a href="javascript:void(0);" id="closePost-{{ post.id }}" onclick="close_post({{ post.id }})"{% if post.id != quest.open_post_id %} style="display:none;"{% endif %}>Close</a>
|
<br /><a href="javascript:void(0);" id="closePost-{{ post.id }}" onclick="close_post_send({{ post.id }})"{% if not post.dicecall.open %} style="display:none;"{% endif %}>Close</a>
|
||||||
<a href="javascript:void(0);" id="openPost-{{ post.id }}" onclick="open_post({{ post.id }})"{% if post.id == quest.open_post_id %} style="display:none;"{% endif %}>Open</a>
|
<a href="javascript:void(0);" id="openPost-{{ post.id }}" onclick="open_post_send({{ post.id }})"{% if post.dicecall.open %} style="display:none;"{% endif %}>Open</a>
|
||||||
|
{% elif post.post_type == "poll" %}
|
||||||
|
<br /><a href="javascript:void(0);" id="closePost-{{ post.id }}" onclick="close_post_send({{ post.id }})"{% if not post.poll.open %} style="display:none;"{% endif %}>Close</a>
|
||||||
|
<a href="javascript:void(0);" id="openPost-{{ post.id }}" onclick="open_post_send({{ post.id }})"{% if post.poll.open %} style="display:none;"{% endif %}>Open</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,13 +59,14 @@
|
||||||
{{ post.post_text }}
|
{{ post.post_text }}
|
||||||
{% endautoescape %}
|
{% endautoescape %}
|
||||||
{% elif post.post_type == "dice" %}
|
{% elif post.post_type == "dice" %}
|
||||||
<h3>{{ post.post_text }} - {% if post.id == quest.open_post_id %}Open{% else %}Closed{% endif %}</h3>
|
<h3>{{ post.post_text }} - {% if post.dicecall.open %}Open{% else %}Closed{% endif %}</h3>
|
||||||
{# for dice_roll in dice_rolls.get(post.id, []) %}
|
{# for dice_roll in dice_rolls.get(post.id, []) %}
|
||||||
<div id="questRollId-{{ dice_roll[0] }}">
|
<div id="questRollId-{{ dice_roll[0] }}">
|
||||||
<b>Rolled {{ dice_roll[4] }} = {{ dice_roll[5] }} ({{ dice_roll[3] }}){% if post.id|dice_chal != 0 %} - {% if dice_roll[5] >= post.id|dice_chal %}Pass{% else %}Fail{% endif %}{% endif %}</b>
|
<b>Rolled {{ dice_roll[4] }} = {{ dice_roll[5] }} ({{ dice_roll[3] }}){% if post.id|dice_chal != 0 %} - {% if dice_roll[5] >= post.id|dice_chal %}Pass{% else %}Fail{% endif %}{% endif %}</b>
|
||||||
</div>
|
</div>
|
||||||
{% endfor #}
|
{% endfor #}
|
||||||
<h3>{{ post.post_test }} - {% if post.id == quest.open_post_id %}Open{% else %}Closed{% endif %}</h3>
|
{% elif post.post_type == "poll" %}
|
||||||
|
<h3>{{ post.post_text }} - {% if post.poll.open %}Open{% else %}Closed{% endif %}</h3>
|
||||||
<table class="poll" id="poll-{{ post.id }}">
|
<table class="poll" id="poll-{{ post.id }}">
|
||||||
{# for option in options.get(post.id, []) %}
|
{# for option in options.get(post.id, []) %}
|
||||||
<tr id="optionRow-{{ option[0] }}">
|
<tr id="optionRow-{{ option[0] }}">
|
||||||
|
@ -109,7 +113,7 @@
|
||||||
<span class="tooltip" title="Only take matching rolls.">Strict</span><br />
|
<span class="tooltip" title="Only take matching rolls.">Strict</span><br />
|
||||||
<input type="checkbox" onclick="document.getElementById('diceChal').disabled=!this.checked;"/>
|
<input type="checkbox" onclick="document.getElementById('diceChal').disabled=!this.checked;"/>
|
||||||
<span class="tooltip" title="Dice challenge">DC:</span>
|
<span class="tooltip" title="Dice challenge">DC:</span>
|
||||||
<input type="number" name="diceChal" id="diceChal" min="1" max="99" disabled/><br />
|
<input type="number" name="diceChal" id="diceChal" min="1" max="999" disabled/><br />
|
||||||
<input type="checkbox" onclick="document.getElementById('diceRollsTaken').disabled=!this.checked;"/>
|
<input type="checkbox" onclick="document.getElementById('diceRollsTaken').disabled=!this.checked;"/>
|
||||||
<span class="tooltip" title="Automatically close the dice call after this many rolls have been made.">Rolls Taken:</span>
|
<span class="tooltip" title="Automatically close the dice call after this many rolls have been made.">Rolls Taken:</span>
|
||||||
<input type="number" name="diceRollsTaken" id="diceRollsTaken" min="1" max="99" disabled/><br />
|
<input type="number" name="diceRollsTaken" id="diceRollsTaken" min="1" max="99" disabled/><br />
|
||||||
|
|
25
quest/migrations/0007_dicecall.py
Normal file
25
quest/migrations/0007_dicecall.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 2.1 on 2018-08-23 15:46
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('quest', '0006_auto_20180817_0921'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='DiceCall',
|
||||||
|
fields=[
|
||||||
|
('post', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='quest.Post')),
|
||||||
|
('dice_roll', models.CharField(max_length=9)),
|
||||||
|
('strict', models.BooleanField()),
|
||||||
|
('dice_challenge', models.IntegerField(blank=True, null=True, validators=[django.core.validators.MaxValueValidator(999), django.core.validators.MinValueValidator(1)])),
|
||||||
|
('rolls_taken', models.IntegerField(blank=True, null=True, validators=[django.core.validators.MaxValueValidator(99), django.core.validators.MinValueValidator(1)])),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
22
quest/migrations/0008_auto_20180824_0855.py
Normal file
22
quest/migrations/0008_auto_20180824_0855.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Generated by Django 2.1 on 2018-08-24 12:55
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('quest', '0007_dicecall'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='quest',
|
||||||
|
name='open_post_id',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='dicecall',
|
||||||
|
name='open',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
|
@ -4,6 +4,7 @@ The main quest models.
|
||||||
"""
|
"""
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
|
|
||||||
class Quest(models.Model):
|
class Quest(models.Model):
|
||||||
"""
|
"""
|
||||||
|
@ -13,7 +14,6 @@ class Quest(models.Model):
|
||||||
owner = models.ForeignKey(
|
owner = models.ForeignKey(
|
||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
on_delete=models.CASCADE)
|
on_delete=models.CASCADE)
|
||||||
open_post_id = models.IntegerField(null=True)
|
|
||||||
|
|
||||||
|
|
||||||
class Post(models.Model):
|
class Post(models.Model):
|
||||||
|
@ -25,11 +25,43 @@ class Post(models.Model):
|
||||||
POST_TYPES = (
|
POST_TYPES = (
|
||||||
('text', 'Text'),
|
('text', 'Text'),
|
||||||
('dice', 'Dice'),
|
('dice', 'Dice'),
|
||||||
('poll', 'Poll'))
|
('poll', 'Poll')
|
||||||
|
)
|
||||||
post_type = models.CharField(max_length=4, choices=POST_TYPES)
|
post_type = models.CharField(max_length=4, choices=POST_TYPES)
|
||||||
post_text = models.TextField()
|
post_text = models.TextField()
|
||||||
timestamp = models.DateTimeField(auto_now=True)
|
timestamp = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
|
||||||
|
class DiceCall(models.Model):
|
||||||
|
"""
|
||||||
|
An object representing dice calls made by the QM.
|
||||||
|
"""
|
||||||
|
post = models.OneToOneField(
|
||||||
|
Post,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
primary_key=True,
|
||||||
|
)
|
||||||
|
dice_roll = models.CharField(max_length=9)
|
||||||
|
strict = models.BooleanField()
|
||||||
|
dice_challenge = models.IntegerField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
validators=[
|
||||||
|
MaxValueValidator(999),
|
||||||
|
MinValueValidator(1)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
rolls_taken = models.IntegerField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
validators=[
|
||||||
|
MaxValueValidator(99),
|
||||||
|
MinValueValidator(1)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
open = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
class PageTitle(models.Model):
|
class PageTitle(models.Model):
|
||||||
"""
|
"""
|
||||||
Represents the title of a quest page.
|
Represents the title of a quest page.
|
||||||
|
@ -41,6 +73,7 @@ class PageTitle(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
|
||||||
class Message(models.Model):
|
class Message(models.Model):
|
||||||
"""
|
"""
|
||||||
Represents a chat message.
|
Represents a chat message.
|
||||||
|
|
|
@ -15,8 +15,7 @@ h3 {
|
||||||
|
|
||||||
#questPane {
|
#questPane {
|
||||||
padding-left: 5%;
|
padding-left: 5%;
|
||||||
padding-right: 35%;
|
width: 65%;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.questPost {
|
.questPost {
|
||||||
|
|
|
@ -27,7 +27,7 @@ function load() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Websocket events */
|
/* Websocket receive */
|
||||||
socket.events['message'] = function(data) {
|
socket.events['message'] = function(data) {
|
||||||
let msg_str = '<div id="message-' + data.message_id + '" class="message">';
|
let msg_str = '<div id="message-' + data.message_id + '" class="message">';
|
||||||
msg_str = '<div class="messageHeader"><span class="messageName">' + data.name + '</span> ';
|
msg_str = '<div class="messageHeader"><span class="messageName">' + data.name + '</span> ';
|
||||||
|
@ -41,6 +41,60 @@ socket.events['message'] = function(data) {
|
||||||
mbox.scrollTop = mbox.scrollHeight;
|
mbox.scrollTop = mbox.scrollHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
socket.events['new_post'] = function(data) {
|
||||||
|
//deactivate_post();
|
||||||
|
let qposts = document.getElementById('questPosts');
|
||||||
|
let post_str = '<div class="questPost ';
|
||||||
|
if (data.post_type == 'text') {
|
||||||
|
post_str += 'textPost">';
|
||||||
|
} else if (data.post_type == 'dice') {
|
||||||
|
post_str += 'dicePost active_post">';
|
||||||
|
} else if (data.post_type == 'poll') {
|
||||||
|
post_str += 'pollPost active_post">';
|
||||||
|
}
|
||||||
|
post_str += '<div class="questPostMeta">' + data.date;
|
||||||
|
post_str += '</div><div class="questPostData" id="questPostData-' + data.post_id + '">';
|
||||||
|
if (data.post_type == 'text') {
|
||||||
|
post_str += data.post_text;
|
||||||
|
} else if (data.post_type == 'dice') {
|
||||||
|
post_str += '<h3>' + data.post_text + ' - Open</h3>';
|
||||||
|
} else if (data.post_type == 'poll') {
|
||||||
|
post_str += '<h3>' + data.post_text + ' - Open</h3>';
|
||||||
|
post_str += '<table class="poll" id="poll-' + data.post_id + '">';
|
||||||
|
post_str += '<col/><col/><col/>';
|
||||||
|
for (i = 0; i < data.options.length; i++) {
|
||||||
|
post_str += '<tr id="optionRow-' + data.options[i][0] + '">';
|
||||||
|
post_str += '<td class="pollCheckBox"><input type="checkbox" id="pollInput-' + data.options[i][0] + '" onchange="pollVote(' + data.post_id + ',' + data.options[i][0] + ')"/>';
|
||||||
|
post_str += '<label for="pollInput-' + data.options[i][0] + '"></label></td>';
|
||||||
|
post_str += '<td class="option_text">' + data.options[i][1] + '</td>';
|
||||||
|
post_str += '<td class="optionVotes">0</td></tr>';
|
||||||
|
}
|
||||||
|
post_str += '</table>';
|
||||||
|
if (data.allow_writein) {
|
||||||
|
post_str += '<div id="writeinContainer">';
|
||||||
|
post_str += 'Write-in: <input type="text" id="writeinInput" placeholder="Custom choice..." maxlength="200" /><br />';
|
||||||
|
post_str += '<input type="submit" id="writeinSubmit" value="Submit" onclick="submitWritein({{ quest_post[0] }});"/></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post_str += '</div></div><br />';
|
||||||
|
qposts.innerHTML = qposts.innerHTML + post_str;
|
||||||
|
};
|
||||||
|
socket.events['close_post'] = function(data) {
|
||||||
|
close_post(data.post_id);
|
||||||
|
}
|
||||||
|
socket.events['open_post'] = function(data) {
|
||||||
|
open_post(data.post_id);
|
||||||
|
}
|
||||||
|
socket.events['close_all_posts'] = function(data) {
|
||||||
|
let class_set = '';
|
||||||
|
if (data.post_type == 'dice') { class_set = 'dicePost activePost'; }
|
||||||
|
else if (data.post_type == 'poll') { class_set = 'pollPost activePost'; }
|
||||||
|
else { class_set = 'activePost'; }
|
||||||
|
let posts = document.getElementsByClassName(class_set);
|
||||||
|
for (let i = 0; i < posts.length; i++) {
|
||||||
|
close_post(posts[i].children[1].id.slice(14)); // retreive the id number at the end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Helpers */
|
/* Helpers */
|
||||||
function padToTwo(number) {
|
function padToTwo(number) {
|
||||||
|
@ -54,7 +108,7 @@ function strftime(date) {
|
||||||
return date_str;
|
return date_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* User-facing */
|
/* DOM editing */
|
||||||
function quote(message_id) {
|
function quote(message_id) {
|
||||||
let textbox = document.getElementById('messageTextArea');
|
let textbox = document.getElementById('messageTextArea');
|
||||||
textbox.value += '>>' + message_id + '\n';
|
textbox.value += '>>' + message_id + '\n';
|
||||||
|
@ -82,3 +136,35 @@ function scrollToMsg(message_id) {
|
||||||
if (!elem) { return; }
|
if (!elem) { return; }
|
||||||
elem.scrollIntoView();
|
elem.scrollIntoView();
|
||||||
}
|
}
|
||||||
|
function close_post(post_id) {
|
||||||
|
let post = document.getElementById('questPostData-' + post_id);
|
||||||
|
post.children[0].textContent = post.children[0].textContent.replace('Open', 'Closed');
|
||||||
|
if (post.parentElement.classList.contains('pollPost')) {
|
||||||
|
let table = document.getElementById('poll-' + post_id);
|
||||||
|
let boxes = table.getElementsByTagName('input');
|
||||||
|
for (let i = 0; i < boxes.length; i++) {
|
||||||
|
boxes[i].disabled = true;
|
||||||
|
}
|
||||||
|
let writein = document.getElementById('writeinContainer');
|
||||||
|
if (writein) {
|
||||||
|
writein.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function open_post(post_id) {
|
||||||
|
let post = document.getElementById('questPostData-' + post_id);
|
||||||
|
post.firstElementChild.textContent = post.firstElementChild.textContent.replace('Closed', 'Open');
|
||||||
|
post.parentElement.className += ' activePost';
|
||||||
|
console.log(post.parentElement.className);
|
||||||
|
if (post.parentElement.classList.contains('pollPost')) {
|
||||||
|
let table = document.getElementById('poll-' + post_id);
|
||||||
|
let boxes = table.getElementsByTagName('input');
|
||||||
|
for (let i = 0; i < boxes.length; i++) {
|
||||||
|
boxes[i].disabled = false;
|
||||||
|
}
|
||||||
|
let writein = document.getElementById('writeinContainer');
|
||||||
|
if (writein) {
|
||||||
|
writein.style.display = 'initial';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
139
quest/static/questQM.js
Normal file
139
quest/static/questQM.js
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/* Websocket receive */
|
||||||
|
socket.events['new_post'] = function(data) {
|
||||||
|
//deactivate_post();
|
||||||
|
let qposts = document.getElementById('questPosts');
|
||||||
|
let post_str = '<div class="questPost ';
|
||||||
|
if (data.post_type == 'text') {
|
||||||
|
post_str += 'textPost">';
|
||||||
|
} else if (data.post_type == 'dice') {
|
||||||
|
post_str += 'dicePost active_post">';
|
||||||
|
} else if (data.post_type == 'poll') {
|
||||||
|
post_str += 'pollPost active_post">';
|
||||||
|
}
|
||||||
|
post_str += '<div class="questPostMeta">' + data.date;
|
||||||
|
/* QM only */
|
||||||
|
if (data.post_type == 'text') {
|
||||||
|
post_str += '<br /><a href="javascript:void(0);" onclick="edit_post(\'' + data.post_id + '\')">Edit</a>';
|
||||||
|
post_str += '<a href="javascript:void(0);" id="savePost-' + data.post_id + '" onclick="save_post(\'' + data.post_id + '\')" style="display:none;">Save</a>';
|
||||||
|
} else if (data.post_type == 'dice' || data.post_type == 'poll') {
|
||||||
|
post_str += '<br /><a href="javascript:void(0);" id="close_post_id-' + data.post_id + '" onclick="close_post(' + data.post_id + ')">Close</a>';
|
||||||
|
post_str += '<a href="javascript:void(0);" id="open_post_id-' + data.post_id + '" onclick="open_post(' + data.post_id + ')" style="display:none;">Open</a>'
|
||||||
|
}
|
||||||
|
/* end QM only */
|
||||||
|
post_str += '</div><div class="questPostData" id="questPostData-' + data.post_id + '">';
|
||||||
|
if (data.post_type == 'text') {
|
||||||
|
post_str += data.post_text;
|
||||||
|
} else if (data.post_type == 'dice') {
|
||||||
|
post_str += '<h3>' + data.post_text + ' - Open</h3>';
|
||||||
|
} else if (data.post_type == 'poll') {
|
||||||
|
post_str += '<h3>' + data.post_text + ' - Open</h3>';
|
||||||
|
post_str += '<table class="poll" id="poll-' + data.post_id + '">';
|
||||||
|
post_str += '<col/><col/><col/>';
|
||||||
|
for (i = 0; i < data.options.length; i++) {
|
||||||
|
post_str += '<tr id="optionRow-' + data.options[i][0] + '">';
|
||||||
|
post_str += '<td class="pollCheckBox"><input type="checkbox" id="pollInput-' + data.options[i][0] + '" onchange="pollVote(' + data.post_id + ',' + data.options[i][0] + ')"/>';
|
||||||
|
post_str += '<label for="pollInput-' + data.options[i][0] + '"></label></td>';
|
||||||
|
post_str += '<td class="option_text">' + data.options[i][1] + '</td>';
|
||||||
|
post_str += '<td class="optionVotes">0</td></tr>';
|
||||||
|
}
|
||||||
|
post_str += '</table>';
|
||||||
|
if (data.allow_writein) {
|
||||||
|
post_str += '<div id="writeinContainer">';
|
||||||
|
post_str += 'Write-in: <input type="text" id="writeinInput" placeholder="Custom choice..." maxlength="200" /><br />';
|
||||||
|
post_str += '<input type="submit" id="writeinSubmit" value="Submit" onclick="submitWritein({{ quest_post[0] }});"/></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post_str += '</div></div><br />';
|
||||||
|
qposts.innerHTML = qposts.innerHTML + post_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Websocket send */
|
||||||
|
function makePost() {
|
||||||
|
let qparea = document.getElementById('postTextArea');
|
||||||
|
let text = qparea.value.trim();
|
||||||
|
qparea.value = '';
|
||||||
|
if (text == '') { return; }
|
||||||
|
socket.send('text_post', {text: text, page_num: page_num, quest_id: quest_id});
|
||||||
|
}
|
||||||
|
function form_post(form_id, event) {
|
||||||
|
let formData = new FormData(document.getElementById(form_id));
|
||||||
|
let obj = {};
|
||||||
|
formData.forEach(function(value, key) {
|
||||||
|
obj[key] = value;
|
||||||
|
});
|
||||||
|
obj.quest_id = quest_id;
|
||||||
|
obj.page_num = page_num;
|
||||||
|
socket.send(event, obj);
|
||||||
|
document.getElementById(form_id).reset();
|
||||||
|
}
|
||||||
|
function close_post_send(post_id) {
|
||||||
|
let post = document.getElementById('questPostData-' + post_id);
|
||||||
|
if (post.parentElement.classList.contains('dicePost')) {
|
||||||
|
data = {post_type: 'dice', post_id: post_id};
|
||||||
|
} else if (post.parentElement.classList.contains('pollPost')) {
|
||||||
|
data = {post_type: 'poll', post_id: post_id};
|
||||||
|
}
|
||||||
|
socket.send('close_post', data);
|
||||||
|
}
|
||||||
|
function open_post_send(post_id) {
|
||||||
|
let post = document.getElementById('questPostData-' + post_id);
|
||||||
|
if (post.parentElement.classList.contains('dicePost')) {
|
||||||
|
data = {post_type: 'dice', post_id: post_id};
|
||||||
|
} else if (post.parentElement.classList.contains('pollPost')) {
|
||||||
|
data = {post_type: 'poll', post_id: post_id};
|
||||||
|
}
|
||||||
|
socket.send('open_post', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DOM editing */
|
||||||
|
function openPostTab(event, modeName) {
|
||||||
|
let QMPostTabContent = document.getElementsByClassName("QMPostTabContent");
|
||||||
|
for (let i = 0; i < QMPostTabContent.length; i++) {
|
||||||
|
QMPostTabContent[i].style.display = "none";
|
||||||
|
}
|
||||||
|
let QMPostTab = document.getElementsByClassName("QMPostTab");
|
||||||
|
for (let i = 0; i < QMPostTab.length; i++) {
|
||||||
|
QMPostTab[i].className = QMPostTab[i].className.replace(" active", "");
|
||||||
|
}
|
||||||
|
document.getElementById(modeName).style.display = "block";
|
||||||
|
event.currentTarget.className += " active";
|
||||||
|
}
|
||||||
|
function close_post(post_id) {
|
||||||
|
let post = document.getElementById('questPostData-' + post_id);
|
||||||
|
post.children[0].textContent = post.children[0].textContent.replace('Open', 'Closed');
|
||||||
|
/* QM only */
|
||||||
|
document.getElementById('closePost-' + post_id).style.display = 'none';
|
||||||
|
document.getElementById('openPost-' + post_id).style.display = 'initial';
|
||||||
|
/* end QM only */
|
||||||
|
if (post.parentElement.classList.contains('pollPost')) {
|
||||||
|
let table = document.getElementById('poll-' + post_id);
|
||||||
|
let boxes = table.getElementsByTagName('input');
|
||||||
|
for (let i = 0; i < boxes.length; i++) {
|
||||||
|
boxes[i].disabled = true;
|
||||||
|
}
|
||||||
|
let writein = document.getElementById('writeinContainer');
|
||||||
|
if (writein) {
|
||||||
|
writein.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function open_post(post_id) {
|
||||||
|
let post = document.getElementById('questPostData-' + post_id);
|
||||||
|
post.firstElementChild.textContent = post.firstElementChild.textContent.replace('Closed', 'Open');
|
||||||
|
post.parentElement.className += ' activePost';
|
||||||
|
/* QM only */
|
||||||
|
document.getElementById('closePost-' + post_id).style.display = 'initial';
|
||||||
|
document.getElementById('openPost-' + post_id).style.display = 'none';
|
||||||
|
/* end QM only */
|
||||||
|
if (post.parentElement.classList.contains('pollPost')) {
|
||||||
|
let table = document.getElementById('poll-' + post_id);
|
||||||
|
let boxes = table.getElementsByTagName('input');
|
||||||
|
for (let i = 0; i < boxes.length; i++) {
|
||||||
|
boxes[i].disabled = false;
|
||||||
|
}
|
||||||
|
let writein = document.getElementById('writeinContainer');
|
||||||
|
if (writein) {
|
||||||
|
writein.style.display = 'initial';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -119,7 +119,7 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
TIME_ZONE = 'America/Chicago'
|
TIME_ZONE = 'America/New_York'
|
||||||
|
|
||||||
USE_I18N = False
|
USE_I18N = False
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user