Merge branch 'master' into supportBDS
- Mise en page - Cleanup des petits cours - Utilisation de custommail - Utilisation du ldap du SPI pour fetch les nouveaux comptes
This commit is contained in:
commit
50b667993f
58 changed files with 818 additions and 2462 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 cof-geek
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -171,6 +171,9 @@ Il ne vous reste plus qu'à initialiser les modèles de Django avec la commande
|
||||||
|
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
|
|
||||||
|
Charger les mails indispensables au bon fonctionnement de GestioCOF :
|
||||||
|
|
||||||
|
python manage.py syncmails
|
||||||
|
|
||||||
Une base de donnée pré-remplie est disponible en lançant les commandes :
|
Une base de donnée pré-remplie est disponible en lançant les commandes :
|
||||||
|
|
||||||
|
|
77
bda/admin.py
77
bda/admin.py
|
@ -1,10 +1,9 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import division
|
import autocomplete_light
|
||||||
from __future__ import print_function
|
from datetime import timedelta
|
||||||
from __future__ import unicode_literals
|
from custommail.shortcuts import send_mass_custom_mail
|
||||||
|
|
||||||
from django.core.mail import send_mail
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.db.models import Sum, Count
|
from django.db.models import Sum, Count
|
||||||
from django.template.defaultfilters import pluralize
|
from django.template.defaultfilters import pluralize
|
||||||
|
@ -13,10 +12,6 @@ from django import forms
|
||||||
from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\
|
from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\
|
||||||
Attribution, Tirage, Quote, CategorieSpectacle, SpectacleRevente
|
Attribution, Tirage, Quote, CategorieSpectacle, SpectacleRevente
|
||||||
|
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
import autocomplete_light
|
|
||||||
|
|
||||||
|
|
||||||
class ChoixSpectacleInline(admin.TabularInline):
|
class ChoixSpectacleInline(admin.TabularInline):
|
||||||
model = ChoixSpectacle
|
model = ChoixSpectacle
|
||||||
|
@ -72,66 +67,20 @@ class ParticipantAdmin(admin.ModelAdmin):
|
||||||
readonly_fields = ("total",)
|
readonly_fields = ("total",)
|
||||||
|
|
||||||
def send_attribs(self, request, queryset):
|
def send_attribs(self, request, queryset):
|
||||||
|
datatuple = []
|
||||||
for member in queryset.all():
|
for member in queryset.all():
|
||||||
attribs = member.attributions.all()
|
attribs = member.attributions.all()
|
||||||
|
context = {'member': member.user}
|
||||||
|
shortname = ""
|
||||||
if len(attribs) == 0:
|
if len(attribs) == 0:
|
||||||
mail = """Cher-e %s,
|
shortname = "bda-attributions-decus"
|
||||||
|
|
||||||
Tu t'es inscrit-e pour le tirage au sort du BdA. Malheureusement, tu n'as
|
|
||||||
obtenu aucune place.
|
|
||||||
|
|
||||||
Nous proposons cependant de nombreuses offres hors-tirage tout au long de
|
|
||||||
l'année, et nous t'invitons à nous contacter si l'une d'entre elles
|
|
||||||
t'intéresse !
|
|
||||||
--
|
|
||||||
Le Bureau des Arts
|
|
||||||
|
|
||||||
"""
|
|
||||||
name = member.user.get_full_name()
|
|
||||||
mail = mail % name
|
|
||||||
else:
|
else:
|
||||||
mail = """Cher-e %s,
|
shortname = "bda-attributions"
|
||||||
|
context['places'] = attribs
|
||||||
Tu t'es inscrit-e pour le tirage au sort du BdA. Tu as été sélectionné-e
|
print(context)
|
||||||
pour les spectacles suivants :
|
datatuple.append((shortname, context, "bda@ens.fr",
|
||||||
|
[member.user.email]))
|
||||||
%s
|
send_mass_custom_mail(datatuple)
|
||||||
|
|
||||||
*Paiement*
|
|
||||||
L'intégralité de ces places de spectacles est à régler dès maintenant et AVANT
|
|
||||||
le %s, au bureau du COF pendant les heures de permanences (du lundi au vendredi
|
|
||||||
entre 12h et 14h, et entre 18h et 20h). Des facilités de paiement sont bien
|
|
||||||
évidemment possibles : nous pouvons ne pas encaisser le chèque immédiatement,
|
|
||||||
ou bien découper votre paiement en deux fois. Pour ceux qui ne pourraient pas
|
|
||||||
venir payer au bureau, merci de nous contacter par mail.
|
|
||||||
|
|
||||||
*Mode de retrait des places*
|
|
||||||
Au moment du paiement, certaines places vous seront remises directement,
|
|
||||||
d'autres seront à récupérer au cours de l'année, d'autres encore seront
|
|
||||||
nominatives et à retirer le soir même dans les theâtres correspondants.
|
|
||||||
Pour chaque spectacle, vous recevrez un mail quelques jours avant la
|
|
||||||
représentation vous indiquant le mode de retrait.
|
|
||||||
|
|
||||||
Nous vous rappelons que l'obtention de places du BdA vous engage à
|
|
||||||
respecter les règles de fonctionnement :
|
|
||||||
http://www.cof.ens.fr/bda/?page_id=1370
|
|
||||||
Le système de revente des places via les mails BdA-revente sera très
|
|
||||||
prochainement disponible, directement sur votre compte GestioCOF.
|
|
||||||
|
|
||||||
En vous souhaitant de très beaux spectacles tout au long de l'année,
|
|
||||||
--
|
|
||||||
Le Bureau des Arts
|
|
||||||
"""
|
|
||||||
attribs_text = ""
|
|
||||||
name = member.user.get_full_name()
|
|
||||||
for attrib in attribs:
|
|
||||||
attribs_text += "- 1 place pour %s\n" % attrib
|
|
||||||
deadline = member.tirage.fermeture + timedelta(days=7)
|
|
||||||
mail = mail % (name, attribs_text,
|
|
||||||
deadline.strftime('%d %b %Y'))
|
|
||||||
send_mail("Résultats du tirage au sort", mail,
|
|
||||||
"bda@ens.fr", [member.user.email],
|
|
||||||
fail_silently=True)
|
|
||||||
count = len(queryset.all())
|
count = len(queryset.all())
|
||||||
if count == 1:
|
if count == 1:
|
||||||
message_bit = "1 membre a"
|
message_bit = "1 membre a"
|
||||||
|
|
|
@ -8,7 +8,6 @@ from datetime import timedelta
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.forms.models import BaseInlineFormSet
|
from django.forms.models import BaseInlineFormSet
|
||||||
from django.db.models import Q
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from bda.models import Attribution, Spectacle
|
from bda.models import Attribution, Spectacle
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import os
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import Group
|
||||||
|
|
||||||
from cof.management.base import MyBaseCommand
|
from cof.management.base import MyBaseCommand
|
||||||
from bda.models import Tirage, Spectacle, Salle, Participant, ChoixSpectacle
|
from bda.models import Tirage, Spectacle, Salle, Participant, ChoixSpectacle
|
||||||
|
@ -77,7 +77,8 @@ class Command(MyBaseCommand):
|
||||||
self.stdout.write("Inscription des utilisateurs aux tirages")
|
self.stdout.write("Inscription des utilisateurs aux tirages")
|
||||||
ChoixSpectacle.objects.all().delete()
|
ChoixSpectacle.objects.all().delete()
|
||||||
choices = []
|
choices = []
|
||||||
for user in User.objects.filter(profile__cof__is_cof=True):
|
cof_members = Group.objects.get(name="cof_members")
|
||||||
|
for user in cof_members.user_set.all():
|
||||||
for tirage in tirages:
|
for tirage in tirages:
|
||||||
part, _ = Participant.objects.get_or_create(
|
part, _ = Participant.objects.get_or_create(
|
||||||
user=user,
|
user=user,
|
||||||
|
|
156
bda/models.py
156
bda/models.py
|
@ -3,12 +3,11 @@
|
||||||
import calendar
|
import calendar
|
||||||
import random
|
import random
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from custommail.shortcuts import send_mass_custom_mail
|
||||||
|
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.template import loader
|
|
||||||
from django.core import mail
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import timezone, formats
|
from django.utils import timezone, formats
|
||||||
|
|
||||||
|
@ -91,33 +90,30 @@ class Spectacle(models.Model):
|
||||||
if member.id in members:
|
if member.id in members:
|
||||||
members[member.id][1] = 2
|
members[member.id][1] = 2
|
||||||
else:
|
else:
|
||||||
members[member.id] = [member.first_name, 1, member.email]
|
members[member.id] = [member, 1]
|
||||||
# Pour le BdA
|
# FIXME : faire quelque chose de ça, un utilisateur bda_generic ?
|
||||||
members[0] = ['BdA', 1, 'bda@ens.fr']
|
# # Pour le BdA
|
||||||
members[-1] = ['BdA', 2, 'bda@ens.fr']
|
# members[0] = ['BdA', 1, 'bda@ens.fr']
|
||||||
|
# members[-1] = ['BdA', 2, 'bda@ens.fr']
|
||||||
# On écrit un mail personnalisé à chaque participant
|
# On écrit un mail personnalisé à chaque participant
|
||||||
mails_to_send = []
|
datatuple = [(
|
||||||
mail_object = str(self)
|
'bda-rappel',
|
||||||
for member in members.values():
|
{'member': member[0], 'nb_attr': member[1], 'show': self},
|
||||||
mail_body = loader.render_to_string('bda/mails/rappel.txt', {
|
settings.MAIL_DATA['rappels']['FROM'],
|
||||||
'name': member[0],
|
[member[0].email])
|
||||||
'nb_attr': member[1],
|
for member in members.values()
|
||||||
'show': self})
|
]
|
||||||
mail_tot = mail.EmailMessage(
|
send_mass_custom_mail(datatuple)
|
||||||
mail_object, mail_body,
|
|
||||||
settings.MAIL_DATA['rappels']['FROM'], [member[2]],
|
|
||||||
[], headers={
|
|
||||||
'Reply-To': settings.MAIL_DATA['rappels']['REPLYTO']})
|
|
||||||
mails_to_send.append(mail_tot)
|
|
||||||
# On envoie les mails
|
|
||||||
connection = mail.get_connection()
|
|
||||||
connection.send_messages(mails_to_send)
|
|
||||||
# On enregistre le fait que l'envoi a bien eu lieu
|
# On enregistre le fait que l'envoi a bien eu lieu
|
||||||
self.rappel_sent = timezone.now()
|
self.rappel_sent = timezone.now()
|
||||||
self.save()
|
self.save()
|
||||||
# On renvoie la liste des destinataires
|
# On renvoie la liste des destinataires
|
||||||
return members.values()
|
return members.values()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_past(self):
|
||||||
|
return self.date < timezone.now()
|
||||||
|
|
||||||
|
|
||||||
class Quote(models.Model):
|
class Quote(models.Model):
|
||||||
spectacle = models.ForeignKey(Spectacle)
|
spectacle = models.ForeignKey(Spectacle)
|
||||||
|
@ -238,26 +234,24 @@ class SpectacleRevente(models.Model):
|
||||||
verbose_name = "Revente"
|
verbose_name = "Revente"
|
||||||
|
|
||||||
def send_notif(self):
|
def send_notif(self):
|
||||||
|
"""
|
||||||
|
Envoie une notification pour indiquer la mise en vente d'une place sur
|
||||||
|
BdA-Revente à tous les intéressés.
|
||||||
|
"""
|
||||||
inscrits = self.attribution.spectacle.subscribed.select_related('user')
|
inscrits = self.attribution.spectacle.subscribed.select_related('user')
|
||||||
|
datatuple = [(
|
||||||
mails_to_send = []
|
'bda-revente',
|
||||||
mail_object = "%s" % (self.attribution.spectacle)
|
{
|
||||||
for participant in inscrits:
|
'member': participant.user,
|
||||||
mail_body = loader.render_to_string('bda/mails/revente.txt', {
|
'show': self.attribution.spectacle,
|
||||||
'user': participant.user,
|
|
||||||
'spectacle': self.attribution.spectacle,
|
|
||||||
'revente': self,
|
'revente': self,
|
||||||
'domain': Site.objects.get_current().domain})
|
'site': Site.objects.get_current()
|
||||||
mail_tot = mail.EmailMessage(
|
},
|
||||||
mail_object, mail_body,
|
|
||||||
settings.MAIL_DATA['revente']['FROM'],
|
settings.MAIL_DATA['revente']['FROM'],
|
||||||
[participant.user.email],
|
[participant.user.email])
|
||||||
[], headers={
|
for participant in inscrits
|
||||||
'Reply-To': settings.MAIL_DATA['revente']['REPLYTO']})
|
]
|
||||||
mails_to_send.append(mail_tot)
|
send_mass_custom_mail(datatuple)
|
||||||
|
|
||||||
connection = mail.get_connection()
|
|
||||||
connection.send_messages(mails_to_send)
|
|
||||||
self.notif_sent = True
|
self.notif_sent = True
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
@ -267,25 +261,18 @@ class SpectacleRevente(models.Model):
|
||||||
leur indiquer qu'il est désormais disponible au shotgun.
|
leur indiquer qu'il est désormais disponible au shotgun.
|
||||||
"""
|
"""
|
||||||
inscrits = self.attribution.spectacle.subscribed.select_related('user')
|
inscrits = self.attribution.spectacle.subscribed.select_related('user')
|
||||||
|
datatuple = [(
|
||||||
mails_to_send = []
|
'bda-shotgun',
|
||||||
mail_object = "%s" % (self.attribution.spectacle)
|
{
|
||||||
for participant in inscrits:
|
'member': participant.user,
|
||||||
mail_body = loader.render_to_string('bda/mails/shotgun.txt', {
|
'show': self.attribution.spectacle,
|
||||||
'user': participant.user,
|
'site': Site.objects.get_current(),
|
||||||
'spectacle': self.attribution.spectacle,
|
},
|
||||||
'domain': Site.objects.get_current(),
|
|
||||||
'mail': self.attribution.participant.user.email})
|
|
||||||
mail_tot = mail.EmailMessage(
|
|
||||||
mail_object, mail_body,
|
|
||||||
settings.MAIL_DATA['revente']['FROM'],
|
settings.MAIL_DATA['revente']['FROM'],
|
||||||
[participant.user.email],
|
[participant.user.email])
|
||||||
[], headers={
|
for participant in inscrits
|
||||||
'Reply-To': settings.MAIL_DATA['revente']['REPLYTO']})
|
]
|
||||||
mails_to_send.append(mail_tot)
|
send_mass_custom_mail(datatuple)
|
||||||
|
|
||||||
connection = mail.get_connection()
|
|
||||||
connection.send_messages(mails_to_send)
|
|
||||||
self.notif_sent = True
|
self.notif_sent = True
|
||||||
# Flag inutile, sauf si l'horloge interne merde
|
# Flag inutile, sauf si l'horloge interne merde
|
||||||
self.tirage_done = True
|
self.tirage_done = True
|
||||||
|
@ -303,56 +290,41 @@ class SpectacleRevente(models.Model):
|
||||||
seller = self.seller
|
seller = self.seller
|
||||||
|
|
||||||
if inscrits:
|
if inscrits:
|
||||||
mails = []
|
|
||||||
mail_subject = "BdA-Revente : {:s}".format(spectacle.title)
|
|
||||||
|
|
||||||
# Envoie un mail au gagnant et au vendeur
|
# Envoie un mail au gagnant et au vendeur
|
||||||
winner = random.choice(inscrits)
|
winner = random.choice(inscrits)
|
||||||
self.soldTo = winner
|
self.soldTo = winner
|
||||||
|
datatuple = []
|
||||||
context = {
|
context = {
|
||||||
'acheteur': winner.user,
|
'acheteur': winner.user,
|
||||||
'vendeur': seller.user,
|
'vendeur': seller.user,
|
||||||
'spectacle': spectacle,
|
'show': spectacle,
|
||||||
}
|
}
|
||||||
mails.append(mail.EmailMessage(
|
datatuple.append((
|
||||||
mail_subject,
|
'bda-revente-winner',
|
||||||
loader.render_to_string('bda/mails/revente-winner.txt',
|
context,
|
||||||
context),
|
settings.MAIL_DATA['revente']['FROM'],
|
||||||
from_email=settings.MAIL_DATA['revente']['FROM'],
|
[winner.user.email],
|
||||||
to=[winner.user.email],
|
|
||||||
reply_to=[seller.user.email],
|
|
||||||
))
|
))
|
||||||
mails.append(mail.EmailMessage(
|
datatuple.append((
|
||||||
mail_subject,
|
'bda-revente-seller',
|
||||||
loader.render_to_string('bda/mails/revente-seller.txt',
|
context,
|
||||||
context),
|
settings.MAIL_DATA['revente']['FROM'],
|
||||||
from_email=settings.MAIL_DATA['revente']['FROM'],
|
[seller.user.email]
|
||||||
to=[seller.user.email],
|
|
||||||
reply_to=[winner.user.email],
|
|
||||||
))
|
))
|
||||||
|
|
||||||
# Envoie un mail aux perdants
|
# Envoie un mail aux perdants
|
||||||
for inscrit in inscrits:
|
for inscrit in inscrits:
|
||||||
if inscrit == winner:
|
if inscrit != winner:
|
||||||
continue
|
context['acheteur'] = inscrit.user
|
||||||
|
datatuple.append((
|
||||||
mail_body = loader.render_to_string(
|
'bda-revente-loser',
|
||||||
'bda/mails/revente-loser.txt',
|
context,
|
||||||
{'acheteur': inscrit.user,
|
settings.MAIL_DATA['revente']['FROM'],
|
||||||
'vendeur': seller.user,
|
[inscrit.user.email]
|
||||||
'spectacle': spectacle}
|
|
||||||
)
|
|
||||||
mails.append(mail.EmailMessage(
|
|
||||||
mail_subject, mail_body,
|
|
||||||
from_email=settings.MAIL_DATA['revente']['FROM'],
|
|
||||||
to=[inscrit.user.email],
|
|
||||||
reply_to=[settings.MAIL_DATA['revente']['REPLYTO']],
|
|
||||||
))
|
))
|
||||||
mail.get_connection().send_messages(mails)
|
send_mass_custom_mail(datatuple)
|
||||||
|
|
||||||
# Si personne ne veut de la place, elle part au shotgun
|
# Si personne ne veut de la place, elle part au shotgun
|
||||||
else:
|
else:
|
||||||
self.shotgun = True
|
self.shotgun = True
|
||||||
|
|
||||||
self.tirage_done = True
|
self.tirage_done = True
|
||||||
self.save()
|
self.save()
|
||||||
|
|
18
bda/static/bda/js/jquery-1.6.2.min.js
vendored
18
bda/static/bda/js/jquery-1.6.2.min.js
vendored
File diff suppressed because one or more lines are too long
347
bda/static/bda/js/jquery-ui-1.8.15.custom.min.js
vendored
347
bda/static/bda/js/jquery-ui-1.8.15.custom.min.js
vendored
|
@ -1,347 +0,0 @@
|
||||||
/*!
|
|
||||||
* jQuery UI 1.8.15
|
|
||||||
*
|
|
||||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/UI
|
|
||||||
*/
|
|
||||||
(function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.15",
|
|
||||||
keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({propAttr:c.fn.prop||c.fn.attr,_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=
|
|
||||||
this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,
|
|
||||||
"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":
|
|
||||||
"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,
|
|
||||||
outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a,
|
|
||||||
"tabindex"),d=isNaN(b);return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&
|
|
||||||
a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&
|
|
||||||
c.ui.isOverAxis(b,e,i)}})}})(jQuery);
|
|
||||||
;/*!
|
|
||||||
* jQuery UI Widget 1.8.15
|
|
||||||
*
|
|
||||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/UI/Widget
|
|
||||||
*/
|
|
||||||
(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,
|
|
||||||
a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.charAt(0)==="_")return h;
|
|
||||||
e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,
|
|
||||||
this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},
|
|
||||||
widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},
|
|
||||||
enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
|
|
||||||
;/*!
|
|
||||||
* jQuery UI Mouse 1.8.15
|
|
||||||
*
|
|
||||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/UI/Mouse
|
|
||||||
*
|
|
||||||
* Depends:
|
|
||||||
* jquery.ui.widget.js
|
|
||||||
*/
|
|
||||||
(function(b){b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(c){return a._mouseDown(c)}).bind("click."+this.widgetName,function(c){if(true===b.data(c.target,a.widgetName+".preventClickEvent")){b.removeData(c.target,a.widgetName+".preventClickEvent");c.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=
|
|
||||||
a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var c=this,e=a.which==1,f=typeof this.options.cancel=="string"?b(a.target).closest(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){c.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=this._mouseStart(a)!==
|
|
||||||
false;if(!this._mouseStarted){a.preventDefault();return true}}true===b.data(a.target,this.widgetName+".preventClickEvent")&&b.removeData(a.target,this.widgetName+".preventClickEvent");this._mouseMoveDelegate=function(d){return c._mouseMove(d)};this._mouseUpDelegate=function(d){return c._mouseUp(d)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(b.browser.msie&&
|
|
||||||
!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=
|
|
||||||
false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
|
|
||||||
;/*
|
|
||||||
* jQuery UI Position 1.8.15
|
|
||||||
*
|
|
||||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/UI/Position
|
|
||||||
*/
|
|
||||||
(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY,
|
|
||||||
left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+=
|
|
||||||
k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-=
|
|
||||||
m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=
|
|
||||||
d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+=
|
|
||||||
a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b),
|
|
||||||
g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
|
|
||||||
;/*
|
|
||||||
* jQuery UI Sortable 1.8.15
|
|
||||||
*
|
|
||||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/UI/Sortables
|
|
||||||
*
|
|
||||||
* Depends:
|
|
||||||
* jquery.ui.core.js
|
|
||||||
* jquery.ui.mouse.js
|
|
||||||
* jquery.ui.widget.js
|
|
||||||
*/
|
|
||||||
(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var a=this.options;this.containerCache={};this.element.addClass("ui-sortable");
|
|
||||||
this.refresh();this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a===
|
|
||||||
"disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&
|
|
||||||
!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,
|
|
||||||
left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};
|
|
||||||
this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=
|
|
||||||
document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);
|
|
||||||
return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top<
|
|
||||||
b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()-
|
|
||||||
b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,
|
|
||||||
a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],
|
|
||||||
e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();
|
|
||||||
c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):
|
|
||||||
this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,
|
|
||||||
dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},
|
|
||||||
toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||
|
|
||||||
this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?j:g<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection();
|
|
||||||
var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c=="right"||a=="down"?2:1:a&&(a=="down"?2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)},
|
|
||||||
_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();
|
|
||||||
if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),
|
|
||||||
this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element),
|
|
||||||
this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&&
|
|
||||||
this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=0;b--){var c=this.items[b];if(!(c.instance!=this.currentContainer&&this.currentContainer&&c.item[0]!=this.currentItem[0])){var e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=
|
|
||||||
this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=
|
|
||||||
d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||
|
|
||||||
0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",
|
|
||||||
a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-
|
|
||||||
f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b=
|
|
||||||
this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width==
|
|
||||||
""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=
|
|
||||||
this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a=
|
|
||||||
{top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),
|
|
||||||
10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?
|
|
||||||
document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),
|
|
||||||
10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b=
|
|
||||||
this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&
|
|
||||||
this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();
|
|
||||||
var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-
|
|
||||||
this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g-
|
|
||||||
this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],
|
|
||||||
this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]=
|
|
||||||
"";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove",
|
|
||||||
f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,
|
|
||||||
this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",
|
|
||||||
a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()},
|
|
||||||
_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});d.extend(d.ui.sortable,{version:"1.8.15"})})(jQuery);
|
|
||||||
;/*
|
|
||||||
* jQuery UI Accordion 1.8.15
|
|
||||||
*
|
|
||||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/UI/Accordion
|
|
||||||
*
|
|
||||||
* Depends:
|
|
||||||
* jquery.ui.core.js
|
|
||||||
* jquery.ui.widget.js
|
|
||||||
*/
|
|
||||||
(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");
|
|
||||||
a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
|
|
||||||
if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion",
|
|
||||||
function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a=
|
|
||||||
this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex");
|
|
||||||
this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons();
|
|
||||||
b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target);
|
|
||||||
a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+
|
|
||||||
c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options;
|
|
||||||
if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);
|
|
||||||
if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(),
|
|
||||||
e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight||
|
|
||||||
e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false",
|
|
||||||
"aria-selected":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.15",
|
|
||||||
animations:{slide:function(a,b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);
|
|
||||||
f[i]={value:j[1],unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",
|
|
||||||
paddingTop:"hide",paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery);
|
|
||||||
;/*
|
|
||||||
* jQuery UI Autocomplete 1.8.15
|
|
||||||
*
|
|
||||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/UI/Autocomplete
|
|
||||||
*
|
|
||||||
* Depends:
|
|
||||||
* jquery.ui.core.js
|
|
||||||
* jquery.ui.widget.js
|
|
||||||
* jquery.ui.position.js
|
|
||||||
*/
|
|
||||||
(function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.propAttr("readOnly"))){g=
|
|
||||||
false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=
|
|
||||||
a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};
|
|
||||||
this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&&
|
|
||||||
a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");
|
|
||||||
d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&&
|
|
||||||
b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source=
|
|
||||||
this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.pending++;this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();
|
|
||||||
this.pending--;this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label||
|
|
||||||
b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position));this.options.autoFocus&&this.menu.next(new d.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var g=this;
|
|
||||||
d.each(b,function(c,f){g._renderItem(a,f)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,
|
|
||||||
"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery);
|
|
||||||
(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
|
|
||||||
-1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.scrollTop(),c=this.element.height();if(b<0)this.element.scrollTop(g+b);else b>=c&&this.element.scrollTop(g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");
|
|
||||||
this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b,
|
|
||||||
this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active||
|
|
||||||
this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active||
|
|
||||||
this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[d.fn.prop?"prop":"attr"]("scrollHeight")},select:function(e){this._trigger("selected",e,{item:this.active})}})})(jQuery);
|
|
||||||
;/*
|
|
||||||
* jQuery UI Dialog 1.8.15
|
|
||||||
*
|
|
||||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/UI/Dialog
|
|
||||||
*
|
|
||||||
* Depends:
|
|
||||||
* jquery.ui.core.js
|
|
||||||
* jquery.ui.widget.js
|
|
||||||
* jquery.ui.button.js
|
|
||||||
* jquery.ui.draggable.js
|
|
||||||
* jquery.ui.mouse.js
|
|
||||||
* jquery.ui.position.js
|
|
||||||
* jquery.ui.resizable.js
|
|
||||||
*/
|
|
||||||
(function(c,l){var m={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},n={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},o=c.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,
|
|
||||||
position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+
|
|
||||||
b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),
|
|
||||||
h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id",
|
|
||||||
e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");
|
|
||||||
a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==
|
|
||||||
b.uiDialog[0]){e=c(this).css("z-index");isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()};c.ui.dialog.maxZ+=1;
|
|
||||||
d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===
|
|
||||||
f[0]&&e.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,
|
|
||||||
function(){return!(d=true)});if(d){c.each(a,function(f,h){h=c.isFunction(h)?{click:h,text:f}:h;var i=c('<button type="button"></button>').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",
|
|
||||||
handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,
|
|
||||||
originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize",
|
|
||||||
f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):
|
|
||||||
[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f);
|
|
||||||
if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"):
|
|
||||||
e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a=
|
|
||||||
this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height-
|
|
||||||
b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.15",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),
|
|
||||||
create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),
|
|
||||||
height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);
|
|
||||||
b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,function(){a=
|
|
||||||
a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);
|
|
||||||
;/*
|
|
||||||
* jQuery UI Tabs 1.8.15
|
|
||||||
*
|
|
||||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/UI/Tabs
|
|
||||||
*
|
|
||||||
* Depends:
|
|
||||||
* jquery.ui.core.js
|
|
||||||
* jquery.ui.widget.js
|
|
||||||
*/
|
|
||||||
(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&&
|
|
||||||
e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=
|
|
||||||
d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]||
|
|
||||||
(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");
|
|
||||||
this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected=
|
|
||||||
this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");
|
|
||||||
if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));
|
|
||||||
this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+
|
|
||||||
g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal",
|
|
||||||
function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")};
|
|
||||||
this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected=
|
|
||||||
-1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier.";
|
|
||||||
d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=
|
|
||||||
d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b,
|
|
||||||
e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]);
|
|
||||||
j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();
|
|
||||||
if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=b}),function(h){return h>=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null,
|
|
||||||
this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this},
|
|
||||||
load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c,
|
|
||||||
"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},
|
|
||||||
url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.15"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k<a.anchors.length?k:0)},b);j&&j.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(j){j.clientX&&
|
|
||||||
a.rotate(null)}:function(){t=c.selected;h()});if(b){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(a.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery);
|
|
||||||
;/*
|
|
||||||
* jQuery UI Datepicker 1.8.15
|
|
||||||
*
|
|
||||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/UI/Datepicker
|
|
||||||
*
|
|
||||||
* Depends:
|
|
||||||
* jquery.ui.core.js
|
|
||||||
*/
|
|
||||||
(function(d,C){function M(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass=
|
|
||||||
"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su",
|
|
||||||
"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",
|
|
||||||
minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false,disabled:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=N(d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}function N(a){return a.bind("mouseout",
|
|
||||||
function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");b.length&&b.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(d.datepicker._isDisabledDatepicker(J.inline?a.parent()[0]:J.input[0])||!b.length)){b.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
|
|
||||||
b.addClass("ui-state-hover");b.hasClass("ui-datepicker-prev")&&b.addClass("ui-datepicker-prev-hover");b.hasClass("ui-datepicker-next")&&b.addClass("ui-datepicker-next-hover")}})}function H(a,b){d.extend(a,b);for(var c in b)if(b[c]==null||b[c]==C)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.15"}});var B=(new Date).getTime(),J;d.extend(M.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},
|
|
||||||
setDefaults:function(a){H(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g,
|
|
||||||
"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:N(d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}},_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",
|
|
||||||
function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b);b.settings.disabled&&this._disableDatepicker(a)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c==
|
|
||||||
"focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():
|
|
||||||
d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,
|
|
||||||
b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),true);this._updateDatepicker(b);this._updateAlternate(b);b.settings.disabled&&this._disableDatepicker(a);b.dpDiv.css("display","block")}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=
|
|
||||||
1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}H(a.settings,e||{});b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/
|
|
||||||
2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=
|
|
||||||
d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=
|
|
||||||
a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().removeClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a,
|
|
||||||
"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().addClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==
|
|
||||||
a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?
|
|
||||||
d.extend({},e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&this._hideDatepicker();var h=this._getDateDatepicker(a,true),i=this._getMinMaxDate(e,"min"),g=this._getMinMaxDate(e,"max");H(e.settings,f);if(i!==null&&f.dateFormat!==C&&f.minDate===C)e.settings.minDate=this._formatDate(e,i);if(g!==null&&f.dateFormat!==C&&f.maxDate===C)e.settings.maxDate=this._formatDate(e,g);this._attachments(d(a),e);this._autoSize(e);this._setDate(e,h);this._updateAlternate(e);
|
|
||||||
this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");
|
|
||||||
b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass+":not(."+d.datepicker._currentClass+")",b.dpDiv);c[0]&&d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]);if(a=d.datepicker._get(b,"onSelect")){c=d.datepicker._formatDate(b);a.apply(b.input?b.input[0]:null,[c,b])}else d.datepicker._hideDatepicker();return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,
|
|
||||||
a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=
|
|
||||||
a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,
|
|
||||||
"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));var c=String.fromCharCode(a.charCode==C?a.keyCode:a.charCode);
|
|
||||||
return a.ctrlKey||a.metaKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input",
|
|
||||||
a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);if(d.datepicker._curInst&&d.datepicker._curInst!=b){d.datepicker._datepickerShowing&&d.datepicker._triggerOnClose(d.datepicker._curInst);d.datepicker._curInst.dpDiv.stop(true,true)}var c=d.datepicker._get(b,"beforeShow");H(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos=
|
|
||||||
d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,
|
|
||||||
c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.datepicker._datepickerShowing=true;d.effects&&
|
|
||||||
d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){this.maxRows=4;var b=d.datepicker._getBorders(a.dpDiv);J=a;a.dpDiv.empty().append(this._generateHTML(a));var c=a.dpDiv.find("iframe.ui-datepicker-cover");c.length&&c.css({left:-b[0],top:-b[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()});a.dpDiv.find("."+
|
|
||||||
this._dayOverClass+" a").mouseover();b=this._getNumberOfMonths(a);c=b[1];a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");c>1&&a.dpDiv.addClass("ui-datepicker-multi-"+c).css("width",17*c+"em");a.dpDiv[(b[0]!=1||b[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&
|
|
||||||
a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var e=a.yearshtml;setTimeout(function(){e===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);e=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():
|
|
||||||
0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),
|
|
||||||
"isRTL");a&&(a.type=="hidden"||a.nodeType!=1||d.expr.filters.hidden(a));)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_triggerOnClose:function(a){var b=this._get(a,"onClose");if(b)b.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a])},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=
|
|
||||||
null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();d.datepicker._triggerOnClose(b);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},
|
|
||||||
_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):
|
|
||||||
0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e["selected"+(c=="M"?
|
|
||||||
"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a);
|
|
||||||
this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,
|
|
||||||
"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b==
|
|
||||||
"")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=A+1<a.length&&a.charAt(A+1)==p)&&A++;return p},m=function(p){var D=o(p);p=new RegExp("^\\d{1,"+
|
|
||||||
(p=="@"?14:p=="!"?20:p=="y"&&D?4:p=="o"?3:2)+"}");p=b.substring(q).match(p);if(!p)throw"Missing number at position "+q;q+=p[0].length;return parseInt(p[0],10)},n=function(p,D,K){p=d.map(o(p)?K:D,function(w,x){return[[x,w]]}).sort(function(w,x){return-(w[1].length-x[1].length)});var E=-1;d.each(p,function(w,x){w=x[1];if(b.substr(q,w.length).toLowerCase()==w.toLowerCase()){E=x[0];q+=w.length;return false}});if(E!=-1)return E+1;else throw"Unknown name at position "+q;},s=function(){if(b.charAt(q)!=a.charAt(A))throw"Unexpected literal at position "+
|
|
||||||
q;q++},q=0,A=0;A<a.length;A++)if(k)if(a.charAt(A)=="'"&&!o("'"))k=false;else s();else switch(a.charAt(A)){case "d":l=m("d");break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":j=m("m");break;case "M":j=n("M",i,g);break;case "y":c=m("y");break;case "@":var v=new Date(m("@"));c=v.getFullYear();j=v.getMonth()+1;l=v.getDate();break;case "!":v=new Date((m("!")-this._ticksTo1970)/1E4);c=v.getFullYear();j=v.getMonth()+1;l=v.getDate();break;case "'":if(o("'"))s();else k=true;break;default:s()}if(q<
|
|
||||||
b.length)throw"Extra/unparsed characters found in date: "+b.substring(q);if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,j-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=j||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",
|
|
||||||
RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=k+1<a.length&&
|
|
||||||
a.charAt(k+1)==o)&&k++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},j=function(o,m,n,s){return i(o)?s[m]:n[m]},l="",u=false;if(b)for(var k=0;k<a.length;k++)if(u)if(a.charAt(k)=="'"&&!i("'"))u=false;else l+=a.charAt(k);else switch(a.charAt(k)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=j("D",b.getDay(),e,f);break;case "o":l+=g("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5),3);
|
|
||||||
break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=j("M",b.getMonth(),h,c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+="'";else u=true;break;default:l+=a.charAt(k)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=
|
|
||||||
false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+="0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==C?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,
|
|
||||||
e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,
|
|
||||||
"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,j=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,k=u.exec(h);k;){switch(k[2]||"d"){case "d":case "D":g+=parseInt(k[1],10);break;case "w":case "W":g+=parseInt(k[1],10)*7;break;case "m":case "M":l+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break;case "y":case "Y":j+=parseInt(k[1],10);g=Math.min(g,
|
|
||||||
d.datepicker._getDaysInMonth(j,l));break}k=u.exec(h)}return new Date(j,l,g)};if(b=(b=b==null||b===""?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):new Date(b.getTime()))&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;
|
|
||||||
b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a));if(c=this._get(a,"onSelect")){e=this._formatDate(a);c.apply(a.input?a.input[0]:null,[e,a])}},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==
|
|
||||||
""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,
|
|
||||||
9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&n<k?k:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a));
|
|
||||||
n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+B+".datepicker._adjustDate('#"+a.id+"', -"+j+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>";var s=this._get(a,"nextText");s=!h?s:this.formatDate(s,this._daylightSavingAdjust(new Date(m,
|
|
||||||
g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+B+".datepicker._adjustDate('#"+a.id+"', +"+j+", 'M');\" title=\""+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>";j=this._get(a,"currentText");s=this._get(a,"gotoCurrent")&&
|
|
||||||
a.currentDay?u:b;j=!h?j:this.formatDate(j,s,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+B+'.datepicker._hideDatepicker();">'+this._get(a,"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,s)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+
|
|
||||||
B+".datepicker._gotoToday('#"+a.id+"');\">"+j+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");s=this._get(a,"dayNames");this._get(a,"dayNamesShort");var q=this._get(a,"dayNamesMin"),A=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),D=this._get(a,"showOtherMonths"),K=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var E=this._getDefaultDate(a),w="",x=0;x<i[0];x++){var O=
|
|
||||||
"";this.maxRows=4;for(var G=0;G<i[1];G++){var P=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",y="";if(l){y+='<div class="ui-datepicker-group';if(i[1]>1)switch(G){case 0:y+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:y+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:y+=" ui-datepicker-group-middle";t="";break}y+='">'}y+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&
|
|
||||||
x==0?c?f:n:"")+(/all|right/.test(t)&&x==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,x>0||G>0,A,v)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var z=j?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var r=(t+h)%7;z+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+s[r]+'">'+q[r]+"</span></th>"}y+=z+"</tr></thead><tbody>";z=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,
|
|
||||||
z);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;z=Math.ceil((t+z)/7);this.maxRows=z=l?this.maxRows>z?this.maxRows:z:z;r=this._daylightSavingAdjust(new Date(m,g,1-t));for(var Q=0;Q<z;Q++){y+="<tr>";var R=!j?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(r)+"</td>";for(t=0;t<7;t++){var I=p?p.apply(a.input?a.input[0]:null,[r]):[true,""],F=r.getMonth()!=g,L=F&&!K||!I[0]||k&&r<k||o&&r>o;R+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(F?" ui-datepicker-other-month":"")+(r.getTime()==
|
|
||||||
P.getTime()&&g==a.selectedMonth&&a._keyEvent||E.getTime()==r.getTime()&&E.getTime()==P.getTime()?" "+this._dayOverClass:"")+(L?" "+this._unselectableClass+" ui-state-disabled":"")+(F&&!D?"":" "+I[1]+(r.getTime()==u.getTime()?" "+this._currentClass:"")+(r.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!F||D)&&I[2]?' title="'+I[2]+'"':"")+(L?"":' onclick="DP_jQuery_'+B+".datepicker._selectDay('#"+a.id+"',"+r.getMonth()+","+r.getFullYear()+', this);return false;"')+">"+(F&&!D?" ":L?'<span class="ui-state-default">'+
|
|
||||||
r.getDate()+"</span>":'<a class="ui-state-default'+(r.getTime()==b.getTime()?" ui-state-highlight":"")+(r.getTime()==u.getTime()?" ui-state-active":"")+(F?" ui-priority-secondary":"")+'" href="#">'+r.getDate()+"</a>")+"</td>";r.setDate(r.getDate()+1);r=this._daylightSavingAdjust(r)}y+=R+"</tr>"}g++;if(g>11){g=0;m++}y+="</tbody></table>"+(l?"</div>"+(i[0]>0&&G==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");O+=y}w+=O}w+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':
|
|
||||||
"");a._keyEvent=false;return w},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='<div class="ui-datepicker-title">',o="";if(h||!j)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+B+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" >";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&
|
|
||||||
(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(k+=o+(h||!(j&&l)?" ":""));if(!a.yearshtml){a.yearshtml="";if(h||!l)k+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var s=(new Date).getFullYear();i=function(q){q=q.match(/c[+-].*/)?c+parseInt(q.substring(1),10):q.match(/[+-].*/)?s+parseInt(q,10):parseInt(q,10);return isNaN(q)?s:q};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b,
|
|
||||||
e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+B+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" >";b<=g;b++)a.yearshtml+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";a.yearshtml+="</select>";k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="</div>";return k},_adjustInstDate:function(a,b,c){var e=a.drawYear+(c=="Y"?b:0),f=a.drawMonth+
|
|
||||||
(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");if(b)b.apply(a.input?
|
|
||||||
a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);c=this._daylightSavingAdjust(new Date(c,
|
|
||||||
e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,
|
|
||||||
"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=function(a){if(!this.length)return this;
|
|
||||||
if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));return this.each(function(){typeof a==
|
|
||||||
"string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new M;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.15";window["DP_jQuery_"+B]=d})(jQuery);
|
|
||||||
;
|
|
|
@ -43,3 +43,6 @@ td {
|
||||||
margin: 10px 0px;
|
margin: 10px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spectacle-passe {
|
||||||
|
opacity:0.5;
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
{% block extra_head %}
|
{% block extra_head %}
|
||||||
<script src="{% static 'bda/js/jquery-1.6.2.min.js'%}" type="text/javascript"></script>
|
<script src="{% static 'js/jquery.min.js'%}" type="text/javascript"></script>
|
||||||
<script src="{% static 'bda/js/jquery-ui-1.8.15.custom.min.js' %}" type="text/javascript"></script>
|
<script src="{% static 'js/jquery-ui.min.js' %}" type="text/javascript"></script>
|
||||||
|
<script src="{% static "js/jquery.ui.touch-punch.min.js" %}" type="text/javascript"></script>
|
||||||
|
<link type="text/css" rel="stylesheet" href="{% static "css/jquery-ui.min.css" %}" />
|
||||||
<link type="text/css" rel="stylesheet" href="{% static "css/bda.css" %}" />
|
<link type="text/css" rel="stylesheet" href="{% static "css/bda.css" %}" />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
43
bda/templates/bda/mails-rappel.html
Normal file
43
bda/templates/bda/mails-rappel.html
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{% extends "base_title.html" %}
|
||||||
|
|
||||||
|
{% block realcontent %}
|
||||||
|
<h2>Mails de rappels</h2>
|
||||||
|
{% if sent %}
|
||||||
|
<h3>Les mails de rappel pour le spectacle {{ show.title }} ont bien été envoyés aux personnes suivantes</h3>
|
||||||
|
<ul>
|
||||||
|
{% for member in members %}
|
||||||
|
<li>{{ member.get_full_name }} ({{ member.email }})</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<h3>Voulez vous envoyer les mails de rappel pour le spectacle
|
||||||
|
{{ show.title }} ?</h3>
|
||||||
|
{% if show.rappel_sent %}
|
||||||
|
<p class="error">Attention, les mails ont déjà été envoyés le
|
||||||
|
{{ show.rappel_sent }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if not sent %}
|
||||||
|
<form action="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="pull-right">
|
||||||
|
<input class="btn btn-primary" type="submit" value="Envoyer" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<hr/>
|
||||||
|
<h3>Forme des mails</h3>
|
||||||
|
|
||||||
|
<h4>Une seule place</h4>
|
||||||
|
{% for part in exemple_mail_1place %}
|
||||||
|
<pre>{{ part }}</pre>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<h4>Deux places</h4>
|
||||||
|
{% for part in exemple_mail_2places %}
|
||||||
|
<pre>{{ part }}</pre>
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
|
@ -1,6 +0,0 @@
|
||||||
Bonjour {{ vendeur.first_name }} !
|
|
||||||
|
|
||||||
Je souhaiterais racheter ta place pour {{ spectacle.title }} le {{ spectacle.date }} ({{ spectacle.location }}) à {{ spectacle.price|floatformat:2 }}€.
|
|
||||||
Contacte-moi si tu es toujours intéressé·e !
|
|
||||||
|
|
||||||
{{ acheteur.get_full_name }} ({{ acheteur.email }})
|
|
|
@ -1,23 +0,0 @@
|
||||||
Bonjour {{ name }},
|
|
||||||
|
|
||||||
Nous te rappellons que tu as eu la chance d'obtenir {{ nb_attr|pluralize:"une place,deux places" }}
|
|
||||||
pour {{ show.title }}, le {{ show.date }} au {{ show.location }}. N'oublie pas de t'y rendre !
|
|
||||||
{% if nb_attr == 2 %}
|
|
||||||
Tu as obtenu deux places pour ce spectacle. Nous te rappelons que
|
|
||||||
ces places sont strictement réservées aux personnes de moins de 28 ans.
|
|
||||||
{% endif %}
|
|
||||||
{% if show.listing %}Pour ce spectacle, tu as reçu des places sur
|
|
||||||
listing. Il te faudra donc te rendre 15 minutes en avance sur les lieux de la représentation
|
|
||||||
pour retirer {{ nb_attr|pluralize:"ta place,tes places" }}.
|
|
||||||
{% else %}Pour assister à ce spectacle, tu dois présenter les billets qui ont
|
|
||||||
été distribués au burô.
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
Si tu ne peux plus assister à cette représentation, tu peux
|
|
||||||
revendre ta place via BdA-revente, accessible directement sur
|
|
||||||
GestioCOF (lien "revendre une place du premier tirage" sur la page
|
|
||||||
d'accueil https://www.cof.ens.fr/gestion/).
|
|
||||||
|
|
||||||
En te souhaitant un excellent spectacle,
|
|
||||||
|
|
||||||
Le Bureau des Arts
|
|
|
@ -1,9 +0,0 @@
|
||||||
Bonjour {{ acheteur.first_name }},
|
|
||||||
|
|
||||||
Tu t'étais inscrit-e pour la revente de la place de {{ vendeur.get_full_name }}
|
|
||||||
pour {{ spectacle.title }}.
|
|
||||||
Malheureusement, une autre personne a été tirée au sort pour racheter la place.
|
|
||||||
Tu pourras certainement retenter ta chance pour une autre revente !
|
|
||||||
|
|
||||||
À très bientôt,
|
|
||||||
Le Bureau des Arts
|
|
|
@ -1,13 +0,0 @@
|
||||||
Bonjour {{ vendeur.first_name }},
|
|
||||||
|
|
||||||
Tu t’es bien inscrit-e pour la revente de {{ spectacle.title }}.
|
|
||||||
|
|
||||||
{% with revente.date_tirage as time %}
|
|
||||||
Le tirage au sort entre tout-e-s les racheteuse-eur-s potentiel-le-s aura lieu
|
|
||||||
le {{ time|date:"DATE_FORMAT" }} à {{ time|time:"TIME_FORMAT" }} (dans {{time|timeuntil }}).
|
|
||||||
Si personne ne s’est inscrit pour racheter la place, celle-ci apparaitra parmi
|
|
||||||
les « Places disponibles immédiatement à la revente » sur GestioCOF.
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
Bonne revente !
|
|
||||||
Le Bureau des Arts
|
|
|
@ -1,7 +0,0 @@
|
||||||
Bonjour {{ vendeur.first_name }},
|
|
||||||
|
|
||||||
La personne tirée au sort pour racheter ta place pour {{ spectacle.title }} est {{ acheteur.get_full_name }}.
|
|
||||||
Tu peux le/la contacter à l'adresse {{ acheteur.email }}, ou en répondant à ce mail.
|
|
||||||
|
|
||||||
Chaleureusement,
|
|
||||||
Le BdA
|
|
|
@ -1,7 +0,0 @@
|
||||||
Bonjour {{ acheteur.first_name }},
|
|
||||||
|
|
||||||
Tu as été tiré-e au sort pour racheter une place pour {{ spectacle.title }} le {{ spectacle.date }} ({{ spectacle.location }}) à {{ spectacle.price|floatformat:2 }}€.
|
|
||||||
Tu peux contacter le/la vendeur-se à l'adresse {{ vendeur.email }}, ou en répondant à ce mail.
|
|
||||||
|
|
||||||
Chaleureusement,
|
|
||||||
Le BdA
|
|
|
@ -1,14 +0,0 @@
|
||||||
Bonjour {{ user.first_name }}
|
|
||||||
|
|
||||||
Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date }})
|
|
||||||
a été postée sur BdA-Revente.
|
|
||||||
|
|
||||||
{% with revente.date_tirage as time %}
|
|
||||||
Si ce spectacle t'intéresse toujours, merci de nous le signaler en cliquant
|
|
||||||
sur ce lien : http://{{ domain }}/gestion{% url "bda-revente-interested" revente.id %}.
|
|
||||||
Dans le cas où plusieurs personnes seraient intéressées, nous procèderons à
|
|
||||||
un tirage au sort le {{ time|date:"DATE_FORMAT" }} à {{ time|time:"TIME_FORMAT" }} (dans {{time|timeuntil}}).
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
Chaleureusement,
|
|
||||||
Le BdA
|
|
|
@ -1,11 +0,0 @@
|
||||||
Bonjour {{ user.first_name }}
|
|
||||||
|
|
||||||
Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date }})
|
|
||||||
a été postée sur BdA-Revente.
|
|
||||||
|
|
||||||
Puisque ce spectacle a lieu dans moins de 24h, il n'y a pas de tirage au sort pour
|
|
||||||
cette place : elle est disponible immédiatement à l'adresse
|
|
||||||
http://{{ domain }}/gestion{% url "bda-buy-revente" spectacle.id %}, à la disposition de tous.
|
|
||||||
|
|
||||||
Chaleureusement,
|
|
||||||
Le BdA
|
|
|
@ -1,35 +0,0 @@
|
||||||
{% extends "base_title.html" %}
|
|
||||||
|
|
||||||
{% block realcontent %}
|
|
||||||
{% if sent %}
|
|
||||||
<h3>Les mails de rappel pour le spectacle {{ show.title }} ont bien été envoyés aux personnes suivantes</h3>
|
|
||||||
<ul>
|
|
||||||
{% for member in members %}
|
|
||||||
<li>{{ member.get_full_name }} ({{ member.email }})</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
|
||||||
<h3>Voulez vous envoyer les mails de rappel pour le spectacle
|
|
||||||
{{ show.title }} ?</h3>
|
|
||||||
{% if show.rappel_sent %}
|
|
||||||
<p class="error">Attention, les mails ont déjà été envoyés le
|
|
||||||
{{ show.rappel_sent }}</p>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if not sent %}
|
|
||||||
<form action="" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<br />
|
|
||||||
<input type="submit" value="Envoyer" />
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<h3>Forme des mails</h3>
|
|
||||||
|
|
||||||
<br />Une seule place<br /><br />
|
|
||||||
<pre>{{ exemple_mail_1place }}</pre>
|
|
||||||
|
|
||||||
<br />Deux places<br /><br />
|
|
||||||
<pre>{{ exemple_mail_2places }}</pre>
|
|
||||||
{% endblock %}
|
|
|
@ -1,6 +1,10 @@
|
||||||
{% extends "base_title.html" %}
|
{% extends "base_title.html" %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
|
{% block extra_head %}
|
||||||
|
<link type="text/css" rel="stylesheet" href="{% static "css/bda.css" %}" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block realcontent %}
|
{% block realcontent %}
|
||||||
<h2><strong>{{tirage_name}}</strong></h2>
|
<h2><strong>{{tirage_name}}</strong></h2>
|
||||||
<h3>Liste des spectacles</h3>
|
<h3>Liste des spectacles</h3>
|
||||||
|
@ -17,9 +21,9 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for spectacle in object_list %}
|
{% for spectacle in object_list %}
|
||||||
<tr class="clickable-row" data-href="{% url 'bda-spectacle' tirage_id spectacle.id %}">
|
<tr class="clickable-row {% if spectacle.is_past %}spectacle-passe{% endif %}" data-href="{% url 'bda-spectacle' tirage_id spectacle.id %}">
|
||||||
<td><a href="{% url 'bda-spectacle' tirage_id spectacle.id %}">{{ spectacle.title }} <span style="font-size:small;" class="glyphicon glyphicon-link" aria-hidden="true"></span></a></td>
|
<td><a href="{% url 'bda-spectacle' tirage_id spectacle.id %}">{{ spectacle.title }} <span style="font-size:small;" class="glyphicon glyphicon-link" aria-hidden="true"></span></a></td>
|
||||||
<td data-sort-value="{{ spectacle.timestamp }}">{{ spectacle.date }}</td>
|
<td data-sort-value="{{ spectacle.timestamp }}"">{{ spectacle.date }}</td>
|
||||||
<td data-sort-value="{{ spectacle.location }}">{{ spectacle.location }}</td>
|
<td data-sort-value="{{ spectacle.location }}">{{ spectacle.location }}</td>
|
||||||
<td data-sort-value="{{ spectacle.price |stringformat:".3f" }}">
|
<td data-sort-value="{{ spectacle.price |stringformat:".3f" }}">
|
||||||
{{ spectacle.price |floatformat }}€
|
{{ spectacle.price |floatformat }}€
|
||||||
|
|
79
bda/views.py
79
bda/views.py
|
@ -3,20 +3,20 @@
|
||||||
import random
|
import random
|
||||||
import hashlib
|
import hashlib
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from custommail.shortcuts import (
|
||||||
|
send_mass_custom_mail, send_custom_mail, render_custom_mail
|
||||||
|
)
|
||||||
|
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
|
from django.core import serializers
|
||||||
from django.db.models import Count, Q, Sum
|
from django.db.models import Count, Q, Sum
|
||||||
from django.core import serializers, mail
|
|
||||||
from django.forms.models import inlineformset_factory
|
from django.forms.models import inlineformset_factory
|
||||||
from django.http import HttpResponseBadRequest, HttpResponseRedirect
|
from django.http import HttpResponseBadRequest, HttpResponseRedirect
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.mail import send_mail
|
|
||||||
from django.template import loader
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.views.generic.list import ListView
|
from django.views.generic.list import ListView
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ def revente(request, tirage_id):
|
||||||
resellform = ResellForm(participant, request.POST, prefix='resell')
|
resellform = ResellForm(participant, request.POST, prefix='resell')
|
||||||
annulform = AnnulForm(participant, prefix='annul')
|
annulform = AnnulForm(participant, prefix='annul')
|
||||||
if resellform.is_valid():
|
if resellform.is_valid():
|
||||||
mails = []
|
datatuple = []
|
||||||
attributions = resellform.cleaned_data["attributions"]
|
attributions = resellform.cleaned_data["attributions"]
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
for attribution in attributions:
|
for attribution in attributions:
|
||||||
|
@ -315,24 +315,18 @@ def revente(request, tirage_id):
|
||||||
revente.notif_sent = False
|
revente.notif_sent = False
|
||||||
revente.tirage_done = False
|
revente.tirage_done = False
|
||||||
revente.shotgun = False
|
revente.shotgun = False
|
||||||
mail_subject = "BdA-Revente : {:s}".format(
|
context = {
|
||||||
attribution.spectacle.title)
|
'vendeur': participant.user,
|
||||||
mail_body = loader.render_to_string(
|
'show': attribution.spectacle,
|
||||||
'bda/mails/revente-new.txt',
|
'revente': revente
|
||||||
{'vendeur': participant.user,
|
}
|
||||||
'spectacle': attribution.spectacle,
|
datatuple.append((
|
||||||
'revente': revente}
|
'bda-revente-new', context,
|
||||||
)
|
settings.MAIL_DATA['revente']['FROM'],
|
||||||
mails.append(mail.EmailMessage(
|
[participant.user.email]
|
||||||
mail_subject, mail_body,
|
|
||||||
from_email=settings.MAIL_DATA['revente']['FROM'],
|
|
||||||
to=[participant.user.email],
|
|
||||||
reply_to=[
|
|
||||||
settings.MAIL_DATA['revente']['REPLYTO']
|
|
||||||
],
|
|
||||||
))
|
))
|
||||||
revente.save()
|
revente.save()
|
||||||
mail.get_connection().send_messages(mails)
|
send_mass_custom_mail(datatuple)
|
||||||
# On annule une revente
|
# On annule une revente
|
||||||
elif 'annul' in request.POST:
|
elif 'annul' in request.POST:
|
||||||
annulform = AnnulForm(participant, request.POST, prefix='annul')
|
annulform = AnnulForm(participant, request.POST, prefix='annul')
|
||||||
|
@ -402,7 +396,7 @@ def revente(request, tirage_id):
|
||||||
@login_required
|
@login_required
|
||||||
def revente_interested(request, revente_id):
|
def revente_interested(request, revente_id):
|
||||||
revente = get_object_or_404(SpectacleRevente, id=revente_id)
|
revente = get_object_or_404(SpectacleRevente, id=revente_id)
|
||||||
participant, created = Participant.objects.get_or_create(
|
participant, _ = Participant.objects.get_or_create(
|
||||||
user=request.user, tirage=revente.attribution.spectacle.tirage)
|
user=request.user, tirage=revente.attribution.spectacle.tirage)
|
||||||
if (timezone.now() < revente.date + timedelta(hours=1)) or revente.shotgun:
|
if (timezone.now() < revente.date + timedelta(hours=1)) or revente.shotgun:
|
||||||
return render(request, "bda-wrongtime.html",
|
return render(request, "bda-wrongtime.html",
|
||||||
|
@ -417,7 +411,7 @@ def revente_interested(request, revente_id):
|
||||||
@login_required
|
@login_required
|
||||||
def list_revente(request, tirage_id):
|
def list_revente(request, tirage_id):
|
||||||
tirage = get_object_or_404(Tirage, id=tirage_id)
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
||||||
participant, created = Participant.objects.get_or_create(
|
participant, _ = Participant.objects.get_or_create(
|
||||||
user=request.user, tirage=tirage)
|
user=request.user, tirage=tirage)
|
||||||
deja_revente = False
|
deja_revente = False
|
||||||
success = False
|
success = False
|
||||||
|
@ -465,7 +459,7 @@ def list_revente(request, tirage_id):
|
||||||
def buy_revente(request, spectacle_id):
|
def buy_revente(request, spectacle_id):
|
||||||
spectacle = get_object_or_404(Spectacle, id=spectacle_id)
|
spectacle = get_object_or_404(Spectacle, id=spectacle_id)
|
||||||
tirage = spectacle.tirage
|
tirage = spectacle.tirage
|
||||||
participant, created = Participant.objects.get_or_create(
|
participant, _ = Participant.objects.get_or_create(
|
||||||
user=request.user, tirage=tirage)
|
user=request.user, tirage=tirage)
|
||||||
reventes = SpectacleRevente.objects.filter(
|
reventes = SpectacleRevente.objects.filter(
|
||||||
attribution__spectacle=spectacle,
|
attribution__spectacle=spectacle,
|
||||||
|
@ -488,15 +482,17 @@ def buy_revente(request, spectacle_id):
|
||||||
revente = random.choice(reventes_shotgun)
|
revente = random.choice(reventes_shotgun)
|
||||||
revente.soldTo = participant
|
revente.soldTo = participant
|
||||||
revente.save()
|
revente.save()
|
||||||
mail = loader.render_to_string('bda/mails/buy-shotgun.txt', {
|
context = {
|
||||||
'spectacle': spectacle,
|
'show': spectacle,
|
||||||
'acheteur': request.user,
|
'acheteur': request.user,
|
||||||
'vendeur': revente.seller.user,
|
'vendeur': revente.seller.user
|
||||||
})
|
}
|
||||||
send_mail("BdA-Revente : %s" % spectacle.title, mail,
|
send_custom_mail(
|
||||||
request.user.email,
|
'bda-buy-shotgun',
|
||||||
|
'bda@ens.fr',
|
||||||
[revente.seller.user.email],
|
[revente.seller.user.email],
|
||||||
fail_silently=False)
|
context=context,
|
||||||
|
)
|
||||||
return render(request, "bda-success.html",
|
return render(request, "bda-success.html",
|
||||||
{"seller": revente.attribution.participant.user,
|
{"seller": revente.attribution.participant.user,
|
||||||
"spectacle": spectacle})
|
"spectacle": spectacle})
|
||||||
|
@ -580,15 +576,16 @@ def unpaid(request, tirage_id):
|
||||||
def send_rappel(request, spectacle_id):
|
def send_rappel(request, spectacle_id):
|
||||||
show = get_object_or_404(Spectacle, id=spectacle_id)
|
show = get_object_or_404(Spectacle, id=spectacle_id)
|
||||||
# Mails d'exemples
|
# Mails d'exemples
|
||||||
fake_member = request.user
|
exemple_mail_1place = render_custom_mail('bda-rappel', {
|
||||||
fake_member.nb_attr = 1
|
'member': request.user,
|
||||||
exemple_mail_1place = loader.render_to_string('bda/mails/rappel.txt', {
|
'show': show,
|
||||||
'member': fake_member,
|
'nb_attr': 1
|
||||||
'show': show})
|
})
|
||||||
fake_member.nb_attr = 2
|
exemple_mail_2places = render_custom_mail('bda-rappel', {
|
||||||
exemple_mail_2places = loader.render_to_string('bda/mails/rappel.txt', {
|
'member': request.user,
|
||||||
'member': fake_member,
|
'show': show,
|
||||||
'show': show})
|
'nb_attr': 2
|
||||||
|
})
|
||||||
# Contexte
|
# Contexte
|
||||||
ctxt = {'show': show,
|
ctxt = {'show': show,
|
||||||
'exemple_mail_1place': exemple_mail_1place,
|
'exemple_mail_1place': exemple_mail_1place,
|
||||||
|
@ -601,7 +598,7 @@ def send_rappel(request, spectacle_id):
|
||||||
# Demande de confirmation
|
# Demande de confirmation
|
||||||
else:
|
else:
|
||||||
ctxt['sent'] = False
|
ctxt['sent'] = False
|
||||||
return render(request, "mails-rappel.html", ctxt)
|
return render(request, "bda/mails-rappel.html", ctxt)
|
||||||
|
|
||||||
|
|
||||||
def descriptions_spectacles(request, tirage_id):
|
def descriptions_spectacles(request, tirage_id):
|
||||||
|
|
22
cof/admin.py
22
cof/admin.py
|
@ -7,12 +7,6 @@ from __future__ import unicode_literals
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from .models import SurveyQuestionAnswer, SurveyQuestion, \
|
|
||||||
CofProfile, EventOption, EventOptionChoice, Event, Club, CustomMail, \
|
|
||||||
Survey, EventCommentField, EventRegistration
|
|
||||||
from .petits_cours_models import PetitCoursDemande, \
|
|
||||||
PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \
|
|
||||||
PetitCoursAttributionCounter
|
|
||||||
from django.contrib.auth.models import User, Group, Permission
|
from django.contrib.auth.models import User, Group, Permission
|
||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
@ -22,6 +16,17 @@ import django.utils.six as six
|
||||||
|
|
||||||
import autocomplete_light
|
import autocomplete_light
|
||||||
|
|
||||||
|
from .petits_cours_models import PetitCoursDemande, \
|
||||||
|
PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \
|
||||||
|
PetitCoursAttributionCounter
|
||||||
|
from .models import (
|
||||||
|
SurveyQuestionAnswer, SurveyQuestion, CofProfile, EventOption,
|
||||||
|
EventOptionChoice, Event, Club, EventCommentField, EventRegistration,
|
||||||
|
Survey
|
||||||
|
)
|
||||||
|
|
||||||
|
from gestion.models import Profile
|
||||||
|
|
||||||
|
|
||||||
def add_link_field(target_model='', field='', link_text=six.text_type,
|
def add_link_field(target_model='', field='', link_text=six.text_type,
|
||||||
desc_text=six.text_type):
|
desc_text=six.text_type):
|
||||||
|
@ -271,10 +276,6 @@ class PetitCoursDemandeAdmin(admin.ModelAdmin):
|
||||||
search_fields = ('name', 'email', 'phone', 'lieu', 'remarques')
|
search_fields = ('name', 'email', 'phone', 'lieu', 'remarques')
|
||||||
|
|
||||||
|
|
||||||
class CustomMailAdmin(admin.ModelAdmin):
|
|
||||||
search_fields = ('shortname', 'title')
|
|
||||||
|
|
||||||
|
|
||||||
class ClubAdminForm(forms.ModelForm):
|
class ClubAdminForm(forms.ModelForm):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super(ClubAdminForm, self).clean()
|
cleaned_data = super(ClubAdminForm, self).clean()
|
||||||
|
@ -301,7 +302,6 @@ admin.site.unregister(User)
|
||||||
admin.site.register(User, UserProfileAdmin)
|
admin.site.register(User, UserProfileAdmin)
|
||||||
admin.site.register(CofProfile)
|
admin.site.register(CofProfile)
|
||||||
admin.site.register(Club, ClubAdmin)
|
admin.site.register(Club, ClubAdmin)
|
||||||
admin.site.register(CustomMail)
|
|
||||||
admin.site.register(PetitCoursSubject)
|
admin.site.register(PetitCoursSubject)
|
||||||
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
|
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
|
||||||
admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin)
|
admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin)
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import division
|
from ldap3 import Connection
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django import shortcuts
|
from django import shortcuts
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from .models import CofProfile, Clipper
|
from .models import CofProfile
|
||||||
from .decorators import buro_required
|
from .decorators import buro_required
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class Clipper(object):
|
||||||
|
def __init__(self, clipper, fullname):
|
||||||
|
self.clipper = clipper
|
||||||
|
self.fullname = fullname
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
|
@ -25,9 +29,9 @@ def autocomplete(request):
|
||||||
queries = {}
|
queries = {}
|
||||||
bits = q.split()
|
bits = q.split()
|
||||||
|
|
||||||
queries['members'] = CofProfile.objects.filter(Q(is_cof=True))
|
# Fetching data from User and Profile tables
|
||||||
queries['users'] = User.objects.filter(Q(profile__cof__is_cof=False))
|
queries['members'] = CofProfile.objects.filter(is_cof=True)
|
||||||
queries['clippers'] = Clipper.objects
|
queries['users'] = User.objects.filter(profile__cof__is_cof=False)
|
||||||
for bit in bits:
|
for bit in bits:
|
||||||
queries['members'] = queries['members'].filter(
|
queries['members'] = queries['members'].filter(
|
||||||
Q(profile__user__first_name__icontains=bit)
|
Q(profile__user__first_name__icontains=bit)
|
||||||
|
@ -38,24 +42,38 @@ def autocomplete(request):
|
||||||
Q(first_name__icontains=bit)
|
Q(first_name__icontains=bit)
|
||||||
| Q(last_name__icontains=bit)
|
| Q(last_name__icontains=bit)
|
||||||
| Q(username__icontains=bit))
|
| Q(username__icontains=bit))
|
||||||
queries['clippers'] = queries['clippers'].filter(
|
|
||||||
Q(fullname__icontains=bit)
|
|
||||||
| Q(username__icontains=bit))
|
|
||||||
queries['members'] = queries['members'].distinct()
|
queries['members'] = queries['members'].distinct()
|
||||||
queries['users'] = queries['users'].distinct()
|
queries['users'] = queries['users'].distinct()
|
||||||
usernames = list(queries['members'].values_list('profile__login_clipper',
|
|
||||||
flat='True')) \
|
# Clearing redundancies
|
||||||
+ list(queries['users'].values_list('profile__login_clipper',
|
usernames = (
|
||||||
|
set(queries['members'].values_list('login_clipper', flat='True'))
|
||||||
|
| set(queries['users'].values_list('profile__login_clipper',
|
||||||
flat='True'))
|
flat='True'))
|
||||||
queries['clippers'] = queries['clippers'] \
|
)
|
||||||
.exclude(username__in=usernames).distinct()
|
|
||||||
# add clippers
|
|
||||||
|
|
||||||
|
# Fetching data from the SPI
|
||||||
|
if hasattr(settings, 'LDAP_SERVER_URL'):
|
||||||
|
# Fetching
|
||||||
|
ldap_query = '(|{:s})'.format(''.join(
|
||||||
|
['(cn=*{bit:s}*)(uid=*{bit:s}*)'.format(**{"bit": bit})
|
||||||
|
for bit in bits]
|
||||||
|
))
|
||||||
|
with Connection(settings.LDAP_SERVER_URL) as conn:
|
||||||
|
conn.search(
|
||||||
|
'dc=spi,dc=ens,dc=fr', ldap_query,
|
||||||
|
attributes=['uid', 'cn']
|
||||||
|
)
|
||||||
|
queries['clippers'] = conn.entries
|
||||||
|
# Clearing redundancies
|
||||||
|
queries['clippers'] = [
|
||||||
|
Clipper(clipper.uid, clipper.cn)
|
||||||
|
for clipper in queries['clippers']
|
||||||
|
if str(clipper.uid) not in usernames
|
||||||
|
]
|
||||||
|
|
||||||
|
# Resulting data
|
||||||
data.update(queries)
|
data.update(queries)
|
||||||
|
data['options'] = sum(len(query) for query in queries)
|
||||||
options = 0
|
|
||||||
for query in queries.values():
|
|
||||||
options += len(query)
|
|
||||||
data['options'] = options
|
|
||||||
|
|
||||||
return shortcuts.render(request, "autocomplete_user.html", data)
|
return shortcuts.render(request, "autocomplete_user.html", data)
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import autocomplete_light
|
import autocomplete_light
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
autocomplete_light.register(
|
autocomplete_light.register(
|
||||||
User, search_fields=('username', 'first_name', 'last_name'),
|
User, search_fields=('username', 'first_name', 'last_name'),
|
||||||
autocomplete_js_attributes={'placeholder': 'membre...'})
|
attrs={'placeholder': 'membre...'}
|
||||||
|
)
|
||||||
|
|
|
@ -49,10 +49,10 @@ class Command(MyBaseCommand):
|
||||||
# Gaulois
|
# Gaulois
|
||||||
gaulois = self.from_json('gaulois.json', DATA_DIR, User)
|
gaulois = self.from_json('gaulois.json', DATA_DIR, User)
|
||||||
for user in gaulois:
|
for user in gaulois:
|
||||||
CofProfile.objects.create(
|
cofprofile = CofProfile.objects.create(
|
||||||
profile=user.profile,
|
profile=user.profile,
|
||||||
is_cof=True
|
|
||||||
)
|
)
|
||||||
|
cofprofile.is_cof = True
|
||||||
|
|
||||||
# Romains
|
# Romains
|
||||||
self.from_json('romains.json', DATA_DIR, User)
|
self.from_json('romains.json', DATA_DIR, User)
|
||||||
|
@ -113,3 +113,9 @@ class Command(MyBaseCommand):
|
||||||
# ---
|
# ---
|
||||||
|
|
||||||
call_command('loadbdadevdata')
|
call_command('loadbdadevdata')
|
||||||
|
|
||||||
|
# ---
|
||||||
|
# La K-Fêt
|
||||||
|
# ---
|
||||||
|
|
||||||
|
call_command('loadkfetdevdata')
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.dispatch import receiver
|
from django.contrib.auth.models import Group, User
|
||||||
from django.contrib.auth.models import Group, Permission, User
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
import django.utils.six as six
|
import django.utils.six as six
|
||||||
from django.db.models.signals import post_save, post_delete
|
|
||||||
|
|
||||||
from gestion.models import Profile
|
from gestion.models import Profile
|
||||||
from bda.models import Spectacle
|
from bda.models import Spectacle
|
||||||
|
@ -54,7 +48,6 @@ class CofProfile(models.Model):
|
||||||
_("Remarques et précisions pour les petits cours"),
|
_("Remarques et précisions pour les petits cours"),
|
||||||
blank=True, default="")
|
blank=True, default="")
|
||||||
|
|
||||||
|
|
||||||
# is_cof = models.BooleanField("Membre du COF", default=False)
|
# is_cof = models.BooleanField("Membre du COF", default=False)
|
||||||
@property
|
@property
|
||||||
def is_cof(self):
|
def is_cof(self):
|
||||||
|
@ -64,8 +57,7 @@ class CofProfile(models.Model):
|
||||||
def is_cof(self, really):
|
def is_cof(self, really):
|
||||||
if really:
|
if really:
|
||||||
g = Group.objects.get(name='cof_members')
|
g = Group.objects.get(name='cof_members')
|
||||||
self.groups.add(g)
|
self.profile.user.groups.add(g)
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Profil COF"
|
verbose_name = "Profil COF"
|
||||||
|
@ -87,22 +79,6 @@ class Club(models.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class CustomMail(models.Model):
|
|
||||||
shortname = models.SlugField(max_length=50, blank=False)
|
|
||||||
title = models.CharField("Titre", max_length=200, blank=False)
|
|
||||||
content = models.TextField("Contenu", blank=False)
|
|
||||||
comments = models.TextField("Informations contextuelles sur le mail",
|
|
||||||
blank=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = "Mail personnalisable"
|
|
||||||
verbose_name_plural = "Mails personnalisables"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "%s: %s" % (self.shortname, self.title)
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Event(models.Model):
|
class Event(models.Model):
|
||||||
title = models.CharField("Titre", max_length=200)
|
title = models.CharField("Titre", max_length=200)
|
||||||
|
@ -249,15 +225,6 @@ class SurveyAnswer(models.Model):
|
||||||
self.survey.title)
|
self.survey.title)
|
||||||
|
|
||||||
|
|
||||||
#XXX. this needs to be removed according to Martin
|
|
||||||
class Clipper(models.Model):
|
|
||||||
username = models.CharField("Identifiant", max_length=20)
|
|
||||||
fullname = models.CharField("Nom complet", max_length=200)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Clipper %s" % self.username
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class CalendarSubscription(models.Model):
|
class CalendarSubscription(models.Model):
|
||||||
token = models.UUIDField()
|
token = models.UUIDField()
|
||||||
|
|
54
cof/petits_cours_forms.py
Normal file
54
cof/petits_cours_forms.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from captcha.fields import ReCaptchaField
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from django.forms import ModelForm
|
||||||
|
from django.forms.models import inlineformset_factory, BaseInlineFormSet
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from .petits_cours_models import PetitCoursDemande, PetitCoursAbility
|
||||||
|
|
||||||
|
|
||||||
|
class BaseMatieresFormSet(BaseInlineFormSet):
|
||||||
|
def clean(self):
|
||||||
|
super(BaseMatieresFormSet, self).clean()
|
||||||
|
if any(self.errors):
|
||||||
|
# Don't bother validating the formset unless each form is
|
||||||
|
# valid on its own
|
||||||
|
return
|
||||||
|
matieres = []
|
||||||
|
for i in range(0, self.total_form_count()):
|
||||||
|
form = self.forms[i]
|
||||||
|
if not form.cleaned_data:
|
||||||
|
continue
|
||||||
|
matiere = form.cleaned_data['matiere']
|
||||||
|
niveau = form.cleaned_data['niveau']
|
||||||
|
delete = form.cleaned_data['DELETE']
|
||||||
|
if not delete and (matiere, niveau) in matieres:
|
||||||
|
raise forms.ValidationError(
|
||||||
|
"Vous ne pouvez pas vous inscrire deux fois pour la "
|
||||||
|
"même matiere avec le même niveau.")
|
||||||
|
matieres.append((matiere, niveau))
|
||||||
|
|
||||||
|
|
||||||
|
class DemandeForm(ModelForm):
|
||||||
|
captcha = ReCaptchaField(attrs={'theme': 'clean', 'lang': 'fr'})
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(DemandeForm, self).__init__(*args, **kwargs)
|
||||||
|
self.fields['matieres'].help_text = ''
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = PetitCoursDemande
|
||||||
|
fields = ('name', 'email', 'phone', 'quand', 'freq', 'lieu',
|
||||||
|
'matieres', 'agrege_requis', 'niveau', 'remarques')
|
||||||
|
widgets = {'matieres': forms.CheckboxSelectMultiple}
|
||||||
|
|
||||||
|
|
||||||
|
MatieresFormSet = inlineformset_factory(
|
||||||
|
User,
|
||||||
|
PetitCoursAbility,
|
||||||
|
fields=("matiere", "niveau", "agrege"),
|
||||||
|
formset=BaseMatieresFormSet
|
||||||
|
)
|
|
@ -1,14 +1,11 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import division
|
from functools import reduce
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Min
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
from django.utils.six.moves import reduce
|
|
||||||
|
|
||||||
|
|
||||||
def choices_length(choices):
|
def choices_length(choices):
|
||||||
|
@ -24,7 +21,6 @@ LEVELS_CHOICES = (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class PetitCoursSubject(models.Model):
|
class PetitCoursSubject(models.Model):
|
||||||
name = models.CharField(_("Matière"), max_length=30)
|
name = models.CharField(_("Matière"), max_length=30)
|
||||||
users = models.ManyToManyField(User, related_name="petits_cours_matieres",
|
users = models.ManyToManyField(User, related_name="petits_cours_matieres",
|
||||||
|
@ -38,7 +34,6 @@ class PetitCoursSubject(models.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class PetitCoursAbility(models.Model):
|
class PetitCoursAbility(models.Model):
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière"))
|
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière"))
|
||||||
|
@ -52,11 +47,11 @@ class PetitCoursAbility(models.Model):
|
||||||
verbose_name_plural = "Compétences des petits cours"
|
verbose_name_plural = "Compétences des petits cours"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s - %s - %s" % (self.user.username,
|
return "{:s} - {!s} - {:s}".format(
|
||||||
self.matiere, self.niveau)
|
self.user.username, self.matiere, self.niveau
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class PetitCoursDemande(models.Model):
|
class PetitCoursDemande(models.Model):
|
||||||
name = models.CharField(_("Nom/prénom"), max_length=200)
|
name = models.CharField(_("Nom/prénom"), max_length=200)
|
||||||
email = models.CharField(_("Adresse email"), max_length=300)
|
email = models.CharField(_("Adresse email"), max_length=300)
|
||||||
|
@ -70,7 +65,7 @@ class PetitCoursDemande(models.Model):
|
||||||
freq = models.CharField(
|
freq = models.CharField(
|
||||||
_("Fréquence"),
|
_("Fréquence"),
|
||||||
help_text=_("Indiquez ici la fréquence envisagée "
|
help_text=_("Indiquez ici la fréquence envisagée "
|
||||||
+ "(hebdomadaire, 2 fois par semaine, ...)"),
|
"(hebdomadaire, 2 fois par semaine, ...)"),
|
||||||
max_length=300, blank=True)
|
max_length=300, blank=True)
|
||||||
lieu = models.CharField(
|
lieu = models.CharField(
|
||||||
_("Lieu (si préférence)"),
|
_("Lieu (si préférence)"),
|
||||||
|
@ -94,16 +89,42 @@ class PetitCoursDemande(models.Model):
|
||||||
blank=True, null=True)
|
blank=True, null=True)
|
||||||
created = models.DateTimeField(_("Date de création"), auto_now_add=True)
|
created = models.DateTimeField(_("Date de création"), auto_now_add=True)
|
||||||
|
|
||||||
|
def get_candidates(self, redo=False):
|
||||||
|
"""
|
||||||
|
Donne la liste des profs disponibles pour chaque matière de la demande.
|
||||||
|
- On ne donne que les agrégés si c'est demandé
|
||||||
|
- Si ``redo`` vaut ``True``, cela signifie qu'on retraite la demande et
|
||||||
|
il ne faut pas proposer à nouveau des noms qui ont déjà été proposés
|
||||||
|
"""
|
||||||
|
for matiere in self.matieres.all():
|
||||||
|
candidates = PetitCoursAbility.objects.filter(
|
||||||
|
matiere=matiere,
|
||||||
|
niveau=self.niveau,
|
||||||
|
user__profile__is_cof=True,
|
||||||
|
user__profile__petits_cours_accept=True
|
||||||
|
)
|
||||||
|
if self.agrege_requis:
|
||||||
|
candidates = candidates.filter(agrege=True)
|
||||||
|
if redo:
|
||||||
|
attrs = self.petitcoursattribution_set.filter(matiere=matiere)
|
||||||
|
already_proposed = [
|
||||||
|
attr.user
|
||||||
|
for attr in attrs
|
||||||
|
]
|
||||||
|
candidates = candidates.exclude(user__in=already_proposed)
|
||||||
|
candidates = candidates.order_by('?').select_related().all()
|
||||||
|
yield (matiere, candidates)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Demande de petits cours"
|
verbose_name = "Demande de petits cours"
|
||||||
verbose_name_plural = "Demandes de petits cours"
|
verbose_name_plural = "Demandes de petits cours"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Demande %d du %s" % (self.id,
|
return "Demande {:d} du {:s}".format(
|
||||||
self.created.strftime("%d %b %Y"))
|
self.id, self.created.strftime("%d %b %Y")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class PetitCoursAttribution(models.Model):
|
class PetitCoursAttribution(models.Model):
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
demande = models.ForeignKey(PetitCoursDemande, verbose_name=_("Demande"))
|
demande = models.ForeignKey(PetitCoursDemande, verbose_name=_("Demande"))
|
||||||
|
@ -118,20 +139,40 @@ class PetitCoursAttribution(models.Model):
|
||||||
verbose_name_plural = "Attributions de petits cours"
|
verbose_name_plural = "Attributions de petits cours"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Attribution de la demande %d à %s pour %s" \
|
return "Attribution de la demande {:d} à {:s} pour {!s}".format(
|
||||||
% (self.demande.id, self.user.username, self.matiere)
|
self.demande.id, self.user.username, self.matiere
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class PetitCoursAttributionCounter(models.Model):
|
class PetitCoursAttributionCounter(models.Model):
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matiere"))
|
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matiere"))
|
||||||
count = models.IntegerField("Nombre d'envois", default=0)
|
count = models.IntegerField("Nombre d'envois", default=0)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_uptodate(cls, user, matiere):
|
||||||
|
"""
|
||||||
|
Donne le compteur de l'utilisateur pour cette matière. Si le compteur
|
||||||
|
n'existe pas encore, il est initialisé avec le minimum des valeurs des
|
||||||
|
compteurs de tout le monde.
|
||||||
|
"""
|
||||||
|
counter, created = cls.objects.get_or_create(
|
||||||
|
user=user, matiere=matiere)
|
||||||
|
if created:
|
||||||
|
mincount = (
|
||||||
|
cls.objects.filter(matiere=matiere).exclude(user=user)
|
||||||
|
.aggregate(Min('count'))
|
||||||
|
['count__min']
|
||||||
|
)
|
||||||
|
counter.count = mincount
|
||||||
|
counter.save()
|
||||||
|
return counter
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Compteur d'attribution de petits cours"
|
verbose_name = "Compteur d'attribution de petits cours"
|
||||||
verbose_name_plural = "Compteurs d'attributions de petits cours"
|
verbose_name_plural = "Compteurs d'attributions de petits cours"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%d demandes envoyées à %s pour %s" \
|
return "{:d} demandes envoyées à {:s} pour {!s}".format(
|
||||||
% (self.count, self.user.username, self.matiere)
|
self.count, self.user.username, self.matiere
|
||||||
|
)
|
||||||
|
|
|
@ -1,36 +1,25 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import division
|
import json
|
||||||
from __future__ import print_function
|
from datetime import datetime
|
||||||
from __future__ import unicode_literals
|
from custommail.shortcuts import render_custom_mail
|
||||||
|
|
||||||
from django.shortcuts import render, get_object_or_404, redirect
|
from django.shortcuts import render, get_object_or_404, redirect
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.core.mail import EmailMessage
|
|
||||||
from django.forms import ModelForm
|
|
||||||
from django import forms
|
|
||||||
from django.forms.models import inlineformset_factory, BaseInlineFormSet
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.views.generic import ListView
|
from django.views.generic import ListView, DetailView
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.template import loader
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.db.models import Min
|
|
||||||
|
|
||||||
from .models import CofProfile
|
from .models import CofProfile
|
||||||
from .petits_cours_models import PetitCoursDemande, \
|
from .petits_cours_models import (
|
||||||
PetitCoursAttribution, PetitCoursAttributionCounter, PetitCoursAbility, \
|
PetitCoursDemande, PetitCoursAttribution, PetitCoursAttributionCounter,
|
||||||
PetitCoursSubject
|
PetitCoursAbility, PetitCoursSubject
|
||||||
|
)
|
||||||
from .decorators import buro_required
|
from .decorators import buro_required
|
||||||
from .shared import lock_table, unlock_tables
|
from .shared import lock_table, unlock_tables
|
||||||
|
from .petits_cours_forms import DemandeForm, MatieresFormSet
|
||||||
from captcha.fields import ReCaptchaField
|
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
import base64
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
class DemandeListView(ListView):
|
class DemandeListView(ListView):
|
||||||
|
@ -41,47 +30,17 @@ class DemandeListView(ListView):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return PetitCoursDemande.objects.order_by('traitee', '-id').all()
|
return PetitCoursDemande.objects.order_by('traitee', '-id').all()
|
||||||
|
|
||||||
@method_decorator(buro_required)
|
|
||||||
def dispatch(self, *args, **kwargs):
|
|
||||||
return super(DemandeListView, self).dispatch(*args, **kwargs)
|
|
||||||
|
|
||||||
|
class DemandeDetailView(DetailView):
|
||||||
|
model = PetitCoursDemande
|
||||||
|
template_name = "cof/details_demande_petit_cours.html"
|
||||||
|
context_object_name = "demande"
|
||||||
|
|
||||||
@buro_required
|
def get_context_data(self, **kwargs):
|
||||||
def details(request, demande_id):
|
context = super(DemandeDetailView, self).get_context_data(**kwargs)
|
||||||
demande = get_object_or_404(PetitCoursDemande, id=demande_id)
|
obj = self.object
|
||||||
attributions = PetitCoursAttribution.objects.filter(demande=demande).all()
|
context['attributions'] = obj.petitcoursattribution_set.all()
|
||||||
return render(request, "details_demande_petit_cours.html",
|
return context
|
||||||
{"demande": demande,
|
|
||||||
"attributions": attributions})
|
|
||||||
|
|
||||||
|
|
||||||
def _get_attrib_counter(user, matiere):
|
|
||||||
counter, created = PetitCoursAttributionCounter \
|
|
||||||
.objects.get_or_create(user=user, matiere=matiere)
|
|
||||||
if created:
|
|
||||||
mincount = PetitCoursAttributionCounter.objects \
|
|
||||||
.filter(matiere=matiere).exclude(user=user).all() \
|
|
||||||
.aggregate(Min('count'))
|
|
||||||
counter.count = mincount['count__min']
|
|
||||||
counter.save()
|
|
||||||
return counter
|
|
||||||
|
|
||||||
|
|
||||||
def _get_demande_candidates(demande, redo=False):
|
|
||||||
for matiere in demande.matieres.all():
|
|
||||||
candidates = PetitCoursAbility.objects.filter(matiere=matiere,
|
|
||||||
niveau=demande.niveau)
|
|
||||||
candidates = candidates.filter(user__profile__is_cof=True,
|
|
||||||
user__profile__petits_cours_accept=True)
|
|
||||||
if demande.agrege_requis:
|
|
||||||
candidates = candidates.filter(agrege=True)
|
|
||||||
if redo:
|
|
||||||
attributions = PetitCoursAttribution.objects \
|
|
||||||
.filter(demande=demande, matiere=matiere).all()
|
|
||||||
for attrib in attributions:
|
|
||||||
candidates = candidates.exclude(user=attrib.user)
|
|
||||||
candidates = candidates.order_by('?').select_related().all()
|
|
||||||
yield (matiere, candidates)
|
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
|
@ -95,12 +54,15 @@ def traitement(request, demande_id, redo=False):
|
||||||
proposed_for = {}
|
proposed_for = {}
|
||||||
unsatisfied = []
|
unsatisfied = []
|
||||||
attribdata = {}
|
attribdata = {}
|
||||||
for matiere, candidates in _get_demande_candidates(demande, redo):
|
for matiere, candidates in demande.get_candidates(redo):
|
||||||
if candidates:
|
if candidates:
|
||||||
tuples = []
|
tuples = []
|
||||||
for candidate in candidates:
|
for candidate in candidates:
|
||||||
user = candidate.user
|
user = candidate.user
|
||||||
tuples.append((candidate, _get_attrib_counter(user, matiere)))
|
tuples.append((
|
||||||
|
candidate,
|
||||||
|
PetitCoursAttributionCounter.get_uptodate(user, matiere)
|
||||||
|
))
|
||||||
tuples = sorted(tuples, key=lambda c: c[1].count)
|
tuples = sorted(tuples, key=lambda c: c[1].count)
|
||||||
candidates, _ = zip(*tuples)
|
candidates, _ = zip(*tuples)
|
||||||
candidates = candidates[0:min(3, len(candidates))]
|
candidates = candidates[0:min(3, len(candidates))]
|
||||||
|
@ -131,7 +93,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
|
||||||
proposed_for = proposed_for.items()
|
proposed_for = proposed_for.items()
|
||||||
attribdata = list(attribdata.items())
|
attribdata = list(attribdata.items())
|
||||||
proposed_mails = _generate_eleve_email(demande, proposed_for)
|
proposed_mails = _generate_eleve_email(demande, proposed_for)
|
||||||
mainmail = loader.render_to_string("petits-cours-mail-demandeur.txt", {
|
mainmail = render_custom_mail("petits-cours-mail-demandeur", {
|
||||||
"proposals": proposals,
|
"proposals": proposals,
|
||||||
"unsatisfied": unsatisfied,
|
"unsatisfied": unsatisfied,
|
||||||
"extra":
|
"extra":
|
||||||
|
@ -139,7 +101,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
|
||||||
'style="width:99%; height: 90px;">'
|
'style="width:99%; height: 90px;">'
|
||||||
'</textarea>'
|
'</textarea>'
|
||||||
})
|
})
|
||||||
return render(request, "traitement_demande_petit_cours.html",
|
return render(request, "gestioncof/traitement_demande_petit_cours.html",
|
||||||
{"demande": demande,
|
{"demande": demande,
|
||||||
"unsatisfied": unsatisfied,
|
"unsatisfied": unsatisfied,
|
||||||
"proposals": proposals,
|
"proposals": proposals,
|
||||||
|
@ -153,14 +115,16 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
|
||||||
|
|
||||||
|
|
||||||
def _generate_eleve_email(demande, proposed_for):
|
def _generate_eleve_email(demande, proposed_for):
|
||||||
proposed_mails = []
|
return [
|
||||||
for user, matieres in proposed_for:
|
(
|
||||||
msg = loader.render_to_string("petits-cours-mail-eleve.txt", {
|
user,
|
||||||
|
render_custom_mail('petit-cours-mail-eleve', {
|
||||||
"demande": demande,
|
"demande": demande,
|
||||||
"matieres": matieres
|
"matieres": matieres
|
||||||
})
|
})
|
||||||
proposed_mails.append((user, msg))
|
)
|
||||||
return proposed_mails
|
for user, matieres in proposed_for
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def _traitement_other_preparing(request, demande):
|
def _traitement_other_preparing(request, demande):
|
||||||
|
@ -170,7 +134,7 @@ def _traitement_other_preparing(request, demande):
|
||||||
proposed_for = {}
|
proposed_for = {}
|
||||||
attribdata = {}
|
attribdata = {}
|
||||||
errors = []
|
errors = []
|
||||||
for matiere, candidates in _get_demande_candidates(demande, redo):
|
for matiere, candidates in demande.get_candidates(redo):
|
||||||
if candidates:
|
if candidates:
|
||||||
candidates = dict([(candidate.user.id, candidate.user)
|
candidates = dict([(candidate.user.id, candidate.user)
|
||||||
for candidate in candidates])
|
for candidate in candidates])
|
||||||
|
@ -178,17 +142,19 @@ def _traitement_other_preparing(request, demande):
|
||||||
proposals[matiere] = []
|
proposals[matiere] = []
|
||||||
for choice_id in range(min(3, len(candidates))):
|
for choice_id in range(min(3, len(candidates))):
|
||||||
choice = int(
|
choice = int(
|
||||||
request.POST["proposal-%d-%d" % (matiere.id, choice_id)])
|
request.POST["proposal-{:d}-{:d}"
|
||||||
|
.format(matiere.id, choice_id)]
|
||||||
|
)
|
||||||
if choice == -1:
|
if choice == -1:
|
||||||
continue
|
continue
|
||||||
if choice not in candidates:
|
if choice not in candidates:
|
||||||
errors.append("Choix invalide pour la proposition %d"
|
errors.append("Choix invalide pour la proposition {:d}"
|
||||||
"en %s" % (choice_id + 1, matiere))
|
"en {!s}".format(choice_id + 1, matiere))
|
||||||
continue
|
continue
|
||||||
user = candidates[choice]
|
user = candidates[choice]
|
||||||
if user in proposals[matiere]:
|
if user in proposals[matiere]:
|
||||||
errors.append("La proposition %d en %s est un doublon"
|
errors.append("La proposition {:d} en {!s} est un doublon"
|
||||||
% (choice_id + 1, matiere))
|
.format(choice_id + 1, matiere))
|
||||||
continue
|
continue
|
||||||
proposals[matiere].append(user)
|
proposals[matiere].append(user)
|
||||||
attribdata[matiere.id].append(user.id)
|
attribdata[matiere.id].append(user.id)
|
||||||
|
@ -197,10 +163,11 @@ def _traitement_other_preparing(request, demande):
|
||||||
else:
|
else:
|
||||||
proposed_for[user].append(matiere)
|
proposed_for[user].append(matiere)
|
||||||
if not proposals[matiere]:
|
if not proposals[matiere]:
|
||||||
errors.append("Aucune proposition pour %s" % (matiere,))
|
errors.append("Aucune proposition pour {!s}".format(matiere))
|
||||||
elif len(proposals[matiere]) < 3:
|
elif len(proposals[matiere]) < 3:
|
||||||
errors.append("Seulement %d proposition%s pour %s"
|
errors.append("Seulement {:d} proposition{:s} pour {!s}"
|
||||||
% (len(proposals[matiere]),
|
.format(
|
||||||
|
len(proposals[matiere]),
|
||||||
"s" if len(proposals[matiere]) > 1 else "",
|
"s" if len(proposals[matiere]) > 1 else "",
|
||||||
matiere))
|
matiere))
|
||||||
else:
|
else:
|
||||||
|
@ -219,12 +186,15 @@ def _traitement_other(request, demande, redo):
|
||||||
proposed_for = {}
|
proposed_for = {}
|
||||||
unsatisfied = []
|
unsatisfied = []
|
||||||
attribdata = {}
|
attribdata = {}
|
||||||
for matiere, candidates in _get_demande_candidates(demande, redo):
|
for matiere, candidates in demande.get_candidates(redo):
|
||||||
if candidates:
|
if candidates:
|
||||||
tuples = []
|
tuples = []
|
||||||
for candidate in candidates:
|
for candidate in candidates:
|
||||||
user = candidate.user
|
user = candidate.user
|
||||||
tuples.append((candidate, _get_attrib_counter(user, matiere)))
|
tuples.append((
|
||||||
|
candidate,
|
||||||
|
PetitCoursAttributionCounter.get_uptodate(user, matiere)
|
||||||
|
))
|
||||||
tuples = sorted(tuples, key=lambda c: c[1].count)
|
tuples = sorted(tuples, key=lambda c: c[1].count)
|
||||||
candidates, _ = zip(*tuples)
|
candidates, _ = zip(*tuples)
|
||||||
attribdata[matiere.id] = []
|
attribdata[matiere.id] = []
|
||||||
|
@ -241,7 +211,8 @@ def _traitement_other(request, demande, redo):
|
||||||
unsatisfied.append(matiere)
|
unsatisfied.append(matiere)
|
||||||
proposals = proposals.items()
|
proposals = proposals.items()
|
||||||
proposed_for = proposed_for.items()
|
proposed_for = proposed_for.items()
|
||||||
return render(request, "traitement_demande_petit_cours_autre_niveau.html",
|
return render(request,
|
||||||
|
"gestiocof/traitement_demande_petit_cours_autre_niveau.html",
|
||||||
{"demande": demande,
|
{"demande": demande,
|
||||||
"unsatisfied": unsatisfied,
|
"unsatisfied": unsatisfied,
|
||||||
"proposals": proposals,
|
"proposals": proposals,
|
||||||
|
@ -272,7 +243,7 @@ def _traitement_post(request, demande):
|
||||||
proposals_list = proposals.items()
|
proposals_list = proposals.items()
|
||||||
proposed_for = proposed_for.items()
|
proposed_for = proposed_for.items()
|
||||||
proposed_mails = _generate_eleve_email(demande, proposed_for)
|
proposed_mails = _generate_eleve_email(demande, proposed_for)
|
||||||
mainmail = loader.render_to_string("petits-cours-mail-demandeur.txt", {
|
mainmail = render_custom_mail("petits-cours-mail-demandeur", {
|
||||||
"proposals": proposals_list,
|
"proposals": proposals_list,
|
||||||
"unsatisfied": unsatisfied,
|
"unsatisfied": unsatisfied,
|
||||||
"extra": extra,
|
"extra": extra,
|
||||||
|
@ -282,11 +253,11 @@ def _traitement_post(request, demande):
|
||||||
replyto = settings.MAIL_DATA['petits_cours']['REPLYTO']
|
replyto = settings.MAIL_DATA['petits_cours']['REPLYTO']
|
||||||
mails_to_send = []
|
mails_to_send = []
|
||||||
for (user, msg) in proposed_mails:
|
for (user, msg) in proposed_mails:
|
||||||
msg = EmailMessage("Petits cours ENS par le COF", msg,
|
msg = mail.EmailMessage("Petits cours ENS par le COF", msg,
|
||||||
frommail, [user.email],
|
frommail, [user.email],
|
||||||
[bccaddress], headers={'Reply-To': replyto})
|
[bccaddress], headers={'Reply-To': replyto})
|
||||||
mails_to_send.append(msg)
|
mails_to_send.append(msg)
|
||||||
mails_to_send.append(EmailMessage("Cours particuliers ENS", mainmail,
|
mails_to_send.append(mail.EmailMessage("Cours particuliers ENS", mainmail,
|
||||||
frommail, [demande.email],
|
frommail, [demande.email],
|
||||||
[bccaddress],
|
[bccaddress],
|
||||||
headers={'Reply-To': replyto}))
|
headers={'Reply-To': replyto}))
|
||||||
|
@ -307,43 +278,18 @@ def _traitement_post(request, demande):
|
||||||
demande.traitee_par = request.user
|
demande.traitee_par = request.user
|
||||||
demande.processed = datetime.now()
|
demande.processed = datetime.now()
|
||||||
demande.save()
|
demande.save()
|
||||||
return render(request, "traitement_demande_petit_cours_success.html",
|
return render(request,
|
||||||
|
"gestioncof/traitement_demande_petit_cours_success.html",
|
||||||
{"demande": demande,
|
{"demande": demande,
|
||||||
"redo": redo,
|
"redo": redo,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class BaseMatieresFormSet(BaseInlineFormSet):
|
|
||||||
def clean(self):
|
|
||||||
super(BaseMatieresFormSet, self).clean()
|
|
||||||
if any(self.errors):
|
|
||||||
# Don't bother validating the formset unless each form is
|
|
||||||
# valid on its own
|
|
||||||
return
|
|
||||||
matieres = []
|
|
||||||
for i in range(0, self.total_form_count()):
|
|
||||||
form = self.forms[i]
|
|
||||||
if not form.cleaned_data:
|
|
||||||
continue
|
|
||||||
matiere = form.cleaned_data['matiere']
|
|
||||||
niveau = form.cleaned_data['niveau']
|
|
||||||
delete = form.cleaned_data['DELETE']
|
|
||||||
if not delete and (matiere, niveau) in matieres:
|
|
||||||
raise forms.ValidationError(
|
|
||||||
"Vous ne pouvez pas vous inscrire deux fois pour la "
|
|
||||||
"même matiere avec le même niveau.")
|
|
||||||
matieres.append((matiere, niveau))
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def inscription(request):
|
def inscription(request):
|
||||||
profile, created = CofProfile.objects.get_or_create(user=request.user)
|
profile, created = CofProfile.objects.get_or_create(user=request.user)
|
||||||
if not profile.is_cof:
|
if not profile.is_cof:
|
||||||
return redirect("cof-denied")
|
return redirect("cof-denied")
|
||||||
MatieresFormSet = inlineformset_factory(User, PetitCoursAbility,
|
|
||||||
fields=("matiere", "niveau",
|
|
||||||
"agrege",),
|
|
||||||
formset=BaseMatieresFormSet)
|
|
||||||
success = False
|
success = False
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
formset = MatieresFormSet(request.POST, instance=request.user)
|
formset = MatieresFormSet(request.POST, instance=request.user)
|
||||||
|
@ -354,10 +300,14 @@ def inscription(request):
|
||||||
profile.save()
|
profile.save()
|
||||||
lock_table(PetitCoursAttributionCounter, PetitCoursAbility, User,
|
lock_table(PetitCoursAttributionCounter, PetitCoursAbility, User,
|
||||||
PetitCoursSubject)
|
PetitCoursSubject)
|
||||||
abilities = PetitCoursAbility.objects \
|
abilities = (
|
||||||
.filter(user=request.user).all()
|
PetitCoursAbility.objects.filter(user=request.user).all()
|
||||||
|
)
|
||||||
for ability in abilities:
|
for ability in abilities:
|
||||||
_get_attrib_counter(ability.user, ability.matiere)
|
PetitCoursAttributionCounter.get_uptodate(
|
||||||
|
ability.user,
|
||||||
|
ability.matiere
|
||||||
|
)
|
||||||
unlock_tables()
|
unlock_tables()
|
||||||
success = True
|
success = True
|
||||||
formset = MatieresFormSet(instance=request.user)
|
formset = MatieresFormSet(instance=request.user)
|
||||||
|
@ -369,20 +319,6 @@ def inscription(request):
|
||||||
"remarques": profile.petits_cours_remarques})
|
"remarques": profile.petits_cours_remarques})
|
||||||
|
|
||||||
|
|
||||||
class DemandeForm(ModelForm):
|
|
||||||
captcha = ReCaptchaField(attrs={'theme': 'clean', 'lang': 'fr'})
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(DemandeForm, self).__init__(*args, **kwargs)
|
|
||||||
self.fields['matieres'].help_text = ''
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = PetitCoursDemande
|
|
||||||
fields = ('name', 'email', 'phone', 'quand', 'freq', 'lieu',
|
|
||||||
'matieres', 'agrege_requis', 'niveau', 'remarques')
|
|
||||||
widgets = {'matieres': forms.CheckboxSelectMultiple}
|
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def demande(request):
|
def demande(request):
|
||||||
success = False
|
success = False
|
||||||
|
|
|
@ -9,12 +9,9 @@ from django.conf import settings
|
||||||
from django_cas_ng.backends import CASBackend
|
from django_cas_ng.backends import CASBackend
|
||||||
from django_cas_ng.utils import get_cas_client
|
from django_cas_ng.utils import get_cas_client
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.models import User as DjangoUser
|
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.core.mail import send_mail
|
|
||||||
from django.template import Template, Context
|
|
||||||
|
|
||||||
from .models import CofProfile, CustomMail
|
from .models import CofProfile
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
@ -99,18 +96,3 @@ def unlock_tables(*models):
|
||||||
return row
|
return row
|
||||||
|
|
||||||
unlock_table = unlock_tables
|
unlock_table = unlock_tables
|
||||||
|
|
||||||
|
|
||||||
def send_custom_mail(to, shortname, context=None, from_email="cof@ens.fr"):
|
|
||||||
if context is None:
|
|
||||||
context = {}
|
|
||||||
if isinstance(to, DjangoUser):
|
|
||||||
context["nom"] = to.get_full_name()
|
|
||||||
context["prenom"] = to.first_name
|
|
||||||
to = to.email
|
|
||||||
mail = CustomMail.objects.get(shortname=shortname)
|
|
||||||
template = Template(mail.content)
|
|
||||||
message = template.render(Context(context))
|
|
||||||
send_mail(mail.title, message,
|
|
||||||
from_email, [to],
|
|
||||||
fail_silently=True)
|
|
||||||
|
|
|
@ -1088,3 +1088,8 @@ tr.awesome{
|
||||||
color: white;
|
color: white;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.petitcours-raw {
|
||||||
|
padding:20px;
|
||||||
|
background:#fff;
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
{% if clippers %}
|
{% if clippers %}
|
||||||
<li class="autocomplete-header">Utilisateurs <tt>clipper</tt></li>
|
<li class="autocomplete-header">Utilisateurs <tt>clipper</tt></li>
|
||||||
{% for clipper in clippers %}{% if forloop.counter < 5 %}
|
{% for clipper in clippers %}{% if forloop.counter < 5 %}
|
||||||
<li class="autocomplete-value"><a href="{% url 'clipper-registration' clipper.username %}">{{ clipper|highlight_clipper:q }}</a></li>
|
<li class="autocomplete-value"><a href="{% url 'clipper-registration' clipper.clipper clipper.fullname %}">{{ clipper|highlight_clipper:q }}</a></li>
|
||||||
{% elif forloop.counter == 5 %}<li class="autocomplete-more">...</a>{% endif %}{% endfor %}
|
{% elif forloop.counter == 5 %}<li class="autocomplete-more">...</a>{% endif %}{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,16 @@
|
||||||
<h4>Mails pour les membres proposés :</h4>
|
<h4>Mails pour les membres proposés :</h4>
|
||||||
{% for proposeduser, mail in proposed_mails %}
|
{% for proposeduser, mail in proposed_mails %}
|
||||||
<h5>Pour {{ proposeduser }}:</h5>
|
<h5>Pour {{ proposeduser }}:</h5>
|
||||||
<pre>{{ mail }}</pre>
|
{% with object=mail.0 content=mail.1 %}
|
||||||
|
<pre>{{ object }}</pre>
|
||||||
|
<pre>{{ content }}</pre>
|
||||||
|
{% endwith %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<h4>Mail pour l'auteur de la demande :</h4>
|
<h4>Mail pour l'auteur de la demande :</h4>
|
||||||
<pre style="margin-top: 15px;">{{ mainmail|safe }}</pre>
|
{% with object=mainmail.0 content=mainmail.1 %}
|
||||||
|
<pre style="margin-top: 15px;">{{ object }}</pre>
|
||||||
|
<pre style="margin-top: 15px;">{{ content|safe }}</pre>
|
||||||
|
{% endwith %}
|
||||||
<input type="hidden" name="attribdata" value="{{ attribdata }}" />
|
<input type="hidden" name="attribdata" value="{{ attribdata }}" />
|
||||||
{% if redo %}<input type="hidden" name="redo" value="1" />{% endif %}
|
{% if redo %}<input type="hidden" name="redo" value="1" />{% endif %}
|
||||||
<input class="btn btn-primary pull-right" type="submit" value="Valider le {% if redo %}re{% endif %}traitement de la demande" />
|
<input class="btn btn-primary pull-right" type="submit" value="Valider le {% if redo %}re{% endif %}traitement de la demande" />
|
|
@ -1,11 +1,19 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% load bootstrap %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="petitcours-raw">
|
||||||
{% if success %}
|
{% if success %}
|
||||||
<p class="success">Votre demande a été enregistrée avec succès !</p>
|
<p class="success">Votre demande a été enregistrée avec succès !</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<form id="demandecours" method="post" action="{% url "cof.petits_cours_views.demande_raw" %}">
|
<form id="demandecours" method="post" action="{% url "cof.petits_cours_views.demande_raw" %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<table>
|
<table>
|
||||||
{{ form.as_table }}
|
{{ form | bootstrap }}
|
||||||
</table>
|
</table>
|
||||||
<input type="submit" class="btn-submit" value="Enregistrer" />
|
<input type="submit" class="btn-submit" value="Enregistrer" />
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
{% block extra_head %}
|
{% block extra_head %}
|
||||||
<link href="{% static "grappelli/jquery/ui/css/custom-theme/jquery-ui-1.8.custom.css" %}" rel="stylesheet" type="text/css" media="screen" title="no title" charset="utf-8" />
|
<script src="{% static "js/jquery.min.js" %}" type="text/javascript"></script>
|
||||||
<script src="{% static "grappelli/jquery/jquery-1.6.2.min.js" %}" type="text/javascript"></script>
|
<script src="{% static "js/jquery-ui.min.js" %}" type="text/javascript"></script>
|
||||||
<script src="{% static "grappelli/jquery/ui/js/jquery-ui-1.8.15.custom.min.js" %}" type="text/javascript"></script>
|
<script src="{% static "js/jquery.ui.touch-punch.min.js" %}" type="text/javascript"></script>
|
||||||
<link href="{% static "grappelli/css/tools.css" %}" rel="stylesheet" type="text/css" />
|
<link type="text/css" rel="stylesheet" href="{% static "css/jquery-ui.min.css" %}" />
|
||||||
<link href="{% static "grappelli/css/jquery-ui-grappelli-extensions.css" %}" rel="stylesheet" type="text/css" />
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block realcontent %}
|
{% block realcontent %}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
Bonjour,
|
|
||||||
|
|
||||||
Je vous contacte au sujet de votre annonce passée sur le site du COF pour rentrer en contact avec un élève normalien pour des cours particuliers. Voici les coordonnées d'élèves qui sont motivés par de tels cours et correspondent aux critères que vous nous aviez transmis :
|
|
||||||
|
|
||||||
{% for matiere, proposed in proposals %}¤ {{ matiere }} :{% for user in proposed %}
|
|
||||||
¤ {{ user.get_full_name }}{% if user.profile.phone %}, {{ user.profile.phone }}{% endif %}{% if user.email %}, {{ user.email }}{% endif %}{% endfor %}
|
|
||||||
|
|
||||||
{% endfor %}{% if unsatisfied %}Nous n'avons cependant pas pu trouver d'élève disponible pour des cours de {% for matiere in unsatisfied %}{% if forloop.counter0 > 0 %}, {% endif %}{{ matiere }}{% endfor %}.
|
|
||||||
|
|
||||||
{% endif %}Si pour une raison ou une autre ces numéros ne suffisaient pas, n'hésitez pas à répondre à cet e-mail et je vous en ferai parvenir d'autres sans problème.
|
|
||||||
{% if extra|length > 0 %}
|
|
||||||
{{ extra|safe }}
|
|
||||||
{% endif %}
|
|
||||||
Cordialement,
|
|
||||||
|
|
||||||
--
|
|
||||||
Le COF, BdE de l'ENS
|
|
|
@ -1,28 +0,0 @@
|
||||||
Salut,
|
|
||||||
|
|
||||||
Le COF a reçu une demande de petit cours qui te correspond. Tu es en haut de la liste d'attente donc on a transmis tes coordonnées, ainsi que celles de 2 autres qui correspondaient aussi (c'est la vie, on donne les numéros 3 par 3 pour que ce soit plus souple). Voici quelques infos sur l'annonce en question :
|
|
||||||
|
|
||||||
¤ Nom : {{ demande.name }}
|
|
||||||
|
|
||||||
¤ Période : {{ demande.quand }}
|
|
||||||
|
|
||||||
¤ Fréquence : {{ demande.freq }}
|
|
||||||
|
|
||||||
¤ Lieu (si préféré) : {{ demande.lieu }}
|
|
||||||
|
|
||||||
¤ Niveau : {{ demande.get_niveau_display }}
|
|
||||||
|
|
||||||
¤ Remarques diverses (désolé pour les balises HTML) : {{ demande.remarques }}
|
|
||||||
|
|
||||||
{% if matieres|length > 1 %}¤ Matières :
|
|
||||||
{% for matiere in matieres %} ¤ {{ matiere }}
|
|
||||||
{% endfor %}{% else %}¤ Matière : {% for matiere in matieres %}{{ matiere }}
|
|
||||||
{% endfor %}{% endif %}
|
|
||||||
Voilà, cette personne te contactera peut-être sous peu, tu pourras voir les détails directement avec elle (prix, modalités, ...). Pour indication, 30 Euro/h semble être la moyenne.
|
|
||||||
|
|
||||||
Si tu te rends compte qu'en fait tu ne peux pas/plus donner de cours en ce moment, ça serait cool que tu décoches la case "Recevoir des propositions de petits cours" sur GestioCOF. Ensuite dès que tu voudras réapparaître tu pourras recocher la case et tu seras à nouveau sur la liste.
|
|
||||||
|
|
||||||
À bientôt,
|
|
||||||
|
|
||||||
--
|
|
||||||
Le COF, pour les petits cours
|
|
|
@ -43,7 +43,7 @@ def highlight_user(user, q):
|
||||||
@register.filter
|
@register.filter
|
||||||
def highlight_clipper(clipper, q):
|
def highlight_clipper(clipper, q):
|
||||||
if clipper.fullname:
|
if clipper.fullname:
|
||||||
text = "%s (<tt>%s</tt>)" % (clipper.fullname, clipper.username)
|
text = "%s (<tt>%s</tt>)" % (clipper.fullname, clipper.clipper)
|
||||||
else:
|
else:
|
||||||
text = clipper.username
|
text = clipper.clipper
|
||||||
return highlight_text(text, q)
|
return highlight_text(text, q)
|
||||||
|
|
15
cof/urls.py
15
cof/urls.py
|
@ -1,13 +1,11 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from .petits_cours_views import DemandeListView
|
from .petits_cours_views import DemandeListView, DemandeDetailView
|
||||||
|
from .decorators import buro_required
|
||||||
from . import views, petits_cours_views
|
from . import views, petits_cours_views
|
||||||
|
|
||||||
|
|
||||||
export_patterns = [
|
export_patterns = [
|
||||||
url(r'^members$', views.export_members),
|
url(r'^members$', views.export_members),
|
||||||
url(r'^mega/avecremarques$', views.export_mega_remarksonly),
|
url(r'^mega/avecremarques$', views.export_mega_remarksonly),
|
||||||
|
@ -24,10 +22,11 @@ petitcours_patterns = [
|
||||||
name='petits-cours-demande'),
|
name='petits-cours-demande'),
|
||||||
url(r'^demande-raw$', petits_cours_views.demande_raw,
|
url(r'^demande-raw$', petits_cours_views.demande_raw,
|
||||||
name='petits-cours-demande-raw'),
|
name='petits-cours-demande-raw'),
|
||||||
url(r'^demandes$', DemandeListView.as_view(),
|
url(r'^demandes$',
|
||||||
|
buro_required(DemandeListView.as_view()),
|
||||||
name='petits-cours-demandes-list'),
|
name='petits-cours-demandes-list'),
|
||||||
url(r'^demandes/(?P<demande_id>\d+)$',
|
url(r'^demandes/(?P<pk>\d+)$',
|
||||||
petits_cours_views.details,
|
buro_required(DemandeDetailView.as_view()),
|
||||||
name='petits-cours-demande-details'),
|
name='petits-cours-demande-details'),
|
||||||
url(r'^demandes/(?P<demande_id>\d+)/traitement$',
|
url(r'^demandes/(?P<demande_id>\d+)/traitement$',
|
||||||
petits_cours_views.traitement,
|
petits_cours_views.traitement,
|
||||||
|
|
59
cof/views.py
59
cof/views.py
|
@ -1,13 +1,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import unicodecsv
|
import unicodecsv
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from icalendar import Calendar, Event as Vevent
|
from icalendar import Calendar, Event as Vevent
|
||||||
|
from custommail.shortcuts import send_custom_mail
|
||||||
|
|
||||||
from django.shortcuts import redirect, get_object_or_404, render
|
from django.shortcuts import redirect, get_object_or_404, render
|
||||||
from django.http import Http404, HttpResponse, HttpResponseForbidden
|
from django.http import Http404, HttpResponse, HttpResponseForbidden
|
||||||
|
@ -24,8 +21,7 @@ from .models import Event, EventRegistration, EventOption, \
|
||||||
EventOptionChoice
|
EventOptionChoice
|
||||||
from .models import EventCommentField, EventCommentValue, \
|
from .models import EventCommentField, EventCommentValue, \
|
||||||
CalendarSubscription
|
CalendarSubscription
|
||||||
from .shared import send_custom_mail
|
from .models import CofProfile, Club
|
||||||
from .models import CofProfile, Clipper, Club
|
|
||||||
from .decorators import buro_required, cof_required
|
from .decorators import buro_required, cof_required
|
||||||
from .forms import (
|
from .forms import (
|
||||||
EventStatusFilterForm, SurveyForm, SurveyStatusFilterForm,
|
EventStatusFilterForm, SurveyForm, SurveyStatusFilterForm,
|
||||||
|
@ -311,11 +307,11 @@ def registration_set_ro_fields(user_form, profile_form):
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def registration_form2(request, login_clipper=None, username=None):
|
def registration_form2(request, login_clipper=None, username=None,
|
||||||
|
fullname=None):
|
||||||
events = Event.objects.filter(old=False).all()
|
events = Event.objects.filter(old=False).all()
|
||||||
member = None
|
member = None
|
||||||
if login_clipper:
|
if login_clipper:
|
||||||
clipper = get_object_or_404(Clipper, username=login_clipper)
|
|
||||||
try: # check if the given user is already registered
|
try: # check if the given user is already registered
|
||||||
member = User.objects.get(username=login_clipper)
|
member = User.objects.get(username=login_clipper)
|
||||||
username = member.username
|
username = member.username
|
||||||
|
@ -326,8 +322,8 @@ def registration_form2(request, login_clipper=None, username=None):
|
||||||
user_form = RegistrationUserForm(initial={
|
user_form = RegistrationUserForm(initial={
|
||||||
'username': login_clipper,
|
'username': login_clipper,
|
||||||
'email': "%s@clipper.ens.fr" % login_clipper})
|
'email': "%s@clipper.ens.fr" % login_clipper})
|
||||||
if clipper.fullname:
|
if fullname:
|
||||||
bits = clipper.fullname.split(" ")
|
bits = fullname.split(" ")
|
||||||
user_form.fields['first_name'].initial = bits[0]
|
user_form.fields['first_name'].initial = bits[0]
|
||||||
if len(bits) > 1:
|
if len(bits) > 1:
|
||||||
user_form.fields['last_name'].initial = " ".join(bits[1:])
|
user_form.fields['last_name'].initial = " ".join(bits[1:])
|
||||||
|
@ -409,11 +405,11 @@ def registration(request):
|
||||||
try:
|
try:
|
||||||
member = User.objects.get(username=username)
|
member = User.objects.get(username=username)
|
||||||
user_form = RegistrationUserForm(request_dict, instance=member)
|
user_form = RegistrationUserForm(request_dict, instance=member)
|
||||||
|
if member.profile.login_clipper:
|
||||||
|
login_clipper = member.profile.login_clipper
|
||||||
|
else:
|
||||||
|
user_form.force_long_username()
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
try:
|
|
||||||
clipper = Clipper.objects.get(username=username)
|
|
||||||
login_clipper = clipper.username
|
|
||||||
except Clipper.DoesNotExist:
|
|
||||||
user_form.force_long_username()
|
user_form.force_long_username()
|
||||||
else:
|
else:
|
||||||
user_form.force_long_username()
|
user_form.force_long_username()
|
||||||
|
@ -445,10 +441,12 @@ def registration(request):
|
||||||
))
|
))
|
||||||
if forms_are_valid:
|
if forms_are_valid:
|
||||||
# Enregistrement du profil
|
# Enregistrement du profil
|
||||||
profile_form.save()
|
profile = profile_form.save()
|
||||||
cofprofile = cofprofile_form.save()
|
if profile.is_cof and not was_cof:
|
||||||
if cofprofile.is_cof and not was_cof:
|
send_custom_mail(
|
||||||
send_custom_mail(member, "bienvenue")
|
"welcome", "cof@ens.fr", [member.email],
|
||||||
|
context={'member': member},
|
||||||
|
)
|
||||||
# Enregistrement des inscriptions aux événements
|
# Enregistrement des inscriptions aux événements
|
||||||
for form in event_formset:
|
for form in event_formset:
|
||||||
if 'status' not in form.cleaned_data:
|
if 'status' not in form.cleaned_data:
|
||||||
|
@ -471,17 +469,20 @@ def registration(request):
|
||||||
current_registration.paid = \
|
current_registration.paid = \
|
||||||
(form.cleaned_data['status'] == 'paid')
|
(form.cleaned_data['status'] == 'paid')
|
||||||
current_registration.save()
|
current_registration.save()
|
||||||
if form.event.title == "Mega 15" and created_reg:
|
# if form.event.title == "Mega 15" and created_reg:
|
||||||
field = EventCommentField.objects.get(
|
# field = EventCommentField.objects.get(
|
||||||
event=form.event, name="Commentaires")
|
# event=form.event, name="Commentaires")
|
||||||
try:
|
# try:
|
||||||
comments = EventCommentValue.objects.get(
|
# comments = EventCommentValue.objects.get(
|
||||||
commentfield=field,
|
# commentfield=field,
|
||||||
registration=current_registration).content
|
# registration=current_registration).content
|
||||||
except EventCommentValue.DoesNotExist:
|
# except EventCommentValue.DoesNotExist:
|
||||||
comments = field.default
|
# comments = field.default
|
||||||
send_custom_mail(member, "mega",
|
# FIXME : il faut faire quelque chose de propre ici,
|
||||||
{"remarques": comments})
|
# par exemple écrire un mail générique pour
|
||||||
|
# l'inscription aux événements et/ou donner la
|
||||||
|
# possibilité d'associer un mail aux événements
|
||||||
|
# send_custom_mail(...)
|
||||||
# Enregistrement des inscriptions aux clubs
|
# Enregistrement des inscriptions aux clubs
|
||||||
member.clubs.clear()
|
member.clubs.clear()
|
||||||
for club in clubs_form.cleaned_data['clubs']:
|
for club in clubs_form.cleaned_data['clubs']:
|
||||||
|
|
|
@ -9,10 +9,6 @@ For the full list of settings and their values, see
|
||||||
https://docs.djangoproject.com/en/1.8/ref/settings/
|
https://docs.djangoproject.com/en/1.8/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -52,6 +48,7 @@ INSTALLED_APPS = (
|
||||||
'cof',
|
'cof',
|
||||||
'gestion',
|
'gestion',
|
||||||
'kfet',
|
'kfet',
|
||||||
|
'custommail',
|
||||||
)
|
)
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
MIDDLEWARE_CLASSES = (
|
||||||
|
@ -162,6 +159,8 @@ AUTHENTICATION_BACKENDS = (
|
||||||
'kfet.backends.GenericTeamBackend',
|
'kfet.backends.GenericTeamBackend',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# LDAP_SERVER_URL = 'ldaps://ldap.spi.ens.fr:636'
|
||||||
|
|
||||||
# EMAIL_HOST="nef.ens.fr"
|
# EMAIL_HOST="nef.ens.fr"
|
||||||
|
|
||||||
RECAPTCHA_PUBLIC_KEY = "DUMMY"
|
RECAPTCHA_PUBLIC_KEY = "DUMMY"
|
||||||
|
|
|
@ -4,10 +4,6 @@
|
||||||
Fichier principal de configuration des urls du projet GestioCOF
|
Fichier principal de configuration des urls du projet GestioCOF
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import autocomplete_light
|
import autocomplete_light
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
|
@ -7,15 +7,16 @@ from .forms import ProfileForm, UserForm
|
||||||
@login_required
|
@login_required
|
||||||
def profile(request):
|
def profile(request):
|
||||||
success = False
|
success = False
|
||||||
user = request.user
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
user_form = UserForm(request.POST, instance=user)
|
user_form = UserForm(request.POST, instance=request.user)
|
||||||
|
if user_form.is_valid():
|
||||||
|
user = user_form.save()
|
||||||
profile_form = ProfileForm(request.POST, instance=user.profile)
|
profile_form = ProfileForm(request.POST, instance=user.profile)
|
||||||
if all((user_form.is_valid(), profile_form.is_valid())):
|
if profile_form.is_valid():
|
||||||
user_form.save()
|
|
||||||
profile_form.save()
|
profile_form.save()
|
||||||
success = True
|
success = True
|
||||||
else:
|
else:
|
||||||
|
user = request.user
|
||||||
user_form = UserForm(instance=user)
|
user_form = UserForm(instance=user)
|
||||||
profile_form = ProfileForm(instance=user.profile)
|
profile_form = ProfileForm(instance=user.profile)
|
||||||
return render(request, "gestion/profile.html",
|
return render(request, "gestion/profile.html",
|
||||||
|
|
|
@ -1,16 +1,23 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import (absolute_import, division,
|
from ldap3 import Connection
|
||||||
print_function, unicode_literals)
|
|
||||||
from builtins import *
|
|
||||||
|
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from cof.models import User, Clipper
|
from django.conf import settings
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
from kfet.decorators import teamkfet_required
|
from kfet.decorators import teamkfet_required
|
||||||
from kfet.models import Account
|
from kfet.models import Account
|
||||||
|
|
||||||
|
|
||||||
|
class Clipper(object):
|
||||||
|
def __init__(self, clipper, fullname):
|
||||||
|
self.clipper = clipper
|
||||||
|
self.fullname = fullname
|
||||||
|
|
||||||
|
|
||||||
@teamkfet_required
|
@teamkfet_required
|
||||||
def account_create(request):
|
def account_create(request):
|
||||||
if "q" not in request.GET:
|
if "q" not in request.GET:
|
||||||
|
@ -25,10 +32,10 @@ def account_create(request):
|
||||||
queries = {}
|
queries = {}
|
||||||
search_words = q.split()
|
search_words = q.split()
|
||||||
|
|
||||||
|
# Fetching data from User, CofProfile and Account tables
|
||||||
queries['kfet'] = Account.objects
|
queries['kfet'] = Account.objects
|
||||||
queries['users_cof'] = User.objects.filter(Q(profile__cof__is_cof = True))
|
queries['users_cof'] = User.objects.filter(profile__cof__is_cof=True)
|
||||||
queries['users_notcof'] = User.objects.filter(Q(profile__cof__is_cof = False))
|
queries['users_notcof'] = User.objects.filter(profile__cof__is_cof=False)
|
||||||
queries['clippers'] = Clipper.objects
|
|
||||||
|
|
||||||
for word in search_words:
|
for word in search_words:
|
||||||
queries['kfet'] = queries['kfet'].filter(
|
queries['kfet'] = queries['kfet'].filter(
|
||||||
|
@ -46,37 +53,47 @@ def account_create(request):
|
||||||
| Q(first_name__icontains=word)
|
| Q(first_name__icontains=word)
|
||||||
| Q(last_name__icontains=word)
|
| Q(last_name__icontains=word)
|
||||||
)
|
)
|
||||||
queries['clippers'] = queries['clippers'].filter(
|
|
||||||
Q(username__icontains = word)
|
|
||||||
| Q(fullname__icontains = word)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# Clearing redundancies
|
||||||
queries['kfet'] = queries['kfet'].distinct()
|
queries['kfet'] = queries['kfet'].distinct()
|
||||||
|
usernames = set(
|
||||||
usernames = list( \
|
|
||||||
queries['kfet'].values_list('profile__user__username', flat=True))
|
queries['kfet'].values_list('profile__user__username', flat=True))
|
||||||
|
queries['kfet'] = [
|
||||||
queries['kfet'] = [ (account, account.profile.user) \
|
(account, account.profile.user)
|
||||||
for account in queries['kfet'] ]
|
for account in queries['kfet']
|
||||||
|
]
|
||||||
|
|
||||||
queries['users_cof'] = \
|
queries['users_cof'] = \
|
||||||
queries['users_cof'].exclude(username__in=usernames).distinct()
|
queries['users_cof'].exclude(username__in=usernames).distinct()
|
||||||
queries['users_notcof'] = \
|
queries['users_notcof'] = \
|
||||||
queries['users_notcof'].exclude(username__in=usernames).distinct()
|
queries['users_notcof'].exclude(username__in=usernames).distinct()
|
||||||
|
usernames |= set(
|
||||||
usernames += list( \
|
|
||||||
queries['users_cof'].values_list('username', flat=True))
|
queries['users_cof'].values_list('username', flat=True))
|
||||||
usernames += list( \
|
usernames |= set(
|
||||||
queries['users_notcof'].values_list('username', flat=True))
|
queries['users_notcof'].values_list('username', flat=True))
|
||||||
|
|
||||||
queries['clippers'] = \
|
# Fetching data from the SPI
|
||||||
queries['clippers'].exclude(username__in=usernames).distinct()
|
if hasattr(settings, 'LDAP_SERVER_URL'):
|
||||||
|
# Fetching
|
||||||
|
ldap_query = '(|{:s})'.format(''.join(
|
||||||
|
['(cn=*{bit:s}*)(uid=*{bit:s}*)'.format(**{"bit": bit})
|
||||||
|
for bit in search_words]
|
||||||
|
))
|
||||||
|
with Connection(settings.LDAP_SERVER_URL) as conn:
|
||||||
|
conn.search(
|
||||||
|
'dc=spi,dc=ens,dc=fr', ldap_query,
|
||||||
|
attributes=['uid', 'cn']
|
||||||
|
)
|
||||||
|
queries['clippers'] = conn.entries
|
||||||
|
# Clearing redundancies
|
||||||
|
queries['clippers'] = [
|
||||||
|
Clipper(clipper.uid, clipper.cn)
|
||||||
|
for clipper in queries['clippers']
|
||||||
|
if str(clipper.uid) not in usernames
|
||||||
|
]
|
||||||
|
|
||||||
|
# Resulting data
|
||||||
data.update(queries)
|
data.update(queries)
|
||||||
|
data['options'] = sum([len(query) for query in queries])
|
||||||
options = 0
|
|
||||||
for query in queries.values():
|
|
||||||
options += len(query)
|
|
||||||
data['options'] = options
|
|
||||||
|
|
||||||
return render(request, "kfet/account_create_autocomplete.html", data)
|
return render(request, "kfet/account_create_autocomplete.html", data)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,98 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"model": "auth.group",
|
|
||||||
"pk": 1,
|
|
||||||
"fields": {
|
|
||||||
"name": "K-F\u00eat chef",
|
|
||||||
"permissions": [
|
|
||||||
115,
|
|
||||||
116,
|
|
||||||
117,
|
|
||||||
118,
|
|
||||||
119,
|
|
||||||
120,
|
|
||||||
133,
|
|
||||||
134,
|
|
||||||
135,
|
|
||||||
130,
|
|
||||||
131,
|
|
||||||
132,
|
|
||||||
136,
|
|
||||||
137,
|
|
||||||
138,
|
|
||||||
121,
|
|
||||||
122,
|
|
||||||
123,
|
|
||||||
127,
|
|
||||||
128,
|
|
||||||
129,
|
|
||||||
124,
|
|
||||||
125,
|
|
||||||
126,
|
|
||||||
188,
|
|
||||||
189,
|
|
||||||
190,
|
|
||||||
169,
|
|
||||||
176,
|
|
||||||
183,
|
|
||||||
170,
|
|
||||||
171,
|
|
||||||
182,
|
|
||||||
172,
|
|
||||||
178,
|
|
||||||
177,
|
|
||||||
181,
|
|
||||||
175,
|
|
||||||
179,
|
|
||||||
173,
|
|
||||||
174,
|
|
||||||
184,
|
|
||||||
180,
|
|
||||||
139,
|
|
||||||
140,
|
|
||||||
141,
|
|
||||||
142,
|
|
||||||
143,
|
|
||||||
144,
|
|
||||||
166,
|
|
||||||
167,
|
|
||||||
168,
|
|
||||||
163,
|
|
||||||
164,
|
|
||||||
165,
|
|
||||||
151,
|
|
||||||
152,
|
|
||||||
153,
|
|
||||||
154,
|
|
||||||
155,
|
|
||||||
156,
|
|
||||||
185,
|
|
||||||
186,
|
|
||||||
187,
|
|
||||||
145,
|
|
||||||
146,
|
|
||||||
147,
|
|
||||||
148,
|
|
||||||
149,
|
|
||||||
150,
|
|
||||||
160,
|
|
||||||
161,
|
|
||||||
162,
|
|
||||||
157,
|
|
||||||
158,
|
|
||||||
159
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"model": "auth.group",
|
|
||||||
"pk": 2,
|
|
||||||
"fields": {
|
|
||||||
"name": "K-F\u00eat girl",
|
|
||||||
"permissions": [
|
|
||||||
172,
|
|
||||||
173
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
170
kfet/management/commands/loadkfetdevdata.py
Normal file
170
kfet/management/commands/loadkfetdevdata.py
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
"""
|
||||||
|
Crée des utilisateurs, des articles et des opérations aléatoires
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
from datetime import timedelta
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.contrib.auth.models import User, Group, Permission, ContentType
|
||||||
|
|
||||||
|
from cof.management.base import MyBaseCommand
|
||||||
|
from gestion.models import Profile
|
||||||
|
from kfet.models import Account, Article, OperationGroup, Operation, Checkout
|
||||||
|
|
||||||
|
# Où sont stockés les fichiers json
|
||||||
|
DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)),
|
||||||
|
'data')
|
||||||
|
|
||||||
|
|
||||||
|
class Command(MyBaseCommand):
|
||||||
|
help = "Crée des utilisateurs, des articles et des opérations aléatoires"
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
# ---
|
||||||
|
# Groupes
|
||||||
|
# ---
|
||||||
|
|
||||||
|
Group.objects.filter(name__icontains='K-Fêt').delete()
|
||||||
|
|
||||||
|
group_chef = Group(name="K-Fêt César")
|
||||||
|
group_boy = Group(name="K-Fêt Légionnaire")
|
||||||
|
|
||||||
|
group_chef.save()
|
||||||
|
group_boy.save()
|
||||||
|
|
||||||
|
permissions_chef = Permission.objects.filter(
|
||||||
|
content_type__in=ContentType.objects.filter(
|
||||||
|
app_label='kfet'))
|
||||||
|
permissions_boy = Permission.objects.filter(
|
||||||
|
codename__in=['is_team', 'perform_deposit'])
|
||||||
|
|
||||||
|
group_chef.permissions.add(*permissions_chef)
|
||||||
|
group_boy.permissions.add(*permissions_boy)
|
||||||
|
|
||||||
|
# ---
|
||||||
|
# Comptes
|
||||||
|
# ---
|
||||||
|
|
||||||
|
self.stdout.write("Création des comptes K-Fêt")
|
||||||
|
|
||||||
|
gaulois = Profile.objects.filter(user__last_name='Gaulois')
|
||||||
|
gaulois_trigramme = map('{:03d}'.format, range(50))
|
||||||
|
|
||||||
|
romains = Profile.objects.filter(user__last_name='Romain')
|
||||||
|
romains_trigramme = map(lambda x: str(100+x), range(99))
|
||||||
|
|
||||||
|
created_accounts = 0
|
||||||
|
team_accounts = 0
|
||||||
|
|
||||||
|
for (profile, trigramme) in zip(gaulois, gaulois_trigramme):
|
||||||
|
account, created = Account.objects.get_or_create(
|
||||||
|
trigramme=trigramme,
|
||||||
|
profile=profile,
|
||||||
|
defaults={'balance': random.randint(1, 999)/10}
|
||||||
|
)
|
||||||
|
created_accounts += int(created)
|
||||||
|
|
||||||
|
if profile.user.first_name == 'Abraracourcix':
|
||||||
|
profile.user.groups.add(group_chef)
|
||||||
|
|
||||||
|
for (profile, trigramme) in zip(romains, romains_trigramme):
|
||||||
|
account, created = Account.objects.get_or_create(
|
||||||
|
trigramme=trigramme,
|
||||||
|
profile=profile,
|
||||||
|
defaults={'balance': random.randint(1, 999)/10}
|
||||||
|
)
|
||||||
|
created_accounts += int(created)
|
||||||
|
|
||||||
|
if random.random() > 0.75 and created:
|
||||||
|
profile.user.groups.add(group_boy)
|
||||||
|
team_accounts += 1
|
||||||
|
|
||||||
|
self.stdout.write("- {:d} comptes créés, {:d} dans l'équipe K-Fêt"
|
||||||
|
.format(created_accounts, team_accounts))
|
||||||
|
|
||||||
|
# Compte liquide
|
||||||
|
|
||||||
|
liq_user, _ = User.objects.get_or_create(username='liquide')
|
||||||
|
liq_profile, _ = Profile.objects.get_or_create(user=liq_user)
|
||||||
|
liq_account, _ = Account.objects.get_or_create(profile=liq_profile,
|
||||||
|
trigramme='LIQ')
|
||||||
|
|
||||||
|
# ---
|
||||||
|
# Caisse
|
||||||
|
# ---
|
||||||
|
|
||||||
|
checkout, _ = Checkout.objects.get_or_create(
|
||||||
|
created_by=Account.objects.get(trigramme='000'),
|
||||||
|
name='Chaudron',
|
||||||
|
valid_from=timezone.now(),
|
||||||
|
valid_to=timezone.now() + timedelta(days=365)
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---
|
||||||
|
# Opérations
|
||||||
|
# ---
|
||||||
|
|
||||||
|
self.stdout.write("Génération d'opérations")
|
||||||
|
|
||||||
|
articles = Article.objects.all()
|
||||||
|
accounts = Account.objects.exclude(trigramme='LIQ')
|
||||||
|
|
||||||
|
num_op = 100
|
||||||
|
# Operations are put uniformly over the span of a week
|
||||||
|
past_date = 3600*24*7
|
||||||
|
|
||||||
|
for i in range(num_op):
|
||||||
|
if random.random() > 0.25:
|
||||||
|
account = random.choice(accounts)
|
||||||
|
else:
|
||||||
|
account = liq_account
|
||||||
|
|
||||||
|
amount = Decimal('0')
|
||||||
|
at = timezone.now() - timedelta(
|
||||||
|
seconds=random.randint(0, past_date))
|
||||||
|
|
||||||
|
opegroup = OperationGroup(
|
||||||
|
on_acc=account,
|
||||||
|
checkout=checkout,
|
||||||
|
at=at,
|
||||||
|
is_cof=False
|
||||||
|
)
|
||||||
|
if hasattr(account.profile, "cof"):
|
||||||
|
opegroup.is_cof = account.profile.cof.is_cof
|
||||||
|
opegroup.save()
|
||||||
|
opegroup.save()
|
||||||
|
|
||||||
|
for j in range(random.randint(1, 4)):
|
||||||
|
typevar = random.random()
|
||||||
|
if typevar > 0.9 and account != liq_account:
|
||||||
|
ope = Operation(
|
||||||
|
group=opegroup,
|
||||||
|
type=Operation.DEPOSIT,
|
||||||
|
amount=Decimal(random.randint(1, 99)/10,)
|
||||||
|
)
|
||||||
|
elif typevar > 0.8 and account != liq_account:
|
||||||
|
ope = Operation(
|
||||||
|
group=opegroup,
|
||||||
|
type=Operation.WITHDRAW,
|
||||||
|
amount=-Decimal(random.randint(1, 99)/10,)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
article = random.choice(articles)
|
||||||
|
nb = random.randint(1, 5)
|
||||||
|
|
||||||
|
ope = Operation(
|
||||||
|
group=opegroup,
|
||||||
|
type=Operation.PURCHASE,
|
||||||
|
amount=-article.price*nb,
|
||||||
|
article=article,
|
||||||
|
article_nb=nb
|
||||||
|
)
|
||||||
|
|
||||||
|
ope.save()
|
||||||
|
amount += ope.amount
|
||||||
|
|
||||||
|
opegroup.amount = amount
|
||||||
|
opegroup.save()
|
|
@ -36,7 +36,7 @@
|
||||||
<li class="user_category"><span class="text">Utilisateurs clipper</span></li>
|
<li class="user_category"><span class="text">Utilisateurs clipper</span></li>
|
||||||
{% for clipper in clippers %}
|
{% for clipper in clippers %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url "kfet.account.create.fromclipper" clipper.username %}">
|
<a href="{% url "kfet.account.create.fromclipper" clipper.clipper clipper.fullname%}">
|
||||||
{{ clipper|highlight_clipper:q }}
|
{{ clipper|highlight_clipper:q }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -35,7 +35,8 @@ urlpatterns = [
|
||||||
name = 'kfet.account.create_special'),
|
name = 'kfet.account.create_special'),
|
||||||
url(r'^accounts/new/user/(?P<username>.+)$', views.account_create_ajax,
|
url(r'^accounts/new/user/(?P<username>.+)$', views.account_create_ajax,
|
||||||
name = 'kfet.account.create.fromuser'),
|
name = 'kfet.account.create.fromuser'),
|
||||||
url(r'^accounts/new/clipper/(?P<login_clipper>.+)$', views.account_create_ajax,
|
url(r'^accounts/new/clipper/(?P<login_clipper>[\w-]+)/(?P<fullname>.*)$',
|
||||||
|
views.account_create_ajax,
|
||||||
name = 'kfet.account.create.fromclipper'),
|
name = 'kfet.account.create.fromclipper'),
|
||||||
url(r'^accounts/new/empty$', views.account_create_ajax,
|
url(r'^accounts/new/empty$', views.account_create_ajax,
|
||||||
name = 'kfet.account.create.empty'),
|
name = 'kfet.account.create.empty'),
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import (absolute_import, division,
|
|
||||||
print_function, unicode_literals)
|
|
||||||
from builtins import *
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import hashlib
|
import hashlib
|
||||||
|
@ -10,29 +7,30 @@ import heapq
|
||||||
import statistics
|
import statistics
|
||||||
|
|
||||||
from django.shortcuts import render, get_object_or_404, redirect
|
from django.shortcuts import render, get_object_or_404, redirect
|
||||||
from django.core.exceptions import PermissionDenied, ValidationError
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.views.generic import ListView, DetailView
|
from django.views.generic import ListView, DetailView
|
||||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView
|
from django.views.generic.edit import CreateView, UpdateView
|
||||||
from django.core.urlresolvers import reverse_lazy
|
from django.core.urlresolvers import reverse_lazy
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.contrib.auth import authenticate, login
|
from django.contrib.auth import authenticate, login
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.contrib.auth.models import User, Permission, Group
|
from django.contrib.auth.models import User, Permission, Group
|
||||||
from django.http import HttpResponse, JsonResponse, Http404
|
from django.http import JsonResponse, Http404
|
||||||
from django.forms import modelformset_factory, formset_factory
|
from django.forms import formset_factory
|
||||||
from django.db import IntegrityError, transaction
|
from django.db import transaction
|
||||||
from django.db.models import F, Sum, Prefetch, Count, Func
|
from django.db.models import F, Sum, Prefetch, Count
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.crypto import get_random_string
|
from django.utils.crypto import get_random_string
|
||||||
from gestion.models import Profile
|
from gestion.models import Profile
|
||||||
from cof.models import Clipper
|
|
||||||
from kfet.decorators import teamkfet_required
|
from kfet.decorators import teamkfet_required
|
||||||
from kfet.models import (Account, Checkout, Article, Settings, AccountNegative,
|
from kfet.models import (
|
||||||
CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory,
|
Account, Checkout, Article, Settings, AccountNegative, CheckoutStatement,
|
||||||
InventoryArticle, Order, OrderArticle)
|
GenericTeamToken, Supplier, SupplierArticle, Inventory, InventoryArticle,
|
||||||
|
Order, OrderArticle
|
||||||
|
)
|
||||||
from kfet.forms import *
|
from kfet.forms import *
|
||||||
from kfet import consumers
|
from kfet import consumers
|
||||||
import django_cas_ng
|
import django_cas_ng
|
||||||
|
@ -223,19 +221,20 @@ def account_form_set_readonly_fields(user_form, cof_form):
|
||||||
cof_form.fields['login_clipper'].widget.attrs['readonly'] = True
|
cof_form.fields['login_clipper'].widget.attrs['readonly'] = True
|
||||||
cof_form.fields['is_cof'].widget.attrs['disabled'] = True
|
cof_form.fields['is_cof'].widget.attrs['disabled'] = True
|
||||||
|
|
||||||
def get_account_create_forms(request=None, username=None, login_clipper=None):
|
def get_account_create_forms(request=None, username=None, login_clipper=None,
|
||||||
|
fullname=None):
|
||||||
user = None
|
user = None
|
||||||
clipper = None
|
clipper = False
|
||||||
if login_clipper and (login_clipper == username or not username):
|
if login_clipper and (login_clipper == username or not username):
|
||||||
# à partir d'un clipper
|
# à partir d'un clipper
|
||||||
# le user associé à ce clipper ne devrait pas encore exister
|
# le user associé à ce clipper ne devrait pas encore exister
|
||||||
clipper = get_object_or_404(Clipper, username = login_clipper)
|
clipper = True
|
||||||
try:
|
try:
|
||||||
# Vérification que clipper ne soit pas déjà dans User
|
# Vérification que clipper ne soit pas déjà dans User
|
||||||
user = User.objects.get(username=login_clipper)
|
user = User.objects.get(username=login_clipper)
|
||||||
# Ici, on nous a menti, le user existe déjà
|
# Ici, on nous a menti, le user existe déjà
|
||||||
username = user.username
|
username = user.username
|
||||||
clipper = None
|
clipper = False
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
# Clipper (sans user déjà existant)
|
# Clipper (sans user déjà existant)
|
||||||
|
|
||||||
|
@ -243,9 +242,9 @@ def get_account_create_forms(request=None, username=None, login_clipper=None):
|
||||||
user_initial = {
|
user_initial = {
|
||||||
'username' : login_clipper,
|
'username' : login_clipper,
|
||||||
'email' : "%s@clipper.ens.fr" % login_clipper}
|
'email' : "%s@clipper.ens.fr" % login_clipper}
|
||||||
if clipper.fullname:
|
if fullname:
|
||||||
# Prefill du nom et prénom
|
# Prefill du nom et prénom
|
||||||
names = clipper.fullname.split()
|
names = fullname.split()
|
||||||
# Le premier, c'est le prénom
|
# Le premier, c'est le prénom
|
||||||
user_initial['first_name'] = names[0]
|
user_initial['first_name'] = names[0]
|
||||||
if len(names) > 1:
|
if len(names) > 1:
|
||||||
|
@ -309,8 +308,11 @@ def get_account_create_forms(request=None, username=None, login_clipper=None):
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@teamkfet_required
|
@teamkfet_required
|
||||||
def account_create_ajax(request, username=None, login_clipper=None):
|
def account_create_ajax(request, username=None, login_clipper=None,
|
||||||
forms = get_account_create_forms(request=None, username=username, login_clipper=login_clipper)
|
fullname=None):
|
||||||
|
forms = get_account_create_forms(
|
||||||
|
request=None, username=username, login_clipper=login_clipper,
|
||||||
|
fullname=fullname)
|
||||||
return render(request, "kfet/account_create_form.html", {
|
return render(request, "kfet/account_create_form.html", {
|
||||||
'account_form' : forms['account_form'],
|
'account_form' : forms['account_form'],
|
||||||
'cof_form' : forms['cof_form'],
|
'cof_form' : forms['cof_form'],
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
source ~/venv/bin/activate
|
source ~/venv/bin/activate
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
python manage.py loaddata gestion sites
|
python manage.py loaddata gestion sites articles
|
||||||
python manage.py loaddevdata
|
python manage.py loaddevdata
|
||||||
|
python manage.py syncmails
|
||||||
python manage.py collectstatic --noinput
|
python manage.py collectstatic --noinput
|
||||||
|
|
|
@ -17,4 +17,6 @@ asgi-redis==0.14.0
|
||||||
statistics==1.0.3.5
|
statistics==1.0.3.5
|
||||||
future==0.15.2
|
future==0.15.2
|
||||||
django-widget-tweaks==1.4.1
|
django-widget-tweaks==1.4.1
|
||||||
|
git+https://git.eleves.ens.fr/cof-geek/django_custommail.git#egg=django_custommail
|
||||||
|
ldap3
|
||||||
git+https://github.com/Aureplop/channels.git#egg=channels
|
git+https://github.com/Aureplop/channels.git#egg=channels
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gestioCOF.settings")
|
|
||||||
|
|
||||||
from cof.models import Clipper
|
|
||||||
current = {}
|
|
||||||
print("[ FETCHING ]")
|
|
||||||
for clipper in Clipper.objects.all():
|
|
||||||
current[clipper.username] = clipper
|
|
||||||
print("[ SYNCING ]")
|
|
||||||
for line in sys.stdin:
|
|
||||||
bits = line.split(":")
|
|
||||||
username = bits[0]
|
|
||||||
fullname = bits[4]
|
|
||||||
if username in current:
|
|
||||||
clipper = current[username]
|
|
||||||
if clipper.fullname != fullname:
|
|
||||||
clipper.fullname = fullname
|
|
||||||
clipper.save()
|
|
||||||
print("Updated", username)
|
|
||||||
else:
|
|
||||||
clipper = Clipper(username=username, fullname=fullname)
|
|
||||||
clipper.save()
|
|
||||||
print("Created", username)
|
|
||||||
print("[ DONE ]")
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
ssh cof@sas.eleves.ens.fr ypcat passwd | python sync_clipper.py
|
|
Loading…
Reference in a new issue