diff --git a/.gitignore b/.gitignore index c7daa30..9c92758 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,3 @@ /.idea /._bootstrapTemplates /env -/venv -/bower_components \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index dbecb74..0000000 --- a/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# docker build -t "blechreiz_website" . -FROM ubuntu:20.04 - - -RUN apt-get update \ - && apt-get install -y python3 python3-venv python3-wheel \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -ADD . /blechreiz -ENV BLECHREIZ_DATA /data -ENV PYTHONUNBUFFERED 1 -ENV PYTHONPATH /blechreiz - -RUN cd /blechreiz \ - && python3 -m venv env \ - && . /blechreiz/env/bin/activate \ - && rm -r /blechreiz/blechreiz/data \ - && /blechreiz/env/bin/pip install -r requirements.txt - -EXPOSE 8000 - -CMD /blechreiz/env/bin/python3 /blechreiz/manage.py collectstatic --noinput \ - && /blechreiz/env/bin/gunicorn -b 0.0.0.0:8000 blechreiz.wsgi diff --git a/blechreiz/data/calendarCredentials.dat b/blechreiz/data/calendarCredentials.dat deleted file mode 100644 index 88aead4..0000000 --- a/blechreiz/data/calendarCredentials.dat +++ /dev/null @@ -1 +0,0 @@ -{"_module": "oauth2client.client", "token_expiry": "2018-12-18T12:55:20Z", "access_token": "ya29.Gl12BuJlFBtRZSBtMkxubhfG8rYDsLUgc1yKMpO9_aE3tmi4sLFGLq_Djq5R9zr1919oZAobX0oaD6bTj3s4i9kqWfw0gpOGKJKRHM1Y9gHc0JsCe2kChNszu_RCAaE", "token_uri": "https://accounts.google.com/o/oauth2/token", "invalid": false, "token_response": {"access_token": "ya29.Gl12BuJlFBtRZSBtMkxubhfG8rYDsLUgc1yKMpO9_aE3tmi4sLFGLq_Djq5R9zr1919oZAobX0oaD6bTj3s4i9kqWfw0gpOGKJKRHM1Y9gHc0JsCe2kChNszu_RCAaE", "scope": "https://www.googleapis.com/auth/calendar", "expires_in": 3600, "token_type": "Bearer"}, "client_id": "34462582242-4kpdvvbi27ajt4u22uitqurpve9o8ipj.apps.googleusercontent.com", "id_token": null, "client_secret": "y4t9XBrJdCODPTO5UvtONWWn", "revoke_uri": "https://accounts.google.com/o/oauth2/revoke", "_class": "OAuth2Credentials", "refresh_token": "1/txixroRJyyVmuENPpaXyB_bGeXa1XV-pClAxqKHk_5-JW1qGFE0Gl-WlgCu1Eizq", "user_agent": null} \ No newline at end of file diff --git a/blechreiz/data/database.sqlite b/blechreiz/data/database.sqlite deleted file mode 100644 index a676d1f..0000000 Binary files a/blechreiz/data/database.sqlite and /dev/null differ diff --git a/blechreiz/middleware.py b/blechreiz/middleware.py index 7009648..f97648e 100644 --- a/blechreiz/middleware.py +++ b/blechreiz/middleware.py @@ -1,37 +1,41 @@ -from django.http import HttpResponseRedirect -from django.conf import settings import re +from django.conf import settings +from django.http import HttpResponseRedirect + class EnforceLoginMiddleware: """ - Middlware class which requires the user to be authenticated for all urls except - those defined in PUBLIC_URLS in settings.py. PUBLIC_URLS should be a tuple of regular - expresssions for the urls you want anonymous users to have access to. If PUBLIC_URLS - is not defined, it falls back to LOGIN_URL or failing that '/accounts/login/'. - Requests for urls not matching PUBLIC_URLS get redirected to LOGIN_URL with next set - to original path of the unauthenticted request. + Middleware class which requires the user to be authenticated for all urls except + those defined in PUBLIC_URLS in settings.py. PUBLIC_URLS should be a tuple of regular + expressions for the urls you want anonymous users to have access to. If PUBLIC_URLS + is not defined, it falls back to LOGIN_URL or failing that '/accounts/login/'. + Requests for urls not matching PUBLIC_URLS get redirected to LOGIN_URL with next set + to original path of the unauthenticated request. Any urls statically served by django are excluded from this check. To enforce the same validation on these set SERVE_STATIC_TO_PUBLIC to False. """ def __init__(self, get_response): - self.login_url = getattr(settings, 'LOGIN_URL', '/accounts/login/') self.get_response = get_response + self.login_url = getattr(settings, "LOGIN_URL", "/accounts/login/") - if hasattr(settings, 'PUBLIC_URLS'): + if hasattr(settings, "PUBLIC_URLS"): public_urls = [re.compile(url) for url in settings.PUBLIC_URLS] else: - public_urls = [(re.compile("^%s/?$" % (self.login_url[1:])))] - if getattr(settings, 'SERVE_STATIC_TO_PUBLIC', True): - root_urlconf = __import__(settings.ROOT_URLCONF) - public_urls.extend([re.compile(url.regex) - for url in root_urlconf.urls.urlpatterns - if url.__dict__.get('_callback_str') == 'django.views.static.serve' - ]) + public_urls = [re.compile("^%s/?$" % (self.login_url[1:]))] + self.public_urls = tuple(public_urls) def __call__(self, request): + # Check if user needs to be redirected to login + redirect_response = self.check_login(request) + if redirect_response: + return redirect_response + + return self.get_response(request) + + def check_login(self, request): """ Redirect anonymous users to login_url from non public urls """ @@ -40,52 +44,63 @@ class EnforceLoginMiddleware: for url in self.public_urls: if url.match(request.path[1:]): return None - return HttpResponseRedirect("%s?next=%s" % (self.login_url, request.path)) + return HttpResponseRedirect( + "%s?next=%s" % (self.login_url, request.path) + ) except AttributeError: return HttpResponseRedirect("%s?next=%s" % (self.login_url, request.path)) - - return self.get_response(request) + return None class DetectDevice: + """ + Middleware to detect the device type from user agent string. + """ def __init__(self, get_response): self.get_response = get_response def __call__(self, request): - device = self.mobile(request) + request.device = self.detect_device(request) + return self.get_response(request) - request.device = device - response = self.get_response(request) - return response - - def mobile(self, request): + def detect_device(self, request): device = {} - ua = request.META.get('HTTP_USER_AGENT', '').lower() + ua = request.META.get("HTTP_USER_AGENT", "").lower() - if ua.find("iphone") > 0: - device['iphone'] = "iphone" + re.search("iphone os (\d)", ua).groups(0)[0] + if "iphone" in ua: + match = re.search(r"iphone os (\d)", ua) + if match: + device["iphone"] = "iphone" + match.group(1) + else: + device["iphone"] = "iphone" - if ua.find("ipad") > 0: - device['ipad'] = "ipad" + if "ipad" in ua: + device["ipad"] = "ipad" - if ua.find("android") > 0: - device['android'] = "android" + re.search("android (\d\.\d)", ua).groups(0)[0].translate(None, '.') + if "android" in ua: + match = re.search(r"android (\d\.\d)", ua) + if match: + version = match.group(1).replace(".", "") + device["android"] = "android" + version + else: + device["android"] = "android" - if ua.find("blackberry") > 0: - device['blackberry'] = "blackberry" + if "blackberry" in ua: + device["blackberry"] = "blackberry" - if ua.find("windows phone os 7") > 0: - device['winphone7'] = "winphone7" + if "windows phone os 7" in ua: + device["winphone7"] = "winphone7" - if ua.find("iemobile") > 0: - device['winmo'] = "winmo" + if "iemobile" in ua: + device["winmo"] = "winmo" - if not device: # either desktop, or something we don't care about. - device['baseline'] = "baseline" + if not device: + # either desktop, or something we don't care about. + device["baseline"] = "baseline" # spits out device names for CSS targeting, to be applied to or . - device['classes'] = " ".join(v for (k, v) in device.items()) + device["classes"] = " ".join(v for (k, v) in device.items()) return device diff --git a/blechreiz/settings.py b/blechreiz/settings.py index b887f5f..b7dc72a 100644 --- a/blechreiz/settings.py +++ b/blechreiz/settings.py @@ -1,233 +1,205 @@ # Setting the path import os +from pathlib import Path -gettext = lambda s: s +BASE_DIR = Path(__file__).resolve().parent PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) -DATA_PATH = os.environ.get('BLECHREIZ_DATA', default=os.path.join(PROJECT_PATH, "data")) # Django settings for blechreiz project. DEBUG = True -TEMPLATE_DEBUG = DEBUG -ADMINS = ( - ('Martin Bauer', 'bauer_martin@gmx.de'), -) +ADMINS = [ + ("Martin Bauer", "bauer_martin@gmx.de"), +] MANAGERS = ADMINS + DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(DATA_PATH, 'database.sqlite'), + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": os.path.join(PROJECT_PATH, "database.sqlite"), } } +# Default primary key field type +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + # Email -EMAIL_HOST = 'smtp.blechreiz.com' -EMAIL_HOST_USER = 'm02b721a' -EMAIL_HOST_PASSWORD = '9Hp4WG5bZ2WVPX5z' +EMAIL_HOST = "smtp.blechreiz.com" +EMAIL_HOST_USER = "m02b721a" +EMAIL_HOST_PASSWORD = "9Hp4WG5bZ2WVPX5z" EMAIL_USE_TLS = False + # Hosts/domain names that are valid for this site; required if DEBUG is False -# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ["localhost", "127.0.0.1", ".blechreiz.com", ".bauer.technology"] -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# In a Windows environment this must be set to your system time zone. -TIME_ZONE = 'Europe/Berlin' +# Local time zone for this installation. +TIME_ZONE = "Europe/Berlin" -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'de' +# Language code for this installation. +LANGUAGE_CODE = "de" SITE_ID = 1 -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. +# Internationalization USE_I18N = True - -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale. USE_L10N = True - -# If you set this to False, Django will not use timezone-aware datetimes. USE_TZ = True # Absolute filesystem path to the directory that will hold user-uploaded files. -# Example: "/var/www/example.com/media/" -MEDIA_ROOT = PROJECT_PATH + "/media" +MEDIA_ROOT = PROJECT_PATH + "/media/" -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash. -# Examples: "http://example.com/media/", "http://media.example.com/" -MEDIA_URL = '/media/' +# URL that handles the media served from MEDIA_ROOT. +MEDIA_URL = "/media/" # Absolute path to the directory static files should be collected to. -# Don't put anything in this directory yourself; store your static files -# in apps' "static/" subdirectories and in STATICFILES_DIRS. -# Example: "/var/www/example.com/static/" -STATIC_ROOT = PROJECT_PATH + '/static_collection' +STATIC_ROOT = PROJECT_PATH + "/static_collection" # URL prefix for static files. -# Example: "http://example.com/static/", "http://static.example.com/" -STATIC_URL = '/static/' +STATIC_URL = "/static/" LOGIN_URL = "/musicians/login" -PUBLIC_URLS = ("^musicians/login/?$", "^musicians/login/usernames/?$", "^eventplanner_gcal/gcalApiCallback*") +PUBLIC_URLS = ( + "^musicians/login/?$", + "^musicians/login/usernames/?$", + "^eventplanner_gcal/gcalApiCallback*", +) # Additional locations of static files -STATICFILES_DIRS = ( - #PROJECT_PATH + '/static', - # Put strings here, like "/home/html/static" or "C:/www/django/static". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) +STATICFILES_DIRS = [ + PROJECT_PATH + "/static", +] -# List of finder classes that know how to find static files in -# various locations. -STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - # 'django.contrib.staticfiles.finders.DefaultStorageFinder', -) +# List of finder classes that know how to find static files in various locations. +STATICFILES_FINDERS = [ + "django.contrib.staticfiles.finders.FileSystemFinder", + "django.contrib.staticfiles.finders.AppDirectoriesFinder", +] # Make this unique, and don't share it with anybody. -SECRET_KEY = 'x$8&9s6t%eeg=wyhar87934wh_s$dbpm(73g4ho&n)9_wogj6p' +SECRET_KEY = "x$8&9s6t%eeg=wyhar87934wh_s$dbpm(73g4ho&n)9_wogj6p" + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "blechreiz.middleware.EnforceLoginMiddleware", + "blechreiz.middleware.DetectDevice", +] + +ROOT_URLCONF = "blechreiz.urls" + +# Python dotted path to the WSGI application used by Django's runserver. +WSGI_APPLICATION = "blechreiz.wsgi.application" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - PROJECT_PATH + '/templates', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [ + PROJECT_PATH + "/templates", ], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - # Insert your TEMPLATE_CONTEXT_PROCESSORS here or use this - # list if you haven't customized them: - 'django.contrib.auth.context_processors.auth', - 'django.template.context_processors.i18n', - 'django.template.context_processors.request', - 'django.template.context_processors.media', - 'django.template.context_processors.static', - 'sekizai.context_processors.sekizai', + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "django.template.context_processors.i18n", + "django.template.context_processors.media", + "django.template.context_processors.static", + "sekizai.context_processors.sekizai", ], }, }, ] -MIDDLEWARE = ( - 'django.middleware.security.SecurityMiddleware', - 'whitenoise.middleware.WhiteNoiseMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - #'blechreiz.middleware.EnforceLoginMiddleware', - 'blechreiz.middleware.DetectDevice', - # Uncomment the next line for simple clickjacking protection: - # 'django.middleware.clickjacking.XFrameOptionsMiddleware', -) -ROOT_URLCONF = 'blechreiz.urls' - -# Python dotted path to the WSGI application used by Django's runserver. -WSGI_APPLICATION = 'blechreiz.wsgi.application' - - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'django.contrib.admin', - 'django.contrib.admindocs', - 'crispy_forms', # better looking forms ( bootstrap ) - 'sekizai', # for the addtoblock directive in templates - 'rest_framework', # for event management api - - # Own Things - 'bootstrapTheme', # Theme - 'website', # Blechreiz Website in general - 'musicians', # User Management - 'eventplanner', # Event Management - 'eventplanner_gcal', # Event Management Sync with Google Calendar - 'simpleforum', # Messages ( Forum ) - 'location_field', # custom location field used in Event Management - 'scoremanager', # manager of scores, repertoire etc. - # 'imagestore', - # 'sorl.thumbnail', - # 'tagging' -) +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.sites", + "django.contrib.messages", + "django.contrib.staticfiles", + # Third-party apps + "crispy_forms", + "crispy_bootstrap5", + "sekizai", + "rest_framework", + # Own apps + "bootstrapTheme", + "website", + "musicians", + "eventplanner", + "eventplanner_gcal", + "simpleforum", + "location_field", + "scoremanager", + # 'imagestore', # Disabled +] IMAGESTORE_TEMPLATE = "website/base.html" + REST_FRAMEWORK = { - 'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',), - 'PAGINATE_BY': 10 + "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"], + "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination", + "PAGE_SIZE": 10, } + GCAL_COUPLING = { - 'eventPrefix': 'Blechreiz: ', - 'developerKey': 'blechreiz-homepage', - 'clientId': '34462582242-4kpdvvbi27ajt4u22uitqurpve9o8ipj.apps.googleusercontent.com', - 'client_secret': 'y4t9XBrJdCODPTO5UvtONWWn', - 'credentials_file': DATA_PATH + '/calendarCredentials.dat', - 'push_url': "https://blechreiz.bauer.technology/eventplanner_gcal/gcalApiCallback", + "eventPrefix": "Blechreiz: ", + "developerKey": "blechreiz-homepage", + "clientId": "34462582242-4kpdvvbi27ajt4u22uitqurpve9o8ipj.apps.googleusercontent.com", + "client_secret": "y4t9XBrJdCODPTO5UvtONWWn", + "credentials_file": PROJECT_PATH + "/calendarCredentials.dat", + "push_url": "https://blechreiz.bauer.technology/eventplanner_gcal/gcalApiCallback", } -GOOGLE_MAPS_API_KEY = 'AIzaSyCf9Lm5ckjmVd08scTOd7fB1dC_UCoumKg' -GCAL_SYNC_ENABLED = True -CRISPY_TEMPLATE_PACK = 'bootstrap' +# Crispy Forms configuration +CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" +CRISPY_TEMPLATE_PACK = "bootstrap5" -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. -# See http://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. +# Logging configuration LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'formatters': { - 'verbose': { - 'format': '{levelname} {asctime} {module} {message}', - 'style': '{', + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "file": { + "level": "DEBUG", + "class": "logging.FileHandler", + "filename": PROJECT_PATH + "/eventplanner.log", }, - 'simple': { - 'format': '{levelname} {asctime} {message}', - 'style': '{', + "console": { + "level": "DEBUG", + "class": "logging.StreamHandler", }, }, - 'handlers': { - 'file': { - 'level': 'DEBUG', - 'class': 'logging.FileHandler', - 'filename': DATA_PATH + '/eventplanner.log', + "loggers": { + "eventplanner_gcal": { + "handlers": ["file", "console"], + "level": "DEBUG", + "propagate": True, + }, + "eventplanner": { + "handlers": ["file", "console"], + "level": "DEBUG", + "propagate": True, }, }, - 'loggers': { - 'eventplanner_gcal': { - 'handlers': ['file'], - 'level': 'DEBUG', - 'propagate': True, - }, - 'eventplanner': { - 'handler': ['file'], - 'level': 'DEBUG', - 'propagate': True, - } - }, - } - diff --git a/blechreiz/urls.py b/blechreiz/urls.py index afc906e..734d353 100644 --- a/blechreiz/urls.py +++ b/blechreiz/urls.py @@ -1,28 +1,21 @@ -from django.conf.urls import include, url - -from django.contrib import admin - -import simpleforum.views - -import eventplanner.urls -import musicians.urls -import website.urls -import scoremanager.urls -import eventplanner_gcal.urls - -from . import settings +from django.conf import settings from django.conf.urls.static import static +from django.contrib import admin +from django.urls import include, path, re_path -admin.autodiscover() +from simpleforum import views as simpleforum_views urlpatterns = [ - url(r'^', include(website.urls)), - url(r'^events/', include(eventplanner.urls.urlpatterns)), - url(r'^musicians/', include(musicians.urls.urlpatterns)), - url(r'^scores/', include(scoremanager.urls.urlpatterns)), - url(r'^messages/$', simpleforum.views.message_view), - url(r'^admin/', admin.site.urls), - url(r'^location_field/', include('location_field.urls')), - url(r'^eventplanner_gcal/', include(eventplanner_gcal.urls)), - # url(r'^gallery/', include(imagestore.urls, namespace='imagestore') ), - ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + path("", include("website.urls")), + path("events/", include("eventplanner.urls")), + path("musicians/", include("musicians.urls")), + path("scores/", include("scoremanager.urls")), + path("messages/", simpleforum_views.message_view), + path("admin/", admin.site.urls), + path("location_field/", include("location_field.urls")), + path("eventplanner_gcal/", include("eventplanner_gcal.urls")), + # url(r'^gallery/', include('imagestore.urls', namespace='imagestore')), +] + +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/blechreiz/wsgi.py b/blechreiz/wsgi.py index 7a60579..026dab2 100644 --- a/blechreiz/wsgi.py +++ b/blechreiz/wsgi.py @@ -1,32 +1,16 @@ """ WSGI config for blechreiz project. -This module contains the WSGI application used by Django's development server -and any production WSGI deployments. It should expose a module-level variable -named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover -this application via the ``WSGI_APPLICATION`` setting. - -Usually you will have the standard Django WSGI application here, but it also -might make sense to replace the whole Django WSGI application with a custom one -that later delegates to the Django one. For example, you could introduce WSGI -middleware here, or combine a Django application with an application of another -framework. +It exposes the WSGI callable as a module-level variable named ``application``. +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ """ + import os -# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks -# if running multiple sites in the same mod_wsgi process. To fix this, use -# mod_wsgi daemon mode with each site in its own daemon process, or use -# os.environ["DJANGO_SETTINGS_MODULE"] = "blechreiz.settings" +from django.core.wsgi import get_wsgi_application + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "blechreiz.settings") -# This application object is used by any WSGI server configured to use this -# file. This includes Django's development server, if the WSGI_APPLICATION -# setting points here. -from django.core.wsgi import get_wsgi_application application = get_wsgi_application() - -# Apply WSGI middleware here. -# from helloworld.wsgi import HelloWorldApplication -# application = HelloWorldApplication(application) diff --git a/bootstrapTheme/static/css/images/ui-icons_444444_256x240.png b/bootstrapTheme/static/css/images/ui-icons_444444_256x240.png deleted file mode 100644 index c2daae1..0000000 Binary files a/bootstrapTheme/static/css/images/ui-icons_444444_256x240.png and /dev/null differ diff --git a/bootstrapTheme/static/css/images/ui-icons_555555_256x240.png b/bootstrapTheme/static/css/images/ui-icons_555555_256x240.png deleted file mode 100644 index 4784928..0000000 Binary files a/bootstrapTheme/static/css/images/ui-icons_555555_256x240.png and /dev/null differ diff --git a/bootstrapTheme/static/css/images/ui-icons_777620_256x240.png b/bootstrapTheme/static/css/images/ui-icons_777620_256x240.png deleted file mode 100644 index d2f58d2..0000000 Binary files a/bootstrapTheme/static/css/images/ui-icons_777620_256x240.png and /dev/null differ diff --git a/bootstrapTheme/static/css/images/ui-icons_777777_256x240.png b/bootstrapTheme/static/css/images/ui-icons_777777_256x240.png deleted file mode 100644 index 1d53258..0000000 Binary files a/bootstrapTheme/static/css/images/ui-icons_777777_256x240.png and /dev/null differ diff --git a/bootstrapTheme/static/css/images/ui-icons_cc0000_256x240.png b/bootstrapTheme/static/css/images/ui-icons_cc0000_256x240.png deleted file mode 100644 index 2825f20..0000000 Binary files a/bootstrapTheme/static/css/images/ui-icons_cc0000_256x240.png and /dev/null differ diff --git a/bootstrapTheme/static/css/images/ui-icons_ffffff_256x240.png b/bootstrapTheme/static/css/images/ui-icons_ffffff_256x240.png deleted file mode 100644 index 136a4f9..0000000 Binary files a/bootstrapTheme/static/css/images/ui-icons_ffffff_256x240.png and /dev/null differ diff --git a/bootstrapTheme/static/css/jquery-ui-1.12.1.min.css b/bootstrapTheme/static/css/jquery-ui-1.12.1.min.css deleted file mode 100644 index 776e259..0000000 --- a/bootstrapTheme/static/css/jquery-ui-1.12.1.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! jQuery UI - v1.12.1 - 2016-09-14 -* http://jqueryui.com -* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css -* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6 -* Copyright jQuery Foundation and other contributors; Licensed MIT */ - -.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;font-size:100%}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-button{padding:.4em 1em;display:inline-block;position:relative;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2em;box-sizing:border-box;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-button-icon-only{text-indent:0}.ui-button-icon-only .ui-icon{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px}.ui-button.ui-icon-notext .ui-icon{padding:0;width:2.1em;height:2.1em;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-icon-notext .ui-icon{width:auto;height:auto;text-indent:0;white-space:normal;padding:.4em 1em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-controlgroup{vertical-align:middle;display:inline-block}.ui-controlgroup > .ui-controlgroup-item{float:left;margin-left:0;margin-right:0}.ui-controlgroup > .ui-controlgroup-item:focus,.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus{z-index:9999}.ui-controlgroup-vertical > .ui-controlgroup-item{display:block;float:none;width:100%;margin-top:0;margin-bottom:0;text-align:left}.ui-controlgroup-vertical .ui-controlgroup-item{box-sizing:border-box}.ui-controlgroup .ui-controlgroup-label{padding:.4em 1em}.ui-controlgroup .ui-controlgroup-label span{font-size:80%}.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item{border-left:none}.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item{border-top:none}.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content{border-right:none}.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content{border-bottom:none}.ui-controlgroup-vertical .ui-spinner-input{width:75%;width:calc( 100% - 2.4em )}.ui-controlgroup-vertical .ui-spinner .ui-spinner-up{border-top-style:solid}.ui-checkboxradio-label .ui-icon-background{box-shadow:inset 1px 1px 1px #ccc;border-radius:.12em;border:none}.ui-checkboxradio-radio-label .ui-icon-background{width:16px;height:16px;border-radius:1em;overflow:visible;border:none}.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon{background-image:none;width:8px;height:8px;border-width:4px;border-style:solid}.ui-checkboxradio-disabled{pointer-events:none}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker .ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se,.ui-dialog .ui-resizable-sw,.ui-dialog .ui-resizable-ne,.ui-dialog .ui-resizable-nw{width:7px;height:7px}.ui-dialog .ui-resizable-se{right:0;bottom:0}.ui-dialog .ui-resizable-sw{left:0;bottom:0}.ui-dialog .ui-resizable-ne{right:0;top:0}.ui-dialog .ui-resizable-nw{left:0;top:0}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-text{display:block;margin-right:20px;overflow:hidden;text-overflow:ellipsis}.ui-selectmenu-button.ui-button{text-align:left;white-space:nowrap;width:14em}.ui-selectmenu-icon.ui-icon{float:right;margin-top:0}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:.222em 0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:2em}.ui-spinner-button{width:1.6em;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top-style:none;border-bottom-style:none;border-right-style:none}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_777620_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cc0000_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_777777_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:3px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:3px}.ui-widget-overlay{background:#aaa;opacity:.003;filter:Alpha(Opacity=.3)}.ui-widget-shadow{-webkit-box-shadow:0 0 5px #666;box-shadow:0 0 5px #666} \ No newline at end of file diff --git a/bootstrapTheme/static/js/bootstrap-datepicker.de.js b/bootstrapTheme/static/js/bootstrap-datepicker.de.js index e2e61d2..e941ed0 100644 --- a/bootstrapTheme/static/js/bootstrap-datepicker.de.js +++ b/bootstrapTheme/static/js/bootstrap-datepicker.de.js @@ -1,37 +1,17 @@ -/* German initialisation for the jQuery UI date picker plugin. */ -/* Written by Milian Wolff (mail@milianw.de). */ -( function( factory ) { - if ( typeof define === "function" && define.amd ) { - - // AMD. Register as an anonymous module. - define( [ "../widgets/datepicker" ], factory ); - } else { - - // Browser globals - factory( jQuery.datepicker ); - } -}( function( datepicker ) { - -datepicker.regional.de = { - closeText: "Schließen", - prevText: "<Zurück", - nextText: "Vor>", - currentText: "Heute", - monthNames: [ "Januar","Februar","März","April","Mai","Juni", - "Juli","August","September","Oktober","November","Dezember" ], - monthNamesShort: [ "Jan","Feb","Mär","Apr","Mai","Jun", - "Jul","Aug","Sep","Okt","Nov","Dez" ], - dayNames: [ "Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag" ], - dayNamesShort: [ "So","Mo","Di","Mi","Do","Fr","Sa" ], - dayNamesMin: [ "So","Mo","Di","Mi","Do","Fr","Sa" ], - weekHeader: "KW", - dateFormat: "dd.mm.yy", - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: "" }; -datepicker.setDefaults( datepicker.regional.de ); - -return datepicker.regional.de; - -} ) ); \ No newline at end of file +/** +* German translation for bootstrap-datepicker +* Sam Zurcher +*/ +;(function($){ +$.fn.datepicker.dates['de'] = { +days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], +daysShort: ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam", "Son"], +daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"], +months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], +monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], +today: "Heute", +clear: "Löschen", +weekStart: 1, +format: "dd.mm.yyyy" +}; +}(jQuery)); \ No newline at end of file diff --git a/bootstrapTheme/static/js/jquery-ui-1.12.1.min.js b/bootstrapTheme/static/js/jquery-ui-1.12.1.min.js deleted file mode 100644 index 25398a1..0000000 --- a/bootstrapTheme/static/js/jquery-ui-1.12.1.min.js +++ /dev/null @@ -1,13 +0,0 @@ -/*! jQuery UI - v1.12.1 - 2016-09-14 -* http://jqueryui.com -* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js -* Copyright jQuery Foundation and other contributors; Licensed MIT */ - -(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){function e(t){for(var e=t.css("visibility");"inherit"===e;)t=t.parent(),e=t.css("visibility");return"hidden"!==e}function i(t){for(var e,i;t.length&&t[0]!==document;){if(e=t.css("position"),("absolute"===e||"relative"===e||"fixed"===e)&&(i=parseInt(t.css("zIndex"),10),!isNaN(i)&&0!==i))return i;t=t.parent()}return 0}function s(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,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:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,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:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.regional.en=t.extend(!0,{},this.regional[""]),this.regional["en-US"]=t.extend(!0,{},this.regional.en),this.dpDiv=n(t("
"))}function n(e){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.on("mouseout",i,function(){t(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).removeClass("ui-datepicker-next-hover")}).on("mouseover",i,o)}function o(){t.datepicker._isDisabledDatepicker(m.inline?m.dpDiv.parent()[0]:m.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).addClass("ui-datepicker-next-hover"))}function a(e,i){t.extend(e,i);for(var s in i)null==i[s]&&(e[s]=i[s]);return e}function r(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.ui=t.ui||{},t.ui.version="1.12.1";var h=0,l=Array.prototype.slice;t.cleanData=function(e){return function(i){var s,n,o;for(o=0;null!=(n=i[o]);o++)try{s=t._data(n,"events"),s&&s.remove&&t(n).triggerHandler("remove")}catch(a){}e(i)}}(t.cleanData),t.widget=function(e,i,s){var n,o,a,r={},h=e.split(".")[0];e=e.split(".")[1];var l=h+"-"+e;return s||(s=i,i=t.Widget),t.isArray(s)&&(s=t.extend.apply(null,[{}].concat(s))),t.expr[":"][l.toLowerCase()]=function(e){return!!t.data(e,l)},t[h]=t[h]||{},n=t[h][e],o=t[h][e]=function(t,e){return this._createWidget?(arguments.length&&this._createWidget(t,e),void 0):new o(t,e)},t.extend(o,n,{version:s.version,_proto:t.extend({},s),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(s,function(e,s){return t.isFunction(s)?(r[e]=function(){function t(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}return function(){var e,i=this._super,o=this._superApply;return this._super=t,this._superApply=n,e=s.apply(this,arguments),this._super=i,this._superApply=o,e}}(),void 0):(r[e]=s,void 0)}),o.prototype=t.widget.extend(a,{widgetEventPrefix:n?a.widgetEventPrefix||e:e},r,{constructor:o,namespace:h,widgetName:e,widgetFullName:l}),n?(t.each(n._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete n._childConstructors):i._childConstructors.push(o),t.widget.bridge(e,o),o},t.widget.extend=function(e){for(var i,s,n=l.call(arguments,1),o=0,a=n.length;a>o;o++)for(i in n[o])s=n[o][i],n[o].hasOwnProperty(i)&&void 0!==s&&(e[i]=t.isPlainObject(s)?t.isPlainObject(e[i])?t.widget.extend({},e[i],s):t.widget.extend({},s):s);return e},t.widget.bridge=function(e,i){var s=i.prototype.widgetFullName||e;t.fn[e]=function(n){var o="string"==typeof n,a=l.call(arguments,1),r=this;return o?this.length||"instance"!==n?this.each(function(){var i,o=t.data(this,s);return"instance"===n?(r=o,!1):o?t.isFunction(o[n])&&"_"!==n.charAt(0)?(i=o[n].apply(o,a),i!==o&&void 0!==i?(r=i&&i.jquery?r.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+n+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+n+"'")}):r=void 0:(a.length&&(n=t.widget.extend.apply(null,[n].concat(a))),this.each(function(){var e=t.data(this,s);e?(e.option(n||{}),e._init&&e._init()):t.data(this,s,new i(n,this))})),r}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{classes:{},disabled:!1,create:null},_createWidget:function(e,i){i=t(i||this.defaultElement||this)[0],this.element=t(i),this.uuid=h++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},i!==this&&(t.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===i&&this.destroy()}}),this.document=t(i.style?i.ownerDocument:i.document||i),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+o.eventNamespace,c=h[2];c?n.on(l,c,r):i.on(l,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,h=/top|center|bottom/,l=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
"),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};l>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),h.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-r-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-r-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-h,(i>0||u>a(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.extend({disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.off(".ui-disableSelection")}});var c="ui-effects-",u="ui-effects-style",d="ui-effects-animated",p=t;t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(t,o){var a,r=o.re.exec(i),h=r&&o.parse(r),l=o.space||"rgba";return h?(a=s[l](h),s[c[l].cache]=a[c[l].cache],n=s._rgba=a._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,o.transparent),s):o[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var o,a="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],l=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=l.support={},p=t("

")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),l.fn=t.extend(l.prototype,{parse:function(n,a,r,h){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(a),a=e);var u=this,d=t.type(n),p=this._rgba=[];return a!==e&&(n=[n,a,r,h],d="array"),"string"===d?this.parse(s(n)||o._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof l?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var o=s.cache;f(s.props,function(t,e){if(!u[o]&&s.to){if("alpha"===t||null==n[t])return;u[o]=s.to(u._rgba)}u[o][e.idx]=i(n[t],e,!0)}),u[o]&&0>t.inArray(null,u[o].slice(0,3))&&(u[o][3]=1,s.from&&(u._rgba=s.from(u[o])))}),this):e},is:function(t){var i=l(t),s=!0,n=this;return f(c,function(t,o){var a,r=i[o.cache];return r&&(a=n[o.cache]||o.to&&o.to(n._rgba)||[],f(o.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===a[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=l(t),n=s._space(),o=c[n],a=0===this.alpha()?l("transparent"):this,r=a[o.cache]||o.to(a._rgba),h=r.slice();return s=s[o.cache],f(o.props,function(t,n){var o=n.idx,a=r[o],l=s[o],c=u[n.type]||{};null!==l&&(null===a?h[o]=l:(c.mod&&(l-a>c.mod/2?a+=c.mod:a-l>c.mod/2&&(a-=c.mod)),h[o]=i((l-a)*e+a,n)))}),this[n](h)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(e)._rgba;return l(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,o=t[2]/255,a=t[3],r=Math.max(s,n,o),h=Math.min(s,n,o),l=r-h,c=r+h,u=.5*c;return e=h===r?0:s===r?60*(n-o)/l+360:n===r?60*(o-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=u?l/c:l/(2-c),[Math.round(e)%360,i,u,null==a?1:a]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],o=t[3],a=.5>=s?s*(1+i):s+i-s*i,r=2*s-a;return[Math.round(255*n(r,a,e+1/3)),Math.round(255*n(r,a,e)),Math.round(255*n(r,a,e-1/3)),o]},f(c,function(s,n){var o=n.props,a=n.cache,h=n.to,c=n.from;l.fn[s]=function(s){if(h&&!this[a]&&(this[a]=h(this._rgba)),s===e)return this[a].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[a].slice();return f(o,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=l(c(d)),n[a]=d,n):l(d)},f(o,function(e,i){l.fn[e]||(l.fn[e]=function(n){var o,a=t.type(n),h="alpha"===e?this._hsla?"hsla":"rgba":s,l=this[h](),c=l[i.idx];return"undefined"===a?c:("function"===a&&(n=n.call(this,c),a=t.type(n)),null==n&&i.empty?this:("string"===a&&(o=r.exec(n),o&&(n=c+parseFloat(o[2])*("+"===o[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var o,a,r="";if("transparent"!==n&&("string"!==t.type(n)||(o=s(n)))){if(n=l(o||n),!d.rgba&&1!==n._rgba[3]){for(a="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&a&&a.style;)try{r=t.css(a,"backgroundColor"),a=a.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(h){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=l(e.elem,i),e.end=l(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},l.hook(a),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},o=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(p),function(){function e(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,o={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(o[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(o[i]=n[i]);return o}function i(e,i){var s,o,a={};for(s in i)o=i[s],e[s]!==o&&(n[s]||(t.fx.step[s]||!isNaN(parseFloat(o)))&&(a[s]=o));return a}var s=["add","remove","toggle"],n={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(p.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(n,o,a,r){var h=t.speed(o,a,r);return this.queue(function(){var o,a=t(this),r=a.attr("class")||"",l=h.children?a.find("*").addBack():a;l=l.map(function(){var i=t(this);return{el:i,start:e(this)}}),o=function(){t.each(s,function(t,e){n[e]&&a[e+"Class"](n[e])})},o(),l=l.map(function(){return this.end=e(this.el[0]),this.diff=i(this.start,this.end),this}),a.attr("class",r),l=l.map(function(){var e=this,i=t.Deferred(),s=t.extend({},h,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,l.get()).done(function(){o(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),h.complete.call(a[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,o){return s?t.effects.animateClass.call(this,{add:i},s,n,o):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,o){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,o):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(e){return function(i,s,n,o,a){return"boolean"==typeof s||void 0===s?n?t.effects.animateClass.call(this,s?{add:i}:{remove:i},n,o,a):e.apply(this,arguments):t.effects.animateClass.call(this,{toggle:i},s,n,o)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,o){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,o)}})}(),function(){function e(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function i(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}function s(t,e){var i=e.outerWidth(),s=e.outerHeight(),n=/^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,o=n.exec(t)||["",0,i,s,0];return{top:parseFloat(o[1])||0,right:"auto"===o[2]?i:parseFloat(o[2]),bottom:"auto"===o[3]?s:parseFloat(o[3]),left:parseFloat(o[4])||0}}t.expr&&t.expr.filters&&t.expr.filters.animated&&(t.expr.filters.animated=function(e){return function(i){return!!t(i).data(d)||e(i)}}(t.expr.filters.animated)),t.uiBackCompat!==!1&&t.extend(t.effects,{save:function(t,e){for(var i=0,s=e.length;s>i;i++)null!==e[i]&&t.data(c+e[i],t[0].style[e[i]])},restore:function(t,e){for(var i,s=0,n=e.length;n>s;s++)null!==e[s]&&(i=t.data(c+e[s]),t.css(e[s],i))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("

").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},o=document.activeElement;try{o.id}catch(a){o=document.body}return e.wrap(s),(e[0]===o||t.contains(e[0],o))&&t(o).trigger("focus"),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).trigger("focus")),e}}),t.extend(t.effects,{version:"1.12.1",define:function(e,i,s){return s||(s=i,i="effect"),t.effects.effect[e]=s,t.effects.effect[e].mode=i,s},scaledDimensions:function(t,e,i){if(0===e)return{height:0,width:0,outerHeight:0,outerWidth:0};var s="horizontal"!==i?(e||100)/100:1,n="vertical"!==i?(e||100)/100:1;return{height:t.height()*n,width:t.width()*s,outerHeight:t.outerHeight()*n,outerWidth:t.outerWidth()*s}},clipToBox:function(t){return{width:t.clip.right-t.clip.left,height:t.clip.bottom-t.clip.top,left:t.clip.left,top:t.clip.top}},unshift:function(t,e,i){var s=t.queue();e>1&&s.splice.apply(s,[1,0].concat(s.splice(e,i))),t.dequeue()},saveStyle:function(t){t.data(u,t[0].style.cssText)},restoreStyle:function(t){t[0].style.cssText=t.data(u)||"",t.removeData(u)},mode:function(t,e){var i=t.is(":hidden");return"toggle"===e&&(e=i?"show":"hide"),(i?"hide"===e:"show"===e)&&(e="none"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createPlaceholder:function(e){var i,s=e.css("position"),n=e.position();return e.css({marginTop:e.css("marginTop"),marginBottom:e.css("marginBottom"),marginLeft:e.css("marginLeft"),marginRight:e.css("marginRight")}).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()),/^(static|relative)/.test(s)&&(s="absolute",i=t("<"+e[0].nodeName+">").insertAfter(e).css({display:/^(inline|ruby)/.test(e.css("display"))?"inline-block":"block",visibility:"hidden",marginTop:e.css("marginTop"),marginBottom:e.css("marginBottom"),marginLeft:e.css("marginLeft"),marginRight:e.css("marginRight"),"float":e.css("float")}).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).addClass("ui-effects-placeholder"),e.data(c+"placeholder",i)),e.css({position:s,left:n.left,top:n.top}),i},removePlaceholder:function(t){var e=c+"placeholder",i=t.data(e);i&&(i.remove(),t.removeData(e))},cleanUp:function(e){t.effects.restoreStyle(e),t.effects.removePlaceholder(e)},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var o=e.cssUnit(i);o[0]>0&&(n[i]=o[0]*s+o[1])}),n}}),t.fn.extend({effect:function(){function i(e){function i(){r.removeData(d),t.effects.cleanUp(r),"hide"===s.mode&&r.hide(),a()}function a(){t.isFunction(h)&&h.call(r[0]),t.isFunction(e)&&e()}var r=t(this);s.mode=c.shift(),t.uiBackCompat===!1||o?"none"===s.mode?(r[l](),a()):n.call(r[0],s,i):(r.is(":hidden")?"hide"===l:"show"===l)?(r[l](),a()):n.call(r[0],s,a)}var s=e.apply(this,arguments),n=t.effects.effect[s.effect],o=n.mode,a=s.queue,r=a||"fx",h=s.complete,l=s.mode,c=[],u=function(e){var i=t(this),s=t.effects.mode(i,l)||o;i.data(d,!0),c.push(s),o&&("show"===s||s===o&&"hide"===s)&&i.show(),o&&"none"===s||t.effects.saveStyle(i),t.isFunction(e)&&e()};return t.fx.off||!n?l?this[l](s.duration,h):this.each(function(){h&&h.call(this)}):a===!1?this.each(u).each(i):this.queue(r,u).queue(r,i)},show:function(t){return function(s){if(i(s))return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="show",this.effect.call(this,n) -}}(t.fn.show),hide:function(t){return function(s){if(i(s))return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="hide",this.effect.call(this,n)}}(t.fn.hide),toggle:function(t){return function(s){if(i(s)||"boolean"==typeof s)return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s},cssClip:function(t){return t?this.css("clip","rect("+t.top+"px "+t.right+"px "+t.bottom+"px "+t.left+"px)"):s(this.css("clip"),this)},transfer:function(e,i){var s=t(this),n=t(e.to),o="fixed"===n.css("position"),a=t("body"),r=o?a.scrollTop():0,h=o?a.scrollLeft():0,l=n.offset(),c={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("
").appendTo("body").addClass(e.className).css({top:u.top-r,left:u.left-h,height:s.innerHeight(),width:s.innerWidth(),position:o?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),t.isFunction(i)&&i()})}}),t.fx.step.clip=function(e){e.clipInit||(e.start=t(e.elem).cssClip(),"string"==typeof e.end&&(e.end=s(e.end,e.elem)),e.clipInit=!0),t(e.elem).cssClip({top:e.pos*(e.end.top-e.start.top)+e.start.top,right:e.pos*(e.end.right-e.start.right)+e.start.right,bottom:e.pos*(e.end.bottom-e.start.bottom)+e.start.bottom,left:e.pos*(e.end.left-e.start.left)+e.start.left})}}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}();var f=t.effects;t.effects.define("blind","hide",function(e,i){var s={up:["bottom","top"],vertical:["bottom","top"],down:["top","bottom"],left:["right","left"],horizontal:["right","left"],right:["left","right"]},n=t(this),o=e.direction||"up",a=n.cssClip(),r={clip:t.extend({},a)},h=t.effects.createPlaceholder(n);r.clip[s[o][0]]=r.clip[s[o][1]],"show"===e.mode&&(n.cssClip(r.clip),h&&h.css(t.effects.clipToBox(r)),r.clip=a),h&&h.animate(t.effects.clipToBox(r),e.duration,e.easing),n.animate(r,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("bounce",function(e,i){var s,n,o,a=t(this),r=e.mode,h="hide"===r,l="show"===r,c=e.direction||"up",u=e.distance,d=e.times||5,p=2*d+(l||h?1:0),f=e.duration/p,g=e.easing,m="up"===c||"down"===c?"top":"left",_="up"===c||"left"===c,v=0,b=a.queue().length;for(t.effects.createPlaceholder(a),o=a.css(m),u||(u=a["top"===m?"outerHeight":"outerWidth"]()/3),l&&(n={opacity:1},n[m]=o,a.css("opacity",0).css(m,_?2*-u:2*u).animate(n,f,g)),h&&(u/=Math.pow(2,d-1)),n={},n[m]=o;d>v;v++)s={},s[m]=(_?"-=":"+=")+u,a.animate(s,f,g).animate(n,f,g),u=h?2*u:u/2;h&&(s={opacity:0},s[m]=(_?"-=":"+=")+u,a.animate(s,f,g)),a.queue(i),t.effects.unshift(a,b,p+1)}),t.effects.define("clip","hide",function(e,i){var s,n={},o=t(this),a=e.direction||"vertical",r="both"===a,h=r||"horizontal"===a,l=r||"vertical"===a;s=o.cssClip(),n.clip={top:l?(s.bottom-s.top)/2:s.top,right:h?(s.right-s.left)/2:s.right,bottom:l?(s.bottom-s.top)/2:s.bottom,left:h?(s.right-s.left)/2:s.left},t.effects.createPlaceholder(o),"show"===e.mode&&(o.cssClip(n.clip),n.clip=s),o.animate(n,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("drop","hide",function(e,i){var s,n=t(this),o=e.mode,a="show"===o,r=e.direction||"left",h="up"===r||"down"===r?"top":"left",l="up"===r||"left"===r?"-=":"+=",c="+="===l?"-=":"+=",u={opacity:0};t.effects.createPlaceholder(n),s=e.distance||n["top"===h?"outerHeight":"outerWidth"](!0)/2,u[h]=l+s,a&&(n.css(u),u[h]=c+s,u.opacity=1),n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("explode","hide",function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),i()}var o,a,r,h,l,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=e.mode,g="show"===f,m=p.show().css("visibility","hidden").offset(),_=Math.ceil(p.outerWidth()/d),v=Math.ceil(p.outerHeight()/u),b=[];for(o=0;u>o;o++)for(h=m.top+o*v,c=o-(u-1)/2,a=0;d>a;a++)r=m.left+a*_,l=a-(d-1)/2,p.clone().appendTo("body").wrap("
").css({position:"absolute",visibility:"visible",left:-a*_,top:-o*v}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:_,height:v,left:r+(g?l*_:0),top:h+(g?c*v:0),opacity:g?0:1}).animate({left:r+(g?0:l*_),top:h+(g?0:c*v),opacity:g?1:0},e.duration||500,e.easing,s)}),t.effects.define("fade","toggle",function(e,i){var s="show"===e.mode;t(this).css("opacity",s?0:1).animate({opacity:s?1:0},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("fold","hide",function(e,i){var s=t(this),n=e.mode,o="show"===n,a="hide"===n,r=e.size||15,h=/([0-9]+)%/.exec(r),l=!!e.horizFirst,c=l?["right","bottom"]:["bottom","right"],u=e.duration/2,d=t.effects.createPlaceholder(s),p=s.cssClip(),f={clip:t.extend({},p)},g={clip:t.extend({},p)},m=[p[c[0]],p[c[1]]],_=s.queue().length;h&&(r=parseInt(h[1],10)/100*m[a?0:1]),f.clip[c[0]]=r,g.clip[c[0]]=r,g.clip[c[1]]=0,o&&(s.cssClip(g.clip),d&&d.css(t.effects.clipToBox(g)),g.clip=p),s.queue(function(i){d&&d.animate(t.effects.clipToBox(f),u,e.easing).animate(t.effects.clipToBox(g),u,e.easing),i()}).animate(f,u,e.easing).animate(g,u,e.easing).queue(i),t.effects.unshift(s,_,4)}),t.effects.define("highlight","show",function(e,i){var s=t(this),n={backgroundColor:s.css("backgroundColor")};"hide"===e.mode&&(n.opacity=0),t.effects.saveStyle(s),s.css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(n,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("size",function(e,i){var s,n,o,a=t(this),r=["fontSize"],h=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],l=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],c=e.mode,u="effect"!==c,d=e.scale||"both",p=e.origin||["middle","center"],f=a.css("position"),g=a.position(),m=t.effects.scaledDimensions(a),_=e.from||m,v=e.to||t.effects.scaledDimensions(a,0);t.effects.createPlaceholder(a),"show"===c&&(o=_,_=v,v=o),n={from:{y:_.height/m.height,x:_.width/m.width},to:{y:v.height/m.height,x:v.width/m.width}},("box"===d||"both"===d)&&(n.from.y!==n.to.y&&(_=t.effects.setTransition(a,h,n.from.y,_),v=t.effects.setTransition(a,h,n.to.y,v)),n.from.x!==n.to.x&&(_=t.effects.setTransition(a,l,n.from.x,_),v=t.effects.setTransition(a,l,n.to.x,v))),("content"===d||"both"===d)&&n.from.y!==n.to.y&&(_=t.effects.setTransition(a,r,n.from.y,_),v=t.effects.setTransition(a,r,n.to.y,v)),p&&(s=t.effects.getBaseline(p,m),_.top=(m.outerHeight-_.outerHeight)*s.y+g.top,_.left=(m.outerWidth-_.outerWidth)*s.x+g.left,v.top=(m.outerHeight-v.outerHeight)*s.y+g.top,v.left=(m.outerWidth-v.outerWidth)*s.x+g.left),a.css(_),("content"===d||"both"===d)&&(h=h.concat(["marginTop","marginBottom"]).concat(r),l=l.concat(["marginLeft","marginRight"]),a.find("*[width]").each(function(){var i=t(this),s=t.effects.scaledDimensions(i),o={height:s.height*n.from.y,width:s.width*n.from.x,outerHeight:s.outerHeight*n.from.y,outerWidth:s.outerWidth*n.from.x},a={height:s.height*n.to.y,width:s.width*n.to.x,outerHeight:s.height*n.to.y,outerWidth:s.width*n.to.x};n.from.y!==n.to.y&&(o=t.effects.setTransition(i,h,n.from.y,o),a=t.effects.setTransition(i,h,n.to.y,a)),n.from.x!==n.to.x&&(o=t.effects.setTransition(i,l,n.from.x,o),a=t.effects.setTransition(i,l,n.to.x,a)),u&&t.effects.saveStyle(i),i.css(o),i.animate(a,e.duration,e.easing,function(){u&&t.effects.restoreStyle(i)})})),a.animate(v,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){var e=a.offset();0===v.opacity&&a.css("opacity",_.opacity),u||(a.css("position","static"===f?"relative":f).offset(e),t.effects.saveStyle(a)),i()}})}),t.effects.define("scale",function(e,i){var s=t(this),n=e.mode,o=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"effect"!==n?0:100),a=t.extend(!0,{from:t.effects.scaledDimensions(s),to:t.effects.scaledDimensions(s,o,e.direction||"both"),origin:e.origin||["middle","center"]},e);e.fade&&(a.from.opacity=1,a.to.opacity=0),t.effects.effect.size.call(this,a,i)}),t.effects.define("puff","hide",function(e,i){var s=t.extend(!0,{},e,{fade:!0,percent:parseInt(e.percent,10)||150});t.effects.effect.scale.call(this,s,i)}),t.effects.define("pulsate","show",function(e,i){var s=t(this),n=e.mode,o="show"===n,a="hide"===n,r=o||a,h=2*(e.times||5)+(r?1:0),l=e.duration/h,c=0,u=1,d=s.queue().length;for((o||!s.is(":visible"))&&(s.css("opacity",0).show(),c=1);h>u;u++)s.animate({opacity:c},l,e.easing),c=1-c;s.animate({opacity:c},l,e.easing),s.queue(i),t.effects.unshift(s,d,h+1)}),t.effects.define("shake",function(e,i){var s=1,n=t(this),o=e.direction||"left",a=e.distance||20,r=e.times||3,h=2*r+1,l=Math.round(e.duration/h),c="up"===o||"down"===o?"top":"left",u="up"===o||"left"===o,d={},p={},f={},g=n.queue().length;for(t.effects.createPlaceholder(n),d[c]=(u?"-=":"+=")+a,p[c]=(u?"+=":"-=")+2*a,f[c]=(u?"-=":"+=")+2*a,n.animate(d,l,e.easing);r>s;s++)n.animate(p,l,e.easing).animate(f,l,e.easing);n.animate(p,l,e.easing).animate(d,l/2,e.easing).queue(i),t.effects.unshift(n,g,h+1)}),t.effects.define("slide","show",function(e,i){var s,n,o=t(this),a={up:["bottom","top"],down:["top","bottom"],left:["right","left"],right:["left","right"]},r=e.mode,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h,u=e.distance||o["top"===l?"outerHeight":"outerWidth"](!0),d={};t.effects.createPlaceholder(o),s=o.cssClip(),n=o.position()[l],d[l]=(c?-1:1)*u+n,d.clip=o.cssClip(),d.clip[a[h][1]]=d.clip[a[h][0]],"show"===r&&(o.cssClip(d.clip),o.css(l,d[l]),d.clip=s,d[l]=n),o.animate(d,{queue:!1,duration:e.duration,easing:e.easing,complete:i})});var f;t.uiBackCompat!==!1&&(f=t.effects.define("transfer",function(e,i){t(this).transfer(e,i)})),t.ui.focusable=function(i,s){var n,o,a,r,h,l=i.nodeName.toLowerCase();return"area"===l?(n=i.parentNode,o=n.name,i.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap='#"+o+"']"),a.length>0&&a.is(":visible")):!1):(/^(input|select|textarea|button|object)$/.test(l)?(r=!i.disabled,r&&(h=t(i).closest("fieldset")[0],h&&(r=!h.disabled))):r="a"===l?i.href||s:s,r&&t(i).is(":visible")&&e(t(i)))},t.extend(t.expr[":"],{focusable:function(e){return t.ui.focusable(e,null!=t.attr(e,"tabindex"))}}),t.ui.focusable,t.fn.form=function(){return"string"==typeof this[0].form?this.closest("form"):t(this[0].form)},t.ui.formResetMixin={_formResetHandler:function(){var e=t(this);setTimeout(function(){var i=e.data("ui-form-reset-instances");t.each(i,function(){this.refresh()})})},_bindFormResetHandler:function(){if(this.form=this.element.form(),this.form.length){var t=this.form.data("ui-form-reset-instances")||[];t.length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t)}},_unbindFormResetHandler:function(){if(this.form.length){var e=this.form.data("ui-form-reset-instances");e.splice(t.inArray(this,e),1),e.length?this.form.data("ui-form-reset-instances",e):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset")}}},"1.7"===t.fn.jquery.substring(0,3)&&(t.each(["Width","Height"],function(e,i){function s(e,i,s,o){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),o&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],o=i.toLowerCase(),a={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?a["inner"+i].call(this):this.each(function(){t(this).css(o,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?a["outer"+i].call(this,e):this.each(function(){t(this).css(o,s(this,e,!0,n)+"px")})}}),t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.ui.escapeSelector=function(){var t=/([!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g;return function(e){return e.replace(t,"\\$1")}}(),t.fn.labels=function(){var e,i,s,n,o;return this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(n=this.eq(0).parents("label"),s=this.attr("id"),s&&(e=this.eq(0).parents().last(),o=e.add(e.length?e.siblings():this.siblings()),i="label[for='"+t.ui.escapeSelector(s)+"']",n=n.add(o.find(i).addBack(i))),this.pushStack(n))},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.extend(t.expr[":"],{tabbable:function(e){var i=t.attr(e,"tabindex"),s=null!=i;return(!s||i>=0)&&t.ui.focusable(e,s)}}),t.fn.extend({uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.widget("ui.accordion",{version:"1.12.1",options:{active:0,animate:{},classes:{"ui-accordion-header":"ui-corner-top","ui-accordion-header-collapsed":"ui-corner-all","ui-accordion-content":"ui-corner-bottom"},collapsible:!1,event:"click",header:"> li > :first-child, > :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this._addClass("ui-accordion","ui-widget ui-helper-reset"),this.element.attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t()}},_createIcons:function(){var e,i,s=this.options.icons;s&&(e=t(""),this._addClass(e,"ui-accordion-header-icon","ui-icon "+s.header),e.prependTo(this.headers),i=this.active.children(".ui-accordion-header-icon"),this._removeClass(i,s.header)._addClass(i,null,s.activeHeader)._addClass(this.headers,"ui-accordion-icons"))},_destroyIcons:function(){this._removeClass(this.headers,"ui-accordion-icons"),this.headers.children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeAttr("role"),this.headers.removeAttr("role aria-expanded aria-selected aria-controls tabIndex").removeUniqueId(),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role aria-hidden aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),void 0)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t),this._toggleClass(this.headers.add(this.headers.next()),null,"ui-state-disabled",!!t)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),o=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:o=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:o=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:o=this.headers[0];break;case i.END:o=this.headers[s-1]}o&&(t(e.target).attr("tabIndex",-1),t(o).attr("tabIndex",0),t(o).trigger("focus"),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().trigger("focus")},refresh:function(){var e=this.options;this._processPanels(),e.active===!1&&e.collapsible===!0||!this.headers.length?(e.active=!1,this.active=t()):e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var t=this.headers,e=this.panels;this.headers=this.element.find(this.options.header),this._addClass(this.headers,"ui-accordion-header ui-accordion-header-collapsed","ui-state-default"),this.panels=this.headers.next().filter(":not(.ui-accordion-content-active)").hide(),this._addClass(this.panels,"ui-accordion-content","ui-helper-reset ui-widget-content"),e&&(this._off(t.not(this.headers)),this._off(e.not(this.panels)))},_refresh:function(){var e,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active),this._addClass(this.active,"ui-accordion-header-active","ui-state-active")._removeClass(this.active,"ui-accordion-header-collapsed"),this._addClass(this.active.next(),"ui-accordion-content-active"),this.active.next().show(),this.headers.attr("role","tab").each(function(){var e=t(this),i=e.uniqueId().attr("id"),s=e.next(),n=s.uniqueId().attr("id");e.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(i.event),"fill"===s?(e=n.height(),this.element.siblings(":visible").each(function(){var i=t(this),s=i.css("position");"absolute"!==s&&"fixed"!==s&&(e-=i.outerHeight(!0))}),this.headers.each(function(){e-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,e-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===s&&(e=0,this.headers.next().each(function(){var i=t(this).is(":visible");i||t(this).show(),e=Math.max(e,t(this).css("height","").height()),i||t(this).hide()}).height(e))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i,s,n=this.options,o=this.active,a=t(e.currentTarget),r=a[0]===o[0],h=r&&n.collapsible,l=h?t():a.next(),c=o.next(),u={oldHeader:o,oldPanel:c,newHeader:h?t():a,newPanel:l};e.preventDefault(),r&&!n.collapsible||this._trigger("beforeActivate",e,u)===!1||(n.active=h?!1:this.headers.index(a),this.active=r?t():a,this._toggle(u),this._removeClass(o,"ui-accordion-header-active","ui-state-active"),n.icons&&(i=o.children(".ui-accordion-header-icon"),this._removeClass(i,null,n.icons.activeHeader)._addClass(i,null,n.icons.header)),r||(this._removeClass(a,"ui-accordion-header-collapsed")._addClass(a,"ui-accordion-header-active","ui-state-active"),n.icons&&(s=a.children(".ui-accordion-header-icon"),this._removeClass(s,null,n.icons.header)._addClass(s,null,n.icons.activeHeader)),this._addClass(a.next(),"ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-hidden":"true"}),s.prev().attr({"aria-selected":"false","aria-expanded":"false"}),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===parseInt(t(this).attr("tabIndex"),10)}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_animate:function(t,e,i){var s,n,o,a=this,r=0,h=t.css("box-sizing"),l=t.length&&(!e.length||t.index()",delay:300,options:{icons:{submenu:"ui-icon-caret-1-e"},items:"> *",menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().attr({role:this.options.role,tabIndex:0}),this._addClass("ui-menu","ui-widget ui-widget-content"),this._on({"mousedown .ui-menu-item":function(t){t.preventDefault()},"click .ui-menu-item":function(e){var i=t(e.target),s=t(t.ui.safeActiveElement(this.document[0]));!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(e),e.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(e):!this.element.is(":focus")&&s.closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){if(!this.previousFilter){var i=t(e.target).closest(".ui-menu-item"),s=t(e.currentTarget);i[0]===s[0]&&(this._removeClass(s.siblings().children(".ui-state-active"),null,"ui-state-active"),this.focus(e,s))}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.find(this.options.items).eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){var i=!t.contains(this.element[0],t.ui.safeActiveElement(this.document[0]));i&&this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){this._closeOnDocumentClick(t)&&this.collapseAll(t),this.mouseHandled=!1}})},_destroy:function(){var e=this.element.find(".ui-menu-item").removeAttr("role aria-disabled"),i=e.children(".ui-menu-item-wrapper").removeUniqueId().removeAttr("tabIndex role aria-haspopup");this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeAttr("role aria-labelledby aria-expanded aria-hidden aria-disabled tabIndex").removeUniqueId().show(),i.children().each(function(){var e=t(this);e.data("ui-menu-submenu-caret")&&e.remove()})},_keydown:function(e){var i,s,n,o,a=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:a=!1,s=this.previousFilter||"",o=!1,n=e.keyCode>=96&&105>=e.keyCode?""+(e.keyCode-96):String.fromCharCode(e.keyCode),clearTimeout(this.filterTimer),n===s?o=!0:n=s+n,i=this._filterMenuItems(n),i=o&&-1!==i.index(this.active.next())?this.active.nextAll(".ui-menu-item"):i,i.length||(n=String.fromCharCode(e.keyCode),i=this._filterMenuItems(n)),i.length?(this.focus(e,i),this.previousFilter=n,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}a&&e.preventDefault()},_activate:function(t){this.active&&!this.active.is(".ui-state-disabled")&&(this.active.children("[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i,s,n,o,a=this,r=this.options.icons.submenu,h=this.element.find(this.options.menus);this._toggleClass("ui-menu-icons",null,!!this.element.find(".ui-icon").length),s=h.filter(":not(.ui-menu)").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),i=e.prev(),s=t("").data("ui-menu-submenu-caret",!0);a._addClass(s,"ui-menu-icon","ui-icon "+r),i.attr("aria-haspopup","true").prepend(s),e.attr("aria-labelledby",i.attr("id"))}),this._addClass(s,"ui-menu","ui-widget ui-widget-content ui-front"),e=h.add(this.element),i=e.find(this.options.items),i.not(".ui-menu-item").each(function(){var e=t(this);a._isDivider(e)&&a._addClass(e,"ui-menu-divider","ui-widget-content")}),n=i.not(".ui-menu-item, .ui-menu-divider"),o=n.children().not(".ui-menu").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),this._addClass(n,"ui-menu-item")._addClass(o,"ui-menu-item-wrapper"),i.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){if("icons"===t){var i=this.element.find(".ui-menu-icon");this._removeClass(i,null,this.options.icons.submenu)._addClass(i,null,e.submenu)}this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t+""),this._toggleClass(null,"ui-state-disabled",!!t)},focus:function(t,e){var i,s,n;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children(".ui-menu-item-wrapper"),this._addClass(s,null,"ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),n=this.active.parent().closest(".ui-menu-item").children(".ui-menu-item-wrapper"),this._addClass(n,null,"ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,o,a,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,o=this.activeMenu.scrollTop(),a=this.activeMenu.height(),r=e.outerHeight(),0>n?this.activeMenu.scrollTop(o+n):n+r>a&&this.activeMenu.scrollTop(o+n-a+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this._removeClass(this.active.children(".ui-menu-item-wrapper"),null,"ui-state-active"),this._trigger("blur",t,{item:this.active}),this.active=null)},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this._removeClass(s.find(".ui-state-active"),null,"ui-state-active"),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false")},_closeOnDocumentClick:function(e){return!t(e.target).closest(".ui-menu").length},_isDivider:function(t){return!/[^\-\u2014\u2013\s]/.test(t.text())},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.find(this.options.items)[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.find(this.options.items)[this.active?"last":"first"]())),void 0):(this.next(e),void 0)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.find(this.options.items).first())),void 0):(this.next(e),void 0)},_hasScroll:function(){return this.element.outerHeight()",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var e,i,s,n=this.element[0].nodeName.toLowerCase(),o="textarea"===n,a="input"===n; -this.isMultiLine=o||!a&&this._isContentEditable(this.element),this.valueMethod=this.element[o||a?"val":"text"],this.isNewMenu=!0,this._addClass("ui-autocomplete-input"),this.element.attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return e=!0,s=!0,i=!0,void 0;e=!1,s=!1,i=!1;var o=t.ui.keyCode;switch(n.keyCode){case o.PAGE_UP:e=!0,this._move("previousPage",n);break;case o.PAGE_DOWN:e=!0,this._move("nextPage",n);break;case o.UP:e=!0,this._keyEvent("previous",n);break;case o.DOWN:e=!0,this._keyEvent("next",n);break;case o.ENTER:this.menu.active&&(e=!0,n.preventDefault(),this.menu.select(n));break;case o.TAB:this.menu.active&&this.menu.select(n);break;case o.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(e)return e=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),void 0;if(!i){var n=t.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(t){return s?(s=!1,t.preventDefault(),void 0):(this._searchTimeout(t),void 0)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(clearTimeout(this.searching),this.close(t),this._change(t),void 0)}}),this._initSource(),this.menu=t("
    ").appendTo(this._appendTo()).menu({role:null}).hide().menu("instance"),this._addClass(this.menu.element,"ui-autocomplete","ui-front"),this._on(this.menu.element,{mousedown:function(e){e.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,this.element[0]!==t.ui.safeActiveElement(this.document[0])&&this.element.trigger("focus")})},menufocus:function(e,i){var s,n;return this.isNewMenu&&(this.isNewMenu=!1,e.originalEvent&&/^mouse/.test(e.originalEvent.type))?(this.menu.blur(),this.document.one("mousemove",function(){t(e.target).trigger(e.originalEvent)}),void 0):(n=i.item.data("ui-autocomplete-item"),!1!==this._trigger("focus",e,{item:n})&&e.originalEvent&&/^key/.test(e.originalEvent.type)&&this._value(n.value),s=i.item.attr("aria-label")||n.value,s&&t.trim(s).length&&(this.liveRegion.children().hide(),t("
    ").text(s).appendTo(this.liveRegion)),void 0)},menuselect:function(e,i){var s=i.item.data("ui-autocomplete-item"),n=this.previous;this.element[0]!==t.ui.safeActiveElement(this.document[0])&&(this.element.trigger("focus"),this.previous=n,this._delay(function(){this.previous=n,this.selectedItem=s})),!1!==this._trigger("select",e,{item:s})&&this._value(s.value),this.term=this._value(),this.close(e),this.selectedItem=s}}),this.liveRegion=t("
    ",{role:"status","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_isEventTargetInWidget:function(e){var i=this.menu.element[0];return e.target===this.element[0]||e.target===i||t.contains(i,e.target)},_closeOnClickOutside:function(t){this._isEventTargetInWidget(t)||this.close()},_appendTo:function(){var e=this.options.appendTo;return e&&(e=e.jquery||e.nodeType?t(e):this.document.find(e).eq(0)),e&&e[0]||(e=this.element.closest(".ui-front, dialog")),e.length||(e=this.document[0].body),e},_initSource:function(){var e,i,s=this;t.isArray(this.options.source)?(e=this.options.source,this.source=function(i,s){s(t.ui.autocomplete.filter(e,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(e,n){s.xhr&&s.xhr.abort(),s.xhr=t.ajax({url:i,data:e,dataType:"json",success:function(t){n(t)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(t){clearTimeout(this.searching),this.searching=this._delay(function(){var e=this.term===this._value(),i=this.menu.element.is(":visible"),s=t.altKey||t.ctrlKey||t.metaKey||t.shiftKey;(!e||e&&!i&&!s)&&(this.selectedItem=null,this.search(null,t))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length").append(t("
    ").text(i.label)).appendTo(e)},_move:function(t,e){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this.isMultiLine||this._value(this.term),this.menu.blur(),void 0):(this.menu[t](e),void 0):(this.search(null,e),void 0)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(t,e),e.preventDefault())},_isContentEditable:function(t){if(!t.length)return!1;var e=t.prop("contentEditable");return"inherit"===e?this._isContentEditable(t.parent()):"true"===e}}),t.extend(t.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(e,i){var s=RegExp(t.ui.autocomplete.escapeRegex(i),"i");return t.grep(e,function(t){return s.test(t.label||t.value||t)})}}),t.widget("ui.autocomplete",t.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(t>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(e){var i;this._superApply(arguments),this.options.disabled||this.cancelSearch||(i=e&&e.length?this.options.messages.results(e.length):this.options.messages.noResults,this.liveRegion.children().hide(),t("
    ").text(i).appendTo(this.liveRegion))}}),t.ui.autocomplete;var g=/ui-corner-([a-z]){2,6}/g;t.widget("ui.controlgroup",{version:"1.12.1",defaultElement:"
    ",options:{direction:"horizontal",disabled:null,onlyVisible:!0,items:{button:"input[type=button], input[type=submit], input[type=reset], button, a",controlgroupLabel:".ui-controlgroup-label",checkboxradio:"input[type='checkbox'], input[type='radio']",selectmenu:"select",spinner:".ui-spinner-input"}},_create:function(){this._enhance()},_enhance:function(){this.element.attr("role","toolbar"),this.refresh()},_destroy:function(){this._callChildMethod("destroy"),this.childWidgets.removeData("ui-controlgroup-data"),this.element.removeAttr("role"),this.options.items.controlgroupLabel&&this.element.find(this.options.items.controlgroupLabel).find(".ui-controlgroup-label-contents").contents().unwrap()},_initWidgets:function(){var e=this,i=[];t.each(this.options.items,function(s,n){var o,a={};return n?"controlgroupLabel"===s?(o=e.element.find(n),o.each(function(){var e=t(this);e.children(".ui-controlgroup-label-contents").length||e.contents().wrapAll("")}),e._addClass(o,null,"ui-widget ui-widget-content ui-state-default"),i=i.concat(o.get()),void 0):(t.fn[s]&&(a=e["_"+s+"Options"]?e["_"+s+"Options"]("middle"):{classes:{}},e.element.find(n).each(function(){var n=t(this),o=n[s]("instance"),r=t.widget.extend({},a);if("button"!==s||!n.parent(".ui-spinner").length){o||(o=n[s]()[s]("instance")),o&&(r.classes=e._resolveClassesValues(r.classes,o)),n[s](r);var h=n[s]("widget");t.data(h[0],"ui-controlgroup-data",o?o:n[s]("instance")),i.push(h[0])}})),void 0):void 0}),this.childWidgets=t(t.unique(i)),this._addClass(this.childWidgets,"ui-controlgroup-item")},_callChildMethod:function(e){this.childWidgets.each(function(){var i=t(this),s=i.data("ui-controlgroup-data");s&&s[e]&&s[e]()})},_updateCornerClass:function(t,e){var i="ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all",s=this._buildSimpleOptions(e,"label").classes.label;this._removeClass(t,null,i),this._addClass(t,null,s)},_buildSimpleOptions:function(t,e){var i="vertical"===this.options.direction,s={classes:{}};return s.classes[e]={middle:"",first:"ui-corner-"+(i?"top":"left"),last:"ui-corner-"+(i?"bottom":"right"),only:"ui-corner-all"}[t],s},_spinnerOptions:function(t){var e=this._buildSimpleOptions(t,"ui-spinner");return e.classes["ui-spinner-up"]="",e.classes["ui-spinner-down"]="",e},_buttonOptions:function(t){return this._buildSimpleOptions(t,"ui-button")},_checkboxradioOptions:function(t){return this._buildSimpleOptions(t,"ui-checkboxradio-label")},_selectmenuOptions:function(t){var e="vertical"===this.options.direction;return{width:e?"auto":!1,classes:{middle:{"ui-selectmenu-button-open":"","ui-selectmenu-button-closed":""},first:{"ui-selectmenu-button-open":"ui-corner-"+(e?"top":"tl"),"ui-selectmenu-button-closed":"ui-corner-"+(e?"top":"left")},last:{"ui-selectmenu-button-open":e?"":"ui-corner-tr","ui-selectmenu-button-closed":"ui-corner-"+(e?"bottom":"right")},only:{"ui-selectmenu-button-open":"ui-corner-top","ui-selectmenu-button-closed":"ui-corner-all"}}[t]}},_resolveClassesValues:function(e,i){var s={};return t.each(e,function(n){var o=i.options.classes[n]||"";o=t.trim(o.replace(g,"")),s[n]=(o+" "+e[n]).replace(/\s+/g," ")}),s},_setOption:function(t,e){return"direction"===t&&this._removeClass("ui-controlgroup-"+this.options.direction),this._super(t,e),"disabled"===t?(this._callChildMethod(e?"disable":"enable"),void 0):(this.refresh(),void 0)},refresh:function(){var e,i=this;this._addClass("ui-controlgroup ui-controlgroup-"+this.options.direction),"horizontal"===this.options.direction&&this._addClass(null,"ui-helper-clearfix"),this._initWidgets(),e=this.childWidgets,this.options.onlyVisible&&(e=e.filter(":visible")),e.length&&(t.each(["first","last"],function(t,s){var n=e[s]().data("ui-controlgroup-data");if(n&&i["_"+n.widgetName+"Options"]){var o=i["_"+n.widgetName+"Options"](1===e.length?"only":s);o.classes=i._resolveClassesValues(o.classes,n),n.element[n.widgetName](o)}else i._updateCornerClass(e[s](),s)}),this._callChildMethod("refresh"))}}),t.widget("ui.checkboxradio",[t.ui.formResetMixin,{version:"1.12.1",options:{disabled:null,label:null,icon:!0,classes:{"ui-checkboxradio-label":"ui-corner-all","ui-checkboxradio-icon":"ui-corner-all"}},_getCreateOptions:function(){var e,i,s=this,n=this._super()||{};return this._readType(),i=this.element.labels(),this.label=t(i[i.length-1]),this.label.length||t.error("No label found for checkboxradio widget"),this.originalLabel="",this.label.contents().not(this.element[0]).each(function(){s.originalLabel+=3===this.nodeType?t(this).text():this.outerHTML}),this.originalLabel&&(n.label=this.originalLabel),e=this.element[0].disabled,null!=e&&(n.disabled=e),n},_create:function(){var t=this.element[0].checked;this._bindFormResetHandler(),null==this.options.disabled&&(this.options.disabled=this.element[0].disabled),this._setOption("disabled",this.options.disabled),this._addClass("ui-checkboxradio","ui-helper-hidden-accessible"),this._addClass(this.label,"ui-checkboxradio-label","ui-button ui-widget"),"radio"===this.type&&this._addClass(this.label,"ui-checkboxradio-radio-label"),this.options.label&&this.options.label!==this.originalLabel?this._updateLabel():this.originalLabel&&(this.options.label=this.originalLabel),this._enhance(),t&&(this._addClass(this.label,"ui-checkboxradio-checked","ui-state-active"),this.icon&&this._addClass(this.icon,null,"ui-state-hover")),this._on({change:"_toggleClasses",focus:function(){this._addClass(this.label,null,"ui-state-focus ui-visual-focus")},blur:function(){this._removeClass(this.label,null,"ui-state-focus ui-visual-focus")}})},_readType:function(){var e=this.element[0].nodeName.toLowerCase();this.type=this.element[0].type,"input"===e&&/radio|checkbox/.test(this.type)||t.error("Can't create checkboxradio on element.nodeName="+e+" and element.type="+this.type)},_enhance:function(){this._updateIcon(this.element[0].checked)},widget:function(){return this.label},_getRadioGroup:function(){var e,i=this.element[0].name,s="input[name='"+t.ui.escapeSelector(i)+"']";return i?(e=this.form.length?t(this.form[0].elements).filter(s):t(s).filter(function(){return 0===t(this).form().length}),e.not(this.element)):t([])},_toggleClasses:function(){var e=this.element[0].checked;this._toggleClass(this.label,"ui-checkboxradio-checked","ui-state-active",e),this.options.icon&&"checkbox"===this.type&&this._toggleClass(this.icon,null,"ui-icon-check ui-state-checked",e)._toggleClass(this.icon,null,"ui-icon-blank",!e),"radio"===this.type&&this._getRadioGroup().each(function(){var e=t(this).checkboxradio("instance");e&&e._removeClass(e.label,"ui-checkboxradio-checked","ui-state-active")})},_destroy:function(){this._unbindFormResetHandler(),this.icon&&(this.icon.remove(),this.iconSpace.remove())},_setOption:function(t,e){return"label"!==t||e?(this._super(t,e),"disabled"===t?(this._toggleClass(this.label,null,"ui-state-disabled",e),this.element[0].disabled=e,void 0):(this.refresh(),void 0)):void 0},_updateIcon:function(e){var i="ui-icon ui-icon-background ";this.options.icon?(this.icon||(this.icon=t(""),this.iconSpace=t(" "),this._addClass(this.iconSpace,"ui-checkboxradio-icon-space")),"checkbox"===this.type?(i+=e?"ui-icon-check ui-state-checked":"ui-icon-blank",this._removeClass(this.icon,null,e?"ui-icon-blank":"ui-icon-check")):i+="ui-icon-blank",this._addClass(this.icon,"ui-checkboxradio-icon",i),e||this._removeClass(this.icon,null,"ui-icon-check ui-state-checked"),this.icon.prependTo(this.label).after(this.iconSpace)):void 0!==this.icon&&(this.icon.remove(),this.iconSpace.remove(),delete this.icon)},_updateLabel:function(){var t=this.label.contents().not(this.element[0]);this.icon&&(t=t.not(this.icon[0])),this.iconSpace&&(t=t.not(this.iconSpace[0])),t.remove(),this.label.append(this.options.label)},refresh:function(){var t=this.element[0].checked,e=this.element[0].disabled;this._updateIcon(t),this._toggleClass(this.label,"ui-checkboxradio-checked","ui-state-active",t),null!==this.options.label&&this._updateLabel(),e!==this.options.disabled&&this._setOptions({disabled:e})}}]),t.ui.checkboxradio,t.widget("ui.button",{version:"1.12.1",defaultElement:"").addClass(this._triggerClass).html(o?t("").attr({src:o,alt:n,title:n}):n)),e[r?"before":"after"](i.trigger),i.trigger.on("click",function(){return t.datepicker._datepickerShowing&&t.datepicker._lastInput===e[0]?t.datepicker._hideDatepicker():t.datepicker._datepickerShowing&&t.datepicker._lastInput!==e[0]?(t.datepicker._hideDatepicker(),t.datepicker._showDatepicker(e[0])):t.datepicker._showDatepicker(e[0]),!1}))},_autoSize:function(t){if(this._get(t,"autoSize")&&!t.inline){var e,i,s,n,o=new Date(2009,11,20),a=this._get(t,"dateFormat");a.match(/[DM]/)&&(e=function(t){for(i=0,s=0,n=0;t.length>n;n++)t[n].length>i&&(i=t[n].length,s=n);return s},o.setMonth(e(this._get(t,a.match(/MM/)?"monthNames":"monthNamesShort"))),o.setDate(e(this._get(t,a.match(/DD/)?"dayNames":"dayNamesShort"))+20-o.getDay())),t.input.attr("size",this._formatDate(t,o).length)}},_inlineDatepicker:function(e,i){var s=t(e);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),t.data(e,"datepicker",i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(e),i.dpDiv.css("display","block"))},_dialogDatepicker:function(e,i,s,n,o){var r,h,l,c,u,d=this._dialogInst;return d||(this.uuid+=1,r="dp"+this.uuid,this._dialogInput=t(""),this._dialogInput.on("keydown",this._doKeyDown),t("body").append(this._dialogInput),d=this._dialogInst=this._newInst(this._dialogInput,!1),d.settings={},t.data(this._dialogInput[0],"datepicker",d)),a(d.settings,n||{}),i=i&&i.constructor===Date?this._formatDate(d,i):i,this._dialogInput.val(i),this._pos=o?o.length?o:[o.pageX,o.pageY]:null,this._pos||(h=document.documentElement.clientWidth,l=document.documentElement.clientHeight,c=document.documentElement.scrollLeft||document.body.scrollLeft,u=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[h/2-100+c,l/2-150+u]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),d.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),t.blockUI&&t.blockUI(this.dpDiv),t.data(this._dialogInput[0],"datepicker",d),this},_destroyDatepicker:function(e){var i,s=t(e),n=t.data(e,"datepicker");s.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),t.removeData(e,"datepicker"),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).off("focus",this._showDatepicker).off("keydown",this._doKeyDown).off("keypress",this._doKeyPress).off("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty(),m===n&&(m=null))},_enableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,"datepicker");n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!1,o.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}))},_disableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,"datepicker");n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!0,o.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}),this._disabledInputs[this._disabledInputs.length]=e)},_isDisabledDatepicker:function(t){if(!t)return!1;for(var e=0;this._disabledInputs.length>e;e++)if(this._disabledInputs[e]===t)return!0;return!1},_getInst:function(e){try{return t.data(e,"datepicker")}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(e,i,s){var n,o,r,h,l=this._getInst(e);return 2===arguments.length&&"string"==typeof i?"defaults"===i?t.extend({},t.datepicker._defaults):l?"all"===i?t.extend({},l.settings):this._get(l,i):null:(n=i||{},"string"==typeof i&&(n={},n[i]=s),l&&(this._curInst===l&&this._hideDatepicker(),o=this._getDateDatepicker(e,!0),r=this._getMinMaxDate(l,"min"),h=this._getMinMaxDate(l,"max"),a(l.settings,n),null!==r&&void 0!==n.dateFormat&&void 0===n.minDate&&(l.settings.minDate=this._formatDate(l,r)),null!==h&&void 0!==n.dateFormat&&void 0===n.maxDate&&(l.settings.maxDate=this._formatDate(l,h)),"disabled"in n&&(n.disabled?this._disableDatepicker(e):this._enableDatepicker(e)),this._attachments(t(e),l),this._autoSize(l),this._setDate(l,o),this._updateAlternate(l),this._updateDatepicker(l)),void 0)},_changeDatepicker:function(t,e,i){this._optionDatepicker(t,e,i)},_refreshDatepicker:function(t){var e=this._getInst(t);e&&this._updateDatepicker(e)},_setDateDatepicker:function(t,e){var i=this._getInst(t);i&&(this._setDate(i,e),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(t,e){var i=this._getInst(t);return i&&!i.inline&&this._setDateFromField(i,e),i?this._getDate(i):null},_doKeyDown:function(e){var i,s,n,o=t.datepicker._getInst(e.target),a=!0,r=o.dpDiv.is(".ui-datepicker-rtl");if(o._keyEvent=!0,t.datepicker._datepickerShowing)switch(e.keyCode){case 9:t.datepicker._hideDatepicker(),a=!1;break;case 13:return n=t("td."+t.datepicker._dayOverClass+":not(."+t.datepicker._currentClass+")",o.dpDiv),n[0]&&t.datepicker._selectDay(e.target,o.selectedMonth,o.selectedYear,n[0]),i=t.datepicker._get(o,"onSelect"),i?(s=t.datepicker._formatDate(o),i.apply(o.input?o.input[0]:null,[s,o])):t.datepicker._hideDatepicker(),!1;case 27:t.datepicker._hideDatepicker();break;case 33:t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 34:t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 35:(e.ctrlKey||e.metaKey)&&t.datepicker._clearDate(e.target),a=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&t.datepicker._gotoToday(e.target),a=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?1:-1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,-7,"D"),a=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?-1:1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,7,"D"),a=e.ctrlKey||e.metaKey;break;default:a=!1}else 36===e.keyCode&&e.ctrlKey?t.datepicker._showDatepicker(this):a=!1;a&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(e){var i,s,n=t.datepicker._getInst(e.target);return t.datepicker._get(n,"constrainInput")?(i=t.datepicker._possibleChars(t.datepicker._get(n,"dateFormat")),s=String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),e.ctrlKey||e.metaKey||" ">s||!i||i.indexOf(s)>-1):void 0},_doKeyUp:function(e){var i,s=t.datepicker._getInst(e.target);if(s.input.val()!==s.lastVal)try{i=t.datepicker.parseDate(t.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,t.datepicker._getFormatConfig(s)),i&&(t.datepicker._setDateFromField(s),t.datepicker._updateAlternate(s),t.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(e){if(e=e.target||e,"input"!==e.nodeName.toLowerCase()&&(e=t("input",e.parentNode)[0]),!t.datepicker._isDisabledDatepicker(e)&&t.datepicker._lastInput!==e){var s,n,o,r,h,l,c;s=t.datepicker._getInst(e),t.datepicker._curInst&&t.datepicker._curInst!==s&&(t.datepicker._curInst.dpDiv.stop(!0,!0),s&&t.datepicker._datepickerShowing&&t.datepicker._hideDatepicker(t.datepicker._curInst.input[0])),n=t.datepicker._get(s,"beforeShow"),o=n?n.apply(e,[e,s]):{},o!==!1&&(a(s.settings,o),s.lastVal=null,t.datepicker._lastInput=e,t.datepicker._setDateFromField(s),t.datepicker._inDialog&&(e.value=""),t.datepicker._pos||(t.datepicker._pos=t.datepicker._findPos(e),t.datepicker._pos[1]+=e.offsetHeight),r=!1,t(e).parents().each(function(){return r|="fixed"===t(this).css("position"),!r}),h={left:t.datepicker._pos[0],top:t.datepicker._pos[1]},t.datepicker._pos=null,s.dpDiv.empty(),s.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),t.datepicker._updateDatepicker(s),h=t.datepicker._checkOffset(s,h,r),s.dpDiv.css({position:t.datepicker._inDialog&&t.blockUI?"static":r?"fixed":"absolute",display:"none",left:h.left+"px",top:h.top+"px"}),s.inline||(l=t.datepicker._get(s,"showAnim"),c=t.datepicker._get(s,"duration"),s.dpDiv.css("z-index",i(t(e))+1),t.datepicker._datepickerShowing=!0,t.effects&&t.effects.effect[l]?s.dpDiv.show(l,t.datepicker._get(s,"showOptions"),c):s.dpDiv[l||"show"](l?c:null),t.datepicker._shouldFocusInput(s)&&s.input.trigger("focus"),t.datepicker._curInst=s)) -}},_updateDatepicker:function(e){this.maxRows=4,m=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e);var i,s=this._getNumberOfMonths(e),n=s[1],a=17,r=e.dpDiv.find("."+this._dayOverClass+" a");r.length>0&&o.apply(r.get(0)),e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&e.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),e.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e===t.datepicker._curInst&&t.datepicker._datepickerShowing&&t.datepicker._shouldFocusInput(e)&&e.input.trigger("focus"),e.yearshtml&&(i=e.yearshtml,setTimeout(function(){i===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),i=e.yearshtml=null},0))},_shouldFocusInput:function(t){return t.input&&t.input.is(":visible")&&!t.input.is(":disabled")&&!t.input.is(":focus")},_checkOffset:function(e,i,s){var n=e.dpDiv.outerWidth(),o=e.dpDiv.outerHeight(),a=e.input?e.input.outerWidth():0,r=e.input?e.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:t(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:t(document).scrollTop());return i.left-=this._get(e,"isRTL")?n-a:0,i.left-=s&&i.left===e.input.offset().left?t(document).scrollLeft():0,i.top-=s&&i.top===e.input.offset().top+r?t(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+o>l&&l>o?Math.abs(o+r):0),i},_findPos:function(e){for(var i,s=this._getInst(e),n=this._get(s,"isRTL");e&&("hidden"===e.type||1!==e.nodeType||t.expr.filters.hidden(e));)e=e[n?"previousSibling":"nextSibling"];return i=t(e).offset(),[i.left,i.top]},_hideDatepicker:function(e){var i,s,n,o,a=this._curInst;!a||e&&a!==t.data(e,"datepicker")||this._datepickerShowing&&(i=this._get(a,"showAnim"),s=this._get(a,"duration"),n=function(){t.datepicker._tidyDialog(a)},t.effects&&(t.effects.effect[i]||t.effects[i])?a.dpDiv.hide(i,t.datepicker._get(a,"showOptions"),s,n):a.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,o=this._get(a,"onClose"),o&&o.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),t.blockUI&&(t.unblockUI(),t("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(t){t.dpDiv.removeClass(this._dialogClass).off(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(t.datepicker._curInst){var i=t(e.target),s=t.datepicker._getInst(i[0]);(i[0].id!==t.datepicker._mainDivId&&0===i.parents("#"+t.datepicker._mainDivId).length&&!i.hasClass(t.datepicker.markerClassName)&&!i.closest("."+t.datepicker._triggerClass).length&&t.datepicker._datepickerShowing&&(!t.datepicker._inDialog||!t.blockUI)||i.hasClass(t.datepicker.markerClassName)&&t.datepicker._curInst!==s)&&t.datepicker._hideDatepicker()}},_adjustDate:function(e,i,s){var n=t(e),o=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(o,i+("M"===s?this._get(o,"showCurrentAtPos"):0),s),this._updateDatepicker(o))},_gotoToday:function(e){var i,s=t(e),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(e,i,s){var n=t(e),o=this._getInst(n[0]);o["selected"+("M"===s?"Month":"Year")]=o["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(o),this._adjustDate(n)},_selectDay:function(e,i,s,n){var o,a=t(e);t(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(a[0])||(o=this._getInst(a[0]),o.selectedDay=o.currentDay=t("a",n).html(),o.selectedMonth=o.currentMonth=i,o.selectedYear=o.currentYear=s,this._selectDate(e,this._formatDate(o,o.currentDay,o.currentMonth,o.currentYear)))},_clearDate:function(e){var i=t(e);this._selectDate(i,"")},_selectDate:function(e,i){var s,n=t(e),o=this._getInst(n[0]);i=null!=i?i:this._formatDate(o),o.input&&o.input.val(i),this._updateAlternate(o),s=this._get(o,"onSelect"),s?s.apply(o.input?o.input[0]:null,[i,o]):o.input&&o.input.trigger("change"),o.inline?this._updateDatepicker(o):(this._hideDatepicker(),this._lastInput=o.input[0],"object"!=typeof o.input[0]&&o.input.trigger("focus"),this._lastInput=null)},_updateAlternate:function(e){var i,s,n,o=this._get(e,"altField");o&&(i=this._get(e,"altFormat")||this._get(e,"dateFormat"),s=this._getDate(e),n=this.formatDate(i,s,this._getFormatConfig(e)),t(o).val(n))},noWeekends:function(t){var e=t.getDay();return[e>0&&6>e,""]},iso8601Week:function(t){var e,i=new Date(t.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),e=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((e-i)/864e5)/7)+1},parseDate:function(e,i,s){if(null==e||null==i)throw"Invalid arguments";if(i="object"==typeof i?""+i:i+"",""===i)return null;var n,o,a,r,h=0,l=(s?s.shortYearCutoff:null)||this._defaults.shortYearCutoff,c="string"!=typeof l?l:(new Date).getFullYear()%100+parseInt(l,10),u=(s?s.dayNamesShort:null)||this._defaults.dayNamesShort,d=(s?s.dayNames:null)||this._defaults.dayNames,p=(s?s.monthNamesShort:null)||this._defaults.monthNamesShort,f=(s?s.monthNames:null)||this._defaults.monthNames,g=-1,m=-1,_=-1,v=-1,b=!1,y=function(t){var i=e.length>n+1&&e.charAt(n+1)===t;return i&&n++,i},w=function(t){var e=y(t),s="@"===t?14:"!"===t?20:"y"===t&&e?4:"o"===t?3:2,n="y"===t?s:1,o=RegExp("^\\d{"+n+","+s+"}"),a=i.substring(h).match(o);if(!a)throw"Missing number at position "+h;return h+=a[0].length,parseInt(a[0],10)},k=function(e,s,n){var o=-1,a=t.map(y(e)?n:s,function(t,e){return[[e,t]]}).sort(function(t,e){return-(t[1].length-e[1].length)});if(t.each(a,function(t,e){var s=e[1];return i.substr(h,s.length).toLowerCase()===s.toLowerCase()?(o=e[0],h+=s.length,!1):void 0}),-1!==o)return o+1;throw"Unknown name at position "+h},x=function(){if(i.charAt(h)!==e.charAt(n))throw"Unexpected literal at position "+h;h++};for(n=0;e.length>n;n++)if(b)"'"!==e.charAt(n)||y("'")?x():b=!1;else switch(e.charAt(n)){case"d":_=w("d");break;case"D":k("D",u,d);break;case"o":v=w("o");break;case"m":m=w("m");break;case"M":m=k("M",p,f);break;case"y":g=w("y");break;case"@":r=new Date(w("@")),g=r.getFullYear(),m=r.getMonth()+1,_=r.getDate();break;case"!":r=new Date((w("!")-this._ticksTo1970)/1e4),g=r.getFullYear(),m=r.getMonth()+1,_=r.getDate();break;case"'":y("'")?x():b=!0;break;default:x()}if(i.length>h&&(a=i.substr(h),!/^\s+/.test(a)))throw"Extra/unparsed characters found in date: "+a;if(-1===g?g=(new Date).getFullYear():100>g&&(g+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c>=g?0:-100)),v>-1)for(m=1,_=v;;){if(o=this._getDaysInMonth(g,m-1),o>=_)break;m++,_-=o}if(r=this._daylightSavingAdjust(new Date(g,m-1,_)),r.getFullYear()!==g||r.getMonth()+1!==m||r.getDate()!==_)throw"Invalid date";return r},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:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(t,e,i){if(!e)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,o=(i?i.dayNames:null)||this._defaults.dayNames,a=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(e){var i=t.length>s+1&&t.charAt(s+1)===e;return i&&s++,i},l=function(t,e,i){var s=""+e;if(h(t))for(;i>s.length;)s="0"+s;return s},c=function(t,e,i,s){return h(t)?s[e]:i[e]},u="",d=!1;if(e)for(s=0;t.length>s;s++)if(d)"'"!==t.charAt(s)||h("'")?u+=t.charAt(s):d=!1;else switch(t.charAt(s)){case"d":u+=l("d",e.getDate(),2);break;case"D":u+=c("D",e.getDay(),n,o);break;case"o":u+=l("o",Math.round((new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime()-new Date(e.getFullYear(),0,0).getTime())/864e5),3);break;case"m":u+=l("m",e.getMonth()+1,2);break;case"M":u+=c("M",e.getMonth(),a,r);break;case"y":u+=h("y")?e.getFullYear():(10>e.getFullYear()%100?"0":"")+e.getFullYear()%100;break;case"@":u+=e.getTime();break;case"!":u+=1e4*e.getTime()+this._ticksTo1970;break;case"'":h("'")?u+="'":d=!0;break;default:u+=t.charAt(s)}return u},_possibleChars:function(t){var e,i="",s=!1,n=function(i){var s=t.length>e+1&&t.charAt(e+1)===i;return s&&e++,s};for(e=0;t.length>e;e++)if(s)"'"!==t.charAt(e)||n("'")?i+=t.charAt(e):s=!1;else switch(t.charAt(e)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=t.charAt(e)}return i},_get:function(t,e){return void 0!==t.settings[e]?t.settings[e]:this._defaults[e]},_setDateFromField:function(t,e){if(t.input.val()!==t.lastVal){var i=this._get(t,"dateFormat"),s=t.lastVal=t.input?t.input.val():null,n=this._getDefaultDate(t),o=n,a=this._getFormatConfig(t);try{o=this.parseDate(i,s,a)||n}catch(r){s=e?"":s}t.selectedDay=o.getDate(),t.drawMonth=t.selectedMonth=o.getMonth(),t.drawYear=t.selectedYear=o.getFullYear(),t.currentDay=s?o.getDate():0,t.currentMonth=s?o.getMonth():0,t.currentYear=s?o.getFullYear():0,this._adjustInstDate(t)}},_getDefaultDate:function(t){return this._restrictMinMax(t,this._determineDate(t,this._get(t,"defaultDate"),new Date))},_determineDate:function(e,i,s){var n=function(t){var e=new Date;return e.setDate(e.getDate()+t),e},o=function(i){try{return t.datepicker.parseDate(t.datepicker._get(e,"dateFormat"),i,t.datepicker._getFormatConfig(e))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?t.datepicker._getDate(e):null)||new Date,o=n.getFullYear(),a=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":a+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a));break;case"y":case"Y":o+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a))}l=h.exec(i)}return new Date(o,a,r)},a=null==i||""===i?s:"string"==typeof i?o(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return a=a&&"Invalid Date"==""+a?s:a,a&&(a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)),this._daylightSavingAdjust(a)},_daylightSavingAdjust:function(t){return t?(t.setHours(t.getHours()>12?t.getHours()+2:0),t):null},_setDate:function(t,e,i){var s=!e,n=t.selectedMonth,o=t.selectedYear,a=this._restrictMinMax(t,this._determineDate(t,e,new Date));t.selectedDay=t.currentDay=a.getDate(),t.drawMonth=t.selectedMonth=t.currentMonth=a.getMonth(),t.drawYear=t.selectedYear=t.currentYear=a.getFullYear(),n===t.selectedMonth&&o===t.selectedYear||i||this._notifyChange(t),this._adjustInstDate(t),t.input&&t.input.val(s?"":this._formatDate(t))},_getDate:function(t){var e=!t.currentYear||t.input&&""===t.input.val()?null:this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return e},_attachHandlers:function(e){var i=this._get(e,"stepMonths"),s="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){t.datepicker._adjustDate(s,-i,"M")},next:function(){t.datepicker._adjustDate(s,+i,"M")},hide:function(){t.datepicker._hideDatepicker()},today:function(){t.datepicker._gotoToday(s)},selectDay:function(){return t.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return t.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return t.datepicker._selectMonthYear(s,this,"Y"),!1}};t(this).on(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(t){var e,i,s,n,o,a,r,h,l,c,u,d,p,f,g,m,_,v,b,y,w,k,x,C,D,I,T,P,M,S,H,z,O,A,N,W,E,F,L,R=new Date,B=this._daylightSavingAdjust(new Date(R.getFullYear(),R.getMonth(),R.getDate())),Y=this._get(t,"isRTL"),j=this._get(t,"showButtonPanel"),q=this._get(t,"hideIfNoPrevNext"),K=this._get(t,"navigationAsDateFormat"),U=this._getNumberOfMonths(t),V=this._get(t,"showCurrentAtPos"),$=this._get(t,"stepMonths"),X=1!==U[0]||1!==U[1],G=this._daylightSavingAdjust(t.currentDay?new Date(t.currentYear,t.currentMonth,t.currentDay):new Date(9999,9,9)),Q=this._getMinMaxDate(t,"min"),J=this._getMinMaxDate(t,"max"),Z=t.drawMonth-V,te=t.drawYear;if(0>Z&&(Z+=12,te--),J)for(e=this._daylightSavingAdjust(new Date(J.getFullYear(),J.getMonth()-U[0]*U[1]+1,J.getDate())),e=Q&&Q>e?Q:e;this._daylightSavingAdjust(new Date(te,Z,1))>e;)Z--,0>Z&&(Z=11,te--);for(t.drawMonth=Z,t.drawYear=te,i=this._get(t,"prevText"),i=K?this.formatDate(i,this._daylightSavingAdjust(new Date(te,Z-$,1)),this._getFormatConfig(t)):i,s=this._canAdjustMonth(t,-1,te,Z)?""+i+"":q?"":""+i+"",n=this._get(t,"nextText"),n=K?this.formatDate(n,this._daylightSavingAdjust(new Date(te,Z+$,1)),this._getFormatConfig(t)):n,o=this._canAdjustMonth(t,1,te,Z)?""+n+"":q?"":""+n+"",a=this._get(t,"currentText"),r=this._get(t,"gotoCurrent")&&t.currentDay?G:B,a=K?this.formatDate(a,r,this._getFormatConfig(t)):a,h=t.inline?"":"",l=j?"
    "+(Y?h:"")+(this._isInRange(t,r)?"":"")+(Y?"":h)+"
    ":"",c=parseInt(this._get(t,"firstDay"),10),c=isNaN(c)?0:c,u=this._get(t,"showWeek"),d=this._get(t,"dayNames"),p=this._get(t,"dayNamesMin"),f=this._get(t,"monthNames"),g=this._get(t,"monthNamesShort"),m=this._get(t,"beforeShowDay"),_=this._get(t,"showOtherMonths"),v=this._get(t,"selectOtherMonths"),b=this._getDefaultDate(t),y="",k=0;U[0]>k;k++){for(x="",this.maxRows=4,C=0;U[1]>C;C++){if(D=this._daylightSavingAdjust(new Date(te,Z,t.selectedDay)),I=" ui-corner-all",T="",X){if(T+="
    "}for(T+="
    "+(/all|left/.test(I)&&0===k?Y?o:s:"")+(/all|right/.test(I)&&0===k?Y?s:o:"")+this._generateMonthYearHeader(t,Z,te,Q,J,k>0||C>0,f,g)+"
    "+"",P=u?"":"",w=0;7>w;w++)M=(w+c)%7,P+="";for(T+=P+"",S=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,S)),H=(this._getFirstDayOfMonth(te,Z)-c+7)%7,z=Math.ceil((H+S)/7),O=X?this.maxRows>z?this.maxRows:z:z,this.maxRows=O,A=this._daylightSavingAdjust(new Date(te,Z,1-H)),N=0;O>N;N++){for(T+="",W=u?"":"",w=0;7>w;w++)E=m?m.apply(t.input?t.input[0]:null,[A]):[!0,""],F=A.getMonth()!==Z,L=F&&!v||!E[0]||Q&&Q>A||J&&A>J,W+="",A.setDate(A.getDate()+1),A=this._daylightSavingAdjust(A);T+=W+""}Z++,Z>11&&(Z=0,te++),T+="
    "+this._get(t,"weekHeader")+"=5?" class='ui-datepicker-week-end'":"")+">"+""+p[M]+"
    "+this._get(t,"calculateWeek")(A)+""+(F&&!_?" ":L?""+A.getDate()+"":""+A.getDate()+"")+"
    "+(X?"
    "+(U[0]>0&&C===U[1]-1?"
    ":""):""),x+=T}y+=x}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,o,a,r){var h,l,c,u,d,p,f,g,m=this._get(t,"changeMonth"),_=this._get(t,"changeYear"),v=this._get(t,"showMonthAfterYear"),b="
    ",y="";if(o||!m)y+=""+a[e]+"";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+=""}if(v||(b+=y+(!o&&m&&_?"":" ")),!t.yearshtml)if(t.yearshtml="",o||!_)b+=""+i+"";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);return isNaN(e)?d:e},f=p(u[0]),g=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,g=n?Math.min(g,n.getFullYear()):g,t.yearshtml+="",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),v&&(b+=(!o&&m&&_?"":" ")+y),b+="
    "},_adjustInstDate:function(t,e,i){var s=t.selectedYear+("Y"===i?e:0),n=t.selectedMonth+("M"===i?e:0),o=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),a=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,o)));t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),o=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&o.setDate(this._getDaysInMonth(o.getFullYear(),o.getMonth())),this._isInRange(t,o)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),o=this._getMinMaxDate(t,"max"),a=null,r=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),a=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(a+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||e.getTime()>=n.getTime())&&(!o||e.getTime()<=o.getTime())&&(!a||e.getFullYear()>=a)&&(!r||r>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).on("mousedown",t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new s,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.12.1",t.datepicker,t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var _=!1;t(document).on("mouseup",function(){_=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!_){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,n="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),_=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,_=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.ui.safeBlur=function(e){e&&"body"!==e.nodeName.toLowerCase()&&t(e).trigger("blur")},t.widget("ui.draggable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this._addClass("ui-draggable"),this._setHandleClassName(),this._mouseInit()},_setOption:function(t,e){this._super(t,e),"handle"===t&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(this._blurActiveElement(e),this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(e){this.iframeBlocks=this.document.find(e).map(function(){var e=t(this);return t("
    ").css("position","absolute").appendTo(e.parent()).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(e){var i=t.ui.safeActiveElement(this.document[0]),s=t(e.target);s.closest(i).length||t.ui.safeBlur(i)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this._addClass(this.helper,"ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===t(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(e),this.originalPosition=this.position=this._generatePosition(e,!1),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_refreshOffsets:function(t){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:t.pageX-this.offset.left,top:t.pageY-this.offset.top}},_mouseDrag:function(e,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(e,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp(new t.Event("mouseup",e)),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i=this,s=!1;return t.ui.ddmanager&&!this.options.dropBehaviour&&(s=t.ui.ddmanager.drop(this,e)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",e)!==!1&&i._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1},_mouseUp:function(e){return this._unblockFrames(),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),this.handleElement.is(e.target)&&this.element.trigger("focus"),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp(new t.Event("mouseup",{target:this.element[0]})):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this._addClass(this.handleElement,"ui-draggable-handle")},_removeHandleClassName:function(){this._removeClass(this.handleElement,"ui-draggable-handle")},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper),n=s?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_isRootNode:function(t){return/(html|body)/i.test(t.tagName)||t===this.document[0]},_getParentOffset:function(){var e=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var t=this.element.position(),e=this._isRootNode(this.scrollParent[0]);return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+(e?0:this.scrollParent.scrollTop()),left:t.left-(parseInt(this.helper.css("left"),10)||0)+(e?0:this.scrollParent.scrollLeft())} -},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options,o=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,t(o).width()-this.helperProportions.width-this.margins.left,(t(o).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(t,e){e||(e=this.position);var i="absolute"===t?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:e.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:e.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(t,e){var i,s,n,o,a=this.options,r=this._isRootNode(this.scrollParent[0]),h=t.pageX,l=t.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),e&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.lefti[2]&&(h=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,h=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o),"y"===a.axis&&(h=this.originalPageX),"x"===a.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}},_clear:function(){this._removeClass(this.helper,"ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s,this],!0),/^(drag|start|stop)/.test(e)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i,s){var n=t.extend({},i,{item:s.element});s.sortables=[],t(s.options.connectToSortable).each(function(){var i=t(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",e,n))})},stop:function(e,i,s){var n=t.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,t.each(s.sortables,function(){var t=this;t.isOver?(t.isOver=0,s.cancelHelperRemoval=!0,t.cancelHelperRemoval=!1,t._storedCSS={position:t.placeholder.css("position"),top:t.placeholder.css("top"),left:t.placeholder.css("left")},t._mouseStop(e),t.options.helper=t.options._helper):(t.cancelHelperRemoval=!0,t._trigger("deactivate",e,n))})},drag:function(e,i,s){t.each(s.sortables,function(){var n=!1,o=this;o.positionAbs=s.positionAbs,o.helperProportions=s.helperProportions,o.offset.click=s.offset.click,o._intersectsWith(o.containerCache)&&(n=!0,t.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==o&&this._intersectsWith(this.containerCache)&&t.contains(o.element[0],this.element[0])&&(n=!1),n})),n?(o.isOver||(o.isOver=1,s._parent=i.helper.parent(),o.currentItem=i.helper.appendTo(o.element).data("ui-sortable-item",!0),o.options._helper=o.options.helper,o.options.helper=function(){return i.helper[0]},e.target=o.currentItem[0],o._mouseCapture(e,!0),o._mouseStart(e,!0,!0),o.offset.click.top=s.offset.click.top,o.offset.click.left=s.offset.click.left,o.offset.parent.left-=s.offset.parent.left-o.offset.parent.left,o.offset.parent.top-=s.offset.parent.top-o.offset.parent.top,s._trigger("toSortable",e),s.dropped=o.element,t.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,o.fromOutside=s),o.currentItem&&(o._mouseDrag(e),i.position=o.position)):o.isOver&&(o.isOver=0,o.cancelHelperRemoval=!0,o.options._revert=o.options.revert,o.options.revert=!1,o._trigger("out",e,o._uiHash(o)),o._mouseStop(e,!0),o.options.revert=o.options._revert,o.options.helper=o.options._helper,o.placeholder&&o.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(e),i.position=s._generatePosition(e,!0),s._trigger("fromSortable",e),s.dropped=!1,t.each(s.sortables,function(){this.refreshPositions()}))})}}),t.ui.plugin.add("draggable","cursor",{start:function(e,i,s){var n=t("body"),o=s.options;n.css("cursor")&&(o._cursor=n.css("cursor")),n.css("cursor",o.cursor)},stop:function(e,i,s){var n=s.options;n._cursor&&t("body").css("cursor",n._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("opacity")&&(o._opacity=n.css("opacity")),n.css("opacity",o.opacity)},stop:function(e,i,s){var n=s.options;n._opacity&&t(i.helper).css("opacity",n._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(t,e,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(e,i,s){var n=s.options,o=!1,a=s.scrollParentNotHidden[0],r=s.document[0];a!==r&&"HTML"!==a.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+a.offsetHeight-e.pageY=0;d--)h=s.snapElements[d].left-s.margins.left,l=h+s.snapElements[d].width,c=s.snapElements[d].top-s.margins.top,u=c+s.snapElements[d].height,h-g>_||m>l+g||c-g>b||v>u+g||!t.contains(s.snapElements[d].item.ownerDocument,s.snapElements[d].item)?(s.snapElements[d].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=!1):("inner"!==f.snapMode&&(n=g>=Math.abs(c-b),o=g>=Math.abs(u-v),a=g>=Math.abs(h-_),r=g>=Math.abs(l-m),n&&(i.position.top=s._convertPositionTo("relative",{top:c-s.helperProportions.height,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||o||a||r,"outer"!==f.snapMode&&(n=g>=Math.abs(c-v),o=g>=Math.abs(u-b),a=g>=Math.abs(h-m),r=g>=Math.abs(l-_),n&&(i.position.top=s._convertPositionTo("relative",{top:c,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[d].snapping&&(n||o||a||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=n||o||a||r||p)}}),t.ui.plugin.add("draggable","stack",{start:function(e,i,s){var n,o=s.options,a=t.makeArray(t(o.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});a.length&&(n=parseInt(t(a[0]).css("zIndex"),10)||0,t(a).each(function(e){t(this).css("zIndex",n+e)}),this.css("zIndex",n+a.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("zIndex")&&(o._zIndex=n.css("zIndex")),n.css("zIndex",o.zIndex)},stop:function(e,i,s){var n=s.options;n._zIndex&&t(i.helper).css("zIndex",n._zIndex)}}),t.ui.draggable,t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
    ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
    "),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
    "),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,g=s.maxWidth&&p>s.maxWidth,m=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),g&&(p-=l),m&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable,t.widget("ui.dialog",{version:"1.12.1",options:{appendTo:"body",autoOpen:!0,buttons:[],classes:{"ui-dialog":"ui-corner-all","ui-dialog-titlebar":"ui-corner-all"},closeOnEscape:!0,closeText:"Close",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},sizeRelatedOptions:{buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},resizableRelatedOptions:{maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),null==this.options.title&&null!=this.originalTitle&&(this.options.title=this.originalTitle),this.options.disabled&&(this.options.disabled=!1),this._createWrapper(),this.element.show().removeAttr("title").appendTo(this.uiDialog),this._addClass("ui-dialog-content","ui-widget-content"),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1,this._trackFocus()},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._untrackInstance(),this._destroyOverlay(),this.element.removeUniqueId().css(this.originalCss).detach(),this.uiDialog.remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog -},disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._focusedElement=null,this._destroyOverlay(),this._untrackInstance(),this.opener.filter(":focusable").trigger("focus").length||t.ui.safeBlur(t.ui.safeActiveElement(this.document[0])),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(e,i){var s=!1,n=this.uiDialog.siblings(".ui-front:visible").map(function(){return+t(this).css("z-index")}).get(),o=Math.max.apply(null,n);return o>=+this.uiDialog.css("z-index")&&(this.uiDialog.css("z-index",o+1),s=!0),s&&!i&&this._trigger("focus",e),s},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=t(t.ui.safeActiveElement(this.document[0])),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var t=this._focusedElement;t||(t=this.element.find("[autofocus]")),t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).trigger("focus")},_keepFocus:function(e){function i(){var e=t.ui.safeActiveElement(this.document[0]),i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("
    ").hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._addClass(this.uiDialog,"ui-dialog","ui-widget ui-widget-content ui-front"),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),void 0;if(e.keyCode===t.ui.keyCode.TAB&&!e.isDefaultPrevented()){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(this._delay(function(){n.trigger("focus")}),e.preventDefault()):(this._delay(function(){s.trigger("focus")}),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("
    "),this._addClass(this.uiDialogTitlebar,"ui-dialog-titlebar","ui-widget-header ui-helper-clearfix"),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.trigger("focus")}}),this.uiDialogTitlebarClose=t("").button({label:t("").text(this.options.closeText).html(),icon:"ui-icon-closethick",showLabel:!1}).appendTo(this.uiDialogTitlebar),this._addClass(this.uiDialogTitlebarClose,"ui-dialog-titlebar-close"),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("").uniqueId().prependTo(this.uiDialogTitlebar),this._addClass(e,"ui-dialog-title"),this._title(e),this.uiDialogTitlebar.prependTo(this.uiDialog),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title?t.text(this.options.title):t.html(" ")},_createButtonPane:function(){this.uiDialogButtonPane=t("
    "),this._addClass(this.uiDialogButtonPane,"ui-dialog-buttonpane","ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("
    ").appendTo(this.uiDialogButtonPane),this._addClass(this.uiButtonSet,"ui-dialog-buttonset"),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this._removeClass(this.uiDialog,"ui-dialog-buttons"),void 0):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,o={icon:s.icon,iconPosition:s.iconPosition,showLabel:s.showLabel,icons:s.icons,text:s.text},delete s.click,delete s.icon,delete s.iconPosition,delete s.showLabel,delete s.icons,"boolean"==typeof s.text&&delete s.text,t("",s).button(o).appendTo(e.uiButtonSet).on("click",function(){n.apply(e.element[0],arguments)})}),this._addClass(this.uiDialog,"ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){i._addClass(t(this),"ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){var a=o.offset.left-i.document.scrollLeft(),r=o.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(a>=0?"+":"")+a+" "+"top"+(r>=0?"+":"")+r,of:i.window},i._removeClass(t(this),"ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o))}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){i._addClass(t(this),"ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){var a=i.uiDialog.offset(),r=a.left-i.document.scrollLeft(),h=a.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(h>=0?"+":"")+h,of:i.window},i._removeClass(t(this),"ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_trackFocus:function(){this._on(this.widget(),{focusin:function(e){this._makeFocusTarget(),this._focusedElement=t(e.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var e=this._trackingInstances(),i=t.inArray(this,e);-1!==i&&e.splice(i,1)},_trackingInstances:function(){var t=this.document.data("ui-dialog-instances");return t||(t=[],this.document.data("ui-dialog-instances",t)),t},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(e){var i=this,s=!1,n={};t.each(e,function(t,e){i._setOption(t,e),t in i.sizeRelatedOptions&&(s=!0),t in i.resizableRelatedOptions&&(n[t]=e)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,i){var s,n,o=this.uiDialog;"disabled"!==e&&(this._super(e,i),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:t("").text(""+this.options.closeText).html()}),"draggable"===e&&(s=o.is(":data(ui-draggable)"),s&&!i&&o.draggable("destroy"),!s&&i&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(n=o.is(":data(ui-resizable)"),n&&!i&&o.resizable("destroy"),n&&"string"==typeof i&&o.resizable("option","handles",i),n||i===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("
    ").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=!0;this._delay(function(){e=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(t){e||this._allowInteraction(t)||(t.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=t("
    ").appendTo(this._appendTo()),this._addClass(this.overlay,null,"ui-widget-overlay ui-front"),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var t=this.document.data("ui-dialog-overlays")-1;t?this.document.data("ui-dialog-overlays",t):(this._off(this.document,"focusin"),this.document.removeData("ui-dialog-overlays")),this.overlay.remove(),this.overlay=null}}}),t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{options:{dialogClass:""},_createWrapper:function(){this._super(),this.uiDialog.addClass(this.options.dialogClass)},_setOption:function(t,e){"dialogClass"===t&&this.uiDialog.removeClass(this.options.dialogClass).addClass(e),this._superApply(arguments)}}),t.ui.dialog,t.widget("ui.droppable",{version:"1.12.1",widgetEventPrefix:"drop",options:{accept:"*",addClasses:!0,greedy:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(s)?s:function(t){return t.is(s)},this.proportions=function(){return arguments.length?(e=arguments[0],void 0):e?e:e={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this._addClass("ui-droppable")},_addToManager:function(e){t.ui.ddmanager.droppables[e]=t.ui.ddmanager.droppables[e]||[],t.ui.ddmanager.droppables[e].push(this)},_splice:function(t){for(var e=0;t.length>e;e++)t[e]===this&&t.splice(e,1)},_destroy:function(){var e=t.ui.ddmanager.droppables[this.options.scope];this._splice(e)},_setOption:function(e,i){if("accept"===e)this.accept=t.isFunction(i)?i:function(t){return t.is(i)};else if("scope"===e){var s=t.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(e,i)},_activate:function(e){var i=t.ui.ddmanager.current;this._addActiveClass(),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this._removeActiveClass(),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._addHoverClass(),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._removeHoverClass(),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=t(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&v(s,t.extend(i,{offset:i.element.offset()}),i.options.tolerance,e)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this._removeActiveClass(),this._removeHoverClass(),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}},_addHoverClass:function(){this._addClass("ui-droppable-hover")},_removeHoverClass:function(){this._removeClass("ui-droppable-hover")},_addActiveClass:function(){this._addClass("ui-droppable-active")},_removeActiveClass:function(){this._removeClass("ui-droppable-active")}});var v=t.ui.intersect=function(){function t(t,e,i){return t>=e&&e+i>t}return function(e,i,s,n){if(!i.offset)return!1;var o=(e.positionAbs||e.position.absolute).left+e.margins.left,a=(e.positionAbs||e.position.absolute).top+e.margins.top,r=o+e.helperProportions.width,h=a+e.helperProportions.height,l=i.offset.left,c=i.offset.top,u=l+i.proportions().width,d=c+i.proportions().height;switch(s){case"fit":return o>=l&&u>=r&&a>=c&&d>=h;case"intersect":return o+e.helperProportions.width/2>l&&u>r-e.helperProportions.width/2&&a+e.helperProportions.height/2>c&&d>h-e.helperProportions.height/2;case"pointer":return t(n.pageY,c,i.proportions().height)&&t(n.pageX,l,i.proportions().width);case"touch":return(a>=c&&d>=a||h>=c&&d>=h||c>a&&h>d)&&(o>=l&&u>=o||r>=l&&u>=r||l>o&&r>u);default:return!1}}}();t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,o=t.ui.ddmanager.droppables[e.options.scope]||[],a=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;o.length>s;s++)if(!(o[s].options.disabled||e&&!o[s].accept.call(o[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===o[s].element[0]){o[s].proportions().height=0;continue t}o[s].visible="none"!==o[s].element.css("display"),o[s].visible&&("mousedown"===a&&o[s]._activate.call(o[s],i),o[s].offset=o[s].element.offset(),o[s].proportions({width:o[s].element[0].offsetWidth,height:o[s].element[0].offsetHeight}))}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&v(e,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").on("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,o,a=v(e,this,this.options.tolerance,i),r=!a&&this.isover?"isout":a&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,o=this.element.parents(":data(ui-droppable)").filter(function(){return t(this).droppable("instance").options.scope===n}),o.length&&(s=t(o[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").off("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}},t.uiBackCompat!==!1&&t.widget("ui.droppable",t.ui.droppable,{options:{hoverClass:!1,activeClass:!1},_addActiveClass:function(){this._super(),this.options.activeClass&&this.element.addClass(this.options.activeClass)},_removeActiveClass:function(){this._super(),this.options.activeClass&&this.element.removeClass(this.options.activeClass)},_addHoverClass:function(){this._super(),this.options.hoverClass&&this.element.addClass(this.options.hoverClass)},_removeHoverClass:function(){this._super(),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass)}}),t.ui.droppable,t.widget("ui.progressbar",{version:"1.12.1",options:{classes:{"ui-progressbar":"ui-corner-all","ui-progressbar-value":"ui-corner-left","ui-progressbar-complete":"ui-corner-right"},max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.attr({role:"progressbar","aria-valuemin":this.min}),this._addClass("ui-progressbar","ui-widget ui-widget-content"),this.valueDiv=t("
    ").appendTo(this.element),this._addClass(this.valueDiv,"ui-progressbar-value","ui-widget-header"),this._refreshValue()},_destroy:function(){this.element.removeAttr("role aria-valuemin aria-valuemax aria-valuenow"),this.valueDiv.remove()},value:function(t){return void 0===t?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),void 0)},_constrainedValue:function(t){return void 0===t&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).width(i.toFixed(0)+"%"),this._toggleClass(this.valueDiv,"ui-progressbar-complete",null,e===this.options.max)._toggleClass("ui-progressbar-indeterminate",null,this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("
    ").appendTo(this.valueDiv),this._addClass(this.overlayDiv,"ui-progressbar-overlay"))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}}),t.widget("ui.selectable",t.ui.mouse,{version:"1.12.1",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e=this;this._addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e.elementPos=t(e.element[0]).offset(),e.selectees=t(e.options.filter,e.element[0]),e._addClass(e.selectees,"ui-selectee"),e.selectees.each(function(){var i=t(this),s=i.offset(),n={left:s.left-e.elementPos.left,top:s.top-e.elementPos.top};t.data(this,"selectable-item",{element:this,$element:i,left:n.left,top:n.top,right:n.left+i.outerWidth(),bottom:n.top+i.outerHeight(),startselected:!1,selected:i.hasClass("ui-selected"),selecting:i.hasClass("ui-selecting"),unselecting:i.hasClass("ui-unselecting")})})},this.refresh(),this._mouseInit(),this.helper=t("
    "),this._addClass(this.helper,"ui-selectable-helper")},_destroy:function(){this.selectees.removeData("selectable-item"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.elementPos=t(this.element[0]).offset(),this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(i._removeClass(s.$element,"ui-selected"),s.selected=!1,i._addClass(s.$element,"ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),i._removeClass(n.$element,s?"ui-unselecting":"ui-selected")._addClass(n.$element,s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,o=this.opos[0],a=this.opos[1],r=e.pageX,h=e.pageY;return o>r&&(i=r,r=o,o=i),a>h&&(i=h,h=a,a=i),this.helper.css({left:o,top:a,width:r-o,height:h-a}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),l=!1,c={};i&&i.element!==s.element[0]&&(c.left=i.left+s.elementPos.left,c.right=i.right+s.elementPos.left,c.top=i.top+s.elementPos.top,c.bottom=i.bottom+s.elementPos.top,"touch"===n.tolerance?l=!(c.left>r||o>c.right||c.top>h||a>c.bottom):"fit"===n.tolerance&&(l=c.left>o&&r>c.right&&c.top>a&&h>c.bottom),l?(i.selected&&(s._removeClass(i.$element,"ui-selected"),i.selected=!1),i.unselecting&&(s._removeClass(i.$element,"ui-unselecting"),i.unselecting=!1),i.selecting||(s._addClass(i.$element,"ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,s._addClass(i.$element,"ui-selected"),i.selected=!0):(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,i.startselected&&(s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(s._removeClass(i.$element,"ui-selected"),i.selected=!1,s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-selecting")._addClass(s.$element,"ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}}),t.widget("ui.selectmenu",[t.ui.formResetMixin,{version:"1.12.1",defaultElement:"",widgetEventPrefix:"spin",options:{classes:{"ui-spinner":"ui-corner-all","ui-spinner-down":"ui-corner-br","ui-spinner-up":"ui-corner-tr"},culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e=this._super(),i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);null!=n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var e=this.element[0]===t.ui.safeActiveElement(this.document[0]);e||(this.element.trigger("focus"),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===t.ui.safeActiveElement(this.document[0])?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap("").parent().append("")},_draw:function(){this._enhance(),this._addClass(this.uiSpinner,"ui-spinner","ui-widget ui-widget-content"),this._addClass("ui-spinner-input"),this.element.attr("role","spinbutton"),this.buttons=this.uiSpinner.children("a").attr("tabIndex",-1).attr("aria-hidden",!0).button({classes:{"ui-button":""}}),this._removeClass(this.buttons,"ui-corner-all"),this._addClass(this.buttons.first(),"ui-spinner-button ui-spinner-up"),this._addClass(this.buttons.last(),"ui-spinner-button ui-spinner-down"),this.buttons.first().button({icon:this.options.icons.up,showLabel:!1}),this.buttons.last().button({icon:this.options.icons.down,showLabel:!1}),this.buttons.height()>Math.ceil(.5*this.uiSpinner.height())&&this.uiSpinner.height()>0&&this.uiSpinner.height(this.uiSpinner.height())},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){var i,s,n;return"culture"===t||"numberFormat"===t?(i=this._parse(this.element.val()),this.options[t]=e,this.element.val(this._format(i)),void 0):(("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(s=this.buttons.first().find(".ui-icon"),this._removeClass(s,null,this.options.icons.up),this._addClass(s,null,e.up),n=this.buttons.last().find(".ui-icon"),this._removeClass(n,null,this.options.icons.down),this._addClass(n,null,e.down)),this._super(t,e),void 0)},_setOptionDisabled:function(t){this._super(t),this._toggleClass(this.uiSpinner,null,"ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable")},_setOptions:r(function(t){this._super(t)}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var t=this.value();return null===t?!1:t===this._adjustValue(t)},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.prop("disabled",!1).removeAttr("autocomplete role aria-valuemin aria-valuemax aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:r(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:r(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:r(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:r(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(r(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),t.uiBackCompat!==!1&&t.widget("ui.spinner",t.ui.spinner,{_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml())},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""}}),t.ui.spinner,t.widget("ui.tabs",{version:"1.12.1",delay:300,options:{active:null,classes:{"ui-tabs":"ui-corner-all","ui-tabs-nav":"ui-corner-all","ui-tabs-panel":"ui-corner-bottom","ui-tabs-tab":"ui-corner-top"},collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var t=/#.*$/;return function(e){var i,s;i=e.href.replace(t,""),s=location.href.replace(t,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return e.hash.length>1&&i===s}}(),_create:function(){var e=this,i=this.options;this.running=!1,this._addClass("ui-tabs","ui-widget ui-widget-content"),this._toggleClass("ui-tabs-collapsible",null,i.collapsible),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var e=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===e&&(s&&this.tabs.each(function(i,n){return t(n).attr("aria-controls")===s?(e=i,!1):void 0}),null===e&&(e=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===e||-1===e)&&(e=this.tabs.length?0:!1)),e!==!1&&(e=this.tabs.index(this.tabs.eq(e)),-1===e&&(e=i?!1:0)),!i&&e===!1&&this.anchors.length&&(e=0),e},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(e){var i=t(t.ui.safeActiveElement(this.document[0])).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(e)){switch(e.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:s++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:n=!1,s--;break;case t.ui.keyCode.END:s=this.anchors.length-1;break;case t.ui.keyCode.HOME:s=0;break;case t.ui.keyCode.SPACE:return e.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case t.ui.keyCode.ENTER:return e.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}e.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),e.ctrlKey||e.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.trigger("focus"))},_handlePageNav:function(e){return e.altKey&&e.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):e.altKey&&e.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).trigger("focus"),t},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):(this._super(t,e),"collapsible"===t&&(this._toggleClass("ui-tabs-collapsible",null,e),e||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(e),"heightStyle"===t&&this._setupHeightStyle(e),void 0)},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setOptionDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._addClass(this.active,"ui-tabs-active","ui-state-active"),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this,i=this.tabs,s=this.anchors,n=this.panels;this.tablist=this._getList().attr("role","tablist"),this._addClass(this.tablist,"ui-tabs-nav","ui-helper-reset ui-helper-clearfix ui-widget-header"),this.tablist.on("mousedown"+this.eventNamespace,"> li",function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).on("focus"+this.eventNamespace,".ui-tabs-anchor",function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").attr({role:"tab",tabIndex:-1}),this._addClass(this.tabs,"ui-tabs-tab","ui-state-default"),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).attr({role:"presentation",tabIndex:-1}),this._addClass(this.anchors,"ui-tabs-anchor"),this.panels=t(),this.anchors.each(function(i,s){var n,o,a,r=t(s).uniqueId().attr("id"),h=t(s).closest("li"),l=h.attr("aria-controls");e._isLocal(s)?(n=s.hash,a=n.substring(1),o=e.element.find(e._sanitizeSelector(n))):(a=h.attr("aria-controls")||t({}).uniqueId()[0].id,n="#"+a,o=e.element.find(n),o.length||(o=e._createPanel(a),o.insertAfter(e.panels[i-1]||e.tablist)),o.attr("aria-live","polite")),o.length&&(e.panels=e.panels.add(o)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":a,"aria-labelledby":r}),o.attr("aria-labelledby",r)}),this.panels.attr("role","tabpanel"),this._addClass(this.panels,"ui-tabs-panel","ui-widget-content"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol, ul").eq(0)},_createPanel:function(e){return t("
    ").attr("id",e).data("ui-tabs-destroy",!0)},_setOptionDisabled:function(e){var i,s,n;for(t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1),n=0;s=this.tabs[n];n++)i=t(s),e===!0||-1!==t.inArray(n,e)?(i.attr("aria-disabled","true"),this._addClass(i,null,"ui-state-disabled")):(i.removeAttr("aria-disabled"),this._removeClass(i,null,"ui-state-disabled"));this.options.disabled=e,this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,e===!0)},_setupEvents:function(e){var i={};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(t){t.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){o._addClass(i.newTab.closest("li"),"ui-tabs-active","ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){o._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),n()}):(this._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+t.ui.escapeSelector(e)+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.tablist.removeAttr("role").off(this.eventNamespace),this.anchors.removeAttr("role tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeAttr("role tabIndex aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(e){var i=this.options.disabled;i!==!1&&(void 0===e?i=!1:(e=this._getIndex(e),i=t.isArray(i)?t.map(i,function(t){return t!==e?t:null}):t.map(this.tabs,function(t,i){return i!==e?i:null})),this._setOptionDisabled(i))},disable:function(e){var i=this.options.disabled;if(i!==!0){if(void 0===e)i=!0;else{if(e=this._getIndex(e),-1!==t.inArray(e,i))return;i=t.isArray(i)?t.merge([e],i).sort():[e]}this._setOptionDisabled(i)}},load:function(e,i){e=this._getIndex(e);var s=this,n=this.tabs.eq(e),o=n.find(".ui-tabs-anchor"),a=this._getPanelForTab(n),r={tab:n,panel:a},h=function(t,e){"abort"===e&&s.panels.stop(!1,!0),s._removeClass(n,"ui-tabs-loading"),a.removeAttr("aria-busy"),t===s.xhr&&delete s.xhr};this._isLocal(o[0])||(this.xhr=t.ajax(this._ajaxSettings(o,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(this._addClass(n,"ui-tabs-loading"),a.attr("aria-busy","true"),this.xhr.done(function(t,e,n){setTimeout(function(){a.html(t),s._trigger("load",i,r),h(n,e)},1)}).fail(function(t,e){setTimeout(function(){h(t,e)},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href").replace(/#.*$/,""),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),t.uiBackCompat!==!1&&t.widget("ui.tabs",t.ui.tabs,{_processTabs:function(){this._superApply(arguments),this._addClass(this.tabs,"ui-tab")}}),t.ui.tabs,t.widget("ui.tooltip",{version:"1.12.1",options:{classes:{"ui-tooltip":"ui-corner-all ui-widget-shadow"},content:function(){var e=t(this).attr("title")||"";return t("").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,track:!1,close:null,open:null},_addDescribedBy:function(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))},_removeDescribedBy:function(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.liveRegion=t("
    ").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this.disabledTitles=t([])},_setOption:function(e,i){var s=this;this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e.element)})},_setOptionDisabled:function(t){this[t?"_disable":"_enable"]()},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s.element[0],e.close(n,!0)}),this.disabledTitles=this.disabledTitles.add(this.element.find(this.options.items).addBack().filter(function(){var e=t(this);return e.is("[title]")?e.data("ui-tooltip-title",e.attr("title")).removeAttr("title"):void 0}))},_enable:function(){this.disabledTitles.each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))}),this.disabledTitles=t([])},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(e,s),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s||s.nodeType||s.jquery?this._open(e,t,s):(i=s.call(t[0],function(i){n._delay(function(){t.data("ui-tooltip-open")&&(e&&(e.type=o),this._open(e,t,i))})}),i&&this._open(e,t,i),void 0)},_open:function(e,i,s){function n(t){l.of=t,a.is(":hidden")||a.position(l)}var o,a,r,h,l=t.extend({},this.options.position);if(s){if(o=this._find(i))return o.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(e&&"mouseover"===e.type?i.attr("title",""):i.removeAttr("title")),o=this._tooltip(i),a=o.tooltip,this._addDescribedBy(i,a.attr("id")),a.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),h=t("
    ").html(a.find(".ui-tooltip-content").html()),h.removeAttr("name").find("[name]").removeAttr("name"),h.removeAttr("id").find("[id]").removeAttr("id"),h.appendTo(this.liveRegion),this.options.track&&e&&/^mouse/.test(e.type)?(this._on(this.document,{mousemove:n}),n(e)):a.position(t.extend({of:i},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.track&&this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){a.is(":visible")&&(n(l.of),clearInterval(r))},t.fx.interval)),this._trigger("open",e,{tooltip:a})}},_registerCloseHandlers:function(e,i){var s={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var s=t.Event(e);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),e&&"mouseover"!==e.type||(s.mouseleave="close"),e&&"focusin"!==e.type||(s.focusout="close"),this._on(!0,i,s)},close:function(e){var i,s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);return o?(i=o.tooltip,o.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),o.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),o.closing=!0,this._trigger("close",e,{tooltip:i}),o.hiding||(o.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(e){var i=t("
    ").attr("role","tooltip"),s=t("
    ").appendTo(i),n=i.uniqueId().attr("id");return this._addClass(s,"ui-tooltip-content"),this._addClass(i,"ui-tooltip","ui-widget ui-widget-content"),i.appendTo(this._appendTo(e)),this.tooltips[n]={element:e,tooltip:i}},_find:function(t){var e=t.data("ui-tooltip-id");return e?this.tooltips[e]:null},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_appendTo:function(t){var e=t.closest(".ui-front, dialog");return e.length||(e=this.document[0].body),e},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur"),o=s.element;n.target=n.currentTarget=o[0],e.close(n,!0),t("#"+i).remove(),o.data("ui-tooltip-title")&&(o.attr("title")||o.attr("title",o.data("ui-tooltip-title")),o.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}}),t.uiBackCompat!==!1&&t.widget("ui.tooltip",t.ui.tooltip,{options:{tooltipClass:null},_tooltip:function(){var t=this._superApply(arguments);return this.options.tooltipClass&&t.tooltip.addClass(this.options.tooltipClass),t}}),t.ui.tooltip}); \ No newline at end of file diff --git a/bootstrapTheme/templates/bootstrapTheme/bootstrapTheme.html b/bootstrapTheme/templates/bootstrapTheme/bootstrapTheme.html index a736f20..b289368 100644 --- a/bootstrapTheme/templates/bootstrapTheme/bootstrapTheme.html +++ b/bootstrapTheme/templates/bootstrapTheme/bootstrapTheme.html @@ -1,62 +1,72 @@ -{% load sekizai_tags staticfiles %} - - -{% addtoblock "css" strip %} {% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} - -{% addtoblock "css" %} - -{% endaddtoblock %} - - - -{% addtoblock "js" strip %} {% endaddtoblock %} -{% addtoblock "js" strip %} {% endaddtoblock %} -{% addtoblock "js" strip %} {% endaddtoblock %} -{% addtoblock "js" strip %} {% endaddtoblock %} -{% addtoblock "js" strip %} {% endaddtoblock %} -{% addtoblock "js" strip %} {% endaddtoblock %} - -{% addtoblock "js" %} +{% load sekizai_tags static %} {% addtoblock "css" strip %} +{% endaddtoblock %} {% addtoblock "css" strip %} + +{% endaddtoblock %} {% addtoblock "css" strip %} +{% endaddtoblock %} {% addtoblock "css" strip %} +{% endaddtoblock %} {% addtoblock "css" strip %} + +{% endaddtoblock %} {% addtoblock "css" strip %} +{% endaddtoblock %} {% addtoblock "css" %} + +{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "js" %} {% endaddtoblock %} - - diff --git a/eventplanner/admin.py b/eventplanner/admin.py index 97acf0e..e81db37 100644 --- a/eventplanner/admin.py +++ b/eventplanner/admin.py @@ -1,20 +1,69 @@ -#from django.contrib import admin -#from eventplanner.models import Event, EventParticipation -# -# -#class EventParticipationInline(admin.TabularInline): -# model = EventParticipation -# extra = 1 -# readonly_fields = ('user',) -# fields = ('user', 'status', 'comment',) -# has_add_permission = lambda self, req: False -# has_delete_permission = lambda self, req, obj: False -# -# template = "eventplanner/admin_tabular.html" -# -# -#class EventAdmin(admin.ModelAdmin): -# inlines = (EventParticipationInline,) -# -# -#admin.site.register(Event, EventAdmin) +from django.contrib import admin + +from .models import Event, EventParticipation + + +class EventParticipationInline(admin.TabularInline): + """Inline admin for event participations.""" + + model = EventParticipation + extra = 0 + readonly_fields = ("user",) + fields = ("user", "status", "comment") + + def has_add_permission(self, request, obj=None): + return False + + def has_delete_permission(self, request, obj=None): + return False + + +@admin.register(Event) +class EventAdmin(admin.ModelAdmin): + """Admin configuration for Event model.""" + + list_display = ("title", "type", "date", "time", "location") + list_filter = ("type", "date") + search_fields = ("short_desc", "location", "desc") + date_hierarchy = "date" + ordering = ("-date",) + + inlines = (EventParticipationInline,) + + fieldsets = ( + ( + None, + { + "fields": ("type", "short_desc", "date", "end_date"), + }, + ), + ( + "Time", + { + "fields": ("time", "meeting_time"), + }, + ), + ( + "Location", + { + "fields": ("location", "map_location"), + }, + ), + ( + "Description", + { + "fields": ("desc",), + "classes": ("collapse",), + }, + ), + ) + + +@admin.register(EventParticipation) +class EventParticipationAdmin(admin.ModelAdmin): + """Admin configuration for EventParticipation model.""" + + list_display = ("event", "user", "status", "comment") + list_filter = ("status", "event__date") + search_fields = ("user__username", "event__short_desc", "comment") + raw_id_fields = ("event", "user") diff --git a/eventplanner/migrations/0001_initial.py b/eventplanner/migrations/0001_initial.py new file mode 100644 index 0000000..27d3f19 --- /dev/null +++ b/eventplanner/migrations/0001_initial.py @@ -0,0 +1,55 @@ +# Generated by Django 5.1.15 on 2026-03-30 19:15 + +import django.db.models.deletion +import location_field.models +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Event', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('type', models.CharField(choices=[('Reh', 'Rehearsal'), ('Conc', 'Concert'), ('Party', 'Party'), ('Travel', 'Travel'), ('Option', 'Option')], default='Reh', max_length=6, verbose_name='type')), + ('short_desc', models.CharField(blank=True, max_length=100, null=True, verbose_name='Short Description')), + ('location', models.TextField(blank=True, verbose_name='location')), + ('map_location', location_field.models.PlainLocationField(based_field=models.TextField(blank=True, verbose_name='location'), blank=True, max_length=63, verbose_name='Location on map', zoom=7)), + ('desc', models.TextField(blank=True, verbose_name='description')), + ('date', models.DateField(verbose_name='date')), + ('time', models.TimeField(blank=True, null=True, verbose_name='time')), + ('meeting_time', models.TimeField(blank=True, null=True, verbose_name='meeting_time')), + ('end_date', models.DateField(blank=True, null=True, verbose_name='End Date')), + ], + options={ + 'ordering': ['date', 'time'], + }, + ), + migrations.CreateModel( + name='EventParticipation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status', models.CharField(choices=[('?', '?'), ('Yes', 'Yes'), ('No', 'No'), ('-', '-')], default='?', max_length=3, verbose_name='status')), + ('comment', models.CharField(blank=True, max_length=64, verbose_name='comment')), + ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eventplanner.event', verbose_name='event')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user')), + ], + options={ + 'permissions': (('admin', 'Admin'), ('member', 'Member')), + 'unique_together': {('event', 'user')}, + }, + ), + migrations.AddField( + model_name='event', + name='participants', + field=models.ManyToManyField(through='eventplanner.EventParticipation', to=settings.AUTH_USER_MODEL, verbose_name='participants'), + ), + ] diff --git a/eventplanner/migrations/__init__.py b/eventplanner/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/eventplanner/models.py b/eventplanner/models.py index 1a5a7c7..67e29c9 100644 --- a/eventplanner/models.py +++ b/eventplanner/models.py @@ -1,9 +1,10 @@ -from django.db import models -from django.utils.translation import ugettext as _ -from django.contrib.auth.models import User, Permission -from django.db.models import Q - from datetime import datetime + +from django.contrib.auth.models import Permission, User +from django.db import models +from django.db.models import Q +from django.utils.translation import gettext_lazy as _ + from location_field.models import PlainLocationField @@ -14,38 +15,53 @@ class NoNextEventException(Exception): class Event(models.Model): EVENT_TYPES = ( - ('Reh', _('Rehearsal')), - ('Conc', _('Concert')), - ('Party', _('Party')), - ('Travel', _('Travel')), - ('Option', _('Option')), + ("Reh", _("Rehearsal")), + ("Conc", _("Concert")), + ("Party", _("Party")), + ("Travel", _("Travel")), + ("Option", _("Option")), ) - type = models.CharField(max_length=6, choices=EVENT_TYPES, default='Reh', verbose_name=_("type")) - short_desc = models.CharField(null=True, max_length=100, blank=True, verbose_name=_("Short Description")) + type = models.CharField( + max_length=6, choices=EVENT_TYPES, default="Reh", verbose_name=_("type") + ) + short_desc = models.CharField( + null=True, max_length=100, blank=True, verbose_name=_("Short Description") + ) location = models.TextField(blank=True, verbose_name=_("location")) - map_location = PlainLocationField(blank=True, based_field=location, zoom=7, verbose_name=_("Location on map")) + map_location = PlainLocationField( + blank=True, based_field=location, zoom=7, verbose_name=_("Location on map") + ) desc = models.TextField(blank=True, verbose_name=_("description")) date = models.DateField(verbose_name=_("date")) time = models.TimeField(null=True, blank=True, verbose_name=_("time")) - meeting_time = models.TimeField(null=True, blank=True, verbose_name=_("meeting_time")) + meeting_time = models.TimeField( + null=True, blank=True, verbose_name=_("meeting_time") + ) end_date = models.DateField(null=True, blank=True, verbose_name=_("End Date")) - participants = models.ManyToManyField(User, through='EventParticipation', verbose_name=_("participants")) + participants = models.ManyToManyField( + User, through="EventParticipation", verbose_name=_("participants") + ) - def __unicode__(self): + class Meta: + ordering = ["date", "time"] + + def __str__(self): return self.title def save(self, *args, **kwargs): # Call the "real" save() method - super(Event, self).save(*args, **kwargs) + super().save(*args, **kwargs) - # Create a "Don't Know" participation for each Musician + # Create a "Don't Know" participation for each Musician for u in User.objects.all(): - if not u in self.participants.all(): - EventParticipation.objects.create(event=self, user=u, status='-', comment='') + if u not in self.participants.all(): + EventParticipation.objects.create( + event=self, user=u, status="-", comment="" + ) @property def title(self): @@ -64,7 +80,7 @@ class Event(models.Model): @property def displaydatetime(self): - if not self.displaytime == None: + if self.displaytime is not None: return datetime.combine(self.date, self.displaytime) else: return datetime.combine(self.date, datetime.min.time()) @@ -72,14 +88,18 @@ class Event(models.Model): @staticmethod def getNextEvent(eventType="", includePreviousFromToday=True): """Return the next event, of the given type. If type is the empty string the next event is returned - regardless of its type. - if includePreviousFromToday the nextEvent returned could also have been today with a startime < now """ + regardless of its type. + if includePreviousFromToday the nextEvent returned could also have been today with a startime < now""" if includePreviousFromToday: if eventType == "": - nextEvents = Event.objects.filter(date__gte=datetime.now()).order_by('date')[:1] + nextEvents = Event.objects.filter(date__gte=datetime.now()).order_by( + "date" + )[:1] else: - nextEvents = Event.objects.filter(date__gte=datetime.now(), type=eventType).order_by('date')[:1] + nextEvents = Event.objects.filter( + date__gte=datetime.now(), type=eventType + ).order_by("date")[:1] if len(nextEvents) == 0: raise NoNextEventException() @@ -89,11 +109,13 @@ class Event(models.Model): maximalNumberOfEventsOnSameDay = 4 nextEvents = [] if eventType == "": - nextEvents = Event.objects.filter(date__gte=datetime.now()).order_by('date')[ - :maximalNumberOfEventsOnSameDay] + nextEvents = Event.objects.filter(date__gte=datetime.now()).order_by( + "date" + )[:maximalNumberOfEventsOnSameDay] else: - nextEvents = Event.objects.filter(date__gte=datetime.now(), type=eventType).order_by('date')[ - :maximalNumberOfEventsOnSameDay] + nextEvents = Event.objects.filter( + date__gte=datetime.now(), type=eventType + ).order_by("date")[:maximalNumberOfEventsOnSameDay] if len(nextEvents) == 0: raise NoNextEventException() @@ -112,28 +134,38 @@ class Event(models.Model): class EventParticipation(models.Model): - OPTIONS = (('?', _('?')), - ('Yes', _('Yes')), - ('No', _('No')), - ('-', _('-')) - ) + OPTIONS = ( + ("?", _("?")), + ("Yes", _("Yes")), + ("No", _("No")), + ("-", _("-")), + ) - event = models.ForeignKey(Event, verbose_name=_("event"), on_delete=models.PROTECT) - user = models.ForeignKey(User, verbose_name=_("user"), on_delete=models.PROTECT) - status = models.CharField(max_length=3, choices=OPTIONS, default='?', verbose_name=_("status")) + event = models.ForeignKey(Event, on_delete=models.CASCADE, verbose_name=_("event")) + user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_("user")) + status = models.CharField( + max_length=3, choices=OPTIONS, default="?", verbose_name=_("status") + ) comment = models.CharField(max_length=64, blank=True, verbose_name=_("comment")) + class Meta: + unique_together = ("event", "user") + permissions = ( + ("admin", _("Admin")), + ("member", _("Member")), + ) + def get_username(self): return self.user.username def save(self, *args, **kwargs): prev = EventParticipation.objects.filter(event=self.event, user=self.user) if len(prev) == 0: - super(EventParticipation, self).save(*args, **kwargs) + super().save(*args, **kwargs) else: prev = prev[0] if prev.status != self.status or prev.comment != self.comment: - super(EventParticipation, self).save(*args, **kwargs) + super().save(*args, **kwargs) @staticmethod def hasUserSetParticipationForAllEvents(user): @@ -142,7 +174,7 @@ class EventParticipation(models.Model): futurePart = EventParticipation.objects.filter(event__date__gte=datetime.now()) - notYetEntered = futurePart.filter(user=user).filter(status='-') + notYetEntered = futurePart.filter(user=user).filter(status="-") if len(notYetEntered) > 0: return False else: @@ -150,30 +182,27 @@ class EventParticipation(models.Model): @staticmethod def isMember(user): - return user.has_perm('eventplanner.member') + return user.has_perm("eventplanner.member") @staticmethod def isAdmin(user): - return user.has_perm('eventplanner.admin') + return user.has_perm("eventplanner.admin") @staticmethod def members(): - perm = Permission.objects.get(codename='member') - f = User.objects.filter(Q(groups__permissions=perm) | Q(user_permissions=perm)).distinct() - return f.order_by('musician__position') + perm = Permission.objects.get(codename="member") + f = User.objects.filter( + Q(groups__permissions=perm) | Q(user_permissions=perm) + ).distinct() + return f.order_by("musician__position") @staticmethod def get_or_create(user, event): try: result = EventParticipation.objects.get(event=event, user=user) except EventParticipation.DoesNotExist: - result = EventParticipation.objects.create(event=event, user=user, status='-', comment='') + result = EventParticipation.objects.create( + event=event, user=user, status="-", comment="" + ) return result - - class Meta: - unique_together = ("event", "user") - permissions = ( - ("admin", _("Admin")), - ("member", _("Member")), - ) diff --git a/eventplanner/serializers.py b/eventplanner/serializers.py index 910b5ce..5c02c10 100644 --- a/eventplanner/serializers.py +++ b/eventplanner/serializers.py @@ -1,19 +1,24 @@ from rest_framework import serializers -from .models import EventParticipation, Event + +from .models import Event, EventParticipation class ParticipationSerializer(serializers.ModelSerializer): - event = serializers.PrimaryKeyRelatedField(many=False, read_only=False, queryset=Event.objects.all()) - user = serializers.Field(source='get_username') - status = serializers.CharField(source='status', required=False) - - def get_identity(self, data): - """ This hook is required for bulk update. """ - try: - return data.get('event', None), data.get('user') - except AttributeError: - return None + event = serializers.PrimaryKeyRelatedField(queryset=Event.objects.all()) + user = serializers.CharField(source="get_username", read_only=True) + status = serializers.CharField(required=False) class Meta: model = EventParticipation - fields = ('event', 'user', 'status', 'comment') + fields = ("event", "user", "status", "comment") + + def create(self, validated_data): + # Remove the get_username source field as it's read-only + validated_data.pop("get_username", None) + return super().create(validated_data) + + def update(self, instance, validated_data): + instance.status = validated_data.get("status", instance.status) + instance.comment = validated_data.get("comment", instance.comment) + instance.save() + return instance diff --git a/eventplanner/snippets.py b/eventplanner/snippets.py index 1aef148..4f32059 100644 --- a/eventplanner/snippets.py +++ b/eventplanner/snippets.py @@ -1,50 +1,58 @@ from datetime import datetime -from .models import Event, EventParticipation, NoNextEventException + from musicians.models import Musician +from .models import Event, EventParticipation, NoNextEventException + def addEventCountdownForNextEventToContext(context, username, eventType=""): - """Returns an object that has to be added to the render context on the page where the countdown - should be displayed . The username is required to also supply participation information.""" + """Returns an object that has to be added to the render context on the page where the countdown + should be displayed. The username is required to also supply participation information.""" try: nextEvent = Event.getNextEvent(eventType, False) except NoNextEventException: return - countdown = dict() + countdown = {} if EventParticipation.isMember(username): part = EventParticipation.objects.filter(user=username).filter(event=nextEvent) - countdown['participation'] = part[0].status + if part.exists(): + countdown["participation"] = part[0].status eventTime = nextEvent.displaydatetime - countdown['event'] = nextEvent - countdown['epoch'] = int((eventTime - datetime.now()).total_seconds() * 1000) + countdown["event"] = nextEvent + countdown["epoch"] = int((eventTime - datetime.now()).total_seconds() * 1000) context["countdown"] = countdown def addEventRouteForNextEventToContext(context, username, eventType=""): - """Returns an object that has to be added to the render context on the page where the route - should be displayed . The starting address of the route will be the home of the specified user""" + """Returns an object that has to be added to the render context on the page where the route + should be displayed. The starting address of the route will be the home of the specified user""" try: nextEvent = Event.getNextEvent(eventType, True) except NoNextEventException: return - routeInfo = dict() + routeInfo = {} - routeInfo['event'] = nextEvent + routeInfo["event"] = nextEvent - musician = Musician.objects.get(user=username); - routeInfo['origin'] = musician.street + ", " + str(musician.zip_code) + " " + musician.city + try: + musician = Musician.objects.get(user=username) + routeInfo["origin"] = ( + musician.street + ", " + str(musician.zip_code) + " " + musician.city + ) + except Musician.DoesNotExist: + routeInfo["origin"] = "" if nextEvent.map_location: - # map_location has format "lat,longitute,zoomlevel" - routeInfo['destination'] = ",".join(nextEvent.map_location.split(",")[:2]) + # map_location has format "lat,longitude,zoomlevel" + routeInfo["destination"] = ",".join(nextEvent.map_location.split(",")[:2]) else: - routeInfo['destination'] = nextEvent.location + routeInfo["destination"] = nextEvent.location context["route"] = routeInfo diff --git a/eventplanner/templates/eventplanner/admin_tabular.html b/eventplanner/templates/eventplanner/admin_tabular.html index 355cc9a..0b5c31a 100644 --- a/eventplanner/templates/eventplanner/admin_tabular.html +++ b/eventplanner/templates/eventplanner/admin_tabular.html @@ -1,4 +1,4 @@ -{% load i18n admin_static admin_modify %} +{% load i18n static admin_modify %}
    +
    {% endif %} diff --git a/eventplanner/templates/eventplanner/event_update_form.html b/eventplanner/templates/eventplanner/event_update_form.html index 4e33d09..807f6b3 100644 --- a/eventplanner/templates/eventplanner/event_update_form.html +++ b/eventplanner/templates/eventplanner/event_update_form.html @@ -1,138 +1,131 @@ -{% extends "website/base.html" %} - -{% load sekizai_tags staticfiles %} -{% load crispy_forms_tags %} - - - -{% block content %} - +{% extends "website/base.html" %} {% load sekizai_tags static %} {% load crispy_forms_tags %} {% block content %} {{ form.media }}
    -
    -
    -

    Termin bearbeiten

    +
    +
    +

    Termin bearbeiten

    - {% crispy form %} - -
    -
    + {% crispy form %} +
    +
    - - - - -{% addtoblock "css" strip %} - -{% endaddtoblock %} +{% addtoblock "css" strip %} +{% endaddtoblock %} {% addtoblock "css" strip %} +{% endaddtoblock %} {% addtoblock "css" strip %} +{% endaddtoblock %} {% addtoblock "js" %} + + + - -{% addtoblock "js" %} - - -{% endaddtoblock %} - - - -{% endblock %} - - - +{% endaddtoblock %} {% endblock %} diff --git a/eventplanner/templates/eventplanner/eventplanning_view.html b/eventplanner/templates/eventplanner/eventplanning_view.html index 7cc5ec8..bdd74da 100644 --- a/eventplanner/templates/eventplanner/eventplanning_view.html +++ b/eventplanner/templates/eventplanner/eventplanning_view.html @@ -1,10 +1,10 @@ {% extends "website/base.html" %} -{% load sekizai_tags staticfiles %} +{% load sekizai_tags static %} {% block content %} - + {% addtoblock "css" %} - {% endaddtoblock %} - + {% endaddtoblock %} + {% addtoblock "js" %} - + {% endaddtoblock %} - +
    @@ -249,7 +256,7 @@
    {% endif %} - +
    diff --git a/eventplanner/templates/eventplanner/routeToEventMap.inc.html b/eventplanner/templates/eventplanner/routeToEventMap.inc.html index 5cb3fb1..52d6c05 100644 --- a/eventplanner/templates/eventplanner/routeToEventMap.inc.html +++ b/eventplanner/templates/eventplanner/routeToEventMap.inc.html @@ -1,208 +1,215 @@ -{% comment %} - Displays google map with directions to next conert - - Context: - Coordinates or textual adresses: - {{route.origin}} - {{route.destination}} - Event object: - {{route.event}} -{% endcomment %} - - - - -{% load sekizai_tags staticfiles %} - - -{% if route %} - -{% addtoblock "css" strip %}{% endaddtoblock %} -{% addtoblock "js" strip %}{% endaddtoblock %} - - -{% addtoblock "js" %} +{% comment %} Displays google map with directions to next conert Context: +Coordinates or textual adresses: {{route.origin}} {{route.destination}} Event +object: {{route.event}} {% endcomment %} {% load sekizai_tags static %} +{% if route %} {% addtoblock "css" strip %}{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "js" %} {% endaddtoblock %} - - -
    -
    +
    -

    Nächstes Konzert

    - - - - - - - {% if route.event.meeting_time %} {% endif %} - - -
    Ort: {{route.event.location}}
    Datum: {{route.event.date | date:"D, d.m.y" }}
    Uhrzeit: {{route.event.time | time:"H:i" }} Uhr
    Treffen um: {{route.event.meeting_time | time:"H:i" }} Uhr
    Fahrzeit:
    Strecke:
    - - - -
    Schliessen + + + + + + + + + + + + + + {% if route.event.meeting_time %} + + + + + {% endif %} + + + + + + + + +
    Ort:{{route.event.location}}
    Datum:{{route.event.date | date:"D, d.m.y" }}
    Uhrzeit:{{route.event.time | time:"H:i" }} Uhr
    Treffen um: + {{route.event.meeting_time | time:"H:i" }} + Uhr +
    Fahrzeit:
    Strecke:
    + + Schliessen +
    -
    + + {% endif %}
    - - -{% endif %} \ No newline at end of file diff --git a/eventplanner/urls.py b/eventplanner/urls.py index 5824877..8418cb8 100644 --- a/eventplanner/urls.py +++ b/eventplanner/urls.py @@ -1,15 +1,21 @@ -from django.conf.urls import url -from django.contrib.auth.decorators import permission_required -from eventplanner.views import events_grid, eventplanning, event_api, EventUpdate, EventCreate, deleteEvent +from django.urls import path, re_path + +from . import views + +app_name = "eventplanner" urlpatterns = [ - url(r'^$', eventplanning), - url(r'^grid$', events_grid), - url(r'^planning$', eventplanning), - url(r'^(?P\d+)$', permission_required('eventplanner.change_event')(EventUpdate.as_view())), - url(r'^add$', permission_required('eventplanner.add_event')(EventCreate.as_view())), - url(r'^(?P\d+)/delete$', permission_required('eventplanner.delete_event')(deleteEvent)), - url(r'^api/', event_api, name="event_api"), - url(r'^api/(\w+)/$', event_api, name="event_api_per_user"), - url(r'^api/(\w+)/(\d+)$', event_api, name="event_api_per_user_event"), + path("", views.eventplanning, name="eventplanning"), + path("grid/", views.events_grid, name="events_grid"), + path("delete//", views.deleteEvent, name="delete_event"), + path("event//", views.EventUpdate.as_view(), name="event_update"), + path("event/create/", views.EventCreate.as_view(), name="event_create"), + # API endpoints + path("api/", views.event_api, name="event_api"), + path("api//", views.event_api, name="event_api_user"), + path( + "api///", + views.event_api, + name="event_api_user_event", + ), ] diff --git a/eventplanner/views.py b/eventplanner/views.py index 4489795..6ed68fb 100644 --- a/eventplanner/views.py +++ b/eventplanner/views.py @@ -1,29 +1,30 @@ -from django.shortcuts import render, redirect -from django.http import HttpResponse -from django.forms.models import ModelForm -from django.forms import TextInput, TimeInput - -from .models import Event, EventParticipation - -from .serializers import ParticipationSerializer - import datetime -from rest_framework.decorators import api_view -from rest_framework.response import Response -from rest_framework import status - from crispy_forms.helper import FormHelper from crispy_forms.layout import Submit +from django.forms import TextInput +from django.forms.models import ModelForm +from django.http import HttpResponse +from django.shortcuts import redirect, render +from django.views.generic.edit import CreateView, UpdateView +from rest_framework import status +from rest_framework.decorators import api_view +from rest_framework.response import Response +from location_field.widgets import LocationWidget + +from .models import Event, EventParticipation +from .serializers import ParticipationSerializer # ---------------------------------------- API --------------------------------------------------------- -@api_view(['GET', 'PUT']) +@api_view(["GET", "PUT"]) def event_api(request, username=None, eventId=None): try: - participationQs = EventParticipation.objects.filter(event__date__gte=datetime.date.today()) + participationQs = EventParticipation.objects.filter( + event__date__gte=datetime.date.today() + ) if username: participationQs = EventParticipation.objects.filter(user__username=username) if eventId: @@ -31,58 +32,70 @@ def event_api(request, username=None, eventId=None): except EventParticipation.DoesNotExist: return HttpResponse(status=404) - if request.method == 'GET': - serializer = ParticipationSerializer(participationQs) + if request.method == "GET": + serializer = ParticipationSerializer(participationQs, many=True) return Response(serializer.data) - elif request.method == 'PUT': - serializer = ParticipationSerializer(participationQs, data=request.DATA, many=True) + elif request.method == "PUT": + serializer = ParticipationSerializer(data=request.data, many=True) if serializer.is_valid(): - for serializedObject in serializer.object: - if not (EventParticipation.isMember(request.user) or EventParticipation.isAdmin(request.user)): + for item in serializer.validated_data: + event = item.get("event") + user_obj = item.get("user") + if not ( + EventParticipation.isMember(request.user) + or EventParticipation.isAdmin(request.user) + ): return Response(status=status.HTTP_403_FORBIDDEN) - if serializedObject.user != request.user: + if user_obj != request.user: if not EventParticipation.isAdmin(request.user): return Response(status=status.HTTP_403_FORBIDDEN) serializer.save() return Response(serializer.data) else: - return Response(status=status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # ------------------------------------ Normal Views ---------------------------------------------------- + def eventplanning(request): """ - View for a specific user, to edit his events + View for a specific user, to edit his events """ # non-members see the grid - but cannot edit anything if not EventParticipation.isMember(request.user): return events_grid(request) # All events in the future sorted by date - all_future_events = list(Event.objects.filter(date__gte=datetime.date.today()).order_by('date')) + all_future_events = list( + Event.objects.filter(date__gte=datetime.date.today()).order_by("date") + ) for e in all_future_events: e.participation = EventParticipation.get_or_create(event=e, user=request.user) - context = {'events': all_future_events} - return render(request, 'eventplanner/eventplanning_view.html', context) + context = {"events": all_future_events} + return render(request, "eventplanner/eventplanning_view.html", context) def events_grid(request): usernames = [u.username for u in EventParticipation.members()] - all_future_events = list(Event.objects.filter(date__gte=datetime.date.today()).order_by('date')) + all_future_events = list( + Event.objects.filter(date__gte=datetime.date.today()).order_by("date") + ) for e in all_future_events: - e.participation = [EventParticipation.get_or_create(event=e, user=u) for u in EventParticipation.members()] + e.participation = [ + EventParticipation.get_or_create(event=e, user=u) + for u in EventParticipation.members() + ] - context = {'events': all_future_events, - 'usernames': usernames} + context = {"events": all_future_events, "usernames": usernames} - return render(request, 'eventplanner/events_grid.html', context) + return render(request, "eventplanner/events_grid.html", context) def deleteEvent(request, pk): @@ -93,27 +106,30 @@ def deleteEvent(request, pk): # ------------------------------------ Detail Views ---------------------------------------------------- -from django.views.generic.edit import UpdateView, CreateView - -from location_field.widgets import LocationWidget - - class EventForm(ModelForm): def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self.helper = FormHelper() - self.helper.form_class = 'form-horizontal' - self.helper.add_input(Submit('submit', 'Speichern')) - super(EventForm, self).__init__(*args, **kwargs) + self.helper.form_class = "form-horizontal" + self.helper.add_input(Submit("submit", "Speichern")) class Meta: model = Event - fields = ['type', 'short_desc', 'date', 'end_date', 'time', 'meeting_time', 'location', 'map_location', - 'desc', ] + fields = [ + "type", + "short_desc", + "date", + "end_date", + "time", + "meeting_time", + "location", + "map_location", + "desc", + ] widgets = { - 'time': TimeInput(format='%H:%M'), - 'location': TextInput(), - 'map_location': LocationWidget(), + "location": TextInput(), + "map_location": LocationWidget(), } @@ -121,11 +137,11 @@ class EventUpdate(UpdateView): form_class = EventForm model = Event template_name_suffix = "_update_form" - success_url = '.' + success_url = "." def get_context_data(self, **kwargs): - context = super(UpdateView, self).get_context_data(**kwargs) - context['viewtype'] = "update" + context = super().get_context_data(**kwargs) + context["viewtype"] = "update" return context @@ -133,9 +149,9 @@ class EventCreate(CreateView): form_class = EventForm model = Event template_name_suffix = "_update_form" - success_url = '.' + success_url = "." def get_context_data(self, **kwargs): - context = super(CreateView, self).get_context_data(**kwargs) - context['viewtype'] = "create" + context = super().get_context_data(**kwargs) + context["viewtype"] = "create" return context diff --git a/eventplanner_gcal/__init__.py b/eventplanner_gcal/__init__.py index e69de29..d0419e0 100644 --- a/eventplanner_gcal/__init__.py +++ b/eventplanner_gcal/__init__.py @@ -0,0 +1,3 @@ +# eventplanner_gcal app +# Signals are loaded in apps.py AppConfig.ready() +default_app_config = "eventplanner_gcal.apps.EventplannerGcalConfig" diff --git a/eventplanner_gcal/apps.py b/eventplanner_gcal/apps.py new file mode 100644 index 0000000..b2d4b26 --- /dev/null +++ b/eventplanner_gcal/apps.py @@ -0,0 +1,14 @@ +from django.apps import AppConfig + + +class EventplannerGcalConfig(AppConfig): + """App configuration for eventplanner_gcal.""" + + name = "eventplanner_gcal" + verbose_name = "Event Planner Google Calendar Integration" + default_auto_field = "django.db.models.BigAutoField" + + def ready(self): + """Import signal handlers when the app is ready.""" + # Import signals to register them + from . import signals # noqa: F401 diff --git a/eventplanner_gcal/google_sync.py b/eventplanner_gcal/google_sync.py index 6c10b91..ce4591a 100644 --- a/eventplanner_gcal/google_sync.py +++ b/eventplanner_gcal/google_sync.py @@ -1,70 +1,112 @@ -import logging -import httplib2 +""" +Google Calendar synchronization module. + +This module handles synchronization between the local event database +and Google Calendar, including push notifications for real-time updates. +""" + import datetime +import logging import time +from django.conf import settings +from django.contrib.auth.models import User + from eventplanner.models import Event, EventParticipation from eventplanner_gcal.models import GCalMapping, GCalPushChannel, UserGCalCoupling -# noinspection PyUnresolvedReferences,PyUnresolvedReferences -from apiclient.http import BatchHttpRequest -from builtins import str as text # python2 and python3 -from django.conf import settings logger = logging.getLogger(__name__) +# Module-level service object cache +_service_object = None -# ---------------------------------- Authentication using oauth2 ----------------------------------------------------- def create_gcal_service_object(): - """Creates a Google API service object. This object is required whenever a Google API call is made""" - from oauth2client.file import Storage - # noinspection PyUnresolvedReferences - from apiclient.discovery import build + """ + Creates a Google API service object. - gcal_settings = settings.GCAL_COUPLING + This object is required whenever a Google API call is made. + Uses the new google-auth library instead of oauth2client. + """ + try: + import os + import pickle - storage = Storage(gcal_settings['credentials_file']) - credentials = storage.get() - - logger.debug("Credentials", credentials) - if credentials is None or credentials.invalid is True: - # flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES) - logger.error("Unable to initialize Google Calendar coupling. Check your settings!") + from google.auth.transport.requests import Request + from google.oauth2.credentials import Credentials + from google_auth_oauthlib.flow import InstalledAppFlow + from googleapiclient.discovery import build + except ImportError as e: + logger.error(f"Required Google API libraries not installed: {e}") return None - http = httplib2.Http() - http = credentials.authorize(http) - res = build(serviceName='calendar', version='v3', - http=http, developerKey=gcal_settings['developerKey']) + gcal_settings = settings.GCAL_COUPLING + credentials_file = gcal_settings["credentials_file"] - if res is None: - logger.error("Authentication at Google API failed. Check your settings!") - return res + creds = None + + # Try to load existing credentials + if os.path.exists(credentials_file): + try: + with open(credentials_file, "rb") as token: + creds = pickle.load(token) + except Exception as e: + logger.warning(f"Could not load credentials from {credentials_file}: {e}") + + # Check if credentials are valid + if creds and creds.expired and creds.refresh_token: + try: + creds.refresh(Request()) + # Save refreshed credentials + with open(credentials_file, "wb") as token: + pickle.dump(creds, token) + except Exception as e: + logger.error(f"Failed to refresh credentials: {e}") + creds = None + + if not creds or not creds.valid: + logger.error( + "Invalid or missing Google Calendar credentials. " + "Please run the credential setup process." + ) + return None + + try: + service = build("calendar", "v3", credentials=creds) + return service + except Exception as e: + logger.error(f"Failed to build Google Calendar service: {e}") + return None def get_service_object(): - if get_service_object.__serviceObject is None: - get_service_object.__serviceObject = create_gcal_service_object() - - return get_service_object.__serviceObject + """Get or create the Google Calendar service object.""" + global _service_object + if _service_object is None: + _service_object = create_gcal_service_object() + return _service_object -get_service_object.__serviceObject = None +def reset_service_object(): + """Reset the cached service object (useful for testing or credential refresh).""" + global _service_object + _service_object = None -# --------------------- Building GCal event representation ---------------------------------------------------------- +# --------------------- Building GCal event representation ------------------------------------ def build_gcal_attendees_obj(event): - """Builds an attendees object that is inserted into the GCal event. - Attendees are all users that have a google mail address.""" + """ + Builds an attendees object that is inserted into the GCal event. + + Attendees are all users that have a Google mail address. + """ result = [] - for userMapping in UserGCalCoupling.objects.all(): - u = userMapping.user + for user_mapping in UserGCalCoupling.objects.all(): + u = user_mapping.user - # No get or create here, since a create would trigger another synchronization - # participation = EventParticipation.get_or_create( u, event ) try: participation = EventParticipation.objects.get(event=event, user=u) local_status = participation.status @@ -76,31 +118,33 @@ def build_gcal_attendees_obj(event): status = "needsAction" if local_status == "?": status = "tentative" - elif local_status == 'Yes': + elif local_status == "Yes": status = "accepted" - elif local_status == 'No': + elif local_status == "No": status = "declined" - o = { - 'id': userMapping.email, - 'email': userMapping.email, - 'displayName': u.username, - 'comment': local_comment, - 'responseStatus': status, + attendee = { + "email": user_mapping.email, + "displayName": u.username, + "comment": local_comment, + "responseStatus": status, } - result.append(o) + result.append(attendee) return result def build_gcal_event(event, timezone="Europe/Berlin"): - """ Builds a GCal event using a local event. """ + """Builds a GCal event using a local event.""" - def create_date_time_obj(date, time_obj): - if time_obj is None: - return {'date': text(date), 'timeZone': timezone} + def create_datetime_obj(date, time_val): + if time_val is None: + return {"date": str(date), "timeZone": timezone} else: - return {'dateTime': text(date) + 'T' + text(time_obj), 'timeZone': timezone} + return { + "dateTime": f"{date}T{time_val}", + "timeZone": timezone, + } start_date = event.date end_date = event.end_date @@ -116,251 +160,356 @@ def build_gcal_event(event, timezone="Europe/Berlin"): else: end_time = datetime.time(22, 30) - g_location = text(event.location) + g_location = str(event.location) if event.map_location: # Map location has the following format: latitude,longitude,zoomlevel # the first two are needed - s = event.map_location.split(",") - g_location = text("%s,%s" % (s[0], s[1])) + parts = event.map_location.split(",") + if len(parts) >= 2: + g_location = f"{parts[0]},{parts[1]}" + + gcal_settings = settings.GCAL_COUPLING return { - 'summary': text(settings.GCAL_COUPLING['eventPrefix'] + event.title), - 'description': text(event.desc), - 'location': g_location, - 'start': create_date_time_obj(start_date, start_time), - 'end': create_date_time_obj(end_date, end_time), - 'extendedProperties': { - 'private': { - 'blechreizEvent': 'true', - 'blechreizID': event.id, + "summary": gcal_settings["eventPrefix"] + event.title, + "description": str(event.desc), + "location": g_location, + "start": create_datetime_obj(start_date, start_time), + "end": create_datetime_obj(end_date, end_time), + "extendedProperties": { + "private": { + "blechreizEvent": "true", + "blechreizID": str(event.id), } }, - 'attendees': build_gcal_attendees_obj(event), + "attendees": build_gcal_attendees_obj(event), } -# ------------------------------ Callback Functions ------------------------------------------------------------------- +# ------------------------------ Callback Functions ------------------------------------------------ -def on_gcal_event_created(_, response, exception=None): - """Callback function for created events to enter new gcal id in the mapping table""" + +def on_gcal_event_created(request_id, response, exception=None): + """Callback function for created events to enter new gcal id in the mapping table.""" if exception is not None: - logger.error("on_gcal_event_created: Exception " + str(exception)) + logger.error(f"Error creating GCal event: {exception}") raise exception - google_id = response['id'] - django_id = response['extendedProperties']['private']['blechreizID'] - mapping = GCalMapping(gcal_id=google_id, event=Event.objects.get(pk=django_id)) - mapping.save() + google_id = response["id"] + django_id = response["extendedProperties"]["private"]["blechreizID"] + + try: + event = Event.objects.get(pk=django_id) + mapping = GCalMapping(gcal_id=google_id, event=event) + mapping.save() + logger.info(f"Created mapping: GCal {google_id} <-> Event {django_id}") + except Event.DoesNotExist: + logger.error(f"Event {django_id} not found when creating GCal mapping") -# ------------------------------ GCal Api Calls -------------------------------------------------------------------- +# ------------------------------ GCal Api Calls ------------------------------------------------- + def get_all_gcal_events(service, from_now=False): - """Retrieves all gcal events with custom property blechreizEvent=True i.e. all - events that have been created by this script.""" + """ + Retrieves all gcal events with custom property blechreizEvent=True. + These are all events that have been created by this script. + """ if from_now: now = datetime.datetime.now() min_time = now.strftime("%Y-%m-%dT%H:%M:%S-00:00") else: - min_time = '2000-01-01T00:00:00-00:00' + min_time = "2000-01-01T00:00:00-00:00" - events = service.events().list( - calendarId='primary', - singleEvents=True, - maxResults=1000, - orderBy='startTime', - timeMin=min_time, - timeMax='2100-01-01T00:00:00-00:00', - privateExtendedProperty='blechreizEvent=true', - ).execute() - return events['items'] + try: + events = ( + service.events() + .list( + calendarId="primary", + singleEvents=True, + maxResults=1000, + orderBy="startTime", + timeMin=min_time, + timeMax="2100-01-01T00:00:00-00:00", + privateExtendedProperty="blechreizEvent=true", + ) + .execute() + ) + return events.get("items", []) + except Exception as e: + logger.error(f"Failed to retrieve GCal events: {e}") + return [] -def create_gcal_event(service, event, timezone="Europe/Berlin"): - """Creates a new gcal event using a local event""" +def create_gcal_event_request(service, event, timezone="Europe/Berlin"): + """Creates a request to create a new gcal event using a local event.""" google_event = build_gcal_event(event, timezone) - return service.events().insert(calendarId='primary', body=google_event) + return service.events().insert(calendarId="primary", body=google_event) -def update_gcal_event(service, event, timezone="Europe/Berlin"): - """Updates an existing gcal event, using a local event""" +def update_gcal_event_request(service, event, timezone="Europe/Berlin"): + """Creates a request to update an existing gcal event using a local event.""" google_event = build_gcal_event(event, timezone) try: mapping = GCalMapping.objects.get(event=event) except GCalMapping.DoesNotExist: - return create_gcal_event(service, event, timezone) + return create_gcal_event_request(service, event, timezone) - return service.events().patch(calendarId='primary', eventId=mapping.gcal_id, body=google_event) + return service.events().patch( + calendarId="primary", eventId=mapping.gcal_id, body=google_event + ) -def delete_gcal_event(service, event): - """Deletes gcal that belongs to the given local event""" - mapping = GCalMapping.objects.get(event=event) - gcal_id = mapping.gcal_id - mapping.delete() - return service.events().delete(calendarId='primary', eventId=gcal_id) - - -# ------------------------------------- Synchronization ------------------------------------------------------------- - -def delete_all_gcal_events(service=None): - """Deletes all gcal events that have been created by this script""" - - if service is None: - service = get_service_object() - - gcal_ids = [ev['id'] for ev in get_all_gcal_events(service)] - num_ids = len(gcal_ids) - if num_ids == 0: - return num_ids - - batch = BatchHttpRequest() - for ev_id in gcal_ids: - batch.add(service.events().delete(calendarId='primary', eventId=ev_id)) - batch.execute() - - GCalMapping.objects.all().delete() - - return num_ids - - -def sync_from_local_to_google(service=None): - """ Creates a google event for each local event (if it does not exist yet) and deletes all google events - that are not found in local database. Updates participation info of gcal events using local data - """ - - if service is None: - service = get_service_object() - - all_events = get_all_gcal_events(service) - - events_at_google_django_id = set() - events_at_google_google_id = set() - for gcal_ev in all_events: - events_at_google_django_id.add(int(gcal_ev['extendedProperties']['private']['blechreizID'])) - events_at_google_google_id.add(gcal_ev['id']) - - local_events_django_id = set(Event.objects.all().values_list('pk', flat=True)) - local_events_google_id = set(GCalMapping.objects.all().values_list('gcal_id', flat=True)) - - events_to_create_django_id = local_events_django_id - events_at_google_django_id - events_to_delete_google_id = events_at_google_google_id - local_events_google_id - - batch = BatchHttpRequest() - - batch_is_empty = True - for event_django_id in events_to_create_django_id: - batch.add(create_gcal_event(service, Event.objects.get(pk=event_django_id)), callback=on_gcal_event_created) - batch_is_empty = False - - for eventGoogleID in events_to_delete_google_id: - batch.add(service.events().delete(calendarId='primary', eventId=eventGoogleID)) - batch_is_empty = False - - for gcal_ev in all_events: - event_django_id = int(gcal_ev['extendedProperties']['private']['blechreizID']) - try: - django_ev = Event.objects.get(pk=event_django_id) - if 'attendees' not in gcal_ev: - gcal_ev['attendees'] = [] - - if gcal_ev['attendees'] != build_gcal_attendees_obj(django_ev): - batch.add(update_gcal_event(service, django_ev)) - batch_is_empty = False - except Event.DoesNotExist: - pass - - if not batch_is_empty: - batch.execute() - - return len(events_to_create_django_id), len(events_to_delete_google_id) - - -def sync_from_google_to_local(service=None): - """Retrieves only participation infos for all events and updates local database if anything has changed. """ - - if service is None: - service = get_service_object() - - new_status_received = False - all_events = get_all_gcal_events(service, from_now=True) - for e in all_events: - local_id = e['extendedProperties']['private']['blechreizID'] - local_event = Event.objects.get(pk=local_id) - for a in e['attendees']: - user = UserGCalCoupling.objects.get(email=a['email']).user - part = EventParticipation.get_or_create(user, local_event) - if 'comment' in a: - part.comment = a['comment'] - - if a['responseStatus'] == 'needsAction': - part.status = "-" - elif a['responseStatus'] == 'tentative': - part.status = '?' - elif a['responseStatus'] == 'accepted': - part.status = 'Yes' - elif a['responseStatus'] == 'declined': - part.status = 'No' - else: - logger.error("Unknown response status when mapping gcal event: " + a['responseStatus']) - - prev = EventParticipation.objects.get(event=part.event, user=part.user) - - # Important: Save only if the participation info has changed - # otherwise everything is synced back to google via the post save signal - # and an endless loop is entered - if prev.status != part.status or prev.comment != part.comment: - part.save() - new_status_received = True - - return new_status_received +def delete_gcal_event_request(service, event): + """Creates a request to delete gcal event that belongs to the given local event.""" + try: + mapping = GCalMapping.objects.get(event=event) + gcal_id = mapping.gcal_id + mapping.delete() + return service.events().delete(calendarId="primary", eventId=gcal_id) + except GCalMapping.DoesNotExist: + logger.warning(f"No GCal mapping found for event {event.id}") + return None # ------------------------------------- Synchronization ---------------------------------------------------- -def check_gcal_subscription(service=None, time_to_live=14 * 24 * 3600, renew_before_expiry=None): - """Google offers a push service if any event information has changed. This works using a so called - channel, which has a certain time to live. This method checks that a valid channel exists: - - if none exists a new one is created - - if existing channel does expire soon, the channel is renewed - - if channel has already expired a sync is triggered and a new channel is created +def delete_all_gcal_events(service=None): + """Deletes all gcal events that have been created by this script.""" + if service is None: + service = get_service_object() + + if service is None: + logger.error("No service object available") + return 0 + + gcal_events = get_all_gcal_events(service) + gcal_ids = [ev["id"] for ev in gcal_events] + count = len(gcal_ids) + + if count == 0: + return 0 + + # Use batch request for efficiency + from googleapiclient.http import BatchHttpRequest + + batch = BatchHttpRequest() + for gcal_id in gcal_ids: + batch.add(service.events().delete(calendarId="primary", eventId=gcal_id)) + + try: + batch.execute() + except Exception as e: + logger.error(f"Error deleting GCal events: {e}") + + GCalMapping.objects.all().delete() + + return count + + +def sync_from_local_to_google(service=None): + """ + Creates a google event for each local event (if it does not exist yet) and + deletes all google events that are not found in local database. + Updates participation info of gcal events using local data. """ if service is None: service = get_service_object() + if service is None: + logger.error("No service object available for sync") + return 0, 0 + + all_events = get_all_gcal_events(service) + + events_at_google_django_id = set() + events_at_google_google_id = set() + + for gcal_ev in all_events: + try: + django_id = int(gcal_ev["extendedProperties"]["private"]["blechreizID"]) + events_at_google_django_id.add(django_id) + events_at_google_google_id.add(gcal_ev["id"]) + except (KeyError, ValueError) as e: + logger.warning(f"Invalid GCal event structure: {e}") + + local_events_django_id = set(Event.objects.all().values_list("pk", flat=True)) + local_events_google_id = set( + GCalMapping.objects.all().values_list("gcal_id", flat=True) + ) + + events_to_create_django_id = local_events_django_id - events_at_google_django_id + events_to_delete_google_id = events_at_google_google_id - local_events_google_id + + from googleapiclient.http import BatchHttpRequest + + batch = BatchHttpRequest() + batch_is_empty = True + + for event_django_id in events_to_create_django_id: + try: + event = Event.objects.get(pk=event_django_id) + batch.add( + create_gcal_event_request(service, event), + callback=on_gcal_event_created, + ) + batch_is_empty = False + except Event.DoesNotExist: + pass + + for event_google_id in events_to_delete_google_id: + batch.add( + service.events().delete(calendarId="primary", eventId=event_google_id) + ) + batch_is_empty = False + + for gcal_ev in all_events: + try: + event_django_id = int( + gcal_ev["extendedProperties"]["private"]["blechreizID"] + ) + django_ev = Event.objects.get(pk=event_django_id) + + gcal_attendees = gcal_ev.get("attendees", []) + local_attendees = build_gcal_attendees_obj(django_ev) + + # Simple comparison - check if attendees differ + if gcal_attendees != local_attendees: + batch.add(update_gcal_event_request(service, django_ev)) + batch_is_empty = False + except Event.DoesNotExist: + pass + except (KeyError, ValueError): + pass + + if not batch_is_empty: + try: + batch.execute() + except Exception as e: + logger.error(f"Error executing batch request: {e}") + + return len(events_to_create_django_id), len(events_to_delete_google_id) + + +def sync_from_google_to_local(service=None): + """ + Retrieves only participation infos for all events and + updates local database if anything has changed. + """ + if service is None: + service = get_service_object() + + if service is None: + logger.error("No service object available for sync") + return False + + new_status_received = False + all_events = get_all_gcal_events(service, from_now=True) + + for e in all_events: + try: + local_id = e["extendedProperties"]["private"]["blechreizID"] + local_event = Event.objects.get(pk=local_id) + + for a in e.get("attendees", []): + try: + user_coupling = UserGCalCoupling.objects.get(email=a["email"]) + user = user_coupling.user + part = EventParticipation.get_or_create(user, local_event) + + if "comment" in a: + part.comment = a["comment"] + + response_status = a.get("responseStatus", "needsAction") + if response_status == "needsAction": + part.status = "-" + elif response_status == "tentative": + part.status = "?" + elif response_status == "accepted": + part.status = "Yes" + elif response_status == "declined": + part.status = "No" + else: + logger.error( + f"Unknown response status when mapping gcal event: {response_status}" + ) + + prev = EventParticipation.objects.get( + event=part.event, user=part.user + ) + + # Important: Save only if the participation info has changed + # otherwise everything is synced back to google via the post save signal + # and an endless loop is entered + if prev.status != part.status or prev.comment != part.comment: + part.save() + new_status_received = True + + except UserGCalCoupling.DoesNotExist: + pass + + except Event.DoesNotExist: + logger.warning(f"Event with id {local_id} not found in local database") + except KeyError as e: + logger.warning(f"Invalid event structure: {e}") + + return new_status_received + + +# ------------------------------------- Push Channel Management ---------------------------------------------------- + + +def check_gcal_subscription( + service=None, time_to_live=14 * 24 * 3600, renew_before_expiry=None +): + """ + Google offers a push service if any event information has changed. + + This works using a so called channel, which has a certain time to live. + This method checks that a valid channel exists: + - if none exists a new one is created + - if existing channel does expire soon, the channel is renewed + - if channel has already expired a sync is triggered and a new channel is created + """ + if service is None: + service = get_service_object() + + if service is None: + logger.error("No service object available") + return + if renew_before_expiry is None: renew_before_expiry = 0.8 * time_to_live - callback_url = settings.GCAL_COUPLING['push_url'] + callback_url = settings.GCAL_COUPLING["push_url"] - # Test if a channel already exists for this callbackURL try: db_channel = GCalPushChannel.objects.get(address=callback_url) - g_channel = db_channel.to_google_channel() - # if expiration time between 0 and two days: stop and create new channel cur_time = int(time.time() * 1000) - if g_channel.expiration > cur_time: + + if db_channel.expiration > cur_time: # not yet expired - if cur_time + renew_before_expiry * 1000 > g_channel.expiration: - # will expire in less than "renewBeforeExpiry" - logger.info("Renewing Google Calendar Subscription: " + callback_url) - GCalPushChannel.stop(service, g_channel) + if cur_time + renew_before_expiry * 1000 > db_channel.expiration: + # will expire in less than "renew_before_expiry" + logger.info(f"Renewing Google Calendar Subscription: {callback_url}") + db_channel.stop(service) GCalPushChannel.create_new(callback_url, service, time_to_live) else: - logger.info("Channel active until %d " % (g_channel.expiration,)) + logger.info(f"Channel active until {db_channel.expiration}") else: - logger.info("Google calendar subscription had expired - getting new subscription") + logger.info( + "Google calendar subscription had expired - getting new subscription" + ) # to get back in sync again we have to decide which data to take # so we use the local data as reference sync_from_local_to_google(service) GCalPushChannel.create_new(callback_url, service, time_to_live) except GCalPushChannel.DoesNotExist: - # create new channel and save it in database - logger.info("No CGalCallback Channel exists yet for: " + callback_url) + logger.info(f"No GCalCallback Channel exists yet for: {callback_url}") # to get back in sync again we have to decide which data to take # so we use the local data as reference sync_from_local_to_google(service) @@ -368,45 +517,68 @@ def check_gcal_subscription(service=None, time_to_live=14 * 24 * 3600, renew_bef def stop_all_gcal_subscriptions(service=None): - """Stops the channel subscription """ - + """Stops all channel subscriptions.""" if service is None: service = get_service_object() - for dbChannel in GCalPushChannel.objects.all(): - logger.info("Stopping %s expiry at %d " % (dbChannel.id, dbChannel.expiration)) - GCalPushChannel.stop(service, dbChannel.to_google_channel()) + if service is None: + logger.error("No service object available") + return + + for db_channel in GCalPushChannel.objects.all(): + logger.info( + f"Stopping channel {db_channel.id} expiry at {db_channel.expiration}" + ) + db_channel.stop(service) def check_if_google_callback_is_valid(token, channel_id, resource_id, service=None): + """Validate an incoming Google Calendar push notification.""" if service is None: service = get_service_object() all_channels = GCalPushChannel.objects.all() + if len(all_channels) == 0: return False # no known subscriptions -> callback has to be from an old channel if len(all_channels) > 1: - logger.warning("Multiple GCal subscriptions! This is strange and probably an error. " - "All channels are closed and one new is created. ") + logger.warning( + "Multiple GCal subscriptions! This is strange and probably an error. " + "All channels are closed and one new is created." + ) stop_all_gcal_subscriptions(service) check_gcal_subscription() all_channels = GCalPushChannel.objects.all() - assert (len(all_channels) == 1) + if len(all_channels) != 1: + return False the_channel = all_channels[0] - if channel_id != the_channel.id or resource_id != the_channel.resource_id or token != the_channel.token: - logger.warning("Got GCal Response from an unexpected Channel" - "Got (%s,%s,%s) " - "expected (%s,%s,%s) " - "Old Channel is stopped." - % (channel_id, resource_id, token, the_channel.id, the_channel.resource_id, the_channel.token)) - - channel_to_stop = GCalPushChannel(id=channel_id, resource_id=resource_id, token=token) - GCalPushChannel.stop(service, channel_to_stop.to_google_channel()) + if ( + channel_id != the_channel.id + or resource_id != the_channel.resource_id + or token != the_channel.token + ): + logger.warning( + f"Got GCal Response from an unexpected Channel. " + f"Got ({channel_id}, {resource_id}, {token}) " + f"expected ({the_channel.id}, {the_channel.resource_id}, {the_channel.token}). " + f"Old Channel is stopped." + ) + GCalPushChannel.stop_channel(service, channel_id, resource_id) return False return True + + +# Backwards compatibility aliases +syncFromLocalToGoogle = sync_from_local_to_google +syncFromGoogleToLocal = sync_from_google_to_local +checkIfGoogleCallbackIsValid = check_if_google_callback_is_valid +checkGCalSubscription = check_gcal_subscription +stopAllGCalSubscriptions = stop_all_gcal_subscriptions +deleteAllGCalEvents = delete_all_gcal_events +getServiceObject = get_service_object diff --git a/eventplanner_gcal/management/commands/gcal_check_subscription.py b/eventplanner_gcal/management/commands/gcal_check_subscription.py index 2374fd7..69aa950 100644 --- a/eventplanner_gcal/management/commands/gcal_check_subscription.py +++ b/eventplanner_gcal/management/commands/gcal_check_subscription.py @@ -1,11 +1,9 @@ from django.core.management.base import NoArgsCommand -from eventplanner_gcal.google_sync import check_gcal_subscription - +from eventplanner_gcal.google_sync import checkGCalSubscription class Command(NoArgsCommand): help = 'Checks if the GCal notification channel is still active' - def handle_noargs(self, **options): - print("Checking Subscription") - check_gcal_subscription() + print ( "Checking Subscription") + checkGCalSubscription() diff --git a/eventplanner_gcal/management/commands/gcal_delete_all.py b/eventplanner_gcal/management/commands/gcal_delete_all.py index a6da00d..cfb2864 100644 --- a/eventplanner_gcal/management/commands/gcal_delete_all.py +++ b/eventplanner_gcal/management/commands/gcal_delete_all.py @@ -1,11 +1,9 @@ from django.core.management.base import NoArgsCommand -from eventplanner_gcal.google_sync import delete_all_gcal_events - +from eventplanner_gcal.google_sync import deleteAllGCalEvents class Command(NoArgsCommand): help = 'Delete all events in the google calendar created by this app' - def handle_noargs(self, **options): - print("Deleting all GCal Events.") - nr_of_deleted_events = delete_all_gcal_events() - print("Deleted %d events. To Restore them from local database run gcal_sync" % (nr_of_deleted_events,)) + print ("Deleting all GCal Events.") + nrOfDeletedEvents = deleteAllGCalEvents() + print ("Deleted %d events. To Restore them from local database run gcal_sync" % (nrOfDeletedEvents, ) ) diff --git a/eventplanner_gcal/management/commands/gcal_stop_subscriptions.py b/eventplanner_gcal/management/commands/gcal_stop_subscriptions.py index 3ec8547..ec44aeb 100644 --- a/eventplanner_gcal/management/commands/gcal_stop_subscriptions.py +++ b/eventplanner_gcal/management/commands/gcal_stop_subscriptions.py @@ -1,10 +1,8 @@ from django.core.management.base import NoArgsCommand -from eventplanner_gcal.google_sync import stop_all_gcal_subscriptions - +from eventplanner_gcal.google_sync import stopAllGCalSubscriptions class Command(NoArgsCommand): help = 'Stops all GCal subscriptions' - def handle_noargs(self, **options): - stop_all_gcal_subscriptions() + stopAllGCalSubscriptions() diff --git a/eventplanner_gcal/management/commands/gcal_sync.py b/eventplanner_gcal/management/commands/gcal_sync.py index d7a129a..98e3983 100644 --- a/eventplanner_gcal/management/commands/gcal_sync.py +++ b/eventplanner_gcal/management/commands/gcal_sync.py @@ -1,11 +1,10 @@ from django.core.management.base import NoArgsCommand -from eventplanner_gcal.google_sync import sync_from_local_to_google +from eventplanner_gcal.google_sync import syncFromLocalToGoogle class Command(NoArgsCommand): help = 'Synchronize Google Calendar with locally stored Events' - def handle_noargs(self, **options): - print("Running Sync") - created, deleted = sync_from_local_to_google() - print("Created %d and deleted %d events" % (created, deleted)) + print ( "Running Sync") + created, deleted = syncFromLocalToGoogle() + print ( "Created %d and deleted %d events" % (created,deleted) ) diff --git a/eventplanner_gcal/migrations/0001_initial.py b/eventplanner_gcal/migrations/0001_initial.py new file mode 100644 index 0000000..7f5e92b --- /dev/null +++ b/eventplanner_gcal/migrations/0001_initial.py @@ -0,0 +1,55 @@ +# Generated by Django 5.1.15 on 2026-03-30 19:15 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('eventplanner', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='GCalMapping', + fields=[ + ('gcal_id', models.CharField(max_length=64)), + ('event', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='eventplanner.event')), + ], + options={ + 'verbose_name': 'Google Calendar Mapping', + 'verbose_name_plural': 'Google Calendar Mappings', + }, + ), + migrations.CreateModel( + name='GCalPushChannel', + fields=[ + ('id', models.CharField(max_length=128, primary_key=True, serialize=False)), + ('address', models.CharField(max_length=256)), + ('token', models.CharField(max_length=128)), + ('resource_id', models.CharField(max_length=128)), + ('expiration', models.BigIntegerField()), + ], + options={ + 'verbose_name': 'Google Calendar Push Channel', + 'verbose_name_plural': 'Google Calendar Push Channels', + }, + ), + migrations.CreateModel( + name='UserGCalCoupling', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('email', models.CharField(max_length=1024)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'User Google Calendar Coupling', + 'verbose_name_plural': 'User Google Calendar Couplings', + }, + ), + ] diff --git a/eventplanner_gcal/migrations/__init__.py b/eventplanner_gcal/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/eventplanner_gcal/models.py b/eventplanner_gcal/models.py index 56f4ebd..bb3de1c 100644 --- a/eventplanner_gcal/models.py +++ b/eventplanner_gcal/models.py @@ -1,59 +1,127 @@ import logging import uuid -from eventplanner.models import Event -from django.contrib.auth.models import User -from apiclient.channel import Channel +from django.contrib.auth.models import User from django.db import models +from eventplanner.models import Event + logger = logging.getLogger(__name__) class UserGCalCoupling(models.Model): - # For every user in this table the gcal coupling is activated + """For every user in this table the gcal coupling is activated.""" + user = models.OneToOneField(User, on_delete=models.CASCADE) email = models.CharField(max_length=1024) + class Meta: + verbose_name = "User Google Calendar Coupling" + verbose_name_plural = "User Google Calendar Couplings" + + def __str__(self): + return f"{self.user.username} <-> {self.email}" + class GCalMapping(models.Model): - """Mapping between event id at google and local event id""" + """Mapping between event id at google and local event id.""" + gcal_id = models.CharField(max_length=64) - event = models.OneToOneField(Event, primary_key=True, on_delete=models.CASCADE) + event = models.OneToOneField(Event, on_delete=models.CASCADE, primary_key=True) + + class Meta: + verbose_name = "Google Calendar Mapping" + verbose_name_plural = "Google Calendar Mappings" + + def __str__(self): + return f"GCal:{self.gcal_id} <-> Event:{self.event_id}" class GCalPushChannel(models.Model): """This table has either zero or one entry. Required to store if a channel already exists, - when it expires and how to stop (renew) the channel + when it expires and how to stop (renew) the channel. """ id = models.CharField(max_length=128, primary_key=True) address = models.CharField(max_length=256) token = models.CharField(max_length=128) resource_id = models.CharField(max_length=128) - expiration = models.IntegerField() + expiration = models.BigIntegerField() - def to_google_channel(self): - return Channel('web_hook', self.id, self.token, self.address, self.expiration, resource_id=self.resource_id) + class Meta: + verbose_name = "Google Calendar Push Channel" + verbose_name_plural = "Google Calendar Push Channels" - @staticmethod - def from_google_channel(google_channel): - return GCalPushChannel(id=google_channel.id, - address=google_channel.address, - token=google_channel.token, - expiration=google_channel.expiration, - resource_id=google_channel.resource_id) + def __str__(self): + return f"Channel {self.id} expires at {self.expiration}" - @staticmethod - def create_new(callback_url, service, ttl=None): - gChannel = Channel('web_hook', str(uuid.uuid4()), 'blechreizGcal', callback_url, params={'ttl': int(ttl)}) - response = service.events().watch(calendarId='primary', body=gChannel.body()).execute() - gChannel.update(response) + def to_channel_dict(self): + """Return a dictionary representation for the Google API.""" + return { + "id": self.id, + "type": "web_hook", + "address": self.address, + "token": self.token, + "expiration": self.expiration, + "resourceId": self.resource_id, + } - dbChannel = GCalPushChannel.from_google_channel(gChannel) - dbChannel.save() + @classmethod + def from_response(cls, response, address, token): + """Create a GCalPushChannel from a Google API response.""" + return cls( + id=response["id"], + address=address, + token=token, + expiration=int(response.get("expiration", 0)), + resource_id=response.get("resourceId", ""), + ) - @staticmethod - def stop(service, google_channel): - channel_service = service.channels() - channel_service.stop(body=google_channel.body()).execute() - GCalPushChannel.from_google_channel(google_channel).delete() + @classmethod + def create_new(cls, callback_url, service, ttl=None): + """Create a new push channel subscription.""" + channel_id = str(uuid.uuid4()) + token = "blechreizGcal" + + body = { + "id": channel_id, + "type": "web_hook", + "address": callback_url, + "token": token, + } + + if ttl: + body["params"] = {"ttl": str(int(ttl))} + + response = service.events().watch(calendarId="primary", body=body).execute() + + db_channel = cls.from_response(response, callback_url, token) + db_channel.save() + return db_channel + + def stop(self, service): + """Stop this push channel subscription.""" + body = { + "id": self.id, + "resourceId": self.resource_id, + } + try: + service.channels().stop(body=body).execute() + except Exception as e: + logger.warning(f"Failed to stop channel {self.id}: {e}") + self.delete() + + @classmethod + def stop_channel(cls, service, channel_id, resource_id): + """Stop a push channel by ID and resource ID.""" + body = { + "id": channel_id, + "resourceId": resource_id, + } + try: + service.channels().stop(body=body).execute() + except Exception as e: + logger.warning(f"Failed to stop channel {channel_id}: {e}") + + # Also delete from database if it exists + cls.objects.filter(id=channel_id).delete() diff --git a/eventplanner_gcal/signals.py b/eventplanner_gcal/signals.py index 726358d..82716cb 100644 --- a/eventplanner_gcal/signals.py +++ b/eventplanner_gcal/signals.py @@ -1,61 +1,120 @@ -from django.db.models.signals import post_save, pre_delete -from django.dispatch import receiver -from eventplanner.models import Event, EventParticipation -from eventplanner_gcal.google_sync import get_service_object, \ - create_gcal_event, delete_gcal_event, update_gcal_event, on_gcal_event_created +""" +Django signal handlers for Google Calendar synchronization. + +These handlers are currently disabled (early return) but can be enabled +to automatically sync events with Google Calendar when they are created, +updated, or deleted. +""" import logging -from django.conf import settings + +from django.contrib.auth.models import User +from django.db.models.signals import post_save, pre_delete +from django.dispatch import receiver + +from eventplanner.models import Event, EventParticipation + +from .google_sync import ( + create_gcal_event_request, + delete_gcal_event_request, + get_service_object, + on_gcal_event_created, + update_gcal_event_request, +) logger = logging.getLogger(__name__) -# @receiver( post_save, sender=User ) -# def user_changed( **kwargs ): -# logger.info("Synchronizing with google - user information changed") -# syncFromLocalToGoogle( getServiceObject() ) +# @receiver(post_save, sender=User) +# def user_changed(**kwargs): +# """Sync with Google when user information changes.""" +# logger.info("Synchronizing with google - user information changed") +# sync_from_local_to_google(get_service_object()) @receiver(post_save, sender=Event) -def event_post_save_handler(**kwargs): - if not settings.GCAL_SYNC_ENABLED: +def event_post_save_handler(sender, instance, created, **kwargs): + """ + Handle Event post_save signal. + + Creates or updates the corresponding Google Calendar event. + Currently disabled - remove the early return to enable. + """ + # Disabled - remove this return statement to enable auto-sync + return + + event = instance + service = get_service_object() + + if service is None: + logger.warning("No Google Calendar service available") return - event = kwargs['instance'] - created = kwargs['created'] try: if created: - logger.info("Creating Gcal event") - response = create_gcal_event(get_service_object(), event).execute() + logger.info(f"Creating GCal event for Event {event.id}") + request = create_gcal_event_request(service, event) + response = request.execute() on_gcal_event_created(None, response, None) else: - logger.info("Updating Gcal event") - update_gcal_event(get_service_object(), event).execute() + logger.info(f"Updating GCal event for Event {event.id}") + request = update_gcal_event_request(service, event) + request.execute() except Exception as e: - logger.error("Error updating Gcal event" + str(e)) + logger.error(f"Error syncing event {event.id} to GCal: {e}") @receiver(pre_delete, sender=Event) -def event_pre_delete_handler(**kwargs): - if not settings.GCAL_SYNC_ENABLED: +def event_pre_delete_handler(sender, instance, **kwargs): + """ + Handle Event pre_delete signal. + + Deletes the corresponding Google Calendar event. + Currently disabled - remove the early return to enable. + """ + # Disabled - remove this return statement to enable auto-sync + return + + event = instance + service = get_service_object() + + if service is None: + logger.warning("No Google Calendar service available") return try: - event = kwargs['instance'] - logger.info("Deleting Gcal event") - delete_gcal_event(get_service_object(), event).execute() + logger.info(f"Deleting GCal event for Event {event.id}") + request = delete_gcal_event_request(service, event) + if request: + request.execute() except Exception as e: - logger.error("Error deleting GCAL event" + str(e)) + logger.error(f"Error deleting GCal event for Event {event.id}: {e}") @receiver(post_save, sender=EventParticipation) -def participation_post_save_handler(**kwargs): - if not settings.GCAL_SYNC_ENABLED: +def participation_post_save_handler(sender, instance, **kwargs): + """ + Handle EventParticipation post_save signal. + + Updates the Google Calendar event when participation changes. + Currently disabled - remove the early return to enable. + """ + # Disabled - remove this return statement to enable auto-sync + return + + participation = instance + service = get_service_object() + + if service is None: + logger.warning("No Google Calendar service available") return try: - participation = kwargs['instance'] - logger.info("Participation post save -> update gcal") - update_gcal_event(get_service_object(), participation.event).execute() + logger.info( + f"Participation changed for Event {participation.event.id} " + f"by User {participation.user.username}" + ) + request = update_gcal_event_request(service, participation.event) + request.execute() except Exception as e: - logger.error("Error deleting GCAL event" + str(e)) + logger.error(f"Error updating GCal event for participation change: {e}") diff --git a/eventplanner_gcal/templates/eventplanner_gcal/management.html b/eventplanner_gcal/templates/eventplanner_gcal/management.html index 345b79c..86f520f 100644 --- a/eventplanner_gcal/templates/eventplanner_gcal/management.html +++ b/eventplanner_gcal/templates/eventplanner_gcal/management.html @@ -1,10 +1,10 @@ {% extends "website/base.html" %} -{% load sekizai_tags staticfiles %} +{% load sekizai_tags static %} {% block content %} {% addtoblock "css" strip %} - + {% endaddtoblock %} {% addtoblock "css" %} @@ -25,7 +25,7 @@ {% endaddtoblock %} {% addtoblock "js" strip %} - + {% endaddtoblock %} {% addtoblock "js" %} @@ -72,7 +72,7 @@ weil man alle anderen eigenen Termine auch im Blick hat.

    - +

    SO GEHTS:
    @@ -115,11 +115,11 @@
    - +
    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/eventplanner_gcal/urls.py b/eventplanner_gcal/urls.py index e09a083..6c087a9 100644 --- a/eventplanner_gcal/urls.py +++ b/eventplanner_gcal/urls.py @@ -1,9 +1,11 @@ -from django.conf.urls import url +from django.urls import path -from .views import run_sync, gcal_api_callback, manage +from . import views + +app_name = "eventplanner_gcal" urlpatterns = [ - url(r'^runSync$', run_sync), - url(r'^gcalApiCallback$', gcal_api_callback), - url(r'^manage$', manage), + path("runSync/", views.run_sync, name="run_sync"), + path("gcalApiCallback/", views.gcal_api_callback, name="gcal_api_callback"), + path("manage/", views.manage, name="manage"), ] diff --git a/eventplanner_gcal/views.py b/eventplanner_gcal/views.py index 967e64a..5f2ce34 100644 --- a/eventplanner_gcal/views.py +++ b/eventplanner_gcal/views.py @@ -1,63 +1,101 @@ -from django.shortcuts import redirect -from eventplanner_gcal.google_sync import sync_from_google_to_local, sync_from_local_to_google -from django.http import HttpResponse -from django.views.decorators.csrf import csrf_exempt -from eventplanner_gcal.google_sync import check_if_google_callback_is_valid -from eventplanner_gcal.models import UserGCalCoupling -from django.shortcuts import render +""" +Views for Google Calendar integration management. +""" import logging +from django.http import HttpResponse +from django.shortcuts import redirect, render +from django.views.decorators.csrf import csrf_exempt + +from .google_sync import ( + check_if_google_callback_is_valid, + sync_from_google_to_local, + sync_from_local_to_google, +) +from .models import UserGCalCoupling + logger = logging.getLogger(__name__) def run_sync(request): + """Manually trigger a sync from local to Google Calendar.""" sync_from_local_to_google() return redirect("/") def manage(request): - if request.method == 'POST': - if request.POST['activate'] == "1": - UserGCalCoupling.objects.filter(user=request.user).delete() - c = UserGCalCoupling(user=request.user, email=request.POST['email']) - c.save() - sync_from_local_to_google() + """ + View for managing Google Calendar integration settings. + + Allows users to enable/disable GCal sync and configure their email. + """ + if request.method == "POST": + activate = request.POST.get("activate", "0") + + if activate == "1": + # Enable GCal coupling + email = request.POST.get("email", "") + if email: + UserGCalCoupling.objects.filter(user=request.user).delete() + coupling = UserGCalCoupling(user=request.user, email=email) + coupling.save() + sync_from_local_to_google() else: + # Disable GCal coupling UserGCalCoupling.objects.filter(user=request.user).delete() sync_from_local_to_google() context = {} user_coupling = UserGCalCoupling.objects.filter(user=request.user) - context['enabled'] = len(user_coupling) - assert (len(user_coupling) < 2) - if len(user_coupling) == 1: - context['mail'] = user_coupling[0].email + context["enabled"] = user_coupling.exists() - return render(request, 'eventplanner_gcal/management.html', context) + if user_coupling.count() > 1: + logger.warning( + f"User {request.user.username} has multiple GCal couplings. " + "This should not happen." + ) + + if user_coupling.exists(): + context["mail"] = user_coupling.first().email + + return render(request, "eventplanner_gcal/management.html", context) @csrf_exempt def gcal_api_callback(request): - token = "" - if 'HTTP_X_GOOG_CHANNEL_TOKEN' in request.META: - token = request.META['HTTP_X_GOOG_CHANNEL_TOKEN'] + """ + Callback endpoint for Google Calendar push notifications. - channel_id = "" - if 'HTTP_X_GOOG_CHANNEL_ID' in request.META: - channel_id = request.META['HTTP_X_GOOG_CHANNEL_ID'] - - resource_id = "" - if 'HTTP_X_GOOG_RESOURCE_ID' in request.META: - resource_id = request.META['HTTP_X_GOOG_RESOURCE_ID'] + This is called by Google when calendar events are updated. + """ + token = request.META.get("HTTP_X_GOOG_CHANNEL_TOKEN", "") + channel_id = request.META.get("HTTP_X_GOOG_CHANNEL_ID", "") + resource_id = request.META.get("HTTP_X_GOOG_RESOURCE_ID", "") valid = check_if_google_callback_is_valid(token, channel_id, resource_id) if not valid: - return HttpResponse('

    Old Channel - no update triggered

    ') + logger.warning( + f"Received invalid GCal callback: token={token}, " + f"channel_id={channel_id}, resource_id={resource_id}" + ) + return HttpResponse("

    Old Channel - no update triggered

    ") + + logger.info( + f"Received Google Callback with headers - " + f"Token: {token}, ID: {channel_id}, ResID: {resource_id}" + ) - logger.info("Received Google Callback with the following headers Token: " - "%s ID %s ResID %s " % (token, channel_id, resource_id)) result = sync_from_google_to_local() - logger.info("Finished processing callback from GCal - New Information present: %d " % (result,)) - return HttpResponse('

    Callback successful

    ') + + logger.info( + f"Finished processing callback from GCal - New Information present: {result}" + ) + + return HttpResponse("

    Callback successful

    ") + + +# Backwards compatibility aliases +runSync = run_sync +gcalApiCallback = gcal_api_callback diff --git a/imagestore/__init__.py b/imagestore/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/imagestore/admin.py b/imagestore/admin.py new file mode 100644 index 0000000..6da3fb2 --- /dev/null +++ b/imagestore/admin.py @@ -0,0 +1,36 @@ +from django.contrib import admin +from imagestore.models import Image, Album, AlbumUpload +from sorl.thumbnail.admin import AdminInlineImageMixin +from django.conf import settings + +class InlineImageAdmin(AdminInlineImageMixin, admin.TabularInline): + model = Image + fieldsets = ((None, {'fields': ['image', 'user', 'title', 'order', 'tags', 'album']}),) + raw_id_fields = ('user', ) + extra = 0 + +class AlbumAdmin(admin.ModelAdmin): + fieldsets = ((None, {'fields': ['name', 'user', 'is_public', 'order']}),) + list_display = ('name', 'admin_thumbnail', 'user', 'created', 'updated', 'is_public', 'order') + list_editable = ('order', ) + inlines = [InlineImageAdmin] + +admin.site.register(Album, AlbumAdmin) + +class ImageAdmin(admin.ModelAdmin): + fieldsets = ((None, {'fields': ['user', 'title', 'image', 'description', 'order', 'tags', 'album']}),) + list_display = ('admin_thumbnail', 'user', 'order', 'album', 'title') + raw_id_fields = ('user', ) + list_filter = ('album', ) + +class AlbumUploadAdmin(admin.ModelAdmin): + def has_change_permission(self, request, obj=None): + return False + +IMAGE_MODEL = getattr(settings, 'IMAGESTORE_IMAGE_MODEL', None) +if not IMAGE_MODEL: + admin.site.register(Image, ImageAdmin) + +ALBUM_MODEL = getattr(settings, 'IMAGESTORE_ALBUM_MODEL', None) +if not ALBUM_MODEL: + admin.site.register(AlbumUpload, AlbumUploadAdmin) diff --git a/imagestore/autocomplete_light_registry.py b/imagestore/autocomplete_light_registry.py new file mode 100644 index 0000000..0670223 --- /dev/null +++ b/imagestore/autocomplete_light_registry.py @@ -0,0 +1,9 @@ +# coding=utf-8 +from __future__ import unicode_literals +import autocomplete_light +from tagging.models import Tag + +autocomplete_light.register( + Tag, + search_fields=['^name'] +) \ No newline at end of file diff --git a/imagestore/context_processors.py b/imagestore/context_processors.py new file mode 100644 index 0000000..089d180 --- /dev/null +++ b/imagestore/context_processors.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +from django.core.urlresolvers import reverse, NoReverseMatch +from django.conf import settings +from utils import get_model_string +from imagestore.models import image_applabel, image_classname +from imagestore.models import album_applabel, album_classname + +def imagestore_processor(request): + template = getattr(settings, 'IMAGESTORE_TEMPLATE', False) + ret = { + 'IMAGESTORE_SHOW_USER': getattr(settings, 'IMAGESTORE_SHOW_USER', True), + 'IMAGESTORE_SHOW_TAGS': getattr(settings, 'IMAGESTORE_SHOW_TAGS', True), + 'IMAGESTORE_MODEL_STRING': get_model_string('Image'), + 'IMAGESTORE_LOAD_CSS': getattr(settings, 'IMAGESTORE_LOAD_CSS', True), + } + try: + ret['imagestore_index_url'] = reverse('imagestore:index') + except NoReverseMatch: #Bastard django-cms from hell!!!!111 + pass + if template: + ret['IMAGESTORE_TEMPLATE'] = template + ret['imagestore_perms'] = { + 'add_image': request.user.has_perm('%s.add_%s' % (image_applabel, image_classname)), + 'add_album': request.user.has_perm('%s.add_%s' % (album_applabel, album_classname)), + } + return ret + + \ No newline at end of file diff --git a/imagestore/forms.py b/imagestore/forms.py new file mode 100644 index 0000000..03ba9bf --- /dev/null +++ b/imagestore/forms.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +try: + import autocomplete_light + AUTOCOMPLETE_LIGHT_INSTALLED = True +except ImportError: + AUTOCOMPLETE_LIGHT_INSTALLED = False + +__author__ = 'zeus' + +from django import forms +from models import Image, Album +from django.utils.translation import ugettext_lazy as _ + + +class ImageForm(forms.ModelForm): + class Meta(object): + model = Image + exclude = ('user', 'order') + + description = forms.CharField(widget=forms.Textarea(attrs={'rows': 2, 'cols': 19}), required=False, + label=_('Description')) + + def __init__(self, user, *args, **kwargs): + super(ImageForm, self).__init__(*args, **kwargs) + self.fields['album'].queryset = Album.objects.filter(user=user) + self.fields['album'].required = True + if AUTOCOMPLETE_LIGHT_INSTALLED: + self.fields['tags'].widget = autocomplete_light.TextWidget('TagAutocomplete') + + +class AlbumForm(forms.ModelForm): + class Meta(object): + model = Album + exclude = ('user', 'created', 'updated') + + def __init__(self, *args, **kwargs): + super(AlbumForm, self).__init__(*args, **kwargs) + if 'instance' in kwargs and kwargs['instance']: + self.fields['head'].queryset = Image.objects.filter(album=kwargs['instance']) + else: + self.fields['head'].widget = forms.HiddenInput() diff --git a/imagestore/imagestore_cms/__init__.py b/imagestore/imagestore_cms/__init__.py new file mode 100644 index 0000000..04ccd4b --- /dev/null +++ b/imagestore/imagestore_cms/__init__.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + \ No newline at end of file diff --git a/imagestore/imagestore_cms/cms_app.py b/imagestore/imagestore_cms/cms_app.py new file mode 100644 index 0000000..0b81e01 --- /dev/null +++ b/imagestore/imagestore_cms/cms_app.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + +from cms.app_base import CMSApp +from cms.apphook_pool import apphook_pool +from django.utils.translation import ugettext_lazy as _ + +class ImagestoreApp(CMSApp): + name = _("Imagestore App") # give your app a name, this is required + urls = ["imagestore.imagestore_cms.urls"] # link your app to url configuration(s) + +apphook_pool.register(ImagestoreApp) # register your app + \ No newline at end of file diff --git a/imagestore/imagestore_cms/cms_plugins.py b/imagestore/imagestore_cms/cms_plugins.py new file mode 100644 index 0000000..c4b97b2 --- /dev/null +++ b/imagestore/imagestore_cms/cms_plugins.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + +from cms.plugin_base import CMSPluginBase +from cms.plugin_pool import plugin_pool +from models import ImagestoreAlbumPtr, ImagestoreAlbumCarousel +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings + +class AlbumPlugin(CMSPluginBase): + model = ImagestoreAlbumPtr + name = _('Album') + render_template = "cms/plugins/imagestore_album.html" + text_enabled = True + + def render(self, context, instance, placeholder): + context.update({'album': instance.album}) + return context + + +class AlbumCarouselPlugin(CMSPluginBase): + model = ImagestoreAlbumCarousel + name = _('Album as carousel') + render_template = "cms/plugins/imagestore_album_carousel.html" + text_enabled = True + + def render(self, context, instance, placeholder): + + # default carousel template in the settings file + carousel_template = getattr(settings, 'IMAGESTORE_CAROUSEL_TEMPLATE', None) + + if carousel_template: + self.render_template = carousel_template + + if instance.template_file: + self.render_template = instance.template_file + else: + if carousel_template: + instance.template_file = carousel_template + else: + instance.template_file = self.render_template + instance.save() + + images = instance.album.images.all() + if instance.limit: + images = images[:instance.limit] + context.update({'images': images, 'carousel': instance}) + return context + +plugin_pool.register_plugin(AlbumCarouselPlugin) +plugin_pool.register_plugin(AlbumPlugin) \ No newline at end of file diff --git a/imagestore/imagestore_cms/migrations/0001_initial.py b/imagestore/imagestore_cms/migrations/0001_initial.py new file mode 100644 index 0000000..d3be993 --- /dev/null +++ b/imagestore/imagestore_cms/migrations/0001_initial.py @@ -0,0 +1,112 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'ImagestoreAlbumPtr' + db.create_table('cmsplugin_imagestorealbumptr', ( + ('cmsplugin_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['cms.CMSPlugin'], unique=True, primary_key=True)), + ('album', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['imagestore.Album'])), + )) + db.send_create_signal('imagestore_cms', ['ImagestoreAlbumPtr']) + + + def backwards(self, orm): + + # Deleting model 'ImagestoreAlbumPtr' + db.delete_table('cmsplugin_imagestorealbumptr') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'cms.cmsplugin': { + 'Meta': {'object_name': 'CMSPlugin'}, + 'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}), + 'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}), + 'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'cms.placeholder': { + 'Meta': {'object_name': 'Placeholder'}, + 'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore_cms.imagestorealbumptr': { + 'Meta': {'object_name': 'ImagestoreAlbumPtr', 'db_table': "'cmsplugin_imagestorealbumptr'", '_ormbases': ['cms.CMSPlugin']}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']"}), + 'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}) + } + } + + complete_apps = ['imagestore_cms'] diff --git a/imagestore/imagestore_cms/migrations/0002_add_carusel.py b/imagestore/imagestore_cms/migrations/0002_add_carusel.py new file mode 100644 index 0000000..5cdd9c5 --- /dev/null +++ b/imagestore/imagestore_cms/migrations/0002_add_carusel.py @@ -0,0 +1,121 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'ImagestoreAlbumCarusel' + db.create_table('cmsplugin_imagestorealbumcarusel', ( + ('cmsplugin_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['cms.CMSPlugin'], unique=True, primary_key=True)), + ('album', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['imagestore.Album'])), + ('width', self.gf('django.db.models.fields.IntegerField')(default=200)), + ('limit', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)), + )) + db.send_create_signal('imagestore_cms', ['ImagestoreAlbumCarusel']) + + + def backwards(self, orm): + + # Deleting model 'ImagestoreAlbumCarusel' + db.delete_table('cmsplugin_imagestorealbumcarusel') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'cms.cmsplugin': { + 'Meta': {'object_name': 'CMSPlugin'}, + 'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}), + 'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}), + 'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'cms.placeholder': { + 'Meta': {'object_name': 'Placeholder'}, + 'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore_cms.imagestorealbumcarusel': { + 'Meta': {'object_name': 'ImagestoreAlbumCarusel', 'db_table': "'cmsplugin_imagestorealbumcarusel'", '_ormbases': ['cms.CMSPlugin']}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']"}), + 'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}), + 'limit': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'width': ('django.db.models.fields.IntegerField', [], {'default': '200'}) + }, + 'imagestore_cms.imagestorealbumptr': { + 'Meta': {'object_name': 'ImagestoreAlbumPtr', 'db_table': "'cmsplugin_imagestorealbumptr'", '_ormbases': ['cms.CMSPlugin']}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']"}), + 'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}) + } + } + + complete_apps = ['imagestore_cms'] diff --git a/imagestore/imagestore_cms/migrations/0003_more_carousel_options.py b/imagestore/imagestore_cms/migrations/0003_more_carousel_options.py new file mode 100644 index 0000000..1b09fc1 --- /dev/null +++ b/imagestore/imagestore_cms/migrations/0003_more_carousel_options.py @@ -0,0 +1,137 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Deleting model 'ImagestoreAlbumCarusel' + db.delete_table('cmsplugin_imagestorealbumcarusel') + + # Adding model 'ImagestoreAlbumCarousel' + db.create_table('cmsplugin_imagestorealbumcarousel', ( + ('cmsplugin_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['cms.CMSPlugin'], unique=True, primary_key=True)), + ('album', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['imagestore.Album'])), + ('width', self.gf('django.db.models.fields.IntegerField')(default=200)), + ('height', self.gf('django.db.models.fields.IntegerField')(default=200)), + ('skin', self.gf('django.db.models.fields.CharField')(default='jcarousel-skin-tango', max_length=100)), + ('limit', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)), + )) + db.send_create_signal('imagestore_cms', ['ImagestoreAlbumCarousel']) + + + def backwards(self, orm): + + # Adding model 'ImagestoreAlbumCarusel' + db.create_table('cmsplugin_imagestorealbumcarusel', ( + ('album', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['imagestore.Album'])), + ('limit', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)), + ('cmsplugin_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['cms.CMSPlugin'], unique=True, primary_key=True)), + ('width', self.gf('django.db.models.fields.IntegerField')(default=200)), + )) + db.send_create_signal('imagestore_cms', ['ImagestoreAlbumCarusel']) + + # Deleting model 'ImagestoreAlbumCarousel' + db.delete_table('cmsplugin_imagestorealbumcarousel') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'cms.cmsplugin': { + 'Meta': {'object_name': 'CMSPlugin'}, + 'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}), + 'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}), + 'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'cms.placeholder': { + 'Meta': {'object_name': 'Placeholder'}, + 'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore_cms.imagestorealbumcarousel': { + 'Meta': {'object_name': 'ImagestoreAlbumCarousel', 'db_table': "'cmsplugin_imagestorealbumcarousel'", '_ormbases': ['cms.CMSPlugin']}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']"}), + 'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}), + 'height': ('django.db.models.fields.IntegerField', [], {'default': '200'}), + 'limit': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'skin': ('django.db.models.fields.CharField', [], {'default': "'jcarousel-skin-tango'", 'max_length': '100'}), + 'width': ('django.db.models.fields.IntegerField', [], {'default': '200'}) + }, + 'imagestore_cms.imagestorealbumptr': { + 'Meta': {'object_name': 'ImagestoreAlbumPtr', 'db_table': "'cmsplugin_imagestorealbumptr'", '_ormbases': ['cms.CMSPlugin']}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']"}), + 'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}) + } + } + + complete_apps = ['imagestore_cms'] diff --git a/imagestore/imagestore_cms/migrations/0004_add_carousel_sizes.py b/imagestore/imagestore_cms/migrations/0004_add_carousel_sizes.py new file mode 100644 index 0000000..43cb76c --- /dev/null +++ b/imagestore/imagestore_cms/migrations/0004_add_carousel_sizes.py @@ -0,0 +1,135 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Deleting field 'ImagestoreAlbumCarousel.height' + db.delete_column('cmsplugin_imagestorealbumcarousel', 'height') + + # Deleting field 'ImagestoreAlbumCarousel.width' + db.delete_column('cmsplugin_imagestorealbumcarousel', 'width') + + # Adding field 'ImagestoreAlbumCarousel.size' + db.add_column('cmsplugin_imagestorealbumcarousel', 'size', self.gf('django.db.models.fields.CharField')(default='72x72', max_length=20), keep_default=False) + + # Adding field 'ImagestoreAlbumCarousel.full_size' + db.add_column('cmsplugin_imagestorealbumcarousel', 'full_size', self.gf('django.db.models.fields.CharField')(default='600x600', max_length=20), keep_default=False) + + + def backwards(self, orm): + + # Adding field 'ImagestoreAlbumCarousel.height' + db.add_column('cmsplugin_imagestorealbumcarousel', 'height', self.gf('django.db.models.fields.IntegerField')(default=200), keep_default=False) + + # Adding field 'ImagestoreAlbumCarousel.width' + db.add_column('cmsplugin_imagestorealbumcarousel', 'width', self.gf('django.db.models.fields.IntegerField')(default=200), keep_default=False) + + # Deleting field 'ImagestoreAlbumCarousel.size' + db.delete_column('cmsplugin_imagestorealbumcarousel', 'size') + + # Deleting field 'ImagestoreAlbumCarousel.full_size' + db.delete_column('cmsplugin_imagestorealbumcarousel', 'full_size') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'cms.cmsplugin': { + 'Meta': {'object_name': 'CMSPlugin'}, + 'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}), + 'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}), + 'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'cms.placeholder': { + 'Meta': {'object_name': 'Placeholder'}, + 'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore_cms.imagestorealbumcarousel': { + 'Meta': {'object_name': 'ImagestoreAlbumCarousel', 'db_table': "'cmsplugin_imagestorealbumcarousel'", '_ormbases': ['cms.CMSPlugin']}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']"}), + 'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}), + 'full_size': ('django.db.models.fields.CharField', [], {'default': "'600x600'", 'max_length': '20'}), + 'limit': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'size': ('django.db.models.fields.CharField', [], {'default': "'72x72'", 'max_length': '20'}), + 'skin': ('django.db.models.fields.CharField', [], {'default': "'jcarousel-skin-tango'", 'max_length': '100'}) + }, + 'imagestore_cms.imagestorealbumptr': { + 'Meta': {'object_name': 'ImagestoreAlbumPtr', 'db_table': "'cmsplugin_imagestorealbumptr'", '_ormbases': ['cms.CMSPlugin']}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']"}), + 'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}) + } + } + + complete_apps = ['imagestore_cms'] diff --git a/imagestore/imagestore_cms/migrations/0005_auto__add_field_imagestorealbumcarousel_template_file.py b/imagestore/imagestore_cms/migrations/0005_auto__add_field_imagestorealbumcarousel_template_file.py new file mode 100644 index 0000000..232f475 --- /dev/null +++ b/imagestore/imagestore_cms/migrations/0005_auto__add_field_imagestorealbumcarousel_template_file.py @@ -0,0 +1,210 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding field 'ImagestoreAlbumCarousel.template_file' + db.add_column('cmsplugin_imagestorealbumcarousel', 'template_file', self.gf('django.db.models.fields.CharField')(default='cms/plugins/imagestore_album_carousel.html', max_length=100), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'ImagestoreAlbumCarousel.template_file' + db.delete_column('cmsplugin_imagestorealbumcarousel', 'template_file') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'cms.cmsplugin': { + 'Meta': {'object_name': 'CMSPlugin'}, + 'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}), + 'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}), + 'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'cms.placeholder': { + 'Meta': {'object_name': 'Placeholder'}, + 'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'image.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image', 'db_table': "'imagestore_image'"}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'place': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['places.GeoPlace']"}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['image.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore_cms.imagestorealbumcarousel': { + 'Meta': {'object_name': 'ImagestoreAlbumCarousel', 'db_table': "'cmsplugin_imagestorealbumcarousel'", '_ormbases': ['cms.CMSPlugin']}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']"}), + 'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}), + 'full_size': ('django.db.models.fields.CharField', [], {'default': "'600x600'", 'max_length': '20'}), + 'limit': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'size': ('django.db.models.fields.CharField', [], {'default': "'72x72'", 'max_length': '20'}), + 'skin': ('django.db.models.fields.CharField', [], {'default': "'jcarousel-skin-tango'", 'max_length': '100'}), + 'template_file': ('django.db.models.fields.CharField', [], {'default': "'cms/plugins/imagestore_album_carousel.html'", 'max_length': '100'}) + }, + 'imagestore_cms.imagestorealbumptr': { + 'Meta': {'object_name': 'ImagestoreAlbumPtr', 'db_table': "'cmsplugin_imagestorealbumptr'", '_ormbases': ['cms.CMSPlugin']}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']"}), + 'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}) + }, + 'places.geoplace': { + 'Meta': {'object_name': 'GeoPlace'}, + 'addional_info': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'address': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'imagestore_tag': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'latitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'longtitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'metro': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'minuses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'near_objects': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'near_objects_rel_+'", 'null': 'True', 'to': "orm['places.GeoPlace']"}), + 'near_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'path_to': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'phone': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'pluses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'private': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'topic': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pybb.Topic']", 'null': 'True', 'blank': 'True'}), + 'topic_on_demand': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['places.PlaceType']", 'null': 'None', 'blank': 'None'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'work_time': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + 'places.placetype': { + 'Meta': {'object_name': 'PlaceType'}, + 'forum': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pybb.Forum']", 'null': 'True', 'blank': 'True'}), + 'forum_user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'icon_style': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'name_plural': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'path_to_image': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}) + }, + 'pybb.category': { + 'Meta': {'ordering': "['position']", 'object_name': 'Category'}, + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'position': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}) + }, + 'pybb.forum': { + 'Meta': {'ordering': "['position']", 'object_name': 'Forum'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'forums'", 'to': "orm['pybb.Category']"}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'headline': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'moderators': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'position': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}), + 'post_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}), + 'readed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'readed_forums'", 'symmetrical': 'False', 'through': "orm['pybb.ForumReadTracker']", 'to': "orm['auth.User']"}), + 'topic_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'pybb.forumreadtracker': { + 'Meta': {'object_name': 'ForumReadTracker'}, + 'forum': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pybb.Forum']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'time_stamp': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'pybb.topic': { + 'Meta': {'ordering': "['-created']", 'object_name': 'Topic'}, + 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'forum': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'topics'", 'to': "orm['pybb.Forum']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'on_moderation': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'post_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}), + 'readed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'readed_topics'", 'symmetrical': 'False', 'through': "orm['pybb.TopicReadTracker']", 'to': "orm['auth.User']"}), + 'sticky': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'subscribers': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'subscriptions'", 'blank': 'True', 'to': "orm['auth.User']"}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'views': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}) + }, + 'pybb.topicreadtracker': { + 'Meta': {'object_name': 'TopicReadTracker'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'time_stamp': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'topic': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pybb.Topic']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore_cms'] diff --git a/imagestore/imagestore_cms/migrations/__init__.py b/imagestore/imagestore_cms/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/imagestore/imagestore_cms/models.py b/imagestore/imagestore_cms/models.py new file mode 100644 index 0000000..c4d18d5 --- /dev/null +++ b/imagestore/imagestore_cms/models.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + +from cms.models import CMSPlugin +from django.db import models +from imagestore.models import Album +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings + +class ImagestoreAlbumPtr(CMSPlugin): + album = models.ForeignKey(Album, verbose_name=_('Album'), blank=False, null=False) + +class ImagestoreAlbumCarousel(CMSPlugin): + album = models.ForeignKey(Album, verbose_name=_('Album'), blank=False, null=False) + skin = models.CharField(max_length=100, verbose_name=_('Skin'), default='jcarousel-skin-tango') + limit = models.IntegerField(verbose_name=_('Image limit'), blank=True, null=True) + size = models.CharField(max_length=20, verbose_name=_('Thumbnail size'), default='72x72') + full_size = models.CharField(max_length=20, verbose_name=_('Full size view'), default='600x600') + template_file = models.CharField(max_length=100, verbose_name=_('Template file'), default=getattr(settings,'IMAGESTORE_CAROUSEL_TEMPLATE','cms/plugins/imagestore_album_carousel.html'), blank=True, null=True) \ No newline at end of file diff --git a/imagestore/imagestore_cms/urls.py b/imagestore/imagestore_cms/urls.py new file mode 100644 index 0000000..f386372 --- /dev/null +++ b/imagestore/imagestore_cms/urls.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + +from django.conf.urls.defaults import * +from imagestore.views import AlbumListView + +urlpatterns = patterns('', + url(r'^', include('imagestore.urls', namespace='imagestore')), + ) \ No newline at end of file diff --git a/imagestore/locale/de/LC_MESSAGES/django.mo b/imagestore/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000..011f84f Binary files /dev/null and b/imagestore/locale/de/LC_MESSAGES/django.mo differ diff --git a/imagestore/locale/de/LC_MESSAGES/django.po b/imagestore/locale/de/LC_MESSAGES/django.po new file mode 100644 index 0000000..c689e71 --- /dev/null +++ b/imagestore/locale/de/LC_MESSAGES/django.po @@ -0,0 +1,276 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-09-29 16:54+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: forms.py:22 models/bases/image.py:44 +msgid "Description" +msgstr "Beschreibung" + +#: views.py:63 +#, python-format +msgid "No Tag found matching \"%s\"." +msgstr "Kein Tag gefunden der auf \"%s\" passt." + +#: imagestore_cms/cms_app.py:11 +msgid "Imagestore App" +msgstr "" + +#: imagestore_cms/cms_plugins.py:14 imagestore_cms/models.py:13 +#: imagestore_cms/models.py:16 models/album.py:14 models/bases/image.py:51 +#: templates/imagestore/image-scope.html:9 templates/imagestore/image.html:16 +msgid "Album" +msgstr "" + +#: imagestore_cms/cms_plugins.py:25 +msgid "Album as carousel" +msgstr "Album als Karousel" + +#: imagestore_cms/models.py:17 +msgid "Skin" +msgstr "Skin" + +#: imagestore_cms/models.py:18 +msgid "Image limit" +msgstr "Bilder Limit" + +#: imagestore_cms/models.py:19 +msgid "Thumbnail size" +msgstr "Thumbnail Größe" + +#: imagestore_cms/models.py:20 +msgid "Full size view" +msgstr "Vollbild Ansicht" + +#: imagestore_cms/models.py:21 +msgid "Template file" +msgstr "Template File" + +#: models/album.py:15 +msgid "Albums" +msgstr "Alben" + +#: models/image.py:13 templates/imagestore/image.html:8 +msgid "Image" +msgstr "Bild" + +#: models/image.py:14 +msgid "Images" +msgstr "Bilder" + +#: models/upload.py:84 +msgid "images file (.zip)" +msgstr "Bild Datei (.zip)" + +#: models/upload.py:85 +msgid "Select a .zip file of images to upload into a new Gallery." +msgstr "Zip Datei mit Bilder auswählen um eine neue Gallerie zu erstellen." + +#: models/upload.py:90 +msgid "" +"Select an album to add these images to. leave this empty to create a new " +"album from the supplied title." +msgstr "Bitte Album für neue Bilder auswählen. Leer lassen um ein neues Album zu erstellen." + +#: models/upload.py:95 +msgid "New album name" +msgstr "Name für neues Album" + +#: models/upload.py:96 +msgid "" +"If not empty new album with this name will be created and images will be " +"upload to this album" +msgstr "Falls nicht leer wird ein Album mit diesem Namen erstellt, und hochgeladene Bilder werden in dieses Album hinzugefügt." + +#: models/upload.py:98 +msgid "tags" +msgstr "Tags" + +#: models/upload.py:101 +msgid "Album upload" +msgstr "Album upload" + +#: models/upload.py:102 +msgid "Album uploads" +msgstr "Album uploads" + +#: models/bases/album.py:38 models/bases/image.py:48 +#: templates/imagestore/image-scope.html:4 templates/imagestore/image.html:13 +#: templates/imagestore/user_info.html:7 +msgid "User" +msgstr "Benutzer" + +#: models/bases/album.py:39 +msgid "Name" +msgstr "Name" + +#: models/bases/album.py:40 models/bases/image.py:49 +msgid "Created" +msgstr "Erstellt" + +#: models/bases/album.py:41 models/bases/image.py:50 +msgid "Updated" +msgstr "Aktualisiert" + +#: models/bases/album.py:42 +msgid "Is public" +msgstr "Öffentlich" + +#: models/bases/album.py:45 models/bases/image.py:46 +msgid "Order" +msgstr "Reihenfolge" + +#: models/bases/album.py:72 templates/imagestore/album_list.html:53 +msgid "Empty album" +msgstr "Leeres Album" + +#: models/bases/album.py:74 +msgid "Head" +msgstr "" + +#: models/bases/image.py:43 +msgid "Title" +msgstr "Titel" + +#: models/bases/image.py:45 templates/imagestore/image.html:77 +#: templates/imagestore/tag-cloud.html:7 +msgid "Tags" +msgstr "" + +#: models/bases/image.py:47 +msgid "File" +msgstr "Datei" + +#: models/bases/image.py:68 +msgid "Thumbnail" +msgstr "Vorschau" + +#: templates/imagestore/album_delete.html:6 +msgid "Are you sure that you would like to delete this album?" +msgstr "Dieses Album wirklich löschen?" + +#: templates/imagestore/album_delete.html:10 +#: templates/imagestore/image_confirm_delete.html:10 +#: templates/imagestore/image_delete.html:10 +msgid "No, take me back" +msgstr "Nein, zurück" + +#: templates/imagestore/album_delete.html:11 +#: templates/imagestore/image_confirm_delete.html:11 +#: templates/imagestore/image_delete.html:11 +msgid "Yes, I am sure" +msgstr "Ja" + +#: templates/imagestore/album_list.html:7 +#: templates/imagestore/album_list.html:16 +#: templates/imagestore/album_list.html:37 +msgid "Albums for user" +msgstr "" + +#: templates/imagestore/album_list.html:9 +#: templates/imagestore/album_list.html:18 +#: templates/imagestore/album_list.html:39 +msgid "All albums" +msgstr "Alle Alben" + +#: templates/imagestore/album_list.html:60 +msgid "user" +msgstr "Benutzer" + +#: templates/imagestore/base.html:27 +msgid "Home" +msgstr "Home" + +#: templates/imagestore/base.html:30 templates/imagestore/tag.html:7 +msgid "Gallery" +msgstr "Galerie" + +#: templates/imagestore/base.html:46 +#: templates/imagestore/forms/image_form.html:7 +#: templates/imagestore/forms/image_form.html:11 +#: templates/imagestore/forms/image_form.html:15 +msgid "Upload image" +msgstr "Bild hochladen" + +#: templates/imagestore/base.html:49 +msgid "Create new album" +msgstr "Neues Album erstellen" + +#: templates/imagestore/image-list.html:14 +#: templates/imagestore/image_list.html:55 +msgid "Info" +msgstr "" + +#: templates/imagestore/image-scope.html:14 templates/imagestore/image.html:19 +#: templates/imagestore/tag.html:7 templates/imagestore/tag.html.py:11 +#: templates/imagestore/tag.html:15 +msgid "Tag" +msgstr "" + +#: templates/imagestore/image.html:56 +msgid "previous image" +msgstr "Vorheriges Bild" + +#: templates/imagestore/image.html:59 +msgid "next image" +msgstr "Nächstes Bild" + +#: templates/imagestore/image.html:69 +msgid "Edit info" +msgstr "Info editieren" + +#: templates/imagestore/image.html:70 +msgid "Delete image" +msgstr "Bild löschen" + +#: templates/imagestore/image.html:85 +msgid "Place" +msgstr "" + +#: templates/imagestore/image_confirm_delete.html:6 +#: templates/imagestore/image_delete.html:6 +msgid "Are you sure that you would like to delete this image?" +msgstr "Soll das Bild sicher gelöscht werden?" + +#: templates/imagestore/image_list.html:34 +#: templates/imagestore/forms/album_form.html:13 +#: templates/imagestore/forms/album_form.html:23 +msgid "Edit album" +msgstr "Album bearbeiten" + +#: templates/imagestore/pagination.html:8 +msgid "previous page" +msgstr "Vorherige Seite" + +#: templates/imagestore/pagination.html:22 +msgid "next page" +msgstr "Nächste Seite" + +#: templates/imagestore/forms/album_form.html:7 +#: templates/imagestore/forms/album_form.html:15 +#: templates/imagestore/forms/album_form.html:25 +msgid "Create album" +msgstr "Neues album" + +#: templates/imagestore/forms/album_form.html:31 +msgid "Save" +msgstr "Speichern" + +#: templates/imagestore/forms/image_form.html:19 +msgid "Upload" +msgstr "Hochladen" diff --git a/imagestore/migrations/0001_initial.py b/imagestore/migrations/0001_initial.py new file mode 100644 index 0000000..b1b6942 --- /dev/null +++ b/imagestore/migrations/0001_initial.py @@ -0,0 +1,78 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'Category' + db.create_table('imagestore_category', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('parent', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='children', null=True, to=orm['imagestore.Category'])), + ('slug', self.gf('django.db.models.fields.SlugField')(max_length=200, db_index=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=200)), + ('order', self.gf('django.db.models.fields.IntegerField')()), + ('is_public', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + )) + db.send_create_signal('imagestore', ['Category']) + + # Adding model 'Image' + db.create_table('imagestore_image', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('slug', self.gf('django.db.models.fields.SlugField')(db_index=True, max_length=200, null=True, blank=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True)), + ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), + ('tags', self.gf('tagging.fields.TagField')()), + ('category', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['imagestore.Category'])), + ('order', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)), + ('is_public', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('image', self.gf('sorl.thumbnail.fields.ImageField')(max_length=100)), + )) + db.send_create_signal('imagestore', ['Image']) + + + def backwards(self, orm): + + # Deleting model 'Category' + db.delete_table('imagestore_category') + + # Deleting model 'Image' + db.delete_table('imagestore_image') + + + models = { + 'imagestore.category': { + 'Meta': {'object_name': 'Category'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['imagestore.Category']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '200', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'imagestore.image': { + 'Meta': {'object_name': 'Image'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Category']"}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0002_removeslug.py b/imagestore/migrations/0002_removeslug.py new file mode 100644 index 0000000..4d6fe66 --- /dev/null +++ b/imagestore/migrations/0002_removeslug.py @@ -0,0 +1,48 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Deleting field 'Image.slug' + db.delete_column('imagestore_image', 'slug') + + + def backwards(self, orm): + + # Adding field 'Image.slug' + db.add_column('imagestore_image', 'slug', self.gf('django.db.models.fields.SlugField')(blank=True, max_length=200, null=True, db_index=True), keep_default=False) + + + models = { + 'imagestore.category': { + 'Meta': {'ordering': "('order', 'title')", 'object_name': 'Category'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['imagestore.Category']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '200', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'imagestore.image': { + 'Meta': {'object_name': 'Image'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'images'", 'to': "orm['imagestore.Category']"}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0003_adduser.py b/imagestore/migrations/0003_adduser.py new file mode 100644 index 0000000..e458f79 --- /dev/null +++ b/imagestore/migrations/0003_adduser.py @@ -0,0 +1,85 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding field 'Image.user' + db.add_column('imagestore_image', 'user', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='images', null=True, to=orm['auth.User']), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'Image.user' + db.delete_column('imagestore_image', 'user_id') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.category': { + 'Meta': {'ordering': "('order', 'title')", 'object_name': 'Category'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['imagestore.Category']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '200', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'imagestore.image': { + 'Meta': {'object_name': 'Image'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'images'", 'to': "orm['imagestore.Category']"}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0004_nonullorder.py b/imagestore/migrations/0004_nonullorder.py new file mode 100644 index 0000000..783bbba --- /dev/null +++ b/imagestore/migrations/0004_nonullorder.py @@ -0,0 +1,85 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Changing field 'Image.order' + db.alter_column('imagestore_image', 'order', self.gf('django.db.models.fields.IntegerField')()) + + + def backwards(self, orm): + + # Changing field 'Image.order' + db.alter_column('imagestore_image', 'order', self.gf('django.db.models.fields.IntegerField')(null=True)) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.category': { + 'Meta': {'ordering': "('order', 'title')", 'object_name': 'Category'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['imagestore.Category']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '200', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'images'", 'to': "orm['imagestore.Category']"}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0005_addalbum.py b/imagestore/migrations/0005_addalbum.py new file mode 100644 index 0000000..b92d5bd --- /dev/null +++ b/imagestore/migrations/0005_addalbum.py @@ -0,0 +1,98 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'Album' + db.create_table('imagestore_album', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), + ('updated', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), + )) + db.send_create_signal('imagestore', ['Album']) + + + def backwards(self, orm): + + # Deleting model 'Album' + db.delete_table('imagestore_album') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + 'imagestore.category': { + 'Meta': {'ordering': "('order', 'title')", 'object_name': 'Category'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['imagestore.Category']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '200', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'images'", 'to': "orm['imagestore.Category']"}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0006_addcreatedupdated.py b/imagestore/migrations/0006_addcreatedupdated.py new file mode 100644 index 0000000..7a13588 --- /dev/null +++ b/imagestore/migrations/0006_addcreatedupdated.py @@ -0,0 +1,106 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding field 'Image.created' + db.add_column('imagestore_image', 'created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, null=True, blank=True), keep_default=False) + + # Adding field 'Image.updated' + db.add_column('imagestore_image', 'updated', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, null=True, blank=True), keep_default=False) + + # Changing field 'Image.category' + db.alter_column('imagestore_image', 'category_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['imagestore.Category'])) + + + def backwards(self, orm): + + # Deleting field 'Image.created' + db.delete_column('imagestore_image', 'created') + + # Deleting field 'Image.updated' + db.delete_column('imagestore_image', 'updated') + + # User chose to not deal with backwards NULL issues for 'Image.category' + raise RuntimeError("Cannot reverse this migration. 'Image.category' and its values cannot be restored.") + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + 'imagestore.category': { + 'Meta': {'ordering': "('order', 'title')", 'object_name': 'Category'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['imagestore.Category']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '200', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Category']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0007_albumfix.py b/imagestore/migrations/0007_albumfix.py new file mode 100644 index 0000000..7a8d6a1 --- /dev/null +++ b/imagestore/migrations/0007_albumfix.py @@ -0,0 +1,131 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Deleting model 'Category' + db.delete_table('imagestore_category') + + # Adding field 'Album.user' + db.add_column('imagestore_album', 'user', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='albums', null=True, to=orm['auth.User']), keep_default=False) + + # Adding field 'Album.is_public' + db.add_column('imagestore_album', 'is_public', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False) + + # Adding field 'Album.head' + db.add_column('imagestore_album', 'head', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='head_of', null=True, to=orm['imagestore.Image']), keep_default=False) + + # Deleting field 'Image.is_public' + db.delete_column('imagestore_image', 'is_public') + + # Deleting field 'Image.category' + db.delete_column('imagestore_image', 'category_id') + + # Adding field 'Image.album' + db.add_column('imagestore_image', 'album', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='images', null=True, to=orm['imagestore.Album']), keep_default=False) + + + def backwards(self, orm): + + # Adding model 'Category' + db.create_table('imagestore_category', ( + ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('parent', self.gf('django.db.models.fields.related.ForeignKey')(related_name='children', null=True, to=orm['imagestore.Category'], blank=True)), + ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('is_public', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('slug', self.gf('django.db.models.fields.SlugField')(max_length=200, db_index=True)), + ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=200)), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('order', self.gf('django.db.models.fields.IntegerField')(default=0)), + )) + db.send_create_signal('imagestore', ['Category']) + + # Deleting field 'Album.user' + db.delete_column('imagestore_album', 'user_id') + + # Deleting field 'Album.is_public' + db.delete_column('imagestore_album', 'is_public') + + # Deleting field 'Album.head' + db.delete_column('imagestore_album', 'head_id') + + # Adding field 'Image.is_public' + db.add_column('imagestore_image', 'is_public', self.gf('django.db.models.fields.BooleanField')(default=True), keep_default=False) + + # Adding field 'Image.category' + db.add_column('imagestore_image', 'category', self.gf('django.db.models.fields.related.ForeignKey')(related_name='images', null=True, to=orm['imagestore.Category'], blank=True), keep_default=False) + + # Deleting field 'Image.album' + db.delete_column('imagestore_image', 'album_id') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0008_permissions.py b/imagestore/migrations/0008_permissions.py new file mode 100644 index 0000000..f6cf342 --- /dev/null +++ b/imagestore/migrations/0008_permissions.py @@ -0,0 +1,93 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models +from django.contrib.auth.management import create_permissions +from django.contrib.auth.models import User, Permission +from django.db.models import get_app + +class Migration(DataMigration): + + def forwards(self, orm): + app = get_app('imagestore') + create_permissions(app, (), 2) + add_image_permission = Permission.objects.get_by_natural_key('add_image', 'imagestore', 'image') + add_album_permission = Permission.objects.get_by_natural_key('add_album', 'imagestore', 'album') + change_image_permission = Permission.objects.get_by_natural_key('change_image', 'imagestore', 'image') + change_album_permission = Permission.objects.get_by_natural_key('change_album', 'imagestore', 'album') + delete_image_permission = Permission.objects.get_by_natural_key('delete_image', 'imagestore','image') + delete_album_permission = Permission.objects.get_by_natural_key('delete_album', 'imagestore', 'album') + for user in User.objects.all(): + user.user_permissions.add(add_image_permission, add_album_permission,) + user.user_permissions.add(change_image_permission, change_album_permission,) + user.user_permissions.add(delete_image_permission, delete_album_permission,) + user.save() + + def backwards(self, orm): + "Write your backwards methods here." + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0009_limits.py b/imagestore/migrations/0009_limits.py new file mode 100644 index 0000000..8ec5ffb --- /dev/null +++ b/imagestore/migrations/0009_limits.py @@ -0,0 +1,89 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Changing field 'Album.name' + db.alter_column('imagestore_album', 'name', self.gf('django.db.models.fields.CharField')(max_length=20)) + + # Changing field 'Image.title' + db.alter_column('imagestore_image', 'title', self.gf('django.db.models.fields.CharField')(max_length=20, null=True)) + + + def backwards(self, orm): + + # Changing field 'Album.name' + db.alter_column('imagestore_album', 'name', self.gf('django.db.models.fields.CharField')(max_length=200)) + + # Changing field 'Image.title' + db.alter_column('imagestore_image', 'title', self.gf('django.db.models.fields.CharField')(max_length=200, null=True)) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0010_addplace.py b/imagestore/migrations/0010_addplace.py new file mode 100644 index 0000000..6ba9731 --- /dev/null +++ b/imagestore/migrations/0010_addplace.py @@ -0,0 +1,172 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models +try: + from places.models import GeoPlace +except: + GeoPlace = None + +class Migration(SchemaMigration): + + def forwards(self, orm): + if GeoPlace: + # Adding field 'Image.place' + db.add_column('imagestore_image', 'place', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='images', null=True, to=orm['places.GeoPlace']), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'Image.place' + db.delete_column('imagestore_image', 'place_id') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'place': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['places.GeoPlace']"}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'places.geoplace': { + 'Meta': {'object_name': 'GeoPlace'}, + 'addional_info': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'address': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'imagestore_tag': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'latitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'longtitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'metro': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'minuses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'near_objects': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'near_objects_rel_+'", 'null': 'True', 'to': "orm['places.GeoPlace']"}), + 'near_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'path_to': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'phone': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'pluses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'topic': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pybb.Topic']", 'null': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['places.PlaceType']", 'null': 'None', 'blank': 'None'}), + 'work_time': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + 'places.placetype': { + 'Meta': {'object_name': 'PlaceType'}, + 'forum': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pybb.Forum']", 'null': 'True', 'blank': 'True'}), + 'forum_user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'icon_style': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'name_plural': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'path_to_image': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}) + }, + 'pybb.category': { + 'Meta': {'ordering': "['position']", 'object_name': 'Category'}, + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'position': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}) + }, + 'pybb.forum': { + 'Meta': {'ordering': "['position']", 'object_name': 'Forum'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'forums'", 'to': "orm['pybb.Category']"}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'headline': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'moderators': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'position': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}), + 'post_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}), + 'readed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'readed_forums'", 'symmetrical': 'False', 'through': "orm['pybb.ForumReadTracker']", 'to': "orm['auth.User']"}), + 'topic_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'pybb.forumreadtracker': { + 'Meta': {'object_name': 'ForumReadTracker'}, + 'forum': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pybb.Forum']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'time_stamp': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'pybb.topic': { + 'Meta': {'ordering': "['-created']", 'object_name': 'Topic'}, + 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'forum': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'topics'", 'to': "orm['pybb.Forum']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'post_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}), + 'readed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'readed_topics'", 'symmetrical': 'False', 'through': "orm['pybb.TopicReadTracker']", 'to': "orm['auth.User']"}), + 'sticky': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'subscribers': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'subscriptions'", 'blank': 'True', 'to': "orm['auth.User']"}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'views': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}) + }, + 'pybb.topicreadtracker': { + 'Meta': {'object_name': 'TopicReadTracker'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'time_stamp': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'topic': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pybb.Topic']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0011_add_mass_upload.py b/imagestore/migrations/0011_add_mass_upload.py new file mode 100644 index 0000000..f0df949 --- /dev/null +++ b/imagestore/migrations/0011_add_mass_upload.py @@ -0,0 +1,98 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'AlbumUpload' + db.create_table('imagestore_albumupload', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('zip_file', self.gf('django.db.models.fields.files.FileField')(max_length=100)), + ('album', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['imagestore.Album'], null=True, blank=True)), + ('new_album_name', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('tags', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + )) + db.send_create_signal('imagestore', ['AlbumUpload']) + + + def backwards(self, orm): + + # Deleting model 'AlbumUpload' + db.delete_table('imagestore_albumupload') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.albumupload': { + 'Meta': {'object_name': 'AlbumUpload'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'new_album_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'tags': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'zip_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0012_add_order.py b/imagestore/migrations/0012_add_order.py new file mode 100644 index 0000000..181a4b5 --- /dev/null +++ b/imagestore/migrations/0012_add_order.py @@ -0,0 +1,92 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding field 'Album.order' + db.add_column('imagestore_album', 'order', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'Album.order' + db.delete_column('imagestore_album', 'order') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.albumupload': { + 'Meta': {'object_name': 'AlbumUpload'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'new_album_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'tags': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'zip_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0013_fix_album_title_length.py b/imagestore/migrations/0013_fix_album_title_length.py new file mode 100644 index 0000000..fa3f42f --- /dev/null +++ b/imagestore/migrations/0013_fix_album_title_length.py @@ -0,0 +1,92 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Changing field 'Image.title' + db.alter_column('imagestore_image', 'title', self.gf('django.db.models.fields.CharField')(max_length=100, null=True)) + + + def backwards(self, orm): + + # Changing field 'Image.title' + db.alter_column('imagestore_image', 'title', self.gf('django.db.models.fields.CharField')(max_length=20, null=True)) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.albumupload': { + 'Meta': {'object_name': 'AlbumUpload'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'new_album_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'tags': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'zip_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/0014_fix_album_name_length.py b/imagestore/migrations/0014_fix_album_name_length.py new file mode 100644 index 0000000..2cc2713 --- /dev/null +++ b/imagestore/migrations/0014_fix_album_name_length.py @@ -0,0 +1,92 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Changing field 'Album.name' + db.alter_column('imagestore_album', 'name', self.gf('django.db.models.fields.CharField')(max_length=100)) + + + def backwards(self, orm): + + # Changing field 'Album.name' + db.alter_column('imagestore_album', 'name', self.gf('django.db.models.fields.CharField')(max_length=20)) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'imagestore.album': { + 'Meta': {'ordering': "('created', 'name')", 'object_name': 'Album'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'head_of'", 'null': 'True', 'to': "orm['imagestore.Image']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'albums'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'imagestore.albumupload': { + 'Meta': {'object_name': 'AlbumUpload'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['imagestore.Album']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'new_album_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'tags': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'zip_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}) + }, + 'imagestore.image': { + 'Meta': {'ordering': "('order', 'id')", 'object_name': 'Image'}, + 'album': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['imagestore.Album']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'tags': ('tagging.fields.TagField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'images'", 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['imagestore'] diff --git a/imagestore/migrations/__init__.py b/imagestore/migrations/__init__.py new file mode 100644 index 0000000..04ccd4b --- /dev/null +++ b/imagestore/migrations/__init__.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + \ No newline at end of file diff --git a/imagestore/models/__init__.py b/imagestore/models/__init__.py new file mode 100644 index 0000000..c9fd014 --- /dev/null +++ b/imagestore/models/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' +from imagestore.utils import load_class, get_model_string +from django.conf import settings + +Album = load_class(getattr(settings, 'IMAGESTORE_ALBUM_MODEL', 'imagestore.models.album.Album')) +Image = load_class(getattr(settings, 'IMAGESTORE_IMAGE_MODEL', 'imagestore.models.image.Image')) + +# This labels and classnames used to generate permissons labels +image_applabel = Image._meta.app_label +image_classname = Image.__name__.lower() + +album_applabel = Album._meta.app_label +album_classname = Album.__name__.lower() + + +from upload import AlbumUpload \ No newline at end of file diff --git a/imagestore/models/album.py b/imagestore/models/album.py new file mode 100644 index 0000000..1e69927 --- /dev/null +++ b/imagestore/models/album.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + +from bases.album import BaseAlbum +from django.utils.translation import ugettext_lazy as _ +from imagestore.utils import load_class, get_model_string + +class Album(BaseAlbum): + + class Meta(BaseAlbum.Meta): + abstract = False + verbose_name = _('Album') + verbose_name_plural = _('Albums') + app_label = 'imagestore' \ No newline at end of file diff --git a/imagestore/models/bases/__init__.py b/imagestore/models/bases/__init__.py new file mode 100644 index 0000000..04ccd4b --- /dev/null +++ b/imagestore/models/bases/__init__.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + \ No newline at end of file diff --git a/imagestore/models/bases/album.py b/imagestore/models/bases/album.py new file mode 100644 index 0000000..cf64801 --- /dev/null +++ b/imagestore/models/bases/album.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + + +from django.db import models +from django.db.models import permalink +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from sorl.thumbnail import get_thumbnail + +try: + from django.contrib.auth import get_user_model + User = get_user_model() +except ImportError: + from django.contrib.auth.models import User + +try: + import Image as PILImage +except ImportError: + from PIL import Image as PILImage + +from imagestore.utils import get_model_string + + +SELF_MANAGE = getattr(settings, 'IMAGESTORE_SELF_MANAGE', True) + + +class BaseAlbum(models.Model): + class Meta(object): + abstract = True + ordering = ('order', 'created', 'name') + permissions = ( + ('moderate_albums', 'View, update and delete any album'), + ) + + user = models.ForeignKey(User, verbose_name=_('User'), null=True, blank=True, related_name='albums') + name = models.CharField(_('Name'), max_length=100, blank=False, null=False) + created = models.DateTimeField(_('Created'), auto_now_add=True) + updated = models.DateTimeField(_('Updated'), auto_now=True) + is_public = models.BooleanField(_('Is public'), default=True) + head = models.ForeignKey(get_model_string('Image'), related_name='head_of', null=True, blank=True, on_delete=models.SET_NULL) + + order = models.IntegerField(_('Order'), default=0) + + def get_head(self): + if self.head: + return self.head + else: + if self.images.all().count()>0: + self.head = self.images.all()[0] + self.save() + return self.head + else: + return None + + @permalink + def get_absolute_url(self): + return 'imagestore:album', (), {'album_id': self.id} + + def __unicode__(self): + return self.name + + def admin_thumbnail(self): + img = self.get_head() + if img: + try: + return '' % get_thumbnail(img.image, '100x100', crop='center').url + except IOError: + return 'IOError' + return _('Empty album') + + admin_thumbnail.short_description = _('Head') + admin_thumbnail.allow_tags = True \ No newline at end of file diff --git a/imagestore/models/bases/image.py b/imagestore/models/bases/image.py new file mode 100644 index 0000000..ef2ef21 --- /dev/null +++ b/imagestore/models/bases/image.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + + +from django.db import models +from django.db.models import permalink +from sorl.thumbnail.helpers import ThumbnailError +from tagging.fields import TagField +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from sorl.thumbnail import ImageField, get_thumbnail +from django.contrib.auth.models import Permission +from django.db.models.signals import post_save +from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ObjectDoesNotExist + +try: + from django.contrib.auth import get_user_model + User = get_user_model() +except ImportError: + from django.contrib.auth.models import User + +try: + import Image as PILImage +except ImportError: + from PIL import Image as PILImage + +from imagestore.utils import get_file_path, get_model_string + +SELF_MANAGE = getattr(settings, 'IMAGESTORE_SELF_MANAGE', True) + + +class BaseImage(models.Model): + class Meta(object): + abstract = True + ordering = ('order', 'id') + permissions = ( + ('moderate_images', 'View, update and delete any image'), + ) + + title = models.CharField(_('Title'), max_length=100, blank=True, null=True) + description = models.TextField(_('Description'), blank=True, null=True) + tags = TagField(_('Tags'), blank=True) + order = models.IntegerField(_('Order'), default=0) + image = ImageField(verbose_name = _('File'), upload_to=get_file_path) + user = models.ForeignKey(User, verbose_name=_('User'), null=True, blank=True, related_name='images') + created = models.DateTimeField(_('Created'), auto_now_add=True, null=True) + updated = models.DateTimeField(_('Updated'), auto_now=True, null=True) + album = models.ForeignKey(get_model_string('Album'), verbose_name=_('Album'), null=True, blank=True, related_name='images') + + @permalink + def get_absolute_url(self): + return 'imagestore:image', (), {'pk': self.id} + + def __unicode__(self): + return '%s'% self.id + + def admin_thumbnail(self): + try: + return '' % get_thumbnail(self.image, '100x100', crop='center').url + except IOError: + return 'IOError' + except ThumbnailError, ex: + return 'ThumbnailError, %s' % ex.message + + admin_thumbnail.short_description = _('Thumbnail') + admin_thumbnail.allow_tags = True + + +#noinspection PyUnusedLocal +def setup_imagestore_permissions(instance, created, **kwargs): + if not created: + return + try: + from imagestore.models import Album, Image + album_type = ContentType.objects.get( + #app_label=load_class('imagestore.models.Album')._meta.app_label, + app_label = Album._meta.app_label, + name='Album' + ) + image_type = ContentType.objects.get( + #app_label=load_class('imagestore.models.Image')._meta.app_label, + app_label = Image._meta.app_label, + name='Image' + ) + add_image_permission = Permission.objects.get(codename='add_image', content_type=image_type) + add_album_permission = Permission.objects.get(codename='add_album', content_type=album_type) + change_image_permission = Permission.objects.get(codename='change_image', content_type=image_type) + change_album_permission = Permission.objects.get(codename='change_album', content_type=album_type) + delete_image_permission = Permission.objects.get(codename='delete_image', content_type=image_type) + delete_album_permission = Permission.objects.get(codename='delete_album', content_type=album_type) + instance.user_permissions.add(add_image_permission, add_album_permission,) + instance.user_permissions.add(change_image_permission, change_album_permission,) + instance.user_permissions.add(delete_image_permission, delete_album_permission,) + except ObjectDoesNotExist: + # Permissions are not yet installed or conten does not created yet + # probaly this is first + pass + + +if SELF_MANAGE: + post_save.connect(setup_imagestore_permissions, User) \ No newline at end of file diff --git a/imagestore/models/image.py b/imagestore/models/image.py new file mode 100644 index 0000000..17876f1 --- /dev/null +++ b/imagestore/models/image.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + +from bases.image import BaseImage +from django.utils.translation import ugettext_lazy as _ +from imagestore.utils import load_class, get_model_string + +class Image(BaseImage): + class Meta(BaseImage.Meta): + abstract = False + verbose_name = _('Image') + verbose_name_plural = _('Images') + app_label = 'imagestore' \ No newline at end of file diff --git a/imagestore/models/upload.py b/imagestore/models/upload.py new file mode 100644 index 0000000..348a7a9 --- /dev/null +++ b/imagestore/models/upload.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +from django.core.exceptions import ImproperlyConfigured +from django.utils.importlib import import_module + +__author__ = 'zeus' + +import os +import zipfile +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from django.core.files.base import ContentFile +try: + import Image as PILImage +except ImportError: + from PIL import Image as PILImage + +from imagestore.models import Album, Image + +TEMP_DIR = getattr(settings, 'TEMP_DIR', 'temp/') + + +def process_zipfile(uploaded_album): + if os.path.isfile(uploaded_album.zip_file.path): + # TODO: implement try-except here + zip = zipfile.ZipFile(uploaded_album.zip_file.path) + bad_file = zip.testzip() + if bad_file: + raise Exception('"%s" in the .zip archive is corrupt.' % bad_file) + + if not uploaded_album.album: + uploaded_album.album = Album.objects.create(name=uploaded_album.new_album_name) + + from cStringIO import StringIO + for filename in sorted(zip.namelist()): + if filename.startswith('__'): # do not process meta files + continue + print filename + data = zip.read(filename) + if len(data): + try: + # the following is taken from django.forms.fields.ImageField: + # load() could spot a truncated JPEG, but it loads the entire + # image in memory, which is a DoS vector. See #3848 and #18520. + # verify() must be called immediately after the constructor. + PILImage.open(StringIO(data)).verify() + except Exception, ex: + # if a "bad" file is found we just skip it. + print('Error verify image: %s' % ex.message) + continue + if hasattr(data, 'seek') and callable(data.seek): + print 'seeked' + data.seek(0) + try: + img = Image(album=uploaded_album.album) + img.image.save(filename, ContentFile(data)) + img.save() + except Exception, ex: + print('error create Image: %s' % ex.message) + zip.close() + uploaded_album.delete() + + +upload_processor_function = getattr(settings, 'IMAGESTORE_UPLOAD_ALBUM_PROCESSOR', None) +upload_processor = process_zipfile +if upload_processor_function: + i = upload_processor_function.rfind('.') + module, attr = upload_processor_function[:i], upload_processor_function[i+1:] + try: + mod = import_module(module) + except ImportError as e: + raise ImproperlyConfigured('Error importing request processor module %s: "%s"' % (module, e)) + try: + upload_processor = getattr(mod, attr) + except AttributeError: + raise ImproperlyConfigured('Module "%s" does not define a "%s" callable request processor' % (module, attr)) + + +class AlbumUpload(models.Model): + """ + Just re-written django-photologue GalleryUpload method + """ + zip_file = models.FileField(_('images file (.zip)'), upload_to=TEMP_DIR, + help_text=_('Select a .zip file of images to upload into a new Gallery.')) + album = models.ForeignKey( + Album, + null=True, + blank=True, + help_text=_('Select an album to add these images to. leave this empty to create a new album from the supplied title.') + ) + new_album_name = models.CharField( + max_length=255, + blank=True, + verbose_name=_('New album name'), + help_text=_('If not empty new album with this name will be created and images will be upload to this album') + ) + tags = models.CharField(max_length=255, blank=True, verbose_name=_('tags')) + + class Meta(object): + verbose_name = _('Album upload') + verbose_name_plural = _('Album uploads') + app_label = 'imagestore' + + def save(self, *args, **kwargs): + super(AlbumUpload, self).save(*args, **kwargs) + upload_processor(self) + + def delete(self, *args, **kwargs): + storage, path = self.zip_file.storage, self.zip_file.path + super(AlbumUpload, self).delete(*args, **kwargs) + storage.delete(path) diff --git a/imagestore/static/imagestore.css b/imagestore/static/imagestore.css new file mode 100644 index 0000000..b5bc09c --- /dev/null +++ b/imagestore/static/imagestore.css @@ -0,0 +1,107 @@ +#category-list li{ + font-size: 120%; + padding-bottom: 15px; +} + +#category-list { + padding-bottom: 10px; +} + +#controls { + font-size: 90%; +} + +#controls .controls-group { + padding-top: 10px; +} + +.image-description { + padding: 10px 0 10px 0; +} + +.navigation { + text-align: center; + padding: 0 0 10px 0; + font-size: 110%; +} + +.navigation .next-link { + margin-left: 100px; +} + +img.current { + border: 1px red solid; +} + +#image-view img.preview { + display: block; + margin: 0 auto 0 auto; +} + +#image-view { + margin-right: 300px; +} + +.album-list .album { + width: 160px; + height: 200px; + float: left; + padding: 5px; + margin: 10px; +} + +.album-name { + width: 100%; + text-align: center; +} + +.album-user { + width: 100%; + text-align: center; + font-size: 80%; + color: #CCC; +} + +.album-head { + height: 150px; + width: 150px; + display: table-cell; + vertical-align: middle; + text-align: center; +} +.album-head a { + text-align: center; +} + +.user-info { + padding: 20px 0; +} + +.image-preview { + float: left; + width: 130px; + padding: 5px; + height: 160px; +} + +.image-preview .image-title { + font-size: 80%; +} + +.extra-fields { + font-size: 80%; + margin: 10px 0; +} + +.extra-fields label { + color: #666666; +} + +.basic-fields, .extra-fields { + display: block; + float: left; +} + +.pagination .disabled { + display: none; +} \ No newline at end of file diff --git a/imagestore/static/prettyphoto/README b/imagestore/static/prettyphoto/README new file mode 100755 index 0000000..1e56842 --- /dev/null +++ b/imagestore/static/prettyphoto/README @@ -0,0 +1,30 @@ +prettyPhoto v3.1.4 +© Copyright, Stephane Caron +http://www.no-margin-for-errors.com + + +============================= Released under ============================= + +Creative Commons 2.5 +http://creativecommons.org/licenses/by/2.5/ + +OR + +GPLV2 license +http://www.gnu.org/licenses/gpl-2.0.html + +You are free to use prettyPhoto in commercial projects as long as the +copyright header is left intact. + +============================ More information ============================ +http://www.no-margin-for-errors.com/projects/prettyPhoto/ + + +============================== Description =============================== + +prettyPhoto is a jQuery based lightbox clone. Not only does it support images, +it also add support for videos, flash, YouTube, iFrame. It's a full blown +media modal box. + +Please refer to http://www.no-margin-for-errors.com/projects/prettyPhoto/ +for all the details on how to use. diff --git a/imagestore/static/prettyphoto/css/prettyPhoto.css b/imagestore/static/prettyphoto/css/prettyPhoto.css new file mode 100644 index 0000000..8a2a2fd --- /dev/null +++ b/imagestore/static/prettyphoto/css/prettyPhoto.css @@ -0,0 +1,170 @@ +div.pp_default .pp_top,div.pp_default .pp_top .pp_middle,div.pp_default .pp_top .pp_left,div.pp_default .pp_top .pp_right,div.pp_default .pp_bottom,div.pp_default .pp_bottom .pp_left,div.pp_default .pp_bottom .pp_middle,div.pp_default .pp_bottom .pp_right{height:13px} +div.pp_default .pp_top .pp_left{background:url(../images/prettyPhoto/default/sprite.png) -78px -93px no-repeat} +div.pp_default .pp_top .pp_middle{background:url(../images/prettyPhoto/default/sprite_x.png) top left repeat-x} +div.pp_default .pp_top .pp_right{background:url(../images/prettyPhoto/default/sprite.png) -112px -93px no-repeat} +div.pp_default .pp_content .ppt{color:#f8f8f8} +div.pp_default .pp_content_container .pp_left{background:url(../images/prettyPhoto/default/sprite_y.png) -7px 0 repeat-y;padding-left:13px} +div.pp_default .pp_content_container .pp_right{background:url(../images/prettyPhoto/default/sprite_y.png) top right repeat-y;padding-right:13px} +div.pp_default .pp_next:hover{background:url(../images/prettyPhoto/default/sprite_next.png) center right no-repeat;cursor:pointer} +div.pp_default .pp_previous:hover{background:url(../images/prettyPhoto/default/sprite_prev.png) center left no-repeat;cursor:pointer} +div.pp_default .pp_expand{background:url(../images/prettyPhoto/default/sprite.png) 0 -29px no-repeat;cursor:pointer;width:28px;height:28px} +div.pp_default .pp_expand:hover{background:url(../images/prettyPhoto/default/sprite.png) 0 -56px no-repeat;cursor:pointer} +div.pp_default .pp_contract{background:url(../images/prettyPhoto/default/sprite.png) 0 -84px no-repeat;cursor:pointer;width:28px;height:28px} +div.pp_default .pp_contract:hover{background:url(../images/prettyPhoto/default/sprite.png) 0 -113px no-repeat;cursor:pointer} +div.pp_default .pp_close{width:30px;height:30px;background:url(../images/prettyPhoto/default/sprite.png) 2px 1px no-repeat;cursor:pointer} +div.pp_default .pp_gallery ul li a{background:url(../images/prettyPhoto/default/default_thumb.png) center center #f8f8f8;border:1px solid #aaa} +div.pp_default .pp_social{margin-top:7px} +div.pp_default .pp_gallery a.pp_arrow_previous,div.pp_default .pp_gallery a.pp_arrow_next{position:static;left:auto} +div.pp_default .pp_nav .pp_play,div.pp_default .pp_nav .pp_pause{background:url(../images/prettyPhoto/default/sprite.png) -51px 1px no-repeat;height:30px;width:30px} +div.pp_default .pp_nav .pp_pause{background-position:-51px -29px} +div.pp_default a.pp_arrow_previous,div.pp_default a.pp_arrow_next{background:url(../images/prettyPhoto/default/sprite.png) -31px -3px no-repeat;height:20px;width:20px;margin:4px 0 0} +div.pp_default a.pp_arrow_next{left:52px;background-position:-82px -3px} +div.pp_default .pp_content_container .pp_details{margin-top:5px} +div.pp_default .pp_nav{clear:none;height:30px;width:110px;position:relative} +div.pp_default .pp_nav .currentTextHolder{font-family:Georgia;font-style:italic;color:#999;font-size:11px;left:75px;line-height:25px;position:absolute;top:2px;margin:0;padding:0 0 0 10px} +div.pp_default .pp_close:hover,div.pp_default .pp_nav .pp_play:hover,div.pp_default .pp_nav .pp_pause:hover,div.pp_default .pp_arrow_next:hover,div.pp_default .pp_arrow_previous:hover{opacity:0.7} +div.pp_default .pp_description{font-size:11px;font-weight:700;line-height:14px;margin:5px 50px 5px 0} +div.pp_default .pp_bottom .pp_left{background:url(../images/prettyPhoto/default/sprite.png) -78px -127px no-repeat} +div.pp_default .pp_bottom .pp_middle{background:url(../images/prettyPhoto/default/sprite_x.png) bottom left repeat-x} +div.pp_default .pp_bottom .pp_right{background:url(../images/prettyPhoto/default/sprite.png) -112px -127px no-repeat} +div.pp_default .pp_loaderIcon{background:url(../images/prettyPhoto/default/loader.gif) center center no-repeat} +div.light_rounded .pp_top .pp_left{background:url(../images/prettyPhoto/light_rounded/sprite.png) -88px -53px no-repeat} +div.light_rounded .pp_top .pp_right{background:url(../images/prettyPhoto/light_rounded/sprite.png) -110px -53px no-repeat} +div.light_rounded .pp_next:hover{background:url(../images/prettyPhoto/light_rounded/btnNext.png) center right no-repeat;cursor:pointer} +div.light_rounded .pp_previous:hover{background:url(../images/prettyPhoto/light_rounded/btnPrevious.png) center left no-repeat;cursor:pointer} +div.light_rounded .pp_expand{background:url(../images/prettyPhoto/light_rounded/sprite.png) -31px -26px no-repeat;cursor:pointer} +div.light_rounded .pp_expand:hover{background:url(../images/prettyPhoto/light_rounded/sprite.png) -31px -47px no-repeat;cursor:pointer} +div.light_rounded .pp_contract{background:url(../images/prettyPhoto/light_rounded/sprite.png) 0 -26px no-repeat;cursor:pointer} +div.light_rounded .pp_contract:hover{background:url(../images/prettyPhoto/light_rounded/sprite.png) 0 -47px no-repeat;cursor:pointer} +div.light_rounded .pp_close{width:75px;height:22px;background:url(../images/prettyPhoto/light_rounded/sprite.png) -1px -1px no-repeat;cursor:pointer} +div.light_rounded .pp_nav .pp_play{background:url(../images/prettyPhoto/light_rounded/sprite.png) -1px -100px no-repeat;height:15px;width:14px} +div.light_rounded .pp_nav .pp_pause{background:url(../images/prettyPhoto/light_rounded/sprite.png) -24px -100px no-repeat;height:15px;width:14px} +div.light_rounded .pp_arrow_previous{background:url(../images/prettyPhoto/light_rounded/sprite.png) 0 -71px no-repeat} +div.light_rounded .pp_arrow_next{background:url(../images/prettyPhoto/light_rounded/sprite.png) -22px -71px no-repeat} +div.light_rounded .pp_bottom .pp_left{background:url(../images/prettyPhoto/light_rounded/sprite.png) -88px -80px no-repeat} +div.light_rounded .pp_bottom .pp_right{background:url(../images/prettyPhoto/light_rounded/sprite.png) -110px -80px no-repeat} +div.dark_rounded .pp_top .pp_left{background:url(../images/prettyPhoto/dark_rounded/sprite.png) -88px -53px no-repeat} +div.dark_rounded .pp_top .pp_right{background:url(../images/prettyPhoto/dark_rounded/sprite.png) -110px -53px no-repeat} +div.dark_rounded .pp_content_container .pp_left{background:url(../images/prettyPhoto/dark_rounded/contentPattern.png) top left repeat-y} +div.dark_rounded .pp_content_container .pp_right{background:url(../images/prettyPhoto/dark_rounded/contentPattern.png) top right repeat-y} +div.dark_rounded .pp_next:hover{background:url(../images/prettyPhoto/dark_rounded/btnNext.png) center right no-repeat;cursor:pointer} +div.dark_rounded .pp_previous:hover{background:url(../images/prettyPhoto/dark_rounded/btnPrevious.png) center left no-repeat;cursor:pointer} +div.dark_rounded .pp_expand{background:url(../images/prettyPhoto/dark_rounded/sprite.png) -31px -26px no-repeat;cursor:pointer} +div.dark_rounded .pp_expand:hover{background:url(../images/prettyPhoto/dark_rounded/sprite.png) -31px -47px no-repeat;cursor:pointer} +div.dark_rounded .pp_contract{background:url(../images/prettyPhoto/dark_rounded/sprite.png) 0 -26px no-repeat;cursor:pointer} +div.dark_rounded .pp_contract:hover{background:url(../images/prettyPhoto/dark_rounded/sprite.png) 0 -47px no-repeat;cursor:pointer} +div.dark_rounded .pp_close{width:75px;height:22px;background:url(../images/prettyPhoto/dark_rounded/sprite.png) -1px -1px no-repeat;cursor:pointer} +div.dark_rounded .pp_description{margin-right:85px;color:#fff} +div.dark_rounded .pp_nav .pp_play{background:url(../images/prettyPhoto/dark_rounded/sprite.png) -1px -100px no-repeat;height:15px;width:14px} +div.dark_rounded .pp_nav .pp_pause{background:url(../images/prettyPhoto/dark_rounded/sprite.png) -24px -100px no-repeat;height:15px;width:14px} +div.dark_rounded .pp_arrow_previous{background:url(../images/prettyPhoto/dark_rounded/sprite.png) 0 -71px no-repeat} +div.dark_rounded .pp_arrow_next{background:url(../images/prettyPhoto/dark_rounded/sprite.png) -22px -71px no-repeat} +div.dark_rounded .pp_bottom .pp_left{background:url(../images/prettyPhoto/dark_rounded/sprite.png) -88px -80px no-repeat} +div.dark_rounded .pp_bottom .pp_right{background:url(../images/prettyPhoto/dark_rounded/sprite.png) -110px -80px no-repeat} +div.dark_rounded .pp_loaderIcon{background:url(../images/prettyPhoto/dark_rounded/loader.gif) center center no-repeat} +div.dark_square .pp_left,div.dark_square .pp_middle,div.dark_square .pp_right,div.dark_square .pp_content{background:#000} +div.dark_square .pp_description{color:#fff;margin:0 85px 0 0} +div.dark_square .pp_loaderIcon{background:url(../images/prettyPhoto/dark_square/loader.gif) center center no-repeat} +div.dark_square .pp_expand{background:url(../images/prettyPhoto/dark_square/sprite.png) -31px -26px no-repeat;cursor:pointer} +div.dark_square .pp_expand:hover{background:url(../images/prettyPhoto/dark_square/sprite.png) -31px -47px no-repeat;cursor:pointer} +div.dark_square .pp_contract{background:url(../images/prettyPhoto/dark_square/sprite.png) 0 -26px no-repeat;cursor:pointer} +div.dark_square .pp_contract:hover{background:url(../images/prettyPhoto/dark_square/sprite.png) 0 -47px no-repeat;cursor:pointer} +div.dark_square .pp_close{width:75px;height:22px;background:url(../images/prettyPhoto/dark_square/sprite.png) -1px -1px no-repeat;cursor:pointer} +div.dark_square .pp_nav{clear:none} +div.dark_square .pp_nav .pp_play{background:url(../images/prettyPhoto/dark_square/sprite.png) -1px -100px no-repeat;height:15px;width:14px} +div.dark_square .pp_nav .pp_pause{background:url(../images/prettyPhoto/dark_square/sprite.png) -24px -100px no-repeat;height:15px;width:14px} +div.dark_square .pp_arrow_previous{background:url(../images/prettyPhoto/dark_square/sprite.png) 0 -71px no-repeat} +div.dark_square .pp_arrow_next{background:url(../images/prettyPhoto/dark_square/sprite.png) -22px -71px no-repeat} +div.dark_square .pp_next:hover{background:url(../images/prettyPhoto/dark_square/btnNext.png) center right no-repeat;cursor:pointer} +div.dark_square .pp_previous:hover{background:url(../images/prettyPhoto/dark_square/btnPrevious.png) center left no-repeat;cursor:pointer} +div.light_square .pp_expand{background:url(../images/prettyPhoto/light_square/sprite.png) -31px -26px no-repeat;cursor:pointer} +div.light_square .pp_expand:hover{background:url(../images/prettyPhoto/light_square/sprite.png) -31px -47px no-repeat;cursor:pointer} +div.light_square .pp_contract{background:url(../images/prettyPhoto/light_square/sprite.png) 0 -26px no-repeat;cursor:pointer} +div.light_square .pp_contract:hover{background:url(../images/prettyPhoto/light_square/sprite.png) 0 -47px no-repeat;cursor:pointer} +div.light_square .pp_close{width:75px;height:22px;background:url(../images/prettyPhoto/light_square/sprite.png) -1px -1px no-repeat;cursor:pointer} +div.light_square .pp_nav .pp_play{background:url(../images/prettyPhoto/light_square/sprite.png) -1px -100px no-repeat;height:15px;width:14px} +div.light_square .pp_nav .pp_pause{background:url(../images/prettyPhoto/light_square/sprite.png) -24px -100px no-repeat;height:15px;width:14px} +div.light_square .pp_arrow_previous{background:url(../images/prettyPhoto/light_square/sprite.png) 0 -71px no-repeat} +div.light_square .pp_arrow_next{background:url(../images/prettyPhoto/light_square/sprite.png) -22px -71px no-repeat} +div.light_square .pp_next:hover{background:url(../images/prettyPhoto/light_square/btnNext.png) center right no-repeat;cursor:pointer} +div.light_square .pp_previous:hover{background:url(../images/prettyPhoto/light_square/btnPrevious.png) center left no-repeat;cursor:pointer} +div.facebook .pp_top .pp_left{background:url(../images/prettyPhoto/facebook/sprite.png) -88px -53px no-repeat} +div.facebook .pp_top .pp_middle{background:url(../images/prettyPhoto/facebook/contentPatternTop.png) top left repeat-x} +div.facebook .pp_top .pp_right{background:url(../images/prettyPhoto/facebook/sprite.png) -110px -53px no-repeat} +div.facebook .pp_content_container .pp_left{background:url(../images/prettyPhoto/facebook/contentPatternLeft.png) top left repeat-y} +div.facebook .pp_content_container .pp_right{background:url(../images/prettyPhoto/facebook/contentPatternRight.png) top right repeat-y} +div.facebook .pp_expand{background:url(../images/prettyPhoto/facebook/sprite.png) -31px -26px no-repeat;cursor:pointer} +div.facebook .pp_expand:hover{background:url(../images/prettyPhoto/facebook/sprite.png) -31px -47px no-repeat;cursor:pointer} +div.facebook .pp_contract{background:url(../images/prettyPhoto/facebook/sprite.png) 0 -26px no-repeat;cursor:pointer} +div.facebook .pp_contract:hover{background:url(../images/prettyPhoto/facebook/sprite.png) 0 -47px no-repeat;cursor:pointer} +div.facebook .pp_close{width:22px;height:22px;background:url(../images/prettyPhoto/facebook/sprite.png) -1px -1px no-repeat;cursor:pointer} +div.facebook .pp_description{margin:0 37px 0 0} +div.facebook .pp_loaderIcon{background:url(../images/prettyPhoto/facebook/loader.gif) center center no-repeat} +div.facebook .pp_arrow_previous{background:url(../images/prettyPhoto/facebook/sprite.png) 0 -71px no-repeat;height:22px;margin-top:0;width:22px} +div.facebook .pp_arrow_previous.disabled{background-position:0 -96px;cursor:default} +div.facebook .pp_arrow_next{background:url(../images/prettyPhoto/facebook/sprite.png) -32px -71px no-repeat;height:22px;margin-top:0;width:22px} +div.facebook .pp_arrow_next.disabled{background-position:-32px -96px;cursor:default} +div.facebook .pp_nav{margin-top:0} +div.facebook .pp_nav p{font-size:15px;padding:0 3px 0 4px} +div.facebook .pp_nav .pp_play{background:url(../images/prettyPhoto/facebook/sprite.png) -1px -123px no-repeat;height:22px;width:22px} +div.facebook .pp_nav .pp_pause{background:url(../images/prettyPhoto/facebook/sprite.png) -32px -123px no-repeat;height:22px;width:22px} +div.facebook .pp_next:hover{background:url(../images/prettyPhoto/facebook/btnNext.png) center right no-repeat;cursor:pointer} +div.facebook .pp_previous:hover{background:url(../images/prettyPhoto/facebook/btnPrevious.png) center left no-repeat;cursor:pointer} +div.facebook .pp_bottom .pp_left{background:url(../images/prettyPhoto/facebook/sprite.png) -88px -80px no-repeat} +div.facebook .pp_bottom .pp_middle{background:url(../images/prettyPhoto/facebook/contentPatternBottom.png) top left repeat-x} +div.facebook .pp_bottom .pp_right{background:url(../images/prettyPhoto/facebook/sprite.png) -110px -80px no-repeat} +div.pp_pic_holder a:focus{outline:none} +div.pp_overlay{background:#000;display:none;left:0;position:absolute;top:0;width:100%;z-index:9500} +div.pp_pic_holder{display:none;position:absolute;width:100px;z-index:10000} +.pp_content{height:40px;min-width:40px} +* html .pp_content{width:40px} +.pp_content_container{position:relative;text-align:left;width:100%} +.pp_content_container .pp_left{padding-left:20px} +.pp_content_container .pp_right{padding-right:20px} +.pp_content_container .pp_details{float:left;margin:10px 0 2px} +.pp_description{display:none;margin:0} +.pp_social{float:left;margin:0} +.pp_social .facebook{float:left;margin-left:5px;width:55px;overflow:hidden} +.pp_social .twitter{float:left} +.pp_nav{clear:right;float:left;margin:3px 10px 0 0} +.pp_nav p{float:left;white-space:nowrap;margin:2px 4px} +.pp_nav .pp_play,.pp_nav .pp_pause{float:left;margin-right:4px;text-indent:-10000px} +a.pp_arrow_previous,a.pp_arrow_next{display:block;float:left;height:15px;margin-top:3px;overflow:hidden;text-indent:-10000px;width:14px} +.pp_hoverContainer{position:absolute;top:0;width:100%;z-index:2000} +.pp_gallery{display:none;left:50%;margin-top:-50px;position:absolute;z-index:10000} +.pp_gallery div{float:left;overflow:hidden;position:relative} +.pp_gallery ul{float:left;height:35px;position:relative;white-space:nowrap;margin:0 0 0 5px;padding:0} +.pp_gallery ul a{border:1px rgba(0,0,0,0.5) solid;display:block;float:left;height:33px;overflow:hidden} +.pp_gallery ul a img{border:0} +.pp_gallery li{display:block;float:left;margin:0 5px 0 0;padding:0} +.pp_gallery li.default a{background:url(../images/prettyPhoto/facebook/default_thumbnail.gif) 0 0 no-repeat;display:block;height:33px;width:50px} +.pp_gallery .pp_arrow_previous,.pp_gallery .pp_arrow_next{margin-top:7px!important} +a.pp_next{background:url(../images/prettyPhoto/light_rounded/btnNext.png) 10000px 10000px no-repeat;display:block;float:right;height:100%;text-indent:-10000px;width:49%} +a.pp_previous{background:url(../images/prettyPhoto/light_rounded/btnNext.png) 10000px 10000px no-repeat;display:block;float:left;height:100%;text-indent:-10000px;width:49%} +a.pp_expand,a.pp_contract{cursor:pointer;display:none;height:20px;position:absolute;right:30px;text-indent:-10000px;top:10px;width:20px;z-index:20000} +a.pp_close{position:absolute;right:0;top:0;display:block;line-height:22px;text-indent:-10000px} +.pp_loaderIcon{display:block;height:24px;left:50%;position:absolute;top:50%;width:24px;margin:-12px 0 0 -12px} +#pp_full_res{line-height:1!important} +#pp_full_res .pp_inline{text-align:left} +#pp_full_res .pp_inline p{margin:0 0 15px} +div.ppt{color:#fff;display:none;font-size:17px;z-index:9999;margin:0 0 5px 15px} +div.pp_default .pp_content,div.light_rounded .pp_content{background-color:#fff} +div.pp_default #pp_full_res .pp_inline,div.light_rounded .pp_content .ppt,div.light_rounded #pp_full_res .pp_inline,div.light_square .pp_content .ppt,div.light_square #pp_full_res .pp_inline,div.facebook .pp_content .ppt,div.facebook #pp_full_res .pp_inline{color:#000} +div.pp_default .pp_gallery ul li a:hover,div.pp_default .pp_gallery ul li.selected a,.pp_gallery ul a:hover,.pp_gallery li.selected a{border-color:#fff} +div.pp_default .pp_details,div.light_rounded .pp_details,div.dark_rounded .pp_details,div.dark_square .pp_details,div.light_square .pp_details,div.facebook .pp_details{position:relative} +div.light_rounded .pp_top .pp_middle,div.light_rounded .pp_content_container .pp_left,div.light_rounded .pp_content_container .pp_right,div.light_rounded .pp_bottom .pp_middle,div.light_square .pp_left,div.light_square .pp_middle,div.light_square .pp_right,div.light_square .pp_content,div.facebook .pp_content{background:#fff} +div.light_rounded .pp_description,div.light_square .pp_description{margin-right:85px} +div.light_rounded .pp_gallery a.pp_arrow_previous,div.light_rounded .pp_gallery a.pp_arrow_next,div.dark_rounded .pp_gallery a.pp_arrow_previous,div.dark_rounded .pp_gallery a.pp_arrow_next,div.dark_square .pp_gallery a.pp_arrow_previous,div.dark_square .pp_gallery a.pp_arrow_next,div.light_square .pp_gallery a.pp_arrow_previous,div.light_square .pp_gallery a.pp_arrow_next{margin-top:12px!important} +div.light_rounded .pp_arrow_previous.disabled,div.dark_rounded .pp_arrow_previous.disabled,div.dark_square .pp_arrow_previous.disabled,div.light_square .pp_arrow_previous.disabled{background-position:0 -87px;cursor:default} +div.light_rounded .pp_arrow_next.disabled,div.dark_rounded .pp_arrow_next.disabled,div.dark_square .pp_arrow_next.disabled,div.light_square .pp_arrow_next.disabled{background-position:-22px -87px;cursor:default} +div.light_rounded .pp_loaderIcon,div.light_square .pp_loaderIcon{background:url(../images/prettyPhoto/light_rounded/loader.gif) center center no-repeat} +div.dark_rounded .pp_top .pp_middle,div.dark_rounded .pp_content,div.dark_rounded .pp_bottom .pp_middle{background:url(../images/prettyPhoto/dark_rounded/contentPattern.png) top left repeat} +div.dark_rounded .currentTextHolder,div.dark_square .currentTextHolder{color:#c4c4c4} +div.dark_rounded #pp_full_res .pp_inline,div.dark_square #pp_full_res .pp_inline{color:#fff} +.pp_top,.pp_bottom{height:20px;position:relative} +* html .pp_top,* html .pp_bottom{padding:0 20px} +.pp_top .pp_left,.pp_bottom .pp_left{height:20px;left:0;position:absolute;width:20px} +.pp_top .pp_middle,.pp_bottom .pp_middle{height:20px;left:20px;position:absolute;right:20px} +* html .pp_top .pp_middle,* html .pp_bottom .pp_middle{left:0;position:static} +.pp_top .pp_right,.pp_bottom .pp_right{height:20px;left:auto;position:absolute;right:0;top:0;width:20px} +.pp_fade,.pp_gallery li.default a img{display:none} \ No newline at end of file diff --git a/imagestore/static/prettyphoto/images/.DS_Store b/imagestore/static/prettyphoto/images/.DS_Store new file mode 100644 index 0000000..83aa22a Binary files /dev/null and b/imagestore/static/prettyphoto/images/.DS_Store differ diff --git a/imagestore/static/prettyphoto/images/fullscreen/1.jpg b/imagestore/static/prettyphoto/images/fullscreen/1.jpg new file mode 100755 index 0000000..ffb4763 Binary files /dev/null and b/imagestore/static/prettyphoto/images/fullscreen/1.jpg differ diff --git a/imagestore/static/prettyphoto/images/fullscreen/2.jpg b/imagestore/static/prettyphoto/images/fullscreen/2.jpg new file mode 100755 index 0000000..b8759b4 Binary files /dev/null and b/imagestore/static/prettyphoto/images/fullscreen/2.jpg differ diff --git a/imagestore/static/prettyphoto/images/fullscreen/3.jpg b/imagestore/static/prettyphoto/images/fullscreen/3.jpg new file mode 100755 index 0000000..145c696 Binary files /dev/null and b/imagestore/static/prettyphoto/images/fullscreen/3.jpg differ diff --git a/imagestore/static/prettyphoto/images/fullscreen/4.jpg b/imagestore/static/prettyphoto/images/fullscreen/4.jpg new file mode 100755 index 0000000..33f221c Binary files /dev/null and b/imagestore/static/prettyphoto/images/fullscreen/4.jpg differ diff --git a/imagestore/static/prettyphoto/images/fullscreen/5.jpg b/imagestore/static/prettyphoto/images/fullscreen/5.jpg new file mode 100755 index 0000000..47d0b90 Binary files /dev/null and b/imagestore/static/prettyphoto/images/fullscreen/5.jpg differ diff --git a/imagestore/static/prettyphoto/images/fullscreen/6.jpg b/imagestore/static/prettyphoto/images/fullscreen/6.jpg new file mode 100755 index 0000000..31524dc Binary files /dev/null and b/imagestore/static/prettyphoto/images/fullscreen/6.jpg differ diff --git a/imagestore/static/prettyphoto/images/fullscreen/high.gif b/imagestore/static/prettyphoto/images/fullscreen/high.gif new file mode 100755 index 0000000..ccf5d16 Binary files /dev/null and b/imagestore/static/prettyphoto/images/fullscreen/high.gif differ diff --git a/imagestore/static/prettyphoto/images/fullscreen/huge.gif b/imagestore/static/prettyphoto/images/fullscreen/huge.gif new file mode 100755 index 0000000..5b3102e Binary files /dev/null and b/imagestore/static/prettyphoto/images/fullscreen/huge.gif differ diff --git a/imagestore/static/prettyphoto/images/fullscreen/wide.gif b/imagestore/static/prettyphoto/images/fullscreen/wide.gif new file mode 100755 index 0000000..f17c5b8 Binary files /dev/null and b/imagestore/static/prettyphoto/images/fullscreen/wide.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/btnNext.png b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/btnNext.png new file mode 100755 index 0000000..b28c1ef Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/btnNext.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/btnPrevious.png b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/btnPrevious.png new file mode 100755 index 0000000..e0cd9c4 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/btnPrevious.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/contentPattern.png b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/contentPattern.png new file mode 100755 index 0000000..e5a047c Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/contentPattern.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/default_thumbnail.gif b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/default_thumbnail.gif new file mode 100755 index 0000000..2b1280f Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/default_thumbnail.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/loader.gif b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/loader.gif new file mode 100755 index 0000000..50820ee Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/loader.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/sprite.png b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/sprite.png new file mode 100755 index 0000000..fb8c0f8 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_rounded/sprite.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/btnNext.png b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/btnNext.png new file mode 100755 index 0000000..b28c1ef Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/btnNext.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/btnPrevious.png b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/btnPrevious.png new file mode 100755 index 0000000..e0cd9c4 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/btnPrevious.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/contentPattern.png b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/contentPattern.png new file mode 100755 index 0000000..7b50aff Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/contentPattern.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/default_thumbnail.gif b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/default_thumbnail.gif new file mode 100755 index 0000000..2b1280f Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/default_thumbnail.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/loader.gif b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/loader.gif new file mode 100755 index 0000000..50820ee Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/loader.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/sprite.png b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/sprite.png new file mode 100755 index 0000000..4fe3547 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/dark_square/sprite.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/default/default_thumb.png b/imagestore/static/prettyphoto/images/prettyPhoto/default/default_thumb.png new file mode 100644 index 0000000..1a26e4b Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/default/default_thumb.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/default/loader.gif b/imagestore/static/prettyphoto/images/prettyPhoto/default/loader.gif new file mode 100644 index 0000000..35d397c Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/default/loader.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite.png b/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite.png new file mode 100644 index 0000000..5f07ddc Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_next.png b/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_next.png new file mode 100644 index 0000000..379dc0d Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_next.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_prev.png b/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_prev.png new file mode 100644 index 0000000..1ee4865 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_prev.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_x.png b/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_x.png new file mode 100644 index 0000000..d4433ab Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_x.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_y.png b/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_y.png new file mode 100644 index 0000000..7786ab5 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/default/sprite_y.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/facebook/btnNext.png b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/btnNext.png new file mode 100755 index 0000000..e809c3b Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/btnNext.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/facebook/btnPrevious.png b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/btnPrevious.png new file mode 100755 index 0000000..0812542 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/btnPrevious.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternBottom.png b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternBottom.png new file mode 100755 index 0000000..a9be3b2 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternBottom.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternLeft.png b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternLeft.png new file mode 100755 index 0000000..277c87a Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternLeft.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternRight.png b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternRight.png new file mode 100755 index 0000000..76e50d0 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternRight.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternTop.png b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternTop.png new file mode 100755 index 0000000..8b110ba Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/contentPatternTop.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/facebook/default_thumbnail.gif b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/default_thumbnail.gif new file mode 100755 index 0000000..2b1280f Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/default_thumbnail.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/facebook/loader.gif b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/loader.gif new file mode 100755 index 0000000..7ac990c Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/loader.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/facebook/sprite.png b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/sprite.png new file mode 100755 index 0000000..660a254 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/facebook/sprite.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/btnNext.png b/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/btnNext.png new file mode 100755 index 0000000..b28c1ef Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/btnNext.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/btnPrevious.png b/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/btnPrevious.png new file mode 100755 index 0000000..e0cd9c4 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/btnPrevious.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/default_thumbnail.gif b/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/default_thumbnail.gif new file mode 100755 index 0000000..2b1280f Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/default_thumbnail.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/loader.gif b/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/loader.gif new file mode 100755 index 0000000..7ac990c Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/loader.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/sprite.png b/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/sprite.png new file mode 100755 index 0000000..7f28379 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/light_rounded/sprite.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/light_square/btnNext.png b/imagestore/static/prettyphoto/images/prettyPhoto/light_square/btnNext.png new file mode 100755 index 0000000..b28c1ef Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/light_square/btnNext.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/light_square/btnPrevious.png b/imagestore/static/prettyphoto/images/prettyPhoto/light_square/btnPrevious.png new file mode 100755 index 0000000..e0cd9c4 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/light_square/btnPrevious.png differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/light_square/default_thumbnail.gif b/imagestore/static/prettyphoto/images/prettyPhoto/light_square/default_thumbnail.gif new file mode 100755 index 0000000..2b1280f Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/light_square/default_thumbnail.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/light_square/loader.gif b/imagestore/static/prettyphoto/images/prettyPhoto/light_square/loader.gif new file mode 100755 index 0000000..7ac990c Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/light_square/loader.gif differ diff --git a/imagestore/static/prettyphoto/images/prettyPhoto/light_square/sprite.png b/imagestore/static/prettyphoto/images/prettyPhoto/light_square/sprite.png new file mode 100755 index 0000000..4fe3547 Binary files /dev/null and b/imagestore/static/prettyphoto/images/prettyPhoto/light_square/sprite.png differ diff --git a/imagestore/static/prettyphoto/images/thumbnails/flash-logo.png b/imagestore/static/prettyphoto/images/thumbnails/flash-logo.png new file mode 100755 index 0000000..4b81e00 Binary files /dev/null and b/imagestore/static/prettyphoto/images/thumbnails/flash-logo.png differ diff --git a/imagestore/static/prettyphoto/images/thumbnails/quicktime-logo.gif b/imagestore/static/prettyphoto/images/thumbnails/quicktime-logo.gif new file mode 100755 index 0000000..b6a20ef Binary files /dev/null and b/imagestore/static/prettyphoto/images/thumbnails/quicktime-logo.gif differ diff --git a/imagestore/static/prettyphoto/images/thumbnails/t_1.jpg b/imagestore/static/prettyphoto/images/thumbnails/t_1.jpg new file mode 100755 index 0000000..8c4e865 Binary files /dev/null and b/imagestore/static/prettyphoto/images/thumbnails/t_1.jpg differ diff --git a/imagestore/static/prettyphoto/images/thumbnails/t_2.jpg b/imagestore/static/prettyphoto/images/thumbnails/t_2.jpg new file mode 100755 index 0000000..7f427c6 Binary files /dev/null and b/imagestore/static/prettyphoto/images/thumbnails/t_2.jpg differ diff --git a/imagestore/static/prettyphoto/images/thumbnails/t_3.jpg b/imagestore/static/prettyphoto/images/thumbnails/t_3.jpg new file mode 100755 index 0000000..91b774a Binary files /dev/null and b/imagestore/static/prettyphoto/images/thumbnails/t_3.jpg differ diff --git a/imagestore/static/prettyphoto/images/thumbnails/t_4.jpg b/imagestore/static/prettyphoto/images/thumbnails/t_4.jpg new file mode 100755 index 0000000..9781430 Binary files /dev/null and b/imagestore/static/prettyphoto/images/thumbnails/t_4.jpg differ diff --git a/imagestore/static/prettyphoto/images/thumbnails/t_5.jpg b/imagestore/static/prettyphoto/images/thumbnails/t_5.jpg new file mode 100755 index 0000000..7c16952 Binary files /dev/null and b/imagestore/static/prettyphoto/images/thumbnails/t_5.jpg differ diff --git a/imagestore/static/prettyphoto/index.html b/imagestore/static/prettyphoto/index.html new file mode 100755 index 0000000..de35293 --- /dev/null +++ b/imagestore/static/prettyphoto/index.html @@ -0,0 +1,236 @@ + + + + jQuery lightbox clone - prettyPhoto - by Stephane Caron + + + + + + + + + +
    +

    prettyPhoto

    + +

    This page has been made for testing purpose only. It covers all the basic things you can handle in prettyPhoto.

    + +

    For complete documentation, please refer to the official website: http://www.no-margin-for-errors.com/projects/prettyphoto-jquery-lightbox-clone/

    + +

    Gallery

    + + +

    Gallery 2

    + + +

    API Call

    + +

    API call

    + +

    Picture alone

    + +
    +

    Flash

    + +
    +
    +

    YouTube

    + +
    +
    +

    Vimeo

    + +
    + +
    + +

    Movies (.mov)

    + + +

    Movies (.mov) alone

    + + +

    Unusual sizes

    + + +

    Iframe

    + + +

    AJAX

    + + +

    Mixed gallery

    + + +

    Inline content

    + + + + + +

    Custom content

    + + +

    + + + + + + + + + + + + + + + +
    + + \ No newline at end of file diff --git a/imagestore/static/prettyphoto/js/jquery-1.3.2.min.js b/imagestore/static/prettyphoto/js/jquery-1.3.2.min.js new file mode 100755 index 0000000..b1ae21d --- /dev/null +++ b/imagestore/static/prettyphoto/js/jquery-1.3.2.min.js @@ -0,0 +1,19 @@ +/* + * jQuery JavaScript Library v1.3.2 + * http://jquery.com/ + * + * Copyright (c) 2009 John Resig + * Dual licensed under the MIT and GPL licenses. + * http://docs.jquery.com/License + * + * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) + * Revision: 6246 + */ +(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
    "]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
    ","
    "]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); +/* + * Sizzle CSS Selector Engine - v0.9.3 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

    ";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
    ";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
    ").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
    ';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); \ No newline at end of file diff --git a/imagestore/static/prettyphoto/js/jquery-1.4.4.min.js b/imagestore/static/prettyphoto/js/jquery-1.4.4.min.js new file mode 100644 index 0000000..2bd4cbb --- /dev/null +++ b/imagestore/static/prettyphoto/js/jquery-1.4.4.min.js @@ -0,0 +1,167 @@ +/*! + * jQuery JavaScript Library v1.4.4 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu Nov 11 19:04:53 2010 -0500 + */ +(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h= +h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;kd)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La, +"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this, +e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a, +"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+ +a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/, +C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j, +s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this, +j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length}, +toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j=== +-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false; +if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload", +b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&& +!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&& +l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H
    a";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"), +k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false, +scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent= +false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom= +1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="
    ";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="
    t
    ";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display= +"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h= +c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando); +else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one"; +if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true}, +attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&& +b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0}; +c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem, +arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid= +d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+ +c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType=== +8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k=== +"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+ +d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired= +B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type=== +"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]=== +0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}}); +(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3]; +break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr, +q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h= +l;g.sort(w);if(h)for(var i=1;i0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n, +m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled=== +true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"=== +g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return in[3]-0},nth:function(g,i,n){return n[3]- +0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()=== +i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]]; +if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m, +g);else if(typeof g.length==="number")for(var p=g.length;n";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g); +n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&& +function(){var g=k,i=t.createElement("div");i.innerHTML="

    ";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F|| +p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g= +t.createElement("div");g.innerHTML="
    ";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition? +function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n0)for(var h=d;h0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h= +h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context): +c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a, +2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a, +b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&& +e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/\s]+\/)>/g,P={option:[1, +""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div
    ","
    "];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null; +else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1>");try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append", +prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument|| +b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]===""&&!x?r.childNodes:[];for(o=k.length- +1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script")))); +d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i, +jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true, +zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b), +h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b); +if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f= +d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left; +e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/)<[^<]*)*<\/script>/gi, +ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b=== +"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("
    ").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&& +!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})}, +getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html", +script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data|| +!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache= +false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset; +A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type", +b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&& +c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d|| +c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]= +encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess", +[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"), +e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}}); +if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show", +3),a,b,d);else{d=0;for(var e=this.length;d=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b, +d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a* +Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)} +var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true; +this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide|| +this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a= +c.timers,b=0;b-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a, +e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&& +c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase(); +c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+ +b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window); \ No newline at end of file diff --git a/imagestore/static/prettyphoto/js/jquery-1.6.1.min.js b/imagestore/static/prettyphoto/js/jquery-1.6.1.min.js new file mode 100644 index 0000000..eb6a596 --- /dev/null +++ b/imagestore/static/prettyphoto/js/jquery-1.6.1.min.js @@ -0,0 +1,18 @@ +/*! + * jQuery JavaScript Library v1.6.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu May 12 15:04:36 2011 -0400 + */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!cj[a]){var b=f("<"+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),c.body.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write("");b=cl.createElement(a),cl.body.appendChild(b),d=f.css(b,"display"),c.body.removeChild(ck)}cj[a]=d}return cj[a]}function cu(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function ct(){cq=b}function cs(){setTimeout(ct,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g=0===c})}function W(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function O(a,b){return(a&&a!=="*"?a+".":"")+b.replace(A,"`").replace(B,"&")}function N(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function L(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function F(){return!0}function E(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function H(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(H,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=d.userAgent,x,y,z,A=Object.prototype.toString,B=Object.prototype.hasOwnProperty,C=Array.prototype.push,D=Array.prototype.slice,E=String.prototype.trim,F=Array.prototype.indexOf,G={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.1",length:0,size:function(){return this.length},toArray:function(){return D.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?C.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(D.apply(this,arguments),"slice",D.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:C,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!y){y=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",z,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",z),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&H()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):G[A.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!B.call(a,"constructor")&&!B.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||B.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
    a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};f=c.createElement("select"),g=f.appendChild(c.createElement("option")),h=a.getElementsByTagName("input")[0],j={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},h.checked=!0,j.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,j.optDisabled=!g.disabled;try{delete a.test}catch(s){j.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function b(){j.noCloneEvent=!1,a.detachEvent("onclick",b)}),a.cloneNode(!0).fireEvent("onclick")),h=c.createElement("input"),h.value="t",h.setAttribute("type","radio"),j.radioValue=h.value==="t",h.setAttribute("checked","checked"),a.appendChild(h),k=c.createDocumentFragment(),k.appendChild(a.firstChild),j.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",l=c.createElement("body"),m={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"};for(q in m)l.style[q]=m[q];l.appendChild(a),b.insertBefore(l,b.firstChild),j.appendChecked=h.checked,j.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,j.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
    ",j.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
    t
    ",n=a.getElementsByTagName("td"),r=n[0].offsetHeight===0,n[0].style.display="",n[1].style.display="none",j.reliableHiddenOffsets=r&&n[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(i=c.createElement("div"),i.style.width="0",i.style.marginRight="0",a.appendChild(i),j.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(i,null)||{marginRight:0}).marginRight,10)||0)===0),l.innerHTML="",b.removeChild(l);if(a.attachEvent)for(q in{submit:1,change:1,focusin:1})p="on"+q,r=p in a,r||(a.setAttribute(p,"return;"),r=typeof a[p]=="function"),j[q+"Bubbles"]=r;return j}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;return(e.value||"").replace(p,"")}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);c=j&&f.attrFix[c]||c,i=f.attrHooks[c],i||(!t.test(c)||typeof d!="boolean"&&d!==b&&d.toLowerCase()!==c.toLowerCase()?v&&(f.nodeName(a,"form")||u.test(c))&&(i=v):i=w);if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j)return i.get(a,c);h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);c=i&&f.propFix[c]||c,h=f.propHooks[c];return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return a[f.propFix[c]||c]?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=b),a.setAttribute(c,c.toLowerCase()));return c}},f.attrHooks.value={get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return a.value},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=Object.prototype.hasOwnProperty,y=/\.(.*)$/,z=/^(?:textarea|input|select)$/i,A=/\./g,B=/ /g,C=/[^\w\s.|`]/g,D=function(a){return a.replace(C,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=E;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=E);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),D).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem +)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},K=function(c){var d=c.target,e,g;if(!!z.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=J(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:K,beforedeactivate:K,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&K.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&K.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",J(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in I)f.event.add(this,c+".specialChange",I[c]);return z.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return z.test(this.nodeName)}},I=f.event.special.change.filters,I.focus=I.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=U.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(W(c[0])||W(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=T.call(arguments);P.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!V[a]?f.unique(e):e,(this.length>1||R.test(d))&&Q.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var Y=/ jQuery\d+="(?:\d+|null)"/g,Z=/^\s+/,$=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,_=/<([\w:]+)/,ba=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Y,""):null;if(typeof a=="string"&&!bc.test(a)&&(f.support.leadingWhitespace||!Z.test(a))&&!bg[(_.exec(a)||["",""])[1].toLowerCase()]){a=a.replace($,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bj(a,d),e=bk(a),g=bk(d);for(h=0;e[h];++h)bj(e[h],g[h])}if(b){bi(a,d);if(c){e=bk(a),g=bk(d);for(h=0;e[h];++h)bi(e[h],g[h])}}return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument|| +b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!bb.test(k))k=b.createTextNode(k);else{k=k.replace($,"<$1>");var l=(_.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=ba.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Z.test(k)&&o.insertBefore(b.createTextNode(Z.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bp.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bo.test(g)?g.replace(bo,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,c){var d,e,g;c=c.replace(br,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bs.test(d)&&bt.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bE=/%20/g,bF=/\[\]$/,bG=/\r?\n/g,bH=/#.*$/,bI=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bJ=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bK=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bL=/^(?:GET|HEAD)$/,bM=/^\/\//,bN=/\?/,bO=/)<[^<]*)*<\/script>/gi,bP=/^(?:select|textarea)/i,bQ=/\s+/,bR=/([?&])_=[^&]*/,bS=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bT=f.fn.load,bU={},bV={},bW,bX;try{bW=e.href}catch(bY){bW=c.createElement("a"),bW.href="",bW=bW.href}bX=bS.exec(bW.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bT)return bT.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bO,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bP.test(this.nodeName)||bJ.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bG,"\r\n")}}):{name:b.name,value:c.replace(bG,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bW,isLocal:bK.test(bX[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bZ(bU),ajaxTransport:bZ(bV),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?ca(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=cb(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bI.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bH,"").replace(bM,bX[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bQ),d.crossDomain==null&&(r=bS.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bX[1]&&r[2]==bX[2]&&(r[3]||(r[1]==="http:"?80:443))==(bX[3]||(bX[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bU,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bL.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bN.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bR,"$1_="+x);d.url=y+(y===d.url?(bN.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bV,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bE,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq,cr=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
    ";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){return this[0]?parseFloat(f.css(this[0],d,"padding")):null},f.fn["outer"+c]=function(a){return this[0]?parseFloat(f.css(this[0],d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/imagestore/static/prettyphoto/js/jquery.prettyPhoto.js b/imagestore/static/prettyphoto/js/jquery.prettyPhoto.js new file mode 100644 index 0000000..d958202 --- /dev/null +++ b/imagestore/static/prettyphoto/js/jquery.prettyPhoto.js @@ -0,0 +1,7 @@ +/* ------------------------------------------------------------------------ + Class: prettyPhoto + Use: Lightbox clone for jQuery + Author: Stephane Caron (http://www.no-margin-for-errors.com) + Version: 3.1.5 +------------------------------------------------------------------------- */ +(function(e){function t(){var e=location.href;hashtag=e.indexOf("#prettyPhoto")!==-1?decodeURI(e.substring(e.indexOf("#prettyPhoto")+1,e.length)):false;return hashtag}function n(){if(typeof theRel=="undefined")return;location.hash=theRel+"/"+rel_index+"/"}function r(){if(location.href.indexOf("#prettyPhoto")!==-1)location.hash="prettyPhoto"}function i(e,t){e=e.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");var n="[\\?&]"+e+"=([^&#]*)";var r=new RegExp(n);var i=r.exec(t);return i==null?"":i[1]}e.prettyPhoto={version:"3.1.5"};e.fn.prettyPhoto=function(s){function g(){e(".pp_loaderIcon").hide();projectedTop=scroll_pos["scrollTop"]+(d/2-a["containerHeight"]/2);if(projectedTop<0)projectedTop=0;$ppt.fadeTo(settings.animation_speed,1);$pp_pic_holder.find(".pp_content").animate({height:a["contentHeight"],width:a["contentWidth"]},settings.animation_speed);$pp_pic_holder.animate({top:projectedTop,left:v/2-a["containerWidth"]/2<0?0:v/2-a["containerWidth"]/2,width:a["containerWidth"]},settings.animation_speed,function(){$pp_pic_holder.find(".pp_hoverContainer,#fullResImage").height(a["height"]).width(a["width"]);$pp_pic_holder.find(".pp_fade").fadeIn(settings.animation_speed);if(isSet&&S(pp_images[set_position])=="image"){$pp_pic_holder.find(".pp_hoverContainer").show()}else{$pp_pic_holder.find(".pp_hoverContainer").hide()}if(settings.allow_expand){if(a["resized"]){e("a.pp_expand,a.pp_contract").show()}else{e("a.pp_expand").hide()}}if(settings.autoplay_slideshow&&!m&&!f)e.prettyPhoto.startSlideshow();settings.changepicturecallback();f=true});C();s.ajaxcallback()}function y(t){$pp_pic_holder.find("#pp_full_res object,#pp_full_res embed").css("visibility","hidden");$pp_pic_holder.find(".pp_fade").fadeOut(settings.animation_speed,function(){e(".pp_loaderIcon").show();t()})}function b(t){t>1?e(".pp_nav").show():e(".pp_nav").hide()}function w(e,t){resized=false;E(e,t);imageWidth=e,imageHeight=t;if((p>v||h>d)&&doresize&&settings.allow_resize&&!u){resized=true,fitting=false;while(!fitting){if(p>v){imageWidth=v-200;imageHeight=t/e*imageWidth}else if(h>d){imageHeight=d-200;imageWidth=e/t*imageHeight}else{fitting=true}h=imageHeight,p=imageWidth}if(p>v||h>d){w(p,h)}E(imageWidth,imageHeight)}return{width:Math.floor(imageWidth),height:Math.floor(imageHeight),containerHeight:Math.floor(h),containerWidth:Math.floor(p)+settings.horizontal_padding*2,contentHeight:Math.floor(l),contentWidth:Math.floor(c),resized:resized}}function E(t,n){t=parseFloat(t);n=parseFloat(n);$pp_details=$pp_pic_holder.find(".pp_details");$pp_details.width(t);detailsHeight=parseFloat($pp_details.css("marginTop"))+parseFloat($pp_details.css("marginBottom"));$pp_details=$pp_details.clone().addClass(settings.theme).width(t).appendTo(e("body")).css({position:"absolute",top:-1e4});detailsHeight+=$pp_details.height();detailsHeight=detailsHeight<=34?36:detailsHeight;$pp_details.remove();$pp_title=$pp_pic_holder.find(".ppt");$pp_title.width(t);titleHeight=parseFloat($pp_title.css("marginTop"))+parseFloat($pp_title.css("marginBottom"));$pp_title=$pp_title.clone().appendTo(e("body")).css({position:"absolute",top:-1e4});titleHeight+=$pp_title.height();$pp_title.remove();l=n+detailsHeight;c=t;h=l+titleHeight+$pp_pic_holder.find(".pp_top").height()+$pp_pic_holder.find(".pp_bottom").height();p=t}function S(e){if(e.match(/youtube\.com\/watch/i)||e.match(/youtu\.be/i)){return"youtube"}else if(e.match(/vimeo\.com/i)){return"vimeo"}else if(e.match(/\b.mov\b/i)){return"quicktime"}else if(e.match(/\b.swf\b/i)){return"flash"}else if(e.match(/\biframe=true\b/i)){return"iframe"}else if(e.match(/\bajax=true\b/i)){return"ajax"}else if(e.match(/\bcustom=true\b/i)){return"custom"}else if(e.substr(0,1)=="#"){return"inline"}else{return"image"}}function x(){if(doresize&&typeof $pp_pic_holder!="undefined"){scroll_pos=T();contentHeight=$pp_pic_holder.height(),contentwidth=$pp_pic_holder.width();projectedTop=d/2+scroll_pos["scrollTop"]-contentHeight/2;if(projectedTop<0)projectedTop=0;if(contentHeight>d)return;$pp_pic_holder.css({top:projectedTop,left:v/2+scroll_pos["scrollLeft"]-contentwidth/2})}}function T(){if(self.pageYOffset){return{scrollTop:self.pageYOffset,scrollLeft:self.pageXOffset}}else if(document.documentElement&&document.documentElement.scrollTop){return{scrollTop:document.documentElement.scrollTop,scrollLeft:document.documentElement.scrollLeft}}else if(document.body){return{scrollTop:document.body.scrollTop,scrollLeft:document.body.scrollLeft}}}function N(){d=e(window).height(),v=e(window).width();if(typeof $pp_overlay!="undefined")$pp_overlay.height(e(document).height()).width(v)}function C(){if(isSet&&settings.overlay_gallery&&S(pp_images[set_position])=="image"){itemWidth=52+5;navWidth=settings.theme=="facebook"||settings.theme=="pp_default"?50:30;itemsPerPage=Math.floor((a["containerWidth"]-100-navWidth)/itemWidth);itemsPerPage=itemsPerPage"}toInject=settings.gallery_markup.replace(/{gallery}/g,toInject);$pp_pic_holder.find("#pp_full_res").after(toInject);$pp_gallery=e(".pp_pic_holder .pp_gallery"),$pp_gallery_li=$pp_gallery.find("li");$pp_gallery.find(".pp_arrow_next").click(function(){e.prettyPhoto.changeGalleryPage("next");e.prettyPhoto.stopSlideshow();return false});$pp_gallery.find(".pp_arrow_previous").click(function(){e.prettyPhoto.changeGalleryPage("previous");e.prettyPhoto.stopSlideshow();return false});$pp_pic_holder.find(".pp_content").hover(function(){$pp_pic_holder.find(".pp_gallery:not(.disabled)").fadeIn()},function(){$pp_pic_holder.find(".pp_gallery:not(.disabled)").fadeOut()});itemWidth=52+5;$pp_gallery_li.each(function(t){e(this).find("a").click(function(){e.prettyPhoto.changePage(t);e.prettyPhoto.stopSlideshow();return false})})}if(settings.slideshow){$pp_pic_holder.find(".pp_nav").prepend('Play');$pp_pic_holder.find(".pp_nav .pp_play").click(function(){e.prettyPhoto.startSlideshow();return false})}$pp_pic_holder.attr("class","pp_pic_holder "+settings.theme);$pp_overlay.css({opacity:0,height:e(document).height(),width:e(window).width()}).bind("click",function(){if(!settings.modal)e.prettyPhoto.close()});e("a.pp_close").bind("click",function(){e.prettyPhoto.close();return false});if(settings.allow_expand){e("a.pp_expand").bind("click",function(t){if(e(this).hasClass("pp_expand")){e(this).removeClass("pp_expand").addClass("pp_contract");doresize=false}else{e(this).removeClass("pp_contract").addClass("pp_expand");doresize=true}y(function(){e.prettyPhoto.open()});return false})}$pp_pic_holder.find(".pp_previous, .pp_nav .pp_arrow_previous").bind("click",function(){e.prettyPhoto.changePage("previous");e.prettyPhoto.stopSlideshow();return false});$pp_pic_holder.find(".pp_next, .pp_nav .pp_arrow_next").bind("click",function(){e.prettyPhoto.changePage("next");e.prettyPhoto.stopSlideshow();return false});x()}s=jQuery.extend({hook:"rel",animation_speed:"fast",ajaxcallback:function(){},slideshow:5e3,autoplay_slideshow:false,opacity:.8,show_title:true,allow_resize:true,allow_expand:true,default_width:500,default_height:344,counter_separator_label:"/",theme:"pp_default",horizontal_padding:20,hideflash:false,wmode:"opaque",autoplay:true,modal:false,deeplinking:true,overlay_gallery:true,overlay_gallery_max:30,keyboard_shortcuts:true,changepicturecallback:function(){},callback:function(){},ie6_fallback:true,markup:'
     
    ',gallery_markup:'',image_markup:'',flash_markup:'',quicktime_markup:'',iframe_markup:'',inline_markup:'
    {content}
    ',custom_markup:"",social_tools:''},s);var o=this,u=false,a,f,l,c,h,p,d=e(window).height(),v=e(window).width(),m;doresize=true,scroll_pos=T();e(window).unbind("resize.prettyphoto").bind("resize.prettyphoto",function(){x();N()});if(s.keyboard_shortcuts){e(document).unbind("keydown.prettyphoto").bind("keydown.prettyphoto",function(t){if(typeof $pp_pic_holder!="undefined"){if($pp_pic_holder.is(":visible")){switch(t.keyCode){case 37:e.prettyPhoto.changePage("previous");t.preventDefault();break;case 39:e.prettyPhoto.changePage("next");t.preventDefault();break;case 27:if(!settings.modal)e.prettyPhoto.close();t.preventDefault();break}}}})}e.prettyPhoto.initialize=function(){settings=s;if(settings.theme=="pp_default")settings.horizontal_padding=16;theRel=e(this).attr(settings.hook);galleryRegExp=/\[(?:.*)\]/;isSet=galleryRegExp.exec(theRel)?true:false;pp_images=isSet?jQuery.map(o,function(t,n){if(e(t).attr(settings.hook).indexOf(theRel)!=-1)return e(t).attr("href")}):e.makeArray(e(this).attr("href"));pp_titles=isSet?jQuery.map(o,function(t,n){if(e(t).attr(settings.hook).indexOf(theRel)!=-1)return e(t).find("img").attr("alt")?e(t).find("img").attr("alt"):""}):e.makeArray(e(this).find("img").attr("alt"));pp_descriptions=isSet?jQuery.map(o,function(t,n){if(e(t).attr(settings.hook).indexOf(theRel)!=-1)return e(t).attr("title")?e(t).attr("title"):""}):e.makeArray(e(this).attr("title"));if(pp_images.length>settings.overlay_gallery_max)settings.overlay_gallery=false;set_position=jQuery.inArray(e(this).attr("href"),pp_images);rel_index=isSet?set_position:e("a["+settings.hook+"^='"+theRel+"']").index(e(this));k(this);if(settings.allow_resize)e(window).bind("scroll.prettyphoto",function(){x()});e.prettyPhoto.open();return false};e.prettyPhoto.open=function(t){if(typeof settings=="undefined"){settings=s;pp_images=e.makeArray(arguments[0]);pp_titles=arguments[1]?e.makeArray(arguments[1]):e.makeArray("");pp_descriptions=arguments[2]?e.makeArray(arguments[2]):e.makeArray("");isSet=pp_images.length>1?true:false;set_position=arguments[3]?arguments[3]:0;k(t.target)}if(settings.hideflash)e("object,embed,iframe[src*=youtube],iframe[src*=vimeo]").css("visibility","hidden");b(e(pp_images).size());e(".pp_loaderIcon").show();if(settings.deeplinking)n();if(settings.social_tools){facebook_like_link=settings.social_tools.replace("{location_href}",encodeURIComponent(location.href));$pp_pic_holder.find(".pp_social").html(facebook_like_link)}if($ppt.is(":hidden"))$ppt.css("opacity",0).show();$pp_overlay.show().fadeTo(settings.animation_speed,settings.opacity);$pp_pic_holder.find(".currentTextHolder").text(set_position+1+settings.counter_separator_label+e(pp_images).size());if(typeof pp_descriptions[set_position]!="undefined"&&pp_descriptions[set_position]!=""){$pp_pic_holder.find(".pp_description").show().html(unescape(pp_descriptions[set_position]))}else{$pp_pic_holder.find(".pp_description").hide()}movie_width=parseFloat(i("width",pp_images[set_position]))?i("width",pp_images[set_position]):settings.default_width.toString();movie_height=parseFloat(i("height",pp_images[set_position]))?i("height",pp_images[set_position]):settings.default_height.toString();u=false;if(movie_height.indexOf("%")!=-1){movie_height=parseFloat(e(window).height()*parseFloat(movie_height)/100-150);u=true}if(movie_width.indexOf("%")!=-1){movie_width=parseFloat(e(window).width()*parseFloat(movie_width)/100-150);u=true}$pp_pic_holder.fadeIn(function(){settings.show_title&&pp_titles[set_position]!=""&&typeof pp_titles[set_position]!="undefined"?$ppt.html(unescape(pp_titles[set_position])):$ppt.html(" ");imgPreloader="";skipInjection=false;switch(S(pp_images[set_position])){case"image":imgPreloader=new Image;nextImage=new Image;if(isSet&&set_position0)movie_id=movie_id.substr(0,movie_id.indexOf("?"));if(movie_id.indexOf("&")>0)movie_id=movie_id.substr(0,movie_id.indexOf("&"))}movie="http://www.youtube.com/embed/"+movie_id;i("rel",pp_images[set_position])?movie+="?rel="+i("rel",pp_images[set_position]):movie+="?rel=1";if(settings.autoplay)movie+="&autoplay=1";toInject=settings.iframe_markup.replace(/{width}/g,a["width"]).replace(/{height}/g,a["height"]).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,movie);break;case"vimeo":a=w(movie_width,movie_height);movie_id=pp_images[set_position];var t=/http(s?):\/\/(www\.)?vimeo.com\/(\d+)/;var n=movie_id.match(t);movie="http://player.vimeo.com/video/"+n[3]+"?title=0&byline=0&portrait=0";if(settings.autoplay)movie+="&autoplay=1;";vimeo_width=a["width"]+"/embed/?moog_width="+a["width"];toInject=settings.iframe_markup.replace(/{width}/g,vimeo_width).replace(/{height}/g,a["height"]).replace(/{path}/g,movie);break;case"quicktime":a=w(movie_width,movie_height);a["height"]+=15;a["contentHeight"]+=15;a["containerHeight"]+=15;toInject=settings.quicktime_markup.replace(/{width}/g,a["width"]).replace(/{height}/g,a["height"]).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,pp_images[set_position]).replace(/{autoplay}/g,settings.autoplay);break;case"flash":a=w(movie_width,movie_height);flash_vars=pp_images[set_position];flash_vars=flash_vars.substring(pp_images[set_position].indexOf("flashvars")+10,pp_images[set_position].length);filename=pp_images[set_position];filename=filename.substring(0,filename.indexOf("?"));toInject=settings.flash_markup.replace(/{width}/g,a["width"]).replace(/{height}/g,a["height"]).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,filename+"?"+flash_vars);break;case"iframe":a=w(movie_width,movie_height);frame_url=pp_images[set_position];frame_url=frame_url.substr(0,frame_url.indexOf("iframe")-1);toInject=settings.iframe_markup.replace(/{width}/g,a["width"]).replace(/{height}/g,a["height"]).replace(/{path}/g,frame_url);break;case"ajax":doresize=false;a=w(movie_width,movie_height);doresize=true;skipInjection=true;e.get(pp_images[set_position],function(e){toInject=settings.inline_markup.replace(/{content}/g,e);$pp_pic_holder.find("#pp_full_res")[0].innerHTML=toInject;g()});break;case"custom":a=w(movie_width,movie_height);toInject=settings.custom_markup;break;case"inline":myClone=e(pp_images[set_position]).clone().append('
    ').css({width:settings.default_width}).wrapInner('
    ').appendTo(e("body")).show();doresize=false;a=w(e(myClone).width(),e(myClone).height());doresize=true;e(myClone).remove();toInject=settings.inline_markup.replace(/{content}/g,e(pp_images[set_position]).html());break}if(!imgPreloader&&!skipInjection){$pp_pic_holder.find("#pp_full_res")[0].innerHTML=toInject;g()}});return false};e.prettyPhoto.changePage=function(t){currentGalleryPage=0;if(t=="previous"){set_position--;if(set_position<0)set_position=e(pp_images).size()-1}else if(t=="next"){set_position++;if(set_position>e(pp_images).size()-1)set_position=0}else{set_position=t}rel_index=set_position;if(!doresize)doresize=true;if(settings.allow_expand){e(".pp_contract").removeClass("pp_contract").addClass("pp_expand")}y(function(){e.prettyPhoto.open()})};e.prettyPhoto.changeGalleryPage=function(e){if(e=="next"){currentGalleryPage++;if(currentGalleryPage>totalPage)currentGalleryPage=0}else if(e=="previous"){currentGalleryPage--;if(currentGalleryPage<0)currentGalleryPage=totalPage}else{currentGalleryPage=e}slide_speed=e=="next"||e=="previous"?settings.animation_speed:0;slide_to=currentGalleryPage*itemsPerPage*itemWidth;$pp_gallery.find("ul").animate({left:-slide_to},slide_speed)};e.prettyPhoto.startSlideshow=function(){if(typeof m=="undefined"){$pp_pic_holder.find(".pp_play").unbind("click").removeClass("pp_play").addClass("pp_pause").click(function(){e.prettyPhoto.stopSlideshow();return false});m=setInterval(e.prettyPhoto.startSlideshow,settings.slideshow)}else{e.prettyPhoto.changePage("next")}};e.prettyPhoto.stopSlideshow=function(){$pp_pic_holder.find(".pp_pause").unbind("click").removeClass("pp_pause").addClass("pp_play").click(function(){e.prettyPhoto.startSlideshow();return false});clearInterval(m);m=undefined};e.prettyPhoto.close=function(){if($pp_overlay.is(":animated"))return;e.prettyPhoto.stopSlideshow();$pp_pic_holder.stop().find("object,embed").css("visibility","hidden");e("div.pp_pic_holder,div.ppt,.pp_fade").fadeOut(settings.animation_speed,function(){e(this).remove()});$pp_overlay.fadeOut(settings.animation_speed,function(){if(settings.hideflash)e("object,embed,iframe[src*=youtube],iframe[src*=vimeo]").css("visibility","visible");e(this).remove();e(window).unbind("scroll.prettyphoto");r();settings.callback();doresize=true;f=false;delete settings})};if(!pp_alreadyInitialized&&t()){pp_alreadyInitialized=true;hashIndex=t();hashRel=hashIndex;hashIndex=hashIndex.substring(hashIndex.indexOf("/")+1,hashIndex.length-1);hashRel=hashRel.substring(0,hashRel.indexOf("/"));setTimeout(function(){e("a["+s.hook+"^='"+hashRel+"']:eq("+hashIndex+")").trigger("click")},50)}return this.unbind("click.prettyphoto").bind("click.prettyphoto",e.prettyPhoto.initialize)};})(jQuery);var pp_alreadyInitialized=false \ No newline at end of file diff --git a/imagestore/static/prettyphoto/xhr_response.html b/imagestore/static/prettyphoto/xhr_response.html new file mode 100644 index 0000000..84490c8 --- /dev/null +++ b/imagestore/static/prettyphoto/xhr_response.html @@ -0,0 +1,5 @@ +

    This is an XHR Response

    +
    +

    This is sample content brought in.

    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

    +
    \ No newline at end of file diff --git a/imagestore/tahoma.ttf b/imagestore/tahoma.ttf new file mode 100644 index 0000000..4bc6857 Binary files /dev/null and b/imagestore/tahoma.ttf differ diff --git a/imagestore/templates/cms/plugins/imagestore_album.html b/imagestore/templates/cms/plugins/imagestore_album.html new file mode 100644 index 0000000..69af394 --- /dev/null +++ b/imagestore/templates/cms/plugins/imagestore_album.html @@ -0,0 +1,23 @@ +{% load thumbnail %} + diff --git a/imagestore/templates/cms/plugins/imagestore_album_carousel.html b/imagestore/templates/cms/plugins/imagestore_album_carousel.html new file mode 100644 index 0000000..11ec0ec --- /dev/null +++ b/imagestore/templates/cms/plugins/imagestore_album_carousel.html @@ -0,0 +1 @@ +{% include 'cms/plugins/imagestore_album_carousel_base.html' %} diff --git a/imagestore/templates/cms/plugins/imagestore_album_carousel_base.html b/imagestore/templates/cms/plugins/imagestore_album_carousel_base.html new file mode 100644 index 0000000..7d55320 --- /dev/null +++ b/imagestore/templates/cms/plugins/imagestore_album_carousel_base.html @@ -0,0 +1,28 @@ +{% load thumbnail %} +
    +
      + {% for image in images %} + {% thumbnail image.image carousel.size crop="center" as im %} + {% thumbnail image.image carousel.full_size as full %} +
    • + {{ image.title }} +
    • + {% endthumbnail %} + {% endthumbnail %} + {% endfor %} +
    + + +
    \ No newline at end of file diff --git a/imagestore/templates/imagestore/album_delete.html b/imagestore/templates/imagestore/album_delete.html new file mode 100644 index 0000000..ebecfdd --- /dev/null +++ b/imagestore/templates/imagestore/album_delete.html @@ -0,0 +1,14 @@ +{% extends "imagestore/base.html" %} + +{% load i18n %} + +{% block imagestore_content %} +

    {% trans "Are you sure that you would like to delete this album?" %}

    +
    + {% csrf_token %} +

    + ← {% trans "No, take me back" %} + +

    +
    +{% endblock %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/album_list.html b/imagestore/templates/imagestore/album_list.html new file mode 100644 index 0000000..a776d17 --- /dev/null +++ b/imagestore/templates/imagestore/album_list.html @@ -0,0 +1,70 @@ +{% extends "imagestore/base.html" %} +{% load i18n %} +{% load thumbnail %} + +{% block title %} + {% if view_user %} + {% trans "Albums for user" %} {{ view_user }} + {% else %} + {% trans "All albums" %} + {% endif %} +{% endblock %} + +{% block imagestore-breadcrumb %} +
  • + {% if view_user %} + {% trans "Albums for user" %} {{ view_user }} + {% else %} + {% trans "All albums" %} + {% endif %} +
  • +{% endblock %} + +{% block imagestore-info %} + {% if view_user and IMAGESTORE_SHOW_USER %} + {% with user=view_user %} + {% include "imagestore/user_info.html" %} + {% endwith %} + {% endif %} +{% endblock %} + +{% block imagestore-related %} + {% include "imagestore/tag-cloud.html" %} +{% endblock %} + +{% block imagestore_content %} +

    {% if view_user %} + {% trans "Albums for user" %} {{ view_user }} + {% else %} + {% trans "All albums" %} + {% endif %}

    + {% include "imagestore/pagination.html" %} + + {% include "imagestore/pagination.html" %} +{% endblock %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/base.html b/imagestore/templates/imagestore/base.html new file mode 100644 index 0000000..d31cf3a --- /dev/null +++ b/imagestore/templates/imagestore/base.html @@ -0,0 +1,60 @@ +{% extends "website/base.html" %} +{% load i18n %} +{% load url from future %} +{% load sekizai_tags static %} + + +{% block navbar_options %} navbar navbar-inverse navbar-static-top {% endblock %} + + +{% block content %} + +{% include "imagestore/pphoto.html" %} + + +{% addtoblock "css" %} + +{% endaddtoblock %} + +
    +
    +
    + + {% block breadcrumb %} + + {% endblock %} + + {% block imagestore_content %} + {% endblock imagestore_content %} + + {% block imagestore_content-related %} + {% block imagestore-info %} + {% endblock %} +
    + +
    + {% block imagestore-related %} + {% endblock %} + {% endblock %} +
    +
    +
    +{% endblock content %} diff --git a/imagestore/templates/imagestore/forms/album_form.html b/imagestore/templates/imagestore/forms/album_form.html new file mode 100644 index 0000000..612308d --- /dev/null +++ b/imagestore/templates/imagestore/forms/album_form.html @@ -0,0 +1,33 @@ +{% extends "imagestore/base.html" %} +{% load i18n %} +{% load thumbnail %} + + +{% block title %} + {% trans "Create album" %} +{% endblock %} + +{% block imagestore-breadcrumb %} +
  • + {% if object %} + {% trans "Edit album" %}: {{ object.name }} + {% else %} + {% trans "Create album" %} + {% endif %} +
  • +{% endblock %} + +{% block imagestore_content %} +

    + {% if object %} + {% trans "Edit album" %}: {{ object.name }} + {% else %} + {% trans "Create album" %} + {% endif %} +

    +
    + {% csrf_token %} + {{ form.as_p }} + +
    +{% endblock imagestore_content %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/forms/image_form.html b/imagestore/templates/imagestore/forms/image_form.html new file mode 100644 index 0000000..5e34681 --- /dev/null +++ b/imagestore/templates/imagestore/forms/image_form.html @@ -0,0 +1,21 @@ +{% extends "imagestore/base.html" %} +{% load i18n %} +{% load thumbnail %} +{% load url from future %} + +{% block title %} + {% trans "Upload image" %} +{% endblock %} + +{% block imagestore-breadcrumb %} +
  • {% trans "Upload image" %}
  • +{% endblock %} + +{% block imagestore_content %} +

    {% trans "Upload image" %}

    +
    + {% csrf_token %} + {{ form.as_p }} + +
    +{% endblock imagestore_content %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/image-href.html b/imagestore/templates/imagestore/image-href.html new file mode 100644 index 0000000..4131eb9 --- /dev/null +++ b/imagestore/templates/imagestore/image-href.html @@ -0,0 +1,10 @@ +{% load url from future %} +{% if album %} + {% url 'imagestore:image-album' album_id=album.id pk=image.id %} +{% else %} + {% if tag %} + {% url 'imagestore:image-tag' tag=tag pk=image.id %} + {% else %} + {{ image.get_absolute_url }} + {% endif %} +{% endif %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/image-list.html b/imagestore/templates/imagestore/image-list.html new file mode 100644 index 0000000..dae6863 --- /dev/null +++ b/imagestore/templates/imagestore/image-list.html @@ -0,0 +1,22 @@ +{% load i18n %} +{% load thumbnail %} + +
    + {% for image in image_list %} + {% thumbnail image.image "120x120" crop="center" as im %} + + {{ image.title }} + + + {% if image.title %} +
    {{ image.title }} + {% else %} + {% trans 'Info' %} + {% endif %} +
    + {% endthumbnail %} + {% endfor %} + {% include "imagestore/pagination.html" %} +
    + + diff --git a/imagestore/templates/imagestore/image-scope.html b/imagestore/templates/imagestore/image-scope.html new file mode 100644 index 0000000..3d5881c --- /dev/null +++ b/imagestore/templates/imagestore/image-scope.html @@ -0,0 +1,16 @@ +{% load i18n %} +{% if view_user %} + {% if scope_tag %}<{{ scope_tag }} class='scope-view-user'>{% endif %} + {% trans "User" %}: {{ view_user }} + {% if scope_tag %}{% endif %} +{% endif %} +{% if album %} + {% if scope_tag %}<{{ scope_tag }} class='scope-album'>{% endif %} + {% trans "Album" %}: {{ album.name }} + {% if scope_tag %}{% endif %} +{% endif %} +{% if tag %} + {% if scope_tag %}<{{ scope_tag }} class='scope-album'>{% endif %} + {% trans "Tag" %}: {{ tag }} + {% if scope_tag %}{% endif %} +{% endif %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/image.html b/imagestore/templates/imagestore/image.html new file mode 100644 index 0000000..569e3a4 --- /dev/null +++ b/imagestore/templates/imagestore/image.html @@ -0,0 +1,89 @@ +{% extends "imagestore/base.html" %} +{% load i18n %} +{% load thumbnail %} +{% load tagging_tags %} +{% load url from future %} + +{% block title %} + {% trans "Image" %} - {{ image.title }} +{% endblock %} + +{% block imagestore-breadcrumb %} + {% if view_user and IMAGESTORE_SHOW_USER %} +
  • {% trans "User" %}: {{ view_user }} /
  • + {% endif %} + {% if album %} +
  • {% trans "Album" %}: {{ album.name }} /
  • + {% endif %} + {% if tag %} +
  • {% trans "Tag" %}: {{ tag }} /
  • + {% endif %} +
  • + {% if image.title %} + {{ image.title }} + {% else %} + {{ image.id }} + {% endif %} +
  • +{% endblock %} + +{% block imagestore-info %} + +{% endblock %} + +{% block imagestore_content %} + {% if image.title %}

    {{ image.title }}

    {% endif %} + {% if album or tag or view_user %} +

    + {% include "imagestore/image-scope.html" %} +

    + {% endif %} +
    + {{ image.description }} +
    +
    + + {% thumbnail image.image "800x800" as full_im %} + {{ image.title }} + {% endthumbnail %} +
    +{% endblock imagestore_content %} + +{% block controls %} + {% if request.user == image.user or perms.imagestore.moderate_images %} +
  • {% trans "Edit info" %}
  • +
  • {% trans "Delete image" %}
  • + {% endif %} +{% endblock %} + +{% block imagestore-related %} + +
    +

    {% trans "Tags" %}

    + {% tags_for_object image as itags %} + {% for tag in itags %} + {{ tag.name }} + {% endfor %} +
    + {% if image.place %} +
    +

    {% trans "Place" %}

    + {{ image.place.name }} → +
    + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/image_confirm_delete.html b/imagestore/templates/imagestore/image_confirm_delete.html new file mode 100644 index 0000000..44f7685 --- /dev/null +++ b/imagestore/templates/imagestore/image_confirm_delete.html @@ -0,0 +1,14 @@ +{% extends "imagestore/base.html" %} + +{% load i18n %} + +{% block imagestore_content %} +

    {% trans "Are you sure that you would like to delete this image?" %}

    +
    + {% csrf_token %} +

    + ← {% trans "No, take me back" %} + +

    +
    +{% endblock %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/image_delete.html b/imagestore/templates/imagestore/image_delete.html new file mode 100644 index 0000000..44f7685 --- /dev/null +++ b/imagestore/templates/imagestore/image_delete.html @@ -0,0 +1,14 @@ +{% extends "imagestore/base.html" %} + +{% load i18n %} + +{% block imagestore_content %} +

    {% trans "Are you sure that you would like to delete this image?" %}

    +
    + {% csrf_token %} +

    + ← {% trans "No, take me back" %} + +

    +
    +{% endblock %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/image_list.html b/imagestore/templates/imagestore/image_list.html new file mode 100644 index 0000000..6089732 --- /dev/null +++ b/imagestore/templates/imagestore/image_list.html @@ -0,0 +1,65 @@ +{% extends "imagestore/base.html" %} +{% load i18n %} +{% load thumbnail %} +{% load url from future %} + +{% block imagestore-breadcrumb %} + {% with "li" as scope_tag %} + {% include "imagestore/image-scope.html" %} + {% endwith %} +{% endblock %} + +{% block title %} + {% include "imagestore/image-scope.html" %} +{% endblock %} + +{% block imagestore-info %} + {% if view_user and IMAGESTORE_SHOW_USER %} + {% with user=view_user %} + {% include "imagestore/user_info.html" %} + {% endwith %} + {% endif %} + {% if album and IMAGESTORE_SHOW_USER %} + {% with user=album.user %} + {% include "imagestore/user_info.html" %} + {% endwith %} + {% endif %} + +{% endblock %} + + +{% block controls %} + {% if album %} + {% if request.user == album.user or perms.imagestore.moderate_albums %} +
  • {% trans "Edit album" %}
  • + {% endif %} + {% endif %} +{% endblock %} + +{% block imagestore_content %} +

    + {% include "imagestore/image-scope.html" %} +

    + {% include "imagestore/pagination.html" %} +
    + {% for image in image_list %} +
    + {% thumbnail image.image "120x120" crop="center" as im %} + + {{ image.title }} + + + {% if image.title %} +
    {{ image.title }} + {% else %} + {% trans 'Info' %} + {% endif %} +
    + {% endthumbnail %} +
    + {% endfor %} +
    + {% include "imagestore/pagination.html" %} +{% endblock %} + + diff --git a/imagestore/templates/imagestore/pagination.html b/imagestore/templates/imagestore/pagination.html new file mode 100644 index 0000000..c46ea50 --- /dev/null +++ b/imagestore/templates/imagestore/pagination.html @@ -0,0 +1,26 @@ +{% load i18n %} + +{% if is_paginated %} + +{% endif %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/pphoto.html b/imagestore/templates/imagestore/pphoto.html new file mode 100644 index 0000000..901f276 --- /dev/null +++ b/imagestore/templates/imagestore/pphoto.html @@ -0,0 +1,38 @@ +{% load sekizai_tags static %} {% addtoblock "css" %} + +{% endaddtoblock %} {% addtoblock "js" %} + + + +{% endaddtoblock %} diff --git a/imagestore/templates/imagestore/tag-cloud.html b/imagestore/templates/imagestore/tag-cloud.html new file mode 100644 index 0000000..c89d450 --- /dev/null +++ b/imagestore/templates/imagestore/tag-cloud.html @@ -0,0 +1,13 @@ +{% load tagging_tags %} +{% load i18n %} +{% load url from future %} + +{% if IMAGESTORE_SHOW_TAGS %} +
    +

    {% trans "Tags" %}

    + {% tag_cloud_for_model imagestore.Image as image_tags %} + {% for tag in image_tags %} + {{ tag.name }} + {% endfor %} +
    +{% endif %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/tag.html b/imagestore/templates/imagestore/tag.html new file mode 100644 index 0000000..8929682 --- /dev/null +++ b/imagestore/templates/imagestore/tag.html @@ -0,0 +1,21 @@ +{% extends "imagestore/base.html" %} + +{% load i18n %} +{% load thumbnail %} + +{% block title %} + {% trans "Gallery" %} - {% trans "Tag" %}: {{ tag }} +{% endblock %} + +{% block imagestore-breadcrumb %} +
  • {% trans "Tag" %}: {{ tag }}
  • +{% endblock %} + +{% block imagestore_content %} +

    {% trans "Tag" %} - {{ tag }}

    + {% include "imagestore/image-list.html" %} +{% endblock imagestore_content %} + +{% block imagestore_content-related %} + {% include "imagestore/tag-cloud.html" %} +{% endblock %} \ No newline at end of file diff --git a/imagestore/templates/imagestore/user_info.html b/imagestore/templates/imagestore/user_info.html new file mode 100644 index 0000000..8e5323b --- /dev/null +++ b/imagestore/templates/imagestore/user_info.html @@ -0,0 +1,22 @@ +{% load i18n %} +{% load thumbnail %} + +{# if we can't get profile then return user model itself #} +{% with profile=user.get_profile|default_if_none:user %} + +{% endwith %} \ No newline at end of file diff --git a/imagestore/test_img.jpg b/imagestore/test_img.jpg new file mode 100644 index 0000000..7ff447f Binary files /dev/null and b/imagestore/test_img.jpg differ diff --git a/imagestore/tests.py b/imagestore/tests.py new file mode 100644 index 0000000..b2f2f5d --- /dev/null +++ b/imagestore/tests.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + +from django.test import TestCase +from django.test.client import Client +from django.core.urlresolvers import reverse +from models import * +import os +from django.contrib.auth.models import User +from django.db import models + +try: + from lxml import html +except: + raise ImportError('Imagestore require lxml for self-testing') + +class ImagestoreTest(TestCase): + def setUp(self): + self.image_file = open(os.path.join(os.path.dirname(__file__), 'test_img.jpg')) + self.user = User.objects.create_user('zeus', 'zeus@example.com', 'zeus') + self.client = Client() + self.album = Album(name='test album', user=self.user) + self.album.save() + + def _upload_test_image(self, username='zeus', password='zeus'): + self.client.login(username=username, password=password) + self.image_file = open(os.path.join(os.path.dirname(__file__), 'test_img.jpg')) + response = self.client.get(reverse('imagestore:upload')) + self.assertEqual(response.status_code, 200) + tree = html.fromstring(response.content) + values = dict(tree.xpath('//form[@method="post"]')[0].form_values()) + values['image'] = self.image_file + values['album'] = Album.objects.filter(user=self.user)[0].id + response = self.client.post(reverse('imagestore:upload'), values, follow=True) + return response + + def _create_test_album(self, username='zeus', password='zeus'): + self.client.login(username=username, password=password) + response = self.client.get(reverse('imagestore:create-album')) + self.assertEqual(response.status_code, 200) + tree = html.fromstring(response.content) + values = dict(tree.xpath('//form[@method="post"]')[0].form_values()) + values['name'] = 'test album creation' + response = self.client.post(reverse('imagestore:create-album'), values, follow=True) + return response + + def test_empty_index(self): + response = self.client.get(reverse('imagestore:index')) + self.assertEqual(response.status_code, 200) + + def test_empty_album(self): + self.album.is_public = False + self.album.save() + response = self.client.get(self.album.get_absolute_url()) + self.assertTrue(response.status_code == 403) + self.client.login(username='zeus', password='zeus') + self.user.is_superuser = True + self.user.save() + response = self.client.get(self.album.get_absolute_url()) + self.assertEqual(response.status_code, 200) + + def test_user(self): + response = self.client.get(reverse('imagestore:user', kwargs={'username': 'zeus'})) + self.assertEqual(response.status_code, 200) + + def test_album_creation(self): + response = self._create_test_album() + self.assertEqual(response.status_code, 200) + + def test_album_edit(self): + response = self._create_test_album() + album_id = Album.objects.get(name='test album creation').id + self.client.login(username='zeus', password='zeus') + response = self.client.get(reverse('imagestore:update-album', kwargs={'pk': album_id})) + self.assertEqual(response.status_code, 200) + tree = html.fromstring(response.content) + values = dict(tree.xpath('//form[@method="post"]')[0].form_values()) + values['name'] = 'test album update' + self.client.post(reverse('imagestore:update-album', kwargs={'pk': album_id}), values, follow=True) + self.assertEqual(response.status_code, 200) + self.assertTrue(Album.objects.get(id=album_id).name == 'test album update') + + def test_album_delete(self): + response = self._create_test_album() + self.client.login(username='zeus', password='zeus') + album_id = Album.objects.get(name='test album creation').id + response = self.client.post(reverse('imagestore:delete-album', kwargs={'pk': album_id}), follow=True) + self.assertEqual(response.status_code, 200) + self.assertTrue(len(Album.objects.filter(id=album_id)) == 0) + + + def test_image_upload(self): + response = self._create_test_album() + response = self._upload_test_image() + self.assertEqual(response.status_code, 200) + img_url = Image.objects.get(user__username='zeus').get_absolute_url() + response = self.client.get(img_url) + self.assertEqual(response.status_code, 200) + self.test_user() + + def test_tagging(self): + response = self._create_test_album() + self.client.login(username='zeus', password='zeus') + response = self.client.get(reverse('imagestore:upload')) + self.assertEqual(response.status_code, 200) + tree = html.fromstring(response.content) + values = dict(tree.xpath('//form[@method="post"]')[0].form_values()) + values['image'] = self.image_file + values['tags'] = 'one, tow, three' + values['album'] = Album.objects.filter(user=self.user)[0].id + self.client.post(reverse('imagestore:upload'), values, follow=True) + self.assertEqual(response.status_code, 200) + response = self.client.get(reverse('imagestore:tag', kwargs={'tag': 'one'})) + self.assertEqual(response.status_code, 200) + self.assertTrue(len(response.context['image_list']) == 1) + + def test_delete(self): + User.objects.create_user('bad', 'bad@example.com', 'bad') + response = self._create_test_album() + self._upload_test_image() + self.client.login(username='bad', password='bad') + image_id = Image.objects.get(user__username='zeus').id + response = self.client.post(reverse('imagestore:delete-image', kwargs={'pk': image_id}), follow=True) + self.assertEqual(response.status_code, 404) + self.client.login(username='zeus', password='zeus') + response = self.client.post(reverse('imagestore:delete-image', kwargs={'pk': image_id}), follow=True) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(Image.objects.all()), 0) + + def test_update_image(self): + self._upload_test_image() + self.client.login(username='zeus', password='zeus') + image_id = Image.objects.get(user__username='zeus').id + response = self.client.get(reverse('imagestore:update-image', kwargs={'pk': image_id}), follow=True) + self.assertEqual(response.status_code, 200) + tree = html.fromstring(response.content) + values = dict(tree.xpath('//form[@method="post"]')[0].form_values()) + values['tags'] = 'one, tow, three' + values['title'] = 'changed title' + values['album'] = Album.objects.filter(user=self.user)[0].id + self.client.post(reverse('imagestore:update-image', kwargs={'pk': image_id}), values, follow=True) + self.assertEqual(response.status_code, 200) + self.assertTrue(Image.objects.get(user__username='zeus').title == 'changed title') + + def test_prev_next_with_ordering(self): + self.test_album_creation() + for i in range(1, 6): + self._upload_test_image() + img = Image.objects.order_by('-id')[0] + img.order = i + img.save() + # Swap two id's + im1 = Image.objects.get(order=2) + im2 = Image.objects.get(order=4) + im1.order, im2.order = 4, 2 + im1.save() + im2.save() + response = self.client.get(Image.objects.get(order=3).get_absolute_url()) + self.assertEqual(response.context['next'], im1) + self.assertEqual(response.context['previous'], im2) + + def test_album_order(self): + self.album.delete() + a1 = Album.objects.create(name='b2', order=1, user=self.user) + a2 = Album.objects.create(name='a1', order=2, user=self.user) + response = self.client.get(reverse('imagestore:index')) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['object_list'][0].name, 'b2') + self.assertEqual(response.context['object_list'][1].name, 'a1') + a1.order, a2.order = 2, 1 + a1.save() + a2.save() + response = self.client.get(reverse('imagestore:index')) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['object_list'][0].name, 'a1') + self.assertEqual(response.context['object_list'][1].name, 'b2') \ No newline at end of file diff --git a/imagestore/urls.py b/imagestore/urls.py new file mode 100644 index 0000000..7a0e916 --- /dev/null +++ b/imagestore/urls.py @@ -0,0 +1,33 @@ +try: + from django.conf.urls import patterns, url +except ImportError: + from django.conf.urls.defaults import patterns, url +from views import (AlbumListView, ImageListView, UpdateImage, UpdateAlbum, CreateImage, CreateAlbum, DeleteImage, \ + DeleteAlbum, ImageView) + + +urlpatterns = patterns('imagestore.views', + url(r'^$', AlbumListView.as_view(), name='index'), + + + url(r'^album/add/$', CreateAlbum.as_view(), name='create-album'), + url(r'^album/(?P\d+)/$', ImageListView.as_view(), name='album'), + url(r'^album/(?P\d+)/edit/$', UpdateAlbum.as_view(), name='update-album'), + url(r'^album/(?P\d+)/delete/$', DeleteAlbum.as_view(), name='delete-album'), + + url(r'^tag/(?P[^/]+)/$', ImageListView.as_view(), name='tag'), + + url(r'^user/(?P\w+)/albums/', AlbumListView.as_view(), name='user'), + url(r'^user/(?P\w+)/$', ImageListView.as_view(), name='user-images'), + + url(r'^upload/$', CreateImage.as_view(), name='upload'), + + url(r'^image/(?P\d+)/$', ImageView.as_view(), name='image'), + url(r'^album/(?P\d+)/image/(?P\d+)/$', ImageView.as_view(), name='image-album'), + url(r'^tag/(?P[^/]+)/image/(?P\d+)/$', ImageView.as_view(), name='image-tag'), + url(r'^image/(?P\d+)/delete/$', DeleteImage.as_view(), name='delete-image'), + url(r'^image/(?P\d+)/update/$', UpdateImage.as_view(), name='update-image'), + ) + + + diff --git a/imagestore/utils.py b/imagestore/utils.py new file mode 100644 index 0000000..973f85c --- /dev/null +++ b/imagestore/utils.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 + +__author__ = 'zeus' + +import os +import uuid +from django.core.exceptions import ImproperlyConfigured +from django.utils.importlib import import_module +from django.conf import settings + +UPLOAD_TO = getattr(settings, 'IMAGESTORE_UPLOAD_TO', 'imagestore/') + +def load_class(class_path, setting_name=None): + """ + Loads a class given a class_path. + The setting_name parameter is only there for pretty error output, and + therefore is optional + + Taken from https://github.com/divio/django-shop/blob/master/shop/util/loader.py + """ + try: + class_module, class_name = class_path.rsplit('.', 1) + except ValueError: + if setting_name: + txt = '%s isn\'t a valid module. Check your %s setting' % (class_path,setting_name) + else: + txt = '%s isn\'t a valid module.' % class_path + raise ImproperlyConfigured(txt) + + try: + mod = import_module(class_module) + except ImportError, e: + if setting_name: + txt = 'Error importing backend %s: "%s". Check your %s setting' % (class_module, e, setting_name) + else: + txt = 'Error importing backend %s: "%s".' % (class_module, e) + raise ImproperlyConfigured(txt) + + try: + clazz = getattr(mod, class_name) + except AttributeError, e: + if setting_name: + txt = 'Backend module "%s" does not define a "%s" class. Check your %s setting. (%s)' % (class_module, class_name, setting_name) + else: + txt = 'Backend module "%s" does not define a "%s" class. (%s)' % (class_module, class_name, e) + raise ImproperlyConfigured(txt) + return clazz + +def get_model_string(model_name): + """ + Returns the model string notation Django uses for lazily loaded ForeignKeys + (eg 'auth.User') to prevent circular imports. + This is needed to allow our crazy custom model usage. + + Taken from https://github.com/divio/django-shop/blob/master/shop/util/loader.py + """ + class_path = getattr(settings, 'IMAGESTORE_%s_MODEL' % model_name.upper().replace('_', ''), None) + if not class_path: + return 'imagestore.%s' % model_name + else: + klass = load_class(class_path) + return '%s.%s' % (klass._meta.app_label, klass.__name__) + +def get_file_path(instance, filename): + ext = filename.split('.')[-1] + filename = "%s.%s" % (uuid.uuid4(), ext) + return os.path.join(UPLOAD_TO, filename) \ No newline at end of file diff --git a/imagestore/views.py b/imagestore/views.py new file mode 100644 index 0000000..2d1a933 --- /dev/null +++ b/imagestore/views.py @@ -0,0 +1,256 @@ +from django.core.exceptions import PermissionDenied +from django.core.urlresolvers import reverse +from django.utils.decorators import method_decorator +from imagestore.models import Album, Image +from imagestore.models import image_applabel, image_classname +from imagestore.models import album_applabel, album_classname +from django.shortcuts import get_object_or_404 +from django.http import Http404, HttpResponseRedirect +from django.conf import settings +from django.contrib.auth.models import User +from django.contrib.auth.decorators import permission_required +from django.contrib.auth.decorators import login_required +from django.utils.translation import ugettext_lazy as _ +from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView +from tagging.models import TaggedItem +from tagging.utils import get_tag +from utils import load_class +from django.db.models import Q + +try: + from django.contrib.auth import get_user_model + User = get_user_model() + username_field = User.USERNAME_FIELD +except ImportError: + from django.contrib.auth.models import User + username_field = 'username' + +IMAGESTORE_IMAGES_ON_PAGE = getattr(settings, 'IMAGESTORE_IMAGES_ON_PAGE', 20) + +IMAGESTORE_ON_PAGE = getattr(settings, 'IMAGESTORE_ON_PAGE', 20) + +ImageForm = load_class(getattr(settings, 'IMAGESTORE_IMAGE_FORM', 'imagestore.forms.ImageForm')) +AlbumForm = load_class(getattr(settings, 'IMAGESTORE_ALBUM_FORM', 'imagestore.forms.AlbumForm')) + + +class AlbumListView(ListView): + context_object_name = 'album_list' + template_name = 'imagestore/album_list.html' + paginate_by = getattr(settings, 'IMAGESTORE_ALBUMS_ON_PAGE', 20) + allow_empty = True + + def get_queryset(self): + albums = Album.objects.filter(is_public=True).select_related('head') + self.e_context = dict() + if 'username' in self.kwargs: + user = get_object_or_404(**{'klass': User, username_field: self.kwargs['username']}) + albums = albums.filter(user=user) + self.e_context['view_user'] = user + return albums + + def get_context_data(self, **kwargs): + context = super(AlbumListView, self).get_context_data(**kwargs) + context.update(self.e_context) + return context + + +def get_images_queryset(self): + images = Image.objects.all() + self.e_context = dict() + if 'tag' in self.kwargs: + tag_instance = get_tag(self.kwargs['tag']) + if tag_instance is None: + raise Http404(_('No Tag found matching "%s".') % self.kwargs['tag']) + self.e_context['tag'] = tag_instance + images = TaggedItem.objects.get_by_model(images, tag_instance) + if 'username' in self.kwargs: + user = get_object_or_404(**{'klass': User, username_field: self.kwargs['username']}) + self.e_context['view_user'] = user + images = images.filter(user=user) + if 'album_id' in self.kwargs: + album = get_object_or_404(Album, id=self.kwargs['album_id']) + self.e_context['album'] = album + images = images.filter(album=album) + if (not album.is_public) and\ + (self.request.user != album.user) and\ + (not self.request.user.has_perm('imagestore.moderate_albums')): + raise PermissionDenied + return images + + +class ImageListView(ListView): + context_object_name = 'image_list' + template_name = 'imagestore/image_list.html' + paginate_by = getattr(settings, 'IMAGESTORE_IMAGES_ON_PAGE', 20) + allow_empty = True + + get_queryset = get_images_queryset + + def get_context_data(self, **kwargs): + context = super(ImageListView, self).get_context_data(**kwargs) + context.update(self.e_context) + return context + + +class ImageView(DetailView): + context_object_name = 'image' + template_name = 'imagestore/image.html' + + get_queryset = get_images_queryset + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + + if self.object.album: + if (not self.object.album.is_public) and\ + (self.request.user != self.object.album.user) and\ + (not self.request.user.has_perm('imagestore.moderate_albums')): + raise PermissionDenied + + context = self.get_context_data(object=self.object) + return self.render_to_response(context) + + def get_context_data(self, **kwargs): + context = super(ImageView, self).get_context_data(**kwargs) + image = context['image'] + + base_qs = self.get_queryset() + count = base_qs.count() + img_pos = base_qs.filter( + Q(order__lt=image.order)| + Q(id__lt=image.id, order=image.order) + ).count() + next = None + previous = None + if count - 1 > img_pos: + try: + next = base_qs.filter( + Q(order__gt=image.order)| + Q(id__gt=image.id, order=image.order) + )[0] + except IndexError: + pass + if img_pos > 0: + try: + previous = base_qs.filter( + Q(order__lt=image.order)| + Q(id__lt=image.id, order=image.order) + ).order_by('-order', '-id')[0] + except IndexError: + pass + context['next'] = next + context['previous'] = previous + context.update(self.e_context) + return context + + +class CreateAlbum(CreateView): + template_name = 'imagestore/forms/album_form.html' + model = Album + form_class = AlbumForm + + @method_decorator(login_required) + @method_decorator(permission_required('%s.add_%s' % (album_applabel, album_classname))) + def dispatch(self, *args, **kwargs): + return super(CreateAlbum, self).dispatch(*args, **kwargs) + + def form_valid(self, form): + self.object = form.save(commit=False) + self.object.user = self.request.user + self.object.save() + return HttpResponseRedirect(self.get_success_url()) + + +def filter_album_queryset(self): + if self.request.user.has_perm('imagestore.moderate_albums'): + return Album.objects.all() + else: + return Album.objects.filter(user=self.request.user) + + +class UpdateAlbum(UpdateView): + template_name = 'imagestore/forms/album_form.html' + model = Album + form_class = AlbumForm + + get_queryset = filter_album_queryset + + @method_decorator(login_required) + @method_decorator(permission_required('%s.add_%s' % (album_applabel, album_classname))) + def dispatch(self, *args, **kwargs): + return super(UpdateAlbum, self).dispatch(*args, **kwargs) + + +class DeleteAlbum(DeleteView): + template_name = 'imagestore/album_delete.html' + model = Album + + def get_success_url(self): + return reverse('imagestore:index') + + get_queryset = filter_album_queryset + + @method_decorator(login_required) + @method_decorator(permission_required('%s.change_%s' % (album_applabel, album_classname))) + def dispatch(self, *args, **kwargs): + return super(DeleteAlbum, self).dispatch(*args, **kwargs) + + +class CreateImage(CreateView): + template_name = 'imagestore/forms/image_form.html' + model = Image + form_class = ImageForm + + @method_decorator(login_required) + @method_decorator(permission_required('%s.add_%s' % (image_applabel, image_classname))) + def dispatch(self, *args, **kwargs): + return super(CreateImage, self).dispatch(*args, **kwargs) + + def get_form(self, form_class): + return form_class(user=self.request.user, **self.get_form_kwargs()) + + def form_valid(self, form): + self.object = form.save(commit=False) + self.object.user = self.request.user + self.object.save() + if self.object.album: + self.object.album.save() + return HttpResponseRedirect(self.get_success_url()) + + +def get_edit_image_queryset(self): + if self.request.user.has_perm('%s.moderate_%s' % (image_applabel, image_classname)): + return Image.objects.all() + else: + return Image.objects.filter(user=self.request.user) + + +class UpdateImage(UpdateView): + template_name = 'imagestore/forms/image_form.html' + model = Image + form_class = ImageForm + + get_queryset = get_edit_image_queryset + + def get_form(self, form_class): + return form_class(user=self.object.user, **self.get_form_kwargs()) + + @method_decorator(login_required) + @method_decorator(permission_required('%s.change_%s' % (image_applabel, image_classname))) + def dispatch(self, *args, **kwargs): + return super(UpdateImage, self).dispatch(*args, **kwargs) + + +class DeleteImage(DeleteView): + template_name = 'imagestore/image_delete.html' + model = Image + + def get_success_url(self): + return reverse('imagestore:index') + + get_queryset = get_edit_image_queryset + + @method_decorator(login_required) + @method_decorator(permission_required('%s.delete_%s' % (image_applabel, image_classname))) + def dispatch(self, *args, **kwargs): + return super(DeleteImage, self).dispatch(*args, **kwargs) \ No newline at end of file diff --git a/location_field/forms.py b/location_field/forms.py index 15cc3fc..f4094d9 100644 --- a/location_field/forms.py +++ b/location_field/forms.py @@ -1,26 +1,23 @@ from django.forms import fields -from location_field.widgets import LocationWidget + +from .widgets import LocationWidget class PlainLocationField(fields.CharField): + """A form field for entering location data with a map widget.""" + def __init__(self, based_field=None, zoom=None, default=None, *args, **kwargs): - - kwargs['initial'] = default + kwargs["initial"] = default self.widget = LocationWidget(based_field=based_field, zoom=zoom, **kwargs) - dwargs = { - 'required': True, - 'label': None, - 'initial': None, - 'help_text': None, - 'error_messages': None, - 'show_hidden_initial': False, + # Extract only the valid kwargs for CharField + field_kwargs = { + "required": kwargs.get("required", True), + "label": kwargs.get("label", None), + "initial": kwargs.get("initial", None), + "help_text": kwargs.get("help_text", None), + "error_messages": kwargs.get("error_messages", None), + "show_hidden_initial": kwargs.get("show_hidden_initial", False), } - for attr in dwargs: - if attr in kwargs: - dwargs[attr] = kwargs[attr] - - super(PlainLocationField, self).__init__(*args, **dwargs) - - + super().__init__(*args, **field_kwargs) diff --git a/location_field/media/form.js b/location_field/media/form.js index 4f7d505..5969e7d 100644 --- a/location_field/media/form.js +++ b/location_field/media/form.js @@ -40,14 +40,14 @@ theObject.placeMarker( l ); theObject.saveToInputField(); }); - }; + } this.placeMarker = function( location ) { this.marker.setPosition( location ); this.map.setCenter( location ); this.map.panTo( location ); - }; + } this.geocode = function(address, cb) @@ -60,7 +60,7 @@ } }); } - }; + } this.geocode_reverse = function( cb) { @@ -71,13 +71,13 @@ } }); } - }; + } this.saveToInputField = function() { var p = this.marker.getPosition(); coordinate_field.value = p.lat().toFixed(6) + "," + p.lng().toFixed(6) + "," + this.map.getZoom() ; - }; + } this.loadFromInputField = function() { @@ -95,7 +95,7 @@ this.placeMarker( init_position ); this.map.setZoom( 16 ); } - }; + } // --------------------------- Constructor ------------------------------------- @@ -118,7 +118,7 @@ }); theObject.loadFromInputField(); - }; + } this.init(); } @@ -132,6 +132,7 @@ autoOpen: false } ); + $('input[data-location-widget]').click( function() { var formCoordField = $(this); @@ -168,7 +169,7 @@ $dialogElement[0].map.placeMarkerUsingAddressString( $dialogLocationField.val() ); $dialogLocationField.on("keypress", function(e) { - if ( e.keyCode === 13 ) { // enter + if ( e.keyCode == 13 ) { // enter $dialogElement[0].map.placeMarkerUsingAddressString( $dialogLocationField.val() ); return false; } @@ -183,5 +184,7 @@ $dialogElement.dialog('open'); }); - + + + }); diff --git a/location_field/models.py b/location_field/models.py index 5031cbc..91596ca 100755 --- a/location_field/models.py +++ b/location_field/models.py @@ -3,7 +3,9 @@ from django.db.models import CharField from location_field import forms -class BaseLocationField(object): +class BaseLocationField: + """Base class for location fields.""" + def __init__(self, based_field=None, zoom=2, default=None, *args, **kwargs): self._based_field = based_field self._zoom = zoom @@ -11,29 +13,31 @@ class BaseLocationField(object): self.default = default def formfield(self, **kwargs): - return super(BaseLocationField, self).formfield( + return super().formfield( form_class=self.formfield_class, based_field=self._based_field, zoom=self._zoom, default=self._default, - **kwargs) + **kwargs, + ) class PlainLocationField(BaseLocationField, CharField): + """A CharField that stores location data as 'latitude,longitude,zoom'.""" + formfield_class = forms.PlainLocationField - def __init__(self, based_field=None, zoom=None, - max_length=63, *args, **kwargs): - - super(PlainLocationField, self).__init__(based_field=based_field, - zoom=zoom, *args, **kwargs) - + def __init__(self, based_field=None, zoom=None, max_length=63, *args, **kwargs): + BaseLocationField.__init__( + self, based_field=based_field, zoom=zoom, *args, **kwargs + ) CharField.__init__(self, max_length=max_length, *args, **kwargs) - -# south compatibility -try: - from south.modelsinspector import add_introspection_rules - add_introspection_rules([], ["^location_field\.models\.PlainLocationField"]) -except: - pass + def deconstruct(self): + """Return enough information to recreate the field.""" + name, path, args, kwargs = super().deconstruct() + if self._based_field is not None: + kwargs["based_field"] = self._based_field + if self._zoom is not None: + kwargs["zoom"] = self._zoom + return name, path, args, kwargs diff --git a/location_field/urls.py b/location_field/urls.py index c1b888c..338d40a 100644 --- a/location_field/urls.py +++ b/location_field/urls.py @@ -1,9 +1,8 @@ -import os -from django.urls import re_path -from django.views.static import serve +from django.urls import path -app_dir = os.path.dirname(__file__) +app_name = "location_field" -urlpatterns = [ - re_path(r'^media/(.*)$', serve, {'document_root': '%s/media' % app_dir}), -] +# Static files for location_field should be placed in location_field/static/location_field/ +# and will be served automatically by Django's staticfiles system. + +urlpatterns = [] diff --git a/location_field/widgets.py b/location_field/widgets.py index 2c99cbb..e4dd25b 100644 --- a/location_field/widgets.py +++ b/location_field/widgets.py @@ -1,54 +1,67 @@ +import os + from django.forms import widgets from django.utils.safestring import mark_safe -from django.conf import settings -import os class LocationWidget(widgets.TextInput): - def __init__(self, attrs=None, based_field=None, zoom=None, width=610, height=480, **kwargs): + """A widget that displays a map for selecting a location.""" + + def __init__( + self, attrs=None, based_field=None, zoom=None, width=610, height=480, **kwargs + ): self.based_field = based_field self.zoom = zoom self.width = width self.height = height - super(LocationWidget, self).__init__(attrs) + super().__init__(attrs) def render(self, name, value, attrs=None, renderer=None): - if value is not None and len(value) > 0: - lat, lng, zoom = value.split(',') - - value = '%s,%s,%d' % ( - float(lat), - float(lng), - float(zoom) - ) + try: + lat, lng, zoom = value.split(",") + value = "%s,%s,%d" % (float(lat), float(lng), int(float(zoom))) + except (ValueError, TypeError): + value = "" else: - value = '' + value = "" - based_field = "#id_" + self.based_field.name + if self.based_field is not None: + based_field = "#id_" + self.based_field.name + else: + based_field = "" attrs = attrs or {} - attrs['readonly'] = "readonly" - attrs['data-location-widget'] = name - attrs['data-based-field'] = based_field - attrs['data-zoom'] = self.zoom - attrs['data-map'] = '#map_' + name - attrs['data-dialog-id'] = "#map_dialog_" + name - text_input = super(LocationWidget, self).render(name, value, attrs) + attrs["readonly"] = "readonly" + attrs["data-location-widget"] = name + attrs["data-based-field"] = based_field + attrs["data-zoom"] = self.zoom or 7 + attrs["data-map"] = "#map_" + name + attrs["data-dialog-id"] = "#map_dialog_" + name + text_input = super().render(name, value, attrs, renderer) + + # Load the HTML template for the map dialog path = os.path.abspath(os.path.dirname(__file__)) - with open(path + "/media/form.html", 'r') as content_file: - html = content_file.read() + template_path = os.path.join(path, "media", "form.html") - return mark_safe(text_input + html % {'name': name, 'width': self.width, 'height': self.height}) + try: + with open(template_path, "r") as content_file: + html = content_file.read() + html = html % {"name": name, "width": self.width, "height": self.height} + except (FileNotFoundError, IOError): + html = "" + + return mark_safe(text_input + html) class Media: - css = { - 'all': ('/location_field/media/form.css',) - } - # Use schemaless URL so it works with both, http and https websites + css = {"all": ("location_field/form.css",)} js = ( - '//maps.google.com/maps/api/js?sensor=false&language=de&key={}'.format(settings.GOOGLE_MAPS_API_KEY), - '/static/js/bindWithDelay.js', - '/location_field/media/form.js', + # jQuery and jQuery UI (consider using local copies or newer CDN) + "https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js", + "https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js", + # Google Maps API - you may need to add an API key + "https://maps.google.com/maps/api/js?language=de", + "js/bindWithDelay.js", + "location_field/form.js", ) diff --git a/manage.py b/manage.py index f207ecf..5296b08 100755 --- a/manage.py +++ b/manage.py @@ -1,10 +1,23 @@ #!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" + import os import sys -if __name__ == "__main__": + +def main(): + """Run administrative tasks.""" os.environ.setdefault("DJANGO_SETTINGS_MODULE", "blechreiz.settings") - - from django.core.management import execute_from_command_line - + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/musicians/admin.py b/musicians/admin.py index 32a52d1..02033ee 100644 --- a/musicians/admin.py +++ b/musicians/admin.py @@ -1,32 +1,128 @@ from django.contrib import admin -from django.contrib.auth.admin import UserAdmin +from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.models import User -from django.utils.translation import ugettext as _ -from musicians.models import Musician -# from eventplanner.admin import EventParticipationInline +from django.utils.translation import gettext_lazy as _ + +from .models import Musician -# Define an inline admin descriptor for Musician model -# which acts a bit like a singleton class MusicianInline(admin.StackedInline): + """Inline admin for Musician model attached to User.""" + model = Musician can_delete = False - verbose_name_plural = _('musicians') - verbose_name = _('musician') + verbose_name_plural = _("musician profile") + verbose_name = _("musician profile") + + fieldsets = ( + ( + _("Images"), + { + "fields": ("image", "small_image"), + "classes": ("collapse",), + }, + ), + ( + _("Contact"), + { + "fields": ("phone_home", "phone_mobile", "phone_work"), + }, + ), + ( + _("Address"), + { + "fields": ("street", "city", "zip_code"), + }, + ), + ( + _("Details"), + { + "fields": ("instrument", "birthday", "position", "public_description"), + }, + ), + ) -# Define a new User admin -class UserAdmin(UserAdmin): +class CustomUserAdmin(BaseUserAdmin): + """Extended User admin with Musician inline.""" + inlines = (MusicianInline,) + list_display = ( + "username", + "email", + "first_name", + "last_name", + "is_staff", + "get_instrument", + ) + list_select_related = ("musician",) + + @admin.display(description=_("Instrument")) + def get_instrument(self, obj): + try: + return obj.musician.get_instrument_display() + except Musician.DoesNotExist: + return "-" +@admin.register(Musician) class MusicianAdmin(admin.ModelAdmin): - readonly_fields = ('user',) - # inlines = ( EventParticipationInline, ) - model = Musician + """Admin configuration for Musician model.""" + + list_display = ( + "user", + "instrument", + "phone_mobile", + "city", + "position", + ) + list_filter = ("instrument",) + search_fields = ( + "user__username", + "user__first_name", + "user__last_name", + "city", + "phone_mobile", + ) + readonly_fields = ("user",) + ordering = ("position", "user__username") + + fieldsets = ( + ( + None, + { + "fields": ("user", "instrument", "position"), + }, + ), + ( + _("Images"), + { + "fields": ("image", "small_image"), + "classes": ("collapse",), + }, + ), + ( + _("Contact Information"), + { + "fields": ("phone_home", "phone_mobile", "phone_work"), + }, + ), + ( + _("Address"), + { + "fields": ("street", "city", "zip_code"), + }, + ), + ( + _("Personal"), + { + "fields": ("birthday", "public_description"), + "classes": ("collapse",), + }, + ), + ) -# Re-register UserAdmin +# Re-register UserAdmin with Musician inline admin.site.unregister(User) -admin.site.register(User, UserAdmin) -admin.site.register(Musician, MusicianAdmin) +admin.site.register(User, CustomUserAdmin) diff --git a/musicians/migrations/0001_initial.py b/musicians/migrations/0001_initial.py new file mode 100644 index 0000000..ffd177a --- /dev/null +++ b/musicians/migrations/0001_initial.py @@ -0,0 +1,40 @@ +# Generated by Django 5.1.15 on 2026-03-30 19:15 + +import django.db.models.deletion +import musicians.models +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Musician', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image', models.ImageField(blank=True, null=True, upload_to=musicians.models.musicianPictureName, verbose_name='image')), + ('small_image', models.ImageField(blank=True, null=True, upload_to=musicians.models.musicianSmallPictureName, verbose_name='circular thumbnail')), + ('instrument', models.CharField(blank=True, choices=[('TR', 'Trumpet'), ('TRB', 'Trombone'), ('HRN', 'Horn'), ('TUBA', 'Tuba')], max_length=4, verbose_name='instrument')), + ('birthday', models.DateField(blank=True, null=True, verbose_name='birthday')), + ('street', models.CharField(blank=True, max_length=80, verbose_name='street')), + ('city', models.CharField(blank=True, max_length=40, verbose_name='city')), + ('zip_code', models.IntegerField(blank=True, null=True, verbose_name='zip_code')), + ('phone_home', models.CharField(blank=True, max_length=18, verbose_name='phone_home')), + ('phone_mobile', models.CharField(blank=True, max_length=18, verbose_name='phone_mobile')), + ('phone_work', models.CharField(blank=True, max_length=18, verbose_name='phone_work')), + ('position', models.IntegerField(blank=True, null=True, verbose_name='Position')), + ('public_description', models.TextField(blank=True, verbose_name='public_description')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user')), + ], + options={ + 'ordering': ['position', 'user__username'], + }, + ), + ] diff --git a/musicians/migrations/__init__.py b/musicians/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/musicians/models.py b/musicians/models.py index c44294d..01cf005 100644 --- a/musicians/models.py +++ b/musicians/models.py @@ -1,14 +1,14 @@ -from django.db import models -from django.contrib.auth.models import User -from django.utils.translation import ugettext as _ - import os +from django.contrib.auth.models import User +from django.db import models +from django.utils.translation import gettext_lazy as _ + INSTRUMENTS = ( - ('TR', _('Trumpet')), - ('TRB', _('Trombone')), - ('HRN', _('Horn')), - ('TUBA', _('Tuba')) + ("TR", _("Trumpet")), + ("TRB", _("Trombone")), + ("HRN", _("Horn")), + ("TUBA", _("Tuba")), ) @@ -24,35 +24,58 @@ def musicianSmallPictureName(musician, originalName): class Musician(models.Model): # Link to user object, contains first name and last name - user = models.OneToOneField(User, verbose_name=_("user"), on_delete=models.CASCADE) + user = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name=_("user")) - image = models.ImageField(upload_to=musicianPictureName, verbose_name=_("image")) - small_image = models.ImageField(upload_to=musicianSmallPictureName, verbose_name=_("circular thumbnail")) + image = models.ImageField( + upload_to=musicianPictureName, + verbose_name=_("image"), + blank=True, + null=True, + ) + small_image = models.ImageField( + upload_to=musicianSmallPictureName, + verbose_name=_("circular thumbnail"), + blank=True, + null=True, + ) # Properties - instrument = models.CharField(max_length=4, choices=INSTRUMENTS, blank=True, verbose_name=_("instrument")) + instrument = models.CharField( + max_length=4, choices=INSTRUMENTS, blank=True, verbose_name=_("instrument") + ) - birthday = models.DateField(null=True, verbose_name=_("birthday")) + birthday = models.DateField(null=True, blank=True, verbose_name=_("birthday")) street = models.CharField(max_length=80, blank=True, verbose_name=_("street")) city = models.CharField(max_length=40, blank=True, verbose_name=_("city")) - zip_code = models.IntegerField(null=True, verbose_name=_("zip_code")) + zip_code = models.IntegerField(null=True, blank=True, verbose_name=_("zip_code")) - phone_home = models.CharField(max_length=18, blank=True, verbose_name=_("phone_home")) - phone_mobile = models.CharField(max_length=18, blank=True, verbose_name=_("phone_mobile")) - phone_work = models.CharField(max_length=18, blank=True, verbose_name=_("phone_work")) + phone_home = models.CharField( + max_length=18, blank=True, verbose_name=_("phone_home") + ) + phone_mobile = models.CharField( + max_length=18, blank=True, verbose_name=_("phone_mobile") + ) + phone_work = models.CharField( + max_length=18, blank=True, verbose_name=_("phone_work") + ) - position = models.IntegerField(null=True, verbose_name=_("Position")) + position = models.IntegerField(null=True, blank=True, verbose_name=_("Position")) - public_description = models.TextField(blank=True, verbose_name=_("public_description")) + public_description = models.TextField( + blank=True, verbose_name=_("public_description") + ) + + class Meta: + ordering = ["position", "user__username"] @property def isDeepBrass(self): - return self.instrument == 'TRB' or self.instrument == "EUPH" or self.instrument == "TUBA" or self.instrument == "HRN" + return self.instrument in ("TRB", "EUPH", "TUBA", "HRN") @property def isHighBrass(self): - return self.instrument == 'TR' + return self.instrument == "TR" - def __unicode__(self): + def __str__(self): return self.user.username diff --git a/musicians/templates/musicians/addressbook.html b/musicians/templates/musicians/addressbook.html index 732f6e5..832dbfd 100644 --- a/musicians/templates/musicians/addressbook.html +++ b/musicians/templates/musicians/addressbook.html @@ -1,178 +1,236 @@ -{% extends "website/base.html" %} - - -{% load sekizai_tags staticfiles %} - - - -{% block content %} - -{% addtoblock "css" strip %}{% endaddtoblock %} - -{% addtoblock "css" strip %}{% endaddtoblock %} -{% addtoblock "css" strip %}{% endaddtoblock %} - -{% addtoblock "css" %} +{% extends "website/base.html" %} {% load sekizai_tags static %} {% block content %} {% addtoblock "css" strip %}{% endaddtoblock %} {% addtoblock "css" strip %}{% endaddtoblock %} {% addtoblock "css" strip %}{% endaddtoblock %} {% addtoblock "css" %} -{% endaddtoblock %} - - -{% addtoblock "js" strip %} {% endaddtoblock %} - - -{% addtoblock "js" %} +{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "js" %} + + // filter items when filter link is clicked + $filters.click(function () { + $filters.removeClass("active"); + $(this).addClass("active"); + var selector = $(this).data("filter"); + $container.isotope({ filter: selector }); + return false; + }); + }); + {% endaddtoblock %} -
    -
    -
    -

    Adressbuch

    +
    +
    +

    Adressbuch

    -
    -
    -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    +
    +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    - {% endblock %} - diff --git a/musicians/templates/musicians/login.html b/musicians/templates/musicians/login.html index 71f37e5..a06722f 100644 --- a/musicians/templates/musicians/login.html +++ b/musicians/templates/musicians/login.html @@ -1,101 +1,120 @@ -{% extends "website/base.html" %} +{% extends "website/base.html" %} {% load sekizai_tags static %} {% block menu_contents %} {% endblock %} {% block content %} {% addtoblock "css" strip %}{% endaddtoblock %} {% addtoblock "css" strip %} +{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "css" strip %} +{% endaddtoblock %} {% addtoblock "css" strip %} +{% endaddtoblock %} + +{% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "css" strip %} +{% endaddtoblock %} -{% load sekizai_tags staticfiles %} + +{% addtoblock "js" %} + +{% endaddtoblock %} +
    +
    +
    +
    +

    Login zum internen Bereich

    +

    Hier dürfen nur Ensemble Mitglieder rein...

    +
    + -{% block content %} - -{% addtoblock "css" strip %}{% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} - - -{% addtoblock "js" strip %} {% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} - - -{% addtoblock "js" strip %} {% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} - - - - - {% addtoblock "js" %} - - {% endaddtoblock %} - - - -
    -
    -
    -
    -

    Login zum internen Bereich

    -

    Hier dürfen nur Ensemble Mitglieder rein...

    +
    +
    +
    - - - -
    -
    - -
    - -
    -
    +
    {% endblock %} - diff --git a/musicians/urls.py b/musicians/urls.py index d93cf29..0410deb 100644 --- a/musicians/urls.py +++ b/musicians/urls.py @@ -1,12 +1,14 @@ -from django.conf.urls import url +from django.urls import path -import musicians.views +from . import views + +app_name = "musicians" urlpatterns = [ - url(r'^$', musicians.views.addressbook), - url(r'^profile$', musicians.views.own_profile), - url(r'^changePassword/$', musicians.views.change_password), - url(r'^login/$', musicians.views.login_view), - url(r'^login/usernames$', musicians.views.userlistForAutocompletion), - url(r'^logout/$', musicians.views.logout_view), + path("", views.addressbook, name="addressbook"), + path("profile/", views.own_profile, name="profile"), + path("changePassword/", views.change_password, name="change_password"), + path("login/", views.login_view, name="login"), + path("login/usernames/", views.userlistForAutocompletion, name="usernames"), + path("logout/", views.logout_view, name="logout"), ] diff --git a/musicians/views.py b/musicians/views.py index c81f8ce..9e66805 100644 --- a/musicians/views.py +++ b/musicians/views.py @@ -1,10 +1,17 @@ -from django.views.generic.edit import UpdateView -from django.views.generic import ListView -from musicians.models import Musician +import json +from datetime import timedelta + from django import forms -from django.http import HttpResponseRedirect -from django.shortcuts import render -from django.shortcuts import get_object_or_404 +from django.contrib.auth import authenticate, login, logout +from django.contrib.auth.models import User +from django.contrib.auth.views import PasswordChangeView +from django.http import HttpResponse, HttpResponseRedirect +from django.shortcuts import get_object_or_404, redirect, render +from django.urls import reverse_lazy +from django.views.generic import ListView +from django.views.generic.edit import UpdateView + +from .models import Musician class MusicianList(ListView): @@ -14,32 +21,49 @@ class MusicianList(ListView): class UserEditForm(forms.ModelForm): email = forms.EmailField() - def __init__(self, *args, **kw): - - if 'instance' in kw.keys(): - user = kw['instance'].user - initVals = {'email': user.email} - if not 'initial' in kw.keys(): - kw['initial'] = initVals - else: - kw['initial'].update(initVals) - - super(UserEditForm, self).__init__(*args, **kw) - - self.fields.keyOrder.remove('email') - - self.fields.keyOrder.insert(2, 'email') - - def save(self): - if self.is_valid(): - super(UserEditForm, self).save() - self.instance.user.email = self.cleaned_data['email'] - self.instance.user.save() - class Meta: model = Musician - exclude = ['user', 'image', 'small_image', 'instrument', 'position', 'public_description'] - # fields = '__all__' + exclude = [ + "user", + "image", + "small_image", + "instrument", + "position", + "public_description", + ] + + def __init__(self, *args, **kw): + if "instance" in kw: + user = kw["instance"].user + initVals = {"email": user.email} + if "initial" not in kw: + kw["initial"] = initVals + else: + kw["initial"].update(initVals) + + super().__init__(*args, **kw) + + # Reorder fields to put email near the top + if "email" in self.fields: + email_field = self.fields.pop("email") + new_fields = {} + field_names = list(self.fields.keys()) + # Insert email at position 2 (after first two fields) + for i, name in enumerate(field_names): + if i == 2: + new_fields["email"] = email_field + new_fields[name] = self.fields[name] + if "email" not in new_fields: + new_fields["email"] = email_field + self.fields = new_fields + + def save(self, commit=True): + if self.is_valid(): + instance = super().save(commit=commit) + self.instance.user.email = self.cleaned_data["email"] + self.instance.user.save() + return instance + return None def own_profile(request): @@ -49,30 +73,31 @@ def own_profile(request): def user_edit(request, username): musician = get_object_or_404(Musician, user__username=username) - if request.method == 'POST': # If the form has been submitted... - form = UserEditForm(request.POST) # A form bound to the POST data - form.instance = musician - if form.is_valid(): # All validation rules pass + if request.method == "POST": + form = UserEditForm(request.POST, instance=musician) + if form.is_valid(): form.save() - return HttpResponseRedirect('/') # Redirect after POST + return HttpResponseRedirect("/") else: form = UserEditForm(instance=musician) - return render(request, 'musicians/musician_edit.html', {'form': form, 'musician': musician}) + return render( + request, "musicians/musician_edit.html", {"form": form, "musician": musician} + ) class MusicianUpdate(UpdateView): model = Musician - # fields = [] template_name = "musicians/musician_edit.html" - success_url = '/books/' + success_url = "/books/" + fields = "__all__" def addressbook(request): - context = dict() - context['musicians'] = Musician.objects.all().order_by('user__first_name') + context = {} + context["musicians"] = Musician.objects.all().order_by("user__first_name") - return render(request, 'musicians/addressbook.html', context) + return render(request, "musicians/addressbook.html", context) ############################################################################################################ @@ -80,17 +105,13 @@ def addressbook(request): ############################################################################################################ -from django.contrib.auth.views import PasswordChangeView -from django.contrib.auth import authenticate, login, logout -from django.shortcuts import redirect -from django.http import HttpResponse -import json -from django.contrib.auth.models import User -from datetime import timedelta +class ChangePasswordView(PasswordChangeView): + template_name = "musicians/change_password.html" + success_url = reverse_lazy("website:home") def change_password(request): - return PasswordChangeView.as_view(request, "musicians/change_password.html", post_change_redirect="/") + return ChangePasswordView.as_view()(request) def logout_view(request): @@ -100,47 +121,44 @@ def logout_view(request): def userlistForAutocompletion(request): result = [u.username for u in User.objects.all()] - return HttpResponse(json.dumps(result), content_type='application/json') + return HttpResponse(json.dumps(result), content_type="application/json") def login_view(request): - if request.method == 'POST': # If the form has been submitted... - raise_first_letter = lambda s: s[:1].upper() + s[1:] if s else '' - username = raise_first_letter(request.POST['username']) - password = request.POST['password'] - user = authenticate(username=username, password=password) - result = dict() - result['err'] = "" + if request.method == "POST": + raiseFirstLetter = lambda s: s[:1].upper() + s[1:] if s else "" + username = raiseFirstLetter(request.POST.get("username", "")) + password = request.POST.get("password", "") + user = authenticate(request, username=username, password=password) + result = {} + result["err"] = "" if user is not None: if user.is_active: - if not request.POST.get('remember', None): + if not request.POST.get("remember", None): # Expire in one year - request.session.set_expiry(timedelta(weeks=52).seconds) + request.session.set_expiry(timedelta(weeks=52)) else: # Expire on browser close request.session.set_expiry(0) login(request, user) - result['redirect'] = "/" - print("Setting Redirect") - if 'next' in request.POST: - result['redirect'] = request.POST["next"] - print("Using " + request.POST["next"]) + result["redirect"] = "/" + if "next" in request.POST: + result["redirect"] = request.POST["next"] else: - result['err'] = "Dein Account wurde deaktiviert." - # Return a 'disabled account' error message + result["err"] = "Dein Account wurde deaktiviert." else: - result['err'] = "Falscher Benutzername oder falsches Kennwort." + result["err"] = "Falscher Benutzername oder falsches Kennwort." - return HttpResponse(json.dumps(result), content_type='application/json') + return HttpResponse(json.dumps(result), content_type="application/json") else: # Check if user already logged in if request.user.is_authenticated: return redirect("/") - if 'next' in request.GET: - nextPage = request.GET['next'] + if "next" in request.GET: + nextPage = request.GET["next"] else: nextPage = "/" - return render(request, 'musicians/login.html', {'next': nextPage}) + return render(request, "musicians/login.html", {"next": nextPage}) diff --git a/requirements.txt b/requirements.txt index 723ecd2..4292616 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,22 +1,24 @@ -cachetools==3.0.0 -Django==2.1.4 -django-classy-tags==0.8.0 -django-crispy-forms==1.7.2 -django-sekizai==0.10.0 -djangorestframework==3.9.0 -google-api-python-client==1.7.6 -google-auth==1.6.2 -google-auth-httplib2==0.0.3 -gunicorn==19.9.0 -httplib2==0.12.0 -oauth2client==4.1.3 -Pillow==5.3.0 -pkg-resources==0.0.0 -pyasn1==0.4.4 -pyasn1-modules==0.2.2 -pytz==2018.7 -reportlab==3.5.12 -rsa==4.0 -six==1.12.0 -uritemplate==3.0.0 -whitenoise==4.1.2 +# Django and core +Django>=5.1,<5.2 + +# Forms +django-crispy-forms>=2.3 +crispy-bootstrap5>=2024.2 + +# Template utilities +django-sekizai>=4.1 + +# REST API +djangorestframework>=3.15 + +# Google Calendar integration +google-api-python-client>=2.140 +google-auth-oauthlib>=1.2 +google-auth-httplib2>=0.2 +httplib2>=0.22 + +# PDF generation (for scoremanager) +reportlab>=4.2 + +# Image handling +Pillow>=10.4 diff --git a/scoremanager/migrations/0001_initial.py b/scoremanager/migrations/0001_initial.py new file mode 100644 index 0000000..fdef5fd --- /dev/null +++ b/scoremanager/migrations/0001_initial.py @@ -0,0 +1,95 @@ +# Generated by Django 5.1.15 on 2026-03-30 19:15 + +import django.db.models.deletion +import scoremanager.models +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Piece', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255, unique=True, verbose_name='title')), + ('composer', models.CharField(blank=True, max_length=255, verbose_name='composer')), + ('repertoire_nr', models.IntegerField(blank=True, default=None, null=True, unique=True)), + ], + options={ + 'ordering': ['title'], + 'permissions': (('manage_scores', 'Administrate and manage scores'),), + }, + ), + migrations.CreateModel( + name='BookLocation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('book', models.CharField(max_length=100, verbose_name='Buch')), + ('page', models.IntegerField(verbose_name='page')), + ('piece', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scoremanager.piece')), + ], + options={ + 'ordering': ['book', 'page'], + }, + ), + migrations.CreateModel( + name='Score', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('score_type', models.CharField(max_length=100, verbose_name='score type')), + ('file', models.FileField(upload_to=scoremanager.models.score_filename, verbose_name='file')), + ('piece', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scores', to='scoremanager.piece')), + ('uploaded_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='uploaded_by')), + ], + options={ + 'ordering': ['score_type'], + 'unique_together': {('piece', 'score_type')}, + }, + ), + migrations.CreateModel( + name='Recording', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('artist', models.CharField(max_length=100, verbose_name='Artist')), + ('file', models.FileField(upload_to=scoremanager.models.recording_filename, verbose_name='file')), + ('piece', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='recordings', to='scoremanager.piece')), + ('uploaded_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='uploaded_by')), + ], + options={ + 'ordering': ['artist'], + 'unique_together': {('piece', 'artist')}, + }, + ), + migrations.CreateModel( + name='ScoreUserMapping', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('piece', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scoremanager.piece')), + ('score', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scoremanager.score')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('piece', 'user')}, + }, + ), + migrations.CreateModel( + name='YoutubeRecording', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('link', models.CharField(max_length=300)), + ('piece', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='youtubeLinks', to='scoremanager.piece')), + ('uploaded_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='uploaded_by')), + ], + options={ + 'unique_together': {('link', 'piece')}, + }, + ), + ] diff --git a/scoremanager/migrations/__init__.py b/scoremanager/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scoremanager/models.py b/scoremanager/models.py index 97c360d..9a5c7fd 100644 --- a/scoremanager/models.py +++ b/scoremanager/models.py @@ -1,41 +1,44 @@ import os import re +from django.contrib.auth.models import User from django.db import models from django.db.models.fields.related import ForeignKey -from django.utils.translation import ugettext as _ -from django.contrib.auth.models import User from django.utils.safestring import mark_safe - +from django.utils.translation import gettext_lazy as _ ############################# Helper Functions ####################################################### def space_to_camelcase(value): + """Convert a space-separated string to camelCase.""" + def camelcase(): - yield type(value).lower + yield str.lower while True: - yield type(value).capitalize + yield str.capitalize c = camelcase() - return "".join(c.next()(x) if x else '_' for x in value.split()) + return "".join(next(c)(x) if x else "_" for x in value.split()) def score_filename(score, original_name): - fileExtension = os.path.splitext(original_name)[1] + """Generate filename for uploaded score files.""" + file_extension = os.path.splitext(original_name)[1] filename = "scores/" filename += space_to_camelcase(score.piece.title) + "/" filename += space_to_camelcase(score.score_type) - filename += fileExtension + filename += file_extension return filename -def recordingFileName(recording, originalName): - fileExtension = os.path.splitext(originalName)[1] +def recording_filename(recording, original_name): + """Generate filename for uploaded recording files.""" + file_extension = os.path.splitext(original_name)[1] filename = "recordings/" filename += space_to_camelcase(recording.piece.title) + "/" filename += space_to_camelcase(recording.artist) - filename += fileExtension + filename += file_extension return filename @@ -43,130 +46,195 @@ def recordingFileName(recording, originalName): class Piece(models.Model): + """A musical piece in the repertoire.""" + title = models.CharField(max_length=255, verbose_name=_("title"), unique=True) composer = models.CharField(max_length=255, blank=True, verbose_name=_("composer")) - repertoire_nr = models.IntegerField(null=True, blank=True, unique=True, default=None) - - def __unicode__(self): - res = self.title - return res - - def isInRepertoire(self): - return self.repertoire_nr is not None - - def get_score_for_user(self, user): - try: - return ScoreUserMapping.objects.get(user=user, score__in=self.scores.all()).score - except Piece.DoesNotExist: - if len(self.scores.all()) > 0: - return self.scores.all()[0] - else: - return None - - @staticmethod - def getRepertoire(): - return Piece.objects.filter(repertoire_nr__isnull=False).order_by('repertoire_nr') + repertoire_nr = models.IntegerField( + null=True, blank=True, unique=True, default=None + ) class Meta: - permissions = ( - ("manage_scores", "Administrate and manage scores"), + ordering = ["title"] + permissions = (("manage_scores", "Administrate and manage scores"),) + + def __str__(self): + return self.title + + def is_in_repertoire(self): + return self.repertoire_nr is not None + + # Backwards compatibility + isInRepertoire = is_in_repertoire + + def get_score_for_user(self, user): + """Get the preferred score for a user, or the first available score.""" + try: + return ScoreUserMapping.objects.get( + user=user, score__in=self.scores.all() + ).score + except ScoreUserMapping.DoesNotExist: + if self.scores.exists(): + return self.scores.first() + return None + + @staticmethod + def get_repertoire(): + """Get all pieces that are in the repertoire, ordered by repertoire number.""" + return Piece.objects.filter(repertoire_nr__isnull=False).order_by( + "repertoire_nr" ) + # Backwards compatibility + getRepertoire = get_repertoire + class BookLocation(models.Model): - piece = models.ForeignKey('Piece', on_delete=models.PROTECT) + """Location of a piece in a physical book.""" + + piece = models.ForeignKey("Piece", on_delete=models.CASCADE) book = models.CharField(max_length=100, blank=False, verbose_name=_("Buch")) page = models.IntegerField(verbose_name=_("page")) - def __unicode__(self): - return "%s, %d" % (self.book, self.page) + class Meta: + ordering = ["book", "page"] + + def __str__(self): + return f"{self.book}, {self.page}" class Score(models.Model): - piece = ForeignKey('Piece', related_name="scores", on_delete=models.PROTECT) - score_type = models.CharField(max_length=100, verbose_name="score type") # for example partitur, unterstimmen ... + """A score file for a piece (e.g., full score, parts, etc.).""" + + piece = ForeignKey("Piece", on_delete=models.CASCADE, related_name="scores") + score_type = models.CharField(max_length=100, verbose_name="score type") file = models.FileField(upload_to=score_filename, verbose_name=_("file")) - uploaded_by = ForeignKey(User, verbose_name=_("uploaded_by"), on_delete=models.PROTECT) + uploaded_by = ForeignKey( + User, on_delete=models.SET_NULL, null=True, verbose_name=_("uploaded_by") + ) + + class Meta: + unique_together = (("piece", "score_type"),) + ordering = ["score_type"] + + def __str__(self): + return f"{self.piece.title} - {self.score_type}" @property def image_file_name(self): + """Get the path for the cached image preview of this score.""" return os.path.splitext("image_cache/" + str(self.file))[0] + ".jpg" @staticmethod def pdf2jpg(source_file, target_file, resolution=100, crop=15): - from wand.image import Image - ret = True + """Convert a PDF to a JPG preview image.""" try: - with Image(filename=source_file, resolution=(resolution, resolution)) as img: - img.crop(crop, crop, width=img.width - 2 * crop, height=int(0.5 * img.height) - 2 * crop) - img.format = 'jpeg' - img.save(filename=target_file) - except Exception as e: - print(e) - ret = False + from wand.image import Image - return ret + with Image( + filename=source_file, resolution=(resolution, resolution) + ) as img: + img.crop( + crop, + crop, + width=img.width - 2 * crop, + height=int(0.5 * img.height) - 2 * crop, + ) + img.format = "jpeg" + img.save(filename=target_file) + return True + except Exception as e: + print(f"Error converting PDF to JPG: {e}") + return False def get_image_file(self): + """Get or create a preview image for this score.""" from django.conf import settings - inputFile = settings.MEDIA_ROOT + "/" + str(self.file) - cacheFile = settings.MEDIA_ROOT + "/" + str(self.image_file_name) + input_file = settings.MEDIA_ROOT + "/" + str(self.file) + cache_file = settings.MEDIA_ROOT + "/" + str(self.image_file_name) + # Create a jpg for this score, if it does not exist yet - if not os.path.exists(cacheFile): - if not os.path.exists(os.path.dirname(cacheFile)): - os.makedirs(os.path.dirname(cacheFile)) - Score.pdf2jpg(inputFile, cacheFile) + if not os.path.exists(cache_file): + cache_dir = os.path.dirname(cache_file) + if not os.path.exists(cache_dir): + os.makedirs(cache_dir) + Score.pdf2jpg(input_file, cache_file) return self.image_file_name def is_active_score(self, user): - return len(ScoreUserMapping.objects.filter(score=self, user=user)) > 0 - - class Meta: - unique_together = (("piece", "score_type"),) - ordering = ['score_type'] + """Check if this is the active score for a user.""" + return ScoreUserMapping.objects.filter(score=self, user=user).exists() class Recording(models.Model): - piece = ForeignKey('Piece', related_name='recordings', on_delete=models.PROTECT) + """An audio recording of a piece.""" + + piece = ForeignKey("Piece", on_delete=models.CASCADE, related_name="recordings") artist = models.CharField(max_length=100, verbose_name=_("Artist")) - file = models.FileField(upload_to=recordingFileName, verbose_name=_("file")) - uploaded_by = ForeignKey(User, verbose_name=_("uploaded_by"), on_delete=models.PROTECT) + file = models.FileField(upload_to=recording_filename, verbose_name=_("file")) + uploaded_by = ForeignKey( + User, on_delete=models.SET_NULL, null=True, verbose_name=_("uploaded_by") + ) class Meta: unique_together = (("piece", "artist"),) - ordering = ['artist'] + ordering = ["artist"] + + def __str__(self): + return f"{self.piece.title} - {self.artist}" class YoutubeRecording(models.Model): - piece = models.ForeignKey('Piece', related_name="youtubeLinks", on_delete=models.PROTECT) - link = models.CharField(max_length=300, blank=False) - uploaded_by = ForeignKey(User, verbose_name=_("uploaded_by"), on_delete=models.PROTECT) + """A YouTube link for a piece.""" - youtubeRegex = re.compile(u'(?:https://)?(?:http://)?www.youtube.(?:com|de)/watch\?v=(?P[-\w]*)') + piece = models.ForeignKey( + "Piece", on_delete=models.CASCADE, related_name="youtubeLinks" + ) + link = models.CharField(max_length=300, blank=False) + uploaded_by = ForeignKey( + User, on_delete=models.SET_NULL, null=True, verbose_name=_("uploaded_by") + ) + + youtube_regex = re.compile( + r"(?:https://)?(?:http://)?www\.youtube\.(?:com|de)/watch\?v=(?P[-\w]*)" + ) + + class Meta: + unique_together = (("link", "piece"),) + + def __str__(self): + return f"{self.piece.title} - YouTube" @property def embed_html(self): + """Generate embeddable HTML for this YouTube video.""" replacement = """ -
    +
    + +
    """ - return mark_safe(YoutubeRecording.youtubeRegex.sub(replacement, self.link)) - - class Meta: - unique_together = ("link", "piece") + return mark_safe(self.youtube_regex.sub(replacement, self.link)) class ScoreUserMapping(models.Model): - score = ForeignKey('Score', on_delete=models.PROTECT) - user = models.OneToOneField(User, on_delete=models.PROTECT) - piece = ForeignKey('Piece', on_delete=models.PROTECT) + """Maps a user's preferred score for each piece.""" + + score = ForeignKey("Score", on_delete=models.CASCADE) + user = models.ForeignKey(User, on_delete=models.CASCADE) + piece = ForeignKey("Piece", on_delete=models.CASCADE) + + class Meta: + unique_together = (("piece", "user"),) + + def __str__(self): + return f"{self.user.username} -> {self.score}" @staticmethod def add_user_score_mapping(score, user): + """Set the preferred score for a user for a given piece.""" piece = score.piece ScoreUserMapping.objects.filter(user=user, piece=piece).delete() ScoreUserMapping.objects.create(score=score, user=user, piece=piece) - - class Meta: - unique_together = ("piece", "user") diff --git a/scoremanager/pdf_views.py b/scoremanager/pdf_views.py index 974fefc..45f621b 100644 --- a/scoremanager/pdf_views.py +++ b/scoremanager/pdf_views.py @@ -1,95 +1,157 @@ -# ----------------------------- Pdf Views ------------------------------------------ - -from django.http import HttpResponse -from scoremanager.models import Piece - -from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate, Flowable, Table, PageBreak, NextPageTemplate -from reportlab.lib import pagesizes, units, utils -from reportlab.lib.colors import Color +""" +PDF generation views for the score manager application. +""" import os -class RepertoireDocTemplate( BaseDocTemplate ): - def __init__(self, *args, **kwargs ): - BaseDocTemplate.__init__(self,*args, **kwargs) +from django.http import HttpResponse +from reportlab.lib import pagesizes, units, utils +from reportlab.lib.colors import Color +from reportlab.platypus import ( + BaseDocTemplate, + Flowable, + Frame, + NextPageTemplate, + PageBreak, + PageTemplate, + Table, +) - self.pagesize = kwargs['pagesize'] +from .models import Piece - leftBorder = 1 * units.cm - rightBorder = 1 * units.cm - topBorder = 3 * units.cm - bottomBorder = 1 * units.cm - frameWidth = (self.pagesize[0] - rightBorder - leftBorder ) /2 - frameHeight = (self.pagesize[1] - topBorder - bottomBorder ) +class RepertoireDocTemplate(BaseDocTemplate): + """Document template for repertoire PDFs with header and two-column layout.""" - leftColumn = Frame( leftBorder, bottomBorder, frameWidth, frameHeight, showBoundary=0 ) - rightColumn = Frame( leftBorder+frameWidth , bottomBorder, frameWidth, frameHeight, showBoundary=0 ) + def __init__(self, *args, **kwargs): + BaseDocTemplate.__init__(self, *args, **kwargs) - tocTemplate = PageTemplate( id='TOC', frames=[leftColumn,rightColumn], onPage=RepertoireDocTemplate._drawHeader ) - fullPageTemplate = PageTemplate( id='FullPage', frames = [ Frame(0,0, self.pagesize[0], self.pagesize[1] ) ] ) + self.pagesize = kwargs["pagesize"] - self.addPageTemplates( [ tocTemplate, fullPageTemplate ] ) + left_border = 1 * units.cm + right_border = 1 * units.cm + top_border = 3 * units.cm + bottom_border = 1 * units.cm + + frame_width = (self.pagesize[0] - right_border - left_border) / 2 + frame_height = self.pagesize[1] - top_border - bottom_border + + left_column = Frame( + left_border, bottom_border, frame_width, frame_height, showBoundary=0 + ) + right_column = Frame( + left_border + frame_width, + bottom_border, + frame_width, + frame_height, + showBoundary=0, + ) + + toc_template = PageTemplate( + id="TOC", + frames=[left_column, right_column], + onPage=RepertoireDocTemplate._draw_header, + ) + full_page_template = PageTemplate( + id="FullPage", + frames=[Frame(0, 0, self.pagesize[0], self.pagesize[1])], + ) + + self.addPageTemplates([toc_template, full_page_template]) @staticmethod - def _drawHeader(canvas,document): + def _draw_header(canvas, document): + """Draw the header with logo and gradient background.""" + current_path = os.path.dirname(os.path.realpath(__file__)) + logo_image_file = current_path + "/static/pdfImg/logo.png" + bg_image_file = current_path + "/static/pdfImg/body_bg.jpg" - currentPath = os.path.dirname(os.path.realpath(__file__)) - logoImageFile = currentPath + "/static/pdfImg/logo.png" - bgImageFile = currentPath + "/static/pdfImg/body_bg.jpg" - - #Gradient - titleAreaHeight = 2 * units.cm - gradientColors = [ Color(0.1,0.1,0.1), Color(0.2,0.2,0.2)] + # Gradient + title_area_height = 2 * units.cm + gradient_colors = [Color(0.1, 0.1, 0.1), Color(0.2, 0.2, 0.2)] ps = document.pagesize - gradientStart = ( ps[0]/2, ps[1] ) - gradientEnd = ( ps[0]/2, ps[1] - titleAreaHeight) - canvas.linearGradient( gradientStart[0],gradientStart[1], gradientEnd[0], gradientEnd[1],gradientColors, extend=False ) - titleAreaMidY = 0.5 * ( gradientStart[1] + gradientEnd[1] ) + gradient_start = (ps[0] / 2, ps[1]) + gradient_end = (ps[0] / 2, ps[1] - title_area_height) + canvas.linearGradient( + gradient_start[0], + gradient_start[1], + gradient_end[0], + gradient_end[1], + gradient_colors, + extend=False, + ) + title_area_mid_y = 0.5 * (gradient_start[1] + gradient_end[1]) # Draw Logo - logoImg = utils.ImageReader( logoImageFile ) - logoSize = logoImg.getSize() - logoFraction = 0.6 - logoSize = (logoFraction * logoSize[0], logoFraction*logoSize[1]) - logoPosition = ( ps[0] - 5*units.cm, titleAreaMidY - 0.5*logoSize[1] ) - canvas.drawImage( logoImg, logoPosition[0], logoPosition[1], width=logoSize[0], height=logoSize[1], mask=Color(0,0,0) ) + if os.path.exists(logo_image_file): + logo_img = utils.ImageReader(logo_image_file) + logo_size = logo_img.getSize() + logo_fraction = 0.6 + logo_size = (logo_fraction * logo_size[0], logo_fraction * logo_size[1]) + logo_position = ( + ps[0] - 5 * units.cm, + title_area_mid_y - 0.5 * logo_size[1], + ) + canvas.drawImage( + logo_img, + logo_position[0], + logo_position[1], + width=logo_size[0], + height=logo_size[1], + mask=Color(0, 0, 0), + ) # Draw Title text = canvas.beginText() - text.setTextOrigin( 1 * units.cm, titleAreaMidY-25/2 ) - text.setFillColorRGB( 0.95,0.95,0.95 ) - text.setFont( 'Helvetica', 25 ) - text.textLine( "Inhaltsverzeichnis" ) - canvas.drawText( text ) + text.setTextOrigin(1 * units.cm, title_area_mid_y - 25 / 2) + text.setFillColorRGB(0.95, 0.95, 0.95) + text.setFont("Helvetica", 25) + text.textLine("Inhaltsverzeichnis") + canvas.drawText(text) # Draw Background - bgImage = utils.ImageReader( bgImageFile ) - bgImageSize = bgImage.getSize() - curPos = [0, gradientEnd[1]-bgImageSize[1] ] - while curPos[1] > -bgImageSize[1]: - curPos[0] = 0 - while curPos[0] < ps[0]: - canvas.drawImage( bgImage, curPos[0], curPos[1] ) - curPos[0] += bgImageSize[0] - - curPos[1] -= bgImageSize[1] + if os.path.exists(bg_image_file): + bg_image = utils.ImageReader(bg_image_file) + bg_image_size = bg_image.getSize() + cur_pos = [0, gradient_end[1] - bg_image_size[1]] + while cur_pos[1] > -bg_image_size[1]: + cur_pos[0] = 0 + while cur_pos[0] < ps[0]: + canvas.drawImage(bg_image, cur_pos[0], cur_pos[1]) + cur_pos[0] += bg_image_size[0] + cur_pos[1] -= bg_image_size[1] class PdfImage(Flowable): - """PdfImage wraps the first page from a PDF file as a Flowable - which can be included into a ReportLab Platypus document. - Based on the vectorpdf extension in rst2pdf (http://code.google.com/p/rst2pdf/)""" + """ + PdfImage wraps the first page from a PDF file as a Flowable + which can be included into a ReportLab Platypus document. - def __init__(self, filename_or_object, page=0, width=None, height=None, kind='direct'): - from pdfrw import PdfReader - from pdfrw.buildxobj import pagexobj + Based on the vectorpdf extension in rst2pdf (http://code.google.com/p/rst2pdf/) + """ + + def __init__( + self, filename_or_object, page=0, width=None, height=None, kind="direct" + ): + Flowable.__init__(self) + + try: + from pdfrw import PdfReader + from pdfrw.buildxobj import pagexobj + except ImportError: + raise ImportError( + "pdfrw is required for PDF embedding. Install it with: pip install pdfrw" + ) # If using StringIO buffer, set pointer to beginning - if hasattr(filename_or_object, 'read'): + if hasattr(filename_or_object, "read"): filename_or_object.seek(0) - page = PdfReader(filename_or_object, decompress=False).pages[page] - self.xobj = pagexobj(page) + + pdf_pages = PdfReader(filename_or_object, decompress=False).pages + if page >= len(pdf_pages): + page = 0 + + self.xobj = pagexobj(pdf_pages[page]) self.imageWidth = width self.imageHeight = height x1, y1, x2, y2 = self.xobj.BBox @@ -99,36 +161,42 @@ class PdfImage(Flowable): self.imageWidth = self._w if not self.imageHeight: self.imageHeight = self._h - self.__ratio = float(self.imageWidth)/self.imageHeight - if kind in ['direct','absolute'] or width==None or height==None: + + self.__ratio = float(self.imageWidth) / self.imageHeight + + if kind in ["direct", "absolute"] or width is None or height is None: self.drawWidth = width or self.imageWidth self.drawHeight = height or self.imageHeight - elif kind in ['bound','proportional']: - factor = min(float(width)/self._w,float(height)/self._h) - self.drawWidth = self._w*factor - self.drawHeight = self._h*factor + elif kind in ["bound", "proportional"]: + factor = min(float(width) / self._w, float(height) / self._h) + self.drawWidth = self._w * factor + self.drawHeight = self._h * factor def wrap(self, aW, aH): return self.drawWidth, self.drawHeight def drawOn(self, canv, x, y, _sW=0): - from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT - from pdfrw.toreportlab import makerl + from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT - if _sW > 0 and hasattr(self, 'hAlign'): + try: + from pdfrw.toreportlab import makerl + except ImportError: + raise ImportError("pdfrw is required for PDF embedding.") + + if _sW > 0 and hasattr(self, "hAlign"): a = self.hAlign - if a in ('CENTER', 'CENTRE', TA_CENTER): - x += 0.5*_sW - elif a in ('RIGHT', TA_RIGHT): + if a in ("CENTER", "CENTRE", TA_CENTER): + x += 0.5 * _sW + elif a in ("RIGHT", TA_RIGHT): x += _sW - elif a not in ('LEFT', TA_LEFT): + elif a not in ("LEFT", TA_LEFT): raise ValueError("Bad hAlign value " + str(a)) xobj = self.xobj xobj_name = makerl(canv._doc, xobj) - xscale = self.drawWidth/self._w - yscale = self.drawHeight/self._h + xscale = self.drawWidth / self._w + yscale = self.drawHeight / self._h x -= xobj.BBox[0] * xscale y -= xobj.BBox[1] * yscale @@ -141,81 +209,97 @@ class PdfImage(Flowable): class Bookmark(Flowable): - """ Utility class to display PDF bookmark. """ + """Utility class to display PDF bookmark.""" + def __init__(self, title, key): self.title = title self.key = key Flowable.__init__(self) def wrap(self, availWidth, availHeight): - """ Doesn't take up any space. """ + """Doesn't take up any space.""" return (0, 0) def draw(self): # set the bookmark outline to show when the file's opened self.canv.showOutline() - # step 1: put a bookmark on the + # step 1: put a bookmark on the page self.canv.bookmarkPage(self.key) # step 2: put an entry in the bookmark outline self.canv.addOutlineEntry(self.title, self.key, 0, 0) -def repertoire_pdf( request ): - response = HttpResponse(content_type='application/pdf') - response['Content-Disposition'] = 'attachment; filename="Repertoire.pdf"' +def repertoire_pdf(request): + """Generate a PDF containing the full repertoire with scores.""" + response = HttpResponse(content_type="application/pdf") + response["Content-Disposition"] = 'attachment; filename="Repertoire.pdf"' - # Create the PDF object, using the response object as its "file. + # Create the PDF object, using the response object as its "file" doc = RepertoireDocTemplate(response, pagesize=pagesizes.A4) elements = [] - elements.append( Bookmark("Inhaltsverzeichnis", "Contents") ) - #TOC + elements.append(Bookmark("Inhaltsverzeichnis", "Contents")) + + # Table of Contents data = [] - for piece in Piece.getRepertoire(): - data.append( [ "%d %s" % ( piece.repertoire_nr, piece.title ) ] ) - table = Table(data) - table.hAlign = "LEFT" - elements.append(table) + for piece in Piece.get_repertoire(): + data.append([f"{piece.repertoire_nr} {piece.title}"]) + if data: + table = Table(data) + table.hAlign = "LEFT" + elements.append(table) - elements.append( NextPageTemplate('FullPage') ) + elements.append(NextPageTemplate("FullPage")) elements.append(PageBreak()) - pagesize=pagesizes.A4 - for piece in Piece.getRepertoire(): - score = piece.get_score_for_user( request.user ) + + pagesize = pagesizes.A4 + for piece in Piece.get_repertoire(): + score = piece.get_score_for_user(request.user) + if score is None: + continue + filename = score.file - bookmarkTitle = "%02d %s - %s " % ( piece.repertoire_nr, piece.title, score.score_type ) - elements.append( Bookmark( bookmarkTitle, str(piece.id) ) ) - - #TODO support also multiple pages!! - image_flowable = PdfImage( filename, 0, width=pagesize[0]*0.98, height=pagesize[1] *0.98 ) - image_flowable.hAlign = "CENTER" - elements.append( image_flowable ) + bookmark_title = ( + f"{piece.repertoire_nr:02d} {piece.title} - {score.score_type}" + ) + elements.append(Bookmark(bookmark_title, str(piece.id))) + try: + # TODO: support multiple pages + image_flowable = PdfImage( + filename, 0, width=pagesize[0] * 0.98, height=pagesize[1] * 0.98 + ) + image_flowable.hAlign = "CENTER" + elements.append(image_flowable) + except Exception as e: + # Skip this score if PDF processing fails + print(f"Error processing PDF for {piece.title}: {e}") + continue doc.build(elements) return response +def repertoire_toc(request): + """Generate a PDF containing only the table of contents.""" + response = HttpResponse(content_type="application/pdf") + response["Content-Disposition"] = 'attachment; filename="Inhaltsverzeichnis.pdf"' -def repertoire_toc( request ): - response = HttpResponse(content_type='application/pdf') - response['Content-Disposition'] = 'attachment; filename="Inhaltsverzeichnis.pdf"' - - # Create the PDF object, using the response object as its "file. - doc = RepertoireDocTemplate(response,pagesize=pagesizes.A4 ) + # Create the PDF object, using the response object as its "file" + doc = RepertoireDocTemplate(response, pagesize=pagesizes.A4) elements = [] data = [] - for piece in Piece.getRepertoire(): - data.append( [ "%d %s" % ( piece.repertoire_nr, piece.title ) ] ) + for piece in Piece.get_repertoire(): + data.append([f"{piece.repertoire_nr} {piece.title}"]) - table = Table(data) - table.hAlign = "LEFT" - elements.append(table) + if data: + table = Table(data) + table.hAlign = "LEFT" + elements.append(table) doc.build(elements) return response - diff --git a/scoremanager/templates/scoremanager/list_repertoire.html b/scoremanager/templates/scoremanager/list_repertoire.html index 06c2b03..936e407 100644 --- a/scoremanager/templates/scoremanager/list_repertoire.html +++ b/scoremanager/templates/scoremanager/list_repertoire.html @@ -1,133 +1,130 @@ - {% extends "website/base.html" %} {% load sekizai_tags staticfiles %} +{% extends "website/base.html" %} {% load sekizai_tags static %} {% block content %} {% addtoblock "css" %} + {% endaddtoblock %} +
    +
    +
    +
    +

    Repertoire

    - -
    -
    - -
    - -
    - -

    Repertoire

    - - - - - - - - - - {% for piece in repertoire %} - - - - - - - - {% endfor %} -
    # Stück
    - {{ piece.repertoire_nr }} - - - {{ piece.title }} - - - {{ piece.booklocation }} -
    -
    + + + + + + + + + {% for piece in repertoire %} + + + + + + + + {% endfor %} +
    #Stück
    {{ piece.repertoire_nr }} + + {{ piece.title }} + + {{ piece.booklocation }}
    +
    + + - +
    +
    +
    +
    - -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/scoremanager/templates/scoremanager/manage_repertoire.html b/scoremanager/templates/scoremanager/manage_repertoire.html index 9248560..9c39655 100644 --- a/scoremanager/templates/scoremanager/manage_repertoire.html +++ b/scoremanager/templates/scoremanager/manage_repertoire.html @@ -1,284 +1,282 @@ - {% extends "website/base.html" %} {% load sekizai_tags staticfiles %} +{% extends "website/base.html" %} {% load sekizai_tags static %} {% block content %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "js" strip %} + +{% endaddtoblock %} {% addtoblock "css" strip %} + +{% endaddtoblock %} {% addtoblock "css" %} + + .piecelist .composer { + font-style: italic; + font-size: 0.8em; + padding-left: 10px; + } + + .piecelist .bookLocation { + font-style: italic; + font-size: 0.8em; + margin-left: 6px; + } + + .piecelist li span { + width: 100%; + } + + .pagination { + min-height: 30px; + } + .pagination li { + display: inline-block; + padding: 5px; + } + + #saveButton { + float: right; + margin-top: 20px; + } + +{% endaddtoblock %} {% addtoblock "js" %} + {% endaddtoblock %} -{% addtoblock "js" %} - -{% endaddtoblock %} -
    -
    -
    -
    -

    Repertoire Manager

    -
    -
    - -
    - -
    -

    Alle Stücke

    - - - - -
      - {% for piece in allPieces %} -
    • -

      - - {{ piece.title }} -
      - {{ piece.composer}} - {% if piece.booklocation %} ( {{piece.booklocation}} ) {% endif %} - -

      -
    • - {% endfor %} -
    - - -
    - -
    - -

    Repertoire

    - -
      - {% for piece in repertoire %} -
    1. -

      - - - {{ piece.title }} -
      - {{ piece.composer}} - {% if piece.booklocation %} ( {{piece.booklocation}} ) {% endif %} - -

      -
    2. - {% endfor %} -
    +
    +
    +
    +

    Repertoire Manager

    +
    +
    +
    +
    +

    Alle Stücke

    - + +
      + {% for piece in allPieces %} +
    • +

      + + {{ piece.title }} +
      + {{ piece.composer}} + {% if piece.booklocation %} + + ( {{piece.booklocation}} ) + + {% endif %} +

      +
    • + {% endfor %} +
    -
    -
    - -
    + +
    +
    +

    Repertoire

    + +
      + {% for piece in repertoire %} +
    1. +

      + + + {{ piece.title }} +
      + {{ piece.composer}} + {% if piece.booklocation %} + + ( {{piece.booklocation}} ) + + {% endif %} +

      +
    2. + {% endfor %} +
    + + +
    +
    +
    - -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/scoremanager/templates/scoremanager/piece_view.html b/scoremanager/templates/scoremanager/piece_view.html index 4316139..9d0c4b5 100644 --- a/scoremanager/templates/scoremanager/piece_view.html +++ b/scoremanager/templates/scoremanager/piece_view.html @@ -1,6 +1,6 @@ {% extends "website/base.html" %} -{% load sekizai_tags staticfiles %} +{% load sekizai_tags static %} {% block content %} @@ -72,7 +72,7 @@ } #section2 { - background: url("{{STATIC_URL}}img/backgrounds/aqua.jpg") no-repeat scroll 0% 0% / cover transparent; + background: url("{{STATIC_URL}}/img/backgrounds/aqua.jpg") no-repeat scroll 0% 0% / cover transparent; display: block; padding-top:50px; padding-bottom:20px; @@ -107,7 +107,7 @@ $("a.score-label").click( function() { var id = $(this).data("id"); $.ajax( { - url: "{% url 'scoremanager.views.score_user_mapping_save' %}", + url: "{% url 'scoremanager:score_user_mapping_save' %}", type: 'POST', contentType: 'application/json; charset=utf-8', data: ' { "myScore" : ' + id + ' } ', @@ -120,7 +120,7 @@ $(".delete-button").click(function() { var id = $(this).data("id"); - var scoreUrl = "{% url 'scoremanager.views.score' '4242' %}" + var scoreUrl = "{% url 'scoremanager:score' '4242' %}" if (confirm('Diesen Notensatz wirklich löschen?')) { $.ajax( { @@ -141,7 +141,7 @@ "pieceId": "{{ piece.id }}" }; $.ajax( { - url: "{% url 'scoremanager.views.youtube_link' %}", + url: "{% url 'scoremanager:youtube_link' %}", type: 'POST', contentType: 'application/json; charset=utf-8', data: JSON.stringify(data), @@ -154,7 +154,7 @@ $(".youtubeDeleteButton").click( function() { var id = $(this).data("id"); $.ajax( { - url: "{% url 'scoremanager.views.youtube_link' %}", + url: "{% url 'scoremanager:youtube_link' %}", type: 'DELETE', contentType: 'application/json; charset=utf-8', data: ' { "linkid" : ' + id + ' } ', @@ -178,7 +178,7 @@
    {% if pictureScore %} - + {% endif %} @@ -307,4 +307,4 @@
    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/scoremanager/urls.py b/scoremanager/urls.py index e603a2f..3e4b8b1 100644 --- a/scoremanager/urls.py +++ b/scoremanager/urls.py @@ -1,16 +1,25 @@ -from django.conf.urls import url +from django.urls import path -import scoremanager.views -import scoremanager.pdf_views +from . import pdf_views, views + +app_name = "scoremanager" urlpatterns = [ - url(r'^repertoireManager$', scoremanager.views.manage_repertoire), - url(r'^repertoireAjaxSave$$', scoremanager.views.manage_repertoire_ajax_save), - url(r'^$', scoremanager.views.list_repertoire), - url(r'^piece/(?P\d+)', scoremanager.views.piece_view), - url(r'^score_usermapping_save', scoremanager.views.score_user_mapping_save), - url(r'^score/(?P\d+)', scoremanager.views.score), - url(r'^youtubeLink$', scoremanager.views.youtube_link), - url(r'^inhaltsverzeichnis.pdf$', scoremanager.pdf_views.repertoire_toc), - url(r'^repertoire.pdf', scoremanager.pdf_views.repertoire_pdf), + path("", views.list_repertoire, name="list_repertoire"), + path("repertoireManager/", views.manage_repertoire, name="manage_repertoire"), + path( + "repertoireAjaxSave/", + views.manage_repertoire_ajax_save, + name="manage_repertoire_ajax_save", + ), + path("piece//", views.piece_view, name="piece_view"), + path( + "score_usermapping_save/", + views.score_user_mapping_save, + name="score_user_mapping_save", + ), + path("score//", views.score, name="score"), + path("youtubeLink/", views.youtube_link, name="youtube_link"), + path("inhaltsverzeichnis.pdf", pdf_views.repertoire_toc, name="repertoire_toc"), + path("repertoire.pdf", pdf_views.repertoire_pdf, name="repertoire_pdf"), ] diff --git a/scoremanager/views.py b/scoremanager/views.py index 68e1580..e5aeced 100644 --- a/scoremanager/views.py +++ b/scoremanager/views.py @@ -1,154 +1,211 @@ +""" +Views for the score manager application. +""" -from django.shortcuts import render -from django.http import HttpResponse -from django import forms -from django.conf import settings -from django.utils.translation import ugettext as _ -from django.core.exceptions import PermissionDenied - -from scoremanager.models import Piece, Score, Recording, ScoreUserMapping, YoutubeRecording import json import os -def manage_repertoire( request ): - context = {} - context['repertoire'] = Piece.getRepertoire() - context['allPieces' ] = Piece.objects.all().order_by( 'title' ) - return render ( request, 'scoremanager/manage_repertoire.html', context ) - - -def manage_repertoire_ajax_save( request ): - if request.is_ajax(): - if request.method == 'POST': - result = json.loads( request.body ) - - parsedResult = { int(key): value for ( key,value ) in result.items() } - Piece.objects.all().update( repertoire_nr = None) - for piece in Piece.objects.all(): - if piece.pk in parsedResult: - piece.repertoire_nr = parsedResult[piece.pk] - piece.save() - - return HttpResponse("OK") - - - - -def list_repertoire( request ): - context = { 'repertoire': Piece.getRepertoire() } - return render( request, 'scoremanager/list_repertoire.html' , context ) +from django import forms +from django.conf import settings +from django.core.exceptions import PermissionDenied +from django.http import HttpResponse +from django.shortcuts import render +from django.utils.translation import gettext_lazy as _ + +from .models import Piece, Recording, Score, ScoreUserMapping, YoutubeRecording +def manage_repertoire(request): + """View for managing the repertoire order and contents.""" + context = { + "repertoire": Piece.get_repertoire(), + "allPieces": Piece.objects.all().order_by("title"), + } + return render(request, "scoremanager/manage_repertoire.html", context) +def manage_repertoire_ajax_save(request): + """AJAX endpoint for saving repertoire order changes.""" + if request.headers.get("X-Requested-With") == "XMLHttpRequest": + if request.method == "POST": + try: + result = json.loads(request.body) + parsed_result = {int(key): value for (key, value) in result.items()} + + # Clear all repertoire numbers first + Piece.objects.all().update(repertoire_nr=None) + + # Set new repertoire numbers + for piece in Piece.objects.all(): + if piece.pk in parsed_result: + piece.repertoire_nr = parsed_result[piece.pk] + piece.save() + except (json.JSONDecodeError, ValueError) as e: + return HttpResponse(f"Error: {e}", status=400) + + return HttpResponse("OK") +def list_repertoire(request): + """View for listing the current repertoire.""" + context = {"repertoire": Piece.get_repertoire()} + return render(request, "scoremanager/list_repertoire.html", context) # ----------------------------- Piece View + Ajax views + Forms ------------------------------------------ - -def score_user_mapping_save( request ): - if request.is_ajax(): - if request.method == 'POST': - result = json.loads( request.body ) - print ( "Result " + str( result ) ) - print ( "Resulting score: " + str( result['myScore'] ) ) - result = int(result['myScore']) - ScoreUserMapping.add_user_score_mapping( user=request.user, score= Score.objects.get(pk=result) ) +def score_user_mapping_save(request): + """AJAX endpoint for saving a user's preferred score for a piece.""" + if request.headers.get("X-Requested-With") == "XMLHttpRequest": + if request.method == "POST": + try: + result = json.loads(request.body) + score_id = int(result["myScore"]) + score = Score.objects.get(pk=score_id) + ScoreUserMapping.add_user_score_mapping(user=request.user, score=score) + except ( + json.JSONDecodeError, + KeyError, + ValueError, + Score.DoesNotExist, + ) as e: + return HttpResponse(f"Error: {e}", status=400) return HttpResponse("OK") -def score( request, pk ): - requestedScore = Score.objects.get(pk=pk) - if request.method == 'GET': - imageFile = requestedScore.get_image_file() - image_data = open( settings.MEDIA_ROOT + imageFile, "rb").read() - return HttpResponse(image_data, content_type="image/jpeg") +def score(request, pk): + """View for serving or deleting a score's preview image.""" + try: + requested_score = Score.objects.get(pk=pk) + except Score.DoesNotExist: + return HttpResponse("Score not found", status=404) + + if request.method == "GET": + image_file = requested_score.get_image_file() + image_path = os.path.join(settings.MEDIA_ROOT, image_file) + + try: + with open(image_path, "rb") as f: + image_data = f.read() + return HttpResponse(image_data, content_type="image/jpeg") + except FileNotFoundError: + return HttpResponse("Image not found", status=404) + if request.method == "DELETE": - if requestedScore.uploaded_by != request.user or request.user.has_perm('scoremanager.manage_scores'): + if not ( + requested_score.uploaded_by == request.user + or request.user.has_perm("scoremanager.manage_scores") + ): raise PermissionDenied - requestedScore.delete() + requested_score.delete() return HttpResponse("OK") + return HttpResponse("Method not allowed", status=405) -def youtube_link( request ): - result = json.loads( request.body ) - print("Youtube link: " + str(result) ) - if request.method == 'DELETE': - linkId = int( result['linkid'] ) - youtubeRecording = YoutubeRecording.objects.get( pk = linkId ) - if youtubeRecording.uploaded_by == request.user or request.user.has_perm('scoremanager.manage_scores'): - youtubeRecording.delete() - else: - raise PermissionDenied +def youtube_link(request): + """AJAX endpoint for adding or deleting YouTube links.""" + try: + result = json.loads(request.body) + except json.JSONDecodeError: + return HttpResponse("Invalid JSON", status=400) - return HttpResponse("OK") + if request.method == "DELETE": + try: + link_id = int(result["linkid"]) + youtube_recording = YoutubeRecording.objects.get(pk=link_id) - elif request.method == 'POST': - link = str( result['link'] ) - pieceId = int( result['pieceId'] ) + if youtube_recording.uploaded_by == request.user or request.user.has_perm( + "scoremanager.manage_scores" + ): + youtube_recording.delete() + else: + raise PermissionDenied - newRecording = YoutubeRecording(piece=Piece.objects.get(pk=pieceId), link=link) - newRecording.uploaded_by = request.user - newRecording.save() - return HttpResponse("OK") + return HttpResponse("OK") + except (KeyError, ValueError, YoutubeRecording.DoesNotExist) as e: + return HttpResponse(f"Error: {e}", status=400) + elif request.method == "POST": + try: + link = str(result["link"]) + piece_id = int(result["pieceId"]) + piece = Piece.objects.get(pk=piece_id) + + new_recording = YoutubeRecording(piece=piece, link=link) + new_recording.uploaded_by = request.user + new_recording.save() + return HttpResponse("OK") + except (KeyError, ValueError, Piece.DoesNotExist) as e: + return HttpResponse(f"Error: {e}", status=400) + + return HttpResponse("Method not allowed", status=405) class UploadFileForm(forms.Form): - file = forms.FileField( max_length="80") + """Form for uploading score and recording files.""" + + file = forms.FileField(max_length=80) def clean_file(self): - f = self.cleaned_data['file'] - extension = os.path.splitext( f.name )[1] - if extension != ".pdf" and extension !=".mp3" and extension != ".zip": - raise forms.ValidationError( _("Unknown extension. Allowed extension are mp3, pdf and zip")) + f = self.cleaned_data["file"] + extension = os.path.splitext(f.name)[1].lower() + allowed_extensions = [".pdf", ".mp3", ".zip"] + + if extension not in allowed_extensions: + raise forms.ValidationError( + _("Unknown extension. Allowed extensions are mp3, pdf and zip") + ) + + return f -def piece_view( request, pk ): - currentPiece = Piece.objects.get( pk=pk ) - context = {'piece': currentPiece } +def piece_view(request, pk): + """View for displaying a piece's details and handling file uploads.""" + try: + current_piece = Piece.objects.get(pk=pk) + except Piece.DoesNotExist: + return HttpResponse("Piece not found", status=404) - for score in currentPiece.scores.all(): - if score.is_active_score( request.user ): - context['activeScore'] = score - context['pictureScore'] = score + context = {"piece": current_piece} + # Find active score for user + for score_obj in current_piece.scores.all(): + if score_obj.is_active_score(request.user): + context["activeScore"] = score_obj + context["pictureScore"] = score_obj + break - if not 'pictureScore' in context.keys() and len( currentPiece.scores.all()) > 0: - context['pictureScore'] = currentPiece.scores.all()[0] + # Fall back to first score if no active score + if "pictureScore" not in context and current_piece.scores.exists(): + context["pictureScore"] = current_piece.scores.first() - if request.method == 'POST': + if request.method == "POST": form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): - f = request.FILES['file'] - [basename,extension] = os.path.splitext( f.name ) - print ("extension " + extension + " basename " + basename) - if extension == ".mp3": - print("Uploaded Recording") - recording = Recording( piece=currentPiece, artist=basename, file=f ) - recording.uploaded_by=request.user - recording.save() - elif extension == ".pdf": - print("Uploaded Score") - score = Score( piece=currentPiece, score_type=basename, file=f ) - score.uploaded_by=request.user - score.save() - elif extension == ".zip": - #TODO - print ("uploaded zip - not yet supported") + f = request.FILES["file"] + basename, extension = os.path.splitext(f.name) + extension = extension.lower() + if extension == ".mp3": + recording = Recording(piece=current_piece, artist=basename, file=f) + recording.uploaded_by = request.user + recording.save() + + elif extension == ".pdf": + score_obj = Score(piece=current_piece, score_type=basename, file=f) + score_obj.uploaded_by = request.user + score_obj.save() + + elif extension == ".zip": + # TODO: Handle zip file uploads + pass else: form = UploadFileForm() - context['form'] = form - - return render( request, 'scoremanager/piece_view.html', context ) - - + context["form"] = form + return render(request, "scoremanager/piece_view.html", context) diff --git a/simpleforum/admin.py b/simpleforum/admin.py index 297113f..b3224b5 100644 --- a/simpleforum/admin.py +++ b/simpleforum/admin.py @@ -1,4 +1,31 @@ from django.contrib import admin -from simpleforum.models import Message -admin.site.register(Message) \ No newline at end of file +from .models import Message + + +@admin.register(Message) +class MessageAdmin(admin.ModelAdmin): + """Admin configuration for Message model.""" + + list_display = ("titel", "author", "creation_time") + list_filter = ("creation_time", "author") + search_fields = ("titel", "text", "author__username") + date_hierarchy = "creation_time" + ordering = ("-creation_time",) + readonly_fields = ("creation_time",) + + fieldsets = ( + ( + None, + { + "fields": ("titel", "text", "author"), + }, + ), + ( + "Metadata", + { + "fields": ("creation_time",), + "classes": ("collapse",), + }, + ), + ) diff --git a/simpleforum/migrations/0001_initial.py b/simpleforum/migrations/0001_initial.py new file mode 100644 index 0000000..7e3cfa9 --- /dev/null +++ b/simpleforum/migrations/0001_initial.py @@ -0,0 +1,30 @@ +# Generated by Django 5.1.15 on 2026-03-30 19:15 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Message', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('titel', models.CharField(max_length=100, verbose_name='titel')), + ('text', models.TextField(verbose_name='text')), + ('creation_time', models.DateTimeField(verbose_name='creation_time')), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Author')), + ], + options={ + 'ordering': ['-creation_time'], + }, + ), + ] diff --git a/simpleforum/migrations/__init__.py b/simpleforum/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/simpleforum/models.py b/simpleforum/models.py index ea81d99..50a977c 100644 --- a/simpleforum/models.py +++ b/simpleforum/models.py @@ -1,12 +1,12 @@ -from django.db import models -from django.utils.translation import ugettext as _ from django.contrib.auth.models import User +from django.core.mail import EmailMultiAlternatives +from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver -from django.core.mail import EmailMultiAlternatives +from django.template.loader import render_to_string +from django.utils.translation import gettext_lazy as _ + from musicians.models import Musician -from django.template.loader import get_template -from django.template import Context class Message(models.Model): @@ -14,30 +14,41 @@ class Message(models.Model): text = models.TextField(blank=False, verbose_name=_("text")) creation_time = models.DateTimeField(verbose_name=_("creation_time")) - author = models.ForeignKey(User, verbose_name=_("Author"), on_delete=models.PROTECT) - def __unicode__(self): + author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_("Author")) + + class Meta: + ordering = ["-creation_time"] + + def __str__(self): return self.author.username + " : " + self.titel @receiver(post_save, sender=Message) -def my_handler(sender, instance, created, **kwargs): +def send_forum_notification(sender, instance, created, **kwargs): + """Send email notification when a new message is created.""" if not created: return - receivers = [m.user.email for m in Musician.objects.all()] + receivers = [m.user.email for m in Musician.objects.all() if m.user.email] + + if not receivers: + return subject = "Blechreiz Forum: " + instance.titel - from_email = 'forum@blechreiz.com' + from_email = "forum@blechreiz.com" - c = {'messages': Message.objects.all().order_by('-creation_time')[:10]} + context = {"messages": Message.objects.all().order_by("-creation_time")[:10]} - text_template = get_template("simpleforum/mail.txt") - # html_template = get_template( "simpleforum/mail.html" ) - - text_content = text_template.render(Context(c)) - # html_content = html_template.render( Context(c) ) + text_content = render_to_string("simpleforum/mail.txt", context) msg = EmailMultiAlternatives(subject, text_content, from_email, receivers) - # msg.attach_alternative( html_content, "text/html" ) - msg.send() + # Uncomment to add HTML version: + # html_content = render_to_string("simpleforum/mail.html", context) + # msg.attach_alternative(html_content, "text/html") + + try: + msg.send() + except Exception: + # Log the error but don't crash + pass diff --git a/simpleforum/templates/simpleforum/simpleforum.html b/simpleforum/templates/simpleforum/simpleforum.html index edf3faf..6d0a7ed 100644 --- a/simpleforum/templates/simpleforum/simpleforum.html +++ b/simpleforum/templates/simpleforum/simpleforum.html @@ -1,152 +1,160 @@ -{% extends "website/base.html" %} - -{% load sekizai_tags staticfiles youtubefilter %} - -{% block content %} - - -{% addtoblock "css" strip %} {% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} - - -{% addtoblock "css" %} +{% extends "website/base.html" %} {% load sekizai_tags static youtubefilter %} +{% block content %} {% addtoblock "css" strip %} +{% endaddtoblock %} {% addtoblock "css" strip %} + +{% endaddtoblock %} {% addtoblock "css" %} -{% endaddtoblock %} - - -{% addtoblock "js" %} - - +{% endaddtoblock %} {% addtoblock "js" %} + + {% endaddtoblock %} -
    -
    - {% if archiveMode %} -

    Forum Archiv {{month}}/{{year}}

    - {% else %} -

    Forum

    - {% endif %} - -
    - +
    + {% if archiveMode %} +

    Forum Archiv {{month}}/{{year}}

    + {% else %} +

    Forum

    + {% endif %} - -
    -
    - {% for message in messages %} -
    -
    - -
    - -
    -
    -
    - {{ message.titel }} -
    -
    {{ message.author.first_name}} am {{message.creation_time}}
    -
    {{message.text | linebreaks | youtube }}
    -
    - -
    -
    - {% endfor %} -
    +
    +
    +
    + {% for message in messages %} +
    +
    +
    + +
    +
    +
    {{ message.titel }}
    +
    + {{ message.author.first_name}} am + {{message.creation_time}} +
    +
    + {{message.text | linebreaks | youtube }} +
    +
    +
    +
    + {% endfor %} +
    - -
    -

    Neue Nachricht

    -
    - {% csrf_token %} -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    - - -
    - - - - - -
    -
    +
    +

    Neue Nachricht

    +
    + {% csrf_token %} +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + + +
    +
    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/simpleforum/templatetags/youtubefilter.py b/simpleforum/templatetags/youtubefilter.py index 51ad7b7..5e9298b 100644 --- a/simpleforum/templatetags/youtubefilter.py +++ b/simpleforum/templatetags/youtubefilter.py @@ -1,21 +1,36 @@ +""" +Template filter for embedding YouTube videos in forum posts. +""" + import re -import django.template + +from django import template from django.template.defaultfilters import stringfilter from django.utils.safestring import mark_safe +register = template.Library() -register = django.template.Library() +# Regex to match YouTube URLs +YOUTUBE_REGEX = re.compile( + r"(?:https://)?(?:http://)?(?:www\.)?youtube\.(?:com|de)/watch\?v=(?P[-\w]*)" +) -youtubeRegex = re.compile( u'(?:https://)?(?:http://)?www.youtube.(?:com|de)/watch\?v=(?P[-\w]*)' ) - -@register.filter( name='youtube' ) +@register.filter(name="youtube") @stringfilter -def youtube_filter( value ): - replacement = """ -
    +def youtube_filter(value): """ - return mark_safe( youtubeRegex.sub( replacement, value ) ) + Convert YouTube URLs in text to embedded video iframes. - - + Usage in template: + {{ message.text|youtube }} + """ + replacement = """ +
    + +
    + """ + return mark_safe(YOUTUBE_REGEX.sub(replacement, value)) diff --git a/simpleforum/views.py b/simpleforum/views.py index a8e3a56..6e3a20c 100644 --- a/simpleforum/views.py +++ b/simpleforum/views.py @@ -1,34 +1,55 @@ from datetime import datetime -from django.shortcuts import render, redirect -from simpleforum.models import Message + +from django.shortcuts import redirect, render +from django.utils import timezone + +from .models import Message def message_view(request): - if request.method == 'POST': - if 'titel' in request.POST and 'text' in request.POST: - titel = request.POST.get('titel') - text = request.POST.get('text') + """View for displaying and creating forum messages.""" - if len(titel) > 0 and len(text) > 0: - Message.objects.create(titel=titel, text=text, author=request.user, creation_time=datetime.now()) + if request.method == "POST": + titel = request.POST.get("titel", "") + text = request.POST.get("text", "") + + if titel and text: + Message.objects.create( + titel=titel, + text=text, + author=request.user, + creation_time=timezone.now(), + ) return redirect(message_view) - context = dict() + context = {} - if request.method == 'GET': - if 'month' in request.GET and 'year' in request.GET: - year = int(request.GET['year']) - month = int(request.GET['month']) - until_date = datetime(year, month + 1, 1) - from_date = datetime(year, month, 1) - context['archiveMode'] = True - context['year'] = year - context['month'] = month - context['messages'] = Message.objects.filter(creation_time__lt=until_date).filter( - creation_time__gte=from_date).order_by('-creation_time') + if request.method == "GET": + if "month" in request.GET and "year" in request.GET: + try: + year = int(request.GET["year"]) + month = int(request.GET["month"]) + + from_date = datetime(year, month, 1) + # Handle December -> January transition + if month == 12: + until_date = datetime(year + 1, 1, 1) + else: + until_date = datetime(year, month + 1, 1) + + context["archiveMode"] = True + context["year"] = year + context["month"] = month + context["messages"] = Message.objects.filter( + creation_time__lt=until_date, creation_time__gte=from_date + ).order_by("-creation_time") + except (ValueError, TypeError): + # Invalid date parameters, fall back to default view + context["messages"] = Message.objects.order_by("-creation_time")[:20] + context["archiveMode"] = False else: - context['messages'] = Message.objects.order_by('-creation_time')[:20] - context['archiveMode'] = False + context["messages"] = Message.objects.order_by("-creation_time")[:20] + context["archiveMode"] = False - return render(request, 'simpleforum/simpleforum.html', context) + return render(request, "simpleforum/simpleforum.html", context) diff --git a/website/static/favicon.ico b/website/static/favicon.ico deleted file mode 100644 index 69dd1af..0000000 Binary files a/website/static/favicon.ico and /dev/null differ diff --git a/website/static/js/snowflakes.js b/website/static/js/snowflakes.js new file mode 100644 index 0000000..dd70d6b --- /dev/null +++ b/website/static/js/snowflakes.js @@ -0,0 +1,228 @@ +//////////////////////////////////////////////////////////////////////// +// SnowFlakes-Script (c) 2011, Dominik Scholz / go4u.de Webdesign +//////////////////////////////////////////////////////////////////////// + +var snowflakes = { + + ///////////////////////////// configuration //////////////////////////// + + // amout of flakes + _amount: 70, + // random colors + _color: ['#AAAACC', '#DDDDFF', '#CCCCDD', '#F3F3F3', '#F0FFFF'], + // random fonts + _type: ['Arial Black', 'Arial Narrow', 'Times', 'Comic Sans MS'], + // char used for flake + _flakeChar: '*', + // speed of flakes + _speed: .2, + // minimum flake font size + _minSize: 8, + // maximum flake font size + _maxSize: 22, + // horizontal drift + _drift: 15, + // zIndex of flakes + _zIndex: 20000, + + + + ///////////////////////////// private vars ///////////////////////////// + + _flakes: [], + _bodyWidth: 0, + _bodyHeight: 0, + _range: null, + _count: 0, + _timeout: 20, + _lastInterval: 0, + _eventHandlerResize: window.onresize, + _eventHandlerLoad: window.onload, + + + + ////////////////////////////// functions /////////////////////////////// + + // start snow + start: function() + { + if (this._eventHandlerLoad != null) this._eventHandlerLoad(); + + // calculate range + this._range = this._maxSize - this._minSize; + + // init window size + this._windowSize(); + + // add new flakes + while (this._amount > this._flakes.length) + this._createFlake(this._flakes.length); + + // start to move snow + this._lastInterval = this._time(); + window.setInterval(function() { snowflakes._move(); }, this._timeout); + }, + + + // get current time + _time: function() + { + return +new Date(); + }, + + + // return a random number bewtween 0 and range + _random: function(range) + { + return Math.floor(Math.random() * range); + }, + + + // creates a new snowflake + _createFlake: function(i) + { + // select body tag + var insertBody = document.getElementsByTagName('body')[0]; + + // create span child for flake + var f = document.createElement('div'); + f.id = 'flake' + i; + f.style.position = 'absolute'; + f.style.left = '0px'; + f.style.top = '-' + this._maxSize + 'px'; + f.style.color = this._color[this._random(this._color.length - 1)]; + f.style.family = this._type[this._random(this._type.length - 1)]; + f.style.fontSize = (this._random(this._range) + this._minSize) + 'px'; + f.style.zIndex = this._zIndex; + f.innerHTML = this._flakeChar; + insertBody.appendChild(f); + + // create array element + this._flakes[i] = { + x: this._random(this._bodyWidth - this._drift - this._maxSize - 3) + this._drift + 1, + y: -this._maxSize - this._random(this._bodyHeight), + size: this._random(this._range) + this._minSize, + count: this._random(10000) + }; + }, + + + // restart an existing snow flake + _restartFlake: function(i) + { + this._flakes[i] = { + x: this._random(this._bodyWidth - this._drift - this._maxSize - 3) + this._drift + 1, + y: -this._maxSize, + size: this._random(this._range) + this._minSize, + count: this._random(10000) + }; + }, + + + // move existing flakes + _move: function() + { + // calculate movement factor + var dif = this._time() - this._lastInterval; + this._lastInterval = this._time(); + var f = dif * this._speed; + + this._count += f / 80; + + for (var i = 0; i < this._flakes.length; i++) + { + var flake = this._flakes[i]; + flake.y += f * this._speed * this._maxSize / flake.size; + + // restart existing flake + if (flake.y + flake.size >= this._bodyHeight) + { + this._restartFlake(i); + continue; + } + + var flakeDiv = document.getElementById('flake' + i); + flakeDiv.style.left = Math.floor(flake.x + Math.sin(flake.count + this._count) * this._drift) + 'px'; + flakeDiv.style.top = Math.floor(flake.y) + 'px'; + } + }, + + + // calculate new positions for all flakes + _windowSize: function() + { + // save old width + var oldWidth = this._bodyWidth; + + // get new width and height + this._bodyWidth = this._getWindowWidth() - this._maxSize; + this._bodyHeight = this._getWindowHeight() - this._maxSize; + + // calculate correction ratio + var ratio = this._bodyWidth / oldWidth; + + // for all flakes + for (var i = 0; i < this._flakes.length; i++) + { + var flake = this._flakes[i]; + + // do width correction + flake.x *= ratio; + + // restart existing flake + if ((flake.y + flake.size) >= this._bodyHeight) + this._restartFlake(i); + } + }, + + + // get window width + _getWindowWidth: function() + { + var w = Math.max(self.innerWidth || 0, window.innerWidth || 0); + + if (document.documentElement) + w = Math.max(w, document.documentElement.clientWidth || 0); + if (document.body) + { + w = Math.max(w, document.body.clientWidth || 0); + w = Math.max(w, document.body.scrollWidth || 0); + w = Math.max(w, document.body.offsetWidth || 0); + } + + return w; + }, + + + // get window height + _getWindowHeight: function() + { + var h = Math.max(self.innerHeight || 0, window.innerHeight || 0); + + if (document.documentElement) + h = Math.max(h, document.documentElement.clientHeight || 0); + if (document.body) + { + h = Math.max(h, document.body.clientHeight || 0); + h = Math.max(h, document.body.scrollHeight || 0); + h = Math.max(h, document.body.offsetHeight || 0); + } + + return h; + }, + + + // handle resize event + resize: function() + { + if (this._eventHandlerResize != null) + this._eventHandlerResize(); + this._windowSize(); + } + +}; + + +// register window resize event +window.onresize = function() { snowflakes.resize(); } +window.onload = function() { snowflakes.start(); } diff --git a/website/templates/website/base.html b/website/templates/website/base.html index 56477ef..7c5e17a 100644 --- a/website/templates/website/base.html +++ b/website/templates/website/base.html @@ -1,72 +1,65 @@ -{% load sekizai_tags staticfiles %} +{% load sekizai_tags static %} {% include "bootstrapTheme/bootstrapTheme.html" %} - - - Blechreiz + Blechreiz - - - {% render_block "css" %} - {% render_block "js" %} - + + {% render_block "css" %} - - - + {% render_block "js" %} - - - - - - - - - diff --git a/website/templates/website/mainpage.html b/website/templates/website/mainpage.html index 9de6096..6bd9acf 100644 --- a/website/templates/website/mainpage.html +++ b/website/templates/website/mainpage.html @@ -1,14 +1,8 @@ {% extends "website/base.html" %} - -{% load sekizai_tags staticfiles %} - -{% block navbar_options %} navbar transparent navbar-inverse navbar-fixed-top {% endblock %} - +{% load sekizai_tags static %} +{% block navbar_options %} navbar transparent navbar-inverse navbar-fixed-top {% endblock %} {% block content %} - - {% include "website/slider_intern_area.html" %} - {% include "eventplanner/countdown.inc.html" %} - {% include "eventplanner/routeToEventMap.inc.html" %} - +{% include "website/slider_intern_area.html" %} +{% include "eventplanner/countdown.inc.html" %} +{% include "eventplanner/routeToEventMap.inc.html" %} {% endblock %} - diff --git a/website/templates/website/menu_column.html b/website/templates/website/menu_column.html index b515b45..7db610f 100644 --- a/website/templates/website/menu_column.html +++ b/website/templates/website/menu_column.html @@ -1,32 +1,121 @@ - - - -{% addtoblock "css" strip %} {% endaddtoblock %} -{% addtoblock "css" strip %} {% endaddtoblock %} +{% load sekizai_tags static %} +{% addtoblock "css" strip %} + +{% endaddtoblock %} {% addtoblock "css" strip %} + +{% endaddtoblock %} + + +
    + diff --git a/website/templates/website/slider_intern_area.html b/website/templates/website/slider_intern_area.html index c1f912c..3353aa0 100644 --- a/website/templates/website/slider_intern_area.html +++ b/website/templates/website/slider_intern_area.html @@ -1,125 +1,118 @@ -{% load sekizai_tags staticfiles %} - - - -{% comment %} - Displays a slider linking to - /events - /messages - /addressbook - Requires context "hasParticipationSetForAllEvents" - to diplay if a user has finished the event planning -{% endcomment %} - - - - - -{% addtoblock "css" %} +{% load sekizai_tags static %} {% comment %} Displays a slider linking to +/events /messages /addressbook Requires context +"hasParticipationSetForAllEvents" to diplay if a user has finished the event +planning {% endcomment %} {% addtoblock "css" %} {% endaddtoblock %} - - - -
    +
    + +
    + GoogleCalendar +
    + Jetzt auch auf dem Handy im Google Kalender Termine planen +
    +
    +
    -
    +
    +
    + Einsatzplanung - -
    - GoogleCalendar -
    Jetzt auch auf dem Handy im Google Kalender Termine planen
    -
    +
    + {% if hasParticipationSetForAllEvents %} Sehr gut - du hast dich + für alles eingetragen {% else %} Du hast dich noch nicht für + alle Termine eingetragen!! {% endif %} +
    +
    +
    -
    - - - -
    - -
    - Einsatzplanung - -
    - {% if hasParticipationSetForAllEvents %} - Sehr gut - du hast dich für alles eingetragen - {% else %} - Du hast dich noch nicht für alle Termine eingetragen!! - {% endif %} -
    -
    - -
    - -
    - -
    - Forum -
    Nachricht an alle schreiben...
    -
    -
    - -
    -
    - Adressbuch -
    Geburtstage, Telefonnummern, ...
    -
    -
    +
    + +
    + Forum +
    Nachricht an alle schreiben...
    +
    +
    +
    +
    + Adressbuch +
    + Geburtstage, Telefonnummern, ... +
    +
    +
    - diff --git a/website/urls.py b/website/urls.py index 40b7e17..2bddda0 100644 --- a/website/urls.py +++ b/website/urls.py @@ -1,7 +1,9 @@ -from django.conf.urls import url +from django.urls import path -from website.views import home_view +from . import views + +app_name = "website" urlpatterns = [ - url(r'$^', home_view), + path("", views.home_view, name="home"), ] diff --git a/website/views.py b/website/views.py index 23ade6d..b7d7678 100644 --- a/website/views.py +++ b/website/views.py @@ -1,21 +1,24 @@ -from django.shortcuts import render -from django.conf import settings from django.contrib.auth.decorators import login_required -from eventplanner.snippets import addEventCountdownForNextEventToContext, addEventRouteForNextEventToContext +from django.shortcuts import render + from eventplanner.models import EventParticipation +from eventplanner.snippets import ( + addEventCountdownForNextEventToContext, + addEventRouteForNextEventToContext, +) @login_required def home_view(request): - context = dict() + context = {} # Event participation for slider text if EventParticipation.isMember(request.user): - context['hasParticipationSetForAllEvents'] = EventParticipation.hasUserSetParticipationForAllEvents( - request.user) + context["hasParticipationSetForAllEvents"] = ( + EventParticipation.hasUserSetParticipationForAllEvents(request.user) + ) addEventCountdownForNextEventToContext(context, request.user) - addEventRouteForNextEventToContext(context, request.user, 'Conc') + addEventRouteForNextEventToContext(context, request.user, "Conc") - context['GOOGLE_MAPS_API_KEY'] = settings.GOOGLE_MAPS_API_KEY - return render(request, 'website/mainpage.html', context) + return render(request, "website/mainpage.html", context)