From 58c1936d7c2a2f68bea72cc11c0cd75acb46e224 Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Fri, 9 May 2025 15:20:49 +0200 Subject: [PATCH 01/19] chore: update requirements --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c48c84ea40..13e02d0e33 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -django==3.0 +django==4.2.11 flake8==3.7.0 pytest-django==3.9.0 \ No newline at end of file From 5f3d48e895f76f93ef4655fd7e797d2aaf5f23e5 Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Fri, 16 May 2025 14:40:16 +0200 Subject: [PATCH 02/19] refactor: clean db --- oc-lettings-site.sqlite3 | Bin 151552 -> 180224 bytes ...ng_address_remove_profile_user_and_more.py | 30 ++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 oc_lettings_site/migrations/0002_remove_letting_address_remove_profile_user_and_more.py diff --git a/oc-lettings-site.sqlite3 b/oc-lettings-site.sqlite3 index 3d885414f9f3ed046704e8b09bdcd5c791c82d42..8258bc7c2e30cc9e0e0eaa83ecda1f82af1c3ba9 100644 GIT binary patch delta 3126 zcma)8Yi!%r73LKw>qYU}l|9>a64Ornwq(kZEXkW|%eG|M^+UG&NCFfpEzuIKXGHo@ zqlF`<4bb&ZQWar0Q&WxQPyZKXI14*xXz%xr4_V`+B(hUTxLVF8Lm+x#^+qgU?9fu zJevq}0gmMvilVv$X(parWl9qPIuuGX99M!<>Esd{V*)E2lMc{{P#~U6Gu>3T%}Cjd z<{r}A-AhruHmk|$v{)&tyIP6tA9cxAoa7*w+)O|ii?Vak_vZiY+}iCBH&Q7%-^KIa zom+ak&1SDbiBv7P=oLOfQReOd9plA}NoiX$v1yJEBKcq%JVBPeA%AirRh1`#cV zUpm>c%Exx2@;R5m8_3bqnR#Wk614!~(?MVWc=n~P=9UVy9u#*Y?LlcMLp!$B6qAm# z9LFXTlvr|=+23@vG}LItSDg49fdb^=3AhADVLjBsPv8&X`^4wan#=r(=&!`~*X;x= z$BIi}DOUNZdkB;x)n={z*Z1MXX9)Zl{sO)Z&%iCnK?ZuE1s;GJ;{xSX`{to^c{tCW@$MM6sJD2&L zZu2n=Gy!~-W!6f0rz$bf25_;m8J;PDUE5$VLMOsIps4}_2LUenEG;uibUKMnjtGdx zPym$)>#V z_OG8t3G|wv8UXbe*oVAWXdeLQK<*S!6s`>c=RULQKBC3mMwDMDC$YDom00t%(nHwD#oFj}L1Ry(Wh)T%Xq&|J}+(WEs#O{)e`-^^ur zwYrf~BB05L3wLgT{i-feX*1&jb{jOPOtR7`Ds4tlIoPqgOor$LDIN(a*L7p3M5GhO zibNfftxibX5{cSnVa z_O7Tkl1&oX?&>H-C0iHH{}wD&Nwsm>rxHKP2ttZOEe@49ip{MdUvc~sD3*;{p+Acd zKhvMhWlrfgw+_{xZO!<1;(PdkL^DZ8q3|qr9)?>3n36I6iMm_w9Gj54-Zp-8mKcAu( zCfxJu9=~g4b)Ad&%oEOO?|OJOxM}p;?8z0kBQ_lMhxlM>eVO6SQ%<8Xd}N5X+vz7Q z$A;&^q4k)P=Z@0Tj+v-;Fv8Bek|SRCpl3ccXjz_#+N1Ub?`k4wjk=fCjnm^v@A6W# z*SzB4>9yV@l?--=W0ASYM#$-K*dmTOJHyWVE$$6!ni?IRILghAhRnk&YopOphp-;R{qgP_tSI_rB zSBTC$uGn7CP;bxnov+Qlb#6#AlMJQV@Cvi>^7&TXSTd5x7=gH|FH2vj-s}Hr!WATk%@7b6!18OSgj##o2@;2ADX_#!SIvT+U+tuNMsEZUZizP>DrFCPl|Z&{9ax6aKwA38_Cv2Hq=P637!cv!hsRc zBA^M-VOeCuB1TS5&61OIduUr#7{BM-o15G;$(J_9^tC1JQoC8(=G8W>i(M?W?b@wlWOf^C)7$2z$=W=2 zZ#tMD>uuG46ls^?0l`rwQo9E%28<#&-N1>U)FQa)s-p_xKoC)6%-3y~jk2~LIB>r2 z`*F_s{l3S@BAFD~f|+3Vw#yL4?b230{T(G(vGk{>N~#+(`RSVmLS^q*BrN zh!m8fDIu5?6XEEXz?8#A(L9zdH*6H;Lm^R+B-Wy$-6(XFkB=mR!-;rGh^K<76G?&7 z>*)#&Kc0#NN5nL#FRj+mR zAdrG72tybA2*`;`Z!*)y95aFcf_DayvCwdXQtA3AIIKTyaO!^3^=0IC9r@x2*0Poc4d*tI z?~dRjs@;4nDiB{kt~T}XW3rXeQ}PZfCqiO$WL$VouA=i-ns{<~0GANQ0B)uIA)ZJB z*r(aYkB=!@$TRZuC*^Hu1?%T5`WlY&>ytyHp|C3`MR-?3quuFsD9fI7Hyr46ojBAL z?|jDY=?Nqw0oM>O9f%zd_Z+J^*x4R<_IP*i-os+w0jVe4J?`xG)^{EYjrv>;m!sCv zSnKrI9L+5rXG=q4U2{`|v&qAUV$nDs%H0U!YU9~K+o=VHwnJ@Ny`aduWXRTj|MegZ z=o(S)LRJR%qEorYccC{>?v8*E&VAa3n#*hH4$4F=P}-f`yk<#L#NK8fQN`$w=~r=< zK7=X^%hZBCVwlm1`kI1oXXLYNua~t9`v@9E#V0o_-Jo-`h;0fQ)fS%*z35EwLu0}^ zT)u!e^Q+tTxBCO_wt)ZXp7s)3}QpM_z9`wS4gO(KTMkXSk#~+%*QBg_-<9tl0v>oTg;Rr8o zcay*cJVjbBU|a6$DDpA64?^fE#3=Rg`;7c6xpM&%^7%#lKAFCVeFKw^HLof#72H^X ze1orJmiJezRbagUWa(`jA%D!{Lh{)hHW?qjh9u{4J=@#zKS|6#v_TT{k;=)krh62+ zHl~oDU=P22f3j)TQYhMh!=5?(5z=PSE!r{1%pwPE*PbEj1*FvVUTyBoHz;h*G1K^O z$fDVQ;oT%=j4U!-p$u0t@_Po&pF diff --git a/oc_lettings_site/migrations/0002_remove_letting_address_remove_profile_user_and_more.py b/oc_lettings_site/migrations/0002_remove_letting_address_remove_profile_user_and_more.py new file mode 100644 index 0000000000..ec34d47d68 --- /dev/null +++ b/oc_lettings_site/migrations/0002_remove_letting_address_remove_profile_user_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 4.2.11 on 2025-05-16 12:00 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('oc_lettings_site', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='letting', + name='address', + ), + migrations.RemoveField( + model_name='profile', + name='user', + ), + migrations.DeleteModel( + name='Address', + ), + migrations.DeleteModel( + name='Letting', + ), + migrations.DeleteModel( + name='Profile', + ), + ] From a2660da0d69a1e6f8e3dc08a3e11d8354b8f2cd1 Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Fri, 16 May 2025 14:40:38 +0200 Subject: [PATCH 03/19] refactor: lettings app --- lettings/__init__.py | 0 lettings/admin.py | 6 +++ lettings/apps.py | 6 +++ lettings/migrations/0001_initial.py | 36 +++++++++++++++ .../0002_copy_data_from_old_models.py | 37 +++++++++++++++ lettings/migrations/__init__.py | 0 lettings/models.py | 22 +++++++++ lettings/templates/lettings/index.html | 45 +++++++++++++++++++ lettings/templates/lettings/letting.html | 41 +++++++++++++++++ lettings/tests.py | 3 ++ lettings/urls.py | 9 ++++ lettings/views.py | 15 +++++++ 12 files changed, 220 insertions(+) create mode 100644 lettings/__init__.py create mode 100644 lettings/admin.py create mode 100644 lettings/apps.py create mode 100644 lettings/migrations/0001_initial.py create mode 100644 lettings/migrations/0002_copy_data_from_old_models.py create mode 100644 lettings/migrations/__init__.py create mode 100644 lettings/models.py create mode 100644 lettings/templates/lettings/index.html create mode 100644 lettings/templates/lettings/letting.html create mode 100644 lettings/tests.py create mode 100644 lettings/urls.py create mode 100644 lettings/views.py diff --git a/lettings/__init__.py b/lettings/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lettings/admin.py b/lettings/admin.py new file mode 100644 index 0000000000..acd55bc056 --- /dev/null +++ b/lettings/admin.py @@ -0,0 +1,6 @@ +from django.contrib import admin +from .models import Letting, Address + +# Register your models here. +admin.site.register(Letting) +admin.site.register(Address) diff --git a/lettings/apps.py b/lettings/apps.py new file mode 100644 index 0000000000..63dada00c4 --- /dev/null +++ b/lettings/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class LettingsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'lettings' diff --git a/lettings/migrations/0001_initial.py b/lettings/migrations/0001_initial.py new file mode 100644 index 0000000000..bd7d8ded63 --- /dev/null +++ b/lettings/migrations/0001_initial.py @@ -0,0 +1,36 @@ +# Generated by Django 4.2.11 on 2025-05-16 11:59 + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Address', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('number', models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(9999)])), + ('street', models.CharField(max_length=64)), + ('city', models.CharField(max_length=64)), + ('state', models.CharField(max_length=2, validators=[django.core.validators.MinLengthValidator(2)])), + ('zip_code', models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(99999)])), + ('country_iso_code', models.CharField(max_length=3, validators=[django.core.validators.MinLengthValidator(3)])), + ], + ), + migrations.CreateModel( + name='Letting', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=256)), + ('address', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='lettings.address')), + ], + ), + ] diff --git a/lettings/migrations/0002_copy_data_from_old_models.py b/lettings/migrations/0002_copy_data_from_old_models.py new file mode 100644 index 0000000000..c70d60b390 --- /dev/null +++ b/lettings/migrations/0002_copy_data_from_old_models.py @@ -0,0 +1,37 @@ +from django.db import migrations + +def copy_lettings_and_addresses(apps, schema_editor): + OldAddress = apps.get_model('oc_lettings_site', 'Address') + OldLetting = apps.get_model('oc_lettings_site', 'Letting') + NewAddress = apps.get_model('lettings', 'Address') + NewLetting = apps.get_model('lettings', 'Letting') + + # Copier les adresses + old_to_new_address = {} + for old_addr in OldAddress.objects.all(): + new_addr = NewAddress.objects.create( + number=old_addr.number, + street=old_addr.street, + city=old_addr.city, + state=old_addr.state, + zip_code=old_addr.zip_code, + country_iso_code=old_addr.country_iso_code, + ) + old_to_new_address[old_addr.id] = new_addr + + # Copier les lettings + for old_letting in OldLetting.objects.all(): + NewLetting.objects.create( + title=old_letting.title, + address=old_to_new_address.get(old_letting.address_id) + ) + +class Migration(migrations.Migration): + dependencies = [ + ('lettings', '0001_initial'), + ('oc_lettings_site', '__first__'), + ] + + operations = [ + migrations.RunPython(copy_lettings_and_addresses), + ] \ No newline at end of file diff --git a/lettings/migrations/__init__.py b/lettings/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lettings/models.py b/lettings/models.py new file mode 100644 index 0000000000..8e76ef00d2 --- /dev/null +++ b/lettings/models.py @@ -0,0 +1,22 @@ +from django.db import models +from django.core.validators import MaxValueValidator, MinLengthValidator + + +class Address(models.Model): + number = models.PositiveIntegerField(validators=[MaxValueValidator(9999)]) + street = models.CharField(max_length=64) + city = models.CharField(max_length=64) + state = models.CharField(max_length=2, validators=[MinLengthValidator(2)]) + zip_code = models.PositiveIntegerField(validators=[MaxValueValidator(99999)]) + country_iso_code = models.CharField(max_length=3, validators=[MinLengthValidator(3)]) + + def __str__(self): + return f'{self.number} {self.street}' + + +class Letting(models.Model): + title = models.CharField(max_length=256) + address = models.OneToOneField(Address, on_delete=models.CASCADE) + + def __str__(self): + return self.title diff --git a/lettings/templates/lettings/index.html b/lettings/templates/lettings/index.html new file mode 100644 index 0000000000..0251067b6b --- /dev/null +++ b/lettings/templates/lettings/index.html @@ -0,0 +1,45 @@ +{% extends "base.html" %} +{% block title %}Lettings{% endblock title %} + +{% block content %} + + +
+
+
+

Lettings

+
+
+
+ +
+
+
+
+ {% if lettings_list %} + + {% else %} +

No lettings are available.

+ {% endif %} +
+
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/lettings/templates/lettings/letting.html b/lettings/templates/lettings/letting.html new file mode 100644 index 0000000000..3a050e03cc --- /dev/null +++ b/lettings/templates/lettings/letting.html @@ -0,0 +1,41 @@ +{% extends "base.html" %} +{% load static %} +{% block title %}{{ title }}{% endblock title %} + +{% block content %} + +
+
+
+

{{ title }}

+
+
+
+ +
+
+
+
+

{{ address.number }} {{ address.street }}

+

{{ address.city }}, {{ address.state }} {{ address.zip_code }}

+

{{ address.country_iso_code }}

+
+
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/lettings/tests.py b/lettings/tests.py new file mode 100644 index 0000000000..7ce503c2dd --- /dev/null +++ b/lettings/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/lettings/urls.py b/lettings/urls.py new file mode 100644 index 0000000000..f86b5ec42f --- /dev/null +++ b/lettings/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from . import views + +app_name = 'lettings' + +urlpatterns = [ + path('', views.index, name='index'), + path('/', views.letting, name='letting'), +] \ No newline at end of file diff --git a/lettings/views.py b/lettings/views.py new file mode 100644 index 0000000000..f1a4845edd --- /dev/null +++ b/lettings/views.py @@ -0,0 +1,15 @@ +from django.shortcuts import render, get_object_or_404 +from .models import Letting + +def index(request): + lettings_list = Letting.objects.all() + context = {'lettings_list': lettings_list} + return render(request, 'lettings/index.html', context) + +def letting(request, letting_id): + letting = get_object_or_404(Letting, id=letting_id) + context = { + 'title': letting.title, + 'address': letting.address, + } + return render(request, 'lettings/letting.html', context) From 051a32c9a35003240ffbc5c5f48ae0cc084dff64 Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Fri, 16 May 2025 14:40:57 +0200 Subject: [PATCH 04/19] refactor: profiles app --- profiles/__init__.py | 0 profiles/admin.py | 5 +++ profiles/apps.py | 6 +++ profiles/migrations/0001_initial.py | 25 +++++++++++ .../0002_copy_data_from_old_models.py | 22 ++++++++++ profiles/migrations/__init__.py | 0 profiles/models.py | 10 +++++ profiles/templates/profiles/index.html | 43 +++++++++++++++++++ profiles/templates/profiles/profile.html | 40 +++++++++++++++++ profiles/tests.py | 3 ++ profiles/urls.py | 9 ++++ profiles/views.py | 12 ++++++ 12 files changed, 175 insertions(+) create mode 100644 profiles/__init__.py create mode 100644 profiles/admin.py create mode 100644 profiles/apps.py create mode 100644 profiles/migrations/0001_initial.py create mode 100644 profiles/migrations/0002_copy_data_from_old_models.py create mode 100644 profiles/migrations/__init__.py create mode 100644 profiles/models.py create mode 100644 profiles/templates/profiles/index.html create mode 100644 profiles/templates/profiles/profile.html create mode 100644 profiles/tests.py create mode 100644 profiles/urls.py create mode 100644 profiles/views.py diff --git a/profiles/__init__.py b/profiles/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/profiles/admin.py b/profiles/admin.py new file mode 100644 index 0000000000..123dd95de0 --- /dev/null +++ b/profiles/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin +from .models import Profile + +# Register your models here. +admin.site.register(Profile) diff --git a/profiles/apps.py b/profiles/apps.py new file mode 100644 index 0000000000..d722976462 --- /dev/null +++ b/profiles/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ProfilesConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'profiles' diff --git a/profiles/migrations/0001_initial.py b/profiles/migrations/0001_initial.py new file mode 100644 index 0000000000..fae9ad6bb1 --- /dev/null +++ b/profiles/migrations/0001_initial.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.11 on 2025-05-16 11:59 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('favorite_city', models.CharField(blank=True, max_length=64)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/profiles/migrations/0002_copy_data_from_old_models.py b/profiles/migrations/0002_copy_data_from_old_models.py new file mode 100644 index 0000000000..2338da9b98 --- /dev/null +++ b/profiles/migrations/0002_copy_data_from_old_models.py @@ -0,0 +1,22 @@ +from django.db import migrations + +def copy_profiles(apps, schema_editor): + OldProfile = apps.get_model('oc_lettings_site', 'Profile') + NewProfile = apps.get_model('profiles', 'Profile') + User = apps.get_model('auth', 'User') + + for old_profile in OldProfile.objects.all(): + NewProfile.objects.create( + user=User.objects.get(pk=old_profile.user_id), + favorite_city=old_profile.favorite_city, + ) + +class Migration(migrations.Migration): + dependencies = [ + ('profiles', '0001_initial'), + ('oc_lettings_site', '__first__'), + ] + + operations = [ + migrations.RunPython(copy_profiles), + ] \ No newline at end of file diff --git a/profiles/migrations/__init__.py b/profiles/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/profiles/models.py b/profiles/models.py new file mode 100644 index 0000000000..84c85c1001 --- /dev/null +++ b/profiles/models.py @@ -0,0 +1,10 @@ +from django.db import models +from django.contrib.auth.models import User + + +class Profile(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + favorite_city = models.CharField(max_length=64, blank=True) + + def __str__(self): + return self.user.username diff --git a/profiles/templates/profiles/index.html b/profiles/templates/profiles/index.html new file mode 100644 index 0000000000..09ee8df3ec --- /dev/null +++ b/profiles/templates/profiles/index.html @@ -0,0 +1,43 @@ +{% extends "base.html" %} +{% block title %}Profiles{% endblock title %} + +{% block content %} +
+
+
+

Profiles

+
+
+
+ +
+
+
+
+ {% if profiles_list %} + + {% else %} +

No profiles are available.

+ {% endif %} +
+
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/profiles/templates/profiles/profile.html b/profiles/templates/profiles/profile.html new file mode 100644 index 0000000000..c87f86d5f2 --- /dev/null +++ b/profiles/templates/profiles/profile.html @@ -0,0 +1,40 @@ +{% extends "base.html" %} +{% block title %}{{ profile.user.username }}{% endblock title %} + +{% block content %} +
+
+
+

{{ profile.user.username }}

+
+
+
+ +
+
+
+
+

First name : {{ profile.user.first_name }}

+

Last name : {{ profile.user.last_name }}

+

Email : {{ profile.user.email }}

+

Favorite city : {{ profile.favorite_city }}

+
+
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/profiles/tests.py b/profiles/tests.py new file mode 100644 index 0000000000..7ce503c2dd --- /dev/null +++ b/profiles/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/profiles/urls.py b/profiles/urls.py new file mode 100644 index 0000000000..e97f355941 --- /dev/null +++ b/profiles/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from . import views + +app_name = 'profiles' + +urlpatterns = [ + path('', views.index, name='index'), + path('/', views.profile, name='profile'), +] \ No newline at end of file diff --git a/profiles/views.py b/profiles/views.py new file mode 100644 index 0000000000..e9ffd6d7d9 --- /dev/null +++ b/profiles/views.py @@ -0,0 +1,12 @@ +from django.shortcuts import render, get_object_or_404 +from .models import Profile + +def index(request): + profiles_list = Profile.objects.all() + context = {'profiles_list': profiles_list} + return render(request, 'profiles/index.html', context) + +def profile(request, username): + profile = get_object_or_404(Profile, user__username=username) + context = {'profile': profile} + return render(request, 'profiles/profile.html', context) From 048abb99ed8592e7ca1b1fd07cee2ecf89e3f9f8 Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Fri, 16 May 2025 14:41:33 +0200 Subject: [PATCH 05/19] refactor: templates --- .../templates}/base.html | 6 +-- .../templates}/index.html | 6 +-- templates/letting.html | 41 ----------------- templates/lettings_index.html | 45 ------------------- 4 files changed, 6 insertions(+), 92 deletions(-) rename {templates => oc_lettings_site/templates}/base.html (97%) rename {templates => oc_lettings_site/templates}/index.html (90%) delete mode 100644 templates/letting.html delete mode 100644 templates/lettings_index.html diff --git a/templates/base.html b/oc_lettings_site/templates/base.html similarity index 97% rename from templates/base.html rename to oc_lettings_site/templates/base.html index ab7addba01..a480792d39 100644 --- a/templates/base.html +++ b/oc_lettings_site/templates/base.html @@ -24,10 +24,10 @@
Logo Orange County Lettings @@ -64,4 +64,4 @@ }); - \ No newline at end of file + \ No newline at end of file diff --git a/templates/index.html b/oc_lettings_site/templates/index.html similarity index 90% rename from templates/index.html rename to oc_lettings_site/templates/index.html index 71a8e61a46..cf7f8d8122 100644 --- a/templates/index.html +++ b/oc_lettings_site/templates/index.html @@ -14,13 +14,13 @@

Welcome to Holiday Homes

-{% endblock %} \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/templates/letting.html b/templates/letting.html deleted file mode 100644 index 7e5f3a73fd..0000000000 --- a/templates/letting.html +++ /dev/null @@ -1,41 +0,0 @@ -{% extends "base.html" %} -{% load static %} -{% block title %}{{ title }}{% endblock title %} - -{% block content %} - -
-
-
-

{{ title }}

-
-
-
- -
-
-
-
-

{{ address.number }} {{ address.street }}

-

{{ address.city }}, {{ address.state }} {{ address.zip_code }}

-

{{ address.country_iso_code }}

-
-
-
- - - -{% endblock %} \ No newline at end of file diff --git a/templates/lettings_index.html b/templates/lettings_index.html deleted file mode 100644 index 92857a78d9..0000000000 --- a/templates/lettings_index.html +++ /dev/null @@ -1,45 +0,0 @@ -{% extends "base.html" %} -{% block title %}Lettings{% endblock title %} - -{% block content %} - - -
-
-
-

Lettings

-
-
-
- -
-
-
-
- {% if lettings_list %} - - {% else %} -

No lettings are available.

- {% endif %} -
-
-
- - - -{% endblock %} \ No newline at end of file From f5b2c25d0de663c7e1d8030f0fa0b7591d863be0 Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Fri, 16 May 2025 14:41:50 +0200 Subject: [PATCH 06/19] refactor: main app --- oc_lettings_site/admin.py | 10 +-------- oc_lettings_site/models.py | 32 +--------------------------- oc_lettings_site/settings.py | 4 +++- oc_lettings_site/urls.py | 9 +++----- oc_lettings_site/views.py | 41 ------------------------------------ 5 files changed, 8 insertions(+), 88 deletions(-) diff --git a/oc_lettings_site/admin.py b/oc_lettings_site/admin.py index 63328c6dd3..d29977c6bb 100644 --- a/oc_lettings_site/admin.py +++ b/oc_lettings_site/admin.py @@ -1,10 +1,2 @@ from django.contrib import admin - -from .models import Letting -from .models import Address -from .models import Profile - - -admin.site.register(Letting) -admin.site.register(Address) -admin.site.register(Profile) +# Les modèles ont été déplacés dans les applications 'lettings' et 'profiles'. diff --git a/oc_lettings_site/models.py b/oc_lettings_site/models.py index ed255e8c11..65bb1527fd 100644 --- a/oc_lettings_site/models.py +++ b/oc_lettings_site/models.py @@ -1,31 +1 @@ -from django.db import models -from django.core.validators import MaxValueValidator, MinLengthValidator -from django.contrib.auth.models import User - - -class Address(models.Model): - number = models.PositiveIntegerField(validators=[MaxValueValidator(9999)]) - street = models.CharField(max_length=64) - city = models.CharField(max_length=64) - state = models.CharField(max_length=2, validators=[MinLengthValidator(2)]) - zip_code = models.PositiveIntegerField(validators=[MaxValueValidator(99999)]) - country_iso_code = models.CharField(max_length=3, validators=[MinLengthValidator(3)]) - - def __str__(self): - return f'{self.number} {self.street}' - - -class Letting(models.Model): - title = models.CharField(max_length=256) - address = models.OneToOneField(Address, on_delete=models.CASCADE) - - def __str__(self): - return self.title - - -class Profile(models.Model): - user = models.OneToOneField(User, on_delete=models.CASCADE) - favorite_city = models.CharField(max_length=64, blank=True) - - def __str__(self): - return self.user.username +# Les modèles ont été déplacés dans les applications 'lettings' et 'profiles'. diff --git a/oc_lettings_site/settings.py b/oc_lettings_site/settings.py index a18bee8106..ac2ec49c90 100644 --- a/oc_lettings_site/settings.py +++ b/oc_lettings_site/settings.py @@ -28,6 +28,8 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'lettings', + 'profiles', ] MIDDLEWARE = [ @@ -45,7 +47,7 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates')], + 'DIRS': [os.path.join(BASE_DIR, 'oc_lettings_site/templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/oc_lettings_site/urls.py b/oc_lettings_site/urls.py index f0ff5897ab..71d2e86c5a 100644 --- a/oc_lettings_site/urls.py +++ b/oc_lettings_site/urls.py @@ -1,13 +1,10 @@ from django.contrib import admin -from django.urls import path - +from django.urls import path, include from . import views urlpatterns = [ path('', views.index, name='index'), - path('lettings/', views.lettings_index, name='lettings_index'), - path('lettings//', views.letting, name='letting'), - path('profiles/', views.profiles_index, name='profiles_index'), - path('profiles//', views.profile, name='profile'), + path('lettings/', include('lettings.urls', namespace='lettings')), + path('profiles/', include('profiles.urls', namespace='profiles')), path('admin/', admin.site.urls), ] diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index a72db27074..cbd3ce2411 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -1,45 +1,4 @@ from django.shortcuts import render -from .models import Letting, Profile - - - -# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque molestie quam lobortis leo consectetur ullamcorper non id est. Praesent dictum, nulla eget feugiat sagittis, sem mi convallis eros, -# vitae dapibus nisi lorem dapibus sem. Maecenas pharetra purus ipsum, eget consequat ipsum lobortis quis. Phasellus eleifend ex auctor venenatis tempus. -# Aliquam vitae erat ac orci placerat luctus. Nullam elementum urna nisi, pellentesque iaculis enim cursus in. Praesent volutpat porttitor magna, non finibus neque cursus id. def index(request): return render(request, 'index.html') - -# Aenean leo magna, vestibulum et tincidunt fermentum, consectetur quis velit. Sed non placerat massa. Integer est nunc, pulvinar a -# tempor et, bibendum id arcu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Cras eget scelerisque -def lettings_index(request): - lettings_list = Letting.objects.all() - context = {'lettings_list': lettings_list} - return render(request, 'lettings_index.html', context) - - -#Cras ultricies dignissim purus, vitae hendrerit ex varius non. In accumsan porta nisl id eleifend. Praesent dignissim, odio eu consequat pretium, purus urna vulputate arcu, vitae efficitur -# lacus justo nec purus. Aenean finibus faucibus lectus at porta. Maecenas auctor, est ut luctus congue, dui enim mattis enim, ac condimentum velit libero in magna. Suspendisse potenti. In tempus a nisi sed laoreet. -# Suspendisse porta dui eget sem accumsan interdum. Ut quis urna pellentesque justo mattis ullamcorper ac non tellus. In tristique mauris eu velit fermentum, tempus pharetra est luctus. Vivamus consequat aliquam libero, eget bibendum lorem. Sed non dolor risus. Mauris condimentum auctor elementum. Donec quis nisi ligula. Integer vehicula tincidunt enim, ac lacinia augue pulvinar sit amet. -def letting(request, letting_id): - letting = Letting.objects.get(id=letting_id) - context = { - 'title': letting.title, - 'address': letting.address, - } - return render(request, 'letting.html', context) - -# Sed placerat quam in pulvinar commodo. Nullam laoreet consectetur ex, sed consequat libero pulvinar eget. Fusc -# faucibus, urna quis auctor pharetra, massa dolor cursus neque, quis dictum lacus d -def profiles_index(request): - profiles_list = Profile.objects.all() - context = {'profiles_list': profiles_list} - return render(request, 'profiles_index.html', context) - -# Aliquam sed metus eget nisi tincidunt ornare accumsan eget lac -# laoreet neque quis, pellentesque dui. Nullam facilisis pharetra vulputate. Sed tincidunt, dolor id facilisis fringilla, eros leo tristique lacus, -# it. Nam aliquam dignissim congue. Pellentesque habitant morbi tristique senectus et netus et males -def profile(request, username): - profile = Profile.objects.get(user__username=username) - context = {'profile': profile} - return render(request, 'profile.html', context) From d84c8c7ea2bfd12a580e755667a6eef2d3a34c2e Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Fri, 23 May 2025 15:00:36 +0200 Subject: [PATCH 07/19] feat: error 404 and 500 templates --- .../migrations/0002_copy_data_from_old_models.py | 1 - oc_lettings_site/settings.py | 2 +- oc_lettings_site/templates/404.html | 12 ++++++++++++ oc_lettings_site/templates/500.html | 13 +++++++++++++ oc_lettings_site/urls.py | 8 +++++++- oc_lettings_site/views.py | 9 +++++++++ 6 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 oc_lettings_site/templates/404.html create mode 100644 oc_lettings_site/templates/500.html diff --git a/lettings/migrations/0002_copy_data_from_old_models.py b/lettings/migrations/0002_copy_data_from_old_models.py index c70d60b390..fd16f02d90 100644 --- a/lettings/migrations/0002_copy_data_from_old_models.py +++ b/lettings/migrations/0002_copy_data_from_old_models.py @@ -6,7 +6,6 @@ def copy_lettings_and_addresses(apps, schema_editor): NewAddress = apps.get_model('lettings', 'Address') NewLetting = apps.get_model('lettings', 'Letting') - # Copier les adresses old_to_new_address = {} for old_addr in OldAddress.objects.all(): new_addr = NewAddress.objects.create( diff --git a/oc_lettings_site/settings.py b/oc_lettings_site/settings.py index ac2ec49c90..d00ad365ac 100644 --- a/oc_lettings_site/settings.py +++ b/oc_lettings_site/settings.py @@ -15,7 +15,7 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['localhost', '127.0.0.1'] # Application definition diff --git a/oc_lettings_site/templates/404.html b/oc_lettings_site/templates/404.html new file mode 100644 index 0000000000..4d71daac0c --- /dev/null +++ b/oc_lettings_site/templates/404.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block title %}Page non trouvée{% endblock %} + +{% block content %} +
+

404

+

Oops !

+

La page que vous recherchez n'existe pas.

+ Retour à l'accueil +
+{% endblock %} diff --git a/oc_lettings_site/templates/500.html b/oc_lettings_site/templates/500.html new file mode 100644 index 0000000000..725094beac --- /dev/null +++ b/oc_lettings_site/templates/500.html @@ -0,0 +1,13 @@ +{% extends 'base.html' %} + +{% block title %}Erreur serveur{% endblock %} + +{% block content %} +
+

500

+

Oops !

+

Une erreur inattendue s'est produite.

+

Notre équipe technique a été notifiée et travaille à résoudre le problème.

+ Retour à l'accueil +
+{% endblock %} diff --git a/oc_lettings_site/urls.py b/oc_lettings_site/urls.py index 71d2e86c5a..6395d2933e 100644 --- a/oc_lettings_site/urls.py +++ b/oc_lettings_site/urls.py @@ -1,5 +1,8 @@ from django.contrib import admin from django.urls import path, include +from django.conf import settings +from django.conf.urls.static import static + from . import views urlpatterns = [ @@ -7,4 +10,7 @@ path('lettings/', include('lettings.urls', namespace='lettings')), path('profiles/', include('profiles.urls', namespace='profiles')), path('admin/', admin.site.urls), -] + # Test URLs for error pages + path('404/', views.test_404, name='test_404'), + path('500/', views.test_500, name='test_500'), +] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index cbd3ce2411..508217a5d2 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -1,4 +1,13 @@ from django.shortcuts import render +from django.http import Http404 def index(request): return render(request, 'index.html') + +def test_404(request): + raise Http404("Page de test 404") + +def test_500(request): + # Forcer une erreur 500 en divisant par zéro + division_by_zero = 1 / 0 + return render(request, 'index.html') From 18276800e270defc1e4ddc8475e6122175c0e7d4 Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Fri, 23 May 2025 15:14:13 +0200 Subject: [PATCH 08/19] docs:add docstings --- lettings/models.py | 20 ++++++++++++++++++++ lettings/views.py | 21 +++++++++++++++++++++ oc_lettings_site/views.py | 28 +++++++++++++++++++++++++++- profiles/models.py | 12 ++++++++++++ profiles/views.py | 22 ++++++++++++++++++++++ 5 files changed, 102 insertions(+), 1 deletion(-) diff --git a/lettings/models.py b/lettings/models.py index 8e76ef00d2..4baab75e43 100644 --- a/lettings/models.py +++ b/lettings/models.py @@ -3,6 +3,12 @@ class Address(models.Model): + """ + Model representing a physical address. + + This model stores : + number, street, city, state, zip code, and country code. + """ number = models.PositiveIntegerField(validators=[MaxValueValidator(9999)]) street = models.CharField(max_length=64) city = models.CharField(max_length=64) @@ -11,12 +17,26 @@ class Address(models.Model): country_iso_code = models.CharField(max_length=3, validators=[MinLengthValidator(3)]) def __str__(self): + """ + Returns a string representation of the address. + + Returns: + str: The address in the format 'number street' + """ return f'{self.number} {self.street}' class Letting(models.Model): + """ + Model representing a property letting. + + This model stores title and associated address. + """ title = models.CharField(max_length=256) address = models.OneToOneField(Address, on_delete=models.CASCADE) def __str__(self): + """ + Returns the title of the letting. + """ return self.title diff --git a/lettings/views.py b/lettings/views.py index f1a4845edd..d23516c266 100644 --- a/lettings/views.py +++ b/lettings/views.py @@ -2,11 +2,32 @@ from .models import Letting def index(request): + """ + View function for the lettings list page. + + Args: + request: The HTTP request object + Returns: + template 'lettings/index.html' with a list of all lettings + """ lettings_list = Letting.objects.all() context = {'lettings_list': lettings_list} return render(request, 'lettings/index.html', context) def letting(request, letting_id): + """ + View function for displaying a specific letting's details. + + Args: + request: The HTTP request object + letting_id: The ID of the letting to display + + Returns: + template 'lettings/letting.html' with the requested letting's details + + Raises: + Http404: If the letting with the given ID doesn't exist + """ letting = get_object_or_404(Letting, id=letting_id) context = { 'title': letting.title, diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index 508217a5d2..47341afde5 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -2,12 +2,38 @@ from django.http import Http404 def index(request): + """ + View function for the home page. + + Args: + request: The HTTP request object + + Returns: + Rendered template 'index.html' + """ return render(request, 'index.html') def test_404(request): + """ + Test view that raises a 404 error. + + Args: + request: The HTTP request object + + Raises: + Http404: Always raises a 404 error for testing purposes + """ raise Http404("Page de test 404") def test_500(request): - # Forcer une erreur 500 en divisant par zéro + """ + Test view that raises a 500 error by performing a division by zero. + + Args: + request: The HTTP request object + + Returns: + This function never returns as it raises a ZeroDivisionError + """ division_by_zero = 1 / 0 return render(request, 'index.html') diff --git a/profiles/models.py b/profiles/models.py index 84c85c1001..84d34c12cb 100644 --- a/profiles/models.py +++ b/profiles/models.py @@ -3,8 +3,20 @@ class Profile(models.Model): + """ + Model representing a user profile. + + This model extends the default Django User model with additional information + about the user's favorite city. + """ user = models.OneToOneField(User, on_delete=models.CASCADE) favorite_city = models.CharField(max_length=64, blank=True) def __str__(self): + """ + Returns the username of the associated user. + + Returns: + str: The username of the user + """ return self.user.username diff --git a/profiles/views.py b/profiles/views.py index e9ffd6d7d9..6688410fee 100644 --- a/profiles/views.py +++ b/profiles/views.py @@ -2,11 +2,33 @@ from .models import Profile def index(request): + """ + View function for the profiles list page. + + Args: + request: The HTTP request object + + Returns: + Rendered template 'profiles/index.html' with a list of all profiles + """ profiles_list = Profile.objects.all() context = {'profiles_list': profiles_list} return render(request, 'profiles/index.html', context) def profile(request, username): + """ + View function for displaying a specific user's profile. + + Args: + request: The HTTP request object + username: The username of the profile to display + + Returns: + Rendered template 'profiles/profile.html' with the requested profile + + Raises: + Http404: If the profile with the given username doesn't exist + """ profile = get_object_or_404(Profile, user__username=username) context = {'profile': profile} return render(request, 'profiles/profile.html', context) From cf670d1e89769a7378ad20698a0d18726b6e72ad Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Fri, 23 May 2025 15:37:01 +0200 Subject: [PATCH 09/19] chore: clean code --- lettings/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lettings/models.py b/lettings/models.py index 4baab75e43..0a507536ff 100644 --- a/lettings/models.py +++ b/lettings/models.py @@ -30,7 +30,7 @@ class Letting(models.Model): """ Model representing a property letting. - This model stores title and associated address. + This model stores title and associated addresses. """ title = models.CharField(max_length=256) address = models.OneToOneField(Address, on_delete=models.CASCADE) From e55deac6934f15810ccd604158eb7c1beccc95de Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Mon, 26 May 2025 11:03:16 +0200 Subject: [PATCH 10/19] chore: clean code --- lettings/models.py | 3 --- lettings/urls.py | 2 +- lettings/views.py | 8 +++----- oc_lettings_site/settings.py | 2 +- oc_lettings_site/views.py | 9 +++------ profiles/models.py | 2 -- profiles/urls.py | 2 +- profiles/views.py | 7 ++----- 8 files changed, 11 insertions(+), 24 deletions(-) diff --git a/lettings/models.py b/lettings/models.py index 0a507536ff..c4abb499f0 100644 --- a/lettings/models.py +++ b/lettings/models.py @@ -5,7 +5,6 @@ class Address(models.Model): """ Model representing a physical address. - This model stores : number, street, city, state, zip code, and country code. """ @@ -19,7 +18,6 @@ class Address(models.Model): def __str__(self): """ Returns a string representation of the address. - Returns: str: The address in the format 'number street' """ @@ -29,7 +27,6 @@ def __str__(self): class Letting(models.Model): """ Model representing a property letting. - This model stores title and associated addresses. """ title = models.CharField(max_length=256) diff --git a/lettings/urls.py b/lettings/urls.py index f86b5ec42f..b2f0174c74 100644 --- a/lettings/urls.py +++ b/lettings/urls.py @@ -6,4 +6,4 @@ urlpatterns = [ path('', views.index, name='index'), path('/', views.letting, name='letting'), -] \ No newline at end of file +] diff --git a/lettings/views.py b/lettings/views.py index d23516c266..c9c4caf556 100644 --- a/lettings/views.py +++ b/lettings/views.py @@ -1,12 +1,12 @@ from django.shortcuts import render, get_object_or_404 from .models import Letting + def index(request): """ View function for the lettings list page. - Args: - request: The HTTP request object + request: The HTTP request object Returns: template 'lettings/index.html' with a list of all lettings """ @@ -14,17 +14,15 @@ def index(request): context = {'lettings_list': lettings_list} return render(request, 'lettings/index.html', context) + def letting(request, letting_id): """ View function for displaying a specific letting's details. - Args: request: The HTTP request object letting_id: The ID of the letting to display - Returns: template 'lettings/letting.html' with the requested letting's details - Raises: Http404: If the letting with the given ID doesn't exist """ diff --git a/oc_lettings_site/settings.py b/oc_lettings_site/settings.py index d00ad365ac..be98636d2a 100644 --- a/oc_lettings_site/settings.py +++ b/oc_lettings_site/settings.py @@ -113,4 +113,4 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATIC_URL = '/static/' -STATICFILES_DIRS = [BASE_DIR / "static",] +STATICFILES_DIRS = [BASE_DIR / "static"] diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index 47341afde5..7962fef08b 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -1,37 +1,34 @@ from django.shortcuts import render from django.http import Http404 + def index(request): """ View function for the home page. - Args: request: The HTTP request object - Returns: Rendered template 'index.html' """ return render(request, 'index.html') + def test_404(request): """ Test view that raises a 404 error. - Args: request: The HTTP request object - Raises: Http404: Always raises a 404 error for testing purposes """ raise Http404("Page de test 404") + def test_500(request): """ Test view that raises a 500 error by performing a division by zero. - Args: request: The HTTP request object - Returns: This function never returns as it raises a ZeroDivisionError """ diff --git a/profiles/models.py b/profiles/models.py index 84d34c12cb..3dfee9cae8 100644 --- a/profiles/models.py +++ b/profiles/models.py @@ -5,7 +5,6 @@ class Profile(models.Model): """ Model representing a user profile. - This model extends the default Django User model with additional information about the user's favorite city. """ @@ -15,7 +14,6 @@ class Profile(models.Model): def __str__(self): """ Returns the username of the associated user. - Returns: str: The username of the user """ diff --git a/profiles/urls.py b/profiles/urls.py index e97f355941..9a6d0ee8e3 100644 --- a/profiles/urls.py +++ b/profiles/urls.py @@ -6,4 +6,4 @@ urlpatterns = [ path('', views.index, name='index'), path('/', views.profile, name='profile'), -] \ No newline at end of file +] diff --git a/profiles/views.py b/profiles/views.py index 6688410fee..96ccf09ed9 100644 --- a/profiles/views.py +++ b/profiles/views.py @@ -1,13 +1,12 @@ from django.shortcuts import render, get_object_or_404 from .models import Profile + def index(request): """ View function for the profiles list page. - Args: request: The HTTP request object - Returns: Rendered template 'profiles/index.html' with a list of all profiles """ @@ -15,17 +14,15 @@ def index(request): context = {'profiles_list': profiles_list} return render(request, 'profiles/index.html', context) + def profile(request, username): """ View function for displaying a specific user's profile. - Args: request: The HTTP request object username: The username of the profile to display - Returns: Rendered template 'profiles/profile.html' with the requested profile - Raises: Http404: If the profile with the given username doesn't exist """ From 483a9bc1453f96a6da33e776fe971ea6f455830d Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Fri, 30 May 2025 12:31:57 +0200 Subject: [PATCH 11/19] feat: coverage-tests --- .coverage | Bin 0 -> 53248 bytes .gitignore | 1 + Makefile | 33 +++++++++++ lettings/tests.py | 52 +++++++++++++++++- oc_lettings_site/tests.py | 31 +++++++++++ .../0002_copy_data_from_old_models.py | 22 -------- profiles/tests.py | 50 ++++++++++++++++- 7 files changed, 163 insertions(+), 26 deletions(-) create mode 100644 .coverage create mode 100644 Makefile delete mode 100644 profiles/migrations/0002_copy_data_from_old_models.py diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..ed0d4d7fac4599a6a3a71e972aa662f129729af7 GIT binary patch literal 53248 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 bfCP{L5 Date: Fri, 30 May 2025 13:36:32 +0200 Subject: [PATCH 12/19] feat: pluralisation --- lettings/models.py | 6 ++++++ profiles/models.py | 3 +++ 2 files changed, 9 insertions(+) diff --git a/lettings/models.py b/lettings/models.py index c4abb499f0..84f1d51f36 100644 --- a/lettings/models.py +++ b/lettings/models.py @@ -15,6 +15,9 @@ class Address(models.Model): zip_code = models.PositiveIntegerField(validators=[MaxValueValidator(99999)]) country_iso_code = models.CharField(max_length=3, validators=[MinLengthValidator(3)]) + class Meta: + verbose_name_plural = "Addresses" + def __str__(self): """ Returns a string representation of the address. @@ -32,6 +35,9 @@ class Letting(models.Model): title = models.CharField(max_length=256) address = models.OneToOneField(Address, on_delete=models.CASCADE) + class Meta: + verbose_name_plural = "Lettings" + def __str__(self): """ Returns the title of the letting. diff --git a/profiles/models.py b/profiles/models.py index 3dfee9cae8..9ac020da62 100644 --- a/profiles/models.py +++ b/profiles/models.py @@ -11,6 +11,9 @@ class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) favorite_city = models.CharField(max_length=64, blank=True) + class Meta: + verbose_name_plural = "Profiles" + def __str__(self): """ Returns the username of the associated user. From 6e85e04cc183db2803d8dc4036f55d7dcb63978f Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Sat, 31 May 2025 19:10:24 +0200 Subject: [PATCH 13/19] chore:clean code flake8 --- lettings/tests.py | 5 ----- oc_lettings_site/admin.py | 1 - oc_lettings_site/tests.py | 6 +++--- oc_lettings_site/views.py | 2 +- profiles/tests.py | 10 +++++----- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/lettings/tests.py b/lettings/tests.py index 6e4b835821..dcbbcc52de 100644 --- a/lettings/tests.py +++ b/lettings/tests.py @@ -24,7 +24,6 @@ def test_index_view(self): """Test the index view.""" url = reverse('lettings:index') response = self.client.get(url) - self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'lettings/index.html') self.assertIn('lettings_list', response.context) @@ -33,10 +32,8 @@ def test_index_view(self): def test_letting_view(self): """Test the letting detail view.""" - url = reverse('lettings:letting', args=[self.letting.id]) response = self.client.get(url) - self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'lettings/letting.html') self.assertEqual(response.context['title'], self.letting.title) @@ -44,8 +41,6 @@ def test_letting_view(self): def test_letting_view_404(self): """Test the letting detail view with non-existent letting.""" - url = reverse('lettings:letting', args=[999]) response = self.client.get(url) - self.assertEqual(response.status_code, 404) diff --git a/oc_lettings_site/admin.py b/oc_lettings_site/admin.py index d29977c6bb..65bb1527fd 100644 --- a/oc_lettings_site/admin.py +++ b/oc_lettings_site/admin.py @@ -1,2 +1 @@ -from django.contrib import admin # Les modèles ont été déplacés dans les applications 'lettings' et 'profiles'. diff --git a/oc_lettings_site/tests.py b/oc_lettings_site/tests.py index 2884106360..656ffe7894 100644 --- a/oc_lettings_site/tests.py +++ b/oc_lettings_site/tests.py @@ -1,6 +1,5 @@ from django.test import TestCase, Client from django.urls import reverse -from django.http import Http404 class OCLettingsSiteViewsTest(TestCase): @@ -12,14 +11,14 @@ def test_index_view(self): """Test the index view.""" url = reverse('index') response = self.client.get(url) - + self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'index.html') def test_404_view(self): """Test the 404 error view.""" url = reverse('test_404') - + response = self.client.get(url) self.assertEqual(response.status_code, 404) @@ -29,5 +28,6 @@ def test_500_view(self): with self.assertRaises(ZeroDivisionError): self.client.get(url) + def test_dummy(): assert 1 diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index 7962fef08b..c96cdfa7ce 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -32,5 +32,5 @@ def test_500(request): Returns: This function never returns as it raises a ZeroDivisionError """ - division_by_zero = 1 / 0 + 1 / 0 # Raise ZeroDivisionError return render(request, 'index.html') diff --git a/profiles/tests.py b/profiles/tests.py index 6d83498abf..2a66ccf7dc 100644 --- a/profiles/tests.py +++ b/profiles/tests.py @@ -21,10 +21,10 @@ def setUp(self): def test_index_view(self): """Test the profiles list view.""" - + url = reverse('profiles:index') response = self.client.get(url) - + self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'profiles/index.html') self.assertIn('profiles_list', response.context) @@ -33,17 +33,17 @@ def test_index_view(self): def test_profile_view(self): """Test the profile detail view.""" - + url = reverse('profiles:profile', args=[self.user.username]) response = self.client.get(url) - + self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'profiles/profile.html') self.assertEqual(response.context['profile'], self.profile) def test_profile_view_404(self): """Test the profile detail view with non-existent username.""" - + url = reverse('profiles:profile', args=['nonexistentuser']) response = self.client.get(url) self.assertEqual(response.status_code, 404) From f002ed781ca0d0c82a9d7542c06a758615d1847f Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Sat, 31 May 2025 19:47:49 +0200 Subject: [PATCH 14/19] feat:init sentry --- .gitignore | 1 + lettings/views.py | 33 ++++++++++++++++------- oc_lettings_site/settings.py | 52 +++++++++++++++++++++++++++++++++++- oc_lettings_site/urls.py | 6 +++++ oc_lettings_site/views.py | 12 +++++++-- profiles/views.py | 27 ++++++++++++++----- 6 files changed, 111 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 64e2ff4e2a..47b985badd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.pyc venv .DS_Store +.env \ No newline at end of file diff --git a/lettings/views.py b/lettings/views.py index c9c4caf556..b7a4e2c9f9 100644 --- a/lettings/views.py +++ b/lettings/views.py @@ -1,6 +1,9 @@ from django.shortcuts import render, get_object_or_404 +from django.http import Http404 +import logging from .models import Letting +logger = logging.getLogger(__name__) def index(request): """ @@ -10,10 +13,13 @@ def index(request): Returns: template 'lettings/index.html' with a list of all lettings """ - lettings_list = Letting.objects.all() - context = {'lettings_list': lettings_list} - return render(request, 'lettings/index.html', context) - + try: + lettings_list = Letting.objects.all() + logger.info(f"Retrieved {len(lettings_list)} lettings for index page") + return render(request, 'lettings/index.html', context={'lettings_list': lettings_list}) + except Exception as e: + logger.error(f"Error retrieving lettings list: {str(e)}", exc_info=True) + raise def letting(request, letting_id): """ @@ -26,9 +32,16 @@ def letting(request, letting_id): Raises: Http404: If the letting with the given ID doesn't exist """ - letting = get_object_or_404(Letting, id=letting_id) - context = { - 'title': letting.title, - 'address': letting.address, - } - return render(request, 'lettings/letting.html', context) + try: + letting = get_object_or_404(Letting, id=letting_id) + logger.info(f"Retrieved letting {letting_id}: {letting.title}") + return render(request, 'lettings/letting.html', context={ + 'title': letting.title, + 'address': letting.address, + }) + except Http404: + logger.warning(f"Letting with id {letting_id} not found") + raise + except Exception as e: + logger.error(f"Error retrieving letting {letting_id}: {str(e)}", exc_info=True) + raise diff --git a/oc_lettings_site/settings.py b/oc_lettings_site/settings.py index be98636d2a..e6202e2c49 100644 --- a/oc_lettings_site/settings.py +++ b/oc_lettings_site/settings.py @@ -1,10 +1,60 @@ import os - from pathlib import Path +import sentry_sdk +from sentry_sdk.integrations.django import DjangoIntegration +from sentry_sdk.integrations.logging import LoggingIntegration +import logging + +sentry_sdk.init( + dsn = "https://7220363d53b6d31ec048180b5b0074e9@o452613.ingest.us.sentry.io/4509418921263104", + integrations=[ + DjangoIntegration(), + LoggingIntegration( + level=logging.INFO, + event_level=logging.ERROR + ), + ], + traces_sample_rate=1.0, + send_default_pii=True, +) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = Path(__file__).resolve().parent.parent +# Logging config +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'verbose': { + 'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}', + 'style': '{', + }, + }, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + 'formatter': 'verbose', + }, + }, + 'loggers': { + 'django': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': True, + }, + 'lettings': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': True, + }, + 'profiles': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': True, + }, + }, +} # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ diff --git a/oc_lettings_site/urls.py b/oc_lettings_site/urls.py index 6395d2933e..7bfd70bd58 100644 --- a/oc_lettings_site/urls.py +++ b/oc_lettings_site/urls.py @@ -5,6 +5,9 @@ from . import views +def trigger_error(request): + division_by_zero = 1 / 0 + urlpatterns = [ path('', views.index, name='index'), path('lettings/', include('lettings.urls', namespace='lettings')), @@ -13,4 +16,7 @@ # Test URLs for error pages path('404/', views.test_404, name='test_404'), path('500/', views.test_500, name='test_500'), + # Test sentry + path('sentry-debug/', trigger_error), + ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/oc_lettings_site/views.py b/oc_lettings_site/views.py index c96cdfa7ce..1579bf3f6b 100644 --- a/oc_lettings_site/views.py +++ b/oc_lettings_site/views.py @@ -1,6 +1,8 @@ from django.shortcuts import render from django.http import Http404 +import logging +logger = logging.getLogger(__name__) def index(request): """ @@ -10,8 +12,12 @@ def index(request): Returns: Rendered template 'index.html' """ - return render(request, 'index.html') - + try: + logger.info("Rendering home page") + return render(request, 'index.html') + except Exception as e: + logger.error(f"Error rendering home page: {str(e)}", exc_info=True) + raise def test_404(request): """ @@ -21,6 +27,7 @@ def test_404(request): Raises: Http404: Always raises a 404 error for testing purposes """ + logger.warning("Test 404 error page requested") raise Http404("Page de test 404") @@ -32,5 +39,6 @@ def test_500(request): Returns: This function never returns as it raises a ZeroDivisionError """ + logger.error("Test 500 error page requested") 1 / 0 # Raise ZeroDivisionError return render(request, 'index.html') diff --git a/profiles/views.py b/profiles/views.py index 96ccf09ed9..2eb48c33cb 100644 --- a/profiles/views.py +++ b/profiles/views.py @@ -1,6 +1,9 @@ from django.shortcuts import render, get_object_or_404 +from django.http import Http404 +import logging from .models import Profile +logger = logging.getLogger(__name__) def index(request): """ @@ -10,10 +13,13 @@ def index(request): Returns: Rendered template 'profiles/index.html' with a list of all profiles """ - profiles_list = Profile.objects.all() - context = {'profiles_list': profiles_list} - return render(request, 'profiles/index.html', context) - + try: + profiles_list = Profile.objects.all() + logger.info(f"Retrieved {len(profiles_list)} profiles for index page") + return render(request, 'profiles/index.html', context={'profiles_list': profiles_list}) + except Exception as e: + logger.error(f"Error retrieving profiles list: {str(e)}", exc_info=True) + raise def profile(request, username): """ @@ -26,6 +32,13 @@ def profile(request, username): Raises: Http404: If the profile with the given username doesn't exist """ - profile = get_object_or_404(Profile, user__username=username) - context = {'profile': profile} - return render(request, 'profiles/profile.html', context) + try: + profile = get_object_or_404(Profile, user__username=username) + logger.info(f"Retrieved profile for user {username}") + return render(request, 'profiles/profile.html', context={'profile': profile}) + except Http404: + logger.warning(f"Profile for user {username} not found") + raise + except Exception as e: + logger.error(f"Error retrieving profile for user {username}: {str(e)}", exc_info=True) + raise From 280aa88bec19e95e95371bc745c779441ea86b2b Mon Sep 17 00:00:00 2001 From: "jean-baptiste.guerin" Date: Thu, 3 Jul 2025 10:54:29 +0200 Subject: [PATCH 15/19] feat:setup docker --- .dockerignore | 68 + .github/workflows/ci-cd.yml | 132 + DEPLOYMENT.md | 126 + Dockerfile | 44 + docker-compose.yml | 26 + oc_lettings_site/settings_production.py | 128 + requirements.txt | 6 +- start.sh | 20 + static/assets/img/backgrounds/bg-angles.svg | 15 + static/assets/img/backgrounds/bg-waves.svg | 12 + .../img/device-mockups/iPhoneX/landscape.png | 1 + .../img/device-mockups/iPhoneX/landscape.svg | 7 + .../iPhoneX/landscape_black.svg | 7 + .../img/device-mockups/iPhoneX/portrait.png | 1 + .../img/device-mockups/iPhoneX/portrait.svg | 7 + .../device-mockups/iPhoneX/portrait_black.svg | 7 + static/css/styles.css | 8 +- .../admin/css/autocomplete.4a81fc4242d0.css | 275 + .../css/autocomplete.4a81fc4242d0.css.gz | Bin 0 -> 1147 bytes staticfiles/admin/css/autocomplete.css | 275 + staticfiles/admin/css/autocomplete.css.gz | Bin 0 -> 1147 bytes staticfiles/admin/css/base.523eb49842a7.css | 1145 + .../admin/css/base.523eb49842a7.css.gz | Bin 0 -> 4865 bytes staticfiles/admin/css/base.css | 1145 + staticfiles/admin/css/base.css.gz | Bin 0 -> 4755 bytes .../admin/css/changelists.9237a1ac391b.css | 328 + .../admin/css/changelists.9237a1ac391b.css.gz | Bin 0 -> 1564 bytes staticfiles/admin/css/changelists.css | 328 + staticfiles/admin/css/changelists.css.gz | Bin 0 -> 1564 bytes staticfiles/admin/css/dark_mode.css | 137 + staticfiles/admin/css/dark_mode.css.gz | Bin 0 -> 849 bytes .../admin/css/dark_mode.ef27a31af300.css | 137 + .../admin/css/dark_mode.ef27a31af300.css.gz | Bin 0 -> 849 bytes staticfiles/admin/css/dashboard.css | 29 + staticfiles/admin/css/dashboard.css.gz | Bin 0 -> 267 bytes .../admin/css/dashboard.e90f2068217b.css | 29 + .../admin/css/dashboard.e90f2068217b.css.gz | Bin 0 -> 267 bytes staticfiles/admin/css/forms.c14e1cb06392.css | 534 + .../admin/css/forms.c14e1cb06392.css.gz | Bin 0 -> 2243 bytes staticfiles/admin/css/forms.css | 534 + staticfiles/admin/css/forms.css.gz | Bin 0 -> 2207 bytes staticfiles/admin/css/login.586129c60a93.css | 61 + .../admin/css/login.586129c60a93.css.gz | Bin 0 -> 417 bytes staticfiles/admin/css/login.css | 61 + staticfiles/admin/css/login.css.gz | Bin 0 -> 417 bytes .../admin/css/nav_sidebar.269a1bd44627.css | 144 + .../admin/css/nav_sidebar.269a1bd44627.css.gz | Bin 0 -> 779 bytes staticfiles/admin/css/nav_sidebar.css | 144 + staticfiles/admin/css/nav_sidebar.css.gz | Bin 0 -> 779 bytes staticfiles/admin/css/responsive.css | 999 + staticfiles/admin/css/responsive.css.gz | Bin 0 -> 3441 bytes .../admin/css/responsive.f6533dab034d.css | 999 + .../admin/css/responsive.f6533dab034d.css.gz | Bin 0 -> 3441 bytes .../admin/css/responsive_rtl.7d1130848605.css | 84 + .../css/responsive_rtl.7d1130848605.css.gz | Bin 0 -> 550 bytes staticfiles/admin/css/responsive_rtl.css | 84 + staticfiles/admin/css/responsive_rtl.css.gz | Bin 0 -> 550 bytes staticfiles/admin/css/rtl.512d4b53fc59.css | 298 + staticfiles/admin/css/rtl.512d4b53fc59.css.gz | Bin 0 -> 1281 bytes staticfiles/admin/css/rtl.css | 298 + staticfiles/admin/css/rtl.css.gz | Bin 0 -> 1254 bytes .../select2/LICENSE-SELECT2.f94142512c91.md | 21 + .../LICENSE-SELECT2.f94142512c91.md.gz | Bin 0 -> 685 bytes .../css/vendor/select2/LICENSE-SELECT2.md | 21 + .../css/vendor/select2/LICENSE-SELECT2.md.gz | Bin 0 -> 685 bytes .../vendor/select2/select2.a2194c262648.css | 481 + .../select2/select2.a2194c262648.css.gz | Bin 0 -> 2232 bytes .../admin/css/vendor/select2/select2.css | 481 + .../admin/css/vendor/select2/select2.css.gz | Bin 0 -> 2232 bytes .../select2/select2.min.9f54e6414f87.css | 1 + .../select2/select2.min.9f54e6414f87.css.gz | Bin 0 -> 1978 bytes .../admin/css/vendor/select2/select2.min.css | 1 + .../css/vendor/select2/select2.min.css.gz | Bin 0 -> 1978 bytes staticfiles/admin/css/widgets.css | 604 + staticfiles/admin/css/widgets.css.gz | Bin 0 -> 2474 bytes .../admin/css/widgets.ee33ab26c7c2.css | 604 + .../admin/css/widgets.ee33ab26c7c2.css.gz | Bin 0 -> 2567 bytes staticfiles/admin/img/LICENSE | 20 + staticfiles/admin/img/LICENSE.2c54f4e1ca1c | 20 + staticfiles/admin/img/LICENSE.2c54f4e1ca1c.gz | Bin 0 -> 656 bytes staticfiles/admin/img/LICENSE.gz | Bin 0 -> 656 bytes staticfiles/admin/img/README.a70711a38d87.txt | 7 + .../admin/img/README.a70711a38d87.txt.gz | Bin 0 -> 214 bytes staticfiles/admin/img/README.txt | 7 + staticfiles/admin/img/README.txt.gz | Bin 0 -> 214 bytes .../admin/img/calendar-icons.39b290681a8b.svg | 14 + .../img/calendar-icons.39b290681a8b.svg.gz | Bin 0 -> 385 bytes staticfiles/admin/img/calendar-icons.svg | 14 + staticfiles/admin/img/calendar-icons.svg.gz | Bin 0 -> 385 bytes .../img/gis/move_vertex_off.7a23bf31ef8a.svg | 1 + .../gis/move_vertex_off.7a23bf31ef8a.svg.gz | Bin 0 -> 470 bytes staticfiles/admin/img/gis/move_vertex_off.svg | 1 + .../admin/img/gis/move_vertex_off.svg.gz | Bin 0 -> 470 bytes .../img/gis/move_vertex_on.0047eba25b67.svg | 1 + .../gis/move_vertex_on.0047eba25b67.svg.gz | Bin 0 -> 472 bytes staticfiles/admin/img/gis/move_vertex_on.svg | 1 + .../admin/img/gis/move_vertex_on.svg.gz | Bin 0 -> 472 bytes .../admin/img/icon-addlink.d519b3bab011.svg | 3 + .../img/icon-addlink.d519b3bab011.svg.gz | Bin 0 -> 206 bytes staticfiles/admin/img/icon-addlink.svg | 3 + staticfiles/admin/img/icon-addlink.svg.gz | Bin 0 -> 206 bytes .../admin/img/icon-alert.034cc7d8a67f.svg | 3 + .../admin/img/icon-alert.034cc7d8a67f.svg.gz | Bin 0 -> 329 bytes staticfiles/admin/img/icon-alert.svg | 3 + staticfiles/admin/img/icon-alert.svg.gz | Bin 0 -> 329 bytes .../admin/img/icon-calendar.ac7aea671bea.svg | 9 + .../img/icon-calendar.ac7aea671bea.svg.gz | Bin 0 -> 438 bytes staticfiles/admin/img/icon-calendar.svg | 9 + staticfiles/admin/img/icon-calendar.svg.gz | Bin 0 -> 438 bytes .../img/icon-changelink.18d2fd706348.svg | 3 + .../img/icon-changelink.18d2fd706348.svg.gz | Bin 0 -> 269 bytes staticfiles/admin/img/icon-changelink.svg | 3 + staticfiles/admin/img/icon-changelink.svg.gz | Bin 0 -> 269 bytes .../admin/img/icon-clock.e1d4dfac3f2b.svg | 9 + .../admin/img/icon-clock.e1d4dfac3f2b.svg.gz | Bin 0 -> 357 bytes staticfiles/admin/img/icon-clock.svg | 9 + staticfiles/admin/img/icon-clock.svg.gz | Bin 0 -> 357 bytes .../img/icon-deletelink.564ef9dc3854.svg | 3 + .../img/icon-deletelink.564ef9dc3854.svg.gz | Bin 0 -> 221 bytes staticfiles/admin/img/icon-deletelink.svg | 3 + staticfiles/admin/img/icon-deletelink.svg.gz | Bin 0 -> 221 bytes .../admin/img/icon-no.439e821418cd.svg | 3 + .../admin/img/icon-no.439e821418cd.svg.gz | Bin 0 -> 297 bytes staticfiles/admin/img/icon-no.svg | 3 + staticfiles/admin/img/icon-no.svg.gz | Bin 0 -> 297 bytes .../img/icon-unknown-alt.81536e128bb6.svg | 3 + .../img/icon-unknown-alt.81536e128bb6.svg.gz | Bin 0 -> 377 bytes staticfiles/admin/img/icon-unknown-alt.svg | 3 + staticfiles/admin/img/icon-unknown-alt.svg.gz | Bin 0 -> 377 bytes .../admin/img/icon-unknown.a18cb4398978.svg | 3 + .../img/icon-unknown.a18cb4398978.svg.gz | Bin 0 -> 377 bytes staticfiles/admin/img/icon-unknown.svg | 3 + staticfiles/admin/img/icon-unknown.svg.gz | Bin 0 -> 377 bytes .../admin/img/icon-viewlink.41eb31f7826e.svg | 3 + .../img/icon-viewlink.41eb31f7826e.svg.gz | Bin 0 -> 346 bytes staticfiles/admin/img/icon-viewlink.svg | 3 + staticfiles/admin/img/icon-viewlink.svg.gz | Bin 0 -> 346 bytes .../admin/img/icon-yes.d2f9f035226a.svg | 3 + .../admin/img/icon-yes.d2f9f035226a.svg.gz | Bin 0 -> 266 bytes staticfiles/admin/img/icon-yes.svg | 3 + staticfiles/admin/img/icon-yes.svg.gz | Bin 0 -> 266 bytes .../admin/img/inline-delete.fec1b761f254.svg | 3 + .../img/inline-delete.fec1b761f254.svg.gz | Bin 0 -> 293 bytes staticfiles/admin/img/inline-delete.svg | 3 + staticfiles/admin/img/inline-delete.svg.gz | Bin 0 -> 293 bytes staticfiles/admin/img/search.7cf54ff789c6.svg | 3 + .../admin/img/search.7cf54ff789c6.svg.gz | Bin 0 -> 264 bytes staticfiles/admin/img/search.svg | 3 + staticfiles/admin/img/search.svg.gz | Bin 0 -> 264 bytes .../admin/img/selector-icons.b4555096cea2.svg | 34 + .../img/selector-icons.b4555096cea2.svg.gz | Bin 0 -> 770 bytes staticfiles/admin/img/selector-icons.svg | 34 + staticfiles/admin/img/selector-icons.svg.gz | Bin 0 -> 770 bytes .../admin/img/sorting-icons.3a097b59f104.svg | 19 + .../img/sorting-icons.3a097b59f104.svg.gz | Bin 0 -> 366 bytes staticfiles/admin/img/sorting-icons.svg | 19 + staticfiles/admin/img/sorting-icons.svg.gz | Bin 0 -> 366 bytes .../admin/img/tooltag-add.e59d620a9742.svg | 3 + .../admin/img/tooltag-add.e59d620a9742.svg.gz | Bin 0 -> 203 bytes staticfiles/admin/img/tooltag-add.svg | 3 + staticfiles/admin/img/tooltag-add.svg.gz | Bin 0 -> 203 bytes .../img/tooltag-arrowright.bbfb788a849e.svg | 3 + .../tooltag-arrowright.bbfb788a849e.svg.gz | Bin 0 -> 194 bytes staticfiles/admin/img/tooltag-arrowright.svg | 3 + .../admin/img/tooltag-arrowright.svg.gz | Bin 0 -> 194 bytes .../admin/js/SelectBox.7d3ce5a98007.js | 116 + .../admin/js/SelectBox.7d3ce5a98007.js.gz | Bin 0 -> 1025 bytes staticfiles/admin/js/SelectBox.js | 116 + staticfiles/admin/js/SelectBox.js.gz | Bin 0 -> 1025 bytes .../admin/js/SelectFilter2.bdb8d0cc579e.js | 283 + .../admin/js/SelectFilter2.bdb8d0cc579e.js.gz | Bin 0 -> 2914 bytes staticfiles/admin/js/SelectFilter2.js | 283 + staticfiles/admin/js/SelectFilter2.js.gz | Bin 0 -> 2914 bytes staticfiles/admin/js/actions.eac7e3441574.js | 201 + .../admin/js/actions.eac7e3441574.js.gz | Bin 0 -> 1874 bytes staticfiles/admin/js/actions.js | 201 + staticfiles/admin/js/actions.js.gz | Bin 0 -> 1874 bytes .../admin/DateTimeShortcuts.9f6e209cebca.js | 408 + .../DateTimeShortcuts.9f6e209cebca.js.gz | Bin 0 -> 3645 bytes .../admin/js/admin/DateTimeShortcuts.js | 408 + .../admin/js/admin/DateTimeShortcuts.js.gz | Bin 0 -> 3645 bytes .../RelatedObjectLookups.8609f99b9ab2.js | 238 + .../RelatedObjectLookups.8609f99b9ab2.js.gz | Bin 0 -> 2301 bytes .../admin/js/admin/RelatedObjectLookups.js | 238 + .../admin/js/admin/RelatedObjectLookups.js.gz | Bin 0 -> 2301 bytes .../admin/js/autocomplete.01591ab27be7.js | 33 + .../admin/js/autocomplete.01591ab27be7.js.gz | Bin 0 -> 425 bytes staticfiles/admin/js/autocomplete.js | 33 + staticfiles/admin/js/autocomplete.js.gz | Bin 0 -> 425 bytes staticfiles/admin/js/calendar.f8a5d055eb33.js | 221 + .../admin/js/calendar.f8a5d055eb33.js.gz | Bin 0 -> 2193 bytes staticfiles/admin/js/calendar.js | 221 + staticfiles/admin/js/calendar.js.gz | Bin 0 -> 2193 bytes staticfiles/admin/js/cancel.ecc4c5ca7b32.js | 29 + .../admin/js/cancel.ecc4c5ca7b32.js.gz | Bin 0 -> 430 bytes staticfiles/admin/js/cancel.js | 29 + staticfiles/admin/js/cancel.js.gz | Bin 0 -> 430 bytes .../admin/js/change_form.9d8ca4f96b75.js | 16 + .../admin/js/change_form.9d8ca4f96b75.js.gz | Bin 0 -> 322 bytes staticfiles/admin/js/change_form.js | 16 + staticfiles/admin/js/change_form.js.gz | Bin 0 -> 322 bytes staticfiles/admin/js/collapse.f84e7410290f.js | 43 + .../admin/js/collapse.f84e7410290f.js.gz | Bin 0 -> 614 bytes staticfiles/admin/js/collapse.js | 43 + staticfiles/admin/js/collapse.js.gz | Bin 0 -> 614 bytes staticfiles/admin/js/core.cf103cd04ebf.js | 170 + staticfiles/admin/js/core.cf103cd04ebf.js.gz | Bin 0 -> 1505 bytes staticfiles/admin/js/core.js | 170 + staticfiles/admin/js/core.js.gz | Bin 0 -> 1505 bytes staticfiles/admin/js/filters.0e360b7a9f80.js | 30 + .../admin/js/filters.0e360b7a9f80.js.gz | Bin 0 -> 502 bytes staticfiles/admin/js/filters.js | 30 + staticfiles/admin/js/filters.js.gz | Bin 0 -> 502 bytes staticfiles/admin/js/inlines.22d4d93c00b4.js | 359 + .../admin/js/inlines.22d4d93c00b4.js.gz | Bin 0 -> 3744 bytes staticfiles/admin/js/inlines.js | 359 + staticfiles/admin/js/inlines.js.gz | Bin 0 -> 3744 bytes .../admin/js/jquery.init.b7781a0897fc.js | 8 + .../admin/js/jquery.init.b7781a0897fc.js.gz | Bin 0 -> 236 bytes staticfiles/admin/js/jquery.init.js | 8 + staticfiles/admin/js/jquery.init.js.gz | Bin 0 -> 236 bytes .../admin/js/nav_sidebar.3b9190d420b1.js | 79 + .../admin/js/nav_sidebar.3b9190d420b1.js.gz | Bin 0 -> 845 bytes staticfiles/admin/js/nav_sidebar.js | 79 + staticfiles/admin/js/nav_sidebar.js.gz | Bin 0 -> 845 bytes .../admin/js/popup_response.c6cc78ea5551.js | 16 + .../js/popup_response.c6cc78ea5551.js.gz | Bin 0 -> 270 bytes staticfiles/admin/js/popup_response.js | 16 + staticfiles/admin/js/popup_response.js.gz | Bin 0 -> 270 bytes .../admin/js/prepopulate.bd2361dfd64d.js | 43 + .../admin/js/prepopulate.bd2361dfd64d.js.gz | Bin 0 -> 536 bytes staticfiles/admin/js/prepopulate.js | 43 + staticfiles/admin/js/prepopulate.js.gz | Bin 0 -> 536 bytes .../admin/js/prepopulate_init.6cac7f3105b8.js | 15 + .../js/prepopulate_init.6cac7f3105b8.js.gz | Bin 0 -> 277 bytes staticfiles/admin/js/prepopulate_init.js | 15 + staticfiles/admin/js/prepopulate_init.js.gz | Bin 0 -> 277 bytes staticfiles/admin/js/theme.ab270f56bb9c.js | 56 + staticfiles/admin/js/theme.ab270f56bb9c.js.gz | Bin 0 -> 605 bytes staticfiles/admin/js/theme.js | 56 + staticfiles/admin/js/theme.js.gz | Bin 0 -> 605 bytes staticfiles/admin/js/urlify.ae970a820212.js | 169 + .../admin/js/urlify.ae970a820212.js.gz | Bin 0 -> 2578 bytes staticfiles/admin/js/urlify.js | 169 + staticfiles/admin/js/urlify.js.gz | Bin 0 -> 2578 bytes .../js/vendor/jquery/LICENSE.de877aa6d744.txt | 20 + .../vendor/jquery/LICENSE.de877aa6d744.txt.gz | Bin 0 -> 656 bytes .../admin/js/vendor/jquery/LICENSE.txt | 20 + .../admin/js/vendor/jquery/LICENSE.txt.gz | Bin 0 -> 656 bytes .../js/vendor/jquery/jquery.0208b96062ba.js | 10965 +++++++++ .../vendor/jquery/jquery.0208b96062ba.js.gz | Bin 0 -> 86002 bytes staticfiles/admin/js/vendor/jquery/jquery.js | 10965 +++++++++ .../admin/js/vendor/jquery/jquery.js.gz | Bin 0 -> 86002 bytes .../vendor/jquery/jquery.min.641dd1437010.js | 2 + .../jquery/jquery.min.641dd1437010.js.gz | Bin 0 -> 31011 bytes .../admin/js/vendor/jquery/jquery.min.js | 2 + .../admin/js/vendor/jquery/jquery.min.js.gz | Bin 0 -> 31011 bytes .../js/vendor/select2/LICENSE.f94142512c91.md | 21 + .../vendor/select2/LICENSE.f94142512c91.md.gz | Bin 0 -> 685 bytes .../admin/js/vendor/select2/LICENSE.md | 21 + .../admin/js/vendor/select2/LICENSE.md.gz | Bin 0 -> 685 bytes .../js/vendor/select2/i18n/af.4f6fcd73488c.js | 3 + .../vendor/select2/i18n/af.4f6fcd73488c.js.gz | Bin 0 -> 460 bytes .../admin/js/vendor/select2/i18n/af.js | 3 + .../admin/js/vendor/select2/i18n/af.js.gz | Bin 0 -> 460 bytes .../js/vendor/select2/i18n/ar.65aa8e36bf5d.js | 3 + .../vendor/select2/i18n/ar.65aa8e36bf5d.js.gz | Bin 0 -> 498 bytes .../admin/js/vendor/select2/i18n/ar.js | 3 + .../admin/js/vendor/select2/i18n/ar.js.gz | Bin 0 -> 498 bytes .../js/vendor/select2/i18n/az.270c257daf81.js | 3 + .../vendor/select2/i18n/az.270c257daf81.js.gz | Bin 0 -> 413 bytes .../admin/js/vendor/select2/i18n/az.js | 3 + .../admin/js/vendor/select2/i18n/az.js.gz | Bin 0 -> 413 bytes .../js/vendor/select2/i18n/bg.39b8be30d4f0.js | 3 + .../vendor/select2/i18n/bg.39b8be30d4f0.js.gz | Bin 0 -> 541 bytes .../admin/js/vendor/select2/i18n/bg.js | 3 + .../admin/js/vendor/select2/i18n/bg.js.gz | Bin 0 -> 541 bytes .../js/vendor/select2/i18n/bn.6d42b4dd5665.js | 3 + .../vendor/select2/i18n/bn.6d42b4dd5665.js.gz | Bin 0 -> 553 bytes .../admin/js/vendor/select2/i18n/bn.js | 3 + .../admin/js/vendor/select2/i18n/bn.js.gz | Bin 0 -> 553 bytes .../js/vendor/select2/i18n/bs.91624382358e.js | 3 + .../vendor/select2/i18n/bs.91624382358e.js.gz | Bin 0 -> 523 bytes .../admin/js/vendor/select2/i18n/bs.js | 3 + .../admin/js/vendor/select2/i18n/bs.js.gz | Bin 0 -> 523 bytes .../js/vendor/select2/i18n/ca.a166b745933a.js | 3 + .../vendor/select2/i18n/ca.a166b745933a.js.gz | Bin 0 -> 470 bytes .../admin/js/vendor/select2/i18n/ca.js | 3 + .../admin/js/vendor/select2/i18n/ca.js.gz | Bin 0 -> 470 bytes .../js/vendor/select2/i18n/cs.4f43e8e7d33a.js | 3 + .../vendor/select2/i18n/cs.4f43e8e7d33a.js.gz | Bin 0 -> 623 bytes .../admin/js/vendor/select2/i18n/cs.js | 3 + .../admin/js/vendor/select2/i18n/cs.js.gz | Bin 0 -> 623 bytes .../js/vendor/select2/i18n/da.766346afe4dd.js | 3 + .../vendor/select2/i18n/da.766346afe4dd.js.gz | Bin 0 -> 441 bytes .../admin/js/vendor/select2/i18n/da.js | 3 + .../admin/js/vendor/select2/i18n/da.js.gz | Bin 0 -> 441 bytes .../js/vendor/select2/i18n/de.8a1c222b0204.js | 3 + .../vendor/select2/i18n/de.8a1c222b0204.js.gz | Bin 0 -> 467 bytes .../admin/js/vendor/select2/i18n/de.js | 3 + .../admin/js/vendor/select2/i18n/de.js.gz | Bin 0 -> 467 bytes .../vendor/select2/i18n/dsb.56372c92d2f1.js | 3 + .../select2/i18n/dsb.56372c92d2f1.js.gz | Bin 0 -> 551 bytes .../admin/js/vendor/select2/i18n/dsb.js | 3 + .../admin/js/vendor/select2/i18n/dsb.js.gz | Bin 0 -> 551 bytes .../js/vendor/select2/i18n/el.27097f071856.js | 3 + .../vendor/select2/i18n/el.27097f071856.js.gz | Bin 0 -> 644 bytes .../admin/js/vendor/select2/i18n/el.js | 3 + .../admin/js/vendor/select2/i18n/el.js.gz | Bin 0 -> 644 bytes .../js/vendor/select2/i18n/en.cf932ba09a98.js | 3 + .../vendor/select2/i18n/en.cf932ba09a98.js.gz | Bin 0 -> 447 bytes .../admin/js/vendor/select2/i18n/en.js | 3 + .../admin/js/vendor/select2/i18n/en.js.gz | Bin 0 -> 447 bytes .../js/vendor/select2/i18n/es.66dbc2652fb1.js | 3 + .../vendor/select2/i18n/es.66dbc2652fb1.js.gz | Bin 0 -> 474 bytes .../admin/js/vendor/select2/i18n/es.js | 3 + .../admin/js/vendor/select2/i18n/es.js.gz | Bin 0 -> 474 bytes .../js/vendor/select2/i18n/et.2b96fd98289d.js | 3 + .../vendor/select2/i18n/et.2b96fd98289d.js.gz | Bin 0 -> 432 bytes .../admin/js/vendor/select2/i18n/et.js | 3 + .../admin/js/vendor/select2/i18n/et.js.gz | Bin 0 -> 432 bytes .../js/vendor/select2/i18n/eu.adfe5c97b72c.js | 3 + .../vendor/select2/i18n/eu.adfe5c97b72c.js.gz | Bin 0 -> 450 bytes .../admin/js/vendor/select2/i18n/eu.js | 3 + .../admin/js/vendor/select2/i18n/eu.js.gz | Bin 0 -> 450 bytes .../js/vendor/select2/i18n/fa.3b5bd1961cfd.js | 3 + .../vendor/select2/i18n/fa.3b5bd1961cfd.js.gz | Bin 0 -> 538 bytes .../admin/js/vendor/select2/i18n/fa.js | 3 + .../admin/js/vendor/select2/i18n/fa.js.gz | Bin 0 -> 538 bytes .../js/vendor/select2/i18n/fi.614ec42aa9ba.js | 3 + .../vendor/select2/i18n/fi.614ec42aa9ba.js.gz | Bin 0 -> 429 bytes .../admin/js/vendor/select2/i18n/fi.js | 3 + .../admin/js/vendor/select2/i18n/fi.js.gz | Bin 0 -> 429 bytes .../js/vendor/select2/i18n/fr.05e0542fcfe6.js | 3 + .../vendor/select2/i18n/fr.05e0542fcfe6.js.gz | Bin 0 -> 484 bytes .../admin/js/vendor/select2/i18n/fr.js | 3 + .../admin/js/vendor/select2/i18n/fr.js.gz | Bin 0 -> 484 bytes .../js/vendor/select2/i18n/gl.d99b1fedaa86.js | 3 + .../vendor/select2/i18n/gl.d99b1fedaa86.js.gz | Bin 0 -> 465 bytes .../admin/js/vendor/select2/i18n/gl.js | 3 + .../admin/js/vendor/select2/i18n/gl.js.gz | Bin 0 -> 465 bytes .../js/vendor/select2/i18n/he.e420ff6cd3ed.js | 3 + .../vendor/select2/i18n/he.e420ff6cd3ed.js.gz | Bin 0 -> 518 bytes .../admin/js/vendor/select2/i18n/he.js | 3 + .../admin/js/vendor/select2/i18n/he.js.gz | Bin 0 -> 518 bytes .../js/vendor/select2/i18n/hi.70640d41628f.js | 3 + .../vendor/select2/i18n/hi.70640d41628f.js.gz | Bin 0 -> 572 bytes .../admin/js/vendor/select2/i18n/hi.js | 3 + .../admin/js/vendor/select2/i18n/hi.js.gz | Bin 0 -> 572 bytes .../js/vendor/select2/i18n/hr.a2b092cc1147.js | 3 + .../vendor/select2/i18n/hr.a2b092cc1147.js.gz | Bin 0 -> 477 bytes .../admin/js/vendor/select2/i18n/hr.js | 3 + .../admin/js/vendor/select2/i18n/hr.js.gz | Bin 0 -> 477 bytes .../vendor/select2/i18n/hsb.fa3b55265efe.js | 3 + .../select2/i18n/hsb.fa3b55265efe.js.gz | Bin 0 -> 556 bytes .../admin/js/vendor/select2/i18n/hsb.js | 3 + .../admin/js/vendor/select2/i18n/hsb.js.gz | Bin 0 -> 556 bytes .../js/vendor/select2/i18n/hu.6ec6039cb8a3.js | 3 + .../vendor/select2/i18n/hu.6ec6039cb8a3.js.gz | Bin 0 -> 467 bytes .../admin/js/vendor/select2/i18n/hu.js | 3 + .../admin/js/vendor/select2/i18n/hu.js.gz | Bin 0 -> 467 bytes .../js/vendor/select2/i18n/hy.c7babaeef5a6.js | 3 + .../vendor/select2/i18n/hy.c7babaeef5a6.js.gz | Bin 0 -> 530 bytes .../admin/js/vendor/select2/i18n/hy.js | 3 + .../admin/js/vendor/select2/i18n/hy.js.gz | Bin 0 -> 530 bytes .../js/vendor/select2/i18n/id.04debded514d.js | 3 + .../vendor/select2/i18n/id.04debded514d.js.gz | Bin 0 -> 416 bytes .../admin/js/vendor/select2/i18n/id.js | 3 + .../admin/js/vendor/select2/i18n/id.js.gz | Bin 0 -> 416 bytes .../js/vendor/select2/i18n/is.3ddd9a6a97e9.js | 3 + .../vendor/select2/i18n/is.3ddd9a6a97e9.js.gz | Bin 0 -> 465 bytes .../admin/js/vendor/select2/i18n/is.js | 3 + .../admin/js/vendor/select2/i18n/is.js.gz | Bin 0 -> 465 bytes .../js/vendor/select2/i18n/it.be4fe8d365b5.js | 3 + .../vendor/select2/i18n/it.be4fe8d365b5.js.gz | Bin 0 -> 488 bytes .../admin/js/vendor/select2/i18n/it.js | 3 + .../admin/js/vendor/select2/i18n/it.js.gz | Bin 0 -> 488 bytes .../js/vendor/select2/i18n/ja.170ae885d74f.js | 3 + .../vendor/select2/i18n/ja.170ae885d74f.js.gz | Bin 0 -> 511 bytes .../admin/js/vendor/select2/i18n/ja.js | 3 + .../admin/js/vendor/select2/i18n/ja.js.gz | Bin 0 -> 511 bytes .../js/vendor/select2/i18n/ka.2083264a54f0.js | 3 + .../vendor/select2/i18n/ka.2083264a54f0.js.gz | Bin 0 -> 533 bytes .../admin/js/vendor/select2/i18n/ka.js | 3 + .../admin/js/vendor/select2/i18n/ka.js.gz | Bin 0 -> 533 bytes .../js/vendor/select2/i18n/km.c23089cb06ca.js | 3 + .../vendor/select2/i18n/km.c23089cb06ca.js.gz | Bin 0 -> 540 bytes .../admin/js/vendor/select2/i18n/km.js | 3 + .../admin/js/vendor/select2/i18n/km.js.gz | Bin 0 -> 540 bytes .../js/vendor/select2/i18n/ko.e7be6c20e673.js | 3 + .../vendor/select2/i18n/ko.e7be6c20e673.js.gz | Bin 0 -> 506 bytes .../admin/js/vendor/select2/i18n/ko.js | 3 + .../admin/js/vendor/select2/i18n/ko.js.gz | Bin 0 -> 506 bytes .../js/vendor/select2/i18n/lt.23c7ce903300.js | 3 + .../vendor/select2/i18n/lt.23c7ce903300.js.gz | Bin 0 -> 521 bytes .../admin/js/vendor/select2/i18n/lt.js | 3 + .../admin/js/vendor/select2/i18n/lt.js.gz | Bin 0 -> 521 bytes .../js/vendor/select2/i18n/lv.08e62128eac1.js | 3 + .../vendor/select2/i18n/lv.08e62128eac1.js.gz | Bin 0 -> 505 bytes .../admin/js/vendor/select2/i18n/lv.js | 3 + .../admin/js/vendor/select2/i18n/lv.js.gz | Bin 0 -> 505 bytes .../js/vendor/select2/i18n/mk.dabbb9087130.js | 3 + .../vendor/select2/i18n/mk.dabbb9087130.js.gz | Bin 0 -> 557 bytes .../admin/js/vendor/select2/i18n/mk.js | 3 + .../admin/js/vendor/select2/i18n/mk.js.gz | Bin 0 -> 557 bytes .../js/vendor/select2/i18n/ms.4ba82c9a51ce.js | 3 + .../vendor/select2/i18n/ms.4ba82c9a51ce.js.gz | Bin 0 -> 436 bytes .../admin/js/vendor/select2/i18n/ms.js | 3 + .../admin/js/vendor/select2/i18n/ms.js.gz | Bin 0 -> 436 bytes .../js/vendor/select2/i18n/nb.da2fce143f27.js | 3 + .../vendor/select2/i18n/nb.da2fce143f27.js.gz | Bin 0 -> 413 bytes .../admin/js/vendor/select2/i18n/nb.js | 3 + .../admin/js/vendor/select2/i18n/nb.js.gz | Bin 0 -> 413 bytes .../js/vendor/select2/i18n/ne.3d79fd3f08db.js | 3 + .../vendor/select2/i18n/ne.3d79fd3f08db.js.gz | Bin 0 -> 591 bytes .../admin/js/vendor/select2/i18n/ne.js | 3 + .../admin/js/vendor/select2/i18n/ne.js.gz | Bin 0 -> 591 bytes .../js/vendor/select2/i18n/nl.997868a37ed8.js | 3 + .../vendor/select2/i18n/nl.997868a37ed8.js.gz | Bin 0 -> 469 bytes .../admin/js/vendor/select2/i18n/nl.js | 3 + .../admin/js/vendor/select2/i18n/nl.js.gz | Bin 0 -> 469 bytes .../js/vendor/select2/i18n/pl.6031b4f16452.js | 3 + .../vendor/select2/i18n/pl.6031b4f16452.js.gz | Bin 0 -> 524 bytes .../admin/js/vendor/select2/i18n/pl.js | 3 + .../admin/js/vendor/select2/i18n/pl.js.gz | Bin 0 -> 524 bytes .../js/vendor/select2/i18n/ps.38dfa47af9e0.js | 3 + .../vendor/select2/i18n/ps.38dfa47af9e0.js.gz | Bin 0 -> 587 bytes .../admin/js/vendor/select2/i18n/ps.js | 3 + .../admin/js/vendor/select2/i18n/ps.js.gz | Bin 0 -> 587 bytes .../vendor/select2/i18n/pt-BR.e1b294433e7f.js | 3 + .../select2/i18n/pt-BR.e1b294433e7f.js.gz | Bin 0 -> 486 bytes .../admin/js/vendor/select2/i18n/pt-BR.js | 3 + .../admin/js/vendor/select2/i18n/pt-BR.js.gz | Bin 0 -> 486 bytes .../js/vendor/select2/i18n/pt.33b4a3b44d43.js | 3 + .../vendor/select2/i18n/pt.33b4a3b44d43.js.gz | Bin 0 -> 470 bytes .../admin/js/vendor/select2/i18n/pt.js | 3 + .../admin/js/vendor/select2/i18n/pt.js.gz | Bin 0 -> 470 bytes .../js/vendor/select2/i18n/ro.f75cb460ec3b.js | 3 + .../vendor/select2/i18n/ro.f75cb460ec3b.js.gz | Bin 0 -> 511 bytes .../admin/js/vendor/select2/i18n/ro.js | 3 + .../admin/js/vendor/select2/i18n/ro.js.gz | Bin 0 -> 511 bytes .../js/vendor/select2/i18n/ru.934aa95f5b5f.js | 3 + .../vendor/select2/i18n/ru.934aa95f5b5f.js.gz | Bin 0 -> 632 bytes .../admin/js/vendor/select2/i18n/ru.js | 3 + .../admin/js/vendor/select2/i18n/ru.js.gz | Bin 0 -> 632 bytes .../js/vendor/select2/i18n/sk.33d02cef8d11.js | 3 + .../vendor/select2/i18n/sk.33d02cef8d11.js.gz | Bin 0 -> 617 bytes .../admin/js/vendor/select2/i18n/sk.js | 3 + .../admin/js/vendor/select2/i18n/sk.js.gz | Bin 0 -> 617 bytes .../js/vendor/select2/i18n/sl.131a78bc0752.js | 3 + .../vendor/select2/i18n/sl.131a78bc0752.js.gz | Bin 0 -> 487 bytes .../admin/js/vendor/select2/i18n/sl.js | 3 + .../admin/js/vendor/select2/i18n/sl.js.gz | Bin 0 -> 487 bytes .../js/vendor/select2/i18n/sq.5636b60d29c9.js | 3 + .../vendor/select2/i18n/sq.5636b60d29c9.js.gz | Bin 0 -> 490 bytes .../admin/js/vendor/select2/i18n/sq.js | 3 + .../admin/js/vendor/select2/i18n/sq.js.gz | Bin 0 -> 490 bytes .../select2/i18n/sr-Cyrl.f254bb8c4c7c.js | 3 + .../select2/i18n/sr-Cyrl.f254bb8c4c7c.js.gz | Bin 0 -> 608 bytes .../admin/js/vendor/select2/i18n/sr-Cyrl.js | 3 + .../js/vendor/select2/i18n/sr-Cyrl.js.gz | Bin 0 -> 608 bytes .../js/vendor/select2/i18n/sr.5ed85a48f483.js | 3 + .../vendor/select2/i18n/sr.5ed85a48f483.js.gz | Bin 0 -> 552 bytes .../admin/js/vendor/select2/i18n/sr.js | 3 + .../admin/js/vendor/select2/i18n/sr.js.gz | Bin 0 -> 552 bytes .../js/vendor/select2/i18n/sv.7a9c2f71e777.js | 3 + .../vendor/select2/i18n/sv.7a9c2f71e777.js.gz | Bin 0 -> 429 bytes .../admin/js/vendor/select2/i18n/sv.js | 3 + .../admin/js/vendor/select2/i18n/sv.js.gz | Bin 0 -> 429 bytes .../js/vendor/select2/i18n/th.f38c20b0221b.js | 3 + .../vendor/select2/i18n/th.f38c20b0221b.js.gz | Bin 0 -> 515 bytes .../admin/js/vendor/select2/i18n/th.js | 3 + .../admin/js/vendor/select2/i18n/th.js.gz | Bin 0 -> 515 bytes .../js/vendor/select2/i18n/tk.7c572a68c78f.js | 3 + .../vendor/select2/i18n/tk.7c572a68c78f.js.gz | Bin 0 -> 434 bytes .../admin/js/vendor/select2/i18n/tk.js | 3 + .../admin/js/vendor/select2/i18n/tk.js.gz | Bin 0 -> 434 bytes .../js/vendor/select2/i18n/tr.b5a0643d1545.js | 3 + .../vendor/select2/i18n/tr.b5a0643d1545.js.gz | Bin 0 -> 423 bytes .../admin/js/vendor/select2/i18n/tr.js | 3 + .../admin/js/vendor/select2/i18n/tr.js.gz | Bin 0 -> 423 bytes .../js/vendor/select2/i18n/uk.8cede7f4803c.js | 3 + .../vendor/select2/i18n/uk.8cede7f4803c.js.gz | Bin 0 -> 626 bytes .../admin/js/vendor/select2/i18n/uk.js | 3 + .../admin/js/vendor/select2/i18n/uk.js.gz | Bin 0 -> 626 bytes .../js/vendor/select2/i18n/vi.097a5b75b3e1.js | 3 + .../vendor/select2/i18n/vi.097a5b75b3e1.js.gz | Bin 0 -> 479 bytes .../admin/js/vendor/select2/i18n/vi.js | 3 + .../admin/js/vendor/select2/i18n/vi.js.gz | Bin 0 -> 479 bytes .../vendor/select2/i18n/zh-CN.2cff662ec5f9.js | 3 + .../select2/i18n/zh-CN.2cff662ec5f9.js.gz | Bin 0 -> 468 bytes .../admin/js/vendor/select2/i18n/zh-CN.js | 3 + .../admin/js/vendor/select2/i18n/zh-CN.js.gz | Bin 0 -> 468 bytes .../vendor/select2/i18n/zh-TW.04554a227c2b.js | 3 + .../select2/i18n/zh-TW.04554a227c2b.js.gz | Bin 0 -> 451 bytes .../admin/js/vendor/select2/i18n/zh-TW.js | 3 + .../admin/js/vendor/select2/i18n/zh-TW.js.gz | Bin 0 -> 451 bytes .../select2/select2.full.c2afdeda3058.js | 6820 ++++++ .../select2/select2.full.c2afdeda3058.js.gz | Bin 0 -> 37925 bytes .../admin/js/vendor/select2/select2.full.js | 6820 ++++++ .../js/vendor/select2/select2.full.js.gz | Bin 0 -> 37925 bytes .../select2/select2.full.min.fcd7500d8e13.js | 2 + .../select2.full.min.fcd7500d8e13.js.gz | Bin 0 -> 21986 bytes .../js/vendor/select2/select2.full.min.js | 2 + .../js/vendor/select2/select2.full.min.js.gz | Bin 0 -> 21986 bytes .../vendor/xregexp/LICENSE.bf79e414957a.txt | 21 + .../xregexp/LICENSE.bf79e414957a.txt.gz | Bin 0 -> 679 bytes .../admin/js/vendor/xregexp/LICENSE.txt | 21 + .../admin/js/vendor/xregexp/LICENSE.txt.gz | Bin 0 -> 679 bytes .../js/vendor/xregexp/xregexp.efda034b9537.js | 4652 ++++ .../vendor/xregexp/xregexp.efda034b9537.js.gz | Bin 0 -> 60899 bytes .../admin/js/vendor/xregexp/xregexp.js | 4652 ++++ .../admin/js/vendor/xregexp/xregexp.js.gz | Bin 0 -> 60899 bytes .../xregexp/xregexp.min.b0439563a5d3.js | 160 + .../xregexp/xregexp.min.b0439563a5d3.js.gz | Bin 0 -> 37609 bytes .../admin/js/vendor/xregexp/xregexp.min.js | 160 + .../admin/js/vendor/xregexp/xregexp.min.js.gz | Bin 0 -> 37609 bytes .../Metropolis-Black.de55ae52af85.otf | Bin 0 -> 23696 bytes .../Metropolis-Black.de55ae52af85.otf.gz | Bin 0 -> 17858 bytes .../fonts/metropolis/Metropolis-Black.otf | Bin 0 -> 23696 bytes .../fonts/metropolis/Metropolis-Black.otf.gz | Bin 0 -> 17858 bytes .../Metropolis-BlackItalic.ef50aa42a925.otf | Bin 0 -> 24288 bytes ...Metropolis-BlackItalic.ef50aa42a925.otf.gz | Bin 0 -> 18400 bytes .../metropolis/Metropolis-BlackItalic.otf | Bin 0 -> 24288 bytes .../metropolis/Metropolis-BlackItalic.otf.gz | Bin 0 -> 18400 bytes .../Metropolis-Bold.dea4998b081c.otf | Bin 0 -> 23664 bytes .../Metropolis-Bold.dea4998b081c.otf.gz | Bin 0 -> 17866 bytes .../fonts/metropolis/Metropolis-Bold.otf | Bin 0 -> 23664 bytes .../fonts/metropolis/Metropolis-Bold.otf.gz | Bin 0 -> 17866 bytes .../Metropolis-BoldItalic.15b149fc383c.otf | Bin 0 -> 24332 bytes .../Metropolis-BoldItalic.15b149fc383c.otf.gz | Bin 0 -> 18493 bytes .../metropolis/Metropolis-BoldItalic.otf | Bin 0 -> 24332 bytes .../metropolis/Metropolis-BoldItalic.otf.gz | Bin 0 -> 18493 bytes .../Metropolis-ExtraBold.d7eaa8ab58ec.otf | Bin 0 -> 23700 bytes .../Metropolis-ExtraBold.d7eaa8ab58ec.otf.gz | Bin 0 -> 17770 bytes .../fonts/metropolis/Metropolis-ExtraBold.otf | Bin 0 -> 23700 bytes .../metropolis/Metropolis-ExtraBold.otf.gz | Bin 0 -> 17770 bytes ...etropolis-ExtraBoldItalic.f1e8fdf108c2.otf | Bin 0 -> 24588 bytes ...opolis-ExtraBoldItalic.f1e8fdf108c2.otf.gz | Bin 0 -> 18586 bytes .../metropolis/Metropolis-ExtraBoldItalic.otf | Bin 0 -> 24588 bytes .../Metropolis-ExtraBoldItalic.otf.gz | Bin 0 -> 18586 bytes .../Metropolis-ExtraLight.c5ae09393655.otf | Bin 0 -> 23080 bytes .../Metropolis-ExtraLight.c5ae09393655.otf.gz | Bin 0 -> 17363 bytes .../metropolis/Metropolis-ExtraLight.otf | Bin 0 -> 23080 bytes .../metropolis/Metropolis-ExtraLight.otf.gz | Bin 0 -> 17363 bytes ...tropolis-ExtraLightItalic.414a434d6ad4.otf | Bin 0 -> 24284 bytes ...polis-ExtraLightItalic.414a434d6ad4.otf.gz | Bin 0 -> 18402 bytes .../Metropolis-ExtraLightItalic.otf | Bin 0 -> 24284 bytes .../Metropolis-ExtraLightItalic.otf.gz | Bin 0 -> 18402 bytes .../Metropolis-Light.c82170e08b76.otf | Bin 0 -> 23200 bytes .../Metropolis-Light.c82170e08b76.otf.gz | Bin 0 -> 17524 bytes .../fonts/metropolis/Metropolis-Light.otf | Bin 0 -> 23200 bytes .../fonts/metropolis/Metropolis-Light.otf.gz | Bin 0 -> 17524 bytes .../Metropolis-LightItalic.2de2a64942ec.otf | Bin 0 -> 24208 bytes ...Metropolis-LightItalic.2de2a64942ec.otf.gz | Bin 0 -> 18446 bytes .../metropolis/Metropolis-LightItalic.otf | Bin 0 -> 24208 bytes .../metropolis/Metropolis-LightItalic.otf.gz | Bin 0 -> 18446 bytes .../Metropolis-Medium.f4bca87fd0d1.otf | Bin 0 -> 23240 bytes .../Metropolis-Medium.f4bca87fd0d1.otf.gz | Bin 0 -> 17531 bytes .../fonts/metropolis/Metropolis-Medium.otf | Bin 0 -> 23240 bytes .../fonts/metropolis/Metropolis-Medium.otf.gz | Bin 0 -> 17531 bytes .../Metropolis-MediumItalic.60eace1cb8db.otf | Bin 0 -> 24352 bytes ...etropolis-MediumItalic.60eace1cb8db.otf.gz | Bin 0 -> 18523 bytes .../metropolis/Metropolis-MediumItalic.otf | Bin 0 -> 24352 bytes .../metropolis/Metropolis-MediumItalic.otf.gz | Bin 0 -> 18523 bytes .../Metropolis-Regular.f7b5e589f882.otf | Bin 0 -> 23124 bytes .../Metropolis-Regular.f7b5e589f882.otf.gz | Bin 0 -> 17414 bytes .../fonts/metropolis/Metropolis-Regular.otf | Bin 0 -> 23124 bytes .../metropolis/Metropolis-Regular.otf.gz | Bin 0 -> 17414 bytes .../Metropolis-RegularItalic.763b44257f3a.otf | Bin 0 -> 24236 bytes ...tropolis-RegularItalic.763b44257f3a.otf.gz | Bin 0 -> 18391 bytes .../metropolis/Metropolis-RegularItalic.otf | Bin 0 -> 24236 bytes .../Metropolis-RegularItalic.otf.gz | Bin 0 -> 18391 bytes .../Metropolis-SemiBold.2556a4f74e2c.otf | Bin 0 -> 23480 bytes .../Metropolis-SemiBold.2556a4f74e2c.otf.gz | Bin 0 -> 17678 bytes .../fonts/metropolis/Metropolis-SemiBold.otf | Bin 0 -> 23480 bytes .../metropolis/Metropolis-SemiBold.otf.gz | Bin 0 -> 17678 bytes ...Metropolis-SemiBoldItalic.536778d712a7.otf | Bin 0 -> 24284 bytes ...ropolis-SemiBoldItalic.536778d712a7.otf.gz | Bin 0 -> 18422 bytes .../metropolis/Metropolis-SemiBoldItalic.otf | Bin 0 -> 24284 bytes .../Metropolis-SemiBoldItalic.otf.gz | Bin 0 -> 18422 bytes .../Metropolis-Thin.152ab0324f44.otf | Bin 0 -> 22920 bytes .../Metropolis-Thin.152ab0324f44.otf.gz | Bin 0 -> 17154 bytes .../fonts/metropolis/Metropolis-Thin.otf | Bin 0 -> 22920 bytes .../fonts/metropolis/Metropolis-Thin.otf.gz | Bin 0 -> 17154 bytes .../Metropolis-ThinItalic.a10db35c6f48.otf | Bin 0 -> 24052 bytes .../Metropolis-ThinItalic.a10db35c6f48.otf.gz | Bin 0 -> 18235 bytes .../metropolis/Metropolis-ThinItalic.otf | Bin 0 -> 24052 bytes .../metropolis/Metropolis-ThinItalic.otf.gz | Bin 0 -> 18235 bytes .../SIL Open Font License.c57a7243a693.txt | 43 + .../SIL Open Font License.c57a7243a693.txt.gz | Bin 0 -> 1893 bytes .../metropolis/SIL Open Font License.txt | 43 + .../metropolis/SIL Open Font License.txt.gz | Bin 0 -> 1893 bytes .../backgrounds/bg-angles.86aa216ed924.svg | 15 + .../backgrounds/bg-angles.86aa216ed924.svg.gz | Bin 0 -> 336 bytes .../assets/img/backgrounds/bg-angles.svg | 15 + .../assets/img/backgrounds/bg-angles.svg.gz | Bin 0 -> 336 bytes .../img/backgrounds/bg-waves.5d8706256c0d.svg | 12 + .../backgrounds/bg-waves.5d8706256c0d.svg.gz | Bin 0 -> 326 bytes .../assets/img/backgrounds/bg-waves.svg | 12 + .../assets/img/backgrounds/bg-waves.svg.gz | Bin 0 -> 326 bytes .../iPhoneX/landscape.7215ee9c7d9d.png | 1 + .../iPhoneX/landscape.ef6fe3565ad7.svg | 7 + .../iPhoneX/landscape.ef6fe3565ad7.svg.gz | Bin 0 -> 294 bytes .../img/device-mockups/iPhoneX/landscape.png | 1 + .../img/device-mockups/iPhoneX/landscape.svg | 7 + .../device-mockups/iPhoneX/landscape.svg.gz | Bin 0 -> 294 bytes .../iPhoneX/landscape_black.a6c19346cb06.svg | 7 + .../landscape_black.a6c19346cb06.svg.gz | Bin 0 -> 297 bytes .../iPhoneX/landscape_black.svg | 7 + .../iPhoneX/landscape_black.svg.gz | Bin 0 -> 297 bytes .../iPhoneX/portrait.31d1551eb654.svg | 7 + .../iPhoneX/portrait.31d1551eb654.svg.gz | Bin 0 -> 292 bytes .../iPhoneX/portrait.7215ee9c7d9d.png | 1 + .../img/device-mockups/iPhoneX/portrait.png | 1 + .../img/device-mockups/iPhoneX/portrait.svg | 7 + .../device-mockups/iPhoneX/portrait.svg.gz | Bin 0 -> 292 bytes .../iPhoneX/portrait_black.d08f91b96905.svg | 7 + .../portrait_black.d08f91b96905.svg.gz | Bin 0 -> 295 bytes .../device-mockups/iPhoneX/portrait_black.svg | 7 + .../iPhoneX/portrait_black.svg.gz | Bin 0 -> 295 bytes staticfiles/assets/img/logo.914481b1bde7.png | Bin 0 -> 27037 bytes staticfiles/assets/img/logo.png | Bin 0 -> 27037 bytes staticfiles/css/styles.ba54308dbf55.css | 20247 ++++++++++++++++ staticfiles/css/styles.ba54308dbf55.css.gz | Bin 0 -> 47836 bytes staticfiles/css/styles.css | 20240 +++++++++++++++ staticfiles/css/styles.css.gz | Bin 0 -> 47544 bytes staticfiles/js/scripts.8f70dc8a6692.js | 50 + staticfiles/js/scripts.8f70dc8a6692.js.gz | Bin 0 -> 764 bytes staticfiles/js/scripts.js | 50 + staticfiles/js/scripts.js.gz | Bin 0 -> 764 bytes staticfiles/staticfiles.json | 1 + 632 files changed, 102732 insertions(+), 5 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/ci-cd.yml create mode 100644 DEPLOYMENT.md create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 oc_lettings_site/settings_production.py create mode 100644 start.sh create mode 100644 static/assets/img/backgrounds/bg-angles.svg create mode 100644 static/assets/img/backgrounds/bg-waves.svg create mode 100644 static/assets/img/device-mockups/iPhoneX/landscape.png create mode 100644 static/assets/img/device-mockups/iPhoneX/landscape.svg create mode 100644 static/assets/img/device-mockups/iPhoneX/landscape_black.svg create mode 100644 static/assets/img/device-mockups/iPhoneX/portrait.png create mode 100644 static/assets/img/device-mockups/iPhoneX/portrait.svg create mode 100644 static/assets/img/device-mockups/iPhoneX/portrait_black.svg create mode 100644 staticfiles/admin/css/autocomplete.4a81fc4242d0.css create mode 100644 staticfiles/admin/css/autocomplete.4a81fc4242d0.css.gz create mode 100644 staticfiles/admin/css/autocomplete.css create mode 100644 staticfiles/admin/css/autocomplete.css.gz create mode 100644 staticfiles/admin/css/base.523eb49842a7.css create mode 100644 staticfiles/admin/css/base.523eb49842a7.css.gz create mode 100644 staticfiles/admin/css/base.css create mode 100644 staticfiles/admin/css/base.css.gz create mode 100644 staticfiles/admin/css/changelists.9237a1ac391b.css create mode 100644 staticfiles/admin/css/changelists.9237a1ac391b.css.gz create mode 100644 staticfiles/admin/css/changelists.css create mode 100644 staticfiles/admin/css/changelists.css.gz create mode 100644 staticfiles/admin/css/dark_mode.css create mode 100644 staticfiles/admin/css/dark_mode.css.gz create mode 100644 staticfiles/admin/css/dark_mode.ef27a31af300.css create mode 100644 staticfiles/admin/css/dark_mode.ef27a31af300.css.gz create mode 100644 staticfiles/admin/css/dashboard.css create mode 100644 staticfiles/admin/css/dashboard.css.gz create mode 100644 staticfiles/admin/css/dashboard.e90f2068217b.css create mode 100644 staticfiles/admin/css/dashboard.e90f2068217b.css.gz create mode 100644 staticfiles/admin/css/forms.c14e1cb06392.css create mode 100644 staticfiles/admin/css/forms.c14e1cb06392.css.gz create mode 100644 staticfiles/admin/css/forms.css create mode 100644 staticfiles/admin/css/forms.css.gz create mode 100644 staticfiles/admin/css/login.586129c60a93.css create mode 100644 staticfiles/admin/css/login.586129c60a93.css.gz create mode 100644 staticfiles/admin/css/login.css create mode 100644 staticfiles/admin/css/login.css.gz create mode 100644 staticfiles/admin/css/nav_sidebar.269a1bd44627.css create mode 100644 staticfiles/admin/css/nav_sidebar.269a1bd44627.css.gz create mode 100644 staticfiles/admin/css/nav_sidebar.css create mode 100644 staticfiles/admin/css/nav_sidebar.css.gz create mode 100644 staticfiles/admin/css/responsive.css create mode 100644 staticfiles/admin/css/responsive.css.gz create mode 100644 staticfiles/admin/css/responsive.f6533dab034d.css create mode 100644 staticfiles/admin/css/responsive.f6533dab034d.css.gz create mode 100644 staticfiles/admin/css/responsive_rtl.7d1130848605.css create mode 100644 staticfiles/admin/css/responsive_rtl.7d1130848605.css.gz create mode 100644 staticfiles/admin/css/responsive_rtl.css create mode 100644 staticfiles/admin/css/responsive_rtl.css.gz create mode 100644 staticfiles/admin/css/rtl.512d4b53fc59.css create mode 100644 staticfiles/admin/css/rtl.512d4b53fc59.css.gz create mode 100644 staticfiles/admin/css/rtl.css create mode 100644 staticfiles/admin/css/rtl.css.gz create mode 100644 staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.f94142512c91.md create mode 100644 staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.f94142512c91.md.gz create mode 100644 staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.md create mode 100644 staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.md.gz create mode 100644 staticfiles/admin/css/vendor/select2/select2.a2194c262648.css create mode 100644 staticfiles/admin/css/vendor/select2/select2.a2194c262648.css.gz create mode 100644 staticfiles/admin/css/vendor/select2/select2.css create mode 100644 staticfiles/admin/css/vendor/select2/select2.css.gz create mode 100644 staticfiles/admin/css/vendor/select2/select2.min.9f54e6414f87.css create mode 100644 staticfiles/admin/css/vendor/select2/select2.min.9f54e6414f87.css.gz create mode 100644 staticfiles/admin/css/vendor/select2/select2.min.css create mode 100644 staticfiles/admin/css/vendor/select2/select2.min.css.gz create mode 100644 staticfiles/admin/css/widgets.css create mode 100644 staticfiles/admin/css/widgets.css.gz create mode 100644 staticfiles/admin/css/widgets.ee33ab26c7c2.css create mode 100644 staticfiles/admin/css/widgets.ee33ab26c7c2.css.gz create mode 100644 staticfiles/admin/img/LICENSE create mode 100644 staticfiles/admin/img/LICENSE.2c54f4e1ca1c create mode 100644 staticfiles/admin/img/LICENSE.2c54f4e1ca1c.gz create mode 100644 staticfiles/admin/img/LICENSE.gz create mode 100644 staticfiles/admin/img/README.a70711a38d87.txt create mode 100644 staticfiles/admin/img/README.a70711a38d87.txt.gz create mode 100644 staticfiles/admin/img/README.txt create mode 100644 staticfiles/admin/img/README.txt.gz create mode 100644 staticfiles/admin/img/calendar-icons.39b290681a8b.svg create mode 100644 staticfiles/admin/img/calendar-icons.39b290681a8b.svg.gz create mode 100644 staticfiles/admin/img/calendar-icons.svg create mode 100644 staticfiles/admin/img/calendar-icons.svg.gz create mode 100644 staticfiles/admin/img/gis/move_vertex_off.7a23bf31ef8a.svg create mode 100644 staticfiles/admin/img/gis/move_vertex_off.7a23bf31ef8a.svg.gz create mode 100644 staticfiles/admin/img/gis/move_vertex_off.svg create mode 100644 staticfiles/admin/img/gis/move_vertex_off.svg.gz create mode 100644 staticfiles/admin/img/gis/move_vertex_on.0047eba25b67.svg create mode 100644 staticfiles/admin/img/gis/move_vertex_on.0047eba25b67.svg.gz create mode 100644 staticfiles/admin/img/gis/move_vertex_on.svg create mode 100644 staticfiles/admin/img/gis/move_vertex_on.svg.gz create mode 100644 staticfiles/admin/img/icon-addlink.d519b3bab011.svg create mode 100644 staticfiles/admin/img/icon-addlink.d519b3bab011.svg.gz create mode 100644 staticfiles/admin/img/icon-addlink.svg create mode 100644 staticfiles/admin/img/icon-addlink.svg.gz create mode 100644 staticfiles/admin/img/icon-alert.034cc7d8a67f.svg create mode 100644 staticfiles/admin/img/icon-alert.034cc7d8a67f.svg.gz create mode 100644 staticfiles/admin/img/icon-alert.svg create mode 100644 staticfiles/admin/img/icon-alert.svg.gz create mode 100644 staticfiles/admin/img/icon-calendar.ac7aea671bea.svg create mode 100644 staticfiles/admin/img/icon-calendar.ac7aea671bea.svg.gz create mode 100644 staticfiles/admin/img/icon-calendar.svg create mode 100644 staticfiles/admin/img/icon-calendar.svg.gz create mode 100644 staticfiles/admin/img/icon-changelink.18d2fd706348.svg create mode 100644 staticfiles/admin/img/icon-changelink.18d2fd706348.svg.gz create mode 100644 staticfiles/admin/img/icon-changelink.svg create mode 100644 staticfiles/admin/img/icon-changelink.svg.gz create mode 100644 staticfiles/admin/img/icon-clock.e1d4dfac3f2b.svg create mode 100644 staticfiles/admin/img/icon-clock.e1d4dfac3f2b.svg.gz create mode 100644 staticfiles/admin/img/icon-clock.svg create mode 100644 staticfiles/admin/img/icon-clock.svg.gz create mode 100644 staticfiles/admin/img/icon-deletelink.564ef9dc3854.svg create mode 100644 staticfiles/admin/img/icon-deletelink.564ef9dc3854.svg.gz create mode 100644 staticfiles/admin/img/icon-deletelink.svg create mode 100644 staticfiles/admin/img/icon-deletelink.svg.gz create mode 100644 staticfiles/admin/img/icon-no.439e821418cd.svg create mode 100644 staticfiles/admin/img/icon-no.439e821418cd.svg.gz create mode 100644 staticfiles/admin/img/icon-no.svg create mode 100644 staticfiles/admin/img/icon-no.svg.gz create mode 100644 staticfiles/admin/img/icon-unknown-alt.81536e128bb6.svg create mode 100644 staticfiles/admin/img/icon-unknown-alt.81536e128bb6.svg.gz create mode 100644 staticfiles/admin/img/icon-unknown-alt.svg create mode 100644 staticfiles/admin/img/icon-unknown-alt.svg.gz create mode 100644 staticfiles/admin/img/icon-unknown.a18cb4398978.svg create mode 100644 staticfiles/admin/img/icon-unknown.a18cb4398978.svg.gz create mode 100644 staticfiles/admin/img/icon-unknown.svg create mode 100644 staticfiles/admin/img/icon-unknown.svg.gz create mode 100644 staticfiles/admin/img/icon-viewlink.41eb31f7826e.svg create mode 100644 staticfiles/admin/img/icon-viewlink.41eb31f7826e.svg.gz create mode 100644 staticfiles/admin/img/icon-viewlink.svg create mode 100644 staticfiles/admin/img/icon-viewlink.svg.gz create mode 100644 staticfiles/admin/img/icon-yes.d2f9f035226a.svg create mode 100644 staticfiles/admin/img/icon-yes.d2f9f035226a.svg.gz create mode 100644 staticfiles/admin/img/icon-yes.svg create mode 100644 staticfiles/admin/img/icon-yes.svg.gz create mode 100644 staticfiles/admin/img/inline-delete.fec1b761f254.svg create mode 100644 staticfiles/admin/img/inline-delete.fec1b761f254.svg.gz create mode 100644 staticfiles/admin/img/inline-delete.svg create mode 100644 staticfiles/admin/img/inline-delete.svg.gz create mode 100644 staticfiles/admin/img/search.7cf54ff789c6.svg create mode 100644 staticfiles/admin/img/search.7cf54ff789c6.svg.gz create mode 100644 staticfiles/admin/img/search.svg create mode 100644 staticfiles/admin/img/search.svg.gz create mode 100644 staticfiles/admin/img/selector-icons.b4555096cea2.svg create mode 100644 staticfiles/admin/img/selector-icons.b4555096cea2.svg.gz create mode 100644 staticfiles/admin/img/selector-icons.svg create mode 100644 staticfiles/admin/img/selector-icons.svg.gz create mode 100644 staticfiles/admin/img/sorting-icons.3a097b59f104.svg create mode 100644 staticfiles/admin/img/sorting-icons.3a097b59f104.svg.gz create mode 100644 staticfiles/admin/img/sorting-icons.svg create mode 100644 staticfiles/admin/img/sorting-icons.svg.gz create mode 100644 staticfiles/admin/img/tooltag-add.e59d620a9742.svg create mode 100644 staticfiles/admin/img/tooltag-add.e59d620a9742.svg.gz create mode 100644 staticfiles/admin/img/tooltag-add.svg create mode 100644 staticfiles/admin/img/tooltag-add.svg.gz create mode 100644 staticfiles/admin/img/tooltag-arrowright.bbfb788a849e.svg create mode 100644 staticfiles/admin/img/tooltag-arrowright.bbfb788a849e.svg.gz create mode 100644 staticfiles/admin/img/tooltag-arrowright.svg create mode 100644 staticfiles/admin/img/tooltag-arrowright.svg.gz create mode 100644 staticfiles/admin/js/SelectBox.7d3ce5a98007.js create mode 100644 staticfiles/admin/js/SelectBox.7d3ce5a98007.js.gz create mode 100644 staticfiles/admin/js/SelectBox.js create mode 100644 staticfiles/admin/js/SelectBox.js.gz create mode 100644 staticfiles/admin/js/SelectFilter2.bdb8d0cc579e.js create mode 100644 staticfiles/admin/js/SelectFilter2.bdb8d0cc579e.js.gz create mode 100644 staticfiles/admin/js/SelectFilter2.js create mode 100644 staticfiles/admin/js/SelectFilter2.js.gz create mode 100644 staticfiles/admin/js/actions.eac7e3441574.js create mode 100644 staticfiles/admin/js/actions.eac7e3441574.js.gz create mode 100644 staticfiles/admin/js/actions.js create mode 100644 staticfiles/admin/js/actions.js.gz create mode 100644 staticfiles/admin/js/admin/DateTimeShortcuts.9f6e209cebca.js create mode 100644 staticfiles/admin/js/admin/DateTimeShortcuts.9f6e209cebca.js.gz create mode 100644 staticfiles/admin/js/admin/DateTimeShortcuts.js create mode 100644 staticfiles/admin/js/admin/DateTimeShortcuts.js.gz create mode 100644 staticfiles/admin/js/admin/RelatedObjectLookups.8609f99b9ab2.js create mode 100644 staticfiles/admin/js/admin/RelatedObjectLookups.8609f99b9ab2.js.gz create mode 100644 staticfiles/admin/js/admin/RelatedObjectLookups.js create mode 100644 staticfiles/admin/js/admin/RelatedObjectLookups.js.gz create mode 100644 staticfiles/admin/js/autocomplete.01591ab27be7.js create mode 100644 staticfiles/admin/js/autocomplete.01591ab27be7.js.gz create mode 100644 staticfiles/admin/js/autocomplete.js create mode 100644 staticfiles/admin/js/autocomplete.js.gz create mode 100644 staticfiles/admin/js/calendar.f8a5d055eb33.js create mode 100644 staticfiles/admin/js/calendar.f8a5d055eb33.js.gz create mode 100644 staticfiles/admin/js/calendar.js create mode 100644 staticfiles/admin/js/calendar.js.gz create mode 100644 staticfiles/admin/js/cancel.ecc4c5ca7b32.js create mode 100644 staticfiles/admin/js/cancel.ecc4c5ca7b32.js.gz create mode 100644 staticfiles/admin/js/cancel.js create mode 100644 staticfiles/admin/js/cancel.js.gz create mode 100644 staticfiles/admin/js/change_form.9d8ca4f96b75.js create mode 100644 staticfiles/admin/js/change_form.9d8ca4f96b75.js.gz create mode 100644 staticfiles/admin/js/change_form.js create mode 100644 staticfiles/admin/js/change_form.js.gz create mode 100644 staticfiles/admin/js/collapse.f84e7410290f.js create mode 100644 staticfiles/admin/js/collapse.f84e7410290f.js.gz create mode 100644 staticfiles/admin/js/collapse.js create mode 100644 staticfiles/admin/js/collapse.js.gz create mode 100644 staticfiles/admin/js/core.cf103cd04ebf.js create mode 100644 staticfiles/admin/js/core.cf103cd04ebf.js.gz create mode 100644 staticfiles/admin/js/core.js create mode 100644 staticfiles/admin/js/core.js.gz create mode 100644 staticfiles/admin/js/filters.0e360b7a9f80.js create mode 100644 staticfiles/admin/js/filters.0e360b7a9f80.js.gz create mode 100644 staticfiles/admin/js/filters.js create mode 100644 staticfiles/admin/js/filters.js.gz create mode 100644 staticfiles/admin/js/inlines.22d4d93c00b4.js create mode 100644 staticfiles/admin/js/inlines.22d4d93c00b4.js.gz create mode 100644 staticfiles/admin/js/inlines.js create mode 100644 staticfiles/admin/js/inlines.js.gz create mode 100644 staticfiles/admin/js/jquery.init.b7781a0897fc.js create mode 100644 staticfiles/admin/js/jquery.init.b7781a0897fc.js.gz create mode 100644 staticfiles/admin/js/jquery.init.js create mode 100644 staticfiles/admin/js/jquery.init.js.gz create mode 100644 staticfiles/admin/js/nav_sidebar.3b9190d420b1.js create mode 100644 staticfiles/admin/js/nav_sidebar.3b9190d420b1.js.gz create mode 100644 staticfiles/admin/js/nav_sidebar.js create mode 100644 staticfiles/admin/js/nav_sidebar.js.gz create mode 100644 staticfiles/admin/js/popup_response.c6cc78ea5551.js create mode 100644 staticfiles/admin/js/popup_response.c6cc78ea5551.js.gz create mode 100644 staticfiles/admin/js/popup_response.js create mode 100644 staticfiles/admin/js/popup_response.js.gz create mode 100644 staticfiles/admin/js/prepopulate.bd2361dfd64d.js create mode 100644 staticfiles/admin/js/prepopulate.bd2361dfd64d.js.gz create mode 100644 staticfiles/admin/js/prepopulate.js create mode 100644 staticfiles/admin/js/prepopulate.js.gz create mode 100644 staticfiles/admin/js/prepopulate_init.6cac7f3105b8.js create mode 100644 staticfiles/admin/js/prepopulate_init.6cac7f3105b8.js.gz create mode 100644 staticfiles/admin/js/prepopulate_init.js create mode 100644 staticfiles/admin/js/prepopulate_init.js.gz create mode 100644 staticfiles/admin/js/theme.ab270f56bb9c.js create mode 100644 staticfiles/admin/js/theme.ab270f56bb9c.js.gz create mode 100644 staticfiles/admin/js/theme.js create mode 100644 staticfiles/admin/js/theme.js.gz create mode 100644 staticfiles/admin/js/urlify.ae970a820212.js create mode 100644 staticfiles/admin/js/urlify.ae970a820212.js.gz create mode 100644 staticfiles/admin/js/urlify.js create mode 100644 staticfiles/admin/js/urlify.js.gz create mode 100644 staticfiles/admin/js/vendor/jquery/LICENSE.de877aa6d744.txt create mode 100644 staticfiles/admin/js/vendor/jquery/LICENSE.de877aa6d744.txt.gz create mode 100644 staticfiles/admin/js/vendor/jquery/LICENSE.txt create mode 100644 staticfiles/admin/js/vendor/jquery/LICENSE.txt.gz create mode 100644 staticfiles/admin/js/vendor/jquery/jquery.0208b96062ba.js create mode 100644 staticfiles/admin/js/vendor/jquery/jquery.0208b96062ba.js.gz create mode 100644 staticfiles/admin/js/vendor/jquery/jquery.js create mode 100644 staticfiles/admin/js/vendor/jquery/jquery.js.gz create mode 100644 staticfiles/admin/js/vendor/jquery/jquery.min.641dd1437010.js create mode 100644 staticfiles/admin/js/vendor/jquery/jquery.min.641dd1437010.js.gz create mode 100644 staticfiles/admin/js/vendor/jquery/jquery.min.js create mode 100644 staticfiles/admin/js/vendor/jquery/jquery.min.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/LICENSE.f94142512c91.md create mode 100644 staticfiles/admin/js/vendor/select2/LICENSE.f94142512c91.md.gz create mode 100644 staticfiles/admin/js/vendor/select2/LICENSE.md create mode 100644 staticfiles/admin/js/vendor/select2/LICENSE.md.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/af.4f6fcd73488c.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/af.4f6fcd73488c.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/af.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/af.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ar.65aa8e36bf5d.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ar.65aa8e36bf5d.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ar.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ar.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/az.270c257daf81.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/az.270c257daf81.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/az.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/az.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bg.39b8be30d4f0.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bg.39b8be30d4f0.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bg.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bg.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bn.6d42b4dd5665.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bn.6d42b4dd5665.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bn.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bn.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bs.91624382358e.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bs.91624382358e.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bs.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/bs.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ca.a166b745933a.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ca.a166b745933a.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ca.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ca.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/cs.4f43e8e7d33a.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/cs.4f43e8e7d33a.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/cs.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/cs.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/da.766346afe4dd.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/da.766346afe4dd.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/da.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/da.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/de.8a1c222b0204.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/de.8a1c222b0204.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/de.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/de.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/dsb.56372c92d2f1.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/dsb.56372c92d2f1.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/dsb.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/dsb.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/el.27097f071856.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/el.27097f071856.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/el.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/el.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/en.cf932ba09a98.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/en.cf932ba09a98.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/en.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/en.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/es.66dbc2652fb1.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/es.66dbc2652fb1.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/es.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/es.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/et.2b96fd98289d.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/et.2b96fd98289d.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/et.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/et.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/eu.adfe5c97b72c.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/eu.adfe5c97b72c.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/eu.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/eu.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fa.3b5bd1961cfd.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fa.3b5bd1961cfd.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fa.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fa.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fi.614ec42aa9ba.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fi.614ec42aa9ba.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fi.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fi.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fr.05e0542fcfe6.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fr.05e0542fcfe6.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fr.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/fr.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/gl.d99b1fedaa86.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/gl.d99b1fedaa86.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/gl.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/gl.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/he.e420ff6cd3ed.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/he.e420ff6cd3ed.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/he.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/he.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hi.70640d41628f.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hi.70640d41628f.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hi.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hi.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hr.a2b092cc1147.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hr.a2b092cc1147.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hr.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hr.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hsb.fa3b55265efe.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hsb.fa3b55265efe.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hsb.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hsb.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hu.6ec6039cb8a3.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hu.6ec6039cb8a3.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hu.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hu.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hy.c7babaeef5a6.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hy.c7babaeef5a6.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hy.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/hy.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/id.04debded514d.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/id.04debded514d.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/id.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/id.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/is.3ddd9a6a97e9.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/is.3ddd9a6a97e9.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/is.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/is.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/it.be4fe8d365b5.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/it.be4fe8d365b5.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/it.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/it.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ja.170ae885d74f.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ja.170ae885d74f.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ja.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ja.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ka.2083264a54f0.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ka.2083264a54f0.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ka.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ka.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/km.c23089cb06ca.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/km.c23089cb06ca.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/km.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/km.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ko.e7be6c20e673.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ko.e7be6c20e673.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ko.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ko.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/lt.23c7ce903300.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/lt.23c7ce903300.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/lt.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/lt.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/lv.08e62128eac1.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/lv.08e62128eac1.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/lv.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/lv.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/mk.dabbb9087130.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/mk.dabbb9087130.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/mk.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/mk.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ms.4ba82c9a51ce.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ms.4ba82c9a51ce.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ms.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ms.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/nb.da2fce143f27.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/nb.da2fce143f27.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/nb.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/nb.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ne.3d79fd3f08db.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ne.3d79fd3f08db.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ne.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ne.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/nl.997868a37ed8.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/nl.997868a37ed8.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/nl.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/nl.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pl.6031b4f16452.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pl.6031b4f16452.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pl.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pl.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ps.38dfa47af9e0.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ps.38dfa47af9e0.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ps.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ps.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pt-BR.e1b294433e7f.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pt-BR.e1b294433e7f.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pt-BR.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pt-BR.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pt.33b4a3b44d43.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pt.33b4a3b44d43.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pt.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/pt.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ro.f75cb460ec3b.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ro.f75cb460ec3b.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ro.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ro.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ru.934aa95f5b5f.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ru.934aa95f5b5f.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ru.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/ru.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sk.33d02cef8d11.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sk.33d02cef8d11.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sk.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sk.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sl.131a78bc0752.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sl.131a78bc0752.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sl.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sl.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sq.5636b60d29c9.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sq.5636b60d29c9.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sq.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sq.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sr-Cyrl.f254bb8c4c7c.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sr-Cyrl.f254bb8c4c7c.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sr-Cyrl.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sr-Cyrl.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sr.5ed85a48f483.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sr.5ed85a48f483.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sr.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sr.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sv.7a9c2f71e777.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sv.7a9c2f71e777.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sv.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/sv.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/th.f38c20b0221b.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/th.f38c20b0221b.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/th.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/th.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/tk.7c572a68c78f.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/tk.7c572a68c78f.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/tk.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/tk.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/tr.b5a0643d1545.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/tr.b5a0643d1545.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/tr.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/tr.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/uk.8cede7f4803c.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/uk.8cede7f4803c.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/uk.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/uk.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/vi.097a5b75b3e1.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/vi.097a5b75b3e1.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/vi.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/vi.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/zh-CN.2cff662ec5f9.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/zh-CN.2cff662ec5f9.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/zh-CN.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/zh-CN.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/zh-TW.04554a227c2b.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/zh-TW.04554a227c2b.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/i18n/zh-TW.js create mode 100644 staticfiles/admin/js/vendor/select2/i18n/zh-TW.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/select2.full.c2afdeda3058.js create mode 100644 staticfiles/admin/js/vendor/select2/select2.full.c2afdeda3058.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/select2.full.js create mode 100644 staticfiles/admin/js/vendor/select2/select2.full.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/select2.full.min.fcd7500d8e13.js create mode 100644 staticfiles/admin/js/vendor/select2/select2.full.min.fcd7500d8e13.js.gz create mode 100644 staticfiles/admin/js/vendor/select2/select2.full.min.js create mode 100644 staticfiles/admin/js/vendor/select2/select2.full.min.js.gz create mode 100644 staticfiles/admin/js/vendor/xregexp/LICENSE.bf79e414957a.txt create mode 100644 staticfiles/admin/js/vendor/xregexp/LICENSE.bf79e414957a.txt.gz create mode 100644 staticfiles/admin/js/vendor/xregexp/LICENSE.txt create mode 100644 staticfiles/admin/js/vendor/xregexp/LICENSE.txt.gz create mode 100644 staticfiles/admin/js/vendor/xregexp/xregexp.efda034b9537.js create mode 100644 staticfiles/admin/js/vendor/xregexp/xregexp.efda034b9537.js.gz create mode 100644 staticfiles/admin/js/vendor/xregexp/xregexp.js create mode 100644 staticfiles/admin/js/vendor/xregexp/xregexp.js.gz create mode 100644 staticfiles/admin/js/vendor/xregexp/xregexp.min.b0439563a5d3.js create mode 100644 staticfiles/admin/js/vendor/xregexp/xregexp.min.b0439563a5d3.js.gz create mode 100644 staticfiles/admin/js/vendor/xregexp/xregexp.min.js create mode 100644 staticfiles/admin/js/vendor/xregexp/xregexp.min.js.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Black.de55ae52af85.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Black.de55ae52af85.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Black.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Black.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-BlackItalic.ef50aa42a925.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-BlackItalic.ef50aa42a925.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-BlackItalic.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-BlackItalic.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Bold.dea4998b081c.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Bold.dea4998b081c.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Bold.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Bold.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-BoldItalic.15b149fc383c.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-BoldItalic.15b149fc383c.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-BoldItalic.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-BoldItalic.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraBold.d7eaa8ab58ec.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraBold.d7eaa8ab58ec.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraBold.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraBold.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraBoldItalic.f1e8fdf108c2.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraBoldItalic.f1e8fdf108c2.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraBoldItalic.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraBoldItalic.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraLight.c5ae09393655.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraLight.c5ae09393655.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraLight.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraLight.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraLightItalic.414a434d6ad4.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraLightItalic.414a434d6ad4.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraLightItalic.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ExtraLightItalic.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Light.c82170e08b76.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Light.c82170e08b76.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Light.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Light.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-LightItalic.2de2a64942ec.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-LightItalic.2de2a64942ec.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-LightItalic.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-LightItalic.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Medium.f4bca87fd0d1.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Medium.f4bca87fd0d1.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Medium.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Medium.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-MediumItalic.60eace1cb8db.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-MediumItalic.60eace1cb8db.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-MediumItalic.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-MediumItalic.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Regular.f7b5e589f882.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Regular.f7b5e589f882.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Regular.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Regular.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-RegularItalic.763b44257f3a.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-RegularItalic.763b44257f3a.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-RegularItalic.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-RegularItalic.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-SemiBold.2556a4f74e2c.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-SemiBold.2556a4f74e2c.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-SemiBold.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-SemiBold.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-SemiBoldItalic.536778d712a7.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-SemiBoldItalic.536778d712a7.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-SemiBoldItalic.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-SemiBoldItalic.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Thin.152ab0324f44.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Thin.152ab0324f44.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Thin.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-Thin.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ThinItalic.a10db35c6f48.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ThinItalic.a10db35c6f48.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ThinItalic.otf create mode 100644 staticfiles/assets/fonts/metropolis/Metropolis-ThinItalic.otf.gz create mode 100644 staticfiles/assets/fonts/metropolis/SIL Open Font License.c57a7243a693.txt create mode 100644 staticfiles/assets/fonts/metropolis/SIL Open Font License.c57a7243a693.txt.gz create mode 100644 staticfiles/assets/fonts/metropolis/SIL Open Font License.txt create mode 100644 staticfiles/assets/fonts/metropolis/SIL Open Font License.txt.gz create mode 100644 staticfiles/assets/img/backgrounds/bg-angles.86aa216ed924.svg create mode 100644 staticfiles/assets/img/backgrounds/bg-angles.86aa216ed924.svg.gz create mode 100644 staticfiles/assets/img/backgrounds/bg-angles.svg create mode 100644 staticfiles/assets/img/backgrounds/bg-angles.svg.gz create mode 100644 staticfiles/assets/img/backgrounds/bg-waves.5d8706256c0d.svg create mode 100644 staticfiles/assets/img/backgrounds/bg-waves.5d8706256c0d.svg.gz create mode 100644 staticfiles/assets/img/backgrounds/bg-waves.svg create mode 100644 staticfiles/assets/img/backgrounds/bg-waves.svg.gz create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/landscape.7215ee9c7d9d.png create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/landscape.ef6fe3565ad7.svg create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/landscape.ef6fe3565ad7.svg.gz create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/landscape.png create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/landscape.svg create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/landscape.svg.gz create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/landscape_black.a6c19346cb06.svg create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/landscape_black.a6c19346cb06.svg.gz create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/landscape_black.svg create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/landscape_black.svg.gz create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/portrait.31d1551eb654.svg create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/portrait.31d1551eb654.svg.gz create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/portrait.7215ee9c7d9d.png create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/portrait.png create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/portrait.svg create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/portrait.svg.gz create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/portrait_black.d08f91b96905.svg create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/portrait_black.d08f91b96905.svg.gz create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/portrait_black.svg create mode 100644 staticfiles/assets/img/device-mockups/iPhoneX/portrait_black.svg.gz create mode 100644 staticfiles/assets/img/logo.914481b1bde7.png create mode 100644 staticfiles/assets/img/logo.png create mode 100644 staticfiles/css/styles.ba54308dbf55.css create mode 100644 staticfiles/css/styles.ba54308dbf55.css.gz create mode 100644 staticfiles/css/styles.css create mode 100644 staticfiles/css/styles.css.gz create mode 100644 staticfiles/js/scripts.8f70dc8a6692.js create mode 100644 staticfiles/js/scripts.8f70dc8a6692.js.gz create mode 100644 staticfiles/js/scripts.js create mode 100644 staticfiles/js/scripts.js.gz create mode 100644 staticfiles/staticfiles.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..a83efe0a75 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,68 @@ +# Git +.git +.gitignore + +# Python +__pycache__ +*.pyc +*.pyo +*.pyd +.Python +env +pip-log.txt +pip-delete-this-directory.txt +.tox +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.log +.git +.mypy_cache +.pytest_cache +.hypothesis + +# Django +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Environnements virtuels +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Tests +htmlcov/ +.coverage +.pytest_cache/ + +# Documentation +README.md +docs/ + +# CI/CD +.github/ \ No newline at end of file diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 0000000000..daa3da1629 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,132 @@ +# Nom de la pipeline CI/CD +name: CI/CD Pipeline + +# Définition des événements qui déclenchent la pipeline +on: + # Se déclenche à chaque push sur la branche main + push: + branches: [ main ] + # Se déclenche à chaque pull request vers la branche main + pull_request: + branches: [ main ] + +# Variables d'environnement globales +env: + # Nom de l'image Docker (utilise le nom d'utilisateur DockerHub stocké dans les secrets) + DOCKER_IMAGE: ${{ secrets.DOCKER_USERNAME }}/oc-lettings-site + # Tag de l'image basé sur le SHA du commit + DOCKER_TAG: ${{ github.sha }} + +jobs: + # Job de test : vérifie la qualité du code et la couverture des tests + test: + runs-on: ubuntu-latest + steps: + # Récupération du code source + - uses: actions/checkout@v3 + + # Configuration de l'environnement Python + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + # Installation des dépendances nécessaires + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pytest pytest-cov flake8 + + # Vérification de la qualité du code avec Flake8 + - name: Run Flake8 + run: | + # Première vérification : erreurs critiques (échoue si erreurs trouvées) + # E9: Erreurs de syntaxe + # F63: Problèmes de comparaison + # F7: Problèmes de déclaration + # F82: Problèmes de référence non définie + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # Deuxième vérification : style du code (n'échoue pas) + # - Complexité maximale de 10 + # - Longueur de ligne maximale de 127 caractères + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + + # Exécution des tests avec mesure de la couverture + - name: Run tests with coverage + run: | + pytest --cov=. --cov-report=xml + + # Vérification que la couverture de tests est supérieure à 80% + - name: Check coverage threshold + run: | + coverage=$(python -c "import xml.etree.ElementTree as ET; tree = ET.parse('coverage.xml'); root = tree.getroot(); print(float(root.attrib['line-rate']) * 100)") + if (( $(echo "$coverage < 80" | bc -l) )); then + echo "Coverage is below 80%" + exit 1 + fi + + # Job de test Docker : vérifie que l'image Docker fonctionne + test-docker: + runs-on: ubuntu-latest + needs: test + steps: + - uses: actions/checkout@v3 + + # Test de build de l'image Docker + - name: Build Docker image + run: docker build -t oc-lettings-site . + + # Test que l'image peut démarrer + - name: Test Docker image startup + run: | + docker run -d --name test-container oc-lettings-site + sleep 10 + docker logs test-container + docker stop test-container + docker rm test-container + + # Job de build et push : crée et publie l'image Docker + build-and-push: + # S'exécute uniquement si les tests sont passés + needs: [test, test-docker] + runs-on: ubuntu-latest + # S'exécute uniquement sur les pushes vers main + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + steps: + - uses: actions/checkout@v3 + + # Authentification sur DockerHub + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + # Construction et publication de l'image Docker + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + context: . + push: true + # Tag l'image avec le SHA du commit et 'latest' + tags: ${{ env.DOCKER_IMAGE }}:${{ env.DOCKER_TAG }},${{ env.DOCKER_IMAGE }}:latest + # Cache pour optimiser les builds + cache-from: type=gha + cache-to: type=gha,mode=max + + # Job de déploiement : déploie l'application sur Render + deploy: + # S'exécute uniquement si le build est réussi + needs: build-and-push + runs-on: ubuntu-latest + # S'exécute uniquement sur les pushes vers main + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + steps: + # Déploiement sur Render + - name: Deploy to Render + uses: render-actions/deploy@v1 + with: + render-token: ${{ secrets.RENDER_TOKEN }} + service-id: ${{ secrets.RENDER_SERVICE_ID }} + environment: production diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000000..2d52d7cfe2 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,126 @@ +# Guide de Déploiement - OC Lettings Site + +## Prérequis + +- Docker et Docker Compose installés +- Compte DockerHub +- Compte Render (pour le déploiement) +- Variables d'environnement configurées + +## Configuration des Variables d'Environnement + +### GitHub Secrets (pour la CI/CD) + +Configurez ces secrets dans votre repository GitHub : + +- `DOCKER_USERNAME` : Votre nom d'utilisateur DockerHub +- `DOCKER_PASSWORD` : Votre token d'accès DockerHub +- `RENDER_TOKEN` : Votre token d'API Render +- `RENDER_SERVICE_ID` : L'ID de votre service Render + +### Variables d'Environnement pour la Production + +- `SECRET_KEY` : Clé secrète Django (générée automatiquement si non définie) +- `DEBUG` : `False` pour la production +- `ALLOWED_HOSTS` : Liste des domaines autorisés (séparés par des virgules) +- `DATABASE_URL` : URL de la base de données (optionnel, SQLite par défaut) +- `SENTRY_DSN` : URL Sentry pour le monitoring (optionnel) + +## Test Local avec Docker + +### 1. Build de l'image Docker + +```bash +docker build -t oc-lettings-site . +``` + +### 2. Test avec Docker Compose + +```bash +# Démarrer l'application +docker-compose up web + +# Exécuter les tests +docker-compose run test +``` + +### 3. Test direct de l'image + +```bash +# Démarrer le conteneur +docker run -p 8000:8000 oc-lettings-site + +# Accéder à l'application +open http://localhost:8000 +``` + +## Pipeline CI/CD + +La pipeline GitHub Actions s'exécute automatiquement sur chaque push vers `main` : + +1. **Tests** : Vérification de la qualité du code et couverture des tests (>80%) +2. **Test Docker** : Vérification que l'image Docker fonctionne +3. **Build & Push** : Construction et publication de l'image sur DockerHub +4. **Déploiement** : Déploiement automatique sur Render + +## Déploiement sur Render + +### Configuration du Service + +1. Créez un nouveau service Web sur Render +2. Connectez votre repository GitHub +3. Configurez les variables d'environnement : + - `DOCKER_IMAGE` : `votre-username/oc-lettings-site` + - `SECRET_KEY` : Clé secrète Django + - `DEBUG` : `False` + - `ALLOWED_HOSTS` : Votre domaine Render + +### Désactivation du Déploiement Automatique + +⚠️ **Important** : Désactivez le déploiement automatique sur Render car la CI/CD GitHub Actions gère le déploiement. + +## Structure des Fichiers + +``` +├── Dockerfile # Configuration Docker +├── docker-compose.yml # Configuration Docker Compose +├── start.sh # Script de démarrage +├── requirements.txt # Dépendances Python +├── .dockerignore # Fichiers exclus de Docker +├── oc_lettings_site/ +│ ├── settings.py # Configuration développement +│ └── settings_production.py # Configuration production +└── .github/workflows/ + └── ci-cd.yml # Pipeline CI/CD +``` + +## Sécurité + +- Utilisateur non-root dans le conteneur +- Variables d'environnement pour les secrets +- Configuration de sécurité Django pour la production +- Headers de sécurité configurés + +## Monitoring + +- Logs structurés avec Django +- Intégration Sentry (optionnelle) +- Métriques de couverture de tests + +## Troubleshooting + +### Problèmes Courants + +1. **Erreur de permissions** : Vérifiez que `start.sh` est exécutable +2. **Fichiers statiques manquants** : Vérifiez la configuration WhiteNoise +3. **Base de données** : Vérifiez les variables d'environnement DATABASE_URL + +### Logs + +```bash +# Voir les logs du conteneur +docker logs + +# Logs en temps réel +docker logs -f +``` \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..1ea58aa7f8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,44 @@ +FROM python:3.11-slim + +# Set the working directory +WORKDIR /app + +# Install required system dependencies +RUN apt-get update && apt-get install -y \ + gcc \ + && rm -rf /var/lib/apt/lists/* + +# Copy dependency files +COPY requirements.txt . + +# Install Python dependencies globally +RUN pip install --no-cache-dir -r requirements.txt + +# Create a non-root user for security +RUN groupadd -r django && useradd -r -g django django + +# Copy the source code +COPY . . + +# Make the startup script executable +RUN chmod +x start.sh + +# Create the directory for static files +RUN mkdir -p /app/staticfiles + +# Collect static files (as root before changing permissions) +RUN python manage.py collectstatic --noinput --settings=oc_lettings_site.settings_production + +# Change permissions for the django user +RUN chown -R django:django /app +# Switch to the django user +USER django +# Expose port 8000 +EXPOSE 8000 + +# Default environment variables +ENV PYTHONUNBUFFERED=1 +ENV DJANGO_SETTINGS_MODULE=oc_lettings_site.settings_production + +# Default command to start the application +CMD ["./start.sh"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..406373a727 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3.8' + +services: + web: + build: . + ports: + - "8000:8000" + environment: + - DEBUG=False + - DJANGO_SETTINGS_MODULE=oc_lettings_site.settings_production + - ALLOWED_HOSTS=localhost,127.0.0.1 + volumes: + - ./staticfiles:/app/staticfiles + - ./static:/app/static + + command: gunicorn --bind 0.0.0.0:8000 --workers 3 oc_lettings_site.wsgi:application + + # Service pour les tests + test: + build: . + environment: + - DEBUG=True + - DJANGO_SETTINGS_MODULE=oc_lettings_site.settings + command: python -m pytest --cov=. --cov-report=term-missing + volumes: + - .:/app \ No newline at end of file diff --git a/oc_lettings_site/settings_production.py b/oc_lettings_site/settings_production.py new file mode 100644 index 0000000000..66bba92e28 --- /dev/null +++ b/oc_lettings_site/settings_production.py @@ -0,0 +1,128 @@ +import os +from pathlib import Path +from .settings import * + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = Path(__file__).resolve().parent.parent + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.environ.get('SECRET_KEY', 'fp$9^593hsriajg$_%=5trot9g!1qa@ew(o-1#@=&4%=hp46(s') + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = os.environ.get('DEBUG', 'False').lower() == 'true' + +# Allowed hosts for production +ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',') + +# Add WhiteNoise to serve static files +INSTALLED_APPS = INSTALLED_APPS + ['whitenoise.runserver_nostatic'] + +# Middleware configuration for WhiteNoise +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'whitenoise.middleware.WhiteNoiseMiddleware', # Add WhiteNoise + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +# Database configuration for production +# If DATABASE_URL is set, use PostgreSQL, otherwise use SQLite +DATABASE_URL = os.environ.get('DATABASE_URL') +if DATABASE_URL: + try: + import dj_database_url + DATABASES = { + 'default': dj_database_url.parse(DATABASE_URL) + } + except ImportError: + # Fallback to SQLite if dj-database-url is not installed + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'oc-lettings-site.sqlite3'), + } + } +else: + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'oc-lettings-site.sqlite3'), + } + } + +# Static files configuration for production +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') +STATIC_URL = '/static/' +STATICFILES_DIRS = [BASE_DIR / "static"] + +# Security configuration for production +SECURE_BROWSER_XSS_FILTER = True +SECURE_CONTENT_TYPE_NOSNIFF = True +X_FRAME_OPTIONS = 'DENY' +SECURE_HSTS_SECONDS = 31536000 +SECURE_HSTS_INCLUDE_SUBDOMAINS = True +SECURE_HSTS_PRELOAD = True + +# CSRF configuration +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True + +# Logging configuration for production +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'verbose': { + 'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}', + 'style': '{', + }, + }, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + 'formatter': 'verbose', + }, + }, + 'loggers': { + 'django': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': True, + }, + 'lettings': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': True, + }, + 'profiles': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': True, + }, + }, +} + +# Sentry configuration for production +SENTRY_DSN = os.environ.get('SENTRY_DSN') +if SENTRY_DSN: + import sentry_sdk + from sentry_sdk.integrations.django import DjangoIntegration + from sentry_sdk.integrations.logging import LoggingIntegration + import logging + + sentry_sdk.init( + dsn=SENTRY_DSN, + integrations=[ + DjangoIntegration(), + LoggingIntegration( + level=logging.INFO, + event_level=logging.ERROR + ), + ], + traces_sample_rate=1.0, + send_default_pii=True, + ) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 13e02d0e33..161340ea2f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,7 @@ django==4.2.11 flake8==3.7.0 -pytest-django==3.9.0 \ No newline at end of file +pytest-django==3.9.0 +dj-database-url==2.1.0 +gunicorn==21.2.0 +whitenoise==6.6.0 +sentry-sdk==1.40.0 \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100644 index 0000000000..18131e8f09 --- /dev/null +++ b/start.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# Startup script for the Django application in production + +echo "Starting Django application..." + +# Wait for the database to be ready (if needed) +# sleep 5 + +# Apply database migrations +echo "Applying database migrations..." +python manage.py migrate --noinput + +# Collect static files +echo "Collecting static files..." +python manage.py collectstatic --noinput + +# Start Gunicorn +echo "Starting Gunicorn server..." +exec gunicorn --bind 0.0.0.0:8000 --workers 3 --timeout 120 oc_lettings_site.wsgi:application \ No newline at end of file diff --git a/static/assets/img/backgrounds/bg-angles.svg b/static/assets/img/backgrounds/bg-angles.svg new file mode 100644 index 0000000000..e694ab51de --- /dev/null +++ b/static/assets/img/backgrounds/bg-angles.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/assets/img/backgrounds/bg-waves.svg b/static/assets/img/backgrounds/bg-waves.svg new file mode 100644 index 0000000000..83c995c6e4 --- /dev/null +++ b/static/assets/img/backgrounds/bg-waves.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/static/assets/img/device-mockups/iPhoneX/landscape.png b/static/assets/img/device-mockups/iPhoneX/landscape.png new file mode 100644 index 0000000000..0519ecba6e --- /dev/null +++ b/static/assets/img/device-mockups/iPhoneX/landscape.png @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/img/device-mockups/iPhoneX/landscape.svg b/static/assets/img/device-mockups/iPhoneX/landscape.svg new file mode 100644 index 0000000000..a80fb6b5f9 --- /dev/null +++ b/static/assets/img/device-mockups/iPhoneX/landscape.svg @@ -0,0 +1,7 @@ + + + + + + iPhone X Landscape + \ No newline at end of file diff --git a/static/assets/img/device-mockups/iPhoneX/landscape_black.svg b/static/assets/img/device-mockups/iPhoneX/landscape_black.svg new file mode 100644 index 0000000000..d278246f0b --- /dev/null +++ b/static/assets/img/device-mockups/iPhoneX/landscape_black.svg @@ -0,0 +1,7 @@ + + + + + + iPhone X Landscape Black + \ No newline at end of file diff --git a/static/assets/img/device-mockups/iPhoneX/portrait.png b/static/assets/img/device-mockups/iPhoneX/portrait.png new file mode 100644 index 0000000000..0519ecba6e --- /dev/null +++ b/static/assets/img/device-mockups/iPhoneX/portrait.png @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/img/device-mockups/iPhoneX/portrait.svg b/static/assets/img/device-mockups/iPhoneX/portrait.svg new file mode 100644 index 0000000000..f0f63a9572 --- /dev/null +++ b/static/assets/img/device-mockups/iPhoneX/portrait.svg @@ -0,0 +1,7 @@ + + + + + + iPhone X Portrait + \ No newline at end of file diff --git a/static/assets/img/device-mockups/iPhoneX/portrait_black.svg b/static/assets/img/device-mockups/iPhoneX/portrait_black.svg new file mode 100644 index 0000000000..4407420457 --- /dev/null +++ b/static/assets/img/device-mockups/iPhoneX/portrait_black.svg @@ -0,0 +1,7 @@ + + + + + + iPhone X Portrait Black + \ No newline at end of file diff --git a/static/css/styles.css b/static/css/styles.css index 53c1b18d5f..258aa4e201 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -20057,7 +20057,7 @@ section { .device[data-device=iPhoneX][data-orientation=portrait][data-color=black] { padding-bottom: 198.89807163%; - background-image: url("../assets/img/device-mockups/iPhoneX/portrait.png"); + background-image: url("../assets/img/device-mockups/iPhoneX/portrait.svg"); z-index: initial; } @@ -20072,7 +20072,7 @@ section { .device[data-device=iPhoneX][data-orientation=landscape][data-color=black] { padding-bottom: 50.27700831%; - background-image: url("../assets/img/device-mockups/iPhoneX/landscape.png"); + background-image: url("../assets/img/device-mockups/iPhoneX/landscape.svg"); z-index: initial; } @@ -20098,7 +20098,7 @@ section { .device[data-device=iPhoneX][data-orientation=portrait][data-color=black]::after { content: ""; - background-image: url("../assets/img/device-mockups/iPhoneX/portrait_black.png"); + background-image: url("../assets/img/device-mockups/iPhoneX/portrait_black.svg"); } .device[data-device=iPhoneX][data-orientation=portrait][data-color=black] .button { @@ -20122,7 +20122,7 @@ section { .device[data-device=iPhoneX][data-orientation=landscape][data-color=black]::after { content: ""; - background-image: url("../assets/img/device-mockups/iPhoneX/landscape_black.png"); + background-image: url("../assets/img/device-mockups/iPhoneX/landscape_black.svg"); } .device[data-device=iPhoneX][data-orientation=landscape][data-color=black] .button { diff --git a/staticfiles/admin/css/autocomplete.4a81fc4242d0.css b/staticfiles/admin/css/autocomplete.4a81fc4242d0.css new file mode 100644 index 0000000000..69c94e7347 --- /dev/null +++ b/staticfiles/admin/css/autocomplete.4a81fc4242d0.css @@ -0,0 +1,275 @@ +select.admin-autocomplete { + width: 20em; +} + +.select2-container--admin-autocomplete.select2-container { + min-height: 30px; +} + +.select2-container--admin-autocomplete .select2-selection--single, +.select2-container--admin-autocomplete .select2-selection--multiple { + min-height: 30px; + padding: 0; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection, +.select2-container--admin-autocomplete.select2-container--open .select2-selection { + border-color: var(--body-quiet-color); + min-height: 30px; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection.select2-selection--single, +.select2-container--admin-autocomplete.select2-container--open .select2-selection.select2-selection--single { + padding: 0; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection.select2-selection--multiple, +.select2-container--admin-autocomplete.select2-container--open .select2-selection.select2-selection--multiple { + padding: 0; +} + +.select2-container--admin-autocomplete .select2-selection--single { + background-color: var(--body-bg); + border: 1px solid var(--border-color); + border-radius: 4px; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__rendered { + color: var(--body-fg); + line-height: 30px; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__placeholder { + color: var(--body-quiet-color); +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow { + height: 26px; + position: absolute; + top: 1px; + right: 1px; + width: 20px; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow b { + border-color: #888 transparent transparent transparent; + border-style: solid; + border-width: 5px 4px 0 4px; + height: 0; + left: 50%; + margin-left: -4px; + margin-top: -2px; + position: absolute; + top: 50%; + width: 0; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--single .select2-selection__clear { + float: left; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--single .select2-selection__arrow { + left: 1px; + right: auto; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--single { + background-color: var(--darkened-bg); + cursor: default; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--single .select2-selection__clear { + display: none; +} + +.select2-container--admin-autocomplete.select2-container--open .select2-selection--single .select2-selection__arrow b { + border-color: transparent transparent #888 transparent; + border-width: 0 4px 5px 4px; +} + +.select2-container--admin-autocomplete .select2-selection--multiple { + background-color: var(--body-bg); + border: 1px solid var(--border-color); + border-radius: 4px; + cursor: text; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__rendered { + box-sizing: border-box; + list-style: none; + margin: 0; + padding: 0 10px 5px 5px; + width: 100%; + display: flex; + flex-wrap: wrap; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__rendered li { + list-style: none; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__placeholder { + color: var(--body-quiet-color); + margin-top: 5px; + float: left; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; + margin: 5px; + position: absolute; + right: 0; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice { + background-color: var(--darkened-bg); + border: 1px solid var(--border-color); + border-radius: 4px; + cursor: default; + float: left; + margin-right: 5px; + margin-top: 5px; + padding: 0 5px; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove { + color: var(--body-quiet-color); + cursor: pointer; + display: inline-block; + font-weight: bold; + margin-right: 2px; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove:hover { + color: var(--body-fg); +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-search--inline { + float: right; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice { + margin-left: 5px; + margin-right: auto; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove { + margin-left: 2px; + margin-right: auto; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection--multiple { + border: solid var(--body-quiet-color) 1px; + outline: 0; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--multiple { + background-color: var(--darkened-bg); + cursor: default; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection__choice__remove { + display: none; +} + +.select2-container--admin-autocomplete.select2-container--open.select2-container--above .select2-selection--single, .select2-container--admin-autocomplete.select2-container--open.select2-container--above .select2-selection--multiple { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.select2-container--admin-autocomplete.select2-container--open.select2-container--below .select2-selection--single, .select2-container--admin-autocomplete.select2-container--open.select2-container--below .select2-selection--multiple { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.select2-container--admin-autocomplete .select2-search--dropdown { + background: var(--darkened-bg); +} + +.select2-container--admin-autocomplete .select2-search--dropdown .select2-search__field { + background: var(--body-bg); + color: var(--body-fg); + border: 1px solid var(--border-color); + border-radius: 4px; +} + +.select2-container--admin-autocomplete .select2-search--inline .select2-search__field { + background: transparent; + color: var(--body-fg); + border: none; + outline: 0; + box-shadow: none; + -webkit-appearance: textfield; +} + +.select2-container--admin-autocomplete .select2-results > .select2-results__options { + max-height: 200px; + overflow-y: auto; + color: var(--body-fg); + background: var(--body-bg); +} + +.select2-container--admin-autocomplete .select2-results__option[role=group] { + padding: 0; +} + +.select2-container--admin-autocomplete .select2-results__option[aria-disabled=true] { + color: var(--body-quiet-color); +} + +.select2-container--admin-autocomplete .select2-results__option[aria-selected=true] { + background-color: var(--selected-bg); + color: var(--body-fg); +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option { + padding-left: 1em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__group { + padding-left: 0; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option { + margin-left: -1em; + padding-left: 2em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -2em; + padding-left: 3em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -3em; + padding-left: 4em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -4em; + padding-left: 5em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -5em; + padding-left: 6em; +} + +.select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected] { + background-color: var(--primary); + color: var(--primary-fg); +} + +.select2-container--admin-autocomplete .select2-results__group { + cursor: default; + display: block; + padding: 6px; +} diff --git a/staticfiles/admin/css/autocomplete.4a81fc4242d0.css.gz b/staticfiles/admin/css/autocomplete.4a81fc4242d0.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..7cd12df9483ef372338842a86eb0aedf148d04aa GIT binary patch literal 1147 zcmV->1cdt^iwFP!00002|J_;ZZsRBv{@-s>)U8MMhPG4T({S@nSql zcD3)m*kIxdPU7p#Y=5K)V9s}L-#OrvFcQkI2=8eOQ6_oF_X#7CfPe0Q`a4i8BOk0h zvVXn%_wMd%T0F3VA&(`ZF%b~9A8xNQ+vN)*LU)n$!K0TPd+Z79GX0cDY7Vo#os*s-NiDBuFCRUv0w_}~W;e?S;; ze1d;vlt?}P=j&MS^wD*^BYRk(TbQxW?5@2ObPFlmi19%xgR7PdQ24PEJd3d-+Jc=4 zG98aTcu0;Q<&0vx>Kv!FrBEPDv(yJqQ}KmkYO@g}R>BB2%Ct4umKrc6at0Q2q6!&7 zC3%LKNOMdHr?DhLgV{2U6bzB0F(XPoJQ#QZXLv?<2}2=?lnl%8*LY?&C`br?Fd$0j zte!1_^OWZ6e1HNKb(ti3T=Jv{Mg2?Y$Lw!g{bu#CMjkl%`t!@n3y=cEX@XRQ%C7IV zgh}Oz5npFlZNliYR;j0w33xiCsuuH1h?A}QvG%^0!hpn1DXB-HeaH+KHiWC2Ol`L` zQ2H>?cTC0GCn4FV_c3W?GA37M8R6B))Fx~OTrOy2^}#en0aNrfn5HojA0#IDOw}df zV6sK3f-HdWn(x#eigHdqhVO}W&;Bkt8iP#@m9;vRB_HaTITM#)EQ>HX z!h=AH;PTI9lxMW$l$MS&itk_Xo0Y;^b{G-&hdfOWRgIhVwOS`^HJwwhh|{n?t52Be zwlK8ZS#i3t#oE<1tlI}{JvO`9@4J+z11|tvZP_l+pKEi-ps&Z&F2K*8o5^kxtauI zpZl41!(<4uPL2&qIQQ^8lex>sUm#s(`~GPOUd__>}6IAH(8syvET{jhq#qu?&O+6 zQe$Sb*;2xACxH5q?ZOr1&$wi*)xVn+YaNVl(CU1Ut8%YB3PwoTwz^6+VZjHL5G9F1 zgW{0rLu!F(khX%PDsEHotu?gS@Fb7y)E2j+y(?aM_Jva3hNL4I ziT1nTjJ)OhC-2j|Bxnjif+AZz-lWLL`+PUXPT_j8A-t=OmW!`u+jw-{6E#Pe{^+6C zi`W4|+Y?1tIKg;JL#Y|2ek)xVrVVkmyuF5?U%Amg{(9(psrBeq>*+UAtCzk{ZhhDP z2Yq`PV(m7>^E8HlFj5tj .select2-results__options { + max-height: 200px; + overflow-y: auto; + color: var(--body-fg); + background: var(--body-bg); +} + +.select2-container--admin-autocomplete .select2-results__option[role=group] { + padding: 0; +} + +.select2-container--admin-autocomplete .select2-results__option[aria-disabled=true] { + color: var(--body-quiet-color); +} + +.select2-container--admin-autocomplete .select2-results__option[aria-selected=true] { + background-color: var(--selected-bg); + color: var(--body-fg); +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option { + padding-left: 1em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__group { + padding-left: 0; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option { + margin-left: -1em; + padding-left: 2em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -2em; + padding-left: 3em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -3em; + padding-left: 4em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -4em; + padding-left: 5em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -5em; + padding-left: 6em; +} + +.select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected] { + background-color: var(--primary); + color: var(--primary-fg); +} + +.select2-container--admin-autocomplete .select2-results__group { + cursor: default; + display: block; + padding: 6px; +} diff --git a/staticfiles/admin/css/autocomplete.css.gz b/staticfiles/admin/css/autocomplete.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..7cd12df9483ef372338842a86eb0aedf148d04aa GIT binary patch literal 1147 zcmV->1cdt^iwFP!00002|J_;ZZsRBv{@-s>)U8MMhPG4T({S@nSql zcD3)m*kIxdPU7p#Y=5K)V9s}L-#OrvFcQkI2=8eOQ6_oF_X#7CfPe0Q`a4i8BOk0h zvVXn%_wMd%T0F3VA&(`ZF%b~9A8xNQ+vN)*LU)n$!K0TPd+Z79GX0cDY7Vo#os*s-NiDBuFCRUv0w_}~W;e?S;; ze1d;vlt?}P=j&MS^wD*^BYRk(TbQxW?5@2ObPFlmi19%xgR7PdQ24PEJd3d-+Jc=4 zG98aTcu0;Q<&0vx>Kv!FrBEPDv(yJqQ}KmkYO@g}R>BB2%Ct4umKrc6at0Q2q6!&7 zC3%LKNOMdHr?DhLgV{2U6bzB0F(XPoJQ#QZXLv?<2}2=?lnl%8*LY?&C`br?Fd$0j zte!1_^OWZ6e1HNKb(ti3T=Jv{Mg2?Y$Lw!g{bu#CMjkl%`t!@n3y=cEX@XRQ%C7IV zgh}Oz5npFlZNliYR;j0w33xiCsuuH1h?A}QvG%^0!hpn1DXB-HeaH+KHiWC2Ol`L` zQ2H>?cTC0GCn4FV_c3W?GA37M8R6B))Fx~OTrOy2^}#en0aNrfn5HojA0#IDOw}df zV6sK3f-HdWn(x#eigHdqhVO}W&;Bkt8iP#@m9;vRB_HaTITM#)EQ>HX z!h=AH;PTI9lxMW$l$MS&itk_Xo0Y;^b{G-&hdfOWRgIhVwOS`^HJwwhh|{n?t52Be zwlK8ZS#i3t#oE<1tlI}{JvO`9@4J+z11|tvZP_l+pKEi-ps&Z&F2K*8o5^kxtauI zpZl41!(<4uPL2&qIQQ^8lex>sUm#s(`~GPOUd__>}6IAH(8syvET{jhq#qu?&O+6 zQe$Sb*;2xACxH5q?ZOr1&$wi*)xVn+YaNVl(CU1Ut8%YB3PwoTwz^6+VZjHL5G9F1 zgW{0rLu!F(khX%PDsEHotu?gS@Fb7y)E2j+y(?aM_Jva3hNL4I ziT1nTjJ)OhC-2j|Bxnjif+AZz-lWLL`+PUXPT_j8A-t=OmW!`u+jw-{6E#Pe{^+6C zi`W4|+Y?1tIKg;JL#Y|2ek)xVrVVkmyuF5?U%Amg{(9(psrBeq>*+UAtCzk{ZhhDP z2Yq`PV(m7>^E8HlFj5tj li { + list-style-type: square; + padding: 1px 0; +} + +li ul { + margin-bottom: 0; +} + +li, dt, dd { + font-size: 0.8125rem; + line-height: 1.25rem; +} + +dt { + font-weight: bold; + margin-top: 4px; +} + +dd { + margin-left: 0; +} + +form { + margin: 0; + padding: 0; +} + +fieldset { + margin: 0; + min-width: 0; + padding: 0; + border: none; + border-top: 1px solid var(--hairline-color); +} + +blockquote { + font-size: 0.6875rem; + color: #777; + margin-left: 2px; + padding-left: 10px; + border-left: 5px solid #ddd; +} + +code, pre { + font-family: var(--font-family-monospace); + color: var(--body-quiet-color); + font-size: 0.75rem; + overflow-x: auto; +} + +pre.literal-block { + margin: 10px; + background: var(--darkened-bg); + padding: 6px 8px; +} + +code strong { + color: #930; +} + +hr { + clear: both; + color: var(--hairline-color); + background-color: var(--hairline-color); + height: 1px; + border: none; + margin: 0; + padding: 0; + line-height: 1px; +} + +/* TEXT STYLES & MODIFIERS */ + +.small { + font-size: 0.6875rem; +} + +.mini { + font-size: 0.625rem; +} + +.help, p.help, form p.help, div.help, form div.help, div.help li { + font-size: 0.6875rem; + color: var(--body-quiet-color); +} + +div.help ul { + margin-bottom: 0; +} + +.help-tooltip { + cursor: help; +} + +p img, h1 img, h2 img, h3 img, h4 img, td img { + vertical-align: middle; +} + +.quiet, a.quiet:link, a.quiet:visited { + color: var(--body-quiet-color); + font-weight: normal; +} + +.clear { + clear: both; +} + +.nowrap { + white-space: nowrap; +} + +.hidden { + display: none !important; +} + +/* TABLES */ + +table { + border-collapse: collapse; + border-color: var(--border-color); +} + +td, th { + font-size: 0.8125rem; + line-height: 1rem; + border-bottom: 1px solid var(--hairline-color); + vertical-align: top; + padding: 8px; +} + +th { + font-weight: 600; + text-align: left; +} + +thead th, +tfoot td { + color: var(--body-quiet-color); + padding: 5px 10px; + font-size: 0.6875rem; + background: var(--body-bg); + border: none; + border-top: 1px solid var(--hairline-color); + border-bottom: 1px solid var(--hairline-color); +} + +tfoot td { + border-bottom: none; + border-top: 1px solid var(--hairline-color); +} + +thead th.required { + color: var(--body-loud-color); +} + +tr.alt { + background: var(--darkened-bg); +} + +tr:nth-child(odd), .row-form-errors { + background: var(--body-bg); +} + +tr:nth-child(even), +tr:nth-child(even) .errorlist, +tr:nth-child(odd) + .row-form-errors, +tr:nth-child(odd) + .row-form-errors .errorlist { + background: var(--darkened-bg); +} + +/* SORTABLE TABLES */ + +thead th { + padding: 5px 10px; + line-height: normal; + text-transform: uppercase; + background: var(--darkened-bg); +} + +thead th a:link, thead th a:visited { + color: var(--body-quiet-color); +} + +thead th.sorted { + background: var(--selected-bg); +} + +thead th.sorted .text { + padding-right: 42px; +} + +table thead th .text span { + padding: 8px 10px; + display: block; +} + +table thead th .text a { + display: block; + cursor: pointer; + padding: 8px 10px; +} + +table thead th .text a:focus, table thead th .text a:hover { + background: var(--selected-bg); +} + +thead th.sorted a.sortremove { + visibility: hidden; +} + +table thead th.sorted:hover a.sortremove { + visibility: visible; +} + +table thead th.sorted .sortoptions { + display: block; + padding: 9px 5px 0 5px; + float: right; + text-align: right; +} + +table thead th.sorted .sortpriority { + font-size: .8em; + min-width: 12px; + text-align: center; + vertical-align: 3px; + margin-left: 2px; + margin-right: 2px; +} + +table thead th.sorted .sortoptions a { + position: relative; + width: 14px; + height: 14px; + display: inline-block; + background: url("../img/sorting-icons.3a097b59f104.svg") 0 0 no-repeat; + background-size: 14px auto; +} + +table thead th.sorted .sortoptions a.sortremove { + background-position: 0 0; +} + +table thead th.sorted .sortoptions a.sortremove:after { + content: '\\'; + position: absolute; + top: -6px; + left: 3px; + font-weight: 200; + font-size: 1.125rem; + color: var(--body-quiet-color); +} + +table thead th.sorted .sortoptions a.sortremove:focus:after, +table thead th.sorted .sortoptions a.sortremove:hover:after { + color: var(--link-fg); +} + +table thead th.sorted .sortoptions a.sortremove:focus, +table thead th.sorted .sortoptions a.sortremove:hover { + background-position: 0 -14px; +} + +table thead th.sorted .sortoptions a.ascending { + background-position: 0 -28px; +} + +table thead th.sorted .sortoptions a.ascending:focus, +table thead th.sorted .sortoptions a.ascending:hover { + background-position: 0 -42px; +} + +table thead th.sorted .sortoptions a.descending { + top: 1px; + background-position: 0 -56px; +} + +table thead th.sorted .sortoptions a.descending:focus, +table thead th.sorted .sortoptions a.descending:hover { + background-position: 0 -70px; +} + +/* FORM DEFAULTS */ + +input, textarea, select, .form-row p, form .button { + margin: 2px 0; + padding: 2px 3px; + vertical-align: middle; + font-family: var(--font-family-primary); + font-weight: normal; + font-size: 0.8125rem; +} +.form-row div.help { + padding: 2px 3px; +} + +textarea { + vertical-align: top; +} + +input[type=text], input[type=password], input[type=email], input[type=url], +input[type=number], input[type=tel], textarea, select, .vTextField { + border: 1px solid var(--border-color); + border-radius: 4px; + padding: 5px 6px; + margin-top: 0; + color: var(--body-fg); + background-color: var(--body-bg); +} + +input[type=text]:focus, input[type=password]:focus, input[type=email]:focus, +input[type=url]:focus, input[type=number]:focus, input[type=tel]:focus, +textarea:focus, select:focus, .vTextField:focus { + border-color: var(--body-quiet-color); +} + +select { + height: 1.875rem; +} + +select[multiple] { + /* Allow HTML size attribute to override the height in the rule above. */ + height: auto; + min-height: 150px; +} + +/* FORM BUTTONS */ + +.button, input[type=submit], input[type=button], .submit-row input, a.button { + background: var(--button-bg); + padding: 10px 15px; + border: none; + border-radius: 4px; + color: var(--button-fg); + cursor: pointer; + transition: background 0.15s; +} + +a.button { + padding: 4px 5px; +} + +.button:active, input[type=submit]:active, input[type=button]:active, +.button:focus, input[type=submit]:focus, input[type=button]:focus, +.button:hover, input[type=submit]:hover, input[type=button]:hover { + background: var(--button-hover-bg); +} + +.button[disabled], input[type=submit][disabled], input[type=button][disabled] { + opacity: 0.4; +} + +.button.default, input[type=submit].default, .submit-row input.default { + border: none; + font-weight: 400; + background: var(--default-button-bg); +} + +.button.default:active, input[type=submit].default:active, +.button.default:focus, input[type=submit].default:focus, +.button.default:hover, input[type=submit].default:hover { + background: var(--default-button-hover-bg); +} + +.button[disabled].default, +input[type=submit][disabled].default, +input[type=button][disabled].default { + opacity: 0.4; +} + + +/* MODULES */ + +.module { + border: none; + margin-bottom: 30px; + background: var(--body-bg); +} + +.module p, .module ul, .module h3, .module h4, .module dl, .module pre { + padding-left: 10px; + padding-right: 10px; +} + +.module blockquote { + margin-left: 12px; +} + +.module ul, .module ol { + margin-left: 1.5em; +} + +.module h3 { + margin-top: .6em; +} + +.module h2, .module caption, .inline-group h2 { + margin: 0; + padding: 8px; + font-weight: 400; + font-size: 0.8125rem; + text-align: left; + background: var(--primary); + color: var(--header-link-color); +} + +.module caption, +.inline-group h2 { + font-size: 0.75rem; + letter-spacing: 0.5px; + text-transform: uppercase; +} + +.module table { + border-collapse: collapse; +} + +/* MESSAGES & ERRORS */ + +ul.messagelist { + padding: 0; + margin: 0; +} + +ul.messagelist li { + display: block; + font-weight: 400; + font-size: 0.8125rem; + padding: 10px 10px 10px 65px; + margin: 0 0 10px 0; + background: var(--message-success-bg) url("../img/icon-yes.d2f9f035226a.svg") 40px 12px no-repeat; + background-size: 16px auto; + color: var(--body-fg); + word-break: break-word; +} + +ul.messagelist li.warning { + background: var(--message-warning-bg) url("../img/icon-alert.034cc7d8a67f.svg") 40px 14px no-repeat; + background-size: 14px auto; +} + +ul.messagelist li.error { + background: var(--message-error-bg) url("../img/icon-no.439e821418cd.svg") 40px 12px no-repeat; + background-size: 16px auto; +} + +.errornote { + font-size: 0.875rem; + font-weight: 700; + display: block; + padding: 10px 12px; + margin: 0 0 10px 0; + color: var(--error-fg); + border: 1px solid var(--error-fg); + border-radius: 4px; + background-color: var(--body-bg); + background-position: 5px 12px; + overflow-wrap: break-word; +} + +ul.errorlist { + margin: 0 0 4px; + padding: 0; + color: var(--error-fg); + background: var(--body-bg); +} + +ul.errorlist li { + font-size: 0.8125rem; + display: block; + margin-bottom: 4px; + overflow-wrap: break-word; +} + +ul.errorlist li:first-child { + margin-top: 0; +} + +ul.errorlist li a { + color: inherit; + text-decoration: underline; +} + +td ul.errorlist { + margin: 0; + padding: 0; +} + +td ul.errorlist li { + margin: 0; +} + +.form-row.errors { + margin: 0; + border: none; + border-bottom: 1px solid var(--hairline-color); + background: none; +} + +.form-row.errors ul.errorlist li { + padding-left: 0; +} + +.errors input, .errors select, .errors textarea, +td ul.errorlist + input, td ul.errorlist + select, td ul.errorlist + textarea { + border: 1px solid var(--error-fg); +} + +.description { + font-size: 0.75rem; + padding: 5px 0 0 12px; +} + +/* BREADCRUMBS */ + +div.breadcrumbs { + background: var(--breadcrumbs-bg); + padding: 10px 40px; + border: none; + color: var(--breadcrumbs-fg); + text-align: left; +} + +div.breadcrumbs a { + color: var(--breadcrumbs-link-fg); +} + +div.breadcrumbs a:focus, div.breadcrumbs a:hover { + color: var(--breadcrumbs-fg); +} + +/* ACTION ICONS */ + +.viewlink, .inlineviewlink { + padding-left: 16px; + background: url("../img/icon-viewlink.41eb31f7826e.svg") 0 1px no-repeat; +} + +.addlink { + padding-left: 16px; + background: url("../img/icon-addlink.d519b3bab011.svg") 0 1px no-repeat; +} + +.changelink, .inlinechangelink { + padding-left: 16px; + background: url("../img/icon-changelink.18d2fd706348.svg") 0 1px no-repeat; +} + +.deletelink { + padding-left: 16px; + background: url("../img/icon-deletelink.564ef9dc3854.svg") 0 1px no-repeat; +} + +a.deletelink:link, a.deletelink:visited { + color: #CC3434; /* XXX Probably unused? */ +} + +a.deletelink:focus, a.deletelink:hover { + color: #993333; /* XXX Probably unused? */ + text-decoration: none; +} + +/* OBJECT TOOLS */ + +.object-tools { + font-size: 0.625rem; + font-weight: bold; + padding-left: 0; + float: right; + position: relative; + margin-top: -48px; +} + +.object-tools li { + display: block; + float: left; + margin-left: 5px; + height: 1rem; +} + +.object-tools a { + border-radius: 15px; +} + +.object-tools a:link, .object-tools a:visited { + display: block; + float: left; + padding: 3px 12px; + background: var(--object-tools-bg); + color: var(--object-tools-fg); + font-weight: 400; + font-size: 0.6875rem; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.object-tools a:focus, .object-tools a:hover { + background-color: var(--object-tools-hover-bg); +} + +.object-tools a:focus{ + text-decoration: none; +} + +.object-tools a.viewsitelink, .object-tools a.addlink { + background-repeat: no-repeat; + background-position: right 7px center; + padding-right: 26px; +} + +.object-tools a.viewsitelink { + background-image: url("../img/tooltag-arrowright.bbfb788a849e.svg"); +} + +.object-tools a.addlink { + background-image: url("../img/tooltag-add.e59d620a9742.svg"); +} + +/* OBJECT HISTORY */ + +#change-history table { + width: 100%; +} + +#change-history table tbody th { + width: 16em; +} + +#change-history .paginator { + color: var(--body-quiet-color); + border-bottom: 1px solid var(--hairline-color); + background: var(--body-bg); + overflow: hidden; +} + +/* PAGE STRUCTURE */ + +#container { + position: relative; + width: 100%; + min-width: 980px; + padding: 0; + display: flex; + flex-direction: column; + height: 100%; +} + +#container > div { + flex-shrink: 0; +} + +#container > .main { + display: flex; + flex: 1 0 auto; +} + +.main > .content { + flex: 1 0; + max-width: 100%; +} + +.skip-to-content-link { + position: absolute; + top: -999px; + margin: 5px; + padding: 5px; + background: var(--body-bg); + z-index: 1; +} + +.skip-to-content-link:focus { + left: 0px; + top: 0px; +} + +#content { + padding: 20px 40px; +} + +.dashboard #content { + width: 600px; +} + +#content-main { + float: left; + width: 100%; +} + +#content-related { + float: right; + width: 260px; + position: relative; + margin-right: -300px; +} + +#footer { + clear: both; + padding: 10px; +} + +/* COLUMN TYPES */ + +.colMS { + margin-right: 300px; +} + +.colSM { + margin-left: 300px; +} + +.colSM #content-related { + float: left; + margin-right: 0; + margin-left: -300px; +} + +.colSM #content-main { + float: right; +} + +.popup .colM { + width: auto; +} + +/* HEADER */ + +#header { + width: auto; + height: auto; + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 40px; + background: var(--header-bg); + color: var(--header-color); + overflow: hidden; +} + +#header a:link, #header a:visited, #logout-form button { + color: var(--header-link-color); +} + +#header a:focus , #header a:hover { + text-decoration: underline; +} + +#branding { + display: flex; +} + +#branding h1 { + padding: 0; + margin: 0; + margin-inline-end: 20px; + font-weight: 300; + font-size: 1.5rem; + color: var(--header-branding-color); +} + +#branding h1 a:link, #branding h1 a:visited { + color: var(--accent); +} + +#branding h2 { + padding: 0 10px; + font-size: 0.875rem; + margin: -8px 0 8px 0; + font-weight: normal; + color: var(--header-color); +} + +#branding a:hover { + text-decoration: none; +} + +#logout-form { + display: inline; +} + +#logout-form button { + background: none; + border: 0; + cursor: pointer; + font-family: var(--font-family-primary); +} + +#user-tools { + float: right; + margin: 0 0 0 20px; + text-align: right; +} + +#user-tools, #logout-form button{ + padding: 0; + font-weight: 300; + font-size: 0.6875rem; + letter-spacing: 0.5px; + text-transform: uppercase; +} + +#user-tools a, #logout-form button { + border-bottom: 1px solid rgba(255, 255, 255, 0.25); +} + +#user-tools a:focus, #user-tools a:hover, +#logout-form button:active, #logout-form button:hover { + text-decoration: none; + border-bottom: 0; +} + +#logout-form button:active, #logout-form button:hover { + margin-bottom: 1px; +} + +/* SIDEBAR */ + +#content-related { + background: var(--darkened-bg); +} + +#content-related .module { + background: none; +} + +#content-related h3 { + color: var(--body-quiet-color); + padding: 0 16px; + margin: 0 0 16px; +} + +#content-related h4 { + font-size: 0.8125rem; +} + +#content-related p { + padding-left: 16px; + padding-right: 16px; +} + +#content-related .actionlist { + padding: 0; + margin: 16px; +} + +#content-related .actionlist li { + line-height: 1.2; + margin-bottom: 10px; + padding-left: 18px; +} + +#content-related .module h2 { + background: none; + padding: 16px; + margin-bottom: 16px; + border-bottom: 1px solid var(--hairline-color); + font-size: 1.125rem; + color: var(--body-fg); +} + +.delete-confirmation form input[type="submit"] { + background: var(--delete-button-bg); + border-radius: 4px; + padding: 10px 15px; + color: var(--button-fg); +} + +.delete-confirmation form input[type="submit"]:active, +.delete-confirmation form input[type="submit"]:focus, +.delete-confirmation form input[type="submit"]:hover { + background: var(--delete-button-hover-bg); +} + +.delete-confirmation form .cancel-link { + display: inline-block; + vertical-align: middle; + height: 0.9375rem; + line-height: 0.9375rem; + border-radius: 4px; + padding: 10px 15px; + color: var(--button-fg); + background: var(--close-button-bg); + margin: 0 0 0 10px; +} + +.delete-confirmation form .cancel-link:active, +.delete-confirmation form .cancel-link:focus, +.delete-confirmation form .cancel-link:hover { + background: var(--close-button-hover-bg); +} + +/* POPUP */ +.popup #content { + padding: 20px; +} + +.popup #container { + min-width: 0; +} + +.popup #header { + padding: 10px 20px; +} + +/* PAGINATOR */ + +.paginator { + display: flex; + align-items: center; + gap: 4px; + font-size: 0.8125rem; + padding-top: 10px; + padding-bottom: 10px; + line-height: 22px; + margin: 0; + border-top: 1px solid var(--hairline-color); + width: 100%; +} + +.paginator a:link, .paginator a:visited { + padding: 2px 6px; + background: var(--button-bg); + text-decoration: none; + color: var(--button-fg); +} + +.paginator a.showall { + border: none; + background: none; + color: var(--link-fg); +} + +.paginator a.showall:focus, .paginator a.showall:hover { + background: none; + color: var(--link-hover-color); +} + +.paginator .end { + margin-right: 6px; +} + +.paginator .this-page { + padding: 2px 6px; + font-weight: bold; + font-size: 0.8125rem; + vertical-align: top; +} + +.paginator a:focus, .paginator a:hover { + color: white; + background: var(--link-hover-color); +} + +.paginator input { + margin-left: auto; +} + +.base-svgs { + display: none; +} diff --git a/staticfiles/admin/css/base.523eb49842a7.css.gz b/staticfiles/admin/css/base.523eb49842a7.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..ee59980b9a7e851d0ba5fba7fcd8cf497ae2ff4e GIT binary patch literal 4865 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 literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/base.css b/staticfiles/admin/css/base.css new file mode 100644 index 0000000000..93db7d062a --- /dev/null +++ b/staticfiles/admin/css/base.css @@ -0,0 +1,1145 @@ +/* + DJANGO Admin styles +*/ + +/* VARIABLE DEFINITIONS */ +html[data-theme="light"], +:root { + --primary: #79aec8; + --secondary: #417690; + --accent: #f5dd5d; + --primary-fg: #fff; + + --body-fg: #333; + --body-bg: #fff; + --body-quiet-color: #666; + --body-loud-color: #000; + + --header-color: #ffc; + --header-branding-color: var(--accent); + --header-bg: var(--secondary); + --header-link-color: var(--primary-fg); + + --breadcrumbs-fg: #c4dce8; + --breadcrumbs-link-fg: var(--body-bg); + --breadcrumbs-bg: var(--primary); + + --link-fg: #417893; + --link-hover-color: #036; + --link-selected-fg: #5b80b2; + + --hairline-color: #e8e8e8; + --border-color: #ccc; + + --error-fg: #ba2121; + + --message-success-bg: #dfd; + --message-warning-bg: #ffc; + --message-error-bg: #ffefef; + + --darkened-bg: #f8f8f8; /* A bit darker than --body-bg */ + --selected-bg: #e4e4e4; /* E.g. selected table cells */ + --selected-row: #ffc; + + --button-fg: #fff; + --button-bg: var(--primary); + --button-hover-bg: #609ab6; + --default-button-bg: var(--secondary); + --default-button-hover-bg: #205067; + --close-button-bg: #747474; + --close-button-hover-bg: #333; + --delete-button-bg: #ba2121; + --delete-button-hover-bg: #a41515; + + --object-tools-fg: var(--button-fg); + --object-tools-bg: var(--close-button-bg); + --object-tools-hover-bg: var(--close-button-hover-bg); + + --font-family-primary: + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + system-ui, + Roboto, + "Helvetica Neue", + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; + --font-family-monospace: + ui-monospace, + Menlo, + Monaco, + "Cascadia Mono", + "Segoe UI Mono", + "Roboto Mono", + "Oxygen Mono", + "Ubuntu Monospace", + "Source Code Pro", + "Fira Mono", + "Droid Sans Mono", + "Courier New", + monospace, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; +} + +html, body { + height: 100%; +} + +body { + margin: 0; + padding: 0; + font-size: 0.875rem; + font-family: var(--font-family-primary); + color: var(--body-fg); + background: var(--body-bg); +} + +/* LINKS */ + +a:link, a:visited { + color: var(--link-fg); + text-decoration: none; + transition: color 0.15s, background 0.15s; +} + +a:focus, a:hover { + color: var(--link-hover-color); +} + +a:focus { + text-decoration: underline; +} + +a img { + border: none; +} + +a.section:link, a.section:visited { + color: var(--header-link-color); + text-decoration: none; +} + +a.section:focus, a.section:hover { + text-decoration: underline; +} + +/* GLOBAL DEFAULTS */ + +p, ol, ul, dl { + margin: .2em 0 .8em 0; +} + +p { + padding: 0; + line-height: 140%; +} + +h1,h2,h3,h4,h5 { + font-weight: bold; +} + +h1 { + margin: 0 0 20px; + font-weight: 300; + font-size: 1.25rem; + color: var(--body-quiet-color); +} + +h2 { + font-size: 1rem; + margin: 1em 0 .5em 0; +} + +h2.subhead { + font-weight: normal; + margin-top: 0; +} + +h3 { + font-size: 0.875rem; + margin: .8em 0 .3em 0; + color: var(--body-quiet-color); + font-weight: bold; +} + +h4 { + font-size: 0.75rem; + margin: 1em 0 .8em 0; + padding-bottom: 3px; +} + +h5 { + font-size: 0.625rem; + margin: 1.5em 0 .5em 0; + color: var(--body-quiet-color); + text-transform: uppercase; + letter-spacing: 1px; +} + +ul > li { + list-style-type: square; + padding: 1px 0; +} + +li ul { + margin-bottom: 0; +} + +li, dt, dd { + font-size: 0.8125rem; + line-height: 1.25rem; +} + +dt { + font-weight: bold; + margin-top: 4px; +} + +dd { + margin-left: 0; +} + +form { + margin: 0; + padding: 0; +} + +fieldset { + margin: 0; + min-width: 0; + padding: 0; + border: none; + border-top: 1px solid var(--hairline-color); +} + +blockquote { + font-size: 0.6875rem; + color: #777; + margin-left: 2px; + padding-left: 10px; + border-left: 5px solid #ddd; +} + +code, pre { + font-family: var(--font-family-monospace); + color: var(--body-quiet-color); + font-size: 0.75rem; + overflow-x: auto; +} + +pre.literal-block { + margin: 10px; + background: var(--darkened-bg); + padding: 6px 8px; +} + +code strong { + color: #930; +} + +hr { + clear: both; + color: var(--hairline-color); + background-color: var(--hairline-color); + height: 1px; + border: none; + margin: 0; + padding: 0; + line-height: 1px; +} + +/* TEXT STYLES & MODIFIERS */ + +.small { + font-size: 0.6875rem; +} + +.mini { + font-size: 0.625rem; +} + +.help, p.help, form p.help, div.help, form div.help, div.help li { + font-size: 0.6875rem; + color: var(--body-quiet-color); +} + +div.help ul { + margin-bottom: 0; +} + +.help-tooltip { + cursor: help; +} + +p img, h1 img, h2 img, h3 img, h4 img, td img { + vertical-align: middle; +} + +.quiet, a.quiet:link, a.quiet:visited { + color: var(--body-quiet-color); + font-weight: normal; +} + +.clear { + clear: both; +} + +.nowrap { + white-space: nowrap; +} + +.hidden { + display: none !important; +} + +/* TABLES */ + +table { + border-collapse: collapse; + border-color: var(--border-color); +} + +td, th { + font-size: 0.8125rem; + line-height: 1rem; + border-bottom: 1px solid var(--hairline-color); + vertical-align: top; + padding: 8px; +} + +th { + font-weight: 600; + text-align: left; +} + +thead th, +tfoot td { + color: var(--body-quiet-color); + padding: 5px 10px; + font-size: 0.6875rem; + background: var(--body-bg); + border: none; + border-top: 1px solid var(--hairline-color); + border-bottom: 1px solid var(--hairline-color); +} + +tfoot td { + border-bottom: none; + border-top: 1px solid var(--hairline-color); +} + +thead th.required { + color: var(--body-loud-color); +} + +tr.alt { + background: var(--darkened-bg); +} + +tr:nth-child(odd), .row-form-errors { + background: var(--body-bg); +} + +tr:nth-child(even), +tr:nth-child(even) .errorlist, +tr:nth-child(odd) + .row-form-errors, +tr:nth-child(odd) + .row-form-errors .errorlist { + background: var(--darkened-bg); +} + +/* SORTABLE TABLES */ + +thead th { + padding: 5px 10px; + line-height: normal; + text-transform: uppercase; + background: var(--darkened-bg); +} + +thead th a:link, thead th a:visited { + color: var(--body-quiet-color); +} + +thead th.sorted { + background: var(--selected-bg); +} + +thead th.sorted .text { + padding-right: 42px; +} + +table thead th .text span { + padding: 8px 10px; + display: block; +} + +table thead th .text a { + display: block; + cursor: pointer; + padding: 8px 10px; +} + +table thead th .text a:focus, table thead th .text a:hover { + background: var(--selected-bg); +} + +thead th.sorted a.sortremove { + visibility: hidden; +} + +table thead th.sorted:hover a.sortremove { + visibility: visible; +} + +table thead th.sorted .sortoptions { + display: block; + padding: 9px 5px 0 5px; + float: right; + text-align: right; +} + +table thead th.sorted .sortpriority { + font-size: .8em; + min-width: 12px; + text-align: center; + vertical-align: 3px; + margin-left: 2px; + margin-right: 2px; +} + +table thead th.sorted .sortoptions a { + position: relative; + width: 14px; + height: 14px; + display: inline-block; + background: url(../img/sorting-icons.svg) 0 0 no-repeat; + background-size: 14px auto; +} + +table thead th.sorted .sortoptions a.sortremove { + background-position: 0 0; +} + +table thead th.sorted .sortoptions a.sortremove:after { + content: '\\'; + position: absolute; + top: -6px; + left: 3px; + font-weight: 200; + font-size: 1.125rem; + color: var(--body-quiet-color); +} + +table thead th.sorted .sortoptions a.sortremove:focus:after, +table thead th.sorted .sortoptions a.sortremove:hover:after { + color: var(--link-fg); +} + +table thead th.sorted .sortoptions a.sortremove:focus, +table thead th.sorted .sortoptions a.sortremove:hover { + background-position: 0 -14px; +} + +table thead th.sorted .sortoptions a.ascending { + background-position: 0 -28px; +} + +table thead th.sorted .sortoptions a.ascending:focus, +table thead th.sorted .sortoptions a.ascending:hover { + background-position: 0 -42px; +} + +table thead th.sorted .sortoptions a.descending { + top: 1px; + background-position: 0 -56px; +} + +table thead th.sorted .sortoptions a.descending:focus, +table thead th.sorted .sortoptions a.descending:hover { + background-position: 0 -70px; +} + +/* FORM DEFAULTS */ + +input, textarea, select, .form-row p, form .button { + margin: 2px 0; + padding: 2px 3px; + vertical-align: middle; + font-family: var(--font-family-primary); + font-weight: normal; + font-size: 0.8125rem; +} +.form-row div.help { + padding: 2px 3px; +} + +textarea { + vertical-align: top; +} + +input[type=text], input[type=password], input[type=email], input[type=url], +input[type=number], input[type=tel], textarea, select, .vTextField { + border: 1px solid var(--border-color); + border-radius: 4px; + padding: 5px 6px; + margin-top: 0; + color: var(--body-fg); + background-color: var(--body-bg); +} + +input[type=text]:focus, input[type=password]:focus, input[type=email]:focus, +input[type=url]:focus, input[type=number]:focus, input[type=tel]:focus, +textarea:focus, select:focus, .vTextField:focus { + border-color: var(--body-quiet-color); +} + +select { + height: 1.875rem; +} + +select[multiple] { + /* Allow HTML size attribute to override the height in the rule above. */ + height: auto; + min-height: 150px; +} + +/* FORM BUTTONS */ + +.button, input[type=submit], input[type=button], .submit-row input, a.button { + background: var(--button-bg); + padding: 10px 15px; + border: none; + border-radius: 4px; + color: var(--button-fg); + cursor: pointer; + transition: background 0.15s; +} + +a.button { + padding: 4px 5px; +} + +.button:active, input[type=submit]:active, input[type=button]:active, +.button:focus, input[type=submit]:focus, input[type=button]:focus, +.button:hover, input[type=submit]:hover, input[type=button]:hover { + background: var(--button-hover-bg); +} + +.button[disabled], input[type=submit][disabled], input[type=button][disabled] { + opacity: 0.4; +} + +.button.default, input[type=submit].default, .submit-row input.default { + border: none; + font-weight: 400; + background: var(--default-button-bg); +} + +.button.default:active, input[type=submit].default:active, +.button.default:focus, input[type=submit].default:focus, +.button.default:hover, input[type=submit].default:hover { + background: var(--default-button-hover-bg); +} + +.button[disabled].default, +input[type=submit][disabled].default, +input[type=button][disabled].default { + opacity: 0.4; +} + + +/* MODULES */ + +.module { + border: none; + margin-bottom: 30px; + background: var(--body-bg); +} + +.module p, .module ul, .module h3, .module h4, .module dl, .module pre { + padding-left: 10px; + padding-right: 10px; +} + +.module blockquote { + margin-left: 12px; +} + +.module ul, .module ol { + margin-left: 1.5em; +} + +.module h3 { + margin-top: .6em; +} + +.module h2, .module caption, .inline-group h2 { + margin: 0; + padding: 8px; + font-weight: 400; + font-size: 0.8125rem; + text-align: left; + background: var(--primary); + color: var(--header-link-color); +} + +.module caption, +.inline-group h2 { + font-size: 0.75rem; + letter-spacing: 0.5px; + text-transform: uppercase; +} + +.module table { + border-collapse: collapse; +} + +/* MESSAGES & ERRORS */ + +ul.messagelist { + padding: 0; + margin: 0; +} + +ul.messagelist li { + display: block; + font-weight: 400; + font-size: 0.8125rem; + padding: 10px 10px 10px 65px; + margin: 0 0 10px 0; + background: var(--message-success-bg) url(../img/icon-yes.svg) 40px 12px no-repeat; + background-size: 16px auto; + color: var(--body-fg); + word-break: break-word; +} + +ul.messagelist li.warning { + background: var(--message-warning-bg) url(../img/icon-alert.svg) 40px 14px no-repeat; + background-size: 14px auto; +} + +ul.messagelist li.error { + background: var(--message-error-bg) url(../img/icon-no.svg) 40px 12px no-repeat; + background-size: 16px auto; +} + +.errornote { + font-size: 0.875rem; + font-weight: 700; + display: block; + padding: 10px 12px; + margin: 0 0 10px 0; + color: var(--error-fg); + border: 1px solid var(--error-fg); + border-radius: 4px; + background-color: var(--body-bg); + background-position: 5px 12px; + overflow-wrap: break-word; +} + +ul.errorlist { + margin: 0 0 4px; + padding: 0; + color: var(--error-fg); + background: var(--body-bg); +} + +ul.errorlist li { + font-size: 0.8125rem; + display: block; + margin-bottom: 4px; + overflow-wrap: break-word; +} + +ul.errorlist li:first-child { + margin-top: 0; +} + +ul.errorlist li a { + color: inherit; + text-decoration: underline; +} + +td ul.errorlist { + margin: 0; + padding: 0; +} + +td ul.errorlist li { + margin: 0; +} + +.form-row.errors { + margin: 0; + border: none; + border-bottom: 1px solid var(--hairline-color); + background: none; +} + +.form-row.errors ul.errorlist li { + padding-left: 0; +} + +.errors input, .errors select, .errors textarea, +td ul.errorlist + input, td ul.errorlist + select, td ul.errorlist + textarea { + border: 1px solid var(--error-fg); +} + +.description { + font-size: 0.75rem; + padding: 5px 0 0 12px; +} + +/* BREADCRUMBS */ + +div.breadcrumbs { + background: var(--breadcrumbs-bg); + padding: 10px 40px; + border: none; + color: var(--breadcrumbs-fg); + text-align: left; +} + +div.breadcrumbs a { + color: var(--breadcrumbs-link-fg); +} + +div.breadcrumbs a:focus, div.breadcrumbs a:hover { + color: var(--breadcrumbs-fg); +} + +/* ACTION ICONS */ + +.viewlink, .inlineviewlink { + padding-left: 16px; + background: url(../img/icon-viewlink.svg) 0 1px no-repeat; +} + +.addlink { + padding-left: 16px; + background: url(../img/icon-addlink.svg) 0 1px no-repeat; +} + +.changelink, .inlinechangelink { + padding-left: 16px; + background: url(../img/icon-changelink.svg) 0 1px no-repeat; +} + +.deletelink { + padding-left: 16px; + background: url(../img/icon-deletelink.svg) 0 1px no-repeat; +} + +a.deletelink:link, a.deletelink:visited { + color: #CC3434; /* XXX Probably unused? */ +} + +a.deletelink:focus, a.deletelink:hover { + color: #993333; /* XXX Probably unused? */ + text-decoration: none; +} + +/* OBJECT TOOLS */ + +.object-tools { + font-size: 0.625rem; + font-weight: bold; + padding-left: 0; + float: right; + position: relative; + margin-top: -48px; +} + +.object-tools li { + display: block; + float: left; + margin-left: 5px; + height: 1rem; +} + +.object-tools a { + border-radius: 15px; +} + +.object-tools a:link, .object-tools a:visited { + display: block; + float: left; + padding: 3px 12px; + background: var(--object-tools-bg); + color: var(--object-tools-fg); + font-weight: 400; + font-size: 0.6875rem; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.object-tools a:focus, .object-tools a:hover { + background-color: var(--object-tools-hover-bg); +} + +.object-tools a:focus{ + text-decoration: none; +} + +.object-tools a.viewsitelink, .object-tools a.addlink { + background-repeat: no-repeat; + background-position: right 7px center; + padding-right: 26px; +} + +.object-tools a.viewsitelink { + background-image: url(../img/tooltag-arrowright.svg); +} + +.object-tools a.addlink { + background-image: url(../img/tooltag-add.svg); +} + +/* OBJECT HISTORY */ + +#change-history table { + width: 100%; +} + +#change-history table tbody th { + width: 16em; +} + +#change-history .paginator { + color: var(--body-quiet-color); + border-bottom: 1px solid var(--hairline-color); + background: var(--body-bg); + overflow: hidden; +} + +/* PAGE STRUCTURE */ + +#container { + position: relative; + width: 100%; + min-width: 980px; + padding: 0; + display: flex; + flex-direction: column; + height: 100%; +} + +#container > div { + flex-shrink: 0; +} + +#container > .main { + display: flex; + flex: 1 0 auto; +} + +.main > .content { + flex: 1 0; + max-width: 100%; +} + +.skip-to-content-link { + position: absolute; + top: -999px; + margin: 5px; + padding: 5px; + background: var(--body-bg); + z-index: 1; +} + +.skip-to-content-link:focus { + left: 0px; + top: 0px; +} + +#content { + padding: 20px 40px; +} + +.dashboard #content { + width: 600px; +} + +#content-main { + float: left; + width: 100%; +} + +#content-related { + float: right; + width: 260px; + position: relative; + margin-right: -300px; +} + +#footer { + clear: both; + padding: 10px; +} + +/* COLUMN TYPES */ + +.colMS { + margin-right: 300px; +} + +.colSM { + margin-left: 300px; +} + +.colSM #content-related { + float: left; + margin-right: 0; + margin-left: -300px; +} + +.colSM #content-main { + float: right; +} + +.popup .colM { + width: auto; +} + +/* HEADER */ + +#header { + width: auto; + height: auto; + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 40px; + background: var(--header-bg); + color: var(--header-color); + overflow: hidden; +} + +#header a:link, #header a:visited, #logout-form button { + color: var(--header-link-color); +} + +#header a:focus , #header a:hover { + text-decoration: underline; +} + +#branding { + display: flex; +} + +#branding h1 { + padding: 0; + margin: 0; + margin-inline-end: 20px; + font-weight: 300; + font-size: 1.5rem; + color: var(--header-branding-color); +} + +#branding h1 a:link, #branding h1 a:visited { + color: var(--accent); +} + +#branding h2 { + padding: 0 10px; + font-size: 0.875rem; + margin: -8px 0 8px 0; + font-weight: normal; + color: var(--header-color); +} + +#branding a:hover { + text-decoration: none; +} + +#logout-form { + display: inline; +} + +#logout-form button { + background: none; + border: 0; + cursor: pointer; + font-family: var(--font-family-primary); +} + +#user-tools { + float: right; + margin: 0 0 0 20px; + text-align: right; +} + +#user-tools, #logout-form button{ + padding: 0; + font-weight: 300; + font-size: 0.6875rem; + letter-spacing: 0.5px; + text-transform: uppercase; +} + +#user-tools a, #logout-form button { + border-bottom: 1px solid rgba(255, 255, 255, 0.25); +} + +#user-tools a:focus, #user-tools a:hover, +#logout-form button:active, #logout-form button:hover { + text-decoration: none; + border-bottom: 0; +} + +#logout-form button:active, #logout-form button:hover { + margin-bottom: 1px; +} + +/* SIDEBAR */ + +#content-related { + background: var(--darkened-bg); +} + +#content-related .module { + background: none; +} + +#content-related h3 { + color: var(--body-quiet-color); + padding: 0 16px; + margin: 0 0 16px; +} + +#content-related h4 { + font-size: 0.8125rem; +} + +#content-related p { + padding-left: 16px; + padding-right: 16px; +} + +#content-related .actionlist { + padding: 0; + margin: 16px; +} + +#content-related .actionlist li { + line-height: 1.2; + margin-bottom: 10px; + padding-left: 18px; +} + +#content-related .module h2 { + background: none; + padding: 16px; + margin-bottom: 16px; + border-bottom: 1px solid var(--hairline-color); + font-size: 1.125rem; + color: var(--body-fg); +} + +.delete-confirmation form input[type="submit"] { + background: var(--delete-button-bg); + border-radius: 4px; + padding: 10px 15px; + color: var(--button-fg); +} + +.delete-confirmation form input[type="submit"]:active, +.delete-confirmation form input[type="submit"]:focus, +.delete-confirmation form input[type="submit"]:hover { + background: var(--delete-button-hover-bg); +} + +.delete-confirmation form .cancel-link { + display: inline-block; + vertical-align: middle; + height: 0.9375rem; + line-height: 0.9375rem; + border-radius: 4px; + padding: 10px 15px; + color: var(--button-fg); + background: var(--close-button-bg); + margin: 0 0 0 10px; +} + +.delete-confirmation form .cancel-link:active, +.delete-confirmation form .cancel-link:focus, +.delete-confirmation form .cancel-link:hover { + background: var(--close-button-hover-bg); +} + +/* POPUP */ +.popup #content { + padding: 20px; +} + +.popup #container { + min-width: 0; +} + +.popup #header { + padding: 10px 20px; +} + +/* PAGINATOR */ + +.paginator { + display: flex; + align-items: center; + gap: 4px; + font-size: 0.8125rem; + padding-top: 10px; + padding-bottom: 10px; + line-height: 22px; + margin: 0; + border-top: 1px solid var(--hairline-color); + width: 100%; +} + +.paginator a:link, .paginator a:visited { + padding: 2px 6px; + background: var(--button-bg); + text-decoration: none; + color: var(--button-fg); +} + +.paginator a.showall { + border: none; + background: none; + color: var(--link-fg); +} + +.paginator a.showall:focus, .paginator a.showall:hover { + background: none; + color: var(--link-hover-color); +} + +.paginator .end { + margin-right: 6px; +} + +.paginator .this-page { + padding: 2px 6px; + font-weight: bold; + font-size: 0.8125rem; + vertical-align: top; +} + +.paginator a:focus, .paginator a:hover { + color: white; + background: var(--link-hover-color); +} + +.paginator input { + margin-left: auto; +} + +.base-svgs { + display: none; +} diff --git a/staticfiles/admin/css/base.css.gz b/staticfiles/admin/css/base.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..a4753c53ce938101efea46f79d30c9fe8401e9ce GIT binary patch literal 4755 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 h!PJQ_4AVpfXJF8W< * { + display: inline; +} + +#changelist-filter details > summary { + list-style-type: none; +} + +#changelist-filter details > summary::-webkit-details-marker { + display: none; +} + +#changelist-filter details > summary::before { + content: '→'; + font-weight: bold; + color: var(--link-hover-color); +} + +#changelist-filter details[open] > summary::before { + content: '↓'; +} + +#changelist-filter ul { + margin: 5px 0; + padding: 0 15px 15px; + border-bottom: 1px solid var(--hairline-color); +} + +#changelist-filter ul:last-child { + border-bottom: none; +} + +#changelist-filter li { + list-style-type: none; + margin-left: 0; + padding-left: 0; +} + +#changelist-filter a { + display: block; + color: var(--body-quiet-color); + word-break: break-word; +} + +#changelist-filter li.selected { + border-left: 5px solid var(--hairline-color); + padding-left: 10px; + margin-left: -15px; +} + +#changelist-filter li.selected a { + color: var(--link-selected-fg); +} + +#changelist-filter a:focus, #changelist-filter a:hover, +#changelist-filter li.selected a:focus, +#changelist-filter li.selected a:hover { + color: var(--link-hover-color); +} + +#changelist-filter #changelist-filter-clear a { + font-size: 0.8125rem; + padding-bottom: 10px; + border-bottom: 1px solid var(--hairline-color); +} + +/* DATE DRILLDOWN */ + +.change-list .toplinks { + display: flex; + padding-bottom: 5px; + flex-wrap: wrap; + gap: 3px 17px; + font-weight: bold; +} + +.change-list .toplinks a { + font-size: 0.8125rem; +} + +.change-list .toplinks .date-back { + color: var(--body-quiet-color); +} + +.change-list .toplinks .date-back:focus, +.change-list .toplinks .date-back:hover { + color: var(--link-hover-color); +} + +/* ACTIONS */ + +.filtered .actions { + border-right: none; +} + +#changelist table input { + margin: 0; + vertical-align: baseline; +} + +/* Once the :has() pseudo-class is supported by all browsers, the tr.selected + selector and the JS adding the class can be removed. */ +#changelist tbody tr.selected { + background-color: var(--selected-row); +} + +#changelist tbody tr:has(.action-select:checked) { + background-color: var(--selected-row); +} + +#changelist .actions { + padding: 10px; + background: var(--body-bg); + border-top: none; + border-bottom: none; + line-height: 1.5rem; + color: var(--body-quiet-color); + width: 100%; +} + +#changelist .actions span.all, +#changelist .actions span.action-counter, +#changelist .actions span.clear, +#changelist .actions span.question { + font-size: 0.8125rem; + margin: 0 0.5em; +} + +#changelist .actions:last-child { + border-bottom: none; +} + +#changelist .actions select { + vertical-align: top; + height: 1.5rem; + color: var(--body-fg); + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 0.875rem; + padding: 0 0 0 4px; + margin: 0; + margin-left: 10px; +} + +#changelist .actions select:focus { + border-color: var(--body-quiet-color); +} + +#changelist .actions label { + display: inline-block; + vertical-align: middle; + font-size: 0.8125rem; +} + +#changelist .actions .button { + font-size: 0.8125rem; + border: 1px solid var(--border-color); + border-radius: 4px; + background: var(--body-bg); + box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; + cursor: pointer; + height: 1.5rem; + line-height: 1; + padding: 4px 8px; + margin: 0; + color: var(--body-fg); +} + +#changelist .actions .button:focus, #changelist .actions .button:hover { + border-color: var(--body-quiet-color); +} diff --git a/staticfiles/admin/css/changelists.9237a1ac391b.css.gz b/staticfiles/admin/css/changelists.9237a1ac391b.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..108028ffb0d372e01226f033207e8dd7a10fcce5 GIT binary patch literal 1564 zcmV+%2IKi3iwFP!00002|HW9_juST+zTc;?Kou;Chh*6mXjVm9VB2n$vJ!073&e$I z>}1?^#)Iu)lOk^W0PP$0N$S&_51CDoN)RMI{KxM<`RNnz`lpMxKVB}c-ru|jPo5qf zJ&Y5St_h=3fiFiu|G`vd4DCX&Vq|-6mk^`t6jDVt(k(-&kWg;(_gpHv+QFEoiliz8 zGD9(e5m9%9q~}Lpn@oc0J6v(GvG)*7iSYal{SYkl2jz-89vhm%JBn2jf_aCcLJ=eW zvOlz#&%d+hJU8fAClq6nt|(zxf-j|}DNo5c=$u|rridW8!64!S69ENXCt6i|^Jw_y zms0wKxErVQdA1$95(px5rsNC^9mvp{rbuxyJE~S6D$ZGi#H@A_)6ckT^EWk$foTF>&;Spe~o`8V#W9!+=exGw!PHAhvFHd>8)%UJmO06 zjlPp@f#i&0@EM865GIHUeVk|*F)og~C<{Zf}4w1%gb(9dVeGY;f_CSJXn(^Iy|8bJp;=-fikzD*(w?% z25k_B8jKh-G7v-slK{nv@)X7iiEksmHJav|v=wB*nL&YBQDmzM2C+^8L<})-sKRXq zp7L}$E6&wKk2*WwTwgC=UA%MF^}*7%ATn{d$>NapUwJ~G0`0>lR)Mh&1F|t z?XK$cTGGu&WE-(uo7YS5q}`~~)Krgs1YWkpb=XroMxcq1aYJ;7grQb7x}^&GEx0kL z5pCJ-Ni-tb`=l)Fexi8v&!2xiI`0}e;tcoX4%0qD8|Fh1+!Wvg&q(@lk{EwK8lsgK zU3L)^295m~=(Z9EcDEJpkRkmuPAJ3uee;+f7#)X14Y4i*G}WpW`^lp=CL+e;+w;lY z_((GBRVI*xkyw$IC7hIJQ+ltaVx5lAEkozU{ZgR5KGkBhI8qh59_#ti2731_%4d5e zD9hu%bM@kQSWI=7V9a!dE6uRCX=$a!1H(ku$u}1_m*CC2tL5^|^>40FHb>spsM+)K z(H5x;T>A=QrmPTDv)0=Dd}adtd83-a literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/changelists.css b/staticfiles/admin/css/changelists.css new file mode 100644 index 0000000000..a7545131a3 --- /dev/null +++ b/staticfiles/admin/css/changelists.css @@ -0,0 +1,328 @@ +/* CHANGELISTS */ + +#changelist { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +#changelist .changelist-form-container { + flex: 1 1 auto; + min-width: 0; +} + +#changelist table { + width: 100%; +} + +.change-list .hiddenfields { display:none; } + +.change-list .filtered table { + border-right: none; +} + +.change-list .filtered { + min-height: 400px; +} + +.change-list .filtered .results, .change-list .filtered .paginator, +.filtered #toolbar, .filtered div.xfull { + width: auto; +} + +.change-list .filtered table tbody th { + padding-right: 1em; +} + +#changelist-form .results { + overflow-x: auto; + width: 100%; +} + +#changelist .toplinks { + border-bottom: 1px solid var(--hairline-color); +} + +#changelist .paginator { + color: var(--body-quiet-color); + border-bottom: 1px solid var(--hairline-color); + background: var(--body-bg); + overflow: hidden; +} + +/* CHANGELIST TABLES */ + +#changelist table thead th { + padding: 0; + white-space: nowrap; + vertical-align: middle; +} + +#changelist table thead th.action-checkbox-column { + width: 1.5em; + text-align: center; +} + +#changelist table tbody td.action-checkbox { + text-align: center; +} + +#changelist table tfoot { + color: var(--body-quiet-color); +} + +/* TOOLBAR */ + +#toolbar { + padding: 8px 10px; + margin-bottom: 15px; + border-top: 1px solid var(--hairline-color); + border-bottom: 1px solid var(--hairline-color); + background: var(--darkened-bg); + color: var(--body-quiet-color); +} + +#toolbar form input { + border-radius: 4px; + font-size: 0.875rem; + padding: 5px; + color: var(--body-fg); +} + +#toolbar #searchbar { + height: 1.1875rem; + border: 1px solid var(--border-color); + padding: 2px 5px; + margin: 0; + vertical-align: top; + font-size: 0.8125rem; + max-width: 100%; +} + +#toolbar #searchbar:focus { + border-color: var(--body-quiet-color); +} + +#toolbar form input[type="submit"] { + border: 1px solid var(--border-color); + font-size: 0.8125rem; + padding: 4px 8px; + margin: 0; + vertical-align: middle; + background: var(--body-bg); + box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; + cursor: pointer; + color: var(--body-fg); +} + +#toolbar form input[type="submit"]:focus, +#toolbar form input[type="submit"]:hover { + border-color: var(--body-quiet-color); +} + +#changelist-search img { + vertical-align: middle; + margin-right: 4px; +} + +#changelist-search .help { + word-break: break-word; +} + +/* FILTER COLUMN */ + +#changelist-filter { + flex: 0 0 240px; + order: 1; + background: var(--darkened-bg); + border-left: none; + margin: 0 0 0 30px; +} + +#changelist-filter h2 { + font-size: 0.875rem; + text-transform: uppercase; + letter-spacing: 0.5px; + padding: 5px 15px; + margin-bottom: 12px; + border-bottom: none; +} + +#changelist-filter h3, +#changelist-filter details summary { + font-weight: 400; + padding: 0 15px; + margin-bottom: 10px; +} + +#changelist-filter details summary > * { + display: inline; +} + +#changelist-filter details > summary { + list-style-type: none; +} + +#changelist-filter details > summary::-webkit-details-marker { + display: none; +} + +#changelist-filter details > summary::before { + content: '→'; + font-weight: bold; + color: var(--link-hover-color); +} + +#changelist-filter details[open] > summary::before { + content: '↓'; +} + +#changelist-filter ul { + margin: 5px 0; + padding: 0 15px 15px; + border-bottom: 1px solid var(--hairline-color); +} + +#changelist-filter ul:last-child { + border-bottom: none; +} + +#changelist-filter li { + list-style-type: none; + margin-left: 0; + padding-left: 0; +} + +#changelist-filter a { + display: block; + color: var(--body-quiet-color); + word-break: break-word; +} + +#changelist-filter li.selected { + border-left: 5px solid var(--hairline-color); + padding-left: 10px; + margin-left: -15px; +} + +#changelist-filter li.selected a { + color: var(--link-selected-fg); +} + +#changelist-filter a:focus, #changelist-filter a:hover, +#changelist-filter li.selected a:focus, +#changelist-filter li.selected a:hover { + color: var(--link-hover-color); +} + +#changelist-filter #changelist-filter-clear a { + font-size: 0.8125rem; + padding-bottom: 10px; + border-bottom: 1px solid var(--hairline-color); +} + +/* DATE DRILLDOWN */ + +.change-list .toplinks { + display: flex; + padding-bottom: 5px; + flex-wrap: wrap; + gap: 3px 17px; + font-weight: bold; +} + +.change-list .toplinks a { + font-size: 0.8125rem; +} + +.change-list .toplinks .date-back { + color: var(--body-quiet-color); +} + +.change-list .toplinks .date-back:focus, +.change-list .toplinks .date-back:hover { + color: var(--link-hover-color); +} + +/* ACTIONS */ + +.filtered .actions { + border-right: none; +} + +#changelist table input { + margin: 0; + vertical-align: baseline; +} + +/* Once the :has() pseudo-class is supported by all browsers, the tr.selected + selector and the JS adding the class can be removed. */ +#changelist tbody tr.selected { + background-color: var(--selected-row); +} + +#changelist tbody tr:has(.action-select:checked) { + background-color: var(--selected-row); +} + +#changelist .actions { + padding: 10px; + background: var(--body-bg); + border-top: none; + border-bottom: none; + line-height: 1.5rem; + color: var(--body-quiet-color); + width: 100%; +} + +#changelist .actions span.all, +#changelist .actions span.action-counter, +#changelist .actions span.clear, +#changelist .actions span.question { + font-size: 0.8125rem; + margin: 0 0.5em; +} + +#changelist .actions:last-child { + border-bottom: none; +} + +#changelist .actions select { + vertical-align: top; + height: 1.5rem; + color: var(--body-fg); + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 0.875rem; + padding: 0 0 0 4px; + margin: 0; + margin-left: 10px; +} + +#changelist .actions select:focus { + border-color: var(--body-quiet-color); +} + +#changelist .actions label { + display: inline-block; + vertical-align: middle; + font-size: 0.8125rem; +} + +#changelist .actions .button { + font-size: 0.8125rem; + border: 1px solid var(--border-color); + border-radius: 4px; + background: var(--body-bg); + box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; + cursor: pointer; + height: 1.5rem; + line-height: 1; + padding: 4px 8px; + margin: 0; + color: var(--body-fg); +} + +#changelist .actions .button:focus, #changelist .actions .button:hover { + border-color: var(--body-quiet-color); +} diff --git a/staticfiles/admin/css/changelists.css.gz b/staticfiles/admin/css/changelists.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..108028ffb0d372e01226f033207e8dd7a10fcce5 GIT binary patch literal 1564 zcmV+%2IKi3iwFP!00002|HW9_juST+zTc;?Kou;Chh*6mXjVm9VB2n$vJ!073&e$I z>}1?^#)Iu)lOk^W0PP$0N$S&_51CDoN)RMI{KxM<`RNnz`lpMxKVB}c-ru|jPo5qf zJ&Y5St_h=3fiFiu|G`vd4DCX&Vq|-6mk^`t6jDVt(k(-&kWg;(_gpHv+QFEoiliz8 zGD9(e5m9%9q~}Lpn@oc0J6v(GvG)*7iSYal{SYkl2jz-89vhm%JBn2jf_aCcLJ=eW zvOlz#&%d+hJU8fAClq6nt|(zxf-j|}DNo5c=$u|rridW8!64!S69ENXCt6i|^Jw_y zms0wKxErVQdA1$95(px5rsNC^9mvp{rbuxyJE~S6D$ZGi#H@A_)6ckT^EWk$foTF>&;Spe~o`8V#W9!+=exGw!PHAhvFHd>8)%UJmO06 zjlPp@f#i&0@EM865GIHUeVk|*F)og~C<{Zf}4w1%gb(9dVeGY;f_CSJXn(^Iy|8bJp;=-fikzD*(w?% z25k_B8jKh-G7v-slK{nv@)X7iiEksmHJav|v=wB*nL&YBQDmzM2C+^8L<})-sKRXq zp7L}$E6&wKk2*WwTwgC=UA%MF^}*7%ATn{d$>NapUwJ~G0`0>lR)Mh&1F|t z?XK$cTGGu&WE-(uo7YS5q}`~~)Krgs1YWkpb=XroMxcq1aYJ;7grQb7x}^&GEx0kL z5pCJ-Ni-tb`=l)Fexi8v&!2xiI`0}e;tcoX4%0qD8|Fh1+!Wvg&q(@lk{EwK8lsgK zU3L)^295m~=(Z9EcDEJpkRkmuPAJ3uee;+f7#)X14Y4i*G}WpW`^lp=CL+e;+w;lY z_((GBRVI*xkyw$IC7hIJQ+ltaVx5lAEkozU{ZgR5KGkBhI8qh59_#ti2731_%4d5e zD9hu%bM@kQSWI=7V9a!dE6uRCX=$a!1H(ku$u}1_m*CC2tL5^|^>40FHb>spsM+)K z(H5x;T>A=QrmPTDv)0=Dd}adtd83-a literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/dark_mode.css b/staticfiles/admin/css/dark_mode.css new file mode 100644 index 0000000000..6d08233aae --- /dev/null +++ b/staticfiles/admin/css/dark_mode.css @@ -0,0 +1,137 @@ +@media (prefers-color-scheme: dark) { + :root { + --primary: #264b5d; + --primary-fg: #f7f7f7; + + --body-fg: #eeeeee; + --body-bg: #121212; + --body-quiet-color: #e0e0e0; + --body-loud-color: #ffffff; + + --breadcrumbs-link-fg: #e0e0e0; + --breadcrumbs-bg: var(--primary); + + --link-fg: #81d4fa; + --link-hover-color: #4ac1f7; + --link-selected-fg: #6f94c6; + + --hairline-color: #272727; + --border-color: #353535; + + --error-fg: #e35f5f; + --message-success-bg: #006b1b; + --message-warning-bg: #583305; + --message-error-bg: #570808; + + --darkened-bg: #212121; + --selected-bg: #1b1b1b; + --selected-row: #00363a; + + --close-button-bg: #333333; + --close-button-hover-bg: #666666; + } + } + + +html[data-theme="dark"] { + --primary: #264b5d; + --primary-fg: #f7f7f7; + + --body-fg: #eeeeee; + --body-bg: #121212; + --body-quiet-color: #e0e0e0; + --body-loud-color: #ffffff; + + --breadcrumbs-link-fg: #e0e0e0; + --breadcrumbs-bg: var(--primary); + + --link-fg: #81d4fa; + --link-hover-color: #4ac1f7; + --link-selected-fg: #6f94c6; + + --hairline-color: #272727; + --border-color: #353535; + + --error-fg: #e35f5f; + --message-success-bg: #006b1b; + --message-warning-bg: #583305; + --message-error-bg: #570808; + + --darkened-bg: #212121; + --selected-bg: #1b1b1b; + --selected-row: #00363a; + + --close-button-bg: #333333; + --close-button-hover-bg: #666666; +} + +/* THEME SWITCH */ +.theme-toggle { + cursor: pointer; + border: none; + padding: 0; + background: transparent; + vertical-align: middle; + margin-inline-start: 5px; + margin-top: -1px; +} + +.theme-toggle svg { + vertical-align: middle; + height: 1rem; + width: 1rem; + display: none; +} + +/* +Fully hide screen reader text so we only show the one matching the current +theme. +*/ +.theme-toggle .visually-hidden { + display: none; +} + +html[data-theme="auto"] .theme-toggle .theme-label-when-auto { + display: block; +} + +html[data-theme="dark"] .theme-toggle .theme-label-when-dark { + display: block; +} + +html[data-theme="light"] .theme-toggle .theme-label-when-light { + display: block; +} + +/* ICONS */ +.theme-toggle svg.theme-icon-when-auto, +.theme-toggle svg.theme-icon-when-dark, +.theme-toggle svg.theme-icon-when-light { + fill: var(--header-link-color); + color: var(--header-bg); +} + +html[data-theme="auto"] .theme-toggle svg.theme-icon-when-auto { + display: block; +} + +html[data-theme="dark"] .theme-toggle svg.theme-icon-when-dark { + display: block; +} + +html[data-theme="light"] .theme-toggle svg.theme-icon-when-light { + display: block; +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + overflow: hidden; + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; + color: var(--body-fg); + background-color: var(--body-bg); +} diff --git a/staticfiles/admin/css/dark_mode.css.gz b/staticfiles/admin/css/dark_mode.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..faebccea590bbf329596f47495cc027ed38ea3c8 GIT binary patch literal 849 zcmV-X1FrlZiwFP!00002|D{!3PunmQeb2A3*b7A%T1pE`HE9xJf`@GnAnjq=gJa($ zR$V)@9STDG@AF3pO-tG$Y$3J2r{{j1d-=Km#tAyCG~}QSrb;M{4J}~-DPly=2k1FL z?xb2N+k8d{<4W@d(N8J*bT&QDCTzBD!Fl0~`GvpU*xED28Y6@=>sm5z8J+pNX8Bul zurWmcK}(_~mqi3kF302HWD^vfMaaeQa(LMZ#cK+r zOE&;Qn@6u4Z84$>vQa0D)~eMqL^+<0Nr#;ZWdLWjwMs^gaX7QL5wSf1Hw`D^{w4k| zNlLpAzZtOvTR#wA4t($jf0`-in}MDQNVciJPy0KSzfJeazM9{y_+*>fcWQmB(vv+@ z-mCFstG@S8_a55bs_bN!s<&ynSJBBnYTm77r{U8hbboXG{Tki-H9{E?7NjGfsP&A=$b5jB@O2<6X zu!t{9&TP5*z__Udd3wn*lq~sH3-N?X&YUBv0VMMC0UB9&w8$v51f-;cm{Ki~3(S23 z7q+FPD^GZE74@Y^LewY8M%_;yxT%SAgPj}ZJUsV=v$2FoZIxR>Yjp9OAQ=d}EJ0!q zTPMwgqVu;|o7J|9)x+MwDt!I-pbfZwUZ>*QtDisaHs$Md&^&PJhM>*-cn_S$}OX!(8~a8u^>v2=11Oc1!ngcpPriv}MVy+e8(i;D>LiN!8tg b!#A4S{4*b{Z$rF^Y6S2frdt^naSH$dGXj{n literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/dark_mode.ef27a31af300.css b/staticfiles/admin/css/dark_mode.ef27a31af300.css new file mode 100644 index 0000000000..6d08233aae --- /dev/null +++ b/staticfiles/admin/css/dark_mode.ef27a31af300.css @@ -0,0 +1,137 @@ +@media (prefers-color-scheme: dark) { + :root { + --primary: #264b5d; + --primary-fg: #f7f7f7; + + --body-fg: #eeeeee; + --body-bg: #121212; + --body-quiet-color: #e0e0e0; + --body-loud-color: #ffffff; + + --breadcrumbs-link-fg: #e0e0e0; + --breadcrumbs-bg: var(--primary); + + --link-fg: #81d4fa; + --link-hover-color: #4ac1f7; + --link-selected-fg: #6f94c6; + + --hairline-color: #272727; + --border-color: #353535; + + --error-fg: #e35f5f; + --message-success-bg: #006b1b; + --message-warning-bg: #583305; + --message-error-bg: #570808; + + --darkened-bg: #212121; + --selected-bg: #1b1b1b; + --selected-row: #00363a; + + --close-button-bg: #333333; + --close-button-hover-bg: #666666; + } + } + + +html[data-theme="dark"] { + --primary: #264b5d; + --primary-fg: #f7f7f7; + + --body-fg: #eeeeee; + --body-bg: #121212; + --body-quiet-color: #e0e0e0; + --body-loud-color: #ffffff; + + --breadcrumbs-link-fg: #e0e0e0; + --breadcrumbs-bg: var(--primary); + + --link-fg: #81d4fa; + --link-hover-color: #4ac1f7; + --link-selected-fg: #6f94c6; + + --hairline-color: #272727; + --border-color: #353535; + + --error-fg: #e35f5f; + --message-success-bg: #006b1b; + --message-warning-bg: #583305; + --message-error-bg: #570808; + + --darkened-bg: #212121; + --selected-bg: #1b1b1b; + --selected-row: #00363a; + + --close-button-bg: #333333; + --close-button-hover-bg: #666666; +} + +/* THEME SWITCH */ +.theme-toggle { + cursor: pointer; + border: none; + padding: 0; + background: transparent; + vertical-align: middle; + margin-inline-start: 5px; + margin-top: -1px; +} + +.theme-toggle svg { + vertical-align: middle; + height: 1rem; + width: 1rem; + display: none; +} + +/* +Fully hide screen reader text so we only show the one matching the current +theme. +*/ +.theme-toggle .visually-hidden { + display: none; +} + +html[data-theme="auto"] .theme-toggle .theme-label-when-auto { + display: block; +} + +html[data-theme="dark"] .theme-toggle .theme-label-when-dark { + display: block; +} + +html[data-theme="light"] .theme-toggle .theme-label-when-light { + display: block; +} + +/* ICONS */ +.theme-toggle svg.theme-icon-when-auto, +.theme-toggle svg.theme-icon-when-dark, +.theme-toggle svg.theme-icon-when-light { + fill: var(--header-link-color); + color: var(--header-bg); +} + +html[data-theme="auto"] .theme-toggle svg.theme-icon-when-auto { + display: block; +} + +html[data-theme="dark"] .theme-toggle svg.theme-icon-when-dark { + display: block; +} + +html[data-theme="light"] .theme-toggle svg.theme-icon-when-light { + display: block; +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + overflow: hidden; + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; + color: var(--body-fg); + background-color: var(--body-bg); +} diff --git a/staticfiles/admin/css/dark_mode.ef27a31af300.css.gz b/staticfiles/admin/css/dark_mode.ef27a31af300.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..faebccea590bbf329596f47495cc027ed38ea3c8 GIT binary patch literal 849 zcmV-X1FrlZiwFP!00002|D{!3PunmQeb2A3*b7A%T1pE`HE9xJf`@GnAnjq=gJa($ zR$V)@9STDG@AF3pO-tG$Y$3J2r{{j1d-=Km#tAyCG~}QSrb;M{4J}~-DPly=2k1FL z?xb2N+k8d{<4W@d(N8J*bT&QDCTzBD!Fl0~`GvpU*xED28Y6@=>sm5z8J+pNX8Bul zurWmcK}(_~mqi3kF302HWD^vfMaaeQa(LMZ#cK+r zOE&;Qn@6u4Z84$>vQa0D)~eMqL^+<0Nr#;ZWdLWjwMs^gaX7QL5wSf1Hw`D^{w4k| zNlLpAzZtOvTR#wA4t($jf0`-in}MDQNVciJPy0KSzfJeazM9{y_+*>fcWQmB(vv+@ z-mCFstG@S8_a55bs_bN!s<&ynSJBBnYTm77r{U8hbboXG{Tki-H9{E?7NjGfsP&A=$b5jB@O2<6X zu!t{9&TP5*z__Udd3wn*lq~sH3-N?X&YUBv0VMMC0UB9&w8$v51f-;cm{Ki~3(S23 z7q+FPD^GZE74@Y^LewY8M%_;yxT%SAgPj}ZJUsV=v$2FoZIxR>Yjp9OAQ=d}EJ0!q zTPMwgqVu;|o7J|9)x+MwDt!I-pbfZwUZ>*QtDisaHs$Md&^&PJhM>*-cn_S$}OX!(8~a8u^>v2=11Oc1!ngcpPriv}MVy+e8(i;D>LiN!8tg b!#A4S{4*b{Z$rF^Y6S2frdt^naSH$dGXj{n literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/dashboard.css b/staticfiles/admin/css/dashboard.css new file mode 100644 index 0000000000..242b81a45f --- /dev/null +++ b/staticfiles/admin/css/dashboard.css @@ -0,0 +1,29 @@ +/* DASHBOARD */ +.dashboard td, .dashboard th { + word-break: break-word; +} + +.dashboard .module table th { + width: 100%; +} + +.dashboard .module table td { + white-space: nowrap; +} + +.dashboard .module table td a { + display: block; + padding-right: .6em; +} + +/* RECENT ACTIONS MODULE */ + +.module ul.actionlist { + margin-left: 0; +} + +ul.actionlist li { + list-style-type: none; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/staticfiles/admin/css/dashboard.css.gz b/staticfiles/admin/css/dashboard.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..06db5fd5cf463e2a3989b143df3b5bdc73962e1e GIT binary patch literal 267 zcmV+m0rdVKiwFP!00002|AmmTZi6rohIgLgmM*9Ux^y5D4M?rj1}RA&z;F&e#n{Mp zN>SB!FA&nEQ#{zZ-}n9h*>MPYwtIdmvuzGx97M>StPHmZ9`E70l<*b6xO!ueRaWq0 z3iH7xWfgn}*L2hxJShR5SJVCr6MC7#Lz3LxAn-y+@`AaJ*CGXNdds_;Bwtu0*C{@X zb1G9GSF_e}MA8kj)JUH~^eEcdFAiZ_tc%Savi1I@-0a}3%->&&=~seF!bwHE_GGjo z=a-O{+lDk#;xO7Jv)BJNMN8*YG3N&*m>;_NIa-{jG9SVol<8BDgede`_2SdBzbl~> Rb&lMW@dMe)7Ztey007?gfrSB!FA&nEQ#{zZ-}n9h*>MPYwtIdmvuzGx97M>StPHmZ9`E70l<*b6xO!ueRaWq0 z3iH7xWfgn}*L2hxJShR5SJVCr6MC7#Lz3LxAn-y+@`AaJ*CGXNdds_;Bwtu0*C{@X zb1G9GSF_e}MA8kj)JUH~^eEcdFAiZ_tc%Savi1I@-0a}3%->&&=~seF!bwHE_GGjo z=a-O{+lDk#;xO7Jv)BJNMN8*YG3N&*m>;_NIa-{jG9SVol<8BDgede`_2SdBzbl~> Rb&lMW@dMe)7Ztey007?gfr div { + padding-bottom: 10px; +} + +/* FORM LABELS */ + +label { + font-weight: normal; + color: var(--body-quiet-color); + font-size: 0.8125rem; +} + +.required label, label.required { + font-weight: bold; + color: var(--body-fg); +} + +/* RADIO BUTTONS */ + +form div.radiolist div { + padding-right: 7px; +} + +form div.radiolist.inline div { + display: inline-block; +} + +form div.radiolist label { + width: auto; +} + +form div.radiolist input[type="radio"] { + margin: -2px 4px 0 0; + padding: 0; +} + +form ul.inline { + margin-left: 0; + padding: 0; +} + +form ul.inline li { + float: left; + padding-right: 7px; +} + +/* ALIGNED FIELDSETS */ + +.aligned label { + display: block; + padding: 4px 10px 0 0; + min-width: 160px; + width: 160px; + word-wrap: break-word; + line-height: 1; +} + +.aligned label:not(.vCheckboxLabel):after { + content: ''; + display: inline-block; + vertical-align: middle; + height: 1.625rem; +} + +.aligned label + p, .aligned .checkbox-row + div.help, .aligned label + div.readonly { + padding: 6px 0; + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + overflow-wrap: break-word; +} + +.aligned ul label { + display: inline; + float: none; + width: auto; +} + +.aligned .form-row input { + margin-bottom: 0; +} + +.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField { + width: 350px; +} + +form .aligned ul { + margin-left: 160px; + padding-left: 10px; +} + +form .aligned div.radiolist { + display: inline-block; + margin: 0; + padding: 0; +} + +form .aligned p.help, +form .aligned div.help { + margin-top: 0; + margin-left: 160px; + padding-left: 10px; +} + +form .aligned p.date div.help.timezonewarning, +form .aligned p.datetime div.help.timezonewarning, +form .aligned p.time div.help.timezonewarning { + margin-left: 0; + padding-left: 0; + font-weight: normal; +} + +form .aligned p.help:last-child, +form .aligned div.help:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +form .aligned input + p.help, +form .aligned textarea + p.help, +form .aligned select + p.help, +form .aligned input + div.help, +form .aligned textarea + div.help, +form .aligned select + div.help { + margin-left: 160px; + padding-left: 10px; +} + +form .aligned ul li { + list-style: none; +} + +form .aligned table p { + margin-left: 0; + padding-left: 0; +} + +.aligned .vCheckboxLabel { + float: none; + width: auto; + display: inline-block; + vertical-align: -3px; + padding: 0 0 5px 5px; +} + +.aligned .vCheckboxLabel + p.help, +.aligned .vCheckboxLabel + div.help { + margin-top: -4px; +} + +.colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField { + width: 610px; +} + +fieldset .fieldBox { + margin-right: 20px; +} + +/* WIDE FIELDSETS */ + +.wide label { + width: 200px; +} + +form .wide p, +form .wide ul.errorlist, +form .wide input + p.help, +form .wide input + div.help { + margin-left: 200px; +} + +form .wide p.help, +form .wide div.help { + padding-left: 50px; +} + +form div.help ul { + padding-left: 0; + margin-left: 0; +} + +.colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField { + width: 450px; +} + +/* COLLAPSED FIELDSETS */ + +fieldset.collapsed * { + display: none; +} + +fieldset.collapsed h2, fieldset.collapsed { + display: block; +} + +fieldset.collapsed { + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; +} + +fieldset.collapsed h2 { + background: var(--darkened-bg); + color: var(--body-quiet-color); +} + +fieldset .collapse-toggle { + color: var(--header-link-color); +} + +fieldset.collapsed .collapse-toggle { + background: transparent; + display: inline; + color: var(--link-fg); +} + +/* MONOSPACE TEXTAREAS */ + +fieldset.monospace textarea { + font-family: var(--font-family-monospace); +} + +/* SUBMIT ROW */ + +.submit-row { + padding: 12px 14px 12px; + margin: 0 0 20px; + background: var(--darkened-bg); + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +body.popup .submit-row { + overflow: auto; +} + +.submit-row input { + height: 2.1875rem; + line-height: 0.9375rem; +} + +.submit-row input, .submit-row a { + margin: 0; +} + +.submit-row input.default { + text-transform: uppercase; +} + +.submit-row a.deletelink { + margin-left: auto; +} + +.submit-row a.deletelink { + display: block; + background: var(--delete-button-bg); + border-radius: 4px; + padding: 0.625rem 0.9375rem; + height: 0.9375rem; + line-height: 0.9375rem; + color: var(--button-fg); +} + +.submit-row a.closelink { + display: inline-block; + background: var(--close-button-bg); + border-radius: 4px; + padding: 10px 15px; + height: 0.9375rem; + line-height: 0.9375rem; + color: var(--button-fg); +} + +.submit-row a.deletelink:focus, +.submit-row a.deletelink:hover, +.submit-row a.deletelink:active { + background: var(--delete-button-hover-bg); + text-decoration: none; +} + +.submit-row a.closelink:focus, +.submit-row a.closelink:hover, +.submit-row a.closelink:active { + background: var(--close-button-hover-bg); + text-decoration: none; +} + +/* CUSTOM FORM FIELDS */ + +.vSelectMultipleField { + vertical-align: top; +} + +.vCheckboxField { + border: none; +} + +.vDateField, .vTimeField { + margin-right: 2px; + margin-bottom: 4px; +} + +.vDateField { + min-width: 6.85em; +} + +.vTimeField { + min-width: 4.7em; +} + +.vURLField { + width: 30em; +} + +.vLargeTextField, .vXMLLargeTextField { + width: 48em; +} + +.flatpages-flatpage #id_content { + height: 40.2em; +} + +.module table .vPositiveSmallIntegerField { + width: 2.2em; +} + +.vIntegerField { + width: 5em; +} + +.vBigIntegerField { + width: 10em; +} + +.vForeignKeyRawIdAdminField { + width: 5em; +} + +.vTextField, .vUUIDField { + width: 20em; +} + +/* INLINES */ + +.inline-group { + padding: 0; + margin: 0 0 30px; +} + +.inline-group thead th { + padding: 8px 10px; +} + +.inline-group .aligned label { + width: 160px; +} + +.inline-related { + position: relative; +} + +.inline-related h3 { + margin: 0; + color: var(--body-quiet-color); + padding: 5px; + font-size: 0.8125rem; + background: var(--darkened-bg); + border-top: 1px solid var(--hairline-color); + border-bottom: 1px solid var(--hairline-color); +} + +.inline-related h3 span.delete { + float: right; +} + +.inline-related h3 span.delete label { + margin-left: 2px; + font-size: 0.6875rem; +} + +.inline-related fieldset { + margin: 0; + background: var(--body-bg); + border: none; + width: 100%; +} + +.inline-related fieldset.module h3 { + margin: 0; + padding: 2px 5px 3px 5px; + font-size: 0.6875rem; + text-align: left; + font-weight: bold; + background: #bcd; + color: var(--body-bg); +} + +.inline-group .tabular fieldset.module { + border: none; +} + +.inline-related.tabular fieldset.module table { + width: 100%; + overflow-x: scroll; +} + +.last-related fieldset { + border: none; +} + +.inline-group .tabular tr.has_original td { + padding-top: 2em; +} + +.inline-group .tabular tr td.original { + padding: 2px 0 0 0; + width: 0; + _position: relative; +} + +.inline-group .tabular th.original { + width: 0px; + padding: 0; +} + +.inline-group .tabular td.original p { + position: absolute; + left: 0; + height: 1.1em; + padding: 2px 9px; + overflow: hidden; + font-size: 0.5625rem; + font-weight: bold; + color: var(--body-quiet-color); + _width: 700px; +} + +.inline-group ul.tools { + padding: 0; + margin: 0; + list-style: none; +} + +.inline-group ul.tools li { + display: inline; + padding: 0 5px; +} + +.inline-group div.add-row, +.inline-group .tabular tr.add-row td { + color: var(--body-quiet-color); + background: var(--darkened-bg); + padding: 8px 10px; + border-bottom: 1px solid var(--hairline-color); +} + +.inline-group .tabular tr.add-row td { + padding: 8px 10px; + border-bottom: 1px solid var(--hairline-color); +} + +.inline-group ul.tools a.add, +.inline-group div.add-row a, +.inline-group .tabular tr.add-row td a { + background: url("../img/icon-addlink.d519b3bab011.svg") 0 1px no-repeat; + padding-left: 16px; + font-size: 0.75rem; +} + +.empty-form { + display: none; +} + +/* RELATED FIELD ADD ONE / LOOKUP */ + +.related-lookup { + margin-left: 5px; + display: inline-block; + vertical-align: middle; + background-repeat: no-repeat; + background-size: 14px; +} + +.related-lookup { + width: 1rem; + height: 1rem; + background-image: url("../img/search.7cf54ff789c6.svg"); +} + +form .related-widget-wrapper ul { + display: inline-block; + margin-left: 0; + padding-left: 0; +} + +.clearable-file-input input { + margin-top: 0; +} diff --git a/staticfiles/admin/css/forms.c14e1cb06392.css.gz b/staticfiles/admin/css/forms.c14e1cb06392.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..1cc0c35dd7af8c029001edeed231706597db72a5 GIT binary patch literal 2243 zcmV;!2t4;6iwFP!00002|Fs(ZZ`(HZ_xu$?hG9(`DYg?ksf|0F+qef~PFy4oHefgu zltkM?Xi<|WCt1+{{T?NeA|=vxHnc_En0oK=eSazci8cvMnUkmF-SJZtt}x3yjL*-J z-x~y%LC*`a?D%AKbaeLK`7*z|aqi~7-8=8kj*h$~O*d{zpPbht2ma74PM3r}4V`rq zhBzJ-rwIzfC|(VnZYOyzkCrrMZWjH8hfc@4>h}66-jq*#nua)aeaaZ!07~-gWRygq zvqkAU*IlD1B~gssfD)PlQ{PoCqRr~mQNG4W&MMY`GZqDixQIlnc<5|^L4q6j1o@bh zXn(Mm1pn(eSmWT)r_aa#tLSV{x{6|#(F9l@8A*2vs+_38OH$!i%5Vu@G6Cu>34R8N zVunDpw1NzyEFtJ+=UI@3nbn<4==W zY2Z>JueHsdaI{(j<1x@jq?Erf#jrAvPs11Y&pg6Rn#gW&&S{DPI>lkB{L}Kk`qXf@ zPf2LIdAT|fvfPcYr*r4i!(uVNEu|?;0*dfb6h`1w88fIQEibvOl+woWqPWm$jVdiw zK5>0QgGURtqpB35jje|c${DqRtIk-QHav0YxIKuG3;5R&4k-gp@x+`6zBNCVZnz(h zMAG3X0wj()+NCjB23;?Vx>KeAub;G(^|$2Fkh*! zJCJ$Ba02&mIRr8jDv4P(mQdE3ub4w&(?lOb9%8KXRAaSZ6c z{4(0*3cE58eTZC+|?q`Fs3#X&PlY8@CeeVb{H1F7QXUQyq624HxB zpV^lPlMvL_g82PrrUU6wd*1J;IYO1u5Mqi;>Ls9SrlMzo*L}_O>19Jpvk9N7P`RX>U1`XZe^ztD=W%)2>rKTTC3kqeI7u(F(gxX`vi@su; z&-2-A{Pn)o%}JVY13^g!PV&B4u<96X1Fw6hj^Wtc6`D!BDx>28GovzR@)Db8MT0rA zjIcJY#jPlKT%|ORLotYiD1F2bE3UsfIc!4Gf<@c`fx21|EIUnw#2UIeU><~eG|^Dl zv`|x-W+{rZ1TuQeM)s~uyT7d zTcS-wUIcOF$d!2Vs{4meH`4`QL6q4c%l%EnlpRF9ZQyfJx0oDy!n(3eg1dhNF)6@%*x$ zOPZ8UH4ac?KJA#1ybv!@P6Qj=FWkZvc{&_Ad6M8XKpAdfBfun>VeW*c|cR_mnj)er|XMJ%GRQr;})Fmqc! zHZog3-ovYAxPw{c75(9UF~2F7eq~KBbL#fK=-+Sn`Y<6_Z48<{EHsm);IjEtp+(ZH z^|QT(u}-uk+XakhDtx0c)U&o6iDc_q6BGFLQfS~^^+mpF-&4a~c$X6F;cjM{^E(ot z)l}_mpsob&k|36#70z7olk-y)eybKpja+=u@p=MrL&F^Eb~(;?+pjc>xHsIxJW8g3 zyuzvB;$BT)Ylo^e^eI}|!Me2uzR(nSjDN*1cj##vjzdu8PQseD9v-IGCT0bF@X6`z zYmmUhf~A^ApU{ko z8C)q{OoOs)z>QXEYq2m*t37OO2D+Wj&pYoE0dDgLY3p9O7jVwSe!woC%=}fBu2=Pz z7b&WEKly?6^@_hbF+~d`r<|a)C6lcR=&G=ympSjXtxj#@{5*8BAcZlfq+RUUEJn3* z(vX9t-Wp}!DEMI%BjT{IF_RaO(rb89iwNL(lE!P>nw|P}MkQYL?c1Il(!6Qiyhe~~ zx1~GjDC{P!Y=(RY@tjret!*Xh*B4#kewv^kcMm|C6ZZ#7@;dmvUpq&Bt8{SLF{k*P zc#Kk#?W-#z`@+#eP;M!WgS4{i>l+#4n;?MUUEt{s2dzMA-#kPqhZF-tef)xW(eowrS&Uz$dfuLhS3D@%6PcznwT|&TKya_2FyT zVpW;aC6qqq#$~6hHGlKnX0517v5wEG~2q3GK|t- z?Og`T{>5^6dG#?El-5ypy5i>YH)4wIOM=sSJ-hd1+yO5e0s@TiBIhn6_$b#hhIg6b RE!_8`{{zpkZquzJ003@1bG!fm literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/forms.css b/staticfiles/admin/css/forms.css new file mode 100644 index 0000000000..9a8dad08cc --- /dev/null +++ b/staticfiles/admin/css/forms.css @@ -0,0 +1,534 @@ +@import url('widgets.css'); + +/* FORM ROWS */ + +.form-row { + overflow: hidden; + padding: 10px; + font-size: 0.8125rem; + border-bottom: 1px solid var(--hairline-color); +} + +.form-row img, .form-row input { + vertical-align: middle; +} + +.form-row label input[type="checkbox"] { + margin-top: 0; + vertical-align: 0; +} + +form .form-row p { + padding-left: 0; +} + +.flex-container { + display: flex; +} + +.form-multiline { + flex-wrap: wrap; +} + +.form-multiline > div { + padding-bottom: 10px; +} + +/* FORM LABELS */ + +label { + font-weight: normal; + color: var(--body-quiet-color); + font-size: 0.8125rem; +} + +.required label, label.required { + font-weight: bold; + color: var(--body-fg); +} + +/* RADIO BUTTONS */ + +form div.radiolist div { + padding-right: 7px; +} + +form div.radiolist.inline div { + display: inline-block; +} + +form div.radiolist label { + width: auto; +} + +form div.radiolist input[type="radio"] { + margin: -2px 4px 0 0; + padding: 0; +} + +form ul.inline { + margin-left: 0; + padding: 0; +} + +form ul.inline li { + float: left; + padding-right: 7px; +} + +/* ALIGNED FIELDSETS */ + +.aligned label { + display: block; + padding: 4px 10px 0 0; + min-width: 160px; + width: 160px; + word-wrap: break-word; + line-height: 1; +} + +.aligned label:not(.vCheckboxLabel):after { + content: ''; + display: inline-block; + vertical-align: middle; + height: 1.625rem; +} + +.aligned label + p, .aligned .checkbox-row + div.help, .aligned label + div.readonly { + padding: 6px 0; + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + overflow-wrap: break-word; +} + +.aligned ul label { + display: inline; + float: none; + width: auto; +} + +.aligned .form-row input { + margin-bottom: 0; +} + +.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField { + width: 350px; +} + +form .aligned ul { + margin-left: 160px; + padding-left: 10px; +} + +form .aligned div.radiolist { + display: inline-block; + margin: 0; + padding: 0; +} + +form .aligned p.help, +form .aligned div.help { + margin-top: 0; + margin-left: 160px; + padding-left: 10px; +} + +form .aligned p.date div.help.timezonewarning, +form .aligned p.datetime div.help.timezonewarning, +form .aligned p.time div.help.timezonewarning { + margin-left: 0; + padding-left: 0; + font-weight: normal; +} + +form .aligned p.help:last-child, +form .aligned div.help:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +form .aligned input + p.help, +form .aligned textarea + p.help, +form .aligned select + p.help, +form .aligned input + div.help, +form .aligned textarea + div.help, +form .aligned select + div.help { + margin-left: 160px; + padding-left: 10px; +} + +form .aligned ul li { + list-style: none; +} + +form .aligned table p { + margin-left: 0; + padding-left: 0; +} + +.aligned .vCheckboxLabel { + float: none; + width: auto; + display: inline-block; + vertical-align: -3px; + padding: 0 0 5px 5px; +} + +.aligned .vCheckboxLabel + p.help, +.aligned .vCheckboxLabel + div.help { + margin-top: -4px; +} + +.colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField { + width: 610px; +} + +fieldset .fieldBox { + margin-right: 20px; +} + +/* WIDE FIELDSETS */ + +.wide label { + width: 200px; +} + +form .wide p, +form .wide ul.errorlist, +form .wide input + p.help, +form .wide input + div.help { + margin-left: 200px; +} + +form .wide p.help, +form .wide div.help { + padding-left: 50px; +} + +form div.help ul { + padding-left: 0; + margin-left: 0; +} + +.colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField { + width: 450px; +} + +/* COLLAPSED FIELDSETS */ + +fieldset.collapsed * { + display: none; +} + +fieldset.collapsed h2, fieldset.collapsed { + display: block; +} + +fieldset.collapsed { + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; +} + +fieldset.collapsed h2 { + background: var(--darkened-bg); + color: var(--body-quiet-color); +} + +fieldset .collapse-toggle { + color: var(--header-link-color); +} + +fieldset.collapsed .collapse-toggle { + background: transparent; + display: inline; + color: var(--link-fg); +} + +/* MONOSPACE TEXTAREAS */ + +fieldset.monospace textarea { + font-family: var(--font-family-monospace); +} + +/* SUBMIT ROW */ + +.submit-row { + padding: 12px 14px 12px; + margin: 0 0 20px; + background: var(--darkened-bg); + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +body.popup .submit-row { + overflow: auto; +} + +.submit-row input { + height: 2.1875rem; + line-height: 0.9375rem; +} + +.submit-row input, .submit-row a { + margin: 0; +} + +.submit-row input.default { + text-transform: uppercase; +} + +.submit-row a.deletelink { + margin-left: auto; +} + +.submit-row a.deletelink { + display: block; + background: var(--delete-button-bg); + border-radius: 4px; + padding: 0.625rem 0.9375rem; + height: 0.9375rem; + line-height: 0.9375rem; + color: var(--button-fg); +} + +.submit-row a.closelink { + display: inline-block; + background: var(--close-button-bg); + border-radius: 4px; + padding: 10px 15px; + height: 0.9375rem; + line-height: 0.9375rem; + color: var(--button-fg); +} + +.submit-row a.deletelink:focus, +.submit-row a.deletelink:hover, +.submit-row a.deletelink:active { + background: var(--delete-button-hover-bg); + text-decoration: none; +} + +.submit-row a.closelink:focus, +.submit-row a.closelink:hover, +.submit-row a.closelink:active { + background: var(--close-button-hover-bg); + text-decoration: none; +} + +/* CUSTOM FORM FIELDS */ + +.vSelectMultipleField { + vertical-align: top; +} + +.vCheckboxField { + border: none; +} + +.vDateField, .vTimeField { + margin-right: 2px; + margin-bottom: 4px; +} + +.vDateField { + min-width: 6.85em; +} + +.vTimeField { + min-width: 4.7em; +} + +.vURLField { + width: 30em; +} + +.vLargeTextField, .vXMLLargeTextField { + width: 48em; +} + +.flatpages-flatpage #id_content { + height: 40.2em; +} + +.module table .vPositiveSmallIntegerField { + width: 2.2em; +} + +.vIntegerField { + width: 5em; +} + +.vBigIntegerField { + width: 10em; +} + +.vForeignKeyRawIdAdminField { + width: 5em; +} + +.vTextField, .vUUIDField { + width: 20em; +} + +/* INLINES */ + +.inline-group { + padding: 0; + margin: 0 0 30px; +} + +.inline-group thead th { + padding: 8px 10px; +} + +.inline-group .aligned label { + width: 160px; +} + +.inline-related { + position: relative; +} + +.inline-related h3 { + margin: 0; + color: var(--body-quiet-color); + padding: 5px; + font-size: 0.8125rem; + background: var(--darkened-bg); + border-top: 1px solid var(--hairline-color); + border-bottom: 1px solid var(--hairline-color); +} + +.inline-related h3 span.delete { + float: right; +} + +.inline-related h3 span.delete label { + margin-left: 2px; + font-size: 0.6875rem; +} + +.inline-related fieldset { + margin: 0; + background: var(--body-bg); + border: none; + width: 100%; +} + +.inline-related fieldset.module h3 { + margin: 0; + padding: 2px 5px 3px 5px; + font-size: 0.6875rem; + text-align: left; + font-weight: bold; + background: #bcd; + color: var(--body-bg); +} + +.inline-group .tabular fieldset.module { + border: none; +} + +.inline-related.tabular fieldset.module table { + width: 100%; + overflow-x: scroll; +} + +.last-related fieldset { + border: none; +} + +.inline-group .tabular tr.has_original td { + padding-top: 2em; +} + +.inline-group .tabular tr td.original { + padding: 2px 0 0 0; + width: 0; + _position: relative; +} + +.inline-group .tabular th.original { + width: 0px; + padding: 0; +} + +.inline-group .tabular td.original p { + position: absolute; + left: 0; + height: 1.1em; + padding: 2px 9px; + overflow: hidden; + font-size: 0.5625rem; + font-weight: bold; + color: var(--body-quiet-color); + _width: 700px; +} + +.inline-group ul.tools { + padding: 0; + margin: 0; + list-style: none; +} + +.inline-group ul.tools li { + display: inline; + padding: 0 5px; +} + +.inline-group div.add-row, +.inline-group .tabular tr.add-row td { + color: var(--body-quiet-color); + background: var(--darkened-bg); + padding: 8px 10px; + border-bottom: 1px solid var(--hairline-color); +} + +.inline-group .tabular tr.add-row td { + padding: 8px 10px; + border-bottom: 1px solid var(--hairline-color); +} + +.inline-group ul.tools a.add, +.inline-group div.add-row a, +.inline-group .tabular tr.add-row td a { + background: url(../img/icon-addlink.svg) 0 1px no-repeat; + padding-left: 16px; + font-size: 0.75rem; +} + +.empty-form { + display: none; +} + +/* RELATED FIELD ADD ONE / LOOKUP */ + +.related-lookup { + margin-left: 5px; + display: inline-block; + vertical-align: middle; + background-repeat: no-repeat; + background-size: 14px; +} + +.related-lookup { + width: 1rem; + height: 1rem; + background-image: url(../img/search.svg); +} + +form .related-widget-wrapper ul { + display: inline-block; + margin-left: 0; + padding-left: 0; +} + +.clearable-file-input input { + margin-top: 0; +} diff --git a/staticfiles/admin/css/forms.css.gz b/staticfiles/admin/css/forms.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..da29e8697aa4c4b7478bf270c2b89055681402aa GIT binary patch literal 2207 zcmV;Q2w?XgiwFP!00002|Fs%xZ`-!^dwzwm;i63&DYg?QnT-u|8u!AO6Bn_A4Y(Kz zTB2nkw5UmxlPu_ezlV}YkrHV;8``37Or3Lh-Y@0XXp_*CIeALnzk7;;5VOqlv+UjR z@aX9DgY$WIf9u@OexExZPLGbf6-_s8N}rt9BM1J_ElyX2J`J386a+XP7N-dcf+!9L zPPdahmq#laGdGL=#sjD0U3Gi?6mQBWOPU5ab(fSex&f5r*~uu00%wcT_pZA}QA(m1 zyFMi}1*X2KTtu7j#8JM+NzN+PfHM~Ph`5MEVLWg)z#zd5e1evklxY8BFA4tn2Y-$I z$0dFK;m?ZB2Bl#XyNo8l`p`(aQ&8nZ6<(4Gzfy)v@QMjgZ$EL zF9U}^RT$mmghgBj6e)^ z1LHB!N2HX$FvXxU(2@o(?q7L?nKY5z;GEMG19XamQu!z4fAy*1?jXzQ9aW;r4d+%*ORXJeF&yELZ#bk`~n8h)mzk4^_j)glqE-dO>ZhjaY%*Z! z?H?_MWZo^#Dl`k*bBiTQMAArS`zFe zZ!x=;TlBQAmp)5wdSd}_&l>U%czJXBkdphA2CVGV#@hk1Bc$DPaRX0#d-LKO(&9yJ zKK?Mn4DvMp>6$+4j8yGHPw78@pWKX_%>vNHrmm^i(fy==ldf2NgXRUNDNVV%Xb;R0 zq&?c@y5_6fv>G&Yhttc41eN8(n3bA-EG;OMU0!T6V-sqREzkRkZ9dJW)6tiCtDBQF z;Rb?|44mXcvtZRR+6G?tP8`Frxhpi2cvVKn17=2L&g3OF&x!_fXc=K`T#H+g{}`q; zj{`A?1SoyP5G(F7JU(nf(t<_Y0f8EZ1j|lSA+d&T4wwg_9!)e9HZ9atrdf*OEP;$3 zv!T5!)9x=WRz|Jc+1+gZW%Oz6EXIE*}Elb}O`r$crGZ9Jvxt zUNwKXzMU-i3Zl#oS-#vvOxZ!y+Xg-tb&JWNC#);mB>3Bt<>wF+ekbQL4Ep>iN}1CVAqtl~7+)cg+fr+AfRHqvv(6F6%vvHXL=lpUy7pxui+yMB@N8=F^TD z$qVobQXE zYq2m*t37OO2D+Wje|Fv{0^H^g($>9lFW{Vs{eWFOnfa?MU9ajbFH%(Teq8$2*DK5L z*c2_0oN|KFmQ1!PpsT`)Ugo^lwmP+q^Yg&T{1nEVl6J9Yvl!LNNka~ndTW$@rQnBA zjEKX6#!OyBO0VHbEh2#DNgA(hYj*0_8I^d|x37D0Nb{z3^BO^}-Ing8qp+K_vKd-J zi07P%;|-yXh{Jyn$&T|((&ZrpCl;_?q)X4aaiL>@Gy zS0GARyRxS@vL}*%Yl`j~+8j69KzFSfCBrE7*M&Kht*yAK{56+izmnjzUcl~s-FCq1 h1fRgwyo|Z42tLZii{Wjhc+d9j=>PKE#{+^R008OLMce=Y literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/login.586129c60a93.css b/staticfiles/admin/css/login.586129c60a93.css new file mode 100644 index 0000000000..389772f5bc --- /dev/null +++ b/staticfiles/admin/css/login.586129c60a93.css @@ -0,0 +1,61 @@ +/* LOGIN FORM */ + +.login { + background: var(--darkened-bg); + height: auto; +} + +.login #header { + height: auto; + padding: 15px 16px; + justify-content: center; +} + +.login #header h1 { + font-size: 1.125rem; + margin: 0; +} + +.login #header h1 a { + color: var(--header-link-color); +} + +.login #content { + padding: 20px 20px 0; +} + +.login #container { + background: var(--body-bg); + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; + width: 28em; + min-width: 300px; + margin: 100px auto; + height: auto; +} + +.login .form-row { + padding: 4px 0; +} + +.login .form-row label { + display: block; + line-height: 2em; +} + +.login .form-row #id_username, .login .form-row #id_password { + padding: 8px; + width: 100%; + box-sizing: border-box; +} + +.login .submit-row { + padding: 1em 0 0 0; + margin: 0; + text-align: center; +} + +.login .password-reset-link { + text-align: center; +} diff --git a/staticfiles/admin/css/login.586129c60a93.css.gz b/staticfiles/admin/css/login.586129c60a93.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..ca9d533055da1635cd52842a4569b1046aabcdb5 GIT binary patch literal 417 zcmV;S0bc$eiwFP!00002|8-K)O2aS|ecx9EM9^Wjc5WiwyCSFqe?ZdauDvczN|L%w z@!w6`q;p$sA&{GMPtG~H(=mBoJwCmXht=B)8Ba%}iBLI8@;xH%OIfzbwW=jg$S2cR zlyaswAc4~~zh1VO0x&OZLRf9pa`e+PTok}KXwP(vYAO}u9A%!6cv0<0d{^zd`bTXn zuJ<%k(t>m?nOi{*Q5UgiUpp){_yvw_63-SI%8smL+BGC3`lp?Ff=mgegU9Ze3X~h# z9$X)Fdttt_w=s*HjdqF7;0$G-#CfKv;`>9MsnYItXT&iXC6EVI47HO4y`%$}YR0iP z37Llw)hFn+P}_tQ$T`Tax@j8ofg-7s%gh16r~YZph$q#f;gyluotX2e;n8 zGkX~_-8Hk+qI|xtbR@vkX^D2oattMjn*VJ6nyrPMrA%NhhsJsmv{DTQY&(FSf4K1% L;-h8;z5@UNH15V| literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/login.css b/staticfiles/admin/css/login.css new file mode 100644 index 0000000000..389772f5bc --- /dev/null +++ b/staticfiles/admin/css/login.css @@ -0,0 +1,61 @@ +/* LOGIN FORM */ + +.login { + background: var(--darkened-bg); + height: auto; +} + +.login #header { + height: auto; + padding: 15px 16px; + justify-content: center; +} + +.login #header h1 { + font-size: 1.125rem; + margin: 0; +} + +.login #header h1 a { + color: var(--header-link-color); +} + +.login #content { + padding: 20px 20px 0; +} + +.login #container { + background: var(--body-bg); + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; + width: 28em; + min-width: 300px; + margin: 100px auto; + height: auto; +} + +.login .form-row { + padding: 4px 0; +} + +.login .form-row label { + display: block; + line-height: 2em; +} + +.login .form-row #id_username, .login .form-row #id_password { + padding: 8px; + width: 100%; + box-sizing: border-box; +} + +.login .submit-row { + padding: 1em 0 0 0; + margin: 0; + text-align: center; +} + +.login .password-reset-link { + text-align: center; +} diff --git a/staticfiles/admin/css/login.css.gz b/staticfiles/admin/css/login.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..ca9d533055da1635cd52842a4569b1046aabcdb5 GIT binary patch literal 417 zcmV;S0bc$eiwFP!00002|8-K)O2aS|ecx9EM9^Wjc5WiwyCSFqe?ZdauDvczN|L%w z@!w6`q;p$sA&{GMPtG~H(=mBoJwCmXht=B)8Ba%}iBLI8@;xH%OIfzbwW=jg$S2cR zlyaswAc4~~zh1VO0x&OZLRf9pa`e+PTok}KXwP(vYAO}u9A%!6cv0<0d{^zd`bTXn zuJ<%k(t>m?nOi{*Q5UgiUpp){_yvw_63-SI%8smL+BGC3`lp?Ff=mgegU9Ze3X~h# z9$X)Fdttt_w=s*HjdqF7;0$G-#CfKv;`>9MsnYItXT&iXC6EVI47HO4y`%$}YR0iP z37Llw)hFn+P}_tQ$T`Tax@j8ofg-7s%gh16r~YZph$q#f;gyluotX2e;n8 zGkX~_-8Hk+qI|xtbR@vkX^D2oattMjn*VJ6nyrPMrA%NhhsJsmv{DTQY&(FSf4K1% L;-h8;z5@UNH15V| literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/nav_sidebar.269a1bd44627.css b/staticfiles/admin/css/nav_sidebar.269a1bd44627.css new file mode 100644 index 0000000000..f76e6ce485 --- /dev/null +++ b/staticfiles/admin/css/nav_sidebar.269a1bd44627.css @@ -0,0 +1,144 @@ +.sticky { + position: sticky; + top: 0; + max-height: 100vh; +} + +.toggle-nav-sidebar { + z-index: 20; + left: 0; + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 23px; + width: 23px; + border: 0; + border-right: 1px solid var(--hairline-color); + background-color: var(--body-bg); + cursor: pointer; + font-size: 1.25rem; + color: var(--link-fg); + padding: 0; +} + +[dir="rtl"] .toggle-nav-sidebar { + border-left: 1px solid var(--hairline-color); + border-right: 0; +} + +.toggle-nav-sidebar:hover, +.toggle-nav-sidebar:focus { + background-color: var(--darkened-bg); +} + +#nav-sidebar { + z-index: 15; + flex: 0 0 275px; + left: -276px; + margin-left: -276px; + border-top: 1px solid transparent; + border-right: 1px solid var(--hairline-color); + background-color: var(--body-bg); + overflow: auto; +} + +[dir="rtl"] #nav-sidebar { + border-left: 1px solid var(--hairline-color); + border-right: 0; + left: 0; + margin-left: 0; + right: -276px; + margin-right: -276px; +} + +.toggle-nav-sidebar::before { + content: '\00BB'; +} + +.main.shifted .toggle-nav-sidebar::before { + content: '\00AB'; +} + +.main > #nav-sidebar { + visibility: hidden; +} + +.main.shifted > #nav-sidebar { + margin-left: 0; + visibility: visible; +} + +[dir="rtl"] .main.shifted > #nav-sidebar { + margin-right: 0; +} + +#nav-sidebar .module th { + width: 100%; + overflow-wrap: anywhere; +} + +#nav-sidebar .module th, +#nav-sidebar .module caption { + padding-left: 16px; +} + +#nav-sidebar .module td { + white-space: nowrap; +} + +[dir="rtl"] #nav-sidebar .module th, +[dir="rtl"] #nav-sidebar .module caption { + padding-left: 8px; + padding-right: 16px; +} + +#nav-sidebar .current-app .section:link, +#nav-sidebar .current-app .section:visited { + color: var(--header-color); + font-weight: bold; +} + +#nav-sidebar .current-model { + background: var(--selected-row); +} + +.main > #nav-sidebar + .content { + max-width: calc(100% - 23px); +} + +.main.shifted > #nav-sidebar + .content { + max-width: calc(100% - 299px); +} + +@media (max-width: 767px) { + #nav-sidebar, #toggle-nav-sidebar { + display: none; + } + + .main > #nav-sidebar + .content, + .main.shifted > #nav-sidebar + .content { + max-width: 100%; + } +} + +#nav-filter { + width: 100%; + box-sizing: border-box; + padding: 2px 5px; + margin: 5px 0; + border: 1px solid var(--border-color); + background-color: var(--darkened-bg); + color: var(--body-fg); +} + +#nav-filter:focus { + border-color: var(--body-quiet-color); +} + +#nav-filter.no-results { + background: var(--message-error-bg); +} + +#nav-sidebar table { + width: 100%; +} diff --git a/staticfiles/admin/css/nav_sidebar.269a1bd44627.css.gz b/staticfiles/admin/css/nav_sidebar.269a1bd44627.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..7398c4df9feb1b5f31ae72b632bf2debd3f25dd7 GIT binary patch literal 779 zcmV+m1N8hKiwFP!00002|Fu@zQrj>Pea}~D%5;Ef?3Jwu79`TV1#bFel9%HPH>ln9YLfG2Xl1Z{7a2brq~m! zrQl@C%oU{>6GjRJ=uc{M?VqrClNwzr-iSkQ9BF=_QR=PY(%4E@Xwiuf!^YY?0=f#8 zD+9SV?&6@s4NY2{f^jZXS_h0p{>g>;`oTE);WwEsxX-F7^La`2>adt-qZs8ywCO5iV-?oyRnN%n`RQTNL34SStGfdfn z862Q@9)+r8iPXE0u+r&48!z6ae}gsamB-7x`A8LCX(py2j3ChleALIKy!^FTJUm=B z&vGVIU^9_8;N(9+esn>|x3N-fg%y#I!XbfVf^$$KZbx5^6{L$+f0i&@yR)Ht+tf1) za?MK##AW`4=P6{C=#u zGho$zbyuz?^PN9~k(T^KJeVoS0XMeb79>W1tZ4M^dV1hLAzrf`$1&SeKR7Xy@l`cF zgx1II`t2<^8}9C|#rvKE7mQqWEZ4Vd)Ov(2{+wJ)-lyK#S6V?+QS?y#c_aDxi_zJs zy-M$8&7O}vON7KbJ++RJ-dBgazQmquQS|CWFOjKNeIgAjLI2CfkkLKhIhUn>KnG)5 zAD*OpTbs1{$GPLK_wa8iz#YTrBLqrQ1GbdTPR?--*0K~R7^BVjiFXVsb*#wGvwzZY Jd|`$P005G@hg1Ln literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/nav_sidebar.css b/staticfiles/admin/css/nav_sidebar.css new file mode 100644 index 0000000000..f76e6ce485 --- /dev/null +++ b/staticfiles/admin/css/nav_sidebar.css @@ -0,0 +1,144 @@ +.sticky { + position: sticky; + top: 0; + max-height: 100vh; +} + +.toggle-nav-sidebar { + z-index: 20; + left: 0; + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 23px; + width: 23px; + border: 0; + border-right: 1px solid var(--hairline-color); + background-color: var(--body-bg); + cursor: pointer; + font-size: 1.25rem; + color: var(--link-fg); + padding: 0; +} + +[dir="rtl"] .toggle-nav-sidebar { + border-left: 1px solid var(--hairline-color); + border-right: 0; +} + +.toggle-nav-sidebar:hover, +.toggle-nav-sidebar:focus { + background-color: var(--darkened-bg); +} + +#nav-sidebar { + z-index: 15; + flex: 0 0 275px; + left: -276px; + margin-left: -276px; + border-top: 1px solid transparent; + border-right: 1px solid var(--hairline-color); + background-color: var(--body-bg); + overflow: auto; +} + +[dir="rtl"] #nav-sidebar { + border-left: 1px solid var(--hairline-color); + border-right: 0; + left: 0; + margin-left: 0; + right: -276px; + margin-right: -276px; +} + +.toggle-nav-sidebar::before { + content: '\00BB'; +} + +.main.shifted .toggle-nav-sidebar::before { + content: '\00AB'; +} + +.main > #nav-sidebar { + visibility: hidden; +} + +.main.shifted > #nav-sidebar { + margin-left: 0; + visibility: visible; +} + +[dir="rtl"] .main.shifted > #nav-sidebar { + margin-right: 0; +} + +#nav-sidebar .module th { + width: 100%; + overflow-wrap: anywhere; +} + +#nav-sidebar .module th, +#nav-sidebar .module caption { + padding-left: 16px; +} + +#nav-sidebar .module td { + white-space: nowrap; +} + +[dir="rtl"] #nav-sidebar .module th, +[dir="rtl"] #nav-sidebar .module caption { + padding-left: 8px; + padding-right: 16px; +} + +#nav-sidebar .current-app .section:link, +#nav-sidebar .current-app .section:visited { + color: var(--header-color); + font-weight: bold; +} + +#nav-sidebar .current-model { + background: var(--selected-row); +} + +.main > #nav-sidebar + .content { + max-width: calc(100% - 23px); +} + +.main.shifted > #nav-sidebar + .content { + max-width: calc(100% - 299px); +} + +@media (max-width: 767px) { + #nav-sidebar, #toggle-nav-sidebar { + display: none; + } + + .main > #nav-sidebar + .content, + .main.shifted > #nav-sidebar + .content { + max-width: 100%; + } +} + +#nav-filter { + width: 100%; + box-sizing: border-box; + padding: 2px 5px; + margin: 5px 0; + border: 1px solid var(--border-color); + background-color: var(--darkened-bg); + color: var(--body-fg); +} + +#nav-filter:focus { + border-color: var(--body-quiet-color); +} + +#nav-filter.no-results { + background: var(--message-error-bg); +} + +#nav-sidebar table { + width: 100%; +} diff --git a/staticfiles/admin/css/nav_sidebar.css.gz b/staticfiles/admin/css/nav_sidebar.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..7398c4df9feb1b5f31ae72b632bf2debd3f25dd7 GIT binary patch literal 779 zcmV+m1N8hKiwFP!00002|Fu@zQrj>Pea}~D%5;Ef?3Jwu79`TV1#bFel9%HPH>ln9YLfG2Xl1Z{7a2brq~m! zrQl@C%oU{>6GjRJ=uc{M?VqrClNwzr-iSkQ9BF=_QR=PY(%4E@Xwiuf!^YY?0=f#8 zD+9SV?&6@s4NY2{f^jZXS_h0p{>g>;`oTE);WwEsxX-F7^La`2>adt-qZs8ywCO5iV-?oyRnN%n`RQTNL34SStGfdfn z862Q@9)+r8iPXE0u+r&48!z6ae}gsamB-7x`A8LCX(py2j3ChleALIKy!^FTJUm=B z&vGVIU^9_8;N(9+esn>|x3N-fg%y#I!XbfVf^$$KZbx5^6{L$+f0i&@yR)Ht+tf1) za?MK##AW`4=P6{C=#u zGho$zbyuz?^PN9~k(T^KJeVoS0XMeb79>W1tZ4M^dV1hLAzrf`$1&SeKR7Xy@l`cF zgx1II`t2<^8}9C|#rvKE7mQqWEZ4Vd)Ov(2{+wJ)-lyK#S6V?+QS?y#c_aDxi_zJs zy-M$8&7O}vON7KbJ++RJ-dBgazQmquQS|CWFOjKNeIgAjLI2CfkkLKhIhUn>KnG)5 zAD*OpTbs1{$GPLK_wa8iz#YTrBLqrQ1GbdTPR?--*0K~R7^BVjiFXVsb*#wGvwzZY Jd|`$P005G@hg1Ln literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/responsive.css b/staticfiles/admin/css/responsive.css new file mode 100644 index 0000000000..1d0a188f2c --- /dev/null +++ b/staticfiles/admin/css/responsive.css @@ -0,0 +1,999 @@ +/* Tablets */ + +input[type="submit"], button { + -webkit-appearance: none; + appearance: none; +} + +@media (max-width: 1024px) { + /* Basic */ + + html { + -webkit-text-size-adjust: 100%; + } + + td, th { + padding: 10px; + font-size: 0.875rem; + } + + .small { + font-size: 0.75rem; + } + + /* Layout */ + + #container { + min-width: 0; + } + + #content { + padding: 15px 20px 20px; + } + + div.breadcrumbs { + padding: 10px 30px; + } + + /* Header */ + + #header { + flex-direction: column; + padding: 15px 30px; + justify-content: flex-start; + } + + #branding h1 { + margin: 0 0 8px; + line-height: 1.2; + } + + #user-tools { + margin: 0; + font-weight: 400; + line-height: 1.85; + text-align: left; + } + + #user-tools a { + display: inline-block; + line-height: 1.4; + } + + /* Dashboard */ + + .dashboard #content { + width: auto; + } + + #content-related { + margin-right: -290px; + } + + .colSM #content-related { + margin-left: -290px; + } + + .colMS { + margin-right: 290px; + } + + .colSM { + margin-left: 290px; + } + + .dashboard .module table td a { + padding-right: 0; + } + + td .changelink, td .addlink { + font-size: 0.8125rem; + } + + /* Changelist */ + + #toolbar { + border: none; + padding: 15px; + } + + #changelist-search > div { + display: flex; + flex-wrap: nowrap; + max-width: 480px; + } + + #changelist-search label { + line-height: 1.375rem; + } + + #toolbar form #searchbar { + flex: 1 0 auto; + width: 0; + height: 1.375rem; + margin: 0 10px 0 6px; + } + + #toolbar form input[type=submit] { + flex: 0 1 auto; + } + + #changelist-search .quiet { + width: 0; + flex: 1 0 auto; + margin: 5px 0 0 25px; + } + + #changelist .actions { + display: flex; + flex-wrap: wrap; + padding: 15px 0; + } + + #changelist .actions label { + display: flex; + } + + #changelist .actions select { + background: var(--body-bg); + } + + #changelist .actions .button { + min-width: 48px; + margin: 0 10px; + } + + #changelist .actions span.all, + #changelist .actions span.clear, + #changelist .actions span.question, + #changelist .actions span.action-counter { + font-size: 0.6875rem; + margin: 0 10px 0 0; + } + + #changelist-filter { + flex-basis: 200px; + } + + .change-list .filtered .results, + .change-list .filtered .paginator, + .filtered #toolbar, + .filtered .actions, + + #changelist .paginator { + border-top-color: var(--hairline-color); /* XXX Is this used at all? */ + } + + #changelist .results + .paginator { + border-top: none; + } + + /* Forms */ + + label { + font-size: 0.875rem; + } + + .form-row input[type=text], + .form-row input[type=password], + .form-row input[type=email], + .form-row input[type=url], + .form-row input[type=tel], + .form-row input[type=number], + .form-row textarea, + .form-row select, + .form-row .vTextField { + box-sizing: border-box; + margin: 0; + padding: 6px 8px; + min-height: 2.25rem; + font-size: 0.875rem; + } + + .form-row select { + height: 2.25rem; + } + + .form-row select[multiple] { + height: auto; + min-height: 0; + } + + fieldset .fieldBox + .fieldBox { + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid var(--hairline-color); + } + + textarea { + max-width: 100%; + max-height: 120px; + } + + .aligned label { + padding-top: 6px; + } + + .aligned .related-lookup, + .aligned .datetimeshortcuts, + .aligned .related-lookup + strong { + align-self: center; + margin-left: 15px; + } + + form .aligned div.radiolist { + margin-left: 2px; + } + + .submit-row { + padding: 8px; + } + + .submit-row a.deletelink { + padding: 10px 7px; + } + + .button, input[type=submit], input[type=button], .submit-row input, a.button { + padding: 7px; + } + + /* Related widget */ + + .related-widget-wrapper { + float: none; + } + + .related-widget-wrapper-link + .selector { + max-width: calc(100% - 30px); + margin-right: 15px; + } + + select + .related-widget-wrapper-link, + .related-widget-wrapper-link + .related-widget-wrapper-link { + margin-left: 10px; + } + + /* Selector */ + + .selector { + display: flex; + width: 100%; + } + + .selector .selector-filter { + display: flex; + align-items: center; + } + + .selector .selector-filter label { + margin: 0 8px 0 0; + } + + .selector .selector-filter input { + width: auto; + min-height: 0; + flex: 1 1; + } + + .selector-available, .selector-chosen { + width: auto; + flex: 1 1; + display: flex; + flex-direction: column; + } + + .selector select { + width: 100%; + flex: 1 0 auto; + margin-bottom: 5px; + } + + .selector ul.selector-chooser { + width: 26px; + height: 52px; + padding: 2px 0; + margin: auto 15px; + border-radius: 20px; + transform: translateY(-10px); + } + + .selector-add, .selector-remove { + width: 20px; + height: 20px; + background-size: 20px auto; + } + + .selector-add { + background-position: 0 -120px; + } + + .selector-remove { + background-position: 0 -80px; + } + + a.selector-chooseall, a.selector-clearall { + align-self: center; + } + + .stacked { + flex-direction: column; + max-width: 480px; + } + + .stacked > * { + flex: 0 1 auto; + } + + .stacked select { + margin-bottom: 0; + } + + .stacked .selector-available, .stacked .selector-chosen { + width: auto; + } + + .stacked ul.selector-chooser { + width: 52px; + height: 26px; + padding: 0 2px; + margin: 15px auto; + transform: none; + } + + .stacked .selector-chooser li { + padding: 3px; + } + + .stacked .selector-add, .stacked .selector-remove { + background-size: 20px auto; + } + + .stacked .selector-add { + background-position: 0 -40px; + } + + .stacked .active.selector-add { + background-position: 0 -40px; + } + + .active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -140px; + } + + .stacked .active.selector-add:focus, .stacked .active.selector-add:hover { + background-position: 0 -60px; + } + + .stacked .selector-remove { + background-position: 0 0; + } + + .stacked .active.selector-remove { + background-position: 0 0; + } + + .active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -100px; + } + + .stacked .active.selector-remove:focus, .stacked .active.selector-remove:hover { + background-position: 0 -20px; + } + + .help-tooltip, .selector .help-icon { + display: none; + } + + .datetime input { + width: 50%; + max-width: 120px; + } + + .datetime span { + font-size: 0.8125rem; + } + + .datetime .timezonewarning { + display: block; + font-size: 0.6875rem; + color: var(--body-quiet-color); + } + + .datetimeshortcuts { + color: var(--border-color); /* XXX Redundant, .datetime span also sets #ccc */ + } + + .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField { + width: 75%; + } + + .inline-group { + overflow: auto; + } + + /* Messages */ + + ul.messagelist li { + padding-left: 55px; + background-position: 30px 12px; + } + + ul.messagelist li.error { + background-position: 30px 12px; + } + + ul.messagelist li.warning { + background-position: 30px 14px; + } + + /* Login */ + + .login #header { + padding: 15px 20px; + } + + .login #branding h1 { + margin: 0; + } + + /* GIS */ + + div.olMap { + max-width: calc(100vw - 30px); + max-height: 300px; + } + + .olMap + .clear_features { + display: block; + margin-top: 10px; + } + + /* Docs */ + + .module table.xfull { + width: 100%; + } + + pre.literal-block { + overflow: auto; + } +} + +/* Mobile */ + +@media (max-width: 767px) { + /* Layout */ + + #header, #content, #footer { + padding: 15px; + } + + #footer:empty { + padding: 0; + } + + div.breadcrumbs { + padding: 10px 15px; + } + + /* Dashboard */ + + .colMS, .colSM { + margin: 0; + } + + #content-related, .colSM #content-related { + width: 100%; + margin: 0; + } + + #content-related .module { + margin-bottom: 0; + } + + #content-related .module h2 { + padding: 10px 15px; + font-size: 1rem; + } + + /* Changelist */ + + #changelist { + align-items: stretch; + flex-direction: column; + } + + #toolbar { + padding: 10px; + } + + #changelist-filter { + margin-left: 0; + } + + #changelist .actions label { + flex: 1 1; + } + + #changelist .actions select { + flex: 1 0; + width: 100%; + } + + #changelist .actions span { + flex: 1 0 100%; + } + + #changelist-filter { + position: static; + width: auto; + margin-top: 30px; + } + + .object-tools { + float: none; + margin: 0 0 15px; + padding: 0; + overflow: hidden; + } + + .object-tools li { + height: auto; + margin-left: 0; + } + + .object-tools li + li { + margin-left: 15px; + } + + /* Forms */ + + .form-row { + padding: 15px 0; + } + + .aligned .form-row, + .aligned .form-row > div { + max-width: 100vw; + } + + .aligned .form-row > div { + width: calc(100vw - 30px); + } + + .flex-container { + flex-flow: column; + } + + .flex-container.checkbox-row { + flex-flow: row; + } + + textarea { + max-width: none; + } + + .vURLField { + width: auto; + } + + fieldset .fieldBox + .fieldBox { + margin-top: 15px; + padding-top: 15px; + } + + fieldset.collapsed .form-row { + display: none; + } + + .aligned label { + width: 100%; + min-width: auto; + padding: 0 0 10px; + } + + .aligned label:after { + max-height: 0; + } + + .aligned .form-row input, + .aligned .form-row select, + .aligned .form-row textarea { + flex: 1 1 auto; + max-width: 100%; + } + + .aligned .checkbox-row input { + flex: 0 1 auto; + margin: 0; + } + + .aligned .vCheckboxLabel { + flex: 1 0; + padding: 1px 0 0 5px; + } + + .aligned label + p, + .aligned label + div.help, + .aligned label + div.readonly { + padding: 0; + margin-left: 0; + } + + .aligned p.file-upload { + font-size: 0.8125rem; + } + + span.clearable-file-input { + margin-left: 15px; + } + + span.clearable-file-input label { + font-size: 0.8125rem; + padding-bottom: 0; + } + + .aligned .timezonewarning { + flex: 1 0 100%; + margin-top: 5px; + } + + form .aligned .form-row div.help { + width: 100%; + margin: 5px 0 0; + padding: 0; + } + + form .aligned ul, + form .aligned ul.errorlist { + margin-left: 0; + padding-left: 0; + } + + form .aligned div.radiolist { + margin-top: 5px; + margin-right: 15px; + margin-bottom: -3px; + } + + form .aligned div.radiolist:not(.inline) div + div { + margin-top: 5px; + } + + /* Related widget */ + + .related-widget-wrapper { + width: 100%; + display: flex; + align-items: flex-start; + } + + .related-widget-wrapper .selector { + order: 1; + } + + .related-widget-wrapper > a { + order: 2; + } + + .related-widget-wrapper .radiolist ~ a { + align-self: flex-end; + } + + .related-widget-wrapper > select ~ a { + align-self: center; + } + + select + .related-widget-wrapper-link, + .related-widget-wrapper-link + .related-widget-wrapper-link { + margin-left: 15px; + } + + /* Selector */ + + .selector { + flex-direction: column; + } + + .selector > * { + float: none; + } + + .selector-available, .selector-chosen { + margin-bottom: 0; + flex: 1 1 auto; + } + + .selector select { + max-height: 96px; + } + + .selector ul.selector-chooser { + display: block; + float: none; + width: 52px; + height: 26px; + padding: 0 2px; + margin: 15px auto 20px; + transform: none; + } + + .selector ul.selector-chooser li { + float: left; + } + + .selector-remove { + background-position: 0 0; + } + + .active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -20px; + } + + .selector-add { + background-position: 0 -40px; + } + + .active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -60px; + } + + /* Inlines */ + + .inline-group[data-inline-type="stacked"] .inline-related { + border: 1px solid var(--hairline-color); + border-radius: 4px; + margin-top: 15px; + overflow: auto; + } + + .inline-group[data-inline-type="stacked"] .inline-related > * { + box-sizing: border-box; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module { + padding: 0 10px; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module .form-row { + border-top: 1px solid var(--hairline-color); + border-bottom: none; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module .form-row:first-child { + border-top: none; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 { + padding: 10px; + border-top-width: 0; + border-bottom-width: 2px; + display: flex; + flex-wrap: wrap; + align-items: center; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 .inline_label { + margin-right: auto; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 span.delete { + float: none; + flex: 1 1 100%; + margin-top: 5px; + } + + .inline-group[data-inline-type="stacked"] .aligned .form-row > div:not([class]) { + width: 100%; + } + + .inline-group[data-inline-type="stacked"] .aligned label { + width: 100%; + } + + .inline-group[data-inline-type="stacked"] div.add-row { + margin-top: 15px; + border: 1px solid var(--hairline-color); + border-radius: 4px; + } + + .inline-group div.add-row, + .inline-group .tabular tr.add-row td { + padding: 0; + } + + .inline-group div.add-row a, + .inline-group .tabular tr.add-row td a { + display: block; + padding: 8px 10px 8px 26px; + background-position: 8px 9px; + } + + /* Submit row */ + + .submit-row { + padding: 10px; + margin: 0 0 15px; + flex-direction: column; + gap: 8px; + } + + .submit-row input, .submit-row input.default, .submit-row a { + text-align: center; + } + + .submit-row a.closelink { + padding: 10px 0; + text-align: center; + } + + .submit-row a.deletelink { + margin: 0; + } + + /* Messages */ + + ul.messagelist li { + padding-left: 40px; + background-position: 15px 12px; + } + + ul.messagelist li.error { + background-position: 15px 12px; + } + + ul.messagelist li.warning { + background-position: 15px 14px; + } + + /* Paginator */ + + .paginator .this-page, .paginator a:link, .paginator a:visited { + padding: 4px 10px; + } + + /* Login */ + + body.login { + padding: 0 15px; + } + + .login #container { + width: auto; + max-width: 480px; + margin: 50px auto; + } + + .login #header, + .login #content { + padding: 15px; + } + + .login #content-main { + float: none; + } + + .login .form-row { + padding: 0; + } + + .login .form-row + .form-row { + margin-top: 15px; + } + + .login .form-row label { + margin: 0 0 5px; + line-height: 1.2; + } + + .login .submit-row { + padding: 15px 0 0; + } + + .login br { + display: none; + } + + .login .submit-row input { + margin: 0; + text-transform: uppercase; + } + + .errornote { + margin: 0 0 20px; + padding: 8px 12px; + font-size: 0.8125rem; + } + + /* Calendar and clock */ + + .calendarbox, .clockbox { + position: fixed !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%); + margin: 0; + border: none; + overflow: visible; + } + + .calendarbox:before, .clockbox:before { + content: ''; + position: fixed; + top: 50%; + left: 50%; + width: 100vw; + height: 100vh; + background: rgba(0, 0, 0, 0.75); + transform: translate(-50%, -50%); + } + + .calendarbox > *, .clockbox > * { + position: relative; + z-index: 1; + } + + .calendarbox > div:first-child { + z-index: 2; + } + + .calendarbox .calendar, .clockbox h2 { + border-radius: 4px 4px 0 0; + overflow: hidden; + } + + .calendarbox .calendar-cancel, .clockbox .calendar-cancel { + border-radius: 0 0 4px 4px; + overflow: hidden; + } + + .calendar-shortcuts { + padding: 10px 0; + font-size: 0.75rem; + line-height: 0.75rem; + } + + .calendar-shortcuts a { + margin: 0 4px; + } + + .timelist a { + background: var(--body-bg); + padding: 4px; + } + + .calendar-cancel { + padding: 8px 10px; + } + + .clockbox h2 { + padding: 8px 15px; + } + + .calendar caption { + padding: 10px; + } + + .calendarbox .calendarnav-previous, .calendarbox .calendarnav-next { + z-index: 1; + top: 10px; + } + + /* History */ + + table#change-history tbody th, table#change-history tbody td { + font-size: 0.8125rem; + word-break: break-word; + } + + table#change-history tbody th { + width: auto; + } + + /* Docs */ + + table.model tbody th, table.model tbody td { + font-size: 0.8125rem; + word-break: break-word; + } +} diff --git a/staticfiles/admin/css/responsive.css.gz b/staticfiles/admin/css/responsive.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..fe370fb18b5321f129c5dbce26cde31b8d41839e GIT binary patch literal 3441 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 TI{K|n@#W~hN@bgee@FlTgzmxv literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/responsive.f6533dab034d.css b/staticfiles/admin/css/responsive.f6533dab034d.css new file mode 100644 index 0000000000..1d0a188f2c --- /dev/null +++ b/staticfiles/admin/css/responsive.f6533dab034d.css @@ -0,0 +1,999 @@ +/* Tablets */ + +input[type="submit"], button { + -webkit-appearance: none; + appearance: none; +} + +@media (max-width: 1024px) { + /* Basic */ + + html { + -webkit-text-size-adjust: 100%; + } + + td, th { + padding: 10px; + font-size: 0.875rem; + } + + .small { + font-size: 0.75rem; + } + + /* Layout */ + + #container { + min-width: 0; + } + + #content { + padding: 15px 20px 20px; + } + + div.breadcrumbs { + padding: 10px 30px; + } + + /* Header */ + + #header { + flex-direction: column; + padding: 15px 30px; + justify-content: flex-start; + } + + #branding h1 { + margin: 0 0 8px; + line-height: 1.2; + } + + #user-tools { + margin: 0; + font-weight: 400; + line-height: 1.85; + text-align: left; + } + + #user-tools a { + display: inline-block; + line-height: 1.4; + } + + /* Dashboard */ + + .dashboard #content { + width: auto; + } + + #content-related { + margin-right: -290px; + } + + .colSM #content-related { + margin-left: -290px; + } + + .colMS { + margin-right: 290px; + } + + .colSM { + margin-left: 290px; + } + + .dashboard .module table td a { + padding-right: 0; + } + + td .changelink, td .addlink { + font-size: 0.8125rem; + } + + /* Changelist */ + + #toolbar { + border: none; + padding: 15px; + } + + #changelist-search > div { + display: flex; + flex-wrap: nowrap; + max-width: 480px; + } + + #changelist-search label { + line-height: 1.375rem; + } + + #toolbar form #searchbar { + flex: 1 0 auto; + width: 0; + height: 1.375rem; + margin: 0 10px 0 6px; + } + + #toolbar form input[type=submit] { + flex: 0 1 auto; + } + + #changelist-search .quiet { + width: 0; + flex: 1 0 auto; + margin: 5px 0 0 25px; + } + + #changelist .actions { + display: flex; + flex-wrap: wrap; + padding: 15px 0; + } + + #changelist .actions label { + display: flex; + } + + #changelist .actions select { + background: var(--body-bg); + } + + #changelist .actions .button { + min-width: 48px; + margin: 0 10px; + } + + #changelist .actions span.all, + #changelist .actions span.clear, + #changelist .actions span.question, + #changelist .actions span.action-counter { + font-size: 0.6875rem; + margin: 0 10px 0 0; + } + + #changelist-filter { + flex-basis: 200px; + } + + .change-list .filtered .results, + .change-list .filtered .paginator, + .filtered #toolbar, + .filtered .actions, + + #changelist .paginator { + border-top-color: var(--hairline-color); /* XXX Is this used at all? */ + } + + #changelist .results + .paginator { + border-top: none; + } + + /* Forms */ + + label { + font-size: 0.875rem; + } + + .form-row input[type=text], + .form-row input[type=password], + .form-row input[type=email], + .form-row input[type=url], + .form-row input[type=tel], + .form-row input[type=number], + .form-row textarea, + .form-row select, + .form-row .vTextField { + box-sizing: border-box; + margin: 0; + padding: 6px 8px; + min-height: 2.25rem; + font-size: 0.875rem; + } + + .form-row select { + height: 2.25rem; + } + + .form-row select[multiple] { + height: auto; + min-height: 0; + } + + fieldset .fieldBox + .fieldBox { + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid var(--hairline-color); + } + + textarea { + max-width: 100%; + max-height: 120px; + } + + .aligned label { + padding-top: 6px; + } + + .aligned .related-lookup, + .aligned .datetimeshortcuts, + .aligned .related-lookup + strong { + align-self: center; + margin-left: 15px; + } + + form .aligned div.radiolist { + margin-left: 2px; + } + + .submit-row { + padding: 8px; + } + + .submit-row a.deletelink { + padding: 10px 7px; + } + + .button, input[type=submit], input[type=button], .submit-row input, a.button { + padding: 7px; + } + + /* Related widget */ + + .related-widget-wrapper { + float: none; + } + + .related-widget-wrapper-link + .selector { + max-width: calc(100% - 30px); + margin-right: 15px; + } + + select + .related-widget-wrapper-link, + .related-widget-wrapper-link + .related-widget-wrapper-link { + margin-left: 10px; + } + + /* Selector */ + + .selector { + display: flex; + width: 100%; + } + + .selector .selector-filter { + display: flex; + align-items: center; + } + + .selector .selector-filter label { + margin: 0 8px 0 0; + } + + .selector .selector-filter input { + width: auto; + min-height: 0; + flex: 1 1; + } + + .selector-available, .selector-chosen { + width: auto; + flex: 1 1; + display: flex; + flex-direction: column; + } + + .selector select { + width: 100%; + flex: 1 0 auto; + margin-bottom: 5px; + } + + .selector ul.selector-chooser { + width: 26px; + height: 52px; + padding: 2px 0; + margin: auto 15px; + border-radius: 20px; + transform: translateY(-10px); + } + + .selector-add, .selector-remove { + width: 20px; + height: 20px; + background-size: 20px auto; + } + + .selector-add { + background-position: 0 -120px; + } + + .selector-remove { + background-position: 0 -80px; + } + + a.selector-chooseall, a.selector-clearall { + align-self: center; + } + + .stacked { + flex-direction: column; + max-width: 480px; + } + + .stacked > * { + flex: 0 1 auto; + } + + .stacked select { + margin-bottom: 0; + } + + .stacked .selector-available, .stacked .selector-chosen { + width: auto; + } + + .stacked ul.selector-chooser { + width: 52px; + height: 26px; + padding: 0 2px; + margin: 15px auto; + transform: none; + } + + .stacked .selector-chooser li { + padding: 3px; + } + + .stacked .selector-add, .stacked .selector-remove { + background-size: 20px auto; + } + + .stacked .selector-add { + background-position: 0 -40px; + } + + .stacked .active.selector-add { + background-position: 0 -40px; + } + + .active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -140px; + } + + .stacked .active.selector-add:focus, .stacked .active.selector-add:hover { + background-position: 0 -60px; + } + + .stacked .selector-remove { + background-position: 0 0; + } + + .stacked .active.selector-remove { + background-position: 0 0; + } + + .active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -100px; + } + + .stacked .active.selector-remove:focus, .stacked .active.selector-remove:hover { + background-position: 0 -20px; + } + + .help-tooltip, .selector .help-icon { + display: none; + } + + .datetime input { + width: 50%; + max-width: 120px; + } + + .datetime span { + font-size: 0.8125rem; + } + + .datetime .timezonewarning { + display: block; + font-size: 0.6875rem; + color: var(--body-quiet-color); + } + + .datetimeshortcuts { + color: var(--border-color); /* XXX Redundant, .datetime span also sets #ccc */ + } + + .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField { + width: 75%; + } + + .inline-group { + overflow: auto; + } + + /* Messages */ + + ul.messagelist li { + padding-left: 55px; + background-position: 30px 12px; + } + + ul.messagelist li.error { + background-position: 30px 12px; + } + + ul.messagelist li.warning { + background-position: 30px 14px; + } + + /* Login */ + + .login #header { + padding: 15px 20px; + } + + .login #branding h1 { + margin: 0; + } + + /* GIS */ + + div.olMap { + max-width: calc(100vw - 30px); + max-height: 300px; + } + + .olMap + .clear_features { + display: block; + margin-top: 10px; + } + + /* Docs */ + + .module table.xfull { + width: 100%; + } + + pre.literal-block { + overflow: auto; + } +} + +/* Mobile */ + +@media (max-width: 767px) { + /* Layout */ + + #header, #content, #footer { + padding: 15px; + } + + #footer:empty { + padding: 0; + } + + div.breadcrumbs { + padding: 10px 15px; + } + + /* Dashboard */ + + .colMS, .colSM { + margin: 0; + } + + #content-related, .colSM #content-related { + width: 100%; + margin: 0; + } + + #content-related .module { + margin-bottom: 0; + } + + #content-related .module h2 { + padding: 10px 15px; + font-size: 1rem; + } + + /* Changelist */ + + #changelist { + align-items: stretch; + flex-direction: column; + } + + #toolbar { + padding: 10px; + } + + #changelist-filter { + margin-left: 0; + } + + #changelist .actions label { + flex: 1 1; + } + + #changelist .actions select { + flex: 1 0; + width: 100%; + } + + #changelist .actions span { + flex: 1 0 100%; + } + + #changelist-filter { + position: static; + width: auto; + margin-top: 30px; + } + + .object-tools { + float: none; + margin: 0 0 15px; + padding: 0; + overflow: hidden; + } + + .object-tools li { + height: auto; + margin-left: 0; + } + + .object-tools li + li { + margin-left: 15px; + } + + /* Forms */ + + .form-row { + padding: 15px 0; + } + + .aligned .form-row, + .aligned .form-row > div { + max-width: 100vw; + } + + .aligned .form-row > div { + width: calc(100vw - 30px); + } + + .flex-container { + flex-flow: column; + } + + .flex-container.checkbox-row { + flex-flow: row; + } + + textarea { + max-width: none; + } + + .vURLField { + width: auto; + } + + fieldset .fieldBox + .fieldBox { + margin-top: 15px; + padding-top: 15px; + } + + fieldset.collapsed .form-row { + display: none; + } + + .aligned label { + width: 100%; + min-width: auto; + padding: 0 0 10px; + } + + .aligned label:after { + max-height: 0; + } + + .aligned .form-row input, + .aligned .form-row select, + .aligned .form-row textarea { + flex: 1 1 auto; + max-width: 100%; + } + + .aligned .checkbox-row input { + flex: 0 1 auto; + margin: 0; + } + + .aligned .vCheckboxLabel { + flex: 1 0; + padding: 1px 0 0 5px; + } + + .aligned label + p, + .aligned label + div.help, + .aligned label + div.readonly { + padding: 0; + margin-left: 0; + } + + .aligned p.file-upload { + font-size: 0.8125rem; + } + + span.clearable-file-input { + margin-left: 15px; + } + + span.clearable-file-input label { + font-size: 0.8125rem; + padding-bottom: 0; + } + + .aligned .timezonewarning { + flex: 1 0 100%; + margin-top: 5px; + } + + form .aligned .form-row div.help { + width: 100%; + margin: 5px 0 0; + padding: 0; + } + + form .aligned ul, + form .aligned ul.errorlist { + margin-left: 0; + padding-left: 0; + } + + form .aligned div.radiolist { + margin-top: 5px; + margin-right: 15px; + margin-bottom: -3px; + } + + form .aligned div.radiolist:not(.inline) div + div { + margin-top: 5px; + } + + /* Related widget */ + + .related-widget-wrapper { + width: 100%; + display: flex; + align-items: flex-start; + } + + .related-widget-wrapper .selector { + order: 1; + } + + .related-widget-wrapper > a { + order: 2; + } + + .related-widget-wrapper .radiolist ~ a { + align-self: flex-end; + } + + .related-widget-wrapper > select ~ a { + align-self: center; + } + + select + .related-widget-wrapper-link, + .related-widget-wrapper-link + .related-widget-wrapper-link { + margin-left: 15px; + } + + /* Selector */ + + .selector { + flex-direction: column; + } + + .selector > * { + float: none; + } + + .selector-available, .selector-chosen { + margin-bottom: 0; + flex: 1 1 auto; + } + + .selector select { + max-height: 96px; + } + + .selector ul.selector-chooser { + display: block; + float: none; + width: 52px; + height: 26px; + padding: 0 2px; + margin: 15px auto 20px; + transform: none; + } + + .selector ul.selector-chooser li { + float: left; + } + + .selector-remove { + background-position: 0 0; + } + + .active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -20px; + } + + .selector-add { + background-position: 0 -40px; + } + + .active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -60px; + } + + /* Inlines */ + + .inline-group[data-inline-type="stacked"] .inline-related { + border: 1px solid var(--hairline-color); + border-radius: 4px; + margin-top: 15px; + overflow: auto; + } + + .inline-group[data-inline-type="stacked"] .inline-related > * { + box-sizing: border-box; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module { + padding: 0 10px; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module .form-row { + border-top: 1px solid var(--hairline-color); + border-bottom: none; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module .form-row:first-child { + border-top: none; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 { + padding: 10px; + border-top-width: 0; + border-bottom-width: 2px; + display: flex; + flex-wrap: wrap; + align-items: center; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 .inline_label { + margin-right: auto; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 span.delete { + float: none; + flex: 1 1 100%; + margin-top: 5px; + } + + .inline-group[data-inline-type="stacked"] .aligned .form-row > div:not([class]) { + width: 100%; + } + + .inline-group[data-inline-type="stacked"] .aligned label { + width: 100%; + } + + .inline-group[data-inline-type="stacked"] div.add-row { + margin-top: 15px; + border: 1px solid var(--hairline-color); + border-radius: 4px; + } + + .inline-group div.add-row, + .inline-group .tabular tr.add-row td { + padding: 0; + } + + .inline-group div.add-row a, + .inline-group .tabular tr.add-row td a { + display: block; + padding: 8px 10px 8px 26px; + background-position: 8px 9px; + } + + /* Submit row */ + + .submit-row { + padding: 10px; + margin: 0 0 15px; + flex-direction: column; + gap: 8px; + } + + .submit-row input, .submit-row input.default, .submit-row a { + text-align: center; + } + + .submit-row a.closelink { + padding: 10px 0; + text-align: center; + } + + .submit-row a.deletelink { + margin: 0; + } + + /* Messages */ + + ul.messagelist li { + padding-left: 40px; + background-position: 15px 12px; + } + + ul.messagelist li.error { + background-position: 15px 12px; + } + + ul.messagelist li.warning { + background-position: 15px 14px; + } + + /* Paginator */ + + .paginator .this-page, .paginator a:link, .paginator a:visited { + padding: 4px 10px; + } + + /* Login */ + + body.login { + padding: 0 15px; + } + + .login #container { + width: auto; + max-width: 480px; + margin: 50px auto; + } + + .login #header, + .login #content { + padding: 15px; + } + + .login #content-main { + float: none; + } + + .login .form-row { + padding: 0; + } + + .login .form-row + .form-row { + margin-top: 15px; + } + + .login .form-row label { + margin: 0 0 5px; + line-height: 1.2; + } + + .login .submit-row { + padding: 15px 0 0; + } + + .login br { + display: none; + } + + .login .submit-row input { + margin: 0; + text-transform: uppercase; + } + + .errornote { + margin: 0 0 20px; + padding: 8px 12px; + font-size: 0.8125rem; + } + + /* Calendar and clock */ + + .calendarbox, .clockbox { + position: fixed !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%); + margin: 0; + border: none; + overflow: visible; + } + + .calendarbox:before, .clockbox:before { + content: ''; + position: fixed; + top: 50%; + left: 50%; + width: 100vw; + height: 100vh; + background: rgba(0, 0, 0, 0.75); + transform: translate(-50%, -50%); + } + + .calendarbox > *, .clockbox > * { + position: relative; + z-index: 1; + } + + .calendarbox > div:first-child { + z-index: 2; + } + + .calendarbox .calendar, .clockbox h2 { + border-radius: 4px 4px 0 0; + overflow: hidden; + } + + .calendarbox .calendar-cancel, .clockbox .calendar-cancel { + border-radius: 0 0 4px 4px; + overflow: hidden; + } + + .calendar-shortcuts { + padding: 10px 0; + font-size: 0.75rem; + line-height: 0.75rem; + } + + .calendar-shortcuts a { + margin: 0 4px; + } + + .timelist a { + background: var(--body-bg); + padding: 4px; + } + + .calendar-cancel { + padding: 8px 10px; + } + + .clockbox h2 { + padding: 8px 15px; + } + + .calendar caption { + padding: 10px; + } + + .calendarbox .calendarnav-previous, .calendarbox .calendarnav-next { + z-index: 1; + top: 10px; + } + + /* History */ + + table#change-history tbody th, table#change-history tbody td { + font-size: 0.8125rem; + word-break: break-word; + } + + table#change-history tbody th { + width: auto; + } + + /* Docs */ + + table.model tbody th, table.model tbody td { + font-size: 0.8125rem; + word-break: break-word; + } +} diff --git a/staticfiles/admin/css/responsive.f6533dab034d.css.gz b/staticfiles/admin/css/responsive.f6533dab034d.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..fe370fb18b5321f129c5dbce26cde31b8d41839e GIT binary patch literal 3441 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 TI{K|n@#W~hN@bgee@FlTgzmxv literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/responsive_rtl.7d1130848605.css b/staticfiles/admin/css/responsive_rtl.7d1130848605.css new file mode 100644 index 0000000000..31dc8ff7db --- /dev/null +++ b/staticfiles/admin/css/responsive_rtl.7d1130848605.css @@ -0,0 +1,84 @@ +/* TABLETS */ + +@media (max-width: 1024px) { + [dir="rtl"] .colMS { + margin-right: 0; + } + + [dir="rtl"] #user-tools { + text-align: right; + } + + [dir="rtl"] #changelist .actions label { + padding-left: 10px; + padding-right: 0; + } + + [dir="rtl"] #changelist .actions select { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .change-list .filtered .results, + [dir="rtl"] .change-list .filtered .paginator, + [dir="rtl"] .filtered #toolbar, + [dir="rtl"] .filtered div.xfull, + [dir="rtl"] .filtered .actions, + [dir="rtl"] #changelist-filter { + margin-left: 0; + } + + [dir="rtl"] .inline-group ul.tools a.add, + [dir="rtl"] .inline-group div.add-row a, + [dir="rtl"] .inline-group .tabular tr.add-row td a { + padding: 8px 26px 8px 10px; + background-position: calc(100% - 8px) 9px; + } + + [dir="rtl"] .related-widget-wrapper-link + .selector { + margin-right: 0; + margin-left: 15px; + } + + [dir="rtl"] .selector .selector-filter label { + margin-right: 0; + margin-left: 8px; + } + + [dir="rtl"] .object-tools li { + float: right; + } + + [dir="rtl"] .object-tools li + li { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .dashboard .module table td a { + padding-left: 0; + padding-right: 16px; + } +} + +/* MOBILE */ + +@media (max-width: 767px) { + [dir="rtl"] .aligned .related-lookup, + [dir="rtl"] .aligned .datetimeshortcuts { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .aligned ul, + [dir="rtl"] form .aligned ul.errorlist { + margin-right: 0; + } + + [dir="rtl"] #changelist-filter { + margin-left: 0; + margin-right: 0; + } + [dir="rtl"] .aligned .vCheckboxLabel { + padding: 1px 5px 0 0; + } +} diff --git a/staticfiles/admin/css/responsive_rtl.7d1130848605.css.gz b/staticfiles/admin/css/responsive_rtl.7d1130848605.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..3e2886b55cf18f6ef73ab137f535ab16d1062de9 GIT binary patch literal 550 zcmV+>0@?i^iwFP!00002|E*O~PunmMe($e1fhIwz(-dumwVJds@i3`q5AZha;S#%v z*Gn8Z7aD2ezvDEt6p|)v!Vi`ue|Mk#`MdLY2zTGE7T0&TFdPpCUlS!Y!byUqSZm4g z3?}~h$E-YszXNdNm(=#lk!3pi4PI#I=Jsi$8VTA+r^4ze<{9|&&Bnu^5qMnW$_h4y z^1WzQB?}}Sr8C&1I2<3wm_~|p&fsCl+N3!U28#C5WhkXiBSC7()h)7e-q`CuX&Y0n zNQK)A2A5e0=TkRTiq?m!gh=7Z#P>gds6tNRbC(UQB4j12 z;)@iEwZ$xRwc^gYf-~@H>lxcubPbWa&9_UtTW#O$bydBM?Xru^1b-aGQ~8tLOTHw7 z+*kaK__LQu-lG^L=5b)qI)f)h7No!#q?%hj(d2s7UnbLMGDkNa!p+aCAB*clE%#!2 zaiHUF+GE`pYM+oXt0Eh9Af>~xPE;Nn%VEL!J8QKiDq0%F(%57l;VEm4-L$O#_%;5u oqjV%cEZ6<_ScR*=l#BNN#L406-YEk9bGnDYBlhp|ut*0003SOIl>h($ literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/responsive_rtl.css b/staticfiles/admin/css/responsive_rtl.css new file mode 100644 index 0000000000..31dc8ff7db --- /dev/null +++ b/staticfiles/admin/css/responsive_rtl.css @@ -0,0 +1,84 @@ +/* TABLETS */ + +@media (max-width: 1024px) { + [dir="rtl"] .colMS { + margin-right: 0; + } + + [dir="rtl"] #user-tools { + text-align: right; + } + + [dir="rtl"] #changelist .actions label { + padding-left: 10px; + padding-right: 0; + } + + [dir="rtl"] #changelist .actions select { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .change-list .filtered .results, + [dir="rtl"] .change-list .filtered .paginator, + [dir="rtl"] .filtered #toolbar, + [dir="rtl"] .filtered div.xfull, + [dir="rtl"] .filtered .actions, + [dir="rtl"] #changelist-filter { + margin-left: 0; + } + + [dir="rtl"] .inline-group ul.tools a.add, + [dir="rtl"] .inline-group div.add-row a, + [dir="rtl"] .inline-group .tabular tr.add-row td a { + padding: 8px 26px 8px 10px; + background-position: calc(100% - 8px) 9px; + } + + [dir="rtl"] .related-widget-wrapper-link + .selector { + margin-right: 0; + margin-left: 15px; + } + + [dir="rtl"] .selector .selector-filter label { + margin-right: 0; + margin-left: 8px; + } + + [dir="rtl"] .object-tools li { + float: right; + } + + [dir="rtl"] .object-tools li + li { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .dashboard .module table td a { + padding-left: 0; + padding-right: 16px; + } +} + +/* MOBILE */ + +@media (max-width: 767px) { + [dir="rtl"] .aligned .related-lookup, + [dir="rtl"] .aligned .datetimeshortcuts { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .aligned ul, + [dir="rtl"] form .aligned ul.errorlist { + margin-right: 0; + } + + [dir="rtl"] #changelist-filter { + margin-left: 0; + margin-right: 0; + } + [dir="rtl"] .aligned .vCheckboxLabel { + padding: 1px 5px 0 0; + } +} diff --git a/staticfiles/admin/css/responsive_rtl.css.gz b/staticfiles/admin/css/responsive_rtl.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..3e2886b55cf18f6ef73ab137f535ab16d1062de9 GIT binary patch literal 550 zcmV+>0@?i^iwFP!00002|E*O~PunmMe($e1fhIwz(-dumwVJds@i3`q5AZha;S#%v z*Gn8Z7aD2ezvDEt6p|)v!Vi`ue|Mk#`MdLY2zTGE7T0&TFdPpCUlS!Y!byUqSZm4g z3?}~h$E-YszXNdNm(=#lk!3pi4PI#I=Jsi$8VTA+r^4ze<{9|&&Bnu^5qMnW$_h4y z^1WzQB?}}Sr8C&1I2<3wm_~|p&fsCl+N3!U28#C5WhkXiBSC7()h)7e-q`CuX&Y0n zNQK)A2A5e0=TkRTiq?m!gh=7Z#P>gds6tNRbC(UQB4j12 z;)@iEwZ$xRwc^gYf-~@H>lxcubPbWa&9_UtTW#O$bydBM?Xru^1b-aGQ~8tLOTHw7 z+*kaK__LQu-lG^L=5b)qI)f)h7No!#q?%hj(d2s7UnbLMGDkNa!p+aCAB*clE%#!2 zaiHUF+GE`pYM+oXt0Eh9Af>~xPE;Nn%VEL!J8QKiDq0%F(%57l;VEm4-L$O#_%;5u oqjV%cEZ6<_ScR*=l#BNN#L406-YEk9bGnDYBlhp|ut*0003SOIl>h($ literal 0 HcmV?d00001 diff --git a/staticfiles/admin/css/rtl.512d4b53fc59.css b/staticfiles/admin/css/rtl.512d4b53fc59.css new file mode 100644 index 0000000000..d40e573b8b --- /dev/null +++ b/staticfiles/admin/css/rtl.512d4b53fc59.css @@ -0,0 +1,298 @@ +/* GLOBAL */ + +th { + text-align: right; +} + +.module h2, .module caption { + text-align: right; +} + +.module ul, .module ol { + margin-left: 0; + margin-right: 1.5em; +} + +.viewlink, .addlink, .changelink { + padding-left: 0; + padding-right: 16px; + background-position: 100% 1px; +} + +.deletelink { + padding-left: 0; + padding-right: 16px; + background-position: 100% 1px; +} + +.object-tools { + float: left; +} + +thead th:first-child, +tfoot td:first-child { + border-left: none; +} + +/* LAYOUT */ + +#user-tools { + right: auto; + left: 0; + text-align: left; +} + +div.breadcrumbs { + text-align: right; +} + +#content-main { + float: right; +} + +#content-related { + float: left; + margin-left: -300px; + margin-right: auto; +} + +.colMS { + margin-left: 300px; + margin-right: 0; +} + +/* SORTABLE TABLES */ + +table thead th.sorted .sortoptions { + float: left; +} + +thead th.sorted .text { + padding-right: 0; + padding-left: 42px; +} + +/* dashboard styles */ + +.dashboard .module table td a { + padding-left: .6em; + padding-right: 16px; +} + +/* changelists styles */ + +.change-list .filtered table { + border-left: none; + border-right: 0px none; +} + +#changelist-filter { + border-left: none; + border-right: none; + margin-left: 0; + margin-right: 30px; +} + +#changelist-filter li.selected { + border-left: none; + padding-left: 10px; + margin-left: 0; + border-right: 5px solid var(--hairline-color); + padding-right: 10px; + margin-right: -15px; +} + +#changelist table tbody td:first-child, #changelist table tbody th:first-child { + border-right: none; + border-left: none; +} + +.paginator .end { + margin-left: 6px; + margin-right: 0; +} + +.paginator input { + margin-left: 0; + margin-right: auto; +} + +/* FORMS */ + +.aligned label { + padding: 0 0 3px 1em; +} + +.submit-row a.deletelink { + margin-left: 0; + margin-right: auto; +} + +.vDateField, .vTimeField { + margin-left: 2px; +} + +.aligned .form-row input { + margin-left: 5px; +} + +form .aligned ul { + margin-right: 163px; + padding-right: 10px; + margin-left: 0; + padding-left: 0; +} + +form ul.inline li { + float: right; + padding-right: 0; + padding-left: 7px; +} + +form .aligned p.help, +form .aligned div.help { + margin-right: 160px; + padding-right: 10px; +} + +form div.help ul, +form .aligned .checkbox-row + .help, +form .aligned p.date div.help.timezonewarning, +form .aligned p.datetime div.help.timezonewarning, +form .aligned p.time div.help.timezonewarning { + margin-right: 0; + padding-right: 0; +} + +form .wide p.help, form .wide div.help { + padding-left: 0; + padding-right: 50px; +} + +form .wide p, +form .wide ul.errorlist, +form .wide input + p.help, +form .wide input + div.help { + margin-right: 200px; + margin-left: 0px; +} + +.submit-row { + text-align: right; +} + +fieldset .fieldBox { + margin-left: 20px; + margin-right: 0; +} + +.errorlist li { + background-position: 100% 12px; + padding: 0; +} + +.errornote { + background-position: 100% 12px; + padding: 10px 12px; +} + +/* WIDGETS */ + +.calendarnav-previous { + top: 0; + left: auto; + right: 10px; + background: url("../img/calendar-icons.39b290681a8b.svg") 0 -30px no-repeat; +} + +.calendarbox .calendarnav-previous:focus, +.calendarbox .calendarnav-previous:hover { + background-position: 0 -45px; +} + +.calendarnav-next { + top: 0; + right: auto; + left: 10px; + background: url("../img/calendar-icons.39b290681a8b.svg") 0 0 no-repeat; +} + +.calendarbox .calendarnav-next:focus, +.calendarbox .calendarnav-next:hover { + background-position: 0 -15px; +} + +.calendar caption, .calendarbox h2 { + text-align: center; +} + +.selector { + float: right; +} + +.selector .selector-filter { + text-align: right; +} + +.selector-add { + background: url("../img/selector-icons.b4555096cea2.svg") 0 -64px no-repeat; +} + +.active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -80px; +} + +.selector-remove { + background: url("../img/selector-icons.b4555096cea2.svg") 0 -96px no-repeat; +} + +.active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -112px; +} + +a.selector-chooseall { + background: url("../img/selector-icons.b4555096cea2.svg") right -128px no-repeat; +} + +a.active.selector-chooseall:focus, a.active.selector-chooseall:hover { + background-position: 100% -144px; +} + +a.selector-clearall { + background: url("../img/selector-icons.b4555096cea2.svg") 0 -160px no-repeat; +} + +a.active.selector-clearall:focus, a.active.selector-clearall:hover { + background-position: 0 -176px; +} + +.inline-deletelink { + float: left; +} + +form .form-row p.datetime { + overflow: hidden; +} + +.related-widget-wrapper { + float: right; +} + +/* MISC */ + +.inline-related h2, .inline-group h2 { + text-align: right +} + +.inline-related h3 span.delete { + padding-right: 20px; + padding-left: inherit; + left: 10px; + right: inherit; + float:left; +} + +.inline-related h3 span.delete label { + margin-left: inherit; + margin-right: 2px; +} diff --git a/staticfiles/admin/css/rtl.512d4b53fc59.css.gz b/staticfiles/admin/css/rtl.512d4b53fc59.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..f2503b9ac8561f93afecb122717027553fd7ac18 GIT binary patch literal 1281 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 To~Qb9zDM#8M89D%WCQ>J
+ //
+ // Yesterday | Today | Tomorrow + //
+ //

Cancel

+ // + const cal_box = document.createElement('div'); + cal_box.style.display = 'none'; + cal_box.style.position = 'absolute'; + cal_box.className = 'calendarbox module'; + cal_box.id = DateTimeShortcuts.calendarDivName1 + num; + document.body.appendChild(cal_box); + cal_box.addEventListener('click', function(e) { e.stopPropagation(); }); + + // next-prev links + const cal_nav = quickElement('div', cal_box); + const cal_nav_prev = quickElement('a', cal_nav, '<', 'href', '#'); + cal_nav_prev.className = 'calendarnav-previous'; + cal_nav_prev.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.drawPrev(num); + }); + + const cal_nav_next = quickElement('a', cal_nav, '>', 'href', '#'); + cal_nav_next.className = 'calendarnav-next'; + cal_nav_next.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.drawNext(num); + }); + + // main box + const cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num); + cal_main.className = 'calendar'; + DateTimeShortcuts.calendars[num] = new Calendar(DateTimeShortcuts.calendarDivName2 + num, DateTimeShortcuts.handleCalendarCallback(num)); + DateTimeShortcuts.calendars[num].drawCurrent(); + + // calendar shortcuts + const shortcuts = quickElement('div', cal_box); + shortcuts.className = 'calendar-shortcuts'; + let day_link = quickElement('a', shortcuts, gettext('Yesterday'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, -1); + }); + shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0')); + day_link = quickElement('a', shortcuts, gettext('Today'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, 0); + }); + shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0')); + day_link = quickElement('a', shortcuts, gettext('Tomorrow'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, +1); + }); + + // cancel bar + const cancel_p = quickElement('p', cal_box); + cancel_p.className = 'calendar-cancel'; + const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#'); + cancel_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.dismissCalendar(num); + }); + document.addEventListener('keyup', function(event) { + if (event.which === 27) { + // ESC key closes popup + DateTimeShortcuts.dismissCalendar(num); + event.preventDefault(); + } + }); + }, + openCalendar: function(num) { + const cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1 + num); + const cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName + num); + const inp = DateTimeShortcuts.calendarInputs[num]; + + // Determine if the current value in the input has a valid date. + // If so, draw the calendar with that date's year and month. + if (inp.value) { + const format = get_format('DATE_INPUT_FORMATS')[0]; + const selected = inp.value.strptime(format); + const year = selected.getUTCFullYear(); + const month = selected.getUTCMonth() + 1; + const re = /\d{4}/; + if (re.test(year.toString()) && month >= 1 && month <= 12) { + DateTimeShortcuts.calendars[num].drawDate(month, year, selected); + } + } + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (window.getComputedStyle(document.body).direction !== 'rtl') { + cal_box.style.left = findPosX(cal_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + cal_box.style.left = findPosX(cal_link) - 180 + 'px'; + } + cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + 'px'; + + cal_box.style.display = 'block'; + document.addEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]); + }, + dismissCalendar: function(num) { + document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none'; + document.removeEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]); + }, + drawPrev: function(num) { + DateTimeShortcuts.calendars[num].drawPreviousMonth(); + }, + drawNext: function(num) { + DateTimeShortcuts.calendars[num].drawNextMonth(); + }, + handleCalendarCallback: function(num) { + const format = get_format('DATE_INPUT_FORMATS')[0]; + return function(y, m, d) { + DateTimeShortcuts.calendarInputs[num].value = new Date(y, m - 1, d).strftime(format); + DateTimeShortcuts.calendarInputs[num].focus(); + document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none'; + }; + }, + handleCalendarQuickLink: function(num, offset) { + const d = DateTimeShortcuts.now(); + d.setDate(d.getDate() + offset); + DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]); + DateTimeShortcuts.calendarInputs[num].focus(); + DateTimeShortcuts.dismissCalendar(num); + } + }; + + window.addEventListener('load', DateTimeShortcuts.init); + window.DateTimeShortcuts = DateTimeShortcuts; +} diff --git a/staticfiles/admin/js/admin/DateTimeShortcuts.9f6e209cebca.js.gz b/staticfiles/admin/js/admin/DateTimeShortcuts.9f6e209cebca.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..d184bad9195295d59cc478e9cac68257c835a7c0 GIT binary patch literal 3645 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 literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/admin/DateTimeShortcuts.js b/staticfiles/admin/js/admin/DateTimeShortcuts.js new file mode 100644 index 0000000000..aa1cae9eeb --- /dev/null +++ b/staticfiles/admin/js/admin/DateTimeShortcuts.js @@ -0,0 +1,408 @@ +/*global Calendar, findPosX, findPosY, get_format, gettext, gettext_noop, interpolate, ngettext, quickElement*/ +// Inserts shortcut buttons after all of the following: +// +// +'use strict'; +{ + const DateTimeShortcuts = { + calendars: [], + calendarInputs: [], + clockInputs: [], + clockHours: { + default_: [ + [gettext_noop('Now'), -1], + [gettext_noop('Midnight'), 0], + [gettext_noop('6 a.m.'), 6], + [gettext_noop('Noon'), 12], + [gettext_noop('6 p.m.'), 18] + ] + }, + dismissClockFunc: [], + dismissCalendarFunc: [], + calendarDivName1: 'calendarbox', // name of calendar
that gets toggled + calendarDivName2: 'calendarin', // name of
that contains calendar + calendarLinkName: 'calendarlink', // name of the link that is used to toggle + clockDivName: 'clockbox', // name of clock
that gets toggled + clockLinkName: 'clocklink', // name of the link that is used to toggle + shortCutsClass: 'datetimeshortcuts', // class of the clock and cal shortcuts + timezoneWarningClass: 'timezonewarning', // class of the warning for timezone mismatch + timezoneOffset: 0, + init: function() { + const serverOffset = document.body.dataset.adminUtcOffset; + if (serverOffset) { + const localOffset = new Date().getTimezoneOffset() * -60; + DateTimeShortcuts.timezoneOffset = localOffset - serverOffset; + } + + for (const inp of document.getElementsByTagName('input')) { + if (inp.type === 'text' && inp.classList.contains('vTimeField')) { + DateTimeShortcuts.addClock(inp); + DateTimeShortcuts.addTimezoneWarning(inp); + } + else if (inp.type === 'text' && inp.classList.contains('vDateField')) { + DateTimeShortcuts.addCalendar(inp); + DateTimeShortcuts.addTimezoneWarning(inp); + } + } + }, + // Return the current time while accounting for the server timezone. + now: function() { + const serverOffset = document.body.dataset.adminUtcOffset; + if (serverOffset) { + const localNow = new Date(); + const localOffset = localNow.getTimezoneOffset() * -60; + localNow.setTime(localNow.getTime() + 1000 * (serverOffset - localOffset)); + return localNow; + } else { + return new Date(); + } + }, + // Add a warning when the time zone in the browser and backend do not match. + addTimezoneWarning: function(inp) { + const warningClass = DateTimeShortcuts.timezoneWarningClass; + let timezoneOffset = DateTimeShortcuts.timezoneOffset / 3600; + + // Only warn if there is a time zone mismatch. + if (!timezoneOffset) { + return; + } + + // Check if warning is already there. + if (inp.parentNode.querySelectorAll('.' + warningClass).length) { + return; + } + + let message; + if (timezoneOffset > 0) { + message = ngettext( + 'Note: You are %s hour ahead of server time.', + 'Note: You are %s hours ahead of server time.', + timezoneOffset + ); + } + else { + timezoneOffset *= -1; + message = ngettext( + 'Note: You are %s hour behind server time.', + 'Note: You are %s hours behind server time.', + timezoneOffset + ); + } + message = interpolate(message, [timezoneOffset]); + + const warning = document.createElement('div'); + warning.classList.add('help', warningClass); + warning.textContent = message; + inp.parentNode.appendChild(warning); + }, + // Add clock widget to a given field + addClock: function(inp) { + const num = DateTimeShortcuts.clockInputs.length; + DateTimeShortcuts.clockInputs[num] = inp; + DateTimeShortcuts.dismissClockFunc[num] = function() { DateTimeShortcuts.dismissClock(num); return true; }; + + // Shortcut links (clock icon and "Now" link) + const shortcuts_span = document.createElement('span'); + shortcuts_span.className = DateTimeShortcuts.shortCutsClass; + inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling); + const now_link = document.createElement('a'); + now_link.href = "#"; + now_link.textContent = gettext('Now'); + now_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleClockQuicklink(num, -1); + }); + const clock_link = document.createElement('a'); + clock_link.href = '#'; + clock_link.id = DateTimeShortcuts.clockLinkName + num; + clock_link.addEventListener('click', function(e) { + e.preventDefault(); + // avoid triggering the document click handler to dismiss the clock + e.stopPropagation(); + DateTimeShortcuts.openClock(num); + }); + + quickElement( + 'span', clock_link, '', + 'class', 'clock-icon', + 'title', gettext('Choose a Time') + ); + shortcuts_span.appendChild(document.createTextNode('\u00A0')); + shortcuts_span.appendChild(now_link); + shortcuts_span.appendChild(document.createTextNode('\u00A0|\u00A0')); + shortcuts_span.appendChild(clock_link); + + // Create clock link div + // + // Markup looks like: + //
+ //

Choose a time

+ // + //

Cancel

+ //
+ + const clock_box = document.createElement('div'); + clock_box.style.display = 'none'; + clock_box.style.position = 'absolute'; + clock_box.className = 'clockbox module'; + clock_box.id = DateTimeShortcuts.clockDivName + num; + document.body.appendChild(clock_box); + clock_box.addEventListener('click', function(e) { e.stopPropagation(); }); + + quickElement('h2', clock_box, gettext('Choose a time')); + const time_list = quickElement('ul', clock_box); + time_list.className = 'timelist'; + // The list of choices can be overridden in JavaScript like this: + // DateTimeShortcuts.clockHours.name = [['3 a.m.', 3]]; + // where name is the name attribute of the . + const name = typeof DateTimeShortcuts.clockHours[inp.name] === 'undefined' ? 'default_' : inp.name; + DateTimeShortcuts.clockHours[name].forEach(function(element) { + const time_link = quickElement('a', quickElement('li', time_list), gettext(element[0]), 'href', '#'); + time_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleClockQuicklink(num, element[1]); + }); + }); + + const cancel_p = quickElement('p', clock_box); + cancel_p.className = 'calendar-cancel'; + const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#'); + cancel_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.dismissClock(num); + }); + + document.addEventListener('keyup', function(event) { + if (event.which === 27) { + // ESC key closes popup + DateTimeShortcuts.dismissClock(num); + event.preventDefault(); + } + }); + }, + openClock: function(num) { + const clock_box = document.getElementById(DateTimeShortcuts.clockDivName + num); + const clock_link = document.getElementById(DateTimeShortcuts.clockLinkName + num); + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (window.getComputedStyle(document.body).direction !== 'rtl') { + clock_box.style.left = findPosX(clock_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + clock_box.style.left = findPosX(clock_link) - 110 + 'px'; + } + clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + 'px'; + + // Show the clock box + clock_box.style.display = 'block'; + document.addEventListener('click', DateTimeShortcuts.dismissClockFunc[num]); + }, + dismissClock: function(num) { + document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none'; + document.removeEventListener('click', DateTimeShortcuts.dismissClockFunc[num]); + }, + handleClockQuicklink: function(num, val) { + let d; + if (val === -1) { + d = DateTimeShortcuts.now(); + } + else { + d = new Date(1970, 1, 1, val, 0, 0, 0); + } + DateTimeShortcuts.clockInputs[num].value = d.strftime(get_format('TIME_INPUT_FORMATS')[0]); + DateTimeShortcuts.clockInputs[num].focus(); + DateTimeShortcuts.dismissClock(num); + }, + // Add calendar widget to a given field. + addCalendar: function(inp) { + const num = DateTimeShortcuts.calendars.length; + + DateTimeShortcuts.calendarInputs[num] = inp; + DateTimeShortcuts.dismissCalendarFunc[num] = function() { DateTimeShortcuts.dismissCalendar(num); return true; }; + + // Shortcut links (calendar icon and "Today" link) + const shortcuts_span = document.createElement('span'); + shortcuts_span.className = DateTimeShortcuts.shortCutsClass; + inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling); + const today_link = document.createElement('a'); + today_link.href = '#'; + today_link.appendChild(document.createTextNode(gettext('Today'))); + today_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, 0); + }); + const cal_link = document.createElement('a'); + cal_link.href = '#'; + cal_link.id = DateTimeShortcuts.calendarLinkName + num; + cal_link.addEventListener('click', function(e) { + e.preventDefault(); + // avoid triggering the document click handler to dismiss the calendar + e.stopPropagation(); + DateTimeShortcuts.openCalendar(num); + }); + quickElement( + 'span', cal_link, '', + 'class', 'date-icon', + 'title', gettext('Choose a Date') + ); + shortcuts_span.appendChild(document.createTextNode('\u00A0')); + shortcuts_span.appendChild(today_link); + shortcuts_span.appendChild(document.createTextNode('\u00A0|\u00A0')); + shortcuts_span.appendChild(cal_link); + + // Create calendarbox div. + // + // Markup looks like: + // + //
+ //

+ // + // February 2003 + //

+ //
+ // + //
+ //
+ // Yesterday | Today | Tomorrow + //
+ //

Cancel

+ //
+ const cal_box = document.createElement('div'); + cal_box.style.display = 'none'; + cal_box.style.position = 'absolute'; + cal_box.className = 'calendarbox module'; + cal_box.id = DateTimeShortcuts.calendarDivName1 + num; + document.body.appendChild(cal_box); + cal_box.addEventListener('click', function(e) { e.stopPropagation(); }); + + // next-prev links + const cal_nav = quickElement('div', cal_box); + const cal_nav_prev = quickElement('a', cal_nav, '<', 'href', '#'); + cal_nav_prev.className = 'calendarnav-previous'; + cal_nav_prev.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.drawPrev(num); + }); + + const cal_nav_next = quickElement('a', cal_nav, '>', 'href', '#'); + cal_nav_next.className = 'calendarnav-next'; + cal_nav_next.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.drawNext(num); + }); + + // main box + const cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num); + cal_main.className = 'calendar'; + DateTimeShortcuts.calendars[num] = new Calendar(DateTimeShortcuts.calendarDivName2 + num, DateTimeShortcuts.handleCalendarCallback(num)); + DateTimeShortcuts.calendars[num].drawCurrent(); + + // calendar shortcuts + const shortcuts = quickElement('div', cal_box); + shortcuts.className = 'calendar-shortcuts'; + let day_link = quickElement('a', shortcuts, gettext('Yesterday'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, -1); + }); + shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0')); + day_link = quickElement('a', shortcuts, gettext('Today'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, 0); + }); + shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0')); + day_link = quickElement('a', shortcuts, gettext('Tomorrow'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, +1); + }); + + // cancel bar + const cancel_p = quickElement('p', cal_box); + cancel_p.className = 'calendar-cancel'; + const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#'); + cancel_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.dismissCalendar(num); + }); + document.addEventListener('keyup', function(event) { + if (event.which === 27) { + // ESC key closes popup + DateTimeShortcuts.dismissCalendar(num); + event.preventDefault(); + } + }); + }, + openCalendar: function(num) { + const cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1 + num); + const cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName + num); + const inp = DateTimeShortcuts.calendarInputs[num]; + + // Determine if the current value in the input has a valid date. + // If so, draw the calendar with that date's year and month. + if (inp.value) { + const format = get_format('DATE_INPUT_FORMATS')[0]; + const selected = inp.value.strptime(format); + const year = selected.getUTCFullYear(); + const month = selected.getUTCMonth() + 1; + const re = /\d{4}/; + if (re.test(year.toString()) && month >= 1 && month <= 12) { + DateTimeShortcuts.calendars[num].drawDate(month, year, selected); + } + } + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (window.getComputedStyle(document.body).direction !== 'rtl') { + cal_box.style.left = findPosX(cal_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + cal_box.style.left = findPosX(cal_link) - 180 + 'px'; + } + cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + 'px'; + + cal_box.style.display = 'block'; + document.addEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]); + }, + dismissCalendar: function(num) { + document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none'; + document.removeEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]); + }, + drawPrev: function(num) { + DateTimeShortcuts.calendars[num].drawPreviousMonth(); + }, + drawNext: function(num) { + DateTimeShortcuts.calendars[num].drawNextMonth(); + }, + handleCalendarCallback: function(num) { + const format = get_format('DATE_INPUT_FORMATS')[0]; + return function(y, m, d) { + DateTimeShortcuts.calendarInputs[num].value = new Date(y, m - 1, d).strftime(format); + DateTimeShortcuts.calendarInputs[num].focus(); + document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none'; + }; + }, + handleCalendarQuickLink: function(num, offset) { + const d = DateTimeShortcuts.now(); + d.setDate(d.getDate() + offset); + DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]); + DateTimeShortcuts.calendarInputs[num].focus(); + DateTimeShortcuts.dismissCalendar(num); + } + }; + + window.addEventListener('load', DateTimeShortcuts.init); + window.DateTimeShortcuts = DateTimeShortcuts; +} diff --git a/staticfiles/admin/js/admin/DateTimeShortcuts.js.gz b/staticfiles/admin/js/admin/DateTimeShortcuts.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..d184bad9195295d59cc478e9cac68257c835a7c0 GIT binary patch literal 3645 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 literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/admin/RelatedObjectLookups.8609f99b9ab2.js b/staticfiles/admin/js/admin/RelatedObjectLookups.8609f99b9ab2.js new file mode 100644 index 0000000000..afb6b66c25 --- /dev/null +++ b/staticfiles/admin/js/admin/RelatedObjectLookups.8609f99b9ab2.js @@ -0,0 +1,238 @@ +/*global SelectBox, interpolate*/ +// Handles related-objects functionality: lookup link for raw_id_fields +// and Add Another links. +'use strict'; +{ + const $ = django.jQuery; + let popupIndex = 0; + const relatedWindows = []; + + function dismissChildPopups() { + relatedWindows.forEach(function(win) { + if(!win.closed) { + win.dismissChildPopups(); + win.close(); + } + }); + } + + function setPopupIndex() { + if(document.getElementsByName("_popup").length > 0) { + const index = window.name.lastIndexOf("__") + 2; + popupIndex = parseInt(window.name.substring(index)); + } else { + popupIndex = 0; + } + } + + function addPopupIndex(name) { + return name + "__" + (popupIndex + 1); + } + + function removePopupIndex(name) { + return name.replace(new RegExp("__" + (popupIndex + 1) + "$"), ''); + } + + function showAdminPopup(triggeringLink, name_regexp, add_popup) { + const name = addPopupIndex(triggeringLink.id.replace(name_regexp, '')); + const href = new URL(triggeringLink.href); + if (add_popup) { + href.searchParams.set('_popup', 1); + } + const win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); + relatedWindows.push(win); + win.focus(); + return false; + } + + function showRelatedObjectLookupPopup(triggeringLink) { + return showAdminPopup(triggeringLink, /^lookup_/, true); + } + + function dismissRelatedLookupPopup(win, chosenId) { + const name = removePopupIndex(win.name); + const elem = document.getElementById(name); + if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) { + elem.value += ',' + chosenId; + } else { + document.getElementById(name).value = chosenId; + } + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function showRelatedObjectPopup(triggeringLink) { + return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false); + } + + function updateRelatedObjectLinks(triggeringLink) { + const $this = $(triggeringLink); + const siblings = $this.nextAll('.view-related, .change-related, .delete-related'); + if (!siblings.length) { + return; + } + const value = $this.val(); + if (value) { + siblings.each(function() { + const elm = $(this); + elm.attr('href', elm.attr('data-href-template').replace('__fk__', value)); + }); + } else { + siblings.removeAttr('href'); + } + } + + function updateRelatedSelectsOptions(currentSelect, win, objId, newRepr, newId) { + // After create/edit a model from the options next to the current + // select (+ or :pencil:) update ForeignKey PK of the rest of selects + // in the page. + + const path = win.location.pathname; + // Extract the model from the popup url '...//add/' or + // '...///change/' depending the action (add or change). + const modelName = path.split('/')[path.split('/').length - (objId ? 4 : 3)]; + // Exclude autocomplete selects. + const selectsRelated = document.querySelectorAll(`[data-model-ref="${modelName}"] select:not(.admin-autocomplete)`); + + selectsRelated.forEach(function(select) { + if (currentSelect === select) { + return; + } + + let option = select.querySelector(`option[value="${objId}"]`); + + if (!option) { + option = new Option(newRepr, newId); + select.options.add(option); + return; + } + + option.textContent = newRepr; + option.value = newId; + }); + } + + function dismissAddRelatedObjectPopup(win, newId, newRepr) { + const name = removePopupIndex(win.name); + const elem = document.getElementById(name); + if (elem) { + const elemName = elem.nodeName.toUpperCase(); + if (elemName === 'SELECT') { + elem.options[elem.options.length] = new Option(newRepr, newId, true, true); + updateRelatedSelectsOptions(elem, win, null, newRepr, newId); + } else if (elemName === 'INPUT') { + if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) { + elem.value += ',' + newId; + } else { + elem.value = newId; + } + } + // Trigger a change event to update related links if required. + $(elem).trigger('change'); + } else { + const toId = name + "_to"; + const o = new Option(newRepr, newId); + SelectBox.add_to_cache(toId, o); + SelectBox.redisplay(toId); + } + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) { + const id = removePopupIndex(win.name.replace(/^edit_/, '')); + const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); + const selects = $(selectsSelector); + selects.find('option').each(function() { + if (this.value === objId) { + this.textContent = newRepr; + this.value = newId; + } + }).trigger('change'); + updateRelatedSelectsOptions(selects[0], win, objId, newRepr, newId); + selects.next().find('.select2-selection__rendered').each(function() { + // The element can have a clear button as a child. + // Use the lastChild to modify only the displayed value. + this.lastChild.textContent = newRepr; + this.title = newRepr; + }); + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function dismissDeleteRelatedObjectPopup(win, objId) { + const id = removePopupIndex(win.name.replace(/^delete_/, '')); + const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); + const selects = $(selectsSelector); + selects.find('option').each(function() { + if (this.value === objId) { + $(this).remove(); + } + }).trigger('change'); + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup; + window.dismissRelatedLookupPopup = dismissRelatedLookupPopup; + window.showRelatedObjectPopup = showRelatedObjectPopup; + window.updateRelatedObjectLinks = updateRelatedObjectLinks; + window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup; + window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup; + window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup; + window.dismissChildPopups = dismissChildPopups; + + // Kept for backward compatibility + window.showAddAnotherPopup = showRelatedObjectPopup; + window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup; + + window.addEventListener('unload', function(evt) { + window.dismissChildPopups(); + }); + + $(document).ready(function() { + setPopupIndex(); + $("a[data-popup-opener]").on('click', function(event) { + event.preventDefault(); + opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener")); + }); + $('body').on('click', '.related-widget-wrapper-link[data-popup="yes"]', function(e) { + e.preventDefault(); + if (this.href) { + const event = $.Event('django:show-related', {href: this.href}); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + showRelatedObjectPopup(this); + } + } + }); + $('body').on('change', '.related-widget-wrapper select', function(e) { + const event = $.Event('django:update-related'); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + updateRelatedObjectLinks(this); + } + }); + $('.related-widget-wrapper select').trigger('change'); + $('body').on('click', '.related-lookup', function(e) { + e.preventDefault(); + const event = $.Event('django:lookup-related'); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + showRelatedObjectLookupPopup(this); + } + }); + }); +} diff --git a/staticfiles/admin/js/admin/RelatedObjectLookups.8609f99b9ab2.js.gz b/staticfiles/admin/js/admin/RelatedObjectLookups.8609f99b9ab2.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..2c550cc7553ac5cb3de01307bff1ad36d8bb94b5 GIT binary patch literal 2301 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 0) { + const index = window.name.lastIndexOf("__") + 2; + popupIndex = parseInt(window.name.substring(index)); + } else { + popupIndex = 0; + } + } + + function addPopupIndex(name) { + return name + "__" + (popupIndex + 1); + } + + function removePopupIndex(name) { + return name.replace(new RegExp("__" + (popupIndex + 1) + "$"), ''); + } + + function showAdminPopup(triggeringLink, name_regexp, add_popup) { + const name = addPopupIndex(triggeringLink.id.replace(name_regexp, '')); + const href = new URL(triggeringLink.href); + if (add_popup) { + href.searchParams.set('_popup', 1); + } + const win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); + relatedWindows.push(win); + win.focus(); + return false; + } + + function showRelatedObjectLookupPopup(triggeringLink) { + return showAdminPopup(triggeringLink, /^lookup_/, true); + } + + function dismissRelatedLookupPopup(win, chosenId) { + const name = removePopupIndex(win.name); + const elem = document.getElementById(name); + if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) { + elem.value += ',' + chosenId; + } else { + document.getElementById(name).value = chosenId; + } + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function showRelatedObjectPopup(triggeringLink) { + return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false); + } + + function updateRelatedObjectLinks(triggeringLink) { + const $this = $(triggeringLink); + const siblings = $this.nextAll('.view-related, .change-related, .delete-related'); + if (!siblings.length) { + return; + } + const value = $this.val(); + if (value) { + siblings.each(function() { + const elm = $(this); + elm.attr('href', elm.attr('data-href-template').replace('__fk__', value)); + }); + } else { + siblings.removeAttr('href'); + } + } + + function updateRelatedSelectsOptions(currentSelect, win, objId, newRepr, newId) { + // After create/edit a model from the options next to the current + // select (+ or :pencil:) update ForeignKey PK of the rest of selects + // in the page. + + const path = win.location.pathname; + // Extract the model from the popup url '...//add/' or + // '...///change/' depending the action (add or change). + const modelName = path.split('/')[path.split('/').length - (objId ? 4 : 3)]; + // Exclude autocomplete selects. + const selectsRelated = document.querySelectorAll(`[data-model-ref="${modelName}"] select:not(.admin-autocomplete)`); + + selectsRelated.forEach(function(select) { + if (currentSelect === select) { + return; + } + + let option = select.querySelector(`option[value="${objId}"]`); + + if (!option) { + option = new Option(newRepr, newId); + select.options.add(option); + return; + } + + option.textContent = newRepr; + option.value = newId; + }); + } + + function dismissAddRelatedObjectPopup(win, newId, newRepr) { + const name = removePopupIndex(win.name); + const elem = document.getElementById(name); + if (elem) { + const elemName = elem.nodeName.toUpperCase(); + if (elemName === 'SELECT') { + elem.options[elem.options.length] = new Option(newRepr, newId, true, true); + updateRelatedSelectsOptions(elem, win, null, newRepr, newId); + } else if (elemName === 'INPUT') { + if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) { + elem.value += ',' + newId; + } else { + elem.value = newId; + } + } + // Trigger a change event to update related links if required. + $(elem).trigger('change'); + } else { + const toId = name + "_to"; + const o = new Option(newRepr, newId); + SelectBox.add_to_cache(toId, o); + SelectBox.redisplay(toId); + } + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) { + const id = removePopupIndex(win.name.replace(/^edit_/, '')); + const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); + const selects = $(selectsSelector); + selects.find('option').each(function() { + if (this.value === objId) { + this.textContent = newRepr; + this.value = newId; + } + }).trigger('change'); + updateRelatedSelectsOptions(selects[0], win, objId, newRepr, newId); + selects.next().find('.select2-selection__rendered').each(function() { + // The element can have a clear button as a child. + // Use the lastChild to modify only the displayed value. + this.lastChild.textContent = newRepr; + this.title = newRepr; + }); + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function dismissDeleteRelatedObjectPopup(win, objId) { + const id = removePopupIndex(win.name.replace(/^delete_/, '')); + const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); + const selects = $(selectsSelector); + selects.find('option').each(function() { + if (this.value === objId) { + $(this).remove(); + } + }).trigger('change'); + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup; + window.dismissRelatedLookupPopup = dismissRelatedLookupPopup; + window.showRelatedObjectPopup = showRelatedObjectPopup; + window.updateRelatedObjectLinks = updateRelatedObjectLinks; + window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup; + window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup; + window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup; + window.dismissChildPopups = dismissChildPopups; + + // Kept for backward compatibility + window.showAddAnotherPopup = showRelatedObjectPopup; + window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup; + + window.addEventListener('unload', function(evt) { + window.dismissChildPopups(); + }); + + $(document).ready(function() { + setPopupIndex(); + $("a[data-popup-opener]").on('click', function(event) { + event.preventDefault(); + opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener")); + }); + $('body').on('click', '.related-widget-wrapper-link[data-popup="yes"]', function(e) { + e.preventDefault(); + if (this.href) { + const event = $.Event('django:show-related', {href: this.href}); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + showRelatedObjectPopup(this); + } + } + }); + $('body').on('change', '.related-widget-wrapper select', function(e) { + const event = $.Event('django:update-related'); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + updateRelatedObjectLinks(this); + } + }); + $('.related-widget-wrapper select').trigger('change'); + $('body').on('click', '.related-lookup', function(e) { + e.preventDefault(); + const event = $.Event('django:lookup-related'); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + showRelatedObjectLookupPopup(this); + } + }); + }); +} diff --git a/staticfiles/admin/js/admin/RelatedObjectLookups.js.gz b/staticfiles/admin/js/admin/RelatedObjectLookups.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..2c550cc7553ac5cb3de01307bff1ad36d8bb94b5 GIT binary patch literal 2301 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 { + return { + term: params.term, + page: params.page, + app_label: element.dataset.appLabel, + model_name: element.dataset.modelName, + field_name: element.dataset.fieldName + }; + } + } + }); + }); + return this; + }; + + $(function() { + // Initialize all autocomplete widgets except the one in the template + // form used when a new formset is added. + $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2(); + }); + + document.addEventListener('formset:added', (event) => { + $(event.target).find('.admin-autocomplete').djangoAdminSelect2(); + }); +} diff --git a/staticfiles/admin/js/autocomplete.01591ab27be7.js.gz b/staticfiles/admin/js/autocomplete.01591ab27be7.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..1ed616d139268a907d522dbdd07c3ed735c06a03 GIT binary patch literal 425 zcmV;a0apGWiwFP!00002|9w+Ui`y^|z57?pAz- zmF%pXflsQ}_B$DB`9oxPqitC`D=L_UW;$WJ7rfVDeP!r1#A`iSzU5}VxBxQD%HlO4 z86NOd!+kuNLdF`zfFAo$!S>?=UNTQSdb>bK#^n1NW<8k>>qYv2JNi#ghh;hrLu2q4 znfg)@nSKz6WrUs+vMkU$MW(UX)4f8*zD8(SqSIv51Br|!iH8c)=1piSmLpSjy?5)M zdy)ob4o;WB6K@XK(-VBLnl&2zhX9QM9ND$59}F?UQL7zs06MiaaFiu*mO$I=GDR9P z-KurY_Yl`Y!EsL(5G);YFqQ*!091;Uybic1C8kAqfBSA(N$XgYKT=iSZJTEB)ag^x z{EW!`_K0% { + return { + term: params.term, + page: params.page, + app_label: element.dataset.appLabel, + model_name: element.dataset.modelName, + field_name: element.dataset.fieldName + }; + } + } + }); + }); + return this; + }; + + $(function() { + // Initialize all autocomplete widgets except the one in the template + // form used when a new formset is added. + $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2(); + }); + + document.addEventListener('formset:added', (event) => { + $(event.target).find('.admin-autocomplete').djangoAdminSelect2(); + }); +} diff --git a/staticfiles/admin/js/autocomplete.js.gz b/staticfiles/admin/js/autocomplete.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..1ed616d139268a907d522dbdd07c3ed735c06a03 GIT binary patch literal 425 zcmV;a0apGWiwFP!00002|9w+Ui`y^|z57?pAz- zmF%pXflsQ}_B$DB`9oxPqitC`D=L_UW;$WJ7rfVDeP!r1#A`iSzU5}VxBxQD%HlO4 z86NOd!+kuNLdF`zfFAo$!S>?=UNTQSdb>bK#^n1NW<8k>>qYv2JNi#ghh;hrLu2q4 znfg)@nSKz6WrUs+vMkU$MW(UX)4f8*zD8(SqSIv51Br|!iH8c)=1piSmLpSjy?5)M zdy)ob4o;WB6K@XK(-VBLnl&2zhX9QM9ND$59}F?UQL7zs06MiaaFiu*mO$I=GDR9P z-KurY_Yl`Y!EsL(5G);YFqQ*!091;Uybic1C8kAqfBSA(N$XgYKT=iSZJTEB)ag^x z{EW!`_K0%s1(SI6nU?5#H@92^$D-6u~Ck!RcB^KZ4-t;o$J;z~d4EpGT8_#%#<^(-B)Gfu}?m z#B8}|Cw?S&zXs6;CKj&PuU8juShkvR1d=Q8 z*&5^)O3Tr*J$z6W@yE>Qrr#zE)H;5*`UE`siG9xB(=T-mY{VOg+TMscgFZ{x~Ch-~=Wm(2tgdGMhxj|n&O;6r~s zd!uFFmqVup`5+1Uvq`*P)ph-~=Wmn~0E zWW#5Bmil~;Ir{qpL1aq{W< z-P!fWSFe5>j!No9{08{el>Mx2IC~t9O5K5e5uiB%a~wU({>Gk<*zxf(I~uVceqj0A z=@Gv83%zF}_UE6)#B-W345N82`M$6OZN{a<=fMRfUdbArh%U1kg|5=cH?O=ED`uFq zzA2ee44+kpf3FT-REIxShts3lcvd$k+YQ)UpG~V)-B(5+5d>5XeO?v*kLvJcP4%=( z_0a=W&nSisgfJH zGje+U!WppxHf?44WUS43&JrngtZI5_lW3w-$z$^O5MgJ90v+)I1N7nQw1j5Y5CL0) z#|f^gHDCl3V95dLGe1N~8ib0>QCtK}i4D|6^1x?FEP@-&T^7!EoFKM}*%n(3!eUJ! zLkyFagaCIHgQ^Q$Md5~ViN!G!N+w}Ux8RADpdjzl*L!2=gt0S3;P8!awi14-39QTi z`t@u56&lLEl_Nf!9ZjE&r$^(X*|6s4l-#7qx3;KT_0%b@(nV-LEhR9%#P-eZgp?Q( zENKF>0Ju*lff)|a2Ym0c50~sc*RHSzRr@WVzHA5S zDnG)u&bV4KF(H#H$%wFK1g9BS; z)&#FJ!Kl{eu>#?Kb_9B;Nm0dOBSbtezI5lOacQi0q_Cd7594y3G5sr#jf;DJ{C%ya z=l8)=3`V6orNvel{&#UMIk7e3 zh22ekekJ_432Hj4{1cBFDftg2Jqh&byRHC5{*r+tH znxq|c0V|$JxMb)h;k*oC9a>34J>R6Idv^TJJB3GsIio|seet|9Q(N3v^$Q>aLS84KF&d+IXx9f zynusd#`LFb;!_(6*Ctmmo*oS?=Cy(GrU)DNpz#W0oz%eN96>^cSymcy zRKp3?K+*DRc)%d5Hcx1@QY=LSm0=rkZQTdBrP&kvF1jD|V9qRk(#v~k^Y2rY=psN@ z9(tYYv}B->DMfJGkjbeJXP)}Y>m=kKK!*MOkM6nIO1#>aK<5KwO1Rq8fk#~r~ z023qi=)@yb_7=(F39jG69Q=H8JnghFtoXK;IBf@(}4` z0}niNGRV73M(lJRmj|WL7(ztpijHC<#QFN%b-tkR&=VL3p+a)Ix7IInGw2*s7Dqok z*7zdEI)OGHFuN+h zMaY?2uM)~^**!vq%XXRYh(n+jniCggypg*4|11#^)PyP|Rh5rabklQcY%X2+)Kyx* zJMuXVN4X6rxaDxU)#$j@rHopyq9{OZ*HO0J)D}d|IBz9OgGO>|FkGyhHa-0!VyQyL zFNOP^_VvF+PEFd#2fdALE&BDUZmT+NX%FtzwJs17q<(ZS~c5YRh`E#vUT@5pv{hxj2Sf=gS}I T8}H_W`@w$zFPw%U5+MKp!v8}) literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/calendar.js b/staticfiles/admin/js/calendar.js new file mode 100644 index 0000000000..a62d10a759 --- /dev/null +++ b/staticfiles/admin/js/calendar.js @@ -0,0 +1,221 @@ +/*global gettext, pgettext, get_format, quickElement, removeChildren*/ +/* +calendar.js - Calendar functions by Adrian Holovaty +depends on core.js for utility functions like removeChildren or quickElement +*/ +'use strict'; +{ + // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions + const CalendarNamespace = { + monthsOfYear: [ + gettext('January'), + gettext('February'), + gettext('March'), + gettext('April'), + gettext('May'), + gettext('June'), + gettext('July'), + gettext('August'), + gettext('September'), + gettext('October'), + gettext('November'), + gettext('December') + ], + monthsOfYearAbbrev: [ + pgettext('abbrev. month January', 'Jan'), + pgettext('abbrev. month February', 'Feb'), + pgettext('abbrev. month March', 'Mar'), + pgettext('abbrev. month April', 'Apr'), + pgettext('abbrev. month May', 'May'), + pgettext('abbrev. month June', 'Jun'), + pgettext('abbrev. month July', 'Jul'), + pgettext('abbrev. month August', 'Aug'), + pgettext('abbrev. month September', 'Sep'), + pgettext('abbrev. month October', 'Oct'), + pgettext('abbrev. month November', 'Nov'), + pgettext('abbrev. month December', 'Dec') + ], + daysOfWeek: [ + pgettext('one letter Sunday', 'S'), + pgettext('one letter Monday', 'M'), + pgettext('one letter Tuesday', 'T'), + pgettext('one letter Wednesday', 'W'), + pgettext('one letter Thursday', 'T'), + pgettext('one letter Friday', 'F'), + pgettext('one letter Saturday', 'S') + ], + firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')), + isLeapYear: function(year) { + return (((year % 4) === 0) && ((year % 100) !== 0 ) || ((year % 400) === 0)); + }, + getDaysInMonth: function(month, year) { + let days; + if (month === 1 || month === 3 || month === 5 || month === 7 || month === 8 || month === 10 || month === 12) { + days = 31; + } + else if (month === 4 || month === 6 || month === 9 || month === 11) { + days = 30; + } + else if (month === 2 && CalendarNamespace.isLeapYear(year)) { + days = 29; + } + else { + days = 28; + } + return days; + }, + draw: function(month, year, div_id, callback, selected) { // month = 1-12, year = 1-9999 + const today = new Date(); + const todayDay = today.getDate(); + const todayMonth = today.getMonth() + 1; + const todayYear = today.getFullYear(); + let todayClass = ''; + + // Use UTC functions here because the date field does not contain time + // and using the UTC function variants prevent the local time offset + // from altering the date, specifically the day field. For example: + // + // ``` + // var x = new Date('2013-10-02'); + // var day = x.getDate(); + // ``` + // + // The day variable above will be 1 instead of 2 in, say, US Pacific time + // zone. + let isSelectedMonth = false; + if (typeof selected !== 'undefined') { + isSelectedMonth = (selected.getUTCFullYear() === year && (selected.getUTCMonth() + 1) === month); + } + + month = parseInt(month); + year = parseInt(year); + const calDiv = document.getElementById(div_id); + removeChildren(calDiv); + const calTable = document.createElement('table'); + quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month - 1] + ' ' + year); + const tableBody = quickElement('tbody', calTable); + + // Draw days-of-week header + let tableRow = quickElement('tr', tableBody); + for (let i = 0; i < 7; i++) { + quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]); + } + + const startingPos = new Date(year, month - 1, 1 - CalendarNamespace.firstDayOfWeek).getDay(); + const days = CalendarNamespace.getDaysInMonth(month, year); + + let nonDayCell; + + // Draw blanks before first of month + tableRow = quickElement('tr', tableBody); + for (let i = 0; i < startingPos; i++) { + nonDayCell = quickElement('td', tableRow, ' '); + nonDayCell.className = "nonday"; + } + + function calendarMonth(y, m) { + function onClick(e) { + e.preventDefault(); + callback(y, m, this.textContent); + } + return onClick; + } + + // Draw days of month + let currentDay = 1; + for (let i = startingPos; currentDay <= days; i++) { + if (i % 7 === 0 && currentDay !== 1) { + tableRow = quickElement('tr', tableBody); + } + if ((currentDay === todayDay) && (month === todayMonth) && (year === todayYear)) { + todayClass = 'today'; + } else { + todayClass = ''; + } + + // use UTC function; see above for explanation. + if (isSelectedMonth && currentDay === selected.getUTCDate()) { + if (todayClass !== '') { + todayClass += " "; + } + todayClass += "selected"; + } + + const cell = quickElement('td', tableRow, '', 'class', todayClass); + const link = quickElement('a', cell, currentDay, 'href', '#'); + link.addEventListener('click', calendarMonth(year, month)); + currentDay++; + } + + // Draw blanks after end of month (optional, but makes for valid code) + while (tableRow.childNodes.length < 7) { + nonDayCell = quickElement('td', tableRow, ' '); + nonDayCell.className = "nonday"; + } + + calDiv.appendChild(calTable); + } + }; + + // Calendar -- A calendar instance + function Calendar(div_id, callback, selected) { + // div_id (string) is the ID of the element in which the calendar will + // be displayed + // callback (string) is the name of a JavaScript function that will be + // called with the parameters (year, month, day) when a day in the + // calendar is clicked + this.div_id = div_id; + this.callback = callback; + this.today = new Date(); + this.currentMonth = this.today.getMonth() + 1; + this.currentYear = this.today.getFullYear(); + if (typeof selected !== 'undefined') { + this.selected = selected; + } + } + Calendar.prototype = { + drawCurrent: function() { + CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback, this.selected); + }, + drawDate: function(month, year, selected) { + this.currentMonth = month; + this.currentYear = year; + + if(selected) { + this.selected = selected; + } + + this.drawCurrent(); + }, + drawPreviousMonth: function() { + if (this.currentMonth === 1) { + this.currentMonth = 12; + this.currentYear--; + } + else { + this.currentMonth--; + } + this.drawCurrent(); + }, + drawNextMonth: function() { + if (this.currentMonth === 12) { + this.currentMonth = 1; + this.currentYear++; + } + else { + this.currentMonth++; + } + this.drawCurrent(); + }, + drawPreviousYear: function() { + this.currentYear--; + this.drawCurrent(); + }, + drawNextYear: function() { + this.currentYear++; + this.drawCurrent(); + } + }; + window.Calendar = Calendar; + window.CalendarNamespace = CalendarNamespace; +} diff --git a/staticfiles/admin/js/calendar.js.gz b/staticfiles/admin/js/calendar.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..8f7f5c5012deb9ae26bba2d697ddba358bad4531 GIT binary patch literal 2193 zcmV;C2yXWuiwFP!00002|IJx#bKAHP{;pqvrqdG@Q?jL`&E<6d;Ira6=i(%Db|#a_ zWE_ZGS*RgWB|$m5p8tDy0lpJtXty7#%)|t-Z`fVzJ^&A&-pFvtCA$Ho;G1&UHh;p0 z>s1(SI6nU?5#H@92^$D-6u~Ck!RcB^KZ4-t;o$J;z~d4EpGT8_#%#<^(-B)Gfu}?m z#B8}|Cw?S&zXs6;CKj&PuU8juShkvR1d=Q8 z*&5^)O3Tr*J$z6W@yE>Qrr#zE)H;5*`UE`siG9xB(=T-mY{VOg+TMscgFZ{x~Ch-~=Wm(2tgdGMhxj|n&O;6r~s zd!uFFmqVup`5+1Uvq`*P)ph-~=Wmn~0E zWW#5Bmil~;Ir{qpL1aq{W< z-P!fWSFe5>j!No9{08{el>Mx2IC~t9O5K5e5uiB%a~wU({>Gk<*zxf(I~uVceqj0A z=@Gv83%zF}_UE6)#B-W345N82`M$6OZN{a<=fMRfUdbArh%U1kg|5=cH?O=ED`uFq zzA2ee44+kpf3FT-REIxShts3lcvd$k+YQ)UpG~V)-B(5+5d>5XeO?v*kLvJcP4%=( z_0a=W&nSisgfJH zGje+U!WppxHf?44WUS43&JrngtZI5_lW3w-$z$^O5MgJ90v+)I1N7nQw1j5Y5CL0) z#|f^gHDCl3V95dLGe1N~8ib0>QCtK}i4D|6^1x?FEP@-&T^7!EoFKM}*%n(3!eUJ! zLkyFagaCIHgQ^Q$Md5~ViN!G!N+w}Ux8RADpdjzl*L!2=gt0S3;P8!awi14-39QTi z`t@u56&lLEl_Nf!9ZjE&r$^(X*|6s4l-#7qx3;KT_0%b@(nV-LEhR9%#P-eZgp?Q( zENKF>0Ju*lff)|a2Ym0c50~sc*RHSzRr@WVzHA5S zDnG)u&bV4KF(H#H$%wFK1g9BS; z)&#FJ!Kl{eu>#?Kb_9B;Nm0dOBSbtezI5lOacQi0q_Cd7594y3G5sr#jf;DJ{C%ya z=l8)=3`V6orNvel{&#UMIk7e3 zh22ekekJ_432Hj4{1cBFDftg2Jqh&byRHC5{*r+tH znxq|c0V|$JxMb)h;k*oC9a>34J>R6Idv^TJJB3GsIio|seet|9Q(N3v^$Q>aLS84KF&d+IXx9f zynusd#`LFb;!_(6*Ctmmo*oS?=Cy(GrU)DNpz#W0oz%eN96>^cSymcy zRKp3?K+*DRc)%d5Hcx1@QY=LSm0=rkZQTdBrP&kvF1jD|V9qRk(#v~k^Y2rY=psN@ z9(tYYv}B->DMfJGkjbeJXP)}Y>m=kKK!*MOkM6nIO1#>aK<5KwO1Rq8fk#~r~ z023qi=)@yb_7=(F39jG69Q=H8JnghFtoXK;IBf@(}4` z0}niNGRV73M(lJRmj|WL7(ztpijHC<#QFN%b-tkR&=VL3p+a)Ix7IInGw2*s7Dqok z*7zdEI)OGHFuN+h zMaY?2uM)~^**!vq%XXRYh(n+jniCggypg*4|11#^)PyP|Rh5rabklQcY%X2+)Kyx* zJMuXVN4X6rxaDxU)#$j@rHopyq9{OZ*HO0J)D}d|IBz9OgGO>|FkGyhHa-0!VyQyL zFNOP^_VvF+PEFd#2fdALE&BDUZmT+NX%FtzwJs17q<(ZS~c5YRh`E#vUT@5pv{hxj2Sf=gS}I T8}H_W`@w$zFPw%U5+MKp!v8}) literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/cancel.ecc4c5ca7b32.js b/staticfiles/admin/js/cancel.ecc4c5ca7b32.js new file mode 100644 index 0000000000..3069c6f27b --- /dev/null +++ b/staticfiles/admin/js/cancel.ecc4c5ca7b32.js @@ -0,0 +1,29 @@ +'use strict'; +{ + // Call function fn when the DOM is loaded and ready. If it is already + // loaded, call the function now. + // http://youmightnotneedjquery.com/#ready + function ready(fn) { + if (document.readyState !== 'loading') { + fn(); + } else { + document.addEventListener('DOMContentLoaded', fn); + } + } + + ready(function() { + function handleClick(event) { + event.preventDefault(); + const params = new URLSearchParams(window.location.search); + if (params.has('_popup')) { + window.close(); // Close the popup. + } else { + window.history.back(); // Otherwise, go back. + } + } + + document.querySelectorAll('.cancel-link').forEach(function(el) { + el.addEventListener('click', handleClick); + }); + }); +} diff --git a/staticfiles/admin/js/cancel.ecc4c5ca7b32.js.gz b/staticfiles/admin/js/cancel.ecc4c5ca7b32.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..e0c886974223da9706eee8365a046b8de8e94940 GIT binary patch literal 430 zcmV;f0a5-RiwFP!00002|80`NZX6*DhVSzfu5y5tw#>cJ9;!_al@cY&s^^M=XCYzD z1elCgRo=b8Y$lUUd;nz3hyB}ZhzKzSs}j3x{xy)TZDA{&gKi*|tS9IQMuP;&AY9$u zf{oz3)Tlv{hJaEZ1^nv3rg9}+^}L~`$Tg^fEQA?LeiUy}CZ+yI+aCRJuzQopCqmSZ z&jW^|Q2x+fyhCR|b@7f?FeP5hcEGh)!vQIY8n8<;A$;3xfR$VnRmqt(C1aaLH??wQi@JPbKhWCUadT%j$6Jta{>D z{yNXMIz=DqeubSJTv}F8OnHh4dKu&)!UhOO`2BFRLm8C0uUcJ9;!_al@cY&s^^M=XCYzD z1elCgRo=b8Y$lUUd;nz3hyB}ZhzKzSs}j3x{xy)TZDA{&gKi*|tS9IQMuP;&AY9$u zf{oz3)Tlv{hJaEZ1^nv3rg9}+^}L~`$Tg^fEQA?LeiUy}CZ+yI+aCRJuzQopCqmSZ z&jW^|Q2x+fyhCR|b@7f?FeP5hcEGh)!vQIY8n8<;A$;3xfR$VnRmqt(C1aaLH??wQi@JPbKhWCUadT%j$6Jta{>D z{yNXMIz=DqeubSJTv}F8OnHh4dKu&)!UhOO`2BFRLm8C0uU^8ca zNHU9v^xaLm?e+(8u1+SI@61eC;}JYLof8`+KM91$t?>lfd^RLx>ERY$*<>liGrba`&M9M0Ra`HV@DO2y#ly)Fh zt<9jYt`1TSb^vL}vp!dnq(|Z%uJzCbq+O~HZRbbxi2BF(*xNO*xA>U#M;#)ZA#FL> z7J)5xNWMS&Q^y#?A>50H+1`WOq6j@Nq>Hr^8ca zNHU9v^xaLm?e+(8u1+SI@61eC;}JYLof8`+KM91$t?>lfd^RLx>ERY$*<>liGrba`&M9M0Ra`HV@DO2y#ly)Fh zt<9jYt`1TSb^vL}vp!dnq(|Z%uJzCbq+O~HZRbbxi2BF(*xNO*xA>U#M;#)ZA#FL> z7J)5xNWMS&Q^y#?A>50H+1`WOq6j@Nq>Hr>#|m#8^TV zDU)P(!;pU;6(@F@*yyn7A_d_iAIV30aaFtUT{@^SXZ)G37Bki)gp{LIncd8O&w$Re z^*THYsr9NwpFi1@(PQMy1*zE_){R%$2G1+#0Oc$eaH};)uS|%LWesb(A5C~(e6$+D zS^v}Njm6Iuz!j~>^cFbI#rv9>+=9;Q_$%Zp?Jq;>N zIW4}5C^N3e3;p6ujv)(1SWU3LGe>%n!CSBskbO!Ia)SkVM7+zPt{t)ojET4|=5MA9 zii+=oCw*qJJII=|BD*o}=32<@7QMbR)@gp0_ZPxG1dW^lXVvTQ!r(uGR2MOJv&+|E zuDUwWwO8vRQGzG4b~ad@@dp}HDoQ`C*q+O6FW^>W8L4t&BeOCzC`_DpryA91E4C5K zg1E=EY+U9ewIHLE!}fCwTUpC)X-tW+pSL9pq?8K@Qy#X!SX)aT!p~Y9mdPmbtyLpmriTQ7Ar>0|q?duz8H>Kji z^l$e2Cg`T9P0&(bNoDvTU3cC#bR*v<<*a(557eOl6SBL*yWG3kA3me4rwa!F02yH? AasU7T literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/collapse.js b/staticfiles/admin/js/collapse.js new file mode 100644 index 0000000000..c6c7b0f68a --- /dev/null +++ b/staticfiles/admin/js/collapse.js @@ -0,0 +1,43 @@ +/*global gettext*/ +'use strict'; +{ + window.addEventListener('load', function() { + // Add anchor tag for Show/Hide link + const fieldsets = document.querySelectorAll('fieldset.collapse'); + for (const [i, elem] of fieldsets.entries()) { + // Don't hide if fields in this fieldset have errors + if (elem.querySelectorAll('div.errors, ul.errorlist').length === 0) { + elem.classList.add('collapsed'); + const h2 = elem.querySelector('h2'); + const link = document.createElement('a'); + link.id = 'fieldsetcollapser' + i; + link.className = 'collapse-toggle'; + link.href = '#'; + link.textContent = gettext('Show'); + h2.appendChild(document.createTextNode(' (')); + h2.appendChild(link); + h2.appendChild(document.createTextNode(')')); + } + } + // Add toggle to hide/show anchor tag + const toggleFunc = function(ev) { + if (ev.target.matches('.collapse-toggle')) { + ev.preventDefault(); + ev.stopPropagation(); + const fieldset = ev.target.closest('fieldset'); + if (fieldset.classList.contains('collapsed')) { + // Show + ev.target.textContent = gettext('Hide'); + fieldset.classList.remove('collapsed'); + } else { + // Hide + ev.target.textContent = gettext('Show'); + fieldset.classList.add('collapsed'); + } + } + }; + document.querySelectorAll('fieldset.module').forEach(function(el) { + el.addEventListener('click', toggleFunc); + }); + }); +} diff --git a/staticfiles/admin/js/collapse.js.gz b/staticfiles/admin/js/collapse.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..9770c138207a52d5bcbd72f9985789369b9de1c1 GIT binary patch literal 614 zcmV-s0-60EiwFP!00002|D{#IZrd;nz2_?k>>#|m#8^TV zDU)P(!;pU;6(@F@*yyn7A_d_iAIV30aaFtUT{@^SXZ)G37Bki)gp{LIncd8O&w$Re z^*THYsr9NwpFi1@(PQMy1*zE_){R%$2G1+#0Oc$eaH};)uS|%LWesb(A5C~(e6$+D zS^v}Njm6Iuz!j~>^cFbI#rv9>+=9;Q_$%Zp?Jq;>N zIW4}5C^N3e3;p6ujv)(1SWU3LGe>%n!CSBskbO!Ia)SkVM7+zPt{t)ojET4|=5MA9 zii+=oCw*qJJII=|BD*o}=32<@7QMbR)@gp0_ZPxG1dW^lXVvTQ!r(uGR2MOJv&+|E zuDUwWwO8vRQGzG4b~ad@@dp}HDoQ`C*q+O6FW^>W8L4t&BeOCzC`_DpryA91E4C5K zg1E=EY+U9ewIHLE!}fCwTUpC)X-tW+pSL9pq?8K@Qy#X!SX)aT!p~Y9mdPmbtyLpmriTQ7Ar>0|q?duz8H>Kji z^l$e2Cg`T9P0&(bNoDvTU3cC#bR*v<<*a(557eOl6SBL*yWG3kA3me4rwa!F02yH? AasU7T literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/core.cf103cd04ebf.js b/staticfiles/admin/js/core.cf103cd04ebf.js new file mode 100644 index 0000000000..0344a13f42 --- /dev/null +++ b/staticfiles/admin/js/core.cf103cd04ebf.js @@ -0,0 +1,170 @@ +// Core JavaScript helper functions +'use strict'; + +// quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]); +function quickElement() { + const obj = document.createElement(arguments[0]); + if (arguments[2]) { + const textNode = document.createTextNode(arguments[2]); + obj.appendChild(textNode); + } + const len = arguments.length; + for (let i = 3; i < len; i += 2) { + obj.setAttribute(arguments[i], arguments[i + 1]); + } + arguments[1].appendChild(obj); + return obj; +} + +// "a" is reference to an object +function removeChildren(a) { + while (a.hasChildNodes()) { + a.removeChild(a.lastChild); + } +} + +// ---------------------------------------------------------------------------- +// Find-position functions by PPK +// See https://www.quirksmode.org/js/findpos.html +// ---------------------------------------------------------------------------- +function findPosX(obj) { + let curleft = 0; + if (obj.offsetParent) { + while (obj.offsetParent) { + curleft += obj.offsetLeft - obj.scrollLeft; + obj = obj.offsetParent; + } + } else if (obj.x) { + curleft += obj.x; + } + return curleft; +} + +function findPosY(obj) { + let curtop = 0; + if (obj.offsetParent) { + while (obj.offsetParent) { + curtop += obj.offsetTop - obj.scrollTop; + obj = obj.offsetParent; + } + } else if (obj.y) { + curtop += obj.y; + } + return curtop; +} + +//----------------------------------------------------------------------------- +// Date object extensions +// ---------------------------------------------------------------------------- +{ + Date.prototype.getTwelveHours = function() { + return this.getHours() % 12 || 12; + }; + + Date.prototype.getTwoDigitMonth = function() { + return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1); + }; + + Date.prototype.getTwoDigitDate = function() { + return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate(); + }; + + Date.prototype.getTwoDigitTwelveHour = function() { + return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours(); + }; + + Date.prototype.getTwoDigitHour = function() { + return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours(); + }; + + Date.prototype.getTwoDigitMinute = function() { + return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes(); + }; + + Date.prototype.getTwoDigitSecond = function() { + return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); + }; + + Date.prototype.getAbbrevMonthName = function() { + return typeof window.CalendarNamespace === "undefined" + ? this.getTwoDigitMonth() + : window.CalendarNamespace.monthsOfYearAbbrev[this.getMonth()]; + }; + + Date.prototype.getFullMonthName = function() { + return typeof window.CalendarNamespace === "undefined" + ? this.getTwoDigitMonth() + : window.CalendarNamespace.monthsOfYear[this.getMonth()]; + }; + + Date.prototype.strftime = function(format) { + const fields = { + b: this.getAbbrevMonthName(), + B: this.getFullMonthName(), + c: this.toString(), + d: this.getTwoDigitDate(), + H: this.getTwoDigitHour(), + I: this.getTwoDigitTwelveHour(), + m: this.getTwoDigitMonth(), + M: this.getTwoDigitMinute(), + p: (this.getHours() >= 12) ? 'PM' : 'AM', + S: this.getTwoDigitSecond(), + w: '0' + this.getDay(), + x: this.toLocaleDateString(), + X: this.toLocaleTimeString(), + y: ('' + this.getFullYear()).substr(2, 4), + Y: '' + this.getFullYear(), + '%': '%' + }; + let result = '', i = 0; + while (i < format.length) { + if (format.charAt(i) === '%') { + result += fields[format.charAt(i + 1)]; + ++i; + } + else { + result += format.charAt(i); + } + ++i; + } + return result; + }; + + // ---------------------------------------------------------------------------- + // String object extensions + // ---------------------------------------------------------------------------- + String.prototype.strptime = function(format) { + const split_format = format.split(/[.\-/]/); + const date = this.split(/[.\-/]/); + let i = 0; + let day, month, year; + while (i < split_format.length) { + switch (split_format[i]) { + case "%d": + day = date[i]; + break; + case "%m": + month = date[i] - 1; + break; + case "%Y": + year = date[i]; + break; + case "%y": + // A %y value in the range of [00, 68] is in the current + // century, while [69, 99] is in the previous century, + // according to the Open Group Specification. + if (parseInt(date[i], 10) >= 69) { + year = date[i]; + } else { + year = (new Date(Date.UTC(date[i], 0))).getUTCFullYear() + 100; + } + break; + } + ++i; + } + // Create Date object from UTC since the parsed value is supposed to be + // in UTC, not local time. Also, the calendar uses UTC functions for + // date extraction. + return new Date(Date.UTC(year, month, day)); + }; +} diff --git a/staticfiles/admin/js/core.cf103cd04ebf.js.gz b/staticfiles/admin/js/core.cf103cd04ebf.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..39bab4a5f8cb356202d201efe2624106b584e6ee GIT binary patch literal 1505 zcmV<71s?hziwFP!00002|J7J+Z`(Ey{_bCK2oP9C6xqp!Vv(B_S-QS#O&cuP(7-bW zTB2+=vZ#?%9Aou=-;t6nQIZp9NI%RUY>RyE?&00>cvQa+=UhBNr6C zSMQVa8H>Y@JVXppsArO?>fb*|oKf&RZ`>Pp)@E%RJ@}^s_z94Y0zUZyrx5ZW)018x zC{c6`C1PrZdlNJT<|l+UsJ*RxsSiBNvaPDNRDNN@uO9fUGLC zW167;jUEr5r)rktA}+v*sRD+O?}qsEQsecXgHt%JGS(I)RcCAWRhY4{3za80fTOWR zq?|k&TeMMW0TfhaBGFccot2699@zsXabg`<#eo>M}V)mARK{A?mscuwa_kcpT^3bSTV zCc91%9z~cXmu62^U0sCZA&5!YLN8`t3H_i)4)Y8Q1dn4qFtp_Iy;;{@V)8s(0gbV! zthwG>JJPm%U(MelISYtM(7K0iT0Eq9`Yjx!)mr|!#(}DP@c9|Mv#fciVs_c?9Hs4= z9dr2HJLWak#A53MmO7e9b4EOO-scO}#=KN;#TA|~-V{B&pz$4j$1@?(k?YtyRSy+z zP%|dAguxsS0Pe1=EaHXHmkn=*C56E%CpinBIjz=(JWCp~xt-9ZDLB!1;9)^v>*tk7WLso3s>te#2pTNwi__nlN1q>ah1sSXspC;JLpoRyOXU1!wks9hmyf()Qyi zo_=QMUS4!D?%lJCt}S)dRG;tRy84CRI82sx%>BmQA9#SdrG44%_|G-uHD*pba*508 zR_*G5>-5C?geS8J=ACow!uK_?8>HJVW#hX0U0;8d4O!Wn>0VM$nZ>%sRT~WJ zeWSj)<(Xbw@am1DZtDs_FvA+69M&`2812@vc_A=1vE$1(%BUu6nuqbQA$M@V?7@}w zWLnGzt<^X_q|CCls@Jewr(G|eyJ0MJ=2_FypnfZxxk0<~rMp%>nZ`{0mCwS)<7U+9 zkGww*`{RDa@3~Nz_kSjpw?fyi5(f5ANR}>`s_w!P^S?EFtE{%}J^;?!=4li-~X4s}E!0}9A9P^NkUYxja za#9se@vvk(lN)H88WIFtgnF|mZlpe?G=aB*XDM8zG++@6h|XTGA+0M|N`$2E6Xg^h za!pf+C(MhJwj#EROIO=!QbpKF=)&|Gj%hf4zdkPs40?D5U~$L6vcBu;I2g1T+a;nq z6*=_fxp`G+-Hju`=YUK=GV{tzhef+AT<3rUnWZV$BN%`Qt?I)#qNocAR}kwH5p+fI z;4GHh&GVz^)gY5p8aw67E8LD%Wu{(WB@`sE!&y}4rbo4}H)R4hYOn0ySDk+WO`@tS HG8O;;VD= 12) ? 'PM' : 'AM', + S: this.getTwoDigitSecond(), + w: '0' + this.getDay(), + x: this.toLocaleDateString(), + X: this.toLocaleTimeString(), + y: ('' + this.getFullYear()).substr(2, 4), + Y: '' + this.getFullYear(), + '%': '%' + }; + let result = '', i = 0; + while (i < format.length) { + if (format.charAt(i) === '%') { + result += fields[format.charAt(i + 1)]; + ++i; + } + else { + result += format.charAt(i); + } + ++i; + } + return result; + }; + + // ---------------------------------------------------------------------------- + // String object extensions + // ---------------------------------------------------------------------------- + String.prototype.strptime = function(format) { + const split_format = format.split(/[.\-/]/); + const date = this.split(/[.\-/]/); + let i = 0; + let day, month, year; + while (i < split_format.length) { + switch (split_format[i]) { + case "%d": + day = date[i]; + break; + case "%m": + month = date[i] - 1; + break; + case "%Y": + year = date[i]; + break; + case "%y": + // A %y value in the range of [00, 68] is in the current + // century, while [69, 99] is in the previous century, + // according to the Open Group Specification. + if (parseInt(date[i], 10) >= 69) { + year = date[i]; + } else { + year = (new Date(Date.UTC(date[i], 0))).getUTCFullYear() + 100; + } + break; + } + ++i; + } + // Create Date object from UTC since the parsed value is supposed to be + // in UTC, not local time. Also, the calendar uses UTC functions for + // date extraction. + return new Date(Date.UTC(year, month, day)); + }; +} diff --git a/staticfiles/admin/js/core.js.gz b/staticfiles/admin/js/core.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..39bab4a5f8cb356202d201efe2624106b584e6ee GIT binary patch literal 1505 zcmV<71s?hziwFP!00002|J7J+Z`(Ey{_bCK2oP9C6xqp!Vv(B_S-QS#O&cuP(7-bW zTB2+=vZ#?%9Aou=-;t6nQIZp9NI%RUY>RyE?&00>cvQa+=UhBNr6C zSMQVa8H>Y@JVXppsArO?>fb*|oKf&RZ`>Pp)@E%RJ@}^s_z94Y0zUZyrx5ZW)018x zC{c6`C1PrZdlNJT<|l+UsJ*RxsSiBNvaPDNRDNN@uO9fUGLC zW167;jUEr5r)rktA}+v*sRD+O?}qsEQsecXgHt%JGS(I)RcCAWRhY4{3za80fTOWR zq?|k&TeMMW0TfhaBGFccot2699@zsXabg`<#eo>M}V)mARK{A?mscuwa_kcpT^3bSTV zCc91%9z~cXmu62^U0sCZA&5!YLN8`t3H_i)4)Y8Q1dn4qFtp_Iy;;{@V)8s(0gbV! zthwG>JJPm%U(MelISYtM(7K0iT0Eq9`Yjx!)mr|!#(}DP@c9|Mv#fciVs_c?9Hs4= z9dr2HJLWak#A53MmO7e9b4EOO-scO}#=KN;#TA|~-V{B&pz$4j$1@?(k?YtyRSy+z zP%|dAguxsS0Pe1=EaHXHmkn=*C56E%CpinBIjz=(JWCp~xt-9ZDLB!1;9)^v>*tk7WLso3s>te#2pTNwi__nlN1q>ah1sSXspC;JLpoRyOXU1!wks9hmyf()Qyi zo_=QMUS4!D?%lJCt}S)dRG;tRy84CRI82sx%>BmQA9#SdrG44%_|G-uHD*pba*508 zR_*G5>-5C?geS8J=ACow!uK_?8>HJVW#hX0U0;8d4O!Wn>0VM$nZ>%sRT~WJ zeWSj)<(Xbw@am1DZtDs_FvA+69M&`2812@vc_A=1vE$1(%BUu6nuqbQA$M@V?7@}w zWLnGzt<^X_q|CCls@Jewr(G|eyJ0MJ=2_FypnfZxxk0<~rMp%>nZ`{0mCwS)<7U+9 zkGww*`{RDa@3~Nz_kSjpw?fyi5(f5ANR}>`s_w!P^S?EFtE{%}J^;?!=4li-~X4s}E!0}9A9P^NkUYxja za#9se@vvk(lN)H88WIFtgnF|mZlpe?G=aB*XDM8zG++@6h|XTGA+0M|N`$2E6Xg^h za!pf+C(MhJwj#EROIO=!QbpKF=)&|Gj%hf4zdkPs40?D5U~$L6vcBu;I2g1T+a;nq z6*=_fxp`G+-Hju`=YUK=GV{tzhef+AT<3rUnWZV$BN%`Qt?I)#qNocAR}kwH5p+fI z;4GHh&GVz^)gY5p8aw67E8LD%Wu{(WB@`sE!&y}4rbo4}H)R4hYOn0ySDk+WO`@tS HG8O;;VD { + const detailElement = document.querySelector(`[data-filter-title='${CSS.escape(key)}']`); + + // Check if the filter is present, it could be from other view. + if (detailElement) { + value ? detailElement.setAttribute('open', '') : detailElement.removeAttribute('open'); + } + }); + + // Save filter state when clicks. + const details = document.querySelectorAll('details'); + details.forEach(detail => { + detail.addEventListener('toggle', event => { + filters[`${event.target.dataset.filterTitle}`] = detail.open; + sessionStorage.setItem('django.admin.filtersState', JSON.stringify(filters)); + }); + }); +} diff --git a/staticfiles/admin/js/filters.0e360b7a9f80.js.gz b/staticfiles/admin/js/filters.0e360b7a9f80.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..5bb1833c00073b8da176fa5f911fad53ec5f4caa GIT binary patch literal 502 zcmVYRJdJ)TV_2~6M@I0^-^0+>DPVKxqZTkzan>Un! zqoIb;r{}ADYu!S~U79ZUc$`8bbd9SF9v&}1r8VSBfk7y}(0CvaA}Fk^ { + const detailElement = document.querySelector(`[data-filter-title='${CSS.escape(key)}']`); + + // Check if the filter is present, it could be from other view. + if (detailElement) { + value ? detailElement.setAttribute('open', '') : detailElement.removeAttribute('open'); + } + }); + + // Save filter state when clicks. + const details = document.querySelectorAll('details'); + details.forEach(detail => { + detail.addEventListener('toggle', event => { + filters[`${event.target.dataset.filterTitle}`] = detail.open; + sessionStorage.setItem('django.admin.filtersState', JSON.stringify(filters)); + }); + }); +} diff --git a/staticfiles/admin/js/filters.js.gz b/staticfiles/admin/js/filters.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..5bb1833c00073b8da176fa5f911fad53ec5f4caa GIT binary patch literal 502 zcmVYRJdJ)TV_2~6M@I0^-^0+>DPVKxqZTkzan>Un! zqoIb;r{}ADYu!S~U79ZUc$`8bbd9SF9v&}1r8VSBfk7y}(0CvaA}Fk^' + options.addText + ""); + addButton = $parent.find("tr:last a"); + } else { + // Otherwise, insert it immediately after the last form: + $this.filter(":last").after('"); + addButton = $this.filter(":last").next().find("a"); + } + } + addButton.on('click', addInlineClickHandler); + }; + + const addInlineClickHandler = function(e) { + e.preventDefault(); + const template = $("#" + options.prefix + "-empty"); + const row = template.clone(true); + row.removeClass(options.emptyCssClass) + .addClass(options.formCssClass) + .attr("id", options.prefix + "-" + nextIndex); + addInlineDeleteButton(row); + row.find("*").each(function() { + updateElementIndex(this, options.prefix, totalForms.val()); + }); + // Insert the new form when it has been fully edited. + row.insertBefore($(template)); + // Update number of total forms. + $(totalForms).val(parseInt(totalForms.val(), 10) + 1); + nextIndex += 1; + // Hide the add button if there's a limit and it's been reached. + if ((maxForms.val() !== '') && (maxForms.val() - totalForms.val()) <= 0) { + addButton.parent().hide(); + } + // Show the remove buttons if there are more than min_num. + toggleDeleteButtonVisibility(row.closest('.inline-group')); + + // Pass the new form to the post-add callback, if provided. + if (options.added) { + options.added(row); + } + row.get(0).dispatchEvent(new CustomEvent("formset:added", { + bubbles: true, + detail: { + formsetName: options.prefix + } + })); + }; + + /** + * The "X" button that is part of every unsaved inline. + * (When saved, it is replaced with a "Delete" checkbox.) + */ + const addInlineDeleteButton = function(row) { + if (row.is("tr")) { + // If the forms are laid out in table rows, insert + // the remove button into the last table cell: + row.children(":last").append('"); + } else if (row.is("ul") || row.is("ol")) { + // If they're laid out as an ordered/unordered list, + // insert an
  • after the last list item: + row.append('
  • ' + options.deleteText + "
  • "); + } else { + // Otherwise, just insert the remove button as the + // last child element of the form's container: + row.children(":first").append('' + options.deleteText + ""); + } + // Add delete handler for each row. + row.find("a." + options.deleteCssClass).on('click', inlineDeleteHandler.bind(this)); + }; + + const inlineDeleteHandler = function(e1) { + e1.preventDefault(); + const deleteButton = $(e1.target); + const row = deleteButton.closest('.' + options.formCssClass); + const inlineGroup = row.closest('.inline-group'); + // Remove the parent form containing this button, + // and also remove the relevant row with non-field errors: + const prevRow = row.prev(); + if (prevRow.length && prevRow.hasClass('row-form-errors')) { + prevRow.remove(); + } + row.remove(); + nextIndex -= 1; + // Pass the deleted form to the post-delete callback, if provided. + if (options.removed) { + options.removed(row); + } + document.dispatchEvent(new CustomEvent("formset:removed", { + detail: { + formsetName: options.prefix + } + })); + // Update the TOTAL_FORMS form count. + const forms = $("." + options.formCssClass); + $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length); + // Show add button again once below maximum number. + if ((maxForms.val() === '') || (maxForms.val() - forms.length) > 0) { + addButton.parent().show(); + } + // Hide the remove buttons if at min_num. + toggleDeleteButtonVisibility(inlineGroup); + // Also, update names and ids for all remaining form controls so + // they remain in sequence: + let i, formCount; + const updateElementCallback = function() { + updateElementIndex(this, options.prefix, i); + }; + for (i = 0, formCount = forms.length; i < formCount; i++) { + updateElementIndex($(forms).get(i), options.prefix, i); + $(forms.get(i)).find("*").each(updateElementCallback); + } + }; + + const toggleDeleteButtonVisibility = function(inlineGroup) { + if ((minForms.val() !== '') && (minForms.val() - totalForms.val()) >= 0) { + inlineGroup.find('.inline-deletelink').hide(); + } else { + inlineGroup.find('.inline-deletelink').show(); + } + }; + + $this.each(function(i) { + $(this).not("." + options.emptyCssClass).addClass(options.formCssClass); + }); + + // Create the delete buttons for all unsaved inlines: + $this.filter('.' + options.formCssClass + ':not(.has_original):not(.' + options.emptyCssClass + ')').each(function() { + addInlineDeleteButton($(this)); + }); + toggleDeleteButtonVisibility($this); + + // Create the add button, initially hidden. + addButton = options.addButton; + addInlineAddButton(); + + // Show the add button if allowed to add more items. + // Note that max_num = None translates to a blank string. + const showAddButton = maxForms.val() === '' || (maxForms.val() - totalForms.val()) > 0; + if ($this.length && showAddButton) { + addButton.parent().show(); + } else { + addButton.parent().hide(); + } + + return this; + }; + + /* Setup plugin defaults */ + $.fn.formset.defaults = { + prefix: "form", // The form prefix for your django formset + addText: "add another", // Text for the add link + deleteText: "remove", // Text for the delete link + addCssClass: "add-row", // CSS class applied to the add link + deleteCssClass: "delete-row", // CSS class applied to the delete link + emptyCssClass: "empty-row", // CSS class applied to the empty row + formCssClass: "dynamic-form", // CSS class applied to each form in a formset + added: null, // Function called each time a new form is added + removed: null, // Function called each time a form is deleted + addButton: null // Existing add button to use + }; + + + // Tabular inlines --------------------------------------------------------- + $.fn.tabularFormset = function(selector, options) { + const $rows = $(this); + + const reinitDateTimeShortCuts = function() { + // Reinitialize the calendar and clock widgets by force + if (typeof DateTimeShortcuts !== "undefined") { + $(".datetimeshortcuts").remove(); + DateTimeShortcuts.init(); + } + }; + + const updateSelectFilter = function() { + // If any SelectFilter widgets are a part of the new form, + // instantiate a new SelectFilter instance for it. + if (typeof SelectFilter !== 'undefined') { + $('.selectfilter').each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, false); + }); + $('.selectfilterstacked').each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, true); + }); + } + }; + + const initPrepopulatedFields = function(row) { + row.find('.prepopulated_field').each(function() { + const field = $(this), + input = field.find('input, select, textarea'), + dependency_list = input.data('dependency_list') || [], + dependencies = []; + $.each(dependency_list, function(i, field_name) { + dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id')); + }); + if (dependencies.length) { + input.prepopulate(dependencies, input.attr('maxlength')); + } + }); + }; + + $rows.formset({ + prefix: options.prefix, + addText: options.addText, + formCssClass: "dynamic-" + options.prefix, + deleteCssClass: "inline-deletelink", + deleteText: options.deleteText, + emptyCssClass: "empty-form", + added: function(row) { + initPrepopulatedFields(row); + reinitDateTimeShortCuts(); + updateSelectFilter(); + }, + addButton: options.addButton + }); + + return $rows; + }; + + // Stacked inlines --------------------------------------------------------- + $.fn.stackedFormset = function(selector, options) { + const $rows = $(this); + const updateInlineLabel = function(row) { + $(selector).find(".inline_label").each(function(i) { + const count = i + 1; + $(this).html($(this).html().replace(/(#\d+)/g, "#" + count)); + }); + }; + + const reinitDateTimeShortCuts = function() { + // Reinitialize the calendar and clock widgets by force, yuck. + if (typeof DateTimeShortcuts !== "undefined") { + $(".datetimeshortcuts").remove(); + DateTimeShortcuts.init(); + } + }; + + const updateSelectFilter = function() { + // If any SelectFilter widgets were added, instantiate a new instance. + if (typeof SelectFilter !== "undefined") { + $(".selectfilter").each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, false); + }); + $(".selectfilterstacked").each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, true); + }); + } + }; + + const initPrepopulatedFields = function(row) { + row.find('.prepopulated_field').each(function() { + const field = $(this), + input = field.find('input, select, textarea'), + dependency_list = input.data('dependency_list') || [], + dependencies = []; + $.each(dependency_list, function(i, field_name) { + // Dependency in a fieldset. + let field_element = row.find('.form-row .field-' + field_name); + // Dependency without a fieldset. + if (!field_element.length) { + field_element = row.find('.form-row.field-' + field_name); + } + dependencies.push('#' + field_element.find('input, select, textarea').attr('id')); + }); + if (dependencies.length) { + input.prepopulate(dependencies, input.attr('maxlength')); + } + }); + }; + + $rows.formset({ + prefix: options.prefix, + addText: options.addText, + formCssClass: "dynamic-" + options.prefix, + deleteCssClass: "inline-deletelink", + deleteText: options.deleteText, + emptyCssClass: "empty-form", + removed: updateInlineLabel, + added: function(row) { + initPrepopulatedFields(row); + reinitDateTimeShortCuts(); + updateSelectFilter(); + updateInlineLabel(row); + }, + addButton: options.addButton + }); + + return $rows; + }; + + $(document).ready(function() { + $(".js-inline-admin-formset").each(function() { + const data = $(this).data(), + inlineOptions = data.inlineFormset; + let selector; + switch(data.inlineType) { + case "stacked": + selector = inlineOptions.name + "-group .inline-related"; + $(selector).stackedFormset(selector, inlineOptions.options); + break; + case "tabular": + selector = inlineOptions.name + "-group .tabular.inline-related tbody:first > tr.form-row"; + $(selector).tabularFormset(selector, inlineOptions.options); + break; + } + }); + }); +} diff --git a/staticfiles/admin/js/inlines.22d4d93c00b4.js.gz b/staticfiles/admin/js/inlines.22d4d93c00b4.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..f0be39d1115cc80b60b81235514dc3c04fc01594 GIT binary patch literal 3744 zcmV;R4qx#fiwFP!00002|Lt4rbK5o&|L(s6Wjqz-P?X&dH*@l1&T*19ojB>m?p^2F zjt3GU2{A>e1ZZ2=`hUM&03<;YdbqE%FYNwy0S^ymsTk9gyrha<^98$_ zi(E|#B_ndhQZ`Yqd8$}`Fx(p+9PE(;^713iW`fXU!85|MlxIxBbA0uJN|q3jk&k~b zSiT~!MZSlIr~2VU zEc%*4&VDL*&Sbg5QT#>x7Xma>U_ZBPT!`f==d-yY;iON#I6VAo8Yg`2>V1mgJtRInYcPndV|a{zXCVOSTYMPm(XM#06RA;v*=>IDKKYMHeQjhX$EYNw~Qw&jmULQ@8IXvJ*+hoBGFU7E>g}i^39y4d|9&d7Di;K z-6Bg^PSl){ckG_LxO!Q>(o8cpB6Fpdax@%@B|H{IK4G!QXT#JClf$u02KGn1oG)SC zaIaTLMx@I5MD>pMe%>SSnTSj(vQJJ)qWO=F&X4uW{dk(iQ)}N-GA*)+;vx&hQpr9s z1ZpDi6kbXgxF53z#j+&)`7vq`i4!)ZMT&l>X&kpm?5jD~1Va4MeZ8bP%a9d4Fg8EK z&bVTkfTz4l*#cg_0bM@0+@npFIh*o_h-ArwD@aX(CpS5p>4_Pb-~*ezdRT@*7?9_7 zGJFXJ;SWC~&wshOF^_I;`u)J+rY4uOWlATSAE4+EKzhJLa}J-9a3A>W$KZ9aDrhh0 zxB1itY7L4yPx`T4IxHoMTxR+$ZXY{*ur%h0Z*Bbogwg+RS!IVsGP+=EmcdtMA^i3$ zmwIeFi4uyYI(TV^3!VWzw1#!#*fG-e`|Iqs@f}UWengHAI}W^{54&-8dH&tayKgU_#+zM(XFIO(=H1iR zK>2BsyeO0s+3{ZWT<4eab3m>k#0BRG#zX<(E+?0(O9;YgK*o9|8M9Q}>quy_5Ydq& zc4!P+a>1%^^w9Hid3W=-T@1aC)&oyryBBHdb40xD98mzPk|;V(8Og;xghUR(I#(#{Ix+#UTB!yy6xG40qA~K$Giu3- z#f3;^6+78a;oztrPv$&LAc}_lIAz&P&5yk_Y~+pUa*1)hccOAKNvV{lLC^6TVDCc8 z3w!}jd%@X>N?`p|E@@^)mTZ`}l+3};PJ?H`S&Pgy>>c#JlOa7j8LIrO9aqbbW4wyX zDF+?{m5+cC(6VppBZL#khHDM>9=-9NOIDeM!@tFXB^**qx*~L{Y>L*4pmqJ~H|m~h zfE5OsCD=rII_NRsce^QaS5*PQ-E`$;3quyTf>EGfaT`K;ML&j})|&wSxa~#thP=QB zUjh0_S?*ANbizYx3%fHKDZIVa7zV66u>DH|FhXw@Rt(}5n9qj1HSrDxsnwb^4zcL8 zA`?$ik+D$a1#69lage4K;*Mz(hUF@nbZOXrN4MJSjS1*ho5m{z#^Xs4`2^9}qRc@p z4l5PEWEjDX*+SskBZ={b18@&UC-ZP^EX7Y3dTA)v<}V`cJlIa$t=||!tMI6!9;$}i z&jCck&YVLi9W(eoh3LH^uuGLj`7KGzR(`=?E(3&B8nWMA>{~4dhO05So|qbbJK0BL zuv(P9mSuCU2csOd)~kWS^HXxv;pHo+Bed9Hv?};d@k!30JfS4z3(x_U6-EwkVn7*cOa%m&rXD9UI5(~;MsbQ9rv9v6(08E zghM`6lldzQcp>t6QAi~g=67Igt&ye+k)gZtxEKRskRyVjE9$&Xn1Y&ov?e)P@`!y# ztzEq>S@hRLeIF?NuEIHBcSyYwA+*As2ys4NL5VCWRPq)Ux`2>`|HP=EUq?D^%d$d9 zOr1|jV4Ni&utz4hWAPC8cY&0yi@Es-jpqTDI^;-1BL4Et07G;x4>$yP*9C_@5}nNh zW3A6>Xkw^LSekYLiryS01gybHiSiIk0P^qvltgQyfl>Sb#SGkzQ7j;H)mEecsek!} zl)pu~MUAUo3tdCN5P1SoBpDW&{RYues>nyg0zH^?lJc`Q!oz9cO>E)UVx=>f`Uj{C zsIJkNS04_1{a7I1b?$7s3YFe^14wA0wQs;WrgI@`XN5EadjsM`#`3LhHRXBJudp8Y zBebOH2HR2&)|+NF;0A*&v4MvPQ**us0MR&D%V)oVc)1fSEP9Q{NJDqEHbP&|)CTZ9 z>LA~vouF^hj9mLbDONOxjIsgfx|5t7>RO=zP<@n)Kwo0M1&W)JaR>K&FrKQDuW9`0 zd~E%WXEUPPg~pSk_H2YhG?k)sc;oviyQ7(rPp5)RWP>SZ=;V1WayjydfcpKQ6@u*J zueOdcYS~e?j7B(BJ^^rQP<;>P4^W1IS*+&`XXP}*ceoW5_{Y_la^S<170fXnS};1n;JHG49#rTH|o1z@Rfc0ukAS*&ZC!27FO0Y)Q1et~j-I1tjopUD4o$ob6mv zNZ@j7Nm12H-I9W;Ur|9gA*`#na|kh!Eqe*}r==;x5~-64#lt7Iu<@#jUpe-`q}c01 zxs@G`_)oH*3I-Nv1|@8*@<`LVKzH&*-9{OHVYl$6KIoHbciy%@^C!w3a#-!q;Sv{j zjDAcwIdNnl{Q2`8dD=Ig+}Gt0?{8<%Y!U@Eqmn%-O`v!iLu&fTSZrj;udX#5F z9p3G9pXg<1)zSJ7U038JlQY1C*EU!&{)lk3D+Z{0UV$-hq}Lhb6?G3xr*+Rsd-DWKbK(OG_8d z+HCqr(qkl+jP$vxrt#WFFI`#y1wCEy1+&MQhLSY%97ojXen&bb4O`uGLy@6_WL`aR zsSunwK?Q^=B&+;=&xVj|IxbS0m!Y2we(k5;Ai zz4omW49bm5Ul)bmg=;g2F1u|g=l?cQ9`wty1ms3w3)MRy$$Opvl9G7a2~<5{9VDYx zOD3k>3uhYA1bDv*Km!zO{#z|UjBpHXDa(oaCX27o#ZPCM7)1!50N@M&bT7kg(b5~p zJK3sneXi09_Hk*|uXYa;I$a8$;iWi*hsxId8x+m!iH?ep)8ch{ZcNgsu~Ko*ui{>8 z9L(UA4zl0~wIc$Vs$lExHMol!h3nxlPa>T#(1;YnzizN#bq)0Zg^c7oR`z1{CX=9w z$t?=>C-Lez*!8jcxUrqb)i*g?ie-TaBYBO~<(8v^s^!?jlBSw_qgm_iatdpE3c9aV zg@?$i7@jQ)9d~fBT~lbgzjF@S#I)n}*Dhe2*u+ z{*GRbySTwk*%kSDy}ew&XiSdmd&31_P(#em%-RF@Mp=eArUY_flcy5FwF>Yy+%zz& zbz>!Jw+wv1qubkRPV3;PP6-GtG^;TBKp)M}3QT7(V+UdEOt+B4REuX_}jE z&piGYVPQm8#pE{rgbrPFc&~4@V9ba-@UKLCyFM8et#gHv8KAbjiAs*o30kR(<9`C>e9zE+TDqA?gZU0$=l`ZH{ zW2x<|KZWzhC*kKNv!B57C$QWiTJ`ZdIPCunRM(>%8GM%-{y6ZxAC`9{5dP3)RRq;V3ISfP6jt)#8fl*5|&i!!_=p|2j1^5imS+J^!kKB' + options.addText + ""); + addButton = $parent.find("tr:last a"); + } else { + // Otherwise, insert it immediately after the last form: + $this.filter(":last").after('"); + addButton = $this.filter(":last").next().find("a"); + } + } + addButton.on('click', addInlineClickHandler); + }; + + const addInlineClickHandler = function(e) { + e.preventDefault(); + const template = $("#" + options.prefix + "-empty"); + const row = template.clone(true); + row.removeClass(options.emptyCssClass) + .addClass(options.formCssClass) + .attr("id", options.prefix + "-" + nextIndex); + addInlineDeleteButton(row); + row.find("*").each(function() { + updateElementIndex(this, options.prefix, totalForms.val()); + }); + // Insert the new form when it has been fully edited. + row.insertBefore($(template)); + // Update number of total forms. + $(totalForms).val(parseInt(totalForms.val(), 10) + 1); + nextIndex += 1; + // Hide the add button if there's a limit and it's been reached. + if ((maxForms.val() !== '') && (maxForms.val() - totalForms.val()) <= 0) { + addButton.parent().hide(); + } + // Show the remove buttons if there are more than min_num. + toggleDeleteButtonVisibility(row.closest('.inline-group')); + + // Pass the new form to the post-add callback, if provided. + if (options.added) { + options.added(row); + } + row.get(0).dispatchEvent(new CustomEvent("formset:added", { + bubbles: true, + detail: { + formsetName: options.prefix + } + })); + }; + + /** + * The "X" button that is part of every unsaved inline. + * (When saved, it is replaced with a "Delete" checkbox.) + */ + const addInlineDeleteButton = function(row) { + if (row.is("tr")) { + // If the forms are laid out in table rows, insert + // the remove button into the last table cell: + row.children(":last").append('"); + } else if (row.is("ul") || row.is("ol")) { + // If they're laid out as an ordered/unordered list, + // insert an
  • after the last list item: + row.append('
  • ' + options.deleteText + "
  • "); + } else { + // Otherwise, just insert the remove button as the + // last child element of the form's container: + row.children(":first").append('' + options.deleteText + ""); + } + // Add delete handler for each row. + row.find("a." + options.deleteCssClass).on('click', inlineDeleteHandler.bind(this)); + }; + + const inlineDeleteHandler = function(e1) { + e1.preventDefault(); + const deleteButton = $(e1.target); + const row = deleteButton.closest('.' + options.formCssClass); + const inlineGroup = row.closest('.inline-group'); + // Remove the parent form containing this button, + // and also remove the relevant row with non-field errors: + const prevRow = row.prev(); + if (prevRow.length && prevRow.hasClass('row-form-errors')) { + prevRow.remove(); + } + row.remove(); + nextIndex -= 1; + // Pass the deleted form to the post-delete callback, if provided. + if (options.removed) { + options.removed(row); + } + document.dispatchEvent(new CustomEvent("formset:removed", { + detail: { + formsetName: options.prefix + } + })); + // Update the TOTAL_FORMS form count. + const forms = $("." + options.formCssClass); + $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length); + // Show add button again once below maximum number. + if ((maxForms.val() === '') || (maxForms.val() - forms.length) > 0) { + addButton.parent().show(); + } + // Hide the remove buttons if at min_num. + toggleDeleteButtonVisibility(inlineGroup); + // Also, update names and ids for all remaining form controls so + // they remain in sequence: + let i, formCount; + const updateElementCallback = function() { + updateElementIndex(this, options.prefix, i); + }; + for (i = 0, formCount = forms.length; i < formCount; i++) { + updateElementIndex($(forms).get(i), options.prefix, i); + $(forms.get(i)).find("*").each(updateElementCallback); + } + }; + + const toggleDeleteButtonVisibility = function(inlineGroup) { + if ((minForms.val() !== '') && (minForms.val() - totalForms.val()) >= 0) { + inlineGroup.find('.inline-deletelink').hide(); + } else { + inlineGroup.find('.inline-deletelink').show(); + } + }; + + $this.each(function(i) { + $(this).not("." + options.emptyCssClass).addClass(options.formCssClass); + }); + + // Create the delete buttons for all unsaved inlines: + $this.filter('.' + options.formCssClass + ':not(.has_original):not(.' + options.emptyCssClass + ')').each(function() { + addInlineDeleteButton($(this)); + }); + toggleDeleteButtonVisibility($this); + + // Create the add button, initially hidden. + addButton = options.addButton; + addInlineAddButton(); + + // Show the add button if allowed to add more items. + // Note that max_num = None translates to a blank string. + const showAddButton = maxForms.val() === '' || (maxForms.val() - totalForms.val()) > 0; + if ($this.length && showAddButton) { + addButton.parent().show(); + } else { + addButton.parent().hide(); + } + + return this; + }; + + /* Setup plugin defaults */ + $.fn.formset.defaults = { + prefix: "form", // The form prefix for your django formset + addText: "add another", // Text for the add link + deleteText: "remove", // Text for the delete link + addCssClass: "add-row", // CSS class applied to the add link + deleteCssClass: "delete-row", // CSS class applied to the delete link + emptyCssClass: "empty-row", // CSS class applied to the empty row + formCssClass: "dynamic-form", // CSS class applied to each form in a formset + added: null, // Function called each time a new form is added + removed: null, // Function called each time a form is deleted + addButton: null // Existing add button to use + }; + + + // Tabular inlines --------------------------------------------------------- + $.fn.tabularFormset = function(selector, options) { + const $rows = $(this); + + const reinitDateTimeShortCuts = function() { + // Reinitialize the calendar and clock widgets by force + if (typeof DateTimeShortcuts !== "undefined") { + $(".datetimeshortcuts").remove(); + DateTimeShortcuts.init(); + } + }; + + const updateSelectFilter = function() { + // If any SelectFilter widgets are a part of the new form, + // instantiate a new SelectFilter instance for it. + if (typeof SelectFilter !== 'undefined') { + $('.selectfilter').each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, false); + }); + $('.selectfilterstacked').each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, true); + }); + } + }; + + const initPrepopulatedFields = function(row) { + row.find('.prepopulated_field').each(function() { + const field = $(this), + input = field.find('input, select, textarea'), + dependency_list = input.data('dependency_list') || [], + dependencies = []; + $.each(dependency_list, function(i, field_name) { + dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id')); + }); + if (dependencies.length) { + input.prepopulate(dependencies, input.attr('maxlength')); + } + }); + }; + + $rows.formset({ + prefix: options.prefix, + addText: options.addText, + formCssClass: "dynamic-" + options.prefix, + deleteCssClass: "inline-deletelink", + deleteText: options.deleteText, + emptyCssClass: "empty-form", + added: function(row) { + initPrepopulatedFields(row); + reinitDateTimeShortCuts(); + updateSelectFilter(); + }, + addButton: options.addButton + }); + + return $rows; + }; + + // Stacked inlines --------------------------------------------------------- + $.fn.stackedFormset = function(selector, options) { + const $rows = $(this); + const updateInlineLabel = function(row) { + $(selector).find(".inline_label").each(function(i) { + const count = i + 1; + $(this).html($(this).html().replace(/(#\d+)/g, "#" + count)); + }); + }; + + const reinitDateTimeShortCuts = function() { + // Reinitialize the calendar and clock widgets by force, yuck. + if (typeof DateTimeShortcuts !== "undefined") { + $(".datetimeshortcuts").remove(); + DateTimeShortcuts.init(); + } + }; + + const updateSelectFilter = function() { + // If any SelectFilter widgets were added, instantiate a new instance. + if (typeof SelectFilter !== "undefined") { + $(".selectfilter").each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, false); + }); + $(".selectfilterstacked").each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, true); + }); + } + }; + + const initPrepopulatedFields = function(row) { + row.find('.prepopulated_field').each(function() { + const field = $(this), + input = field.find('input, select, textarea'), + dependency_list = input.data('dependency_list') || [], + dependencies = []; + $.each(dependency_list, function(i, field_name) { + // Dependency in a fieldset. + let field_element = row.find('.form-row .field-' + field_name); + // Dependency without a fieldset. + if (!field_element.length) { + field_element = row.find('.form-row.field-' + field_name); + } + dependencies.push('#' + field_element.find('input, select, textarea').attr('id')); + }); + if (dependencies.length) { + input.prepopulate(dependencies, input.attr('maxlength')); + } + }); + }; + + $rows.formset({ + prefix: options.prefix, + addText: options.addText, + formCssClass: "dynamic-" + options.prefix, + deleteCssClass: "inline-deletelink", + deleteText: options.deleteText, + emptyCssClass: "empty-form", + removed: updateInlineLabel, + added: function(row) { + initPrepopulatedFields(row); + reinitDateTimeShortCuts(); + updateSelectFilter(); + updateInlineLabel(row); + }, + addButton: options.addButton + }); + + return $rows; + }; + + $(document).ready(function() { + $(".js-inline-admin-formset").each(function() { + const data = $(this).data(), + inlineOptions = data.inlineFormset; + let selector; + switch(data.inlineType) { + case "stacked": + selector = inlineOptions.name + "-group .inline-related"; + $(selector).stackedFormset(selector, inlineOptions.options); + break; + case "tabular": + selector = inlineOptions.name + "-group .tabular.inline-related tbody:first > tr.form-row"; + $(selector).tabularFormset(selector, inlineOptions.options); + break; + } + }); + }); +} diff --git a/staticfiles/admin/js/inlines.js.gz b/staticfiles/admin/js/inlines.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..f0be39d1115cc80b60b81235514dc3c04fc01594 GIT binary patch literal 3744 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 literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/jquery.init.js b/staticfiles/admin/js/jquery.init.js new file mode 100644 index 0000000000..f40b27f47d --- /dev/null +++ b/staticfiles/admin/js/jquery.init.js @@ -0,0 +1,8 @@ +/*global jQuery:false*/ +'use strict'; +/* Puts the included jQuery into our own namespace using noConflict and passing + * it 'true'. This ensures that the included jQuery doesn't pollute the global + * namespace (i.e. this preserves pre-existing values for both window.$ and + * window.jQuery). + */ +window.django = {jQuery: jQuery.noConflict(true)}; diff --git a/staticfiles/admin/js/jquery.init.js.gz b/staticfiles/admin/js/jquery.init.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..c3560ae9dd26062eb7f1c54660a0551461aee12c GIT binary patch literal 236 zcmV!(ye%4LW#5t0_}!@HKk@MahY(h1Gw39FxRW zv2X}k>Hg-Cz2ct6J8#I8X<;q}Na;fN>Xm-HXbp9-As21rgcIwG)knvxd8rXAYwI7r mdsC#o*)(^yabmpVy8YLd&O8s@)vNZmL-PlWYtbuP0RRBpx^(OS literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/nav_sidebar.3b9190d420b1.js b/staticfiles/admin/js/nav_sidebar.3b9190d420b1.js new file mode 100644 index 0000000000..7e735db15c --- /dev/null +++ b/staticfiles/admin/js/nav_sidebar.3b9190d420b1.js @@ -0,0 +1,79 @@ +'use strict'; +{ + const toggleNavSidebar = document.getElementById('toggle-nav-sidebar'); + if (toggleNavSidebar !== null) { + const navSidebar = document.getElementById('nav-sidebar'); + const main = document.getElementById('main'); + let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen'); + if (navSidebarIsOpen === null) { + navSidebarIsOpen = 'true'; + } + main.classList.toggle('shifted', navSidebarIsOpen === 'true'); + navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); + + toggleNavSidebar.addEventListener('click', function() { + if (navSidebarIsOpen === 'true') { + navSidebarIsOpen = 'false'; + } else { + navSidebarIsOpen = 'true'; + } + localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen); + main.classList.toggle('shifted'); + navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); + }); + } + + function initSidebarQuickFilter() { + const options = []; + const navSidebar = document.getElementById('nav-sidebar'); + if (!navSidebar) { + return; + } + navSidebar.querySelectorAll('th[scope=row] a').forEach((container) => { + options.push({title: container.innerHTML, node: container}); + }); + + function checkValue(event) { + let filterValue = event.target.value; + if (filterValue) { + filterValue = filterValue.toLowerCase(); + } + if (event.key === 'Escape') { + filterValue = ''; + event.target.value = ''; // clear input + } + let matches = false; + for (const o of options) { + let displayValue = ''; + if (filterValue) { + if (o.title.toLowerCase().indexOf(filterValue) === -1) { + displayValue = 'none'; + } else { + matches = true; + } + } + // show/hide parent + o.node.parentNode.parentNode.style.display = displayValue; + } + if (!filterValue || matches) { + event.target.classList.remove('no-results'); + } else { + event.target.classList.add('no-results'); + } + sessionStorage.setItem('django.admin.navSidebarFilterValue', filterValue); + } + + const nav = document.getElementById('nav-filter'); + nav.addEventListener('change', checkValue, false); + nav.addEventListener('input', checkValue, false); + nav.addEventListener('keyup', checkValue, false); + + const storedValue = sessionStorage.getItem('django.admin.navSidebarFilterValue'); + if (storedValue) { + nav.value = storedValue; + checkValue({target: nav, key: ''}); + } + } + window.initSidebarQuickFilter = initSidebarQuickFilter; + initSidebarQuickFilter(); +} diff --git a/staticfiles/admin/js/nav_sidebar.3b9190d420b1.js.gz b/staticfiles/admin/js/nav_sidebar.3b9190d420b1.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..c666ede6485c9a1afd11aa74ec5b972a2c0bfc9f GIT binary patch literal 845 zcmV-T1G4-diwFP!00002|E*R{Z`&{oz2{e`Cp$pnV%KIV&6*`A9yJPmW3rL>t9Y6AgQBJ%U#%g*L><$%Ml#o!_$z zo~a@ulF783fiTGg%$S3{{j|K!;;6PA2s$6=+B)hFD=e0icn9fZG$Nwpyie+YO;B-E zxIml+Vn&(R=WPFXy*RjGuk~F4)}PCi@_Qo{oq)x-HZY5$>?aiynb2&;MB;n7sJ8B1 z)Ii<#3WSf0Dj{m{R@*z9f0A;l^$pV|smYBaJ!QFpEIK8@ur;2OU}KeNFqZ~L;JGvi zL=~e0crB>Nf^dkj1@SwJ#AM?+Qf*TM0V}B$0AC&n;1S*?y&4pEBJ^<+5v0!rJQ_dv?XR z!3OT`s4T3#M$R6ehW~Sa?IfHu2!7`km{N(*N;tIqDnTvpfkTRoy5tXpIwj z?6GpylxxpaXM|i`+!f_RYFs0E-v^=7e2Qt=(2a(j)_Zr*wc6#s@Miw;k(RE<1B zwpkL7+{qu1>m5rDZs6l>D_)LSyXlVPztsbCZXHhv)^?6M(>gSI&F=!$LN1c<*^B|h Xf2=>fI}Y?=Z`Jz^Ly%bv_X_|3cl@J3 literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/nav_sidebar.js b/staticfiles/admin/js/nav_sidebar.js new file mode 100644 index 0000000000..7e735db15c --- /dev/null +++ b/staticfiles/admin/js/nav_sidebar.js @@ -0,0 +1,79 @@ +'use strict'; +{ + const toggleNavSidebar = document.getElementById('toggle-nav-sidebar'); + if (toggleNavSidebar !== null) { + const navSidebar = document.getElementById('nav-sidebar'); + const main = document.getElementById('main'); + let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen'); + if (navSidebarIsOpen === null) { + navSidebarIsOpen = 'true'; + } + main.classList.toggle('shifted', navSidebarIsOpen === 'true'); + navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); + + toggleNavSidebar.addEventListener('click', function() { + if (navSidebarIsOpen === 'true') { + navSidebarIsOpen = 'false'; + } else { + navSidebarIsOpen = 'true'; + } + localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen); + main.classList.toggle('shifted'); + navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); + }); + } + + function initSidebarQuickFilter() { + const options = []; + const navSidebar = document.getElementById('nav-sidebar'); + if (!navSidebar) { + return; + } + navSidebar.querySelectorAll('th[scope=row] a').forEach((container) => { + options.push({title: container.innerHTML, node: container}); + }); + + function checkValue(event) { + let filterValue = event.target.value; + if (filterValue) { + filterValue = filterValue.toLowerCase(); + } + if (event.key === 'Escape') { + filterValue = ''; + event.target.value = ''; // clear input + } + let matches = false; + for (const o of options) { + let displayValue = ''; + if (filterValue) { + if (o.title.toLowerCase().indexOf(filterValue) === -1) { + displayValue = 'none'; + } else { + matches = true; + } + } + // show/hide parent + o.node.parentNode.parentNode.style.display = displayValue; + } + if (!filterValue || matches) { + event.target.classList.remove('no-results'); + } else { + event.target.classList.add('no-results'); + } + sessionStorage.setItem('django.admin.navSidebarFilterValue', filterValue); + } + + const nav = document.getElementById('nav-filter'); + nav.addEventListener('change', checkValue, false); + nav.addEventListener('input', checkValue, false); + nav.addEventListener('keyup', checkValue, false); + + const storedValue = sessionStorage.getItem('django.admin.navSidebarFilterValue'); + if (storedValue) { + nav.value = storedValue; + checkValue({target: nav, key: ''}); + } + } + window.initSidebarQuickFilter = initSidebarQuickFilter; + initSidebarQuickFilter(); +} diff --git a/staticfiles/admin/js/nav_sidebar.js.gz b/staticfiles/admin/js/nav_sidebar.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..c666ede6485c9a1afd11aa74ec5b972a2c0bfc9f GIT binary patch literal 845 zcmV-T1G4-diwFP!00002|E*R{Z`&{oz2{e`Cp$pnV%KIV&6*`A9yJPmW3rL>t9Y6AgQBJ%U#%g*L><$%Ml#o!_$z zo~a@ulF783fiTGg%$S3{{j|K!;;6PA2s$6=+B)hFD=e0icn9fZG$Nwpyie+YO;B-E zxIml+Vn&(R=WPFXy*RjGuk~F4)}PCi@_Qo{oq)x-HZY5$>?aiynb2&;MB;n7sJ8B1 z)Ii<#3WSf0Dj{m{R@*z9f0A;l^$pV|smYBaJ!QFpEIK8@ur;2OU}KeNFqZ~L;JGvi zL=~e0crB>Nf^dkj1@SwJ#AM?+Qf*TM0V}B$0AC&n;1S*?y&4pEBJ^<+5v0!rJQ_dv?XR z!3OT`s4T3#M$R6ehW~Sa?IfHu2!7`km{N(*N;tIqDnTvpfkTRoy5tXpIwj z?6GpylxxpaXM|i`+!f_RYFs0E-v^=7e2Qt=(2a(j)_Zr*wc6#s@Miw;k(RE<1B zwpkL7+{qu1>m5rDZs6l>D_)LSyXlVPztsbCZXHhv)^?6M(>gSI&F=!$LN1c<*^B|h Xf2=>fI}Y?=Z`Jz^Ly%bv_X_|3cl@J3 literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/popup_response.c6cc78ea5551.js b/staticfiles/admin/js/popup_response.c6cc78ea5551.js new file mode 100644 index 0000000000..2b1d3dd31d --- /dev/null +++ b/staticfiles/admin/js/popup_response.c6cc78ea5551.js @@ -0,0 +1,16 @@ +/*global opener */ +'use strict'; +{ + const initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); + switch(initData.action) { + case 'change': + opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value); + break; + case 'delete': + opener.dismissDeleteRelatedObjectPopup(window, initData.value); + break; + default: + opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj); + break; + } +} diff --git a/staticfiles/admin/js/popup_response.c6cc78ea5551.js.gz b/staticfiles/admin/js/popup_response.c6cc78ea5551.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..095fc38f5d0197012ca2f6b908fa4035dd3f33d9 GIT binary patch literal 270 zcmV+p0rCDHiwFP!00002|DBJ)PQx$^hVOlf+|o`oyHjxh#sLltjR!z(Y`T;*i5iy* zp}jk8C}@XGLj0%L{^RfWdevB8gB3oIqh74mnH(aC$i2}ltL!rqleBk{g>i;Az#y)~ z!}Io01?VH?==IQ%W7QDfS(=|WANQC`Y{50Y1ni6}gAYR}dx~LNMP*tDj-xCTPAem^ zN|xQ?D5?aGqhYiJgh@HjQ^=feE*DOPZf% zQa&1oe!TcSOTB{~=&1H}dsI0ZUy@^qHmmLl-m0T4NS63~mQ5P}Im>Ah(kl#>&oQnM U|9R|b+#x$;UqBT-uqOfl0PG}x3;+NC literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/popup_response.js b/staticfiles/admin/js/popup_response.js new file mode 100644 index 0000000000..2b1d3dd31d --- /dev/null +++ b/staticfiles/admin/js/popup_response.js @@ -0,0 +1,16 @@ +/*global opener */ +'use strict'; +{ + const initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); + switch(initData.action) { + case 'change': + opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value); + break; + case 'delete': + opener.dismissDeleteRelatedObjectPopup(window, initData.value); + break; + default: + opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj); + break; + } +} diff --git a/staticfiles/admin/js/popup_response.js.gz b/staticfiles/admin/js/popup_response.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..095fc38f5d0197012ca2f6b908fa4035dd3f33d9 GIT binary patch literal 270 zcmV+p0rCDHiwFP!00002|DBJ)PQx$^hVOlf+|o`oyHjxh#sLltjR!z(Y`T;*i5iy* zp}jk8C}@XGLj0%L{^RfWdevB8gB3oIqh74mnH(aC$i2}ltL!rqleBk{g>i;Az#y)~ z!}Io01?VH?==IQ%W7QDfS(=|WANQC`Y{50Y1ni6}gAYR}dx~LNMP*tDj-xCTPAem^ zN|xQ?D5?aGqhYiJgh@HjQ^=feE*DOPZf% zQa&1oe!TcSOTB{~=&1H}dsI0ZUy@^qHmmLl-m0T4NS63~mQ5P}Im>Ah(kl#>&oQnM U|9R|b+#x$;UqBT-uqOfl0PG}x3;+NC literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/prepopulate.bd2361dfd64d.js b/staticfiles/admin/js/prepopulate.bd2361dfd64d.js new file mode 100644 index 0000000000..89e95ab44d --- /dev/null +++ b/staticfiles/admin/js/prepopulate.bd2361dfd64d.js @@ -0,0 +1,43 @@ +/*global URLify*/ +'use strict'; +{ + const $ = django.jQuery; + $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) { + /* + Depends on urlify.js + Populates a selected field with the values of the dependent fields, + URLifies and shortens the string. + dependencies - array of dependent fields ids + maxLength - maximum length of the URLify'd string + allowUnicode - Unicode support of the URLify'd string + */ + return this.each(function() { + const prepopulatedField = $(this); + + const populate = function() { + // Bail if the field's value has been changed by the user + if (prepopulatedField.data('_changed')) { + return; + } + + const values = []; + $.each(dependencies, function(i, field) { + field = $(field); + if (field.val().length > 0) { + values.push(field.val()); + } + }); + prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); + }; + + prepopulatedField.data('_changed', false); + prepopulatedField.on('change', function() { + prepopulatedField.data('_changed', true); + }); + + if (!prepopulatedField.val()) { + $(dependencies.join(',')).on('keyup change focus', populate); + } + }); + }; +} diff --git a/staticfiles/admin/js/prepopulate.bd2361dfd64d.js.gz b/staticfiles/admin/js/prepopulate.bd2361dfd64d.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..0ad31cf6fc7e340b982b48e37833ba0b4c92e583 GIT binary patch literal 536 zcmV+z0_Xi7iwFP!00002|BX~lkDD+Qyz?twB_trCq<54as#Q;WXe;fhswxLRg0qf| z{Lw9{^51K0!t#}FeRA-7^Tspd>~|+FkA%b1w?|fYyM2^cji8NUl}XCzPXumNQfLD) z9DtsQILYGt)uQT3e;60FC|ZTBY%M1ST~%#GWtbEx#TErcQ8CmxT*&W76erW#(8#eeNTFuPDZDV#fN2nZ5pG?9 zto^SWB@@bYKEv}eupUlO(2Z0Eh4y{DB;r)es;Ae3_dt{)T|Z|z0~npt9+hxiZqF|E z0z7;eXa+wLI?SDQPsMWpx1F|a>j=Mv;5@!<6&kCAt7f`DQZ?yl+|-lT1Wa6}pS{Qj zh||73E2FLYjYuq!z3Y4UL>LDan0wI@9gKs9XgDGYs2Z0&XYaA|RW7G$h2#*@70ZGW zL(=5u0FY!`9A5P(S7+B~^(kC%h}HqV|5$g$LDTsg7tk9`}*_3 zQAx962+>FQa1Xa%fp*ba-Audh%($-g*r;5q-eZOkro+IqWFk!<$?pFbERe5@T)pY7 zQMn8>~i9D`67C!-ffGtna6k*oI$$WW!F=G#?H3Gi-1~I aRy!Iu=p~hC>6=sa8vO+udA>*c1pojb@B<0} literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/prepopulate.js b/staticfiles/admin/js/prepopulate.js new file mode 100644 index 0000000000..89e95ab44d --- /dev/null +++ b/staticfiles/admin/js/prepopulate.js @@ -0,0 +1,43 @@ +/*global URLify*/ +'use strict'; +{ + const $ = django.jQuery; + $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) { + /* + Depends on urlify.js + Populates a selected field with the values of the dependent fields, + URLifies and shortens the string. + dependencies - array of dependent fields ids + maxLength - maximum length of the URLify'd string + allowUnicode - Unicode support of the URLify'd string + */ + return this.each(function() { + const prepopulatedField = $(this); + + const populate = function() { + // Bail if the field's value has been changed by the user + if (prepopulatedField.data('_changed')) { + return; + } + + const values = []; + $.each(dependencies, function(i, field) { + field = $(field); + if (field.val().length > 0) { + values.push(field.val()); + } + }); + prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); + }; + + prepopulatedField.data('_changed', false); + prepopulatedField.on('change', function() { + prepopulatedField.data('_changed', true); + }); + + if (!prepopulatedField.val()) { + $(dependencies.join(',')).on('keyup change focus', populate); + } + }); + }; +} diff --git a/staticfiles/admin/js/prepopulate.js.gz b/staticfiles/admin/js/prepopulate.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..0ad31cf6fc7e340b982b48e37833ba0b4c92e583 GIT binary patch literal 536 zcmV+z0_Xi7iwFP!00002|BX~lkDD+Qyz?twB_trCq<54as#Q;WXe;fhswxLRg0qf| z{Lw9{^51K0!t#}FeRA-7^Tspd>~|+FkA%b1w?|fYyM2^cji8NUl}XCzPXumNQfLD) z9DtsQILYGt)uQT3e;60FC|ZTBY%M1ST~%#GWtbEx#TErcQ8CmxT*&W76erW#(8#eeNTFuPDZDV#fN2nZ5pG?9 zto^SWB@@bYKEv}eupUlO(2Z0Eh4y{DB;r)es;Ae3_dt{)T|Z|z0~npt9+hxiZqF|E z0z7;eXa+wLI?SDQPsMWpx1F|a>j=Mv;5@!<6&kCAt7f`DQZ?yl+|-lT1Wa6}pS{Qj zh||73E2FLYjYuq!z3Y4UL>LDan0wI@9gKs9XgDGYs2Z0&XYaA|RW7G$h2#*@70ZGW zL(=5u0FY!`9A5P(S7+B~^(kC%h}HqV|5$g$LDTsg7tk9`}*_3 zQAx962+>FQa1Xa%fp*ba-Audh%($-g*r;5q-eZOkro+IqWFk!<$?pFbERe5@T)pY7 zQMn8>~i9D`67C!-ffGtna6k*oI$$WW!F=G#?H3Gi-1~I aRy!Iu=p~hC>6=sa8vO+udA>*c1pojb@B<0} literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/prepopulate_init.6cac7f3105b8.js b/staticfiles/admin/js/prepopulate_init.6cac7f3105b8.js new file mode 100644 index 0000000000..a58841f004 --- /dev/null +++ b/staticfiles/admin/js/prepopulate_init.6cac7f3105b8.js @@ -0,0 +1,15 @@ +'use strict'; +{ + const $ = django.jQuery; + const fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields'); + $.each(fields, function(index, field) { + $( + '.empty-form .form-row .field-' + field.name + + ', .empty-form.form-row .field-' + field.name + + ', .empty-form .form-row.field-' + field.name + ).addClass('prepopulated_field'); + $(field.id).data('dependency_list', field.dependency_list).prepopulate( + field.dependency_ids, field.maxLength, field.allowUnicode + ); + }); +} diff --git a/staticfiles/admin/js/prepopulate_init.6cac7f3105b8.js.gz b/staticfiles/admin/js/prepopulate_init.6cac7f3105b8.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..b000b60fb651bec382824b2a21f4fa4c944fc357 GIT binary patch literal 277 zcmV+w0qXuAiwFP!00002|D}+@Zo?o9hVOX_q(vf8120hRG-;<^cG$VHz-g(7i2_j@ zO?~$zuykbGZ9afy{?9f)A3ZW32BQMs7as+iLpkz+mF$`63((2Q%iD;A$N&Y;YpEeX#dFnb6!ALsFC~IHSBY#`JCX{X9zNC3bz7MC*o*$>kJ-yUy9d3C?z@gCyvX?Y3ycGWb92_uxO-2U$zd z`o)6xTStyjyE>A7nQ)_52Q~IMTS96&TH^!%vPS->*D`Cowd$ANM8jjXgWCb=6wYe_ btaaCSGRo;}|FqzJzVF2+o-%-lN&)}?-Oh*f literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/prepopulate_init.js b/staticfiles/admin/js/prepopulate_init.js new file mode 100644 index 0000000000..a58841f004 --- /dev/null +++ b/staticfiles/admin/js/prepopulate_init.js @@ -0,0 +1,15 @@ +'use strict'; +{ + const $ = django.jQuery; + const fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields'); + $.each(fields, function(index, field) { + $( + '.empty-form .form-row .field-' + field.name + + ', .empty-form.form-row .field-' + field.name + + ', .empty-form .form-row.field-' + field.name + ).addClass('prepopulated_field'); + $(field.id).data('dependency_list', field.dependency_list).prepopulate( + field.dependency_ids, field.maxLength, field.allowUnicode + ); + }); +} diff --git a/staticfiles/admin/js/prepopulate_init.js.gz b/staticfiles/admin/js/prepopulate_init.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..b000b60fb651bec382824b2a21f4fa4c944fc357 GIT binary patch literal 277 zcmV+w0qXuAiwFP!00002|D}+@Zo?o9hVOX_q(vf8120hRG-;<^cG$VHz-g(7i2_j@ zO?~$zuykbGZ9afy{?9f)A3ZW32BQMs7as+iLpkz+mF$`63((2Q%iD;A$N&Y;YpEeX#dFnb6!ALsFC~IHSBY#`JCX{X9zNC3bz7MC*o*$>kJ-yUy9d3C?z@gCyvX?Y3ycGWb92_uxO-2U$zd z`o)6xTStyjyE>A7nQ)_52Q~IMTS96&TH^!%vPS->*D`Cowd$ANM8jjXgWCb=6wYe_ btaaCSGRo;}|FqzJzVF2+o-%-lN&)}?-Oh*f literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/theme.ab270f56bb9c.js b/staticfiles/admin/js/theme.ab270f56bb9c.js new file mode 100644 index 0000000000..794cd15f70 --- /dev/null +++ b/staticfiles/admin/js/theme.ab270f56bb9c.js @@ -0,0 +1,56 @@ +'use strict'; +{ + window.addEventListener('load', function(e) { + + function setTheme(mode) { + if (mode !== "light" && mode !== "dark" && mode !== "auto") { + console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`); + mode = "auto"; + } + document.documentElement.dataset.theme = mode; + localStorage.setItem("theme", mode); + } + + function cycleTheme() { + const currentTheme = localStorage.getItem("theme") || "auto"; + const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; + + if (prefersDark) { + // Auto (dark) -> Light -> Dark + if (currentTheme === "auto") { + setTheme("light"); + } else if (currentTheme === "light") { + setTheme("dark"); + } else { + setTheme("auto"); + } + } else { + // Auto (light) -> Dark -> Light + if (currentTheme === "auto") { + setTheme("dark"); + } else if (currentTheme === "dark") { + setTheme("light"); + } else { + setTheme("auto"); + } + } + } + + function initTheme() { + // set theme defined in localStorage if there is one, or fallback to auto mode + const currentTheme = localStorage.getItem("theme"); + currentTheme ? setTheme(currentTheme) : setTheme("auto"); + } + + function setupTheme() { + // Attach event handlers for toggling themes + const buttons = document.getElementsByClassName("theme-toggle"); + Array.from(buttons).forEach((btn) => { + btn.addEventListener("click", cycleTheme); + }); + initTheme(); + } + + setupTheme(); + }); +} diff --git a/staticfiles/admin/js/theme.ab270f56bb9c.js.gz b/staticfiles/admin/js/theme.ab270f56bb9c.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..1e4a36a7887d1d80274d2ffc352714ddc71c9d37 GIT binary patch literal 605 zcmV-j0;2sNiwFP!00002|E*O~Z`v>re&<)*qNyYjr0*a)u?Ls5gXQ?J;RTNi&4LNEmdGHS!>7dpA}R6>MsRZjr!z*( zws%BI)KMSFFRGQ*lBe7lZQ{ot8bPRMA_W8V6avN!KJWdrO5qQ8fZ^>r}a8tKXKj2rviU5o>2%A+7iH@`R& zB#z?7VoJ5tW@@QNoq@l}BuZ*iZs()3N@yVuUGMEJEFCF`0}@Q{;NBOE-*}fZdk@)7 z`(pL@bu8AV76;0q0xn&b41+gbSJ6XNzYTuPz0P64ee_>oM4Sv4*m^<<9PT`)vkTSC9>z1FICJKm=JWYG1LHOpwBi%c1~MY$n$YcGE`0<#NJRl~Ese0o!hB_g34;QluP8={zW%?_E%7j>S?Fo(Ub9msTD zBD#%B@;GH(g3W-nUw7XmvGzCdL<7b&K%S+&G=}Wb%;+L+5R=pqSUFyCyhfG4;%=a5 r+?VqoU__;$TQ{Chv$q$m>b Light -> Dark + if (currentTheme === "auto") { + setTheme("light"); + } else if (currentTheme === "light") { + setTheme("dark"); + } else { + setTheme("auto"); + } + } else { + // Auto (light) -> Dark -> Light + if (currentTheme === "auto") { + setTheme("dark"); + } else if (currentTheme === "dark") { + setTheme("light"); + } else { + setTheme("auto"); + } + } + } + + function initTheme() { + // set theme defined in localStorage if there is one, or fallback to auto mode + const currentTheme = localStorage.getItem("theme"); + currentTheme ? setTheme(currentTheme) : setTheme("auto"); + } + + function setupTheme() { + // Attach event handlers for toggling themes + const buttons = document.getElementsByClassName("theme-toggle"); + Array.from(buttons).forEach((btn) => { + btn.addEventListener("click", cycleTheme); + }); + initTheme(); + } + + setupTheme(); + }); +} diff --git a/staticfiles/admin/js/theme.js.gz b/staticfiles/admin/js/theme.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..1e4a36a7887d1d80274d2ffc352714ddc71c9d37 GIT binary patch literal 605 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 literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/urlify.js b/staticfiles/admin/js/urlify.js new file mode 100644 index 0000000000..9fc0409496 --- /dev/null +++ b/staticfiles/admin/js/urlify.js @@ -0,0 +1,169 @@ +/*global XRegExp*/ +'use strict'; +{ + const LATIN_MAP = { + 'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', + 'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', + 'Î': 'I', 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', + 'Õ': 'O', 'Ö': 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', + 'Ü': 'U', 'Ű': 'U', 'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à': 'a', + 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', + 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i', + 'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', + 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', + 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y' + }; + const LATIN_SYMBOLS_MAP = { + '©': '(c)' + }; + const GREEK_MAP = { + 'α': 'a', 'β': 'b', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'h', + 'θ': '8', 'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm', 'ν': 'n', 'ξ': '3', + 'ο': 'o', 'π': 'p', 'ρ': 'r', 'σ': 's', 'τ': 't', 'υ': 'y', 'φ': 'f', + 'χ': 'x', 'ψ': 'ps', 'ω': 'w', 'ά': 'a', 'έ': 'e', 'ί': 'i', 'ό': 'o', + 'ύ': 'y', 'ή': 'h', 'ώ': 'w', 'ς': 's', 'ϊ': 'i', 'ΰ': 'y', 'ϋ': 'y', + 'ΐ': 'i', 'Α': 'A', 'Β': 'B', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z', + 'Η': 'H', 'Θ': '8', 'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M', 'Ν': 'N', + 'Ξ': '3', 'Ο': 'O', 'Π': 'P', 'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y', + 'Φ': 'F', 'Χ': 'X', 'Ψ': 'PS', 'Ω': 'W', 'Ά': 'A', 'Έ': 'E', 'Ί': 'I', + 'Ό': 'O', 'Ύ': 'Y', 'Ή': 'H', 'Ώ': 'W', 'Ϊ': 'I', 'Ϋ': 'Y' + }; + const TURKISH_MAP = { + 'ş': 's', 'Ş': 'S', 'ı': 'i', 'İ': 'I', 'ç': 'c', 'Ç': 'C', 'ü': 'u', + 'Ü': 'U', 'ö': 'o', 'Ö': 'O', 'ğ': 'g', 'Ğ': 'G' + }; + const ROMANIAN_MAP = { + 'ă': 'a', 'î': 'i', 'ș': 's', 'ț': 't', 'â': 'a', + 'Ă': 'A', 'Î': 'I', 'Ș': 'S', 'Ț': 'T', 'Â': 'A' + }; + const RUSSIAN_MAP = { + 'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo', + 'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm', + 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u', + 'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch', 'ш': 'sh', 'щ': 'sh', 'ъ': '', + 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya', + 'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo', + 'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M', + 'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U', + 'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sh', 'Ъ': '', + 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya' + }; + const UKRAINIAN_MAP = { + 'Є': 'Ye', 'І': 'I', 'Ї': 'Yi', 'Ґ': 'G', 'є': 'ye', 'і': 'i', + 'ї': 'yi', 'ґ': 'g' + }; + const CZECH_MAP = { + 'č': 'c', 'ď': 'd', 'ě': 'e', 'ň': 'n', 'ř': 'r', 'š': 's', 'ť': 't', + 'ů': 'u', 'ž': 'z', 'Č': 'C', 'Ď': 'D', 'Ě': 'E', 'Ň': 'N', 'Ř': 'R', + 'Š': 'S', 'Ť': 'T', 'Ů': 'U', 'Ž': 'Z' + }; + const SLOVAK_MAP = { + 'á': 'a', 'ä': 'a', 'č': 'c', 'ď': 'd', 'é': 'e', 'í': 'i', 'ľ': 'l', + 'ĺ': 'l', 'ň': 'n', 'ó': 'o', 'ô': 'o', 'ŕ': 'r', 'š': 's', 'ť': 't', + 'ú': 'u', 'ý': 'y', 'ž': 'z', + 'Á': 'a', 'Ä': 'A', 'Č': 'C', 'Ď': 'D', 'É': 'E', 'Í': 'I', 'Ľ': 'L', + 'Ĺ': 'L', 'Ň': 'N', 'Ó': 'O', 'Ô': 'O', 'Ŕ': 'R', 'Š': 'S', 'Ť': 'T', + 'Ú': 'U', 'Ý': 'Y', 'Ž': 'Z' + }; + const POLISH_MAP = { + 'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n', 'ó': 'o', 'ś': 's', + 'ź': 'z', 'ż': 'z', + 'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O', 'Ś': 'S', + 'Ź': 'Z', 'Ż': 'Z' + }; + const LATVIAN_MAP = { + 'ā': 'a', 'č': 'c', 'ē': 'e', 'ģ': 'g', 'ī': 'i', 'ķ': 'k', 'ļ': 'l', + 'ņ': 'n', 'š': 's', 'ū': 'u', 'ž': 'z', + 'Ā': 'A', 'Č': 'C', 'Ē': 'E', 'Ģ': 'G', 'Ī': 'I', 'Ķ': 'K', 'Ļ': 'L', + 'Ņ': 'N', 'Š': 'S', 'Ū': 'U', 'Ž': 'Z' + }; + const ARABIC_MAP = { + 'أ': 'a', 'ب': 'b', 'ت': 't', 'ث': 'th', 'ج': 'g', 'ح': 'h', 'خ': 'kh', 'د': 'd', + 'ذ': 'th', 'ر': 'r', 'ز': 'z', 'س': 's', 'ش': 'sh', 'ص': 's', 'ض': 'd', 'ط': 't', + 'ظ': 'th', 'ع': 'aa', 'غ': 'gh', 'ف': 'f', 'ق': 'k', 'ك': 'k', 'ل': 'l', 'م': 'm', + 'ن': 'n', 'ه': 'h', 'و': 'o', 'ي': 'y' + }; + const LITHUANIAN_MAP = { + 'ą': 'a', 'č': 'c', 'ę': 'e', 'ė': 'e', 'į': 'i', 'š': 's', 'ų': 'u', + 'ū': 'u', 'ž': 'z', + 'Ą': 'A', 'Č': 'C', 'Ę': 'E', 'Ė': 'E', 'Į': 'I', 'Š': 'S', 'Ų': 'U', + 'Ū': 'U', 'Ž': 'Z' + }; + const SERBIAN_MAP = { + 'ђ': 'dj', 'ј': 'j', 'љ': 'lj', 'њ': 'nj', 'ћ': 'c', 'џ': 'dz', + 'đ': 'dj', 'Ђ': 'Dj', 'Ј': 'j', 'Љ': 'Lj', 'Њ': 'Nj', 'Ћ': 'C', + 'Џ': 'Dz', 'Đ': 'Dj' + }; + const AZERBAIJANI_MAP = { + 'ç': 'c', 'ə': 'e', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u', + 'Ç': 'C', 'Ə': 'E', 'Ğ': 'G', 'İ': 'I', 'Ö': 'O', 'Ş': 'S', 'Ü': 'U' + }; + const GEORGIAN_MAP = { + 'ა': 'a', 'ბ': 'b', 'გ': 'g', 'დ': 'd', 'ე': 'e', 'ვ': 'v', 'ზ': 'z', + 'თ': 't', 'ი': 'i', 'კ': 'k', 'ლ': 'l', 'მ': 'm', 'ნ': 'n', 'ო': 'o', + 'პ': 'p', 'ჟ': 'j', 'რ': 'r', 'ს': 's', 'ტ': 't', 'უ': 'u', 'ფ': 'f', + 'ქ': 'q', 'ღ': 'g', 'ყ': 'y', 'შ': 'sh', 'ჩ': 'ch', 'ც': 'c', 'ძ': 'dz', + 'წ': 'w', 'ჭ': 'ch', 'ხ': 'x', 'ჯ': 'j', 'ჰ': 'h' + }; + + const ALL_DOWNCODE_MAPS = [ + LATIN_MAP, + LATIN_SYMBOLS_MAP, + GREEK_MAP, + TURKISH_MAP, + ROMANIAN_MAP, + RUSSIAN_MAP, + UKRAINIAN_MAP, + CZECH_MAP, + SLOVAK_MAP, + POLISH_MAP, + LATVIAN_MAP, + ARABIC_MAP, + LITHUANIAN_MAP, + SERBIAN_MAP, + AZERBAIJANI_MAP, + GEORGIAN_MAP + ]; + + const Downcoder = { + 'Initialize': function() { + if (Downcoder.map) { // already made + return; + } + Downcoder.map = {}; + for (const lookup of ALL_DOWNCODE_MAPS) { + Object.assign(Downcoder.map, lookup); + } + Downcoder.regex = new RegExp(Object.keys(Downcoder.map).join('|'), 'g'); + } + }; + + function downcode(slug) { + Downcoder.Initialize(); + return slug.replace(Downcoder.regex, function(m) { + return Downcoder.map[m]; + }); + } + + + function URLify(s, num_chars, allowUnicode) { + // changes, e.g., "Petty theft" to "petty-theft" + if (!allowUnicode) { + s = downcode(s); + } + s = s.toLowerCase(); // convert to lowercase + // if downcode doesn't hit, the char will be stripped here + if (allowUnicode) { + // Keep Unicode letters including both lowercase and uppercase + // characters, whitespace, and dash; remove other characters. + s = XRegExp.replace(s, XRegExp('[^-_\\p{L}\\p{N}\\s]', 'g'), ''); + } else { + s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars + } + s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces + s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens + s = s.substring(0, num_chars); // trim to first num_chars chars + return s.replace(/-+$/g, ''); // trim any trailing hyphens + } + window.URLify = URLify; +} diff --git a/staticfiles/admin/js/urlify.js.gz b/staticfiles/admin/js/urlify.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..34e9629519d23cdcfa6d0879cf5d0e575676c32a GIT binary patch literal 2578 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 literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/vendor/jquery/LICENSE.de877aa6d744.txt b/staticfiles/admin/js/vendor/jquery/LICENSE.de877aa6d744.txt new file mode 100644 index 0000000000..f642c3f7a7 --- /dev/null +++ b/staticfiles/admin/js/vendor/jquery/LICENSE.de877aa6d744.txt @@ -0,0 +1,20 @@ +Copyright OpenJS Foundation and other contributors, https://openjsf.org/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/staticfiles/admin/js/vendor/jquery/LICENSE.de877aa6d744.txt.gz b/staticfiles/admin/js/vendor/jquery/LICENSE.de877aa6d744.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..484afc0281c7ddb93d1d34d74ab496a5cf28a43f GIT binary patch literal 656 zcmV;B0&o2viwFP!00002|6Nkej+-zLzVj5LoLUJb_q{n_Hf{+<#@RGS0w#DxFtSaf zynV+c?e12Jgly0EJ4wuRxBAk1;FB7ERFIi@Y-_L02=&;4@x8Lpn9*B(p1rXyhTi+h zy=*oH5$~>B8++MAQK{@zI~Rc30ix9T4i{UGUbQiFRw*zYG<|I^Dh6+m{tlC}4gu!u zYdz}m64j_R-NU5sk;a+M-)gHCFST=~(KYfxYnu70M*lF{=|MU8hE}6h^+c?`FCwj~ z2hbz3Dfs&YH|={fd$7u3tR`^8IMfVt8$A4d9`sc|6#{&z$pzBcVS?Z@hO23H7rttV zHO=QiyFQLu?H-Ncr3;sh8UqS*Y>Wk`h9NL$^u1*LaJS5$N;HK+{j;J)_tu;1*Cbd` zH`@^eU0AFDtZ)#x>#@hDUJ>D&g0@Wc0U=r==~pajruzZ70=|62nwu%Qt&sH(iB#t z!t*MIBa=IRkbo0{6!HW-15%veCo9r8qQ6Q(s|vUPwl8x=(->Hh literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/vendor/jquery/LICENSE.txt b/staticfiles/admin/js/vendor/jquery/LICENSE.txt new file mode 100644 index 0000000000..f642c3f7a7 --- /dev/null +++ b/staticfiles/admin/js/vendor/jquery/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright OpenJS Foundation and other contributors, https://openjsf.org/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/staticfiles/admin/js/vendor/jquery/LICENSE.txt.gz b/staticfiles/admin/js/vendor/jquery/LICENSE.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..484afc0281c7ddb93d1d34d74ab496a5cf28a43f GIT binary patch literal 656 zcmV;B0&o2viwFP!00002|6Nkej+-zLzVj5LoLUJb_q{n_Hf{+<#@RGS0w#DxFtSaf zynV+c?e12Jgly0EJ4wuRxBAk1;FB7ERFIi@Y-_L02=&;4@x8Lpn9*B(p1rXyhTi+h zy=*oH5$~>B8++MAQK{@zI~Rc30ix9T4i{UGUbQiFRw*zYG<|I^Dh6+m{tlC}4gu!u zYdz}m64j_R-NU5sk;a+M-)gHCFST=~(KYfxYnu70M*lF{=|MU8hE}6h^+c?`FCwj~ z2hbz3Dfs&YH|={fd$7u3tR`^8IMfVt8$A4d9`sc|6#{&z$pzBcVS?Z@hO23H7rttV zHO=QiyFQLu?H-Ncr3;sh8UqS*Y>Wk`h9NL$^u1*LaJS5$N;HK+{j;J)_tu;1*Cbd` zH`@^eU0AFDtZ)#x>#@hDUJ>D&g0@Wc0U=r==~pajruzZ70=|62nwu%Qt&sH(iB#t z!t*MIBa=IRkbo0{6!HW-15%veCo9r8qQ6Q(s|vUPwl8x=(->Hh literal 0 HcmV?d00001 diff --git a/staticfiles/admin/js/vendor/jquery/jquery.0208b96062ba.js b/staticfiles/admin/js/vendor/jquery/jquery.0208b96062ba.js new file mode 100644 index 0000000000..7f35c11bdf --- /dev/null +++ b/staticfiles/admin/js/vendor/jquery/jquery.0208b96062ba.js @@ -0,0 +1,10965 @@ +/*! + * jQuery JavaScript Library v3.6.4 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2023-03-08T15:28Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket trac-14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.4", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.10 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2023-02-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Make sure the the `:has()` argument is parsed unforgivingly. + // We include `*` in the test to detect buggy implementations that are + // _selectively_ forgiving (specifically when the list includes at least + // one valid selector). + // Note that we treat complete lack of support for `:has()` as if it were + // spec-compliant support, which is fine because use of `:has()` in such + // environments will fail in the qSA path and fall back to jQuery traversal + // anyway. + support.cssHas = assert( function() { + try { + document.querySelector( ":has(*,:jqfake)" ); + return false; + } catch ( e ) { + return true; + } + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + if ( !support.cssHas ) { + + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Our regular `try-catch` mechanism fails to detect natively-unsupported + // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) + // in browsers that parse the `:has()` argument as a forgiving selector list. + // https://drafts.csswg.org/selectors/#relational now requires the argument + // to be parsed unforgivingly, but browsers have not yet fully adjusted. + rbuggyQSA.push( ":has" ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + + // Support: IE <9 only + // IE doesn't have `contains` on `document` so we need to check for + // `documentElement` presence. + // We need to fall back to `a` when `documentElement` is missing + // as `ownerDocument` of elements within `