3
.github/workflows/deploy.yml
vendored
@ -40,8 +40,7 @@ jobs:
|
|||||||
poetry install --with prod --without docs,tests
|
poetry install --with prod --without docs,tests
|
||||||
poetry run ./manage.py install_xapian
|
poetry run ./manage.py install_xapian
|
||||||
poetry run ./manage.py migrate
|
poetry run ./manage.py migrate
|
||||||
echo "yes" | poetry run ./manage.py collectstatic
|
poetry run ./manage.py collectstatic --clear --noinput
|
||||||
poetry run ./manage.py compilestatic
|
|
||||||
poetry run ./manage.py compilemessages
|
poetry run ./manage.py compilemessages
|
||||||
|
|
||||||
sudo systemctl restart uwsgi
|
sudo systemctl restart uwsgi
|
||||||
|
3
.github/workflows/taiste.yml
vendored
@ -39,8 +39,7 @@ jobs:
|
|||||||
poetry install --with prod --without docs,tests
|
poetry install --with prod --without docs,tests
|
||||||
poetry run ./manage.py install_xapian
|
poetry run ./manage.py install_xapian
|
||||||
poetry run ./manage.py migrate
|
poetry run ./manage.py migrate
|
||||||
echo "yes" | poetry run ./manage.py collectstatic
|
poetry run ./manage.py collectstatic --clear --noinput
|
||||||
poetry run ./manage.py compilestatic
|
|
||||||
poetry run ./manage.py compilemessages
|
poetry run ./manage.py compilemessages
|
||||||
|
|
||||||
sudo systemctl restart uwsgi
|
sudo systemctl restart uwsgi
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 273 KiB After Width: | Height: | Size: 273 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 275 KiB |
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 275 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 242 KiB |
@ -2,7 +2,7 @@
|
|||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<title>{% trans %}Slideshow{% endtrans %}</title>
|
<title>{% trans %}Slideshow{% endtrans %}</title>
|
||||||
<link href="{{ scss('com/slideshow.scss') }}" rel="stylesheet" type="text/css" />
|
<link href="{{ scss('com/css/slideshow.scss') }}" rel="stylesheet" type="text/css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="slideshow">
|
<div id="slideshow">
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.models import Group as AuthGroup
|
from django.contrib.auth.models import Group as AuthGroup
|
||||||
|
|
||||||
from core.models import Group, Page, SithFile, User
|
from core.models import Group, OperationLog, Page, SithFile, User
|
||||||
|
|
||||||
admin.site.unregister(AuthGroup)
|
admin.site.unregister(AuthGroup)
|
||||||
|
|
||||||
@ -53,3 +53,10 @@ class SithFileAdmin(admin.ModelAdmin):
|
|||||||
list_display = ("name", "owner", "size", "date", "is_in_sas")
|
list_display = ("name", "owner", "size", "date", "is_in_sas")
|
||||||
autocomplete_fields = ("parent", "owner", "moderator")
|
autocomplete_fields = ("parent", "owner", "moderator")
|
||||||
search_fields = ("name", "parent__name")
|
search_fields = ("name", "parent__name")
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(OperationLog)
|
||||||
|
class OperationLogAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("label", "operator", "operation_type", "date")
|
||||||
|
search_fields = ("label", "date", "operation_type")
|
||||||
|
autocomplete_fields = ("operator",)
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
#
|
|
||||||
# Copyright 2017
|
|
||||||
# - Sli <antoine@bartuccio.fr>
|
|
||||||
#
|
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
|
||||||
# http://ae.utbm.fr.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import sass
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core.management.base import BaseCommand
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
"""Compiles scss in static folder for production."""
|
|
||||||
|
|
||||||
help = "Compile scss files from static folder"
|
|
||||||
|
|
||||||
def compile(self, filename: str):
|
|
||||||
args = {
|
|
||||||
"filename": filename,
|
|
||||||
"include_paths": settings.STATIC_ROOT.name,
|
|
||||||
"output_style": "compressed",
|
|
||||||
}
|
|
||||||
if settings.SASS_PRECISION:
|
|
||||||
args["precision"] = settings.SASS_PRECISION
|
|
||||||
return sass.compile(**args)
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
if not settings.STATIC_ROOT.is_dir():
|
|
||||||
raise Exception(
|
|
||||||
"No static folder availaible, please use collectstatic before compiling scss"
|
|
||||||
)
|
|
||||||
to_exec = list(settings.STATIC_ROOT.rglob("*.scss"))
|
|
||||||
if len(to_exec) == 0:
|
|
||||||
self.stdout.write("Nothing to compile.")
|
|
||||||
sys.exit(0)
|
|
||||||
self.stdout.write("---- Compiling scss files ---")
|
|
||||||
for file in to_exec:
|
|
||||||
# remove existing css files that will be replaced
|
|
||||||
# keeping them while compiling the scss would break
|
|
||||||
# import statements resolution
|
|
||||||
css_file = file.with_suffix(".css")
|
|
||||||
if css_file.exists():
|
|
||||||
css_file.unlink()
|
|
||||||
compiled_files = {file: self.compile(str(file.resolve())) for file in to_exec}
|
|
||||||
for file, scss in compiled_files.items():
|
|
||||||
file.replace(file.with_suffix(".css")).write_text(scss)
|
|
||||||
self.stdout.write(
|
|
||||||
"Files compiled : \n" + "\n- ".join(str(f) for f in compiled_files)
|
|
||||||
)
|
|
@ -1,55 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
#
|
|
||||||
# Copyright 2017
|
|
||||||
# - Sli <antoine@bartuccio.fr>
|
|
||||||
#
|
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
|
||||||
# http://ae.utbm.fr.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
import functools
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import sass
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core.files.base import ContentFile
|
|
||||||
from django.templatetags.static import static
|
|
||||||
from django_jinja.builtins.filters import static
|
|
||||||
|
|
||||||
from core.scss.storage import ScssFileStorage, find_file
|
|
||||||
|
|
||||||
|
|
||||||
@functools.cache
|
|
||||||
def _scss_storage():
|
|
||||||
return ScssFileStorage()
|
|
||||||
|
|
||||||
|
|
||||||
def process_scss_path(path: Path):
|
|
||||||
css_path = path.with_suffix(".css")
|
|
||||||
if settings.DEBUG:
|
|
||||||
compile_args = {
|
|
||||||
"filename": find_file(path),
|
|
||||||
"include_paths": settings.SASS_INCLUDE_FOLDERS,
|
|
||||||
}
|
|
||||||
if settings.SASS_PRECISION:
|
|
||||||
compile_args["precision"] = settings.SASS_PRECISION
|
|
||||||
content = sass.compile(**compile_args)
|
|
||||||
storage = _scss_storage()
|
|
||||||
if storage.exists(css_path):
|
|
||||||
storage.delete(css_path)
|
|
||||||
storage.save(css_path, ContentFile(content))
|
|
||||||
return static(css_path)
|
|
@ -1,43 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
#
|
|
||||||
# Copyright 2017
|
|
||||||
# - Sli <antoine@bartuccio.fr>
|
|
||||||
#
|
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
|
||||||
# http://ae.utbm.fr.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.staticfiles.finders import get_finders
|
|
||||||
from django.core.files.storage import FileSystemStorage
|
|
||||||
|
|
||||||
|
|
||||||
class ScssFileStorage(FileSystemStorage):
|
|
||||||
def __init__(self, location=None, base_url=None, *args, **kwargs):
|
|
||||||
if location is None:
|
|
||||||
location = settings.STATIC_ROOT
|
|
||||||
if base_url is None:
|
|
||||||
base_url = settings.STATIC_URL
|
|
||||||
super().__init__(location, base_url, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def find_file(path):
|
|
||||||
for finder in get_finders():
|
|
||||||
result = finder.find(path)
|
|
||||||
if result:
|
|
||||||
return result
|
|
@ -69,17 +69,41 @@ function getCSRFToken() {
|
|||||||
|
|
||||||
const initialUrlParams = new URLSearchParams(window.location.search);
|
const initialUrlParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
function update_query_string(key, value) {
|
/**
|
||||||
const url = new URL(window.location.href);
|
* @readonly
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
const History = {
|
||||||
|
NONE: 0,
|
||||||
|
PUSH: 1,
|
||||||
|
REPLACE: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} key
|
||||||
|
* @param {string | string[] | null} value
|
||||||
|
* @param {History} action
|
||||||
|
* @param {URL | null} url
|
||||||
|
*/
|
||||||
|
function update_query_string(key, value, action = History.REPLACE, url = null) {
|
||||||
|
if (!url){
|
||||||
|
url = new URL(window.location.href);
|
||||||
|
}
|
||||||
if (!value) {
|
if (!value) {
|
||||||
// If the value is null, undefined or empty => delete it
|
// If the value is null, undefined or empty => delete it
|
||||||
url.searchParams.delete(key)
|
url.searchParams.delete(key)
|
||||||
} else if (Array.isArray(value)) {
|
} else if (Array.isArray(value)) {
|
||||||
|
|
||||||
url.searchParams.delete(key)
|
url.searchParams.delete(key)
|
||||||
value.forEach((v) => url.searchParams.append(key, v))
|
value.forEach((v) => url.searchParams.append(key, v))
|
||||||
} else {
|
} else {
|
||||||
url.searchParams.set(key, value);
|
url.searchParams.set(key, value);
|
||||||
}
|
}
|
||||||
history.pushState(null, document.title, url.toString());
|
|
||||||
|
if (action === History.PUSH) {
|
||||||
|
history.pushState(null, "", url.toString());
|
||||||
|
} else if (action === History.REPLACE) {
|
||||||
|
history.replaceState(null, "", url.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
}
|
}
|
||||||
|
3
core/static/core/js/sentry/bundle.min.js
vendored
11008
core/static/core/js/ui/external/jquery/jquery.js
vendored
@ -1,39 +0,0 @@
|
|||||||
/* French initialisation for the jQuery UI date picker plugin. */
|
|
||||||
/* Written by Keith Wood (kbwood{at}iinet.com.au),
|
|
||||||
Stéphane Nahmani (sholby@sholby.net),
|
|
||||||
Stéphane Raimbault <stephane.raimbault@gmail.com> */
|
|
||||||
( 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.fr = {
|
|
||||||
closeText: "Fermer",
|
|
||||||
prevText: "Précédent",
|
|
||||||
nextText: "Suivant",
|
|
||||||
currentText: "Aujourd'hui",
|
|
||||||
monthNames: [ "janvier", "février", "mars", "avril", "mai", "juin",
|
|
||||||
"juillet", "août", "septembre", "octobre", "novembre", "décembre" ],
|
|
||||||
monthNamesShort: [ "janv.", "févr.", "mars", "avr.", "mai", "juin",
|
|
||||||
"juil.", "août", "sept.", "oct.", "nov.", "déc." ],
|
|
||||||
dayNames: [ "dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi" ],
|
|
||||||
dayNamesShort: [ "dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam." ],
|
|
||||||
dayNamesMin: [ "D","L","M","M","J","V","S" ],
|
|
||||||
weekHeader: "Sem.",
|
|
||||||
dateFormat: "dd/mm/yy",
|
|
||||||
firstDay: 1,
|
|
||||||
isRTL: false,
|
|
||||||
showMonthAfterYear: false,
|
|
||||||
yearSuffix: "" };
|
|
||||||
datepicker.setDefaults( datepicker.regional.fr );
|
|
||||||
|
|
||||||
return datepicker.regional.fr;
|
|
||||||
|
|
||||||
} ) );
|
|
1313
core/static/core/js/ui/jquery-ui.css
vendored
18686
core/static/core/js/ui/jquery-ui.js
vendored
886
core/static/core/js/ui/jquery-ui.structure.css
vendored
@ -1,886 +0,0 @@
|
|||||||
/*!
|
|
||||||
* jQuery UI CSS Framework 1.12.0
|
|
||||||
* http://jqueryui.com
|
|
||||||
*
|
|
||||||
* Copyright jQuery Foundation and other contributors
|
|
||||||
* Released under the MIT license.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://api.jqueryui.com/category/theming/
|
|
||||||
*/
|
|
||||||
.ui-draggable-handle {
|
|
||||||
-ms-touch-action: none;
|
|
||||||
touch-action: none;
|
|
||||||
}
|
|
||||||
/* Layout helpers
|
|
||||||
----------------------------------*/
|
|
||||||
.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); /* support: IE8 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui-front {
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Interaction Cues
|
|
||||||
----------------------------------*/
|
|
||||||
.ui-state-disabled {
|
|
||||||
cursor: default !important;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Icons
|
|
||||||
----------------------------------*/
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Misc visuals
|
|
||||||
----------------------------------*/
|
|
||||||
|
|
||||||
/* Overlays */
|
|
||||||
.ui-widget-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.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-selectable {
|
|
||||||
-ms-touch-action: none;
|
|
||||||
touch-action: none;
|
|
||||||
}
|
|
||||||
.ui-selectable-helper {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 100;
|
|
||||||
border: 1px dotted black;
|
|
||||||
}
|
|
||||||
.ui-sortable-handle {
|
|
||||||
-ms-touch-action: none;
|
|
||||||
touch-action: none;
|
|
||||||
}
|
|
||||||
.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;
|
|
||||||
/* support: IE10, see #8844 */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* icon support */
|
|
||||||
.ui-menu-icons {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.ui-menu-icons .ui-menu-item-wrapper {
|
|
||||||
padding-left: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* left-aligned */
|
|
||||||
.ui-menu .ui-icon {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: .2em;
|
|
||||||
margin: auto 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* right-aligned */
|
|
||||||
.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;
|
|
||||||
|
|
||||||
/* Support: IE <= 11 */
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui-button,
|
|
||||||
.ui-button:link,
|
|
||||||
.ui-button:visited,
|
|
||||||
.ui-button:hover,
|
|
||||||
.ui-button:active {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* to make room for the icon, a width needs to be set here */
|
|
||||||
.ui-button-icon-only {
|
|
||||||
width: 2em;
|
|
||||||
box-sizing: border-box;
|
|
||||||
text-indent: -9999px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* no icon support for input elements */
|
|
||||||
input.ui-button.ui-button-icon-only {
|
|
||||||
text-indent: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* button icon element(s) */
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* workarounds */
|
|
||||||
/* Support: Firefox 5 - 40 */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Spinner specific style fixes */
|
|
||||||
.ui-controlgroup-vertical .ui-spinner-input {
|
|
||||||
|
|
||||||
/* Support: IE8 only, Android < 4.4 only */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* with multiple calendars */
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RTL support */
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Icons */
|
|
||||||
.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-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); /* support: IE8 */
|
|
||||||
opacity: 0.25;
|
|
||||||
}
|
|
||||||
.ui-progressbar-indeterminate .ui-progressbar-value {
|
|
||||||
background-image: none;
|
|
||||||
}
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* support: IE8 - See #6727 */
|
|
||||||
.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-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;
|
|
||||||
}
|
|
||||||
/* more specificity required here to override default borders */
|
|
||||||
.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;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
|
||||||
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;
|
|
||||||
}
|
|
444
core/static/core/js/ui/jquery-ui.theme.css
vendored
@ -1,444 +0,0 @@
|
|||||||
/*!
|
|
||||||
* jQuery UI CSS Framework 1.12.0
|
|
||||||
* http://jqueryui.com
|
|
||||||
*
|
|
||||||
* Copyright jQuery Foundation and other contributors
|
|
||||||
* Released under the MIT license.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* http://api.jqueryui.com/category/theming/
|
|
||||||
*
|
|
||||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=base&cornerRadiusShadow=8px&offsetLeftShadow=0px&offsetTopShadow=0px&thicknessShadow=5px&opacityShadow=30&bgImgOpacityShadow=0&bgTextureShadow=flat&bgColorShadow=666666&opacityOverlay=30&bgImgOpacityOverlay=0&bgTextureOverlay=flat&bgColorOverlay=aaaaaa&iconColorError=cc0000&fcError=5f3f3f&borderColorError=f1a899&bgTextureError=flat&bgColorError=fddfdf&iconColorHighlight=777620&fcHighlight=777620&borderColorHighlight=dad55e&bgTextureHighlight=flat&bgColorHighlight=fffa90&iconColorActive=ffffff&fcActive=ffffff&borderColorActive=003eff&bgTextureActive=flat&bgColorActive=007fff&iconColorHover=555555&fcHover=2b2b2b&borderColorHover=cccccc&bgTextureHover=flat&bgColorHover=ededed&iconColorDefault=777777&fcDefault=454545&borderColorDefault=c5c5c5&bgTextureDefault=flat&bgColorDefault=f6f6f6&iconColorContent=444444&fcContent=333333&borderColorContent=dddddd&bgTextureContent=flat&bgColorContent=ffffff&iconColorHeader=444444&fcHeader=333333&borderColorHeader=dddddd&bgTextureHeader=flat&bgColorHeader=e9e9e9&cornerRadius=3px&fwDefault=normal&fsDefault=1em&ffDefault=Arial%2CHelvetica%2Csans-serif
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* Component containers
|
|
||||||
----------------------------------*/
|
|
||||||
.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 #dddddd;
|
|
||||||
background: #ffffff;
|
|
||||||
color: #333333;
|
|
||||||
}
|
|
||||||
.ui-widget-content a {
|
|
||||||
color: #333333;
|
|
||||||
}
|
|
||||||
.ui-widget-header {
|
|
||||||
border: 1px solid #dddddd;
|
|
||||||
background: #e9e9e9;
|
|
||||||
color: #333333;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.ui-widget-header a {
|
|
||||||
color: #333333;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Interaction states
|
|
||||||
----------------------------------*/
|
|
||||||
.ui-state-default,
|
|
||||||
.ui-widget-content .ui-state-default,
|
|
||||||
.ui-widget-header .ui-state-default,
|
|
||||||
.ui-button,
|
|
||||||
|
|
||||||
/* We use html here because we need a greater specificity to make sure disabled
|
|
||||||
works properly when clicked or hovered */
|
|
||||||
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 #cccccc;
|
|
||||||
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: #ffffff;
|
|
||||||
}
|
|
||||||
.ui-icon-background,
|
|
||||||
.ui-state-active .ui-icon-background {
|
|
||||||
border: #003eff;
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
.ui-state-active a,
|
|
||||||
.ui-state-active a:link,
|
|
||||||
.ui-state-active a:visited {
|
|
||||||
color: #ffffff;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Interaction Cues
|
|
||||||
----------------------------------*/
|
|
||||||
.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); /* support: IE8 */
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
.ui-state-disabled,
|
|
||||||
.ui-widget-content .ui-state-disabled,
|
|
||||||
.ui-widget-header .ui-state-disabled {
|
|
||||||
opacity: .35;
|
|
||||||
filter:Alpha(Opacity=35); /* support: IE8 */
|
|
||||||
background-image: none;
|
|
||||||
}
|
|
||||||
.ui-state-disabled .ui-icon {
|
|
||||||
filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Icons
|
|
||||||
----------------------------------*/
|
|
||||||
|
|
||||||
/* states and images */
|
|
||||||
.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-button .ui-icon {
|
|
||||||
background-image: url("images/ui-icons_777777_256x240.png");
|
|
||||||
}
|
|
||||||
.ui-state-hover .ui-icon,
|
|
||||||
.ui-state-focus .ui-icon,
|
|
||||||
.ui-button:hover .ui-icon,
|
|
||||||
.ui-button:focus .ui-icon,
|
|
||||||
.ui-state-default .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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* positioning */
|
|
||||||
.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 is deprecated, use ui-icon-seek-start instead */
|
|
||||||
.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; }
|
|
||||||
|
|
||||||
|
|
||||||
/* Misc visuals
|
|
||||||
----------------------------------*/
|
|
||||||
|
|
||||||
/* Corner radius */
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Overlays */
|
|
||||||
.ui-widget-overlay {
|
|
||||||
background: #aaaaaa;
|
|
||||||
opacity: .3;
|
|
||||||
filter: Alpha(Opacity=30); /* support: IE8 */
|
|
||||||
}
|
|
||||||
.ui-widget-shadow {
|
|
||||||
-webkit-box-shadow: 0px 0px 5px #666666;
|
|
||||||
box-shadow: 0px 0px 5px #666666;
|
|
||||||
}
|
|
@ -1,399 +0,0 @@
|
|||||||
// WebcamJS v1.0
|
|
||||||
// Webcam library for capturing JPEG/PNG images in JavaScript
|
|
||||||
// Attempts getUserMedia, falls back to Flash
|
|
||||||
// Author: Joseph Huckaby: http://github.com/jhuckaby
|
|
||||||
// Based on JPEGCam: http://code.google.com/p/jpegcam/
|
|
||||||
// Copyright (c) 2012 Joseph Huckaby
|
|
||||||
// Licensed under the MIT License
|
|
||||||
|
|
||||||
/* Usage:
|
|
||||||
<div id="my_camera" style="width:320px; height:240px;"></div>
|
|
||||||
<div id="my_result"></div>
|
|
||||||
|
|
||||||
<script language="JavaScript">
|
|
||||||
Webcam.attach( '#my_camera' );
|
|
||||||
|
|
||||||
function take_snapshot() {
|
|
||||||
var data_uri = Webcam.snap();
|
|
||||||
document.getElementById('my_result').innerHTML =
|
|
||||||
'<img src="'+data_uri+'"/>';
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<a href="javascript:void(take_snapshot())">Take Snapshot</a>
|
|
||||||
*/
|
|
||||||
|
|
||||||
var Webcam = {
|
|
||||||
version: '1.0.0',
|
|
||||||
|
|
||||||
// globals
|
|
||||||
protocol: location.protocol.match(/https/i) ? 'https' : 'http',
|
|
||||||
swfURL: '', // URI to webcam.swf movie (defaults to cwd)
|
|
||||||
loaded: false, // true when webcam movie finishes loading
|
|
||||||
live: false, // true when webcam is initialized and ready to snap
|
|
||||||
userMedia: true, // true when getUserMedia is supported natively
|
|
||||||
|
|
||||||
params: {
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
dest_width: 0, // size of captured image
|
|
||||||
dest_height: 0, // these default to width/height
|
|
||||||
image_format: 'jpeg', // image format (may be jpeg or png)
|
|
||||||
jpeg_quality: 90, // jpeg image quality from 0 (worst) to 100 (best)
|
|
||||||
force_flash: false // force flash mode
|
|
||||||
},
|
|
||||||
|
|
||||||
hooks: {
|
|
||||||
load: null,
|
|
||||||
live: null,
|
|
||||||
uploadcomplete: null,
|
|
||||||
uploadprogress: null,
|
|
||||||
error: function(msg) { alert("Webcam.js Error: " + msg); }
|
|
||||||
}, // callback hook functions
|
|
||||||
|
|
||||||
init: function() {
|
|
||||||
// initialize, check for getUserMedia support
|
|
||||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
|
||||||
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
|
||||||
|
|
||||||
this.userMedia = this.userMedia && !!navigator.getUserMedia && !!window.URL;
|
|
||||||
|
|
||||||
// Older versions of firefox (< 21) apparently claim support but user media does not actually work
|
|
||||||
if (navigator.userAgent.match(/Firefox\D+(\d+)/)) {
|
|
||||||
if (parseInt(RegExp.$1, 10) < 21) this.userMedia = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
attach: function(elem) {
|
|
||||||
// create webcam preview and attach to DOM element
|
|
||||||
// pass in actual DOM reference, ID, or CSS selector
|
|
||||||
if (typeof(elem) == 'string') {
|
|
||||||
elem = document.getElementById(elem) || document.querySelector(elem);
|
|
||||||
}
|
|
||||||
if (!elem) {
|
|
||||||
return this.dispatch('error', "Could not locate DOM element to attach to.");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.container = elem;
|
|
||||||
if (!this.params.width) this.params.width = elem.offsetWidth;
|
|
||||||
if (!this.params.height) this.params.height = elem.offsetHeight;
|
|
||||||
|
|
||||||
// set defaults for dest_width / dest_height if not set
|
|
||||||
if (!this.params.dest_width) this.params.dest_width = this.params.width;
|
|
||||||
if (!this.params.dest_height) this.params.dest_height = this.params.height;
|
|
||||||
|
|
||||||
// if force_flash is set, disable userMedia
|
|
||||||
if (this.params.force_flash) this.userMedia = null;
|
|
||||||
|
|
||||||
if (this.userMedia) {
|
|
||||||
// setup webcam video container
|
|
||||||
var video = document.createElement('video');
|
|
||||||
video.setAttribute('autoplay', 'autoplay');
|
|
||||||
video.style.width = '' + this.params.dest_width + 'px';
|
|
||||||
video.style.height = '' + this.params.dest_height + 'px';
|
|
||||||
|
|
||||||
// adjust scale if dest_width or dest_height is different
|
|
||||||
var scaleX = this.params.width / this.params.dest_width;
|
|
||||||
var scaleY = this.params.height / this.params.dest_height;
|
|
||||||
|
|
||||||
if ((scaleX != 1.0) || (scaleY != 1.0)) {
|
|
||||||
elem.style.overflow = 'visible';
|
|
||||||
video.style.webkitTransformOrigin = '0px 0px';
|
|
||||||
video.style.mozTransformOrigin = '0px 0px';
|
|
||||||
video.style.msTransformOrigin = '0px 0px';
|
|
||||||
video.style.oTransformOrigin = '0px 0px';
|
|
||||||
video.style.transformOrigin = '0px 0px';
|
|
||||||
video.style.webkitTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
|
|
||||||
video.style.mozTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
|
|
||||||
video.style.msTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
|
|
||||||
video.style.oTransform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
|
|
||||||
video.style.transform = 'scaleX('+scaleX+') scaleY('+scaleY+')';
|
|
||||||
}
|
|
||||||
|
|
||||||
// add video element to dom
|
|
||||||
elem.appendChild( video );
|
|
||||||
this.video = video;
|
|
||||||
|
|
||||||
// create offscreen canvas element to hold pixels later on
|
|
||||||
var canvas = document.createElement('canvas');
|
|
||||||
canvas.width = this.params.dest_width;
|
|
||||||
canvas.height = this.params.dest_height;
|
|
||||||
var context = canvas.getContext('2d');
|
|
||||||
this.context = context;
|
|
||||||
this.canvas = canvas;
|
|
||||||
|
|
||||||
// ask user for access to their camera
|
|
||||||
var self = this;
|
|
||||||
navigator.getUserMedia({
|
|
||||||
"audio": false,
|
|
||||||
"video": true
|
|
||||||
},
|
|
||||||
function(stream) {
|
|
||||||
// got access, attach stream to video
|
|
||||||
video.src = window.URL.createObjectURL( stream ) || stream;
|
|
||||||
Webcam.stream = stream;
|
|
||||||
Webcam.loaded = true;
|
|
||||||
Webcam.live = true;
|
|
||||||
Webcam.dispatch('load');
|
|
||||||
Webcam.dispatch('live');
|
|
||||||
},
|
|
||||||
function(err) {
|
|
||||||
return self.dispatch('error', "Could not access webcam.");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// flash fallback
|
|
||||||
elem.innerHTML = this.getSWFHTML();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
reset: function() {
|
|
||||||
// shutdown camera, reset to potentially attach again
|
|
||||||
if (this.userMedia) {
|
|
||||||
try { this.stream.stop(); } catch (e) {;}
|
|
||||||
delete this.stream;
|
|
||||||
delete this.canvas;
|
|
||||||
delete this.context;
|
|
||||||
delete this.video;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.container.innerHTML = '';
|
|
||||||
delete this.container;
|
|
||||||
|
|
||||||
this.loaded = false;
|
|
||||||
this.live = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
set: function() {
|
|
||||||
// set one or more params
|
|
||||||
// variable argument list: 1 param = hash, 2 params = key, value
|
|
||||||
if (arguments.length == 1) {
|
|
||||||
for (var key in arguments[0]) {
|
|
||||||
this.params[key] = arguments[0][key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.params[ arguments[0] ] = arguments[1];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
on: function(name, callback) {
|
|
||||||
// set callback hook
|
|
||||||
// supported hooks: onLoad, onError, onLive
|
|
||||||
name = name.replace(/^on/i, '').toLowerCase();
|
|
||||||
|
|
||||||
if (typeof(this.hooks[name]) == 'undefined')
|
|
||||||
throw "Event type not supported: " + name;
|
|
||||||
|
|
||||||
this.hooks[name] = callback;
|
|
||||||
},
|
|
||||||
|
|
||||||
dispatch: function() {
|
|
||||||
// fire hook callback, passing optional value to it
|
|
||||||
var name = arguments[0].replace(/^on/i, '').toLowerCase();
|
|
||||||
var args = Array.prototype.slice.call(arguments, 1);
|
|
||||||
|
|
||||||
if (this.hooks[name]) {
|
|
||||||
if (typeof(this.hooks[name]) == 'function') {
|
|
||||||
// callback is function reference, call directly
|
|
||||||
this.hooks[name].apply(this, args);
|
|
||||||
}
|
|
||||||
else if (typeof(this.hooks[name]) == 'array') {
|
|
||||||
// callback is PHP-style object instance method
|
|
||||||
this.hooks[name][0][this.hooks[name][1]].apply(this.hooks[name][0], args);
|
|
||||||
}
|
|
||||||
else if (window[this.hooks[name]]) {
|
|
||||||
// callback is global function name
|
|
||||||
window[ this.hooks[name] ].apply(window, args);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false; // no hook defined
|
|
||||||
},
|
|
||||||
|
|
||||||
setSWFLocation: function(url) {
|
|
||||||
// set location of SWF movie (defaults to webcam.swf in cwd)
|
|
||||||
this.swfURL = url;
|
|
||||||
},
|
|
||||||
|
|
||||||
getSWFHTML: function() {
|
|
||||||
// Return HTML for embedding flash based webcam capture movie
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
// make sure we aren't running locally (flash doesn't work)
|
|
||||||
if (location.protocol.match(/file/)) {
|
|
||||||
return '<h1 style="color:red">Sorry, the Webcam.js Flash fallback does not work from local disk. Please upload it to a web server first.</h1>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// set default swfURL if not explicitly set
|
|
||||||
if (!this.swfURL) {
|
|
||||||
// find our script tag, and use that base URL
|
|
||||||
var base_url = '';
|
|
||||||
var scpts = document.getElementsByTagName('script');
|
|
||||||
for (var idx = 0, len = scpts.length; idx < len; idx++) {
|
|
||||||
var src = scpts[idx].getAttribute('src');
|
|
||||||
if (src && src.match(/\/webcam(\.min)?\.js/)) {
|
|
||||||
base_url = src.replace(/\/webcam(\.min)?\.js.*$/, '');
|
|
||||||
idx = len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (base_url) this.swfURL = base_url + '/webcam.swf';
|
|
||||||
else this.swfURL = 'webcam.swf';
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this is the user's first visit, set flashvar so flash privacy settings panel is shown first
|
|
||||||
if (window.localStorage && !localStorage.getItem('visited')) {
|
|
||||||
this.params.new_user = 1;
|
|
||||||
localStorage.setItem('visited', 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// construct flashvars string
|
|
||||||
var flashvars = '';
|
|
||||||
for (var key in this.params) {
|
|
||||||
if (flashvars) flashvars += '&';
|
|
||||||
flashvars += key + '=' + escape(this.params[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" type="application/x-shockwave-flash" codebase="'+this.protocol+'://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+this.params.width+'" height="'+this.params.height+'" id="webcam_movie_obj" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+this.swfURL+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><embed id="webcam_movie_embed" src="'+this.swfURL+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+this.params.width+'" height="'+this.params.height+'" name="webcam_movie_embed" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'"></embed></object>';
|
|
||||||
|
|
||||||
return html;
|
|
||||||
},
|
|
||||||
|
|
||||||
getMovie: function() {
|
|
||||||
// get reference to movie object/embed in DOM
|
|
||||||
if (!this.loaded) return this.dispatch('error', "Flash Movie is not loaded yet");
|
|
||||||
var movie = document.getElementById('webcam_movie_obj');
|
|
||||||
if (!movie || !movie._snap) movie = document.getElementById('webcam_movie_embed');
|
|
||||||
if (!movie) this.dispatch('error', "Cannot locate Flash movie in DOM");
|
|
||||||
return movie;
|
|
||||||
},
|
|
||||||
|
|
||||||
snap: function() {
|
|
||||||
// take snapshot and return image data uri
|
|
||||||
if (!this.loaded) return this.dispatch('error', "Webcam is not loaded yet");
|
|
||||||
if (!this.live) return this.dispatch('error', "Webcam is not live yet");
|
|
||||||
|
|
||||||
if (this.userMedia) {
|
|
||||||
// native implementation
|
|
||||||
this.context.drawImage(this.video, 0, 0, this.params.dest_width, this.params.dest_height);
|
|
||||||
return this.canvas.toDataURL('image/' + this.params.image_format, this.params.jpeg_quality / 100 );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// flash fallback
|
|
||||||
var raw_data = this.getMovie()._snap();
|
|
||||||
return 'data:image/'+this.params.image_format+';base64,' + raw_data;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
configure: function(panel) {
|
|
||||||
// open flash configuration panel -- specify tab name:
|
|
||||||
// "camera", "privacy", "default", "localStorage", "microphone", "settingsManager"
|
|
||||||
if (!panel) panel = "camera";
|
|
||||||
this.getMovie()._configure(panel);
|
|
||||||
},
|
|
||||||
|
|
||||||
flashNotify: function(type, msg) {
|
|
||||||
// receive notification from flash about event
|
|
||||||
switch (type) {
|
|
||||||
case 'flashLoadComplete':
|
|
||||||
// movie loaded successfully
|
|
||||||
this.loaded = true;
|
|
||||||
this.dispatch('load');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'cameraLive':
|
|
||||||
// camera is live and ready to snap
|
|
||||||
this.live = true;
|
|
||||||
this.dispatch('live');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'error':
|
|
||||||
// Flash error
|
|
||||||
this.dispatch('error', msg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// catch-all event, just in case
|
|
||||||
// console.log("webcam flash_notify: " + type + ": " + msg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
b64ToUint6: function(nChr) {
|
|
||||||
// convert base64 encoded character to 6-bit integer
|
|
||||||
// from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
|
|
||||||
return nChr > 64 && nChr < 91 ? nChr - 65
|
|
||||||
: nChr > 96 && nChr < 123 ? nChr - 71
|
|
||||||
: nChr > 47 && nChr < 58 ? nChr + 4
|
|
||||||
: nChr === 43 ? 62 : nChr === 47 ? 63 : 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
base64DecToArr: function(sBase64, nBlocksSize) {
|
|
||||||
// convert base64 encoded string to Uintarray
|
|
||||||
// from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
|
|
||||||
var sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
|
|
||||||
nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2,
|
|
||||||
taBytes = new Uint8Array(nOutLen);
|
|
||||||
|
|
||||||
for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
|
|
||||||
nMod4 = nInIdx & 3;
|
|
||||||
nUint24 |= this.b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4;
|
|
||||||
if (nMod4 === 3 || nInLen - nInIdx === 1) {
|
|
||||||
for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
|
|
||||||
taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
|
|
||||||
}
|
|
||||||
nUint24 = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return taBytes;
|
|
||||||
},
|
|
||||||
|
|
||||||
upload: function(image_data_uri, target_url, callback, form_elem_name='webcam', csrf=null) {
|
|
||||||
// submit image data to server using binary AJAX
|
|
||||||
if (callback) Webcam.on('uploadComplete', callback);
|
|
||||||
|
|
||||||
// detect image format from within image_data_uri
|
|
||||||
var image_fmt = '';
|
|
||||||
if (image_data_uri.match(/^data\:image\/(\w+)/))
|
|
||||||
image_fmt = RegExp.$1;
|
|
||||||
else
|
|
||||||
throw "Cannot locate image format in Data URI";
|
|
||||||
|
|
||||||
// extract raw base64 data from Data URI
|
|
||||||
var raw_image_data = image_data_uri.replace(/^data\:image\/\w+\;base64\,/, '');
|
|
||||||
|
|
||||||
// contruct use AJAX object
|
|
||||||
var http = new XMLHttpRequest();
|
|
||||||
http.open("POST", target_url, true);
|
|
||||||
|
|
||||||
// setup progress events
|
|
||||||
if (http.upload && http.upload.addEventListener) {
|
|
||||||
http.upload.addEventListener( 'progress', function(e) {
|
|
||||||
if (e.lengthComputable) {
|
|
||||||
var progress = e.loaded / e.total;
|
|
||||||
Webcam.dispatch('uploadProgress', progress, e);
|
|
||||||
}
|
|
||||||
}, false );
|
|
||||||
}
|
|
||||||
|
|
||||||
// completion handler
|
|
||||||
http.onload = function() {
|
|
||||||
Webcam.dispatch('uploadComplete', http.status, http.responseText, http.statusText);
|
|
||||||
};
|
|
||||||
|
|
||||||
// create a blob and decode our base64 to binary
|
|
||||||
var blob = new Blob( [ this.base64DecToArr(raw_image_data) ], {type: 'image/'+image_fmt} );
|
|
||||||
|
|
||||||
// stuff into a form, so servers can easily receive it as a standard file upload
|
|
||||||
var form = new FormData();
|
|
||||||
if (csrf)
|
|
||||||
form.append(csrf.name, csrf.value);
|
|
||||||
form.append( form_elem_name, blob, form_elem_name+"."+image_fmt.replace(/e/, '') );
|
|
||||||
|
|
||||||
// send data to server
|
|
||||||
http.send(form);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
Webcam.init();
|
|
@ -260,6 +260,18 @@ a:not(.button) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.btn-red {
|
||||||
|
background-color: #fc8181;
|
||||||
|
color: black;
|
||||||
|
&:not(:disabled):hover {
|
||||||
|
background-color: darken(#fc8181, 15%);
|
||||||
|
}
|
||||||
|
&:disabled {
|
||||||
|
background-color: lighten(#fc8181, 15%);
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i {
|
i {
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,12 @@
|
|||||||
padding: 10px 10px 0;
|
padding: 10px 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.camera-error {
|
||||||
|
background-color: gray;
|
||||||
|
color: white;
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
&-display {
|
&-display {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -74,13 +80,17 @@
|
|||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
>img {
|
> img, > video {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
object-fit: contain;
|
object-fit: cover;
|
||||||
height: auto;
|
height: 100% !important;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> i {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
>p {
|
>p {
|
||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
@ -89,23 +99,43 @@
|
|||||||
|
|
||||||
&-edit {
|
&-edit {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column-reverse;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
> a {
|
> div {
|
||||||
margin-bottom: 15px;
|
max-width: 100%;
|
||||||
}
|
|
||||||
|
> input {
|
||||||
|
font-weight: normal;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
> button {
|
||||||
|
min-width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 750px) {
|
||||||
|
height: auto;
|
||||||
|
align-items: center;
|
||||||
|
display: inline-flex;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
> input {
|
||||||
|
width: 70%;
|
||||||
|
font-size: .6em;
|
||||||
|
&::file-selector-button {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> input {
|
|
||||||
font-size: .8em;
|
|
||||||
font-weight: normal;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> p {
|
> p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 10px;
|
||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 434 KiB |
1
core/static/vendored/jquery/ui/i18n/datepicker-fr.min.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
(e=>{"function"==typeof define&&define.amd?define(["../widgets/datepicker"],e):e(jQuery.datepicker)})(function(e){return e.regional.fr={closeText:"Fermer",prevText:"Précédent",nextText:"Suivant",currentText:"Aujourd'hui",monthNames:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],monthNamesShort:["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],dayNames:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],dayNamesShort:["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],dayNamesMin:["D","L","M","M","J","V","S"],weekHeader:"Sem.",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.setDefaults(e.regional.fr),e.regional.fr});
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>jQuery UI Example Page</title>
|
<title>jQuery UI Example Page</title>
|
||||||
<link href="jquery-ui.css" rel="stylesheet">
|
<link href="jquery-ui.min.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
body{
|
body{
|
||||||
font-family: "Trebuchet MS", sans-serif;
|
font-family: "Trebuchet MS", sans-serif;
|
||||||
@ -401,15 +401,6 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Tooltip -->
|
|
||||||
<h2 class="demoHeaders">Tooltip</h2>
|
|
||||||
<p id="tooltip">
|
|
||||||
<a href="#" title="That's what this widget is">Tooltips</a> can be attached to any element. When you hover
|
|
||||||
the element with your mouse, the title attribute is displayed in a little box next to the element, just like a native tooltip.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Highlight / Error -->
|
<!-- Highlight / Error -->
|
||||||
<h2 class="demoHeaders">Highlight / Error</h2>
|
<h2 class="demoHeaders">Highlight / Error</h2>
|
||||||
<div class="ui-widget">
|
<div class="ui-widget">
|
||||||
@ -426,8 +417,8 @@ the element with your mouse, the title attribute is displayed in a little box ne
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="external/jquery/jquery.js"></script>
|
<script src="../jquery-3.6.2.min.js"></script>
|
||||||
<script src="jquery-ui.js"></script>
|
<script src="jquery-ui.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
$( "#accordion" ).accordion();
|
$( "#accordion" ).accordion();
|
||||||
@ -537,11 +528,6 @@ $( "#spinner" ).spinner();
|
|||||||
$( "#menu" ).menu();
|
$( "#menu" ).menu();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$( "#tooltip" ).tooltip();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$( "#selectmenu" ).selectmenu();
|
$( "#selectmenu" ).selectmenu();
|
||||||
|
|
||||||
|
|
1
core/static/vendored/sentry/bundle.min.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
!function(n,e,r,t,i,o,a,c,s){for(var u=s,f=0;f<document.scripts.length;f++)if(document.scripts[f].src.indexOf(o)>-1){u&&"no"===document.scripts[f].getAttribute("data-lazy")&&(u=!1);break}var p=[];function l(n){return"e"in n}function d(n){return"p"in n}function _(n){return"f"in n}var v=[];function y(n){u&&(l(n)||d(n)||_(n)&&n.f.indexOf("capture")>-1||_(n)&&n.f.indexOf("showReportDialog")>-1)&&m(),v.push(n)}function g(){y({e:[].slice.call(arguments)})}function h(n){y({p:n})}function E(){try{n.SENTRY_SDK_SOURCE="loader";var e=n[i],o=e.init;e.init=function(i){n.removeEventListener(r,g),n.removeEventListener(t,h);var a=c;for(var s in i)Object.prototype.hasOwnProperty.call(i,s)&&(a[s]=i[s]);!function(n,e){var r=n.integrations||[];if(!Array.isArray(r))return;var t=r.map((function(n){return n.name}));n.tracesSampleRate&&-1===t.indexOf("BrowserTracing")&&(e.browserTracingIntegration?r.push(e.browserTracingIntegration({enableInp:!0})):e.BrowserTracing&&r.push(new e.BrowserTracing));(n.replaysSessionSampleRate||n.replaysOnErrorSampleRate)&&-1===t.indexOf("Replay")&&(e.replayIntegration?r.push(e.replayIntegration()):e.Replay&&r.push(new e.Replay));n.integrations=r}(a,e),o(a)},setTimeout((function(){return function(e){try{"function"==typeof n.sentryOnLoad&&(n.sentryOnLoad(),n.sentryOnLoad=void 0);for(var r=0;r<p.length;r++)"function"==typeof p[r]&&p[r]();p.splice(0);for(r=0;r<v.length;r++){_(o=v[r])&&"init"===o.f&&e.init.apply(e,o.a)}L()||e.init();var t=n.onerror,i=n.onunhandledrejection;for(r=0;r<v.length;r++){var o;if(_(o=v[r])){if("init"===o.f)continue;e[o.f].apply(e,o.a)}else l(o)&&t?t.apply(n,o.e):d(o)&&i&&i.apply(n,[o.p])}}catch(n){console.error(n)}}(e)}))}catch(n){console.error(n)}}var O=!1;function m(){if(!O){O=!0;var n=e.scripts[0],r=e.createElement("script");r.src=a,r.crossOrigin="anonymous",r.addEventListener("load",E,{once:!0,passive:!0}),n.parentNode.insertBefore(r,n)}}function L(){var e=n.__SENTRY__,r=void 0!==e&&e.version;return r?!!e[r]:!(void 0===e||!e.hub||!e.hub.getClient())}n[i]=n[i]||{},n[i].onLoad=function(n){L()?n():p.push(n)},n[i].forceLoad=function(){setTimeout((function(){m()}))},["init","addBreadcrumb","captureMessage","captureException","captureEvent","configureScope","withScope","showReportDialog"].forEach((function(e){n[i][e]=function(){y({f:e,a:arguments})}})),n.addEventListener(r,g),n.addEventListener(t,h),u||setTimeout((function(){m()}))}(window,document,"error","unhandledrejection","Sentry",'ab63c6820882cab2883218a4b9deba4d','https://browser.sentry-cdn.com/8.26.0/bundle.min.js',{"dsn":"https://ab63c6820882cab2883218a4b9deba4d@o4505360748642304.ingest.us.sentry.io/4507633486266368"},true);
|
@ -2,8 +2,7 @@
|
|||||||
{% block head %}
|
{% block head %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
<script
|
<script
|
||||||
src="https://browser.sentry-cdn.com/7.11.1/bundle.min.js"
|
src="{{ static('vendored/sentry/bundle.min.js') }}"
|
||||||
integrity="sha384-qcYSo5+/E8hEkPmHFa79GRDsGT84SRhBJHRw3+dbQyh0UwueiFP1jCsRBClEREcs"
|
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
></script>
|
></script>
|
||||||
{% endblock head %}
|
{% endblock head %}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="shortcut icon" href="{{ static('core/img/favicon.ico') }}">
|
<link rel="shortcut icon" href="{{ static('core/img/favicon.ico') }}">
|
||||||
<link rel="stylesheet" href="{{ static('core/base.css') }}">
|
<link rel="stylesheet" href="{{ static('core/base.css') }}">
|
||||||
<link rel="stylesheet" href="{{ static('ajax_select/css/ajax_select.css') }}">
|
<link rel="stylesheet" href="{{ static('ajax_select/css/ajax_select.css') }}">
|
||||||
<link rel="stylesheet" href="{{ scss('core/style.scss') }}">
|
<link rel="stylesheet" href="{{ scss('core/style.scss') }}">
|
||||||
<link rel="stylesheet" href="{{ scss('core/markdown.scss') }}">
|
<link rel="stylesheet" href="{{ scss('core/markdown.scss') }}">
|
||||||
<link rel="stylesheet" href="{{ scss('core/header.scss') }}">
|
<link rel="stylesheet" href="{{ scss('core/header.scss') }}">
|
||||||
@ -14,14 +14,14 @@
|
|||||||
|
|
||||||
{% block jquery_css %}
|
{% block jquery_css %}
|
||||||
{# Thile file is quite heavy (around 250kb), so declaring it in a block allows easy removal #}
|
{# Thile file is quite heavy (around 250kb), so declaring it in a block allows easy removal #}
|
||||||
<link rel="stylesheet" href="{{ static('core/js/ui/jquery-ui.min.css') }}">
|
<link rel="stylesheet" href="{{ static('vendored/jquery/ui/jquery-ui.min.css') }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<link rel="preload" as="style" href="{{ static('core/font-awesome/css/font-awesome.min.css') }}" onload="this.onload=null;this.rel='stylesheet'">
|
<link rel="preload" as="style" href="{{ static('vendored/font-awesome/css/font-awesome.min.css') }}" onload="this.onload=null;this.rel='stylesheet'">
|
||||||
<noscript><link rel="stylesheet" href="{{ static('core/font-awesome/css/font-awesome.min.css') }}"></noscript>
|
<noscript><link rel="stylesheet" href="{{ static('vendored/font-awesome/css/font-awesome.min.css') }}"></noscript>
|
||||||
<script defer href="{{ static('core/font-awesome/js/fontawesone.min.js') }}"></script>
|
<script defer href="{{ static('vendored/font-awesome/js/fontawesome.min.js') }}"></script>
|
||||||
|
|
||||||
<!-- Jquery declared here to be accessible in every django widgets -->
|
<!-- Jquery declared here to be accessible in every django widgets -->
|
||||||
<script src="{{ static('core/js/jquery-3.6.2.min.js') }}"></script>
|
<script src="{{ static('vendored/jquery/jquery-3.6.2.min.js') }}"></script>
|
||||||
<!-- Put here to always have acces to those functions on django widgets -->
|
<!-- Put here to always have acces to those functions on django widgets -->
|
||||||
<script src="{{ static('core/js/script.js') }}"></script>
|
<script src="{{ static('core/js/script.js') }}"></script>
|
||||||
|
|
||||||
@ -29,7 +29,7 @@
|
|||||||
{% block additional_js %}{% endblock %}
|
{% block additional_js %}{% endblock %}
|
||||||
|
|
||||||
{# Alpine JS must be loaded after scripts that use it. #}
|
{# Alpine JS must be loaded after scripts that use it. #}
|
||||||
<script src="{{ static('core/js/alpinejs.min.js') }}" defer></script>
|
<script src="{{ static('vendored/alpine/alpinejs.min.js') }}" defer></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -299,7 +299,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script src="{{ static('core/js/ui/jquery-ui.min.js') }}"></script>
|
<script src="{{ static('vendored/jquery/ui/jquery-ui.min.js') }}"></script>
|
||||||
<script src="{{ static('ajax_select/js/ajax_select.js') }}"></script>
|
<script src="{{ static('ajax_select/js/ajax_select.js') }}"></script>
|
||||||
<script src="{{ url('javascript-catalog') }}"></script>
|
<script src="{{ url('javascript-catalog') }}"></script>
|
||||||
<script>
|
<script>
|
||||||
|
@ -116,6 +116,46 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro paginate_alpine(page, nb_pages) %}
|
||||||
|
{# Add pagination buttons for ajax based content with alpine
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
This can only be used in the scope of your alpine datastore
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
You might need to listen to the "popstate" event in your code
|
||||||
|
to update the current page you are on when the user goes back in
|
||||||
|
it's browser history with the back arrow
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
page (str): name of the alpine page variable in your datastore
|
||||||
|
nb_page (str): call to a javascript function or variable returning
|
||||||
|
the maximum number of pages to paginate
|
||||||
|
#}
|
||||||
|
<nav class="pagination" x-show="{{ nb_pages }} > 1">
|
||||||
|
{# Adding the prevent here is important, because otherwise,
|
||||||
|
clicking on the pagination buttons could submit the picture management form
|
||||||
|
and reload the page #}
|
||||||
|
<button
|
||||||
|
@click.prevent="{{ page }}--"
|
||||||
|
:disabled="{{ page }} <= 1"
|
||||||
|
@keyup.right.window="{{ page }} = Math.min({{ nb_pages }}, {{ page }} + 1)"
|
||||||
|
>
|
||||||
|
<i class="fa fa-caret-left"></i>
|
||||||
|
</button>
|
||||||
|
<template x-for="i in {{ nb_pages }}">
|
||||||
|
<button x-text="i" @click.prevent="{{ page }} = i" :class="{active: {{ page }} === i}"></button>
|
||||||
|
</template>
|
||||||
|
<button
|
||||||
|
@click.prevent="{{ page }}++"
|
||||||
|
:disabled="{{ page }} >= {{ nb_pages }}"
|
||||||
|
@keyup.left.window="{{ page }} = Math.max(1, {{ page }} - 1)"
|
||||||
|
>
|
||||||
|
<i class="fa fa-caret-right"></i>
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro paginate(page_obj, paginator, js_action) %}
|
{% macro paginate(page_obj, paginator, js_action) %}
|
||||||
{% set js = js_action|default('') %}
|
{% set js = js_action|default('') %}
|
||||||
{% if page_obj.has_previous() or page_obj.has_next() %}
|
{% if page_obj.has_previous() or page_obj.has_next() %}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<title>{% trans %}Slideshow{% endtrans %}</title>
|
<title>{% trans %}Slideshow{% endtrans %}</title>
|
||||||
<link href="{{ scss('com/slideshow.scss') }}" rel="stylesheet" type="text/css" />
|
<link href="{{ scss('com/css/slideshow.scss') }}" rel="stylesheet" type="text/css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="slideshow">
|
<div id="slideshow">
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
<h4>{% trans %}Users{% endtrans %}</h4>
|
<h4>{% trans %}Users{% endtrans %}</h4>
|
||||||
<ul>
|
<ul>
|
||||||
{% for i in result.users %}
|
{% for i in result.users %}
|
||||||
<li>
|
{% if user.can_view(i) %}
|
||||||
{{ user_link_with_pict(i) }}
|
<li>
|
||||||
</li>
|
{{ user_link_with_pict(i) }}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<h4>{% trans %}Clubs{% endtrans %}</h4>
|
<h4>{% trans %}Clubs{% endtrans %}</h4>
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
{% extends "core/base.jinja" %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{% trans %}To Markdown{% endtrans %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<form action="" method="post" enctype="multipart/form-data">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="radio" name="syntax" value="doku" {% if request.POST['syntax'] != "bbcode" %}checked{% endif %} >Doku</input>
|
|
||||||
<input type="radio" name="syntax" value="bbcode" {% if request.POST['syntax'] == "bbcode" %}checked{% endif %} >BBCode</input>
|
|
||||||
<textarea name="text" id="text" rows="30" cols="80">
|
|
||||||
{{- text -}}
|
|
||||||
</textarea>
|
|
||||||
<p><input type="submit" value="{% trans %}Convert{% endtrans %}" /></p>
|
|
||||||
</form>
|
|
||||||
<hr>
|
|
||||||
<h6>{% trans %}Markdown{% endtrans %}</h6>
|
|
||||||
<div style="border: 1px solid black; color: white; background: black; padding: 10px; margin: 5px;"><pre>{{- text_md -}}</pre>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<h6>{% trans %}Render{% endtrans %}</h6>
|
|
||||||
<div style="border: 1px solid black; padding: 10px; margin: 5px;" class="page_content">
|
|
||||||
{{ text_md|markdown }}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -8,6 +8,191 @@
|
|||||||
<link rel="stylesheet" href="{{ scss('user/user_edit.scss') }}">
|
<link rel="stylesheet" href="{{ scss('user/user_edit.scss') }}">
|
||||||
{%- endblock -%}
|
{%- endblock -%}
|
||||||
|
|
||||||
|
{% macro profile_picture(field_name) %}
|
||||||
|
<div class="profile-picture" x-data="camera_{{ field_name }}" >
|
||||||
|
<div class="profile-picture-display" :aria-busy="loading" :class="{ 'camera-error': is_camera_error }">
|
||||||
|
<img
|
||||||
|
x-show="!is_camera_enabled && !is_camera_error"
|
||||||
|
:src="get_picture()"
|
||||||
|
alt="{%- trans -%}Profile{%- endtrans -%}" title="{%- trans -%}Profile{%- endtrans -%}"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
<video
|
||||||
|
x-show="is_camera_enabled"
|
||||||
|
x-ref="video"
|
||||||
|
></video>
|
||||||
|
<i
|
||||||
|
x-show="is_camera_error"
|
||||||
|
x-cloak
|
||||||
|
class="fa fa-eye-slash"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
<div class="profile-picture-buttons" x-show="can_edit_picture">
|
||||||
|
<button
|
||||||
|
x-show="can_edit_picture && !is_camera_enabled"
|
||||||
|
class="btn btn-blue"
|
||||||
|
@click.prevent="enable_camera()"
|
||||||
|
>
|
||||||
|
<i class="fa fa-camera"></i>
|
||||||
|
{% trans %}Enable camera{% endtrans %}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
x-show="is_camera_enabled"
|
||||||
|
class="btn btn-blue"
|
||||||
|
@click.prevent="take_picture()"
|
||||||
|
>
|
||||||
|
<i class="fa fa-camera"></i>
|
||||||
|
{% trans %}Take a picture{% endtrans %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div x-ref="form" class="profile-picture-edit">
|
||||||
|
{%- if form[field_name] -%}
|
||||||
|
<div>
|
||||||
|
{{ form[field_name] }}
|
||||||
|
<button class="btn btn-red" @click.prevent="delete_picture()"
|
||||||
|
{%- if not (user.is_root and form.instance[field_name]) -%}
|
||||||
|
:disabled="picture == null"
|
||||||
|
{%- endif -%}
|
||||||
|
x-cloak
|
||||||
|
>
|
||||||
|
{%- trans -%}Delete{%- endtrans -%}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
{{ form[field_name].label }}
|
||||||
|
</p>
|
||||||
|
{%- else -%}
|
||||||
|
<em>{% trans %}To edit your profile picture, ask a member of the AE{% endtrans %}</em>
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
document.addEventListener("alpine:init", () => {
|
||||||
|
Alpine.data("camera_{{ field_name }}", () => ({
|
||||||
|
can_edit_picture: false,
|
||||||
|
|
||||||
|
loading: false,
|
||||||
|
is_camera_enabled: false,
|
||||||
|
is_camera_error: false,
|
||||||
|
picture: null,
|
||||||
|
video: null,
|
||||||
|
picture_form: null,
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.video = this.$refs.video;
|
||||||
|
this.picture_form = this.$refs.form.getElementsByTagName("input");
|
||||||
|
if (this.picture_form.length > 0){
|
||||||
|
this.picture_form = this.picture_form[0];
|
||||||
|
this.can_edit_picture = true;
|
||||||
|
|
||||||
|
{# Link the displayed element to the form input #}
|
||||||
|
this.picture_form.onchange = (event) => {
|
||||||
|
let files = event.srcElement.files;
|
||||||
|
if (files.length > 0){
|
||||||
|
this.picture = (window.URL || window.webkitURL)
|
||||||
|
.createObjectURL(event.srcElement.files[0]);
|
||||||
|
} else {
|
||||||
|
this.picture = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
get_picture() {
|
||||||
|
if (this.picture != null) {
|
||||||
|
return this.picture;
|
||||||
|
}
|
||||||
|
|
||||||
|
{%- if form.instance[field_name] -%}
|
||||||
|
return "{{ form.instance[field_name].get_download_url() }}"
|
||||||
|
{%- else -%}
|
||||||
|
return "{{ static('core/img/unknown.jpg') }}"
|
||||||
|
{%- endif -%}
|
||||||
|
},
|
||||||
|
|
||||||
|
delete_picture() {
|
||||||
|
|
||||||
|
{# Only remove currently displayed picture #}
|
||||||
|
if (this.picture != null){
|
||||||
|
let list = new DataTransfer();
|
||||||
|
this.picture_form.files = list.files;
|
||||||
|
this.picture_form.dispatchEvent(new Event("change"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{# Remove user picture if correct rights are available #}
|
||||||
|
{%- if user.is_root and form.instance[field_name] -%}
|
||||||
|
window.open(
|
||||||
|
'{{ url(
|
||||||
|
'core:file_delete',
|
||||||
|
file_id=form.instance[field_name].id,
|
||||||
|
popup=''
|
||||||
|
) }}',
|
||||||
|
'_self');
|
||||||
|
{%- endif -%}
|
||||||
|
},
|
||||||
|
|
||||||
|
enable_camera() {
|
||||||
|
this.picture = null;
|
||||||
|
this.loading = true;
|
||||||
|
this.is_camera_error = false;
|
||||||
|
navigator.mediaDevices
|
||||||
|
.getUserMedia({ video: true, audio: false })
|
||||||
|
.then((stream) => {
|
||||||
|
this.loading = false;
|
||||||
|
this.is_camera_enabled = true;
|
||||||
|
this.video.srcObject = stream;
|
||||||
|
this.video.play();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.is_camera_error = true;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
take_picture() {
|
||||||
|
let canvas = document.createElement("canvas")
|
||||||
|
const context = canvas.getContext("2d");
|
||||||
|
|
||||||
|
/* Create the image */
|
||||||
|
let settings = this.video.srcObject.getTracks()[0].getSettings();
|
||||||
|
canvas.width = settings.width;
|
||||||
|
canvas.height = settings.height;
|
||||||
|
context.drawImage(this.video, 0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
/* Stop camera */
|
||||||
|
this.video.pause()
|
||||||
|
this.video.srcObject.getTracks().forEach((track) => {
|
||||||
|
if (track.readyState == 'live') {
|
||||||
|
track.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.toBlob((blob) => {
|
||||||
|
let file = new File(
|
||||||
|
[blob],
|
||||||
|
"{% trans %}captured{% endtrans %}.png",
|
||||||
|
{ type: "image/jpeg" },
|
||||||
|
);
|
||||||
|
|
||||||
|
let list = new DataTransfer();
|
||||||
|
list.items.add(file);
|
||||||
|
this.picture_form.files = list.files;
|
||||||
|
|
||||||
|
{# No change event is triggered, we trigger it manually #}
|
||||||
|
this.picture_form.dispatchEvent(new Event("change"));
|
||||||
|
}, "image/webp");
|
||||||
|
|
||||||
|
|
||||||
|
canvas.remove();
|
||||||
|
this.is_camera_enabled = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
{%- block content -%}
|
{%- block content -%}
|
||||||
<h2 class="title">{%- trans -%}Edit user profile{%- endtrans -%}</h2>
|
<h2 class="title">{%- trans -%}Edit user profile{%- endtrans -%}</h2>
|
||||||
<form action="" method="post" enctype="multipart/form-data" id="user_edit">
|
<form action="" method="post" enctype="multipart/form-data" id="user_edit">
|
||||||
@ -17,71 +202,13 @@
|
|||||||
|
|
||||||
{# User Pictures #}
|
{# User Pictures #}
|
||||||
<div class="profile-pictures">
|
<div class="profile-pictures">
|
||||||
<div class="profile-picture">
|
|
||||||
<div class="profile-picture-display">
|
|
||||||
|
|
||||||
{%- if form.instance.profile_pict -%}
|
{{ profile_picture("profile_pict") }}
|
||||||
<img src="{{ form.instance.profile_pict.get_download_url() }}"
|
|
||||||
alt="{%- trans -%}Profile{%- endtrans -%}" title="{%- trans -%}Profile{%- endtrans -%}" />
|
{{ profile_picture("avatar_pict") }}
|
||||||
{%- else -%}
|
|
||||||
<img src="{{ static('core/img/unknown.jpg') }}" alt="{%- trans -%}Profile{%- endtrans -%}"
|
{{ profile_picture("scrub_pict") }}
|
||||||
title="{%- trans -%}Profile{%- endtrans -%}" />
|
|
||||||
{%- endif -%}
|
|
||||||
</div>
|
|
||||||
<div class="profile-picture-edit">
|
|
||||||
{%- if form["profile_pict"] -%}
|
|
||||||
<p>{{ form["profile_pict"].label }}</p>
|
|
||||||
{{ form["profile_pict"] }}
|
|
||||||
{%- else -%}
|
|
||||||
<em>{% trans %}To edit your profile picture, ask a member of the AE{% endtrans %}</em>
|
|
||||||
{%- endif -%}
|
|
||||||
{%- if user.is_board_member and form.instance.profile_pict.id -%}
|
|
||||||
<a href="{{ url('core:file_delete', file_id=form.instance.profile_pict.id, popup='') }}">
|
|
||||||
{%- trans -%}Delete{%- endtrans -%}
|
|
||||||
</a>
|
|
||||||
{%- endif -%}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="profile-picture">
|
|
||||||
<div class="profile-picture-display">
|
|
||||||
{%- if form.instance.avatar_pict -%}
|
|
||||||
<img src="{{ form.instance.avatar_pict.get_download_url() }}" alt="{%- trans -%}Profile{%- endtrans -%}"
|
|
||||||
title="{%- trans -%}Profile{%- endtrans -%}" />
|
|
||||||
{%- else -%}
|
|
||||||
<img src="{{ static('core/img/unknown.jpg') }}" alt="{%- trans -%}Profile{%- endtrans -%}"
|
|
||||||
title="{%- trans -%}Profile{%- endtrans -%}" />
|
|
||||||
{%- endif -%}
|
|
||||||
</div>
|
|
||||||
<div class="profile-picture-edit">
|
|
||||||
<p>{{ form["avatar_pict"].label }}</p>
|
|
||||||
{{ form["avatar_pict"] }}
|
|
||||||
{%- if user.is_board_member and form.instance.avatar_pict.id -%}
|
|
||||||
<a href="{{ url('core:file_delete', file_id=form.instance.avatar_pict.id, popup='') }}">
|
|
||||||
{%- trans -%}Delete{%- endtrans -%}
|
|
||||||
</a>
|
|
||||||
{%- endif -%}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="profile-picture">
|
|
||||||
<div class="profile-picture-display">
|
|
||||||
{%- if form.instance.scrub_pict -%}
|
|
||||||
<img src="{{ form.instance.scrub_pict.get_download_url() }}" alt="{%- trans -%}Profile{%- endtrans -%}"
|
|
||||||
title="{%- trans -%}Profile{%- endtrans -%}" />
|
|
||||||
{%- else -%}
|
|
||||||
<img src="{{ static('core/img/unknown.jpg') }}" alt="{%- trans -%}Profile{%- endtrans -%}"
|
|
||||||
title="{%- trans -%}Profile{%- endtrans -%}" />
|
|
||||||
{%- endif -%}
|
|
||||||
</div>
|
|
||||||
<div class="profile-picture-edit">
|
|
||||||
<p>{{ form["scrub_pict"].label }}</p>
|
|
||||||
{{ form["scrub_pict"] }}
|
|
||||||
{%- if user.is_board_member and form.instance.scrub_pict.id -%}
|
|
||||||
<a href="{{ url('core:file_delete', file_id=form.instance.scrub_pict.id, popup='') }}">
|
|
||||||
{%- trans -%}Delete{%-endtrans -%}
|
|
||||||
</a>
|
|
||||||
{%- endif -%}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -108,7 +235,7 @@
|
|||||||
|
|
||||||
{# Textareas #}
|
{# Textareas #}
|
||||||
<div class="profile-fields">
|
<div class="profile-fields">
|
||||||
{%- for field in [form["quote"], form["forum_signature"]] -%}
|
{%- for field in [form.quote, form.forum_signature] -%}
|
||||||
<div class="profile-field">
|
<div class="profile-field">
|
||||||
<div class="profile-field-label">{{ field.label }}</div>
|
<div class="profile-field-label">{{ field.label }}</div>
|
||||||
<div class="profile-field-content">
|
<div class="profile-field-content">
|
||||||
@ -123,8 +250,8 @@
|
|||||||
|
|
||||||
{# Checkboxes #}
|
{# Checkboxes #}
|
||||||
<div class="profile-visible">
|
<div class="profile-visible">
|
||||||
{{ form["is_subscriber_viewable"] }}
|
{{ form.is_subscriber_viewable }}
|
||||||
{{ form["is_subscriber_viewable"].label }}
|
{{ form.is_subscriber_viewable.label }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{%- if form.instance == user -%}
|
{%- if form.instance == user -%}
|
||||||
@ -153,37 +280,3 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
{%- endblock -%}
|
{%- endblock -%}
|
||||||
|
|
||||||
{%- block script -%}
|
|
||||||
{{ super() }}
|
|
||||||
{%- if not form.instance.profile_pict -%}
|
|
||||||
<script src="{{ static('core/js/webcam.js') }}"></script>
|
|
||||||
<script>
|
|
||||||
Webcam.on('error', function (msg) { console.log('Webcam.js error: ' + msg) })
|
|
||||||
Webcam.set({
|
|
||||||
width: 320,
|
|
||||||
height: 240,
|
|
||||||
dest_width: 320,
|
|
||||||
dest_height: 240,
|
|
||||||
image_format: 'jpeg',
|
|
||||||
jpeg_quality: 90,
|
|
||||||
force_flash: false
|
|
||||||
});
|
|
||||||
Webcam.attach('#camera_canvas');
|
|
||||||
function take_snapshot() {
|
|
||||||
const data_uri = Webcam.snap();
|
|
||||||
const url = "{{ url('core:user_profile_upload', user_id=form.instance.id) }}";
|
|
||||||
Webcam.upload(data_uri, url, function (code, text) {
|
|
||||||
if (code === 302 || code === 200) {
|
|
||||||
$('#new_profile').attr('src', data_uri);
|
|
||||||
$('#take_picture').remove();
|
|
||||||
$('#id_profile_pict').remove();
|
|
||||||
} else {
|
|
||||||
console.log("Unknown error: ");
|
|
||||||
console.log(text);
|
|
||||||
}
|
|
||||||
}, "new_profile_pict", { name: 'csrfmiddlewaretoken', value: '{{ csrf_token }}' });
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{%- endif -%}
|
|
||||||
{%- endblock -%}
|
|
@ -1,15 +1,15 @@
|
|||||||
{% extends "core/base.jinja" %}
|
{% extends "core/base.jinja" %}
|
||||||
|
|
||||||
{%- block additional_css -%}
|
{%- block additional_css -%}
|
||||||
<link rel="stylesheet" href="{{ scss('sas/album.scss') }}">
|
<link rel="stylesheet" href="{{ scss('sas/css/album.scss') }}">
|
||||||
{%- endblock -%}
|
{%- endblock -%}
|
||||||
|
|
||||||
{% block additional_js %}
|
{% block additional_js %}
|
||||||
<script defer type="module">
|
<script defer type="module">
|
||||||
import { showSaveFilePicker } from "{{ static('core/js/native-file-system-adapter/mod.js') }}";
|
import { showSaveFilePicker } from "{{ static('vendored/native-file-system-adapter/mod.js') }}";
|
||||||
window.showSaveFilePicker = showSaveFilePicker; /* Export function to normal javascript */
|
window.showSaveFilePicker = showSaveFilePicker; /* Export function to normal javascript */
|
||||||
</script>
|
</script>
|
||||||
<script defer type="text/javascript" src="{{ static('core/js/zipjs/zip-fs-full.min.js') }}"></script>
|
<script defer type="text/javascript" src="{{ static('vendored/zipjs/zip-fs-full.min.js') }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
@ -17,58 +17,54 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main>
|
<main x-data="user_pictures">
|
||||||
{% if user.id == object.id and albums|length > 0 %}
|
{% if user.id == object.id %}
|
||||||
<div x-data="picture_download" x-cloak>
|
<div x-show="pictures.length > 0" x-cloak>
|
||||||
<button
|
<button
|
||||||
:disabled="in_progress"
|
:disabled="is_downloading"
|
||||||
class="btn btn-blue"
|
class="btn btn-blue"
|
||||||
@click="download_zip()"
|
@click="download_zip()"
|
||||||
>
|
>
|
||||||
<i class="fa fa-download"></i>
|
<i class="fa fa-download"></i>
|
||||||
{% trans %}Download all my pictures{% endtrans %}
|
{% trans %}Download all my pictures{% endtrans %}
|
||||||
</button>
|
</button>
|
||||||
<progress x-ref="progress" x-show="in_progress"></progress>
|
<progress x-ref="progress" x-show="is_downloading"></progress>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for album, pictures in albums|items %}
|
|
||||||
<h4>{{ album }}</h4>
|
<template x-for="[album, pictures] in Object.entries(albums)" x-cloak>
|
||||||
<br />
|
<section>
|
||||||
<div class="photos">
|
<br />
|
||||||
{% for picture in pictures %}
|
<h4 x-text="album"></h4>
|
||||||
{% if picture.can_be_viewed_by(user) %}
|
<div class="photos">
|
||||||
<a href="{{ url("sas:picture", picture_id=picture.id) }}#pict">
|
<template x-for="picture in pictures">
|
||||||
|
<a :href="`/sas/picture/${picture.id}#pict`">
|
||||||
<div
|
<div
|
||||||
class="photo{% if not picture.is_moderated %} not_moderated{% endif %}"
|
class="photo"
|
||||||
style="background-image: url('{% if picture.file %}{{ picture.get_download_thumb_url() }}{% else %}{{ static('core/img/sas.jpg') }}{% endif %}');"
|
:class="{not_moderated: !picture.is_moderated}"
|
||||||
|
:style="`background-image: url(${picture.thumb_url})`"
|
||||||
>
|
>
|
||||||
{% if not picture.is_moderated %}
|
<template x-if="!picture.is_moderated">
|
||||||
<div class="overlay"> </div>
|
<div class="overlay"> </div>
|
||||||
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
|
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
|
||||||
{% else %}
|
</template>
|
||||||
|
<template x-if="picture.is_moderated">
|
||||||
<div class="text"> </div>
|
<div class="text"> </div>
|
||||||
{% endif %}
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
</template>
|
||||||
<div>
|
</div>
|
||||||
<div class="photo">
|
</section>
|
||||||
<div class="text">{% trans %}Picture Unavailable{% endtrans %}</div>
|
</template>
|
||||||
</div>
|
<div class="photos" :aria-busy="loading"></div>
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
{% endfor %}
|
|
||||||
</main>
|
</main>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
|
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
{% if user.id == object.id %}
|
<script>
|
||||||
<script>
|
|
||||||
/**
|
/**
|
||||||
* @typedef Picture
|
* @typedef Picture
|
||||||
* @property {number} id
|
* @property {number} id
|
||||||
@ -82,62 +78,80 @@
|
|||||||
* @property {string} album
|
* @property {string} album
|
||||||
*/
|
*/
|
||||||
|
|
||||||
document.addEventListener("alpine:init", () => {
|
document.addEventListener("alpine:init", () => {
|
||||||
Alpine.data("picture_download", () => ({
|
Alpine.data("user_pictures", () => ({
|
||||||
in_progress: false,
|
is_downloading: false,
|
||||||
|
loading: true,
|
||||||
|
pictures: [],
|
||||||
|
albums: {},
|
||||||
|
|
||||||
/**
|
async init() {
|
||||||
* @return {Promise<Picture[]>}
|
this.pictures = await this.get_pictures();
|
||||||
*/
|
this.albums = this.pictures.reduce((acc, picture) => {
|
||||||
async get_pictures() {
|
if (!acc[picture.album]){
|
||||||
{# The API forbids to get more than 199 items at once
|
acc[picture.album] = [];
|
||||||
from paginated routes.
|
|
||||||
In order to download all the user pictures, it may be needed
|
|
||||||
to performs multiple requests #}
|
|
||||||
const max_per_page = 199;
|
|
||||||
const url = "{{ url("api:pictures") }}"
|
|
||||||
+ "?users_identified={{ object.id }}"
|
|
||||||
+ `&page_size=${max_per_page}`;
|
|
||||||
let promises = [];
|
|
||||||
const nb_pages = Math.ceil({{ nb_pictures }} / max_per_page);
|
|
||||||
for (let i = 1; i <= nb_pages; i++) {
|
|
||||||
promises.push(
|
|
||||||
fetch(url + `&page=${i}`).then(res => res.json().then(json => json.results))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return (await Promise.all(promises)).flat()
|
acc[picture.album].push(picture);
|
||||||
},
|
return acc;
|
||||||
|
}, {});
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Promise<Picture[]>}
|
||||||
|
*/
|
||||||
|
async get_pictures() {
|
||||||
|
{# The API forbids to get more than 199 items at once
|
||||||
|
from paginated routes.
|
||||||
|
In order to download all the user pictures, it may be needed
|
||||||
|
to performs multiple requests #}
|
||||||
|
const max_per_page = 199;
|
||||||
|
const url = "{{ url("api:pictures") }}"
|
||||||
|
+ "?users_identified={{ object.id }}"
|
||||||
|
+ `&page_size=${max_per_page}`;
|
||||||
|
|
||||||
async download_zip(){
|
let first_page = (await ( await fetch(url)).json());
|
||||||
this.in_progress = true;
|
let promises = [first_page.results];
|
||||||
const bar = this.$refs.progress;
|
|
||||||
bar.value = 0;
|
|
||||||
const pictures = await this.get_pictures();
|
|
||||||
bar.max = pictures.length;
|
|
||||||
|
|
||||||
const fileHandle = await window.showSaveFilePicker({
|
const nb_pictures = first_page.count
|
||||||
_preferPolyfill: false,
|
const nb_pages = Math.ceil(nb_pictures / max_per_page);
|
||||||
suggestedName: "{%- trans -%} pictures {%- endtrans -%}.zip",
|
|
||||||
types: {},
|
|
||||||
excludeAcceptAllOption: false,
|
|
||||||
})
|
|
||||||
const zipWriter = new zip.ZipWriter(await fileHandle.createWritable());
|
|
||||||
|
|
||||||
await Promise.all(pictures.map(p => {
|
for (let i = 2; i <= nb_pages; i++) {
|
||||||
const img_name = p.album + "/IMG_" + p.date.replaceAll(/[:\-]/g, "_") + p.name.slice(p.name.lastIndexOf("."));
|
promises.push(
|
||||||
return zipWriter.add(
|
fetch(url + `&page=${i}`).then(res => res.json().then(json => json.results))
|
||||||
img_name,
|
);
|
||||||
new zip.HttpReader(p.full_size_url),
|
|
||||||
{level: 9, lastModDate: new Date(p.date), onstart: () => bar.value += 1}
|
|
||||||
);
|
|
||||||
}));
|
|
||||||
|
|
||||||
await zipWriter.close();
|
|
||||||
this.in_progress = false;
|
|
||||||
}
|
}
|
||||||
}))
|
return (await Promise.all(promises)).flat()
|
||||||
});
|
},
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
|
async download_zip(){
|
||||||
|
this.is_downloading = true;
|
||||||
|
const bar = this.$refs.progress;
|
||||||
|
bar.value = 0;
|
||||||
|
bar.max = this.pictures.length;
|
||||||
|
|
||||||
|
const fileHandle = await window.showSaveFilePicker({
|
||||||
|
_preferPolyfill: false,
|
||||||
|
suggestedName: "{%- trans -%} pictures {%- endtrans -%}.zip",
|
||||||
|
types: {},
|
||||||
|
excludeAcceptAllOption: false,
|
||||||
|
})
|
||||||
|
const zipWriter = new zip.ZipWriter(await fileHandle.createWritable());
|
||||||
|
|
||||||
|
await Promise.all(this.pictures.map(p => {
|
||||||
|
const img_name = p.album + "/IMG_" + p.date.replaceAll(/[:\-]/g, "_") + p.name.slice(p.name.lastIndexOf("."));
|
||||||
|
return zipWriter.add(
|
||||||
|
img_name,
|
||||||
|
new zip.HttpReader(p.full_size_url),
|
||||||
|
{level: 9, lastModDate: new Date(p.date), onstart: () => bar.value += 1}
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
|
||||||
|
await zipWriter.close();
|
||||||
|
this.is_downloading = false;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{% endblock script %}
|
{% endblock script %}
|
||||||
|
@ -190,7 +190,6 @@ or user.is_in_group(pk=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
|||||||
<div>
|
<div>
|
||||||
<h4>{% trans %}Other tools{% endtrans %}</h4>
|
<h4>{% trans %}Other tools{% endtrans %}</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{{ url('core:to_markdown') }}">{% trans %}Convert dokuwiki/BBcode syntax to Markdown{% endtrans %}</a></li>
|
|
||||||
<li><a href="{{ url('trombi:user_tools') }}">{% trans %}Trombi tools{% endtrans %}</a></li>
|
<li><a href="{{ url('trombi:user_tools') }}">{% trans %}Trombi tools{% endtrans %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,14 +26,19 @@ import datetime
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import phonenumbers
|
import phonenumbers
|
||||||
|
import sass
|
||||||
from django import template
|
from django import template
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.staticfiles.finders import find
|
||||||
|
from django.core.files.base import ContentFile
|
||||||
|
from django.core.files.storage import storages
|
||||||
from django.template import TemplateSyntaxError
|
from django.template import TemplateSyntaxError
|
||||||
from django.template.defaultfilters import stringfilter
|
from django.template.defaultfilters import stringfilter
|
||||||
|
from django.templatetags.static import static
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ngettext
|
from django.utils.translation import ngettext
|
||||||
|
|
||||||
from core.markdown import markdown as md
|
from core.markdown import markdown as md
|
||||||
from core.scss.processor import process_scss_path
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
@ -91,4 +96,15 @@ def scss(path):
|
|||||||
path = Path(path)
|
path = Path(path)
|
||||||
if path.suffix != ".scss":
|
if path.suffix != ".scss":
|
||||||
raise TemplateSyntaxError("`scss` tag has been called with a non-scss file")
|
raise TemplateSyntaxError("`scss` tag has been called with a non-scss file")
|
||||||
return process_scss_path(path)
|
|
||||||
|
css_path = path.with_suffix(".css")
|
||||||
|
if settings.DEBUG:
|
||||||
|
compile_args = {"filename": find(path)}
|
||||||
|
if settings.SASS_PRECISION:
|
||||||
|
compile_args["precision"] = settings.SASS_PRECISION
|
||||||
|
content = sass.compile(**compile_args)
|
||||||
|
storage = storages["staticfiles"]
|
||||||
|
if storage.exists(css_path):
|
||||||
|
storage.delete(css_path)
|
||||||
|
storage.save(css_path, ContentFile(content))
|
||||||
|
return static(str(css_path))
|
||||||
|
@ -38,7 +38,6 @@ register_converter(BooleanStringConverter, "bool")
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", index, name="index"),
|
path("", index, name="index"),
|
||||||
path("to_markdown/", ToMarkdownView.as_view(), name="to_markdown"),
|
|
||||||
path("notifications/", NotificationList.as_view(), name="notification_list"),
|
path("notifications/", NotificationList.as_view(), name="notification_list"),
|
||||||
path("notification/<int:notif_id>/", notification, name="notification"),
|
path("notification/<int:notif_id>/", notification, name="notification"),
|
||||||
# Search
|
# Search
|
||||||
|