First commit

This commit is contained in:
Trullemans Gregory 2021-11-02 14:05:32 +01:00
commit 63037499df
135 changed files with 68041 additions and 0 deletions

28
.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
# Django #
*.log
*.pot
*.pyc
__pycache__
db.sqlite3
media
# Python #
*.py[cod]
*$py.class
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Visual Studio Code #
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history

0
README.md Normal file
View File

0
Ultron/__init__.py Normal file
View File

16
Ultron/asgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
ASGI config for Ultron project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Ultron.settings')
application = get_asgi_application()

132
Ultron/settings.py Normal file
View File

@ -0,0 +1,132 @@
"""
Django settings for Ultron project.
Generated by 'django-admin startproject' using Django 3.2.8.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-g_eoy6z%xshku4o5#k%o$4974%i_%nb%_pz80!$_#+t%f$ex9t'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_extensions',
'jumpers',
'followup',
'tools',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'Ultron.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "templates"),],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'Ultron.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = "/static/"
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)
STATIC_ROOT = BASE_DIR / 'staticfiles'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

33
Ultron/urls.py Normal file
View File

@ -0,0 +1,33 @@
"""Ultron URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
import jumpers.urls
import Ultron.views
urlpatterns = [
path(r"jumper/", include(jumpers.urls.jumper_urlpatterns)),
path(r"club/", include(jumpers.urls.club_urlpatterns)),
# path(r"search/", config.views.search, name="global_search"),
# login & logout
# path(r"login/", Ultron.views.login, name="login"),
path(r"logout/", Ultron.views.logout, name="logout"),
path(r"", Ultron.views.home, name="home"),
path('admin/', admin.site.urls),
]

114
Ultron/views.py Normal file
View File

@ -0,0 +1,114 @@
from datetime import datetime, timedelta, date
from functools import reduce
import operator
from django.db.models import Q
from django.shortcuts import render
from django.template import RequestContext
from django.utils import timezone
from django.utils.html import format_html
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods
# def login(request):
# """
# Formulaire d'authentifictation.
# """
# club_list = Club.objects.all()
# if request.method == "POST":
# username = request.POST["login"]
# password = request.POST["password"]
# user = authenticate(username=username, password=password)
# if user is not None: # Pq pas "if user:" ??
# if user.is_active:
# auth_login(request, user)
# try:
# profile = Profile.objects.get(user=user)
# request.session["profileid"] = profile.id
# request.session["template"] = profile.template_color
# request.session["sidebar"] = profile.sidebar_color
# request.session["is_sidebar_minified"] = profile.is_sidebar_minified
# except Exception:
# pass
# request.session["clubid"] = request.POST.get("clubid", None)
# return HttpResponseRedirect("/")
# else:
# context = {"message": "Account disabled.", "clubs": club_list}
# else:
# context = {"message": "Wrong login/password.", "clubs": club_list}
# else:
# context = {"clubs": club_list}
# return render(request, "login.html", context)
@login_required
@require_http_methods(["GET"])
def logout(request):
"""
Fonction de déconnexion
"""
auth_logout(request)
return HttpResponseRedirect("/login/")
@login_required
@require_http_methods(["GET"])
def home(request):
"""Génère la page d'accueil du site basée sur la saison (si celle-ci est
connue)
.. todo:: vérifier s'il y a des élèves qui devait participer à une compé-
tition (passée) pour laquelle il n'y a pas de points encodés. Si c'est le
cas, générer un popup. (le coach doit soit encoder les points soit suppri-
mer la participation de l'élève à l'event)
"""
context = {}
return render(request, "index.html", context)
# @login_required
# @require_http_methods(["GET"])
# def search(request):
# """
# Recherche globale au travers de toutes les applications.
# """
# pattern = request.GET.get("pattern", None)
# if pattern:
# event_list = Event.objects.filter(
# name__icontains=pattern
# ) # ou gymnaste qui y participe !
# gymnast_list = Gymnast.objects.filter(
# Q(user__last_name__icontains=pattern)
# | Q(user__first_name__icontains=pattern)
# )
# accident_list = Accident.objects.filter(
# Q(gymnast__user__last_name__icontains=pattern)
# | Q(gymnast__user__first_name__icontains=pattern)
# )
# skill_list = Skill.objects.filter(
# Q(longLabel__icontains=pattern) | Q(shortLabel__icontains=pattern)
# )
# routine_list = Routine.objects.filter(
# Q(longLabel__icontains=pattern) | Q(shortLabel__icontains=pattern)
# )
# context = {
# "event_list": event_list,
# "gymnast_list": gymnast_list,
# "accident_list": accident_list,
# "skill_list": skill_list,
# "routine_list": routine_list,
# }
# else:
# context = {}
# return render(request, "results.html", context)

16
Ultron/wsgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
WSGI config for Ultron project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Ultron.settings')
application = get_wsgi_application()

0
followup/__init__.py Normal file
View File

30
followup/admin.py Normal file
View File

@ -0,0 +1,30 @@
from django.contrib import admin
from .models import Chrono, LearnedSkill
from django_extensions.admin import ForeignKeyAutocompleteAdmin
class LearnedSkillAdmin(admin.ModelAdmin):
model = LearnedSkill
list_display = ("date", "jumper", "skill")
# search_fields = ('jumper', 'routine')
autocomplete_fields = ["jumper"]
related_search_fields = {
"jumper": ("last_name", "first_name")
}
class ChronoAdmin(ForeignKeyAutocompleteAdmin):
model = Chrono
list_display = ("date", "jumper", "score", "type")
list_filter = ("type", )
# search_fields = ('jumper', 'routine')
autocomplete_fields = ["jumper"]
related_search_fields = {
"jumper": ("last_name", "first_name")
}
admin.site.register(Chrono, ChronoAdmin)
admin.site.register(LearnedSkill, LearnedSkillAdmin)

6
followup/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class FollowupConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'followup'

View File

@ -0,0 +1,48 @@
# Generated by Django 3.2.8 on 2021-10-29 11:36
import datetime
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('jumpers', '0004_auto_20211029_1130'),
]
operations = [
migrations.CreateModel(
name='Chrono',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('type', models.PositiveSmallIntegerField(choices=[(0, '10 |'), (1, 'Routine')], verbose_name='type')),
('skill', models.CharField(max_length=25)),
('score', models.DecimalField(decimal_places=2, max_digits=5)),
('date', models.DateField(default=datetime.date.today, verbose_name='Date')),
('jumper', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chronos', to='jumpers.jumper', verbose_name='Jumper')),
],
options={
'verbose_name': 'Chrono',
'verbose_name_plural': 'Chronos',
'ordering': ['date', 'jumper'],
},
),
migrations.CreateModel(
name='LearnedSkill',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('skill', models.CharField(max_length=25)),
('date', models.DateField(default=datetime.date.today, verbose_name='Date')),
('jumper', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='learned_skill', to='jumpers.jumper', verbose_name='Jumper')),
],
options={
'verbose_name': 'Learned Skill',
'verbose_name_plural': 'Learned Skills',
'ordering': ['date', 'jumper'],
'unique_together': {('jumper', 'skill')},
},
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 3.2.8 on 2021-10-29 11:38
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('followup', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='chrono',
name='skill',
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.8 on 2021-10-31 15:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('followup', '0002_remove_chrono_skill'),
]
operations = [
migrations.AddField(
model_name='chrono',
name='score_type',
field=models.PositiveSmallIntegerField(choices=[(0, 'Chrono'), (1, 'ToF')], default=0, verbose_name='type'),
preserve_default=False,
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 3.2.8 on 2021-10-31 15:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('followup', '0003_chrono_score_type'),
]
operations = [
migrations.AlterField(
model_name='chrono',
name='score',
field=models.DecimalField(decimal_places=3, max_digits=5),
),
migrations.AlterField(
model_name='chrono',
name='score_type',
field=models.PositiveSmallIntegerField(choices=[(0, 'Chrono'), (1, 'ToF')], verbose_name='Score type'),
),
migrations.AlterField(
model_name='chrono',
name='type',
field=models.PositiveSmallIntegerField(choices=[(0, '10 |'), (1, 'Routine')], verbose_name='Chrono type'),
),
]

View File

77
followup/models.py Normal file
View File

@ -0,0 +1,77 @@
from django.db import models
from datetime import date
from jumpers.models import Jumper
class LearnedSkill(models.Model):
"""
Représente les skills qu'un gymnaste sait faire.
"""
class Meta:
verbose_name = "Learned Skill"
verbose_name_plural = "Learned Skills"
ordering = ["date", "jumper"]
unique_together = ("jumper", "skill")
jumper = models.ForeignKey(
Jumper,
verbose_name="Jumper",
related_name="learned_skill",
on_delete=models.CASCADE,
)
skill = models.CharField(max_length=25, null=False, blank=False)
date = models.DateField(default=date.today, verbose_name="Date")
def __str__(self):
return "%s - %s (%s)" % (
self.jumper,
self.skill,
self.date,
)
class Chrono(models.Model):
"""
Représente les chronos (de chandelles ou de série) enregistrés pour un(e) gymnaste.
"""
TYPE_CHOICES = ((0, "10 |"), (1, "Routine"))
SCORE_TYPE_CHOICE = ((0, "Chrono"), (1, "ToF"))
class Meta:
verbose_name = "Chrono"
verbose_name_plural = "Chronos"
ordering = ["date", "jumper"]
# unique_together = ("jumper", "skill")
jumper = models.ForeignKey(
Jumper,
verbose_name="Jumper",
related_name="chronos",
on_delete=models.CASCADE,
)
type = models.PositiveSmallIntegerField(
choices=TYPE_CHOICES, verbose_name="Chrono type"
)
score_type = models.PositiveSmallIntegerField(
choices=SCORE_TYPE_CHOICE, verbose_name="Score type"
)
score = models.DecimalField(max_digits=5, decimal_places=3)
date = models.DateField(default=date.today, verbose_name="Date")
def __str__(self):
return "%s - %s (%s - %s)" % (
self.jumper,
self.score,
self.date,
self.type,
)
@property
def tof(self):
""" Renvoie le time of flight d'un gymnaste. """
if self.score_type == 1:
return self.score
else:
tof = round(( self.score * 13 ) / 15, 3)
tof = ( tof * 1000 ) - (( tof * 1000 ) % 5)
return tof / 1000

3
followup/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

3
followup/views.py Normal file
View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

0
jumpers/__init__.py Normal file
View File

30
jumpers/admin.py Normal file
View File

@ -0,0 +1,30 @@
from django.contrib import admin
from .models import Jumper, Club
class ClubAdmin(admin.ModelAdmin):
model = Club
list_display = ("name", "acronym", "active")
ordering = ("name",)
list_filter = ("active",)
search_fields = ("name",)
class JumperAdmin(admin.ModelAdmin):
model = Jumper
fields = (
"last_name",
"first_name",
"birthdate",
"gender",
"is_active",
"club"
)
list_display = ("last_name", "first_name", "age", "club", "is_active")
list_filter = ("gender", "is_active", "club")
search_fields = ("last_name", "first_name")
autocomplete_fields = ("club",)
admin.site.register(Jumper, JumperAdmin)
admin.site.register(Club, ClubAdmin)

6
jumpers/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class JumpersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'jumpers'

View File

@ -0,0 +1,43 @@
# Generated by Django 3.2.8 on 2021-10-29 10:52
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Club',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Name')),
('acronym', models.CharField(max_length=4, verbose_name='Acronym')),
('active', models.BooleanField(default=1, verbose_name='Active')),
],
options={
'verbose_name': 'Club',
'verbose_name_plural': 'Clubs',
},
),
migrations.CreateModel(
name='Jumper',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('last_name', models.CharField(blank=True, max_length=40, null=True)),
('first_name', models.CharField(blank=True, max_length=25, null=True)),
('birthdate', models.DateField(verbose_name='Date de naissance')),
('gender', models.PositiveSmallIntegerField(choices=[(0, 'Male'), (1, 'Female')], verbose_name='Sexe')),
('club', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='jumpers', to='jumpers.club')),
],
options={
'verbose_name': 'Jumper',
'verbose_name_plural': 'Jumpers',
},
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.8 on 2021-10-29 11:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('jumpers', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='jumper',
name='active',
field=models.BooleanField(default=1, verbose_name='Active'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.8 on 2021-10-29 11:13
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('jumpers', '0002_jumper_active'),
]
operations = [
migrations.RenameField(
model_name='jumper',
old_name='active',
new_name='is_active',
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.8 on 2021-10-29 11:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('jumpers', '0003_rename_active_jumper_is_active'),
]
operations = [
migrations.AlterField(
model_name='jumper',
name='first_name',
field=models.CharField(max_length=25),
),
migrations.AlterField(
model_name='jumper',
name='last_name',
field=models.CharField(max_length=40),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.8 on 2021-10-31 09:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('jumpers', '0004_auto_20211029_1130'),
]
operations = [
migrations.AddField(
model_name='club',
name='city',
field=models.CharField(default='Oostende', max_length=255, verbose_name='City'),
preserve_default=False,
),
]

View File

56
jumpers/models.py Normal file
View File

@ -0,0 +1,56 @@
from django.db import models
from datetime import date
# import pendulum
class Jumper(models.Model):
"""Représente un gymnaste.
Un gymnaste peut être actif ou inactif.
"""
class Meta:
verbose_name = "Jumper"
verbose_name_plural = "Jumpers"
GENDER_CHOICES = ((0, "Male"), (1, "Female"))
last_name = models.CharField(max_length=40, null=False, blank=False)
first_name = models.CharField(max_length=25, null=False, blank=False)
birthdate = models.DateField(verbose_name="Date de naissance")
gender = models.PositiveSmallIntegerField(
choices=GENDER_CHOICES, verbose_name="Sexe"
)
is_active = models.BooleanField(default=1, verbose_name="Active")
club = models.ForeignKey(
"Club", null=True, on_delete=models.SET_NULL, related_name="jumpers"
)
def __str__(self):
return u"%s, %s" % (self.last_name, self.first_name)
@property
def age(self):
""" Renvoie l'âge d'un gymnaste. """
today = date.today()
return (
today.year
- self.birthdate.year
- ((today.month, today.day) < (self.birthdate.month, self.birthdate.day))
)
class Club(models.Model):
"""
Représente un club. Pour faciliter les filtres, un club peut être actif ou non.
"""
class Meta:
verbose_name = "Club"
verbose_name_plural = "Clubs"
name = models.CharField(max_length=255, verbose_name="Name")
city = models.CharField(max_length=255, verbose_name="City")
acronym = models.CharField(max_length=4, verbose_name="Acronym")
active = models.BooleanField(default=1, verbose_name="Active")
def __str__(self):
return "%s (%s)" % (self.name, self.acronym)

3
jumpers/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

12
jumpers/urls.py Normal file
View File

@ -0,0 +1,12 @@
from django.urls import path
from . import views
jumper_urlpatterns = [
path(r"", views.jumper_listing, name="jumper_list"),
path(r"details/<int:jumperid>/", views.jumper_details, name="jumper_details"),
]
club_urlpatterns = [
path(r"", views.club_listing, name="club_list"),
]

50
jumpers/views.py Normal file
View File

@ -0,0 +1,50 @@
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from django.views.decorators.http import require_http_methods
from .models import Club, Jumper
from followup.models import Chrono, LearnedSkill
# @login_required
@require_http_methods(["GET"])
def club_listing(request):
"""
Liste tous les clubs connus
"""
club_list = Club.objects.all()
context = {"club_list": club_list}
return render(request, "clubs/list.html", context)
# @login_required
@require_http_methods(["GET"])
def jumper_listing(request):
"""
Liste tous les gymnasts connus
"""
jumper_list = Jumper.objects.all()
context = {"jumper_list": jumper_list}
return render(request, "jumpers/list.html", context)
# @login_required
@require_http_methods(["GET"])
def jumper_details(request, jumperid):
"""
Récupère toutes les informations d'un gymnaste.
"""
jumper = get_object_or_404(Jumper, pk=jumperid)
learnedskills_list = LearnedSkill.objects.filter(jumper=jumperid).order_by('-date')[:8]
chronos_list = Chrono.objects.filter(jumper=jumperid).order_by('-date')[:8]
straightjump_score = Chrono.objects.filter(jumper=jumperid).filter(type=0).order_by('-date')
routine_score = Chrono.objects.filter(jumper=jumperid).filter(type=1).order_by('-date')
context = {
'jumper': jumper,
'learnedskills_list': learnedskills_list,
'chronos_list': chronos_list,
'straightjump_score': straightjump_score,
'routine_score': routine_score
}
return render(request, "jumpers/details.html", context)

22
manage.py Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Ultron.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

16
static/css/app2.css Normal file
View File

@ -0,0 +1,16 @@
.table-condensed>tbody>tr>td,
.table-condensed>tbody>tr>th,
.table-condensed>tfoot>tr>td,
.table-condensed>tfoot>tr>th,
.table-condensed>thead>tr>td,
.table-condensed>thead>tr>th {
padding: 2px !important;
}
a.maillink {
font-weight: bold !important;
}
.maillink {
font-weight: bold !important;
}

View File

@ -0,0 +1,79 @@
global body padding
body {
padding-top: 20px;
padding-bottom: 20px;
}
@media (min-width: 768px) {
body {
/*padding-top: 50px;*/
padding-bottom: 50px;
}
}
.sidebar-form {
padding-top: 2px;
}
/* global spacing overrides */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
margin-top: 0;
}
hr {
margin-top: 30px;
margin-bottom: 30px;
}
.navbar-fixed-top,
.navbar-static-top {
border-bottom: 0;
}
/* ADD BY GREGG */
/*@media (min-width: 992px) {
nav.sidebar-nav {
position:fixed;
}
}*/
.center {
text-align: center;
}
img.center {
display: block;
margin-left: auto;
margin-right: auto;
}
.scrollable {
overflow: auto;
}
th.centered {
text-align: center;
}
th.push-right {
text-align: right;
}
td.centered {
text-align: center;
}
td.push-right {
text-align: right;
}
.img-responsive {
border-radius: 5px;
}
.information {
text-align: justify;
}

29678
static/css/black-dashboard.css Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

31
static/css/black-dashboard.min.css vendored Normal file

File diff suppressed because one or more lines are too long

543
static/css/nucleo-icons.css Normal file
View File

@ -0,0 +1,543 @@
/* --------------------------------
Nucleo Outline Web Font - nucleoapp.com/
License - nucleoapp.com/license/
Created using IcoMoon - icomoon.io
-------------------------------- */
@font-face {
font-family: 'Nucleo';
src: url('../fonts/nucleo.eot');
src: url('../fonts/nucleo.eot') format('embedded-opentype'), url('../fonts/nucleo.woff2') format('woff2'), url('../fonts/nucleo.woff') format('woff'), url('../fonts/nucleo.ttf') format('truetype'), url('../fonts/nucleo.svg') format('svg');
font-weight: normal;
font-style: normal;
}
/*------------------------
base class definition
-------------------------*/
.tim-icons {
display: inline-block;
font: normal normal normal 1em/1 'Nucleo';
vertical-align: middle;
speak: none;
text-transform: none;
/* Better Font Rendering */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.font-icon-detail {
text-align: center;
padding: 45px 0 30px;
border: 1px solid #e44cc4;
border-radius: .1875rem;
margin: 15px 0;
min-height: 168px;
}
.font-icon-detail i {
color: #FFFFFF;
font-size: 1.5em;
}
.font-icon-detail p {
color: #e44cc4 !important;
margin-top: 30px;
padding: 0 10px;
font-size: .7142em;
}
/*------------------------
change icon size
-------------------------*/
.tim-icons-sm {
font-size: 0.8em;
}
.tim-icons-lg {
font-size: 1.2em;
}
/* absolute units */
.tim-icons-16 {
font-size: 16px;
}
.tim-icons-32 {
font-size: 32px;
}
/*----------------------------------
add a square/circle background
-----------------------------------*/
.tim-icons-bg-square,
.tim-icons-bg-circle {
padding: 0.35em;
}
.tim-icons-bg-circle {
border-radius: 50%;
}
/*------------------------
list icons
-------------------------*/
/*------------------------
spinning icons
-------------------------*/
.tim-icons-is-spinning {
-webkit-animation: tim-icons-spin 2s infinite linear;
-moz-animation: tim-icons-spin 2s infinite linear;
animation: tim-icons-spin 2s infinite linear;
}
@-webkit-keyframes tim-icons-spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes tim-icons-spin {
0% {
-moz-transform: rotate(0deg);
}
100% {
-moz-transform: rotate(360deg);
}
}
@keyframes tim-icons-spin {
0% {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
/*------------------------
rotated/flipped icons
-------------------------*/
/*------------------------
icons
-------------------------*/
.icon-alert-circle-exc::before {
content: "\ea02";
}
.icon-align-center::before {
content: "\ea03";
}
.icon-align-left-2::before {
content: "\ea04";
}
.icon-app::before {
content: "\ea05";
}
.icon-atom::before {
content: "\ea06";
}
.icon-attach-87::before {
content: "\ea07";
}
.icon-badge::before {
content: "\ea08";
}
.icon-bag-16::before {
content: "\ea09";
}
.icon-bank::before {
content: "\ea0a";
}
.icon-basket-simple::before {
content: "\ea0b";
}
.icon-bell-55::before {
content: "\ea0c";
}
.icon-bold::before {
content: "\ea0d";
}
.icon-book-bookmark::before {
content: "\ea0e";
}
.icon-bulb-63::before {
content: "\ea0f";
}
.icon-bullet-list-67::before {
content: "\ea10";
}
.icon-bus-front-12::before {
content: "\ea11";
}
.icon-button-pause::before {
content: "\ea12";
}
.icon-button-power::before {
content: "\ea13";
}
.icon-calendar-60::before {
content: "\ea14";
}
.icon-camera-18::before {
content: "\ea15";
}
.icon-caps-small::before {
content: "\ea16";
}
.icon-cart::before {
content: "\ea17";
}
.icon-chart-bar-32::before {
content: "\ea18";
}
.icon-chart-pie-36::before {
content: "\ea19";
}
.icon-chat-33::before {
content: "\ea1a";
}
.icon-check-2::before {
content: "\ea1b";
}
.icon-cloud-download-93::before {
content: "\ea1c";
}
.icon-cloud-upload-94::before {
content: "\ea1d";
}
.icon-coins::before {
content: "\ea1e";
}
.icon-compass-05::before {
content: "\ea1f";
}
.icon-controller::before {
content: "\ea20";
}
.icon-credit-card::before {
content: "\ea21";
}
.icon-delivery-fast::before {
content: "\ea22";
}
.icon-double-left::before {
content: "\ea23";
}
.icon-double-right::before {
content: "\ea24";
}
.icon-email-85::before {
content: "\ea25";
}
.icon-gift-2::before {
content: "\ea26";
}
.icon-globe-2::before {
content: "\ea27";
}
.icon-headphones::before {
content: "\ea28";
}
.icon-heart-2::before {
content: "\ea29";
}
.icon-html5::before {
content: "\ea2a";
}
.icon-image-02::before {
content: "\ea2b";
}
.icon-istanbul::before {
content: "\ea2c";
}
.icon-key-25::before {
content: "\ea2d";
}
.icon-laptop::before {
content: "\ea2e";
}
.icon-light-3::before {
content: "\ea2f";
}
.icon-link-72::before {
content: "\ea30";
}
.icon-lock-circle::before {
content: "\ea31";
}
.icon-map-big::before {
content: "\ea32";
}
.icon-minimal-down::before {
content: "\ea33";
}
.icon-minimal-left::before {
content: "\ea34";
}
.icon-minimal-right::before {
content: "\ea35";
}
.icon-minimal-up::before {
content: "\ea36";
}
.icon-mobile::before {
content: "\ea37";
}
.icon-molecule-40::before {
content: "\ea38";
}
.icon-money-coins::before {
content: "\ea39";
}
.icon-notes::before {
content: "\ea3a";
}
.icon-palette::before {
content: "\ea3b";
}
.icon-paper::before {
content: "\ea3c";
}
.icon-pencil::before {
content: "\ea3d";
}
.icon-pin::before {
content: "\ea3e";
}
.icon-planet::before {
content: "\ea3f";
}
.icon-puzzle-10::before {
content: "\ea40";
}
.icon-satisfied::before {
content: "\ea41";
}
.icon-scissors::before {
content: "\ea42";
}
.icon-send::before {
content: "\ea43";
}
.icon-settings-gear-63::before {
content: "\ea44";
}
.icon-settings::before {
content: "\ea45";
}
.icon-simple-add::before {
content: "\ea46";
}
.icon-simple-delete::before {
content: "\ea47";
}
.icon-simple-remove::before {
content: "\ea48";
}
.icon-single-02::before {
content: "\ea49";
}
.icon-single-copy-04::before {
content: "\ea4a";
}
.icon-sound-wave::before {
content: "\ea4b";
}
.icon-spaceship::before {
content: "\ea4c";
}
.icon-square-pin::before {
content: "\ea4d";
}
.icon-support-17::before {
content: "\ea4e";
}
.icon-tablet-2::before {
content: "\ea4f";
}
.icon-tag::before {
content: "\ea50";
}
.icon-tap-02::before {
content: "\ea51";
}
.icon-tie-bow::before {
content: "\ea52";
}
.icon-time-alarm::before {
content: "\ea53";
}
.icon-trash-simple::before {
content: "\ea54";
}
.icon-triangle-right-17::before {
content: "\ea55";
}
.icon-trophy::before {
content: "\ea56";
}
.icon-tv-2::before {
content: "\ea57";
}
.icon-upload::before {
content: "\ea58";
}
.icon-user-run::before {
content: "\ea59";
}
.icon-vector::before {
content: "\ea5a";
}
.icon-video-66::before {
content: "\ea5b";
}
.icon-volume-98::before {
content: "\ea5c";
}
.icon-wallet-43::before {
content: "\ea5d";
}
.icon-watch-time::before {
content: "\ea5e";
}
.icon-wifi::before {
content: "\ea5f";
}
.icon-world::before {
content: "\ea60";
}
.icon-zoom-split::before {
content: "\ea61";
}
.icon-refresh-01::before {
content: "\ea62";
}
.icon-refresh-02::before {
content: "\ea63";
}
.icon-shape-star::before {
content: "\ea64";
}
.icon-components::before {
content: "\ea65";
}

BIN
static/fonts/nucleo.eot Normal file

Binary file not shown.

BIN
static/fonts/nucleo.ttf Normal file

Binary file not shown.

BIN
static/fonts/nucleo.woff Normal file

Binary file not shown.

BIN
static/fonts/nucleo.woff2 Normal file

Binary file not shown.

BIN
static/img/AU.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
static/img/BR.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
static/img/DE.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
static/img/GB.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
static/img/RO.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
static/img/US.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
static/img/apple-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
static/img/asc.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 B

BIN
static/img/bg.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

BIN
static/img/card-danger.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

BIN
static/img/card-info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

BIN
static/img/card-primary.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
static/img/card-success.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
static/img/card-warning.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
static/img/desc.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 B

BIN
static/img/emilyz.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
static/img/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
static/img/gucci.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

BIN
static/img/header.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
static/img/img_3115.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
static/img/jacket.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

BIN
static/img/james.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
static/img/jana.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
static/img/lora.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
static/img/mike.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
static/img/placeholder.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
static/img/robi.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
static/img/t-shirt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

BIN
static/img/tania.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@ -0,0 +1,431 @@
"use strict";
/*!
=========================================================
* Black Dashboard PRO - v1.0.0
=========================================================
* Product Page: https://demos.creative-tim.com/marketplace/black-dashboard-pro/examples/dashboard.html
* Copyright 2018 Creative Tim (http://www.creative-tim.com)
* Coded by www.creative-tim.com
=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
var transparent = true;
var transparentDemo = true;
var fixedTop = false;
var navbar_initialized = false;
var backgroundOrange = false;
var sidebar_mini_active = false;
var toggle_initialized = false;
var $html = $('html');
var $body = $('body');
var $navbar_minimize_fixed = $('.navbar-minimize-fixed');
var $collapse = $('.collapse');
var $navbar = $('.navbar');
var $tagsinput = $('.tagsinput');
var $selectpicker = $('.selectpicker');
var $navbar_color = $('.navbar[color-on-scroll]');
var $full_screen_map = $('.full-screen-map');
var $datetimepicker = $('.datetimepicker');
var $datepicker = $('.datepicker');
var $timepicker = $('.timepicker');
var seq = 0,
delays = 80,
durations = 500;
var seq2 = 0,
delays2 = 80,
durations2 = 500;
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
if (immediate && !timeout) func.apply(context, args);
};
};
(function() {
var isWindows = navigator.platform.indexOf('Win') > -1 ? true : false;
if (isWindows) {
// if we are on windows OS we activate the perfectScrollbar function
if ($('.main-panel').length != 0) {
var ps = new PerfectScrollbar('.main-panel', {
wheelSpeed: 2,
wheelPropagation: true,
minScrollbarLength: 20,
suppressScrollX: true
});
}
if ($('.sidebar .sidebar-wrapper').length != 0) {
var ps1 = new PerfectScrollbar('.sidebar .sidebar-wrapper');
$('.table-responsive').each(function() {
var ps2 = new PerfectScrollbar($(this)[0]);
});
}
$html.addClass('perfect-scrollbar-on');
} else {
$html.addClass('perfect-scrollbar-off');
}
})();
$(document).ready(function() {
var scroll_start = 0;
var startchange = $('.row');
var offset = startchange.offset();
var scrollElement = navigator.platform.indexOf('Win') > -1 ? $(".ps") : $(window);
scrollElement.scroll(function() {
scroll_start = $(this).scrollTop();
if (scroll_start > 50) {
$navbar_minimize_fixed.css('opacity', '1');
} else {
$navbar_minimize_fixed.css('opacity', '0');
}
});
// hide the siblings opened collapse
$collapse.on('show.bs.collapse', function() {
$(this).parent().siblings().children('.collapse').each(function() {
$(this).collapse('hide');
});
});
// Activate the Tooltips
$('[data-toggle="tooltip"], [rel="tooltip"]').tooltip();
// Activate Popovers and set color for popovers
$('[data-toggle="popover"]').each(function() {
color_class = $(this).data('color');
$(this).popover({
template: '<div class="popover popover-' + color_class + '" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'
});
});
var tagClass = $tagsinput.data('color');
if ($tagsinput.length != 0) {
$tagsinput.tagsinput();
}
$('.bootstrap-tagsinput').find('.tag').addClass('badge-' + tagClass);
// Activate bootstrap-select
if ($selectpicker.length != 0) {
$selectpicker.selectpicker({
iconBase: "tim-icons",
tickIcon: "icon-check-2"
});
}
//when you click the modal search button the navbar will not be collapsed
$("#search-button").click(function() {
$(this).closest('.navbar-collapse').removeClass('show');
$navbar.addClass('navbar-transparent').removeClass('bg-white');
});
blackDashboard.initMinimizeSidebar();
var scroll_distance = $navbar_color.attr('color-on-scroll') || 500;
// Check if we have the class "navbar-color-on-scroll" then add the function to remove the class "navbar-transparent" so it will transform to a plain color.
if ($navbar_color.length != 0) {
blackDashboard.checkScrollForTransparentNavbar();
$(window).on('scroll', blackDashboard.checkScrollForTransparentNavbar)
}
if ($full_screen_map.length == 0 && $('.bd-docs').length == 0) {
// On click navbar-collapse the menu will be white not transparent
$('.navbar-toggler').click(function() {
$collapse.on('show.bs.collapse', function() {
$(this).closest('.navbar').removeClass('navbar-transparent').addClass('bg-white');
}).on('hide.bs.collapse', function() {
$(this).closest('.navbar').addClass('navbar-transparent').removeClass('bg-white');
});
$navbar.css('transition', '');
});
}
$navbar.css({
'top': '0',
'transition': 'all .5s linear'
});
$('.form-control').on("focus", function() {
$(this).parent('.input-group').addClass("input-group-focus");
}).on("blur", function() {
$(this).parent(".input-group").removeClass("input-group-focus");
});
// Activate bootstrapSwitch
$('.bootstrap-switch').each(function() {
var data_on_label = $(this).data('on-label') || '';
var data_off_label = $(this).data('off-label') || '';
$(this).bootstrapSwitch({
onText: data_on_label,
offText: data_off_label
});
});
});
$(document).on('click', '.navbar-toggle', function() {
var $toggle = $(this);
if (blackDashboard.misc.navbar_menu_visible == 1) {
$html.removeClass('nav-open');
blackDashboard.misc.navbar_menu_visible = 0;
setTimeout(function() {
$toggle.removeClass('toggled');
$('.bodyClick').remove();
}, 550);
} else {
setTimeout(function() {
$toggle.addClass('toggled');
}, 580);
var div = '<div class="bodyClick"></div>';
$(div).appendTo('body').click(function() {
$html.removeClass('nav-open');
blackDashboard.misc.navbar_menu_visible = 0;
setTimeout(function() {
$toggle.removeClass('toggled');
$('.bodyClick').remove();
}, 550);
});
$html.addClass('nav-open');
blackDashboard.misc.navbar_menu_visible = 1;
}
});
$(window).resize(function() {
// reset the seq for charts drawing animations
seq = seq2 = 0;
if ($full_screen_map.length == 0 && $('.bd-docs').length == 0) {
var isExpanded = $navbar.find('[data-toggle="collapse"]').attr("aria-expanded");
if ($navbar.hasClass('bg-white') && $(window).width() > 991) {
$navbar.removeClass('bg-white').addClass('navbar-transparent');
} else if ($navbar.hasClass('navbar-transparent') && $(window).width() < 991 && isExpanded != "false") {
$navbar.addClass('bg-white').removeClass('navbar-transparent');
}
}
});
var blackDashboard = {
misc: {
navbar_menu_visible: 0
},
checkScrollForTransparentNavbar: debounce(function() {
if ($(document).scrollTop() > scroll_distance) {
if (transparent) {
transparent = false;
$navbar_color.removeClass('navbar-transparent');
}
} else {
if (!transparent) {
transparent = true;
$navbar_color.addClass('navbar-transparent');
}
}
}, 17),
// Activate DateTimePicker
initDateTimePicker: function() {
if ($datetimepicker.length != 0) {
$datetimepicker.datetimepicker({
format: 'YYYY-MM-DD H:mm',
// inline: true,
// sideBySide: true,
icons: {
time: "tim-icons icon-watch-time",
date: "tim-icons icon-calendar-60",
up: "far fa-chevron-up",
down: "far fa-chevron-down",
previous: 'tim-icons icon-minimal-left',
next: 'tim-icons icon-minimal-right',
today: 'far fa-screenshot',
clear: 'far fa-trash',
close: 'far fa-remove'
}
});
}
if ($datepicker.length != 0) {
$datepicker.datetimepicker({
// format: 'MM/DD/YYYY',
format: 'YYYY-MM-DD',
icons: {
time: "tim-icons icon-watch-time",
date: "tim-icons icon-calendar-60",
up: "far fa-chevron-up",
down: "far fa-chevron-down",
previous: 'tim-icons icon-minimal-left',
next: 'tim-icons icon-minimal-right',
today: 'far fa-screenshot',
clear: 'far fa-trash',
close: 'far fa-remove'
}
});
}
if ($timepicker.length != 0) {
$timepicker.datetimepicker({
format: 'H:mm', // use this format if you want the 24hours timepicker
// format: 'h:mm A', //use this format if you want the 12hours timpiecker with AM/PM toggle
icons: {
time: "tim-icons icon-watch-time",
date: "tim-icons icon-calendar-60",
up: "far fa-chevron-up",
down: "far fa-chevron-down",
previous: 'tim-icons icon-minimal-left',
next: 'tim-icons icon-minimal-right',
today: 'far fa-screenshot',
clear: 'far fa-trash',
close: 'far fa-remove'
}
});
}
},
initMinimizeSidebar: function() {
if ($('.sidebar-mini').length != 0) {
sidebar_mini_active = true;
}
$('.minimize-sidebar').click(function() {
if (sidebar_mini_active == true) {
$body.removeClass('sidebar-mini');
sidebar_mini_active = false;
blackDashboard.showSidebarMessage('Sidebar mini deactivated...');
} else {
$body.addClass('sidebar-mini');
sidebar_mini_active = true;
blackDashboard.showSidebarMessage('Sidebar mini activated...');
}
// we simulate the window Resize so the charts will get updated in realtime.
var simulateWindowResize = setInterval(function() {
window.dispatchEvent(new Event('resize'));
}, 180);
// we stop the simulation of Window Resize after the animations are completed
setTimeout(function() {
clearInterval(simulateWindowResize);
}, 1000);
});
},
startAnimationForLineChart: function(chart) {
chart.on('draw', function(data) {
if (data.type === 'line' || data.type === 'area') {
data.element.animate({
d: {
begin: 600,
dur: 700,
from: data.path.clone().scale(1, 0).translate(0, data.chartRect.height()).stringify(),
to: data.path.clone().stringify(),
easing: Chartist.Svg.Easing.easeOutQuint
}
});
} else if (data.type === 'point') {
seq++;
data.element.animate({
opacity: {
begin: seq * delays,
dur: durations,
from: 0,
to: 1,
easing: 'ease'
}
});
}
});
seq = 0;
},
startAnimationForBarChart: function(chart) {
chart.on('draw', function(data) {
if (data.type === 'bar') {
seq2++;
data.element.animate({
opacity: {
begin: seq2 * delays2,
dur: durations2,
from: 0,
to: 1,
easing: 'ease'
}
});
}
});
seq2 = 0;
},
showSidebarMessage: function(message) {
try {
$.notify({
icon: "tim-icons icon-bell-55",
message: message
}, {
type: 'primary',
timer: 4000,
placement: {
from: 'top',
align: 'right'
}
});
} catch (e) {
console.log('Notify library is missing, please make sure you have the notifications library added.');
}
}
};
function hexToRGB(hex, alpha) {
var r = parseInt(hex.slice(1, 3), 16),
g = parseInt(hex.slice(3, 5), 16),
b = parseInt(hex.slice(5, 7), 16);
if (alpha) {
return "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")";
} else {
return "rgb(" + r + ", " + g + ", " + b + ")";
}
}

File diff suppressed because one or more lines are too long

2
static/js/black-dashboard.min.js vendored Normal file

File diff suppressed because one or more lines are too long

6
static/js/core/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

4
static/js/core/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

4
static/js/core/popper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

432
static/js/plugins/bootstrap-notify.js vendored Normal file
View File

@ -0,0 +1,432 @@
/*
Creative Tim Modifications
Lines: 238, 239 was changed from top: 5px to top: 50% and we added margin-top: -13px. In this way the close button will be aligned vertically
Line:222 - modified when the icon is set, we add the class "alert-with-icon", so there will be enough space for the icon.
*/
/*
* Project: Bootstrap Notify = v3.1.5
* Description: Turns standard Bootstrap alerts into "Growl-like" notifications.
* Author: Mouse0270 aka Robert McIntosh
* License: MIT License
* Website: https://github.com/mouse0270/bootstrap-growl
*/
/* global define:false, require: false, jQuery:false */
(function(factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function($) {
// Create the defaults once
var defaults = {
element: 'body',
position: null,
type: "info",
allow_dismiss: true,
allow_duplicates: true,
newest_on_top: false,
showProgressbar: false,
placement: {
from: "top",
align: "right"
},
offset: 20,
spacing: 10,
z_index: 1060,
delay: 5000,
timer: 1000,
url_target: '_blank',
mouse_over: null,
animate: {
enter: 'animated fadeInDown',
exit: 'animated fadeOutUp'
},
onShow: null,
onShown: null,
onClose: null,
onClosed: null,
onClick: null,
icon_type: 'class',
template: '<div data-notify="container" class="col-11 col-md-4 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="close" data-notify="dismiss"><i class="tim-icons icon-simple-remove"></i></button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'
};
String.format = function() {
var args = arguments;
var str = arguments[0];
return str.replace(/(\{\{\d\}\}|\{\d\})/g, function(str) {
if (str.substring(0, 2) === "{{") return str;
var num = parseInt(str.match(/\d/)[0]);
return args[num + 1];
});
};
function isDuplicateNotification(notification) {
var isDupe = false;
$('[data-notify="container"]').each(function(i, el) {
var $el = $(el);
var title = $el.find('[data-notify="title"]').html().trim();
var message = $el.find('[data-notify="message"]').html().trim();
// The input string might be different than the actual parsed HTML string!
// (<br> vs <br /> for example)
// So we have to force-parse this as HTML here!
var isSameTitle = title === $("<div>" + notification.settings.content.title + "</div>").html().trim();
var isSameMsg = message === $("<div>" + notification.settings.content.message + "</div>").html().trim();
var isSameType = $el.hasClass('alert-' + notification.settings.type);
if (isSameTitle && isSameMsg && isSameType) {
//we found the dupe. Set the var and stop checking.
isDupe = true;
}
return !isDupe;
});
return isDupe;
}
function Notify(element, content, options) {
// Setup Content of Notify
var contentObj = {
content: {
message: typeof content === 'object' ? content.message : content,
title: content.title ? content.title : '',
icon: content.icon ? content.icon : '',
url: content.url ? content.url : '#',
target: content.target ? content.target : '-'
}
};
options = $.extend(true, {}, contentObj, options);
this.settings = $.extend(true, {}, defaults, options);
this._defaults = defaults;
if (this.settings.content.target === "-") {
this.settings.content.target = this.settings.url_target;
}
this.animations = {
start: 'webkitAnimationStart oanimationstart MSAnimationStart animationstart',
end: 'webkitAnimationEnd oanimationend MSAnimationEnd animationend'
};
if (typeof this.settings.offset === 'number') {
this.settings.offset = {
x: this.settings.offset,
y: this.settings.offset
};
}
//if duplicate messages are not allowed, then only continue if this new message is not a duplicate of one that it already showing
if (this.settings.allow_duplicates || (!this.settings.allow_duplicates && !isDuplicateNotification(this))) {
this.init();
}
}
$.extend(Notify.prototype, {
init: function() {
var self = this;
this.buildNotify();
if (this.settings.content.icon) {
this.setIcon();
}
if (this.settings.content.url != "#") {
this.styleURL();
}
this.styleDismiss();
this.placement();
this.bind();
this.notify = {
$ele: this.$ele,
update: function(command, update) {
var commands = {};
if (typeof command === "string") {
commands[command] = update;
} else {
commands = command;
}
for (var cmd in commands) {
switch (cmd) {
case "type":
this.$ele.removeClass('alert-' + self.settings.type);
this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass('progress-bar-' + self.settings.type);
self.settings.type = commands[cmd];
this.$ele.addClass('alert-' + commands[cmd]).find('[data-notify="progressbar"] > .progress-bar').addClass('progress-bar-' + commands[cmd]);
break;
case "icon":
var $icon = this.$ele.find('[data-notify="icon"]');
if (self.settings.icon_type.toLowerCase() === 'class') {
$icon.removeClass(self.settings.content.icon).addClass(commands[cmd]);
} else {
if (!$icon.is('img')) {
$icon.find('img');
}
$icon.attr('src', commands[cmd]);
}
self.settings.content.icon = commands[command];
break;
case "progress":
var newDelay = self.settings.delay - (self.settings.delay * (commands[cmd] / 100));
this.$ele.data('notify-delay', newDelay);
this.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', commands[cmd]).css('width', commands[cmd] + '%');
break;
case "url":
this.$ele.find('[data-notify="url"]').attr('href', commands[cmd]);
break;
case "target":
this.$ele.find('[data-notify="url"]').attr('target', commands[cmd]);
break;
default:
this.$ele.find('[data-notify="' + cmd + '"]').html(commands[cmd]);
}
}
var posX = this.$ele.outerHeight() + parseInt(self.settings.spacing) + parseInt(self.settings.offset.y);
self.reposition(posX);
},
close: function() {
self.close();
}
};
},
buildNotify: function() {
var content = this.settings.content;
this.$ele = $(String.format(this.settings.template, this.settings.type, content.title, content.message, content.url, content.target));
this.$ele.attr('data-notify-position', this.settings.placement.from + '-' + this.settings.placement.align);
if (!this.settings.allow_dismiss) {
this.$ele.find('[data-notify="dismiss"]').css('display', 'none');
}
if ((this.settings.delay <= 0 && !this.settings.showProgressbar) || !this.settings.showProgressbar) {
this.$ele.find('[data-notify="progressbar"]').remove();
}
},
setIcon: function() {
this.$ele.addClass('alert-with-icon');
if (this.settings.icon_type.toLowerCase() === 'class') {
this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon);
} else {
if (this.$ele.find('[data-notify="icon"]').is('img')) {
this.$ele.find('[data-notify="icon"]').attr('src', this.settings.content.icon);
} else {
this.$ele.find('[data-notify="icon"]').append('<img src="' + this.settings.content.icon + '" alt="Notify Icon" />');
}
}
},
styleDismiss: function() {
this.$ele.find('[data-notify="dismiss"]').css({
position: 'absolute',
right: '10px',
top: '50%',
marginTop: '-13px',
zIndex: this.settings.z_index + 2
});
},
styleURL: function() {
this.$ele.find('[data-notify="url"]').css({
backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)',
height: '100%',
left: 0,
position: 'absolute',
top: 0,
width: '100%',
zIndex: this.settings.z_index + 1
});
},
placement: function() {
var self = this,
offsetAmt = this.settings.offset.y,
css = {
display: 'inline-block',
margin: '0px auto',
position: this.settings.position ? this.settings.position : (this.settings.element === 'body' ? 'fixed' : 'absolute'),
transition: 'all .5s ease-in-out',
zIndex: this.settings.z_index
},
hasAnimation = false,
settings = this.settings;
$('[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])').each(function() {
offsetAmt = Math.max(offsetAmt, parseInt($(this).css(settings.placement.from)) + parseInt($(this).outerHeight()) + parseInt(settings.spacing));
});
if (this.settings.newest_on_top === true) {
offsetAmt = this.settings.offset.y;
}
css[this.settings.placement.from] = offsetAmt + 'px';
switch (this.settings.placement.align) {
case "left":
case "right":
css[this.settings.placement.align] = this.settings.offset.x + 'px';
break;
case "center":
css.left = 0;
css.right = 0;
break;
}
this.$ele.css(css).addClass(this.settings.animate.enter);
$.each(Array('webkit-', 'moz-', 'o-', 'ms-', ''), function(index, prefix) {
self.$ele[0].style[prefix + 'AnimationIterationCount'] = 1;
});
$(this.settings.element).append(this.$ele);
if (this.settings.newest_on_top === true) {
offsetAmt = (parseInt(offsetAmt) + parseInt(this.settings.spacing)) + this.$ele.outerHeight();
this.reposition(offsetAmt);
}
if ($.isFunction(self.settings.onShow)) {
self.settings.onShow.call(this.$ele);
}
this.$ele.one(this.animations.start, function() {
hasAnimation = true;
}).one(this.animations.end, function() {
self.$ele.removeClass(self.settings.animate.enter);
if ($.isFunction(self.settings.onShown)) {
self.settings.onShown.call(this);
}
});
setTimeout(function() {
if (!hasAnimation) {
if ($.isFunction(self.settings.onShown)) {
self.settings.onShown.call(this);
}
}
}, 600);
},
bind: function() {
var self = this;
this.$ele.find('[data-notify="dismiss"]').on('click', function() {
self.close();
});
if ($.isFunction(self.settings.onClick)) {
this.$ele.on('click', function(event) {
if (event.target != self.$ele.find('[data-notify="dismiss"]')[0]) {
self.settings.onClick.call(this, event);
}
});
}
this.$ele.mouseover(function() {
$(this).data('data-hover', "true");
}).mouseout(function() {
$(this).data('data-hover', "false");
});
this.$ele.data('data-hover', "false");
if (this.settings.delay > 0) {
self.$ele.data('notify-delay', self.settings.delay);
var timer = setInterval(function() {
var delay = parseInt(self.$ele.data('notify-delay')) - self.settings.timer;
if ((self.$ele.data('data-hover') === 'false' && self.settings.mouse_over === "pause") || self.settings.mouse_over != "pause") {
var percent = ((self.settings.delay - delay) / self.settings.delay) * 100;
self.$ele.data('notify-delay', delay);
self.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', percent).css('width', percent + '%');
}
if (delay <= -(self.settings.timer)) {
clearInterval(timer);
self.close();
}
}, self.settings.timer);
}
},
close: function() {
var self = this,
posX = parseInt(this.$ele.css(this.settings.placement.from)),
hasAnimation = false;
this.$ele.attr('data-closing', 'true').addClass(this.settings.animate.exit);
self.reposition(posX);
if ($.isFunction(self.settings.onClose)) {
self.settings.onClose.call(this.$ele);
}
this.$ele.one(this.animations.start, function() {
hasAnimation = true;
}).one(this.animations.end, function() {
$(this).remove();
if ($.isFunction(self.settings.onClosed)) {
self.settings.onClosed.call(this);
}
});
setTimeout(function() {
if (!hasAnimation) {
self.$ele.remove();
if (self.settings.onClosed) {
self.settings.onClosed(self.$ele);
}
}
}, 600);
},
reposition: function(posX) {
var self = this,
notifies = '[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])',
$elements = this.$ele.nextAll(notifies);
if (this.settings.newest_on_top === true) {
$elements = this.$ele.prevAll(notifies);
}
$elements.each(function() {
$(this).css(self.settings.placement.from, posX);
posX = (parseInt(posX) + parseInt(self.settings.spacing)) + $(this).outerHeight();
});
}
});
$.notify = function(content, options) {
var plugin = new Notify(this, content, options);
return plugin.notify;
};
$.notifyDefaults = function(options) {
defaults = $.extend(true, {}, defaults, options);
return defaults;
};
$.notifyClose = function(selector) {
if (typeof selector === "undefined" || selector === "all") {
$('[data-notify]').find('[data-notify="dismiss"]').trigger('click');
} else if (selector === 'success' || selector === 'info' || selector === 'warning' || selector === 'danger') {
$('.alert-' + selector + '[data-notify]').find('[data-notify="dismiss"]').trigger('click');
} else if (selector) {
$(selector + '[data-notify]').find('[data-notify="dismiss"]').trigger('click');
} else {
$('[data-notify-position="' + selector + '"]').find('[data-notify="dismiss"]').trigger('click');
}
};
$.notifyCloseExcept = function(selector) {
if (selector === 'success' || selector === 'info' || selector === 'warning' || selector === 'danger') {
$('[data-notify]').not('.alert-' + selector).find('[data-notify="dismiss"]').trigger('click');
} else {
$('[data-notify]').not(selector).find('[data-notify="dismiss"]').trigger('click');
}
};
}));

File diff suppressed because it is too large Load Diff

786
static/js/plugins/bootstrap-switch.js vendored Executable file
View File

@ -0,0 +1,786 @@
/**
* bootstrap-switch - Turn checkboxes and radio buttons into toggle switches.
*
* @version v3.3.4
* @homepage https://bttstrp.github.io/bootstrap-switch
* @author Mattia Larentis <mattia@larentis.eu> (http://larentis.eu)
* @license Apache-2.0
*/
(function(global, factory) {
if (typeof define === "function" && define.amd) {
define(['jquery'], factory);
} else if (typeof exports !== "undefined") {
factory(require('jquery'));
} else {
var mod = {
exports: {}
};
factory(global.jquery);
global.bootstrapSwitch = mod.exports;
}
})(this, function(_jquery) {
'use strict';
var _jquery2 = _interopRequireDefault(_jquery);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
var _extends = Object.assign || function(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
var $ = _jquery2.default || window.jQuery || window.$;
var BootstrapSwitch = function() {
function BootstrapSwitch(element) {
var _this = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, BootstrapSwitch);
this.$element = $(element);
this.options = $.extend({}, $.fn.bootstrapSwitch.defaults, this._getElementOptions(), options);
this.prevOptions = {};
this.$wrapper = $('<div>', {
class: function _class() {
var classes = [];
classes.push(_this.options.state ? 'on' : 'off');
if (_this.options.size) {
classes.push(_this.options.size);
}
if (_this.options.disabled) {
classes.push('disabled');
}
if (_this.options.readonly) {
classes.push('readonly');
}
if (_this.options.indeterminate) {
classes.push('indeterminate');
}
if (_this.options.inverse) {
classes.push('inverse');
}
if (_this.$element.attr('id')) {
classes.push('id-' + _this.$element.attr('id'));
}
return classes.map(_this._getClass.bind(_this)).concat([_this.options.baseClass], _this._getClasses(_this.options.wrapperClass)).join(' ');
}
});
this.$container = $('<div>', {
class: this._getClass('container')
});
this.$on = $('<span>', {
html: this.options.onText,
class: this._getClass('handle-on') + ' ' + this._getClass(this.options.onColor)
});
this.$off = $('<span>', {
html: this.options.offText,
class: this._getClass('handle-off') + ' ' + this._getClass(this.options.offColor)
});
this.$label = $('<span>', {
html: this.options.labelText,
class: this._getClass('label')
});
this.$element.on('init.bootstrapSwitch', this.options.onInit.bind(this, element));
this.$element.on('switchChange.bootstrapSwitch', function() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
if (_this.options.onSwitchChange.apply(element, args) === false) {
if (_this.$element.is(':radio')) {
$('[name="' + _this.$element.attr('name') + '"]').trigger('previousState.bootstrapSwitch', true);
} else {
_this.$element.trigger('previousState.bootstrapSwitch', true);
}
}
});
this.$container = this.$element.wrap(this.$container).parent();
this.$wrapper = this.$container.wrap(this.$wrapper).parent();
this.$element.before(this.options.inverse ? this.$off : this.$on).before(this.$label).before(this.options.inverse ? this.$on : this.$off);
if (this.options.indeterminate) {
this.$element.prop('indeterminate', true);
}
this._init();
this._elementHandlers();
this._handleHandlers();
this._labelHandlers();
this._formHandler();
this._externalLabelHandler();
this.$element.trigger('init.bootstrapSwitch', this.options.state);
}
_createClass(BootstrapSwitch, [{
key: 'setPrevOptions',
value: function setPrevOptions() {
this.prevOptions = _extends({}, this.options);
}
}, {
key: 'state',
value: function state(value, skip) {
if (typeof value === 'undefined') {
return this.options.state;
}
if (this.options.disabled || this.options.readonly || this.options.state && !this.options.radioAllOff && this.$element.is(':radio')) {
return this.$element;
}
if (this.$element.is(':radio')) {
$('[name="' + this.$element.attr('name') + '"]').trigger('setPreviousOptions.bootstrapSwitch');
} else {
this.$element.trigger('setPreviousOptions.bootstrapSwitch');
}
if (this.options.indeterminate) {
this.indeterminate(false);
}
this.$element.prop('checked', Boolean(value)).trigger('change.bootstrapSwitch', skip);
return this.$element;
}
}, {
key: 'toggleState',
value: function toggleState(skip) {
if (this.options.disabled || this.options.readonly) {
return this.$element;
}
if (this.options.indeterminate) {
this.indeterminate(false);
return this.state(true);
} else {
return this.$element.prop('checked', !this.options.state).trigger('change.bootstrapSwitch', skip);
}
}
}, {
key: 'size',
value: function size(value) {
if (typeof value === 'undefined') {
return this.options.size;
}
if (this.options.size != null) {
this.$wrapper.removeClass(this._getClass(this.options.size));
}
if (value) {
this.$wrapper.addClass(this._getClass(value));
}
this._width();
this._containerPosition();
this.options.size = value;
return this.$element;
}
}, {
key: 'animate',
value: function animate(value) {
if (typeof value === 'undefined') {
return this.options.animate;
}
if (this.options.animate === Boolean(value)) {
return this.$element;
}
return this.toggleAnimate();
}
}, {
key: 'toggleAnimate',
value: function toggleAnimate() {
this.options.animate = !this.options.animate;
this.$wrapper.toggleClass(this._getClass('animate'));
return this.$element;
}
}, {
key: 'disabled',
value: function disabled(value) {
if (typeof value === 'undefined') {
return this.options.disabled;
}
if (this.options.disabled === Boolean(value)) {
return this.$element;
}
return this.toggleDisabled();
}
}, {
key: 'toggleDisabled',
value: function toggleDisabled() {
this.options.disabled = !this.options.disabled;
this.$element.prop('disabled', this.options.disabled);
this.$wrapper.toggleClass(this._getClass('disabled'));
return this.$element;
}
}, {
key: 'readonly',
value: function readonly(value) {
if (typeof value === 'undefined') {
return this.options.readonly;
}
if (this.options.readonly === Boolean(value)) {
return this.$element;
}
return this.toggleReadonly();
}
}, {
key: 'toggleReadonly',
value: function toggleReadonly() {
this.options.readonly = !this.options.readonly;
this.$element.prop('readonly', this.options.readonly);
this.$wrapper.toggleClass(this._getClass('readonly'));
return this.$element;
}
}, {
key: 'indeterminate',
value: function indeterminate(value) {
if (typeof value === 'undefined') {
return this.options.indeterminate;
}
if (this.options.indeterminate === Boolean(value)) {
return this.$element;
}
return this.toggleIndeterminate();
}
}, {
key: 'toggleIndeterminate',
value: function toggleIndeterminate() {
this.options.indeterminate = !this.options.indeterminate;
this.$element.prop('indeterminate', this.options.indeterminate);
this.$wrapper.toggleClass(this._getClass('indeterminate'));
this._containerPosition();
return this.$element;
}
}, {
key: 'inverse',
value: function inverse(value) {
if (typeof value === 'undefined') {
return this.options.inverse;
}
if (this.options.inverse === Boolean(value)) {
return this.$element;
}
return this.toggleInverse();
}
}, {
key: 'toggleInverse',
value: function toggleInverse() {
this.$wrapper.toggleClass(this._getClass('inverse'));
var $on = this.$on.clone(true);
var $off = this.$off.clone(true);
this.$on.replaceWith($off);
this.$off.replaceWith($on);
this.$on = $off;
this.$off = $on;
this.options.inverse = !this.options.inverse;
return this.$element;
}
}, {
key: 'onColor',
value: function onColor(value) {
if (typeof value === 'undefined') {
return this.options.onColor;
}
if (this.options.onColor) {
this.$on.removeClass(this._getClass(this.options.onColor));
}
this.$on.addClass(this._getClass(value));
this.options.onColor = value;
return this.$element;
}
}, {
key: 'offColor',
value: function offColor(value) {
if (typeof value === 'undefined') {
return this.options.offColor;
}
if (this.options.offColor) {
this.$off.removeClass(this._getClass(this.options.offColor));
}
this.$off.addClass(this._getClass(value));
this.options.offColor = value;
return this.$element;
}
}, {
key: 'onText',
value: function onText(value) {
if (typeof value === 'undefined') {
return this.options.onText;
}
this.$on.html(value);
this._width();
this._containerPosition();
this.options.onText = value;
return this.$element;
}
}, {
key: 'offText',
value: function offText(value) {
if (typeof value === 'undefined') {
return this.options.offText;
}
this.$off.html(value);
this._width();
this._containerPosition();
this.options.offText = value;
return this.$element;
}
}, {
key: 'labelText',
value: function labelText(value) {
if (typeof value === 'undefined') {
return this.options.labelText;
}
this.$label.html(value);
this._width();
this.options.labelText = value;
return this.$element;
}
}, {
key: 'handleWidth',
value: function handleWidth(value) {
if (typeof value === 'undefined') {
return this.options.handleWidth;
}
this.options.handleWidth = value;
this._width();
this._containerPosition();
return this.$element;
}
}, {
key: 'labelWidth',
value: function labelWidth(value) {
if (typeof value === 'undefined') {
return this.options.labelWidth;
}
this.options.labelWidth = value;
this._width();
this._containerPosition();
return this.$element;
}
}, {
key: 'baseClass',
value: function baseClass(value) {
return this.options.baseClass;
}
}, {
key: 'wrapperClass',
value: function wrapperClass(value) {
if (typeof value === 'undefined') {
return this.options.wrapperClass;
}
if (!value) {
value = $.fn.bootstrapSwitch.defaults.wrapperClass;
}
this.$wrapper.removeClass(this._getClasses(this.options.wrapperClass).join(' '));
this.$wrapper.addClass(this._getClasses(value).join(' '));
this.options.wrapperClass = value;
return this.$element;
}
}, {
key: 'radioAllOff',
value: function radioAllOff(value) {
if (typeof value === 'undefined') {
return this.options.radioAllOff;
}
var val = Boolean(value);
if (this.options.radioAllOff === val) {
return this.$element;
}
this.options.radioAllOff = val;
return this.$element;
}
}, {
key: 'onInit',
value: function onInit(value) {
if (typeof value === 'undefined') {
return this.options.onInit;
}
if (!value) {
value = $.fn.bootstrapSwitch.defaults.onInit;
}
this.options.onInit = value;
return this.$element;
}
}, {
key: 'onSwitchChange',
value: function onSwitchChange(value) {
if (typeof value === 'undefined') {
return this.options.onSwitchChange;
}
if (!value) {
value = $.fn.bootstrapSwitch.defaults.onSwitchChange;
}
this.options.onSwitchChange = value;
return this.$element;
}
}, {
key: 'destroy',
value: function destroy() {
var $form = this.$element.closest('form');
if ($form.length) {
$form.off('reset.bootstrapSwitch').removeData('bootstrap-switch');
}
this.$container.children().not(this.$element).remove();
this.$element.unwrap().unwrap().off('.bootstrapSwitch').removeData('bootstrap-switch');
return this.$element;
}
}, {
key: '_getElementOptions',
value: function _getElementOptions() {
return {
state: this.$element.is(':checked'),
size: this.$element.data('size'),
animate: this.$element.data('animate'),
disabled: this.$element.is(':disabled'),
readonly: this.$element.is('[readonly]'),
indeterminate: this.$element.data('indeterminate'),
inverse: this.$element.data('inverse'),
radioAllOff: this.$element.data('radio-all-off'),
onColor: this.$element.data('on-color'),
offColor: this.$element.data('off-color'),
onText: this.$element.data('on-text'),
offText: this.$element.data('off-text'),
labelText: this.$element.data('label-text'),
handleWidth: this.$element.data('handle-width'),
labelWidth: this.$element.data('label-width'),
baseClass: this.$element.data('base-class'),
wrapperClass: this.$element.data('wrapper-class')
};
}
}, {
key: '_width',
value: function _width() {
var _this2 = this;
var $handles = this.$on.add(this.$off).add(this.$label).css('width', '');
var handleWidth = this.options.handleWidth === 'auto' ? Math.round(Math.max(this.$on.width(), this.$off.width())) : this.options.handleWidth;
$handles.width(handleWidth);
this.$label.width(function(index, width) {
if (_this2.options.labelWidth !== 'auto') {
return _this2.options.labelWidth;
}
if (width < handleWidth) {
return handleWidth;
}
return width;
});
this._handleWidth = this.$on.outerWidth();
this._labelWidth = this.$label.outerWidth();
this.$container.width(this._handleWidth * 2 + this._labelWidth);
return this.$wrapper.width(this._handleWidth + this._labelWidth);
}
}, {
key: '_containerPosition',
value: function _containerPosition() {
var _this3 = this;
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.state;
var callback = arguments[1];
this.$container.css('margin-left', function() {
var values = [0, '-' + _this3._handleWidth + 'px'];
if (_this3.options.indeterminate) {
return '-' + _this3._handleWidth / 2 + 'px';
}
if (state) {
if (_this3.options.inverse) {
return values[1];
} else {
return values[0];
}
} else {
if (_this3.options.inverse) {
return values[0];
} else {
return values[1];
}
}
});
}
}, {
key: '_init',
value: function _init() {
var _this4 = this;
var init = function init() {
_this4.setPrevOptions();
_this4._width();
_this4._containerPosition();
setTimeout(function() {
if (_this4.options.animate) {
return _this4.$wrapper.addClass(_this4._getClass('animate'));
}
}, 50);
};
if (this.$wrapper.is(':visible')) {
init();
return;
}
var initInterval = window.setInterval(function() {
if (_this4.$wrapper.is(':visible')) {
init();
return window.clearInterval(initInterval);
}
}, 50);
}
}, {
key: '_elementHandlers',
value: function _elementHandlers() {
var _this5 = this;
return this.$element.on({
'setPreviousOptions.bootstrapSwitch': this.setPrevOptions.bind(this),
'previousState.bootstrapSwitch': function previousStateBootstrapSwitch() {
_this5.options = _this5.prevOptions;
if (_this5.options.indeterminate) {
_this5.$wrapper.addClass(_this5._getClass('indeterminate'));
}
_this5.$element.prop('checked', _this5.options.state).trigger('change.bootstrapSwitch', true);
},
'change.bootstrapSwitch': function changeBootstrapSwitch(event, skip) {
event.preventDefault();
event.stopImmediatePropagation();
var state = _this5.$element.is(':checked');
_this5._containerPosition(state);
if (state === _this5.options.state) {
return;
}
_this5.options.state = state;
_this5.$wrapper.toggleClass(_this5._getClass('off')).toggleClass(_this5._getClass('on'));
if (!skip) {
if (_this5.$element.is(':radio')) {
$('[name="' + _this5.$element.attr('name') + '"]').not(_this5.$element).prop('checked', false).trigger('change.bootstrapSwitch', true);
}
_this5.$element.trigger('switchChange.bootstrapSwitch', [state]);
}
},
'focus.bootstrapSwitch': function focusBootstrapSwitch(event) {
event.preventDefault();
_this5.$wrapper.addClass(_this5._getClass('focused'));
},
'blur.bootstrapSwitch': function blurBootstrapSwitch(event) {
event.preventDefault();
_this5.$wrapper.removeClass(_this5._getClass('focused'));
},
'keydown.bootstrapSwitch': function keydownBootstrapSwitch(event) {
if (!event.which || _this5.options.disabled || _this5.options.readonly) {
return;
}
if (event.which === 37 || event.which === 39) {
event.preventDefault();
event.stopImmediatePropagation();
_this5.state(event.which === 39);
}
}
});
}
}, {
key: '_handleHandlers',
value: function _handleHandlers() {
var _this6 = this;
this.$on.on('click.bootstrapSwitch', function(event) {
event.preventDefault();
event.stopPropagation();
_this6.state(false);
return _this6.$element.trigger('focus.bootstrapSwitch');
});
return this.$off.on('click.bootstrapSwitch', function(event) {
event.preventDefault();
event.stopPropagation();
_this6.state(true);
return _this6.$element.trigger('focus.bootstrapSwitch');
});
}
}, {
key: '_labelHandlers',
value: function _labelHandlers() {
var _this7 = this;
var handlers = {
click: function click(event) {
event.stopPropagation();
},
'mousedown.bootstrapSwitch touchstart.bootstrapSwitch': function mousedownBootstrapSwitchTouchstartBootstrapSwitch(event) {
if (_this7._dragStart || _this7.options.disabled || _this7.options.readonly) {
return;
}
event.preventDefault();
event.stopPropagation();
_this7._dragStart = (event.pageX || event.originalEvent.touches[0].pageX) - parseInt(_this7.$container.css('margin-left'), 10);
if (_this7.options.animate) {
_this7.$wrapper.removeClass(_this7._getClass('animate'));
}
_this7.$element.trigger('focus.bootstrapSwitch');
},
'mousemove.bootstrapSwitch touchmove.bootstrapSwitch': function mousemoveBootstrapSwitchTouchmoveBootstrapSwitch(event) {
if (_this7._dragStart == null) {
return;
}
var difference = (event.pageX || event.originalEvent.touches[0].pageX) - _this7._dragStart;
event.preventDefault();
if (difference < -_this7._handleWidth || difference > 0) {
return;
}
_this7._dragEnd = difference;
_this7.$container.css('margin-left', _this7._dragEnd + 'px');
},
'mouseup.bootstrapSwitch touchend.bootstrapSwitch': function mouseupBootstrapSwitchTouchendBootstrapSwitch(event) {
if (!_this7._dragStart) {
return;
}
event.preventDefault();
if (_this7.options.animate) {
_this7.$wrapper.addClass(_this7._getClass('animate'));
}
if (_this7._dragEnd) {
var state = _this7._dragEnd > -(_this7._handleWidth / 2);
_this7._dragEnd = false;
_this7.state(_this7.options.inverse ? !state : state);
} else {
_this7.state(!_this7.options.state);
}
_this7._dragStart = false;
},
'mouseleave.bootstrapSwitch': function mouseleaveBootstrapSwitch() {
_this7.$label.trigger('mouseup.bootstrapSwitch');
}
};
this.$label.on(handlers);
}
}, {
key: '_externalLabelHandler',
value: function _externalLabelHandler() {
var _this8 = this;
var $externalLabel = this.$element.closest('label');
$externalLabel.on('click', function(event) {
event.preventDefault();
event.stopImmediatePropagation();
if (event.target === $externalLabel[0]) {
_this8.toggleState();
}
});
}
}, {
key: '_formHandler',
value: function _formHandler() {
var $form = this.$element.closest('form');
if ($form.data('bootstrap-switch')) {
return;
}
$form.on('reset.bootstrapSwitch', function() {
window.setTimeout(function() {
$form.find('input').filter(function() {
return $(this).data('bootstrap-switch');
}).each(function() {
return $(this).bootstrapSwitch('state', this.checked);
});
}, 1);
}).data('bootstrap-switch', true);
}
}, {
key: '_getClass',
value: function _getClass(name) {
return this.options.baseClass + '-' + name;
}
}, {
key: '_getClasses',
value: function _getClasses(classes) {
if (!$.isArray(classes)) {
return [this._getClass(classes)];
}
return classes.map(this._getClass.bind(this));
}
}]);
return BootstrapSwitch;
}();
$.fn.bootstrapSwitch = function(option) {
for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
function reducer(ret, next) {
var $this = $(next);
var existingData = $this.data('bootstrap-switch');
var data = existingData || new BootstrapSwitch(next, option);
if (!existingData) {
$this.data('bootstrap-switch', data);
}
if (typeof option === 'string') {
return data[option].apply(data, args);
}
return ret;
}
return Array.prototype.reduce.call(this, reducer, this);
};
$.fn.bootstrapSwitch.Constructor = BootstrapSwitch;
$.fn.bootstrapSwitch.defaults = {
state: true,
size: null,
animate: true,
disabled: false,
readonly: false,
indeterminate: false,
inverse: false,
radioAllOff: false,
onColor: 'primary',
offColor: 'default',
onText: 'ON',
offText: 'OFF',
labelText: '&nbsp',
handleWidth: 'auto',
labelWidth: 'auto',
baseClass: 'bootstrap-switch',
wrapperClass: 'wrapper',
onInit: function onInit() {},
onSwitchChange: function onSwitchChange() {}
};
});

685
static/js/plugins/bootstrap-tagsinput.js vendored Normal file
View File

@ -0,0 +1,685 @@
/*
* bootstrap-tagsinput v0.8.0
*
*/
(function($) {
"use strict";
var defaultOptions = {
tagClass: function(item) {
return 'badge badge-danger';
},
itemValue: function(item) {
return item ? item.toString() : item;
},
itemText: function(item) {
return this.itemValue(item);
},
itemTitle: function(item) {
return null;
},
freeInput: true,
addOnBlur: true,
maxTags: undefined,
maxChars: undefined,
confirmKeys: [13, 44],
delimiter: ',',
delimiterRegex: null,
cancelConfirmKeysOnEmpty: true,
onTagExists: function(item, $tag) {
$tag.hide().fadeIn();
},
trimValue: false,
allowDuplicates: false
};
/**
* Constructor function
*/
function TagsInput(element, options) {
this.itemsArray = [];
this.$element = $(element);
this.$element.hide();
this.isSelect = (element.tagName === 'SELECT');
this.multiple = (this.isSelect && element.hasAttribute('multiple'));
this.objectItems = options && options.itemValue;
this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
this.inputSize = Math.max(1, this.placeholderText.length);
this.$container = $('<div class="bootstrap-tagsinput"></div>');
this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
this.$element.before(this.$container);
this.build(options);
}
TagsInput.prototype = {
constructor: TagsInput,
/**
* Adds the given item as a new tag. Pass true to dontPushVal to prevent
* updating the elements val()
*/
add: function(item, dontPushVal, options) {
var self = this;
if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
return;
// Ignore falsey values, except false
if (item !== false && !item)
return;
// Trim value
if (typeof item === "string" && self.options.trimValue) {
item = $.trim(item);
}
// Throw an error when trying to add an object while the itemValue option was not set
if (typeof item === "object" && !self.objectItems)
throw ("Can't add objects when itemValue option is not set");
// Ignore strings only containg whitespace
if (item.toString().match(/^\s*$/))
return;
// If SELECT but not multiple, remove current tag
if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
self.remove(self.itemsArray[0]);
if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
var items = item.split(delimiter);
if (items.length > 1) {
for (var i = 0; i < items.length; i++) {
this.add(items[i], true);
}
if (!dontPushVal)
self.pushVal();
return;
}
}
var itemValue = self.options.itemValue(item),
itemText = self.options.itemText(item),
tagClass = self.options.tagClass(item),
itemTitle = self.options.itemTitle(item);
// Ignore items allready added
var existing = $.grep(self.itemsArray, function(item) {
return self.options.itemValue(item) === itemValue;
})[0];
if (existing && !self.options.allowDuplicates) {
// Invoke onTagExists
if (self.options.onTagExists) {
var $existingTag = $(".tag", self.$container).filter(function() {
return $(this).data("item") === existing;
});
self.options.onTagExists(item, $existingTag);
}
return;
}
// if length greater than limit
if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
return;
// raise beforeItemAdd arg
var beforeItemAddEvent = $.Event('beforeItemAdd', {
item: item,
cancel: false,
options: options
});
self.$element.trigger(beforeItemAddEvent);
if (beforeItemAddEvent.cancel)
return;
// register item in internal array and map
self.itemsArray.push(item);
// add a tag element
var $tag = $('<span class="tag ' + htmlEncode(tagClass) + (itemTitle !== null ? ('" title="' + itemTitle) : '') + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>');
$tag.data('item', item);
self.findInputWrapper().before($tag);
$tag.after(' ');
// add <option /> if item represents a value not present in one of the <select />'s options
if (self.isSelect && !$('option[value="' + encodeURIComponent(itemValue) + '"]', self.$element)[0]) {
var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
$option.data('item', item);
$option.attr('value', itemValue);
self.$element.append($option);
}
if (!dontPushVal)
self.pushVal();
// Add class when reached maxTags
if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
self.$container.addClass('bootstrap-tagsinput-max');
self.$element.trigger($.Event('itemAdded', {
item: item,
options: options
}));
},
/**
* Removes the given item. Pass true to dontPushVal to prevent updating the
* elements val()
*/
remove: function(item, dontPushVal, options) {
var self = this;
if (self.objectItems) {
if (typeof item === "object")
item = $.grep(self.itemsArray, function(other) {
return self.options.itemValue(other) == self.options.itemValue(item);
});
else
item = $.grep(self.itemsArray, function(other) {
return self.options.itemValue(other) == item;
});
item = item[item.length - 1];
}
if (item) {
var beforeItemRemoveEvent = $.Event('beforeItemRemove', {
item: item,
cancel: false,
options: options
});
self.$element.trigger(beforeItemRemoveEvent);
if (beforeItemRemoveEvent.cancel)
return;
$('.tag', self.$container).filter(function() {
return $(this).data('item') === item;
}).remove();
$('option', self.$element).filter(function() {
return $(this).data('item') === item;
}).remove();
if ($.inArray(item, self.itemsArray) !== -1)
self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
}
if (!dontPushVal)
self.pushVal();
// Remove class when reached maxTags
if (self.options.maxTags > self.itemsArray.length)
self.$container.removeClass('bootstrap-tagsinput-max');
self.$element.trigger($.Event('itemRemoved', {
item: item,
options: options
}));
},
/**
* Removes all items
*/
removeAll: function() {
var self = this;
$('.tag', self.$container).remove();
$('option', self.$element).remove();
while (self.itemsArray.length > 0)
self.itemsArray.pop();
self.pushVal();
},
/**
* Refreshes the tags so they match the text/value of their corresponding
* item.
*/
refresh: function() {
var self = this;
$('.tag', self.$container).each(function() {
var $tag = $(this),
item = $tag.data('item'),
itemValue = self.options.itemValue(item),
itemText = self.options.itemText(item),
tagClass = self.options.tagClass(item);
// Update tag's class and inner text
$tag.attr('class', null);
$tag.addClass('tag ' + htmlEncode(tagClass));
$tag.contents().filter(function() {
return this.nodeType == 3;
})[0].nodeValue = htmlEncode(itemText);
if (self.isSelect) {
var option = $('option', self.$element).filter(function() {
return $(this).data('item') === item;
});
option.attr('value', itemValue);
}
});
},
/**
* Returns the items added as tags
*/
items: function() {
return this.itemsArray;
},
/**
* Assembly value by retrieving the value of each item, and set it on the
* element.
*/
pushVal: function() {
var self = this,
val = $.map(self.items(), function(item) {
return self.options.itemValue(item).toString();
});
self.$element.val(val, true).trigger('change');
},
/**
* Initializes the tags input behaviour on the element
*/
build: function(options) {
var self = this;
self.options = $.extend({}, defaultOptions, options);
// When itemValue is set, freeInput should always be false
if (self.objectItems)
self.options.freeInput = false;
makeOptionItemFunction(self.options, 'itemValue');
makeOptionItemFunction(self.options, 'itemText');
makeOptionFunction(self.options, 'tagClass');
// Typeahead Bootstrap version 2.3.2
if (self.options.typeahead) {
var typeahead = self.options.typeahead || {};
makeOptionFunction(typeahead, 'source');
self.$input.typeahead($.extend({}, typeahead, {
source: function(query, process) {
function processItems(items) {
var texts = [];
for (var i = 0; i < items.length; i++) {
var text = self.options.itemText(items[i]);
map[text] = items[i];
texts.push(text);
}
process(texts);
}
this.map = {};
var map = this.map,
data = typeahead.source(query);
if ($.isFunction(data.success)) {
// support for Angular callbacks
data.success(processItems);
} else if ($.isFunction(data.then)) {
// support for Angular promises
data.then(processItems);
} else {
// support for functions and jquery promises
$.when(data)
.then(processItems);
}
},
updater: function(text) {
self.add(this.map[text]);
return this.map[text];
},
matcher: function(text) {
return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
},
sorter: function(texts) {
return texts.sort();
},
highlighter: function(text) {
var regex = new RegExp('(' + this.query + ')', 'gi');
return text.replace(regex, "<strong>$1</strong>");
}
}));
}
// typeahead.js
if (self.options.typeaheadjs) {
var typeaheadConfig = null;
var typeaheadDatasets = {};
// Determine if main configurations were passed or simply a dataset
var typeaheadjs = self.options.typeaheadjs;
if ($.isArray(typeaheadjs)) {
typeaheadConfig = typeaheadjs[0];
typeaheadDatasets = typeaheadjs[1];
} else {
typeaheadDatasets = typeaheadjs;
}
self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function(obj, datum) {
if (typeaheadDatasets.valueKey)
self.add(datum[typeaheadDatasets.valueKey]);
else
self.add(datum);
self.$input.typeahead('val', '');
}, self));
}
self.$container.on('click', $.proxy(function(event) {
if (!self.$element.attr('disabled')) {
self.$input.removeAttr('disabled');
}
self.$input.focus();
}, self));
if (self.options.addOnBlur && self.options.freeInput) {
self.$input.on('focusout', $.proxy(function(event) {
// HACK: only process on focusout when no typeahead opened, to
// avoid adding the typeahead text as tag
if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
self.add(self.$input.val());
self.$input.val('');
}
}, self));
}
self.$container.on('keydown', 'input', $.proxy(function(event) {
var $input = $(event.target),
$inputWrapper = self.findInputWrapper();
if (self.$element.attr('disabled')) {
self.$input.attr('disabled', 'disabled');
return;
}
switch (event.which) {
// BACKSPACE
case 8:
if (doGetCaretPosition($input[0]) === 0) {
var prev = $inputWrapper.prev();
if (prev.length) {
self.remove(prev.data('item'));
}
}
break;
// DELETE
case 46:
if (doGetCaretPosition($input[0]) === 0) {
var next = $inputWrapper.next();
if (next.length) {
self.remove(next.data('item'));
}
}
break;
// LEFT ARROW
case 37:
// Try to move the input before the previous tag
var $prevTag = $inputWrapper.prev();
if ($input.val().length === 0 && $prevTag[0]) {
$prevTag.before($inputWrapper);
$input.focus();
}
break;
// RIGHT ARROW
case 39:
// Try to move the input after the next tag
var $nextTag = $inputWrapper.next();
if ($input.val().length === 0 && $nextTag[0]) {
$nextTag.after($inputWrapper);
$input.focus();
}
break;
default:
// ignore
}
// Reset internal input's size
var textLength = $input.val().length,
wordSpace = Math.ceil(textLength / 5),
size = textLength + wordSpace + 1;
$input.attr('size', Math.max(this.inputSize, $input.val().length));
}, self));
self.$container.on('keypress', 'input', $.proxy(function(event) {
var $input = $(event.target);
if (self.$element.attr('disabled')) {
self.$input.attr('disabled', 'disabled');
return;
}
var text = $input.val(),
maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
// Only attempt to add a tag if there is data in the field
if (text.length !== 0) {
self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
$input.val('');
}
// If the field is empty, let the event triggered fire as usual
if (self.options.cancelConfirmKeysOnEmpty === false) {
event.preventDefault();
}
}
// Reset internal input's size
var textLength = $input.val().length,
wordSpace = Math.ceil(textLength / 5),
size = textLength + wordSpace + 1;
$input.attr('size', Math.max(this.inputSize, $input.val().length));
}, self));
// Remove icon clicked
self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
if (self.$element.attr('disabled')) {
return;
}
self.remove($(event.target).closest('.tag').data('item'));
}, self));
// Only add existing value as tags when using strings as tags
if (self.options.itemValue === defaultOptions.itemValue) {
if (self.$element[0].tagName === 'INPUT') {
self.add(self.$element.val());
} else {
$('option', self.$element).each(function() {
self.add($(this).attr('value'), true);
});
}
}
},
/**
* Removes all tagsinput behaviour and unregsiter all event handlers
*/
destroy: function() {
var self = this;
// Unbind events
self.$container.off('keypress', 'input');
self.$container.off('click', '[role=remove]');
self.$container.remove();
self.$element.removeData('tagsinput');
self.$element.show();
},
/**
* Sets focus on the tagsinput
*/
focus: function() {
this.$input.focus();
},
/**
* Returns the internal input element
*/
input: function() {
return this.$input;
},
/**
* Returns the element which is wrapped around the internal input. This
* is normally the $container, but typeahead.js moves the $input element.
*/
findInputWrapper: function() {
var elt = this.$input[0],
container = this.$container[0];
while (elt && elt.parentNode !== container)
elt = elt.parentNode;
return $(elt);
}
};
/**
* Register JQuery plugin
*/
$.fn.tagsinput = function(arg1, arg2, arg3) {
var results = [];
this.each(function() {
var tagsinput = $(this).data('tagsinput');
// Initialize a new tags input
if (!tagsinput) {
tagsinput = new TagsInput(this, arg1);
$(this).data('tagsinput', tagsinput);
results.push(tagsinput);
if (this.tagName === 'SELECT') {
$('option', $(this)).attr('selected', 'selected');
}
// Init tags from $(this).val()
$(this).val($(this).val());
} else if (!arg1 && !arg2) {
// tagsinput already exists
// no function, trying to init
results.push(tagsinput);
} else if (tagsinput[arg1] !== undefined) {
// Invoke function on existing tags input
if (tagsinput[arg1].length === 3 && arg3 !== undefined) {
var retVal = tagsinput[arg1](arg2, null, arg3);
} else {
var retVal = tagsinput[arg1](arg2);
}
if (retVal !== undefined)
results.push(retVal);
}
});
if (typeof arg1 == 'string') {
// Return the results from the invoked function calls
return results.length > 1 ? results : results[0];
} else {
return results;
}
};
$.fn.tagsinput.Constructor = TagsInput;
/**
* Most options support both a string or number as well as a function as
* option value. This function makes sure that the option with the given
* key in the given options is wrapped in a function
*/
function makeOptionItemFunction(options, key) {
if (typeof options[key] !== 'function') {
var propertyName = options[key];
options[key] = function(item) {
return item[propertyName];
};
}
}
function makeOptionFunction(options, key) {
if (typeof options[key] !== 'function') {
var value = options[key];
options[key] = function() {
return value;
};
}
}
/**
* HtmlEncodes the given value
*/
var htmlEncodeContainer = $('<div />');
function htmlEncode(value) {
if (value) {
return htmlEncodeContainer.text(value).html();
} else {
return '';
}
}
/**
* Returns the position of the caret in the given input field
* http://flightschool.acylt.com/devnotes/caret-position-woes/
*/
function doGetCaretPosition(oField) {
var iCaretPos = 0;
if (document.selection) {
oField.focus();
var oSel = document.selection.createRange();
oSel.moveStart('character', -oField.value.length);
iCaretPos = oSel.text.length;
} else if (oField.selectionStart || oField.selectionStart == '0') {
iCaretPos = oField.selectionStart;
}
return (iCaretPos);
}
/**
* Returns boolean indicates whether user has pressed an expected key combination.
* @param object keyPressEvent: JavaScript event object, refer
* http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
* @param object lookupList: expected key combinations, as in:
* [13, {which: 188, shiftKey: true}]
*/
function keyCombinationInList(keyPressEvent, lookupList) {
var found = false;
$.each(lookupList, function(index, keyCombination) {
if (typeof(keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
found = true;
return false;
}
if (keyPressEvent.which === keyCombination.which) {
var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
if (alt && shift && ctrl) {
found = true;
return false;
}
}
});
return found;
}
/**
* Initialize tagsinput behaviour on inputs and selects which have
* data-role=tagsinput
*/
$(function() {
$("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
});
})(window.jQuery);

10
static/js/plugins/chartjs.min.js vendored Normal file

File diff suppressed because one or more lines are too long

12
static/js/plugins/fullcalendar.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4183
static/js/plugins/jquery-jvectormap.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,345 @@
/*!
* jQuery twitter bootstrap wizard plugin
* Examples and documentation at: http://github.com/VinceG/twitter-bootstrap-wizard
* version 1.4.2
* Requires jQuery v1.3.2 or later
* Supports Bootstrap 2.2.x, 2.3.x, 3.0
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
* Authors: Vadim Vincent Gabriel (http://vadimg.com), Jason Gill (www.gilluminate.com)
*/
;
(function($) {
var bootstrapWizardCreate = function(element, options) {
var element = $(element);
var obj = this;
// selector skips any 'li' elements that do not contain a child with a tab data-toggle
var baseItemSelector = 'li:has([data-toggle="tab"])';
var historyStack = [];
// Merge options with defaults
var $settings = $.extend({}, $.fn.bootstrapWizard.defaults, options);
var $activeTab = null;
var $navigation = null;
this.rebindClick = function(selector, fn) {
selector.unbind('click', fn).bind('click', fn);
}
this.fixNavigationButtons = function() {
// Get the current active tab
if (!$activeTab.length) {
// Select first one
$navigation.find('a:first').tab('show');
$activeTab = $navigation.find(baseItemSelector + ':first');
}
// See if we're currently in the first/last then disable the previous and last buttons
$($settings.previousSelector, element).toggleClass('disabled', (obj.firstIndex() >= obj.currentIndex()));
$($settings.nextSelector, element).toggleClass('disabled', (obj.currentIndex() >= obj.navigationLength()));
$($settings.nextSelector, element).toggleClass('hidden', (obj.currentIndex() >= obj.navigationLength() && $($settings.finishSelector, element).length > 0));
$($settings.lastSelector, element).toggleClass('hidden', (obj.currentIndex() >= obj.navigationLength() && $($settings.finishSelector, element).length > 0));
$($settings.finishSelector, element).toggleClass('hidden', (obj.currentIndex() < obj.navigationLength()));
$($settings.backSelector, element).toggleClass('disabled', (historyStack.length == 0));
$($settings.backSelector, element).toggleClass('hidden', (obj.currentIndex() >= obj.navigationLength() && $($settings.finishSelector, element).length > 0));
// We are unbinding and rebinding to ensure single firing and no double-click errors
obj.rebindClick($($settings.nextSelector, element), obj.next);
obj.rebindClick($($settings.previousSelector, element), obj.previous);
obj.rebindClick($($settings.lastSelector, element), obj.last);
obj.rebindClick($($settings.firstSelector, element), obj.first);
obj.rebindClick($($settings.finishSelector, element), obj.finish);
obj.rebindClick($($settings.backSelector, element), obj.back);
if ($settings.onTabShow && typeof $settings.onTabShow === 'function' && $settings.onTabShow($activeTab, $navigation, obj.currentIndex()) === false) {
return false;
}
};
this.next = function(e) {
// If we clicked the last then dont activate this
if (element.hasClass('last')) {
return false;
}
if ($settings.onNext && typeof $settings.onNext === 'function' && $settings.onNext($activeTab, $navigation, obj.nextIndex()) === false) {
return false;
}
var formerIndex = obj.currentIndex();
var $index = obj.nextIndex();
// Did we click the last button
if ($index > obj.navigationLength()) {} else {
historyStack.push(formerIndex);
$navigation.find(baseItemSelector + ($settings.withVisible ? ':visible' : '') + ':eq(' + $index + ') a').tab('show');
}
};
this.previous = function(e) {
// If we clicked the first then dont activate this
if (element.hasClass('first')) {
return false;
}
if ($settings.onPrevious && typeof $settings.onPrevious === 'function' && $settings.onPrevious($activeTab, $navigation, obj.previousIndex()) === false) {
return false;
}
var formerIndex = obj.currentIndex();
var $index = obj.previousIndex();
if ($index < 0) {} else {
historyStack.push(formerIndex);
$navigation.find(baseItemSelector + ($settings.withVisible ? ':visible' : '') + ':eq(' + $index + ') a').tab('show');
}
};
this.first = function(e) {
if ($settings.onFirst && typeof $settings.onFirst === 'function' && $settings.onFirst($activeTab, $navigation, obj.firstIndex()) === false) {
return false;
}
// If the element is disabled then we won't do anything
if (element.hasClass('disabled')) {
return false;
}
historyStack.push(obj.currentIndex());
$navigation.find(baseItemSelector + ':eq(0) a').tab('show');
};
this.last = function(e) {
if ($settings.onLast && typeof $settings.onLast === 'function' && $settings.onLast($activeTab, $navigation, obj.lastIndex()) === false) {
return false;
}
// If the element is disabled then we won't do anything
if (element.hasClass('disabled')) {
return false;
}
historyStack.push(obj.currentIndex());
$navigation.find(baseItemSelector + ':eq(' + obj.navigationLength() + ') a').tab('show');
};
this.finish = function(e) {
if ($settings.onFinish && typeof $settings.onFinish === 'function') {
$settings.onFinish($activeTab, $navigation, obj.lastIndex());
}
};
this.back = function() {
if (historyStack.length == 0) {
return null;
}
var formerIndex = historyStack.pop();
if ($settings.onBack && typeof $settings.onBack === 'function' && $settings.onBack($activeTab, $navigation, formerIndex) === false) {
historyStack.push(formerIndex);
return false;
}
element.find(baseItemSelector + ':eq(' + formerIndex + ') a').tab('show');
};
this.currentIndex = function() {
return $navigation.find(baseItemSelector + ($settings.withVisible ? ':visible' : '')).index($activeTab);
};
this.firstIndex = function() {
return 0;
};
this.lastIndex = function() {
return obj.navigationLength();
};
this.getIndex = function(e) {
return $navigation.find(baseItemSelector + ($settings.withVisible ? ':visible' : '')).index(e);
};
this.nextIndex = function() {
var nextIndexCandidate = this.currentIndex();
var nextTabCandidate = null;
do {
nextIndexCandidate++;
nextTabCandidate = $navigation.find(baseItemSelector + ($settings.withVisible ? ':visible' : '') + ":eq(" + nextIndexCandidate + ")");
} while ((nextTabCandidate) && (nextTabCandidate.hasClass("disabled")));
return nextIndexCandidate;
};
this.previousIndex = function() {
var prevIndexCandidate = this.currentIndex();
var prevTabCandidate = null;
do {
prevIndexCandidate--;
prevTabCandidate = $navigation.find(baseItemSelector + ($settings.withVisible ? ':visible' : '') + ":eq(" + prevIndexCandidate + ")");
} while ((prevTabCandidate) && (prevTabCandidate.hasClass("disabled")));
return prevIndexCandidate;
};
this.navigationLength = function() {
return $navigation.find(baseItemSelector + ($settings.withVisible ? ':visible' : '')).length - 1;
};
this.activeTab = function() {
return $activeTab;
};
this.nextTab = function() {
return $navigation.find(baseItemSelector + ':eq(' + (obj.currentIndex() + 1) + ')').length ? $navigation.find(baseItemSelector + ':eq(' + (obj.currentIndex() + 1) + ')') : null;
};
this.previousTab = function() {
if (obj.currentIndex() <= 0) {
return null;
}
return $navigation.find(baseItemSelector + ':eq(' + parseInt(obj.currentIndex() - 1) + ')');
};
this.show = function(index) {
var tabToShow = isNaN(index) ?
element.find(baseItemSelector + ' a[href="#' + index + '"]') :
element.find(baseItemSelector + ':eq(' + index + ') a');
if (tabToShow.length > 0) {
historyStack.push(obj.currentIndex());
tabToShow.tab('show');
}
};
this.disable = function(index) {
$navigation.find(baseItemSelector + ':eq(' + index + ')').addClass('disabled');
};
this.enable = function(index) {
$navigation.find(baseItemSelector + ':eq(' + index + ')').removeClass('disabled');
};
this.hide = function(index) {
$navigation.find(baseItemSelector + ':eq(' + index + ')').hide();
};
this.display = function(index) {
$navigation.find(baseItemSelector + ':eq(' + index + ')').show();
};
this.remove = function(args) {
var $index = args[0];
var $removeTabPane = typeof args[1] != 'undefined' ? args[1] : false;
var $item = $navigation.find(baseItemSelector + ':eq(' + $index + ')');
// Remove the tab pane first if needed
if ($removeTabPane) {
var $href = $item.find('a').attr('href');
$($href).remove();
}
// Remove menu item
$item.remove();
};
var innerTabClick = function(e) {
// Get the index of the clicked tab
var $ul = $navigation.find(baseItemSelector);
var clickedIndex = $ul.index($(e.currentTarget).parent(baseItemSelector));
var $clickedTab = $($ul[clickedIndex]);
if ($settings.onTabClick && typeof $settings.onTabClick === 'function' && $settings.onTabClick($activeTab, $navigation, obj.currentIndex(), clickedIndex, $clickedTab) === false) {
return false;
}
};
var innerTabShown = function(e) {
var $element = $(e.target).parent();
var nextTab = $navigation.find(baseItemSelector).index($element);
// If it's disabled then do not change
if ($element.hasClass('disabled')) {
return false;
}
if ($settings.onTabChange && typeof $settings.onTabChange === 'function' && $settings.onTabChange($activeTab, $navigation, obj.currentIndex(), nextTab) === false) {
return false;
}
$activeTab = $element; // activated tab
obj.fixNavigationButtons();
};
this.resetWizard = function() {
// remove the existing handlers
$('a[data-toggle="tab"]', $navigation).off('click', innerTabClick);
$('a[data-toggle="tab"]', $navigation).off('show show.bs.tab', innerTabShown);
// reset elements based on current state of the DOM
$navigation = element.find('ul:first', element);
$activeTab = $navigation.find(baseItemSelector + '.active', element);
// re-add handlers
$('a[data-toggle="tab"]', $navigation).on('click', innerTabClick);
$('a[data-toggle="tab"]', $navigation).on('show show.bs.tab', innerTabShown);
obj.fixNavigationButtons();
};
$navigation = element.find('ul:first', element);
$activeTab = $navigation.find(baseItemSelector + '.active', element);
if (!$navigation.hasClass($settings.tabClass)) {
$navigation.addClass($settings.tabClass);
}
// Load onInit
if ($settings.onInit && typeof $settings.onInit === 'function') {
$settings.onInit($activeTab, $navigation, 0);
}
// Load onShow
if ($settings.onShow && typeof $settings.onShow === 'function') {
$settings.onShow($activeTab, $navigation, obj.nextIndex());
}
$('a[data-toggle="tab"]', $navigation).on('click', innerTabClick);
// attach to both show and show.bs.tab to support Bootstrap versions 2.3.2 and 3.0.0
$('a[data-toggle="tab"]', $navigation).on('show show.bs.tab', innerTabShown);
};
$.fn.bootstrapWizard = function(options) {
//expose methods
if (typeof options == 'string') {
var args = Array.prototype.slice.call(arguments, 1)
if (args.length === 1) {
args.toString();
}
return this.data('bootstrapWizard')[options](args);
}
return this.each(function(index) {
var element = $(this);
// Return early if this element already has a plugin instance
if (element.data('bootstrapWizard')) return;
// pass options to plugin constructor
var wizard = new bootstrapWizardCreate(element, options);
// Store plugin object in this element's data
element.data('bootstrapWizard', wizard);
// and then trigger initial change
wizard.fixNavigationButtons();
});
};
// expose options
$.fn.bootstrapWizard.defaults = {
withVisible: true,
tabClass: 'nav nav-pills',
nextSelector: '.wizard li.next',
previousSelector: '.wizard li.previous',
firstSelector: '.wizard li.first',
lastSelector: '.wizard li.last',
finishSelector: '.wizard li.finish',
backSelector: '.wizard li.back',
onShow: null,
onInit: null,
onNext: null,
onPrevious: null,
onLast: null,
onFirst: null,
onFinish: null,
onBack: null,
onTabChange: null,
onTabClick: null,
onTabShow: null
};
})(jQuery);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Some files were not shown because too many files have changed in this diff Show More