├── .gitignore ├── LICENSE ├── README.md ├── media_cdn └── 2 │ └── django_plus_charts_js_share.png ├── requirements.txt ├── runtime.txt ├── src ├── cfelikes │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── db.sqlite3 ├── manage.py ├── posts │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── forms.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_auto_20170309_2235.py │ │ └── __init__.py │ ├── models.py │ ├── templates │ │ └── posts │ │ │ ├── post_detail.html │ │ │ ├── post_form.html │ │ │ └── post_list.html │ ├── tests.py │ ├── urls.py │ ├── utils.py │ └── views.py ├── static │ └── css │ │ └── main.css └── templates │ ├── base.html │ └── base │ ├── bootstrap_defaults.html │ ├── css.html │ └── js.html └── static_cdn ├── admin ├── css │ ├── base.css │ ├── changelists.css │ ├── dashboard.css │ ├── fonts.css │ ├── forms.css │ ├── login.css │ ├── rtl.css │ └── widgets.css ├── fonts │ ├── LICENSE.txt │ ├── README.txt │ ├── Roboto-Bold-webfont.woff │ ├── Roboto-Light-webfont.woff │ └── Roboto-Regular-webfont.woff ├── 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-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 │ ├── actions.min.js │ ├── admin │ ├── DateTimeShortcuts.js │ └── RelatedObjectLookups.js │ ├── calendar.js │ ├── cancel.js │ ├── change_form.js │ ├── collapse.js │ ├── collapse.min.js │ ├── core.js │ ├── inlines.js │ ├── inlines.min.js │ ├── jquery.init.js │ ├── popup_response.js │ ├── prepopulate.js │ ├── prepopulate.min.js │ ├── prepopulate_init.js │ ├── timeparse.js │ ├── urlify.js │ └── vendor │ ├── jquery │ ├── LICENSE-JQUERY.txt │ ├── jquery.js │ └── jquery.min.js │ └── xregexp │ ├── LICENSE-XREGEXP.txt │ ├── xregexp.js │ └── xregexp.min.js ├── css └── main.css └── rest_framework ├── css ├── bootstrap-tweaks.css ├── bootstrap.min.css ├── default.css └── prettify.css ├── docs ├── css │ ├── base.css │ ├── bootstrap-theme.min.css │ ├── bootstrap.min.css │ ├── font-awesome-4.0.3.css │ ├── highlight.css │ └── jquery.json-view.min.css ├── fonts │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── img │ ├── favicon.ico │ └── grid.png └── js │ ├── api.js │ ├── base.js │ ├── bootstrap.min.js │ ├── highlight.pack.js │ ├── jquery-1.10.2.min.js │ └── jquery.json-view.min.js ├── fonts ├── glyphicons-halflings-regular.eot ├── glyphicons-halflings-regular.svg ├── glyphicons-halflings-regular.ttf ├── glyphicons-halflings-regular.woff └── glyphicons-halflings-regular.woff2 ├── img ├── glyphicons-halflings-white.png ├── glyphicons-halflings.png └── grid.png └── js ├── ajax-form.js ├── bootstrap.min.js ├── coreapi-0.1.0.js ├── csrf.js ├── default.js ├── jquery-1.12.4.min.js └── prettify-min.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | bin/ 3 | lib/ 4 | include/ 5 | pip-selfcheck.json 6 | 7 | # Byte-compiled / optimized / DLL files 8 | __pycache__/ 9 | *.py[cod] 10 | *$py.class 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Distribution / packaging 16 | .Python 17 | env/ 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *,cover 52 | .hypothesis/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # IPython Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # dotenv 85 | .env 86 | 87 | # virtualenv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Coding For Entrepreneurs 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 | ![Django Likes Logo](https://cfe2-static.s3-us-west-2.amazonaws.com/media/projects/django-likes/images/share/django_likes_share.png) 2 | 3 | # Django Likes 4 | Learn how to create a ajax-powered `like` button in Django using `jQuery`. 5 | 6 | We show you how to create a `like` button much like what you'd see on Facebook, Instagram, Google+, YouTube, and others. We are using the [Django](http://django.project.com) web framework along with the [Django Rest Framework](http://www.django-rest-framework.org/) and [jQuery](http://jquery.com/). The key here in this series is how to setup Django's backend so your project can collect `like` data. We use `jQuery` as a easy-to-implement solution for working with Django but really, this method could be used with any client technology like Angular, React, Swift, Java, and more. 7 | 8 | Watch it [here](https://www.codingforentrepreneurs.com/projects/django-likes/) 9 | 10 | What to see more Ajax? Submit & Upvote [here](http://joincfe.com/suggest/) 11 | 12 | Subscribe to our YouTube channel: [http://joincfe.com/youtube/](http://joincfe.com/youtube/) 13 | 14 | 15 | ### Code History 16 | [Base project setup](../../tree/8be3ff8ffc5fd3922a8e27da156c093065830707) 17 | 18 | [Django Likes](../../tree/6179763b6689e1fcb80ce87e1008a84517a52c41) -------------------------------------------------------------------------------- /media_cdn/2/django_plus_charts_js_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/media_cdn/2/django_plus_charts_js_share.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | appdirs==1.4.2 2 | Django==1.10.6 3 | djangorestframework==3.6.1 4 | django-crispy-forms==1.6.1 5 | olefile==0.44 6 | packaging==16.8 7 | Pillow==4.0.0 8 | pyparsing==2.1.10 9 | six==1.10.0 10 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.6.0 2 | -------------------------------------------------------------------------------- /src/cfelikes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/src/cfelikes/__init__.py -------------------------------------------------------------------------------- /src/cfelikes/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for cfelikes project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.10.6. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.10/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '-3dixy!-cnkpoale2p2oqarzjth$=_5v50uc6&ka8i#$_0^x+y' 24 | 25 | DEBUG = True 26 | 27 | ALLOWED_HOSTS = ['*'] 28 | 29 | 30 | # Application definition 31 | 32 | INSTALLED_APPS = [ 33 | 'django.contrib.admin', 34 | 'django.contrib.auth', 35 | 'django.contrib.contenttypes', 36 | 'django.contrib.sessions', 37 | 'django.contrib.messages', 38 | 'django.contrib.staticfiles', 39 | 'crispy_forms', 40 | 'rest_framework', 41 | 42 | 'posts', 43 | ] 44 | 45 | CRISPY_TEMPLATE_PACK = 'bootstrap3' 46 | 47 | MIDDLEWARE = [ 48 | 'django.middleware.security.SecurityMiddleware', 49 | 'django.contrib.sessions.middleware.SessionMiddleware', 50 | 'django.middleware.common.CommonMiddleware', 51 | 'django.middleware.csrf.CsrfViewMiddleware', 52 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 53 | 'django.contrib.messages.middleware.MessageMiddleware', 54 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 55 | ] 56 | 57 | ROOT_URLCONF = 'cfelikes.urls' 58 | 59 | TEMPLATES = [ 60 | { 61 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 62 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 63 | 'APP_DIRS': True, 64 | 'OPTIONS': { 65 | 'context_processors': [ 66 | 'django.template.context_processors.debug', 67 | 'django.template.context_processors.request', 68 | 'django.contrib.auth.context_processors.auth', 69 | 'django.contrib.messages.context_processors.messages', 70 | ], 71 | }, 72 | }, 73 | ] 74 | 75 | WSGI_APPLICATION = 'cfelikes.wsgi.application' 76 | 77 | 78 | # Database 79 | # https://docs.djangoproject.com/en/1.10/ref/settings/#databases 80 | 81 | DATABASES = { 82 | 'default': { 83 | 'ENGINE': 'django.db.backends.sqlite3', 84 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 85 | } 86 | } 87 | 88 | 89 | # Password validation 90 | # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators 91 | 92 | AUTH_PASSWORD_VALIDATORS = [ 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 101 | }, 102 | { 103 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 104 | }, 105 | ] 106 | 107 | 108 | # Internationalization 109 | # https://docs.djangoproject.com/en/1.10/topics/i18n/ 110 | 111 | LANGUAGE_CODE = 'en-us' 112 | 113 | TIME_ZONE = 'UTC' 114 | 115 | USE_I18N = True 116 | 117 | USE_L10N = True 118 | 119 | USE_TZ = True 120 | 121 | 122 | # Static files (CSS, JavaScript, Images) 123 | # https://docs.djangoproject.com/en/1.10/howto/static-files/ 124 | 125 | STATIC_URL = '/static/' 126 | 127 | STATICFILES_DIRS = [ 128 | os.path.join(BASE_DIR, "static"), 129 | #'/var/www/static/', 130 | ] 131 | 132 | STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn") 133 | 134 | MEDIA_URL = "/media/" 135 | MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "media_cdn") 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /src/cfelikes/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls import include, url 3 | from django.conf.urls.static import static 4 | from django.contrib import admin 5 | 6 | urlpatterns = [ 7 | url(r'^admin/', admin.site.urls), 8 | url(r'^', include("posts.urls", namespace='posts')), 9 | ] 10 | 11 | 12 | if settings.DEBUG: 13 | urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 14 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) -------------------------------------------------------------------------------- /src/cfelikes/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for likes 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/1.10/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", "cfelikes.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /src/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/src/db.sqlite3 -------------------------------------------------------------------------------- /src/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cfelikes.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /src/posts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/src/posts/__init__.py -------------------------------------------------------------------------------- /src/posts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Post 4 | 5 | class PostModelAdmin(admin.ModelAdmin): 6 | list_display = ["title", "updated", "timestamp"] 7 | list_display_links = ["updated"] 8 | list_editable = ["title"] 9 | list_filter = ["updated", "timestamp"] 10 | 11 | search_fields = ["title", "content"] 12 | class Meta: 13 | model = Post 14 | 15 | 16 | admin.site.register(Post, PostModelAdmin) -------------------------------------------------------------------------------- /src/posts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PostsConfig(AppConfig): 5 | name = 'posts' 6 | -------------------------------------------------------------------------------- /src/posts/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from .models import Post 4 | 5 | 6 | class PostForm(forms.ModelForm): 7 | publish = forms.DateField(widget=forms.SelectDateWidget) 8 | class Meta: 9 | model = Post 10 | fields = [ 11 | "title", 12 | "content", 13 | "image", 14 | "draft", 15 | "publish", 16 | ] -------------------------------------------------------------------------------- /src/posts/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.6 on 2017-03-09 21:35 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | import posts.models 9 | 10 | 11 | class Migration(migrations.Migration): 12 | 13 | initial = True 14 | 15 | dependencies = [ 16 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 17 | ] 18 | 19 | operations = [ 20 | migrations.CreateModel( 21 | name='Post', 22 | fields=[ 23 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 24 | ('title', models.CharField(max_length=120)), 25 | ('slug', models.SlugField(unique=True)), 26 | ('image', models.ImageField(blank=True, height_field='height_field', null=True, upload_to=posts.models.upload_location, width_field='width_field')), 27 | ('height_field', models.IntegerField(default=0)), 28 | ('width_field', models.IntegerField(default=0)), 29 | ('content', models.TextField()), 30 | ('draft', models.BooleanField(default=False)), 31 | ('publish', models.DateField()), 32 | ('read_time', models.IntegerField(default=0)), 33 | ('updated', models.DateTimeField(auto_now=True)), 34 | ('timestamp', models.DateTimeField(auto_now_add=True)), 35 | ('user', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 36 | ], 37 | options={ 38 | 'ordering': ['-timestamp', '-updated'], 39 | }, 40 | ), 41 | ] 42 | -------------------------------------------------------------------------------- /src/posts/migrations/0002_auto_20170309_2235.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.6 on 2017-03-09 22:35 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 13 | ('posts', '0001_initial'), 14 | ] 15 | 16 | operations = [ 17 | migrations.AddField( 18 | model_name='post', 19 | name='likes', 20 | field=models.ManyToManyField(blank=True, related_name='post_likes', to=settings.AUTH_USER_MODEL), 21 | ), 22 | migrations.AlterField( 23 | model_name='post', 24 | name='slug', 25 | field=models.SlugField(blank=True, unique=True), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /src/posts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/src/posts/migrations/__init__.py -------------------------------------------------------------------------------- /src/posts/models.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.conf import settings 4 | from django.contrib.contenttypes.models import ContentType 5 | from django.core.urlresolvers import reverse 6 | from django.db import models 7 | from django.db.models.signals import pre_save 8 | from django.utils import timezone 9 | from django.utils.safestring import mark_safe 10 | from django.utils.text import slugify 11 | 12 | from .utils import get_read_time, unique_slug_generator 13 | 14 | class PostManager(models.Manager): 15 | def active(self, *args, **kwargs): 16 | qs = self.get_queryset().filter( 17 | draft=False, 18 | publish__lte=timezone.now() 19 | ) 20 | return qs 21 | 22 | 23 | def upload_location(instance, filename): 24 | PostModel = instance.__class__ 25 | new_id = PostModel.objects.order_by("id").last().id + 1 26 | return "%s/%s" %(new_id, filename) 27 | 28 | class Post(models.Model): 29 | user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1) 30 | title = models.CharField(max_length=120) 31 | slug = models.SlugField(unique=True, blank=True) 32 | image = models.ImageField(upload_to=upload_location, 33 | null=True, 34 | blank=True, 35 | width_field="width_field", 36 | height_field="height_field") 37 | likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='post_likes') 38 | height_field = models.IntegerField(default=0) 39 | width_field = models.IntegerField(default=0) 40 | content = models.TextField() 41 | draft = models.BooleanField(default=False) 42 | publish = models.DateField(auto_now=False, auto_now_add=False) 43 | read_time = models.IntegerField(default=0) 44 | updated = models.DateTimeField(auto_now=True, auto_now_add=False) 45 | timestamp = models.DateTimeField(auto_now=False, auto_now_add=True) 46 | 47 | objects = PostManager() 48 | 49 | def __unicode__(self): 50 | return self.title 51 | 52 | def __str__(self): 53 | return self.title 54 | 55 | def get_absolute_url(self): 56 | return reverse("posts:detail", kwargs={"slug": self.slug}) 57 | 58 | # def get_api_url(self): 59 | # return reverse("posts-api:detail", kwargs={"slug": self.slug}) 60 | 61 | def get_like_url(self): 62 | return reverse("posts:like-toggle", kwargs={"slug": self.slug}) 63 | 64 | def get_api_like_url(self): 65 | return reverse("posts:like-api-toggle", kwargs={"slug": self.slug}) 66 | 67 | class Meta: 68 | ordering = ["-timestamp", "-updated"] 69 | 70 | @property 71 | def get_content_type(self): 72 | instance = self 73 | content_type = ContentType.objects.get_for_model(instance.__class__) 74 | return content_type 75 | 76 | 77 | 78 | def pre_save_post_receiver(sender, instance, *args, **kwargs): 79 | if not instance.slug: 80 | instance.slug = unique_slug_generator(instance) 81 | 82 | if instance.content: 83 | read_time_var = get_read_time(instance.content) 84 | instance.read_time = read_time_var 85 | 86 | 87 | pre_save.connect(pre_save_post_receiver, sender=Post) 88 | -------------------------------------------------------------------------------- /src/posts/templates/posts/post_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load crispy_forms_tags %} 3 | 4 | 5 | {% block head_title %} 6 | {{ instance.title }} | {{ block.super }} 7 | {% endblock head_title %} 8 | 9 | 10 | {% block post_detail_link %} 11 |
  • {{ instance.title }}
  • 12 | {% endblock %} 13 | 14 | 15 | 16 | {% block content %} 17 |
    18 | {% if instance.image %} 19 | 20 | {% endif %} 21 |

    {{ title }} {% if instance.draft %}Draft {% endif %}{{ instance.publish }}

    22 | 23 | 24 | 25 | 26 |

    Read time: {% if instance.read_time <= 1 %} < 1 Minute {% else %}{{ instance.read_time }} minutes {% endif %}

    27 |

    28 | {% if instance.user.get_full_name %} 29 |

    Author: {{ instance.user.get_full_name }}

    30 | {% endif %} 31 | 32 |

    33 |
    34 |

    35 |
    36 |
    37 | 38 |
    39 | {{ instance.content|safe }} 40 |
    41 | 42 |
    43 |
    44 | 45 | 46 | 47 | 48 | 49 |
    50 |
    51 |
    52 | 53 | 54 | {% endblock content %} -------------------------------------------------------------------------------- /src/posts/templates/posts/post_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load crispy_forms_tags %} 3 | 4 | {% block head_extra %} 5 | {{ form.media }} 6 | 7 | {% endblock head_extra %} 8 | 9 | 10 | 11 | {% block content %} 12 |
    13 |

    Preview

    14 |
    15 |
    16 |

    17 |

    18 |
    19 |
    20 |
    21 |

    Form

    22 |
    23 | 24 |
    {% csrf_token %} 25 | {{ form|crispy }} 26 | 27 |
    28 |
    29 | {% endblock content %} -------------------------------------------------------------------------------- /src/posts/templates/posts/post_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 | 5 |
    6 |

    {{ title }}

    7 |
    8 |
    9 |
    10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 | {% for obj in object_list %} 19 |
    20 |
    21 |
    22 | {% if obj.image %} 23 | 24 | {% endif %} 25 |
    26 | {% if obj.draft %}

    Staff only: Draft

    {% endif %} {% if obj.publish > today %}

    Staff Only: Future Post

    {% endif %} 27 |

    {{ obj.title }} {{ obj.publish }}

    28 |

    29 | {% if obj.user.get_full_name %}

    Author: {{ obj.user.get_full_name }}

    {% endif %} 30 | {{ obj.get_markdown|truncatechars_html:120 }} 31 |

    View

    32 |
    33 |
    34 |
    35 |
    36 |
    37 | {% endfor %} 38 | 39 | 40 | 55 | 56 | 57 | 58 | 59 |
    60 | 61 | {% endblock content %} -------------------------------------------------------------------------------- /src/posts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /src/posts/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from django.contrib import admin 3 | 4 | from .views import ( 5 | post_list, 6 | post_create, 7 | post_detail, 8 | post_update, 9 | post_delete, 10 | PostLikeToggle, 11 | PostLikeAPIToggle, 12 | ) 13 | 14 | urlpatterns = [ 15 | url(r'^$', post_list, name='list'), 16 | url(r'^create/$', post_create), 17 | url(r'^(?P[\w-]+)/$', post_detail, name='detail'), 18 | url(r'^(?P[\w-]+)/like/$', PostLikeToggle.as_view(), name='like-toggle'), 19 | url(r'^api/(?P[\w-]+)/like/$', PostLikeAPIToggle.as_view(), name='like-api-toggle'), 20 | url(r'^(?P[\w-]+)/edit/$', post_update, name='update'), 21 | url(r'^(?P[\w-]+)/delete/$', post_delete), 22 | ] -------------------------------------------------------------------------------- /src/posts/utils.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import math 3 | import re 4 | import random 5 | import string 6 | 7 | from django.utils.text import slugify 8 | from django.utils.html import strip_tags 9 | 10 | 11 | def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits): 12 | """ 13 | Source: https://www.codingforentrepreneurs.com/blog/random-string-generator-in-python/ 14 | """ 15 | return ''.join(random.choice(chars) for _ in range(size)) 16 | 17 | 18 | 19 | def unique_slug_generator(instance, new_slug=None): 20 | """ 21 | This is for a Django project and it assumes your instance 22 | has a model with a slug field and a title character (char) field. 23 | Source: https://www.codingforentrepreneurs.com/blog/a-unique-slug-generator-for-django/ 24 | """ 25 | if new_slug is not None: 26 | slug = new_slug 27 | else: 28 | slug = slugify(instance.title) 29 | 30 | Klass = instance.__class__ 31 | qs_exists = Klass.objects.filter(slug=slug).exists() 32 | if qs_exists: 33 | new_slug = "{slug}-{randstr}".format( 34 | slug=slug, 35 | randstr=random_string_generator(size=4) 36 | ) 37 | return unique_slug_generator(instance, new_slug=new_slug) 38 | return slug 39 | 40 | 41 | 42 | def count_words(html_string): 43 | word_string = strip_tags(html_string) 44 | matching_words = re.findall(r'\w+', word_string) 45 | count = len(matching_words) 46 | return count 47 | 48 | 49 | def get_read_time(html_string): 50 | count = count_words(html_string) 51 | read_time_min = math.ceil(count/200.0) #assuming 200wpm reading 52 | return int(read_time_min) -------------------------------------------------------------------------------- /src/posts/views.py: -------------------------------------------------------------------------------- 1 | try: 2 | from urllib import quote_plus #python 2 3 | except: 4 | pass 5 | 6 | try: 7 | from urllib.parse import quote_plus #python 3 8 | except: 9 | pass 10 | 11 | from django.contrib import messages 12 | from django.contrib.contenttypes.models import ContentType 13 | from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 14 | 15 | from django.db.models import Q 16 | from django.http import HttpResponse, HttpResponseRedirect, Http404 17 | from django.shortcuts import render, get_object_or_404, redirect 18 | from django.views.generic import RedirectView 19 | from django.utils import timezone 20 | 21 | from .forms import PostForm 22 | from .models import Post 23 | 24 | 25 | 26 | def post_create(request): 27 | if not request.user.is_staff or not request.user.is_superuser: 28 | raise Http404 29 | 30 | form = PostForm(request.POST or None, request.FILES or None) 31 | if form.is_valid(): 32 | instance = form.save(commit=False) 33 | instance.user = request.user 34 | instance.save() 35 | # message success 36 | messages.success(request, "Successfully Created") 37 | return HttpResponseRedirect(instance.get_absolute_url()) 38 | context = { 39 | "form": form, 40 | } 41 | return render(request, "posts/post_form.html", context) 42 | 43 | 44 | def post_detail(request, slug=None): 45 | instance = get_object_or_404(Post, slug=slug) 46 | if instance.publish > timezone.now().date() or instance.draft: 47 | if not request.user.is_staff or not request.user.is_superuser: 48 | raise Http404 49 | share_string = quote_plus(instance.content) 50 | 51 | initial_data = { 52 | "content_type": instance.get_content_type, 53 | "object_id": instance.id 54 | } 55 | 56 | context = { 57 | "title": instance.title, 58 | "instance": instance, 59 | "share_string": share_string, 60 | } 61 | return render(request, "posts/post_detail.html", context) 62 | 63 | 64 | class PostLikeToggle(RedirectView): 65 | def get_redirect_url(self, *args, **kwargs): 66 | slug = self.kwargs.get("slug") 67 | print(slug) 68 | obj = get_object_or_404(Post, slug=slug) 69 | url_ = obj.get_absolute_url() 70 | user = self.request.user 71 | if user.is_authenticated(): 72 | if user in obj.likes.all(): 73 | obj.likes.remove(user) 74 | else: 75 | obj.likes.add(user) 76 | return url_ 77 | 78 | 79 | from rest_framework.views import APIView 80 | from rest_framework.response import Response 81 | from rest_framework import authentication, permissions 82 | 83 | class PostLikeAPIToggle(APIView): 84 | authentication_classes = (authentication.SessionAuthentication,) 85 | permission_classes = (permissions.IsAuthenticated,) 86 | 87 | def get(self, request, slug=None, format=None): 88 | # slug = self.kwargs.get("slug") 89 | obj = get_object_or_404(Post, slug=slug) 90 | url_ = obj.get_absolute_url() 91 | user = self.request.user 92 | updated = False 93 | liked = False 94 | if user.is_authenticated(): 95 | if user in obj.likes.all(): 96 | liked = False 97 | obj.likes.remove(user) 98 | else: 99 | liked = True 100 | obj.likes.add(user) 101 | updated = True 102 | data = { 103 | "updated": updated, 104 | "liked": liked 105 | } 106 | return Response(data) 107 | 108 | 109 | 110 | def post_list(request): 111 | today = timezone.now().date() 112 | queryset_list = Post.objects.active() #.order_by("-timestamp") 113 | if request.user.is_staff or request.user.is_superuser: 114 | queryset_list = Post.objects.all() 115 | 116 | query = request.GET.get("q") 117 | if query: 118 | queryset_list = queryset_list.filter( 119 | Q(title__icontains=query)| 120 | Q(content__icontains=query)| 121 | Q(user__first_name__icontains=query) | 122 | Q(user__last_name__icontains=query) 123 | ).distinct() 124 | paginator = Paginator(queryset_list, 8) # Show 25 contacts per page 125 | page_request_var = "page" 126 | page = request.GET.get(page_request_var) 127 | try: 128 | queryset = paginator.page(page) 129 | except PageNotAnInteger: 130 | # If page is not an integer, deliver first page. 131 | queryset = paginator.page(1) 132 | except EmptyPage: 133 | # If page is out of range (e.g. 9999), deliver last page of results. 134 | queryset = paginator.page(paginator.num_pages) 135 | 136 | 137 | context = { 138 | "object_list": queryset, 139 | "title": "List", 140 | "page_request_var": page_request_var, 141 | "today": today, 142 | } 143 | return render(request, "posts/post_list.html", context) 144 | 145 | 146 | def post_update(request, slug=None): 147 | if not request.user.is_staff or not request.user.is_superuser: 148 | raise Http404 149 | instance = get_object_or_404(Post, slug=slug) 150 | form = PostForm(request.POST or None, request.FILES or None, instance=instance) 151 | if form.is_valid(): 152 | instance = form.save(commit=False) 153 | instance.save() 154 | messages.success(request, "Item Saved", extra_tags='html_safe') 155 | return HttpResponseRedirect(instance.get_absolute_url()) 156 | 157 | context = { 158 | "title": instance.title, 159 | "instance": instance, 160 | "form":form, 161 | } 162 | return render(request, "posts/post_form.html", context) 163 | 164 | 165 | def post_delete(request, slug=None): 166 | if not request.user.is_staff or not request.user.is_superuser: 167 | raise Http404 168 | instance = get_object_or_404(Post, slug=slug) 169 | instance.delete() 170 | messages.success(request, "Successfully deleted") 171 | return redirect("posts:list") -------------------------------------------------------------------------------- /src/static/css/main.css: -------------------------------------------------------------------------------- 1 | /* For Custom CSS */ -------------------------------------------------------------------------------- /src/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Django Likes 9 | 10 | {% include 'base/css.html' %} 11 | {% include 'base/bootstrap_defaults.html' %} 12 | 13 | 14 |
    15 | {% block content %} 16 | {% endblock content %} 17 |
    18 | {% include 'base/js.html' %} 19 | 20 | 59 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/templates/base/bootstrap_defaults.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/templates/base/css.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/templates/base/js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /static_cdn/admin/css/changelists.css: -------------------------------------------------------------------------------- 1 | /* CHANGELISTS */ 2 | 3 | #changelist { 4 | position: relative; 5 | width: 100%; 6 | } 7 | 8 | #changelist table { 9 | width: 100%; 10 | } 11 | 12 | .change-list .hiddenfields { display:none; } 13 | 14 | .change-list .filtered table { 15 | border-right: none; 16 | } 17 | 18 | .change-list .filtered { 19 | min-height: 400px; 20 | } 21 | 22 | .change-list .filtered .results, .change-list .filtered .paginator, 23 | .filtered #toolbar, .filtered div.xfull { 24 | margin-right: 280px; 25 | width: auto; 26 | } 27 | 28 | .change-list .filtered table tbody th { 29 | padding-right: 1em; 30 | } 31 | 32 | #changelist-form .results { 33 | overflow-x: auto; 34 | } 35 | 36 | #changelist .toplinks { 37 | border-bottom: 1px solid #ddd; 38 | } 39 | 40 | #changelist .paginator { 41 | color: #666; 42 | border-bottom: 1px solid #eee; 43 | background: #fff; 44 | overflow: hidden; 45 | } 46 | 47 | /* CHANGELIST TABLES */ 48 | 49 | #changelist table thead th { 50 | padding: 0; 51 | white-space: nowrap; 52 | vertical-align: middle; 53 | } 54 | 55 | #changelist table thead th.action-checkbox-column { 56 | width: 1.5em; 57 | text-align: center; 58 | } 59 | 60 | #changelist table tbody td.action-checkbox { 61 | text-align: center; 62 | } 63 | 64 | #changelist table tfoot { 65 | color: #666; 66 | } 67 | 68 | /* TOOLBAR */ 69 | 70 | #changelist #toolbar { 71 | padding: 8px 10px; 72 | margin-bottom: 15px; 73 | border-top: 1px solid #eee; 74 | border-bottom: 1px solid #eee; 75 | background: #f8f8f8; 76 | color: #666; 77 | } 78 | 79 | #changelist #toolbar form input { 80 | border-radius: 4px; 81 | font-size: 14px; 82 | padding: 5px; 83 | color: #333; 84 | } 85 | 86 | #changelist #toolbar form #searchbar { 87 | height: 19px; 88 | border: 1px solid #ccc; 89 | padding: 2px 5px; 90 | margin: 0; 91 | vertical-align: top; 92 | font-size: 13px; 93 | } 94 | 95 | #changelist #toolbar form #searchbar:focus { 96 | border-color: #999; 97 | } 98 | 99 | #changelist #toolbar form input[type="submit"] { 100 | border: 1px solid #ccc; 101 | padding: 2px 10px; 102 | margin: 0; 103 | vertical-align: middle; 104 | background: #fff; 105 | box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; 106 | cursor: pointer; 107 | color: #333; 108 | } 109 | 110 | #changelist #toolbar form input[type="submit"]:focus, 111 | #changelist #toolbar form input[type="submit"]:hover { 112 | border-color: #999; 113 | } 114 | 115 | #changelist #changelist-search img { 116 | vertical-align: middle; 117 | margin-right: 4px; 118 | } 119 | 120 | /* FILTER COLUMN */ 121 | 122 | #changelist-filter { 123 | position: absolute; 124 | top: 0; 125 | right: 0; 126 | z-index: 1000; 127 | width: 240px; 128 | background: #f8f8f8; 129 | border-left: none; 130 | margin: 0; 131 | } 132 | 133 | #changelist-filter h2 { 134 | font-size: 14px; 135 | text-transform: uppercase; 136 | letter-spacing: 0.5px; 137 | padding: 5px 15px; 138 | margin-bottom: 12px; 139 | border-bottom: none; 140 | } 141 | 142 | #changelist-filter h3 { 143 | font-weight: 400; 144 | font-size: 14px; 145 | padding: 0 15px; 146 | margin-bottom: 10px; 147 | } 148 | 149 | #changelist-filter ul { 150 | margin: 5px 0; 151 | padding: 0 15px 15px; 152 | border-bottom: 1px solid #eaeaea; 153 | } 154 | 155 | #changelist-filter ul:last-child { 156 | border-bottom: none; 157 | padding-bottom: none; 158 | } 159 | 160 | #changelist-filter li { 161 | list-style-type: none; 162 | margin-left: 0; 163 | padding-left: 0; 164 | } 165 | 166 | #changelist-filter a { 167 | display: block; 168 | color: #999; 169 | } 170 | 171 | #changelist-filter li.selected { 172 | border-left: 5px solid #eaeaea; 173 | padding-left: 10px; 174 | margin-left: -15px; 175 | } 176 | 177 | #changelist-filter li.selected a { 178 | color: #5b80b2; 179 | } 180 | 181 | #changelist-filter a:focus, #changelist-filter a:hover, 182 | #changelist-filter li.selected a:focus, 183 | #changelist-filter li.selected a:hover { 184 | color: #036; 185 | } 186 | 187 | /* DATE DRILLDOWN */ 188 | 189 | .change-list ul.toplinks { 190 | display: block; 191 | float: left; 192 | padding: 0; 193 | margin: 0; 194 | width: 100%; 195 | } 196 | 197 | .change-list ul.toplinks li { 198 | padding: 3px 6px; 199 | font-weight: bold; 200 | list-style-type: none; 201 | display: inline-block; 202 | } 203 | 204 | .change-list ul.toplinks .date-back a { 205 | color: #999; 206 | } 207 | 208 | .change-list ul.toplinks .date-back a:focus, 209 | .change-list ul.toplinks .date-back a:hover { 210 | color: #036; 211 | } 212 | 213 | /* PAGINATOR */ 214 | 215 | .paginator { 216 | font-size: 13px; 217 | padding-top: 10px; 218 | padding-bottom: 10px; 219 | line-height: 22px; 220 | margin: 0; 221 | border-top: 1px solid #ddd; 222 | } 223 | 224 | .paginator a:link, .paginator a:visited { 225 | padding: 2px 6px; 226 | background: #79aec8; 227 | text-decoration: none; 228 | color: #fff; 229 | } 230 | 231 | .paginator a.showall { 232 | padding: 0; 233 | border: none; 234 | background: none; 235 | color: #5b80b2; 236 | } 237 | 238 | .paginator a.showall:focus, .paginator a.showall:hover { 239 | background: none; 240 | color: #036; 241 | } 242 | 243 | .paginator .end { 244 | margin-right: 6px; 245 | } 246 | 247 | .paginator .this-page { 248 | padding: 2px 6px; 249 | font-weight: bold; 250 | font-size: 13px; 251 | vertical-align: top; 252 | } 253 | 254 | .paginator a:focus, .paginator a:hover { 255 | color: white; 256 | background: #036; 257 | } 258 | 259 | /* ACTIONS */ 260 | 261 | .filtered .actions { 262 | margin-right: 280px; 263 | border-right: none; 264 | } 265 | 266 | #changelist table input { 267 | margin: 0; 268 | vertical-align: baseline; 269 | } 270 | 271 | #changelist table tbody tr.selected { 272 | background-color: #FFFFCC; 273 | } 274 | 275 | #changelist .actions { 276 | padding: 10px; 277 | background: #fff; 278 | border-top: none; 279 | border-bottom: none; 280 | line-height: 24px; 281 | color: #999; 282 | } 283 | 284 | #changelist .actions.selected { 285 | background: #fffccf; 286 | border-top: 1px solid #fffee8; 287 | border-bottom: 1px solid #edecd6; 288 | } 289 | 290 | #changelist .actions span.all, 291 | #changelist .actions span.action-counter, 292 | #changelist .actions span.clear, 293 | #changelist .actions span.question { 294 | font-size: 13px; 295 | margin: 0 0.5em; 296 | display: none; 297 | } 298 | 299 | #changelist .actions:last-child { 300 | border-bottom: none; 301 | } 302 | 303 | #changelist .actions select { 304 | vertical-align: top; 305 | height: 24px; 306 | background: none; 307 | color: #000; 308 | border: 1px solid #ccc; 309 | border-radius: 4px; 310 | font-size: 14px; 311 | padding: 0 0 0 4px; 312 | margin: 0; 313 | margin-left: 10px; 314 | } 315 | 316 | #changelist .actions select:focus { 317 | border-color: #999; 318 | } 319 | 320 | #changelist .actions label { 321 | display: inline-block; 322 | vertical-align: middle; 323 | font-size: 13px; 324 | } 325 | 326 | #changelist .actions .button { 327 | font-size: 13px; 328 | border: 1px solid #ccc; 329 | border-radius: 4px; 330 | background: #fff; 331 | box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; 332 | cursor: pointer; 333 | height: 24px; 334 | line-height: 1; 335 | padding: 4px 8px; 336 | margin: 0; 337 | color: #333; 338 | } 339 | 340 | #changelist .actions .button:focus, #changelist .actions .button:hover { 341 | border-color: #999; 342 | } 343 | -------------------------------------------------------------------------------- /static_cdn/admin/css/dashboard.css: -------------------------------------------------------------------------------- 1 | /* DASHBOARD */ 2 | 3 | .dashboard .module table th { 4 | width: 100%; 5 | } 6 | 7 | .dashboard .module table td { 8 | white-space: nowrap; 9 | } 10 | 11 | .dashboard .module table td a { 12 | display: block; 13 | padding-right: .6em; 14 | } 15 | 16 | /* RECENT ACTIONS MODULE */ 17 | 18 | .module ul.actionlist { 19 | margin-left: 0; 20 | } 21 | 22 | ul.actionlist li { 23 | list-style-type: none; 24 | } 25 | 26 | ul.actionlist li { 27 | overflow: hidden; 28 | text-overflow: ellipsis; 29 | -o-text-overflow: ellipsis; 30 | } 31 | -------------------------------------------------------------------------------- /static_cdn/admin/css/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Roboto'; 3 | src: url('../fonts/Roboto-Bold-webfont.woff'); 4 | font-weight: 700; 5 | font-style: normal; 6 | } 7 | 8 | @font-face { 9 | font-family: 'Roboto'; 10 | src: url('../fonts/Roboto-Regular-webfont.woff'); 11 | font-weight: 400; 12 | font-style: normal; 13 | } 14 | 15 | @font-face { 16 | font-family: 'Roboto'; 17 | src: url('../fonts/Roboto-Light-webfont.woff'); 18 | font-weight: 300; 19 | font-style: normal; 20 | } 21 | -------------------------------------------------------------------------------- /static_cdn/admin/css/forms.css: -------------------------------------------------------------------------------- 1 | @import url('widgets.css'); 2 | 3 | /* FORM ROWS */ 4 | 5 | .form-row { 6 | overflow: hidden; 7 | padding: 10px; 8 | font-size: 13px; 9 | border-bottom: 1px solid #eee; 10 | } 11 | 12 | .form-row img, .form-row input { 13 | vertical-align: middle; 14 | } 15 | 16 | .form-row label input[type="checkbox"] { 17 | margin-top: 0; 18 | vertical-align: 0; 19 | } 20 | 21 | form .form-row p { 22 | padding-left: 0; 23 | } 24 | 25 | .hidden { 26 | display: none; 27 | } 28 | 29 | /* FORM LABELS */ 30 | 31 | label { 32 | font-weight: normal; 33 | color: #666; 34 | font-size: 13px; 35 | } 36 | 37 | .required label, label.required { 38 | font-weight: bold; 39 | color: #333; 40 | } 41 | 42 | /* RADIO BUTTONS */ 43 | 44 | form ul.radiolist li { 45 | list-style-type: none; 46 | } 47 | 48 | form ul.radiolist label { 49 | float: none; 50 | display: inline; 51 | } 52 | 53 | form ul.radiolist input[type="radio"] { 54 | margin: -2px 4px 0 0; 55 | padding: 0; 56 | } 57 | 58 | form ul.inline { 59 | margin-left: 0; 60 | padding: 0; 61 | } 62 | 63 | form ul.inline li { 64 | float: left; 65 | padding-right: 7px; 66 | } 67 | 68 | /* ALIGNED FIELDSETS */ 69 | 70 | .aligned label { 71 | display: block; 72 | padding: 4px 10px 0 0; 73 | float: left; 74 | width: 160px; 75 | word-wrap: break-word; 76 | line-height: 1; 77 | } 78 | 79 | .aligned label:not(.vCheckboxLabel):after { 80 | content: ''; 81 | display: inline-block; 82 | vertical-align: middle; 83 | height: 26px; 84 | } 85 | 86 | .aligned label + p { 87 | padding: 6px 0; 88 | margin-top: 0; 89 | margin-bottom: 0; 90 | margin-left: 170px; 91 | } 92 | 93 | .aligned ul label { 94 | display: inline; 95 | float: none; 96 | width: auto; 97 | } 98 | 99 | .aligned .form-row input { 100 | margin-bottom: 0; 101 | } 102 | 103 | .colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField { 104 | width: 350px; 105 | } 106 | 107 | form .aligned ul { 108 | margin-left: 160px; 109 | padding-left: 10px; 110 | } 111 | 112 | form .aligned ul.radiolist { 113 | display: inline-block; 114 | margin: 0; 115 | padding: 0; 116 | } 117 | 118 | form .aligned p.help { 119 | clear: left; 120 | margin-top: 0; 121 | margin-left: 160px; 122 | padding-left: 10px; 123 | } 124 | 125 | form .aligned label + p.help { 126 | margin-left: 0; 127 | padding-left: 0; 128 | } 129 | 130 | form .aligned p.help:last-child { 131 | margin-bottom: 0; 132 | padding-bottom: 0; 133 | } 134 | 135 | form .aligned input + p.help, 136 | form .aligned textarea + p.help, 137 | form .aligned select + p.help { 138 | margin-left: 160px; 139 | padding-left: 10px; 140 | } 141 | 142 | form .aligned ul li { 143 | list-style: none; 144 | } 145 | 146 | form .aligned table p { 147 | margin-left: 0; 148 | padding-left: 0; 149 | } 150 | 151 | .aligned .vCheckboxLabel { 152 | float: none; 153 | width: auto; 154 | display: inline-block; 155 | vertical-align: -3px; 156 | padding: 0 0 5px 5px; 157 | } 158 | 159 | .aligned .vCheckboxLabel + p.help { 160 | margin-top: -4px; 161 | } 162 | 163 | .colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField { 164 | width: 610px; 165 | } 166 | 167 | .checkbox-row p.help { 168 | margin-left: 0; 169 | padding-left: 0; 170 | } 171 | 172 | fieldset .field-box { 173 | float: left; 174 | margin-right: 20px; 175 | } 176 | 177 | /* WIDE FIELDSETS */ 178 | 179 | .wide label { 180 | width: 200px; 181 | } 182 | 183 | form .wide p, form .wide input + p.help { 184 | margin-left: 200px; 185 | } 186 | 187 | form .wide p.help { 188 | padding-left: 38px; 189 | } 190 | 191 | .colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField { 192 | width: 450px; 193 | } 194 | 195 | /* COLLAPSED FIELDSETS */ 196 | 197 | fieldset.collapsed * { 198 | display: none; 199 | } 200 | 201 | fieldset.collapsed h2, fieldset.collapsed { 202 | display: block; 203 | } 204 | 205 | fieldset.collapsed { 206 | border: 1px solid #eee; 207 | border-radius: 4px; 208 | overflow: hidden; 209 | } 210 | 211 | fieldset.collapsed h2 { 212 | background: #f8f8f8; 213 | color: #666; 214 | } 215 | 216 | fieldset .collapse-toggle { 217 | color: #fff; 218 | } 219 | 220 | fieldset.collapsed .collapse-toggle { 221 | background: transparent; 222 | display: inline; 223 | color: #447e9b; 224 | } 225 | 226 | /* MONOSPACE TEXTAREAS */ 227 | 228 | fieldset.monospace textarea { 229 | font-family: "Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace; 230 | } 231 | 232 | /* SUBMIT ROW */ 233 | 234 | .submit-row { 235 | padding: 12px 14px; 236 | margin: 0 0 20px; 237 | background: #f8f8f8; 238 | border: 1px solid #eee; 239 | border-radius: 4px; 240 | text-align: right; 241 | overflow: hidden; 242 | } 243 | 244 | body.popup .submit-row { 245 | overflow: auto; 246 | } 247 | 248 | .submit-row input { 249 | height: 35px; 250 | line-height: 15px; 251 | margin: 0 0 0 5px; 252 | } 253 | 254 | .submit-row input.default { 255 | margin: 0 0 0 8px; 256 | text-transform: uppercase; 257 | } 258 | 259 | .submit-row p { 260 | margin: 0.3em; 261 | } 262 | 263 | .submit-row p.deletelink-box { 264 | float: left; 265 | margin: 0; 266 | } 267 | 268 | .submit-row a.deletelink { 269 | display: block; 270 | background: #ba2121; 271 | border-radius: 4px; 272 | padding: 10px 15px; 273 | height: 15px; 274 | line-height: 15px; 275 | color: #fff; 276 | } 277 | 278 | .submit-row a.deletelink:focus, 279 | .submit-row a.deletelink:hover, 280 | .submit-row a.deletelink:active { 281 | background: #a41515; 282 | } 283 | 284 | /* CUSTOM FORM FIELDS */ 285 | 286 | .vSelectMultipleField { 287 | vertical-align: top; 288 | } 289 | 290 | .vCheckboxField { 291 | border: none; 292 | } 293 | 294 | .vDateField, .vTimeField { 295 | margin-right: 2px; 296 | margin-bottom: 4px; 297 | } 298 | 299 | .vDateField { 300 | min-width: 6.85em; 301 | } 302 | 303 | .vTimeField { 304 | min-width: 4.7em; 305 | } 306 | 307 | .vURLField { 308 | width: 30em; 309 | } 310 | 311 | .vLargeTextField, .vXMLLargeTextField { 312 | width: 48em; 313 | } 314 | 315 | .flatpages-flatpage #id_content { 316 | height: 40.2em; 317 | } 318 | 319 | .module table .vPositiveSmallIntegerField { 320 | width: 2.2em; 321 | } 322 | 323 | .vTextField { 324 | width: 20em; 325 | } 326 | 327 | .vIntegerField { 328 | width: 5em; 329 | } 330 | 331 | .vBigIntegerField { 332 | width: 10em; 333 | } 334 | 335 | .vForeignKeyRawIdAdminField { 336 | width: 5em; 337 | } 338 | 339 | /* INLINES */ 340 | 341 | .inline-group { 342 | padding: 0; 343 | margin: 0 0 30px; 344 | } 345 | 346 | .inline-group thead th { 347 | padding: 8px 10px; 348 | } 349 | 350 | .inline-group .aligned label { 351 | width: 160px; 352 | } 353 | 354 | .inline-related { 355 | position: relative; 356 | } 357 | 358 | .inline-related h3 { 359 | margin: 0; 360 | color: #666; 361 | padding: 5px; 362 | font-size: 13px; 363 | background: #f8f8f8; 364 | border-top: 1px solid #eee; 365 | border-bottom: 1px solid #eee; 366 | } 367 | 368 | .inline-related h3 span.delete { 369 | float: right; 370 | } 371 | 372 | .inline-related h3 span.delete label { 373 | margin-left: 2px; 374 | font-size: 11px; 375 | } 376 | 377 | .inline-related fieldset { 378 | margin: 0; 379 | background: #fff; 380 | border: none; 381 | width: 100%; 382 | } 383 | 384 | .inline-related fieldset.module h3 { 385 | margin: 0; 386 | padding: 2px 5px 3px 5px; 387 | font-size: 11px; 388 | text-align: left; 389 | font-weight: bold; 390 | background: #bcd; 391 | color: #fff; 392 | } 393 | 394 | .inline-group .tabular fieldset.module { 395 | border: none; 396 | } 397 | 398 | .inline-related.tabular fieldset.module table { 399 | width: 100%; 400 | } 401 | 402 | .last-related fieldset { 403 | border: none; 404 | } 405 | 406 | .inline-group .tabular tr.has_original td { 407 | padding-top: 2em; 408 | } 409 | 410 | .inline-group .tabular tr td.original { 411 | padding: 2px 0 0 0; 412 | width: 0; 413 | _position: relative; 414 | } 415 | 416 | .inline-group .tabular th.original { 417 | width: 0px; 418 | padding: 0; 419 | } 420 | 421 | .inline-group .tabular td.original p { 422 | position: absolute; 423 | left: 0; 424 | height: 1.1em; 425 | padding: 2px 9px; 426 | overflow: hidden; 427 | font-size: 9px; 428 | font-weight: bold; 429 | color: #666; 430 | _width: 700px; 431 | } 432 | 433 | .inline-group ul.tools { 434 | padding: 0; 435 | margin: 0; 436 | list-style: none; 437 | } 438 | 439 | .inline-group ul.tools li { 440 | display: inline; 441 | padding: 0 5px; 442 | } 443 | 444 | .inline-group div.add-row, 445 | .inline-group .tabular tr.add-row td { 446 | color: #666; 447 | background: #f8f8f8; 448 | padding: 8px 10px; 449 | border-bottom: 1px solid #eee; 450 | } 451 | 452 | .inline-group .tabular tr.add-row td { 453 | padding: 8px 10px; 454 | border-bottom: 1px solid #eee; 455 | } 456 | 457 | .inline-group ul.tools a.add, 458 | .inline-group div.add-row a, 459 | .inline-group .tabular tr.add-row td a { 460 | background: url(../img/icon-addlink.svg) 0 1px no-repeat; 461 | padding-left: 16px; 462 | font-size: 12px; 463 | } 464 | 465 | .empty-form { 466 | display: none; 467 | } 468 | 469 | /* RELATED FIELD ADD ONE / LOOKUP */ 470 | 471 | .add-another, .related-lookup { 472 | margin-left: 5px; 473 | display: inline-block; 474 | vertical-align: middle; 475 | background-repeat: no-repeat; 476 | background-size: 14px; 477 | } 478 | 479 | .add-another { 480 | width: 16px; 481 | height: 16px; 482 | background-image: url(../img/icon-addlink.svg); 483 | } 484 | 485 | .related-lookup { 486 | width: 16px; 487 | height: 16px; 488 | background-image: url(../img/search.svg); 489 | } 490 | 491 | form .related-widget-wrapper ul { 492 | display: inline-block; 493 | margin-left: 0; 494 | padding-left: 0; 495 | } 496 | 497 | .clearable-file-input input { 498 | margin-top: 0; 499 | } 500 | -------------------------------------------------------------------------------- /static_cdn/admin/css/login.css: -------------------------------------------------------------------------------- 1 | /* LOGIN FORM */ 2 | 3 | body.login { 4 | background: #f8f8f8; 5 | } 6 | 7 | .login #header { 8 | height: auto; 9 | padding: 5px 16px; 10 | } 11 | 12 | .login #header h1 { 13 | font-size: 18px; 14 | } 15 | 16 | .login #header h1 a { 17 | color: #fff; 18 | } 19 | 20 | .login #content { 21 | padding: 20px 20px 0; 22 | } 23 | 24 | .login #container { 25 | background: #fff; 26 | border: 1px solid #eaeaea; 27 | border-radius: 4px; 28 | overflow: hidden; 29 | width: 28em; 30 | min-width: 300px; 31 | margin: 100px auto; 32 | } 33 | 34 | .login #content-main { 35 | width: 100%; 36 | } 37 | 38 | .login .form-row { 39 | padding: 4px 0; 40 | float: left; 41 | width: 100%; 42 | border-bottom: none; 43 | } 44 | 45 | .login .form-row label { 46 | padding-right: 0.5em; 47 | line-height: 2em; 48 | font-size: 1em; 49 | clear: both; 50 | color: #333; 51 | } 52 | 53 | .login .form-row #id_username, .login .form-row #id_password { 54 | clear: both; 55 | padding: 8px; 56 | width: 100%; 57 | -webkit-box-sizing: border-box; 58 | -moz-box-sizing: border-box; 59 | box-sizing: border-box; 60 | } 61 | 62 | .login span.help { 63 | font-size: 10px; 64 | display: block; 65 | } 66 | 67 | .login .submit-row { 68 | clear: both; 69 | padding: 1em 0 0 9.4em; 70 | margin: 0; 71 | border: none; 72 | background: none; 73 | text-align: left; 74 | } 75 | 76 | .login .password-reset-link { 77 | text-align: center; 78 | } 79 | -------------------------------------------------------------------------------- /static_cdn/admin/css/rtl.css: -------------------------------------------------------------------------------- 1 | body { 2 | direction: rtl; 3 | } 4 | 5 | /* LOGIN */ 6 | 7 | .login .form-row { 8 | float: right; 9 | } 10 | 11 | .login .form-row label { 12 | float: right; 13 | padding-left: 0.5em; 14 | padding-right: 0; 15 | text-align: left; 16 | } 17 | 18 | .login .submit-row { 19 | clear: both; 20 | padding: 1em 9.4em 0 0; 21 | } 22 | 23 | /* GLOBAL */ 24 | 25 | th { 26 | text-align: right; 27 | } 28 | 29 | .module h2, .module caption { 30 | text-align: right; 31 | } 32 | 33 | .module ul, .module ol { 34 | margin-left: 0; 35 | margin-right: 1.5em; 36 | } 37 | 38 | .addlink, .changelink { 39 | padding-left: 0; 40 | padding-right: 16px; 41 | background-position: 100% 1px; 42 | } 43 | 44 | .deletelink { 45 | padding-left: 0; 46 | padding-right: 16px; 47 | background-position: 100% 1px; 48 | } 49 | 50 | .object-tools { 51 | float: left; 52 | } 53 | 54 | thead th:first-child, 55 | tfoot td:first-child { 56 | border-left: none; 57 | } 58 | 59 | /* LAYOUT */ 60 | 61 | #user-tools { 62 | right: auto; 63 | left: 0; 64 | text-align: left; 65 | } 66 | 67 | div.breadcrumbs { 68 | text-align: right; 69 | } 70 | 71 | #content-main { 72 | float: right; 73 | } 74 | 75 | #content-related { 76 | float: left; 77 | margin-left: -300px; 78 | margin-right: auto; 79 | } 80 | 81 | .colMS { 82 | margin-left: 300px; 83 | margin-right: 0; 84 | } 85 | 86 | /* SORTABLE TABLES */ 87 | 88 | table thead th.sorted .sortoptions { 89 | float: left; 90 | } 91 | 92 | thead th.sorted .text { 93 | padding-right: 0; 94 | padding-left: 42px; 95 | } 96 | 97 | /* dashboard styles */ 98 | 99 | .dashboard .module table td a { 100 | padding-left: .6em; 101 | padding-right: 16px; 102 | } 103 | 104 | /* changelists styles */ 105 | 106 | .change-list .filtered table { 107 | border-left: none; 108 | border-right: 0px none; 109 | } 110 | 111 | #changelist-filter { 112 | right: auto; 113 | left: 0; 114 | border-left: none; 115 | border-right: none; 116 | } 117 | 118 | .change-list .filtered .results, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { 119 | margin-right: 0; 120 | margin-left: 280px; 121 | } 122 | 123 | #changelist-filter li.selected { 124 | border-left: none; 125 | padding-left: 10px; 126 | margin-left: 0; 127 | border-right: 5px solid #eaeaea; 128 | padding-right: 10px; 129 | margin-right: -15px; 130 | } 131 | 132 | .filtered .actions { 133 | margin-left: 280px; 134 | margin-right: 0; 135 | } 136 | 137 | #changelist table tbody td:first-child, #changelist table tbody th:first-child { 138 | border-right: none; 139 | border-left: none; 140 | } 141 | 142 | /* FORMS */ 143 | 144 | .aligned label { 145 | padding: 0 0 3px 1em; 146 | float: right; 147 | } 148 | 149 | .submit-row { 150 | text-align: left 151 | } 152 | 153 | .submit-row p.deletelink-box { 154 | float: right; 155 | } 156 | 157 | .submit-row input.default { 158 | margin-left: 0; 159 | } 160 | 161 | .vDateField, .vTimeField { 162 | margin-left: 2px; 163 | } 164 | 165 | .aligned .form-row input { 166 | margin-left: 5px; 167 | } 168 | 169 | form ul.inline li { 170 | float: right; 171 | padding-right: 0; 172 | padding-left: 7px; 173 | } 174 | 175 | input[type=submit].default, .submit-row input.default { 176 | float: left; 177 | } 178 | 179 | fieldset .field-box { 180 | float: right; 181 | margin-left: 20px; 182 | margin-right: 0; 183 | } 184 | 185 | .errorlist li { 186 | background-position: 100% 12px; 187 | padding: 0; 188 | } 189 | 190 | .errornote { 191 | background-position: 100% 12px; 192 | padding: 10px 12px; 193 | } 194 | 195 | /* WIDGETS */ 196 | 197 | .calendarnav-previous { 198 | top: 0; 199 | left: auto; 200 | right: 10px; 201 | } 202 | 203 | .calendarnav-next { 204 | top: 0; 205 | right: auto; 206 | left: 10px; 207 | } 208 | 209 | .calendar caption, .calendarbox h2 { 210 | text-align: center; 211 | } 212 | 213 | .selector { 214 | float: right; 215 | } 216 | 217 | .selector .selector-filter { 218 | text-align: right; 219 | } 220 | 221 | .inline-deletelink { 222 | float: left; 223 | } 224 | 225 | form .form-row p.datetime { 226 | overflow: hidden; 227 | } 228 | 229 | /* MISC */ 230 | 231 | .inline-related h2, .inline-group h2 { 232 | text-align: right 233 | } 234 | 235 | .inline-related h3 span.delete { 236 | padding-right: 20px; 237 | padding-left: inherit; 238 | left: 10px; 239 | right: inherit; 240 | float:left; 241 | } 242 | 243 | .inline-related h3 span.delete label { 244 | margin-left: inherit; 245 | margin-right: 2px; 246 | } 247 | 248 | /* IE7 specific bug fixes */ 249 | 250 | div.colM { 251 | position: relative; 252 | } 253 | 254 | .submit-row input { 255 | float: left; 256 | } 257 | -------------------------------------------------------------------------------- /static_cdn/admin/css/widgets.css: -------------------------------------------------------------------------------- 1 | /* SELECTOR (FILTER INTERFACE) */ 2 | 3 | .selector { 4 | width: 800px; 5 | float: left; 6 | } 7 | 8 | .selector select { 9 | width: 380px; 10 | height: 17.2em; 11 | } 12 | 13 | .selector-available, .selector-chosen { 14 | float: left; 15 | width: 380px; 16 | text-align: center; 17 | margin-bottom: 5px; 18 | } 19 | 20 | .selector-chosen select { 21 | border-top: none; 22 | } 23 | 24 | .selector-available h2, .selector-chosen h2 { 25 | border: 1px solid #ccc; 26 | border-radius: 4px 4px 0 0; 27 | } 28 | 29 | .selector-chosen h2 { 30 | background: #79aec8; 31 | color: #fff; 32 | } 33 | 34 | .selector .selector-available h2 { 35 | background: #f8f8f8; 36 | color: #666; 37 | } 38 | 39 | .selector .selector-filter { 40 | background: white; 41 | border: 1px solid #ccc; 42 | border-width: 0 1px; 43 | padding: 8px; 44 | color: #999; 45 | font-size: 10px; 46 | margin: 0; 47 | text-align: left; 48 | } 49 | 50 | .selector .selector-filter label, 51 | .inline-group .aligned .selector .selector-filter label { 52 | float: left; 53 | margin: 7px 0 0; 54 | width: 18px; 55 | height: 18px; 56 | padding: 0; 57 | overflow: hidden; 58 | line-height: 1; 59 | } 60 | 61 | .selector .selector-available input { 62 | width: 320px; 63 | margin-left: 8px; 64 | } 65 | 66 | .selector ul.selector-chooser { 67 | float: left; 68 | width: 22px; 69 | background-color: #eee; 70 | border-radius: 10px; 71 | margin: 10em 5px 0 5px; 72 | padding: 0; 73 | } 74 | 75 | .selector-chooser li { 76 | margin: 0; 77 | padding: 3px; 78 | list-style-type: none; 79 | } 80 | 81 | .selector select { 82 | padding: 0 10px; 83 | margin: 0 0 10px; 84 | border-radius: 0 0 4px 4px; 85 | } 86 | 87 | .selector-add, .selector-remove { 88 | width: 16px; 89 | height: 16px; 90 | display: block; 91 | text-indent: -3000px; 92 | overflow: hidden; 93 | cursor: default; 94 | opacity: 0.3; 95 | } 96 | 97 | .active.selector-add, .active.selector-remove { 98 | opacity: 1; 99 | } 100 | 101 | .active.selector-add:hover, .active.selector-remove:hover { 102 | cursor: pointer; 103 | } 104 | 105 | .selector-add { 106 | background: url(../img/selector-icons.svg) 0 -96px no-repeat; 107 | } 108 | 109 | .active.selector-add:focus, .active.selector-add:hover { 110 | background-position: 0 -112px; 111 | } 112 | 113 | .selector-remove { 114 | background: url(../img/selector-icons.svg) 0 -64px no-repeat; 115 | } 116 | 117 | .active.selector-remove:focus, .active.selector-remove:hover { 118 | background-position: 0 -80px; 119 | } 120 | 121 | a.selector-chooseall, a.selector-clearall { 122 | display: inline-block; 123 | height: 16px; 124 | text-align: left; 125 | margin: 1px auto 3px; 126 | overflow: hidden; 127 | font-weight: bold; 128 | line-height: 16px; 129 | color: #666; 130 | text-decoration: none; 131 | opacity: 0.3; 132 | } 133 | 134 | a.active.selector-chooseall:focus, a.active.selector-clearall:focus, 135 | a.active.selector-chooseall:hover, a.active.selector-clearall:hover { 136 | color: #447e9b; 137 | } 138 | 139 | a.active.selector-chooseall, a.active.selector-clearall { 140 | opacity: 1; 141 | } 142 | 143 | a.active.selector-chooseall:hover, a.active.selector-clearall:hover { 144 | cursor: pointer; 145 | } 146 | 147 | a.selector-chooseall { 148 | padding: 0 18px 0 0; 149 | background: url(../img/selector-icons.svg) right -160px no-repeat; 150 | cursor: default; 151 | } 152 | 153 | a.active.selector-chooseall:focus, a.active.selector-chooseall:hover { 154 | background-position: 100% -176px; 155 | } 156 | 157 | a.selector-clearall { 158 | padding: 0 0 0 18px; 159 | background: url(../img/selector-icons.svg) 0 -128px no-repeat; 160 | cursor: default; 161 | } 162 | 163 | a.active.selector-clearall:focus, a.active.selector-clearall:hover { 164 | background-position: 0 -144px; 165 | } 166 | 167 | /* STACKED SELECTORS */ 168 | 169 | .stacked { 170 | float: left; 171 | width: 490px; 172 | } 173 | 174 | .stacked select { 175 | width: 480px; 176 | height: 10.1em; 177 | } 178 | 179 | .stacked .selector-available, .stacked .selector-chosen { 180 | width: 480px; 181 | } 182 | 183 | .stacked .selector-available { 184 | margin-bottom: 0; 185 | } 186 | 187 | .stacked .selector-available input { 188 | width: 422px; 189 | } 190 | 191 | .stacked ul.selector-chooser { 192 | height: 22px; 193 | width: 50px; 194 | margin: 0 0 10px 40%; 195 | background-color: #eee; 196 | border-radius: 10px; 197 | } 198 | 199 | .stacked .selector-chooser li { 200 | float: left; 201 | padding: 3px 3px 3px 5px; 202 | } 203 | 204 | .stacked .selector-chooseall, .stacked .selector-clearall { 205 | display: none; 206 | } 207 | 208 | .stacked .selector-add { 209 | background: url(../img/selector-icons.svg) 0 -32px no-repeat; 210 | cursor: default; 211 | } 212 | 213 | .stacked .active.selector-add { 214 | background-position: 0 -48px; 215 | cursor: pointer; 216 | } 217 | 218 | .stacked .selector-remove { 219 | background: url(../img/selector-icons.svg) 0 0 no-repeat; 220 | cursor: default; 221 | } 222 | 223 | .stacked .active.selector-remove { 224 | background-position: 0 -16px; 225 | cursor: pointer; 226 | } 227 | 228 | .selector .help-icon { 229 | background: url(../img/icon-unknown.svg) 0 0 no-repeat; 230 | display: inline-block; 231 | vertical-align: middle; 232 | margin: -2px 0 0 2px; 233 | width: 13px; 234 | height: 13px; 235 | } 236 | 237 | .selector .selector-chosen .help-icon { 238 | background: url(../img/icon-unknown-alt.svg) 0 0 no-repeat; 239 | } 240 | 241 | .selector .search-label-icon { 242 | background: url(../img/search.svg) 0 0 no-repeat; 243 | display: inline-block; 244 | height: 18px; 245 | width: 18px; 246 | } 247 | 248 | /* DATE AND TIME */ 249 | 250 | p.datetime { 251 | line-height: 20px; 252 | margin: 0; 253 | padding: 0; 254 | color: #666; 255 | font-weight: bold; 256 | } 257 | 258 | .datetime span { 259 | white-space: nowrap; 260 | font-weight: normal; 261 | font-size: 11px; 262 | color: #ccc; 263 | } 264 | 265 | .datetime input, .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField { 266 | min-width: 0; 267 | margin-left: 5px; 268 | margin-bottom: 4px; 269 | } 270 | 271 | table p.datetime { 272 | font-size: 11px; 273 | margin-left: 0; 274 | padding-left: 0; 275 | } 276 | 277 | .datetimeshortcuts .clock-icon, .datetimeshortcuts .date-icon { 278 | position: relative; 279 | display: inline-block; 280 | vertical-align: middle; 281 | height: 16px; 282 | width: 16px; 283 | overflow: hidden; 284 | } 285 | 286 | .datetimeshortcuts .clock-icon { 287 | background: url(../img/icon-clock.svg) 0 0 no-repeat; 288 | } 289 | 290 | .datetimeshortcuts a:focus .clock-icon, 291 | .datetimeshortcuts a:hover .clock-icon { 292 | background-position: 0 -16px; 293 | } 294 | 295 | .datetimeshortcuts .date-icon { 296 | background: url(../img/icon-calendar.svg) 0 0 no-repeat; 297 | top: -1px; 298 | } 299 | 300 | .datetimeshortcuts a:focus .date-icon, 301 | .datetimeshortcuts a:hover .date-icon { 302 | background-position: 0 -16px; 303 | } 304 | 305 | .timezonewarning { 306 | font-size: 11px; 307 | color: #999; 308 | } 309 | 310 | /* URL */ 311 | 312 | p.url { 313 | line-height: 20px; 314 | margin: 0; 315 | padding: 0; 316 | color: #666; 317 | font-size: 11px; 318 | font-weight: bold; 319 | } 320 | 321 | .url a { 322 | font-weight: normal; 323 | } 324 | 325 | /* FILE UPLOADS */ 326 | 327 | p.file-upload { 328 | line-height: 20px; 329 | margin: 0; 330 | padding: 0; 331 | color: #666; 332 | font-size: 11px; 333 | font-weight: bold; 334 | } 335 | 336 | .aligned p.file-upload { 337 | margin-left: 170px; 338 | } 339 | 340 | .file-upload a { 341 | font-weight: normal; 342 | } 343 | 344 | .file-upload .deletelink { 345 | margin-left: 5px; 346 | } 347 | 348 | span.clearable-file-input label { 349 | color: #333; 350 | font-size: 11px; 351 | display: inline; 352 | float: none; 353 | } 354 | 355 | /* CALENDARS & CLOCKS */ 356 | 357 | .calendarbox, .clockbox { 358 | margin: 5px auto; 359 | font-size: 12px; 360 | width: 19em; 361 | text-align: center; 362 | background: white; 363 | border: 1px solid #ddd; 364 | border-radius: 4px; 365 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); 366 | overflow: hidden; 367 | position: relative; 368 | } 369 | 370 | .clockbox { 371 | width: auto; 372 | } 373 | 374 | .calendar { 375 | margin: 0; 376 | padding: 0; 377 | } 378 | 379 | .calendar table { 380 | margin: 0; 381 | padding: 0; 382 | border-collapse: collapse; 383 | background: white; 384 | width: 100%; 385 | } 386 | 387 | .calendar caption, .calendarbox h2 { 388 | margin: 0; 389 | text-align: center; 390 | border-top: none; 391 | background: #f5dd5d; 392 | font-weight: 700; 393 | font-size: 12px; 394 | color: #333; 395 | } 396 | 397 | .calendar th { 398 | padding: 8px 5px; 399 | background: #f8f8f8; 400 | border-bottom: 1px solid #ddd; 401 | font-weight: 400; 402 | font-size: 12px; 403 | text-align: center; 404 | color: #666; 405 | } 406 | 407 | .calendar td { 408 | font-weight: 400; 409 | font-size: 12px; 410 | text-align: center; 411 | padding: 0; 412 | border-top: 1px solid #eee; 413 | border-bottom: none; 414 | } 415 | 416 | .calendar td.selected a { 417 | background: #79aec8; 418 | color: #fff; 419 | } 420 | 421 | .calendar td.nonday { 422 | background: #f8f8f8; 423 | } 424 | 425 | .calendar td.today a { 426 | font-weight: 700; 427 | } 428 | 429 | .calendar td a, .timelist a { 430 | display: block; 431 | font-weight: 400; 432 | padding: 6px; 433 | text-decoration: none; 434 | color: #444; 435 | } 436 | 437 | .calendar td a:focus, .timelist a:focus, 438 | .calendar td a:hover, .timelist a:hover { 439 | background: #79aec8; 440 | color: white; 441 | } 442 | 443 | .calendar td a:active, .timelist a:active { 444 | background: #417690; 445 | color: white; 446 | } 447 | 448 | .calendarnav { 449 | font-size: 10px; 450 | text-align: center; 451 | color: #ccc; 452 | margin: 0; 453 | padding: 1px 3px; 454 | } 455 | 456 | .calendarnav a:link, #calendarnav a:visited, 457 | #calendarnav a:focus, #calendarnav a:hover { 458 | color: #999; 459 | } 460 | 461 | .calendar-shortcuts { 462 | background: white; 463 | font-size: 11px; 464 | line-height: 11px; 465 | border-top: 1px solid #eee; 466 | padding: 8px 0; 467 | color: #ccc; 468 | } 469 | 470 | .calendarbox .calendarnav-previous, .calendarbox .calendarnav-next { 471 | display: block; 472 | position: absolute; 473 | top: 8px; 474 | width: 15px; 475 | height: 15px; 476 | text-indent: -9999px; 477 | padding: 0; 478 | } 479 | 480 | .calendarnav-previous { 481 | left: 10px; 482 | background: url(../img/calendar-icons.svg) 0 0 no-repeat; 483 | } 484 | 485 | .calendarbox .calendarnav-previous:focus, 486 | .calendarbox .calendarnav-previous:hover { 487 | background-position: 0 -15px; 488 | } 489 | 490 | .calendarnav-next { 491 | right: 10px; 492 | background: url(../img/calendar-icons.svg) 0 -30px no-repeat; 493 | } 494 | 495 | .calendarbox .calendarnav-next:focus, 496 | .calendarbox .calendarnav-next:hover { 497 | background-position: 0 -45px; 498 | } 499 | 500 | .calendar-cancel { 501 | margin: 0; 502 | padding: 4px 0; 503 | font-size: 12px; 504 | background: #eee; 505 | border-top: 1px solid #ddd; 506 | color: #333; 507 | } 508 | 509 | .calendar-cancel:focus, .calendar-cancel:hover { 510 | background: #ddd; 511 | } 512 | 513 | .calendar-cancel a { 514 | color: black; 515 | display: block; 516 | } 517 | 518 | ul.timelist, .timelist li { 519 | list-style-type: none; 520 | margin: 0; 521 | padding: 0; 522 | } 523 | 524 | .timelist a { 525 | padding: 2px; 526 | } 527 | 528 | /* EDIT INLINE */ 529 | 530 | .inline-deletelink { 531 | float: right; 532 | text-indent: -9999px; 533 | background: url(../img/inline-delete.svg) 0 0 no-repeat; 534 | width: 16px; 535 | height: 16px; 536 | border: 0px none; 537 | } 538 | 539 | .inline-deletelink:focus, .inline-deletelink:hover { 540 | cursor: pointer; 541 | } 542 | 543 | /* RELATED WIDGET WRAPPER */ 544 | .related-widget-wrapper { 545 | float: left; /* display properly in form rows with multiple fields */ 546 | overflow: hidden; /* clear floated contents */ 547 | } 548 | 549 | .related-widget-wrapper-link { 550 | opacity: 0.3; 551 | } 552 | 553 | .related-widget-wrapper-link:link { 554 | opacity: .8; 555 | } 556 | 557 | .related-widget-wrapper-link:link:focus, 558 | .related-widget-wrapper-link:link:hover { 559 | opacity: 1; 560 | } 561 | 562 | select + .related-widget-wrapper-link, 563 | .related-widget-wrapper-link + .related-widget-wrapper-link { 564 | margin-left: 7px; 565 | } 566 | -------------------------------------------------------------------------------- /static_cdn/admin/fonts/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /static_cdn/admin/fonts/README.txt: -------------------------------------------------------------------------------- 1 | Roboto webfont source: https://www.google.com/fonts/specimen/Roboto 2 | Weights used in this project: Light (300), Regular (400), Bold (700) 3 | -------------------------------------------------------------------------------- /static_cdn/admin/fonts/Roboto-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/static_cdn/admin/fonts/Roboto-Bold-webfont.woff -------------------------------------------------------------------------------- /static_cdn/admin/fonts/Roboto-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/static_cdn/admin/fonts/Roboto-Light-webfont.woff -------------------------------------------------------------------------------- /static_cdn/admin/fonts/Roboto-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/static_cdn/admin/fonts/Roboto-Regular-webfont.woff -------------------------------------------------------------------------------- /static_cdn/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_cdn/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 | - http://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_cdn/admin/img/calendar-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /static_cdn/admin/img/gis/move_vertex_off.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static_cdn/admin/img/gis/move_vertex_on.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static_cdn/admin/img/icon-addlink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/img/icon-alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/img/icon-calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static_cdn/admin/img/icon-changelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/img/icon-clock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static_cdn/admin/img/icon-deletelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/img/icon-no.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/img/icon-unknown-alt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/img/icon-unknown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/img/icon-yes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/img/inline-delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/img/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/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_cdn/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_cdn/admin/img/tooltag-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/img/tooltag-arrowright.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static_cdn/admin/js/SelectBox.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | var SelectBox = { 4 | cache: {}, 5 | init: function(id) { 6 | var box = document.getElementById(id); 7 | var node; 8 | SelectBox.cache[id] = []; 9 | var cache = SelectBox.cache[id]; 10 | var boxOptions = box.options; 11 | var boxOptionsLength = boxOptions.length; 12 | for (var i = 0, j = boxOptionsLength; i < j; i++) { 13 | node = boxOptions[i]; 14 | cache.push({value: node.value, text: node.text, displayed: 1}); 15 | } 16 | }, 17 | redisplay: function(id) { 18 | // Repopulate HTML select box from cache 19 | var box = document.getElementById(id); 20 | var node; 21 | $(box).empty(); // clear all options 22 | var new_options = box.outerHTML.slice(0, -9); // grab just the opening tag 23 | var cache = SelectBox.cache[id]; 24 | for (var i = 0, j = cache.length; i < j; i++) { 25 | node = cache[i]; 26 | if (node.displayed) { 27 | var new_option = new Option(node.text, node.value, false, false); 28 | // Shows a tooltip when hovering over the option 29 | new_option.setAttribute("title", node.text); 30 | new_options += new_option.outerHTML; 31 | } 32 | } 33 | new_options += ''; 34 | box.outerHTML = new_options; 35 | }, 36 | filter: function(id, text) { 37 | // Redisplay the HTML select box, displaying only the choices containing ALL 38 | // the words in text. (It's an AND search.) 39 | var tokens = text.toLowerCase().split(/\s+/); 40 | var node, token; 41 | var cache = SelectBox.cache[id]; 42 | for (var i = 0, j = cache.length; i < j; i++) { 43 | node = cache[i]; 44 | node.displayed = 1; 45 | var node_text = node.text.toLowerCase(); 46 | var numTokens = tokens.length; 47 | for (var k = 0; k < numTokens; k++) { 48 | token = tokens[k]; 49 | if (node_text.indexOf(token) === -1) { 50 | node.displayed = 0; 51 | break; // Once the first token isn't found we're done 52 | } 53 | } 54 | } 55 | SelectBox.redisplay(id); 56 | }, 57 | delete_from_cache: function(id, value) { 58 | var node, delete_index = null; 59 | var cache = SelectBox.cache[id]; 60 | for (var i = 0, j = cache.length; i < j; i++) { 61 | node = cache[i]; 62 | if (node.value === value) { 63 | delete_index = i; 64 | break; 65 | } 66 | } 67 | cache.splice(delete_index, 1); 68 | }, 69 | add_to_cache: function(id, option) { 70 | SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1}); 71 | }, 72 | cache_contains: function(id, value) { 73 | // Check if an item is contained in the cache 74 | var node; 75 | var cache = SelectBox.cache[id]; 76 | for (var i = 0, j = cache.length; i < j; i++) { 77 | node = cache[i]; 78 | if (node.value === value) { 79 | return true; 80 | } 81 | } 82 | return false; 83 | }, 84 | move: function(from, to) { 85 | var from_box = document.getElementById(from); 86 | var option; 87 | var boxOptions = from_box.options; 88 | var boxOptionsLength = boxOptions.length; 89 | for (var i = 0, j = boxOptionsLength; i < j; i++) { 90 | option = boxOptions[i]; 91 | var option_value = option.value; 92 | if (option.selected && SelectBox.cache_contains(from, option_value)) { 93 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); 94 | SelectBox.delete_from_cache(from, option_value); 95 | } 96 | } 97 | SelectBox.redisplay(from); 98 | SelectBox.redisplay(to); 99 | }, 100 | move_all: function(from, to) { 101 | var from_box = document.getElementById(from); 102 | var option; 103 | var boxOptions = from_box.options; 104 | var boxOptionsLength = boxOptions.length; 105 | for (var i = 0, j = boxOptionsLength; i < j; i++) { 106 | option = boxOptions[i]; 107 | var option_value = option.value; 108 | if (SelectBox.cache_contains(from, option_value)) { 109 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); 110 | SelectBox.delete_from_cache(from, option_value); 111 | } 112 | } 113 | SelectBox.redisplay(from); 114 | SelectBox.redisplay(to); 115 | }, 116 | sort: function(id) { 117 | SelectBox.cache[id].sort(function(a, b) { 118 | a = a.text.toLowerCase(); 119 | b = b.text.toLowerCase(); 120 | try { 121 | if (a > b) { 122 | return 1; 123 | } 124 | if (a < b) { 125 | return -1; 126 | } 127 | } 128 | catch (e) { 129 | // silently fail on IE 'unknown' exception 130 | } 131 | return 0; 132 | } ); 133 | }, 134 | select_all: function(id) { 135 | var box = document.getElementById(id); 136 | var boxOptions = box.options; 137 | var boxOptionsLength = boxOptions.length; 138 | for (var i = 0; i < boxOptionsLength; i++) { 139 | boxOptions[i].selected = 'selected'; 140 | } 141 | } 142 | }; 143 | window.SelectBox = SelectBox; 144 | })(django.jQuery); 145 | -------------------------------------------------------------------------------- /static_cdn/admin/js/actions.js: -------------------------------------------------------------------------------- 1 | /*global gettext, interpolate, ngettext*/ 2 | (function($) { 3 | 'use strict'; 4 | var lastChecked; 5 | 6 | $.fn.actions = function(opts) { 7 | var options = $.extend({}, $.fn.actions.defaults, opts); 8 | var actionCheckboxes = $(this); 9 | var list_editable_changed = false; 10 | var showQuestion = function() { 11 | $(options.acrossClears).hide(); 12 | $(options.acrossQuestions).show(); 13 | $(options.allContainer).hide(); 14 | }, 15 | showClear = function() { 16 | $(options.acrossClears).show(); 17 | $(options.acrossQuestions).hide(); 18 | $(options.actionContainer).toggleClass(options.selectedClass); 19 | $(options.allContainer).show(); 20 | $(options.counterContainer).hide(); 21 | }, 22 | reset = function() { 23 | $(options.acrossClears).hide(); 24 | $(options.acrossQuestions).hide(); 25 | $(options.allContainer).hide(); 26 | $(options.counterContainer).show(); 27 | }, 28 | clearAcross = function() { 29 | reset(); 30 | $(options.acrossInput).val(0); 31 | $(options.actionContainer).removeClass(options.selectedClass); 32 | }, 33 | checker = function(checked) { 34 | if (checked) { 35 | showQuestion(); 36 | } else { 37 | reset(); 38 | } 39 | $(actionCheckboxes).prop("checked", checked) 40 | .parent().parent().toggleClass(options.selectedClass, checked); 41 | }, 42 | updateCounter = function() { 43 | var sel = $(actionCheckboxes).filter(":checked").length; 44 | // data-actions-icnt is defined in the generated HTML 45 | // and contains the total amount of objects in the queryset 46 | var actions_icnt = $('.action-counter').data('actionsIcnt'); 47 | $(options.counterContainer).html(interpolate( 48 | ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), { 49 | sel: sel, 50 | cnt: actions_icnt 51 | }, true)); 52 | $(options.allToggle).prop("checked", function() { 53 | var value; 54 | if (sel === actionCheckboxes.length) { 55 | value = true; 56 | showQuestion(); 57 | } else { 58 | value = false; 59 | clearAcross(); 60 | } 61 | return value; 62 | }); 63 | }; 64 | // Show counter by default 65 | $(options.counterContainer).show(); 66 | // Check state of checkboxes and reinit state if needed 67 | $(this).filter(":checked").each(function(i) { 68 | $(this).parent().parent().toggleClass(options.selectedClass); 69 | updateCounter(); 70 | if ($(options.acrossInput).val() === 1) { 71 | showClear(); 72 | } 73 | }); 74 | $(options.allToggle).show().click(function() { 75 | checker($(this).prop("checked")); 76 | updateCounter(); 77 | }); 78 | $("a", options.acrossQuestions).click(function(event) { 79 | event.preventDefault(); 80 | $(options.acrossInput).val(1); 81 | showClear(); 82 | }); 83 | $("a", options.acrossClears).click(function(event) { 84 | event.preventDefault(); 85 | $(options.allToggle).prop("checked", false); 86 | clearAcross(); 87 | checker(0); 88 | updateCounter(); 89 | }); 90 | lastChecked = null; 91 | $(actionCheckboxes).click(function(event) { 92 | if (!event) { event = window.event; } 93 | var target = event.target ? event.target : event.srcElement; 94 | if (lastChecked && $.data(lastChecked) !== $.data(target) && event.shiftKey === true) { 95 | var inrange = false; 96 | $(lastChecked).prop("checked", target.checked) 97 | .parent().parent().toggleClass(options.selectedClass, target.checked); 98 | $(actionCheckboxes).each(function() { 99 | if ($.data(this) === $.data(lastChecked) || $.data(this) === $.data(target)) { 100 | inrange = (inrange) ? false : true; 101 | } 102 | if (inrange) { 103 | $(this).prop("checked", target.checked) 104 | .parent().parent().toggleClass(options.selectedClass, target.checked); 105 | } 106 | }); 107 | } 108 | $(target).parent().parent().toggleClass(options.selectedClass, target.checked); 109 | lastChecked = target; 110 | updateCounter(); 111 | }); 112 | $('form#changelist-form table#result_list tr').find('td:gt(0) :input').change(function() { 113 | list_editable_changed = true; 114 | }); 115 | $('form#changelist-form button[name="index"]').click(function(event) { 116 | if (list_editable_changed) { 117 | return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost.")); 118 | } 119 | }); 120 | $('form#changelist-form input[name="_save"]').click(function(event) { 121 | var action_changed = false; 122 | $('select option:selected', options.actionContainer).each(function() { 123 | if ($(this).val()) { 124 | action_changed = true; 125 | } 126 | }); 127 | if (action_changed) { 128 | if (list_editable_changed) { 129 | return confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")); 130 | } else { 131 | return confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button.")); 132 | } 133 | } 134 | }); 135 | }; 136 | /* Setup plugin defaults */ 137 | $.fn.actions.defaults = { 138 | actionContainer: "div.actions", 139 | counterContainer: "span.action-counter", 140 | allContainer: "div.actions span.all", 141 | acrossInput: "div.actions input.select-across", 142 | acrossQuestions: "div.actions span.question", 143 | acrossClears: "div.actions span.clear", 144 | allToggle: "#action-toggle", 145 | selectedClass: "selected" 146 | }; 147 | $(document).ready(function() { 148 | var $actionsEls = $('tr input.action-select'); 149 | if ($actionsEls.length > 0) { 150 | $actionsEls.actions(); 151 | } 152 | }); 153 | })(django.jQuery); 154 | -------------------------------------------------------------------------------- /static_cdn/admin/js/actions.min.js: -------------------------------------------------------------------------------- 1 | (function(a){var f;a.fn.actions=function(e){var b=a.extend({},a.fn.actions.defaults,e),g=a(this),k=!1,l=function(){a(b.acrossClears).hide();a(b.acrossQuestions).show();a(b.allContainer).hide()},m=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()},n=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()},p=function(){n(); 2 | a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)},q=function(c){c?l():n();a(g).prop("checked",c).parent().parent().toggleClass(b.selectedClass,c)},h=function(){var c=a(g).filter(":checked").length,d=a(".action-counter").data("actionsIcnt");a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:d},!0));a(b.allToggle).prop("checked",function(){var a;c===g.length?(a=!0,l()):(a=!1,p());return a})};a(b.counterContainer).show(); 3 | a(this).filter(":checked").each(function(c){a(this).parent().parent().toggleClass(b.selectedClass);h();1===a(b.acrossInput).val()&&m()});a(b.allToggle).show().click(function(){q(a(this).prop("checked"));h()});a("a",b.acrossQuestions).click(function(c){c.preventDefault();a(b.acrossInput).val(1);m()});a("a",b.acrossClears).click(function(c){c.preventDefault();a(b.allToggle).prop("checked",!1);p();q(0);h()});f=null;a(g).click(function(c){c||(c=window.event);var d=c.target?c.target:c.srcElement;if(f&& 4 | a.data(f)!==a.data(d)&&!0===c.shiftKey){var e=!1;a(f).prop("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked);a(g).each(function(){if(a.data(this)===a.data(f)||a.data(this)===a.data(d))e=e?!1:!0;e&&a(this).prop("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass,d.checked);f=d;h()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){k=!0});a('form#changelist-form button[name="index"]').click(function(a){if(k)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))}); 5 | a('form#changelist-form input[name="_save"]').click(function(c){var d=!1;a("select option:selected",b.actionContainer).each(function(){a(this).val()&&(d=!0)});if(d)return k?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})}; 6 | a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across",acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"};a(document).ready(function(){var e=a("tr input.action-select");0' + gettext("Show") + 11 | ')'); 12 | } 13 | }); 14 | // Add toggle to anchor tag 15 | $("fieldset.collapse a.collapse-toggle").click(function(ev) { 16 | if ($(this).closest("fieldset").hasClass("collapsed")) { 17 | // Show 18 | $(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset", [$(this).attr("id")]); 19 | } else { 20 | // Hide 21 | $(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", [$(this).attr("id")]); 22 | } 23 | return false; 24 | }); 25 | }); 26 | })(django.jQuery); 27 | -------------------------------------------------------------------------------- /static_cdn/admin/js/collapse.min.js: -------------------------------------------------------------------------------- 1 | (function(a){a(document).ready(function(){a("fieldset.collapse").each(function(b,c){0===a(c).find("div.errors").length&&a(c).addClass("collapsed").find("h2").first().append(' ('+gettext("Show")+")")});a("fieldset.collapse a.collapse-toggle").click(function(b){a(this).closest("fieldset").hasClass("collapsed")?a(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset",[a(this).attr("id")]):a(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", 2 | [a(this).attr("id")]);return!1})})})(django.jQuery); 3 | -------------------------------------------------------------------------------- /static_cdn/admin/js/core.js: -------------------------------------------------------------------------------- 1 | // Core javascript helper functions 2 | 3 | // basic browser identification & version 4 | var isOpera = (navigator.userAgent.indexOf("Opera") >= 0) && parseFloat(navigator.appVersion); 5 | var isIE = ((document.all) && (!isOpera)) && parseFloat(navigator.appVersion.split("MSIE ")[1].split(";")[0]); 6 | 7 | // Cross-browser event handlers. 8 | function addEvent(obj, evType, fn) { 9 | 'use strict'; 10 | if (obj.addEventListener) { 11 | obj.addEventListener(evType, fn, false); 12 | return true; 13 | } else if (obj.attachEvent) { 14 | var r = obj.attachEvent("on" + evType, fn); 15 | return r; 16 | } else { 17 | return false; 18 | } 19 | } 20 | 21 | function removeEvent(obj, evType, fn) { 22 | 'use strict'; 23 | if (obj.removeEventListener) { 24 | obj.removeEventListener(evType, fn, false); 25 | return true; 26 | } else if (obj.detachEvent) { 27 | obj.detachEvent("on" + evType, fn); 28 | return true; 29 | } else { 30 | return false; 31 | } 32 | } 33 | 34 | function cancelEventPropagation(e) { 35 | 'use strict'; 36 | if (!e) { 37 | e = window.event; 38 | } 39 | e.cancelBubble = true; 40 | if (e.stopPropagation) { 41 | e.stopPropagation(); 42 | } 43 | } 44 | 45 | // quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]); 46 | function quickElement() { 47 | 'use strict'; 48 | var obj = document.createElement(arguments[0]); 49 | if (arguments[2]) { 50 | var textNode = document.createTextNode(arguments[2]); 51 | obj.appendChild(textNode); 52 | } 53 | var len = arguments.length; 54 | for (var i = 3; i < len; i += 2) { 55 | obj.setAttribute(arguments[i], arguments[i + 1]); 56 | } 57 | arguments[1].appendChild(obj); 58 | return obj; 59 | } 60 | 61 | // "a" is reference to an object 62 | function removeChildren(a) { 63 | 'use strict'; 64 | while (a.hasChildNodes()) { 65 | a.removeChild(a.lastChild); 66 | } 67 | } 68 | 69 | // ---------------------------------------------------------------------------- 70 | // Find-position functions by PPK 71 | // See http://www.quirksmode.org/js/findpos.html 72 | // ---------------------------------------------------------------------------- 73 | function findPosX(obj) { 74 | 'use strict'; 75 | var curleft = 0; 76 | if (obj.offsetParent) { 77 | while (obj.offsetParent) { 78 | curleft += obj.offsetLeft - ((isOpera) ? 0 : obj.scrollLeft); 79 | obj = obj.offsetParent; 80 | } 81 | // IE offsetParent does not include the top-level 82 | if (isIE && obj.parentElement) { 83 | curleft += obj.offsetLeft - obj.scrollLeft; 84 | } 85 | } else if (obj.x) { 86 | curleft += obj.x; 87 | } 88 | return curleft; 89 | } 90 | 91 | function findPosY(obj) { 92 | 'use strict'; 93 | var curtop = 0; 94 | if (obj.offsetParent) { 95 | while (obj.offsetParent) { 96 | curtop += obj.offsetTop - ((isOpera) ? 0 : obj.scrollTop); 97 | obj = obj.offsetParent; 98 | } 99 | // IE offsetParent does not include the top-level 100 | if (isIE && obj.parentElement) { 101 | curtop += obj.offsetTop - obj.scrollTop; 102 | } 103 | } else if (obj.y) { 104 | curtop += obj.y; 105 | } 106 | return curtop; 107 | } 108 | 109 | //----------------------------------------------------------------------------- 110 | // Date object extensions 111 | // ---------------------------------------------------------------------------- 112 | (function() { 113 | 'use strict'; 114 | Date.prototype.getTwelveHours = function() { 115 | var hours = this.getHours(); 116 | if (hours === 0) { 117 | return 12; 118 | } 119 | else { 120 | return hours <= 12 ? hours : hours - 12; 121 | } 122 | }; 123 | 124 | Date.prototype.getTwoDigitMonth = function() { 125 | return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1); 126 | }; 127 | 128 | Date.prototype.getTwoDigitDate = function() { 129 | return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate(); 130 | }; 131 | 132 | Date.prototype.getTwoDigitTwelveHour = function() { 133 | return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours(); 134 | }; 135 | 136 | Date.prototype.getTwoDigitHour = function() { 137 | return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours(); 138 | }; 139 | 140 | Date.prototype.getTwoDigitMinute = function() { 141 | return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes(); 142 | }; 143 | 144 | Date.prototype.getTwoDigitSecond = function() { 145 | return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); 146 | }; 147 | 148 | Date.prototype.getHourMinute = function() { 149 | return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute(); 150 | }; 151 | 152 | Date.prototype.getHourMinuteSecond = function() { 153 | return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond(); 154 | }; 155 | 156 | Date.prototype.getFullMonthName = function() { 157 | return typeof window.CalendarNamespace === "undefined" 158 | ? this.getTwoDigitMonth() 159 | : window.CalendarNamespace.monthsOfYear[this.getMonth()]; 160 | }; 161 | 162 | Date.prototype.strftime = function(format) { 163 | var fields = { 164 | B: this.getFullMonthName(), 165 | c: this.toString(), 166 | d: this.getTwoDigitDate(), 167 | H: this.getTwoDigitHour(), 168 | I: this.getTwoDigitTwelveHour(), 169 | m: this.getTwoDigitMonth(), 170 | M: this.getTwoDigitMinute(), 171 | p: (this.getHours() >= 12) ? 'PM' : 'AM', 172 | S: this.getTwoDigitSecond(), 173 | w: '0' + this.getDay(), 174 | x: this.toLocaleDateString(), 175 | X: this.toLocaleTimeString(), 176 | y: ('' + this.getFullYear()).substr(2, 4), 177 | Y: '' + this.getFullYear(), 178 | '%': '%' 179 | }; 180 | var result = '', i = 0; 181 | while (i < format.length) { 182 | if (format.charAt(i) === '%') { 183 | result = result + fields[format.charAt(i + 1)]; 184 | ++i; 185 | } 186 | else { 187 | result = result + format.charAt(i); 188 | } 189 | ++i; 190 | } 191 | return result; 192 | }; 193 | 194 | // ---------------------------------------------------------------------------- 195 | // String object extensions 196 | // ---------------------------------------------------------------------------- 197 | String.prototype.pad_left = function(pad_length, pad_string) { 198 | var new_string = this; 199 | for (var i = 0; new_string.length < pad_length; i++) { 200 | new_string = pad_string + new_string; 201 | } 202 | return new_string; 203 | }; 204 | 205 | String.prototype.strptime = function(format) { 206 | var split_format = format.split(/[.\-/]/); 207 | var date = this.split(/[.\-/]/); 208 | var i = 0; 209 | var day, month, year; 210 | while (i < split_format.length) { 211 | switch (split_format[i]) { 212 | case "%d": 213 | day = date[i]; 214 | break; 215 | case "%m": 216 | month = date[i] - 1; 217 | break; 218 | case "%Y": 219 | year = date[i]; 220 | break; 221 | case "%y": 222 | year = date[i]; 223 | break; 224 | } 225 | ++i; 226 | } 227 | // Create Date object from UTC since the parsed value is supposed to be 228 | // in UTC, not local time. Also, the calendar uses UTC functions for 229 | // date extraction. 230 | return new Date(Date.UTC(year, month, day)); 231 | }; 232 | 233 | })(); 234 | // ---------------------------------------------------------------------------- 235 | // Get the computed style for and element 236 | // ---------------------------------------------------------------------------- 237 | function getStyle(oElm, strCssRule) { 238 | 'use strict'; 239 | var strValue = ""; 240 | if(document.defaultView && document.defaultView.getComputedStyle) { 241 | strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule); 242 | } 243 | else if(oElm.currentStyle) { 244 | strCssRule = strCssRule.replace(/\-(\w)/g, function(strMatch, p1) { 245 | return p1.toUpperCase(); 246 | }); 247 | strValue = oElm.currentStyle[strCssRule]; 248 | } 249 | return strValue; 250 | } 251 | -------------------------------------------------------------------------------- /static_cdn/admin/js/inlines.min.js: -------------------------------------------------------------------------------- 1 | (function(c){c.fn.formset=function(b){var a=c.extend({},c.fn.formset.defaults,b),d=c(this);b=d.parent();var k=function(a,g,l){var b=new RegExp("("+g+"-(\\d+|__prefix__))");g=g+"-"+l;c(a).prop("for")&&c(a).prop("for",c(a).prop("for").replace(b,g));a.id&&(a.id=a.id.replace(b,g));a.name&&(a.name=a.name.replace(b,g))},e=c("#id_"+a.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),l=parseInt(e.val(),10),g=c("#id_"+a.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off"),h=""===g.val()||0'+a.addText+""),m=b.find("tr:last a")):(d.filter(":last").after('"),m=d.filter(":last").next().find("a"));m.click(function(b){b.preventDefault();b=c("#"+a.prefix+"-empty");var f=b.clone(!0);f.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id", 3 | a.prefix+"-"+l);f.is("tr")?f.children(":last").append('"):f.is("ul")||f.is("ol")?f.append('
  • '+a.deleteText+"
  • "):f.children(":first").append(''+a.deleteText+"");f.find("*").each(function(){k(this,a.prefix,e.val())});f.insertBefore(c(b));c(e).val(parseInt(e.val(),10)+1);l+=1;""!==g.val()&&0>=g.val()-e.val()&&m.parent().hide(); 4 | f.find("a."+a.deleteCssClass).click(function(b){b.preventDefault();f.remove();--l;a.removed&&a.removed(f);c(document).trigger("formset:removed",[f,a.prefix]);b=c("."+a.formCssClass);c("#id_"+a.prefix+"-TOTAL_FORMS").val(b.length);(""===g.val()||0 0) { 26 | values.push(field.val()); 27 | } 28 | }); 29 | prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); 30 | }; 31 | 32 | prepopulatedField.data('_changed', false); 33 | prepopulatedField.change(function() { 34 | prepopulatedField.data('_changed', true); 35 | }); 36 | 37 | if (!prepopulatedField.val()) { 38 | $(dependencies.join(',')).keyup(populate).change(populate).focus(populate); 39 | } 40 | }); 41 | }; 42 | })(django.jQuery); 43 | -------------------------------------------------------------------------------- /static_cdn/admin/js/prepopulate.min.js: -------------------------------------------------------------------------------- 1 | (function(c){c.fn.prepopulate=function(e,f,g){return this.each(function(){var a=c(this),b=function(){if(!a.data("_changed")){var b=[];c.each(e,function(a,d){d=c(d);0 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_cdn/css/main.css: -------------------------------------------------------------------------------- 1 | /* For Custom CSS */ -------------------------------------------------------------------------------- /static_cdn/rest_framework/css/bootstrap-tweaks.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This CSS file contains some tweaks specific to the included Bootstrap theme. 4 | It's separate from `style.css` so that it can be easily overridden by replacing 5 | a single block in the template. 6 | 7 | */ 8 | 9 | .form-actions { 10 | background: transparent; 11 | border-top-color: transparent; 12 | padding-top: 0; 13 | text-align: right; 14 | } 15 | 16 | #generic-content-form textarea { 17 | font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace; 18 | font-size: 80%; 19 | } 20 | 21 | .navbar-inverse .brand a { 22 | color: #999999; 23 | } 24 | .navbar-inverse .brand:hover a { 25 | color: white; 26 | text-decoration: none; 27 | } 28 | 29 | /* custom navigation styles */ 30 | .navbar { 31 | width: 100%; 32 | position: fixed; 33 | left: 0; 34 | top: 0; 35 | } 36 | 37 | .navbar { 38 | background: #2C2C2C; 39 | color: white; 40 | border: none; 41 | border-top: 5px solid #A30000; 42 | border-radius: 0px; 43 | } 44 | 45 | .navbar .nav li, .navbar .nav li a, .navbar .brand:hover { 46 | color: white; 47 | } 48 | 49 | .nav-list > .active > a, .nav-list > .active > a:hover { 50 | background: #2C2C2C; 51 | } 52 | 53 | .navbar .dropdown-menu li a, .navbar .dropdown-menu li { 54 | color: #A30000; 55 | } 56 | 57 | .navbar .dropdown-menu li a:hover { 58 | background: #EEEEEE; 59 | color: #C20000; 60 | } 61 | 62 | ul.breadcrumb { 63 | margin: 70px 0 0 0; 64 | } 65 | 66 | .breadcrumb li.active a { 67 | color: #777; 68 | } 69 | 70 | .pagination>.disabled>a, 71 | .pagination>.disabled>a:hover, 72 | .pagination>.disabled>a:focus { 73 | cursor: not-allowed; 74 | pointer-events: none; 75 | } 76 | 77 | .pager>.disabled>a, 78 | .pager>.disabled>a:hover, 79 | .pager>.disabled>a:focus { 80 | pointer-events: none; 81 | } 82 | 83 | .pager .next { 84 | margin-left: 10px; 85 | } 86 | 87 | /*=== dabapps bootstrap styles ====*/ 88 | 89 | html { 90 | width:100%; 91 | background: none; 92 | } 93 | 94 | /*body, .navbar .container-fluid { 95 | max-width: 1150px; 96 | margin: 0 auto; 97 | }*/ 98 | 99 | body { 100 | background: url("../img/grid.png") repeat-x; 101 | background-attachment: fixed; 102 | } 103 | 104 | #content { 105 | margin: 0; 106 | padding-bottom: 60px; 107 | } 108 | 109 | /* sticky footer and footer */ 110 | html, body { 111 | height: 100%; 112 | } 113 | 114 | .wrapper { 115 | position: relative; 116 | top: 0; 117 | left: 0; 118 | padding-top: 60px; 119 | margin: -60px 0; 120 | min-height: 100%; 121 | } 122 | 123 | .form-switcher { 124 | margin-bottom: 0; 125 | } 126 | 127 | .well { 128 | -webkit-box-shadow: none; 129 | -moz-box-shadow: none; 130 | box-shadow: none; 131 | } 132 | 133 | .well .form-actions { 134 | padding-bottom: 0; 135 | margin-bottom: 0; 136 | } 137 | 138 | .well form { 139 | margin-bottom: 0; 140 | } 141 | 142 | .nav-tabs { 143 | border: 0; 144 | } 145 | 146 | .nav-tabs > li { 147 | float: right; 148 | } 149 | 150 | .nav-tabs li a { 151 | margin-right: 0; 152 | } 153 | 154 | .nav-tabs > .active > a { 155 | background: #F5F5F5; 156 | } 157 | 158 | .nav-tabs > .active > a:hover { 159 | background: #F5F5F5; 160 | } 161 | 162 | .tabbable.first-tab-active .tab-content { 163 | border-top-right-radius: 0; 164 | } 165 | 166 | footer { 167 | position: absolute; 168 | bottom: 0; 169 | left: 0; 170 | clear: both; 171 | z-index: 10; 172 | height: 60px; 173 | width: 95%; 174 | margin: 0 2.5%; 175 | } 176 | 177 | footer p { 178 | text-align: center; 179 | color: gray; 180 | border-top: 1px solid #DDDDDD; 181 | padding-top: 10px; 182 | } 183 | 184 | footer a { 185 | color: gray !important; 186 | font-weight: bold; 187 | } 188 | 189 | footer a:hover { 190 | color: gray; 191 | } 192 | 193 | .page-header { 194 | border-bottom: none; 195 | padding-bottom: 0px; 196 | margin: 0; 197 | } 198 | 199 | /* custom general page styles */ 200 | .hero-unit h1, .hero-unit h2 { 201 | color: #A30000; 202 | } 203 | 204 | body a { 205 | color: #A30000; 206 | } 207 | 208 | body a:hover { 209 | color: #c20000; 210 | } 211 | 212 | .request-info { 213 | clear:both; 214 | } 215 | 216 | .horizontal-checkbox label { 217 | padding-top: 0; 218 | } 219 | 220 | .horizontal-checkbox label { 221 | padding-top: 0 !important; 222 | } 223 | 224 | .horizontal-checkbox input { 225 | float: left; 226 | width: 20px; 227 | margin-top: 3px; 228 | } 229 | 230 | .modal-footer form { 231 | margin-left: 5px; 232 | margin-right: 5px; 233 | } 234 | -------------------------------------------------------------------------------- /static_cdn/rest_framework/css/default.css: -------------------------------------------------------------------------------- 1 | 2 | /* The navbar is fixed at >= 980px wide, so add padding to the body to prevent 3 | content running up underneath it. */ 4 | 5 | h1 { 6 | font-weight: 300; 7 | } 8 | 9 | h2, h3 { 10 | font-weight: 300; 11 | } 12 | 13 | .resource-description, .response-info { 14 | margin-bottom: 2em; 15 | } 16 | 17 | .version:before { 18 | content: "v"; 19 | opacity: 0.6; 20 | padding-right: 0.25em; 21 | } 22 | 23 | .version { 24 | font-size: 70%; 25 | } 26 | 27 | .format-option { 28 | font-family: Menlo, Consolas, "Andale Mono", "Lucida Console", monospace; 29 | } 30 | 31 | .button-form { 32 | float: right; 33 | margin-right: 1em; 34 | } 35 | 36 | td.nested { 37 | padding: 0 !important; 38 | } 39 | 40 | td.nested > table { 41 | margin: 0; 42 | } 43 | 44 | form select, form input, form textarea { 45 | width: 90%; 46 | } 47 | 48 | form select[multiple] { 49 | height: 150px; 50 | } 51 | 52 | /* To allow tooltips to work on disabled elements */ 53 | .disabled-tooltip-shield { 54 | position: absolute; 55 | top: 0; 56 | right: 0; 57 | bottom: 0; 58 | left: 0; 59 | } 60 | 61 | .errorlist { 62 | margin-top: 0.5em; 63 | } 64 | 65 | pre { 66 | overflow: auto; 67 | word-wrap: normal; 68 | white-space: pre; 69 | font-size: 12px; 70 | } 71 | 72 | .page-header { 73 | border-bottom: none; 74 | padding-bottom: 0px; 75 | } 76 | 77 | #filtersModal form input[type=submit] { 78 | width: auto; 79 | } 80 | 81 | #filtersModal .modal-body h2 { 82 | margin-top: 0 83 | } 84 | -------------------------------------------------------------------------------- /static_cdn/rest_framework/css/prettify.css: -------------------------------------------------------------------------------- 1 | .com { color: #93a1a1; } 2 | .lit { color: #195f91; } 3 | .pun, .opn, .clo { color: #93a1a1; } 4 | .fun { color: #dc322f; } 5 | .str, .atv { color: #D14; } 6 | .kwd, .prettyprint .tag { color: #1e347b; } 7 | .typ, .atn, .dec, .var { color: teal; } 8 | .pln { color: #48484c; } 9 | 10 | .prettyprint { 11 | padding: 8px; 12 | background-color: #f7f7f9; 13 | border: 1px solid #e1e1e8; 14 | } 15 | .prettyprint.linenums { 16 | -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 17 | -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 18 | box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 19 | } 20 | 21 | /* Specify class=linenums on a pre to get line numbering */ 22 | ol.linenums { 23 | margin: 0 0 0 33px; /* IE indents via margin-left */ 24 | } 25 | ol.linenums li { 26 | padding-left: 12px; 27 | color: #bebec5; 28 | line-height: 20px; 29 | text-shadow: 0 1px 0 #fff; 30 | } -------------------------------------------------------------------------------- /static_cdn/rest_framework/docs/css/base.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | font-size: 45px; 3 | } 4 | 5 | .intro-code { 6 | margin-top: 20px; 7 | } 8 | 9 | pre.highlight code * { 10 | white-space: nowrap; // this sets all children inside to nowrap 11 | } 12 | 13 | pre.highlight { 14 | overflow-x: auto; // this sets the scrolling in x 15 | } 16 | 17 | pre.highlight code { 18 | white-space: pre; // forces to respect
     formatting
     19 | }
     20 | 
     21 | .main-container {
     22 |   padding-left: 30px;
     23 |   padding-right: 30px;
     24 | }
     25 | 
     26 | .btn:focus,
     27 | .btn:focus:active {
     28 |   outline: none;
     29 | }
     30 | 
     31 | .sidebar {
     32 |   overflow: auto;
     33 |   font-family: verdana;
     34 |   font-size: 12px;
     35 |   font-weight: 200;
     36 |   background-color: #2e353d;
     37 |   position: fixed;
     38 |   top: 0px;
     39 |   width: 225px;
     40 |   height: 100%;
     41 |   color: #FFF;
     42 | }
     43 | 
     44 | .sidebar .brand {
     45 |     background-color: #23282e;
     46 |     display: block;
     47 |     text-align: center;
     48 |     padding: 25px 0;
     49 |     margin-top: 0;
     50 |     margin-bottom: 0;
     51 | }
     52 | 
     53 | .sidebar .brand a {
     54 |     color: #FFF;
     55 | }
     56 | 
     57 | .sidebar .brand a:hover,
     58 | .sidebar .brand a:active,
     59 | .sidebar .brand a:focus {
     60 |   text-decoration: none;
     61 | }
     62 | 
     63 | .sidebar .toggle-btn {
     64 |   display: none;
     65 | }
     66 | 
     67 | .sidebar .menu-list ul,
     68 | .sidebar .menu-list li {
     69 |   background: #2e353d;
     70 |   list-style: none;
     71 |   padding: 0px;
     72 |   margin: 0px;
     73 |   line-height: 35px;
     74 |   cursor: pointer;
     75 | }
     76 | 
     77 | .sidebar .menu-list ul :not(collapsed) .arrow:before,
     78 | .sidebar .menu-list li :not(collapsed) .arrow:before {
     79 |   font-family: FontAwesome;
     80 |   content: "\f078";
     81 |   display: inline-block;
     82 |   padding-left: 10px;
     83 |   padding-right: 10px;
     84 |   vertical-align: middle;
     85 |   float: right;
     86 | }
     87 | 
     88 | .sidebar .menu-list ul .active,
     89 | .sidebar .menu-list li .active {
     90 |   border-left: 3px solid #d19b3d;
     91 |   background-color: #4f5b69;
     92 | }
     93 | 
     94 | .sidebar .menu-list ul .sub-menu li.active,
     95 | .sidebar .menu-list li .sub-menu li.active {
     96 |   color: #d19b3d;
     97 | }
     98 | 
     99 | .sidebar .menu-list ul .sub-menu li.active a,
    100 | .sidebar .menu-list li .sub-menu li.active a {
    101 |   color: #d19b3d;
    102 | }
    103 | 
    104 | .sidebar .menu-list ul .sub-menu li,
    105 | .sidebar .menu-list li .sub-menu li {
    106 |   background-color: #181c20;
    107 |   border: none;
    108 |   border-bottom: 1px solid #23282e;
    109 |   margin-left: 0px;
    110 |   text-indent: 10px;
    111 | }
    112 | 
    113 | .sidebar .menu-list ul .sub-menu li:hover,
    114 | .sidebar .menu-list li .sub-menu li:hover {
    115 |   background-color: #020203;
    116 | }
    117 | 
    118 | 
    119 | .sidebar .menu-list ul .sub-menu li a,
    120 | .sidebar .menu-list li .sub-menu li a {
    121 |   display: block;
    122 | }
    123 | 
    124 | .sidebar .menu-list ul .sub-menu li a:before,
    125 | .sidebar .menu-list li .sub-menu li a:before {
    126 |   font-family: FontAwesome;
    127 |   content: "\f105";
    128 |   display: inline-block;
    129 |   padding-left: 10px;
    130 |   padding-right: 10px;
    131 |   vertical-align: middle;
    132 | }
    133 | 
    134 | .sidebar .menu-list li {
    135 |   padding-left: 0px;
    136 |   border-left: 3px solid #2e353d;
    137 |   border-bottom: 1px solid #23282e;
    138 | }
    139 | 
    140 | .sidebar .menu-list li a {
    141 |   text-decoration: none;
    142 |   color: white;
    143 | }
    144 | 
    145 | .sidebar .menu-list li a i {
    146 |   padding-left: 10px;
    147 |   width: 20px;
    148 |   padding-right: 20px;
    149 | }
    150 | 
    151 | .sidebar .menu-list li:hover {
    152 |   border-left: 3px solid #d19b3d;
    153 |   background-color: #4f5b69;
    154 |   -webkit-transition: all 1s ease;
    155 |   -moz-transition: all 1s ease;
    156 |   -o-transition: all 1s ease;
    157 |   -ms-transition: all 1s ease;
    158 |   transition: all 1s ease;
    159 | }
    160 | 
    161 | body {
    162 |   margin: 0px;
    163 |   padding: 0px;
    164 | }
    165 | 
    166 | .coredocs-section-title {
    167 |     margin-top: 20px;
    168 |     padding-bottom: 10px;
    169 |     border-bottom: 1px solid lightgrey;
    170 | }
    171 | 
    172 | .coredocs-link-title a,
    173 | .coredocs-section-title a {
    174 |   display: none;
    175 | }
    176 | 
    177 | .coredocs-link-title a,
    178 | .coredocs-section-title a {
    179 |   text-decoration: none;
    180 | }
    181 | 
    182 | .coredocs-link-title:hover a,
    183 | .coredocs-section-title:hover a {
    184 |   display: inline;
    185 |   font-size: 20px;
    186 | }
    187 | 
    188 | .coredocs-section-title:last-child {
    189 |     margin-top: 0;
    190 | }
    191 | 
    192 | 
    193 | /* @group Language Switcher */
    194 | 
    195 | .sidebar .menu-list.menu-list-bottom {
    196 |     margin-bottom: 0;
    197 |     position: absolute;
    198 |     bottom: 0;
    199 |     left: 0;
    200 |     right: 0;
    201 |     border-top: 1px solid #23282e;
    202 | }
    203 | 
    204 | .sidebar .menu-list-bottom li span {
    205 |   float: right;
    206 |   margin-right: 20px;
    207 |   color: #d19b3d;
    208 | }
    209 | 
    210 | /* @end Language Switcher */
    211 | 
    212 | 
    213 | /* @group Docs Content */
    214 | 
    215 | .docs-content .meta .label {
    216 |     vertical-align: middle;
    217 |     font-size: 14px;
    218 |     font-weight: normal;
    219 | }
    220 | 
    221 | .docs-content .meta code {
    222 |     vertical-align: middle;
    223 |     padding: .2em .6em .3em;
    224 |     font-size: 14px;
    225 | }
    226 | 
    227 | .docs-content .btn {
    228 |   font-size: inherit;
    229 | }
    230 | 
    231 | .code-samples pre {
    232 |   margin-top: 20px;
    233 | }
    234 | 
    235 | /* @end Docs Content */
    236 | 
    237 | 
    238 | @media (max-width: 767px) {
    239 |   .main-container {
    240 |     padding-left: 15px;
    241 |     padding-right: 15px;
    242 |   }
    243 | 
    244 |   .sidebar {
    245 |     position: relative;
    246 |     width: 100%;
    247 |     margin-bottom: 10px;
    248 |     overflow: visible;
    249 |   }
    250 | 
    251 |   .sidebar .toggle-btn {
    252 |     display: block;
    253 |     cursor: pointer;
    254 |     position: absolute;
    255 |     right: 10px;
    256 |     top: 10px;
    257 |     z-index: 10 !important;
    258 |     padding: 3px;
    259 |     width: 40px;
    260 |     text-align: center;
    261 |   }
    262 | 
    263 |   .sidebar .menu-list.menu-list-bottom {
    264 |     position: static;
    265 |   }
    266 | 
    267 |   .sidebar .brand {
    268 |     margin-top: 0;
    269 |     margin-bottom: 0;
    270 | 
    271 |     text-align: left !important;
    272 |     font-size: 22px;
    273 |     padding: 0;
    274 |     padding-left: 20px;
    275 |     line-height: 50px !important;
    276 |   }
    277 | }
    278 | 
    279 | @media (min-width: 767px) {
    280 |   .sidebar .menu-list .menu-content {
    281 |     display: block;
    282 |   }
    283 |   #main {
    284 |     width:calc(100% - 225px);
    285 |     float: right;
    286 |   }
    287 | }
    288 | 
    289 | @media (min-width: 992px) {
    290 |   .modal-lg {
    291 |       width: 980px;
    292 |   }
    293 | }
    294 | 
    295 | .api-modal .modal-title .fa {
    296 |   color: #93c54b;
    297 | }
    298 | 
    299 | .api-modal .modal-body .request-awaiting {
    300 |   padding: 35px 10px;
    301 |   color: #7F8177;
    302 |   text-align: center;
    303 | }
    304 | 
    305 | .api-modal .modal-body .meta {
    306 |   margin-bottom: 20px;
    307 | }
    308 | 
    309 | .api-modal .modal-body .meta .label {
    310 |     vertical-align: middle;
    311 |     font-size: 14px;
    312 |     font-weight: normal;
    313 | }
    314 | 
    315 | .api-modal .modal-body .meta code {
    316 |     vertical-align: middle;
    317 |     padding: .2em .6em .3em;
    318 |     font-size: 14px;
    319 | }
    320 | 
    321 | .api-modal .modal-content .toggle-view {
    322 |   text-align: right;
    323 |   float: right;
    324 | }
    325 | 
    326 | .api-modal .modal-content .response .well {
    327 |   margin: 0;
    328 |   max-height: 550px;
    329 | }
    330 | 
    331 | .highlight {
    332 |     background-color: #f7f7f9
    333 | }
    334 | 
    335 | .checkbox label.control-label {
    336 |     font-weight: bold
    337 | }
    338 | 
    339 | @media (min-width: 768px) {
    340 |     .navbar-nav.navbar-right:last-child {
    341 |         margin-right: 0 !important;
    342 |     }
    343 | }
    344 | 
    
    
    --------------------------------------------------------------------------------
    /static_cdn/rest_framework/docs/css/highlight.css:
    --------------------------------------------------------------------------------
      1 | /*
      2 | This is the GitHub theme for highlight.js
      3 | 
      4 | github.com style (c) Vasily Polovnyov 
      5 | 
      6 | */
      7 | 
      8 | .hljs {
      9 |   display: block;
     10 |   overflow-x: auto;
     11 |   padding: 0.5em;
     12 |   color: #333;
     13 |   -webkit-text-size-adjust: none;
     14 | }
     15 | 
     16 | .hljs-comment,
     17 | .diff .hljs-header,
     18 | .hljs-javadoc {
     19 |   color: #998;
     20 |   font-style: italic;
     21 | }
     22 | 
     23 | .hljs-keyword,
     24 | .css .rule .hljs-keyword,
     25 | .hljs-winutils,
     26 | .nginx .hljs-title,
     27 | .hljs-subst,
     28 | .hljs-request,
     29 | .hljs-status {
     30 |   color: #333;
     31 |   font-weight: bold;
     32 | }
     33 | 
     34 | .hljs-number,
     35 | .hljs-hexcolor,
     36 | .ruby .hljs-constant {
     37 |   color: #008080;
     38 | }
     39 | 
     40 | .hljs-string,
     41 | .hljs-tag .hljs-value,
     42 | .hljs-phpdoc,
     43 | .hljs-dartdoc,
     44 | .tex .hljs-formula {
     45 |   color: #d14;
     46 | }
     47 | 
     48 | .hljs-title,
     49 | .hljs-id,
     50 | .scss .hljs-preprocessor {
     51 |   color: #900;
     52 |   font-weight: bold;
     53 | }
     54 | 
     55 | .hljs-list .hljs-keyword,
     56 | .hljs-subst {
     57 |   font-weight: normal;
     58 | }
     59 | 
     60 | .hljs-class .hljs-title,
     61 | .hljs-type,
     62 | .vhdl .hljs-literal,
     63 | .tex .hljs-command {
     64 |   color: #458;
     65 |   font-weight: bold;
     66 | }
     67 | 
     68 | .hljs-tag,
     69 | .hljs-tag .hljs-title,
     70 | .hljs-rule .hljs-property,
     71 | .django .hljs-tag .hljs-keyword {
     72 |   color: #000080;
     73 |   font-weight: normal;
     74 | }
     75 | 
     76 | .hljs-attribute,
     77 | .hljs-variable,
     78 | .lisp .hljs-body,
     79 | .hljs-name {
     80 |   color: #008080;
     81 | }
     82 | 
     83 | .hljs-regexp {
     84 |   color: #009926;
     85 | }
     86 | 
     87 | .hljs-symbol,
     88 | .ruby .hljs-symbol .hljs-string,
     89 | .lisp .hljs-keyword,
     90 | .clojure .hljs-keyword,
     91 | .scheme .hljs-keyword,
     92 | .tex .hljs-special,
     93 | .hljs-prompt {
     94 |   color: #990073;
     95 | }
     96 | 
     97 | .hljs-built_in {
     98 |   color: #0086b3;
     99 | }
    100 | 
    101 | .hljs-preprocessor,
    102 | .hljs-pragma,
    103 | .hljs-pi,
    104 | .hljs-doctype,
    105 | .hljs-shebang,
    106 | .hljs-cdata {
    107 |   color: #999;
    108 |   font-weight: bold;
    109 | }
    110 | 
    111 | .hljs-deletion {
    112 |   background: #fdd;
    113 | }
    114 | 
    115 | .hljs-addition {
    116 |   background: #dfd;
    117 | }
    118 | 
    119 | .diff .hljs-change {
    120 |   background: #0086b3;
    121 | }
    122 | 
    123 | .hljs-chunk {
    124 |   color: #aaa;
    125 | }
    126 | 
    
    
    --------------------------------------------------------------------------------
    /static_cdn/rest_framework/docs/css/jquery.json-view.min.css:
    --------------------------------------------------------------------------------
     1 | .json-view{position:relative}
     2 | .json-view .collapser{width:20px;height:18px;display:block;position:absolute;left:-1.7em;top:-.2em;z-index:5;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAD1JREFUeNpiYGBgOADE%2F3Hgw0DM4IRHgSsDFOzFInmMAQnY49ONzZRjDFiADT7dMLALiE8y4AGW6LoBAgwAuIkf%2F%2FB7O9sAAAAASUVORK5CYII%3D);background-repeat:no-repeat;background-position:center center;opacity:.5;cursor:pointer}
     3 | .json-view .collapsed{-ms-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-khtml-transform:rotate(-90deg);-webkit-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}
     4 | .json-view .bl{display:block;padding-left:20px;margin-left:-20px;position:relative}
     5 | .json-view{font-family:monospace}
     6 | .json-view ul{list-style-type:none;padding-left:2em;border-left:1px dotted;margin:.3em}
     7 | .json-view ul li{position:relative}
     8 | .json-view .comments,.json-view .dots{display:none;-moz-user-select:none;-ms-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}
     9 | .json-view .comments{padding-left:.8em;font-style:italic;color:#888}
    10 | .json-view .bool,.json-view .null,.json-view .num,.json-view .undef{font-weight:700;color:#1A01CC}
    11 | .json-view .str{color:#800}
    
    
    --------------------------------------------------------------------------------
    /static_cdn/rest_framework/docs/fonts/fontawesome-webfont.eot:
    --------------------------------------------------------------------------------
    https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/static_cdn/rest_framework/docs/fonts/fontawesome-webfont.eot
    
    
    --------------------------------------------------------------------------------
    /static_cdn/rest_framework/docs/fonts/fontawesome-webfont.ttf:
    --------------------------------------------------------------------------------
    https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/static_cdn/rest_framework/docs/fonts/fontawesome-webfont.ttf
    
    
    --------------------------------------------------------------------------------
    /static_cdn/rest_framework/docs/fonts/fontawesome-webfont.woff:
    --------------------------------------------------------------------------------
    https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/static_cdn/rest_framework/docs/fonts/fontawesome-webfont.woff
    
    
    --------------------------------------------------------------------------------
    /static_cdn/rest_framework/docs/img/favicon.ico:
    --------------------------------------------------------------------------------
    https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/static_cdn/rest_framework/docs/img/favicon.ico
    
    
    --------------------------------------------------------------------------------
    /static_cdn/rest_framework/docs/img/grid.png:
    --------------------------------------------------------------------------------
    https://raw.githubusercontent.com/codingforentrepreneurs/Django-Likes/6d087d1214b3c00e8454532c10cfae19162c6032/static_cdn/rest_framework/docs/img/grid.png
    
    
    --------------------------------------------------------------------------------
    /static_cdn/rest_framework/docs/js/api.js:
    --------------------------------------------------------------------------------
      1 | function normalizeHTTPHeader (str) {
      2 |   // Capitalize HTTP headers for display.
      3 |   return (str.charAt(0).toUpperCase() + str.substring(1))
      4 |     .replace(/-(.)/g, function ($1) { return $1.toUpperCase() })
      5 |     .replace(/(Www)/g, function ($1) { return 'WWW' })
      6 |     .replace(/(Xss)/g, function ($1) { return 'XSS' })
      7 |     .replace(/(Md5)/g, function ($1) { return 'MD5' })
      8 | }
      9 | 
     10 | let responseDisplay = 'data'
     11 | const coreapi = window.coreapi
     12 | const schema = window.schema
     13 | 
     14 | // Language Control
     15 | $('#language-control li').click(function (event) {
     16 |     event.preventDefault();
     17 |     const languageMenuItem = $(this).find('a');
     18 |     var language = languageMenuItem.data("language")
     19 | 
     20 |     var languageControls = $(this).closest('ul').find('li');
     21 |     languageControls.find('a').not('[data-language="' + language +'"]').parent().removeClass("active")
     22 |     languageControls.find('a').filter('[data-language="' + language +'"]').parent().addClass("active")
     23 | 
     24 |     $('#selected-language').text(language)
     25 | 
     26 |     var codeBlocks = $('pre.highlight')
     27 |     codeBlocks.not('[data-language="' + language +'"]').addClass("hide")
     28 |     codeBlocks.filter('[data-language="' + language +'"]').removeClass("hide")
     29 | })
     30 | 
     31 | // API Explorer
     32 | $('form.api-interaction').submit(function(event) {
     33 |     event.preventDefault();
     34 | 
     35 |     const form = $(this).closest("form");
     36 |     const key = form.data("key");
     37 |     var params = {};
     38 | 
     39 |     const formData = new FormData(form.get()[0]);
     40 |     for (var [paramKey, paramValue] of formData.entries()) {
     41 |         var elem = form.find("[name=" + paramKey + "]")
     42 |         var dataType = elem.data('type') || 'string'
     43 | 
     44 |         if (dataType === 'integer' && paramValue) {
     45 |             let value = parseInt(paramValue)
     46 |             if (!isNaN(value)) {
     47 |               params[paramKey] = value
     48 |             }
     49 |         } else if (dataType === 'number' && paramValue) {
     50 |             let value = parseFloat(paramValue)
     51 |             if (!isNaN(value)) {
     52 |               params[paramKey] = value
     53 |             }
     54 |         } else if (dataType === 'boolean' && paramValue) {
     55 |             let value = {
     56 |                 'true': true,
     57 |                 'false': false
     58 |             }[paramValue.toLowerCase()]
     59 |             if (value !== undefined) {
     60 |               params[paramKey]
     61 |             }
     62 |         } else if (dataType === 'array' && paramValue) {
     63 |             try {
     64 |               params[paramKey] = JSON.parse(paramValue)
     65 |             } catch (err) {
     66 |               // Ignore malformed JSON
     67 |             }
     68 |         } else if (dataType === 'object' && paramValue) {
     69 |             try {
     70 |               params[paramKey] = JSON.parse(paramValue)
     71 |             } catch (err) {
     72 |               // Ignore malformed JSON
     73 |             }
     74 |         } else if (dataType === 'string' && paramValue) {
     75 |             params[paramKey] = paramValue
     76 |         }
     77 |     }
     78 | 
     79 |     form.find(":checkbox").each(function( index ) {
     80 |         // Handle unselected checkboxes
     81 |         var name = $(this).attr("name");
     82 |         if (!params.hasOwnProperty(name)) {
     83 |             params[name] = false
     84 |         }
     85 |     })
     86 | 
     87 |     function requestCallback(request) {
     88 |         // Fill in the "GET /foo/" display.
     89 |         let parser = document.createElement('a');
     90 |         parser.href = request.url;
     91 |         const method = request.options.method
     92 |         const path = parser.pathname + parser.hash + parser.search
     93 | 
     94 |         form.find(".request-method").text(method)
     95 |         form.find(".request-url").text(path)
     96 |     }
     97 | 
     98 |     function responseCallback(response, responseText) {
     99 |         // Display the 'Data'/'Raw' control.
    100 |         form.closest(".modal-content").find(".toggle-view").removeClass("hide")
    101 | 
    102 |         // Fill in the "200 OK" display.
    103 |         form.find(".response-status-code").removeClass("label-success").removeClass("label-danger")
    104 |         if (response.ok) {
    105 |             form.find(".response-status-code").addClass("label-success")
    106 |         } else {
    107 |             form.find(".response-status-code").addClass("label-danger")
    108 |         }
    109 |         form.find(".response-status-code").text(response.status)
    110 |         form.find(".meta").removeClass("hide")
    111 | 
    112 |         // Fill in the Raw HTTP response display.
    113 |         var panelText = 'HTTP/1.1 ' + response.status + ' ' + response.statusText + '\n';
    114 |         response.headers.forEach((header, key) => {
    115 |             panelText += normalizeHTTPHeader(key) + ': ' + header + '\n'
    116 |         })
    117 |         if (responseText) {
    118 |             panelText += '\n' + responseText
    119 |         }
    120 |         form.find(".response-raw-response").text(panelText)
    121 |     }
    122 | 
    123 |     // Instantiate a client to make the outgoing request.
    124 |     let options = {
    125 |         requestCallback: requestCallback,
    126 |         responseCallback: responseCallback,
    127 |     }
    128 | 
    129 |     // Setup authentication options.
    130 |     if (window.auth && window.auth.type === 'token') {
    131 |       // Header authentication
    132 |       options.auth = new coreapi.auth.TokenAuthentication({
    133 |         prefix: window.auth.scheme,
    134 |         token: window.auth.token
    135 |       })
    136 |     } else if (window.auth && window.auth.type === 'basic') {
    137 |       // Basic authentication
    138 |       options.auth = new coreapi.auth.BasicAuthentication({
    139 |         username: window.auth.username,
    140 |         password: window.auth.password
    141 |       })
    142 |     } else if (window.auth && window.auth.type === 'session') {
    143 |       // Session authentication
    144 |       options.auth = new coreapi.auth.SessionAuthentication({
    145 |         csrfCookieName: 'csrftoken',
    146 |         csrfHeaderName: 'X-CSRFToken'
    147 |       })
    148 |     }
    149 | 
    150 |     const client = new coreapi.Client(options)
    151 | 
    152 |     client.action(schema, key, params).then(function (data) {
    153 |         var response = JSON.stringify(data, null, 2);
    154 |         form.find(".request-awaiting").addClass("hide")
    155 |         form.find(".response-raw").addClass("hide")
    156 |         form.find(".response-data").addClass("hide")
    157 |         form.find(".response-data").text('')
    158 |         form.find(".response-data").jsonView(response)
    159 | 
    160 |         if (responseDisplay === 'data') {
    161 |             form.find(".response-data").removeClass("hide")
    162 |         } else {
    163 |             form.find(".response-raw").removeClass("hide")
    164 |         }
    165 |     }).catch(function (error) {
    166 |         var response = JSON.stringify(error.content, null, 2);
    167 |         form.find(".request-awaiting").addClass("hide")
    168 |         form.find(".response-raw").addClass("hide")
    169 |         form.find(".response-data").addClass("hide")
    170 |         form.find(".response-data").text('')
    171 |         form.find(".response-data").jsonView(response)
    172 | 
    173 |         if (responseDisplay === 'data') {
    174 |             form.find(".response-data").removeClass("hide")
    175 |         } else {
    176 |             form.find(".response-raw").removeClass("hide")
    177 |         }
    178 |     })
    179 | });
    180 | 
    181 | // 'Data'/'Raw' control
    182 | $('.toggle-view button').click(function() {
    183 |     responseDisplay = $(this).data("display-toggle");
    184 |     $(this).removeClass("btn-default").addClass('btn-info').siblings().removeClass('btn-info');
    185 |     if (responseDisplay === 'raw') {
    186 |         $(this).closest(".modal-content").find(".response-raw").removeClass("hide");
    187 |         $(this).closest(".modal-content").find(".response-data").addClass("hide");
    188 |     } else {
    189 |         $(this).closest(".modal-content").find(".response-data").removeClass("hide");
    190 |         $(this).closest(".modal-content").find(".response-raw").addClass("hide");
    191 |     }
    192 | });
    193 | 
    194 | // Authentication: none
    195 | $('#auth-control').find("[data-auth='none']").click(function (event) {
    196 |     event.preventDefault();
    197 |     window.auth = null;
    198 |     $('#selected-authentication').text('none');
    199 |     $('#auth-control').children().removeClass('active');
    200 |     $('#auth-control').find("[data-auth='none']").addClass('active');
    201 | })
    202 | 
    203 | // Authentication: token
    204 | $('form.authentication-token-form').submit(function(event) {
    205 |     event.preventDefault();
    206 |     const form = $(this).closest("form");
    207 |     const scheme = form.find('input#scheme').val();
    208 |     const token = form.find('input#token').val();
    209 |     window.auth = {
    210 |         'type': 'token',
    211 |         'scheme': scheme,
    212 |         'token': token
    213 |     };
    214 |     $('#selected-authentication').text('token');
    215 |     $('#auth-control').children().removeClass('active');
    216 |     $('#auth-control').find("[data-auth='token']").addClass('active');
    217 |     $('#auth_token_modal').modal('hide');
    218 | });
    219 | 
    220 | // Authentication: basic
    221 | $('form.authentication-basic-form').submit(function(event) {
    222 |     event.preventDefault();
    223 |     const form = $(this).closest("form");
    224 |     const username = form.find('input#username').val();
    225 |     const password = form.find('input#password').val();
    226 |     window.auth = {
    227 |         'type': 'basic',
    228 |         'username': username,
    229 |         'password': password
    230 |     };
    231 |     $('#selected-authentication').text('basic');
    232 |     $('#auth-control').children().removeClass('active');
    233 |     $('#auth-control').find("[data-auth='basic']").addClass('active');
    234 |     $('#auth_basic_modal').modal('hide');
    235 | });
    236 | 
    237 | // Authentication: session
    238 | $('form.authentication-session-form').submit(function(event) {
    239 |     event.preventDefault();
    240 |     window.auth = {
    241 |         'type': 'session',
    242 |     };
    243 |     $('#selected-authentication').text('session');
    244 |     $('#auth-control').children().removeClass('active');
    245 |     $('#auth-control').find("[data-auth='session']").addClass('active');
    246 |     $('#auth_session_modal').modal('hide');
    247 | });
    248 | 
    
    
    --------------------------------------------------------------------------------
    /static_cdn/rest_framework/docs/js/base.js:
    --------------------------------------------------------------------------------
     1 | function getSearchTerm()
     2 | {
     3 |     var sPageURL = window.location.search.substring(1);
     4 |     var sURLVariables = sPageURL.split('&');
     5 |     for (var i = 0; i < sURLVariables.length; i++)
     6 |     {
     7 |         var sParameterName = sURLVariables[i].split('=');
     8 |         if (sParameterName[0] == 'q')
     9 |         {
    10 |             return sParameterName[1];
    11 |         }
    12 |     }
    13 | }
    14 | 
    15 | $(document).ready(function() {
    16 | 
    17 |     var search_term = getSearchTerm(),
    18 |         $search_modal = $('#mkdocs_search_modal');
    19 | 
    20 |     if(search_term){
    21 |         $search_modal.modal();
    22 |     }
    23 | 
    24 |     // make sure search input gets autofocus everytime modal opens.
    25 |     $search_modal.on('shown.bs.modal', function () {
    26 |         $search_modal.find('#mkdocs-search-query').focus();
    27 |     });
    28 | 
    29 |     // Highlight.js
    30 |     hljs.initHighlightingOnLoad();
    31 |     $('table').addClass('table table-striped table-hover');
    32 | });
    33 | 
    34 | 
    35 | $('body').scrollspy({
    36 |     target: '.bs-sidebar',
    37 | });
    38 | 
    39 | /* Prevent disabled links from causing a page reload */
    40 | $("li.disabled a").click(function() {
    41 |     event.preventDefault();
    42 | });
    43 | 
    
    
    --------------------------------------------------------------------------------
    /static_cdn/rest_framework/docs/js/jquery.json-view.min.js:
    --------------------------------------------------------------------------------
    1 | /**
    2 |  * jquery.json-view - jQuery collapsible JSON plugin
    3 |  * @version v1.0.0
    4 |  * @link http://github.com/bazh/jquery.json-view
    5 |  * @license MIT
    6 |  */
    7 | !function(e){"use strict";var n=function(n){var a=e("",{"class":"collapser",on:{click:function(){var n=e(this);n.toggleClass("collapsed");var a=n.parent().children(".block"),p=a.children("ul");n.hasClass("collapsed")?(p.hide(),a.children(".dots, .comments").show()):(p.show(),a.children(".dots, .comments").hide())}}});return n&&a.addClass("collapsed"),a},a=function(a,p){var t=e.extend({},{nl2br:!0},p),r=function(e){return e.toString()?e.toString().replace(/&/g,"&").replace(/"/g,""").replace(//g,">"):""},s=function(n,a){return e("",{"class":a,html:r(n)})},l=function(a,p){switch(e.type(a)){case"object":p||(p=0);var c=e("",{"class":"block"}),d=Object.keys(a).length;if(!d)return c.append(s("{","b")).append(" ").append(s("}","b"));c.append(s("{","b"));var i=e("