├── .gitignore ├── LICENSE ├── README.md ├── chat ├── __init__.py ├── admin.py ├── apps.py ├── consumers.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── routing.py ├── serializers.py ├── tests.py └── views │ ├── __init__.py │ ├── chat_view.py │ ├── friends_view.py │ ├── home_view.py │ └── user_view.py ├── devnoms ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py ├── manage.py ├── requirements.txt ├── static └── admin │ ├── css │ ├── autocomplete.css │ ├── base.css │ ├── changelists.css │ ├── dark_mode.css │ ├── dashboard.css │ ├── forms.css │ ├── login.css │ ├── nav_sidebar.css │ ├── responsive.css │ ├── responsive_rtl.css │ ├── rtl.css │ ├── vendor │ │ └── select2 │ │ │ ├── LICENSE-SELECT2.md │ │ │ ├── select2.css │ │ │ └── select2.min.css │ └── widgets.css │ ├── img │ ├── LICENSE │ ├── README.txt │ ├── calendar-icons.svg │ ├── gis │ │ ├── move_vertex_off.svg │ │ └── move_vertex_on.svg │ ├── icon-addlink.svg │ ├── icon-alert.svg │ ├── icon-calendar.svg │ ├── icon-changelink.svg │ ├── icon-clock.svg │ ├── icon-deletelink.svg │ ├── icon-no.svg │ ├── icon-unknown-alt.svg │ ├── icon-unknown.svg │ ├── icon-viewlink.svg │ ├── icon-yes.svg │ ├── inline-delete.svg │ ├── search.svg │ ├── selector-icons.svg │ ├── sorting-icons.svg │ ├── tooltag-add.svg │ └── tooltag-arrowright.svg │ └── js │ ├── SelectBox.js │ ├── SelectFilter2.js │ ├── actions.js │ ├── admin │ ├── DateTimeShortcuts.js │ └── RelatedObjectLookups.js │ ├── autocomplete.js │ ├── calendar.js │ ├── cancel.js │ ├── change_form.js │ ├── collapse.js │ ├── core.js │ ├── filters.js │ ├── inlines.js │ ├── jquery.init.js │ ├── nav_sidebar.js │ ├── popup_response.js │ ├── prepopulate.js │ ├── prepopulate_init.js │ ├── theme.js │ ├── urlify.js │ └── vendor │ ├── jquery │ ├── LICENSE.txt │ ├── jquery.js │ └── jquery.min.js │ ├── select2 │ ├── LICENSE.md │ ├── i18n │ │ ├── af.js │ │ ├── ar.js │ │ ├── az.js │ │ ├── bg.js │ │ ├── bn.js │ │ ├── bs.js │ │ ├── ca.js │ │ ├── cs.js │ │ ├── da.js │ │ ├── de.js │ │ ├── dsb.js │ │ ├── el.js │ │ ├── en.js │ │ ├── es.js │ │ ├── et.js │ │ ├── eu.js │ │ ├── fa.js │ │ ├── fi.js │ │ ├── fr.js │ │ ├── gl.js │ │ ├── he.js │ │ ├── hi.js │ │ ├── hr.js │ │ ├── hsb.js │ │ ├── hu.js │ │ ├── hy.js │ │ ├── id.js │ │ ├── is.js │ │ ├── it.js │ │ ├── ja.js │ │ ├── ka.js │ │ ├── km.js │ │ ├── ko.js │ │ ├── lt.js │ │ ├── lv.js │ │ ├── mk.js │ │ ├── ms.js │ │ ├── nb.js │ │ ├── ne.js │ │ ├── nl.js │ │ ├── pl.js │ │ ├── ps.js │ │ ├── pt-BR.js │ │ ├── pt.js │ │ ├── ro.js │ │ ├── ru.js │ │ ├── sk.js │ │ ├── sl.js │ │ ├── sq.js │ │ ├── sr-Cyrl.js │ │ ├── sr.js │ │ ├── sv.js │ │ ├── th.js │ │ ├── tk.js │ │ ├── tr.js │ │ ├── uk.js │ │ ├── vi.js │ │ ├── zh-CN.js │ │ └── zh-TW.js │ ├── select2.full.js │ └── select2.full.min.js │ └── xregexp │ ├── LICENSE.txt │ ├── xregexp.js │ └── xregexp.min.js └── templates ├── chat.html ├── edit.html ├── friend.html ├── home.html ├── login.html ├── search.html └── signup.html /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore virtual environment 2 | venv/ 3 | venv/* 4 | 5 | # Python bytecode 6 | *.py[cod] 7 | __pycache__/ 8 | 9 | # Django stuff 10 | *.log 11 | *.pot 12 | *.pyc 13 | *.pyo 14 | *.pyd 15 | *.sqlite3 16 | db.sqlite3 17 | 18 | 19 | # Environment variables 20 | .env -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Dev Namdev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # [Django Chat Application (Devnoms)](https://devnoms.onrender.com) 3 | 4 |
5 | 6 | Devnoms Logo 7 | 8 |
9 | 10 | 🚀 Welcome to **Devnoms Chat App**, a modern, feature-rich real-time chat platform! Designed to empower seamless communication, **Devnoms Chat App** allows users to connect with friends, manage profiles, and engage in real-time conversations with an intuitive interface and cutting-edge features. 11 | 12 | --- 13 | 14 | ## 🌐 **Live Preview** 15 | 16 | Experience the power of **Devnoms Chat App** right now: 17 | 18 | [![Live Preview](https://img.shields.io/badge/Live-Preview-brightgreen?style=for-the-badge&logo=django)](https://devnoms.onrender.com) 19 | 20 | --- 21 | 22 | ## 🌟 **About Devnoms Chat App** 23 | 24 | **Devnoms Chat App** is a secure and scalable platform that simplifies how you connect with friends and manage your social interactions. Whether you’re sending friend requests, chatting in real-time, or managing your profile, **Devnoms** has everything you need to stay connected. 25 | 26 | --- 27 | 28 | ## 🎯 **Why Choose Devnoms Chat App?** 29 | 30 | ✨ **Devnoms Chat App** delivers: 31 | 32 | - **Seamless Communication**: Real-time chat functionality to keep you connected. 33 | - **User-Centric Features**: A clean, intuitive interface for effortless navigation. 34 | - **Secure Interactions**: Robust authentication and privacy-focused design. 35 | - **Customization**: Manage your profile, find friends, and control your experience. 36 | 37 | --- 38 | 39 | ## 🚀 **Key Features** 40 | 41 | - **Secure User Authentication**: Login and signup with confidence. 42 | - **Profile Management**: Update your name, image, and other details effortlessly. 43 | - **Friend Management**: Send, accept, or decline friend requests. 44 | - **Real-Time Chat**: Engage in dynamic conversations using API-powered updates. 45 | - **Search and Connect**: Find and connect with users quickly. 46 | 47 | --- 48 | 49 | ## 🛠️ **Technology Stack** 50 | 51 | - **Backend**: Django (Python) 52 | - **Frontend**: HTML, CSS, JavaScript 53 | - **Database**: PostgreSQL 54 | - **Real-Time Communication**: WebSockets (for real-time communication) 55 | 56 | --- 57 | 58 | ## 📝 **User Flow** 59 | 60 | 1. **Sign Up or Log In**: Create your account or log in securely. 61 | 2. **Dashboard Access**: 62 | - Edit your profile and manage settings. 63 | - Search and add friends effortlessly. 64 | 3. **Friend Requests**: Send, accept, or decline friend requests. 65 | 4. **Start Chatting**: Engage in seamless, real-time conversations. 66 | 67 | --- 68 | 69 | ## 🌟 **Project Goals** 70 | 71 | - Build a secure, scalable, and user-friendly platform. 72 | - Enable seamless friend management and communication. 73 | - Ensure high performance with intuitive design. 74 | 75 | --- 76 | 77 | ## 🌍 **Future Enhancements** 78 | 79 | Here’s what’s coming next to **Devnoms Chat App**: 80 | 81 | 1. **Real-Time Notifications**: Alerts for new messages and friend requests. 82 | 2. **Multimedia Sharing**: Send images, videos, and documents in chats. 83 | 3. **Group Chat**: Create and manage group conversations. 84 | 4. **Profile Customization**: Add profile pictures and enhanced details. 85 | 86 | --- 87 | 88 | ## 🖥️ **Getting Started** 89 | 90 | Clone the **Devnoms Chat App** repository and set up locally: 91 | 92 | 1. **Clone the Repository** 93 | 94 | ```bash 95 | git clone https://github.com/devnamdev2003/django-chat-app.git 96 | cd django-chat-app 97 | ``` 98 | 99 | 2. **Install Dependencies** 100 | 101 | ```bash 102 | python -m venv venv 103 | source venv/bin/activate # On Windows: venv\Scripts\activate 104 | pip install -r requirements.txt 105 | ``` 106 | 107 | 3. **Set Up the Database** 108 | 109 | ```bash 110 | python manage.py migrate 111 | ``` 112 | 113 | 4. **Run the Server** 114 | 115 | ```bash 116 | daphne devnoms.asgi:application 117 | ``` 118 | 119 | 5. Open your browser and navigate to: `http://localhost:8000/`. 120 | 121 | --- 122 | 123 | ## 💻 **Contributions** 124 | 125 | We welcome contributions to **Devnoms Chat App**! 126 | 127 | 1. Fork the repository. 128 | 2. Create a feature branch (`git checkout -b feature-name`). 129 | 3. Commit your changes (`git commit -m "Add feature"`). 130 | 4. Push to your branch (`git push origin feature-name`). 131 | 5. Open a pull request. 132 | 133 | --- 134 | 135 | ## 📷 **Screenshots** 136 | 137 | Here’s a preview of the **Devnoms Chat App**: 138 | 139 | **Login Page** 140 | ![Login](https://filesstatic.netlify.app/Chatapp/img/login.png) 141 | 142 | **Signup Page** 143 | ![Signup](https://filesstatic.netlify.app/Chatapp/img/signup.png) 144 | 145 | **Chat Interface** 146 | ![Chat Interface](https://filesstatic.netlify.app/Chatapp/img/chat.png) 147 | 148 | **Profile Management** 149 | ![Edit Profile](https://filesstatic.netlify.app/Chatapp/img/edit.png) 150 | 151 | --- 152 | 153 | ## 📜 **License** 154 | 155 | The **Devnoms Chat App** is released under the [MIT License](LICENSE). 156 | 157 | --- 158 | 159 | # 💬 **Join Devnoms Today!** 160 | 161 | Don’t miss out on seamless communication with **Devnoms Chat App**! Start chatting now and experience a whole new level of connectivity. 162 | 163 | 🔗 [**Try Devnoms Now**](https://devnoms.onrender.com) 164 | -------------------------------------------------------------------------------- /chat/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devnamdev2003/django-chat-app/1f57208327a498136cd723b0c2e38c4fcf22aeab/chat/__init__.py -------------------------------------------------------------------------------- /chat/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import UserRelation 3 | from django.contrib import admin 4 | from django.contrib.auth.admin import UserAdmin 5 | from django.contrib.auth.models import User 6 | from .models import Messages 7 | 8 | 9 | class MessagesAdmin(admin.ModelAdmin): 10 | list_display = ("sender_name", "receiver_name", "time", "seen") 11 | list_filter = ("sender_name", "receiver_name", "seen") 12 | search_fields = ("sender_name__username", "receiver_name__username", "description") 13 | 14 | 15 | admin.site.register(Messages, MessagesAdmin) 16 | 17 | 18 | # Define a custom admin class for the User model 19 | class CustomUserAdmin(UserAdmin): 20 | list_display = ( 21 | "id", 22 | "username", 23 | "email", 24 | "first_name", 25 | "last_name", 26 | "is_staff", 27 | "date_joined", 28 | ) 29 | 30 | 31 | # Unregister the default UserAdmin 32 | admin.site.unregister(User) 33 | 34 | # Register the User model with the custom admin class 35 | admin.site.register(User, CustomUserAdmin) 36 | 37 | 38 | class UserRelationAdmin(admin.ModelAdmin): 39 | list_display = ("id", "user", "friend", "accepted") 40 | list_filter = ("user", "accepted") 41 | search_fields = ("user__username", "friend") 42 | 43 | 44 | admin.site.register(UserRelation, UserRelationAdmin) 45 | -------------------------------------------------------------------------------- /chat/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class chatConfig(AppConfig): 5 | name = 'chat' 6 | -------------------------------------------------------------------------------- /chat/consumers.py: -------------------------------------------------------------------------------- 1 | import json 2 | from channels.generic.websocket import AsyncWebsocketConsumer 3 | 4 | from django.utils import timezone 5 | from channels.db import database_sync_to_async 6 | 7 | # Define an async function to save the message to the database 8 | @database_sync_to_async 9 | def save_message(sender_name, receiver_name, message): 10 | from django.contrib.auth.models import User 11 | from chat.models import Messages 12 | # Get User instances for sender and receiver 13 | sender = User.objects.get(username=sender_name) 14 | receiver = User.objects.get(username=receiver_name) 15 | 16 | # Create a new message 17 | new_message = Messages( 18 | description=message, 19 | sender_name=sender, 20 | receiver_name=receiver, 21 | time=timezone.now().time(), # Store the current time 22 | timestamp=timezone.now(), # Store the timestamp 23 | seen=True 24 | ) 25 | new_message.save() 26 | class ChatConsumer(AsyncWebsocketConsumer): 27 | async def connect(self): 28 | self.room_name = self.scope['url_route']['kwargs']['room_name'] 29 | self.room_group_name = f'chat_{self.room_name}' 30 | print(self.room_name, self.room_group_name) 31 | # Join room group 32 | await self.channel_layer.group_add( 33 | self.room_group_name, 34 | self.channel_name 35 | ) 36 | await self.accept() 37 | 38 | async def disconnect(self, close_code): 39 | # Leave room group 40 | await self.channel_layer.group_discard( 41 | self.room_group_name, 42 | self.channel_name 43 | ) 44 | 45 | # Receive message from WebSocket 46 | async def receive(self, text_data): 47 | text_data_json = json.loads(text_data) 48 | message = text_data_json['message'] 49 | sender_name = text_data_json['sender_name'] 50 | receiver_name = text_data_json['receiver_name'] 51 | await save_message(sender_name, receiver_name, message) 52 | # Send message to room group 53 | await self.channel_layer.group_send( 54 | self.room_group_name, 55 | { 56 | 'type': 'chat_message', 57 | 'message': message, 58 | 'sender': sender_name 59 | } 60 | ) 61 | 62 | # Receive message from room group 63 | async def chat_message(self, event): 64 | message = event['message'] 65 | sender = event['sender'] 66 | 67 | # Send message to WebSocket 68 | await self.send(text_data=json.dumps({ 69 | 'message': message, 70 | 'sender': sender 71 | })) 72 | -------------------------------------------------------------------------------- /chat/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 5.1.3 on 2025-01-26 06:21 2 | 3 | import django.db.models.deletion 4 | import django.utils.timezone 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Messages', 20 | fields=[ 21 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('description', models.TextField()), 23 | ('time', models.TimeField(auto_now_add=True)), 24 | ('seen', models.BooleanField(default=False)), 25 | ('timestamp', models.DateTimeField(blank=True, default=django.utils.timezone.now)), 26 | ('receiver_name', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='receiver', to=settings.AUTH_USER_MODEL)), 27 | ('sender_name', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sender', to=settings.AUTH_USER_MODEL)), 28 | ], 29 | options={ 30 | 'ordering': ('timestamp',), 31 | }, 32 | ), 33 | migrations.CreateModel( 34 | name='UserRelation', 35 | fields=[ 36 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 37 | ('accepted', models.BooleanField(default=False)), 38 | ('relation_key', models.CharField(blank=True, max_length=255, null=True)), 39 | ('friend', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='friend_relations', to=settings.AUTH_USER_MODEL)), 40 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_relations', to=settings.AUTH_USER_MODEL)), 41 | ], 42 | ), 43 | ] 44 | -------------------------------------------------------------------------------- /chat/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devnamdev2003/django-chat-app/1f57208327a498136cd723b0c2e38c4fcf22aeab/chat/migrations/__init__.py -------------------------------------------------------------------------------- /chat/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | from django.utils import timezone 4 | 5 | 6 | class UserRelation(models.Model): 7 | user = models.ForeignKey( 8 | User, on_delete=models.CASCADE, related_name="user_relations" 9 | ) 10 | friend = models.ForeignKey( 11 | User, on_delete=models.CASCADE, related_name="friend_relations", default=None 12 | ) 13 | accepted = models.BooleanField(default=False) 14 | relation_key = models.CharField(max_length=255, blank=True, null=True) # Add relation_key field 15 | def __str__(self): 16 | return f"{self.user.username} - {self.friend.username}" 17 | 18 | 19 | class Messages(models.Model): 20 | description = models.TextField() 21 | sender_name = models.ForeignKey( 22 | User, on_delete=models.CASCADE, related_name="sender" 23 | ) 24 | receiver_name = models.ForeignKey( 25 | User, on_delete=models.CASCADE, related_name="receiver" 26 | ) 27 | time = models.TimeField(auto_now_add=True) 28 | seen = models.BooleanField(default=False) 29 | timestamp = models.DateTimeField(default=timezone.now, blank=True) 30 | 31 | class Meta: 32 | ordering = ("timestamp",) -------------------------------------------------------------------------------- /chat/routing.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import consumers 3 | 4 | websocket_urlpatterns = [ 5 | path('ws/chat//', consumers.ChatConsumer.as_asgi()), 6 | ] 7 | -------------------------------------------------------------------------------- /chat/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from .models import Messages 3 | from django.contrib.auth.models import User 4 | 5 | 6 | 7 | class MessageSerializer(serializers.ModelSerializer): 8 | 9 | sender_name = serializers.SlugRelatedField(many=False, slug_field='username', queryset=User.objects.all()) 10 | receiver_name = serializers.SlugRelatedField(many=False, slug_field='username', queryset=User.objects.all()) 11 | 12 | class Meta: 13 | model = Messages 14 | fields = ['sender_name', 'receiver_name', 'description', 'time'] 15 | -------------------------------------------------------------------------------- /chat/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | -------------------------------------------------------------------------------- /chat/views/__init__.py: -------------------------------------------------------------------------------- 1 | from .chat_view import * 2 | from .friends_view import * 3 | from .home_view import * 4 | from .user_view import * 5 | -------------------------------------------------------------------------------- /chat/views/chat_view.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect 2 | from django.contrib.auth.models import User 3 | from django.contrib.auth.decorators import login_required 4 | from chat.models import UserRelation, Messages 5 | from django.http.response import JsonResponse 6 | from django.contrib import messages as django_messages 7 | 8 | 9 | @login_required(login_url="login") 10 | def chat(request, username): 11 | try: 12 | usersen = request.user 13 | friend = User.objects.get(username=username) 14 | exists = UserRelation.objects.filter( 15 | user=request.user, friend=friend, accepted=True 16 | ).exists() 17 | 18 | if not exists: 19 | django_messages.error(request, "You are not able to chat with this user.") 20 | return redirect("home") # Ensure we return a response here 21 | 22 | except User.DoesNotExist: 23 | return redirect("home") # Ensure we return a response here 24 | 25 | # Get the messages 26 | messages = Messages.objects.filter( 27 | sender_name=usersen, receiver_name=friend 28 | ) | Messages.objects.filter(sender_name=friend, receiver_name=usersen) 29 | 30 | if request.method == "GET": 31 | try: 32 | # Ensure UserRelation exists 33 | relation = UserRelation.objects.get( 34 | user=request.user, friend=friend, accepted=True 35 | ) 36 | return render( 37 | request, 38 | "chat.html", 39 | { 40 | "relation_key": relation.relation_key, 41 | "messages": messages, 42 | "curr_user": usersen, 43 | "friend": friend, 44 | }, 45 | ) 46 | except UserRelation.DoesNotExist: 47 | # If no relation exists, redirect to home 48 | django_messages.error(request, "Relation not found.") 49 | return redirect("home") 50 | 51 | # If the method is not GET, you might want to handle it here (e.g., return an error or a response) 52 | return JsonResponse({"error": "Invalid request method"}, status=405) 53 | 54 | 55 | # @login_required(login_url="login") 56 | # @csrf_exempt 57 | # def message_list(request, sender=None, receiver=None): 58 | # if request.method == "GET": 59 | # messages = Messages.objects.filter( 60 | # sender_name=sender, receiver_name=receiver, seen=False 61 | # ) 62 | # serializer = MessageSerializer( 63 | # messages, many=True, context={"request": request} 64 | # ) 65 | # for message in messages: 66 | # message.seen = True 67 | # message.save() 68 | # return JsonResponse(serializer.data, safe=False) 69 | 70 | # elif request.method == "POST": 71 | # data = JSONParser().parse(request) 72 | # serializer = MessageSerializer(data=data) 73 | # if serializer.is_valid(): 74 | # serializer.save() 75 | # return JsonResponse(serializer.data, status=201) 76 | # return JsonResponse(serializer.errors, status=400) 77 | -------------------------------------------------------------------------------- /chat/views/friends_view.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect 2 | from django.contrib.auth.models import User 3 | from django.contrib.auth.decorators import login_required 4 | from chat.models import UserRelation 5 | from django.contrib import messages 6 | from django.http import HttpResponseRedirect 7 | from django.urls import reverse 8 | 9 | @login_required(login_url="login") 10 | def delete_friend(request): 11 | if request.method == "POST": 12 | username = request.POST.get("username") 13 | user = request.user 14 | friend = User.objects.get(username=username) 15 | try: 16 | print("starts") 17 | exists = UserRelation.objects.filter(user=user, friend=friend).exists() 18 | print("sts") 19 | if exists: 20 | pass 21 | else: 22 | return HttpResponseRedirect( 23 | request.META.get("HTTP_REFERER", reverse("home")) 24 | ) 25 | user_relation = UserRelation.objects.get(user=user, friend=friend) 26 | user_relation.delete() 27 | 28 | user_relation_reverse = UserRelation.objects.get(user=friend, friend=user) 29 | user_relation_reverse.delete() 30 | messages.success(request, "Friend deleted successfully.") 31 | 32 | except UserRelation.DoesNotExist: 33 | messages.success(request, "Request deleted successfully.") 34 | pass 35 | return redirect("home") 36 | else: 37 | return redirect("home") 38 | 39 | 40 | @login_required(login_url="login") 41 | def accept_request(request): 42 | if request.method == "POST": 43 | username = request.POST.get("username") 44 | user = request.user 45 | friend = User.objects.get(username=username) 46 | accepted = True 47 | 48 | exists = UserRelation.objects.filter(user=user, friend=friend).exists() 49 | print("sts") 50 | if exists: 51 | return HttpResponseRedirect( 52 | request.META.get("HTTP_REFERER", reverse("home")) 53 | ) 54 | relation_key = username + "_" + user.username 55 | user_relation = UserRelation( 56 | user=user, friend=friend, accepted=accepted, relation_key=relation_key 57 | ) 58 | user_relation.save() 59 | 60 | user_relation_revrse = UserRelation.objects.get(user=friend, friend=user) 61 | user_relation_revrse.accepted = True 62 | user_relation_revrse.relation_key = relation_key 63 | user_relation_revrse.save() 64 | messages.success(request, "Friend Added successfully.") 65 | 66 | return redirect("home") 67 | else: 68 | return redirect("home") 69 | 70 | 71 | @login_required(login_url="login") 72 | def add_friend(request): 73 | if request.method == "POST": 74 | username = request.POST.get("username") 75 | user = request.user 76 | friend = User.objects.get(username=username) 77 | accepted = False 78 | print("starts") 79 | exists = UserRelation.objects.filter(user=user, friend=friend).exists() 80 | print("sts") 81 | if exists: 82 | print("star") 83 | return HttpResponseRedirect( 84 | request.META.get("HTTP_REFERER", reverse("home")) 85 | ) 86 | user_relation = UserRelation(user=user, friend=friend, accepted=accepted) 87 | user_relation.save() 88 | messages.success(request, "Request sended successfully.") 89 | 90 | return redirect("home") 91 | else: 92 | return redirect("home") 93 | 94 | 95 | @login_required(login_url="login") 96 | def search(request): 97 | if request.method == "GET": 98 | query = request.GET.get("q", "") 99 | if query: 100 | users = User.objects.filter(username__icontains=query) 101 | if users: 102 | return render( 103 | request, 104 | "search.html", 105 | {"query": query, "users": users, "user": request.user.username}, 106 | ) 107 | else: 108 | not_found_message = f'No users found for "{query}"' 109 | return render( 110 | request, 111 | "search.html", 112 | { 113 | "query": query, 114 | "not_found_message": not_found_message, 115 | }, 116 | ) 117 | 118 | return render(request, "search.html", {"user": request.user.username}) 119 | 120 | -------------------------------------------------------------------------------- /chat/views/home_view.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect 2 | from django.contrib.auth.models import User 3 | from django.contrib.auth.decorators import login_required 4 | from chat.models import UserRelation 5 | from django.contrib import messages 6 | 7 | 8 | @login_required(login_url="login") 9 | def userprofile(request, username): 10 | if username == request.user.username: 11 | return redirect("/") 12 | friend_dict = {} 13 | request_dict = {} 14 | friend_dict["accepted"] = False 15 | request_dict["accepted"] = False 16 | friend_dict["name"] = "" 17 | send_request = False 18 | not_accepted = False 19 | me_not_accepted = False 20 | is_friend = False 21 | try: 22 | user = User.objects.get(username=username) 23 | friends_data = UserRelation.objects.all() 24 | for obj in friends_data: 25 | if obj.user.username == request.user.username: 26 | if obj.friend.username == username: 27 | friend_dict = { 28 | "name": obj.friend.username, 29 | "accepted": obj.accepted, 30 | } 31 | for obj in friends_data: 32 | if obj.friend.username == request.user.username: 33 | if obj.user.username == username: 34 | if obj.accepted: 35 | me_not_accepted = False 36 | else: 37 | me_not_accepted = True 38 | 39 | except User.DoesNotExist: 40 | messages.error(request, "User does not exist.") 41 | return render(request, "friend.html") 42 | 43 | if friend_dict["name"] == "": 44 | if me_not_accepted == True: 45 | print("me not accepted") 46 | else: 47 | print("not a friend") 48 | send_request = True 49 | 50 | elif friend_dict["accepted"] == False: 51 | print("not_accepted") 52 | not_accepted = True 53 | 54 | else: 55 | print("friend") 56 | is_friend = True 57 | print("send_request = ", send_request) 58 | print("not_accepted = ", not_accepted) 59 | print("me_not_accepted = ", me_not_accepted) 60 | print("is_friend = ", is_friend) 61 | # You can now access user details, such as username, email, etc. 62 | user_details = { 63 | "username": user.username, 64 | "email": user.email, 65 | "send_request": send_request, 66 | "not_accepted": not_accepted, 67 | "is_friend": is_friend, 68 | "me_not_accepted": me_not_accepted, 69 | } 70 | 71 | return render(request, "friend.html", {"user_details": user_details}) 72 | 73 | 74 | from django.shortcuts import render, redirect 75 | from django.contrib.auth.models import User 76 | from django.contrib.auth.decorators import login_required 77 | from chat.models import UserRelation 78 | from django.contrib import messages 79 | @login_required(login_url="login") 80 | def HomePage(request): 81 | friends_data = UserRelation.objects.all() 82 | friends_list = [] 83 | for obj in friends_data: 84 | if obj.user.username == request.user.username: 85 | friend_dict = {"username": obj.friend.username, "accepted": obj.accepted} 86 | friends_list.append(friend_dict) 87 | 88 | request_list = [] 89 | for obj in friends_data: 90 | if obj.friend.username == request.user.username: 91 | if not obj.accepted: 92 | request_dict = {"username": obj.user.username} 93 | request_list.append(request_dict) 94 | 95 | data = { 96 | "email": request.user.email, 97 | "username": request.user.username, 98 | "friends": friends_list, 99 | "requests": request_list, 100 | } 101 | return render( 102 | request, 103 | "home.html", 104 | { 105 | "data": data, 106 | }, 107 | ) 108 | 109 | 110 | -------------------------------------------------------------------------------- /chat/views/user_view.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect 2 | from django.contrib.auth.models import User 3 | from django.contrib.auth import authenticate, login, logout 4 | from django.contrib.auth.decorators import login_required 5 | from django.db.models import Q 6 | 7 | @login_required(login_url="login") 8 | def EditProfile(request): 9 | success_message = None 10 | error_message = None 11 | 12 | if request.method == "POST": 13 | new_email = request.POST.get("email") 14 | new_username = request.POST.get("username") 15 | 16 | # Check if the new username is already taken 17 | if ( 18 | new_username != request.user.username 19 | and User.objects.filter(username=new_username).exists() 20 | ): 21 | error_message = "Username already exists. Please choose a different one." 22 | elif ( 23 | new_email != request.user.email 24 | and User.objects.filter(email=new_email).exists() 25 | ): 26 | error_message = "Email address already associated with another account. Please choose a different one." 27 | else: 28 | # Update email and username 29 | # print(request.user.id) 30 | request.user.email = new_email 31 | request.user.username = new_username 32 | request.user.save() 33 | success_message = "Profile updated successfully." 34 | 35 | # Pre-fill the form with the user's existing data 36 | initial_data = { 37 | "email": request.user.email, 38 | "username": request.user.username, 39 | } 40 | 41 | return render( 42 | request, 43 | "edit.html", 44 | { 45 | "initial_data": initial_data, 46 | "success_message": success_message, 47 | "error_message": error_message, 48 | }, 49 | ) 50 | 51 | 52 | def SignupPage(request): 53 | if request.user.is_authenticated: 54 | return redirect("home") 55 | error_message = "" # Initialize error_message as None 56 | 57 | if request.method == "POST": 58 | uname = request.POST.get("username") 59 | email = request.POST.get("email") 60 | pass1 = request.POST.get("password1") 61 | pass2 = request.POST.get("password2") 62 | 63 | data = { 64 | "username": uname, 65 | "useremail": email, 66 | } 67 | 68 | # Check if a user with the same email or username already exists 69 | if User.objects.filter(username=uname).exists(): 70 | error_message = "A user with the same username already exists." 71 | return render( 72 | request, 73 | "signup.html", 74 | {"error_message": error_message, "userdata": data}, 75 | ) 76 | 77 | elif User.objects.filter(email=email).exists(): 78 | error_message = "A user with the same email already exists." 79 | return render( 80 | request, 81 | "signup.html", 82 | {"error_message": error_message, "userdata": data}, 83 | ) 84 | 85 | else: 86 | # Create the user 87 | user = User.objects.create_user(username=uname, email=email, password=pass1) 88 | user.save() 89 | # Log the user in after registration 90 | login(request, user) 91 | return redirect("home") 92 | 93 | return render(request, "signup.html", {"error_message": error_message}) 94 | 95 | 96 | def LoginPage(request): 97 | if request.user.is_authenticated: 98 | return redirect("home") 99 | error_message = "" 100 | email_or_username = "" 101 | if request.method == "POST": 102 | email_or_username = request.POST.get("email_or_username") 103 | pass1 = request.POST.get("pass") 104 | try: 105 | curr_user = User.objects.get(Q(email=email_or_username) | Q(username=email_or_username)) 106 | except User.DoesNotExist: 107 | error_message = "User not found. Please check your Email/Username" 108 | return render( 109 | request, "login.html", {"error_message": error_message, "email": email_or_username} 110 | ) 111 | 112 | user = authenticate(request, username=curr_user.username, password=pass1) 113 | if user is not None: 114 | login(request, user) 115 | return redirect("home") 116 | else: 117 | if User.objects.filter(username=curr_user.username).exists(): 118 | error_message = "Incorrect password. Please try again." 119 | else: 120 | error_message = "Email not found. Please check your email." 121 | return render( 122 | request, "login.html", {"error_message": error_message, "email": email_or_username} 123 | ) 124 | 125 | 126 | def LogoutPage(request): 127 | logout(request) 128 | return redirect("login") -------------------------------------------------------------------------------- /devnoms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devnamdev2003/django-chat-app/1f57208327a498136cd723b0c2e38c4fcf22aeab/devnoms/__init__.py -------------------------------------------------------------------------------- /devnoms/asgi.py: -------------------------------------------------------------------------------- 1 | import os 2 | from django.core.asgi import get_asgi_application 3 | from channels.routing import ProtocolTypeRouter, URLRouter 4 | from channels.auth import AuthMiddlewareStack 5 | import chat.routing 6 | 7 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'devnoms.settings') 8 | 9 | application = ProtocolTypeRouter({ 10 | "http": get_asgi_application(), 11 | "websocket": AuthMiddlewareStack( 12 | URLRouter( 13 | chat.routing.websocket_urlpatterns 14 | ) 15 | ), 16 | }) -------------------------------------------------------------------------------- /devnoms/settings.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from dotenv import load_dotenv 3 | import os 4 | 5 | load_dotenv() 6 | 7 | DEVELOPMENT = "live" 8 | DEVELOPMENT = "local" 9 | DEVELOPMENT = "open" 10 | DEBUG = True 11 | BASE_DIR = Path(__file__).resolve().parent.parent 12 | 13 | 14 | if DEVELOPMENT == "local": 15 | # Development 16 | DEBUG = True 17 | DATABASES = { 18 | "default": { 19 | "ENGINE": "django.db.backends.postgresql", 20 | "NAME": "devnoms_localdb", 21 | "USER": os.getenv("DB_USER_LOCAL"), 22 | "PASSWORD": os.getenv("DB_PASS_LOCAL"), 23 | "HOST": os.getenv("DB_HOST_LOCAL"), 24 | "PORT": "", 25 | } 26 | } 27 | SITE_URL = "http://localhost:8000" 28 | SECRET_KEY = os.getenv("SECRET_KEY") 29 | 30 | 31 | elif DEVELOPMENT == "open": 32 | # open 33 | DEBUG = True 34 | SECRET_KEY = "django-insecure-**7)n#r9c(cra!m_$clhc5ff0tycci6!pn^n&_72fx^f6z(pzl" 35 | DATABASES = { 36 | "default": { 37 | "ENGINE": "django.db.backends.sqlite3", 38 | "NAME": BASE_DIR / "db.sqlite3", 39 | } 40 | } 41 | SITE_URL = "http://localhost:8000" 42 | 43 | 44 | else: 45 | # Live 46 | # DEBUG = False 47 | DATABASES = { 48 | "default": { 49 | "ENGINE": "django.db.backends.postgresql", 50 | "NAME": os.getenv("DB_NAME_LIVE"), 51 | "USER": os.getenv("DB_USER_LIVE"), 52 | "PASSWORD": os.getenv("DB_PASS_LIVE"), 53 | "HOST": os.getenv("DB_HOST_LIVE"), 54 | "PORT": "", 55 | "OPTIONS": { 56 | "sslmode": "require", 57 | }, 58 | } 59 | } 60 | SITE_URL = "https://devnoms.onrender.com" 61 | SECRET_KEY = os.getenv("SECRET_KEY") 62 | 63 | 64 | ALLOWED_HOSTS = ["*"] 65 | 66 | 67 | INSTALLED_APPS = [ 68 | "channels", 69 | "django.contrib.admin", 70 | "django.contrib.auth", 71 | "django.contrib.contenttypes", 72 | "django.contrib.sessions", 73 | "django.contrib.messages", 74 | "django.contrib.staticfiles", 75 | "chat", 76 | "corsheaders", 77 | ] 78 | ASGI_APPLICATION = "devnoms.asgi.application" 79 | 80 | CHANNEL_LAYERS = { 81 | "default": { 82 | "BACKEND": "channels.layers.InMemoryChannelLayer", 83 | } 84 | } 85 | 86 | 87 | MIDDLEWARE = [ 88 | "django.middleware.security.SecurityMiddleware", 89 | "django.contrib.sessions.middleware.SessionMiddleware", 90 | "django.middleware.common.CommonMiddleware", 91 | "django.middleware.csrf.CsrfViewMiddleware", 92 | "django.contrib.auth.middleware.AuthenticationMiddleware", 93 | "django.contrib.messages.middleware.MessageMiddleware", 94 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 95 | "corsheaders.middleware.CorsMiddleware", 96 | ] 97 | 98 | ROOT_URLCONF = "devnoms.urls" 99 | 100 | TEMPLATES = [ 101 | { 102 | "BACKEND": "django.template.backends.django.DjangoTemplates", 103 | "DIRS": ["templates"], 104 | "APP_DIRS": True, 105 | "OPTIONS": { 106 | "context_processors": [ 107 | "django.template.context_processors.debug", 108 | "django.template.context_processors.request", 109 | "django.contrib.auth.context_processors.auth", 110 | "django.contrib.messages.context_processors.messages", 111 | ], 112 | }, 113 | }, 114 | ] 115 | 116 | WSGI_APPLICATION = "devnoms.wsgi.application" 117 | 118 | AUTH_PASSWORD_VALIDATORS = [ 119 | { 120 | "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", 121 | }, 122 | { 123 | "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", 124 | }, 125 | { 126 | "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", 127 | }, 128 | { 129 | "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", 130 | }, 131 | ] 132 | 133 | 134 | LANGUAGE_CODE = "en-us" 135 | 136 | # TIME_ZONE = "UTC" 137 | 138 | TIME_ZONE = "Asia/Kolkata" 139 | 140 | USE_I18N = True 141 | 142 | USE_L10N = True 143 | 144 | USE_TZ = True 145 | 146 | LOGIN_URL = "login" 147 | 148 | 149 | STATIC_URL = "/static/" 150 | 151 | DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" 152 | 153 | STATIC_ROOT = os.path.join(BASE_DIR, "static") 154 | 155 | CORS_ALLOWED_ORIGINS = [ 156 | "http://127.0.0.1:5500", 157 | "http://localhost:3000", 158 | "https://devnoms.onrender.com", 159 | "https://django-chat-application.onrender.com", 160 | ] 161 | CORS_ALLOW_ALL_ORIGINS = True 162 | 163 | CSRF_TRUSTED_ORIGINS = [ 164 | "https://devnoms.onrender.com", 165 | "https://django-chat-application.onrender.com", 166 | ] 167 | -------------------------------------------------------------------------------- /devnoms/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from chat.views import * 3 | from django.urls import path 4 | from django.conf import settings 5 | from django.contrib.staticfiles.urls import static 6 | 7 | urlpatterns = [ 8 | path("admin/", admin.site.urls), 9 | path("", LoginPage, name="login"), 10 | path("signup/", SignupPage, name="signup"), 11 | path("logout/", LogoutPage, name="logout"), 12 | path("user/", HomePage, name="home"), 13 | path("edit/", EditProfile, name="edit"), 14 | path("user//", userprofile, name="username"), 15 | path("add_friend/", add_friend, name="add_friend"), 16 | path("accept_request/", accept_request, name="accept_request"), 17 | path("delete_friend/", delete_friend, name="delete_friend"), 18 | path("search/", search, name="search"), 19 | # re_path(r"^.*/$", RedirectView.as_view(pattern_name="login", permanent=False)), 20 | path("chat//", chat, name="chat"), 21 | ] 22 | 23 | 24 | if settings.DEBUG: 25 | urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 26 | -------------------------------------------------------------------------------- /devnoms/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for devnoms project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'devnoms.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'devnoms.settings') 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devnamdev2003/django-chat-app/1f57208327a498136cd723b0c2e38c4fcf22aeab/requirements.txt -------------------------------------------------------------------------------- /static/admin/css/changelists.css: -------------------------------------------------------------------------------- 1 | /* CHANGELISTS */ 2 | 3 | #changelist { 4 | display: flex; 5 | align-items: flex-start; 6 | justify-content: space-between; 7 | } 8 | 9 | #changelist .changelist-form-container { 10 | flex: 1 1 auto; 11 | min-width: 0; 12 | } 13 | 14 | #changelist table { 15 | width: 100%; 16 | } 17 | 18 | .change-list .hiddenfields { display:none; } 19 | 20 | .change-list .filtered table { 21 | border-right: none; 22 | } 23 | 24 | .change-list .filtered { 25 | min-height: 400px; 26 | } 27 | 28 | .change-list .filtered .results, .change-list .filtered .paginator, 29 | .filtered #toolbar, .filtered div.xfull { 30 | width: auto; 31 | } 32 | 33 | .change-list .filtered table tbody th { 34 | padding-right: 1em; 35 | } 36 | 37 | #changelist-form .results { 38 | overflow-x: auto; 39 | width: 100%; 40 | } 41 | 42 | #changelist .toplinks { 43 | border-bottom: 1px solid var(--hairline-color); 44 | } 45 | 46 | #changelist .paginator { 47 | color: var(--body-quiet-color); 48 | border-bottom: 1px solid var(--hairline-color); 49 | background: var(--body-bg); 50 | overflow: hidden; 51 | } 52 | 53 | /* CHANGELIST TABLES */ 54 | 55 | #changelist table thead th { 56 | padding: 0; 57 | white-space: nowrap; 58 | vertical-align: middle; 59 | } 60 | 61 | #changelist table thead th.action-checkbox-column { 62 | width: 1.5em; 63 | text-align: center; 64 | } 65 | 66 | #changelist table tbody td.action-checkbox { 67 | text-align: center; 68 | } 69 | 70 | #changelist table tfoot { 71 | color: var(--body-quiet-color); 72 | } 73 | 74 | /* TOOLBAR */ 75 | 76 | #toolbar { 77 | padding: 8px 10px; 78 | margin-bottom: 15px; 79 | border-top: 1px solid var(--hairline-color); 80 | border-bottom: 1px solid var(--hairline-color); 81 | background: var(--darkened-bg); 82 | color: var(--body-quiet-color); 83 | } 84 | 85 | #toolbar form input { 86 | border-radius: 4px; 87 | font-size: 0.875rem; 88 | padding: 5px; 89 | color: var(--body-fg); 90 | } 91 | 92 | #toolbar #searchbar { 93 | height: 1.1875rem; 94 | border: 1px solid var(--border-color); 95 | padding: 2px 5px; 96 | margin: 0; 97 | vertical-align: top; 98 | font-size: 0.8125rem; 99 | max-width: 100%; 100 | } 101 | 102 | #toolbar #searchbar:focus { 103 | border-color: var(--body-quiet-color); 104 | } 105 | 106 | #toolbar form input[type="submit"] { 107 | border: 1px solid var(--border-color); 108 | font-size: 0.8125rem; 109 | padding: 4px 8px; 110 | margin: 0; 111 | vertical-align: middle; 112 | background: var(--body-bg); 113 | box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; 114 | cursor: pointer; 115 | color: var(--body-fg); 116 | } 117 | 118 | #toolbar form input[type="submit"]:focus, 119 | #toolbar form input[type="submit"]:hover { 120 | border-color: var(--body-quiet-color); 121 | } 122 | 123 | #changelist-search img { 124 | vertical-align: middle; 125 | margin-right: 4px; 126 | } 127 | 128 | #changelist-search .help { 129 | word-break: break-word; 130 | } 131 | 132 | /* FILTER COLUMN */ 133 | 134 | #changelist-filter { 135 | flex: 0 0 240px; 136 | order: 1; 137 | background: var(--darkened-bg); 138 | border-left: none; 139 | margin: 0 0 0 30px; 140 | } 141 | 142 | #changelist-filter h2 { 143 | font-size: 0.875rem; 144 | text-transform: uppercase; 145 | letter-spacing: 0.5px; 146 | padding: 5px 15px; 147 | margin-bottom: 12px; 148 | border-bottom: none; 149 | } 150 | 151 | #changelist-filter h3, 152 | #changelist-filter details summary { 153 | font-weight: 400; 154 | padding: 0 15px; 155 | margin-bottom: 10px; 156 | } 157 | 158 | #changelist-filter details summary > * { 159 | display: inline; 160 | } 161 | 162 | #changelist-filter details > summary { 163 | list-style-type: none; 164 | } 165 | 166 | #changelist-filter details > summary::-webkit-details-marker { 167 | display: none; 168 | } 169 | 170 | #changelist-filter details > summary::before { 171 | content: '→'; 172 | font-weight: bold; 173 | color: var(--link-hover-color); 174 | } 175 | 176 | #changelist-filter details[open] > summary::before { 177 | content: '↓'; 178 | } 179 | 180 | #changelist-filter ul { 181 | margin: 5px 0; 182 | padding: 0 15px 15px; 183 | border-bottom: 1px solid var(--hairline-color); 184 | } 185 | 186 | #changelist-filter ul:last-child { 187 | border-bottom: none; 188 | } 189 | 190 | #changelist-filter li { 191 | list-style-type: none; 192 | margin-left: 0; 193 | padding-left: 0; 194 | } 195 | 196 | #changelist-filter a { 197 | display: block; 198 | color: var(--body-quiet-color); 199 | word-break: break-word; 200 | } 201 | 202 | #changelist-filter li.selected { 203 | border-left: 5px solid var(--hairline-color); 204 | padding-left: 10px; 205 | margin-left: -15px; 206 | } 207 | 208 | #changelist-filter li.selected a { 209 | color: var(--link-selected-fg); 210 | } 211 | 212 | #changelist-filter a:focus, #changelist-filter a:hover, 213 | #changelist-filter li.selected a:focus, 214 | #changelist-filter li.selected a:hover { 215 | color: var(--link-hover-color); 216 | } 217 | 218 | #changelist-filter #changelist-filter-clear a { 219 | font-size: 0.8125rem; 220 | padding-bottom: 10px; 221 | border-bottom: 1px solid var(--hairline-color); 222 | } 223 | 224 | /* DATE DRILLDOWN */ 225 | 226 | .change-list .toplinks { 227 | display: flex; 228 | padding-bottom: 5px; 229 | flex-wrap: wrap; 230 | gap: 3px 17px; 231 | font-weight: bold; 232 | } 233 | 234 | .change-list .toplinks a { 235 | font-size: 0.8125rem; 236 | } 237 | 238 | .change-list .toplinks .date-back { 239 | color: var(--body-quiet-color); 240 | } 241 | 242 | .change-list .toplinks .date-back:focus, 243 | .change-list .toplinks .date-back:hover { 244 | color: var(--link-hover-color); 245 | } 246 | 247 | /* ACTIONS */ 248 | 249 | .filtered .actions { 250 | border-right: none; 251 | } 252 | 253 | #changelist table input { 254 | margin: 0; 255 | vertical-align: baseline; 256 | } 257 | 258 | /* Once the :has() pseudo-class is supported by all browsers, the tr.selected 259 | selector and the JS adding the class can be removed. */ 260 | #changelist tbody tr.selected { 261 | background-color: var(--selected-row); 262 | } 263 | 264 | #changelist tbody tr:has(.action-select:checked) { 265 | background-color: var(--selected-row); 266 | } 267 | 268 | #changelist .actions { 269 | padding: 10px; 270 | background: var(--body-bg); 271 | border-top: none; 272 | border-bottom: none; 273 | line-height: 1.5rem; 274 | color: var(--body-quiet-color); 275 | width: 100%; 276 | } 277 | 278 | #changelist .actions span.all, 279 | #changelist .actions span.action-counter, 280 | #changelist .actions span.clear, 281 | #changelist .actions span.question { 282 | font-size: 0.8125rem; 283 | margin: 0 0.5em; 284 | } 285 | 286 | #changelist .actions:last-child { 287 | border-bottom: none; 288 | } 289 | 290 | #changelist .actions select { 291 | vertical-align: top; 292 | height: 1.5rem; 293 | color: var(--body-fg); 294 | border: 1px solid var(--border-color); 295 | border-radius: 4px; 296 | font-size: 0.875rem; 297 | padding: 0 0 0 4px; 298 | margin: 0; 299 | margin-left: 10px; 300 | } 301 | 302 | #changelist .actions select:focus { 303 | border-color: var(--body-quiet-color); 304 | } 305 | 306 | #changelist .actions label { 307 | display: inline-block; 308 | vertical-align: middle; 309 | font-size: 0.8125rem; 310 | } 311 | 312 | #changelist .actions .button { 313 | font-size: 0.8125rem; 314 | border: 1px solid var(--border-color); 315 | border-radius: 4px; 316 | background: var(--body-bg); 317 | box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; 318 | cursor: pointer; 319 | height: 1.5rem; 320 | line-height: 1; 321 | padding: 4px 8px; 322 | margin: 0; 323 | color: var(--body-fg); 324 | } 325 | 326 | #changelist .actions .button:focus, #changelist .actions .button:hover { 327 | border-color: var(--body-quiet-color); 328 | } 329 | -------------------------------------------------------------------------------- /static/admin/css/dark_mode.css: -------------------------------------------------------------------------------- 1 | @media (prefers-color-scheme: dark) { 2 | :root { 3 | --primary: #264b5d; 4 | --primary-fg: #f7f7f7; 5 | 6 | --body-fg: #eeeeee; 7 | --body-bg: #121212; 8 | --body-quiet-color: #e0e0e0; 9 | --body-loud-color: #ffffff; 10 | 11 | --breadcrumbs-link-fg: #e0e0e0; 12 | --breadcrumbs-bg: var(--primary); 13 | 14 | --link-fg: #81d4fa; 15 | --link-hover-color: #4ac1f7; 16 | --link-selected-fg: #6f94c6; 17 | 18 | --hairline-color: #272727; 19 | --border-color: #353535; 20 | 21 | --error-fg: #e35f5f; 22 | --message-success-bg: #006b1b; 23 | --message-warning-bg: #583305; 24 | --message-error-bg: #570808; 25 | 26 | --darkened-bg: #212121; 27 | --selected-bg: #1b1b1b; 28 | --selected-row: #00363a; 29 | 30 | --close-button-bg: #333333; 31 | --close-button-hover-bg: #666666; 32 | } 33 | } 34 | 35 | 36 | html[data-theme="dark"] { 37 | --primary: #264b5d; 38 | --primary-fg: #f7f7f7; 39 | 40 | --body-fg: #eeeeee; 41 | --body-bg: #121212; 42 | --body-quiet-color: #e0e0e0; 43 | --body-loud-color: #ffffff; 44 | 45 | --breadcrumbs-link-fg: #e0e0e0; 46 | --breadcrumbs-bg: var(--primary); 47 | 48 | --link-fg: #81d4fa; 49 | --link-hover-color: #4ac1f7; 50 | --link-selected-fg: #6f94c6; 51 | 52 | --hairline-color: #272727; 53 | --border-color: #353535; 54 | 55 | --error-fg: #e35f5f; 56 | --message-success-bg: #006b1b; 57 | --message-warning-bg: #583305; 58 | --message-error-bg: #570808; 59 | 60 | --darkened-bg: #212121; 61 | --selected-bg: #1b1b1b; 62 | --selected-row: #00363a; 63 | 64 | --close-button-bg: #333333; 65 | --close-button-hover-bg: #666666; 66 | } 67 | 68 | /* THEME SWITCH */ 69 | .theme-toggle { 70 | cursor: pointer; 71 | border: none; 72 | padding: 0; 73 | background: transparent; 74 | vertical-align: middle; 75 | margin-inline-start: 5px; 76 | margin-top: -1px; 77 | } 78 | 79 | .theme-toggle svg { 80 | vertical-align: middle; 81 | height: 1rem; 82 | width: 1rem; 83 | display: none; 84 | } 85 | 86 | /* 87 | Fully hide screen reader text so we only show the one matching the current 88 | theme. 89 | */ 90 | .theme-toggle .visually-hidden { 91 | display: none; 92 | } 93 | 94 | html[data-theme="auto"] .theme-toggle .theme-label-when-auto { 95 | display: block; 96 | } 97 | 98 | html[data-theme="dark"] .theme-toggle .theme-label-when-dark { 99 | display: block; 100 | } 101 | 102 | html[data-theme="light"] .theme-toggle .theme-label-when-light { 103 | display: block; 104 | } 105 | 106 | /* ICONS */ 107 | .theme-toggle svg.theme-icon-when-auto, 108 | .theme-toggle svg.theme-icon-when-dark, 109 | .theme-toggle svg.theme-icon-when-light { 110 | fill: var(--header-link-color); 111 | color: var(--header-bg); 112 | } 113 | 114 | html[data-theme="auto"] .theme-toggle svg.theme-icon-when-auto { 115 | display: block; 116 | } 117 | 118 | html[data-theme="dark"] .theme-toggle svg.theme-icon-when-dark { 119 | display: block; 120 | } 121 | 122 | html[data-theme="light"] .theme-toggle svg.theme-icon-when-light { 123 | display: block; 124 | } 125 | 126 | .visually-hidden { 127 | position: absolute; 128 | width: 1px; 129 | height: 1px; 130 | padding: 0; 131 | overflow: hidden; 132 | clip: rect(0,0,0,0); 133 | white-space: nowrap; 134 | border: 0; 135 | color: var(--body-fg); 136 | background-color: var(--body-bg); 137 | } 138 | -------------------------------------------------------------------------------- /static/admin/css/dashboard.css: -------------------------------------------------------------------------------- 1 | /* DASHBOARD */ 2 | .dashboard td, .dashboard th { 3 | word-break: break-word; 4 | } 5 | 6 | .dashboard .module table th { 7 | width: 100%; 8 | } 9 | 10 | .dashboard .module table td { 11 | white-space: nowrap; 12 | } 13 | 14 | .dashboard .module table td a { 15 | display: block; 16 | padding-right: .6em; 17 | } 18 | 19 | /* RECENT ACTIONS MODULE */ 20 | 21 | .module ul.actionlist { 22 | margin-left: 0; 23 | } 24 | 25 | ul.actionlist li { 26 | list-style-type: none; 27 | overflow: hidden; 28 | text-overflow: ellipsis; 29 | } 30 | -------------------------------------------------------------------------------- /static/admin/css/login.css: -------------------------------------------------------------------------------- 1 | /* LOGIN FORM */ 2 | 3 | .login { 4 | background: var(--darkened-bg); 5 | height: auto; 6 | } 7 | 8 | .login #header { 9 | height: auto; 10 | padding: 15px 16px; 11 | justify-content: center; 12 | } 13 | 14 | .login #header h1 { 15 | font-size: 1.125rem; 16 | margin: 0; 17 | } 18 | 19 | .login #header h1 a { 20 | color: var(--header-link-color); 21 | } 22 | 23 | .login #content { 24 | padding: 20px 20px 0; 25 | } 26 | 27 | .login #container { 28 | background: var(--body-bg); 29 | border: 1px solid var(--hairline-color); 30 | border-radius: 4px; 31 | overflow: hidden; 32 | width: 28em; 33 | min-width: 300px; 34 | margin: 100px auto; 35 | height: auto; 36 | } 37 | 38 | .login .form-row { 39 | padding: 4px 0; 40 | } 41 | 42 | .login .form-row label { 43 | display: block; 44 | line-height: 2em; 45 | } 46 | 47 | .login .form-row #id_username, .login .form-row #id_password { 48 | padding: 8px; 49 | width: 100%; 50 | box-sizing: border-box; 51 | } 52 | 53 | .login .submit-row { 54 | padding: 1em 0 0 0; 55 | margin: 0; 56 | text-align: center; 57 | } 58 | 59 | .login .password-reset-link { 60 | text-align: center; 61 | } 62 | -------------------------------------------------------------------------------- /static/admin/css/nav_sidebar.css: -------------------------------------------------------------------------------- 1 | .sticky { 2 | position: sticky; 3 | top: 0; 4 | max-height: 100vh; 5 | } 6 | 7 | .toggle-nav-sidebar { 8 | z-index: 20; 9 | left: 0; 10 | display: flex; 11 | align-items: center; 12 | justify-content: center; 13 | flex: 0 0 23px; 14 | width: 23px; 15 | border: 0; 16 | border-right: 1px solid var(--hairline-color); 17 | background-color: var(--body-bg); 18 | cursor: pointer; 19 | font-size: 1.25rem; 20 | color: var(--link-fg); 21 | padding: 0; 22 | } 23 | 24 | [dir="rtl"] .toggle-nav-sidebar { 25 | border-left: 1px solid var(--hairline-color); 26 | border-right: 0; 27 | } 28 | 29 | .toggle-nav-sidebar:hover, 30 | .toggle-nav-sidebar:focus { 31 | background-color: var(--darkened-bg); 32 | } 33 | 34 | #nav-sidebar { 35 | z-index: 15; 36 | flex: 0 0 275px; 37 | left: -276px; 38 | margin-left: -276px; 39 | border-top: 1px solid transparent; 40 | border-right: 1px solid var(--hairline-color); 41 | background-color: var(--body-bg); 42 | overflow: auto; 43 | } 44 | 45 | [dir="rtl"] #nav-sidebar { 46 | border-left: 1px solid var(--hairline-color); 47 | border-right: 0; 48 | left: 0; 49 | margin-left: 0; 50 | right: -276px; 51 | margin-right: -276px; 52 | } 53 | 54 | .toggle-nav-sidebar::before { 55 | content: '\00BB'; 56 | } 57 | 58 | .main.shifted .toggle-nav-sidebar::before { 59 | content: '\00AB'; 60 | } 61 | 62 | .main > #nav-sidebar { 63 | visibility: hidden; 64 | } 65 | 66 | .main.shifted > #nav-sidebar { 67 | margin-left: 0; 68 | visibility: visible; 69 | } 70 | 71 | [dir="rtl"] .main.shifted > #nav-sidebar { 72 | margin-right: 0; 73 | } 74 | 75 | #nav-sidebar .module th { 76 | width: 100%; 77 | overflow-wrap: anywhere; 78 | } 79 | 80 | #nav-sidebar .module th, 81 | #nav-sidebar .module caption { 82 | padding-left: 16px; 83 | } 84 | 85 | #nav-sidebar .module td { 86 | white-space: nowrap; 87 | } 88 | 89 | [dir="rtl"] #nav-sidebar .module th, 90 | [dir="rtl"] #nav-sidebar .module caption { 91 | padding-left: 8px; 92 | padding-right: 16px; 93 | } 94 | 95 | #nav-sidebar .current-app .section:link, 96 | #nav-sidebar .current-app .section:visited { 97 | color: var(--header-color); 98 | font-weight: bold; 99 | } 100 | 101 | #nav-sidebar .current-model { 102 | background: var(--selected-row); 103 | } 104 | 105 | .main > #nav-sidebar + .content { 106 | max-width: calc(100% - 23px); 107 | } 108 | 109 | .main.shifted > #nav-sidebar + .content { 110 | max-width: calc(100% - 299px); 111 | } 112 | 113 | @media (max-width: 767px) { 114 | #nav-sidebar, #toggle-nav-sidebar { 115 | display: none; 116 | } 117 | 118 | .main > #nav-sidebar + .content, 119 | .main.shifted > #nav-sidebar + .content { 120 | max-width: 100%; 121 | } 122 | } 123 | 124 | #nav-filter { 125 | width: 100%; 126 | box-sizing: border-box; 127 | padding: 2px 5px; 128 | margin: 5px 0; 129 | border: 1px solid var(--border-color); 130 | background-color: var(--darkened-bg); 131 | color: var(--body-fg); 132 | } 133 | 134 | #nav-filter:focus { 135 | border-color: var(--body-quiet-color); 136 | } 137 | 138 | #nav-filter.no-results { 139 | background: var(--message-error-bg); 140 | } 141 | 142 | #nav-sidebar table { 143 | width: 100%; 144 | } 145 | -------------------------------------------------------------------------------- /static/admin/css/responsive_rtl.css: -------------------------------------------------------------------------------- 1 | /* TABLETS */ 2 | 3 | @media (max-width: 1024px) { 4 | [dir="rtl"] .colMS { 5 | margin-right: 0; 6 | } 7 | 8 | [dir="rtl"] #user-tools { 9 | text-align: right; 10 | } 11 | 12 | [dir="rtl"] #changelist .actions label { 13 | padding-left: 10px; 14 | padding-right: 0; 15 | } 16 | 17 | [dir="rtl"] #changelist .actions select { 18 | margin-left: 0; 19 | margin-right: 15px; 20 | } 21 | 22 | [dir="rtl"] .change-list .filtered .results, 23 | [dir="rtl"] .change-list .filtered .paginator, 24 | [dir="rtl"] .filtered #toolbar, 25 | [dir="rtl"] .filtered div.xfull, 26 | [dir="rtl"] .filtered .actions, 27 | [dir="rtl"] #changelist-filter { 28 | margin-left: 0; 29 | } 30 | 31 | [dir="rtl"] .inline-group ul.tools a.add, 32 | [dir="rtl"] .inline-group div.add-row a, 33 | [dir="rtl"] .inline-group .tabular tr.add-row td a { 34 | padding: 8px 26px 8px 10px; 35 | background-position: calc(100% - 8px) 9px; 36 | } 37 | 38 | [dir="rtl"] .related-widget-wrapper-link + .selector { 39 | margin-right: 0; 40 | margin-left: 15px; 41 | } 42 | 43 | [dir="rtl"] .selector .selector-filter label { 44 | margin-right: 0; 45 | margin-left: 8px; 46 | } 47 | 48 | [dir="rtl"] .object-tools li { 49 | float: right; 50 | } 51 | 52 | [dir="rtl"] .object-tools li + li { 53 | margin-left: 0; 54 | margin-right: 15px; 55 | } 56 | 57 | [dir="rtl"] .dashboard .module table td a { 58 | padding-left: 0; 59 | padding-right: 16px; 60 | } 61 | } 62 | 63 | /* MOBILE */ 64 | 65 | @media (max-width: 767px) { 66 | [dir="rtl"] .aligned .related-lookup, 67 | [dir="rtl"] .aligned .datetimeshortcuts { 68 | margin-left: 0; 69 | margin-right: 15px; 70 | } 71 | 72 | [dir="rtl"] .aligned ul, 73 | [dir="rtl"] form .aligned ul.errorlist { 74 | margin-right: 0; 75 | } 76 | 77 | [dir="rtl"] #changelist-filter { 78 | margin-left: 0; 79 | margin-right: 0; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /static/admin/css/rtl.css: -------------------------------------------------------------------------------- 1 | /* GLOBAL */ 2 | 3 | th { 4 | text-align: right; 5 | } 6 | 7 | .module h2, .module caption { 8 | text-align: right; 9 | } 10 | 11 | .module ul, .module ol { 12 | margin-left: 0; 13 | margin-right: 1.5em; 14 | } 15 | 16 | .viewlink, .addlink, .changelink { 17 | padding-left: 0; 18 | padding-right: 16px; 19 | background-position: 100% 1px; 20 | } 21 | 22 | .deletelink { 23 | padding-left: 0; 24 | padding-right: 16px; 25 | background-position: 100% 1px; 26 | } 27 | 28 | .object-tools { 29 | float: left; 30 | } 31 | 32 | thead th:first-child, 33 | tfoot td:first-child { 34 | border-left: none; 35 | } 36 | 37 | /* LAYOUT */ 38 | 39 | #user-tools { 40 | right: auto; 41 | left: 0; 42 | text-align: left; 43 | } 44 | 45 | div.breadcrumbs { 46 | text-align: right; 47 | } 48 | 49 | #content-main { 50 | float: right; 51 | } 52 | 53 | #content-related { 54 | float: left; 55 | margin-left: -300px; 56 | margin-right: auto; 57 | } 58 | 59 | .colMS { 60 | margin-left: 300px; 61 | margin-right: 0; 62 | } 63 | 64 | /* SORTABLE TABLES */ 65 | 66 | table thead th.sorted .sortoptions { 67 | float: left; 68 | } 69 | 70 | thead th.sorted .text { 71 | padding-right: 0; 72 | padding-left: 42px; 73 | } 74 | 75 | /* dashboard styles */ 76 | 77 | .dashboard .module table td a { 78 | padding-left: .6em; 79 | padding-right: 16px; 80 | } 81 | 82 | /* changelists styles */ 83 | 84 | .change-list .filtered table { 85 | border-left: none; 86 | border-right: 0px none; 87 | } 88 | 89 | #changelist-filter { 90 | border-left: none; 91 | border-right: none; 92 | margin-left: 0; 93 | margin-right: 30px; 94 | } 95 | 96 | #changelist-filter li.selected { 97 | border-left: none; 98 | padding-left: 10px; 99 | margin-left: 0; 100 | border-right: 5px solid var(--hairline-color); 101 | padding-right: 10px; 102 | margin-right: -15px; 103 | } 104 | 105 | #changelist table tbody td:first-child, #changelist table tbody th:first-child { 106 | border-right: none; 107 | border-left: none; 108 | } 109 | 110 | /* FORMS */ 111 | 112 | .aligned label { 113 | padding: 0 0 3px 1em; 114 | } 115 | 116 | .submit-row a.deletelink { 117 | margin-left: 0; 118 | margin-right: auto; 119 | } 120 | 121 | .vDateField, .vTimeField { 122 | margin-left: 2px; 123 | } 124 | 125 | .aligned .form-row input { 126 | margin-left: 5px; 127 | } 128 | 129 | form .aligned ul { 130 | margin-right: 163px; 131 | padding-right: 10px; 132 | margin-left: 0; 133 | padding-left: 0; 134 | } 135 | 136 | form ul.inline li { 137 | float: right; 138 | padding-right: 0; 139 | padding-left: 7px; 140 | } 141 | 142 | form .aligned p.help, 143 | form .aligned div.help { 144 | margin-right: 160px; 145 | padding-right: 10px; 146 | } 147 | 148 | form div.help ul, 149 | form .aligned .checkbox-row + .help, 150 | form .aligned p.date div.help.timezonewarning, 151 | form .aligned p.datetime div.help.timezonewarning, 152 | form .aligned p.time div.help.timezonewarning { 153 | margin-right: 0; 154 | padding-right: 0; 155 | } 156 | 157 | form .wide p.help, form .wide div.help { 158 | padding-left: 0; 159 | padding-right: 50px; 160 | } 161 | 162 | form .wide p, 163 | form .wide ul.errorlist, 164 | form .wide input + p.help, 165 | form .wide input + div.help { 166 | margin-right: 200px; 167 | margin-left: 0px; 168 | } 169 | 170 | .submit-row { 171 | text-align: right; 172 | } 173 | 174 | fieldset .fieldBox { 175 | margin-left: 20px; 176 | margin-right: 0; 177 | } 178 | 179 | .errorlist li { 180 | background-position: 100% 12px; 181 | padding: 0; 182 | } 183 | 184 | .errornote { 185 | background-position: 100% 12px; 186 | padding: 10px 12px; 187 | } 188 | 189 | /* WIDGETS */ 190 | 191 | .calendarnav-previous { 192 | top: 0; 193 | left: auto; 194 | right: 10px; 195 | background: url(../img/calendar-icons.svg) 0 -30px no-repeat; 196 | } 197 | 198 | .calendarbox .calendarnav-previous:focus, 199 | .calendarbox .calendarnav-previous:hover { 200 | background-position: 0 -45px; 201 | } 202 | 203 | .calendarnav-next { 204 | top: 0; 205 | right: auto; 206 | left: 10px; 207 | background: url(../img/calendar-icons.svg) 0 0 no-repeat; 208 | } 209 | 210 | .calendarbox .calendarnav-next:focus, 211 | .calendarbox .calendarnav-next:hover { 212 | background-position: 0 -15px; 213 | } 214 | 215 | .calendar caption, .calendarbox h2 { 216 | text-align: center; 217 | } 218 | 219 | .selector { 220 | float: right; 221 | } 222 | 223 | .selector .selector-filter { 224 | text-align: right; 225 | } 226 | 227 | .selector-add { 228 | background: url(../img/selector-icons.svg) 0 -64px no-repeat; 229 | } 230 | 231 | .active.selector-add:focus, .active.selector-add:hover { 232 | background-position: 0 -80px; 233 | } 234 | 235 | .selector-remove { 236 | background: url(../img/selector-icons.svg) 0 -96px no-repeat; 237 | } 238 | 239 | .active.selector-remove:focus, .active.selector-remove:hover { 240 | background-position: 0 -112px; 241 | } 242 | 243 | a.selector-chooseall { 244 | background: url(../img/selector-icons.svg) right -128px no-repeat; 245 | } 246 | 247 | a.active.selector-chooseall:focus, a.active.selector-chooseall:hover { 248 | background-position: 100% -144px; 249 | } 250 | 251 | a.selector-clearall { 252 | background: url(../img/selector-icons.svg) 0 -160px no-repeat; 253 | } 254 | 255 | a.active.selector-clearall:focus, a.active.selector-clearall:hover { 256 | background-position: 0 -176px; 257 | } 258 | 259 | .inline-deletelink { 260 | float: left; 261 | } 262 | 263 | form .form-row p.datetime { 264 | overflow: hidden; 265 | } 266 | 267 | .related-widget-wrapper { 268 | float: right; 269 | } 270 | 271 | /* MISC */ 272 | 273 | .inline-related h2, .inline-group h2 { 274 | text-align: right 275 | } 276 | 277 | .inline-related h3 span.delete { 278 | padding-right: 20px; 279 | padding-left: inherit; 280 | left: 10px; 281 | right: inherit; 282 | float:left; 283 | } 284 | 285 | .inline-related h3 span.delete label { 286 | margin-left: inherit; 287 | margin-right: 2px; 288 | } 289 | -------------------------------------------------------------------------------- /static/admin/css/vendor/select2/LICENSE-SELECT2.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /static/admin/img/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Code Charm Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /static/admin/img/README.txt: -------------------------------------------------------------------------------- 1 | All icons are taken from Font Awesome (http://fontawesome.io/) project. 2 | The Font Awesome font is licensed under the SIL OFL 1.1: 3 | - https://scripts.sil.org/OFL 4 | 5 | SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG 6 | Font-Awesome-SVG-PNG is licensed under the MIT license (see file license 7 | in current folder). 8 | -------------------------------------------------------------------------------- /static/admin/img/calendar-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /static/admin/img/gis/move_vertex_off.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/admin/img/gis/move_vertex_on.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/admin/img/icon-addlink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/admin/img/icon-changelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-clock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/admin/img/icon-deletelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-no.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-unknown-alt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-unknown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-viewlink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-yes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/inline-delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/selector-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /static/admin/img/sorting-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /static/admin/img/tooltag-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/tooltag-arrowright.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/js/SelectBox.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | const SelectBox = { 4 | cache: {}, 5 | init: function(id) { 6 | const box = document.getElementById(id); 7 | SelectBox.cache[id] = []; 8 | const cache = SelectBox.cache[id]; 9 | for (const node of box.options) { 10 | cache.push({value: node.value, text: node.text, displayed: 1}); 11 | } 12 | }, 13 | redisplay: function(id) { 14 | // Repopulate HTML select box from cache 15 | const box = document.getElementById(id); 16 | const scroll_value_from_top = box.scrollTop; 17 | box.innerHTML = ''; 18 | for (const node of SelectBox.cache[id]) { 19 | if (node.displayed) { 20 | const new_option = new Option(node.text, node.value, false, false); 21 | // Shows a tooltip when hovering over the option 22 | new_option.title = node.text; 23 | box.appendChild(new_option); 24 | } 25 | } 26 | box.scrollTop = scroll_value_from_top; 27 | }, 28 | filter: function(id, text) { 29 | // Redisplay the HTML select box, displaying only the choices containing ALL 30 | // the words in text. (It's an AND search.) 31 | const tokens = text.toLowerCase().split(/\s+/); 32 | for (const node of SelectBox.cache[id]) { 33 | node.displayed = 1; 34 | const node_text = node.text.toLowerCase(); 35 | for (const token of tokens) { 36 | if (!node_text.includes(token)) { 37 | node.displayed = 0; 38 | break; // Once the first token isn't found we're done 39 | } 40 | } 41 | } 42 | SelectBox.redisplay(id); 43 | }, 44 | get_hidden_node_count(id) { 45 | const cache = SelectBox.cache[id] || []; 46 | return cache.filter(node => node.displayed === 0).length; 47 | }, 48 | delete_from_cache: function(id, value) { 49 | let delete_index = null; 50 | const cache = SelectBox.cache[id]; 51 | for (const [i, node] of cache.entries()) { 52 | if (node.value === value) { 53 | delete_index = i; 54 | break; 55 | } 56 | } 57 | cache.splice(delete_index, 1); 58 | }, 59 | add_to_cache: function(id, option) { 60 | SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1}); 61 | }, 62 | cache_contains: function(id, value) { 63 | // Check if an item is contained in the cache 64 | for (const node of SelectBox.cache[id]) { 65 | if (node.value === value) { 66 | return true; 67 | } 68 | } 69 | return false; 70 | }, 71 | move: function(from, to) { 72 | const from_box = document.getElementById(from); 73 | for (const option of from_box.options) { 74 | const option_value = option.value; 75 | if (option.selected && SelectBox.cache_contains(from, option_value)) { 76 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); 77 | SelectBox.delete_from_cache(from, option_value); 78 | } 79 | } 80 | SelectBox.redisplay(from); 81 | SelectBox.redisplay(to); 82 | }, 83 | move_all: function(from, to) { 84 | const from_box = document.getElementById(from); 85 | for (const option of from_box.options) { 86 | const option_value = option.value; 87 | if (SelectBox.cache_contains(from, option_value)) { 88 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); 89 | SelectBox.delete_from_cache(from, option_value); 90 | } 91 | } 92 | SelectBox.redisplay(from); 93 | SelectBox.redisplay(to); 94 | }, 95 | sort: function(id) { 96 | SelectBox.cache[id].sort(function(a, b) { 97 | a = a.text.toLowerCase(); 98 | b = b.text.toLowerCase(); 99 | if (a > b) { 100 | return 1; 101 | } 102 | if (a < b) { 103 | return -1; 104 | } 105 | return 0; 106 | } ); 107 | }, 108 | select_all: function(id) { 109 | const box = document.getElementById(id); 110 | for (const option of box.options) { 111 | option.selected = true; 112 | } 113 | } 114 | }; 115 | window.SelectBox = SelectBox; 116 | } 117 | -------------------------------------------------------------------------------- /static/admin/js/autocomplete.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | const $ = django.jQuery; 4 | 5 | $.fn.djangoAdminSelect2 = function() { 6 | $.each(this, function(i, element) { 7 | $(element).select2({ 8 | ajax: { 9 | data: (params) => { 10 | return { 11 | term: params.term, 12 | page: params.page, 13 | app_label: element.dataset.appLabel, 14 | model_name: element.dataset.modelName, 15 | field_name: element.dataset.fieldName 16 | }; 17 | } 18 | } 19 | }); 20 | }); 21 | return this; 22 | }; 23 | 24 | $(function() { 25 | // Initialize all autocomplete widgets except the one in the template 26 | // form used when a new formset is added. 27 | $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2(); 28 | }); 29 | 30 | document.addEventListener('formset:added', (event) => { 31 | $(event.target).find('.admin-autocomplete').djangoAdminSelect2(); 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /static/admin/js/cancel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | // Call function fn when the DOM is loaded and ready. If it is already 4 | // loaded, call the function now. 5 | // http://youmightnotneedjquery.com/#ready 6 | function ready(fn) { 7 | if (document.readyState !== 'loading') { 8 | fn(); 9 | } else { 10 | document.addEventListener('DOMContentLoaded', fn); 11 | } 12 | } 13 | 14 | ready(function() { 15 | function handleClick(event) { 16 | event.preventDefault(); 17 | const params = new URLSearchParams(window.location.search); 18 | if (params.has('_popup')) { 19 | window.close(); // Close the popup. 20 | } else { 21 | window.history.back(); // Otherwise, go back. 22 | } 23 | } 24 | 25 | document.querySelectorAll('.cancel-link').forEach(function(el) { 26 | el.addEventListener('click', handleClick); 27 | }); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /static/admin/js/change_form.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | const inputTags = ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA']; 4 | const modelName = document.getElementById('django-admin-form-add-constants').dataset.modelName; 5 | if (modelName) { 6 | const form = document.getElementById(modelName + '_form'); 7 | for (const element of form.elements) { 8 | // HTMLElement.offsetParent returns null when the element is not 9 | // rendered. 10 | if (inputTags.includes(element.tagName) && !element.disabled && element.offsetParent) { 11 | element.focus(); 12 | break; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /static/admin/js/collapse.js: -------------------------------------------------------------------------------- 1 | /*global gettext*/ 2 | 'use strict'; 3 | { 4 | window.addEventListener('load', function() { 5 | // Add anchor tag for Show/Hide link 6 | const fieldsets = document.querySelectorAll('fieldset.collapse'); 7 | for (const [i, elem] of fieldsets.entries()) { 8 | // Don't hide if fields in this fieldset have errors 9 | if (elem.querySelectorAll('div.errors, ul.errorlist').length === 0) { 10 | elem.classList.add('collapsed'); 11 | const h2 = elem.querySelector('h2'); 12 | const link = document.createElement('a'); 13 | link.id = 'fieldsetcollapser' + i; 14 | link.className = 'collapse-toggle'; 15 | link.href = '#'; 16 | link.textContent = gettext('Show'); 17 | h2.appendChild(document.createTextNode(' (')); 18 | h2.appendChild(link); 19 | h2.appendChild(document.createTextNode(')')); 20 | } 21 | } 22 | // Add toggle to hide/show anchor tag 23 | const toggleFunc = function(ev) { 24 | if (ev.target.matches('.collapse-toggle')) { 25 | ev.preventDefault(); 26 | ev.stopPropagation(); 27 | const fieldset = ev.target.closest('fieldset'); 28 | if (fieldset.classList.contains('collapsed')) { 29 | // Show 30 | ev.target.textContent = gettext('Hide'); 31 | fieldset.classList.remove('collapsed'); 32 | } else { 33 | // Hide 34 | ev.target.textContent = gettext('Show'); 35 | fieldset.classList.add('collapsed'); 36 | } 37 | } 38 | }; 39 | document.querySelectorAll('fieldset.module').forEach(function(el) { 40 | el.addEventListener('click', toggleFunc); 41 | }); 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /static/admin/js/core.js: -------------------------------------------------------------------------------- 1 | // Core JavaScript helper functions 2 | 'use strict'; 3 | 4 | // quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]); 5 | function quickElement() { 6 | const obj = document.createElement(arguments[0]); 7 | if (arguments[2]) { 8 | const textNode = document.createTextNode(arguments[2]); 9 | obj.appendChild(textNode); 10 | } 11 | const len = arguments.length; 12 | for (let i = 3; i < len; i += 2) { 13 | obj.setAttribute(arguments[i], arguments[i + 1]); 14 | } 15 | arguments[1].appendChild(obj); 16 | return obj; 17 | } 18 | 19 | // "a" is reference to an object 20 | function removeChildren(a) { 21 | while (a.hasChildNodes()) { 22 | a.removeChild(a.lastChild); 23 | } 24 | } 25 | 26 | // ---------------------------------------------------------------------------- 27 | // Find-position functions by PPK 28 | // See https://www.quirksmode.org/js/findpos.html 29 | // ---------------------------------------------------------------------------- 30 | function findPosX(obj) { 31 | let curleft = 0; 32 | if (obj.offsetParent) { 33 | while (obj.offsetParent) { 34 | curleft += obj.offsetLeft - obj.scrollLeft; 35 | obj = obj.offsetParent; 36 | } 37 | } else if (obj.x) { 38 | curleft += obj.x; 39 | } 40 | return curleft; 41 | } 42 | 43 | function findPosY(obj) { 44 | let curtop = 0; 45 | if (obj.offsetParent) { 46 | while (obj.offsetParent) { 47 | curtop += obj.offsetTop - obj.scrollTop; 48 | obj = obj.offsetParent; 49 | } 50 | } else if (obj.y) { 51 | curtop += obj.y; 52 | } 53 | return curtop; 54 | } 55 | 56 | //----------------------------------------------------------------------------- 57 | // Date object extensions 58 | // ---------------------------------------------------------------------------- 59 | { 60 | Date.prototype.getTwelveHours = function() { 61 | return this.getHours() % 12 || 12; 62 | }; 63 | 64 | Date.prototype.getTwoDigitMonth = function() { 65 | return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1); 66 | }; 67 | 68 | Date.prototype.getTwoDigitDate = function() { 69 | return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate(); 70 | }; 71 | 72 | Date.prototype.getTwoDigitTwelveHour = function() { 73 | return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours(); 74 | }; 75 | 76 | Date.prototype.getTwoDigitHour = function() { 77 | return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours(); 78 | }; 79 | 80 | Date.prototype.getTwoDigitMinute = function() { 81 | return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes(); 82 | }; 83 | 84 | Date.prototype.getTwoDigitSecond = function() { 85 | return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); 86 | }; 87 | 88 | Date.prototype.getAbbrevMonthName = function() { 89 | return typeof window.CalendarNamespace === "undefined" 90 | ? this.getTwoDigitMonth() 91 | : window.CalendarNamespace.monthsOfYearAbbrev[this.getMonth()]; 92 | }; 93 | 94 | Date.prototype.getFullMonthName = function() { 95 | return typeof window.CalendarNamespace === "undefined" 96 | ? this.getTwoDigitMonth() 97 | : window.CalendarNamespace.monthsOfYear[this.getMonth()]; 98 | }; 99 | 100 | Date.prototype.strftime = function(format) { 101 | const fields = { 102 | b: this.getAbbrevMonthName(), 103 | B: this.getFullMonthName(), 104 | c: this.toString(), 105 | d: this.getTwoDigitDate(), 106 | H: this.getTwoDigitHour(), 107 | I: this.getTwoDigitTwelveHour(), 108 | m: this.getTwoDigitMonth(), 109 | M: this.getTwoDigitMinute(), 110 | p: (this.getHours() >= 12) ? 'PM' : 'AM', 111 | S: this.getTwoDigitSecond(), 112 | w: '0' + this.getDay(), 113 | x: this.toLocaleDateString(), 114 | X: this.toLocaleTimeString(), 115 | y: ('' + this.getFullYear()).substr(2, 4), 116 | Y: '' + this.getFullYear(), 117 | '%': '%' 118 | }; 119 | let result = '', i = 0; 120 | while (i < format.length) { 121 | if (format.charAt(i) === '%') { 122 | result += fields[format.charAt(i + 1)]; 123 | ++i; 124 | } 125 | else { 126 | result += format.charAt(i); 127 | } 128 | ++i; 129 | } 130 | return result; 131 | }; 132 | 133 | // ---------------------------------------------------------------------------- 134 | // String object extensions 135 | // ---------------------------------------------------------------------------- 136 | String.prototype.strptime = function(format) { 137 | const split_format = format.split(/[.\-/]/); 138 | const date = this.split(/[.\-/]/); 139 | let i = 0; 140 | let day, month, year; 141 | while (i < split_format.length) { 142 | switch (split_format[i]) { 143 | case "%d": 144 | day = date[i]; 145 | break; 146 | case "%m": 147 | month = date[i] - 1; 148 | break; 149 | case "%Y": 150 | year = date[i]; 151 | break; 152 | case "%y": 153 | // A %y value in the range of [00, 68] is in the current 154 | // century, while [69, 99] is in the previous century, 155 | // according to the Open Group Specification. 156 | if (parseInt(date[i], 10) >= 69) { 157 | year = date[i]; 158 | } else { 159 | year = (new Date(Date.UTC(date[i], 0))).getUTCFullYear() + 100; 160 | } 161 | break; 162 | } 163 | ++i; 164 | } 165 | // Create Date object from UTC since the parsed value is supposed to be 166 | // in UTC, not local time. Also, the calendar uses UTC functions for 167 | // date extraction. 168 | return new Date(Date.UTC(year, month, day)); 169 | }; 170 | } 171 | -------------------------------------------------------------------------------- /static/admin/js/filters.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Persist changelist filters state (collapsed/expanded). 3 | */ 4 | 'use strict'; 5 | { 6 | // Init filters. 7 | let filters = JSON.parse(sessionStorage.getItem('django.admin.filtersState')); 8 | 9 | if (!filters) { 10 | filters = {}; 11 | } 12 | 13 | Object.entries(filters).forEach(([key, value]) => { 14 | const detailElement = document.querySelector(`[data-filter-title='${CSS.escape(key)}']`); 15 | 16 | // Check if the filter is present, it could be from other view. 17 | if (detailElement) { 18 | value ? detailElement.setAttribute('open', '') : detailElement.removeAttribute('open'); 19 | } 20 | }); 21 | 22 | // Save filter state when clicks. 23 | const details = document.querySelectorAll('details'); 24 | details.forEach(detail => { 25 | detail.addEventListener('toggle', event => { 26 | filters[`${event.target.dataset.filterTitle}`] = detail.open; 27 | sessionStorage.setItem('django.admin.filtersState', JSON.stringify(filters)); 28 | }); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /static/admin/js/jquery.init.js: -------------------------------------------------------------------------------- 1 | /*global jQuery:false*/ 2 | 'use strict'; 3 | /* Puts the included jQuery into our own namespace using noConflict and passing 4 | * it 'true'. This ensures that the included jQuery doesn't pollute the global 5 | * namespace (i.e. this preserves pre-existing values for both window.$ and 6 | * window.jQuery). 7 | */ 8 | window.django = {jQuery: jQuery.noConflict(true)}; 9 | -------------------------------------------------------------------------------- /static/admin/js/nav_sidebar.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | const toggleNavSidebar = document.getElementById('toggle-nav-sidebar'); 4 | if (toggleNavSidebar !== null) { 5 | const navSidebar = document.getElementById('nav-sidebar'); 6 | const main = document.getElementById('main'); 7 | let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen'); 8 | if (navSidebarIsOpen === null) { 9 | navSidebarIsOpen = 'true'; 10 | } 11 | main.classList.toggle('shifted', navSidebarIsOpen === 'true'); 12 | navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); 13 | 14 | toggleNavSidebar.addEventListener('click', function() { 15 | if (navSidebarIsOpen === 'true') { 16 | navSidebarIsOpen = 'false'; 17 | } else { 18 | navSidebarIsOpen = 'true'; 19 | } 20 | localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen); 21 | main.classList.toggle('shifted'); 22 | navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); 23 | }); 24 | } 25 | 26 | function initSidebarQuickFilter() { 27 | const options = []; 28 | const navSidebar = document.getElementById('nav-sidebar'); 29 | if (!navSidebar) { 30 | return; 31 | } 32 | navSidebar.querySelectorAll('th[scope=row] a').forEach((container) => { 33 | options.push({title: container.innerHTML, node: container}); 34 | }); 35 | 36 | function checkValue(event) { 37 | let filterValue = event.target.value; 38 | if (filterValue) { 39 | filterValue = filterValue.toLowerCase(); 40 | } 41 | if (event.key === 'Escape') { 42 | filterValue = ''; 43 | event.target.value = ''; // clear input 44 | } 45 | let matches = false; 46 | for (const o of options) { 47 | let displayValue = ''; 48 | if (filterValue) { 49 | if (o.title.toLowerCase().indexOf(filterValue) === -1) { 50 | displayValue = 'none'; 51 | } else { 52 | matches = true; 53 | } 54 | } 55 | // show/hide parent 56 | o.node.parentNode.parentNode.style.display = displayValue; 57 | } 58 | if (!filterValue || matches) { 59 | event.target.classList.remove('no-results'); 60 | } else { 61 | event.target.classList.add('no-results'); 62 | } 63 | sessionStorage.setItem('django.admin.navSidebarFilterValue', filterValue); 64 | } 65 | 66 | const nav = document.getElementById('nav-filter'); 67 | nav.addEventListener('change', checkValue, false); 68 | nav.addEventListener('input', checkValue, false); 69 | nav.addEventListener('keyup', checkValue, false); 70 | 71 | const storedValue = sessionStorage.getItem('django.admin.navSidebarFilterValue'); 72 | if (storedValue) { 73 | nav.value = storedValue; 74 | checkValue({target: nav, key: ''}); 75 | } 76 | } 77 | window.initSidebarQuickFilter = initSidebarQuickFilter; 78 | initSidebarQuickFilter(); 79 | } 80 | -------------------------------------------------------------------------------- /static/admin/js/popup_response.js: -------------------------------------------------------------------------------- 1 | /*global opener */ 2 | 'use strict'; 3 | { 4 | const initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); 5 | switch(initData.action) { 6 | case 'change': 7 | opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value); 8 | break; 9 | case 'delete': 10 | opener.dismissDeleteRelatedObjectPopup(window, initData.value); 11 | break; 12 | default: 13 | opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj); 14 | break; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /static/admin/js/prepopulate.js: -------------------------------------------------------------------------------- 1 | /*global URLify*/ 2 | 'use strict'; 3 | { 4 | const $ = django.jQuery; 5 | $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) { 6 | /* 7 | Depends on urlify.js 8 | Populates a selected field with the values of the dependent fields, 9 | URLifies and shortens the string. 10 | dependencies - array of dependent fields ids 11 | maxLength - maximum length of the URLify'd string 12 | allowUnicode - Unicode support of the URLify'd string 13 | */ 14 | return this.each(function() { 15 | const prepopulatedField = $(this); 16 | 17 | const populate = function() { 18 | // Bail if the field's value has been changed by the user 19 | if (prepopulatedField.data('_changed')) { 20 | return; 21 | } 22 | 23 | const values = []; 24 | $.each(dependencies, function(i, field) { 25 | field = $(field); 26 | if (field.val().length > 0) { 27 | values.push(field.val()); 28 | } 29 | }); 30 | prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); 31 | }; 32 | 33 | prepopulatedField.data('_changed', false); 34 | prepopulatedField.on('change', function() { 35 | prepopulatedField.data('_changed', true); 36 | }); 37 | 38 | if (!prepopulatedField.val()) { 39 | $(dependencies.join(',')).on('keyup change focus', populate); 40 | } 41 | }); 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /static/admin/js/prepopulate_init.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | const $ = django.jQuery; 4 | const fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields'); 5 | $.each(fields, function(index, field) { 6 | $( 7 | '.empty-form .form-row .field-' + field.name + 8 | ', .empty-form.form-row .field-' + field.name + 9 | ', .empty-form .form-row.field-' + field.name 10 | ).addClass('prepopulated_field'); 11 | $(field.id).data('dependency_list', field.dependency_list).prepopulate( 12 | field.dependency_ids, field.maxLength, field.allowUnicode 13 | ); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /static/admin/js/theme.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | window.addEventListener('load', function(e) { 4 | 5 | function setTheme(mode) { 6 | if (mode !== "light" && mode !== "dark" && mode !== "auto") { 7 | console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`); 8 | mode = "auto"; 9 | } 10 | document.documentElement.dataset.theme = mode; 11 | localStorage.setItem("theme", mode); 12 | } 13 | 14 | function cycleTheme() { 15 | const currentTheme = localStorage.getItem("theme") || "auto"; 16 | const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; 17 | 18 | if (prefersDark) { 19 | // Auto (dark) -> Light -> Dark 20 | if (currentTheme === "auto") { 21 | setTheme("light"); 22 | } else if (currentTheme === "light") { 23 | setTheme("dark"); 24 | } else { 25 | setTheme("auto"); 26 | } 27 | } else { 28 | // Auto (light) -> Dark -> Light 29 | if (currentTheme === "auto") { 30 | setTheme("dark"); 31 | } else if (currentTheme === "dark") { 32 | setTheme("light"); 33 | } else { 34 | setTheme("auto"); 35 | } 36 | } 37 | } 38 | 39 | function initTheme() { 40 | // set theme defined in localStorage if there is one, or fallback to auto mode 41 | const currentTheme = localStorage.getItem("theme"); 42 | currentTheme ? setTheme(currentTheme) : setTheme("auto"); 43 | } 44 | 45 | function setupTheme() { 46 | // Attach event handlers for toggling themes 47 | const buttons = document.getElementsByClassName("theme-toggle"); 48 | Array.from(buttons).forEach((btn) => { 49 | btn.addEventListener("click", cycleTheme); 50 | }); 51 | initTheme(); 52 | } 53 | 54 | setupTheme(); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /static/admin/js/urlify.js: -------------------------------------------------------------------------------- 1 | /*global XRegExp*/ 2 | 'use strict'; 3 | { 4 | const LATIN_MAP = { 5 | 'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 6 | 'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 7 | 'Î': 'I', 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 8 | 'Õ': 'O', 'Ö': 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 9 | 'Ü': 'U', 'Ű': 'U', 'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à': 'a', 10 | 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', 11 | 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i', 12 | 'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', 13 | 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', 14 | 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y' 15 | }; 16 | const LATIN_SYMBOLS_MAP = { 17 | '©': '(c)' 18 | }; 19 | const GREEK_MAP = { 20 | 'α': 'a', 'β': 'b', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'h', 21 | 'θ': '8', 'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm', 'ν': 'n', 'ξ': '3', 22 | 'ο': 'o', 'π': 'p', 'ρ': 'r', 'σ': 's', 'τ': 't', 'υ': 'y', 'φ': 'f', 23 | 'χ': 'x', 'ψ': 'ps', 'ω': 'w', 'ά': 'a', 'έ': 'e', 'ί': 'i', 'ό': 'o', 24 | 'ύ': 'y', 'ή': 'h', 'ώ': 'w', 'ς': 's', 'ϊ': 'i', 'ΰ': 'y', 'ϋ': 'y', 25 | 'ΐ': 'i', 'Α': 'A', 'Β': 'B', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z', 26 | 'Η': 'H', 'Θ': '8', 'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M', 'Ν': 'N', 27 | 'Ξ': '3', 'Ο': 'O', 'Π': 'P', 'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y', 28 | 'Φ': 'F', 'Χ': 'X', 'Ψ': 'PS', 'Ω': 'W', 'Ά': 'A', 'Έ': 'E', 'Ί': 'I', 29 | 'Ό': 'O', 'Ύ': 'Y', 'Ή': 'H', 'Ώ': 'W', 'Ϊ': 'I', 'Ϋ': 'Y' 30 | }; 31 | const TURKISH_MAP = { 32 | 'ş': 's', 'Ş': 'S', 'ı': 'i', 'İ': 'I', 'ç': 'c', 'Ç': 'C', 'ü': 'u', 33 | 'Ü': 'U', 'ö': 'o', 'Ö': 'O', 'ğ': 'g', 'Ğ': 'G' 34 | }; 35 | const ROMANIAN_MAP = { 36 | 'ă': 'a', 'î': 'i', 'ș': 's', 'ț': 't', 'â': 'a', 37 | 'Ă': 'A', 'Î': 'I', 'Ș': 'S', 'Ț': 'T', 'Â': 'A' 38 | }; 39 | const RUSSIAN_MAP = { 40 | 'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo', 41 | 'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm', 42 | 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u', 43 | 'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch', 'ш': 'sh', 'щ': 'sh', 'ъ': '', 44 | 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya', 45 | 'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo', 46 | 'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M', 47 | 'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U', 48 | 'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sh', 'Ъ': '', 49 | 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya' 50 | }; 51 | const UKRAINIAN_MAP = { 52 | 'Є': 'Ye', 'І': 'I', 'Ї': 'Yi', 'Ґ': 'G', 'є': 'ye', 'і': 'i', 53 | 'ї': 'yi', 'ґ': 'g' 54 | }; 55 | const CZECH_MAP = { 56 | 'č': 'c', 'ď': 'd', 'ě': 'e', 'ň': 'n', 'ř': 'r', 'š': 's', 'ť': 't', 57 | 'ů': 'u', 'ž': 'z', 'Č': 'C', 'Ď': 'D', 'Ě': 'E', 'Ň': 'N', 'Ř': 'R', 58 | 'Š': 'S', 'Ť': 'T', 'Ů': 'U', 'Ž': 'Z' 59 | }; 60 | const SLOVAK_MAP = { 61 | 'á': 'a', 'ä': 'a', 'č': 'c', 'ď': 'd', 'é': 'e', 'í': 'i', 'ľ': 'l', 62 | 'ĺ': 'l', 'ň': 'n', 'ó': 'o', 'ô': 'o', 'ŕ': 'r', 'š': 's', 'ť': 't', 63 | 'ú': 'u', 'ý': 'y', 'ž': 'z', 64 | 'Á': 'a', 'Ä': 'A', 'Č': 'C', 'Ď': 'D', 'É': 'E', 'Í': 'I', 'Ľ': 'L', 65 | 'Ĺ': 'L', 'Ň': 'N', 'Ó': 'O', 'Ô': 'O', 'Ŕ': 'R', 'Š': 'S', 'Ť': 'T', 66 | 'Ú': 'U', 'Ý': 'Y', 'Ž': 'Z' 67 | }; 68 | const POLISH_MAP = { 69 | 'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n', 'ó': 'o', 'ś': 's', 70 | 'ź': 'z', 'ż': 'z', 71 | 'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O', 'Ś': 'S', 72 | 'Ź': 'Z', 'Ż': 'Z' 73 | }; 74 | const LATVIAN_MAP = { 75 | 'ā': 'a', 'č': 'c', 'ē': 'e', 'ģ': 'g', 'ī': 'i', 'ķ': 'k', 'ļ': 'l', 76 | 'ņ': 'n', 'š': 's', 'ū': 'u', 'ž': 'z', 77 | 'Ā': 'A', 'Č': 'C', 'Ē': 'E', 'Ģ': 'G', 'Ī': 'I', 'Ķ': 'K', 'Ļ': 'L', 78 | 'Ņ': 'N', 'Š': 'S', 'Ū': 'U', 'Ž': 'Z' 79 | }; 80 | const ARABIC_MAP = { 81 | 'أ': 'a', 'ب': 'b', 'ت': 't', 'ث': 'th', 'ج': 'g', 'ح': 'h', 'خ': 'kh', 'د': 'd', 82 | 'ذ': 'th', 'ر': 'r', 'ز': 'z', 'س': 's', 'ش': 'sh', 'ص': 's', 'ض': 'd', 'ط': 't', 83 | 'ظ': 'th', 'ع': 'aa', 'غ': 'gh', 'ف': 'f', 'ق': 'k', 'ك': 'k', 'ل': 'l', 'م': 'm', 84 | 'ن': 'n', 'ه': 'h', 'و': 'o', 'ي': 'y' 85 | }; 86 | const LITHUANIAN_MAP = { 87 | 'ą': 'a', 'č': 'c', 'ę': 'e', 'ė': 'e', 'į': 'i', 'š': 's', 'ų': 'u', 88 | 'ū': 'u', 'ž': 'z', 89 | 'Ą': 'A', 'Č': 'C', 'Ę': 'E', 'Ė': 'E', 'Į': 'I', 'Š': 'S', 'Ų': 'U', 90 | 'Ū': 'U', 'Ž': 'Z' 91 | }; 92 | const SERBIAN_MAP = { 93 | 'ђ': 'dj', 'ј': 'j', 'љ': 'lj', 'њ': 'nj', 'ћ': 'c', 'џ': 'dz', 94 | 'đ': 'dj', 'Ђ': 'Dj', 'Ј': 'j', 'Љ': 'Lj', 'Њ': 'Nj', 'Ћ': 'C', 95 | 'Џ': 'Dz', 'Đ': 'Dj' 96 | }; 97 | const AZERBAIJANI_MAP = { 98 | 'ç': 'c', 'ə': 'e', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u', 99 | 'Ç': 'C', 'Ə': 'E', 'Ğ': 'G', 'İ': 'I', 'Ö': 'O', 'Ş': 'S', 'Ü': 'U' 100 | }; 101 | const GEORGIAN_MAP = { 102 | 'ა': 'a', 'ბ': 'b', 'გ': 'g', 'დ': 'd', 'ე': 'e', 'ვ': 'v', 'ზ': 'z', 103 | 'თ': 't', 'ი': 'i', 'კ': 'k', 'ლ': 'l', 'მ': 'm', 'ნ': 'n', 'ო': 'o', 104 | 'პ': 'p', 'ჟ': 'j', 'რ': 'r', 'ს': 's', 'ტ': 't', 'უ': 'u', 'ფ': 'f', 105 | 'ქ': 'q', 'ღ': 'g', 'ყ': 'y', 'შ': 'sh', 'ჩ': 'ch', 'ც': 'c', 'ძ': 'dz', 106 | 'წ': 'w', 'ჭ': 'ch', 'ხ': 'x', 'ჯ': 'j', 'ჰ': 'h' 107 | }; 108 | 109 | const ALL_DOWNCODE_MAPS = [ 110 | LATIN_MAP, 111 | LATIN_SYMBOLS_MAP, 112 | GREEK_MAP, 113 | TURKISH_MAP, 114 | ROMANIAN_MAP, 115 | RUSSIAN_MAP, 116 | UKRAINIAN_MAP, 117 | CZECH_MAP, 118 | SLOVAK_MAP, 119 | POLISH_MAP, 120 | LATVIAN_MAP, 121 | ARABIC_MAP, 122 | LITHUANIAN_MAP, 123 | SERBIAN_MAP, 124 | AZERBAIJANI_MAP, 125 | GEORGIAN_MAP 126 | ]; 127 | 128 | const Downcoder = { 129 | 'Initialize': function() { 130 | if (Downcoder.map) { // already made 131 | return; 132 | } 133 | Downcoder.map = {}; 134 | for (const lookup of ALL_DOWNCODE_MAPS) { 135 | Object.assign(Downcoder.map, lookup); 136 | } 137 | Downcoder.regex = new RegExp(Object.keys(Downcoder.map).join('|'), 'g'); 138 | } 139 | }; 140 | 141 | function downcode(slug) { 142 | Downcoder.Initialize(); 143 | return slug.replace(Downcoder.regex, function(m) { 144 | return Downcoder.map[m]; 145 | }); 146 | } 147 | 148 | 149 | function URLify(s, num_chars, allowUnicode) { 150 | // changes, e.g., "Petty theft" to "petty-theft" 151 | if (!allowUnicode) { 152 | s = downcode(s); 153 | } 154 | s = s.toLowerCase(); // convert to lowercase 155 | // if downcode doesn't hit, the char will be stripped here 156 | if (allowUnicode) { 157 | // Keep Unicode letters including both lowercase and uppercase 158 | // characters, whitespace, and dash; remove other characters. 159 | s = XRegExp.replace(s, XRegExp('[^-_\\p{L}\\p{N}\\s]', 'g'), ''); 160 | } else { 161 | s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars 162 | } 163 | s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces 164 | s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens 165 | s = s.substring(0, num_chars); // trim to first num_chars chars 166 | return s.replace(/-+$/g, ''); // trim any trailing hyphens 167 | } 168 | window.URLify = URLify; 169 | } 170 | -------------------------------------------------------------------------------- /static/admin/js/vendor/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/af.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/af",[],function(){return{errorLoading:function(){return"Die resultate kon nie gelaai word nie."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Verwyders asseblief "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Voer asseblief "+(e.minimum-e.input.length)+" of meer karakters"},loadingMore:function(){return"Meer resultate word gelaai…"},maximumSelected:function(e){var n="Kies asseblief net "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"Geen resultate gevind"},searching:function(){return"Besig…"},removeAllItems:function(){return"Verwyder alle items"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ar.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(n){return"الرجاء حذف "+(n.input.length-n.maximum)+" عناصر"},inputTooShort:function(n){return"الرجاء إضافة "+(n.minimum-n.input.length)+" عناصر"},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(n){return"تستطيع إختيار "+n.maximum+" بنود فقط"},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"},removeAllItems:function(){return"قم بإزالة كل العناصر"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/az.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/az",[],function(){return{inputTooLong:function(n){return n.input.length-n.maximum+" simvol silin"},inputTooShort:function(n){return n.minimum-n.input.length+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(n){return"Sadəcə "+n.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"},removeAllItems:function(){return"Bütün elementləri sil"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/bg.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bg",[],function(){return{inputTooLong:function(n){var e=n.input.length-n.maximum,u="Моля въведете с "+e+" по-малко символ";return e>1&&(u+="a"),u},inputTooShort:function(n){var e=n.minimum-n.input.length,u="Моля въведете още "+e+" символ";return e>1&&(u+="a"),u},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(n){var e="Можете да направите до "+n.maximum+" ";return n.maximum>1?e+="избора":e+="избор",e},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"},removeAllItems:function(){return"Премахнете всички елементи"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/bn.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bn",[],function(){return{errorLoading:function(){return"ফলাফলগুলি লোড করা যায়নি।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।";return 1!=e&&(u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।"),u},inputTooShort:function(n){return n.minimum-n.input.length+" টি অক্ষর অথবা অধিক অক্ষর লিখুন।"},loadingMore:function(){return"আরো ফলাফল লোড হচ্ছে ..."},maximumSelected:function(n){var e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।";return 1!=n.maximum&&(e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।"),e},noResults:function(){return"কোন ফলাফল পাওয়া যায়নি।"},searching:function(){return"অনুসন্ধান করা হচ্ছে ..."}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/bs.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/bs",[],function(){function e(e,n,r,t){return e%10==1&&e%100!=11?n:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspijelo."},inputTooLong:function(n){var r=n.input.length-n.maximum,t="Obrišite "+r+" simbol";return t+=e(r,"","a","a")},inputTooShort:function(n){var r=n.minimum-n.input.length,t="Ukucajte bar još "+r+" simbol";return t+=e(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(n){var r="Možete izabrati samo "+n.maximum+" stavk";return r+=e(n.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Uklonite sve stavke"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ca.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Si us plau, elimina "+n+" car";return r+=1==n?"àcter":"àcters"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Si us plau, introdueix "+n+" car";return r+=1==n?"àcter":"àcters"},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var n="Només es pot seleccionar "+e.maximum+" element";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"},removeAllItems:function(){return"Treu tots els elements"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/cs.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/cs",[],function(){function e(e,n){switch(e){case 2:return n?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadejte o jeden znak méně.":t<=4?"Prosím, zadejte o "+e(t,!0)+" znaky méně.":"Prosím, zadejte o "+t+" znaků méně."},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadejte ještě jeden znak.":t<=4?"Prosím, zadejte ještě další "+e(t,!0)+" znaky.":"Prosím, zadejte ještě dalších "+t+" znaků."},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(n){var t=n.maximum;return 1==t?"Můžete zvolit jen jednu položku.":t<=4?"Můžete zvolit maximálně "+e(t,!1)+" položky.":"Můžete zvolit maximálně "+t+" položek."},noResults:function(){return"Nenalezeny žádné položky."},searching:function(){return"Vyhledávání…"},removeAllItems:function(){return"Odstraňte všechny položky"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/da.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){return"Angiv venligst "+(e.input.length-e.maximum)+" tegn mindre"},inputTooShort:function(e){return"Angiv venligst "+(e.minimum-e.input.length)+" tegn mere"},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var n="Du kan kun vælge "+e.maximum+" emne";return 1!=e.maximum&&(n+="r"),n},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/de.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/de",[],function(){return{errorLoading:function(){return"Die Ergebnisse konnten nicht geladen werden."},inputTooLong:function(e){return"Bitte "+(e.input.length-e.maximum)+" Zeichen weniger eingeben"},inputTooShort:function(e){return"Bitte "+(e.minimum-e.input.length)+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var n="Sie können nur "+e.maximum+" Element";return 1!=e.maximum&&(n+="e"),n+=" auswählen"},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"},removeAllItems:function(){return"Entferne alle Elemente"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/dsb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/dsb",[],function(){var n=["znamuško","znamušce","znamuška","znamuškow"],e=["zapisk","zapiska","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njejsu se dali zacytaś."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Pšosym lašuj "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Pšosym zapódaj nanejmjenjej "+a+" "+u(a,n)},loadingMore:function(){return"Dalšne wuslědki se zacytaju…"},maximumSelected:function(n){return"Móžoš jano "+n.maximum+" "+u(n.maximum,e)+"wubraś."},noResults:function(){return"Žedne wuslědki namakane"},searching:function(){return"Pyta se…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/el.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(n){var e=n.input.length-n.maximum,u="Παρακαλώ διαγράψτε "+e+" χαρακτήρ";return 1==e&&(u+="α"),1!=e&&(u+="ες"),u},inputTooShort:function(n){return"Παρακαλώ συμπληρώστε "+(n.minimum-n.input.length)+" ή περισσότερους χαρακτήρες"},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(n){var e="Μπορείτε να επιλέξετε μόνο "+n.maximum+" επιλογ";return 1==n.maximum&&(e+="ή"),1!=n.maximum&&(e+="ές"),e},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"},removeAllItems:function(){return"Καταργήστε όλα τα στοιχεία"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/en.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Please delete "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Please enter "+(e.minimum-e.input.length)+" or more characters"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var n="You can only select "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No results found"},searching:function(){return"Searching…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/es.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"No se pudieron cargar los resultados"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Por favor, elimine "+n+" car";return r+=1==n?"ácter":"acteres"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Por favor, introduzca "+n+" car";return r+=1==n?"ácter":"acteres"},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var n="Sólo puede seleccionar "+e.maximum+" elemento";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Eliminar todos los elementos"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/et.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var n=e.input.length-e.maximum,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" vähem"},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" rohkem"},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var n="Saad vaid "+e.maximum+" tulemus";return 1==e.maximum?n+="e":n+="t",n+=" valida"},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"},removeAllItems:function(){return"Eemalda kõik esemed"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/eu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gutxiago"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gehiago"},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return 1===e.maximum?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"},removeAllItems:function(){return"Kendu elementu guztiak"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/fa.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(n){return"لطفاً "+(n.input.length-n.maximum)+" کاراکتر را حذف نمایید"},inputTooShort:function(n){return"لطفاً تعداد "+(n.minimum-n.input.length)+" کاراکتر یا بیشتر وارد نمایید"},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(n){return"شما تنها می‌توانید "+n.maximum+" آیتم را انتخاب نمایید"},noResults:function(){return"هیچ نتیجه‌ای یافت نشد"},searching:function(){return"در حال جستجو..."},removeAllItems:function(){return"همه موارد را حذف کنید"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/fi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fi",[],function(){return{errorLoading:function(){return"Tuloksia ei saatu ladattua."},inputTooLong:function(n){return"Ole hyvä ja anna "+(n.input.length-n.maximum)+" merkkiä vähemmän"},inputTooShort:function(n){return"Ole hyvä ja anna "+(n.minimum-n.input.length)+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(n){return"Voit valita ainoastaan "+n.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){return"Haetaan…"},removeAllItems:function(){return"Poista kaikki kohteet"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/fr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var n=e.input.length-e.maximum;return"Supprimez "+n+" caractère"+(n>1?"s":"")},inputTooShort:function(e){var n=e.minimum-e.input.length;return"Saisissez au moins "+n+" caractère"+(n>1?"s":"")},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){return"Vous pouvez seulement sélectionner "+e.maximum+" élément"+(e.maximum>1?"s":"")},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"},removeAllItems:function(){return"Supprimer tous les éléments"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/gl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/gl",[],function(){return{errorLoading:function(){return"Non foi posíbel cargar os resultados."},inputTooLong:function(e){var n=e.input.length-e.maximum;return 1===n?"Elimine un carácter":"Elimine "+n+" caracteres"},inputTooShort:function(e){var n=e.minimum-e.input.length;return 1===n?"Engada un carácter":"Engada "+n+" caracteres"},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){return 1===e.maximum?"Só pode seleccionar un elemento":"Só pode seleccionar "+e.maximum+" elementos"},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Elimina todos os elementos"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/he.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="נא למחוק ";return r+=1===e?"תו אחד":e+" תווים"},inputTooShort:function(n){var e=n.minimum-n.input.length,r="נא להכניס ";return r+=1===e?"תו אחד":e+" תווים",r+=" או יותר"},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(n){var e="באפשרותך לבחור עד ";return 1===n.maximum?e+="פריט אחד":e+=n.maximum+" פריטים",e},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"},removeAllItems:function(){return"הסר את כל הפריטים"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(n){var e=n.input.length-n.maximum,r=e+" अक्षर को हटा दें";return e>1&&(r=e+" अक्षरों को हटा दें "),r},inputTooShort:function(n){return"कृपया "+(n.minimum-n.input.length)+" या अधिक अक्षर दर्ज करें"},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(n){return"आप केवल "+n.maximum+" आइटम का चयन कर सकते हैं"},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."},removeAllItems:function(){return"सभी वस्तुओं को हटा दें"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hr",[],function(){function n(n){var e=" "+n+" znak";return n%10<5&&n%10>0&&(n%100<5||n%100>19)?n%10>1&&(e+="a"):e+="ova",e}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(e){return"Unesite "+n(e.input.length-e.maximum)},inputTooShort:function(e){return"Unesite još "+n(e.minimum-e.input.length)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(n){return"Maksimalan broj odabranih stavki je "+n.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Ukloni sve stavke"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hsb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hsb",[],function(){var n=["znamješko","znamješce","znamješka","znamješkow"],e=["zapisk","zapiskaj","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njedachu so začitać."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Prošu zhašej "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Prošu zapodaj znajmjeńša "+a+" "+u(a,n)},loadingMore:function(){return"Dalše wuslědki so začitaja…"},maximumSelected:function(n){return"Móžeš jenož "+n.maximum+" "+u(n.maximum,e)+"wubrać"},noResults:function(){return"Žane wuslědki namakane"},searching:function(){return"Pyta so…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/hu",[],function(){return{errorLoading:function(){return"Az eredmények betöltése nem sikerült."},inputTooLong:function(e){return"Túl hosszú. "+(e.input.length-e.maximum)+" karakterrel több, mint kellene."},inputTooShort:function(e){return"Túl rövid. Még "+(e.minimum-e.input.length)+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"},removeAllItems:function(){return"Távolítson el minden elemet"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hy.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hy",[],function(){return{errorLoading:function(){return"Արդյունքները հնարավոր չէ բեռնել։"},inputTooLong:function(n){return"Խնդրում ենք հեռացնել "+(n.input.length-n.maximum)+" նշան"},inputTooShort:function(n){return"Խնդրում ենք մուտքագրել "+(n.minimum-n.input.length)+" կամ ավել նշաններ"},loadingMore:function(){return"Բեռնվում են նոր արդյունքներ․․․"},maximumSelected:function(n){return"Դուք կարող եք ընտրել առավելագույնը "+n.maximum+" կետ"},noResults:function(){return"Արդյունքներ չեն գտնվել"},searching:function(){return"Որոնում․․․"},removeAllItems:function(){return"Հեռացնել բոլոր տարրերը"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/id.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(n){return"Hapuskan "+(n.input.length-n.maximum)+" huruf"},inputTooShort:function(n){return"Masukkan "+(n.minimum-n.input.length)+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(n){return"Anda hanya dapat memilih "+n.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Hapus semua item"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/is.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/is",[],function(){return{inputTooLong:function(n){var t=n.input.length-n.maximum,e="Vinsamlegast styttið texta um "+t+" staf";return t<=1?e:e+"i"},inputTooShort:function(n){var t=n.minimum-n.input.length,e="Vinsamlegast skrifið "+t+" staf";return t>1&&(e+="i"),e+=" í viðbót"},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(n){return"Þú getur aðeins valið "+n.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"},removeAllItems:function(){return"Fjarlægðu öll atriði"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/it.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Per favore cancella "+n+" caratter";return t+=1!==n?"i":"e"},inputTooShort:function(e){return"Per favore inserisci "+(e.minimum-e.input.length)+" o più caratteri"},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var n="Puoi selezionare solo "+e.maximum+" element";return 1!==e.maximum?n+="i":n+="o",n},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"},removeAllItems:function(){return"Rimuovi tutti gli oggetti"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ja.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(n){return n.input.length-n.maximum+" 文字を削除してください"},inputTooShort:function(n){return"少なくとも "+(n.minimum-n.input.length)+" 文字を入力してください"},loadingMore:function(){return"読み込み中…"},maximumSelected:function(n){return n.maximum+" 件しか選択できません"},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"},removeAllItems:function(){return"すべてのアイテムを削除"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ka.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ka",[],function(){return{errorLoading:function(){return"მონაცემების ჩატვირთვა შეუძლებელია."},inputTooLong:function(n){return"გთხოვთ აკრიფეთ "+(n.input.length-n.maximum)+" სიმბოლოთი ნაკლები"},inputTooShort:function(n){return"გთხოვთ აკრიფეთ "+(n.minimum-n.input.length)+" სიმბოლო ან მეტი"},loadingMore:function(){return"მონაცემების ჩატვირთვა…"},maximumSelected:function(n){return"თქვენ შეგიძლიათ აირჩიოთ არაუმეტეს "+n.maximum+" ელემენტი"},noResults:function(){return"რეზულტატი არ მოიძებნა"},searching:function(){return"ძიება…"},removeAllItems:function(){return"ამოიღე ყველა ელემენტი"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/km.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(n){return"សូមលុបចេញ "+(n.input.length-n.maximum)+" អក្សរ"},inputTooShort:function(n){return"សូមបញ្ចូល"+(n.minimum-n.input.length)+" អក្សរ រឺ ច្រើនជាងនេះ"},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(n){return"អ្នកអាចជ្រើសរើសបានតែ "+n.maximum+" ជម្រើសប៉ុណ្ណោះ"},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."},removeAllItems:function(){return"លុបធាតុទាំងអស់"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ko.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(n){return"너무 깁니다. "+(n.input.length-n.maximum)+" 글자 지워주세요."},inputTooShort:function(n){return"너무 짧습니다. "+(n.minimum-n.input.length)+" 글자 더 입력해주세요."},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(n){return"최대 "+n.maximum+"개까지만 선택 가능합니다."},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"},removeAllItems:function(){return"모든 항목 삭제"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/lt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/lt",[],function(){function n(n,e,i,t){return n%10==1&&(n%100<11||n%100>19)?e:n%10>=2&&n%10<=9&&(n%100<11||n%100>19)?i:t}return{inputTooLong:function(e){var i=e.input.length-e.maximum,t="Pašalinkite "+i+" simbol";return t+=n(i,"į","ius","ių")},inputTooShort:function(e){var i=e.minimum-e.input.length,t="Įrašykite dar "+i+" simbol";return t+=n(i,"į","ius","ių")},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(e){var i="Jūs galite pasirinkti tik "+e.maximum+" element";return i+=n(e.maximum,"ą","us","ų")},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"},removeAllItems:function(){return"Pašalinti visus elementus"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/lv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/lv",[],function(){function e(e,n,u,i){return 11===e?n:e%10==1?u:i}return{inputTooLong:function(n){var u=n.input.length-n.maximum,i="Lūdzu ievadiet par "+u;return(i+=" simbol"+e(u,"iem","u","iem"))+" mazāk"},inputTooShort:function(n){var u=n.minimum-n.input.length,i="Lūdzu ievadiet vēl "+u;return i+=" simbol"+e(u,"us","u","us")},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(n){var u="Jūs varat izvēlēties ne vairāk kā "+n.maximum;return u+=" element"+e(n.maximum,"us","u","us")},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"},removeAllItems:function(){return"Noņemt visus vienumus"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/mk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/mk",[],function(){return{inputTooLong:function(n){var e=(n.input.length,n.maximum,"Ве молиме внесете "+n.maximum+" помалку карактер");return 1!==n.maximum&&(e+="и"),e},inputTooShort:function(n){var e=(n.minimum,n.input.length,"Ве молиме внесете уште "+n.maximum+" карактер");return 1!==n.maximum&&(e+="и"),e},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(n){var e="Можете да изберете само "+n.maximum+" ставк";return 1===n.maximum?e+="а":e+="и",e},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"},removeAllItems:function(){return"Отстрани ги сите предмети"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ms.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(n){return"Sila hapuskan "+(n.input.length-n.maximum)+" aksara"},inputTooShort:function(n){return"Sila masukkan "+(n.minimum-n.input.length)+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(n){return"Anda hanya boleh memilih "+n.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Keluarkan semua item"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/nb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){return"Vennligst fjern "+(e.input.length-e.maximum)+" tegn"},inputTooShort:function(e){return"Vennligst skriv inn "+(e.minimum-e.input.length)+" tegn til"},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ne.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ne",[],function(){return{errorLoading:function(){return"नतिजाहरु देखाउन सकिएन।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="कृपया "+e+" अक्षर मेटाउनुहोस्।";return 1!=e&&(u+="कृपया "+e+" अक्षरहरु मेटाउनुहोस्।"),u},inputTooShort:function(n){return"कृपया बाँकी रहेका "+(n.minimum-n.input.length)+" वा अरु धेरै अक्षरहरु भर्नुहोस्।"},loadingMore:function(){return"अरु नतिजाहरु भरिँदैछन् …"},maximumSelected:function(n){var e="तँपाई "+n.maximum+" वस्तु मात्र छान्न पाउँनुहुन्छ।";return 1!=n.maximum&&(e="तँपाई "+n.maximum+" वस्तुहरु मात्र छान्न पाउँनुहुन्छ।"),e},noResults:function(){return"कुनै पनि नतिजा भेटिएन।"},searching:function(){return"खोजि हुँदैछ…"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/nl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){return"Gelieve "+(e.input.length-e.maximum)+" karakters te verwijderen"},inputTooShort:function(e){return"Gelieve "+(e.minimum-e.input.length)+" of meer karakters in te voeren"},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var n=1==e.maximum?"kan":"kunnen",r="Er "+n+" maar "+e.maximum+" item";return 1!=e.maximum&&(r+="s"),r+=" worden geselecteerd"},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"},removeAllItems:function(){return"Verwijder alle items"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/pl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/pl",[],function(){var n=["znak","znaki","znaków"],e=["element","elementy","elementów"],r=function(n,e){return 1===n?e[0]:n>1&&n<=4?e[1]:n>=5?e[2]:void 0};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Usuń "+t+" "+r(t,n)},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Podaj przynajmniej "+t+" "+r(t,n)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(n){return"Możesz zaznaczyć tylko "+n.maximum+" "+r(n.maximum,e)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"},removeAllItems:function(){return"Usuń wszystkie przedmioty"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ps.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ps",[],function(){return{errorLoading:function(){return"پايلي نه سي ترلاسه کېدای"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="د مهربانۍ لمخي "+e+" توری ړنګ کړئ";return 1!=e&&(r=r.replace("توری","توري")),r},inputTooShort:function(n){return"لږ تر لږه "+(n.minimum-n.input.length)+" يا ډېر توري وليکئ"},loadingMore:function(){return"نوري پايلي ترلاسه کيږي..."},maximumSelected:function(n){var e="تاسو يوازي "+n.maximum+" قلم په نښه کولای سی";return 1!=n.maximum&&(e=e.replace("قلم","قلمونه")),e},noResults:function(){return"پايلي و نه موندل سوې"},searching:function(){return"لټول کيږي..."},removeAllItems:function(){return"ټول توکي لرې کړئ"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/pt-BR.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Apague "+n+" caracter";return 1!=n&&(r+="es"),r},inputTooShort:function(e){return"Digite "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var n="Você só pode selecionar "+e.maximum+" ite";return 1==e.maximum?n+="m":n+="ns",n},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/pt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var r=e.input.length-e.maximum,n="Por favor apague "+r+" ";return n+=1!=r?"caracteres":"caractere"},inputTooShort:function(e){return"Introduza "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var r="Apenas pode seleccionar "+e.maximum+" ";return r+=1!=e.maximum?"itens":"item"},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ro.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return 1!==t&&(n+="e"),n},inputTooShort:function(e){return"Vă rugăm să introduceți "+(e.minimum-e.input.length)+" sau mai multe caractere"},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",1!==e.maximum&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"},removeAllItems:function(){return"Eliminați toate elementele"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ru.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ru",[],function(){function n(n,e,r,u){return n%10<5&&n%10>0&&n%100<5||n%100>20?n%10>1?r:e:u}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Пожалуйста, введите на "+r+" символ";return u+=n(r,"","a","ов"),u+=" меньше"},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Пожалуйста, введите ещё хотя бы "+r+" символ";return u+=n(r,"","a","ов")},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(e){var r="Вы можете выбрать не более "+e.maximum+" элемент";return r+=n(e.maximum,"","a","ов")},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"},removeAllItems:function(){return"Удалить все элементы"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{errorLoading:function(){return"Výsledky sa nepodarilo načítať."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadajte o jeden znak menej":t>=2&&t<=4?"Prosím, zadajte o "+e[t](!0)+" znaky menej":"Prosím, zadajte o "+t+" znakov menej"},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadajte ešte jeden znak":t<=4?"Prosím, zadajte ešte ďalšie "+e[t](!0)+" znaky":"Prosím, zadajte ešte ďalších "+t+" znakov"},loadingMore:function(){return"Načítanie ďalších výsledkov…"},maximumSelected:function(n){return 1==n.maximum?"Môžete zvoliť len jednu položku":n.maximum>=2&&n.maximum<=4?"Môžete zvoliť najviac "+e[n.maximum](!1)+" položky":"Môžete zvoliť najviac "+n.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"},removeAllItems:function(){return"Odstráňte všetky položky"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sl",[],function(){return{errorLoading:function(){return"Zadetkov iskanja ni bilo mogoče naložiti."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Prosim zbrišite "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Prosim vpišite še "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},loadingMore:function(){return"Nalagam več zadetkov…"},maximumSelected:function(e){var n="Označite lahko največ "+e.maximum+" predmet";return 2==e.maximum?n+="a":1!=e.maximum&&(n+="e"),n},noResults:function(){return"Ni zadetkov."},searching:function(){return"Iščem…"},removeAllItems:function(){return"Odstranite vse elemente"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sq.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sq",[],function(){return{errorLoading:function(){return"Rezultatet nuk mund të ngarkoheshin."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Të lutem fshi "+n+" karakter";return 1!=n&&(t+="e"),t},inputTooShort:function(e){return"Të lutem shkruaj "+(e.minimum-e.input.length)+" ose më shumë karaktere"},loadingMore:function(){return"Duke ngarkuar më shumë rezultate…"},maximumSelected:function(e){var n="Mund të zgjedhësh vetëm "+e.maximum+" element";return 1!=e.maximum&&(n+="e"),n},noResults:function(){return"Nuk u gjet asnjë rezultat"},searching:function(){return"Duke kërkuar…"},removeAllItems:function(){return"Hiq të gjitha sendet"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sr-Cyrl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr-Cyrl",[],function(){function n(n,e,r,u){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:u}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Обришите "+r+" симбол";return u+=n(r,"","а","а")},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Укуцајте бар још "+r+" симбол";return u+=n(r,"","а","а")},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(e){var r="Можете изабрати само "+e.maximum+" ставк";return r+=n(e.maximum,"у","е","и")},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr",[],function(){function n(n,e,r,t){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(e){var r=e.input.length-e.maximum,t="Obrišite "+r+" simbol";return t+=n(r,"","a","a")},inputTooShort:function(e){var r=e.minimum-e.input.length,t="Ukucajte bar još "+r+" simbol";return t+=n(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(e){var r="Možete izabrati samo "+e.maximum+" stavk";return r+=n(e.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(n){return"Vänligen sudda ut "+(n.input.length-n.maximum)+" tecken"},inputTooShort:function(n){return"Vänligen skriv in "+(n.minimum-n.input.length)+" eller fler tecken"},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(n){return"Du kan max välja "+n.maximum+" element"},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"},removeAllItems:function(){return"Ta bort alla objekt"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/th.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/th",[],function(){return{errorLoading:function(){return"ไม่สามารถค้นข้อมูลได้"},inputTooLong:function(n){return"โปรดลบออก "+(n.input.length-n.maximum)+" ตัวอักษร"},inputTooShort:function(n){return"โปรดพิมพ์เพิ่มอีก "+(n.minimum-n.input.length)+" ตัวอักษร"},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(n){return"คุณสามารถเลือกได้ไม่เกิน "+n.maximum+" รายการ"},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"},removeAllItems:function(){return"ลบรายการทั้งหมด"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/tk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/tk",[],function(){return{errorLoading:function(){return"Netije ýüklenmedi."},inputTooLong:function(e){return e.input.length-e.maximum+" harp bozuň."},inputTooShort:function(e){return"Ýene-de iň az "+(e.minimum-e.input.length)+" harp ýazyň."},loadingMore:function(){return"Köpräk netije görkezilýär…"},maximumSelected:function(e){return"Diňe "+e.maximum+" sanysyny saýlaň."},noResults:function(){return"Netije tapylmady."},searching:function(){return"Gözlenýär…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/tr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/tr",[],function(){return{errorLoading:function(){return"Sonuç yüklenemedi"},inputTooLong:function(n){return n.input.length-n.maximum+" karakter daha girmelisiniz"},inputTooShort:function(n){return"En az "+(n.minimum-n.input.length)+" karakter daha girmelisiniz"},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(n){return"Sadece "+n.maximum+" seçim yapabilirsiniz"},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"},removeAllItems:function(){return"Tüm öğeleri kaldır"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/uk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/uk",[],function(){function n(n,e,u,r){return n%100>10&&n%100<15?r:n%10==1?e:n%10>1&&n%10<5?u:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(e){return"Будь ласка, видаліть "+(e.input.length-e.maximum)+" "+n(e.maximum,"літеру","літери","літер")},inputTooShort:function(n){return"Будь ласка, введіть "+(n.minimum-n.input.length)+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(e){return"Ви можете вибрати лише "+e.maximum+" "+n(e.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"},removeAllItems:function(){return"Видалити всі елементи"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/vi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/vi",[],function(){return{inputTooLong:function(n){return"Vui lòng xóa bớt "+(n.input.length-n.maximum)+" ký tự"},inputTooShort:function(n){return"Vui lòng nhập thêm từ "+(n.minimum-n.input.length)+" ký tự trở lên"},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(n){return"Chỉ có thể chọn được "+n.maximum+" lựa chọn"},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"},removeAllItems:function(){return"Xóa tất cả các mục"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/zh-CN.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(n){return"请删除"+(n.input.length-n.maximum)+"个字符"},inputTooShort:function(n){return"请再输入至少"+(n.minimum-n.input.length)+"个字符"},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(n){return"最多只能选择"+n.maximum+"个项目"},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"},removeAllItems:function(){return"删除所有项目"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/zh-TW.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(n){return"請刪掉"+(n.input.length-n.maximum)+"個字元"},inputTooShort:function(n){return"請再輸入"+(n.minimum-n.input.length)+"個字元"},loadingMore:function(){return"載入中…"},maximumSelected:function(n){return"你只能選擇最多"+n.maximum+"項"},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"},removeAllItems:function(){return"刪除所有項目"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/xregexp/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2007-2017 Steven Levithan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /templates/edit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | Edit 29 | 164 | 165 | 166 |
167 |
168 |
169 |
170 |
171 |
Edit
172 |
173 |
174 |
175 |
176 |
177 | {% csrf_token %} 178 |
179 | 180 | 181 | 182 | 183 |
184 |
185 |
186 | Home 187 |
188 |
189 | 190 |
191 |
192 |
193 | 194 | {% if success_message %} 195 |

{{ success_message }}

196 | {% endif %} 197 | {% if error_message %} 198 |

{{ error_message }}

199 | {% endif %} 200 |
201 | 217 | 218 | -------------------------------------------------------------------------------- /templates/friend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | User 29 | 124 | 125 | 126 |
127 | {% if messages %} 128 |
129 | {% for message in messages %} 130 | {{ message }} 131 | {% endfor %} 132 |
133 | {% else %} 134 |
135 |

Username: {{ user_details.username }}

136 | 137 |
138 | {% endif %} 139 | {% if user_details.send_request %} 140 |
141 |
142 | {% csrf_token %} 143 | 144 | 145 |
146 |
147 | {% elif user_details.not_accepted %} 148 |
149 |
150 | {% csrf_token %} 151 | 152 | 153 |
154 |
155 | {% elif user_details.me_not_accepted %} 156 |
157 |
158 | {% csrf_token %} 159 | 160 | 161 |
162 |
163 | {% else %} 164 | {% if user_details.is_friend %} 165 |
166 |
167 | {% csrf_token %} 168 | 169 | 170 |
171 | 174 |
175 | {% endif %} 176 | {% endif %} 177 |
178 | 179 | 184 | 185 | -------------------------------------------------------------------------------- /templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | Login 29 | 147 | 148 | 149 |
150 |
151 |
152 |
153 |
154 |
155 |
Login
156 |
157 |
158 |
159 |
160 |
161 | {% csrf_token %} 162 |
163 | 164 | 165 |
166 |
167 |
168 | Signup 169 |
170 |
171 | 172 |
173 |
174 | {% if error_message %} 175 |

{{ error_message }}

176 | {% endif %} 177 |
178 | 183 | 184 | -------------------------------------------------------------------------------- /templates/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | {% comment %} {% endcomment %} 25 | 26 | 27 | 28 | 29 | 30 | Search 31 | 183 | 184 | 185 |
186 |
187 |
188 |
189 | {{ user }} 190 |
191 |
192 |
193 |
194 |
195 | 196 | 197 |
198 |
199 | 200 | {% if query %} 201 | {% comment %}

Search Results for "{{ query }}"

{% endcomment %} 202 | 203 |
204 | {% if users %} 205 | {% for fuser in users %} 206 |
207 | {{ fuser.username }} 208 |
209 | {% endfor %} 210 | {% else %} 211 |

{{ not_found_message }}

212 | {% endif %} 213 |
214 | {% endif %} 215 |
216 |
217 | 233 | 234 | -------------------------------------------------------------------------------- /templates/signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | Signup 29 | 147 | 148 | 149 |
150 |
151 |
152 |
153 |
Signup
154 |
155 |
156 |
157 | 158 |
159 | {% csrf_token %} 160 |
161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 |
169 |
170 |
171 | Login 172 |
173 |
174 | 175 |
176 |
177 |

{{ error_message }}

178 |
179 | 206 | 207 | --------------------------------------------------------------------------------