diff --git a/requirements.txt b/requirements.txt index d522063545655e70b2ce3a964da5a6cc38d58730..3a1d68384b1eaf83bb280843a951617301551d04 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ django-tinymce==2.3.0 pytz rcssmin djangorestframework==3.4.4 +django-ical==1.4 diff --git a/website/events/admin.py b/website/events/admin.py index b1f9ffa13f920b636d06bc8dccee2131a35a5734..a96c42447b77a43cb9925ea4cd6f65a1ea574695 100644 --- a/website/events/admin.py +++ b/website/events/admin.py @@ -1,16 +1,16 @@ # -*- coding: utf-8 -*- -from django import forms -from django.urls import reverse +from activemembers.models import Committee from django.contrib import admin from django.http import HttpResponseRedirect +from django.urls import reverse from django.utils import timezone -from django.utils.http import is_safe_url from django.utils.html import format_html +from django.utils.http import is_safe_url from django.utils.translation import ugettext_lazy as _ - -from utils.translation import TranslatedModelAdmin -from activemembers.models import Committee from members.models import Member +from utils.translation import TranslatedModelAdmin + +from . import forms from . import models @@ -32,17 +32,8 @@ class DoNextModelAdmin(TranslatedModelAdmin): return _do_next(request, res) -class RegistrationInformationFieldForm(forms.ModelForm): - - order = forms.IntegerField(label=_('order'), initial=0) - - class Meta: - fields = '__all__' - model = models.RegistrationInformationField - - class RegistrationInformationFieldInline(admin.StackedInline): - form = RegistrationInformationFieldForm + form = forms.RegistrationInformationFieldForm extra = 0 model = models.RegistrationInformationField ordering = ('_order',) diff --git a/website/events/api/serializers.py b/website/events/api/serializers.py index 247dee078805968a91801ce1a306011d6fa42a57..492c6f384dabeff3d4c66f1eea0504a6a8b0b442 100644 --- a/website/events/api/serializers.py +++ b/website/events/api/serializers.py @@ -10,7 +10,7 @@ class CalenderJSSerializer(serializers.ModelSerializer): fields = ( 'start', 'end', 'all_day', 'is_birthday', 'url', 'title', 'description', - 'background_color', 'text_color', 'target_blank' + 'backgroundColor', 'textColor', 'blank' ) start = serializers.SerializerMethodField('_start') @@ -20,9 +20,9 @@ class CalenderJSSerializer(serializers.ModelSerializer): url = serializers.SerializerMethodField('_url') title = serializers.SerializerMethodField('_title') description = serializers.SerializerMethodField('_description') - background_color = serializers.SerializerMethodField('_background_color') - text_color = serializers.SerializerMethodField('_text_color') - target_blank = serializers.SerializerMethodField('_target_blank') + backgroundColor = serializers.SerializerMethodField('_background_color') + textColor = serializers.SerializerMethodField('_text_color') + blank = serializers.SerializerMethodField('_target_blank') def _start(self, instance): return timezone.localtime(instance.start) @@ -60,4 +60,4 @@ class EventSerializer(CalenderJSSerializer): model = Event def _url(self, instance): - return reverse('#') + return reverse('events:event', kwargs={'event_id': instance.id}) diff --git a/website/events/feeds.py b/website/events/feeds.py new file mode 100644 index 0000000000000000000000000000000000000000..7d66107f83634823cb6a695783a559ba9956276e --- /dev/null +++ b/website/events/feeds.py @@ -0,0 +1,71 @@ +from datetime import datetime, timedelta + +from django.urls import reverse +from django.utils.translation import activate +from django_ical.views import ICalFeed +from events.models import Event +from django.utils.translation import ugettext as _ + + +class EventFeed(ICalFeed): + def __init__(self, lang='en'): + super().__init__() + self.lang = lang + + def product_id(self): + return '-//thalia.nu//EventCalendar//' + self.lang.upper() + + def file_name(self): + return "thalia_{}.ics".format(self.lang) + + def title(self): + activate(self.lang) + return _('Study Association Thalia event calendar') + + def items(self): + return Event.objects.filter(published=True).order_by('-start') + + def item_title(self, item): + return item.title + + def item_description(self, item): + return item.description + + def item_start_datetime(self, item): + return item.start + + def item_end_datetime(self, item): + return item.end + + def item_link(self, item): + return reverse('events:event', kwargs={'event_id': item.id}) + + def item_location(self, item): + return "{} - {}".format(item.location, item.map_location) + + +class DeprecationFeed(ICalFeed): + def product_id(self): + return '-//thalia.nu//DEPRECATED' + + def items(self): + return range(7) + + def item_start_datetime(self, item): + today = datetime.now().replace(hour=13, minute=37, second=0) + delta = timedelta(days=item) + return today + delta + + def item_end_datetime(self, item): + today = datetime.now().replace(hour=15, minute=37, second=0) + delta = timedelta(days=item) + return today + delta + + def item_title(self, item): + return ( + 'Oude Thalia Feed, gebruik https://thalia.nu' + + reverse('events:ical-nl') + ) + + def item_link(self, item): + return reverse('events:ical-nl') + '?item={}'.format(item) diff --git a/website/events/forms.py b/website/events/forms.py new file mode 100644 index 0000000000000000000000000000000000000000..fb929273451a8d1016bd50f1331cd119a537fa9a --- /dev/null +++ b/website/events/forms.py @@ -0,0 +1,52 @@ +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from .models import RegistrationInformationField + + +class RegistrationInformationFieldForm(forms.ModelForm): + + order = forms.IntegerField(label=_('order'), initial=0) + + class Meta: + fields = '__all__' + model = RegistrationInformationField + widgets = { + 'type': forms.Select, + } + + +class FieldsForm(forms.Form): + def __init__(self, *args, **kwargs): + registration = kwargs.pop('registration') + super(FieldsForm, self).__init__(*args, **kwargs) + + self.information_fields = registration.registration_information() + + for information_field in self.information_fields: + field = information_field['field'] + key = "info_field_{}".format(field.id) + + if field.type == RegistrationInformationField.BOOLEAN_FIELD: + self.fields[key] = forms.BooleanField( + required=False + ) + elif field.type == RegistrationInformationField.INTEGER_FIELD: + self.fields[key] = forms.IntegerField() + elif field.type == RegistrationInformationField.TEXT_FIELD: + self.fields[key] = forms.CharField() + + self.fields[key].label = field.name + self.fields[key].help_text = field.description + self.fields[key].initial = information_field['value'] + if not field.type == RegistrationInformationField.BOOLEAN_FIELD: + self.fields[key].required = field.required + + def field_values(self): + for information_field in self.information_fields: + key = "info_field_{}".format(information_field['field'].id) + field = { + "field": information_field["field"], + "value": self.cleaned_data[key] + } + yield field diff --git a/website/events/locale/nl/LC_MESSAGES/django.mo b/website/events/locale/nl/LC_MESSAGES/django.mo index f378fe70b2067e65d5da80159364a01d3eaee2d3..ea47ccbc558067be637d28363bb8bd547b1cca97 100644 Binary files a/website/events/locale/nl/LC_MESSAGES/django.mo and b/website/events/locale/nl/LC_MESSAGES/django.mo differ diff --git a/website/events/locale/nl/LC_MESSAGES/django.po b/website/events/locale/nl/LC_MESSAGES/django.po index 067b563f8870e753c7df06d0e86b11e5e696a5b6..17222a831686da7d2d2ac11df9d5b0c6777f93c9 100644 --- a/website/events/locale/nl/LC_MESSAGES/django.po +++ b/website/events/locale/nl/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-09-14 21:48+0200\n" -"PO-Revision-Date: 2016-09-14 21:45+0200\n" +"POT-Creation-Date: 2016-09-28 21:27+0200\n" +"PO-Revision-Date: 2016-09-28 21:28+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: nl\n" @@ -16,178 +16,184 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 1.8.8\n" +"X-Generator: Poedit 1.8.7.1\n" -#: admin.py:36 +#: admin.py:37 msgid "order" msgstr "volgorde" -#: admin.py:71 +#: admin.py:72 msgid "Edit" msgstr "Aanpassen" -#: admin.py:81 +#: admin.py:82 msgid "Number of participants" msgstr "Aantal deelnemers" -#: admin.py:85 +#: admin.py:86 msgid "Publish selected events" msgstr "Publiceer geselecteerde evenementen" -#: admin.py:89 +#: admin.py:90 msgid "Unpublish selected events" msgstr "Publicatie van geselecteerde evenementen ongedaan maken" -#: models.py:12 +#: feeds.py:23 +msgid "Study Association Thalia event calendar" +msgstr "Studievereniginig Thalia evenementenkalender" + +#: models.py:13 msgid "No registration required" msgstr "Geen registratie vereist" -#: models.py:14 templates/events/admin/details.html:47 +#: models.py:17 templates/events/admin/details.html:47 msgid "title" msgstr "titel" -#: models.py:16 models.py:157 +#: models.py:21 models.py:167 msgid "description" msgstr "beschrijving" -#: models.py:18 +#: models.py:23 msgid "start time" msgstr "starttijd" -#: models.py:20 +#: models.py:25 msgid "end time" msgstr "eindtijd" -#: models.py:26 templates/events/admin/details.html:51 +#: models.py:31 templates/events/admin/details.html:51 msgid "organiser" msgstr "organisator" -#: models.py:30 +#: models.py:35 msgid "registration start" msgstr "start registratie" -#: models.py:36 +#: models.py:41 msgid "registration end" msgstr "einde registratie" -#: models.py:42 +#: models.py:47 msgid "cancel deadline" msgstr "afmelddeadline" -#: models.py:47 templates/events/admin/details.html:55 +#: models.py:54 templates/events/admin/details.html:55 +#: templates/events/event.html:21 msgid "location" msgstr "locatie" -#: models.py:50 +#: models.py:59 msgid "location for minimap" msgstr "locatie voor minimap" -#: models.py:52 +#: models.py:61 msgid "Location of Huygens: Heyendaalseweg 135, Nijmegen. Not shown as text!!" msgstr "" "Locatie van ’t Huygens: Heyendaalseweg 135, Nijmegen. Dit veld wordt niet " "getoond als tekst!!" -#: models.py:57 templates/events/admin/details.html:57 +#: models.py:66 templates/events/admin/details.html:57 +#: templates/events/event.html:26 msgid "price" msgstr "prijs" -#: models.py:65 templates/events/admin/details.html:59 +#: models.py:74 templates/events/admin/details.html:59 msgid "cost" msgstr "kosten" -#: models.py:69 +#: models.py:78 msgid "Actual cost of event." msgstr "werkelijke kosten van het evenement" -#: models.py:74 +#: models.py:83 msgid "maximum number of participants" msgstr "maximum aantal deelnemers" -#: models.py:80 +#: models.py:90 msgid "message when there is no registration" msgstr "bericht dat getoond wordt wanneer er geen registratie nodig is" -#: models.py:84 +#: models.py:94 msgid "Default: " msgstr "Standaard: " -#: models.py:88 +#: models.py:98 msgid "published" msgstr "gepubliceerd" -#: models.py:98 +#: models.py:108 msgid "Can't have an event travel back in time" msgstr "Een evenement kan niet terugreizen in de tijd" -#: models.py:103 +#: models.py:113 msgid "Doesn't make sense to have this if you require registrations." msgstr "Het is niet logisch om dit te hebben als je registratie vereist." -#: models.py:108 +#: models.py:118 msgid "If registration is required, you need a start of registration" msgstr "" "Als registratie vereist is, dan heb je een starttijd voor de registratie " "nodig" -#: models.py:113 +#: models.py:123 msgid "If registration is required, you need an end of registration" msgstr "" "Als registratie vereist is, dan heb je een eindtijd voor de registratie nodig" -#: models.py:117 +#: models.py:127 msgid "Registration start should be before registration end" msgstr "De starttijd voor de registratie moet voor de eindtijd liggen" -#: models.py:139 +#: models.py:149 msgid "checkbox" msgstr "checkbox" -#: models.py:140 +#: models.py:150 msgid "text field" msgstr "tekstveld" -#: models.py:141 +#: models.py:151 msgid "integer field" msgstr "integerveld" -#: models.py:146 +#: models.py:156 msgid "field type" msgstr "veldtype" -#: models.py:152 +#: models.py:162 msgid "field name" msgstr "veldnaam" -#: models.py:194 templates/events/admin/registrations_table.html:6 +#: models.py:204 templates/events/admin/registrations_table.html:6 msgid "name" msgstr "naam" -#: models.py:196 +#: models.py:206 msgid "Use this for non-members" msgstr "Gebruikt dit voor niet-leden" -#: models.py:201 +#: models.py:211 msgid "registration date" msgstr "registratiedatum" -#: models.py:202 +#: models.py:212 msgid "cancellation date" msgstr "afmelddatum" -#: models.py:207 templates/events/admin/registrations_table.html:11 +#: models.py:217 templates/events/admin/registrations_table.html:11 msgid "present" msgstr "aanwezig" -#: models.py:211 templates/events/admin/registrations_table.html:12 +#: models.py:221 templates/events/admin/registrations_table.html:12 msgid "paid" msgstr "betaald" -#: models.py:224 models.py:225 +#: models.py:253 models.py:254 msgid "Either specify a member or a name" msgstr "Geef een lid of een naam op" -#: models.py:247 +#: models.py:276 msgid "last changed" msgstr "laatst aangepast" @@ -255,6 +261,96 @@ msgstr "toevoegen" msgid "Nobody %(verb)s yet" msgstr "Niemand heeft zich %(verb)s" +#: templates/events/event.html:13 +msgid "from" +msgstr "van" + +#: templates/events/event.html:17 +msgid "until" +msgstr "tot" + +#: templates/events/event.html:32 +msgid "registration deadline" +msgstr "aanmelddeadline" + +#: templates/events/event.html:36 +msgid "cancellation deadline" +msgstr "afmelddeadline" + +#: templates/events/event.html:40 +msgid "number of registrations" +msgstr "aantal aanmeldingen" + +#: templates/events/event.html:42 +#, python-format +msgid "%(counter)s registration" +msgid_plural "%(counter)s registrations" +msgstr[0] "%(counter)s aanmelding" +msgstr[1] "%(counter)s aanmeldingen" + +#: templates/events/event.html:48 +msgid "max" +msgstr "max" + +#: templates/events/event.html:59 +msgid "registration status" +msgstr "aanmeldstatus" + +#: templates/events/event.html:62 +msgid "You are registered" +msgstr "Je bent aangemeld" + +#: templates/events/event.html:64 +#, python-format +msgid "Waiting list position %(pos)s" +msgstr "Wachtlijst positie %(pos)s" + +#: templates/events/event.html:68 +msgid "Your registration is cancelled after the cancellation deadline" +msgstr "Je bent afgemeld na de afmelddeadline" + +#: templates/events/event.html:70 +msgid "Your registration is cancelled" +msgstr "Je bent afgemeld" + +#: templates/events/event.html:155 +msgid "You have to log in before you can register for this event." +msgstr "Je moet inloggen voordat je jezelf kunt aanmelden." + +#: templates/events/event.html:241 +msgid "cohort" +msgstr "jaarlaag" + +#: templates/events/index.html:13 +msgid "Calendar" +msgstr "Agenda" + +#: templates/events/index.html:49 templates/events/index.html:51 +#: templates/events/index.html:57 +msgid "hide birthdays" +msgstr "Verberg verjaardagen" + +#: templates/events/index.html:49 templates/events/index.html:52 +msgid "show birthdays" +msgstr "Toon verjaardagen" + +#: templates/events/index.html:69 +msgid "list" +msgstr "Lijst" + +#~ msgid "From" +#~ msgstr "Vanaf" + +#, fuzzy +#~| msgid "location" +#~ msgid "Location" +#~ msgstr "locatie" + +#, fuzzy +#~| msgid "price" +#~ msgid "Price" +#~ msgstr "prijs" + #~ msgid "Present" #~ msgstr "Aanwezig" diff --git a/website/events/migrations/0007_auto_20161009_2352.py b/website/events/migrations/0007_auto_20161009_2352.py new file mode 100644 index 0000000000000000000000000000000000000000..16abf9d31900e959677d01954e32050b0fdafe8b --- /dev/null +++ b/website/events/migrations/0007_auto_20161009_2352.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2016-10-09 21:52 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0006_auto_20160921_2201'), + ] + + operations = [ + migrations.AddField( + model_name='registrationinformationfield', + name='required', + field=models.BooleanField(default=True, verbose_name='required'), + preserve_default=False, + ), + migrations.AlterField( + model_name='registrationinformationfield', + name='type', + field=models.CharField(choices=[('boolean', 'Checkbox'), ('text', 'Text'), ('integer', 'Integer')], max_length=10, verbose_name='field type'), + ), + ] diff --git a/website/events/models.py b/website/events/models.py index e28548ba3e70f540b7e459589fd0964d74b31ca5..e2f64ea30d0309bc23e9b496110dbae89c3cda5f 100644 --- a/website/events/models.py +++ b/website/events/models.py @@ -2,6 +2,7 @@ from django.core import validators from django.core.exceptions import ValidationError from django.db import models from django.db.models import Q +from django.urls import reverse from django.utils import timezone from django.utils.translation import ugettext_lazy as _, string_concat from utils.translation import MultilingualField, ModelTranslateMeta @@ -10,6 +11,13 @@ from utils.translation import MultilingualField, ModelTranslateMeta class Event(models.Model, metaclass=ModelTranslateMeta): """Represents events""" + REGISTRATION_NOT_NEEDED = -1 + REGISTRATION_NOT_YET_OPEN = 0 + REGISTRATION_OPEN = 1 + REGISTRATION_OPEN_NO_CANCEL = 2 + REGISTRATION_CLOSED = 3 + REGISTRATION_CLOSED_CANCEL_ONLY = 4 + DEFAULT_NO_REGISTRATION_MESSAGE = _('No registration required') title = MultilingualField( @@ -100,15 +108,42 @@ class Event(models.Model, metaclass=ModelTranslateMeta): published = models.BooleanField(_("published"), default=False) + def after_cancel_deadline(self): + return self.cancel_deadline <= timezone.now() + def registration_required(self): return bool(self.registration_start) or bool(self.registration_end) + def has_fields(self): + return self.registrationinformationfield_set.count() > 0 + + def reached_participants_limit(self): + return self.max_participants <= self.registration_set.count() + + @property + def status(self): + now = timezone.now() + if bool(self.registration_start) or bool(self.registration_end): + if now <= self.registration_start: + return Event.REGISTRATION_NOT_YET_OPEN + elif self.registration_end <= now < self.cancel_deadline: + return Event.REGISTRATION_CLOSED_CANCEL_ONLY + elif self.cancel_deadline <= now < self.registration_end: + return Event.REGISTRATION_OPEN_NO_CANCEL + elif now >= self.registration_end and now >= self.cancel_deadline: + return Event.REGISTRATION_CLOSED + else: + return Event.REGISTRATION_OPEN + else: + return Event.REGISTRATION_NOT_NEEDED + def clean(self): super().clean() errors = {} - if self.end < self.start: + if self.end is not None and self.start is not None and ( + self.end < self.start): errors.update({ - 'end': _("Can't have an event travel back in time")}) + 'end': _("Can't have an event travel back in time")}) if self.registration_required(): if self.no_registration_message: errors.update( @@ -125,8 +160,13 @@ class Event(models.Model, metaclass=ModelTranslateMeta): {'registration_end': _( "If registration is required, you need an end of " "registration")}) + if not self.cancel_deadline: + errors.update( + {'cancel_deadline': _( + "If registration is required, you need a deadline for " + "the cancellation")}) if self.registration_start and self.registration_end and ( - self.registration_start >= self.registration_end): + self.registration_start >= self.registration_end): message = _('Registration start should be before ' 'registration end') errors.update({ @@ -136,7 +176,7 @@ class Event(models.Model, metaclass=ModelTranslateMeta): raise ValidationError(errors) def get_absolute_url(self): - return '' + return reverse('events:event', args=[str(self.pk)]) def __str__(self): return '{}: {}'.format( @@ -149,9 +189,13 @@ class Event(models.Model, metaclass=ModelTranslateMeta): class RegistrationInformationField(models.Model): """Field description to ask for when registering""" - FIELD_TYPES = (('checkbox', _('checkbox')), - ('charfield', _('text field')), - ('intfield', _('integer field'))) + BOOLEAN_FIELD = 'boolean' + INTEGER_FIELD = 'integer' + TEXT_FIELD = 'text' + + FIELD_TYPES = ((BOOLEAN_FIELD, _('Checkbox')), + (TEXT_FIELD, _('Text')), + (INTEGER_FIELD, _('Integer')),) event = models.ForeignKey(Event, models.CASCADE) @@ -172,13 +216,18 @@ class RegistrationInformationField(models.Model): blank=True, ) + required = models.BooleanField( + _('required'), + ) + def get_value_for(self, registration): - if self.type == 'charfield': + if self.type == self.TEXT_FIELD: value_set = self.textregistrationinformation_set - elif self.type == 'checkbox': + elif self.type == self.BOOLEAN_FIELD: value_set = self.booleanregistrationinformation_set - elif self.type == 'intfield': + elif self.type == self.INTEGER_FIELD: value_set = self.integerregistrationinformation_set + try: return value_set.get(registration=registration).value except (TextRegistrationInformation.DoesNotExist, @@ -186,6 +235,31 @@ class RegistrationInformationField(models.Model): IntegerRegistrationInformation.DoesNotExist): return None + def set_value_for(self, registration, value): + if self.type == self.TEXT_FIELD: + value_set = self.textregistrationinformation_set + elif self.type == self.BOOLEAN_FIELD: + value_set = self.booleanregistrationinformation_set + elif self.type == self.INTEGER_FIELD: + value_set = self.integerregistrationinformation_set + + try: + field_value = value_set.get(registration=registration) + except BooleanRegistrationInformation.DoesNotExist: + field_value = BooleanRegistrationInformation() + except TextRegistrationInformation.DoesNotExist: + field_value = TextRegistrationInformation() + except IntegerRegistrationInformation.DoesNotExist: + field_value = IntegerRegistrationInformation() + + field_value.registration = registration + field_value.field = self + field_value.value = value + field_value.save() + + def __str__(self): + return "{} ({})".format(self.name, dict(self.FIELD_TYPES)[self.type]) + class Meta: order_with_respect_to = 'event' @@ -230,6 +304,30 @@ class Registration(models.Model): return [{'field': field, 'value': field.get_value_for(self)} for field in fields] + def is_external(self): + return bool(self.name) + + def is_late_cancellation(self): + return (self.date_cancelled and + self.date_cancelled > self.event.cancel_deadline and + self.event.registration_set.filter( + (Q(date_cancelled__gte=self.date_cancelled) | + Q(date_cancelled=None)) & + Q(date__lte=self.date) + ).count() < self.event.max_participants) + + def is_registered(self): + return self.date_cancelled is None + + def queue_position(self): + if self.event.max_participants is None: + return 0 + + return max(self.event.registration_set.filter( + date_cancelled=None, + date__lte=self.date + ).count() - self.event.max_participants, 0) + def clean(self): if ((self.member is None and not self.name) or (self.member and self.name)): diff --git a/website/events/sitemaps.py b/website/events/sitemaps.py new file mode 100644 index 0000000000000000000000000000000000000000..4db5c267af02175a027422232d969adc4f3a243f --- /dev/null +++ b/website/events/sitemaps.py @@ -0,0 +1,29 @@ +from django.contrib import sitemaps +from django.urls import reverse + +from . import models + + +class StaticViewSitemap(sitemaps.Sitemap): + changefreq = 'daily' + + def items(self): + return ['events:index'] + + def location(self, item): + return reverse(item) + + +class EventSitemap(sitemaps.Sitemap): + + def items(self): + return models.Event.objects.filter(published=True) + + def location(self, item): + return item.get_absolute_url() + + +sitemap = { + 'events-static': StaticViewSitemap, + 'events-events': EventSitemap, +} diff --git a/website/events/static/events/css/fullcalendar.css b/website/events/static/events/css/fullcalendar.css new file mode 100644 index 0000000000000000000000000000000000000000..3d0474d84a7529b44416b6bb0174f9ae4bd5a5fd --- /dev/null +++ b/website/events/static/events/css/fullcalendar.css @@ -0,0 +1,1069 @@ +/*! + * FullCalendar v2.4.0 Stylesheet + * Docs & License: http://fullcalendar.io/ + * (c) 2015 Adam Shaw + */ + + +.fc { + direction: ltr; + text-align: left; +} + +.fc-rtl { + text-align: right; +} + +body .fc { /* extra precedence to overcome jqui */ + font-size: 1em; +} + + +/* Colors +--------------------------------------------------------------------------------------------------*/ + +.fc-unthemed th, +.fc-unthemed td, +.fc-unthemed thead, +.fc-unthemed tbody, +.fc-unthemed .fc-divider, +.fc-unthemed .fc-row, +.fc-unthemed .fc-popover { + border-color: #ddd; +} + +.fc-unthemed .fc-popover { + background-color: #fff; +} + +.fc-unthemed .fc-divider, +.fc-unthemed .fc-popover .fc-header { + background: #eee; +} + +.fc-unthemed .fc-popover .fc-header .fc-close { + color: #666; +} + +.fc-unthemed .fc-today { + background: #fcf8e3; +} + +.fc-highlight { /* when user is selecting cells */ + background: #bce8f1; + opacity: .3; + filter: alpha(opacity=30); /* for IE */ +} + +.fc-bgevent { /* default look for background events */ + background: rgb(143, 223, 130); + opacity: .3; + filter: alpha(opacity=30); /* for IE */ +} + +.fc-nonbusiness { /* default look for non-business-hours areas */ + /* will inherit .fc-bgevent's styles */ + background: #d7d7d7; +} + + +/* Icons (inline elements with styled text that mock arrow icons) +--------------------------------------------------------------------------------------------------*/ + +.fc-icon { + display: inline-block; + width: 1em; + height: 1em; + line-height: 1em; + font-size: 1em; + text-align: center; + overflow: hidden; + font-family: "Courier New", Courier, monospace; + + /* don't allow browser text-selection */ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + +/* +Acceptable font-family overrides for individual icons: + "Arial", sans-serif + "Times New Roman", serif + +NOTE: use percentage font sizes or else old IE chokes +*/ + +.fc-icon:after { + position: relative; + margin: 0 -1em; /* ensures character will be centered, regardless of width */ +} + +.fc-icon-left-single-arrow:after { + content: "\02039"; + font-weight: bold; + font-size: 200%; + top: -7%; + left: 3%; +} + +.fc-icon-right-single-arrow:after { + content: "\0203A"; + font-weight: bold; + font-size: 200%; + top: -7%; + left: -3%; +} + +.fc-icon-left-double-arrow:after { + content: "\000AB"; + font-size: 160%; + top: -7%; +} + +.fc-icon-right-double-arrow:after { + content: "\000BB"; + font-size: 160%; + top: -7%; +} + +.fc-icon-left-triangle:after { + content: "\25C4"; + font-size: 125%; + top: 3%; + left: -2%; +} + +.fc-icon-right-triangle:after { + content: "\25BA"; + font-size: 125%; + top: 3%; + left: 2%; +} + +.fc-icon-down-triangle:after { + content: "\25BC"; + font-size: 125%; + top: 2%; +} + +.fc-icon-x:after { + content: "\000D7"; + font-size: 200%; + top: 6%; +} + + +/* Buttons (styled ").click(function(a){s.hasClass(n+"-state-disabled")||(j(a),(s.hasClass(n+"-state-active")||s.hasClass(n+"-state-disabled"))&&s.removeClass(n+"-state-hover"))}).mousedown(function(){s.not("."+n+"-state-active").not("."+n+"-state-disabled").addClass(n+"-state-down")}).mouseup(function(){s.removeClass(n+"-state-down")}).hover(function(){s.not("."+n+"-state-active").not("."+n+"-state-disabled").addClass(n+"-state-hover")},function(){s.removeClass(n+"-state-hover").removeClass(n+"-state-down")}),g=g.add(s)))}),h&&g.first().addClass(n+"-corner-left").end().last().addClass(n+"-corner-right").end(),g.length>1?(f=a("
"),h&&f.addClass("fc-button-group"),f.append(g),e.append(f)):e.append(g)}),e}function g(a){o.find("h2").text(a)}function h(a){o.find(".fc-"+a+"-button").addClass(n+"-state-active")}function i(a){o.find(".fc-"+a+"-button").removeClass(n+"-state-active")}function j(a){o.find(".fc-"+a+"-button").attr("disabled","disabled").addClass(n+"-state-disabled")}function k(a){o.find(".fc-"+a+"-button").removeAttr("disabled").removeClass(n+"-state-disabled")}function l(){return p}var m=this;m.render=d,m.removeElement=e,m.updateTitle=g,m.activateButton=h,m.deactivateButton=i,m.disableButton=j,m.enableButton=k,m.getViewsWithButtons=l;var n,o=a(),p=[]}function Ka(c){function d(a,b){return!M||a.clone().stripZone()N.clone().stripZone()}function e(a,b){M=a,N=b,U=[];var c=++S,d=R.length;T=d;for(var e=0;d>e;e++)f(R[e],c)}function f(b,c){g(b,function(d){var e,f,g,h=a.isArray(b.events);if(c==S){if(d)for(e=0;e=c&&b.end<=d}function K(a,b){var c=a.start.clone().stripZone(),d=L.getEventEnd(a).stripZone();return b.startc}var L=this;L.isFetchNeeded=d,L.fetchEvents=e,L.addEventSource=h,L.removeEventSource=j,L.updateEvent=m,L.renderEvent=p,L.removeEvents=q,L.clientEvents=r,L.mutateEvent=y,L.normalizeEventRange=u,L.normalizeEventRangeTimes=v,L.ensureVisibleEventRange=w;var M,N,O=L.reportEvents,Q={events:[]},R=[Q],S=0,T=0,U=[];a.each((c.events?[c.events]:[]).concat(c.eventSources||[]),function(a,b){var c=i(b);c&&R.push(c)}),L.getBusinessHoursEvents=A,L.isEventRangeAllowed=B,L.isSelectionRangeAllowed=C,L.isExternalDropRangeAllowed=D,L.getEventCache=function(){return U}}function La(a){a._allDay=a.allDay,a._start=a.start.clone(),a._end=a.end?a.end.clone():null}var Ma=a.fullCalendar={version:"2.4.0"},Na=Ma.views={};a.fn.fullCalendar=function(b){var c=Array.prototype.slice.call(arguments,1),d=this;return this.each(function(e,f){var g,h=a(f),i=h.data("fullCalendar");"string"==typeof b?i&&a.isFunction(i[b])&&(g=i[b].apply(i,c),e||(d=g),"destroy"===b&&h.removeData("fullCalendar")):i||(i=new nb(h,b),h.data("fullCalendar",i),i.render())}),d};var Oa=["header","buttonText","buttonIcons","themeButtonIcons"];Ma.intersectionToSeg=E,Ma.applyAll=W,Ma.debounce=da,Ma.isInt=ba,Ma.htmlEscape=Y,Ma.cssToStr=$,Ma.proxy=ca,Ma.capitaliseFirstLetter=_,Ma.getClientRect=p,Ma.getContentRect=q,Ma.getScrollbarWidths=r;var Pa=null;Ma.intersectRects=w,Ma.parseFieldSpecs=A,Ma.compareByFieldSpecs=B,Ma.compareByFieldSpec=C,Ma.flexibleCompare=D,Ma.computeIntervalUnit=I,Ma.divideRangeByDuration=K,Ma.divideDurationByDuration=L,Ma.multiplyDuration=M,Ma.durationHasTime=N;var Qa=["sun","mon","tue","wed","thu","fri","sat"],Ra=["year","month","week","day","hour","minute","second","millisecond"];Ma.log=function(){var a=window.console;return a&&a.log?a.log.apply(a,arguments):void 0},Ma.warn=function(){var a=window.console;return a&&a.warn?a.warn.apply(a,arguments):Ma.log.apply(Ma,arguments)};var Sa,Ta,Ua,Va={}.hasOwnProperty,Wa=/^\s*\d{4}-\d\d$/,Xa=/^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?)?$/,Ya=b.fn,Za=a.extend({},Ya);Ma.moment=function(){return ea(arguments)},Ma.moment.utc=function(){var a=ea(arguments,!0);return a.hasTime()&&a.utc(),a},Ma.moment.parseZone=function(){return ea(arguments,!0,!0)},Ya.clone=function(){var a=Za.clone.apply(this,arguments);return ga(this,a),this._fullCalendar&&(a._fullCalendar=!0),a},Ya.week=Ya.weeks=function(a){var b=(this._locale||this._lang)._fullCalendar_weekCalc;return null==a&&"function"==typeof b?b(this):"ISO"===b?Za.isoWeek.apply(this,arguments):Za.week.apply(this,arguments)},Ya.time=function(a){if(!this._fullCalendar)return Za.time.apply(this,arguments);if(null==a)return b.duration({hours:this.hours(),minutes:this.minutes(),seconds:this.seconds(),milliseconds:this.milliseconds()});this._ambigTime=!1,b.isDuration(a)||b.isMoment(a)||(a=b.duration(a));var c=0;return b.isDuration(a)&&(c=24*Math.floor(a.asDays())),this.hours(c+a.hours()).minutes(a.minutes()).seconds(a.seconds()).milliseconds(a.milliseconds())},Ya.stripTime=function(){var a;return this._ambigTime||(a=this.toArray(),this.utc(),Ta(this,a.slice(0,3)),this._ambigTime=!0,this._ambigZone=!0),this},Ya.hasTime=function(){return!this._ambigTime},Ya.stripZone=function(){var a,b;return this._ambigZone||(a=this.toArray(),b=this._ambigTime,this.utc(),Ta(this,a),this._ambigTime=b||!1,this._ambigZone=!0),this},Ya.hasZone=function(){return!this._ambigZone},Ya.local=function(){var a=this.toArray(),b=this._ambigZone;return Za.local.apply(this,arguments),this._ambigTime=!1,this._ambigZone=!1,b&&Ua(this,a),this},Ya.utc=function(){return Za.utc.apply(this,arguments),this._ambigTime=!1,this._ambigZone=!1,this},a.each(["zone","utcOffset"],function(a,b){Za[b]&&(Ya[b]=function(a){return null!=a&&(this._ambigTime=!1,this._ambigZone=!1),Za[b].apply(this,arguments)})}),Ya.format=function(){return this._fullCalendar&&arguments[0]?ja(this,arguments[0]):this._ambigTime?ia(this,"YYYY-MM-DD"):this._ambigZone?ia(this,"YYYY-MM-DD[T]HH:mm:ss"):Za.format.apply(this,arguments)},Ya.toISOString=function(){return this._ambigTime?ia(this,"YYYY-MM-DD"):this._ambigZone?ia(this,"YYYY-MM-DD[T]HH:mm:ss"):Za.toISOString.apply(this,arguments)},Ya.isWithin=function(a,b){var c=fa([this,a,b]);return c[0]>=c[1]&&c[0]').addClass(c.className||"").css({top:0,left:0}).append(c.content).appendTo(c.parentEl),this.el.on("click",".fc-close",function(){b.hide()}),c.autoHide&&a(document).on("mousedown",this.documentMousedownProxy=ca(this,"documentMousedown"))},documentMousedown:function(b){this.el&&!a(b.target).closest(this.el).length&&this.hide()},removeElement:function(){this.hide(),this.el&&(this.el.remove(),this.el=null),a(document).off("mousedown",this.documentMousedownProxy)},position:function(){var b,c,d,e,f,g=this.options,h=this.el.offsetParent().offset(),i=this.el.outerWidth(),j=this.el.outerHeight(),k=a(window),l=n(this.el);e=g.top||0,f=void 0!==g.left?g.left:void 0!==g.right?g.right-i:0,l.is(window)||l.is(document)?(l=k,b=0,c=0):(d=l.offset(),b=d.top,c=d.left),b+=k.scrollTop(),c+=k.scrollLeft(),g.viewportConstrain!==!1&&(e=Math.min(e,b+l.outerHeight()-j-this.margin),e=Math.max(e,b+this.margin),f=Math.min(f,c+l.outerWidth()-i-this.margin),f=Math.max(f,c+this.margin)),this.el.css({top:e-h.top,left:f-h.left})},trigger:function(a){this.options[a]&&this.options[a].apply(this,Array.prototype.slice.call(arguments,1)); +}}),db=ra.extend({grid:null,rowCoords:null,colCoords:null,containerEl:null,bounds:null,constructor:function(a){this.grid=a},build:function(){this.grid.build(),this.rowCoords=this.grid.computeRowCoords(),this.colCoords=this.grid.computeColCoords(),this.computeBounds()},clear:function(){this.grid.clear(),this.rowCoords=null,this.colCoords=null},getCell:function(b,c){var d,e,f,g=this.rowCoords,h=g.length,i=this.colCoords,j=i.length,k=null,l=null;if(this.inBounds(b,c)){for(d=0;h>d;d++)if(e=g[d],c>=e.top&&cd;d++)if(e=i[d],b>=e.left&&b=c.left&&a=c.top&&b=b*b&&this.startDrag(a)),this.isDragging&&this.drag(d,e,a)},startDrag:function(a){this.isListening||this.startListening(),this.isDragging||(this.isDragging=!0,this.dragStart(a))},dragStart:function(a){var b=this.subjectEl;this.trigger("dragStart",a),(this.subjectHref=b?b.attr("href"):null)&&b.removeAttr("href")},drag:function(a,b,c){this.trigger("drag",a,b,c),this.updateScroll(c)},mouseup:function(a){this.stopListening(a)},stopDrag:function(a){this.isDragging&&(this.stopScrolling(),this.dragStop(a),this.isDragging=!1)},dragStop:function(a){var b=this;this.trigger("dragStop",a),setTimeout(function(){b.subjectHref&&b.subjectEl.attr("href",b.subjectHref)},0)},stopListening:function(b){this.stopDrag(b),this.isListening&&(this.scrollEl&&(this.scrollEl.off("scroll",this.scrollHandlerProxy),this.scrollHandlerProxy=null),a(document).off("mousemove",this.mousemoveProxy).off("mouseup",this.mouseupProxy).off("selectstart",this.preventDefault),this.mousemoveProxy=null,this.mouseupProxy=null,this.isListening=!1,this.listenStop(b))},listenStop:function(a){this.trigger("listenStop",a)},trigger:function(a){this.options[a]&&this.options[a].apply(this,Array.prototype.slice.call(arguments,1))},preventDefault:function(a){a.preventDefault()},computeScrollBounds:function(){var a=this.scrollEl;this.scrollBounds=a?o(a):null},updateScroll:function(a){var b,c,d,e,f=this.scrollSensitivity,g=this.scrollBounds,h=0,i=0;g&&(b=(f-(a.pageY-g.top))/f,c=(f-(g.bottom-a.pageY))/f,d=(f-(a.pageX-g.left))/f,e=(f-(g.right-a.pageX))/f,b>=0&&1>=b?h=b*this.scrollSpeed*-1:c>=0&&1>=c&&(h=c*this.scrollSpeed),d>=0&&1>=d?i=d*this.scrollSpeed*-1:e>=0&&1>=e&&(i=e*this.scrollSpeed)),this.setScrollVel(h,i)},setScrollVel:function(a,b){this.scrollTopVel=a,this.scrollLeftVel=b,this.constrainScrollVel(),!this.scrollTopVel&&!this.scrollLeftVel||this.scrollIntervalId||(this.scrollIntervalId=setInterval(ca(this,"scrollIntervalFunc"),this.scrollIntervalMs))},constrainScrollVel:function(){var a=this.scrollEl;this.scrollTopVel<0?a.scrollTop()<=0&&(this.scrollTopVel=0):this.scrollTopVel>0&&a.scrollTop()+a[0].clientHeight>=a[0].scrollHeight&&(this.scrollTopVel=0),this.scrollLeftVel<0?a.scrollLeft()<=0&&(this.scrollLeftVel=0):this.scrollLeftVel>0&&a.scrollLeft()+a[0].clientWidth>=a[0].scrollWidth&&(this.scrollLeftVel=0)},scrollIntervalFunc:function(){var a=this.scrollEl,b=this.scrollIntervalMs/1e3;this.scrollTopVel&&a.scrollTop(a.scrollTop()+this.scrollTopVel*b),this.scrollLeftVel&&a.scrollLeft(a.scrollLeft()+this.scrollLeftVel*b),this.constrainScrollVel(),this.scrollTopVel||this.scrollLeftVel||this.stopScrolling()},stopScrolling:function(){this.scrollIntervalId&&(clearInterval(this.scrollIntervalId),this.scrollIntervalId=null,this.scrollStop())},scrollHandler:function(){this.scrollIntervalId||this.scrollStop()},scrollStop:function(){}}),gb=fb.extend({coordMap:null,origCell:null,cell:null,coordAdjust:null,constructor:function(a,b){fb.prototype.constructor.call(this,b),this.coordMap=a},listenStart:function(a){var b,c,d,e=this.subjectEl;fb.prototype.listenStart.apply(this,arguments),this.computeCoords(),a?(c={left:a.pageX,top:a.pageY},d=c,e&&(b=o(e),d=x(d,b)),this.origCell=this.getCell(d.left,d.top),e&&this.options.subjectCenter&&(this.origCell&&(b=w(this.origCell,b)||b),d=y(b)),this.coordAdjust=z(d,c)):(this.origCell=null,this.coordAdjust=null)},computeCoords:function(){this.coordMap.build(),this.computeScrollBounds()},dragStart:function(a){var b;fb.prototype.dragStart.apply(this,arguments),b=this.getCell(a.pageX,a.pageY),b&&this.cellOver(b)},drag:function(a,b,c){var d;fb.prototype.drag.apply(this,arguments),d=this.getCell(c.pageX,c.pageY),sa(d,this.cell)||(this.cell&&this.cellOut(),d&&this.cellOver(d))},dragStop:function(){this.cellDone(),fb.prototype.dragStop.apply(this,arguments)},cellOver:function(a){this.cell=a,this.trigger("cellOver",a,sa(a,this.origCell),this.origCell)},cellOut:function(){this.cell&&(this.trigger("cellOut",this.cell),this.cellDone(),this.cell=null)},cellDone:function(){this.cell&&this.trigger("cellDone",this.cell)},listenStop:function(){fb.prototype.listenStop.apply(this,arguments),this.origCell=this.cell=null,this.coordMap.clear()},scrollStop:function(){fb.prototype.scrollStop.apply(this,arguments),this.computeCoords()},getCell:function(a,b){return this.coordAdjust&&(a+=this.coordAdjust.left,b+=this.coordAdjust.top),this.coordMap.getCell(a,b)}}),hb=ra.extend({options:null,sourceEl:null,el:null,parentEl:null,top0:null,left0:null,mouseY0:null,mouseX0:null,topDelta:null,leftDelta:null,mousemoveProxy:null,isFollowing:!1,isHidden:!1,isAnimating:!1,constructor:function(b,c){this.options=c=c||{},this.sourceEl=b,this.parentEl=c.parentEl?a(c.parentEl):b.parent()},start:function(b){this.isFollowing||(this.isFollowing=!0,this.mouseY0=b.pageY,this.mouseX0=b.pageX,this.topDelta=0,this.leftDelta=0,this.isHidden||this.updatePosition(),a(document).on("mousemove",this.mousemoveProxy=ca(this,"mousemove")))},stop:function(b,c){function d(){this.isAnimating=!1,e.removeElement(),this.top0=this.left0=null,c&&c()}var e=this,f=this.options.revertDuration;this.isFollowing&&!this.isAnimating&&(this.isFollowing=!1,a(document).off("mousemove",this.mousemoveProxy),b&&f&&!this.isHidden?(this.isAnimating=!0,this.el.animate({top:this.top0,left:this.left0},{duration:f,complete:d})):d())},getEl:function(){var a=this.el;return a||(this.sourceEl.width(),a=this.el=this.sourceEl.clone().css({position:"absolute",visibility:"",display:this.isHidden?"none":"",margin:0,right:"auto",bottom:"auto",width:this.sourceEl.width(),height:this.sourceEl.height(),opacity:this.options.opacity||"",zIndex:this.options.zIndex}).appendTo(this.parentEl)),a},removeElement:function(){this.el&&(this.el.remove(),this.el=null)},updatePosition:function(){var a,b;this.getEl(),null===this.top0&&(this.sourceEl.width(),a=this.sourceEl.offset(),b=this.el.offsetParent().offset(),this.top0=a.top-b.top,this.left0=a.left-b.left),this.el.css({top:this.top0+this.topDelta,left:this.left0+this.leftDelta})},mousemove:function(a){this.topDelta=a.pageY-this.mouseY0,this.leftDelta=a.pageX-this.mouseX0,this.isHidden||this.updatePosition()},hide:function(){this.isHidden||(this.isHidden=!0,this.el&&this.el.hide())},show:function(){this.isHidden&&(this.isHidden=!1,this.updatePosition(),this.getEl().show())}}),ib=ra.extend({view:null,isRTL:null,cellHtml:"",constructor:function(a){this.view=a,this.isRTL=a.opt("isRTL")},rowHtml:function(a,b){var c,d,e=this.getHtmlRenderer("cell",a),f="";for(b=b||0,c=0;c"+f+""},bookendCells:function(a,b,c){var d=this.getHtmlRenderer("intro",b)(c||0),e=this.getHtmlRenderer("outro",b)(c||0),f=this.isRTL?e:d,g=this.isRTL?d:e;return"string"==typeof a?f+a+g:a.prepend(f).append(g)},getHtmlRenderer:function(a,b){var c,d,e,f,g=this.view;return c=a+"Html",b&&(d=b+_(a)+"Html"),d&&(f=g[d])?e=g:d&&(f=this[d])?e=this:(f=g[c])?e=g:(f=this[c])&&(e=this),"function"==typeof f?function(){return f.apply(e,arguments)||""}:function(){return f||""}}}),jb=Ma.Grid=ib.extend({start:null,end:null,rowCnt:0,colCnt:0,el:null,coordMap:null,elsByFill:null,externalDragStartProxy:null,colHeadFormat:null,eventTimeFormat:null,displayEventTime:null,displayEventEnd:null,cellDuration:null,largeUnit:null,constructor:function(){ib.apply(this,arguments),this.coordMap=new db(this),this.elsByFill={},this.externalDragStartProxy=ca(this,"externalDragStart")},computeColHeadFormat:function(){},computeEventTimeFormat:function(){return this.view.opt("smallTimeFormat")},computeDisplayEventTime:function(){return!0},computeDisplayEventEnd:function(){return!0},setRange:function(a){this.start=a.start.clone(),this.end=a.end.clone(),this.rangeUpdated(),this.processRangeOptions()},rangeUpdated:function(){},processRangeOptions:function(){var a,b,c=this.view;this.colHeadFormat=c.opt("columnFormat")||this.computeColHeadFormat(),this.eventTimeFormat=c.opt("eventTimeFormat")||c.opt("timeFormat")||this.computeEventTimeFormat(),a=c.opt("displayEventTime"),null==a&&(a=this.computeDisplayEventTime()),b=c.opt("displayEventEnd"),null==b&&(b=this.computeDisplayEventEnd()),this.displayEventTime=a,this.displayEventEnd=b},build:function(){},clear:function(){},rangeToSegs:function(a){},diffDates:function(a,b){return this.largeUnit?H(a,b,this.largeUnit):F(a,b)},getCell:function(b,c){var d;return null==c&&("number"==typeof b?(c=b%this.colCnt,b=Math.floor(b/this.colCnt)):(c=b.col,b=b.row)),d={row:b,col:c},a.extend(d,this.getRowData(b),this.getColData(c)),a.extend(d,this.computeCellRange(d)),d},computeCellRange:function(a){var b=this.computeCellDate(a);return{start:b,end:b.clone().add(this.cellDuration)}},computeCellDate:function(a){},getRowData:function(a){return{}},getColData:function(a){return{}},getRowEl:function(a){},getColEl:function(a){},getCellDayEl:function(a){return this.getColEl(a.col)||this.getRowEl(a.row)},computeRowCoords:function(){var a,b,c,d=[];for(a=0;a"},headHtml:function(){return'
'+this.rowHtml("head")+"
"},headCellHtml:function(a){var b=this.view,c=a.start;return''+Y(c.format(this.colHeadFormat))+""},bgCellHtml:function(a){var b=this.view,c=a.start,d=this.getDayClasses(c);return d.unshift("fc-day",b.widgetContentClass),''},getDayClasses:function(a){var b=this.view,c=b.calendar.getNow().stripTime(),d=["fc-"+Qa[a.day()]];return 1==b.intervalDuration.as("months")&&a.month()!=b.intervalStart.month()&&d.push("fc-other-month"),a.isSame(c,"day")?d.push("fc-today",b.highlightStateClass):c>a?d.push("fc-past"):d.push("fc-future"),d}});jb.mixin({mousedOverSeg:null,isDraggingSeg:!1,isResizingSeg:!1,isDraggingExternal:!1,segs:null,renderEvents:function(a){var b,c,d=this.eventsToSegs(a),e=[],f=[];for(b=0;b *",function(c){var e=a(this).data("fc-seg");return!e||b.isDraggingSeg||b.isResizingSeg?void 0:d.call(this,e,c)})})},triggerSegMouseover:function(a,b){this.mousedOverSeg||(this.mousedOverSeg=a,this.view.trigger("eventMouseover",a.el[0],a.event,b))},triggerSegMouseout:function(a,b){b=b||{},this.mousedOverSeg&&(a=a||this.mousedOverSeg,this.mousedOverSeg=null,this.view.trigger("eventMouseout",a.el[0],a.event,b))},segDragMousedown:function(a,b){var c,d=this,e=this.view,f=e.calendar,i=a.el,j=a.event,k=new hb(a.el,{parentEl:e.el,opacity:e.opt("dragOpacity"),revertDuration:e.opt("dragRevertDuration"),zIndex:2}),l=new gb(e.coordMap,{distance:5,scroll:e.opt("dragScroll"),subjectEl:i,subjectCenter:!0,listenStart:function(a){k.hide(),k.start(a)},dragStart:function(b){d.triggerSegMouseout(a,b),d.segDragStart(a,b),e.hideEvent(j)},cellOver:function(b,h,i){a.cell&&(i=a.cell),c=d.computeEventDrop(i,b,j),c&&!f.isEventRangeAllowed(c,j)&&(g(),c=null),c&&e.renderDrag(c,a)?k.hide():k.show(),h&&(c=null)},cellOut:function(){e.unrenderDrag(),k.show(),c=null},cellDone:function(){h()},dragStop:function(b){k.stop(!c,function(){e.unrenderDrag(),e.showEvent(j),d.segDragStop(a,b),c&&e.reportEventDrop(j,c,this.largeUnit,i,b)})},listenStop:function(){k.stop()}});l.mousedown(b)},segDragStart:function(a,b){this.isDraggingSeg=!0,this.view.trigger("eventDragStart",a.el[0],a.event,b,{})},segDragStop:function(a,b){this.isDraggingSeg=!1,this.view.trigger("eventDragStop",a.el[0],a.event,b,{})},computeEventDrop:function(a,b,c){var d,e,f=this.view.calendar,g=a.start,h=b.start;return g.hasTime()===h.hasTime()?(d=this.diffDates(h,g),c.allDay&&N(d)?(e={start:c.start.clone(),end:f.getEventEnd(c),allDay:!1},f.normalizeEventRangeTimes(e)):e={start:c.start.clone(),end:c.end?c.end.clone():null,allDay:c.allDay},e.start.add(d),e.end&&e.end.add(d)):e={start:h.clone(),end:null,allDay:!h.hasTime()},e},applyDragOpacity:function(a){var b=this.view.opt("dragOpacity");null!=b&&a.each(function(a,c){c.style.opacity=b})},externalDragStart:function(b,c){var d,e,f=this.view;f.opt("droppable")&&(d=a((c?c.item:null)||b.target),e=f.opt("dropAccept"),(a.isFunction(e)?e.call(d[0],d):d.is(e))&&(this.isDraggingExternal||this.listenToExternalDrag(d,b,c)))},listenToExternalDrag:function(a,b,c){var d,e,f=this,i=ya(a);d=new gb(this.coordMap,{listenStart:function(){f.isDraggingExternal=!0},cellOver:function(a){e=f.computeExternalDrop(a,i),e?f.renderDrag(e):g()},cellOut:function(){e=null,f.unrenderDrag(),h()},dragStop:function(){f.unrenderDrag(),h(),e&&f.view.reportExternalDrop(i,e,a,b,c)},listenStop:function(){f.isDraggingExternal=!1}}),d.startDrag(b)},computeExternalDrop:function(a,b){var c={start:a.start.clone(),end:null};return b.startTime&&!c.start.hasTime()&&c.start.time(b.startTime),b.duration&&(c.end=c.start.clone().add(b.duration)),this.view.calendar.isExternalDropRangeAllowed(c,b.eventProps)?c:null},renderDrag:function(a,b){},unrenderDrag:function(){},segResizeMousedown:function(a,b,c){var d,e,f=this,i=this.view,j=i.calendar,k=a.el,l=a.event,m=j.getEventEnd(l);d=new gb(this.coordMap,{distance:5,scroll:i.opt("dragScroll"),subjectEl:k,dragStart:function(b){f.triggerSegMouseout(a,b),f.segResizeStart(a,b)},cellOver:function(b,d,h){e=c?f.computeEventStartResize(h,b,l):f.computeEventEndResize(h,b,l),e&&(j.isEventRangeAllowed(e,l)?e.start.isSame(l.start)&&e.end.isSame(m)&&(e=null):(g(),e=null)),e&&(i.hideEvent(l),f.renderEventResize(e,a))},cellOut:function(){e=null},cellDone:function(){f.unrenderEventResize(),i.showEvent(l),h()},dragStop:function(b){f.segResizeStop(a,b),e&&i.reportEventResize(l,e,this.largeUnit,k,b)}}),d.mousedown(b)},segResizeStart:function(a,b){this.isResizingSeg=!0,this.view.trigger("eventResizeStart",a.el[0],a.event,b,{})},segResizeStop:function(a,b){this.isResizingSeg=!1,this.view.trigger("eventResizeStop",a.el[0],a.event,b,{})},computeEventStartResize:function(a,b,c){return this.computeEventResize("start",a,b,c)},computeEventEndResize:function(a,b,c){return this.computeEventResize("end",a,b,c)},computeEventResize:function(a,b,c,d){var e,f,g=this.view.calendar,h=this.diffDates(c[a],b[a]);return e={start:d.start.clone(),end:g.getEventEnd(d),allDay:d.allDay},e.allDay&&N(h)&&(e.allDay=!1,g.normalizeEventRangeTimes(e)),e[a].add(h),e.start.isBefore(e.end)||(f=d.allDay?g.defaultAllDayEventDuration:g.defaultTimedEventDuration,this.cellDuration&&this.cellDurationj&&h.push({event:i,start:j,end:c.start}),j=c.end;return f>j&&h.push({event:i,start:j,end:f}),h},eventRangeToSegs:function(a,b){var c,d,e;for(a=this.view.calendar.ensureVisibleEventRange(a),c=b?b(a):this.rangeToSegs(a),d=0;db;b++)i+=this.dayRowHtml(b,a);for(this.el.html(i),this.rowEls=this.el.find(".fc-row"),this.dayEls=this.el.find(".fc-day"),c=0;h>c;c++)d=this.getCell(c),e.trigger("dayRender",null,d.start,this.dayEls.eq(c))},unrenderDates:function(){this.removeSegPopover()},renderBusinessHours:function(){var a=this.view.calendar.getBusinessHoursEvents(!0),b=this.eventsToSegs(a);this.renderFill("businessHours",b,"bgevent")},dayRowHtml:function(a,b){var c=this.view,d=["fc-row","fc-week",c.widgetContentClass];return b&&d.push("fc-rigid"),'
'+this.rowHtml("day",a)+'
'+(this.numbersVisible?""+this.rowHtml("number",a)+"":"")+"
"},dayCellHtml:function(a){return this.bgCellHtml(a)},computeColHeadFormat:function(){return this.rowCnt>1?"ddd":this.colCnt>1?this.view.opt("dayOfMonthFormat"):"dddd"},computeEventTimeFormat:function(){return this.view.opt("extraSmallTimeFormat")},computeDisplayEventEnd:function(){return 1==this.colCnt},rangeUpdated:function(){var a,b,c,d;if(this.updateCellDates(),a=this.cellDates,this.breakOnWeeks){for(b=a[0].day(),d=1;dd;d++)e=d*n,f=e+n-1,i=Math.max(e,b),j=Math.min(f,c),i=Math.ceil(i),j=Math.floor(j),j>=i&&(g=i===b,h=j===c,i-=e,j-=e,k={row:d,isStart:g,isEnd:h},l?(k.leftCol=n-j-1,k.rightCol=n-i-1):(k.leftCol=i,k.rightCol=j),o.push(k));return o},dateToCellOffset:function(a){var b=this.dayToCellOffsets,c=a.diff(this.start,"days");return 0>c?b[0]-1:c>=b.length?b[b.length-1]+1:b[c]},renderDrag:function(a,b){return this.renderHighlight(this.eventRangeToSegs(a)),b&&!b.el.closest(this.el).length?(this.renderRangeHelper(a,b),this.applyDragOpacity(this.helperEls),!0):void 0},unrenderDrag:function(){this.unrenderHighlight(),this.unrenderHelper()},renderEventResize:function(a,b){this.renderHighlight(this.eventRangeToSegs(a)),this.renderRangeHelper(a,b)},unrenderEventResize:function(){this.unrenderHighlight(),this.unrenderHelper()},renderHelper:function(b,c){var d,e=[],f=this.eventsToSegs([b]);f=this.renderFgSegEls(f),d=this.renderSegRows(f),this.rowEls.each(function(b,f){var g,h=a(f),i=a('
');g=c&&c.row===b?c.el.position().top:h.find(".fc-content-skeleton tbody").position().top,i.css("top",g).find("table").append(d[b].tbodyEl),h.append(i),e.push(i[0])}),this.helperEls=a(e)},unrenderHelper:function(){this.helperEls&&(this.helperEls.remove(),this.helperEls=null)},fillSegTag:"td",renderFill:function(b,c,d){var e,f,g,h=[];for(c=this.renderFillSegEls(b,c),e=0;e
'),f=e.find("tr"),h>0&&f.append(''),f.append(c.el.attr("colspan",i-h)),g>i&&f.append(''),this.bookendCells(f,b),e}});kb.mixin({rowStructs:null,unrenderEvents:function(){this.removeSegPopover(),jb.prototype.unrenderEvents.apply(this,arguments)},getEventSegs:function(){return jb.prototype.getEventSegs.call(this).concat(this.popoverSegs||[])},renderBgSegs:function(b){var c=a.grep(b,function(a){return a.event.allDay});return jb.prototype.renderBgSegs.call(this,c)},renderFgSegs:function(b){var c;return b=this.renderFgSegEls(b),c=this.rowStructs=this.renderSegRows(b),this.rowEls.each(function(b,d){a(d).find(".fc-content-skeleton > table").append(c[b].tbodyEl)}),b},unrenderFgSegs:function(){for(var a,b=this.rowStructs||[];a=b.pop();)a.tbodyEl.remove();this.rowStructs=null},renderSegRows:function(a){var b,c,d=[];for(b=this.groupSegRows(a),c=0;c'+Y(c)+"")),d=''+(Y(f.title||"")||" ")+"",'
'+(this.isRTL?d+" "+l:l+" "+d)+"
"+(h?'
':"")+(i?'
':"")+""},renderSegRow:function(b,c){function d(b){for(;b>g;)k=(r[e-1]||[])[g],k?k.attr("rowspan",parseInt(k.attr("rowspan")||1,10)+1):(k=a(""),h.append(k)),q[e][g]=k,r[e][g]=k,g++}var e,f,g,h,i,j,k,l=this.colCnt,m=this.buildSegLevels(c),n=Math.max(1,m.length),o=a(""),p=[],q=[],r=[];for(e=0;n>e;e++){if(f=m[e],g=0,h=a(""),p.push([]),q.push([]),r.push([]),f)for(i=0;i').append(j.el),j.leftCol!=j.rightCol?k.attr("colspan",j.rightCol-j.leftCol+1):r[e][g]=k;g<=j.rightCol;)q[e][g]=k,p[e][g]=j,g++;h.append(k)}d(l),this.bookendCells(h,"eventSkeleton"),o.append(h)}return{row:b,tbodyEl:o,cellMatrix:q,segMatrix:p,segLevels:m,segs:c}},buildSegLevels:function(a){var b,c,d,e=[];for(this.sortSegs(a),b=0;b td > :first-child").each(c),e.position().top+f>h)return d;return!1},limitRow:function(b,c){function d(d){for(;d>x;)e=u.getCell(b,x),k=u.getCellSegs(e,c),k.length&&(n=g[c-1][x],t=u.renderMoreLink(e,k),s=a("
").append(t),n.append(s),w.push(s[0])),x++}var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u=this,v=this.rowStructs[b],w=[],x=0;if(c&&c').attr("rowspan",o),k=m[q],e=this.getCell(b,j.leftCol+q),t=this.renderMoreLink(e,[j].concat(k)),s=a("
").append(t),r.append(s),p.push(r[0]),w.push(r[0]);n.addClass("fc-limited").after(a(p)),h.push(n[0])}}d(this.colCnt),v.moreEls=a(w),v.limitedEls=a(h)}}, +unlimitRow:function(a){var b=this.rowStructs[a];b.moreEls&&(b.moreEls.remove(),b.moreEls=null),b.limitedEls&&(b.limitedEls.removeClass("fc-limited"),b.limitedEls=null)},renderMoreLink:function(b,c){var d=this,e=this.view;return a('').text(this.getMoreLinkText(c.length)).on("click",function(f){var g=e.opt("eventLimitClick"),h=b.start,i=a(this),j=d.getCellDayEl(b),k=d.getCellSegs(b),l=d.resliceDaySegs(k,h),m=d.resliceDaySegs(c,h);"function"==typeof g&&(g=e.trigger("eventLimitClick",null,{date:h,dayEl:j,moreEl:i,segs:l,hiddenSegs:m},f)),"popover"===g?d.showSegPopover(b,i,l):"string"==typeof g&&e.calendar.zoomTo(h,g)})},showSegPopover:function(a,b,c){var d,e,f=this,g=this.view,h=b.parent();d=1==this.rowCnt?g.el:this.rowEls.eq(a.row),e={className:"fc-more-popover",content:this.renderSegPopoverContent(a,c),parentEl:this.el,top:d.offset().top,autoHide:!0,viewportConstrain:g.opt("popoverViewportConstrain"),hide:function(){f.segPopover.removeElement(),f.segPopover=null,f.popoverSegs=null}},this.isRTL?e.right=h.offset().left+h.outerWidth()+1:e.left=h.offset().left-1,this.segPopover=new cb(e),this.segPopover.show()},renderSegPopoverContent:function(b,c){var d,e=this.view,f=e.opt("theme"),g=b.start.format(e.opt("dayPopoverFormat")),h=a('
'+Y(g)+'
'),i=h.find(".fc-event-container");for(c=this.renderFgSegEls(c,!0),this.popoverSegs=c,d=0;d'+this.rowHtml("slotBg")+'
'+this.slatRowHtml()+"
"},slotBgCellHtml:function(a){return this.bgCellHtml(a)},slatRowHtml:function(){for(var a,c,d,e=this.view,f=this.isRTL,g="",h=b.duration(+this.minTime);h"+(c?""+Y(a.format(this.labelFormat))+"":"")+"",g+=""+(f?"":d)+''+(f?d:"")+"",h.add(this.slotDuration);return g},processOptions:function(){var c,d=this.view,e=d.opt("slotDuration"),f=d.opt("snapDuration");e=b.duration(e),f=f?b.duration(f):e,this.slotDuration=e,this.snapDuration=f,this.cellDuration=f,this.minTime=b.duration(d.opt("minTime")),this.maxTime=b.duration(d.opt("maxTime")),c=d.opt("slotLabelFormat"),a.isArray(c)&&(c=c[c.length-1]),this.labelFormat=c||d.opt("axisFormat")||d.opt("smallTimeFormat"),c=d.opt("slotLabelInterval"),this.labelInterval=c?b.duration(c):this.computeLabelInterval(e)},computeLabelInterval:function(a){var c,d,e;for(c=yb.length-1;c>=0;c--)if(d=b.duration(yb[c]),e=L(d,a),ba(e)&&e>1)return d;return b.duration(a)},computeColHeadFormat:function(){return this.colCnt>1?this.view.opt("dayOfMonthFormat"):"dddd"},computeEventTimeFormat:function(){return this.view.opt("noMeridiemTimeFormat")},computeDisplayEventEnd:function(){return!0},rangeUpdated:function(){var a,b=this.view,c=[];for(a=this.start.clone();a.isBefore(this.end);)c.push(a.clone()),a.add(1,"day"),a=b.skipHiddenDays(a);this.isRTL&&c.reverse(),this.colDates=c,this.colCnt=c.length,this.rowCnt=Math.ceil((this.maxTime-this.minTime)/this.snapDuration)},computeCellDate:function(a){var b=this.colDates[a.col],c=this.computeSnapTime(a.row);return b=this.view.calendar.rezoneDate(b),b.time(c),b},getColEl:function(a){return this.dayEls.eq(a)},computeSnapTime:function(a){return b.duration(this.minTime+this.snapDuration*a)},rangeToSegs:function(a){var b,c,d,e,f=this.colCnt,g=[];for(a={start:a.start.clone().stripZone(),end:a.end.clone().stripZone()},c=0;f>c;c++)d=this.colDates[c],e={start:d.clone().time(this.minTime),end:d.clone().time(this.maxTime)},b=E(a,e),b&&(b.col=c,g.push(b));return g},updateSize:function(a){this.computeSlatTops(),a&&this.updateSegVerticals()},computeRowCoords:function(){var a,b,c=this.el.offset().top,d=[];for(a=0;a0&&(d[a-1].bottom=b.top),d.push(b);return b.bottom=b.top+this.computeTimeTop(this.computeSnapTime(a)),d},computeDateTop:function(a,c){return this.computeTimeTop(b.duration(a.clone().stripZone()-c.clone().stripTime()))},computeTimeTop:function(a){var b,c,d,e,f=(a-this.minTime)/this.slotDuration;return f=Math.max(0,f),f=Math.min(this.slatEls.length,f),b=Math.floor(f),c=f-b,d=this.slatTops[b],c?(e=this.slatTops[b+1],d+(e-d)*c):d},computeSlatTops:function(){var b,c=[];this.slatEls.each(function(d,e){b=a(e).position().top,c.push(b)}),c.push(b+this.slatEls.last().outerHeight()),this.slatTops=c},renderDrag:function(a,b){return b?(this.renderRangeHelper(a,b),this.applyDragOpacity(this.helperEl),!0):void this.renderHighlight(this.eventRangeToSegs(a))},unrenderDrag:function(){this.unrenderHelper(),this.unrenderHighlight()},renderEventResize:function(a,b){this.renderRangeHelper(a,b)},unrenderEventResize:function(){this.unrenderHelper()},renderHelper:function(b,c){var d,e,f,g,h=this.eventsToSegs([b]);for(h=this.renderFgSegEls(h),d=this.renderSegTable(h),e=0;e').append(d).appendTo(this.el)},unrenderHelper:function(){this.helperEl&&(this.helperEl.remove(),this.helperEl=null)},renderSelection:function(a){this.view.opt("selectHelper")?this.renderRangeHelper(a):this.renderHighlight(this.selectionRangeToSegs(a))},unrenderSelection:function(){this.unrenderHelper(),this.unrenderHighlight()},renderFill:function(b,c,d){var e,f,g,h,i,j,k,l,m,n;if(c.length){for(c=this.renderFillSegEls(b,c),e=this.groupSegCols(c),d=d||b.toLowerCase(),f=a('
'),g=f.find("tr"),h=0;h").appendTo(g),i.length)for(k=a('
').appendTo(j),l=this.colDates[h],m=0;m').append(this.renderSegTable(b))),b},unrenderFgSegs:function(a){this.eventSkeletonEl&&(this.eventSkeletonEl.remove(),this.eventSkeletonEl=null)},renderSegTable:function(b){var c,d,e,f,g,h,i=a("
"),j=i.find("tr");for(c=this.groupSegCols(b),this.computeSegVerticals(b),f=0;f'),d=0;d").append(h))}return this.bookendCells(j,"eventSkeleton"),i},placeSlotSegs:function(a){var b,c,d;if(this.sortSegs(a),b=Ba(a),Ca(b),c=b[0]){for(d=0;d
'+(c?'
'+Y(c)+"
":"")+(g.title?'
'+Y(g.title)+"
":"")+'
'+(j?'
':"")+""},generateSegPositionCss:function(a){var b,c,d=this.view.opt("slotEventOverlap"),e=a.backwardCoord,f=a.forwardCoord,g=this.generateSegVerticalCss(a);return d&&(f=Math.min(1,e+2*(f-e))),this.isRTL?(b=1-f,c=e):(b=e,c=1-f),g.zIndex=a.level+1,g.left=100*b+"%",g.right=100*c+"%",d&&a.forwardPressure&&(g[this.isRTL?"marginLeft":"marginRight"]=20),g},generateSegVerticalCss:function(a){return{top:a.top,bottom:-a.bottom}},groupSegCols:function(a){var b,c=[];for(b=0;b1?"ll":"LL"},formatRange:function(a,b,c){var d=a.end;return d.hasTime()||(d=d.clone().subtract(1)),ma(a.start,d,b,c,this.opt("isRTL"))},setElement:function(a){this.el=a,this.bindGlobalHandlers()},removeElement:function(){this.clear(),this.isSkeletonRendered&&(this.unrenderSkeleton(),this.isSkeletonRendered=!1),this.unbindGlobalHandlers(),this.el.remove()},display:function(b){var c=this,d=null;return this.displaying&&(d=this.queryScroll()),this.clear().then(function(){return c.displaying=a.when(c.displayView(b)).then(function(){c.forceScroll(c.computeInitialScroll(d)),c.triggerRender()})})},clear:function(){var b=this,c=this.displaying;return c?c.then(function(){return b.displaying=null,b.clearEvents(),b.clearView()}):a.when()},displayView:function(a){this.isSkeletonRendered||(this.renderSkeleton(),this.isSkeletonRendered=!0),this.setDate(a),this.render&&this.render(),this.renderDates(),this.updateSize(),this.renderBusinessHours()},clearView:function(){this.unselect(),this.triggerUnrender(),this.unrenderBusinessHours(),this.unrenderDates(),this.destroy&&this.destroy()},renderSkeleton:function(){},unrenderSkeleton:function(){},renderDates:function(){},unrenderDates:function(){},renderBusinessHours:function(){},unrenderBusinessHours:function(){},triggerRender:function(){this.trigger("viewRender",this,this,this.el)},triggerUnrender:function(){this.trigger("viewDestroy",this,this,this.el)},bindGlobalHandlers:function(){a(document).on("mousedown",this.documentMousedownProxy)},unbindGlobalHandlers:function(){a(document).off("mousedown",this.documentMousedownProxy)},initThemingProps:function(){var a=this.opt("theme")?"ui":"fc";this.widgetHeaderClass=a+"-widget-header",this.widgetContentClass=a+"-widget-content",this.highlightStateClass=a+"-state-highlight"},updateSize:function(a){var b;a&&(b=this.queryScroll()),this.updateHeight(a),this.updateWidth(a),a&&this.setScroll(b)},updateWidth:function(a){},updateHeight:function(a){var b=this.calendar;this.setHeight(b.getSuggestedViewHeight(),b.isHeightAuto())},setHeight:function(a,b){},computeScrollerHeight:function(a){var b,c,d=this.scrollerEl;return b=this.el.add(d),b.css({position:"relative",left:-1}),c=this.el.outerHeight()-d.height(),b.css({position:"",left:""}),a-c},computeInitialScroll:function(a){return 0},queryScroll:function(){return this.scrollerEl?this.scrollerEl.scrollTop():void 0},setScroll:function(a){return this.scrollerEl?this.scrollerEl.scrollTop(a):void 0},forceScroll:function(a){var b=this;this.setScroll(a),setTimeout(function(){b.setScroll(a)},0)},displayEvents:function(a){var b=this.queryScroll();this.clearEvents(),this.renderEvents(a),this.isEventsRendered=!0,this.setScroll(b),this.triggerEventRender()},clearEvents:function(){this.isEventsRendered&&(this.triggerEventUnrender(),this.destroyEvents&&this.destroyEvents(),this.unrenderEvents(),this.isEventsRendered=!1)},renderEvents:function(a){},unrenderEvents:function(){},triggerEventRender:function(){this.renderedEventSegEach(function(a){this.trigger("eventAfterRender",a.event,a.event,a.el)}),this.trigger("eventAfterAllRender")},triggerEventUnrender:function(){this.renderedEventSegEach(function(a){this.trigger("eventDestroy",a.event,a.event,a.el)})},resolveEventEl:function(b,c){var d=this.trigger("eventRender",b,b,c);return d===!1?c=null:d&&d!==!0&&(c=a(d)),c},showEvent:function(a){this.renderedEventSegEach(function(a){a.el.css("visibility","")},a)},hideEvent:function(a){this.renderedEventSegEach(function(a){a.el.css("visibility","hidden")},a)},renderedEventSegEach:function(a,b){var c,d=this.getEventSegs();for(c=0;cb;b++)(d[b]=-1!==a.inArray(b,c))||e++;if(!e)throw"invalid hiddenDays";this.isHiddenDayHash=d},isHiddenDay:function(a){return b.isMoment(a)&&(a=a.day()),this.isHiddenDayHash[a]},skipHiddenDays:function(a,b,c){var d=a.clone();for(b=b||1;this.isHiddenDayHash[(d.day()+(c?b:0)+7)%7];)d.add(b,"days");return d},computeDayRange:function(a){var b,c=a.start.clone().stripTime(),d=a.end,e=null;return d&&(e=d.clone().stripTime(),b=+d.time(),b&&b>=this.nextDayThreshold&&e.add(1,"days")),(!d||c>=e)&&(e=c.clone().add(1,"days")),{start:c,end:e}},isMultiDayEvent:function(a){var b=this.computeDayRange(a);return b.end.diff(b.start,"days")>1}}),nb=Ma.Calendar=ra.extend({dirDefaults:null,langDefaults:null,overrides:null,options:null,viewSpecCache:null,view:null,header:null,loadingLevel:0,constructor:Ga,initialize:function(){},initOptions:function(a){var b,e,f,g;a=d(a),b=a.lang,e=ob[b],e||(b=nb.defaults.lang,e=ob[b]||{}),f=X(a.isRTL,e.isRTL,nb.defaults.isRTL),g=f?nb.rtlDefaults:{},this.dirDefaults=g,this.langDefaults=e,this.overrides=a,this.options=c([nb.defaults,g,e,a]),Ha(this.options),this.viewSpecCache={}},getViewSpec:function(a){var b=this.viewSpecCache;return b[a]||(b[a]=this.buildViewSpec(a))},getUnitViewSpec:function(b){var c,d,e;if(-1!=a.inArray(b,Ra))for(c=this.header.getViewsWithButtons(),a.each(Ma.views,function(a){c.push(a)}),d=0;d1,this.weekNumbersVisible=this.opt("weekNumbers"),this.dayGrid.numbersVisible=this.dayNumbersVisible||this.weekNumbersVisible,this.el.addClass("fc-basic-view").html(this.renderHtml()),this.headRowEl=this.el.find("thead .fc-row"),this.scrollerEl=this.el.find(".fc-day-grid-container"),this.dayGrid.coordMap.containerEl=this.scrollerEl,this.dayGrid.setElement(this.el.find(".fc-day-grid")),this.dayGrid.renderDates(this.hasRigidRows())},unrenderDates:function(){this.dayGrid.unrenderDates(),this.dayGrid.removeElement()},renderBusinessHours:function(){this.dayGrid.renderBusinessHours()},renderHtml:function(){return'
'+this.dayGrid.headHtml()+'
'},headIntroHtml:function(){return this.weekNumbersVisible?'"+Y(this.opt("weekNumberTitle"))+"":void 0},numberIntroHtml:function(a){return this.weekNumbersVisible?'"+this.dayGrid.getCell(a,0).start.format("w")+"":void 0},dayIntroHtml:function(){return this.weekNumbersVisible?'":void 0},introHtml:function(){return this.weekNumbersVisible?'":void 0},numberCellHtml:function(a){var b,c=a.start;return this.dayNumbersVisible?(b=this.dayGrid.getDayClasses(c),b.unshift("fc-day-number"),''+c.date()+""):""},weekNumberStyleAttr:function(){return null!==this.weekNumberWidth?'style="width:'+this.weekNumberWidth+'px"':""},hasRigidRows:function(){var a=this.opt("eventLimit");return a&&"number"!=typeof a},updateWidth:function(){this.weekNumbersVisible&&(this.weekNumberWidth=k(this.el.find(".fc-week-number")))},setHeight:function(a,b){var c,d=this.opt("eventLimit");m(this.scrollerEl),f(this.headRowEl),this.dayGrid.removeSegPopover(),d&&"number"==typeof d&&this.dayGrid.limitRows(d),c=this.computeScrollerHeight(a),this.setGridHeight(c,b),d&&"number"!=typeof d&&this.dayGrid.limitRows(d),!b&&l(this.scrollerEl,c)&&(e(this.headRowEl,r(this.scrollerEl)),c=this.computeScrollerHeight(a),this.scrollerEl.height(c))},setGridHeight:function(a,b){b?j(this.dayGrid.rowEls):i(this.dayGrid.rowEls,a,!0)},renderEvents:function(a){this.dayGrid.renderEvents(a),this.updateHeight()},getEventSegs:function(){return this.dayGrid.getEventSegs()},unrenderEvents:function(){this.dayGrid.unrenderEvents()},renderDrag:function(a,b){return this.dayGrid.renderDrag(a,b)},unrenderDrag:function(){this.dayGrid.unrenderDrag()},renderSelection:function(a){this.dayGrid.renderSelection(a)},unrenderSelection:function(){this.dayGrid.unrenderSelection()}}),vb=ub.extend({computeRange:function(a){var b,c=ub.prototype.computeRange.call(this,a);return this.isFixedWeeks()&&(b=Math.ceil(c.end.diff(c.start,"weeks",!0)),c.end.add(6-b,"weeks")),c},setGridHeight:function(a,b){b=b||"variable"===this.opt("weekMode"),b&&(a*=this.rowCnt/6),i(this.dayGrid.rowEls,a,!b)},isFixedWeeks:function(){var a=this.opt("weekMode");return a?"fixed"===a:this.opt("fixedWeekCount")}});Na.basic={"class":ub},Na.basicDay={type:"basic",duration:{days:1}},Na.basicWeek={type:"basic",duration:{weeks:1}},Na.month={"class":vb,duration:{months:1},defaults:{fixedWeekCount:!0}};var wb=mb.extend({timeGrid:null,dayGrid:null,axisWidth:null,noScrollRowEls:null,bottomRuleEl:null,bottomRuleHeight:null,initialize:function(){this.timeGrid=new lb(this),this.opt("allDaySlot")?(this.dayGrid=new kb(this),this.coordMap=new eb([this.dayGrid.coordMap,this.timeGrid.coordMap])):this.coordMap=this.timeGrid.coordMap},setRange:function(a){mb.prototype.setRange.call(this,a),this.timeGrid.setRange(a),this.dayGrid&&this.dayGrid.setRange(a)},renderDates:function(){this.el.addClass("fc-agenda-view").html(this.renderHtml()),this.scrollerEl=this.el.find(".fc-time-grid-container"),this.timeGrid.coordMap.containerEl=this.scrollerEl,this.timeGrid.setElement(this.el.find(".fc-time-grid")),this.timeGrid.renderDates(),this.bottomRuleEl=a('
').appendTo(this.timeGrid.el),this.dayGrid&&(this.dayGrid.setElement(this.el.find(".fc-day-grid")),this.dayGrid.renderDates(),this.dayGrid.bottomCoordPadding=this.dayGrid.el.next("hr").outerHeight()),this.noScrollRowEls=this.el.find(".fc-row:not(.fc-scroller *)")},unrenderDates:function(){this.timeGrid.unrenderDates(),this.timeGrid.removeElement(),this.dayGrid&&(this.dayGrid.unrenderDates(),this.dayGrid.removeElement())},renderBusinessHours:function(){this.timeGrid.renderBusinessHours(),this.dayGrid&&this.dayGrid.renderBusinessHours()},renderHtml:function(){return'
'+this.timeGrid.headHtml()+'
'+(this.dayGrid?'

':"")+'
'},headIntroHtml:function(){var a,b;return this.opt("weekNumbers")?(a=this.timeGrid.getCell(0).start,b=a.format(this.opt("smallWeekFormat")),'"+Y(b)+""):'"},dayIntroHtml:function(){return'"+(this.opt("allDayHtml")||Y(this.opt("allDayText")))+""},slotBgIntroHtml:function(){return'"; +},introHtml:function(){return'"},axisStyleAttr:function(){return null!==this.axisWidth?'style="width:'+this.axisWidth+'px"':""},updateSize:function(a){this.timeGrid.updateSize(a),mb.prototype.updateSize.call(this,a)},updateWidth:function(){this.axisWidth=k(this.el.find(".fc-axis"))},setHeight:function(a,b){var c,d;null===this.bottomRuleHeight&&(this.bottomRuleHeight=this.bottomRuleEl.outerHeight()),this.bottomRuleEl.hide(),this.scrollerEl.css("overflow",""),m(this.scrollerEl),f(this.noScrollRowEls),this.dayGrid&&(this.dayGrid.removeSegPopover(),c=this.opt("eventLimit"),c&&"number"!=typeof c&&(c=xb),c&&this.dayGrid.limitRows(c)),b||(d=this.computeScrollerHeight(a),l(this.scrollerEl,d)?(e(this.noScrollRowEls,r(this.scrollerEl)),d=this.computeScrollerHeight(a),this.scrollerEl.height(d)):(this.scrollerEl.height(d).css("overflow","hidden"),this.bottomRuleEl.show()))},computeInitialScroll:function(){var a=b.duration(this.opt("scrollTime")),c=this.timeGrid.computeTimeTop(a);return c=Math.ceil(c),c&&c++,c},renderEvents:function(a){var b,c,d=[],e=[],f=[];for(c=0;c 1) { + attributes = extend({ + path: '/' + }, api.defaults, attributes); + + if (typeof attributes.expires === 'number') { + var expires = new Date(); + expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5); + attributes.expires = expires; + } + + try { + result = JSON.stringify(value); + if (/^[\{\[]/.test(result)) { + value = result; + } + } catch (e) {} + + value = encodeURIComponent(String(value)); + value = value.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent); + + key = encodeURIComponent(String(key)); + key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent); + key = key.replace(/[\(\)]/g, escape); + + return (document.cookie = [ + key, '=', value, + attributes.expires && '; expires=' + attributes.expires.toUTCString(), // use expires attribute, max-age is not supported by IE + attributes.path && '; path=' + attributes.path, + attributes.domain && '; domain=' + attributes.domain, + attributes.secure ? '; secure' : '' + ].join('')); + } + + // Read + + if (!key) { + result = {}; + } + + // To prevent the for loop in the first place assign an empty array + // in case there are no cookies at all. Also prevents odd result when + // calling "get()" + var cookies = document.cookie ? document.cookie.split('; ') : []; + var rdecode = /(%[0-9A-Z]{2})+/g; + var i = 0; + + for (; i < cookies.length; i++) { + var parts = cookies[i].split('='); + var name = parts[0].replace(rdecode, decodeURIComponent); + var cookie = parts.slice(1).join('='); + + if (cookie.charAt(0) === '"') { + cookie = cookie.slice(1, -1); + } + + try { + cookie = converter && converter(cookie, name) || cookie.replace(rdecode, decodeURIComponent); + + if (this.json) { + try { + cookie = JSON.parse(cookie); + } catch (e) {} + } + + if (key === name) { + result = cookie; + break; + } + + if (!key) { + result[name] = cookie; + } + } catch (e) {} + } + + return result; + } + + api.get = api.set = api; + api.getJSON = function () { + return api.apply({ + json: true + }, [].slice.call(arguments)); + }; + api.defaults = {}; + + api.remove = function (key, attributes) { + api(key, '', extend(attributes, { + expires: -1 + })); + }; + + api.withConverter = init; + + return api; + } + + return init(); +})); diff --git a/website/events/static/events/js/moment.js b/website/events/static/events/js/moment.js new file mode 100644 index 0000000000000000000000000000000000000000..c10f5dd4cb178152f7e46e4b77508e60d9df7f5d --- /dev/null +++ b/website/events/static/events/js/moment.js @@ -0,0 +1,7 @@ +//! moment.js +//! version : 2.10.2 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com +!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return Ac.apply(null,arguments)}function b(a){Ac=a}function c(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function d(a){return"[object Array]"===Object.prototype.toString.call(a)}function e(a){return"[object Date]"===Object.prototype.toString.call(a)||a instanceof Date}function f(a,b){var c,d=[];for(c=0;c0)for(c in Cc)d=Cc[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function m(b){l(this,b),this._d=new Date(+b._d),Dc===!1&&(Dc=!0,a.updateOffset(this),Dc=!1)}function n(a){return a instanceof m||null!=a&&g(a,"_isAMomentObject")}function o(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function p(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&o(a[d])!==o(b[d]))&&g++;return g+f}function q(){}function r(a){return a?a.toLowerCase().replace("_","-"):a}function s(a){for(var b,c,d,e,f=0;f0;){if(d=t(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&p(e,c,!0)>=b-1)break;b--}f++}return null}function t(a){var b=null;if(!Ec[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=Bc._abbr,require("./locale/"+a),u(b)}catch(c){}return Ec[a]}function u(a,b){var c;return a&&(c="undefined"==typeof b?w(a):v(a,b),c&&(Bc=c)),Bc._abbr}function v(a,b){return null!==b?(b.abbr=a,Ec[a]||(Ec[a]=new q),Ec[a].set(b),u(a),Ec[a]):(delete Ec[a],null)}function w(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Bc;if(!d(a)){if(b=t(a))return b;a=[a]}return s(a)}function x(a,b){var c=a.toLowerCase();Fc[c]=Fc[c+"s"]=Fc[b]=a}function y(a){return"string"==typeof a?Fc[a]||Fc[a.toLowerCase()]:void 0}function z(a){var b,c,d={};for(c in a)g(a,c)&&(b=y(c),b&&(d[b]=a[c]));return d}function A(b,c){return function(d){return null!=d?(C(this,b,d),a.updateOffset(this,c),this):B(this,b)}}function B(a,b){return a._d["get"+(a._isUTC?"UTC":"")+b]()}function C(a,b,c){return a._d["set"+(a._isUTC?"UTC":"")+b](c)}function D(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else if(a=y(a),"function"==typeof this[a])return this[a](b);return this}function E(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.lengthb;b++)d[b]=Jc[d[b]]?Jc[d[b]]:G(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function I(a,b){return a.isValid()?(b=J(b,a.localeData()),Ic[b]||(Ic[b]=H(b)),Ic[b](a)):a.localeData().invalidDate()}function J(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Hc.lastIndex=0;d>=0&&Hc.test(a);)a=a.replace(Hc,c),Hc.lastIndex=0,d-=1;return a}function K(a,b,c){Yc[a]="function"==typeof b?b:function(a){return a&&c?c:b}}function L(a,b){return g(Yc,a)?Yc[a](b._strict,b._locale):new RegExp(M(a))}function M(a){return a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function N(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=o(a)}),c=0;cd;d++){if(e=i([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}function U(a,b){var c;return"string"==typeof b&&(b=a.localeData().monthsParse(b),"number"!=typeof b)?a:(c=Math.min(a.date(),Q(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a)}function V(b){return null!=b?(U(this,b),a.updateOffset(this,!0),this):B(this,"Month")}function W(){return Q(this.year(),this.month())}function X(a){var b,c=a._a;return c&&-2===a._pf.overflow&&(b=c[_c]<0||c[_c]>11?_c:c[ad]<1||c[ad]>Q(c[$c],c[_c])?ad:c[bd]<0||c[bd]>24||24===c[bd]&&(0!==c[cd]||0!==c[dd]||0!==c[ed])?bd:c[cd]<0||c[cd]>59?cd:c[dd]<0||c[dd]>59?dd:c[ed]<0||c[ed]>999?ed:-1,a._pf._overflowDayOfYear&&($c>b||b>ad)&&(b=ad),a._pf.overflow=b),a}function Y(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function Z(a,b){var c=!0;return h(function(){return c&&(Y(a),c=!1),b.apply(this,arguments)},b)}function $(a,b){hd[a]||(Y(b),hd[a]=!0)}function _(a){var b,c,d=a._i,e=id.exec(d);if(e){for(a._pf.iso=!0,b=0,c=jd.length;c>b;b++)if(jd[b][1].exec(d)){a._f=jd[b][0]+(e[6]||" ");break}for(b=0,c=kd.length;c>b;b++)if(kd[b][1].exec(d)){a._f+=kd[b][0];break}d.match(Vc)&&(a._f+="Z"),sa(a)}else a._isValid=!1}function aa(b){var c=ld.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(_(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}function ba(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function ca(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function da(a){return ea(a)?366:365}function ea(a){return a%4===0&&a%100!==0||a%400===0}function fa(){return ea(this.year())}function ga(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=za(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function ha(a){return ga(a,this._week.dow,this._week.doy).week}function ia(){return this._week.dow}function ja(){return this._week.doy}function ka(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function la(a){var b=ga(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function ma(a,b,c,d,e){var f,g,h=ca(a,0,1).getUTCDay();return h=0===h?7:h,c=null!=c?c:e,f=e-h+(h>d?7:0)-(e>h?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:da(a-1)+g}}function na(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function oa(a,b,c){return null!=a?a:null!=b?b:c}function pa(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function qa(a){var b,c,d,e,f=[];if(!a._d){for(d=pa(a),a._w&&null==a._a[ad]&&null==a._a[_c]&&ra(a),a._dayOfYear&&(e=oa(a._a[$c],d[$c]),a._dayOfYear>da(e)&&(a._pf._overflowDayOfYear=!0),c=ca(e,0,a._dayOfYear),a._a[_c]=c.getUTCMonth(),a._a[ad]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;7>b;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[bd]&&0===a._a[cd]&&0===a._a[dd]&&0===a._a[ed]&&(a._nextDay=!0,a._a[bd]=0),a._d=(a._useUTC?ca:ba).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[bd]=24)}}function ra(a){var b,c,d,e,f,g,h;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=oa(b.GG,a._a[$c],ga(za(),1,4).year),d=oa(b.W,1),e=oa(b.E,1)):(f=a._locale._week.dow,g=a._locale._week.doy,c=oa(b.gg,a._a[$c],ga(za(),f,g).year),d=oa(b.w,1),null!=b.d?(e=b.d,f>e&&++d):e=null!=b.e?b.e+f:f),h=ma(c,d,e,g,f),a._a[$c]=h.year,a._dayOfYear=h.dayOfYear}function sa(b){if(b._f===a.ISO_8601)return void _(b);b._a=[],b._pf.empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=J(b._f,b._locale).match(Gc)||[],c=0;c0&&b._pf.unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),Jc[f]?(d?b._pf.empty=!1:b._pf.unusedTokens.push(f),P(f,d,b)):b._strict&&!d&&b._pf.unusedTokens.push(f);b._pf.charsLeftOver=i-j,h.length>0&&b._pf.unusedInput.push(h),b._pf.bigHour===!0&&b._a[bd]<=12&&(b._pf.bigHour=void 0),b._a[bd]=ta(b._locale,b._a[bd],b._meridiem),qa(b),X(b)}function ta(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function ua(a){var b,d,e,f,g;if(0===a._f.length)return a._pf.invalidFormat=!0,void(a._d=new Date(0/0));for(f=0;fg)&&(e=g,d=b));h(a,d||b)}function va(a){if(!a._d){var b=z(a._i);a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],qa(a)}}function wa(a){var b,c=a._i,e=a._f;return a._locale=a._locale||w(a._l),null===c||void 0===e&&""===c?k({nullInput:!0}):("string"==typeof c&&(a._i=c=a._locale.preparse(c)),n(c)?new m(X(c)):(d(e)?ua(a):e?sa(a):xa(a),b=new m(X(a)),b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b))}function xa(b){var c=b._i;void 0===c?b._d=new Date:e(c)?b._d=new Date(+c):"string"==typeof c?aa(b):d(c)?(b._a=f(c.slice(0),function(a){return parseInt(a,10)}),qa(b)):"object"==typeof c?va(b):"number"==typeof c?b._d=new Date(c):a.createFromInputFallback(b)}function ya(a,b,d,e,f){var g={};return"boolean"==typeof d&&(e=d,d=void 0),g._isAMomentObject=!0,g._useUTC=g._isUTC=f,g._l=d,g._i=a,g._f=b,g._strict=e,g._pf=c(),wa(g)}function za(a,b,c,d){return ya(a,b,c,d,!1)}function Aa(a,b){var c,e;if(1===b.length&&d(b[0])&&(b=b[0]),!b.length)return za();for(c=b[0],e=1;ea&&(a=-a,c="-"),c+E(~~(a/60),2)+b+E(~~a%60,2)})}function Ga(a){var b=(a||"").match(Vc)||[],c=b[b.length-1]||[],d=(c+"").match(qd)||["-",0,0],e=+(60*d[1])+o(d[2]);return"+"===d[0]?e:-e}function Ha(b,c){var d,f;return c._isUTC?(d=c.clone(),f=(n(b)||e(b)?+b:+za(b))-+d,d._d.setTime(+d._d+f),a.updateOffset(d,!1),d):za(b).local();return c._isUTC?za(b).zone(c._offset||0):za(b).local()}function Ia(a){return 15*-Math.round(a._d.getTimezoneOffset()/15)}function Ja(b,c){var d,e=this._offset||0;return null!=b?("string"==typeof b&&(b=Ga(b)),Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Ia(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?Za(this,Ua(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Ia(this)}function Ka(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function La(a){return this.utcOffset(0,a)}function Ma(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Ia(this),"m")),this}function Na(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Ga(this._i)),this}function Oa(a){return a=a?za(a).utcOffset():0,(this.utcOffset()-a)%60===0}function Pa(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Qa(){if(this._a){var a=this._isUTC?i(this._a):za(this._a);return this.isValid()&&p(this._a,a.toArray())>0}return!1}function Ra(){return!this._isUTC}function Sa(){return this._isUTC}function Ta(){return this._isUTC&&0===this._offset}function Ua(a,b){var c,d,e,f=a,h=null;return Ea(a)?f={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(f={},b?f[b]=a:f.milliseconds=a):(h=rd.exec(a))?(c="-"===h[1]?-1:1,f={y:0,d:o(h[ad])*c,h:o(h[bd])*c,m:o(h[cd])*c,s:o(h[dd])*c,ms:o(h[ed])*c}):(h=sd.exec(a))?(c="-"===h[1]?-1:1,f={y:Va(h[2],c),M:Va(h[3],c),d:Va(h[4],c),h:Va(h[5],c),m:Va(h[6],c),s:Va(h[7],c),w:Va(h[8],c)}):null==f?f={}:"object"==typeof f&&("from"in f||"to"in f)&&(e=Xa(za(f.from),za(f.to)),f={},f.ms=e.milliseconds,f.M=e.months),d=new Da(f),Ea(a)&&g(a,"_locale")&&(d._locale=a._locale),d}function Va(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function Wa(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Xa(a,b){var c;return b=Ha(b,a),a.isBefore(b)?c=Wa(a,b):(c=Wa(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c}function Ya(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||($(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Ua(c,d),Za(this,e,a),this}}function Za(b,c,d,e){var f=c._milliseconds,g=c._days,h=c._months;e=null==e?!0:e,f&&b._d.setTime(+b._d+f*d),g&&C(b,"Date",B(b,"Date")+g*d),h&&U(b,B(b,"Month")+h*d),e&&a.updateOffset(b,g||h)}function $a(a){var b=a||za(),c=Ha(b,this).startOf("day"),d=this.diff(c,"days",!0),e=-6>d?"sameElse":-1>d?"lastWeek":0>d?"lastDay":1>d?"sameDay":2>d?"nextDay":7>d?"nextWeek":"sameElse";return this.format(this.localeData().calendar(e,this,za(b)))}function _a(){return new m(this)}function ab(a,b){var c;return b=y("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=n(a)?a:za(a),+this>+a):(c=n(a)?+a:+za(a),c<+this.clone().startOf(b))}function bb(a,b){var c;return b=y("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=n(a)?a:za(a),+a>+this):(c=n(a)?+a:+za(a),+this.clone().endOf(b)a?Math.ceil(a):Math.floor(a)}function fb(a,b,c){var d,e,f=Ha(a,this),g=6e4*(f.utcOffset()-this.utcOffset());return b=y(b),"year"===b||"month"===b||"quarter"===b?(e=gb(this,f),"quarter"===b?e/=3:"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:eb(e)}function gb(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function hb(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function ib(){var a=this.clone().utc();return 0b;b++)if(this._weekdaysParse[b]||(c=za([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b}function Jb(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Eb(a,this.localeData()),this.add(a-b,"d")):b}function Kb(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Lb(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)}function Mb(a,b){F(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function Nb(a,b){return b._meridiemParse}function Ob(a){return"p"===(a+"").toLowerCase().charAt(0)}function Pb(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Qb(a){F(0,[a,3],0,"millisecond")}function Rb(){return this._isUTC?"UTC":""}function Sb(){return this._isUTC?"Coordinated Universal Time":""}function Tb(a){return za(1e3*a)}function Ub(){return za.apply(null,arguments).parseZone()}function Vb(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.call(b,c):d}function Wb(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b}function Xb(){return this._invalidDate}function Yb(a){return this._ordinal.replace("%d",a)}function Zb(a){return a}function $b(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)}function _b(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)}function ac(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function bc(a,b,c,d){var e=w(),f=i().set(d,b);return e[c](f,a)}function cc(a,b,c,d,e){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return bc(a,b,c,e);var f,g=[];for(f=0;d>f;f++)g[f]=bc(a,f,c,e);return g}function dc(a,b){return cc(a,b,"months",12,"month")}function ec(a,b){return cc(a,b,"monthsShort",12,"month")}function fc(a,b){return cc(a,b,"weekdays",7,"day")}function gc(a,b){return cc(a,b,"weekdaysShort",7,"day")}function hc(a,b){return cc(a,b,"weekdaysMin",7,"day")}function ic(){var a=this._data;return this._milliseconds=Od(this._milliseconds),this._days=Od(this._days),this._months=Od(this._months),a.milliseconds=Od(a.milliseconds),a.seconds=Od(a.seconds),a.minutes=Od(a.minutes),a.hours=Od(a.hours),a.months=Od(a.months),a.years=Od(a.years),this}function jc(a,b,c,d){var e=Ua(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function kc(a,b){return jc(this,a,b,1)}function lc(a,b){return jc(this,a,b,-1)}function mc(){var a,b,c,d=this._milliseconds,e=this._days,f=this._months,g=this._data,h=0;return g.milliseconds=d%1e3,a=eb(d/1e3),g.seconds=a%60,b=eb(a/60),g.minutes=b%60,c=eb(b/60),g.hours=c%24,e+=eb(c/24),h=eb(nc(e)),e-=eb(oc(h)),f+=eb(e/30),e%=30,h+=eb(f/12),f%=12,g.days=e,g.months=f,g.years=h,this}function nc(a){return 400*a/146097}function oc(a){return 146097*a/400}function pc(a){var b,c,d=this._milliseconds;if(a=y(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+12*nc(b),"month"===a?c:c/12;switch(b=this._days+Math.round(oc(this._months/12)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 24*b*60+d/6e4;case"second":return 24*b*60*60+d/1e3;case"millisecond":return Math.floor(24*b*60*60*1e3)+d;default:throw new Error("Unknown unit "+a)}}function qc(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*o(this._months/12)}function rc(a){return function(){return this.as(a)}}function sc(a){return a=y(a),this[a+"s"]()}function tc(a){return function(){return this._data[a]}}function uc(){return eb(this.days()/7)}function vc(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function wc(a,b,c){var d=Ua(a).abs(),e=ce(d.as("s")),f=ce(d.as("m")),g=ce(d.as("h")),h=ce(d.as("d")),i=ce(d.as("M")),j=ce(d.as("y")),k=e0,k[4]=c,vc.apply(null,k)}function xc(a,b){return void 0===de[a]?!1:void 0===b?de[a]:(de[a]=b,!0)}function yc(a){var b=this.localeData(),c=wc(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function zc(){var a=ee(this.years()),b=ee(this.months()),c=ee(this.days()),d=ee(this.hours()),e=ee(this.minutes()),f=ee(this.seconds()+this.milliseconds()/1e3),g=this.asSeconds();return g?(0>g?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"}var Ac,Bc,Cc=a.momentProperties=[],Dc=!1,Ec={},Fc={},Gc=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g,Hc=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Ic={},Jc={},Kc=/\d/,Lc=/\d\d/,Mc=/\d{3}/,Nc=/\d{4}/,Oc=/[+-]?\d{6}/,Pc=/\d\d?/,Qc=/\d{1,3}/,Rc=/\d{1,4}/,Sc=/[+-]?\d{1,6}/,Tc=/\d+/,Uc=/[+-]?\d+/,Vc=/Z|[+-]\d\d:?\d\d/gi,Wc=/[+-]?\d+(\.\d{1,3})?/,Xc=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Yc={},Zc={},$c=0,_c=1,ad=2,bd=3,cd=4,dd=5,ed=6;F("M",["MM",2],"Mo",function(){return this.month()+1}),F("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),F("MMMM",0,0,function(a){return this.localeData().months(this,a)}),x("month","M"),K("M",Pc),K("MM",Pc,Lc),K("MMM",Xc),K("MMMM",Xc),N(["M","MM"],function(a,b){b[_c]=o(a)-1}),N(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[_c]=e:c._pf.invalidMonth=a});var fd="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),gd="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),hd={};a.suppressDeprecationWarnings=!1;var id=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,jd=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],kd=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],ld=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=Z("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),F(0,["YY",2],0,function(){return this.year()%100}),F(0,["YYYY",4],0,"year"),F(0,["YYYYY",5],0,"year"),F(0,["YYYYYY",6,!0],0,"year"),x("year","y"),K("Y",Uc),K("YY",Pc,Lc),K("YYYY",Rc,Nc),K("YYYYY",Sc,Oc),K("YYYYYY",Sc,Oc),N(["YYYY","YYYYY","YYYYYY"],$c),N("YY",function(b,c){c[$c]=a.parseTwoDigitYear(b)}),a.parseTwoDigitYear=function(a){return o(a)+(o(a)>68?1900:2e3)};var md=A("FullYear",!1);F("w",["ww",2],"wo","week"),F("W",["WW",2],"Wo","isoWeek"),x("week","w"),x("isoWeek","W"),K("w",Pc),K("ww",Pc,Lc),K("W",Pc),K("WW",Pc,Lc),O(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=o(a)});var nd={dow:0,doy:6};F("DDD",["DDDD",3],"DDDo","dayOfYear"),x("dayOfYear","DDD"),K("DDD",Qc),K("DDDD",Mc),N(["DDD","DDDD"],function(a,b,c){c._dayOfYear=o(a)}),a.ISO_8601=function(){};var od=Z("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var a=za.apply(null,arguments);return this>a?this:a}),pd=Z("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var a=za.apply(null,arguments);return a>this?this:a});Fa("Z",":"),Fa("ZZ",""),K("Z",Vc),K("ZZ",Vc),N(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ga(a)});var qd=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var rd=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,sd=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Ua.fn=Da.prototype;var td=Ya(1,"add"),ud=Ya(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var vd=Z("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});F(0,["gg",2],0,function(){return this.weekYear()%100}),F(0,["GG",2],0,function(){return this.isoWeekYear()%100}),xb("gggg","weekYear"),xb("ggggg","weekYear"),xb("GGGG","isoWeekYear"),xb("GGGGG","isoWeekYear"),x("weekYear","gg"),x("isoWeekYear","GG"),K("G",Uc),K("g",Uc),K("GG",Pc,Lc),K("gg",Pc,Lc),K("GGGG",Rc,Nc),K("gggg",Rc,Nc),K("GGGGG",Sc,Oc),K("ggggg",Sc,Oc),O(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=o(a)}),O(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),F("Q",0,0,"quarter"),x("quarter","Q"),K("Q",Kc),N("Q",function(a,b){b[_c]=3*(o(a)-1)}),F("D",["DD",2],"Do","date"),x("date","D"),K("D",Pc),K("DD",Pc,Lc),K("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),N(["D","DD"],ad),N("Do",function(a,b){b[ad]=o(a.match(Pc)[0],10)});var wd=A("Date",!0);F("d",0,"do","day"),F("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),F("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),F("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),F("e",0,0,"weekday"),F("E",0,0,"isoWeekday"),x("day","d"),x("weekday","e"),x("isoWeekday","E"),K("d",Pc),K("e",Pc),K("E",Pc),K("dd",Xc),K("ddd",Xc),K("dddd",Xc),O(["dd","ddd","dddd"],function(a,b,c){var d=c._locale.weekdaysParse(a);null!=d?b.d=d:c._pf.invalidWeekday=a}),O(["d","e","E"],function(a,b,c,d){b[d]=o(a)});var xd="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),yd="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),zd="Su_Mo_Tu_We_Th_Fr_Sa".split("_");F("H",["HH",2],0,"hour"),F("h",["hh",2],0,function(){return this.hours()%12||12}),Mb("a",!0),Mb("A",!1),x("hour","h"),K("a",Nb),K("A",Nb),K("H",Pc),K("h",Pc),K("HH",Pc,Lc),K("hh",Pc,Lc),N(["H","HH"],bd),N(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),N(["h","hh"],function(a,b,c){b[bd]=o(a),c._pf.bigHour=!0});var Ad=/[ap]\.?m?\.?/i,Bd=A("Hours",!0);F("m",["mm",2],0,"minute"),x("minute","m"),K("m",Pc),K("mm",Pc,Lc),N(["m","mm"],cd);var Cd=A("Minutes",!1);F("s",["ss",2],0,"second"),x("second","s"),K("s",Pc),K("ss",Pc,Lc),N(["s","ss"],dd);var Dd=A("Seconds",!1);F("S",0,0,function(){return~~(this.millisecond()/100)}),F(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),Qb("SSS"),Qb("SSSS"),x("millisecond","ms"),K("S",Qc,Kc),K("SS",Qc,Lc),K("SSS",Qc,Mc),K("SSSS",Tc),N(["S","SS","SSS","SSSS"],function(a,b){b[ed]=o(1e3*("0."+a))});var Ed=A("Milliseconds",!1);F("z",0,0,"zoneAbbr"),F("zz",0,0,"zoneName");var Fd=m.prototype;Fd.add=td,Fd.calendar=$a,Fd.clone=_a,Fd.diff=fb,Fd.endOf=pb,Fd.format=jb,Fd.from=kb,Fd.fromNow=lb,Fd.get=D,Fd.invalidAt=wb,Fd.isAfter=ab,Fd.isBefore=bb,Fd.isBetween=cb,Fd.isSame=db,Fd.isValid=ub,Fd.lang=vd,Fd.locale=mb,Fd.localeData=nb,Fd.max=pd,Fd.min=od,Fd.parsingFlags=vb,Fd.set=D,Fd.startOf=ob,Fd.subtract=ud,Fd.toArray=tb,Fd.toDate=sb,Fd.toISOString=ib,Fd.toJSON=ib,Fd.toString=hb,Fd.unix=rb,Fd.valueOf=qb,Fd.year=md,Fd.isLeapYear=fa,Fd.weekYear=zb,Fd.isoWeekYear=Ab,Fd.quarter=Fd.quarters=Db,Fd.month=V,Fd.daysInMonth=W,Fd.week=Fd.weeks=ka,Fd.isoWeek=Fd.isoWeeks=la,Fd.weeksInYear=Cb,Fd.isoWeeksInYear=Bb,Fd.date=wd,Fd.day=Fd.days=Jb,Fd.weekday=Kb,Fd.isoWeekday=Lb,Fd.dayOfYear=na,Fd.hour=Fd.hours=Bd,Fd.minute=Fd.minutes=Cd,Fd.second=Fd.seconds=Dd,Fd.millisecond=Fd.milliseconds=Ed,Fd.utcOffset=Ja,Fd.utc=La,Fd.local=Ma,Fd.parseZone=Na,Fd.hasAlignedHourOffset=Oa,Fd.isDST=Pa,Fd.isDSTShifted=Qa,Fd.isLocal=Ra,Fd.isUtcOffset=Sa,Fd.isUtc=Ta,Fd.isUTC=Ta,Fd.zoneAbbr=Rb,Fd.zoneName=Sb,Fd.dates=Z("dates accessor is deprecated. Use date instead.",wd),Fd.months=Z("months accessor is deprecated. Use month instead",V),Fd.years=Z("years accessor is deprecated. Use year instead",md),Fd.zone=Z("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",Ka);var Gd=Fd,Hd={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Id={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY LT",LLLL:"dddd, MMMM D, YYYY LT"},Jd="Invalid date",Kd="%d",Ld=/\d{1,2}/,Md={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Nd=q.prototype;Nd._calendar=Hd,Nd.calendar=Vb,Nd._longDateFormat=Id,Nd.longDateFormat=Wb,Nd._invalidDate=Jd,Nd.invalidDate=Xb,Nd._ordinal=Kd,Nd.ordinal=Yb,Nd._ordinalParse=Ld, + Nd.preparse=Zb,Nd.postformat=Zb,Nd._relativeTime=Md,Nd.relativeTime=$b,Nd.pastFuture=_b,Nd.set=ac,Nd.months=R,Nd._months=fd,Nd.monthsShort=S,Nd._monthsShort=gd,Nd.monthsParse=T,Nd.week=ha,Nd._week=nd,Nd.firstDayOfYear=ja,Nd.firstDayOfWeek=ia,Nd.weekdays=Fb,Nd._weekdays=xd,Nd.weekdaysMin=Hb,Nd._weekdaysMin=zd,Nd.weekdaysShort=Gb,Nd._weekdaysShort=yd,Nd.weekdaysParse=Ib,Nd.isPM=Ob,Nd._meridiemParse=Ad,Nd.meridiem=Pb,u("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===o(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=Z("moment.lang is deprecated. Use moment.locale instead.",u),a.langData=Z("moment.langData is deprecated. Use moment.localeData instead.",w);var Od=Math.abs,Pd=rc("ms"),Qd=rc("s"),Rd=rc("m"),Sd=rc("h"),Td=rc("d"),Ud=rc("w"),Vd=rc("M"),Wd=rc("y"),Xd=tc("milliseconds"),Yd=tc("seconds"),Zd=tc("minutes"),$d=tc("hours"),_d=tc("days"),ae=tc("months"),be=tc("years"),ce=Math.round,de={s:45,m:45,h:22,d:26,M:11},ee=Math.abs,fe=Da.prototype;fe.abs=ic,fe.add=kc,fe.subtract=lc,fe.as=pc,fe.asMilliseconds=Pd,fe.asSeconds=Qd,fe.asMinutes=Rd,fe.asHours=Sd,fe.asDays=Td,fe.asWeeks=Ud,fe.asMonths=Vd,fe.asYears=Wd,fe.valueOf=qc,fe._bubble=mc,fe.get=sc,fe.milliseconds=Xd,fe.seconds=Yd,fe.minutes=Zd,fe.hours=$d,fe.days=_d,fe.weeks=uc,fe.months=ae,fe.years=be,fe.humanize=yc,fe.toISOString=zc,fe.toString=zc,fe.toJSON=zc,fe.locale=mb,fe.localeData=nb,fe.toIsoString=Z("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",zc),fe.lang=vd,F("X",0,0,"unix"),F("x",0,0,"valueOf"),K("x",Uc),K("X",Wc),N("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),N("x",function(a,b,c){c._d=new Date(o(a))}),a.version="2.10.2",b(za),a.fn=Gd,a.min=Ba,a.max=Ca,a.utc=i,a.unix=Tb,a.months=dc,a.isDate=e,a.locale=u,a.invalid=k,a.duration=Ua,a.isMoment=n,a.weekdays=fc,a.parseZone=Ub,a.localeData=w,a.isDuration=Ea,a.monthsShort=ec,a.weekdaysMin=hc,a.defineLocale=v,a.weekdaysShort=gc,a.normalizeUnits=y,a.relativeTimeThreshold=xc;var ge=a;return ge}); \ No newline at end of file diff --git a/website/events/templates/events/admin/registrations_table.html b/website/events/templates/events/admin/registrations_table.html index 7dced333090b123cf65d88c89ab3092d0a5f2d50..feb1dcdbcc019b1bc9c2a3430e9982ee437cb29f 100644 --- a/website/events/templates/events/admin/registrations_table.html +++ b/website/events/templates/events/admin/registrations_table.html @@ -10,10 +10,14 @@ {% endfor %} {% trans "present"|capfirst %} {% trans "paid"|capfirst %} + {% if registrations|length > 0 and registrations.0.date_cancelled is not None %} + {% trans "late"|capfirst %} + {% endif %} {% if addlink != 0 %} - {% trans "add"|capfirst %} + {% trans "add"|capfirst %} {% endif %} + @@ -36,6 +40,9 @@ {% endfor %} {{ registration.present|yesno }} {{ registration.paid|yesno }} + {% if registration.date_cancelled is not None %} + {{ registration.is_late_cancellation|yesno }} + {% endif %} {% trans "change" %} {% empty %} diff --git a/website/events/templates/events/cards.html b/website/events/templates/events/cards.html new file mode 100644 index 0000000000000000000000000000000000000000..7dfb8fec1149e701e7c0224f3a4b3326f039c34d --- /dev/null +++ b/website/events/templates/events/cards.html @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/website/events/templates/events/event.html b/website/events/templates/events/event.html new file mode 100644 index 0000000000000000000000000000000000000000..01fd0f0c068e75b720a1a6ed0ed0afdffb50cdee --- /dev/null +++ b/website/events/templates/events/event.html @@ -0,0 +1,218 @@ +{% extends "base.html" %} +{% load i18n static %} + +{% block title %}{{ event.title }} — {% trans "Calendar"|capfirst %} — {{ block.super }}{% endblock %} + +{% block body %} +

{{ event.title }}

+

{{ event.description }}

+ + {% if messages %} + {% for message in messages %} +
+ {{ message }} + +
+ {% endfor %} + {% endif %} + +
+
+ + + + + + + + + + + + + + + {% if event.price > 0 %} + + + + + {% endif %} + {% if event.registration_required %} + + + + + + + + + + + + + {% if registration %} + + + + + {% endif %} + {% endif %} + + + + + + + + + + {#{% if event.pizzaevent %}#} + {##} + {##} + {##} + {##} + {#{% endif %}#} + +
{% trans "from"|capfirst %}{{ event.start }}
{% trans "until"|capfirst %}{{ event.end }}
{% trans "location"|capfirst %}{{ event.location }}
{% trans "price"|capfirst %} €{{ event.price }}
{% trans "registration deadline"|capfirst %}{{ event.registration_end }}
{% trans "cancellation deadline"|capfirst %}{{ event.cancel_deadline }}
{% trans "number of registrations"|capfirst %} + {% blocktrans count counter=registrations|length trimmed %} + {{ counter }} registration + {% plural %} + {{ counter }} registrations + {% endblocktrans %} + {% if event.max_participants > 0 %} + ({{ event.max_participants }} {% trans "max" %}) + {% with prc=registration_percentage %} +
+
+
+ {% endwith %} + {% endif %} +
{% trans "registration status"|capfirst %} + {% if registration.is_registered and registration.queue_position == 0 %} + {% trans "You are registered" %} + {% elif registration.is_registered and registration.queue_position > 0 %} + {% blocktrans with pos=registration.queue_position trimmed %} + Waiting list position {{ pos }} + {% endblocktrans %} + {% elif not registration.is_registered and registration.is_late_cancellation %} + {% trans "Your registration is cancelled after the cancellation deadline" %} + {% else %} + {% trans "Your registration is cancelled" %} + {% endif %} +
+ {% if request.user.is_authenticated and request.user.member is not None and request.user.member.current_membership is not None %} + {% if event.status == event.REGISTRATION_OPEN or event.status == event.REGISTRATION_OPEN_NO_CANCEL %} + {% if registration is not None and registration.date_cancelled is None and event.has_fields %} + {% trans "Update registration" %} +

+ {% endif %} + {% endif %} + {% if event.status == event.REGISTRATION_OPEN or event.status == event.REGISTRATION_CLOSED_CANCEL_ONLY or event.status == event.REGISTRATION_OPEN_NO_CANCEL %} + {% if registration is None or registration.date_cancelled is not None %} + {% if event.status == event.REGISTRATION_OPEN or event.status == event.REGISTRATION_OPEN_NO_CANCEL %} + + {% if event.reached_participants_limit %} + {% trans "Put me on the waiting list" %} + {% else %} + {% trans "Register" %} + {% endif %} + + {% endif %} + {% elif registration is not None and registration.date_cancelled is None %} + {# Special message to accept costs when cancelling after the deadline, unless member is on the waiting list #} + {% if registration.queue_position == 0 and event.after_cancel_deadline %} + {% trans "Cancel registration" %} + {% else %} + {% trans "Cancel registration" %} + {% endif %} + {% endif %} + {% endif %} + {% elif request.user.is_authenticated is False %} + {% trans "Login" %} + {% endif %} +
+ + + {% if not request.user.is_authenticated %} + {% trans "You have to log in before you can register for this event." %} + {% elif event.status == event.REGISTRATION_NOT_YET_OPEN %} + {% blocktrans with datetime=event.registration_start %}Registration will open {{ datetime }}{% endblocktrans %} + {% elif event.status == event.REGISTRATION_CLOSED or event.status == event.REGISTRATION_CLOSED_CANCEL_ONLY %} + {% blocktrans %}Registration is not possible anymore.{% endblocktrans %} + {% elif status == event.REGISTRATION_NOT_NEEDED %} + {% if event.no_registration_message %} + {{ event.no_registration_message }} + {% else %} + {% trans "No registration required" %} + {% endif %} + {% endif %} + {% if event.status == event.REGISTRATION_OPEN_NO_CANCEL or event.status == event.REGISTRATION_CLOSED %} + {% if registration.date_cancelled is None and event.cost > 0 %} + {% blocktrans with costs=event.cost %}Cancellation isn't possible anymore without having to pay the full costs of €{{ costs }}. Also note that you will be unable to re-register.{% endblocktrans %} + {% endif %} + {% endif %} + +
#} + {#Pizza#} + {##} + {##} + {#{% trans "Order" %}#} + {##} + {#
+
+ +
+
+ +
+
+
+ + {% if user.is_authenticated and registrations|length > 0 %} + + {% endif %} +{% endblock body %} diff --git a/website/events/templates/events/event_fields.html b/website/events/templates/events/event_fields.html new file mode 100644 index 0000000000000000000000000000000000000000..8e2ccc0048061b8449365468542d7432127c4640 --- /dev/null +++ b/website/events/templates/events/event_fields.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} +{% load i18n static fieldtype %} + +{% block title %}{% if action == 'update' %}{% trans "Update registration" %}{% else %}{% trans "Complete registration" %}{% endif %} — {{ event.title }} — {% trans "Calendar" %} — {{ block.super }}{% endblock %} + +{% block body %} + {% if action == 'update' %} +

{% blocktrans with title=event.title %}Update registration for {{ title }}{% endblocktrans %}

+ {% else %} +

{% blocktrans with title=event.title %}Completing registration for {{ title }}{% endblocktrans %}

+ {% endif %} + +
+ {% csrf_token %} + + {% for field in form %} +
+ +
+ {{ field }} + + {% for error in field.errors %} + {{ error|escape }} + {% endfor %} + + {{ field.help_text|safe }} +
+
+ {% endfor %} + + {% if action == 'update' %} + + {% else %} + + {% endif %} + {% trans 'Cancel' %} +
+ +{% endblock %} \ No newline at end of file diff --git a/website/events/templates/events/index.html b/website/events/templates/events/index.html new file mode 100644 index 0000000000000000000000000000000000000000..9dbce6bd6bc81e0191ffc9812b5ac371d5efe36b --- /dev/null +++ b/website/events/templates/events/index.html @@ -0,0 +1,109 @@ +{% extends "base.html" %} +{% load i18n static compress %}} +{% get_current_language as LANGUAGE_CODE %} + +{% block title %}{% trans "Calendar"|capfirst %} — {{ block.super }}{% endblock %} + +{% block css_head %} + {{ block.super }} + {% compress css %} + + + {% endcompress %} +{% endblock %} + +{% block body %} +

+ {% trans "Calendar" %} + + + + + + + +

+ +
+ + +{% endblock body %} + +{% block js_body %} + {{ block.super }} + + + + + +{% endblock js_body %} \ No newline at end of file diff --git a/website/events/templatetags/event_cards.py b/website/events/templatetags/event_cards.py new file mode 100644 index 0000000000000000000000000000000000000000..d58917a088cb120c55af9ad4b9041839221d4d17 --- /dev/null +++ b/website/events/templatetags/event_cards.py @@ -0,0 +1,15 @@ +from django import template +from django.utils import timezone + +from events.models import Event + +register = template.Library() + + +@register.inclusion_tag('events/cards.html') +def show_cards(): + upcoming_events = Event.objects.filter( + published=True, + end__gte=timezone.now() + ).order_by('end') + return {'events': upcoming_events[:4]} diff --git a/website/events/urls.py b/website/events/urls.py index 100e0c906346a1ab4d5ad01aa35a9db4f13576ab..0fb667d5d896ff7704e124e76f6cdbce06d4bb7e 100644 --- a/website/events/urls.py +++ b/website/events/urls.py @@ -4,9 +4,16 @@ Events URL Configuration from django.conf.urls import url +from events.feeds import EventFeed from . import views urlpatterns = [ url(r'admin/(?P\d+)/$', views.admin_details, name='admin-details'), url(r'admin/(?P\d+)/export/$', views.export, name='export'), + url(r'^(?P\d+)/$', views.event, name='event'), + url(r'^(?P\d+)/registration/(?P[-\w]+)/$', + views.registration, name='registration'), + url(r'^$', views.index, name='index'), + url(r'^ical/nl.ics', EventFeed(lang='nl'), name='ical-nl'), + url(r'^ical/en.ics', EventFeed(), name='ical-en'), ] diff --git a/website/events/views.py b/website/events/views.py index dc8cafd48b12e309b5cfadad348ca0139a257eae..4aa374e26a28c14fa000ac7db04452e096c41fe4 100644 --- a/website/events/views.py +++ b/website/events/views.py @@ -2,13 +2,16 @@ import csv from datetime import timedelta from django.http import HttpResponse -from django.shortcuts import render, get_object_or_404 +from django.shortcuts import render, get_object_or_404, redirect +from django.contrib import messages from django.contrib.admin.views.decorators import staff_member_required -from django.contrib.auth.decorators import permission_required +from django.contrib.auth.decorators import permission_required, login_required from django.utils import timezone from django.utils.text import slugify +from django.utils.translation import ugettext_lazy as _ -from .models import Event +from .models import Event, Registration +from .forms import FieldsForm @staff_member_required @@ -79,9 +82,136 @@ def export(request, event_id): return item['date'] - timedelta(days=10000) else: return item['date'] + for row in sorted(rows, key=order): writer.writerow(row) response['Content-Disposition'] = ( 'attachment; filename="{}.csv"'.format(slugify(event.title))) return response + + +def index(request): + upcoming_activity = Event.objects.filter( + published=True, + end__gte=timezone.now() + ).order_by('end').first() + + return render(request, 'events/index.html', { + 'upcoming_activity': upcoming_activity + }) + + +def event(request, event_id): + event = get_object_or_404( + Event.objects.filter(published=True), + pk=event_id + ) + registrations = event.registration_set.filter( + date_cancelled=None)[:event.max_participants] + + context = { + 'event': event, + 'registrations': registrations, + 'user': request.user, + } + + if event.max_participants: + perc = 100.0 * len(registrations) / event.max_participants + context['registration_percentage'] = perc + + try: + registration = Registration.objects.get( + event=event, + member=request.user.member + ) + context['registration'] = registration + except Registration.DoesNotExist: + pass + + return render(request, 'events/event.html', context) + + +@login_required +def registration(request, event_id, action=None): + event = get_object_or_404( + Event.objects.filter(published=True), + pk=event_id + ) + + if (event.status != Event.REGISTRATION_NOT_NEEDED and + request.user.member.current_membership is not None): + try: + obj = Registration.objects.get( + event=event, + member=request.user.member + ) + except Registration.DoesNotExist: + obj = None + + success_message = None + error_message = None + show_fields = False + if action == 'register' and ( + event.status == Event.REGISTRATION_OPEN or + event.status == Event.REGISTRATION_OPEN_NO_CANCEL + ): + if event.has_fields(): + show_fields = True + + if obj is None: + obj = Registration() + obj.event = event + obj.member = request.user.member + elif obj.date_cancelled is not None: + if obj.is_late_cancellation(): + error_message = _("You cannot re-register anymore since " + "you've cancelled after the deadline.") + else: + obj.date = timezone.now() + obj.date_cancelled = None + else: + error_message = _("You were already registered.") + + if error_message is None: + success_message = _("Registration successful.") + elif (action == 'update' + and event.has_fields() + and obj is not None + and (event.status == Event.REGISTRATION_OPEN or + event.status == Event.REGISTRATION_OPEN_NO_CANCEL)): + show_fields = True + success_message = _("Registration successfully updated.") + elif action == 'cancel': + if (obj is not None and + obj.date_cancelled is None): + # Note that this doesn't remove the values for the + # information fields that the user entered upon registering. + # But this is regarded as a feature, not a bug. Especially + # since the values will still appear in the backend. + obj.date_cancelled = timezone.now() + success_message = _("Registration successfully cancelled.") + else: + error_message = _("You were not registered for this event.") + + if show_fields: + if request.POST: + form = FieldsForm(request.POST, registration=obj) + if form.is_valid(): + obj.save() + form_field_values = form.field_values() + for field in form_field_values: + field['field'].set_value_for(obj, + field['value']) + else: + form = FieldsForm(registration=obj) + context = {'event': event, 'form': form, 'action': action} + return render(request, 'events/event_fields.html', context) + + if success_message is not None: + messages.success(request, success_message) + elif error_message is not None: + messages.error(request, error_message) + obj.save() + + return redirect(event) diff --git a/website/partners/admin.py b/website/partners/admin.py index ec76aae12aed1188f817921f259b26b4180a8152..af83107b65aad90c392b6cd9ce617c5ad25098e6 100644 --- a/website/partners/admin.py +++ b/website/partners/admin.py @@ -7,6 +7,7 @@ from partners.models import ( PartnerImage, VacancyCategory, Vacancy, + PartnerEvent ) @@ -58,3 +59,12 @@ class VacancyAdmin(admin.ModelAdmin): 'fields': ('categories', ) }), ) + + +@admin.register(PartnerEvent) +class PartnerEventAdmin(TranslatedModelAdmin): + fields = ['partner', 'title', 'description', 'location', 'start', 'end', + 'url', 'published'] + list_display = ('title', 'start', 'end', + 'partner', 'published') + list_filter = ('start', 'published') diff --git a/website/partners/api/serializers.py b/website/partners/api/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..6d3d1ff49b33eccc2111b98437c5a625bb5ddf04 --- /dev/null +++ b/website/partners/api/serializers.py @@ -0,0 +1,22 @@ +from events.api.serializers import CalenderJSSerializer +from partners.models import PartnerEvent + + +class PartnerEventSerializer(CalenderJSSerializer): + class Meta(CalenderJSSerializer.Meta): + model = PartnerEvent + + def _title(self, instance): + return "{} ({})".format(instance.title, instance.partner.name) + + def _background_color(self, instance): + return '#E62272' + + def _text_color(self, instance): + return 'white' + + def _url(self, instance): + return instance.url + + def _target_blank(self, instance): + return True diff --git a/website/partners/api/urls.py b/website/partners/api/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..b5108da57cd12b412e3c686548eeeb2cd6f1aec0 --- /dev/null +++ b/website/partners/api/urls.py @@ -0,0 +1,7 @@ +from rest_framework import routers + +from partners.api import viewsets + +router = routers.SimpleRouter() +router.register(r'partners', viewsets.PartnerViewset) +urlpatterns = router.urls diff --git a/website/partners/api/viewsets.py b/website/partners/api/viewsets.py new file mode 100644 index 0000000000000000000000000000000000000000..f28370a4cf76c90d0d45b5d729b0ec06defc0017 --- /dev/null +++ b/website/partners/api/viewsets.py @@ -0,0 +1,34 @@ +from rest_framework import viewsets +from rest_framework.exceptions import ParseError +from rest_framework.response import Response +from rest_framework.decorators import list_route +from django.utils import timezone +from datetime import datetime + +from partners.api.serializers import PartnerEventSerializer +from partners.models import Partner, PartnerEvent + + +class PartnerViewset(viewsets.ViewSet): + queryset = Partner.objects.all() + + @list_route() + def events(self, request): + try: + start = timezone.make_aware( + datetime.strptime(request.query_params['start'], '%Y-%m-%d') + ) + end = timezone.make_aware( + datetime.strptime(request.query_params['end'], '%Y-%m-%d') + ) + except: + raise ParseError(detail='start or end query parameters invalid') + + queryset = PartnerEvent.objects.filter( + end__gte=start, + start__lte=end, + published=True + ) + + serializer = PartnerEventSerializer(queryset, many=True) + return Response(serializer.data) diff --git a/website/partners/migrations/0005_partnerevent.py b/website/partners/migrations/0005_partnerevent.py new file mode 100644 index 0000000000000000000000000000000000000000..4dcb32ba99904beef71d0bfdc1bb3e630a1ccea1 --- /dev/null +++ b/website/partners/migrations/0005_partnerevent.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2016-09-25 18:42 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0004_add_tinymce_to_vacancy_and_partner'), + ] + + operations = [ + migrations.CreateModel( + name='PartnerEvent', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start', models.DateTimeField(verbose_name='start time')), + ('end', models.DateTimeField(verbose_name='end time')), + ('url', models.URLField(verbose_name='website')), + ('published', models.BooleanField(default=False, verbose_name='published')), + ('location_en', models.CharField(max_length=255, verbose_name='location (EN)')), + ('location_nl', models.CharField(max_length=255, verbose_name='location (NL)')), + ('title_en', models.CharField(max_length=100, verbose_name='title (EN)')), + ('title_nl', models.CharField(max_length=100, verbose_name='title (NL)')), + ('description_en', models.TextField(verbose_name='description (EN)')), + ('description_nl', models.TextField(verbose_name='description (NL)')), + ('partner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='partners.Partner')), + ], + ), + ] diff --git a/website/partners/models.py b/website/partners/models.py index d209c1b9f9cceef1e5e1a5fead87ddde629dbbc5..d0268ba09ee239cc116ad2632fae3ffb40b0def4 100644 --- a/website/partners/models.py +++ b/website/partners/models.py @@ -1,9 +1,9 @@ -from django.db import models from django.core.validators import RegexValidator, URLValidator +from django.db import models from django.urls import reverse - -from utils.translation import MultilingualField, ModelTranslateMeta +from django.utils.translation import ugettext_lazy as _ from tinymce.models import HTMLField +from utils.translation import MultilingualField, ModelTranslateMeta class Partner(models.Model): @@ -126,3 +126,39 @@ class Vacancy(models.Model): class Meta: verbose_name_plural = 'Vacancies' + + +class PartnerEvent(models.Model, metaclass=ModelTranslateMeta): + partner = models.ForeignKey( + Partner, + on_delete=models.CASCADE, + related_name="events" + ) + + title = MultilingualField( + models.CharField, + _("title"), + max_length=100 + ) + + description = MultilingualField( + models.TextField, + _("description") + ) + + location = MultilingualField( + models.CharField, + _("location"), + max_length=255, + ) + + start = models.DateTimeField(_("start time")) + + end = models.DateTimeField(_("end time")) + + url = models.URLField(_("website")) + + published = models.BooleanField(_("published"), default=False) + + def __str__(self): + return self.title diff --git a/website/thaliawebsite/menus.py b/website/thaliawebsite/menus.py index 2e87815589016e417fba0b9a98af0368b56c9d12..8a127a335a3ebcd986c6067901c013c749e4e1ac 100644 --- a/website/thaliawebsite/menus.py +++ b/website/thaliawebsite/menus.py @@ -19,7 +19,7 @@ main = [ {'title': _('Become Active'), 'name': 'become-active'}, {'title': _('Wiki'), 'url': '/wiki/'}, ]}, - {'title': _('Calendar'), 'name': '#'}, + {'title': _('Calendar'), 'name': 'events:index'}, {'title': _('Career'), 'name': 'partners:index', 'submenu': [ {'title': _('Partners'), 'name': 'partners:index'}, {'title': _('Vacancies'), 'name': 'partners:vacancies'}, diff --git a/website/thaliawebsite/templates/base.html b/website/thaliawebsite/templates/base.html index 1ed2fcf40aae999e900dc4ca7e5e3a02abc0b931..19d4279be839ac1b739f76c27269db84cafa5b99 100644 --- a/website/thaliawebsite/templates/base.html +++ b/website/thaliawebsite/templates/base.html @@ -67,7 +67,7 @@ {% if not user.is_authenticated %} {% else %}
diff --git a/website/thaliawebsite/templates/index.html b/website/thaliawebsite/templates/index.html index d01a26fc0c44e934a550732e28623f633241f2ba..2255faff55321da56856a36b1e249cb8eecb839c 100644 --- a/website/thaliawebsite/templates/index.html +++ b/website/thaliawebsite/templates/index.html @@ -1,13 +1,16 @@ {% extends 'base.html' %} -{% block title %}Thaliawebsite{% endblock %} +{% load i18n event_cards %} {% block body %} -

Hello world

+

{% trans "Thalia, the study association of Computer Science and Information Science" %}

-

Dit is een statische placeholder. Dit werkt op dit moment: -

+

+{% blocktrans %}Thalia is the study association for the Computer Science and Information Science students at Radboud University in Nijmegen. Thalia provides you the necessary distractions during your studies, as we've been doing for the past 25 years. And via Thalia students can easily connect with teachers and students from other years.{% endblocktrans %}

+ +

{% trans "Upcoming events" %}

+ +{% show_cards %} + +

{% trans "Searching for another event?" %} {% trans "Take a look at the entire agenda" %}.

{% endblock %} diff --git a/website/thaliawebsite/urls.py b/website/thaliawebsite/urls.py index ff61fdf09a1be37fe5ca37ec08e6af11346adc3b..a5d75a3cdfc7457578a355cd3bb92cca0db9ba39 100644 --- a/website/thaliawebsite/urls.py +++ b/website/thaliawebsite/urls.py @@ -23,6 +23,7 @@ from django.contrib.sitemaps.views import sitemap from django.views.generic import TemplateView from django.views.i18n import JavaScriptCatalog +from events.feeds import DeprecationFeed from utils.views import private_thumbnails import members @@ -49,6 +50,7 @@ urlpatterns = [ url(r'^members/', include('members.urls', namespace='members')), url(r'^nyi$', TemplateView.as_view(template_name='status/nyi.html'), name='#'), url(r'^events/', include('events.urls', namespace='events')), + url(r'^index\.php/events/ical/feed\.ics', DeprecationFeed()), url(r'^newsletters/', include('newsletters.urls', namespace='newsletters')), url(r'^association$', TemplateView.as_view( @@ -74,6 +76,7 @@ urlpatterns = [ url(r'^api/', include([ url(r'^', include('events.api.urls')), url(r'^', include('members.api.urls')), + url(r'^', include('partners.api.urls')), ])), url(r'^education/', include('education.urls', namespace='education')), # Default login helpers