Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import os
- # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
- BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- # Quick-start development settings - unsuitable for production
- # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
- # SECURITY WARNING: keep the secret key used in production secret!
- SECRET_KEY = 'o0-0sp)e7qbr*6(v((xbv0q89&p#g=312_q=q+2uq4%ros(2+0'
- # SECURITY WARNING: don't run with debug turned on in production!
- DEBUG = True
- ALLOWED_HOSTS = []
- EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
- # Application definition
- INSTALLED_APPS = [
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'drivers', # my apps
- ]
- 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 = 'buster.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 = 'buster.wsgi.application'
- # Database
- # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
- DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql_psycopg2',
- 'NAME': 'buster_db',
- 'USER': 'postgres',
- 'PASSWORD': 'qwerty',
- 'HOST': 'localhost',
- 'PORT': '5432',
- }
- }
- # Password validation
- # https://docs.djangoproject.com/en/2.0/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/2.0/topics/i18n/
- LANGUAGE_CODE = 'ru-ru'
- TIME_ZONE = 'UTC'
- USE_I18N = True
- USE_L10N = True
- USE_TZ = True
- # Static files (CSS, JavaScript, Images)
- # https://docs.djangoproject.com/en/2.0/howto/static-files/
- STATIC_URL = '/static/'
- STATICFILES_DIRS = [
- os.path.join(BASE_DIR, 'static'),
- ]
- from django.contrib import admin
- from django.urls import path, include
- urlpatterns = [
- path('admin/', admin.site.urls),
- path('accounts/', include('drivers.urls')), # application url's
- ]
- from django.forms import ModelForm
- from django.core.exceptions import ValidationError
- from .models import Organization, Car, Profile, OrganizationRoute, Schedule
- from django.contrib.auth.models import User
- from django.contrib.auth.forms import UserChangeForm
- import requests, json
- # Your forms here.
- class OrganizationForm(ModelForm):
- def clean_unp(self):
- EGR_API = 'http://egr.gov.by/egrn/API.jsp?NM='
- unp = self.cleaned_data['unp']
- try:
- r = requests.get(EGR_API + unp)
- json_data = r.json()
- except json.decoder.JSONDecodeError:
- raise ValidationError('UNP is not register')
- if json_data[0]['ACT'] is False:
- raise ValidationError('UNP number in not active')
- return unp
- class Meta:
- model = Organization
- fields = ('name', 'unp', )
- class ProfileForm(UserChangeForm):
- class Meta:
- model = User
- fields = ('email', 'username', 'first_name', 'last_name', 'password')
- class OrganizationRoutesForm(ModelForm):
- class Meta:
- model = OrganizationRoute
- fields = ('start_place', 'final_place', 'start_time', 'final_time', 'price')
- exclude = ('organization', )
- class OrganizationCarsForm(ModelForm):
- class Meta:
- model = Car
- fields = ('model', 'seats', 'number')
- labels = {'model': 'Car model',
- 'seats': 'Number of seats',
- 'number': 'Car number',
- }
- exclude = ('organization', )
- class ScheduleForm(ModelForm):
- class Meta:
- model = Schedule
- fields = ('date', 'org_route', 'driver', 'car')
- from django.db import models
- from django.contrib.auth.models import User
- # Create your models here.
- class Profile(models.Model):
- mobile_number = models.CharField(max_length=12, unique=True)
- user = models.OneToOneField(User, on_delete=models.CASCADE)
- class Organization(models.Model):
- name = models.CharField(max_length=255)
- unp = models.CharField(max_length=9, unique=True)
- class Car(models.Model):
- model = models.CharField(max_length=255)
- seats = models.IntegerField()
- number = models.CharField(max_length=9, unique=True)
- organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
- class Employee(models.Model):
- STATUS = (
- ('OP', 'Operator'),
- ('DR', 'Driver')
- )
- name = models.OneToOneField(User, on_delete=models.CASCADE)
- status = models.CharField(max_length=8, choices=STATUS)
- hire_date = models.DateField()
- hire_end_date = models.DateField(null=True)
- organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
- class OrganizationInvite(models.Model):
- code = models.CharField(unique=True, max_length=10)
- organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
- class OrganizationRoute(models.Model):
- start_place = models.CharField(max_length=255)
- final_place = models.CharField(max_length=255)
- #route_distance = models.IntegerField() # distance rout value
- start_time = models.TimeField()
- #route_time = models.CharField(max_length=4) # time in rout distance
- final_time = models.TimeField()
- price = models.IntegerField()
- organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
- class Schedule(models.Model):
- date = models.DateField()
- org_route = models.ForeignKey(OrganizationRoute, on_delete=models.CASCADE)
- driver = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='schedule_driver')
- car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='schedule_car')
- class Flight(models.Model):
- STATUS = (
- ('True', 'True'),
- ('False', 'False')
- )
- schedule = models.ForeignKey(Schedule, on_delete=models.CASCADE, related_name='flight_schedule')
- user = models.OneToOneField(User, on_delete=models.CASCADE)
- status = models.CharField(max_length=5, choices=STATUS)
- from django.conf.urls import url, include, re_path
- from .views import signup, new_organization, send_invite_code, get_employees, edit_profile, add_route, add_car, add_schedule, get_cars, get_routes, get_main, get_search, get_user_routes, join_invite, flight_activate, get_stats
- from django.contrib.auth.views import login, logout
- urlpatterns = [
- # url(r'^profile/$', home),
- url(r'^signup/$', signup, name='signup'),
- url(r'^logout/', logout, name='logout'),
- url(r'^login/$', login, {'template_name': 'accounts/login.html'}, name='login'),
- url(r'^setting/$', edit_profile, name='settings_page'),
- # url(r'^organization/$', get_organization, name='organization'),
- url(r'^organization/(?P<invite>[a-zA-Z0-9]+)$', join_invite, name='invite_join'),
- #url(r'^organization/new/$', new_organization, name='new_org'),
- url(r'^organization/sho/$', send_invite_code, name='invite'),
- url(r'^organization/activate/$', flight_activate, name='flight_activate'),
- # organization pages
- url(r'^main/$', get_main, name='main_page'),
- url(r'^search$', get_search, name='search_page'),
- url(r'^routes', get_user_routes, name='user_routes'),
- # add
- url(r'^organization/add/route$', add_route, name='add_route'),
- url(r'^organization/add/car$', add_car, name='add_car'),
- url(r'^organization/add/schedule$', add_schedule, name='add_schedule'),
- # get
- url(r'^organization/employees/$', get_employees, name='employees'),
- url(r'^organization/cars/$', get_cars, name='cars'),
- url(r'^organization/routes/$', get_routes, name='routes'),
- url(r'^organization/stats/$', get_stats, name='stats'),
- from django.shortcuts import render, redirect
- from django.db.models import Q
- from django.contrib.auth.forms import UserCreationForm, User
- from .forms import OrganizationForm, ProfileForm, OrganizationRoutesForm, OrganizationCarsForm, ScheduleForm
- from django.contrib.auth import authenticate, login, logout
- from .models import Profile, Organization, Schedule, Car, Employee, OrganizationInvite, OrganizationRoute, Flight
- from django.core.mail import send_mail, BadHeaderError
- from django.http import HttpResponse, HttpResponseRedirect
- from django.contrib import messages
- import string
- import random
- import googlemaps
- import datetime
- GOOGLE_API_KEY = 'AIzaSyBhMPu5yfGH1CdqFXO7yiksGlgNR4T07J0'
- # Create your views here.
- def signup(request):
- if request.method == 'POST':
- form = UserCreationForm(request.POST)
- if form.is_valid():
- form.save()
- username = form.cleaned_data.get('username')
- password = form.cleaned_data.get('password1')
- user = authenticate(username=username, password=password)
- login(request, user)
- return redirect('/accounts/profile')
- else:
- form = UserCreationForm()
- return render(request, 'accounts/signup.html', {'form': form})
- def edit_profile(request):
- if request.method == 'POST':
- form = ProfileForm(request.POST, instance=request.user)
- if form.is_valid():
- form.save()
- return render(request, 'accounts/settings.html')
- else:
- form = ProfileForm(instance=request.user)
- return render(request, 'accounts/settings.html', {'form': form})
- # user organization information
- def get_main(request):
- return render(request, 'search/main_page.html')
- def error_msg(request):
- messages.error(request, '⚠ Пожалуйста выберите начальную и конечную точку маршрута')
- return redirect('main_page')
- def reg_msg(request):
- messages.error(request, '⚠ Вы уже записаны на данный рейс')
- return redirect('main_page')
- def ok_msg(request):
- messages.error(request, '✔ Вы успешно зарегестрированы на рейс')
- return redirect('user_routes')
- def get_search(request):
- queryset_list = Schedule.objects.all()
- if request.method == 'GET':
- #query = request.GET.get('start', 'final')
- start = request.GET['start']
- final = request.GET['final']
- date = request.GET['date']
- time = request.GET['time']
- if start and final:
- queryset_list = queryset_list.filter(
- Q(org_route__start_place__icontains=start) & Q(org_route__final_place__icontains=final)
- )
- elif start and final and date:
- queryset_list = queryset_list.filter(
- Q(org_route__start_place__icontains=start) & Q(org_route__final_place__icontains=final) & Q(date__icontains=date)
- )
- else:
- error_msg(request)
- context = {
- 'queryset': queryset_list,
- }
- return render(request, 'search/main_page.html', context)
- def check_operator_status(user):
- employee = Employee.objects.get(name=user)
- if employee.status == 'OP':
- return True
- def get_employees(request):
- user = request.user
- organization = user.employee.organization
- if organization:
- employees = Employee.objects.filter(organization=organization)
- status = check_operator_status(user)
- return render(request, 'organization/employees_page.html', {'employees': employees, 'status': status})
- def get_cars(request):
- user = request.user
- organization = user.employee.organization
- if organization:
- cars = Car.objects.filter(organization=organization)
- status = check_operator_status(user)
- return render(request, 'organization/cars_page.html', {'cars': cars, 'status': status})
- def get_routes(request):
- user = request.user
- organization = user.employee.organization
- if organization:
- routes = OrganizationRoute.objects.filter(organization=organization)
- status = check_operator_status(user)
- return render(request, 'organization/routes_page.html', {'routes': routes, 'status': status})
- def get_stats(request):
- user = request.user
- organization = user.employee.organization
- if organization:
- routes = OrganizationRoute.objects.filter(organization=organization)
- return render(request, 'organization/statistic_page.html', {'routes': routes})
- def add_route(request):
- gmaps = googlemaps.Client(key=GOOGLE_API_KEY)
- if request.method == 'POST':
- organization = request.user.employee.organization
- form = OrganizationRoutesForm(request.POST)
- if form.is_valid():
- car = form.save(commit=False)
- car.organization = organization
- car.save()
- return render(request, 'organization/add_page.html')
- else:
- form = OrganizationRoutesForm()
- return render(request, 'organization/add_page.html', {'form': form})
- def add_car(request):
- if request.method == 'POST':
- organization = request.user.employee.organization
- form = OrganizationCarsForm(request.POST)
- if form.is_valid():
- route = form.save(commit=False)
- route.organization = organization
- route.save()
- return render(request, 'organization/add_page.html')
- else:
- form = OrganizationCarsForm()
- return render(request, 'organization/add_page.html', {'form': form})
- def add_schedule(request):
- if request.method == 'POST':
- organization = request.user.employee.organization
- form = ScheduleForm(request.POST)
- if form.is_valid():
- car = form.save(commit=False)
- car.organization = organization
- car.save()
- return render(request, 'organization/add_page.html')
- else:
- form = ScheduleForm()
- return render(request, 'organization/add_page.html', {'form': form})
- def new_organization(request):
- if request.method == 'POST':
- form = OrganizationForm(request.POST)
- if form.is_valid():
- form.save()
- name = form.cleaned_data.get('name')
- unp = form.cleaned_data.get('unp')
- return redirect('login')
- else:
- form = OrganizationForm()
- return render(request, 'accounts/new_org.html', {'form': form})
- def get_user_routes(request):
- user = request.user
- # driver = user.employee.schedule
- if user:
- flight = Flight.objects.filter(user=user)
- return render(request, 'accounts/user_routes.html', {'flight': flight})
- def flight_activate(request):
- if request.method == 'POST':
- user = request.user
- schdule = request.POST.get('route')
- kek = Schedule.objects.get(id=schdule)
- flight = Flight.objects.filter(user=user)
- if schdule:
- if flight:
- reg_msg(request)
- else:
- Flight.objects.create(schedule=kek, user=user, status=False)
- ok_msg(request)
- return redirect('main_page')
- # invite 'system'
- def send_invite_code(request):
- # code settings
- user = request.user
- organization = user.employee.organization
- code = ''.join(random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(10))
- # email settings
- subject = 'Buster invite code'
- message = 'Hi! You invited to drivers company. If you not Roman - welcome to service. Invite url - http://localhost:8000/accounts/organization/{}'.format(code)
- from_message = request.POST.get('from_invite', '')
- if from_message and check_operator_status(user):
- try:
- send_mail(subject, message, 'invites@buster.io', [from_message])
- OrganizationInvite.objects.create(code=code, organization=organization)
- except BadHeaderError:
- return HttpResponse('invalid header')
- return redirect('/accounts/organization')
- else:
- return HttpResponse('Make sure all fields are entered and valid.')
- def join_invite(request, invite):
- user = request.user
- invite_code = OrganizationInvite.objects.get(code=invite)
- if invite_code:
- Employee.objects.create(
- name=user,
- status='DR',
- hire_date=datetime.date.today(),
- hire_end_date=datetime.date.today(),
- organization=invite_code.organization
- )
- invite_code.delete()
- var gulp = require('gulp'),
- gutil = require('gulp-util' ),
- sass = require('gulp-sass'),
- browserSync = require('browser-sync'),
- concat = require('gulp-concat'),
- uglify = require('gulp-uglify'),
- cleanCSS = require('gulp-clean-css'),
- rename = require('gulp-rename'),
- del = require('del'),
- imagemin = require('gulp-imagemin'),
- cache = require('gulp-cache'),
- autoprefixer = require('gulp-autoprefixer'),
- ftp = require('vinyl-ftp'),
- notify = require("gulp-notify"),
- rsync = require('gulp-rsync');
- // Пользовательские скрипты проекта
- gulp.task('common-js', function() {
- return gulp.src([
- 'app/js/common.js',
- ])
- .pipe(concat('common.min.js'))
- .pipe(uglify())
- .pipe(gulp.dest('app/js'));
- });
- gulp.task('js', ['common-js'], function() {
- return gulp.src([
- 'app/libs/jquery/dist/jquery.min.js',
- 'app/js/common.min.js', // Всегда в конце
- ])
- .pipe(concat('scripts.min.js'))
- // .pipe(uglify()) // Минимизировать весь js (на выбор)
- .pipe(gulp.dest('app/js'))
- .pipe(browserSync.reload({stream: true}));
- });
- gulp.task('browser-sync', function() {
- browserSync({
- server: {
- baseDir: 'app'
- },
- notify: false,
- // tunnel: true,
- // tunnel: "projectmane", //Demonstration page: http://projectmane.localtunnel.me
- });
- });
- gulp.task('sass', function() {
- return gulp.src('app/sass/**/*.sass')
- .pipe(sass({outputStyle: 'expand'}).on("error", notify.onError()))
- .pipe(rename({suffix: '.min', prefix : ''}))
- .pipe(autoprefixer(['last 15 versions']))
- .pipe(cleanCSS()) // Опционально, закомментировать при отладке
- .pipe(gulp.dest('app/css'))
- .pipe(browserSync.reload({stream: true}));
- });
- gulp.task('watch', ['sass', 'js', 'browser-sync'], function() {
- gulp.watch('app/sass/**/*.sass', ['sass']);
- gulp.watch(['libs/**/*.js', 'app/js/common.js'], ['js']);
- gulp.watch('app/*.html', browserSync.reload);
- });
- gulp.task('imagemin', function() {
- return gulp.src('app/img/**/*')
- .pipe(cache(imagemin())) // Cache Images
- .pipe(gulp.dest('dist/img'));
- });
- gulp.task('build', ['removedist', 'imagemin', 'sass', 'js'], function() {
- var buildFiles = gulp.src([
- 'app/*.html',
- 'app/.htaccess',
- ]).pipe(gulp.dest('dist'));
- var buildCss = gulp.src([
- 'app/css/main.min.css',
- ]).pipe(gulp.dest('dist/css'));
- var buildJs = gulp.src([
- 'app/js/scripts.min.js',
- ]).pipe(gulp.dest('dist/js'));
- var buildFonts = gulp.src([
- 'app/fonts/**/*',
- ]).pipe(gulp.dest('dist/fonts'));
- });
- gulp.task('deploy', function() {
- var conn = ftp.create({
- host: 'hostname.com',
- user: 'username',
- password: 'userpassword',
- parallel: 10,
- log: gutil.log
- });
- var globs = [
- 'dist/**',
- 'dist/.htaccess',
- ];
- return gulp.src(globs, {buffer: false})
- .pipe(conn.dest('/path/to/folder/on/server'));
- });
- gulp.task('rsync', function() {
- return gulp.src('dist/**')
- .pipe(rsync({
- root: 'dist/',
- hostname: 'username@yousite.com',
- destination: 'yousite/public_html/',
- // include: ['*.htaccess'], // Скрытые файлы, которые необходимо включить в деплой
- recursive: true,
- archive: true,
- silent: false,
- compress: true
- }));
- });
- gulp.task('removedist', function() { return del.sync('dist'); });
- gulp.task('clearcache', function () { return cache.clearAll(); });
- gulp.task('default', ['watch']);
- bal gettext, interpolate, ngettext*/
- (function($) {
- 'use strict';
- var lastChecked;
- $.fn.actions = function(opts) {
- var options = $.extend({}, $.fn.actions.defaults, opts);
- var actionCheckboxes = $(this);
- var list_editable_changed = false;
- var showQuestion = function() {
- $(options.acrossClears).hide();
- $(options.acrossQuestions).show();
- $(options.allContainer).hide();
- },
- showClear = function() {
- $(options.acrossClears).show();
- $(options.acrossQuestions).hide();
- $(options.actionContainer).toggleClass(options.selectedClass);
- $(options.allContainer).show();
- $(options.counterContainer).hide();
- },
- reset = function() {
- $(options.acrossClears).hide();
- $(options.acrossQuestions).hide();
- $(options.allContainer).hide();
- $(options.counterContainer).show();
- },
- clearAcross = function() {
- reset();
- $(options.acrossInput).val(0);
- $(options.actionContainer).removeClass(options.selectedClass);
- },
- checker = function(checked) {
- if (checked) {
- showQuestion();
- } else {
- reset();
- }
- $(actionCheckboxes).prop("checked", checked)
- .parent().parent().toggleClass(options.selectedClass, checked);
- },
- updateCounter = function() {
- var sel = $(actionCheckboxes).filter(":checked").length;
- // data-actions-icnt is defined in the generated HTML
- // and contains the total amount of objects in the queryset
- var actions_icnt = $('.action-counter').data('actionsIcnt');
- $(options.counterContainer).html(interpolate(
- ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), {
- sel: sel,
- cnt: actions_icnt
- }, true));
- $(options.allToggle).prop("checked", function() {
- var value;
- if (sel === actionCheckboxes.length) {
- value = true;
- showQuestion();
- } else {
- value = false;
- clearAcross();
- }
- return value;
- });
- };
- // Show counter by default
- $(options.counterContainer).show();
- // Check state of checkboxes and reinit state if needed
- $(this).filter(":checked").each(function(i) {
- $(this).parent().parent().toggleClass(options.selectedClass);
- updateCounter();
- if ($(options.acrossInput).val() === 1) {
- showClear();
- }
- });
- $(options.allToggle).show().click(function() {
- checker($(this).prop("checked"));
- updateCounter();
- });
- $("a", options.acrossQuestions).click(function(event) {
- event.preventDefault();
- $(options.acrossInput).val(1);
- showClear();
- });
- $("a", options.acrossClears).click(function(event) {
- event.preventDefault();
- $(options.allToggle).prop("checked", false);
- clearAcross();
- checker(0);
- updateCounter();
- });
- lastChecked = null;
- $(actionCheckboxes).click(function(event) {
- if (!event) { event = window.event; }
- var target = event.target ? event.target : event.srcElement;
- if (lastChecked && $.data(lastChecked) !== $.data(target) && event.shiftKey === true) {
- var inrange = false;
- $(lastChecked).prop("checked", target.checked)
- .parent().parent().toggleClass(options.selectedClass, target.checked);
- $(actionCheckboxes).each(function() {
- if ($.data(this) === $.data(lastChecked) || $.data(this) === $.data(target)) {
- inrange = (inrange) ? false : true;
- }
- if (inrange) {
- $(this).prop("checked", target.checked)
- .parent().parent().toggleClass(options.selectedClass, target.checked);
- }
- });
- }
- $(target).parent().parent().toggleClass(options.selectedClass, target.checked);
- lastChecked = target;
- updateCounter();
- });
- $('form#changelist-form table#result_list tr').on('change', 'td:gt(0) :input', function() {
- list_editable_changed = true;
- });
- $('form#changelist-form button[name="index"]').click(function(event) {
- if (list_editable_changed) {
- return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."));
- }
- });
- $('form#changelist-form input[name="_save"]').click(function(event) {
- var action_changed = false;
- $('select option:selected', options.actionContainer).each(function() {
- if ($(this).val()) {
- action_changed = true;
- }
- });
- if (action_changed) {
- if (list_editable_changed) {
- return confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action."));
- } else {
- return confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."));
- }
- }
- });
- };
- /* Setup plugin defaults */
- $.fn.actions.defaults = {
- actionContainer: "div.actions",
- counterContainer: "span.action-counter",
- allContainer: "div.actions span.all",
- acrossInput: "div.actions input.select-across",
- acrossQuestions: "div.actions span.question",
- acrossClears: "div.actions span.clear",
- allToggle: "#action-toggle",
- selectedClass: "selected"
- };
- $(document).ready(function() {
- var $actionsEls = $('tr input.action-select');
- if ($actionsEls.length > 0) {
- $actionsEls.actions();
- }
- });
- })(django.jQuery);
- var isOpera = (navigator.userAgent.indexOf("Opera") >= 0) && parseFloat(navigator.appVersion);
- var isIE = ((document.all) && (!isOpera)) && parseFloat(navigator.appVersion.split("MSIE ")[1].split(";")[0]);
- // quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]);
- function quickElement() {
- 'use strict';
- var obj = document.createElement(arguments[0]);
- if (arguments[2]) {
- var textNode = document.createTextNode(arguments[2]);
- obj.appendChild(textNode);
- }
- var len = arguments.length;
- for (var i = 3; i < len; i += 2) {
- obj.setAttribute(arguments[i], arguments[i + 1]);
- }
- arguments[1].appendChild(obj);
- return obj;
- }
- // "a" is reference to an object
- function removeChildren(a) {
- 'use strict';
- while (a.hasChildNodes()) {
- a.removeChild(a.lastChild);
- }
- }
- // ----------------------------------------------------------------------------
- // Find-position functions by PPK
- // See http://www.quirksmode.org/js/findpos.html
- // ----------------------------------------------------------------------------
- function findPosX(obj) {
- 'use strict';
- var curleft = 0;
- if (obj.offsetParent) {
- while (obj.offsetParent) {
- curleft += obj.offsetLeft - ((isOpera) ? 0 : obj.scrollLeft);
- obj = obj.offsetParent;
- }
- // IE offsetParent does not include the top-level
- if (isIE && obj.parentElement) {
- curleft += obj.offsetLeft - obj.scrollLeft;
- }
- } else if (obj.x) {
- curleft += obj.x;
- }
- return curleft;
- }
- function findPosY(obj) {
- 'use strict';
- var curtop = 0;
- if (obj.offsetParent) {
- while (obj.offsetParent) {
- curtop += obj.offsetTop - ((isOpera) ? 0 : obj.scrollTop);
- obj = obj.offsetParent;
- }
- // IE offsetParent does not include the top-level
- if (isIE && obj.parentElement) {
- curtop += obj.offsetTop - obj.scrollTop;
- }
- } else if (obj.y) {
- curtop += obj.y;
- }
- return curtop;
- }
- //-----------------------------------------------------------------------------
- // Date object extensions
- // ----------------------------------------------------------------------------
- (function() {
- 'use strict';
- Date.prototype.getTwelveHours = function() {
- var hours = this.getHours();
- if (hours === 0) {
- return 12;
- }
- else {
- return hours <= 12 ? hours : hours - 12;
- }
- };
- Date.prototype.getTwoDigitMonth = function() {
- return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1);
- };
- Date.prototype.getTwoDigitDate = function() {
- return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();
- };
- Date.prototype.getTwoDigitTwelveHour = function() {
- return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours();
- };
- Date.prototype.getTwoDigitHour = function() {
- return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
- };
- Date.prototype.getTwoDigitMinute = function() {
- return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes();
- };
- Date.prototype.getTwoDigitSecond = function() {
- return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();
- };
- Date.prototype.getHourMinute = function() {
- return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute();
- };
- Date.prototype.getHourMinuteSecond = function() {
- return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond();
- };
- Date.prototype.getFullMonthName = function() {
- return typeof window.CalendarNamespace === "undefined"
- ? this.getTwoDigitMonth()
- : window.CalendarNamespace.monthsOfYear[this.getMonth()];
- };
- Date.prototype.strftime = function(format) {
- var fields = {
- B: this.getFullMonthName(),
- c: this.toString(),
- d: this.getTwoDigitDate(),
- H: this.getTwoDigitHour(),
- I: this.getTwoDigitTwelveHour(),
- m: this.getTwoDigitMonth(),
- M: this.getTwoDigitMinute(),
- p: (this.getHours() >= 12) ? 'PM' : 'AM',
- S: this.getTwoDigitSecond(),
- w: '0' + this.getDay(),
- x: this.toLocaleDateString(),
- X: this.toLocaleTimeString(),
- y: ('' + this.getFullYear()).substr(2, 4),
- Y: '' + this.getFullYear(),
- '%': '%'
- };
- var result = '', i = 0;
- while (i < format.length) {
- if (format.charAt(i) === '%') {
- result = result + fields[format.charAt(i + 1)];
- ++i;
- }
- else {
- result = result + format.charAt(i);
- }
- ++i;
- }
- return result;
- };
- // ----------------------------------------------------------------------------
- // String object extensions
- // ----------------------------------------------------------------------------
- String.prototype.pad_left = function(pad_length, pad_string) {
- var new_string = this;
- for (var i = 0; new_string.length < pad_length; i++) {
- new_string = pad_string + new_string;
- }
- return new_string;
- };
- String.prototype.strptime = function(format) {
- var split_format = format.split(/[.\-/]/);
- var date = this.split(/[.\-/]/);
- var i = 0;
- var day, month, year;
- while (i < split_format.length) {
- switch (split_format[i]) {
- case "%d":
- day = date[i];
- break;
- case "%m":
- month = date[i] - 1;
- break;
- case "%Y":
- year = date[i];
- break;
- case "%y":
- year = date[i];
- break;
- }
- ++i;
- }
- // Create Date object from UTC since the parsed value is supposed to be
- // in UTC, not local time. Also, the calendar uses UTC functions for
- // date extraction.
- return new Date(Date.UTC(year, month, day));
- };
- })();
- function getStyle(oElm, strCssRule) {
- 'use strict';
- var strValue = "";
- if(document.defaultView && document.defaultView.getComputedStyle) {
- strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
- }
- else if(oElm.currentStyle) {
- strCssRule = strCssRule.replace(/\-(\w)/g, function(strMatch, p1) {
- return p1.toUpperCase();
- });
- strValue = oElm.currentStyle[strCssRule];
- }
- return strValue;
- }
- (function($) {
- 'use strict';
- $.fn.formset = function(opts) {
- var options = $.extend({}, $.fn.formset.defaults, opts);
- var $this = $(this);
- var $parent = $this.parent();
- var updateElementIndex = function(el, prefix, ndx) {
- var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
- var replacement = prefix + "-" + ndx;
- if ($(el).prop("for")) {
- $(el).prop("for", $(el).prop("for").replace(id_regex, replacement));
- }
- if (el.id) {
- el.id = el.id.replace(id_regex, replacement);
- }
- if (el.name) {
- el.name = el.name.replace(id_regex, replacement);
- }
- };
- var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").prop("autocomplete", "off");
- var nextIndex = parseInt(totalForms.val(), 10);
- var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").prop("autocomplete", "off");
- // only show the add button if we are allowed to add more items,
- // note that max_num = None translates to a blank string.
- var showAddButton = maxForms.val() === '' || (maxForms.val() - totalForms.val()) > 0;
- $this.each(function(i) {
- $(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
- });
- if ($this.length && showAddButton) {
- var addButton = options.addButton;
- if (addButton === null) {
- if ($this.prop("tagName") === "TR") {
- // If forms are laid out as table rows, insert the
- // "add" button in a new table row:
- var numCols = this.eq(-1).children().length;
- $parent.append('<tr class="' + options.addCssClass + '"><td colspan="' + numCols + '"><a href="#">' + options.addText + "</a></tr>");
- addButton = $parent.find("tr:last a");
- } else {
- // Otherwise, insert it immediately after the last form:
- $this.filter(":last").after('<div class="' + options.addCssClass + '"><a href="#">' + options.addText + "</a></div>");
- addButton = $this.filter(":last").next().find("a");
- }
- }
- addButton.click(function(e) {
- e.preventDefault();
- var template = $("#" + options.prefix + "-empty");
- var row = template.clone(true);
- row.removeClass(options.emptyCssClass)
- .addClass(options.formCssClass)
- .attr("id", options.prefix + "-" + nextIndex);
- if (row.is("tr")) {
- // If the forms are laid out in table rows, insert
- // the remove button into the last table cell:
- row.children(":last").append('<div><a class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></div>");
- } else if (row.is("ul") || row.is("ol")) {
- // If they're laid out as an ordered/unordered list,
- // insert an <li> after the last list item:
- row.append('<li><a class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></li>");
- } else {
- // Otherwise, just insert the remove button as the
- // last child element of the form's container:
- row.children(":first").append('<span><a class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></span>");
- }
- row.find("*").each(function() {
- updateElementIndex(this, options.prefix, totalForms.val());
- });
- // Insert the new form when it has been fully edited
- row.insertBefore($(template));
- // Update number of total forms
- $(totalForms).val(parseInt(totalForms.val(), 10) + 1);
- nextIndex += 1;
- // Hide add button in case we've hit the max, except we want to add infinitely
- if ((maxForms.val() !== '') && (maxForms.val() - totalForms.val()) <= 0) {
- addButton.parent().hide();
- }
- // The delete button of each row triggers a bunch of other things
- row.find("a." + options.deleteCssClass).click(function(e1) {
- e1.preventDefault();
- // Remove the parent form containing this button:
- row.remove();
- nextIndex -= 1;
- // If a post-delete callback was provided, call it with the deleted form:
- if (options.removed) {
- options.removed(row);
- }
- $(document).trigger('formset:removed', [row, options.prefix]);
- // Update the TOTAL_FORMS form count.
- var forms = $("." + options.formCssClass);
- $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
- // Show add button again once we drop below max
- if ((maxForms.val() === '') || (maxForms.val() - forms.length) > 0) {
- addButton.parent().show();
- }
- // Also, update names and ids for all remaining form controls
- // so they remain in sequence:
- var i, formCount;
- var updateElementCallback = function() {
- updateElementIndex(this, options.prefix, i);
- };
- for (i = 0, formCount = forms.length; i < formCount; i++) {
- updateElementIndex($(forms).get(i), options.prefix, i);
- $(forms.get(i)).find("*").each(updateElementCallback);
- }
- });
- // If a post-add callback was supplied, call it with the added form:
- if (options.added) {
- options.added(row);
- }
- $(document).trigger('formset:added', [row, options.prefix]);
- });
- }
- return this;
- };
- /* Setup plugin defaults */
- $.fn.formset.defaults = {
- prefix: "form", // The form prefix for your django formset
- addText: "add another", // Text for the add link
- deleteText: "remove", // Text for the delete link
- addCssClass: "add-row", // CSS class applied to the add link
- deleteCssClass: "delete-row", // CSS class applied to the delete link
- emptyCssClass: "empty-row", // CSS class applied to the empty row
- formCssClass: "dynamic-form", // CSS class applied to each form in a formset
- added: null, // Function called each time a new form is added
- removed: null, // Function called each time a form is deleted
- addButton: null // Existing add button to use
- };
- // Tabular inlines ---------------------------------------------------------
- $.fn.tabularFormset = function(options) {
- var $rows = $(this);
- var alternatingRows = function(row) {
- $($rows.selector).not(".add-row").removeClass("row1 row2")
- .filter(":even").addClass("row1").end()
- .filter(":odd").addClass("row2");
- };
- var reinitDateTimeShortCuts = function() {
- // Reinitialize the calendar and clock widgets by force
- if (typeof DateTimeShortcuts !== "undefined") {
- $(".datetimeshortcuts").remove();
- DateTimeShortcuts.init();
- }
- };
- var updateSelectFilter = function() {
- // If any SelectFilter widgets are a part of the new form,
- // instantiate a new SelectFilter instance for it.
- if (typeof SelectFilter !== 'undefined') {
- $('.selectfilter').each(function(index, value) {
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length - 1], false);
- });
- $('.selectfilterstacked').each(function(index, value) {
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length - 1], true);
- });
- }
- };
- var initPrepopulatedFields = function(row) {
- row.find('.prepopulated_field').each(function() {
- var field = $(this),
- input = field.find('input, select, textarea'),
- dependency_list = input.data('dependency_list') || [],
- dependencies = [];
- $.each(dependency_list, function(i, field_name) {
- dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id'));
- });
- if (dependencies.length) {
- input.prepopulate(dependencies, input.attr('maxlength'));
- }
- });
- };
- $rows.formset({
- prefix: options.prefix,
- addText: options.addText,
- formCssClass: "dynamic-" + options.prefix,
- deleteCssClass: "inline-deletelink",
- deleteText: options.deleteText,
- emptyCssClass: "empty-form",
- removed: alternatingRows,
- added: function(row) {
- initPrepopulatedFields(row);
- reinitDateTimeShortCuts();
- updateSelectFilter();
- alternatingRows(row);
- },
- addButton: options.addButton
- });
- return $rows;
- };
- // Stacked inlines ---------------------------------------------------------
- $.fn.stackedFormset = function(options) {
- var $rows = $(this);
- var updateInlineLabel = function(row) {
- $($rows.selector).find(".inline_label").each(function(i) {
- var count = i + 1;
- $(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
- });
- };
- var reinitDateTimeShortCuts = function() {
- // Reinitialize the calendar and clock widgets by force, yuck.
- if (typeof DateTimeShortcuts !== "undefined") {
- $(".datetimeshortcuts").remove();
- DateTimeShortcuts.init();
- }
- };
- var updateSelectFilter = function() {
- // If any SelectFilter widgets were added, instantiate a new instance.
- if (typeof SelectFilter !== "undefined") {
- $(".selectfilter").each(function(index, value) {
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length - 1], false);
- });
- $(".selectfilterstacked").each(function(index, value) {
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length - 1], true);
- });
- }
- };
- var initPrepopulatedFields = function(row) {
- row.find('.prepopulated_field').each(function() {
- var field = $(this),
- input = field.find('input, select, textarea'),
- dependency_list = input.data('dependency_list') || [],
- dependencies = [];
- $.each(dependency_list, function(i, field_name) {
- dependencies.push('#' + row.find('.form-row .field-' + field_name).find('input, select, textarea').attr('id'));
- });
- if (dependencies.length) {
- input.prepopulate(dependencies, input.attr('maxlength'));
- }
- });
- };
- $rows.formset({
- prefix: options.prefix,
- addText: options.addText,
- formCssClass: "dynamic-" + options.prefix,
- deleteCssClass: "inline-deletelink",
- deleteText: options.deleteText,
- emptyCssClass: "empty-form",
- removed: updateInlineLabel,
- added: function(row) {
- initPrepopulatedFields(row);
- reinitDateTimeShortCuts();
- updateSelectFilter();
- updateInlineLabel(row);
- },
- addButton: options.addButton
- });
- return $rows;
- };
- $(document).ready(function() {
- $(".js-inline-admin-formset").each(function() {
- var data = $(this).data(),
- inlineOptions = data.inlineFormset;
- switch(data.inlineType) {
- case "stacked":
- $(inlineOptions.name + "-group .inline-related").stackedFormset(inlineOptions.options);
- break;
- case "tabular":
- $(inlineOptions.name + "-group .tabular.inline-related tbody:first > tr").tabularFormset(inlineOptions.options);
- break;
- }
- });
- });
- })(django.jQuery);
- (function($) {
- 'use strict';
- function findForm(node) {
- // returns the node of the form containing the given node
- if (node.tagName.toLowerCase() !== 'form') {
- return findForm(node.parentNode);
- }
- return node;
- }
- window.SelectFilter = {
- init: function(field_id, field_name, is_stacked) {
- if (field_id.match(/__prefix__/)) {
- // Don't initialize on empty forms.
- return;
- }
- var from_box = document.getElementById(field_id);
- from_box.id += '_from'; // change its ID
- from_box.className = 'filtered';
- var ps = from_box.parentNode.getElementsByTagName('p');
- for (var i = 0; i < ps.length; i++) {
- if (ps[i].className.indexOf("info") !== -1) {
- // Remove <p class="info">, because it just gets in the way.
- from_box.parentNode.removeChild(ps[i]);
- } else if (ps[i].className.indexOf("help") !== -1) {
- // Move help text up to the top so it isn't below the select
- // boxes or wrapped off on the side to the right of the add
- // button:
- from_box.parentNode.insertBefore(ps[i], from_box.parentNode.firstChild);
- }
- }
- // <div class="selector"> or <div class="selector stacked">
- var selector_div = quickElement('div', from_box.parentNode);
- selector_div.className = is_stacked ? 'selector stacked' : 'selector';
- // <div class="selector-available">
- var selector_available = quickElement('div', selector_div);
- selector_available.className = 'selector-available';
- var title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name]));
- quickElement(
- 'span', title_available, '',
- 'class', 'help help-tooltip help-icon',
- 'title', interpolate(
- gettext(
- 'This is the list of available %s. You may choose some by ' +
- 'selecting them in the box below and then clicking the ' +
- '"Choose" arrow between the two boxes.'
- ),
- [field_name]
- )
- );
- var filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter');
- filter_p.className = 'selector-filter';
- var search_filter_label = quickElement('label', filter_p, '', 'for', field_id + '_input');
- quickElement(
- 'span', search_filter_label, '',
- 'class', 'help-tooltip search-label-icon',
- 'title', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name])
- );
- filter_p.appendChild(document.createTextNode(' '));
- var filter_input = quickElement('input', filter_p, '', 'type', 'text', 'placeholder', gettext("Filter"));
- filter_input.id = field_id + '_input';
- selector_available.appendChild(from_box);
- var choose_all = quickElement('a', selector_available, gettext('Choose all'), 'title', interpolate(gettext('Click to choose all %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_add_all_link');
- choose_all.className = 'selector-chooseall';
- // <ul class="selector-chooser">
- var selector_chooser = quickElement('ul', selector_div);
- selector_chooser.className = 'selector-chooser';
- var add_link = quickElement('a', quickElement('li', selector_chooser), gettext('Choose'), 'title', gettext('Choose'), 'href', '#', 'id', field_id + '_add_link');
- add_link.className = 'selector-add';
- var remove_link = quickElement('a', quickElement('li', selector_chooser), gettext('Remove'), 'title', gettext('Remove'), 'href', '#', 'id', field_id + '_remove_link');
- remove_link.className = 'selector-remove';
- // <div class="selector-chosen">
- var selector_chosen = quickElement('div', selector_div);
- selector_chosen.className = 'selector-chosen';
- var title_chosen = quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s') + ' ', [field_name]));
- quickElement(
- 'span', title_chosen, '',
- 'class', 'help help-tooltip help-icon',
- 'title', interpolate(
- gettext(
- 'This is the list of chosen %s. You may remove some by ' +
- 'selecting them in the box below and then clicking the ' +
- '"Remove" arrow between the two boxes.'
- ),
- [field_name]
- )
- );
- var to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', 'multiple', 'size', from_box.size, 'name', from_box.getAttribute('name'));
- to_box.className = 'filtered';
- var clear_all = quickElement('a', selector_chosen, gettext('Remove all'), 'title', interpolate(gettext('Click to remove all chosen %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_remove_all_link');
- clear_all.className = 'selector-clearall';
- from_box.setAttribute('name', from_box.getAttribute('name') + '_old');
- // Set up the JavaScript event handlers for the select box filter interface
- var move_selection = function(e, elem, move_func, from, to) {
- if (elem.className.indexOf('active') !== -1) {
- move_func(from, to);
- SelectFilter.refresh_icons(field_id);
- }
- e.preventDefault();
- };
- choose_all.addEventListener('click', function(e) {
- move_selection(e, this, SelectBox.move_all, field_id + '_from', field_id + '_to');
- });
- add_link.addEventListener('click', function(e) {
- move_selection(e, this, SelectBox.move, field_id + '_from', field_id + '_to');
- });
- remove_link.addEventListener('click', function(e) {
- move_selection(e, this, SelectBox.move, field_id + '_to', field_id + '_from');
- });
- clear_all.addEventListener('click', function(e) {
- move_selection(e, this, SelectBox.move_all, field_id + '_to', field_id + '_from');
- });
- filter_input.addEventListener('keypress', function(e) {
- SelectFilter.filter_key_press(e, field_id);
- });
- filter_input.addEventListener('keyup', function(e) {
- SelectFilter.filter_key_up(e, field_id);
- });
- filter_input.addEventListener('keydown', function(e) {
- SelectFilter.filter_key_down(e, field_id);
- });
- selector_div.addEventListener('change', function(e) {
- if (e.target.tagName === 'SELECT') {
- SelectFilter.refresh_icons(field_id);
- }
- });
- selector_div.addEventListener('dblclick', function(e) {
- if (e.target.tagName === 'OPTION') {
- if (e.target.closest('select').id === field_id + '_to') {
- SelectBox.move(field_id + '_to', field_id + '_from');
- } else {
- SelectBox.move(field_id + '_from', field_id + '_to');
- }
- SelectFilter.refresh_icons(field_id);
- }
- });
- findForm(from_box).addEventListener('submit', function() {
- SelectBox.select_all(field_id + '_to');
- });
- SelectBox.init(field_id + '_from');
- SelectBox.init(field_id + '_to');
- // Move selected from_box options to to_box
- SelectBox.move(field_id + '_from', field_id + '_to');
- if (!is_stacked) {
- // In horizontal mode, give the same height to the two boxes.
- var j_from_box = $(from_box);
- var j_to_box = $(to_box);
- var resize_filters = function() { j_to_box.height($(filter_p).outerHeight() + j_from_box.outerHeight()); };
- if (j_from_box.outerHeight() > 0) {
- resize_filters(); // This fieldset is already open. Resize now.
- } else {
- // This fieldset is probably collapsed. Wait for its 'show' event.
- j_to_box.closest('fieldset').one('show.fieldset', resize_filters);
- }
- }
- // Initial icon refresh
- SelectFilter.refresh_icons(field_id);
- },
- any_selected: function(field) {
- var any_selected = false;
- try {
- // Temporarily add the required attribute and check validity.
- // This is much faster in WebKit browsers than the fallback.
- field.attr('required', 'required');
- any_selected = field.is(':valid');
- field.removeAttr('required');
- } catch (e) {
- // Browsers that don't support :valid (IE < 10)
- any_selected = field.find('option:selected').length > 0;
- }
- return any_selected;
- },
- refresh_icons: function(field_id) {
- var from = $('#' + field_id + '_from');
- var to = $('#' + field_id + '_to');
- // Active if at least one item is selected
- $('#' + field_id + '_add_link').toggleClass('active', SelectFilter.any_selected(from));
- $('#' + field_id + '_remove_link').toggleClass('active', SelectFilter.any_selected(to));
- // Active if the corresponding box isn't empty
- $('#' + field_id + '_add_all_link').toggleClass('active', from.find('option').length > 0);
- $('#' + field_id + '_remove_all_link').toggleClass('active', to.find('option').length > 0);
- },
- filter_key_press: function(event, field_id) {
- var from = document.getElementById(field_id + '_from');
- // don't submit form if user pressed Enter
- if ((event.which && event.which === 13) || (event.keyCode && event.keyCode === 13)) {
- from.selectedIndex = 0;
- SelectBox.move(field_id + '_from', field_id + '_to');
- from.selectedIndex = 0;
- event.preventDefault();
- return false;
- }
- },
- filter_key_up: function(event, field_id) {
- var from = document.getElementById(field_id + '_from');
- var temp = from.selectedIndex;
- SelectBox.filter(field_id + '_from', document.getElementById(field_id + '_input').value);
- from.selectedIndex = temp;
- return true;
- },
- filter_key_down: function(event, field_id) {
- var from = document.getElementById(field_id + '_from');
- // right arrow -- move across
- if ((event.which && event.which === 39) || (event.keyCode && event.keyCode === 39)) {
- var old_index = from.selectedIndex;
- SelectBox.move(field_id + '_from', field_id + '_to');
- from.selectedIndex = (old_index === from.length) ? from.length - 1 : old_index;
- return false;
- }
- // down arrow -- wrap around
- if ((event.which && event.which === 40) || (event.keyCode && event.keyCode === 40)) {
- from.selectedIndex = (from.length === from.selectedIndex + 1) ? 0 : from.selectedIndex + 1;
- }
- // up arrow -- wrap around
- if ((event.which && event.which === 38) || (event.keyCode && event.keyCode === 38)) {
- from.selectedIndex = (from.selectedIndex === 0) ? from.length - 1 : from.selectedIndex - 1;
- }
- return true;
- }
- };
- window.addEventListener('load', function(e) {
- $('select.selectfilter, select.selectfilterstacked').each(function() {
- var $el = $(this),
- data = $el.data();
- SelectFilter.init($el.attr('id'), data.fieldName, parseInt(data.isStacked, 10));
- });
- });
- })(django.jQuery);
- (function() {
- 'use strict';
- var timeParsePatterns = [
- // 9
- {
- re: /^\d{1,2}$/i,
- handler: function(bits) {
- if (bits[0].length === 1) {
- return '0' + bits[0] + ':00';
- } else {
- return bits[0] + ':00';
- }
- }
- },
- // 13:00
- {
- re: /^\d{2}[:.]\d{2}$/i,
- handler: function(bits) {
- return bits[0].replace('.', ':');
- }
- },
- // 9:00
- {
- re: /^\d[:.]\d{2}$/i,
- handler: function(bits) {
- return '0' + bits[0].replace('.', ':');
- }
- },
- // 3 am / 3 a.m. / 3am
- {
- re: /^(\d+)\s*([ap])(?:.?m.?)?$/i,
- handler: function(bits) {
- var hour = parseInt(bits[1]);
- if (hour === 12) {
- hour = 0;
- }
- if (bits[2].toLowerCase() === 'p') {
- if (hour === 12) {
- hour = 0;
- }
- return (hour + 12) + ':00';
- } else {
- if (hour < 10) {
- return '0' + hour + ':00';
- } else {
- return hour + ':00';
- }
- }
- }
- },
- // 3.30 am / 3:15 a.m. / 3.00am
- {
- re: /^(\d+)[.:](\d{2})\s*([ap]).?m.?$/i,
- handler: function(bits) {
- var hour = parseInt(bits[1]);
- var mins = parseInt(bits[2]);
- if (mins < 10) {
- mins = '0' + mins;
- }
- if (hour === 12) {
- hour = 0;
- }
- if (bits[3].toLowerCase() === 'p') {
- if (hour === 12) {
- hour = 0;
- }
- return (hour + 12) + ':' + mins;
- } else {
- if (hour < 10) {
- return '0' + hour + ':' + mins;
- } else {
- return hour + ':' + mins;
- }
- }
- }
- },
- // noon
- {
- re: /^no/i,
- handler: function(bits) {
- return '12:00';
- }
- },
- // midnight
- {
- re: /^mid/i,
- handler: function(bits) {
- return '00:00';
- }
- }
- ];
- function parseTimeString(s) {
- for (var i = 0; i < timeParsePatterns.length; i++) {
- var re = timeParsePatterns[i].re;
- var handler = timeParsePatterns[i].handler;
- var bits = re.exec(s);
- if (bits) {
- return handler(bits);
- }
- }
- return s;
- }
- window.parseTimeString = parseTimeString;
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement