diff --git a/AKModel/locale/de_DE/LC_MESSAGES/django.po b/AKModel/locale/de_DE/LC_MESSAGES/django.po index 6c91a57b5bdd915de26ba250e65642e528afd773..a4ccc84d896a86a65ac8a9962449aab6710eda99 100644 --- a/AKModel/locale/de_DE/LC_MESSAGES/django.po +++ b/AKModel/locale/de_DE/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-20 17:51+0000\n" +"POT-Creation-Date: 2019-10-24 22:48+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -11,13 +11,13 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: availability.py:38 models.py:20 models.py:40 models.py:105 models.py:153 -#: models.py:184 models.py:209 +#: availability.py:38 models.py:25 models.py:47 models.py:141 models.py:190 +#: models.py:222 models.py:248 msgid "Event" msgstr "Event" -#: availability.py:39 models.py:41 models.py:106 models.py:154 models.py:185 -#: models.py:210 +#: availability.py:39 models.py:48 models.py:142 models.py:191 models.py:223 +#: models.py:249 msgid "Associated event" msgstr "Zugehöriges Event" @@ -29,7 +29,7 @@ msgstr "Person" msgid "Person whose availability this is" msgstr "Person deren Verfügbarkeit hier abgebildet wird" -#: availability.py:56 models.py:188 models.py:203 +#: availability.py:56 models.py:226 models.py:241 msgid "Room" msgstr "Raum" @@ -37,7 +37,7 @@ msgstr "Raum" msgid "Room whose availability this is" msgstr "Raum dessen Verfügbarkeit hier abgebildet wird" -#: availability.py:65 models.py:157 models.py:202 +#: availability.py:65 models.py:194 models.py:240 msgid "AK" msgstr "AK" @@ -47,7 +47,7 @@ msgstr "AK" msgid "AK whose availability this is" msgstr "Verfügbarkeiten" -#: availability.py:74 models.py:63 +#: availability.py:74 models.py:99 msgid "AK Category" msgstr "AK Kategorie" @@ -63,334 +63,354 @@ msgstr "Verfügbarkeit" msgid "Availabilities" msgstr "Verfügbarkeiten" -#: models.py:9 models.py:58 models.py:74 models.py:89 models.py:103 -#: models.py:120 models.py:177 +#: models.py:12 models.py:94 models.py:110 models.py:125 models.py:139 +#: models.py:156 models.py:215 msgid "Name" msgstr "Name" -#: models.py:10 +#: models.py:13 msgid "Name or iteration of the event" msgstr "Name oder Iteration des Events" -#: models.py:11 +#: models.py:14 #, fuzzy #| msgid "Short Name" msgid "Short Form" msgstr "Kurzer Name" -#: models.py:12 +#: models.py:15 msgid "Short name of letters/numbers/dots/dashes/underscores used in URLs." msgstr "" -#: models.py:13 +#: models.py:16 msgid "Start" msgstr "Start" -#: models.py:13 +#: models.py:16 msgid "Time the event begins" msgstr "Zeit zu der das Event beginnt" -#: models.py:14 +#: models.py:17 msgid "End" msgstr "Ende" -#: models.py:14 +#: models.py:17 msgid "Time the event ends" msgstr "Zeit zu der das Event endet" -#: models.py:15 +#: models.py:18 msgid "Place" msgstr "Ort" -#: models.py:16 +#: models.py:19 msgid "City etc. the event takes place in" msgstr "Stadt o.ä. in der das Event stattfindet" -#: models.py:17 +#: models.py:20 msgid "Active State" msgstr "Aktiver Status" -#: models.py:17 +#: models.py:20 msgid "Marks currently active events" msgstr "Markiert aktuell aktive Events" -#: models.py:21 +#: models.py:22 +msgid "Base URL" +msgstr "URL-Prefix" + +#: models.py:22 +msgid "Prefix for wiki link construction" +msgstr "Prefix für die automatische Generierung von Wiki-Links" + +#: models.py:26 msgid "Events" msgstr "Events" -#: models.py:35 +#: models.py:40 msgid "Nickname" msgstr "Spitzname" -#: models.py:35 +#: models.py:40 msgid "Name to identify an AK owner by" msgstr "Name durch den eine AK Leitung identifiziert wird" -#: models.py:36 +#: models.py:41 +msgid "Slug" +msgstr "Slug" + +#: models.py:42 +msgid "Slug for URL generation" +msgstr "Slug für URL-Generierung" + +#: models.py:43 msgid "E-Mail Address" msgstr "E-Mail Adresse" -#: models.py:36 +#: models.py:43 msgid "Contact mail" msgstr "Kontakt E-Mail" -#: models.py:37 +#: models.py:44 msgid "Institution" msgstr "Instutution" -#: models.py:37 +#: models.py:44 msgid "Uni etc." msgstr "Universität o.ä." -#: models.py:38 models.py:129 +#: models.py:45 models.py:165 msgid "Web Link" msgstr "Internet Link" -#: models.py:38 +#: models.py:45 msgid "Link to Homepage" msgstr "Link zu Homepage oder Webseite" -#: models.py:44 +#: models.py:51 msgid "AK Owner" msgstr "AK Leitung" -#: models.py:45 +#: models.py:52 msgid "AK Owners" msgstr "AK Leitungen" -#: models.py:58 +#: models.py:94 msgid "Name of the AK Category" msgstr "Name des AK Kategorie" -#: models.py:59 models.py:75 +#: models.py:95 models.py:111 msgid "Color" msgstr "Farbe" -#: models.py:59 models.py:75 +#: models.py:95 models.py:111 msgid "Color for displaying" msgstr "Farbe für die Anzeige" -#: models.py:60 models.py:123 +#: models.py:96 models.py:159 msgid "Description" msgstr "Beschreibung" -#: models.py:60 +#: models.py:96 msgid "Short description of this AK Category" msgstr "Beschreibung der AK-Kategorie" -#: models.py:64 +#: models.py:100 msgid "AK Categories" msgstr "AK Kategorien" -#: models.py:74 +#: models.py:110 msgid "Name of the AK Track" msgstr "Name des AK Tracks" -#: models.py:78 +#: models.py:114 msgid "AK Track" msgstr "AK Track" -#: models.py:79 +#: models.py:115 msgid "AK Tracks" msgstr "AK Tracks" -#: models.py:89 +#: models.py:125 msgid "Name of the AK Tag" msgstr "Name das AK Tags" -#: models.py:92 +#: models.py:128 msgid "AK Tag" msgstr "AK Tag" -#: models.py:93 +#: models.py:129 msgid "AK Tags" msgstr "AK Tags" -#: models.py:103 +#: models.py:139 msgid "Name of the Requirement" msgstr "Name der Anforderung" -#: models.py:109 +#: models.py:145 msgid "AK Requirement" msgstr "AK Anforderung" -#: models.py:110 +#: models.py:146 msgid "AK Requirements" msgstr "AK Anforderungen" -#: models.py:120 +#: models.py:156 msgid "Name of the AK" msgstr "Name des AKs" -#: models.py:121 +#: models.py:157 msgid "Short Name" msgstr "Kurzer Name" -#: models.py:122 +#: models.py:158 msgid "Name displayed in the schedule" msgstr "Name zur Anzeige im AK Plan" -#: models.py:123 +#: models.py:159 msgid "Description of the AK" msgstr "Beschreibung des AKs" -#: models.py:125 +#: models.py:161 msgid "Owners" msgstr "Leitungen" -#: models.py:126 +#: models.py:162 msgid "Those organizing the AK" msgstr "Menschen, die den AK organisieren und halten" -#: models.py:129 +#: models.py:165 msgid "Link to wiki page" msgstr "Link zur Wiki Seite" -#: models.py:131 +#: models.py:167 msgid "Category" msgstr "Kategorie" -#: models.py:132 +#: models.py:168 msgid "Category of the AK" msgstr "Kategorie des AKs" -#: models.py:133 +#: models.py:169 msgid "Tags" msgstr "Tags" -#: models.py:133 +#: models.py:169 msgid "Tags provided by owners" msgstr "Tags, die durch die AK Leitung vergeben wurden" -#: models.py:134 +#: models.py:170 msgid "Track" msgstr "Track" -#: models.py:135 +#: models.py:171 msgid "Track the AK belongs to" msgstr "Track zu dem der AK gehört" -#: models.py:137 +#: models.py:173 msgid "Resolution Intention" msgstr "Resolutionsabsicht" -#: models.py:138 +#: models.py:174 msgid "Intends to submit a resolution" msgstr "Beabsichtigt eine Resolution einzureichen" -#: models.py:139 +#: models.py:175 msgid "Present this AK" msgstr "AK Präsentieren" -#: models.py:139 +#: models.py:176 msgid "Present results of this AK" msgstr "Die Ergebnisse dieses AKs vorstellen" -#: models.py:141 +#: models.py:178 msgid "Requirements" msgstr "Anforderungen" -#: models.py:142 +#: models.py:179 msgid "AK's Requirements" msgstr "Anforderungen des AKs" -#: models.py:144 +#: models.py:181 msgid "Conflicting AKs" msgstr "AK Konflikte" -#: models.py:145 +#: models.py:182 msgid "AKs that conflict and thus must not take place at the same time" msgstr "" "AKs, die Konflikte haben und deshalb nicht gleichzeitig stattfinden dürfen" -#: models.py:146 +#: models.py:183 msgid "Prerequisite AKs" msgstr "Vorausgesetzte AKs" -#: models.py:147 +#: models.py:184 msgid "AKs that should precede this AK in the schedule" msgstr "AKS die im AK Plan vor diesem AK stattfinden müssen" -#: models.py:149 +#: models.py:186 msgid "Internal Notes" msgstr "Interne Notizen" -#: models.py:149 +#: models.py:186 msgid "Notes to organizers" msgstr "Notizen an die Organisator*innen" -#: models.py:151 +#: models.py:188 msgid "Interest" msgstr "Interesse" -#: models.py:151 +#: models.py:188 msgid "Expected number of people" msgstr "Erwartete Personenzahl" -#: models.py:158 +#: models.py:195 msgid "AKs" msgstr "AKs" -#: models.py:177 +#: models.py:215 msgid "Name or number of the room" msgstr "Name oder Nummer des Raums" -#: models.py:178 +#: models.py:216 msgid "Building" msgstr "Gebäude" -#: models.py:179 +#: models.py:217 msgid "Name or number of the building" msgstr "Name oder Nummer des Gebäudes" -#: models.py:180 +#: models.py:218 msgid "Capacity" msgstr "Kapazität" -#: models.py:180 +#: models.py:218 msgid "Maximum number of people" msgstr "Maximale Personenzahl" -#: models.py:181 +#: models.py:219 msgid "Properties" msgstr "Eigenschaften" -#: models.py:182 +#: models.py:220 msgid "AK requirements fulfilled by the room" msgstr "AK Anforderungen, die dieser Raum erfüllt" -#: models.py:189 +#: models.py:227 msgid "Rooms" msgstr "Räume" -#: models.py:202 +#: models.py:240 msgid "AK being mapped" msgstr "AK, der zugeordnet wird" -#: models.py:204 +#: models.py:242 msgid "Room the AK will take place in" msgstr "Raum in dem der AK stattfindet" -#: models.py:205 +#: models.py:243 msgid "Slot Begin" msgstr "Beginn des Slots" -#: models.py:205 +#: models.py:243 msgid "Time and date the slot begins" msgstr "Zeit und Datum zu der der AK beginnt" -#: models.py:206 +#: models.py:245 msgid "Duration" msgstr "Dauer" -#: models.py:207 +#: models.py:246 msgid "Length in hours" msgstr "Länge in Stunden" -#: models.py:213 +#: models.py:252 msgid "AK Slot" msgstr "AK Slot" -#: models.py:214 +#: models.py:253 msgid "AK Slots" msgstr "AK Slot" + +#: models.py:267 +msgid "Not scheduled yet" +msgstr "Noch nicht geplant" diff --git a/AKModel/migrations/0016_slot_room_blank.py b/AKModel/migrations/0016_slot_room_blank.py new file mode 100644 index 0000000000000000000000000000000000000000..8ba204e414b6f5360e8d4ed37315437c553da51e --- /dev/null +++ b/AKModel/migrations/0016_slot_room_blank.py @@ -0,0 +1,20 @@ +# Generated by Django 2.2.6 on 2019-10-18 23:15 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('AKModel', '0015_ak_present_field'), + ] + + operations = [ + migrations.AlterField( + model_name='akslot', + name='room', + field=models.ForeignKey(blank=True, help_text='Room the AK will take place in', null=True, + on_delete=django.db.models.deletion.SET_NULL, to='AKModel.Room', + verbose_name='Room'), + ), + ] diff --git a/AKModel/migrations/0017_owner_slug.py b/AKModel/migrations/0017_owner_slug.py new file mode 100644 index 0000000000000000000000000000000000000000..c4fbb31bf88f41938b1687c80df961f64ee3a828 --- /dev/null +++ b/AKModel/migrations/0017_owner_slug.py @@ -0,0 +1,41 @@ +# Generated by Django 2.2.6 on 2019-10-19 17:47 + +from django.db import migrations, models + +from AKModel.models import AKOwner + + +def migrate_data_forward(apps, schema_editor): + for instance in AKOwner.objects.all(): + if instance.slug == '': + instance.slug = instance._generate_slug() + instance.save() # Will trigger slug update + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0016_slot_room_blank'), + ] + + operations = [ + migrations.AddField( + model_name='akowner', + name='slug', + field=models.SlugField(blank=True, help_text='Slug for URL generation', max_length=64, verbose_name='Slug'), + ), + migrations.AlterField( + model_name='akowner', + name='name', + field=models.CharField(help_text='Name to identify an AK owner by', max_length=64, verbose_name='Nickname'), + ), + migrations.RunPython( + migrate_data_forward, + migrations.RunPython.noop, + ), + migrations.AlterField( + model_name='akowner', + name='slug', + field=models.SlugField(blank=True, help_text='Slug for URL generation', unique=True, max_length=64, verbose_name='Slug') + ) + ] diff --git a/AKModel/migrations/0018_merge_20191023_2227.py b/AKModel/migrations/0018_merge_20191023_2227.py new file mode 100644 index 0000000000000000000000000000000000000000..a1bcb9bed9461f2671c73c5a90492727b3b9d0fd --- /dev/null +++ b/AKModel/migrations/0018_merge_20191023_2227.py @@ -0,0 +1,14 @@ +# Generated by Django 2.2.6 on 2019-10-23 22:27 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0016_category_description'), + ('AKModel', '0017_owner_slug'), + ] + + operations = [ + ] diff --git a/AKModel/migrations/0019_slot_start_optional.py b/AKModel/migrations/0019_slot_start_optional.py new file mode 100644 index 0000000000000000000000000000000000000000..0d04806ffe5da36076aa34649f8f7f835388d7fe --- /dev/null +++ b/AKModel/migrations/0019_slot_start_optional.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2019-10-24 15:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0018_merge_20191023_2227'), + ] + + operations = [ + migrations.AlterField( + model_name='akslot', + name='start', + field=models.DateTimeField(blank=True, help_text='Time and date the slot begins', null=True, verbose_name='Slot Begin'), + ), + ] diff --git a/AKModel/migrations/0020_ak_unique.py b/AKModel/migrations/0020_ak_unique.py new file mode 100644 index 0000000000000000000000000000000000000000..ee7fbb099699c4af06be965ad1d88437bed5cf5f --- /dev/null +++ b/AKModel/migrations/0020_ak_unique.py @@ -0,0 +1,27 @@ +# Generated by Django 2.2.6 on 2019-10-24 19:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0019_slot_start_optional'), + ] + + operations = [ + migrations.AlterField( + model_name='ak', + name='name', + field=models.CharField(help_text='Name of the AK', max_length=256, verbose_name='Name'), + ), + migrations.AlterField( + model_name='ak', + name='short_name', + field=models.CharField(blank=True, help_text='Name displayed in the schedule', max_length=64, verbose_name='Short Name'), + ), + migrations.AlterUniqueTogether( + name='ak', + unique_together={('short_name', 'event'), ('name', 'event')}, + ), + ] diff --git a/AKModel/migrations/0021_base_url.py b/AKModel/migrations/0021_base_url.py new file mode 100644 index 0000000000000000000000000000000000000000..522fc41ee9a3851eb2e2c49a8e14ad374f13fb2e --- /dev/null +++ b/AKModel/migrations/0021_base_url.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2019-10-24 22:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0020_ak_unique'), + ] + + operations = [ + migrations.AddField( + model_name='event', + name='base_url', + field=models.URLField(blank=True, help_text='Prefix for wiki link construction', verbose_name='Base URL'), + ), + ] diff --git a/AKModel/models.py b/AKModel/models.py index bb161cf952a95ca333e411787d2bf67d756df403..90b0219782db24d716e9580e5aecd2cb7e18861a 100644 --- a/AKModel/models.py +++ b/AKModel/models.py @@ -1,5 +1,8 @@ # Create your models here. +import itertools + from django.db import models +from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ @@ -16,6 +19,8 @@ class Event(models.Model): help_text=_('City etc. the event takes place in')) active = models.BooleanField(verbose_name=_('Active State'), help_text=_('Marks currently active events')) + base_url = models.URLField(verbose_name=_("Base URL"), help_text=_("Prefix for wiki link construction"), blank=True) + class Meta: verbose_name = _('Event') verbose_name_plural = _('Events') @@ -32,7 +37,9 @@ class Event(models.Model): class AKOwner(models.Model): """ An AKOwner describes the person organizing/holding an AK. """ - name = models.CharField(max_length=256, verbose_name=_('Nickname'), help_text=_('Name to identify an AK owner by')) + name = models.CharField(max_length=64, verbose_name=_('Nickname'), help_text=_('Name to identify an AK owner by')) + slug = models.SlugField(max_length=64, blank=True, unique=True, verbose_name=_('Slug'), + help_text=_('Slug for URL generation')) email = models.EmailField(max_length=128, blank=True, verbose_name=_('E-Mail Address'), help_text=_('Contact mail')) institution = models.CharField(max_length=128, blank=True, verbose_name=_('Institution'), help_text=_('Uni etc.')) link = models.URLField(blank=True, verbose_name=_('Web Link'), help_text=_('Link to Homepage')) @@ -51,6 +58,35 @@ class AKOwner(models.Model): return f"{self.name} ({self.institution})" return self.name + def _generate_slug(self): + max_length = self._meta.get_field('slug').max_length + + slug_candidate = slugify(self.name)[:max_length] + if not AKOwner.objects.filter(slug=slug_candidate).exists(): + self.slug = slug_candidate + return + slug_candidate = slugify(slug_candidate + '_' + self.institution)[:max_length] + if not AKOwner.objects.filter(slug=slug_candidate).exists(): + self.slug = slug_candidate + return + for i in itertools.count(1): + if not AKOwner.objects.filter(slug=slug_candidate).exists(): + break + digits = len(str(i)) + slug_candidate = '{}-{}'.format(slug_candidate[:-digits + 1], i) + + self.slug = slug_candidate + + def save(self, *args, **kwargs): + if not self.slug: + self._generate_slug() + + super().save(*args, **kwargs) + + @staticmethod + def get_by_slug(slug): + return AKOwner.objects.get(slug=slug) + class AKCategory(models.Model): """ An AKCategory describes the characteristics of an AK, e.g. content vs. recreational. @@ -117,8 +153,8 @@ class AKRequirement(models.Model): class AK(models.Model): """ An AK is a slot-based activity to be scheduled during an event. """ - name = models.CharField(max_length=256, unique=True, verbose_name=_('Name'), help_text=_('Name of the AK')) - short_name = models.CharField(max_length=64, unique=True, blank=True, verbose_name=_('Short Name'), + name = models.CharField(max_length=256, verbose_name=_('Name'), help_text=_('Name of the AK')) + short_name = models.CharField(max_length=64, blank=True, verbose_name=_('Short Name'), help_text=_('Name displayed in the schedule')) description = models.TextField(blank=True, verbose_name=_('Description'), help_text=_('Description of the AK')) @@ -136,7 +172,8 @@ class AK(models.Model): reso = models.BooleanField(verbose_name=_('Resolution Intention'), default=False, help_text=_('Intends to submit a resolution')) - present = models.BooleanField(verbose_name=_("Present this AK"), null=True, help_text=_("Present results of this AK")) + present = models.BooleanField(verbose_name=_("Present this AK"), null=True, + help_text=_("Present results of this AK")) requirements = models.ManyToManyField(to=AKRequirement, blank=True, verbose_name=_('Requirements'), help_text=_("AK's Requirements")) @@ -156,6 +193,7 @@ class AK(models.Model): class Meta: verbose_name = _('AK') verbose_name_plural = _('AKs') + unique_together = [('name', 'event'), ('short_name', 'event')] def __str__(self): if self.short_name: @@ -200,9 +238,10 @@ class AKSlot(models.Model): """ An AK Mapping matches an AK to a room during a certain time. """ ak = models.ForeignKey(to=AK, on_delete=models.CASCADE, verbose_name=_('AK'), help_text=_('AK being mapped')) - room = models.ForeignKey(to=Room, null=True, on_delete=models.SET_NULL, verbose_name=_('Room'), + room = models.ForeignKey(to=Room, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('Room'), help_text=_('Room the AK will take place in')) - start = models.DateTimeField(verbose_name=_('Slot Begin'), help_text=_('Time and date the slot begins')) + start = models.DateTimeField(verbose_name=_('Slot Begin'), help_text=_('Time and date the slot begins'), + blank=True, null=True) duration = models.DecimalField(max_digits=4, decimal_places=2, default=2, verbose_name=_('Duration'), help_text=_('Length in hours')) @@ -224,4 +263,6 @@ class AKSlot(models.Model): """ Display start time of slot in format weekday + time, e.g. "Fri 14:00" """ + if self.start is None: + return _("Not scheduled yet") return self.start.strftime('%a %H:%M') diff --git a/AKModel/views.py b/AKModel/views.py index 55d76b42a101e13309bccab30fde01b76d38154a..1ef246355f8fa160d3b93577d4b5bfd03d5fbd25 100644 --- a/AKModel/views.py +++ b/AKModel/views.py @@ -1,26 +1,38 @@ -from django.http import Http404 +from django.shortcuts import get_object_or_404 from AKModel.models import Event -class FilterByEventSlugMixin: +class EventSlugMixin: """ - Mixin to filter different querysets based on a event slug from the request url + Mixin to handle views with event slugs """ event = None - def get_queryset(self): + def _load_event(self): # Find event based on event slug - try: - self.event = Event.get_by_slug(self.kwargs.get("event_slug", None)) - except Event.DoesNotExist: - raise Http404 + self.event = get_object_or_404(Event, slug=self.kwargs.get("event_slug", None)) - # Filter current queryset based on url event slug or return 404 if event slug is invalid - return super().get_queryset().filter(event=self.event) + def get(self, request, *args, **kwargs): + self._load_event() + return super().get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + self._load_event() + return super().post(request, *args, **kwargs) def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) # Add event to context (to make it accessible in templates) context["event"] = self.event return context + + +class FilterByEventSlugMixin(EventSlugMixin): + """ + Mixin to filter different querysets based on a event slug from the request url + """ + + def get_queryset(self): + # Filter current queryset based on url event slug or return 404 if event slug is invalid + return super().get_queryset().filter(event=self.event) diff --git a/AKSubmission/forms.py b/AKSubmission/forms.py new file mode 100644 index 0000000000000000000000000000000000000000..60a3047618bd01f5c29d8cf4e9fc9c9e722498ed --- /dev/null +++ b/AKSubmission/forms.py @@ -0,0 +1,116 @@ +from django import forms +from django.core.exceptions import ValidationError + +from AKModel.models import AK, AKOwner + +from django.utils.translation import ugettext_lazy as _ + + +class AKForm(forms.ModelForm): + class Meta: + model = AK + fields = ['name', + 'short_name', + 'link', + 'owners', + 'description', + 'category', + 'reso', + 'present', + 'requirements', + 'conflicts', + 'prerequisites', + 'notes', + 'event' + ] + + widgets = { + 'requirements': forms.CheckboxSelectMultiple, + 'event': forms.HiddenInput, + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Use better multiple select input for owners, conflicts and prerequisites + self.fields["owners"].widget.attrs = {'class': 'chosen-select'} + self.fields["conflicts"].widget.attrs = {'class': 'chosen-select'} + self.fields["prerequisites"].widget.attrs = {'class': 'chosen-select'} + + help_tags_addition = _('Separate multiple tags with semicolon') + + # Add text fields for tags + self.fields["tags_raw"] = forms.CharField( + required=False, + label=AK.tags.field.verbose_name, + help_text=f"{AK.tags.field.help_text} ({help_tags_addition})") + + @staticmethod + def _clean_duration(duration): + # Handle different duration formats (h:mm and decimal comma instead of point) + if ":" in duration: + h, m = duration.split(":") + duration = int(h) + int(m) / 60 + if "," in str(duration): + duration = float(duration.replace(",", ".")) + + try: + float(duration) + except ValueError: + raise ValidationError( + _('"%(duration)s" is not a valid duration'), + code='invalid', + params={'duration': duration}, + ) + + return duration + + def clean(self): + cleaned_data = super().clean() + + # Generate short name if not given + short_name = self.cleaned_data["short_name"] + if len(short_name) == 0: + cleaned_data["short_name"] = ''.join(x for x in self.cleaned_data["name"].title() if x.isalnum()) + + # Get tag names from raw tags + cleaned_data["tag_names"] = [name.strip().lower() for name in cleaned_data["tags_raw"].split(";")] + + # Get durations from raw durations field + if "durations" in cleaned_data: + cleaned_data["durations"] = [self._clean_duration(d) for d in self.cleaned_data["durations"].split()] + return cleaned_data + + +class AKSubmissionForm(AKForm): + + class Meta(AKForm.Meta): + exclude = ['link'] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Add field for durations + self.fields["durations"] = forms.CharField( + widget=forms.Textarea, + label=_("Duration(s)"), + help_text=_("Enter at least one planned duration (in hours). If your AK should have multiple slots, use multiple lines") + ) + + +class AKEditForm(AKForm): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Add existing tags to tag raw field + self.fields["tags_raw"].initial = "; ".join(str(tag) for tag in self.instance.tags.all()) + + +class AKWishForm(AKSubmissionForm): + class Meta(AKForm.Meta): + exclude = ['owners'] + + +class AKOwnerForm(forms.ModelForm): + class Meta: + model = AKOwner + fields = ['name', 'email', 'institution', 'link'] diff --git a/AKSubmission/locale/de_DE/LC_MESSAGES/django.po b/AKSubmission/locale/de_DE/LC_MESSAGES/django.po index 43e0721121ec902323f775729bbaed305dd1013c..7ed4db5e60541f7d6fb3eb059985a7a32e84b092 100644 --- a/AKSubmission/locale/de_DE/LC_MESSAGES/django.po +++ b/AKSubmission/locale/de_DE/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-21 22:38+0000\n" +"POT-Creation-Date: 2019-10-24 23:21+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,58 +17,91 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +#: forms.py:39 +msgid "Separate multiple tags with semicolon" +msgstr "Mehrere Tags mit Semikolon trennen" + +#: forms.py:60 +#, python-format +msgid "\"%(duration)s\" is not a valid duration" +msgstr "\"%(duration)s\" ist keine gültige Dauer" + +#: forms.py:94 +msgid "Duration(s)" +msgstr "Dauer(n)" + +#: forms.py:95 +msgid "" +"Enter at least one planned duration (in hours). If your AK should have " +"multiple slots, use multiple lines" +msgstr "" +"Mindestens eine geplante Dauer (in Stunden) angeben. Wenn der AK mehrere " +"Slots haben soll, mehrere Zeilen verwenden" + #: templates/AKSubmission/ak_detail.html:8 #: templates/AKSubmission/ak_detail.html:13 #: templates/AKSubmission/ak_detail.html:18 -#: templates/AKSubmission/ak_list.html:8 templates/AKSubmission/ak_list.html:13 +#: templates/AKSubmission/ak_edit.html:14 templates/AKSubmission/ak_list.html:8 +#: templates/AKSubmission/ak_list.html:13 #: templates/AKSubmission/ak_list.html:18 +#: templates/AKSubmission/akowner_create_update.html:13 #: templates/AKSubmission/submission_overview.html:6 #: templates/AKSubmission/submission_overview.html:11 #: templates/AKSubmission/submission_overview.html:15 +#: templates/AKSubmission/submit_new.html:19 +#: templates/AKSubmission/submit_new_wish.html:10 msgid "AK Submission" msgstr "AK-Eintragung" -#: templates/AKSubmission/ak_detail.html:27 +#: templates/AKSubmission/ak_detail.html:29 #: templates/AKSubmission/ak_list_table.html:30 msgid "AK Wish" msgstr "AK-Wunsch" -#: templates/AKSubmission/ak_detail.html:30 +#: templates/AKSubmission/ak_detail.html:32 #: templates/AKSubmission/ak_list_table.html:10 msgid "Who?" msgstr "Wer?" -#: templates/AKSubmission/ak_detail.html:32 +#: templates/AKSubmission/ak_detail.html:34 #: templates/AKSubmission/ak_list_table.html:11 msgid "Category" msgstr "Kategorie" -#: templates/AKSubmission/ak_detail.html:38 +#: templates/AKSubmission/ak_detail.html:40 msgid "Present this AK" msgstr "Diesen AK vorstellen" -#: templates/AKSubmission/ak_detail.html:42 +#: templates/AKSubmission/ak_detail.html:44 #: templates/AKSubmission/ak_list.html:26 #: templates/AKSubmission/ak_list_table.html:12 msgid "Tags" msgstr "Tags" -#: templates/AKSubmission/ak_detail.html:48 +#: templates/AKSubmission/ak_detail.html:50 msgid "Reso?" msgstr "Reso?" -#: templates/AKSubmission/ak_detail.html:60 +#: templates/AKSubmission/ak_detail.html:62 msgid "When?" msgstr "Wann?" -#: templates/AKSubmission/ak_detail.html:61 +#: templates/AKSubmission/ak_detail.html:63 msgid "Duration" msgstr "Dauer" -#: templates/AKSubmission/ak_detail.html:62 +#: templates/AKSubmission/ak_detail.html:64 msgid "Room" msgstr "Raum" +#: templates/AKSubmission/ak_edit.html:8 templates/AKSubmission/ak_edit.html:21 +msgid "Edit AK" +msgstr "AK bearbeiten" + +#: templates/AKSubmission/ak_edit.html:16 +msgid "Edit" +msgstr "Bearbeiten" + #: templates/AKSubmission/ak_list.html:14 msgid "AKs" msgstr "AKs" @@ -89,35 +122,85 @@ msgstr "Diesen AK vorstellen" msgid "Reso" msgstr "Reso" -#: templates/AKSubmission/submission_overview.html:17 +#: templates/AKSubmission/akowner_create_update.html:7 +#: templates/AKSubmission/akowner_create_update.html:19 +msgid "AK Owner" +msgstr "AK-Leitung" + +#: templates/AKSubmission/akowner_create_update.html:25 +#: templates/AKSubmission/submit_new.html:34 +msgid "Reset" +msgstr "Zurücksetzen" + +#: templates/AKSubmission/akowner_create_update.html:29 +#: templates/AKSubmission/submit_new.html:38 +msgid "Cancel" +msgstr "Abbrechen" + +#: templates/AKSubmission/akowner_create_update.html:32 +#: templates/AKSubmission/submit_new.html:41 +msgid "Submit" +msgstr "Eintragen" + +#: templates/AKSubmission/submission_overview.html:19 msgid "" "On this page you can see a list of current AKs, change them and add new ones." msgstr "" "Auf dieser Seite kannst du eine Liste von aktuellen AKs sehen, diese " "bearbeiten und neue hinzufügen." -#: templates/AKSubmission/submission_overview.html:20 -msgid "Submit" -msgstr "Eintragen" +#: templates/AKSubmission/submission_overview.html:25 +#: templates/AKSubmission/submit_new_wish.html:5 +#: templates/AKSubmission/submit_new_wish.html:11 +#: templates/AKSubmission/submit_new_wish.html:15 +msgid "New AK Wish" +msgstr "Neuer AK-Wunsch" + +#: templates/AKSubmission/submission_overview.html:29 +msgid "Who" +msgstr "Wer" -#: templates/AKSubmission/submission_overview.html:21 +#: templates/AKSubmission/submission_overview.html:32 +msgid "I do not own AKs yet" +msgstr "Ich leite bisher keine AKs" + +#: templates/AKSubmission/submission_overview.html:40 +#: templates/AKSubmission/submit_new.html:8 +#: templates/AKSubmission/submit_new.html:21 +#: templates/AKSubmission/submit_new.html:28 msgid "New AK" msgstr "Neuer AK" -#: templates/AKSubmission/submission_overview.html:22 -msgid "New AK Wish" -msgstr "Neuer AK-Wunsch" +#: templates/AKSubmission/submission_overview.html:46 +msgid "Edit Person Info" +msgstr "Personen-Info bearbeiten" -#: templates/AKSubmission/submission_overview.html:26 +#: templates/AKSubmission/submission_overview.html:53 msgid "Current AKs" msgstr "Aktuelle AKs" -#: views.py:33 +#: views.py:44 msgid "Wishes" msgstr "Wünsche" -#: views.py:33 +#: views.py:44 msgid "AKs one would like to have" msgstr "" "AKs die sich gewünscht wurden, aber bei denen noch nicht klar ist, wer sie " "macht. Falls du dir das vorstellen kannst, trag dich einfach ein" + +#: views.py:105 +msgid "AK successfully created" +msgstr "AK erfolgreich angelegt" + +#: views.py:152 +msgid "AK successfully updated" +msgstr "AK erfolgreich bearbeitet" + +#: views.py:209 +msgid "Person Info successfully updated" +msgstr "Personen-Info erfolgreich bearbeitet" + +#: views.py:221 +msgid "No user selected" +msgstr "Keine Person ausgewählt" diff --git a/AKSubmission/templates/AKSubmission/ak_detail.html b/AKSubmission/templates/AKSubmission/ak_detail.html index e03d50dc47b0223849bcd7030e5f44716e37e7e7..dcb1d07eea1ade9ae9d90cc5a1741bd8aedcd8c3 100644 --- a/AKSubmission/templates/AKSubmission/ak_detail.html +++ b/AKSubmission/templates/AKSubmission/ak_detail.html @@ -17,11 +17,13 @@ {% block content %} <h1 style="margin-bottom: 30px;">{{ ak.event.name }}: {% trans "AK Submission" %}</h1> + {% include "AKSubmission/messages.html" %} + <div class="float-right"> {% if ak.link != "" %} <a href="{{ ak.link }}" class="btn btn-info">{% fontawesome_icon 'external-link-alt' %}</a> {% endif %} - <a href="#" class="btn btn-success">{% fontawesome_icon 'pencil-alt' %}</a> + <a href="{% url 'submit:ak_edit' event_slug=ak.event.slug pk=ak.pk %}" class="btn btn-success">{% fontawesome_icon 'pencil-alt' %}</a> </div> <h2>{% if ak.wish %}{% trans "AK Wish" %}: {% endif %}{{ ak.name }}</h2> diff --git a/AKSubmission/templates/AKSubmission/ak_edit.html b/AKSubmission/templates/AKSubmission/ak_edit.html new file mode 100644 index 0000000000000000000000000000000000000000..45b1f9d39c735a4140ab27386460279da9b524f8 --- /dev/null +++ b/AKSubmission/templates/AKSubmission/ak_edit.html @@ -0,0 +1,22 @@ +{% extends 'AKSubmission/submit_new.html' %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome %} +{% load staticfiles %} + +{% block title %}{{ event.slug }} - {% trans "Edit AK" %}{% endblock %} + +{% block breadcrumbs %} + <li class="breadcrumb-item"><a href="#">AKPlanning</a></li> + <li class="breadcrumb-item"><a href="#">{{ event.slug }}</a></li> + <li class="breadcrumb-item"><a + href="{% url 'submit:submission_overview' event_slug=event.slug %}">{% trans "AK Submission" %}</a></li> + <li class="breadcrumb-item"><a href="#">{{ ak.short_name }}</a></li> + <li class="breadcrumb-item active">{% trans "Edit" %}</li> +{% endblock %} + + +{% block headline %} + <h2>{% trans 'Edit AK' %}</h2> +{% endblock %} diff --git a/AKSubmission/templates/AKSubmission/ak_list_table.html b/AKSubmission/templates/AKSubmission/ak_list_table.html index 4f5d25cfc568d500526dd497eb02b15ebdd60004..f9d405e844e51d7f6ea89e3996c797704b67db63 100644 --- a/AKSubmission/templates/AKSubmission/ak_list_table.html +++ b/AKSubmission/templates/AKSubmission/ak_list_table.html @@ -39,7 +39,7 @@ {% if ak.link %} <a href="{{ ak.link }}" class="btn btn-info">{% fontawesome_icon 'external-link-alt' %}</a> {% endif %} - <a href="#" class="btn btn-success">{% fontawesome_icon 'pencil-alt' %}</a> + <a href="{% url 'submit:ak_edit' event_slug=event.slug pk=ak.pk %}" class="btn btn-success">{% fontawesome_icon 'pencil-alt' %}</a> </td> </tr> <tr> diff --git a/AKSubmission/templates/AKSubmission/akowner_create_update.html b/AKSubmission/templates/AKSubmission/akowner_create_update.html new file mode 100644 index 0000000000000000000000000000000000000000..7076b281e7cf0253eb29ffcd059bd74d4c36d5f3 --- /dev/null +++ b/AKSubmission/templates/AKSubmission/akowner_create_update.html @@ -0,0 +1,36 @@ +{% extends 'base.html' %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome %} + +{% block title %}{{ event.slug }} - {% trans "AK Owner" %}{% endblock %} + +{% block breadcrumbs %} + <li class="breadcrumb-item"><a href="#">AKPlanning</a></li> + <li class="breadcrumb-item"><a href="#">{{ event.slug }}</a></li> + <li class="breadcrumb-item"><a + href="{% url 'submit:submission_overview' event_slug=event.slug %}">{% trans "AK Submission" %}</a></li> + <li class="breadcrumb-item active">{{ owner.slug }}</li> +{% endblock %} + +{% block content %} + {% block headline %} + <h2>{% trans 'AK Owner' %}</h2> + {% endblock %} + <form method="POST" class="post-form">{% csrf_token %} + {% bootstrap_form form %} + {% buttons %} + <button type="reset" class="btn btn-danger"> + {% fontawesome_icon "undo-alt" %} {% trans "Reset" %} + </button> + + <a href="{% url 'submit:submission_overview' event_slug=event.slug %}" class="btn btn-secondary"> + {% fontawesome_icon "times" %} {% trans "Cancel" %} + </a> + <button type="submit" class="save btn btn-primary float-right"> + {% fontawesome_icon "check" %} {% trans "Submit" %} + </button> + {% endbuttons %} + </form> +{% endblock %} \ No newline at end of file diff --git a/AKSubmission/templates/AKSubmission/messages.html b/AKSubmission/templates/AKSubmission/messages.html new file mode 100644 index 0000000000000000000000000000000000000000..dc8dd31f18b78e92597e39ac66447e778efec8d9 --- /dev/null +++ b/AKSubmission/templates/AKSubmission/messages.html @@ -0,0 +1,10 @@ +{% load tags_AKSubmission %} + +{% if messages %} + {% for message in messages %} + <div class="alert alert-dismissible {{ message.tags | message_bootstrap_class }}"> + <button type="button" class="close" data-dismiss="alert">×</button> + {{ message }} + </div> + {% endfor %} +{% endif %} diff --git a/AKSubmission/templates/AKSubmission/submission_overview.html b/AKSubmission/templates/AKSubmission/submission_overview.html index 7f991d9dadec1840e4fb0a8290f71747ebc60b24..3d502fc13d96e930c8a044ef0c4aaa7248e757e4 100644 --- a/AKSubmission/templates/AKSubmission/submission_overview.html +++ b/AKSubmission/templates/AKSubmission/submission_overview.html @@ -14,12 +14,39 @@ {% block content %} <h1>{{ event.name }}: {% trans "AK Submission" %}</h1> + {% include "AKSubmission/messages.html" %} + {% blocktrans %}On this page you can see a list of current AKs, change them and add new ones.{% endblocktrans %} <div class="jumbotron" style="margin-top:20px;"> - <h2>{% trans "Submit" %}</h2> - <a href="#" class="btn btn-primary">{% trans "New AK" %}</a> - <a href="#" class="btn btn-info">{% trans "New AK Wish" %}</a> + <form method="POST" action="#" class="form-row"> + {% csrf_token %} + <a href="{% url 'submit:submit_ak_wish' event_slug=event.slug %}" class="btn btn-info"> + {% trans "New AK Wish" %} + </a> + <span style="font-size: 1.5em"> + | + <label for="selectOwnerId" class="align-middle d-inline">{% trans "Who" %}:</label> + </span> + <select name="owner_id" id="selectOwnerId" class=""> + <option value="-1">{% trans "I do not own AKs yet" %}</option> + {% for owner in existingOwners %} + <option value="{{ owner.pk }}">{{ owner }}</option> + {% endfor %} + </select> + <input + type="submit" + class="btn btn-primary" + value="{% trans "New AK" %}" + formaction="{% url 'submit:akowner_select' event_slug=event.slug %}" + /> + <input + type="submit" + class="btn btn-success" + value="{% trans 'Edit Person Info' %}" + formaction="{% url 'submit:akowner_edit_dispatch' event_slug=event.slug %}" + /> + </form> </div> diff --git a/AKSubmission/templates/AKSubmission/submit_new.html b/AKSubmission/templates/AKSubmission/submit_new.html new file mode 100644 index 0000000000000000000000000000000000000000..cacda571424d7fb61b40f11bd745fcb5bf76ecc7 --- /dev/null +++ b/AKSubmission/templates/AKSubmission/submit_new.html @@ -0,0 +1,54 @@ +{% extends 'base.html' %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome %} +{% load staticfiles %} + +{% block title %}{{ event.slug }} - {% trans "New AK" %}{% endblock %} + +{% block imports %} + <link rel="stylesheet" href="{% static 'common/vendor/chosen-js/chosen.css' %}"> + <link rel="stylesheet" href="{% static 'common/css/bootstrap-choosen.css' %}"> +{% endblock %} + +{% block breadcrumbs %} + <li class="breadcrumb-item"><a href="#">AKPlanning</a></li> + <li class="breadcrumb-item"><a href="#">{{ event.slug }}</a></li> + <li class="breadcrumb-item"><a + href="{% url 'submit:submission_overview' event_slug=event.slug %}">{% trans "AK Submission" %}</a></li> + <li class="breadcrumb-item"><a href="#">{{ owner.slug }}</a></li> + <li class="breadcrumb-item active">{% trans "New AK" %}</li> +{% endblock %} + +{% block content %} + {% include "AKSubmission/messages.html" %} + + {% block headline %} + <h2>{% trans 'New AK' %}</h2> + {% endblock %} + <form method="POST" class="post-form">{% csrf_token %} + {% bootstrap_form form %} + {% buttons %} + <button type="reset" class="btn btn-danger"> + {% fontawesome_icon "undo-alt" %} {% trans "Reset" %} + </button> + + <a href="{% url 'submit:submission_overview' event_slug=event.slug %}" class="btn btn-secondary"> + {% fontawesome_icon "times" %} {% trans "Cancel" %} + </a> + <button type="submit" class="save btn btn-primary float-right"> + {% fontawesome_icon "check" %} {% trans "Submit" %} + </button> + {% endbuttons %} + </form> +{% endblock %} + +{% block bottom_script %} + <script src="{% static 'common/vendor/chosen-js/chosen.jquery.js' %}"></script> + <script> + $(function() { + $('.chosen-select').chosen(); + }); + </script> +{% endblock %} \ No newline at end of file diff --git a/AKSubmission/templates/AKSubmission/submit_new_wish.html b/AKSubmission/templates/AKSubmission/submit_new_wish.html new file mode 100644 index 0000000000000000000000000000000000000000..b0315ab0177a49ac8e0d00ed5856dc0ca9669a4c --- /dev/null +++ b/AKSubmission/templates/AKSubmission/submit_new_wish.html @@ -0,0 +1,16 @@ +{% extends 'AKSubmission/submit_new.html' %} + +{% load i18n %} + +{% block title %}{{ event.slug }} - {% trans "New AK Wish" %}{% endblock %} + +{% block breadcrumbs %} + <li class="breadcrumb-item"><a href="#">AKPlanning</a></li> + <li class="breadcrumb-item"><a href="#">{{ event.slug }}</a></li> + <li class="breadcrumb-item"><a href="#">{% trans "AK Submission" %}</a></li> + <li class="breadcrumb-item active">{% trans "New AK Wish" %}</li> +{% endblock %} + +{% block headline %} + <h2>{% trans 'New AK Wish' %}</h2> +{% endblock %} \ No newline at end of file diff --git a/AKSubmission/templatetags/tags_AKSubmission.py b/AKSubmission/templatetags/tags_AKSubmission.py index 224453355e8547e21d4603aa4ac582dbabc5d998..fa0019c03619f643854eb09c85ed1e89ba3ead2f 100644 --- a/AKSubmission/templatetags/tags_AKSubmission.py +++ b/AKSubmission/templatetags/tags_AKSubmission.py @@ -24,3 +24,15 @@ def category_list(categories, event_slug): @register.inclusion_tag("AKSubmission/category_linked_badge.html") def category_linked_badge(category, event_slug): return {"category": category, "event_slug": event_slug} + + +@register.filter +def message_bootstrap_class(tag): + print(tag) + if tag == "error": + return "alert-danger" + elif tag == "success": + return "alert-success" + elif tag == "warning": + return "alert-warning" + return "alert-info" diff --git a/AKSubmission/urls.py b/AKSubmission/urls.py index 54092fb6e0457af5b010190c5211dd7ca45d9917..637ce8358cc3cdd2c120babfcdaa8c5e1df2e4ef 100644 --- a/AKSubmission/urls.py +++ b/AKSubmission/urls.py @@ -10,9 +10,16 @@ urlpatterns = [ include([ path('', views.SubmissionOverviewView.as_view(), name='submission_overview'), path('ak/<int:pk>', views.AKDetailView.as_view(), name='ak_detail'), + path('ak/<int:pk>/edit/', views.AKEditView.as_view(), name='ak_edit'), path('aks/', views.AKListView.as_view(), name='ak_list'), path('aks/category/<int:category_pk>', views.AKListByCategoryView.as_view(), name='ak_list_by_category'), path('aks/tag/<int:tag_pk>', views.AKListByTagView.as_view(), name='ak_list_by_tag'), + path('owner/', views.AKOwnerCreateView.as_view(), name='akowner_create'), + path('new/', views.AKOwnerSelectDispatchView.as_view(), name='akowner_select'), + path('owner/edit/', views.AKOwnerEditDispatchView.as_view(), name='akowner_edit_dispatch'), + path('<slug:slug>/edit/', views.AKOwnerEditView.as_view(), name='akowner_edit'), + path('<slug:owner_slug>/new/', views.AKSubmissionView.as_view(), name='submit_ak'), + path('new_wish/', views.AKWishSubmissionView.as_view(), name='submit_ak_wish'), ]) ), ] diff --git a/AKSubmission/views.py b/AKSubmission/views.py index 4be08a38f4270b0b892e77b4312415454cf076b2..2f4f989458fa7a3fc3de8f095d5f9ccad0f355ab 100644 --- a/AKSubmission/views.py +++ b/AKSubmission/views.py @@ -1,9 +1,18 @@ -from django.http import Http404 +from django.contrib import messages +from django.http import Http404, HttpResponseRedirect +from django.shortcuts import get_object_or_404 +from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from django.views.generic import ListView, DetailView +from django.views import View +from django.views.generic import ListView, DetailView, CreateView, UpdateView -from AKModel.models import AK, AKCategory, AKTag +from AKModel.models import AK, AKCategory, AKTag, AKOwner, AKSlot +from AKModel.models import Event +from AKModel.views import EventSlugMixin from AKModel.views import FilterByEventSlugMixin + +from AKSubmission.forms import AKForm, AKWishForm, AKOwnerForm, AKEditForm, AKSubmissionForm + from django.conf import settings @@ -35,6 +44,9 @@ class SubmissionOverviewView(FilterByEventSlugMixin, ListView): categories.append(({"name":_("Wishes"), "pk": "wish", "description": _("AKs one would like to have")}, ak_wishes)) context["categories"] = categories + # Get list of existing owners for event (for AK submission start) + context["existingOwners"] = AKOwner.objects.filter(event=self.event) + return context @@ -82,3 +94,134 @@ class AKListByTagView(AKListView): except AKTag.DoesNotExist: raise Http404 return super().get_queryset().filter(tags=self.tag) + + +class AKAndAKWishSubmissionView(EventSlugMixin, CreateView): + model = AK + template_name = 'AKSubmission/submit_new.html' + form_class = AKSubmissionForm + + def get_success_url(self): + messages.add_message(self.request, messages.SUCCESS, _("AK successfully created")) + return reverse_lazy('submit:ak_detail', kwargs={'event_slug': self.kwargs['event_slug'], 'pk': self.object.pk}) + + def form_valid(self, form): + super_form_valid = super().form_valid(form) + + # Generate wiki link + self.object.link = form.cleaned_data["event"].base_url + form.cleaned_data["name"].replace(" ", "_") + self.object.save() + + # Set tags (and generate them if necessary) + for tag_name in form.cleaned_data["tag_names"]: + tag, _ = AKTag.objects.get_or_create(name=tag_name) + self.object.tags.add(tag) + + # Generate slot(s) + for duration in form.cleaned_data["durations"]: + new_slot = AKSlot(ak=self.object, duration=duration, event=self.object.event) + new_slot.save() + + return super_form_valid + + +class AKSubmissionView(AKAndAKWishSubmissionView): + def get_initial(self): + initials = super(AKAndAKWishSubmissionView, self).get_initial() + initials['owners'] = [AKOwner.get_by_slug(self.kwargs['owner_slug'])] + initials['event'] = self.event + return initials + + def get_context_data(self, *, object_list=None, **kwargs): + context = super().get_context_data(object_list=object_list, **kwargs) + context['owner'] = get_object_or_404(AKOwner, slug=self.kwargs['owner_slug']) + return context + + +class AKWishSubmissionView(AKAndAKWishSubmissionView): + template_name = 'AKSubmission/submit_new_wish.html' + form_class = AKWishForm + + +class AKEditView(EventSlugMixin, UpdateView): + model = AK + template_name = 'AKSubmission/ak_edit.html' + form_class = AKEditForm + + def get_success_url(self): + messages.add_message(self.request, messages.SUCCESS, _("AK successfully updated")) + return reverse_lazy('submit:ak_detail', kwargs={'event_slug': self.kwargs['event_slug'], 'pk': self.object.pk}) + + def form_valid(self, form): + super_form_valid = super().form_valid(form) + + # Detach existing tags + self.object.tags.clear() + + # Set tags (and generate them if necessary) + for tag_name in form.cleaned_data["tag_names"]: + tag, _ = AKTag.objects.get_or_create(name=tag_name) + self.object.tags.add(tag) + + return super_form_valid + + +class AKOwnerCreateView(EventSlugMixin, CreateView): + model = AKOwner + template_name = 'AKSubmission/akowner_create_update.html' + form_class = AKOwnerForm + + def get_success_url(self): + return reverse_lazy('submit:submit_ak', + kwargs={'event_slug': self.kwargs['event_slug'], 'owner_slug': self.object.slug}) + + def form_valid(self, form): + instance = form.save(commit=False) + + # Set event + instance.event = Event.get_by_slug(self.kwargs["event_slug"]) + + return super().form_valid(form) + + +class AKOwnerSelectDispatchView(EventSlugMixin, View): + """ + This view only serves as redirect to prepopulate the owners field in submission create view + """ + def post(self, request, *args, **kwargs): + owner_id = request.POST["owner_id"] + + if owner_id == "-1": + return HttpResponseRedirect( + reverse_lazy('submit:akowner_create', kwargs={'event_slug': kwargs['event_slug']})) + + owner = get_object_or_404(AKOwner, pk=request.POST["owner_id"]) + return HttpResponseRedirect( + reverse_lazy('submit:submit_ak', kwargs={'event_slug': kwargs['event_slug'], 'owner_slug': owner.slug})) + + +class AKOwnerEditView(EventSlugMixin, UpdateView): + model = AKOwner + template_name = "AKSubmission/akowner_create_update.html" + form_class = AKOwnerForm + + def get_success_url(self): + messages.add_message(self.request, messages.SUCCESS, _("Person Info successfully updated")) + return reverse_lazy('submit:submission_overview', kwargs={'event_slug': self.kwargs['event_slug']}) + + +class AKOwnerEditDispatchView(EventSlugMixin, View): + """ + This view only serves as redirect choose the correct edit view + """ + def post(self, request, *args, **kwargs): + owner_id = request.POST["owner_id"] + + if owner_id == "-1": + messages.add_message(self.request, messages.WARNING, _("No user selected")) + return HttpResponseRedirect( + reverse_lazy('submit:submission_overview', kwargs={'event_slug': kwargs['event_slug']})) + + owner = get_object_or_404(AKOwner, pk=request.POST["owner_id"]) + return HttpResponseRedirect( + reverse_lazy('submit:akowner_edit', kwargs={'event_slug': kwargs['event_slug'], 'slug': owner.slug})) diff --git a/static_common/common/css/bootstrap-choosen.css b/static_common/common/css/bootstrap-choosen.css new file mode 100644 index 0000000000000000000000000000000000000000..8189031a8f1a3aeea522f613dc97850a2a9cea3b --- /dev/null +++ b/static_common/common/css/bootstrap-choosen.css @@ -0,0 +1,404 @@ +.chosen-select { + width: 100%; +} +.chosen-select-deselect { + width: 100%; +} +.chosen-container { + display: inline-block; + font-size: 14px; + position: relative; + vertical-align: middle; +} +.chosen-container .chosen-drop { + background: #ffffff; + border: 1px solid #cccccc; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-box-shadow: 0 8px 8px rgba(0, 0, 0, .25); + box-shadow: 0 8px 8px rgba(0, 0, 0, .25); + margin-top: -1px; + position: absolute; + top: 100%; + left: -9000px; + z-index: 1060; +} +.chosen-container.chosen-with-drop .chosen-drop { + left: 0; + right: 0; +} +.chosen-container .chosen-results { + color: #555555; + margin: 0 4px 4px 0; + max-height: 240px; + padding: 0 0 0 4px; + position: relative; + overflow-x: hidden; + overflow-y: auto; + -webkit-overflow-scrolling: touch; +} +.chosen-container .chosen-results li { + display: none; + line-height: 1.42857143; + list-style: none; + margin: 0; + padding: 5px 6px; +} +.chosen-container .chosen-results li em { + background: #feffde; + font-style: normal; +} +.chosen-container .chosen-results li.group-result { + display: list-item; + cursor: default; + color: #999; + font-weight: bold; +} +.chosen-container .chosen-results li.group-option { + padding-left: 15px; +} +.chosen-container .chosen-results li.active-result { + cursor: pointer; + display: list-item; +} +.chosen-container .chosen-results li.highlighted { + background-color: #428bca; + background-image: none; + color: white; +} +.chosen-container .chosen-results li.highlighted em { + background: transparent; +} +.chosen-container .chosen-results li.disabled-result { + display: list-item; + color: #777777; +} +.chosen-container .chosen-results .no-results { + background: #eeeeee; + display: list-item; +} +.chosen-container .chosen-results-scroll { + background: white; + margin: 0 4px; + position: absolute; + text-align: center; + width: 321px; + z-index: 1; +} +.chosen-container .chosen-results-scroll span { + display: inline-block; + height: 1.42857143; + text-indent: -5000px; + width: 9px; +} +.chosen-container .chosen-results-scroll-down { + bottom: 0; +} +.chosen-container .chosen-results-scroll-down span { + background: url("chosen-sprite.png") no-repeat -4px -3px; +} +.chosen-container .chosen-results-scroll-up span { + background: url("chosen-sprite.png") no-repeat -22px -3px; +} +.chosen-container-single .chosen-single { + background-color: #ffffff; + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + border: 1px solid #cccccc; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + color: #555555; + display: block; + height: 34px; + overflow: hidden; + line-height: 34px; + padding: 0 0 0 8px; + position: relative; + text-decoration: none; + white-space: nowrap; +} +.chosen-container-single .chosen-single span { + display: block; + margin-right: 26px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.chosen-container-single .chosen-single abbr { + background: url("chosen-sprite.png") right top no-repeat; + display: block; + font-size: 1px; + height: 10px; + position: absolute; + right: 26px; + top: 12px; + width: 12px; +} +.chosen-container-single .chosen-single abbr:hover { + background-position: right -11px; +} +.chosen-container-single .chosen-single.chosen-disabled .chosen-single abbr:hover { + background-position: right 2px; +} +.chosen-container-single .chosen-single div { + display: block; + height: 100%; + position: absolute; + top: 0; + right: 0; + width: 18px; +} +.chosen-container-single .chosen-single div b { + background: url("chosen-sprite.png") no-repeat 0 7px; + display: block; + height: 100%; + width: 100%; +} +.chosen-container-single .chosen-default { + color: #777777; +} +.chosen-container-single .chosen-search { + margin: 0; + padding: 3px 4px; + position: relative; + white-space: nowrap; + z-index: 1000; +} +.chosen-container-single .chosen-search input[type="text"] { + background: url("chosen-sprite.png") no-repeat 100% -20px, #ffffff; + border: 1px solid #cccccc; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + margin: 1px 0; + padding: 4px 20px 4px 4px; + width: 100%; +} +.chosen-container-single .chosen-drop { + margin-top: -1px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} +.chosen-container-single-nosearch .chosen-search input { + position: absolute; + left: -9000px; +} +.chosen-container-multi .chosen-choices { + background-color: #ffffff; + border: 1px solid #cccccc; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + cursor: text; + height: auto !important; + height: 1%; + margin: 0; + overflow: hidden; + padding: 0; + position: relative; +} +.chosen-container-multi .chosen-choices li { + float: left; + list-style: none; +} +.chosen-container-multi .chosen-choices .search-field { + margin: 0; + padding: 0; + white-space: nowrap; +} +.chosen-container-multi .chosen-choices .search-field input[type="text"] { + background: transparent !important; + border: 0 !important; + -webkit-box-shadow: none; + box-shadow: none; + color: #555555; + height: 32px; + margin: 0; + padding: 4px; + outline: 0; +} +.chosen-container-multi .chosen-choices .search-field .default { + color: #999; +} +.chosen-container-multi .chosen-choices .search-choice { + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + background-color: #eeeeee; + border: 1px solid #cccccc; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + background-image: -webkit-linear-gradient(top, #ffffff 0%, #eeeeee 100%); + background-image: -o-linear-gradient(top, #ffffff 0%, #eeeeee 100%); + background-image: linear-gradient(to bottom, #ffffff 0%, #eeeeee 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffeeeeee', GradientType=0); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + color: #333333; + cursor: default; + line-height: 13px; + margin: 6px 0 3px 5px; + padding: 3px 20px 3px 5px; + position: relative; +} +.chosen-container-multi .chosen-choices .search-choice .search-choice-close { + background: url("chosen-sprite.png") right top no-repeat; + display: block; + font-size: 1px; + height: 10px; + position: absolute; + right: 4px; + top: 5px; + width: 12px; + cursor: pointer; +} +.chosen-container-multi .chosen-choices .search-choice .search-choice-close:hover { + background-position: right -11px; +} +.chosen-container-multi .chosen-choices .search-choice-focus { + background: #d4d4d4; +} +.chosen-container-multi .chosen-choices .search-choice-focus .search-choice-close { + background-position: right -11px; +} +.chosen-container-multi .chosen-results { + margin: 0 0 0 0; + padding: 0; +} +.chosen-container-multi .chosen-drop .result-selected { + display: none; +} +.chosen-container-active .chosen-single { + border: 1px solid #66afe9; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .075) inset, 0 0 8px rgba(82, 168, 236, .6); + box-shadow: 0 1px 1px rgba(0, 0, 0, .075) inset, 0 0 8px rgba(82, 168, 236, .6); + -webkit-transition: border linear .2s, box-shadow linear .2s; + -o-transition: border linear .2s, box-shadow linear .2s; + transition: border linear .2s, box-shadow linear .2s; +} +.chosen-container-active.chosen-with-drop .chosen-single { + background-color: #ffffff; + border: 1px solid #66afe9; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .075) inset, 0 0 8px rgba(82, 168, 236, .6); + box-shadow: 0 1px 1px rgba(0, 0, 0, .075) inset, 0 0 8px rgba(82, 168, 236, .6); + -webkit-transition: border linear .2s, box-shadow linear .2s; + -o-transition: border linear .2s, box-shadow linear .2s; + transition: border linear .2s, box-shadow linear .2s; +} +.chosen-container-active.chosen-with-drop .chosen-single div { + background: transparent; + border-left: none; +} +.chosen-container-active.chosen-with-drop .chosen-single div b { + background-position: -18px 7px; +} +.chosen-container-active .chosen-choices { + border: 1px solid #66afe9; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .075) inset, 0 0 8px rgba(82, 168, 236, .6); + box-shadow: 0 1px 1px rgba(0, 0, 0, .075) inset, 0 0 8px rgba(82, 168, 236, .6); + -webkit-transition: border linear .2s, box-shadow linear .2s; + -o-transition: border linear .2s, box-shadow linear .2s; + transition: border linear .2s, box-shadow linear .2s; +} +.chosen-container-active .chosen-choices .search-field input[type="text"] { + color: #111 !important; +} +.chosen-container-active.chosen-with-drop .chosen-choices { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.chosen-disabled { + cursor: default; + opacity: 0.5 !important; +} +.chosen-disabled .chosen-single { + cursor: default; +} +.chosen-disabled .chosen-choices .search-choice .search-choice-close { + cursor: default; +} +.chosen-rtl { + text-align: right; +} +.chosen-rtl .chosen-single { + padding: 0 8px 0 0; + overflow: visible; +} +.chosen-rtl .chosen-single span { + margin-left: 26px; + margin-right: 0; + direction: rtl; +} +.chosen-rtl .chosen-single div { + left: 7px; + right: auto; +} +.chosen-rtl .chosen-single abbr { + left: 26px; + right: auto; +} +.chosen-rtl .chosen-choices .search-field input[type="text"] { + direction: rtl; +} +.chosen-rtl .chosen-choices li { + float: right; +} +.chosen-rtl .chosen-choices .search-choice { + margin: 6px 5px 3px 0; + padding: 3px 5px 3px 19px; +} +.chosen-rtl .chosen-choices .search-choice .search-choice-close { + background-position: right top; + left: 4px; + right: auto; +} +.chosen-rtl.chosen-container-single .chosen-results { + margin: 0 0 4px 4px; + padding: 0 4px 0 0; +} +.chosen-rtl .chosen-results .group-option { + padding-left: 0; + padding-right: 15px; +} +.chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div { + border-right: none; +} +.chosen-rtl .chosen-search input[type="text"] { + background: url("chosen-sprite.png") no-repeat -28px -20px, #ffffff; + direction: rtl; + padding: 4px 5px 4px 20px; +} +@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-resolution: 144dpi) { + .chosen-rtl .chosen-search input[type="text"], + .chosen-container-single .chosen-single abbr, + .chosen-container-single .chosen-single div b, + .chosen-container-single .chosen-search input[type="text"], + .chosen-container-multi .chosen-choices .search-choice .search-choice-close, + .chosen-container .chosen-results-scroll-down span, + .chosen-container .chosen-results-scroll-up span { + background-image: url("chosen-sprite@2x.png") !important; + background-size: 52px 37px !important; + background-repeat: no-repeat !important; + } +} diff --git a/static_common/common/vendor/chosen-js/README.md b/static_common/common/vendor/chosen-js/README.md new file mode 100644 index 0000000000000000000000000000000000000000..53164e7eef7b9a9e291d5f025229390323ea7ae0 --- /dev/null +++ b/static_common/common/vendor/chosen-js/README.md @@ -0,0 +1,47 @@ +# Chosen + +Chosen is a library for making long, unwieldy select boxes more user friendly. + +- jQuery support: 1.4+ +- Prototype support: 1.7+ + +For **documentation**, usage, and examples, see: +http://harvesthq.github.io/chosen/ + +For **downloads**, see: +https://github.com/harvesthq/chosen/releases/ + +### Package managers + +Chosen is available through [Bower](https://bower.io/) and [npm](https://www.npmjs.com), +_however, the package names are not the same_. + +To install with Bower: + +``` +bower install chosen +``` + +To install with npm: + +``` +npm install chosen-js +``` + +The compiled files for these packages are automatically generated and stored in a [2nd Chosen repository](https://github.com/harvesthq/chosen-package). No pull requests will be accepted to that repository. + +### Contributing to this project + +We welcome all to participate in making Chosen the best software it can be. The repository is maintained by only a few people, but has accepted contributions from over 50 authors after reviewing hundreds of pull requests related to thousands of issues. You can help reduce the maintainers' workload (and increase your chance of having an accepted contribution to Chosen) by following the +[guidelines for contributing](contributing.md). + +* [Bug reports](contributing.md#bugs) +* [Feature requests](contributing.md#features) +* [Pull requests](contributing.md#pull-requests) + +### Chosen Credits + +- Concept and development by [Patrick Filler](http://patrickfiller.com) for [Harvest](http://getharvest.com/). +- Design and CSS by [Matthew Lettini](http://matthewlettini.com/) +- Repository maintained by [@pfiller](http://github.com/pfiller), [@kenearley](http://github.com/kenearley), [@stof](http://github.com/stof), [@koenpunt](http://github.com/koenpunt), and [@tjschuck](http://github.com/tjschuck). +- Chosen includes [contributions by many fine folks](https://github.com/harvesthq/chosen/contributors). diff --git a/static_common/common/vendor/chosen-js/chosen-sprite.png b/static_common/common/vendor/chosen-js/chosen-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..c57da70b4b5b1e08a6977ddde182677af0e5e1b8 Binary files /dev/null and b/static_common/common/vendor/chosen-js/chosen-sprite.png differ diff --git a/static_common/common/vendor/chosen-js/chosen-sprite@2x.png b/static_common/common/vendor/chosen-js/chosen-sprite@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6b50545202cb4770039362c55025b0b9824663ad Binary files /dev/null and b/static_common/common/vendor/chosen-js/chosen-sprite@2x.png differ diff --git a/static_common/common/vendor/chosen-js/chosen.css b/static_common/common/vendor/chosen-js/chosen.css new file mode 100644 index 0000000000000000000000000000000000000000..2b7bb925be956e4470ef1c3c0ccaee7f3ea55961 --- /dev/null +++ b/static_common/common/vendor/chosen-js/chosen.css @@ -0,0 +1,476 @@ +/*! +Chosen, a Select Box Enhancer for jQuery and Prototype +by Patrick Filler for Harvest, http://getharvest.com + +Version 1.7.0 +Full source at https://github.com/harvesthq/chosen +Copyright (c) 2011-2017 Harvest http://getharvest.com + +MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md +This file is generated by `grunt build`, do not edit it by hand. +*/ + +/* @group Base */ +.chosen-container { + position: relative; + display: inline-block; + vertical-align: middle; + font-size: 13px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.chosen-container * { + box-sizing: border-box; +} + +.chosen-container .chosen-drop { + position: absolute; + top: 100%; + z-index: 1010; + width: 100%; + border: 1px solid #aaa; + border-top: 0; + background: #fff; + box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15); + clip: rect(0, 0, 0, 0); +} + +.chosen-container.chosen-with-drop .chosen-drop { + clip: auto; +} + +.chosen-container a { + cursor: pointer; +} + +.chosen-container .search-choice .group-name, .chosen-container .chosen-single .group-name { + margin-right: 4px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-weight: normal; + color: #999999; +} + +.chosen-container .search-choice .group-name:after, .chosen-container .chosen-single .group-name:after { + content: ":"; + padding-left: 2px; + vertical-align: top; +} + +/* @end */ +/* @group Single Chosen */ +.chosen-container-single .chosen-single { + position: relative; + display: block; + overflow: hidden; + padding: 0 0 0 8px; + height: 25px; + border: 1px solid #aaa; + border-radius: 5px; + background-color: #fff; + background: linear-gradient(#fff 20%, #f6f6f6 50%, #eee 52%, #f4f4f4 100%); + background-clip: padding-box; + box-shadow: 0 0 3px #fff inset, 0 1px 1px rgba(0, 0, 0, 0.1); + color: #444; + text-decoration: none; + white-space: nowrap; + line-height: 24px; +} + +.chosen-container-single .chosen-default { + color: #999; +} + +.chosen-container-single .chosen-single span { + display: block; + overflow: hidden; + margin-right: 26px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.chosen-container-single .chosen-single-with-deselect span { + margin-right: 38px; +} + +.chosen-container-single .chosen-single abbr { + position: absolute; + top: 6px; + right: 26px; + display: block; + width: 12px; + height: 12px; + background: url("chosen-sprite.png") -42px 1px no-repeat; + font-size: 1px; +} + +.chosen-container-single .chosen-single abbr:hover { + background-position: -42px -10px; +} + +.chosen-container-single.chosen-disabled .chosen-single abbr:hover { + background-position: -42px -10px; +} + +.chosen-container-single .chosen-single div { + position: absolute; + top: 0; + right: 0; + display: block; + width: 18px; + height: 100%; +} + +.chosen-container-single .chosen-single div b { + display: block; + width: 100%; + height: 100%; + background: url("chosen-sprite.png") no-repeat 0px 2px; +} + +.chosen-container-single .chosen-search { + position: relative; + z-index: 1010; + margin: 0; + padding: 3px 4px; + white-space: nowrap; +} + +.chosen-container-single .chosen-search input[type="text"] { + margin: 1px 0; + padding: 4px 20px 4px 5px; + width: 100%; + height: auto; + outline: 0; + border: 1px solid #aaa; + background: url("chosen-sprite.png") no-repeat 100% -20px; + font-size: 1em; + font-family: sans-serif; + line-height: normal; + border-radius: 0; +} + +.chosen-container-single .chosen-drop { + margin-top: -1px; + border-radius: 0 0 4px 4px; + background-clip: padding-box; +} + +.chosen-container-single.chosen-container-single-nosearch .chosen-search { + position: absolute; + clip: rect(0, 0, 0, 0); +} + +/* @end */ +/* @group Results */ +.chosen-container .chosen-results { + color: #444; + position: relative; + overflow-x: hidden; + overflow-y: auto; + margin: 0 4px 4px 0; + padding: 0 0 0 4px; + max-height: 240px; + -webkit-overflow-scrolling: touch; +} + +.chosen-container .chosen-results li { + display: none; + margin: 0; + padding: 5px 6px; + list-style: none; + line-height: 15px; + word-wrap: break-word; + -webkit-touch-callout: none; +} + +.chosen-container .chosen-results li.active-result { + display: list-item; + cursor: pointer; +} + +.chosen-container .chosen-results li.disabled-result { + display: list-item; + color: #ccc; + cursor: default; +} + +.chosen-container .chosen-results li.highlighted { + background-color: #3875d7; + background-image: linear-gradient(#3875d7 20%, #2a62bc 90%); + color: #fff; +} + +.chosen-container .chosen-results li.no-results { + color: #777; + display: list-item; + background: #f4f4f4; +} + +.chosen-container .chosen-results li.group-result { + display: list-item; + font-weight: bold; + cursor: default; +} + +.chosen-container .chosen-results li.group-option { + padding-left: 15px; +} + +.chosen-container .chosen-results li em { + font-style: normal; + text-decoration: underline; +} + +/* @end */ +/* @group Multi Chosen */ +.chosen-container-multi .chosen-choices { + position: relative; + overflow: hidden; + margin: 0; + padding: 0 5px; + width: 100%; + height: auto; + border: 1px solid #aaa; + background-color: #fff; + background-image: linear-gradient(#eee 1%, #fff 15%); + cursor: text; +} + +.chosen-container-multi .chosen-choices li { + float: left; + list-style: none; +} + +.chosen-container-multi .chosen-choices li.search-field { + margin: 0; + padding: 0; + white-space: nowrap; +} + +.chosen-container-multi .chosen-choices li.search-field input[type="text"] { + margin: 1px 0; + padding: 0; + height: 25px; + outline: 0; + border: 0 !important; + background: transparent !important; + box-shadow: none; + color: #999; + font-size: 100%; + font-family: sans-serif; + line-height: normal; + border-radius: 0; + width: 25px; +} + +.chosen-container-multi .chosen-choices li.search-choice { + position: relative; + margin: 3px 5px 3px 0; + padding: 3px 20px 3px 5px; + border: 1px solid #aaa; + max-width: 100%; + border-radius: 3px; + background-color: #eeeeee; + background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-size: 100% 19px; + background-repeat: repeat-x; + background-clip: padding-box; + box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + color: #333; + line-height: 13px; + cursor: default; +} + +.chosen-container-multi .chosen-choices li.search-choice span { + word-wrap: break-word; +} + +.chosen-container-multi .chosen-choices li.search-choice .search-choice-close { + position: absolute; + top: 4px; + right: 3px; + display: block; + width: 12px; + height: 12px; + background: url("chosen-sprite.png") -42px 1px no-repeat; + font-size: 1px; +} + +.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover { + background-position: -42px -10px; +} + +.chosen-container-multi .chosen-choices li.search-choice-disabled { + padding-right: 5px; + border: 1px solid #ccc; + background-color: #e4e4e4; + background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + color: #666; +} + +.chosen-container-multi .chosen-choices li.search-choice-focus { + background: #d4d4d4; +} + +.chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close { + background-position: -42px -10px; +} + +.chosen-container-multi .chosen-results { + margin: 0; + padding: 0; +} + +.chosen-container-multi .chosen-drop .result-selected { + display: list-item; + color: #ccc; + cursor: default; +} + +/* @end */ +/* @group Active */ +.chosen-container-active .chosen-single { + border: 1px solid #5897fb; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); +} + +.chosen-container-active.chosen-with-drop .chosen-single { + border: 1px solid #aaa; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + background-image: linear-gradient(#eee 20%, #fff 80%); + box-shadow: 0 1px 0 #fff inset; +} + +.chosen-container-active.chosen-with-drop .chosen-single div { + border-left: none; + background: transparent; +} + +.chosen-container-active.chosen-with-drop .chosen-single div b { + background-position: -18px 2px; +} + +.chosen-container-active .chosen-choices { + border: 1px solid #5897fb; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); +} + +.chosen-container-active .chosen-choices li.search-field input[type="text"] { + color: #222 !important; +} + +/* @end */ +/* @group Disabled Support */ +.chosen-disabled { + opacity: 0.5 !important; + cursor: default; +} + +.chosen-disabled .chosen-single { + cursor: default; +} + +.chosen-disabled .chosen-choices .search-choice .search-choice-close { + cursor: default; +} + +/* @end */ +/* @group Right to Left */ +.chosen-rtl { + text-align: right; +} + +.chosen-rtl .chosen-single { + overflow: visible; + padding: 0 8px 0 0; +} + +.chosen-rtl .chosen-single span { + margin-right: 0; + margin-left: 26px; + direction: rtl; +} + +.chosen-rtl .chosen-single-with-deselect span { + margin-left: 38px; +} + +.chosen-rtl .chosen-single div { + right: auto; + left: 3px; +} + +.chosen-rtl .chosen-single abbr { + right: auto; + left: 26px; +} + +.chosen-rtl .chosen-choices li { + float: right; +} + +.chosen-rtl .chosen-choices li.search-field input[type="text"] { + direction: rtl; +} + +.chosen-rtl .chosen-choices li.search-choice { + margin: 3px 5px 3px 0; + padding: 3px 5px 3px 19px; +} + +.chosen-rtl .chosen-choices li.search-choice .search-choice-close { + right: auto; + left: 4px; +} + +.chosen-rtl.chosen-container-single .chosen-results { + margin: 0 0 4px 4px; + padding: 0 4px 0 0; +} + +.chosen-rtl .chosen-results li.group-option { + padding-right: 15px; + padding-left: 0; +} + +.chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div { + border-right: none; +} + +.chosen-rtl .chosen-search input[type="text"] { + padding: 4px 5px 4px 20px; + background: url("chosen-sprite.png") no-repeat -30px -20px; + direction: rtl; +} + +.chosen-rtl.chosen-container-single .chosen-single div b { + background-position: 6px 2px; +} + +.chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b { + background-position: -12px 2px; +} + +/* @end */ +/* @group Retina compatibility */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi), only screen and (min-resolution: 1.5dppx) { + .chosen-rtl .chosen-search input[type="text"], + .chosen-container-single .chosen-single abbr, + .chosen-container-single .chosen-single div b, + .chosen-container-single .chosen-search input[type="text"], + .chosen-container-multi .chosen-choices .search-choice .search-choice-close, + .chosen-container .chosen-results-scroll-down span, + .chosen-container .chosen-results-scroll-up span { + background-image: url("chosen-sprite@2x.png") !important; + background-size: 52px 37px !important; + background-repeat: no-repeat !important; + } +} + +/* @end */ diff --git a/static_common/common/vendor/chosen-js/chosen.jquery.js b/static_common/common/vendor/chosen-js/chosen.jquery.js new file mode 100644 index 0000000000000000000000000000000000000000..3adffbf8594c8aee9f79fa04e7a2633fff4f203d --- /dev/null +++ b/static_common/common/vendor/chosen-js/chosen.jquery.js @@ -0,0 +1,1309 @@ +(function() { + var $, AbstractChosen, Chosen, SelectParser, _ref, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + + SelectParser = (function() { + function SelectParser() { + this.options_index = 0; + this.parsed = []; + } + + SelectParser.prototype.add_node = function(child) { + if (child.nodeName.toUpperCase() === "OPTGROUP") { + return this.add_group(child); + } else { + return this.add_option(child); + } + }; + + SelectParser.prototype.add_group = function(group) { + var group_position, option, _i, _len, _ref, _results; + group_position = this.parsed.length; + this.parsed.push({ + array_index: group_position, + group: true, + label: this.escapeExpression(group.label), + title: group.title ? group.title : void 0, + children: 0, + disabled: group.disabled, + classes: group.className + }); + _ref = group.childNodes; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + option = _ref[_i]; + _results.push(this.add_option(option, group_position, group.disabled)); + } + return _results; + }; + + SelectParser.prototype.add_option = function(option, group_position, group_disabled) { + if (option.nodeName.toUpperCase() === "OPTION") { + if (option.text !== "") { + if (group_position != null) { + this.parsed[group_position].children += 1; + } + this.parsed.push({ + array_index: this.parsed.length, + options_index: this.options_index, + value: option.value, + text: option.text, + html: option.innerHTML, + title: option.title ? option.title : void 0, + selected: option.selected, + disabled: group_disabled === true ? group_disabled : option.disabled, + group_array_index: group_position, + group_label: group_position != null ? this.parsed[group_position].label : null, + classes: option.className, + style: option.style.cssText + }); + } else { + this.parsed.push({ + array_index: this.parsed.length, + options_index: this.options_index, + empty: true + }); + } + return this.options_index += 1; + } + }; + + SelectParser.prototype.escapeExpression = function(text) { + var map, unsafe_chars; + if ((text == null) || text === false) { + return ""; + } + if (!/[\&\<\>\"\'\`]/.test(text)) { + return text; + } + map = { + "<": "<", + ">": ">", + '"': """, + "'": "'", + "`": "`" + }; + unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g; + return text.replace(unsafe_chars, function(chr) { + return map[chr] || "&"; + }); + }; + + return SelectParser; + + })(); + + SelectParser.select_to_array = function(select) { + var child, parser, _i, _len, _ref; + parser = new SelectParser(); + _ref = select.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + parser.add_node(child); + } + return parser.parsed; + }; + + AbstractChosen = (function() { + function AbstractChosen(form_field, options) { + this.form_field = form_field; + this.options = options != null ? options : {}; + this.label_click_handler = __bind(this.label_click_handler, this); + if (!AbstractChosen.browser_is_supported()) { + return; + } + this.is_multiple = this.form_field.multiple; + this.set_default_text(); + this.set_default_values(); + this.setup(); + this.set_up_html(); + this.register_observers(); + this.on_ready(); + } + + AbstractChosen.prototype.set_default_values = function() { + var _this = this; + this.click_test_action = function(evt) { + return _this.test_active_click(evt); + }; + this.activate_action = function(evt) { + return _this.activate_field(evt); + }; + this.active_field = false; + this.mouse_on_container = false; + this.results_showing = false; + this.result_highlighted = null; + this.is_rtl = this.options.rtl || /\bchosen-rtl\b/.test(this.form_field.className); + this.allow_single_deselect = (this.options.allow_single_deselect != null) && (this.form_field.options[0] != null) && this.form_field.options[0].text === "" ? this.options.allow_single_deselect : false; + this.disable_search_threshold = this.options.disable_search_threshold || 0; + this.disable_search = this.options.disable_search || false; + this.enable_split_word_search = this.options.enable_split_word_search != null ? this.options.enable_split_word_search : true; + this.group_search = this.options.group_search != null ? this.options.group_search : true; + this.search_contains = this.options.search_contains || false; + this.single_backstroke_delete = this.options.single_backstroke_delete != null ? this.options.single_backstroke_delete : true; + this.max_selected_options = this.options.max_selected_options || Infinity; + this.inherit_select_classes = this.options.inherit_select_classes || false; + this.display_selected_options = this.options.display_selected_options != null ? this.options.display_selected_options : true; + this.display_disabled_options = this.options.display_disabled_options != null ? this.options.display_disabled_options : true; + this.include_group_label_in_selected = this.options.include_group_label_in_selected || false; + this.max_shown_results = this.options.max_shown_results || Number.POSITIVE_INFINITY; + this.case_sensitive_search = this.options.case_sensitive_search || false; + return this.hide_results_on_select = this.options.hide_results_on_select != null ? this.options.hide_results_on_select : true; + }; + + AbstractChosen.prototype.set_default_text = function() { + if (this.form_field.getAttribute("data-placeholder")) { + this.default_text = this.form_field.getAttribute("data-placeholder"); + } else if (this.is_multiple) { + this.default_text = this.options.placeholder_text_multiple || this.options.placeholder_text || AbstractChosen.default_multiple_text; + } else { + this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || AbstractChosen.default_single_text; + } + this.default_text = this.escape_html(this.default_text); + return this.results_none_found = this.form_field.getAttribute("data-no_results_text") || this.options.no_results_text || AbstractChosen.default_no_result_text; + }; + + AbstractChosen.prototype.choice_label = function(item) { + if (this.include_group_label_in_selected && (item.group_label != null)) { + return "<b class='group-name'>" + item.group_label + "</b>" + item.html; + } else { + return item.html; + } + }; + + AbstractChosen.prototype.mouse_enter = function() { + return this.mouse_on_container = true; + }; + + AbstractChosen.prototype.mouse_leave = function() { + return this.mouse_on_container = false; + }; + + AbstractChosen.prototype.input_focus = function(evt) { + var _this = this; + if (this.is_multiple) { + if (!this.active_field) { + return setTimeout((function() { + return _this.container_mousedown(); + }), 50); + } + } else { + if (!this.active_field) { + return this.activate_field(); + } + } + }; + + AbstractChosen.prototype.input_blur = function(evt) { + var _this = this; + if (!this.mouse_on_container) { + this.active_field = false; + return setTimeout((function() { + return _this.blur_test(); + }), 100); + } + }; + + AbstractChosen.prototype.label_click_handler = function(evt) { + if (this.is_multiple) { + return this.container_mousedown(evt); + } else { + return this.activate_field(); + } + }; + + AbstractChosen.prototype.results_option_build = function(options) { + var content, data, data_content, shown_results, _i, _len, _ref; + content = ''; + shown_results = 0; + _ref = this.results_data; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + data = _ref[_i]; + data_content = ''; + if (data.group) { + data_content = this.result_add_group(data); + } else { + data_content = this.result_add_option(data); + } + if (data_content !== '') { + shown_results++; + content += data_content; + } + if (options != null ? options.first : void 0) { + if (data.selected && this.is_multiple) { + this.choice_build(data); + } else if (data.selected && !this.is_multiple) { + this.single_set_selected_text(this.choice_label(data)); + } + } + if (shown_results >= this.max_shown_results) { + break; + } + } + return content; + }; + + AbstractChosen.prototype.result_add_option = function(option) { + var classes, option_el; + if (!option.search_match) { + return ''; + } + if (!this.include_option_in_results(option)) { + return ''; + } + classes = []; + if (!option.disabled && !(option.selected && this.is_multiple)) { + classes.push("active-result"); + } + if (option.disabled && !(option.selected && this.is_multiple)) { + classes.push("disabled-result"); + } + if (option.selected) { + classes.push("result-selected"); + } + if (option.group_array_index != null) { + classes.push("group-option"); + } + if (option.classes !== "") { + classes.push(option.classes); + } + option_el = document.createElement("li"); + option_el.className = classes.join(" "); + option_el.style.cssText = option.style; + option_el.setAttribute("data-option-array-index", option.array_index); + option_el.innerHTML = option.search_text; + if (option.title) { + option_el.title = option.title; + } + return this.outerHTML(option_el); + }; + + AbstractChosen.prototype.result_add_group = function(group) { + var classes, group_el; + if (!(group.search_match || group.group_match)) { + return ''; + } + if (!(group.active_options > 0)) { + return ''; + } + classes = []; + classes.push("group-result"); + if (group.classes) { + classes.push(group.classes); + } + group_el = document.createElement("li"); + group_el.className = classes.join(" "); + group_el.innerHTML = group.search_text; + if (group.title) { + group_el.title = group.title; + } + return this.outerHTML(group_el); + }; + + AbstractChosen.prototype.results_update_field = function() { + this.set_default_text(); + if (!this.is_multiple) { + this.results_reset_cleanup(); + } + this.result_clear_highlight(); + this.results_build(); + if (this.results_showing) { + return this.winnow_results(); + } + }; + + AbstractChosen.prototype.reset_single_select_options = function() { + var result, _i, _len, _ref, _results; + _ref = this.results_data; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + result = _ref[_i]; + if (result.selected) { + _results.push(result.selected = false); + } else { + _results.push(void 0); + } + } + return _results; + }; + + AbstractChosen.prototype.results_toggle = function() { + if (this.results_showing) { + return this.results_hide(); + } else { + return this.results_show(); + } + }; + + AbstractChosen.prototype.results_search = function(evt) { + if (this.results_showing) { + return this.winnow_results(); + } else { + return this.results_show(); + } + }; + + AbstractChosen.prototype.winnow_results = function() { + var escapedSearchText, highlightRegex, option, regex, results, results_group, searchText, startpos, text, _i, _len, _ref; + this.no_results_clear(); + results = 0; + searchText = this.get_search_text(); + escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + regex = this.get_search_regex(escapedSearchText); + highlightRegex = this.get_highlight_regex(escapedSearchText); + _ref = this.results_data; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + option = _ref[_i]; + option.search_match = false; + results_group = null; + if (this.include_option_in_results(option)) { + if (option.group) { + option.group_match = false; + option.active_options = 0; + } + if ((option.group_array_index != null) && this.results_data[option.group_array_index]) { + results_group = this.results_data[option.group_array_index]; + if (results_group.active_options === 0 && results_group.search_match) { + results += 1; + } + results_group.active_options += 1; + } + option.search_text = option.group ? option.label : option.html; + if (!(option.group && !this.group_search)) { + option.search_match = this.search_string_match(option.search_text, regex); + if (option.search_match && !option.group) { + results += 1; + } + if (option.search_match) { + if (searchText.length) { + startpos = option.search_text.search(highlightRegex); + text = option.search_text.substr(0, startpos + searchText.length) + '</em>' + option.search_text.substr(startpos + searchText.length); + option.search_text = text.substr(0, startpos) + '<em>' + text.substr(startpos); + } + if (results_group != null) { + results_group.group_match = true; + } + } else if ((option.group_array_index != null) && this.results_data[option.group_array_index].search_match) { + option.search_match = true; + } + } + } + } + this.result_clear_highlight(); + if (results < 1 && searchText.length) { + this.update_results_content(""); + return this.no_results(searchText); + } else { + this.update_results_content(this.results_option_build()); + return this.winnow_results_set_highlight(); + } + }; + + AbstractChosen.prototype.get_search_regex = function(escaped_search_string) { + var regex_anchor, regex_flag; + regex_anchor = this.search_contains ? "" : "^"; + regex_flag = this.case_sensitive_search ? "" : "i"; + return new RegExp(regex_anchor + escaped_search_string, regex_flag); + }; + + AbstractChosen.prototype.get_highlight_regex = function(escaped_search_string) { + var regex_anchor, regex_flag; + regex_anchor = this.search_contains ? "" : "\\b"; + regex_flag = this.case_sensitive_search ? "" : "i"; + return new RegExp(regex_anchor + escaped_search_string, regex_flag); + }; + + AbstractChosen.prototype.search_string_match = function(search_string, regex) { + var part, parts, _i, _len; + if (regex.test(search_string)) { + return true; + } else if (this.enable_split_word_search && (search_string.indexOf(" ") >= 0 || search_string.indexOf("[") === 0)) { + parts = search_string.replace(/\[|\]/g, "").split(" "); + if (parts.length) { + for (_i = 0, _len = parts.length; _i < _len; _i++) { + part = parts[_i]; + if (regex.test(part)) { + return true; + } + } + } + } + }; + + AbstractChosen.prototype.choices_count = function() { + var option, _i, _len, _ref; + if (this.selected_option_count != null) { + return this.selected_option_count; + } + this.selected_option_count = 0; + _ref = this.form_field.options; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + option = _ref[_i]; + if (option.selected) { + this.selected_option_count += 1; + } + } + return this.selected_option_count; + }; + + AbstractChosen.prototype.choices_click = function(evt) { + evt.preventDefault(); + this.activate_field(); + if (!(this.results_showing || this.is_disabled)) { + return this.results_show(); + } + }; + + AbstractChosen.prototype.keydown_checker = function(evt) { + var stroke, _ref; + stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; + this.search_field_scale(); + if (stroke !== 8 && this.pending_backstroke) { + this.clear_backstroke(); + } + switch (stroke) { + case 8: + this.backstroke_length = this.get_search_field_value().length; + break; + case 9: + if (this.results_showing && !this.is_multiple) { + this.result_select(evt); + } + this.mouse_on_container = false; + break; + case 13: + if (this.results_showing) { + evt.preventDefault(); + } + break; + case 27: + if (this.results_showing) { + evt.preventDefault(); + } + break; + case 32: + if (this.disable_search) { + evt.preventDefault(); + } + break; + case 38: + evt.preventDefault(); + this.keyup_arrow(); + break; + case 40: + evt.preventDefault(); + this.keydown_arrow(); + break; + } + }; + + AbstractChosen.prototype.keyup_checker = function(evt) { + var stroke, _ref; + stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; + this.search_field_scale(); + switch (stroke) { + case 8: + if (this.is_multiple && this.backstroke_length < 1 && this.choices_count() > 0) { + this.keydown_backstroke(); + } else if (!this.pending_backstroke) { + this.result_clear_highlight(); + this.results_search(); + } + break; + case 13: + evt.preventDefault(); + if (this.results_showing) { + this.result_select(evt); + } + break; + case 27: + if (this.results_showing) { + this.results_hide(); + } + break; + case 9: + case 16: + case 17: + case 18: + case 38: + case 40: + case 91: + break; + default: + this.results_search(); + break; + } + }; + + AbstractChosen.prototype.clipboard_event_checker = function(evt) { + var _this = this; + if (this.is_disabled) { + return; + } + return setTimeout((function() { + return _this.results_search(); + }), 50); + }; + + AbstractChosen.prototype.container_width = function() { + if (this.options.width != null) { + return this.options.width; + } else { + return "" + this.form_field.offsetWidth + "px"; + } + }; + + AbstractChosen.prototype.include_option_in_results = function(option) { + if (this.is_multiple && (!this.display_selected_options && option.selected)) { + return false; + } + if (!this.display_disabled_options && option.disabled) { + return false; + } + if (option.empty) { + return false; + } + return true; + }; + + AbstractChosen.prototype.search_results_touchstart = function(evt) { + this.touch_started = true; + return this.search_results_mouseover(evt); + }; + + AbstractChosen.prototype.search_results_touchmove = function(evt) { + this.touch_started = false; + return this.search_results_mouseout(evt); + }; + + AbstractChosen.prototype.search_results_touchend = function(evt) { + if (this.touch_started) { + return this.search_results_mouseup(evt); + } + }; + + AbstractChosen.prototype.outerHTML = function(element) { + var tmp; + if (element.outerHTML) { + return element.outerHTML; + } + tmp = document.createElement("div"); + tmp.appendChild(element); + return tmp.innerHTML; + }; + + AbstractChosen.prototype.get_single_html = function() { + return "<a class=\"chosen-single chosen-default\">\n <span>" + this.default_text + "</span>\n <div><b></b></div>\n</a>\n<div class=\"chosen-drop\">\n <div class=\"chosen-search\">\n <input class=\"chosen-search-input\" type=\"text\" autocomplete=\"off\" />\n </div>\n <ul class=\"chosen-results\"></ul>\n</div>"; + }; + + AbstractChosen.prototype.get_multi_html = function() { + return "<ul class=\"chosen-choices\">\n <li class=\"search-field\">\n <input class=\"chosen-search-input\" type=\"text\" autocomplete=\"off\" value=\"" + this.default_text + "\" />\n </li>\n</ul>\n<div class=\"chosen-drop\">\n <ul class=\"chosen-results\"></ul>\n</div>"; + }; + + AbstractChosen.prototype.get_no_results_html = function(terms) { + return "<li class=\"no-results\">\n " + this.results_none_found + " <span>" + terms + "</span>\n</li>"; + }; + + AbstractChosen.browser_is_supported = function() { + if ("Microsoft Internet Explorer" === window.navigator.appName) { + return document.documentMode >= 8; + } + if (/iP(od|hone)/i.test(window.navigator.userAgent) || /IEMobile/i.test(window.navigator.userAgent) || /Windows Phone/i.test(window.navigator.userAgent) || /BlackBerry/i.test(window.navigator.userAgent) || /BB10/i.test(window.navigator.userAgent) || /Android.*Mobile/i.test(window.navigator.userAgent)) { + return false; + } + return true; + }; + + AbstractChosen.default_multiple_text = "Select Some Options"; + + AbstractChosen.default_single_text = "Select an Option"; + + AbstractChosen.default_no_result_text = "No results match"; + + return AbstractChosen; + + })(); + + $ = jQuery; + + $.fn.extend({ + chosen: function(options) { + if (!AbstractChosen.browser_is_supported()) { + return this; + } + return this.each(function(input_field) { + var $this, chosen; + $this = $(this); + chosen = $this.data('chosen'); + if (options === 'destroy') { + if (chosen instanceof Chosen) { + chosen.destroy(); + } + return; + } + if (!(chosen instanceof Chosen)) { + $this.data('chosen', new Chosen(this, options)); + } + }); + } + }); + + Chosen = (function(_super) { + __extends(Chosen, _super); + + function Chosen() { + _ref = Chosen.__super__.constructor.apply(this, arguments); + return _ref; + } + + Chosen.prototype.setup = function() { + this.form_field_jq = $(this.form_field); + return this.current_selectedIndex = this.form_field.selectedIndex; + }; + + Chosen.prototype.set_up_html = function() { + var container_classes, container_props; + container_classes = ["chosen-container"]; + container_classes.push("chosen-container-" + (this.is_multiple ? "multi" : "single")); + if (this.inherit_select_classes && this.form_field.className) { + container_classes.push(this.form_field.className); + } + if (this.is_rtl) { + container_classes.push("chosen-rtl"); + } + container_props = { + 'class': container_classes.join(' '), + 'title': this.form_field.title + }; + if (this.form_field.id.length) { + container_props.id = this.form_field.id.replace(/[^\w]/g, '_') + "_chosen"; + } + this.container = $("<div />", container_props); + this.container.width(this.container_width()); + if (this.is_multiple) { + this.container.html(this.get_multi_html()); + } else { + this.container.html(this.get_single_html()); + } + this.form_field_jq.hide().after(this.container); + this.dropdown = this.container.find('div.chosen-drop').first(); + this.search_field = this.container.find('input').first(); + this.search_results = this.container.find('ul.chosen-results').first(); + this.search_field_scale(); + this.search_no_results = this.container.find('li.no-results').first(); + if (this.is_multiple) { + this.search_choices = this.container.find('ul.chosen-choices').first(); + this.search_container = this.container.find('li.search-field').first(); + } else { + this.search_container = this.container.find('div.chosen-search').first(); + this.selected_item = this.container.find('.chosen-single').first(); + } + this.results_build(); + this.set_tab_index(); + return this.set_label_behavior(); + }; + + Chosen.prototype.on_ready = function() { + return this.form_field_jq.trigger("chosen:ready", { + chosen: this + }); + }; + + Chosen.prototype.register_observers = function() { + var _this = this; + this.container.bind('touchstart.chosen', function(evt) { + _this.container_mousedown(evt); + }); + this.container.bind('touchend.chosen', function(evt) { + _this.container_mouseup(evt); + }); + this.container.bind('mousedown.chosen', function(evt) { + _this.container_mousedown(evt); + }); + this.container.bind('mouseup.chosen', function(evt) { + _this.container_mouseup(evt); + }); + this.container.bind('mouseenter.chosen', function(evt) { + _this.mouse_enter(evt); + }); + this.container.bind('mouseleave.chosen', function(evt) { + _this.mouse_leave(evt); + }); + this.search_results.bind('mouseup.chosen', function(evt) { + _this.search_results_mouseup(evt); + }); + this.search_results.bind('mouseover.chosen', function(evt) { + _this.search_results_mouseover(evt); + }); + this.search_results.bind('mouseout.chosen', function(evt) { + _this.search_results_mouseout(evt); + }); + this.search_results.bind('mousewheel.chosen DOMMouseScroll.chosen', function(evt) { + _this.search_results_mousewheel(evt); + }); + this.search_results.bind('touchstart.chosen', function(evt) { + _this.search_results_touchstart(evt); + }); + this.search_results.bind('touchmove.chosen', function(evt) { + _this.search_results_touchmove(evt); + }); + this.search_results.bind('touchend.chosen', function(evt) { + _this.search_results_touchend(evt); + }); + this.form_field_jq.bind("chosen:updated.chosen", function(evt) { + _this.results_update_field(evt); + }); + this.form_field_jq.bind("chosen:activate.chosen", function(evt) { + _this.activate_field(evt); + }); + this.form_field_jq.bind("chosen:open.chosen", function(evt) { + _this.container_mousedown(evt); + }); + this.form_field_jq.bind("chosen:close.chosen", function(evt) { + _this.close_field(evt); + }); + this.search_field.bind('blur.chosen', function(evt) { + _this.input_blur(evt); + }); + this.search_field.bind('keyup.chosen', function(evt) { + _this.keyup_checker(evt); + }); + this.search_field.bind('keydown.chosen', function(evt) { + _this.keydown_checker(evt); + }); + this.search_field.bind('focus.chosen', function(evt) { + _this.input_focus(evt); + }); + this.search_field.bind('cut.chosen', function(evt) { + _this.clipboard_event_checker(evt); + }); + this.search_field.bind('paste.chosen', function(evt) { + _this.clipboard_event_checker(evt); + }); + if (this.is_multiple) { + return this.search_choices.bind('click.chosen', function(evt) { + _this.choices_click(evt); + }); + } else { + return this.container.bind('click.chosen', function(evt) { + evt.preventDefault(); + }); + } + }; + + Chosen.prototype.destroy = function() { + $(this.container[0].ownerDocument).unbind('click.chosen', this.click_test_action); + if (this.form_field_label.length > 0) { + this.form_field_label.unbind('click.chosen'); + } + if (this.search_field[0].tabIndex) { + this.form_field_jq[0].tabIndex = this.search_field[0].tabIndex; + } + this.container.remove(); + this.form_field_jq.removeData('chosen'); + return this.form_field_jq.show(); + }; + + Chosen.prototype.search_field_disabled = function() { + this.is_disabled = this.form_field.disabled || this.form_field_jq.parents('fieldset').is(':disabled'); + this.container.toggleClass('chosen-disabled', this.is_disabled); + this.search_field[0].disabled = this.is_disabled; + if (!this.is_multiple) { + this.selected_item.unbind('focus.chosen', this.activate_field); + } + if (this.is_disabled) { + return this.close_field(); + } else if (!this.is_multiple) { + return this.selected_item.bind('focus.chosen', this.activate_field); + } + }; + + Chosen.prototype.container_mousedown = function(evt) { + var _ref1; + if (this.is_disabled) { + return; + } + if (evt && ((_ref1 = evt.type) === 'mousedown' || _ref1 === 'touchstart') && !this.results_showing) { + evt.preventDefault(); + } + if (!((evt != null) && ($(evt.target)).hasClass("search-choice-close"))) { + if (!this.active_field) { + if (this.is_multiple) { + this.search_field.val(""); + } + $(this.container[0].ownerDocument).bind('click.chosen', this.click_test_action); + this.results_show(); + } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chosen-single").length)) { + evt.preventDefault(); + this.results_toggle(); + } + return this.activate_field(); + } + }; + + Chosen.prototype.container_mouseup = function(evt) { + if (evt.target.nodeName === "ABBR" && !this.is_disabled) { + return this.results_reset(evt); + } + }; + + Chosen.prototype.search_results_mousewheel = function(evt) { + var delta; + if (evt.originalEvent) { + delta = evt.originalEvent.deltaY || -evt.originalEvent.wheelDelta || evt.originalEvent.detail; + } + if (delta != null) { + evt.preventDefault(); + if (evt.type === 'DOMMouseScroll') { + delta = delta * 40; + } + return this.search_results.scrollTop(delta + this.search_results.scrollTop()); + } + }; + + Chosen.prototype.blur_test = function(evt) { + if (!this.active_field && this.container.hasClass("chosen-container-active")) { + return this.close_field(); + } + }; + + Chosen.prototype.close_field = function() { + $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action); + this.active_field = false; + this.results_hide(); + this.container.removeClass("chosen-container-active"); + this.clear_backstroke(); + this.show_search_field_default(); + this.search_field_scale(); + return this.search_field.blur(); + }; + + Chosen.prototype.activate_field = function() { + if (this.is_disabled) { + return; + } + this.container.addClass("chosen-container-active"); + this.active_field = true; + this.search_field.val(this.search_field.val()); + return this.search_field.focus(); + }; + + Chosen.prototype.test_active_click = function(evt) { + var active_container; + active_container = $(evt.target).closest('.chosen-container'); + if (active_container.length && this.container[0] === active_container[0]) { + return this.active_field = true; + } else { + return this.close_field(); + } + }; + + Chosen.prototype.results_build = function() { + this.parsing = true; + this.selected_option_count = null; + this.results_data = SelectParser.select_to_array(this.form_field); + if (this.is_multiple) { + this.search_choices.find("li.search-choice").remove(); + } else if (!this.is_multiple) { + this.single_set_selected_text(); + if (this.disable_search || this.form_field.options.length <= this.disable_search_threshold) { + this.search_field[0].readOnly = true; + this.container.addClass("chosen-container-single-nosearch"); + } else { + this.search_field[0].readOnly = false; + this.container.removeClass("chosen-container-single-nosearch"); + } + } + this.update_results_content(this.results_option_build({ + first: true + })); + this.search_field_disabled(); + this.show_search_field_default(); + this.search_field_scale(); + return this.parsing = false; + }; + + Chosen.prototype.result_do_highlight = function(el) { + var high_bottom, high_top, maxHeight, visible_bottom, visible_top; + if (el.length) { + this.result_clear_highlight(); + this.result_highlight = el; + this.result_highlight.addClass("highlighted"); + maxHeight = parseInt(this.search_results.css("maxHeight"), 10); + visible_top = this.search_results.scrollTop(); + visible_bottom = maxHeight + visible_top; + high_top = this.result_highlight.position().top + this.search_results.scrollTop(); + high_bottom = high_top + this.result_highlight.outerHeight(); + if (high_bottom >= visible_bottom) { + return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0); + } else if (high_top < visible_top) { + return this.search_results.scrollTop(high_top); + } + } + }; + + Chosen.prototype.result_clear_highlight = function() { + if (this.result_highlight) { + this.result_highlight.removeClass("highlighted"); + } + return this.result_highlight = null; + }; + + Chosen.prototype.results_show = function() { + if (this.is_multiple && this.max_selected_options <= this.choices_count()) { + this.form_field_jq.trigger("chosen:maxselected", { + chosen: this + }); + return false; + } + this.container.addClass("chosen-with-drop"); + this.results_showing = true; + this.search_field.focus(); + this.search_field.val(this.get_search_field_value()); + this.winnow_results(); + return this.form_field_jq.trigger("chosen:showing_dropdown", { + chosen: this + }); + }; + + Chosen.prototype.update_results_content = function(content) { + return this.search_results.html(content); + }; + + Chosen.prototype.results_hide = function() { + if (this.results_showing) { + this.result_clear_highlight(); + this.container.removeClass("chosen-with-drop"); + this.form_field_jq.trigger("chosen:hiding_dropdown", { + chosen: this + }); + } + return this.results_showing = false; + }; + + Chosen.prototype.set_tab_index = function(el) { + var ti; + if (this.form_field.tabIndex) { + ti = this.form_field.tabIndex; + this.form_field.tabIndex = -1; + return this.search_field[0].tabIndex = ti; + } + }; + + Chosen.prototype.set_label_behavior = function() { + this.form_field_label = this.form_field_jq.parents("label"); + if (!this.form_field_label.length && this.form_field.id.length) { + this.form_field_label = $("label[for='" + this.form_field.id + "']"); + } + if (this.form_field_label.length > 0) { + return this.form_field_label.bind('click.chosen', this.label_click_handler); + } + }; + + Chosen.prototype.show_search_field_default = function() { + if (this.is_multiple && this.choices_count() < 1 && !this.active_field) { + this.search_field.val(this.default_text); + return this.search_field.addClass("default"); + } else { + this.search_field.val(""); + return this.search_field.removeClass("default"); + } + }; + + Chosen.prototype.search_results_mouseup = function(evt) { + var target; + target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); + if (target.length) { + this.result_highlight = target; + this.result_select(evt); + return this.search_field.focus(); + } + }; + + Chosen.prototype.search_results_mouseover = function(evt) { + var target; + target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); + if (target) { + return this.result_do_highlight(target); + } + }; + + Chosen.prototype.search_results_mouseout = function(evt) { + if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) { + return this.result_clear_highlight(); + } + }; + + Chosen.prototype.choice_build = function(item) { + var choice, close_link, + _this = this; + choice = $('<li />', { + "class": "search-choice" + }).html("<span>" + (this.choice_label(item)) + "</span>"); + if (item.disabled) { + choice.addClass('search-choice-disabled'); + } else { + close_link = $('<a />', { + "class": 'search-choice-close', + 'data-option-array-index': item.array_index + }); + close_link.bind('click.chosen', function(evt) { + return _this.choice_destroy_link_click(evt); + }); + choice.append(close_link); + } + return this.search_container.before(choice); + }; + + Chosen.prototype.choice_destroy_link_click = function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + if (!this.is_disabled) { + return this.choice_destroy($(evt.target)); + } + }; + + Chosen.prototype.choice_destroy = function(link) { + if (this.result_deselect(link[0].getAttribute("data-option-array-index"))) { + if (this.active_field) { + this.search_field.focus(); + } else { + this.show_search_field_default(); + } + if (this.is_multiple && this.choices_count() > 0 && this.get_search_field_value().length < 1) { + this.results_hide(); + } + link.parents('li').first().remove(); + return this.search_field_scale(); + } + }; + + Chosen.prototype.results_reset = function() { + this.reset_single_select_options(); + this.form_field.options[0].selected = true; + this.single_set_selected_text(); + this.show_search_field_default(); + this.results_reset_cleanup(); + this.trigger_form_field_change(); + if (this.active_field) { + return this.results_hide(); + } + }; + + Chosen.prototype.results_reset_cleanup = function() { + this.current_selectedIndex = this.form_field.selectedIndex; + return this.selected_item.find("abbr").remove(); + }; + + Chosen.prototype.result_select = function(evt) { + var high, item; + if (this.result_highlight) { + high = this.result_highlight; + this.result_clear_highlight(); + if (this.is_multiple && this.max_selected_options <= this.choices_count()) { + this.form_field_jq.trigger("chosen:maxselected", { + chosen: this + }); + return false; + } + if (this.is_multiple) { + high.removeClass("active-result"); + } else { + this.reset_single_select_options(); + } + high.addClass("result-selected"); + item = this.results_data[high[0].getAttribute("data-option-array-index")]; + item.selected = true; + this.form_field.options[item.options_index].selected = true; + this.selected_option_count = null; + if (this.is_multiple) { + this.choice_build(item); + } else { + this.single_set_selected_text(this.choice_label(item)); + } + if (!(this.is_multiple && (!this.hide_results_on_select || (evt.metaKey || evt.ctrlKey)))) { + this.results_hide(); + this.show_search_field_default(); + } + if (this.is_multiple || this.form_field.selectedIndex !== this.current_selectedIndex) { + this.trigger_form_field_change({ + selected: this.form_field.options[item.options_index].value + }); + } + this.current_selectedIndex = this.form_field.selectedIndex; + evt.preventDefault(); + return this.search_field_scale(); + } + }; + + Chosen.prototype.single_set_selected_text = function(text) { + if (text == null) { + text = this.default_text; + } + if (text === this.default_text) { + this.selected_item.addClass("chosen-default"); + } else { + this.single_deselect_control_build(); + this.selected_item.removeClass("chosen-default"); + } + return this.selected_item.find("span").html(text); + }; + + Chosen.prototype.result_deselect = function(pos) { + var result_data; + result_data = this.results_data[pos]; + if (!this.form_field.options[result_data.options_index].disabled) { + result_data.selected = false; + this.form_field.options[result_data.options_index].selected = false; + this.selected_option_count = null; + this.result_clear_highlight(); + if (this.results_showing) { + this.winnow_results(); + } + this.trigger_form_field_change({ + deselected: this.form_field.options[result_data.options_index].value + }); + this.search_field_scale(); + return true; + } else { + return false; + } + }; + + Chosen.prototype.single_deselect_control_build = function() { + if (!this.allow_single_deselect) { + return; + } + if (!this.selected_item.find("abbr").length) { + this.selected_item.find("span").first().after("<abbr class=\"search-choice-close\"></abbr>"); + } + return this.selected_item.addClass("chosen-single-with-deselect"); + }; + + Chosen.prototype.get_search_field_value = function() { + return this.search_field.val(); + }; + + Chosen.prototype.get_search_text = function() { + return this.escape_html($.trim(this.get_search_field_value())); + }; + + Chosen.prototype.escape_html = function(text) { + return $('<div/>').text(text).html(); + }; + + Chosen.prototype.winnow_results_set_highlight = function() { + var do_high, selected_results; + selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : []; + do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first(); + if (do_high != null) { + return this.result_do_highlight(do_high); + } + }; + + Chosen.prototype.no_results = function(terms) { + var no_results_html; + no_results_html = this.get_no_results_html(terms); + this.search_results.append(no_results_html); + return this.form_field_jq.trigger("chosen:no_results", { + chosen: this + }); + }; + + Chosen.prototype.no_results_clear = function() { + return this.search_results.find(".no-results").remove(); + }; + + Chosen.prototype.keydown_arrow = function() { + var next_sib; + if (this.results_showing && this.result_highlight) { + next_sib = this.result_highlight.nextAll("li.active-result").first(); + if (next_sib) { + return this.result_do_highlight(next_sib); + } + } else { + return this.results_show(); + } + }; + + Chosen.prototype.keyup_arrow = function() { + var prev_sibs; + if (!this.results_showing && !this.is_multiple) { + return this.results_show(); + } else if (this.result_highlight) { + prev_sibs = this.result_highlight.prevAll("li.active-result"); + if (prev_sibs.length) { + return this.result_do_highlight(prev_sibs.first()); + } else { + if (this.choices_count() > 0) { + this.results_hide(); + } + return this.result_clear_highlight(); + } + } + }; + + Chosen.prototype.keydown_backstroke = function() { + var next_available_destroy; + if (this.pending_backstroke) { + this.choice_destroy(this.pending_backstroke.find("a").first()); + return this.clear_backstroke(); + } else { + next_available_destroy = this.search_container.siblings("li.search-choice").last(); + if (next_available_destroy.length && !next_available_destroy.hasClass("search-choice-disabled")) { + this.pending_backstroke = next_available_destroy; + if (this.single_backstroke_delete) { + return this.keydown_backstroke(); + } else { + return this.pending_backstroke.addClass("search-choice-focus"); + } + } + } + }; + + Chosen.prototype.clear_backstroke = function() { + if (this.pending_backstroke) { + this.pending_backstroke.removeClass("search-choice-focus"); + } + return this.pending_backstroke = null; + }; + + Chosen.prototype.search_field_scale = function() { + var container_width, div, style, style_block, styles, width, _i, _len; + if (!this.is_multiple) { + return; + } + style_block = { + position: 'absolute', + left: '-1000px', + top: '-1000px', + display: 'none', + whiteSpace: 'pre' + }; + styles = ['fontSize', 'fontStyle', 'fontWeight', 'fontFamily', 'lineHeight', 'textTransform', 'letterSpacing']; + for (_i = 0, _len = styles.length; _i < _len; _i++) { + style = styles[_i]; + style_block[style] = this.search_field.css(style); + } + div = $('<div />').css(style_block); + div.text(this.get_search_field_value()); + $('body').append(div); + width = div.width() + 25; + div.remove(); + container_width = this.container.outerWidth(); + width = Math.min(container_width - 10, width); + return this.search_field.width(width); + }; + + Chosen.prototype.trigger_form_field_change = function(extra) { + this.form_field_jq.trigger("input", extra); + return this.form_field_jq.trigger("change", extra); + }; + + return Chosen; + + })(AbstractChosen); + +}).call(this); diff --git a/static_common/common/vendor/chosen-js/package.json b/static_common/common/vendor/chosen-js/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ccce3f4b1f05e1be919bead3b21aa51895fffc52 --- /dev/null +++ b/static_common/common/vendor/chosen-js/package.json @@ -0,0 +1,110 @@ +{ + "_args": [ + [ + { + "raw": "chosen-js@~1.7.0", + "scope": null, + "escapedName": "chosen-js", + "name": "chosen-js", + "rawSpec": "~1.7.0", + "spec": ">=1.7.0 <1.8.0", + "type": "range" + }, + "/mnt/d/repo/pyophase" + ] + ], + "_from": "chosen-js@>=1.7.0 <1.8.0", + "_id": "chosen-js@1.7.0", + "_inCache": true, + "_location": "/chosen-js", + "_nodeVersion": "7.7.4", + "_npmOperationalInternal": { + "host": "packages-18-east.internal.npmjs.com", + "tmp": "tmp/chosen-js-1.7.0.tgz_1490389234489_0.23706221161410213" + }, + "_npmUser": { + "name": "chosenjs", + "email": "chosenjs@getharvest.com" + }, + "_npmVersion": "4.1.2", + "_phantomChildren": {}, + "_requested": { + "raw": "chosen-js@~1.7.0", + "scope": null, + "escapedName": "chosen-js", + "name": "chosen-js", + "rawSpec": "~1.7.0", + "spec": ">=1.7.0 <1.8.0", + "type": "range" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/chosen-js/-/chosen-js-1.7.0.tgz", + "_shasum": "8ceb2e929e2a072886edd384d78989dfbffa58c3", + "_shrinkwrap": null, + "_spec": "chosen-js@~1.7.0", + "_where": "/mnt/d/repo/pyophase", + "bugs": { + "url": "https://github.com/harvesthq/chosen/issues" + }, + "contributors": [ + { + "name": "Patrick Filler", + "url": "https://github.com/pfiller" + }, + { + "name": "Christophe Coevoet", + "url": "https://github.com/stof" + }, + { + "name": "Ken Earley", + "url": "https://github.com/kenearley" + }, + { + "name": "Koen Punt", + "url": "https://github.com/koenpunt" + } + ], + "dependencies": {}, + "description": "Chosen is a JavaScript plugin that makes select boxes user-friendly. It is currently available in both jQuery and Prototype flavors.", + "devDependencies": {}, + "directories": {}, + "dist": { + "shasum": "8ceb2e929e2a072886edd384d78989dfbffa58c3", + "tarball": "https://registry.npmjs.org/chosen-js/-/chosen-js-1.7.0.tgz" + }, + "files": [ + "chosen.jquery.js", + "chosen.css", + "chosen-sprite@2x.png", + "chosen-sprite.png" + ], + "gitHead": "20457c69249226af89fda0b357591622b922b36a", + "homepage": "https://harvesthq.github.io/chosen/", + "keywords": [ + "select", + "multiselect", + "dropdown", + "form", + "input", + "ui" + ], + "license": "MIT", + "main": "chosen.jquery.js", + "maintainers": [ + { + "name": "chosenjs", + "email": "chosenjs@getharvest.com" + } + ], + "name": "chosen-js", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+https://github.com/harvesthq/chosen.git" + }, + "scripts": {}, + "version": "1.7.0" +} diff --git a/templates/base.html b/templates/base.html index 8ff7b8a65d101a1890b3abf30af83c54d72fad02..412b61095cac80628969ee5b75f3d0c9457deb8d 100644 --- a/templates/base.html +++ b/templates/base.html @@ -14,6 +14,7 @@ {% bootstrap_javascript jquery='slim' %} {% fontawesome_stylesheet %} + {% block imports %}{% endblock %} </head> <body> {% block language-switcher %} @@ -60,5 +61,7 @@ {% endblock %} </div> +{% block bottom_script %}{% endblock %} + </body> </html>