diff --git a/contest/forms.py b/contest/forms.py new file mode 100644 index 0000000..8ad27b2 --- /dev/null +++ b/contest/forms.py @@ -0,0 +1,102 @@ +from django import forms +from django.contrib.auth.forms import UserCreationForm + +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Layout, Fieldset, ButtonHolder, Submit +from django.urls import reverse + +from .models import User, Reference, QSO +from .validators import CallUsernameValidator + +class CustomUserCreationForm(UserCreationForm): + class Meta: + model = User + fields = ("username",) + + username = forms.CharField(max_length=50, validators=[CallUsernameValidator()]) + +class UpdateRefForm(forms.Form): + existingRef = forms.ModelChoiceField(label="Existing Reference", queryset=Reference.objects.all(), help_text="If reference already exists, select it here.", required=False) + newRefName = forms.CharField(max_length=50, label="New Reference", help_text="Enter name of new ref, if we should create a new", required=False) + + def clean_newRefName(self): + data = self.cleaned_data["newRefName"].strip() + if Reference.objects.filter(name=data).count() > 0: + raise forms.ValidationError("Reference already exists") + + return data + + def clean(self): + cleaned_data = super(UpdateRefForm, self).clean() + + existingRef = cleaned_data.get("existingRef") + newRefName = cleaned_data.get("newRefName") + + if existingRef and newRefName: + raise forms.ValidationError("Select an existing ref or create a new one, not both!") + if not existingRef and not newRefName: + raise forms.ValidationError("Select either an existing ref or create a new one!") + +class QSOForm(forms.ModelForm): + class Meta: + model = QSO + fields = ["time", "call", "band", "reportTX", "reportRX", "ownNo", "otherNo", "refStr", "remarks"] + + widgets = { + "time": forms.DateTimeInput(attrs={"placeholder": "Current time"}) + } + + def __init__(self, user, *args, **kwargs): + super(QSOForm, self).__init__(*args, **kwargs) + self.user = user + + self.helper = FormHelper() + self.helper.form_id = "qso-log-form" + self.helper.form_class = "form-inline" + self.helper.form_style = 'inline' + self.helper.field_template = "bootstrap3/layout/inline_field.html" + self.helper.action = reverse("contest:log") + self.helper.add_input(Submit('submit', 'Log')) + + self.helper.layout = Layout( + 'time', + 'call', + 'band', + 'reportTX', + 'reportRX', 'ownNo', 'otherNo', 'refStr', 'remarks', + ) + + def clean_call(self): + data = self.cleaned_data["call"].upper().strip() + if Reference.objects.filter(name=data).count() > 0: + raise forms.ValidationError("Reference already exists") + + try: + CallUsernameValidator()(data) + except forms.ValidationError: + raise forms.ValidationError("Enter a valid callsign (1-2 chars, a number, 1-4 chars, maybe a /[A-Z])") + + if data == self.user.username: + raise forms.ValidationError("You cannot log QSOs with yourself") + + return data + + def clean_ownNo(self): + data = self.cleaned_data["ownNo"] + + if data < 1 or data > 100000: + raise forms.ValidationError("Number has to be in range of [1, 1000000]") + + try: + QSO.objects.get(owner=self.user, ownNo=data) + raise forms.ValidationError("You already logged a QSO with the number %s" % data) + except: + return data + + def clean_otherNo(self): + data = self.cleaned_data["otherNo"] + + if data < 1 or data > 100000: + raise forms.ValidationError("Number has to be in range of [1, 1000000]") + + return data diff --git a/contest/migrations/0002_contest.py b/contest/migrations/0002_contest.py new file mode 100644 index 0000000..0b4f640 --- /dev/null +++ b/contest/migrations/0002_contest.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-01-18 11:20 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contest', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Contest', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=20)), + ], + ), + ] diff --git a/contest/migrations/0003_auto_20170118_1208.py b/contest/migrations/0003_auto_20170118_1208.py new file mode 100644 index 0000000..c970083 --- /dev/null +++ b/contest/migrations/0003_auto_20170118_1208.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-01-18 12:08 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contest', '0002_contest'), + ] + + operations = [ + migrations.AddField( + model_name='band', + name='contest', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='contest.Contest'), + preserve_default=False, + ), + migrations.AddField( + model_name='contest', + name='callQrg', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='contest.Frequency'), + ), + migrations.AddField( + model_name='qso', + name='otherNo', + field=models.IntegerField(default=0), + preserve_default=False, + ), + migrations.AddField( + model_name='qso', + name='ownNo', + field=models.IntegerField(default=0), + preserve_default=False, + ), + ] diff --git a/contest/migrations/0004_contest_shortname.py b/contest/migrations/0004_contest_shortname.py new file mode 100644 index 0000000..cd90cd9 --- /dev/null +++ b/contest/migrations/0004_contest_shortname.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-01-18 13:17 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contest', '0003_auto_20170118_1208'), + ] + + operations = [ + migrations.AddField( + model_name='contest', + name='shortName', + field=models.CharField(default='test', max_length=20, unique=True), + preserve_default=False, + ), + ] diff --git a/contest/migrations/0005_frequency_note.py b/contest/migrations/0005_frequency_note.py new file mode 100644 index 0000000..ac4a116 --- /dev/null +++ b/contest/migrations/0005_frequency_note.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-01-18 14:28 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contest', '0004_contest_shortname'), + ] + + operations = [ + migrations.AddField( + model_name='frequency', + name='note', + field=models.CharField(default='', max_length=50), + preserve_default=False, + ), + ] diff --git a/contest/migrations/0006_qso_band.py b/contest/migrations/0006_qso_band.py new file mode 100644 index 0000000..5a5ead7 --- /dev/null +++ b/contest/migrations/0006_qso_band.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-01-19 00:19 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contest', '0005_frequency_note'), + ] + + operations = [ + migrations.AddField( + model_name='qso', + name='band', + field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='contest.Band'), + preserve_default=False, + ), + ] diff --git a/contest/migrations/0007_auto_20170119_0044.py b/contest/migrations/0007_auto_20170119_0044.py new file mode 100644 index 0000000..c43ab22 --- /dev/null +++ b/contest/migrations/0007_auto_20170119_0044.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-01-19 00:44 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contest', '0006_qso_band'), + ] + + operations = [ + migrations.AlterField( + model_name='qso', + name='remarks', + field=models.CharField(blank=True, max_length=50), + ), + migrations.AlterField( + model_name='qso', + name='reportRX', + field=models.CharField(default=59, max_length=7), + ), + migrations.AlterField( + model_name='qso', + name='reportTX', + field=models.CharField(default=59, max_length=7), + ), + ] diff --git a/contest/migrations/0008_auto_20170119_1202.py b/contest/migrations/0008_auto_20170119_1202.py new file mode 100644 index 0000000..f54f023 --- /dev/null +++ b/contest/migrations/0008_auto_20170119_1202.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-01-19 12:02 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contest', '0007_auto_20170119_0044'), + ] + + operations = [ + migrations.AddField( + model_name='qso', + name='ref', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contest.Reference'), + ), + migrations.AddField( + model_name='qso', + name='refStr', + field=models.CharField(default='', max_length=20), + preserve_default=False, + ), + migrations.AlterField( + model_name='qso', + name='time', + field=models.DateTimeField(blank=True), + ), + ] diff --git a/contest/validators.py b/contest/validators.py new file mode 100644 index 0000000..709c2aa --- /dev/null +++ b/contest/validators.py @@ -0,0 +1,18 @@ +from django.core import validators +from django.utils import six +from django.utils.deconstruct import deconstructible +from django.utils.translation import ugettext_lazy as _ + +import re + + +@deconstructible +class CallUsernameValidator(validators.RegexValidator): + #regex = r'^[\w.@+-]+$' + regex = r'^(?:[A-Z]+/)?[A-Z]{1,2}[0-9][A-Z]{1,4}(?:/[A-Z])?$' + message = _( + 'Enter a valid Callsign as Username, ALL UPPERCASE, if needed with /A /B,' + 'e.g. DL7BST, DN1BER/A, DL/OE1FOO' + ) + flags = re.ASCII if six.PY3 else 0 + diff --git a/static/css/style.uni-form.css b/static/css/style.uni-form.css new file mode 100644 index 0000000..27d72f8 --- /dev/null +++ b/static/css/style.uni-form.css @@ -0,0 +1,320 @@ +/* ========================================================================== + UNI-FORM STYLE by DRAGAN BABIC + -------------------------------------------------------------------------- + Copyright (c) 2013, Dragan Babic + -------------------------------------------------------------------------- + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + -------------------------------------------------------------------------- + NOTE ABOUT STYLING FORMS + -------------------------------------------------------------------------- + When styling your form make sure to copy the selector from uni-form.css + into this file and override it with your properties and values. + ========================================================================== */ + +.uni-form { + margin: 1.5em 0; + padding-top: 1px; +} + +/* ========================================================================== + Form titles + ========================================================================== */ + +.uni-form .uni-form-title { + margin: 1.5em 0; + font-weight: bold; + font-size: 1.25em; +} + +/* ========================================================================== + Holders + ========================================================================== */ + +.uni-form .ctrl-holder { + padding: 1em 1em 1.5em 1em; + border: 1px solid #efefef; + border-width: 1px 0 0 0; +} + +.uni-form .inline-labels .ctrl-holder { + padding: 1.5em 1em; +} + +.uni-form fieldset .ctrl-holder:last-child { + border-bottom-width: 1px; +} + +.uni-form .ctrl-holder.focused { + background: #fffcdf +} + +.uni-form .button-holder { + background: #efefef; + margin-top: 1.5em; + padding: 1.5em; + border-radius: 4px; +} + +/* ========================================================================== + Design for input fields + ========================================================================== */ + +.uni-form .input-text, +.uni-form .input-textarea { + padding: 5px; + border: 1px solid #aaa; + background: #fff; + border-radius: 2px; + -webkit-box-shadow: 1px 1px 3px rgba(0,0,0,.15) inset; + box-shadow: 1px 1px 3px rgba(0,0,0,.15) inset; +} + +.uni-form .input-text:focus, +.uni-form .input-textarea:focus { + border-color: #343434; + outline: none; +} + +.uni-form .input-textarea { + height: 12em; +} + +.uni-form .input-select {} + +.uni-form .input-file {} + +/* Disabled inputs */ + +.uni-form .input-disabled { + background-color: #f4f4f4; + border-color: #ccc; + color: #999; + -webkit-box-shadow: none; + box-shadow: none; +} + +/* ========================================================================== + Buttons + ========================================================================== */ + +.uni-form .action-primary { + padding: 1em 2em; + line-height: 1; + background: #254a86; + border: 1px solid #163362; + font-size: 12px; + font-weight: bold; + color: #fff; + border-radius: 4px; + text-shadow: -1px -1px 0 rgba(0,0,0,.25); +} + +.uni-form .action-primary:focus, +.uni-form .action-primary:hover { + background: #2b58a1; +} + +.uni-form .action-primary:active { + background: #1d3c6d; + -webkit-box-shadow: 0 1px 3px rgba(0,0,0,.5) inset; + box-shadow: 0 1px 3px rgba(0,0,0,.5) inset; +} + +.uni-form .action-secondary, +.uni-form button.action-secondary, +.uni-form input[type=submit].action-secondary { + float: right; + background: transparent; + border: none; + margin: 1.25em 0 0 0; + padding: 0; + color: #999; +} + +/* Disabled actions */ + +.uni-form .action-disabled, +.uni-form .action-disabled:link, +.uni-form .action-disabled:visited, +.uni-form .action-disabled:focus, +.uni-form .action-disabled:hover, +.uni-form .action-disabled:active { + background: #ccc; + border: 1px solid #aaa; + color: #999; + text-shadow: 1px 1px 0 rgba(255,255,255,.25); + -webkit-box-shadow: none; + box-shadow: none; + cursor: default; +} + +/* ========================================================================== + Required fields asterisks + ========================================================================== */ + +.uni-form .inline-labels label em, +.uni-form .inline-labels .label em { + font-style: inherit; + font-weight: inherit; +} + +/* ========================================================================== + Labels within grouped controls + ========================================================================== */ + +.uni-form .multi label { + margin-top: .3em; /* Compensate for the smaller font size */ + font-size: .85em; +} + +/* ========================================================================== + Form hints + ========================================================================== */ + +.uni-form .form-hint { + padding-top: .3em; /* Compensate for the smaller font size */ + font-size: .85em; + color: #999; +} + +.uni-form .ctrl-holder.focused .form-hint { + color: #343434; +} + +/* ========================================================================== + Messages + ========================================================================== */ + +/* Error message at the top of the form ------------------------------------- */ + +.uni-form #errorMsg { + background: #ffdfdf; + border: 1px solid #f3afb5; + margin: 1.5em 0; + padding: 0 1.5em; + border-radius: 4px; +} + +.uni-form #errorMsg h3 { + margin: 1em 0 0 0; +} + +.uni-form #errorMsg ol { + margin: 1.5em 0; + padding: 0; +} + + .uni-form #errorMsg li { + list-style: none; + margin: 0 0 4px 0; + padding: 7px; + background: #f6bec1; + position: relative; + font-size: .85em; + border-radius: 3px; + } + +/* Holder errors ------------------------------------------------------------ */ + +.uni-form .ctrl-holder.error, +.uni-form .ctrl-holder.focused.error { + background-color: #ffdfdf; + border-color: #f3afb5; +} + + .uni-form .ctrl-holder.error .input-text.error, + .uni-form .ctrl-holder.error .input-file.error, + .uni-form .ctrl-holder.error .input-select.error, + .uni-form .ctrl-holder.error .input-textarea.error { + color: #af4c4c; + border-color: #c55f68; + } + +/* Success messages at the top of the form ---------------------------------- */ + +.uni-form #okMsg { + background: #e1f4cd; + border: 1px solid #b6cda4; + margin: 0 0 1.5em 0; + padding: 1.5em; + text-align: center; + border-radius: 4px; +} + + .uni-form #okMsg p { + margin: 0 + } + +/* Holder valid input ------------------------------------------------------- */ + +.uni-form .ctrl-holder.valid { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAABpElEQVRIiWNgGAWDAfTvV+2vX6W0/v//UAN0OUZqWbLsoV7BodXv+mF8fUeexkzjGw0wPhM1LPn/v0LhyLp39chiF/d/qUf2GTM1LPqp/GT99y//NJDF2DiZHniZHa+E8Sn20bKHegUfXv1xQBefmGUeiMynyKL//0MNkOMFBvQdeRoZGVdfQBajKOi+yHzd/vvnfwlkMW5+5gvVPncj0dWS7aPpZzUavn78i5GMe1LMErGpJ8ui//9DDS7u/1KPLo4tyGAAI+j+/w81+Kn8bXndaiXGxU3PsWoiJchgAMVH//+HGmRPOL7/w6s/DusmvJq/649RAroGUoMMq0XZE47v//eXQQDGR7eMnCDDahE2ALPs///7AiVzTs1HlxcQYzmAXNTgAihlHSzokH2FbCB6xmRiZvgwtSDGkJGx4wEhi1B8xMi4+sLUAktHJmaGD+gKseV+myChRmIswbCIkGXIQECM5UCU/KUJxFiC1SJiLGNiZvjQHhuBN5URZREhy0gJMoIW4bKM1CAjCfz/H2pQv0ppfesW5fn//9/HSJGjgKYAAELOyUHrhNdJAAAAAElFTkSuQmCC); + background-position: 99% 1em; + background-repeat: no-repeat; + background-size: 18px auto; +} + +.uni-form .inline-labels .ctrl-holder.valid { + background-position: 31% 1.75em; +} + + .ctrl-holder.valid .input-text, + .ctrl-holder.valid .input-select, + .ctrl-holder.valid .input-textarea { + border-color: #88a24f; + color: #88a24f; + } + +/* ========================================================================== + Columns + ========================================================================== */ + +/* Remove borders from .ctrl-holder */ + +.uni-form-row > .ctrl-holder { + border: none; +} + +/* Add borders to rows */ + +.uni-form-row { + border: 1px solid #efefef; + border-width: 1px 0 0 0; +} + +.uni-form-row:last-child { + border-bottom-width: 1px; +} + +/* ========================================================================== + 480 breakpoint + ========================================================================== */ + +@media screen and (max-width: 480px) { + + .uni-form .ctrl-holder, + .uni-form .inline-labels .ctrl-holder { + padding-top: 1em; + padding-bottom: 1.5em; + } + + .uni-form .ctrl-holder.valid, + .uni-form .inline-labels .ctrl-holder.valid { + background-position: 97% 1em; + } + +} \ No newline at end of file diff --git a/static/css/uni-form.css b/static/css/uni-form.css new file mode 100644 index 0000000..38d0800 --- /dev/null +++ b/static/css/uni-form.css @@ -0,0 +1,425 @@ +/* ========================================================================== + Copyright (c) 2013, Dragan Babic + -------------------------------------------------------------------------- + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + -------------------------------------------------------------------------- + Generals + ========================================================================== */ + +.uni-form { + margin: 0; + padding: 0; +} + +.uni-form * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +/* Reset stuff and prevent inheritance */ + +.uni-form fieldset { + border: none; + margin: 0; + padding: 0; +} + +/* This are the main units that contain form elements */ + +.uni-form .ctrl-holder, +.uni-form .button-holder {} + +/* Clear all floats */ + + .uni-form:after, + .uni-form .button-holder:after, + .uni-form .ctrl-holder:after, + .uni-form-row:after { + content: "."; + display: block; + height: 0; + line-height: 0; + font-size: 0; + clear: both; + min-height: 0; + visibility: hidden; + } + +.uni-form label, +.uni-form button { + cursor: pointer; +} + +/* ========================================================================== + Default layout + -------------------------------------------------------------------------- + Styles for form controls where labels are above the input elements + ========================================================================== */ + +/* Target only the "main" labels */ + +.uni-form .ctrl-holder > label, +.uni-form .ctrl-holder > .label { + display: block; + margin: 0; + padding: 0; +} + +/* Required fields asterisk styling */ + +.uni-form label em, +.uni-form .label em { + float: left; + width: .75em; + margin: 0 0 0 -.75em; + font-style: inherit; + font-weight: inherit; +} + +/* Float the input elements */ + +.uni-form .ctrl, +.uni-form .input-text, +.uni-form .input-file, +.uni-form .input-select, +.uni-form .input-textarea { + float: left; + width: 65%; /* 2% for spacing */ + margin: 0; +} + +.uni-form .ctrl { + padding-right: 3%; +} + +/* Make some spacing between the label and the input/list */ + +.uni-form label + .input-text, +.uni-form label + .input-file, +.uni-form label + .input-select, +.uni-form label + .input-textarea { + margin-top: .5em; +} + +/* Postition the hints */ + +.uni-form .form-hint { + float: right; + width: 33%; + margin: 0; +} + +/* Grouped controls (one below the other by default) */ + +.uni-form .multi { + float: left; + width: 67%; + margin: 0; + padding: 0 3% 0 0; +} + +.uni-form .multi + .form-hint { + margin-top: .5em; +} + + .uni-form .multi > li { + margin: .5em 0; + list-style: none; + } + +/* Alternate layout for grouped controls (stacked inline) */ + +.uni-form .multi-inline > li { + float: left; + margin: .5em 0 0 0; +} + +.uni-form .columns-2 > li { + width: 50%; +} + +.uni-form .columns-2 > li + li { + padding-left: 2%; +} + +.uni-form .columns-3 > li { + width: 33.3%; +} + +.uni-form .columns-3 > li + li, +.uni-form .columns-3 > li + li + li { + padding-left: 2%; +} + +.uni-form .multi .input-text, +.uni-form .multi .input-select, +.uni-form .multi select { + display: inline-block; + float: none; + width: 100%; + margin-top: 0; +} + +/* ========================================================================== + Alternate layout + -------------------------------------------------------------------------- + Styles for form controls where labels are in line with the input elements + -------------------------------------------------------------------------- + Set the class of the parent (preferably to a fieldset) to .inline-labels + ========================================================================== */ + +.uni-form .inline-labels .ctrl-holder > label, +.uni-form .inline-labels .ctrl-holder > .label { + float: left; + position: relative; + width: 33%; + padding-right: 3%; +} + +/* Float the input elements */ + +.uni-form .ctrl, +.uni-form .inline-labels .input-text, +.uni-form .inline-labels .input-file, +.uni-form .inline-labels .input-select, +.uni-form .inline-labels .input-textarea { + float: left; + width: 67%; + margin: 0; +} + +/* Postition the hints */ + +.uni-form .inline-labels .form-hint { + clear: both; + float: none; + width: auto; + margin-left: 33%; + padding-top: .5em; /* Must use padding because of the clearing */ +} + +/* Grouped controls (one below the other by default) */ + +.uni-form .inline-labels .multi { + float: left; + width: 67%; + margin: 0; + padding: 0; +} + + .uni-form .inline-labels .multi > li { + margin: 0; + } + + .uni-form .inline-labels .multi > li + li { + margin-top: .5em; + } + + .uni-form .inline-labels .multi label { + float: none; + display: block; + width: 100%; + } + + .uni-form .inline-labels .multi .input-text, + .uni-form .inline-labels .multi .input-select, + .uni-form .inline-labels .multi .input-file, + .uni-form .inline-labels .multi .input-textarea { + float: none; + display: inline-block; + width: 100%; + } + +/* Alternate layout for grouped controls (stacked inline) */ + +.uni-form .inline-labels .multi-inline > li + li { + margin-top: 0; +} + +/* ========================================================================== + Additional stuff + ========================================================================== */ + +/* When you don't want to use a label for grouped fields */ + +.uni-form .inline-labels .no-label .multi { + margin-left: 33%; +} + +/* Classes for control of the widths of the fields */ + +.uni-form .small { + width: 30% !important +} + +.uni-form .medium { + width: 45% !important +} + +.uni-form .large { + float: none; + display: block; + width: 100% !important; +} + +.uni-form .large + .form-hint, +.uni-form .inline-labels .large + .form-hint { + float: none; + width: auto; + margin-left: 0; + padding-top: .3em; +} + +.uni-form .auto { + width: auto !important; + height: auto !important; + display: inline-block !important; + float: none !important; +} + +/* Make spacing in between two inputs */ + +.uni-form .small + input, +.uni-form .medium + input, +.uni-form .auto + input, +.uni-form .small + select, +.uni-form .medium + select, +.uni-form .auto + select { + margin-right: 4px !important; +} + +/* ========================================================================== + Read-Only output + ========================================================================== */ + +/* Default layout */ + +.uni-form .read-only-label { + display: block; + margin: 0; + font-size: 1em; + font-weight: bold; +} + +.uni-form .read-only { + margin: .5em 0 0 0; +} + + .uni-form .read-only .choice-label { + color: #777; + text-transform: uppercase; + font-size: .8em; + letter-spacing: .15em; + } + +/* Alternate layout */ + +.uni-form .inline-labels .read-only-label { + float: left; + position: relative; + width: 33%; + margin: 0; + padding-right: 3%; +} + +.uni-form .inline-labels .read-only { + float: right; + width: 67%; + margin: 0; +} + +.uni-form .inline-labels .read-only + .read-only { + margin-top: .5em; +} + +/* ========================================================================== + Columns + ========================================================================== */ + +.uni-form-row {} + + .uni-form-row > .ctrl-holder { + float: left; + } + + .columns-2 > .ctrl-holder { + width: 50%; + } + + .columns-3 > .ctrl-holder { + width: 33.3%; + } + +/* ========================================================================== + 480 breakpoint + ========================================================================== */ + +@media screen and (max-width: 480px) { + + /* Default layout selectors */ + .uni-form .ctrl-holder > label, + .uni-form .ctrl-holder > .label, + .uni-form .input-text, + .uni-form .input-select, + .uni-form .input-textarea, + .uni-form .input-file, + .uni-form .ctrl, + .uni-form .multi, + .uni-form .multi-inline > li, + .uni-form .form-hint, + /* Alternate layout selectors */ + .uni-form .inline-labels .ctrl-holder > label, + .uni-form .inline-labels .ctrl-holder > .label, + .uni-form .inline-labels .input-text, + .uni-form .inline-labels .input-select, + .uni-form .inline-labels .input-textarea, + .uni-form .inline-labels .input-file, + .uni-form .inline-labels .ctrl, + .uni-form .multi, + .uni-form .inline-labels .multi-inline > li, + .uni-form .inline-labels .form-hint, + .uni-form .inline-labels .no-label .multi { + float: none; + width: 100%; + } + + .uni-form .inline-labels label + .input-text, + .uni-form .inline-labels label + .input-file, + .uni-form .inline-labels label + .input-select, + .uni-form .inline-labels label + .input-textarea { + margin-top: .5em; + } + + .uni-form .inline-labels .ctrl-holder > label, + .uni-form .inline-labels .ctrl-holder > .label, + .uni-form .multi, + .uni-form .multi-inline > li, + .uni-form .columns-2 > li + li, + .uni-form .columns-3 > li + li, + .uni-form .columns-3 > li + li + li { + padding: 0; + } + + .uni-form .form-hint, + .uni-form .inline-labels .form-hint, + .uni-form .inline-labels .no-label .multi{ + margin-left: 0; + } + +} diff --git a/templates/contest/index.html b/templates/contest/index.html new file mode 100644 index 0000000..d205b92 --- /dev/null +++ b/templates/contest/index.html @@ -0,0 +1,37 @@ +{% extends "base.html" %} + +{% block content %} +

Welcome, {{ user }}

+{% if user.ref %} +{# user has a reference, we can start logging QSOs! #} +
+
+

+ Welcome to {{ contest }}! +

+ You got yourself a ref registered. Very nice. Now you are ready to go! So go ahead and log some QSOs! +

+
+
+{% else %} +
+
+

+ Hey you, {{ user }}, you don't have a ref! + You should get your ref registered! + Get yourself registered with your callsign and your current location by calling out to DK0TU + on {{ contest.callQrg }}. +

+
+
+{% endif %} + +{% if user.is_staff %} +
+
+

Hey, you are staff. Do you want to register people?

+
+
+{% endif %} +{% endblock %} + diff --git a/templates/contest/log.html b/templates/contest/log.html new file mode 100644 index 0000000..2b2b88c --- /dev/null +++ b/templates/contest/log.html @@ -0,0 +1,87 @@ +{% extends "base.html" %} + +{% load crispy_forms_tags %} + +{% block content %} +

Welcome!

+
+
+
+
Log a QSO!
+
+ + +
+ {% csrf_token %} + {{ form|crispy }} + + +
+
+
+
+
+ +
+
+
+
Your QSO log
+
+ + + + + + + + + + + + + + + + {% for qso in qsos %} + + + + + + + + + + + + {% endfor %} + +
No.TimeCallBandTX ReportRX ReportOther No.Reference
{{ qso.ownNo }}{{ qso.time }}{{ qso.call }}{{ qso.band }}{{ qso.reportTX }}{{ qso.reportRX }}{{ qso.otherNo }}{{ qso.refStr }}Edit Delete
+
+
+
+
+ +{% endblock %} + diff --git a/templates/contest/logDelete.html b/templates/contest/logDelete.html new file mode 100644 index 0000000..1294438 --- /dev/null +++ b/templates/contest/logDelete.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} + +{% block content %} +

Welcome!

+
+
+ We have the User {{ user }}, create a ref for them or choose an existing ref! + + Are you sure you want to delete this QSO? +
+ {% csrf_token %} + + + + +
QSO{{ qso }}
+ + + +
+
+
+{% endblock %} + diff --git a/templates/contest/logEdit.html b/templates/contest/logEdit.html new file mode 100644 index 0000000..cf35bd2 --- /dev/null +++ b/templates/contest/logEdit.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} + +{% block content %} +

Welcome!

+
+
+ We have the User {{ user }}, create a ref for them or choose an existing ref! + +
+ {% csrf_token %} + + + + + {{ form.as_table }} +
User{{ user }}
+ +
+
+
+{% endblock %} + diff --git a/templates/contest/logTable.html b/templates/contest/logTable.html new file mode 100644 index 0000000..f184e92 --- /dev/null +++ b/templates/contest/logTable.html @@ -0,0 +1,40 @@ + + + + + +{% if logShowComplete %} + + +{% else %} + +{% endif %} + + + + + + + + + + {% for qso in qsos %} + + + +{% if logShowComplete %} + + +{% else %} + +{% endif %} + + + + + + + + {% endfor %} + +
No.TimeCall ACall BCallBandTX ReportRX ReportOther No.Reference
{{ qso.ownNo }}{{ qso.time }}{{ qso.owner.username }}{{ qso.call }}{{ qso.call }}{{ qso.band }}{{ qso.reportTX }}{{ qso.reportRX }}{{ qso.otherNo }}{{ qso.refStr }}Edit Delete
diff --git a/templates/contest/overview.html b/templates/contest/overview.html new file mode 100644 index 0000000..3970491 --- /dev/null +++ b/templates/contest/overview.html @@ -0,0 +1,51 @@ +{% extends "base.html" %} + +{% block content %} +

Contest Rules && Overview!

+
+
+
+
+
The Contest
+

+ Welcome to {{ contest.name }}! +

+

We might be laid back people here at {{ contest.name }}, but we have some rules!

+

The QRG-changing is a serious thing. Also there is other stuff. But + maybe it's funnier if you find that out by yourself. And we punish you for not knowing. Such + is live. +

+
+
+
+
+
+
+
QRGs
+

The following frequencies may be used in this contest

+ + + + + + + + + + + {% for qrg in qrgs %} + + + + + + + {% endfor %} + +
ChannelBandQRGNote
{{ qrg.channel }}{{ qrg.band }}{{ qrg.qrg }}{{ qrg.note }}
+
+
+
+
+{% endblock %} + diff --git a/templates/contest/registerRefs.html b/templates/contest/registerRefs.html new file mode 100644 index 0000000..d1f310f --- /dev/null +++ b/templates/contest/registerRefs.html @@ -0,0 +1,51 @@ +{% extends "base.html" %} + +{% block content %} +

Welcome!

+
+
+

+ Register Someone!!!! + Here be FORM for registering someone without a ref +

+
+
+
+
+
+
Contest Stations
+
+ Here is a Table with all OMs/YLs in the contest! + + + + + + + + + + {% for u in alluser %} + + + + + + {% endfor %} + +
CallRef
{{ u.username }}{{ u.ref|default:"unknown / unset" }}Update / Create ref
+
+
+
+
+
+
Current QSOs
+
+ {% include "contest/logTable.html" with logShowComplete=1 qsos=qsos %} +
+
+
+
+ +{% endblock %} + diff --git a/templates/contest/updateRef.html b/templates/contest/updateRef.html new file mode 100644 index 0000000..249ef52 --- /dev/null +++ b/templates/contest/updateRef.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block content %} +

Welcome!

+
+
+ We have the User {{ user }}, create a ref for them or choose an existing ref! + +
+ {% csrf_token %} + + + + + {{ form.as_table }} +
User{{ user }}
+ +
+
+
+ +{% endblock %} + diff --git a/templates/registration/register.html b/templates/registration/register.html new file mode 100644 index 0000000..595ef78 --- /dev/null +++ b/templates/registration/register.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} + +{% block content %} +

Welcome!

+
+
+ I have {{ call_count }} callsigns in my Database! +
+ {% csrf_token %} + + {{ form.as_table }} +
+ +
+
+
+{% endblock %} +